State:
TYPE = [0..17];
0:
1: id
2: id ←
3: [ ?{id : id},
4: [ ?{id : id}, id
5: [ ?{id : id}, id :
6: [ ?{id : id}, id : id
7: [ ?{id : id}, ]
8: [ ?{id : id}, ] ←
9: LHS ← id
10: ?(LHS ←) id [ ?{id : id},
11: ?(LHS ←) id [ ?{id : id}, id
12: ?(LHS ←) id [ ?{id : id}, id :
13: ?(LHS ←) id [ ?{id : id}, id : id
14: ?(LHS ←) id [ ?{id : id}, ]
15: ?(LHS) id ?([ ?{id : id}, ])) -
16: ?(?(LHS) id ?([ ?{id : id}, ])) - id
17: ?(?(LHS) id ?([ ?{id : id}, ])) ?(- ?id) (;|eom) | eom
where LHS = id | [ ?{id : id}, ]
external parsing routine
Parse:
PUBLIC PROC [s:
IO.
STREAM]
RETURNS [operator:
ROPE, argList, resultList: PairList, switches:
ROPE] = {
token: TokenClass Ź 0C;
idString: ROPE;
tIndex: CARDINAL;
c: CHAR Ź ' ;
NextToken:
PROC =
INLINE {
WHILE c = '
OR c = '\012
OR c = '\015
DO c Ź IO.GetChar[s ! IO.EndOfStream => {c Ź eom; CONTINUE}] ENDLOOP;
tIndex Ź IO.GetIndex[s] - 1;
SELECT c
FROM
IN ['a..'z],
IN ['A..'Z],
IN ['0..'9], '<, '., '+, '~, '!, '$ => {
idString Ź NIL;
DO
SELECT c
FROM
IN ['a..'z], IN ['A..'Z], IN ['0..'9],
'<, '>, '., '+, '~, '!, '$ => {
idString Ź Rope.Concat[idString, Rope.FromChar[c]];
c Ź IO.GetChar[s ! IO.EndOfStream => {c Ź eom; CONTINUE}]};
ENDCASE => EXIT;
ENDLOOP;
token Ź id};
'←, '[, '], ':, '- =>
{token Ź c; c Ź IO.GetChar[s ! IO.EndOfStream => {c Ź eom; CONTINUE}]};
',, ';, eom => token Ź c;
ENDCASE => BadCommand[]};
pair: ARRAY [0..1] OF ROPE;
PushArg: PROC = INLINE {argList Ź CONS[[pair[0], pair[1]], argList]};
PushResult: PROC = INLINE {resultList Ź CONS[[pair[0], pair[1]], resultList]};
RestoreToken: PROC = {IO.SetIndex[s, tIndex]};
BadCommand:
PROC = {
ERROR Failed};
state: State Ź 0;
operator Ź switches Ź NIL; argList Ź resultList Ź NIL;
UNTIL state = 17
DO
NextToken[];
SELECT token
FROM
id =>
SELECT state
FROM
0 => {operator Ź idString; state Ź 1};
2, 8 => {operator Ź idString; state Ź 9};
3 => {pair[0] Ź idString; state Ź 4};
5 => {pair[1] Ź idString; PushResult[]; state Ź 6};
10 => {pair[0] Ź idString; state Ź 11};
12 => {pair[1] Ź idString; PushArg[]; state Ź 13};
15 => {switches Ź switches.Concat[idString]; state Ź 16};
1, 9, 14, 16 => {RestoreToken[]; state Ź 17};
ENDCASE => BadCommand[];
'← =>
SELECT state
FROM
1 => {
pair[0] Ź NIL; pair[1] Ź operator; operator Ź NIL;
PushResult[]; state Ź 2};
7 => state Ź 8;
ENDCASE => BadCommand[];
'[ =>
SELECT state
FROM
0 => state Ź 3;
1, 9 => state Ź 10;
14 => {RestoreToken[]; state Ź 17};
ENDCASE => BadCommand[];
'] =>
SELECT state
FROM
3, 6 => state Ź 7;
10, 13 => state Ź 14;
ENDCASE => BadCommand[];
': =>
SELECT state
FROM
4 => state Ź 5;
11 => state Ź 12;
ENDCASE => BadCommand[];
', =>
SELECT state
FROM
6 => {state Ź 3; c Ź IO.GetChar[s ! IO.EndOfStream => {c Ź eom; CONTINUE}]};
13 => {state Ź 10; c Ź IO.GetChar[s ! IO.EndOfStream => {c Ź eom; CONTINUE}]};
1, 9, 14, 15, 16 => state Ź 17;
ENDCASE => BadCommand[];
'- =>
SELECT state
FROM
0, 1, 9, 14, 16 => state Ź 15;
ENDCASE => BadCommand[];
'; =>
SELECT state
FROM
1, 9, 14, 15, 16 => state Ź 17;
ENDCASE => BadCommand[];
eom =>
SELECT state
FROM
0, 1, 9, 14, 15, 16 => state Ź 17;
ENDCASE => BadCommand[];
ENDCASE;
ENDLOOP;
RETURN};
Echo:
PUBLIC PROC [
d: IO.STREAM,
operator: ROPE, argList, resultList: PairList, switches: ROPE] = {
PutList:
PROC [list: PairList] = {
d.PutChar['[];
FOR p: PairList Ź list, p.rest
UNTIL p =
NIL DO
IF p.first.key # NIL THEN {IO.PutRope[d, p.first.key]; IO.PutRope[d, ": "]};
IO.PutRope[d, p.first.val];
IF p.rest # NIL THEN IO.PutRope[d, ", "];
ENDLOOP;
d.PutChar[']]};
IF resultList #
NIL THEN {
IF resultList.rest =
NIL AND resultList.first.key =
NIL
THEN IO.PutRope[d, resultList.first.val]
ELSE PutList[resultList];
IO.PutRope[d, " ← "]};
IO.PutRope[d, operator];
IF argList # NIL THEN PutList[argList];
IF switches #
NIL AND switches.Length[] > 0
THEN {
d.PutChar['-]; IO.PutRope[d, switches]}};
GetSwitches:
PUBLIC PROC [switches:
ROPE, default: MobCommandUtil.Switches]
RETURNS[MobCommandUtil.Switches] = {
sense: BOOL Ź TRUE;
length: INT Ź switches.Length[];
FOR i:
INT IN [0..length)
DO
c: CHAR = switches.Fetch[i];
temp: CHAR = Ascii.Lower[c];
SELECT temp
FROM
'~ => sense Ź ~sense;
IN ['a..'z] => {default[c] Ź sense; sense Ź TRUE};
ENDCASE;
ENDLOOP;
RETURN[default]};
GetNthPair:
PUBLIC PROC [list: PairList, n:
CARDINAL, delete:
BOOLŹFALSE]
RETURNS [key, value: ROPEŹNIL] = {
i: CARDINAL Ź 0;
FOR p: PairList Ź list, p.rest
UNTIL p =
NIL DO
IF i = n
THEN {key Ź p.first.key; value Ź p.first.val;
IF delete THEN p.first.key Ź p.first.val Ź NIL; EXIT};
i Ź i+1;
ENDLOOP;
RETURN};
ListLength:
PUBLIC PROC [list: PairList]
RETURNS [n:
CARDINALŹ0] = {
FOR p: PairList Ź list, p.rest UNTIL p = NIL DO n Ź n+1 ENDLOOP;
RETURN};
KeyValue:
PUBLIC PROC [key:
ROPE, list: PairList, delete:
BOOLŹFALSE]
RETURNS [s: ROPEŹNIL] = {
FOR p: PairList Ź list, p.rest
UNTIL p =
NIL DO
IF Rope.Equal[p.first.key, key,
FALSE]
THEN {
s Ź p.first.val; IF delete THEN p.first.val Ź NIL; EXIT};
ENDLOOP;
RETURN};
SetExtension:
PUBLIC PROC [root, defaultExt:
ROPE]
RETURNS [name:
ROPE] = {
IF Rope.Find[root, "."] < 0 THEN root Ź Rope.Cat[root, ".", defaultExt];
RETURN[root]};
GetRootName:
PUBLIC PROC [name:
ROPE]
RETURNS [root:
ROPE] = {
dotIndex: INT Ź Rope.Find[name, "."];
RETURN[IF dotIndex < 0 THEN name ELSE Rope.Substr[name, 0, dotIndex]]};
}.