MCrossRefMain.mesa
kap&wsh March 16, 1980 1:55 PM
kap 14-Apr-80 16:51
pdr October 11, 1983 11:59 pm
DIRECTORY
Ascii USING[SP, CR, LF, FF, TAB, ControlZ],
Atom USING[MakeAtom, GetProp, PutProp, MapAtoms],
Basics USING[LowHalf],
Commander USING[Register, Handle],
FS USING[StreamOpen],
FileUtilDefs USING[GetExtendedFileName, FileExists],
IO USING[STREAM, GetChar, Close, RIS, EndOfStream, PutRope, GetLength],
List USING[Reverse],
MCrossRefDefs,
MCrossSorter USING[Enter, Initialize, Finalize],
MessageWindow USING[Confirm],
Rope USING[Size, ROPE, FromRefText, Fetch],
MCrossUtilityDefs USING[IsTerminator];
MCrossRefMain: PROGRAM
IMPORTS Atom, Basics, Commander, IO, FS, FileUtilDefs, List, MCrossRefDefs,
MCrossSorter, MessageWindow, Rope, MCrossUtilityDefs
= BEGIN OPEN MCrossRefDefs;
ERRORs
EndOfProgram: ERROR = CODE;
global variables
lineNumber: LineNumberRange;
herald: Rope.ROPE = "-- Cedar Cross Reference Program of May 2, 1983 12:36 pm --\n";
outputFileName: Rope.ROPE;
inputFileName: Rope.ROPE;
inputSwitches: Rope.ROPE;
inputStream: IO.STREAM ← NIL;
oldch: CHARACTER;
CurrentFileName: ATOMNIL;
tabSpaces: CARDINAL;
lineStringLength: CARDINAL;
scannedString: REF TEXT = NEW[TEXT[100]];
reservedXREF: BOOLEAN;
doLineRefs: BOOLEAN;
charWasPutBack: BOOLEAN;
putBackChar: CHARACTER;
execTS: IO.STREAM;
internal procedures
GetQuotedConstant: PROC =
{ch: CHARACTER;
DO
UNTIL GetChar[] = '" DO NULL; ENDLOOP;
IF (ch ← GetChar[]) # '"
THEN {IF ch # 'L THEN PutCharBack[ch]; EXIT};
ENDLOOP};
PutCharBack: PROC [ch: CHARACTER] =
{IF IsSpacingChar[ch] THEN RETURN;
IF charWasPutBack THEN ERROR;
charWasPutBack ← TRUE;
putBackChar ← ch;
IF lineStringLength>0 THEN lineStringLength ← lineStringLength - 1};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
GetChar: PROC RETURNS[ch: CHARACTER] =
{charSpaces: CARDINAL;
SELECT oldch FROM
Ascii.CR, Ascii.LF => { lineNumber ← lineNumber + 1;
lineStringLength ← 0};
Ascii.FF => { lineNumber ← lineNumber+(Gacha8linesPerPage -
(lineNumber MOD Gacha8linesPerPage));
lineStringLength ← 0};
ENDCASE;
IF charWasPutBack
THEN {charWasPutBack ← FALSE; ch ← putBackChar}
ELSE ch ← IO.GetChar[inputStream];
charSpaces ← (IF ch = Ascii.TAB THEN tabSpaces ELSE 1);
NOTE is this right?
IF ch = Ascii.ControlZ
THEN UNTIL ch = Ascii.CR DO ch ← IO.GetChar[inputStream] ENDLOOP;
IF (lineStringLength ← lineStringLength + charSpaces) > Gacha8charsPerLine THEN
{ -- line overflow
lineNumber ← lineNumber + 1;
lineStringLength ← 0};
oldch ← ch;
RETURN[ch]};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
IsSpacingChar: PROC[ch: CHARACTER] RETURNS[BOOLEAN] =
{ OPEN Ascii;
RETURN[ch = SP OR ch = TAB OR ch = CR OR ch = LF OR ch = FF]};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Scan: PROC RETURNS[token: TokenHandle, ch: CHARACTER] =
{atom: ATOM;
DO --Big Loop, till the next token is scanned
initialize
scannedString.length ← 0;
ch ← GetChar[];
token ← NIL;
WHILE IsSpacingChar[ch] DO ch ← GetChar[] ENDLOOP; --skip initial spaces, tabs, crs
UNTIL MCrossUtilityDefs.IsTerminator[ch]
DO
scannedString[scannedString.length] ← ch;
scannedString.length ← scannedString.length + 1;
ch ← GetChar[];
ENDLOOP;
here with scannedString and terminator(in ch)
IF (scannedString.length # 0) AND scannedString[0] IN ['0..'9] THEN
{PutCharBack[ch]; LOOP}; -- all the way back to retry big loop
IF ch = '- THEN -- look for comments
{ ch ← GetChar[];
IF ch = '- THEN
{ch ← GetChar[];
DO
UNTIL ch = '- OR ch = Ascii.CR DO ch ← GetChar[] ENDLOOP;
IF ch = Ascii.CR THEN EXIT; --comment is snarfed
ch ← GetChar[];
IF ch = '- THEN EXIT; --comment is snarfed
ENDLOOP}
ELSE {PutCharBack[ch]; ch ← '-};
IF scannedString.length = 0 THEN LOOP}; -- all the way back to retry big loop
IF ch = '" THEN --look for quoted constants
{GetQuotedConstant[];
IF scannedString.length = 0
THEN LOOP -- all the way back to retry big loop
ELSE ch ← GetChar[]};
IF ch = '' THEN --look for character constants
{ [] ← GetChar[];
IF scannedString.length = 0
THEN LOOP -- all the way back to retry big loop
ELSE ch ← GetChar[]};
IF scannedString.length = 0 THEN LOOP; -- all the way back to retry big loop
atom ← Atom.MakeAtom[Rope.FromRefText[scannedString]];
IF atom = $END AND ch = '. THEN ERROR EndOfProgram;
token ← NARROW[Atom.GetProp[atom, $MCROSSToken], TokenHandle];
IF token = NIL AND NOT reservedXREF THEN
token ← MakeNewToken[scannedString, identifier, atom];
IF token = NIL OR token.type # (IF reservedXREF THEN reserved ELSE identifier)
THEN LOOP;
RETURN[token, ch];
ENDLOOP}; -- The Big Loop, Scan
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
MakeNewToken: PROC[tokenString: REF TEXT, type: TokenType, atom: ATOMNIL]
RETURNS[TokenHandle] =
{ token : TokenHandle;
IF atom = NIL THEN atom ← Atom.MakeAtom[Rope.FromRefText[tokenString]];
IF Atom.GetProp[atom, $MCROSSToken] # NIL
THEN ERROR; --a supposedly new token ain't new;
token ← NEW[Token ← []];
Atom.PutProp[atom, $MCROSSToken, token];
token.type ← type;
token.name ← atom;
IF type = (IF reservedXREF THEN reserved ELSE identifier)
THEN MCrossSorter.Enter[token];
RETURN[token]};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
SetRef: PROC [fileN: fileNHandle, ln: LineNumberRange, def: BOOLEAN] =
{ p: XRefHandle ← fileN.xrefTail;
np: XRefHandle ← NIL;
IF (fileN.xrefHead = NIL) THEN -- no XRef list yet
{p ← NEW[XRef ← []];
fileN.xrefHead ← fileN.xrefTail ← p};
IF (p.nRefs = maxNRefs) THEN
{p.next ← np ← NEW[XRef ← []];
fileN.xrefTail ← np;
p ← np};
p.coords[(p.nRefs ← p.nRefs + 1)] ← [def, ln]};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
MakeNewFileN: PROC[token: TokenHandle] =
{fN: fileNHandle ← NEW[fileN ← []];
IF token.fileNHead = NIL
THEN token.fileNHead ← fN
ELSE token.fileNTail.next ← fN;
token.fileNTail ← fN;
fN.name ← CurrentFileName};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
Slurp: PROC =
{token: TokenHandle;
ch: CHARACTER;
lineNumber ← 1;
oldch ← Ascii.SP; --vanilla-flavored initial value, or undo last CR from former file
charWasPutBack ← FALSE;
{ DO
ENABLE EndOfProgram, IO.EndOfStream => GOTO eof;
[token, ch] ← Scan[];
IF token = NIL THEN ERROR;
IF token.type # (IF reservedXREF THEN reserved ELSE identifier) THEN ERROR;
see if token is in a new file
IF (token.fileNTail = NIL) OR (token.fileNTail.name # CurrentFileName)
THEN MakeNewFileN[token];
IF doLineRefs THEN SetRef[token.fileNTail, lineNumber, ch = ':];
ENDLOOP;
EXITS
eof => NULL}};
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
NoteReservedWords: PROC[wordList: LIST OF REF ANY] =
BEGIN
IF wordList # NIL
THEN FOR l: LIST OF REF ANY ← wordList, l.rest UNTIL l = NIL
DO [] ← MakeNewToken[NIL, reserved, Atom.MakeAtom[NARROW[l.first]]]
ENDLOOP
ELSE
{[] ← MakeNewToken[NIL, reserved, $ABS];
[] ← MakeNewToken[NIL, reserved, $ALL];
[] ← MakeNewToken[NIL, reserved, $AND];
[] ← MakeNewToken[NIL, reserved, $ANY];
[] ← MakeNewToken[NIL, reserved, $ARRAY];
[] ← MakeNewToken[NIL, reserved, $ATOM];
[] ← MakeNewToken[NIL, reserved, $BASE];
[] ← MakeNewToken[NIL, reserved, $BEGIN];
[] ← MakeNewToken[NIL, reserved, $BOOLEAN];
[] ← MakeNewToken[NIL, reserved, $BROADCAST];
[] ← MakeNewToken[NIL, reserved, $CARDINAL];
[] ← MakeNewToken[NIL, reserved, $CHARACTER];
[] ← MakeNewToken[NIL, reserved, $CODE];
[] ← MakeNewToken[NIL, reserved, $COMPUTED];
[] ← MakeNewToken[NIL, reserved, $CONDITION];
[] ← MakeNewToken[NIL, reserved, $CONFIGURATION];
[] ← MakeNewToken[NIL, reserved, $CONTINUE];
[] ← MakeNewToken[NIL, reserved, $CONTROL];
[] ← MakeNewToken[NIL, reserved, $DECREASING];
[] ← MakeNewToken[NIL, reserved, $DEFINITIONS];
[] ← MakeNewToken[NIL, reserved, $DEPENDENT];
[] ← MakeNewToken[NIL, reserved, $DESCRIPTOR];
[] ← MakeNewToken[NIL, reserved, $DIRECTORY];
[] ← MakeNewToken[NIL, reserved, $DO];
[] ← MakeNewToken[NIL, reserved, $ELSE];
[] ← MakeNewToken[NIL, reserved, $ENABLE];
[] ← MakeNewToken[NIL, reserved, $END];
[] ← MakeNewToken[NIL, reserved, $ENDCASE];
[] ← MakeNewToken[NIL, reserved, $ENDLOOP];
[] ← MakeNewToken[NIL, reserved, $ENTRY];
[] ← MakeNewToken[NIL, reserved, $ERROR];
[] ← MakeNewToken[NIL, reserved, $EXIT];
[] ← MakeNewToken[NIL, reserved, $EXITS];
[] ← MakeNewToken[NIL, reserved, $EXPORTS];
[] ← MakeNewToken[NIL, reserved, $FALSE];
[] ← MakeNewToken[NIL, reserved, $FINISHED];
[] ← MakeNewToken[NIL, reserved, $FIRST];
[] ← MakeNewToken[NIL, reserved, $FOR];
[] ← MakeNewToken[NIL, reserved, $FORK];
[] ← MakeNewToken[NIL, reserved, $FRAME];
[] ← MakeNewToken[NIL, reserved, $FROM];
[] ← MakeNewToken[NIL, reserved, $GO];
[] ← MakeNewToken[NIL, reserved, $GOTO];
[] ← MakeNewToken[NIL, reserved, $IF];
[] ← MakeNewToken[NIL, reserved, $IMPORTS];
[] ← MakeNewToken[NIL, reserved, $IN];
[] ← MakeNewToken[NIL, reserved, $INLINE];
[] ← MakeNewToken[NIL, reserved, $INTEGER];
[] ← MakeNewToken[NIL, reserved, $INTERNAL];
[] ← MakeNewToken[NIL, reserved, $JOIN];
[] ← MakeNewToken[NIL, reserved, $LAST];
[] ← MakeNewToken[NIL, reserved, $LENGTH];
[] ← MakeNewToken[NIL, reserved, $LOCKS];
[] ← MakeNewToken[NIL, reserved, $LONG];
[] ← MakeNewToken[NIL, reserved, $LOOP];
[] ← MakeNewToken[NIL, reserved, $MACHINE];
[] ← MakeNewToken[NIL, reserved, $MAX];
[] ← MakeNewToken[NIL, reserved, $MIN];
[] ← MakeNewToken[NIL, reserved, $MOD];
[] ← MakeNewToken[NIL, reserved, $MONITOR];
[] ← MakeNewToken[NIL, reserved, $MONITORED];
[] ← MakeNewToken[NIL, reserved, $MONITORLOCK];
[] ← MakeNewToken[NIL, reserved, $NEW];
[] ← MakeNewToken[NIL, reserved, $NIL];
[] ← MakeNewToken[NIL, reserved, $NOT];
[] ← MakeNewToken[NIL, reserved, $NOTIFY];
[] ← MakeNewToken[NIL, reserved, $NULL];
[] ← MakeNewToken[NIL, reserved, $OF];
[] ← MakeNewToken[NIL, reserved, $OPEN];
[] ← MakeNewToken[NIL, reserved, $OR];
[] ← MakeNewToken[NIL, reserved, $ORDERED];
[] ← MakeNewToken[NIL, reserved, $OVERLAID];
[] ← MakeNewToken[NIL, reserved, $PACKED];
[] ← MakeNewToken[NIL, reserved, $POINTER];
[] ← MakeNewToken[NIL, reserved, $PORT];
[] ← MakeNewToken[NIL, reserved, $PRIVATE];
[] ← MakeNewToken[NIL, reserved, $PROC];
[] ← MakeNewToken[NIL, reserved, $PROCESS];
[] ← MakeNewToken[NIL, reserved, $PROGRAM];
[] ← MakeNewToken[NIL, reserved, $PUBLIC];
[] ← MakeNewToken[NIL, reserved, $READONLY];
[] ← MakeNewToken[NIL, reserved, $REAL];
[] ← MakeNewToken[NIL, reserved, $RECORD];
[] ← MakeNewToken[NIL, reserved, $REF];
[] ← MakeNewToken[NIL, reserved, $RELATIVE];
[] ← MakeNewToken[NIL, reserved, $REPEAT];
[] ← MakeNewToken[NIL, reserved, $RESTART];
[] ← MakeNewToken[NIL, reserved, $RESUME];
[] ← MakeNewToken[NIL, reserved, $RETRY];
[] ← MakeNewToken[NIL, reserved, $RETURN];
[] ← MakeNewToken[NIL, reserved, $RETURNS];
[] ← MakeNewToken[NIL, reserved, $SELECT];
[] ← MakeNewToken[NIL, reserved, $SHARES];
[] ← MakeNewToken[NIL, reserved, $SIGNAL];
[] ← MakeNewToken[NIL, reserved, $SIZE];
[] ← MakeNewToken[NIL, reserved, $START];
[] ← MakeNewToken[NIL, reserved, $STATE];
[] ← MakeNewToken[NIL, reserved, $STOP];
[] ← MakeNewToken[NIL, reserved, $STRING];
[] ← MakeNewToken[NIL, reserved, $THEN];
[] ← MakeNewToken[NIL, reserved, $THROUGH];
[] ← MakeNewToken[NIL, reserved, $TO];
[] ← MakeNewToken[NIL, reserved, $TRANSFER];
[] ← MakeNewToken[NIL, reserved, $TRUE];
[] ← MakeNewToken[NIL, reserved, $TYPE];
[] ← MakeNewToken[NIL, reserved, $UNSPECIFIED];
[] ← MakeNewToken[NIL, reserved, $UNTIL];
[] ← MakeNewToken[NIL, reserved, $UNWIND];
[] ← MakeNewToken[NIL, reserved, $USING];
[] ← MakeNewToken[NIL, reserved, $WAIT];
[] ← MakeNewToken[NIL, reserved, $WHILE];
[] ← MakeNewToken[NIL, reserved, $WITH];
[] ← MakeNewToken[NIL, reserved, $WORD]
};
END;
Finalize: PROC =
{ inputStream ← NIL;
CurrentFileName ← NIL;
MCrossSorter.Finalize[];
{p: SAFE PROC[atom: ATOM] = TRUSTED {Atom.PutProp[atom, $MCROSSToken, NIL]};
Atom.MapAtoms[p]}};
MCross: SAFE PROC [cmd: Commander.Handle]
RETURNS [result: REFNIL, msg: Rope.ROPENIL] = TRUSTED {
ENABLE UNWIND => GOTO unwind;
comCMStream: IO.STREAM = IO.RIS[cmd.commandLine];
inputFileNames: LIST OF REF ANYNIL;
specifiedWords: LIST OF REF ANYNIL;
snarfingSpecifiedWords: BOOLEANFALSE;
Finalize[];
execTS ← cmd.out;
lineStringLength ← 0;
tabPosition ← 0;
tabSpaces ← 8;
reservedXREF ← FALSE;
doLineRefs ← TRUE;
IO.PutRope[execTS, "\n"];
IO.PutRope[execTS, herald];
try to get an output "mcross" file name from the command line
outputFileName ← NIL;
IF IO.GetLength[comCMStream] # 0
THEN [outputFileName, ] ← FileUtilDefs.GetExtendedFileName[comCMStream, "mcross"];
IF outputFileName = NIL THEN {
IO.PutRope[execTS, "MCross <outFile.mcross> <inFile1.mesa> <inFile2.mesa> ...\n"];
IO.PutRope[execTS,
" File name extensions may be defaulted; outFile extension must be 'mcross'\n"];
Finalize[];
RETURN};
IF FileUtilDefs.FileExists[outputFileName] THEN {
IO.PutRope[execTS, "\n"];
IO.PutRope[execTS, outputFileName];
IO.PutRope[execTS, " exists. Do you want to replace its contents? "];
IF NOT MessageWindow.Confirm["[Confirm]"] THEN {Finalize[];RETURN}};
SetMCrossOutputStream[outputFileName];
IO.PutRope[execTS, " Output to "];
IO.PutRope[execTS, outputFileName];
IO.PutRope[execTS, "\n"];
OutputLine[" ***** Cross Reference for files:"];
OutputChar[Ascii.CR];
MCrossSorter.Initialize[15]; -- only the first 15 chars alphabetized
DO -- read parameters
[inputFileName, inputSwitches]
← FileUtilDefs.GetExtendedFileName[comCMStream,
(IF snarfingSpecifiedWords
THEN NIL
ELSE "mesa"),
FALSE];
FOR i: INT IN [0..Rope.Size[inputSwitches])
DO SELECT Rope.Fetch[inputSwitches, i] FROM
'b, 'B => {IO.PutRope[execTS,
"***Listing references to specified words only.\n"];
reservedXREF ← TRUE;
snarfingSpecifiedWords ← TRUE};
'e, 'E => snarfingSpecifiedWords ← FALSE;
'f, 'F => {IO.PutRope[execTS,
"***Not listing individual line references.\n"];
doLineRefs ← FALSE};
ENDCASE;
ENDLOOP;
IF inputSwitches = NIL AND inputFileName = NIL THEN EXIT; -- no more input files
IF inputFileName = NIL THEN LOOP;
IF snarfingSpecifiedWords
THEN {specifiedWords ← CONS[inputFileName, specifiedWords];
LOOP};
inputFileNames ← CONS[inputFileName, inputFileNames];
IF NOT FileUtilDefs.FileExists[inputFileName] THEN
{IO.PutRope[execTS, inputFileName];
IO.PutRope[execTS, " does not exist. Should I continue? "];
IF MessageWindow.Confirm["[Confirm]"]
THEN LOOP ELSE {Finalize[];RETURN}};
tabPosition ← MAX[tabPosition, Basics.LowHalf[Rope.Size[inputFileName]]+5];
ENDLOOP; -- read parameters
NoteReservedWords[specifiedWords];
inputFileNames ← List.Reverse[inputFileNames];
FOR l: LIST OF REF ANY ← inputFileNames, l.rest UNTIL l = NIL
DO -- process all input files
inputFileName ← NARROW[l.first];
inputStream ← FS.StreamOpen[fileName: inputFileName];
IO.PutRope[execTS, inputFileName];
IO.PutRope[execTS, "..."];
OutputLine[inputFileName];
CurrentFileName ← Atom.MakeAtom[inputFileName];
Slurp[];
IO.Close[inputStream];
ENDLOOP; -- process all input files
IO.PutRope[execTS, "\n"];
IO.PutRope[execTS, "Dumping the Cross Reference..."];
PrintXREF[execTS];
DestroyMCrossOutputStream[];
IO.PutRope[execTS, "done.\n"];
Finalize[];
EXITS unwind => Finalize[];
}; -- END of MCross procedure
MODULE INITIALIZATION
Commander.Register["MCross", MCross, "cross reference maker"];
END.