-- 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.