-- OpDefsGenerator.mesa
-- last edited by Johnsson, November 2, 1978 10:22 AM
-- last edited by Satterthwaite, May 12, 1983 2:06 pm
DIRECTORY
DCSFileTypes: TYPE USING [tLeaderPage],
Directory: TYPE USING [CreateFile, Error, Lookup, UpdateDates, ignore],
File: TYPE USING [Capability, Permissions, delete, grow, read, shrink, write],
Exec: TYPE USING [w],
FileStream: TYPE USING [Create, EndOf, GetIndex, SetIndex],
Format: TYPE USING [NumberFormat, Number, StringProc],
Heap: TYPE USING [systemZone],
LongString: TYPE USING [StringToNumber, StringToOctal],
Stream: TYPE USING [Handle, Delete, GetChar, PutChar, PutWord],
Strings: TYPE USING [String, AppendChar, AppendString],
Time: TYPE USING [AppendCurrent],
TTY: TYPE USING [Handle, GetChar, GetID, PutChar, PutLine, PutString];
OpDefsGenerator: PROGRAM
IMPORTS
Directory, Exec, FileStream, Format, Heap, LongString, Stream, Strings, Time, TTY = {
CompStrDesc: TYPE = RECORD [offset, length: CARDINAL];
nChars: CARDINAL;
in: Stream.Handle;
nOpCodes: CARDINAL = 256;
OpCode: TYPE = [0..nOpCodes);
StringArray: TYPE = ARRAY OpCode OF Strings.String;
NumberArray: TYPE = ARRAY OpCode OF CARDINAL;
stringData: LONG POINTER TO StringArray ← NIL;
push: LONG POINTER TO NumberArray ← NIL;
pop: LONG POINTER TO NumberArray ← NIL;
len: LONG POINTER TO NumberArray ← NIL;
Name: PROC [s: Strings.String] = {
c: CHAR;
nc: CARDINAL ← 0;
collectingChars: BOOL ← FALSE;
s.length ← 0;
DO
IF FileStream.EndOf[in] THEN RETURN;
c ← in.GetChar;
SELECT c FROM
' , '\t, '\n => IF collectingChars THEN EXIT;
IN ['0..'9] => {
IF ~collectingChars THEN {
FileStream.SetIndex[in, FileStream.GetIndex[in]-1]; EXIT};
Strings.AppendChar[s,c]};
IN ['A..'Z], IN ['a..'z] => {
collectingChars ← TRUE; Strings.AppendChar[s,c]};
ENDCASE => SIGNAL SyntaxError;
ENDLOOP;
nChars ← nChars + s.length};
Atom: PROC [s: Strings.String, del: CHAR] = {
c: CHAR;
nc: CARDINAL ← 0;
collectingChars: BOOL ← FALSE;
DO
IF FileStream.EndOf[in] THEN SIGNAL SyntaxError;
c ← in.GetChar;
SELECT c FROM
' , '\n => IF collectingChars THEN EXIT;
IN ['0..'9], IN ['A..'Z], IN ['a..'z], '+ => {
s[nc] ← c; nc ← nc+1; collectingChars ← TRUE};
ENDCASE => EXIT;
ENDLOOP;
s.length ← nc;
IF c # del THEN SIGNAL SyntaxError};
SyntaxError: SIGNAL = CODE;
CollectOpData: PROC = {
name: STRING ← [20];
s: STRING ← [8];
code: CARDINAL;
CRcount: CARDINAL ← 0;
stringData ← (Heap.systemZone).NEW[StringArray ← ALL[NIL]];
push ← (Heap.systemZone).NEW[NumberArray ← ALL[0]];
pop ← (Heap.systemZone).NEW[NumberArray ← ALL[0]];
len ← (Heap.systemZone).NEW[NumberArray ← ALL[0]];
nChars ← 0;
UNTIL CRcount = 3 DO
IF in.GetChar = '\n THEN CRcount ← CRcount+1;
ENDLOOP;
code ← 0;
THROUGH OpCode DO
Name[name]; IF FileStream.EndOf[in] THEN EXIT;
Atom[s, '(];
IF ~(s.length=1 AND s[0]='+) THEN
code ← LongString.StringToNumber[s, 8];
Atom[s, ')]; -- decimal, ignore it
IF name.length # 0 THEN {
stringData[code] ← (Heap.systemZone).NEW[StringBody[name.length]];
Strings.AppendString[stringData[code],name]};
Atom[s, ',];
push[code] ← LongString.StringToOctal[s];
Atom[s, ',];
pop[code] ← LongString.StringToOctal[s];
Atom[s, ';];
len[code] ← LongString.StringToOctal[s];
code ← code+1;
ENDLOOP};
ReleaseOpData: PROC = {
(Heap.systemZone).FREE[@len];
(Heap.systemZone).FREE[@pop]; (Heap.systemZone).FREE[@push];
FOR i: OpCode IN OpCode DO
IF stringData[i] # NIL THEN (Heap.systemZone).FREE[@stringData[i]];
ENDLOOP;
(Heap.systemZone).FREE[@stringData]};
OctalDecimalError: SIGNAL [CARDINAL] = CODE;
OpNameTooLong: ERROR [CARDINAL] = CODE;
OutStrings: PROC [boutfile: STRING] = {
charpos: CARDINAL ← 0;
bOut: Stream.Handle ← CreateFileStream[boutfile, writeAccess];
bOut.PutWord[nOpCodes*CompStrDesc.SIZE+1];
FOR i: OpCode IN OpCode DO
j: CARDINAL = IF stringData[i] # NIL THEN stringData[i].length ELSE 0;
bOut.PutWord[charpos];
bOut.PutWord[j];
charpos ← charpos + j;
ENDLOOP;
bOut.PutWord[nChars]; bOut.PutWord[nChars];
FOR i: OpCode IN OpCode DO
IF stringData[i] # NIL THEN {
FOR j: CARDINAL IN [0..stringData[i].length)
DO bOut.PutChar[stringData[i][j]] ENDLOOP};
ENDLOOP;
Stream.Delete[bOut]};
OutOpParams: PROC [apoutfile: STRING] = {
out: Stream.Handle ← CreateFileStream[apoutfile, writeAccess];
time: STRING ← [20];
GetTime[time];
OutString[out, "-- generated by OpDefsGenerator from "L];
OutString[out, infile]; OutString[out, ", "L]; OutString[out, time];
OutString[out, "\n
Q: TYPE = PRIVATE RECORD [
push, pop: [0..7], length: [0..3]];
OpParms: PRIVATE ARRAY [0..256) OF Q = [\n"L];
FOR i: OpCode IN OpCode DO
IF i MOD 4 = 0 THEN {
f: Format.NumberFormat = [8,TRUE,TRUE,3];
OutString[out, "--"L];
OutNameR[out, stringData[i], 10];
OutNameR[out, stringData[i+1], 11];
OutNameR[out, stringData[i+2], 11];
OutNameR[out, stringData[i+3], 11];
OutString[out, " "L];
OutNumF[out, i, f]; OutChar[out, '-];
OutNumF[out, i+3, f]; OutString[out, "\n "L]};
OutString[out, " Q["L];
OutNum[out, push[i]]; OutChar[out, ',];
OutNum[out, pop[i]]; OutChar[out, ',];
OutNum[out, len[i]]; OutChar[out, ']];
IF i MOD 4 = 3 THEN {
IF i = OpCode.LAST THEN OutString[out, "];"L] ELSE OutChar[out, ',];
OutChar[out, '\n]}
ELSE OutChar[out, ',];
ENDLOOP;
Stream.Delete[out]};
GetTime: PROC [time: STRING] = {
Time.AppendCurrent[time];
time.length ← time.length - 3};
OutMopcodes: PROC [amoutfile, moduleName, prefixString: STRING] = {
out: Stream.Handle ← CreateFileStream[amoutfile, writeAccess];
i: OpCode;
j, l: CARDINAL;
time: STRING ← [20];
GetTime[time];
OutString[out, "-- generated by OpDefsGenerator from "L];
OutString[out, infile]; OutString[out, ", "L]; OutString[out, time];
OutChar[out, '\n]; OutChar[out, '\n];
OutString[out, moduleName];
OutString[out, ": DEFINITIONS = {\n
Op: TYPE = [0..400b);\n\n"L];
FOR i IN OpCode DO
IF stringData[i] # NIL AND (l ← stringData[i].length) # 0 THEN {
IF l > 10 THEN ERROR OpNameTooLong[i];
FOR j IN (l..10) DO OutChar[out, ' ] ENDLOOP;
OutString[out, prefixString];
OutString[out, stringData[i]];
OutString[out, ": Op = "L];
OutNumF[out, i, [8,FALSE,FALSE,3]]; OutChar[out, 'b];
OutChar[out, ';]}
ELSE { -- 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[out, ' ]; ENDLOOP;
EXITS
empty => {
blank: BOOL = (j-i)=3; -- TRUE iff whole line empty
i ← j;
IF blank THEN LOOP}}; -- no CR
IF (i MOD 4) # 3 THEN OutChar[out, ' ] ELSE OutChar[out, '\n];
ENDLOOP;
OutString[out, "}.\n"L];
Stream.Delete[out]};
OutNameR: PROC [out: Stream.Handle, s: Strings.String, n: CARDINAL] = {
l: CARDINAL ← IF s = NIL THEN 0 ELSE s.length;
THROUGH (l..n] DO OutChar[out, ' ]; ENDLOOP;
OutString[out, s]};
OutNameL: PROC [out: Stream.Handle, s: Strings.String, n: CARDINAL] = {
l: CARDINAL ← IF s = NIL THEN 0 ELSE s.length;
OutString[out, s];
THROUGH (l..n] DO OutChar[out, ' ]; ENDLOOP};
OutNum: PROC [out: Stream.Handle, n: CARDINAL] = INLINE {
OutNumF[out, n, [10,FALSE,FALSE,1]]};
OutNumF: PROC [out: Stream.Handle, n: CARDINAL, f: Format.NumberFormat] = {
PutNumber: Format.StringProc = {OutString[out, s]};
Format.Number[n, f, PutNumber]};
OutString: PROC [out: Stream.Handle, s: Strings.String] = {
IF s # NIL THEN
FOR i: CARDINAL IN [0..s.length) DO out.PutChar[s[i]] ENDLOOP};
OutChar: PROC [out: Stream.Handle, c: CHAR] = INLINE {out.PutChar[c]};
OutListing: PROC [listfile: STRING] = {
out: Stream.Handle ← CreateFileStream[listfile, writeAccess];
time: STRING ← [18];
GetTime[time];
OutString[out, listfile]; OutString[out, "; "L];
OutString[out, time]; OutChar[out, '\n];
OutString[out, "Format: name octal(decimal)push,pop,count\n\n"L];
FOR i: OpCode IN OpCode DO
OutNameL[out, stringData[i],8];
OutNumF[out, i,[8,FALSE,FALSE,3]];
OutChar[out, '(];
OutNumF[out, i,[10,FALSE,FALSE,3]];
OutChar[out, ')];
OutNum[out, push[i]]; OutChar[out, ',];
OutNum[out, pop[i]]; OutChar[out, ',];
OutNum[out, len[i]]; OutChar[out, ';];
IF i MOD 4 = 3 THEN OutChar[out, '\n] ELSE OutString[out, " "L];
ENDLOOP;
Stream.Delete[out]};
-- OS utilities
readAccess: File.Permissions = File.read;
writeAccess: File.Permissions = File.write+File.grow+File.shrink+File.delete;
FileError: ERROR [name: Strings.String] = CODE;
CreateFileStream: PROC [name: Strings.String, access: File.Permissions]
RETURNS [Stream.Handle] = {
file: File.Capability;
old: BOOL ← (access = File.read);
IF ~old THEN {
file ← Directory.CreateFile[name, DCSFileTypes.tLeaderPage, 0
! Directory.Error => {
IF type = fileAlreadyExists THEN GOTO fileExists
ELSE GO TO fileProblem}];
EXITS
fileExists => old ← TRUE};
IF old THEN
file ← Directory.Lookup[fileName: name, permissions: Directory.ignore
! Directory.Error => {GO TO fileProblem}];
file ← Directory.UpdateDates[file, access];
RETURN [FileStream.Create[file]]
EXITS
fileProblem => ERROR FileError[name]};
infile: STRING ← [40];
Main: PROC = {
DefaultNames: TYPE = {infile, apoutfile, amoutfile, boutfile, listfile, modulename, prefix};
DefaultStrings: TYPE = ARRAY DefaultNames OF Strings.String;
MopDefaults: DefaultStrings ← [
"OpCodes.txt"L, "OpParams"L, "Mopcodes.mesa"L, "OpNames.binary"L,
"Mopcodes.list"L, "Mopcodes"L, "z"L];
FopDefaults: DefaultStrings ← [
"FOpCodes.txt"L, "FOpParams"L, "FOpCodes.mesa"L, "FOpNames.binary"L,
"FOpCodes.list"L, "FOpCodes"L, "q"L];
apoutfile: STRING ← [40];
amoutfile: STRING ← [40];
boutfile: STRING ← [40];
listfile: STRING ← [40];
moduleName: STRING ← [40];
prefixString: STRING ← [10];
SetDefaults: PROC [p: LONG POINTER TO DefaultStrings] = {
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]]};
tty: TTY.Handle = Exec.w;
GetResponse: PROC [prompt, response: STRING] = {
tty.PutString[prompt];
tty.GetID[response];
tty.PutChar['\n]};
tty.PutString["\nMesa OpData Generator\n"L];
DO
DO
tty.PutString["\nMopdata, Fopdata, or Quit: "L];
SELECT tty.GetChar FROM
'm,'M => {tty.PutLine["Mopdata"L]; SetDefaults[@MopDefaults]; EXIT};
'f,'F => {tty.PutLine["Fopdata"L]; SetDefaults[@FopDefaults]; EXIT};
'q,'Q => {tty.PutLine["Quit"L]; GOTO done};
ENDCASE;
ENDLOOP;
tty.PutLine["\nUse escape key to get defaults"L];
GetResponse["Input file: "L, infile];
IF infile.length = 0 THEN EXIT;
GetResponse[" OpParams file: "L, apoutfile];
GetResponse[" Mopcodes file: "L, amoutfile];
GetResponse[" Module name (capitalize correctly): "L, moduleName];
GetResponse[" Prefix with: "L, prefixString];
GetResponse[" binary file for OpName strings: "L, boutfile];
GetResponse[" listing file: "L, listfile];
in ← CreateFileStream[infile, readAccess];
CollectOpData[];
OutOpParams[apoutfile]; OutStrings[boutfile];
OutMopcodes[amoutfile, moduleName, prefixString]; OutListing[listfile];
ReleaseOpData[];
Stream.Delete[in];
REPEAT
done => NULL;
ENDLOOP};
Main[];
}.