-- OpDefsGenerator.mesa
-- last edited by Johnsson, November 2, 1978 10:22 AM
-- last edited by Satterthwaite, September 16, 1982 9:14 am
DIRECTORY
Ascii: TYPE USING [CR, SP, TAB],
Exec: TYPE USING [w],
Format: TYPE USING [NumberFormat, Number, StringProc],
Heap: TYPE USING [systemZone],
LongString: TYPE USING [StringToNumber, StringToOctal],
Segments: TYPE USING [FHandle, NewFile, Write],
Streams: TYPE USING [
Handle, Write,
CreateStream, Destroy, Ended, GetChar, GetIndex, NewStream, PutChar, PutWord, SetIndex],
Strings: TYPE USING [String, AppendChar, AppendString],
Time: TYPE USING [AppendCurrent],
TTY: TYPE USING [
Handle, GetChar, GetID, PutChar, PutLine, PutString];
OpDefsGenerator: PROGRAM
IMPORTS Exec, Format, Heap, LongString, Segments, Streams, Strings, Time, TTY =
BEGIN
CompStrDesc: TYPE = RECORD [offset, length: CARDINAL];
nChars: CARDINAL;
InStream, bOutStream: Streams.Handle;
tty: TTY.Handle;
numopcodes: CARDINAL = 256;
opcode: TYPE = [0..numopcodes);
StringArray: TYPE = ARRAY opcode OF Strings.String;
NumberArray: TYPE = ARRAY opcode OF CARDINAL;
CharArray: TYPE = ARRAY opcode OF CHARACTER;
StringData: LONG POINTER TO StringArray ← (Heap.systemZone).NEW[StringArray ← ALL[NIL]];
push: LONG POINTER TO ARRAY opcode OF CARDINAL ← (Heap.systemZone).NEW[NumberArray];
pop: LONG POINTER TO NumberArray ← (Heap.systemZone).NEW[NumberArray];
len: LONG POINTER TO NumberArray ← (Heap.systemZone).NEW[NumberArray];
mark: LONG POINTER TO CharArray ← (Heap.systemZone).NEW[CharArray];
Name: PROCEDURE [s: Strings.String] =
BEGIN
c: CHARACTER;
nc: CARDINAL ← 0;
CollectingChars: BOOLEAN ← FALSE;
s.length ← 0;
DO
IF Streams.Ended[InStream] THEN RETURN;
c ← Streams.GetChar[InStream];
SELECT c FROM
Ascii.SP, Ascii.TAB, Ascii.CR =>
IF CollectingChars THEN EXIT;
IN ['0..'9] =>
BEGIN
IF ~CollectingChars THEN
BEGIN
Streams.SetIndex[InStream, Streams.GetIndex[InStream]-1];
EXIT
END;
Strings.AppendChar[s,c];
END;
IN ['A..'Z], IN ['a..'z] =>
BEGIN
CollectingChars ← TRUE;
Strings.AppendChar[s,c];
END;
ENDCASE => SIGNAL SyntaxError;
ENDLOOP;
nChars ← nChars + s.length;
END;
Atom: PROCEDURE [s: Strings.String, del: CHARACTER] =
BEGIN
c: CHARACTER;
nc: CARDINAL ← 0;
CollectingChars: BOOLEAN ← FALSE;
DO
IF Streams.Ended[InStream] THEN SIGNAL SyntaxError;
c ← Streams.GetChar[InStream];
SELECT c FROM
Ascii.SP, Ascii.CR =>
IF CollectingChars THEN EXIT;
IN ['0..'9], IN ['A..'Z], IN ['a..'z], '+ =>
BEGIN s[nc] ← c; nc ← nc+1; CollectingChars ← TRUE END;
ENDCASE => EXIT;
ENDLOOP;
s.length ← nc;
IF c # del THEN SIGNAL SyntaxError;
END;
SyntaxError: SIGNAL = CODE;
CollectOpData: PROCEDURE [stream: Streams.Handle] =
BEGIN
name: STRING ← [20];
s: STRING ← [8];
code: CARDINAL;
CRcount: CARDINAL ← 0;
push↑ ← pop↑ ← len↑ ← ALL[0];
mark↑ ← ALL['F];
FOR i: opcode IN opcode DO
IF StringData[i] # NIL THEN (Heap.systemZone).FREE[@StringData[i]];
ENDLOOP;
nChars ← 0;
UNTIL CRcount = 3 DO
IF Streams.GetChar[InStream] = Ascii.CR THEN CRcount ← CRcount+1;
ENDLOOP;
code ← 177777B;
THROUGH opcode DO
Name[name]; IF Streams.Ended[InStream] THEN EXIT;
Atom[s, '(];
IF s.length = 1 AND s[0] = '+ THEN code ← code + 1
ELSE code ← LongString.StringToNumber[s, 8];
Atom[s, ')]; -- decimal, ignore it
IF name.length # 0 THEN
BEGIN
StringData[code] ← (Heap.systemZone).NEW[StringBody[name.length]];
Strings.AppendString[StringData[code],name];
END;
Atom[s, ',];
push[code] ← LongString.StringToOctal[s];
Atom[s, ',];
pop[code] ← LongString.StringToOctal[s];
Atom[s, ',];
len[code] ← LongString.StringToOctal[s];
Atom[s, ';];
mark[code] ← s[0];
ENDLOOP;
FOR i: opcode IN opcode DO
IF i MOD 4 = 0 THEN
BEGIN
f: Format.NumberFormat = [8,TRUE,TRUE,3];
OutString[stream, "--"L];
OutNameR[stream, StringData[i],12];
OutNameR[stream, StringData[i+1],13];
OutNameR[stream, StringData[i+2],13];
OutNameR[stream, StringData[i+3],13];
OutString[stream, " "L];
OutNumF[stream, i,f]; OutChar[stream, '-];
OutNumF[stream, i+3,f]; OutString[stream, "
"L];
END;
OutString[stream, " Q["L];
OutNum[stream, push[i]]; OutChar[stream, ',];
OutNum[stream, pop[i]]; OutChar[stream, ',];
OutNum[stream, len[i]]; OutChar[stream, ',];
OutChar[stream, mark[i]]; OutChar[stream, ']];
IF i MOD 4 = 3 THEN
BEGIN
IF i = LAST[opcode] THEN OutString[stream, "];"L]
ELSE OutChar[stream, ',];
OutChar[stream, Ascii.CR];
END
ELSE OutChar[stream, ',];
ENDLOOP;
END;
OctalDecimalError: SIGNAL [CARDINAL] = CODE;
OpNameTooLong: ERROR [CARDINAL] = CODE;
OutStrings: PROCEDURE =
BEGIN
charpos: CARDINAL ← 0;
--Streams.Reset[bOutStream];
Streams.PutWord[bOutStream, numopcodes*SIZE[CompStrDesc]+1];
FOR i: opcode IN opcode DO
j: CARDINAL = IF StringData[i] # NIL THEN StringData[i].length ELSE 0;
Streams.PutWord[bOutStream, charpos];
Streams.PutWord[bOutStream, j];
charpos ← charpos + j;
ENDLOOP;
Streams.PutWord[bOutStream, nChars];
Streams.PutWord[bOutStream, nChars];
FOR i: opcode IN opcode DO
IF StringData[i] # NIL THEN
BEGIN
FOR j: CARDINAL IN [0..StringData[i].length)
DO Streams.PutChar[bOutStream, StringData[i][j]] ENDLOOP;
END;
ENDLOOP;
Streams.Destroy[bOutStream];
END;
OutOpParams: PROCEDURE =
BEGIN
stream: Streams.Handle ← Streams.NewStream[apoutfile, Streams.Write];
time: STRING ← [20];
GetTime[time];
OutString[stream, " -- generated by OpDefsGenerator "L];
OutString[stream, time];
OutString[stream, "
Q: TYPE = PRIVATE RECORD [
push: [0..3], pop: [0..7], length: [0..3], mark: BOOLEAN];
T: BOOLEAN = TRUE; F: BOOLEAN = FALSE;
OpParms: PRIVATE ARRAY [0..256) OF Q = [
"L];
CollectOpData[stream];
Streams.Destroy[stream];
END;
GetTime: PROCEDURE [time: STRING] =
BEGIN
Time.AppendCurrent[time];
time.length ← time.length - 3;
END;
OutMopcodes: PROCEDURE =
BEGIN
stream: Streams.Handle ← Streams.NewStream[amoutfile, Streams.Write];
i: opcode;
j, l: CARDINAL;
time: STRING ← [20];
GetTime[time];
OutString[stream, " -- generated by OpDefsGenerator "L];
OutString[stream, time];
OutChar[stream, Ascii.CR];
OutString[stream, modulename];
OutString[stream, ": DEFINITIONS =
BEGIN
op: TYPE = [0..400B);
"L];
FOR i IN opcode DO
IF StringData[i] # NIL AND (l ← StringData[i].length) # 0 THEN
BEGIN
IF l > 10 THEN ERROR OpNameTooLong[i];
FOR j IN (l..10) DO OutChar[stream, ' ] ENDLOOP;
OutString[stream, prefixString];
OutString[stream, StringData[i]];
OutString[stream, ": op = "L];
OutNumF[stream, i, [8,FALSE,FALSE,3]]; OutChar[stream, 'B];
OutChar[stream, ';];
END
ELSE
BEGIN -- null item, check for rest of line empty
FOR j ← i, j+1 DO
IF StringData[j] # NIL AND StringData[j].length # 0 THEN EXIT;
IF j MOD 4 = 3 THEN GOTO empty;
ENDLOOP;
FOR j IN [0..22) DO OutChar[stream, ' ]; ENDLOOP;
EXITS empty =>
BEGIN
blank: BOOLEAN ← j-i=3; -- TRUE iff whole line empty
i ← j;
IF blank THEN LOOP; -- no CR
END;
END;
IF (i MOD 4) # 3 THEN OutChar[stream, ' ] ELSE OutChar[stream, Ascii.CR];
ENDLOOP;
OutString[stream, "END...
"L];
Streams.Destroy[stream];
END;
OutNameR: PROCEDURE [stream: Streams.Handle, s: Strings.String, n: CARDINAL] =
BEGIN
l: CARDINAL ← IF s = NIL THEN 0 ELSE s.length;
THROUGH (l..n] DO OutChar[stream, Ascii.SP]; ENDLOOP;
OutString[stream, s];
END;
OutNameL: PROCEDURE [stream: Streams.Handle, s: Strings.String, n: CARDINAL] =
BEGIN
l: CARDINAL ← IF s = NIL THEN 0 ELSE s.length;
OutString[stream, s];
THROUGH (l..n] DO OutChar[stream, Ascii.SP]; ENDLOOP;
END;
OutNum: PROCEDURE [stream: Streams.Handle, n: CARDINAL] = INLINE
BEGIN
OutNumF[stream, n, [10,FALSE,FALSE,1]];
END;
OutNumF: PROCEDURE [stream: Streams.Handle, n: CARDINAL, f: Format.NumberFormat] =
BEGIN
PutNumber: Format.StringProc = {OutString[stream, s]};
Format.Number[n, f, PutNumber];
END;
OutString: PROCEDURE [stream: Streams.Handle, s: Strings.String] =
BEGIN
IF s # NIL THEN
FOR i: CARDINAL IN [0..s.length) DO Streams.PutChar[stream, s[i]] ENDLOOP;
END;
OutChar: PROCEDURE [stream: Streams.Handle, c: CHARACTER] = INLINE
BEGIN Streams.PutChar[stream, c] END;
OutListing: PROCEDURE [filename: STRING] =
BEGIN
stream: Streams.Handle ← Streams.NewStream[filename, Streams.Write];
time: STRING ← [18];
GetTime[time];
OutString[stream, filename]; OutString[stream, "; "L];
OutString[stream, time]; OutChar[stream, Ascii.CR];
OutString[stream, "Format: name octal(decimal)push,pop,count,mark
"L];
FOR i: opcode IN opcode DO
OutNameL[stream, StringData[i],8];
OutNumF[stream, i,[8,FALSE,FALSE,3]];
OutChar[stream, '(];
OutNumF[stream, i,[10,FALSE,FALSE,3]];
OutChar[stream, ')];
OutNum[stream, push[i]]; OutChar[stream, ',];
OutNum[stream, pop[i]]; OutChar[stream, ',];
OutNum[stream, len[i]]; OutChar[stream, ',];
OutChar[stream, mark[i]]; OutChar[stream, ';];
IF i MOD 4 = 3 THEN OutChar[stream, Ascii.CR] ELSE OutString[stream, " "L];
ENDLOOP;
Streams.Destroy[stream];
END;
DefaultNames: TYPE = {infile, apoutfile, amoutfile, boutfile, listfile, modulename, prefix};
DefaultStrings: TYPE = ARRAY DefaultNames OF Strings.String;
MopDefaults: DefaultStrings ← [
"OpCodes.txt",
"OpParams",
"Mopcodes.mesa",
"OpNames.binary",
"Mopcodes.list",
"Mopcodes",
"z"];
FopDefaults: DefaultStrings ← [
"FOpCodes.txt",
"FOpParams",
"FOpCodes.mesa",
"FOpNames.binary",
"FOpCodes.list",
"FOpCodes",
"q"];
infile: STRING ← [40];
apoutfile: STRING ← [40];
amoutfile: STRING ← [40];
boutfile: STRING ← [40];
listfile: STRING ← [40];
modulename: STRING ← [40];
prefixString: STRING ← [10];
outFH: Segments.FHandle;
SetDefaults: PROCEDURE [p: LONG POINTER TO DefaultStrings] =
BEGIN
infile.length←0; Strings.AppendString[infile, p[$infile]];
apoutfile.length←0; Strings.AppendString[apoutfile, p[$apoutfile]];
amoutfile.length←0; Strings.AppendString[amoutfile, p[$amoutfile]];
boutfile.length←0; Strings.AppendString[boutfile, p[$boutfile]];
listfile.length←0; Strings.AppendString[listfile, p[$listfile]];
modulename.length←0; Strings.AppendString[modulename, p[$modulename]];
prefixString.length←0; Strings.AppendString[prefixString, p[$prefix]];
END;
GetResponse: PROCEDURE[prompt, response: STRING] =
BEGIN
TTY.PutString[tty, prompt];
TTY.GetID[tty, response];
TTY.PutChar[tty, Ascii.CR];
END;
tty ← Exec.w;
TTY.PutString[tty, "
Mesa OpData Generator
"];
DO
DO
TTY.PutString[tty, "
Mopdata, Fopdata, or Quit: "];
SELECT TTY.GetChar[tty] FROM
'm,'M => BEGIN TTY.PutLine[tty, "Mopdata"]; SetDefaults[@MopDefaults]; EXIT END;
'f,'F => BEGIN TTY.PutLine[tty, "Fopdata"]; SetDefaults[@FopDefaults]; EXIT END;
'q,'Q => BEGIN TTY.PutLine[tty, "Quit"]; GOTO done END;
ENDCASE;
ENDLOOP;
TTY.PutChar[tty, Ascii.CR];
TTY.PutLine[tty, "Use escape key to get defaults"];
GetResponse["Input file: ", infile];
IF infile.length = 0 THEN EXIT;
GetResponse[" OpParams file: ", apoutfile];
GetResponse[" Mopcodes file: ", amoutfile];
GetResponse[" Module name (capitalize correctly): ", modulename];
GetResponse[" Prefix with: ", prefixString];
GetResponse[" binary file for OpName strings: ", boutfile];
GetResponse[" listing file: ", listfile];
InStream ← Streams.NewStream[infile];
bOutStream ← Streams.CreateStream[
outFH ← Segments.NewFile[boutfile, Segments.Write],
Streams.Write];
OutOpParams[]; OutStrings[]; OutMopcodes[]; OutListing[listfile];
Streams.Destroy[InStream];
REPEAT done => NULL;
ENDLOOP;
END.