-- file PackCommandPack.mesa -- Derived from Compiler/Binder>CommandPack (state transitions are changed) -- last modified by Satterthwaite, September 22, 1980 12:26 PM -- last modified by Russ Atkinson, 24-Nov-80 14:40:48 -- last modified by Lewis on 2-Apr-81 15:39:47 DIRECTORY CharIO: TYPE USING [CR, PutChar, PutString], CommandUtil: TYPE USING [CommandObject, CommandPtr], LongStorage: TYPE USING [Free, FreeString, Node, String], Streams: TYPE USING [Handle], Strings: TYPE USING [AppendChar, AppendString, EquivalentSubStrings, String, SubString, SubStringDescriptor]; CommandPack: PROGRAM IMPORTS CharIO, Storage: LongStorage, Strings EXPORTS CommandUtil = BEGIN OPEN CommandUtil, Strings; CR: Char = CharIO.CR; Char: TYPE = CHARACTER; String: TYPE = Strings.String; Pair: TYPE = RECORD [key, val: String, next: PairList]; PairList: PUBLIC TYPE = LONG POINTER TO Pair; TokenClass: TYPE = Char; id: TokenClass = 'I; eom: TokenClass = 03C; -- ControlC State: TYPE = [0..18]; -- 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 ] -- 16: ?(LHS _) id ?ARG / -- 17: ?(LHS _) id ?ARG / id -- 18: ?(LHS _) id ?ARG ?(/ ?id) (;|eom) | eom -- where LHS = id | [ ?{id : id}, ] -- and ARG = [ id ] | [ ?{id : id}, ] Failed: PUBLIC ERROR = CODE; -- stream-like utilities GetChar: PROC [p: CommandPtr] RETURNS [c: Char] = { IF p.pos >= p.len THEN RETURN [eom]; c _ p.data[p.pos]; p.pos _ p.pos + 1}; GetIndex: PROC [p: CommandPtr, delta: INTEGER _ 0] RETURNS [CARDINAL] = {pos: CARDINAL _ p.pos + delta; IF delta < 0 AND pos > p.pos THEN pos _ 0; RETURN [pos]; }; SetIndex: PROC [p: CommandPtr, index: CARDINAL] = {p.pos _ index}; Echo: PUBLIC PROC [d: Streams.Handle, operator: String, argList, resultList: PairList, switches: String] = { OPEN CharIO; EchoList: PROC [list: PairList] = { PutChar[d, '[ ]; WHILE list # NIL DO next: PairList _ list.next; PutString[d, list.key]; PutString[d, ": "L]; PutString[d, list.val]; IF next # NIL THEN PutString[d, ", "L]; list _ next; ENDLOOP; PutChar[d, '] ]; }; IF resultList # NIL THEN { EchoList[resultList]; PutString[d, " _ "L]}; PutString[d, operator]; IF argList # NIL THEN EchoList[argList]; IF switches # NIL AND switches.length > 0 THEN {PutString[d, "/"L]; PutString[d, switches]}; }; -- external parsing routine Parse: PUBLIC PROC [s: CommandPtr, opX, argX, resultX: CARDINAL] RETURNS [operator: String, argList, resultList: PairList, switches: String] = { token: TokenClass; state: State; idString: STRING _ [100]; tIndex: CARDINAL; c: Char; NextToken: PROC = { WHILE c = ' OR c = CR DO c _ GetChar[s] ENDLOOP; tIndex _ GetIndex[s] - 1; SELECT c FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9], '<, '., '+, '-, '~, '!, '$ => { idString.length _ 0; WHILE TRUE DO SELECT c FROM IN ['a..'z], IN ['A..'Z], IN ['0..'9], '<, '>, '., '+, '-, '~, '!, '$ => { AppendChar[idString, c]; c _ GetChar[s]}; ENDCASE => EXIT; ENDLOOP; token _ id}; '_, '[, ',, '], ':, '/ => {token _ c; c _ GetChar[s]}; ';, eom => token _ c; ENDCASE => BadCommand[]}; CopyId: PROC [extra: CARDINAL] RETURNS [String] = INLINE { RETURN [CopyString[idString, extra]]}; pair: ARRAY [0..1] OF String; PushArg: PROC = {argList _ AddPair[argList, pair[0], pair[1]]}; PushResult: PROC = {resultList _ AddPair[resultList, pair[0], pair[1]]}; RestoreToken: PROC = {SetIndex[s, tIndex]}; BadCommand: PROC = { operator _ FreeString[operator]; resultList _ FreePairList[resultList]; argList _ FreePairList[argList]; switches _ FreeString[switches]; ERROR Failed}; c _ ' ; state _ 0; operator _ switches _ NIL; argList _ resultList _ NIL; UNTIL state = 18 DO NextToken[]; SELECT token FROM id => SELECT state FROM 0 => {operator _ CopyId[MAX[resultX, opX]]; state _ 1}; 2, 8 => {operator _ CopyId[opX]; state _ 9}; 3 => {pair[0] _ CopyId[0]; state _ 4}; 5 => {pair[1] _ CopyId[resultX]; PushResult[]; state _ 6}; 10 => {pair[0] _ CopyId[0]; state _ 11}; 12 => {pair[1] _ CopyId[argX]; PushArg[]; state _ 13}; 16 => {switches _ CopyId[0]; state _ 17}; 1, 9, 14, 17 => {RestoreToken[]; state _ 18}; 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 _ 18}; ENDCASE => BadCommand[]; '] => SELECT state FROM 3, 6 => state _ 7; 10, 13 => state _ 14; 11 => {pair[1] _ pair[0]; pair[0] _ NIL; PushArg[]; state _ 15}; ENDCASE => BadCommand[]; ': => SELECT state FROM 4 => state _ 5; 11 => state _ 12; ENDCASE => BadCommand[]; ', => SELECT state FROM 6 => state _ 3; 13 => state _ 10; ENDCASE => BadCommand[]; '/ => SELECT state FROM 0, 1, 9, 14, 15 => state _ 16; ENDCASE => BadCommand[]; '; => SELECT state FROM 1, 9, 14, 15, 16, 17 => state _ 18; ENDCASE => BadCommand[]; eom => SELECT state FROM 0, 1, 9, 14, 15, 16, 17 => state _ 18; ENDCASE => BadCommand[]; ENDCASE; ENDLOOP; RETURN}; CopyString: PUBLIC PROC [s: String, extra: CARDINAL _ 0] RETURNS [String] = { copy: String = Storage.String[IF s=NIL THEN 0 ELSE s.length + extra]; IF s # NIL THEN AppendString[copy, s]; RETURN [copy]}; FreeString: PUBLIC PROC [s: String] RETURNS [String] = { IF s # NIL THEN Storage.FreeString[s]; RETURN [NIL]}; -- PairList utilities GetNthPair: PUBLIC PROC [list: PairList, n: CARDINAL, delete: BOOLEAN _ FALSE] RETURNS [key,value: String _ NIL] = { i: CARDINAL _ 0; FOR p: PairList _ list, p.next UNTIL p = NIL DO IF i = n THEN {key _ p.key; value _ p.val; IF delete THEN p.key _ p.val _ NIL; EXIT}; i _ i+1; ENDLOOP; RETURN}; ListLength: PUBLIC PROC [list: PairList] RETURNS [n: CARDINAL _ 0] = { FOR p: PairList _ list, p.next UNTIL p = NIL DO n _ n+1 ENDLOOP; RETURN}; KeyValue: PUBLIC PROC [key: Strings.SubString, list: PairList, delete: BOOLEAN _ FALSE] RETURNS [s: String _ NIL] = { FOR p: PairList _ list, p.next UNTIL p = NIL DO ss: Strings.SubStringDescriptor _ [base: p.key, offset: 0, length: p.key.length]; IF Strings.EquivalentSubStrings[@ss, key] THEN {s _ p.val; IF delete THEN p.val _ NIL; EXIT}; ENDLOOP; RETURN}; FreePairList: PUBLIC PROC [list: PairList] RETURNS [PairList] = { next: PairList; p: PairList _ list; UNTIL p = NIL DO next _ p.next; [] _ FreeString[p.key]; [] _ FreeString[p.val]; Storage.Free[p]; p _ next; ENDLOOP; RETURN [NIL]}; AddPair: PUBLIC PROC [list: PairList, key,val: String] RETURNS [PairList] = { new: PairList _ LOOPHOLE[Storage.Node[SIZE[Pair]]]; new^ _ [key: key, val: val, next: list]; RETURN [new]}; SetExtension: PUBLIC PROC [root, defaultExt: String] RETURNS [name: String] = { SELECT TRUE FROM ~Dotted[root] => { name _ AdjustString[root, defaultExt.length + 2]; AppendChar[name, '.]; AppendString[name, defaultExt]}; ENDCASE => name _ root; RETURN}; -- string utilities Dotted: PROC [s: String] RETURNS [BOOLEAN] = INLINE { FOR i: CARDINAL IN [0..s.length) DO IF s[i] = '. THEN RETURN [TRUE] ENDLOOP; RETURN [FALSE]}; -- storage allocation AdjustString: PROC [old: String, extra: CARDINAL] RETURNS [new: String] = { IF old.length + extra <= old.maxlength THEN new _ old ELSE { new _ Storage.String[old.length + extra]; AppendString[new, old]; Storage.FreeString[old]}; RETURN}; END.