"exception" value ["with" Signatures "end"] --> "exception" value ["with" Signatures] "end" "raise" value ["with" Bindings "end"] --> "raise" value ["with" Bindings] "end" "extend" value ["with" Bindings "end"] --> "extend" value ["with" Bindings] "end"Diese Änderung wurde nötig, da Ausdrücke wie
raise exception "lala" with endauf zwei verschiedene Arten geparst werden können:
raise {exception "lala"} with end
raise {exception "lala" with end}
Dies ist eine Variante des dangling-else-Problems.
"Exception" ["with" Signatures "end"] --> "Exception" Signatures "end"Analog zur Wertebene.
Ide ::= identifier | infix | colonInfix | "{" Ide "}"
-->
Ide ::= identifier | "infix" (infix | colonInfix)
Wenn man einen Infix-Identifier in seiner Rolle als Identifier und
nicht als Operator ansprechen will, muß man ihn nun explizit als
"infix" markieren.
Das verhindert Fehler wie z.B.
if test then 1 else -1 endIn der neuen Syntax heißt das nämlich:
if test then 1 else
infix- (* Wert wird ignoriert *)
1
end
Weitere Beispiele:
let infix+ = int.add let x = a + b let y = infix+(a b)
"open" ValueIde ":" Type --> "open" ValueIde "as" TypeDer Ausdruck
tuple open x :Int endkönnte interpretiert werden als
tuple {open x :Int} end
tuple {open x} :Int end
Im zweiten Fall würde `:Int' als anonyme Typbindung interpretiert.
"tuple" "case" ideG "of" type [with] Bindings "end" -->
"tuple_case" ideG "of" type ["with" Bindings] "end"
Der Ausdruck
tuple
case x
when c1 then 1
when c2 then 2
end
end
führte vorher zu einem Parse-Fehler.
fun(x :Bool) x andif foomehrdeutig geparst werden:
{fun(x :Bool) x} andif foo
fun(x :Bool) {x andif foo}
Da die zweite Interpretation die normalerweise gewünschte ist, wurde
`fun' die niedrigste Präzedenz zugeordnet. Dadurch kann in den
meisten Fällen genauso formuliert werden wie in der alten Syntax.Es gibt eine Ausnahme: Wenn `fun' innerhalb eines Infix-Ausdrucks auftaucht, müssen explizit Klammern gesetzt werden.
Das selbe Problem entsteht mit `assert' und auf der Typebene mit `Fun' und `Oper'.
Beispiele:
let infix @@ (A,B<:Ok a:A b:B) = tuple a b end;
let f = fun(x :Int) x @@ 7; (* genau wie bisher *)
100 @@ fun(x:Int) 7 @@ 8; (* nicht erlaubt *)
(* so wurde es bisher interpretiert: *)
100 @@ fun(x:Int) {7 @@ 8};
100 @@ {fun(x:Int) 7 @@ 8};
(* das hätte aber auch gemeint sein können: *)
100 @@ {fun(x:Int) 7} @@ 8;
(* Auch hier sind Klammern nötig: *)
f := {fun () :Int 17}
Das Bootfile interpretiert alle Kommandozeilen-Argumente als Quelltextfiles. Jeder File wird mit sccs ausgecheckt, umgewandelt, und mit dem Kommentar "tl2ntl" wieder eingecheckt.
Es empfiehlt sich, nur Files aus dem aktuellen Verzeichnis zu behandeln, da es sonst Probleme mit SCCS gibt.
Die Files müssen genau ein Semikolon enthalten. Ist keins drin, steigt das Programm mit einer exception aus ("failed"), sind mehrere drin, wird nur der Text bis zum ersten Semikolon umgewandelt, der Rest bleibt wie er war. Das dürfte nur bei scripts (.tyc) eine Rolle spielen.
Bei der Umwandlung werden einige Kürzel ausgegeben, die für die angewandten Modifikationen stehen:
ide ::= identifier |
"infix" (infix | colonInfix);
ideList ::=
ide {"," ide};
optType ::= [":" type];
optBound ::=
["<:" type];
typeBinding1 ::=
["Dyn"] ide formalParameters optBound "=" type;
typeBinding ::=
"Let" ["Rec"] typeBinding1 {"and" typeBinding1};
(* Signatures *)
Signatures ::=
{ ValueOrTypeSignatures | TypeBinding | "Repeat" Type };
ValueOrTypeSignatures ::=
["var" | "Dyn"] [ideList formalParameters] (":" | "<:") type;
formalParameters ::=
{ "(" signatures ")" };
withSignatures ::=
["with" signatures];
(* Types *)
Type ::=
"Oper" "(" signatures ")" optBound Type |
"Fun" "(" signatures ")" ":" Type |
Type1;
Type1 ::=
Type2 { colonInfix Type2 };
Type2 ::=
Type3 { infix Type3 };
Type3 ::=
Type4 { "(" { Type } ")" };
Type4 ::=
"{" Type "}" |
ide { "." ide } |
"Ok" |
"Nok" |
"Tuple" signatures
{ "case" ideList withSignatures }
"end" |
"Record" signatures "end" |
"Exception" signatures "end" ;
(* values *)
optVar ::= [ "var" ];
valueBinding1 ::=
optVar ide formalParameters optType "=" value;
valueRecBinding1 ::=
optVar ide formalParameters optType "=" value;
valueBinding ::=
valueBinding1 { "and" valueBinding1 } |
"rec" valueRecBinding1 { "and" valueRecBinding1 };
bindings ::=
{ optVar value |
"let" valueBinding |
typeBinding |
":" "Dyn" type |
"open" ide [ "as" type ]
}
tuple ::=
"tuple" bindings "end";
withBindings ::=
["with" bindings];
tupleCase ::=
"tuple_case" ideG "of" type withBindings "end";
else ::= ["else" bindings];
if ::=
"if" value "then" bindings
{ "elsif" value "then" bindings }
elseG
"end";
withIde ::=
["with" ide];
caseBranch ::=
"when" ideList withIde "then" bindings;
case ::=
"case" ["of"] value { caseBranch } else "end";
tryBranch ::=
"when" value withIde "then" bindings;
try ::=
"try" bindings { tryBranch } else "end";
for ::=
"for" ide "=" value ( "upto" | "downto" ) value "do"
bindings
"end";
value4 ::=
ide |
integer | real | string | char | longreal |
tuple |
tupleCase |
"record" bindings "end" |
"extend" value withBindings "end" |
"array" bindings "end" |
"exception" value withSignatures "end" |
"begin" bindings "end" |
"loop" bindings "end" |
"ok" |
"exit" |
"while" value "do" bindings "end" |
if |
for |
case |
try |
"raise" value withBindings "end" |
"reraise" |
"{" value "}" |
"typeRep_new" "(" ":" type ")" |
"dynamic_new" "(" value ")" |
"dynamic_be" "(" value ":" type ")" |
"_reflect" bindings "end";
value3 ::=
value4
{ "(" bindings ")" |
"?" ide |
"." ide |
"!" ide |
"[" value "]" |
"of" bindings "end"
};
value2 ::=
value3 { infix value3 };
value1 ::=
value2 { ("orif" | "andif" | colonInfix) value2 };
fun ::=
"fun" "(" signatures ")" optType value;
assert ::=
"assert" value;
value ::=
value1 |
fun |
assert;