file MBCommandPack.Mesa
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 24-Aug-81 14:42:07
last modified by Sweet on March 10, 1981 9:58 AM
last modified by Loretta on 24-Aug-81 19:44:10
last modified by JGS on 17-Aug-81 21:45:14
last modified by Levin on April 5, 1983 2:32 pm
DIRECTORY
Ascii: TYPE USING [CR, NUL],
Heap: TYPE USING [systemZone],
LongString:
TYPE
USING [
AppendChar, AppendString, EquivalentSubStrings, SubString, SubStringDescriptor],
MBCommandUtil: TYPE USING [CommandObject, CommandPtr],
Streams: TYPE USING [Handle, PutChar];
MBCommandPack:
PROGRAM
IMPORTS Heap, Streams, String: LongString
EXPORTS MBCommandUtil
SHARES MBCommandUtil =
BEGIN
OPEN MBCommandUtil, String;
CR: Char = Ascii.CR;
Char: TYPE = CHARACTER;
String: TYPE = LONG STRING;
Pair: TYPE = RECORD [key, val: String, next: PairList];
PairList: PUBLIC TYPE = LONG POINTER TO Pair;
TokenClass:
TYPE = Char;
id: TokenClass = 'I;
eom: TokenClass = Ascii.NUL;
State:
TYPE = [0..17];
0:
1: id
2: id ←
3: [ ?{ARG},
4: [ ?{ARG}, id
5: [ ?{ARG}, id :
6: [ ?{ARG}, id : id
7: [ ?{ARG}, ]
8: [ ?{ARG}, ] ←
9: LHS ← id
10: ?(LHS ←) id [ ?{ARG},
11: ?(LHS ←) id [ ?{ARG}, id
12: ?(LHS ←) id [ ?{ARG}, id :
13: ?(LHS ←) id [ ?{ARG}, id : id
14: ?(LHS ←) id RHS
15: ?(LHS ←) id ?RHS /
16: ?(?(LHS ←) id ?RHS) / id
17: ?(?(LHS ←) id ?RHS) ?(/ ?id) (;|eom) | eom
where LHS = id | [ ?{ARG}, ]
RHS = [ ?{ARG}, ]
ARG = id : id | id (if allowNoTagParm)
Failed: PUBLIC ERROR = CODE;
stream-like utilities
Echo:
PUBLIC
PROC [
d: Streams.Handle, operator: String, argList, resultList: PairList, switches: String] = {
PutString:
PROC [d: Streams.Handle, s:
LONG
STRING] = {
FOR i: CARDINAL IN [0..s.length) DO Streams.PutChar[d, s[i]] ENDLOOP};
EchoList:
PROC [list: PairList] = {
Streams.PutChar[d, '[];
FOR p: PairList ← list, p.next
UNTIL p =
NIL
DO
IF p.key # NIL THEN {PutString[d, p.key]; PutString[d, ": "L]};
PutString[d, p.val];
IF p.next # NIL THEN PutString[d, ", "L];
ENDLOOP;
Streams.PutChar[d, ']];
};
IF resultList #
NIL
THEN {
IF resultList.next = NIL AND resultList.key = NIL THEN PutString[d, resultList.val]
ELSE 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];
};
object management
Create:
PUBLIC
PROC [get:
PROC
RETURNS [
CHARACTER]]
RETURNS [cmd: CommandPtr] = {
cmd ← (Heap.systemZone).NEW[MBCommandUtil.CommandObject ← [getChar: get]];
cmd.idString ← (Heap.systemZone).NEW[StringBody[100]];
};
Destroy:
PUBLIC
PROC [cmd: CommandPtr] = {
IF cmd = NIL THEN RETURN;
(Heap.systemZone).FREE[@cmd.idString];
(Heap.systemZone).FREE[@cmd];
};
external parsing routine
Parse:
PUBLIC
PROC [
cmd: MBCommandUtil.CommandPtr, opX, argX, resultX: CARDINAL, allowNoTagParm: BOOL ← FALSE]
RETURNS [operator: String, argList, resultList: PairList, switches: String] = {
state: State;
RestoreToken: PROC = INLINE {cmd.reset ← TRUE};
NextToken:
PROC = {
IF cmd.reset THEN {cmd.reset ← FALSE; RETURN};
WHILE cmd.c = ' OR cmd.c = CR DO cmd.c ← cmd.getChar[] ENDLOOP;
SELECT cmd.c
FROM
IN ['a..'z],
IN ['A..'Z],
IN ['0..'9], '<, '., '+, '-, '~, '!, '$ => {
cmd.idString.length ← 0;
WHILE
TRUE
DO
SELECT cmd.c
FROM
IN ['a..'z], IN ['A..'Z], IN ['0..'9],
'<, '>, '., '+, '-, '~, '!, '$ => {
AppendChar[cmd.idString, cmd.c]; cmd.c ← cmd.getChar[]};
ENDCASE => EXIT;
ENDLOOP;
cmd.token ← id;
};
'←, '[, ',, '], ':, '/ => {cmd.token ← cmd.c; cmd.c ← cmd.getChar[]};
'" => {
cmd.idString.length ← 0;
DO
cmd.c ← cmd.getChar[];
IF cmd.c = '" THEN {cmd.c ← cmd.getChar[]; IF cmd.c # '" THEN EXIT};
AppendChar[cmd.idString, cmd.c];
ENDLOOP;
cmd.token ← id;
};
';, eom => cmd.token ← cmd.c;
ENDCASE => BadCommand[]};
CopyId:
PROC [extra:
CARDINAL]
RETURNS [String] =
INLINE {
RETURN[CopyString[cmd.idString, extra]]};
pair: ARRAY [0..1] OF String;
PushArg: PROC = INLINE {argList ← AddPair[argList, pair[0], pair[1]]};
PushResult: PROC = INLINE {resultList ← AddPair[resultList, pair[0], pair[1]]};
BadCommand:
PROC = {
operator ← FreeString[operator];
resultList ← FreePairList[resultList];
argList ← FreePairList[argList];
switches ← FreeString[switches];
ERROR Failed
};
IF ~cmd.reset THEN cmd.c ← ' ;
state ← 0; operator ← switches ← NIL;
argList ← resultList ← NIL;
UNTIL state =
LAST[State]
DO
NextToken[];
SELECT cmd.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};
15 => {switches ← CopyId[0]; 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;
4 =>
IF allowNoTagParm
THEN {
pair[1] ← pair[0]; pair[0] ← NIL;
PushArg[]; state ← 7}
ELSE BadCommand[];
10, 13 => state ← 14;
11 =>
IF allowNoTagParm
THEN {
pair[1] ← pair[0]; pair[0] ← NIL;
PushArg[]; state ← 14}
ELSE BadCommand[];
ENDCASE => BadCommand[];
': =>
SELECT state
FROM
4 => state ← 5;
11 => state ← 12;
ENDCASE => BadCommand[];
', =>
SELECT state
FROM
4 =>
IF allowNoTagParm
THEN {
pair[1] ← pair[0]; pair[0] ← NIL;
PushArg[]; state ← 3}
ELSE BadCommand[];
6 => state ← 3;
11 =>
IF allowNoTagParm
THEN {
pair[1] ← pair[0]; pair[0] ← NIL;
PushArg[]; state ← 10}
ELSE BadCommand[];
13 => state ← 10;
ENDCASE => BadCommand[];
'/ =>
SELECT state
FROM
0, 1, 9, 14 => 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;
};
CopyString:
PUBLIC
PROC [s: String, extra:
CARDINAL ← 0]
RETURNS [String] = {
copy: String = (Heap.systemZone).NEW[StringBody[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 ←
NIL] = {
IF s # NIL THEN (Heap.systemZone).FREE[@s];
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;
};
ListLength:
PUBLIC
PROC [list: PairList]
RETURNS [n:
CARDINAL ← 0] = {
FOR p: PairList ← list, p.next UNTIL p = NIL DO n ← n+1 ENDLOOP;
};
KeyValue:
PUBLIC
PROC [key: SubString, list: PairList, delete:
BOOLEAN ←
FALSE]
RETURNS [s: String ← NIL] = {
FOR p: PairList ← list, p.next
UNTIL p =
NIL
DO
ss: SubStringDescriptor ← [base: p.key, offset: 0, length: p.key.length];
IF EquivalentSubStrings[@ss, key]
THEN {s ← p.val; IF delete THEN p.val ← NIL; EXIT};
ENDLOOP;
};
FreePairList:
PUBLIC
PROC [list: PairList]
RETURNS [PairList ←
NIL] = {
next: PairList;
p: PairList ← list;
UNTIL p =
NIL
DO
next ← p.next;
[] ← FreeString[p.key]; [] ← FreeString[p.val];
(Heap.systemZone).FREE[@p]; p ← next;
ENDLOOP;
};
AddPair:
PUBLIC
PROC [list: PairList, key,val: String]
RETURNS [PairList] = {
new: PairList ← (Heap.systemZone).NEW[Pair ← [key: key, val: val, next: NIL]];
p: PairList;
IF list = NIL THEN list ← new
ELSE {
FOR p ← list, p.next UNTIL p.next = NIL DO ENDLOOP;
p.next ← new};
RETURN [list]
};
file naming utilities
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;
};
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 ← (Heap.systemZone).NEW[StringBody[old.length + extra]];
AppendString[new, old];
(Heap.systemZone).FREE[@old];
};
};