CommandPack.Mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Satterthwaite, December 10, 1982 10:47 am
Maxwell, August 29, 1983 8:11 am
Paul Rovner, December 2, 1983 5:35 pm
Russ Atkinson (RRA) March 7, 1985 4:26:00 am PST
DIRECTORY
Ascii USING [Lower],
CommandUtil USING [PairList, Switches],
IO USING [GetChar, GetIndex, PutChar, PutRope, SetIndex, STREAM, EndOfStream],
Rope USING [Cat, Concat, Equal, Fetch, Find, FromChar, Length, ROPE, Substr];
CommandPack: PROGRAM
IMPORTS Ascii, IO, Rope
EXPORTS CommandUtil = {
PairList: TYPE = CommandUtil.PairList;
ROPE: TYPE = Rope.ROPE;
TokenClass: TYPE = CHAR;
id: TokenClass = 'I;
eom: TokenClass = '\003; -- ControlC
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}, ]
Failed: PUBLIC ERROR = CODE;
external parsing routine
Parse: PUBLIC PROC [s: IO.STREAM] RETURNS [operator: ROPE, argList, resultList: PairList, switches: ROPE] = {
token: TokenClass;
idString: ROPE;
tIndex: CARDINAL;
c: CHAR ← ' ;
NextToken: PROC = INLINE {
WHILE c = ' OR c = '\n
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: CommandUtil.Switches]
RETURNS[CommandUtil.Switches] = {
sense: BOOLTRUE;
length: INT ← switches.Length[];
FOR i: INT IN [0..length) DO
c: CHAR = switches.Fetch[i];
SELECT Ascii.Lower[c] FROM
'-, '~ => sense ← ~sense;
IN ['a..'z] => {default[c] ← sense; sense ← TRUE};
ENDCASE;
ENDLOOP;
RETURN[default]};
PairList utilities
GetNthPair: PUBLIC PROC [list: PairList, n: CARDINAL, delete: BOOLFALSE]
RETURNS [key, value: ROPENIL] = {
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𡤀] = {
FOR p: PairList ← list, p.rest UNTIL p = NIL DO n ← n+1 ENDLOOP;
RETURN};
KeyValue: PUBLIC PROC [key: ROPE, list: PairList, delete: BOOLFALSE]
RETURNS [s: ROPENIL] = {
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};
file naming utilities
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]]};
}.