IMPLEMENTATION MODULE -->modulename; (* Scanner generated by Coco/R - using the FileIO library supplied with this project. *) IMPORT FileIO, Storage; FROM Storage IMPORT ALLOCATE; (* gm2 needs this for NEW substitution *) CONST noSYMB = -->unknownsym; (*error token code*) (* not only for errors but also for not finished states of scanner analysis *) eof = CHR(26) (* MS-DOS Keyboard eof char *); EOF = CHR(0); EOL = CHR(13); CR = CHR(13); LF = CHR(10); Long0 = 0; Long1 = 1; BlkSize = 16384; TYPE BufBlock = ARRAY [0 .. BlkSize-1] OF CHAR; Buffer = ARRAY [0 .. 31] OF POINTER TO BufBlock; StartTable = ARRAY [0 .. 255] OF INTEGER; GetCH = PROCEDURE (INT32): CHAR; VAR lastCh, ch: CHAR; (*current input character*) curLine: INTEGER; (*current input line (may be higher than line)*) lineStart: INT32; (*start position of current line*) apx: INT32; (*length of appendix (CONTEXT phrase)*) oldEols: INTEGER; (*number of EOLs in a comment*) bp, bp0: INT32; (*current position in buf (bp0: position of current token)*) inputLen: INT32; (*source file size*) buf: Buffer; (*source buffer for low-level access*) start: StartTable; (*start state for every character*) CurrentCh: GetCH; (* Two-phase parse probe (milestone 1): exact save/restore of the scanner state around a token-level shadow skip. The pushed state covers the low-level buffer cursor plus every published position variable, so PopPos resumes the parse bit-exactly. `errors` is included: re-scanning a bad character must not double-count. *) posDepth: CARDINAL; saveLastCh: ARRAY [0 .. 7] OF CHAR; saveCh: ARRAY [0 .. 7] OF CHAR; saveCurLine: ARRAY [0 .. 7] OF INTEGER; saveLineStart: ARRAY [0 .. 7] OF INT32; saveApx: ARRAY [0 .. 7] OF INT32; saveOldEols: ARRAY [0 .. 7] OF INTEGER; saveBp: ARRAY [0 .. 7] OF INT32; saveBp0: ARRAY [0 .. 7] OF INT32; saveLine: ARRAY [0 .. 7] OF INTEGER; saveCol: ARRAY [0 .. 7] OF INTEGER; saveLen: ARRAY [0 .. 7] OF CARDINAL; savePos: ARRAY [0 .. 7] OF INT32; saveNextLine: ARRAY [0 .. 7] OF INTEGER; saveNextCol: ARRAY [0 .. 7] OF INTEGER; saveNextLen: ARRAY [0 .. 7] OF CARDINAL; saveNextPos: ARRAY [0 .. 7] OF INT32; saveErrors: ARRAY [0 .. 7] OF INTEGER; PROCEDURE Err (nr, line, col: INTEGER; pos: INT32); BEGIN INC(errors) END Err; PROCEDURE NextCh; (* Return global variable ch *) BEGIN lastCh := ch; INC(bp); ch := CurrentCh(bp); IF (ch = EOL) OR (ch = LF) AND (lastCh # EOL) THEN INC(curLine); lineStart := bp END END NextCh; PROCEDURE Comment (): BOOLEAN; VAR level, startLine: INTEGER; oldLineStart: INT32; BEGIN level := 1; startLine := curLine; oldLineStart := lineStart; -->commentRETURN FALSE; END Comment; PROCEDURE Get (VAR sym: CARDINAL); VAR state: CARDINAL; PROCEDURE Equal (s: ARRAY OF CHAR): BOOLEAN; VAR i: CARDINAL; q: INT32; BEGIN IF nextLen # LENGTH(s) THEN RETURN FALSE END; i := 1; q := bp0; INC(q); WHILE i < nextLen DO IF CurrentCh(q) # s[i] THEN RETURN FALSE END; INC(i); INC(q) END; RETURN TRUE END Equal; PROCEDURE CheckLiteral; BEGIN -->literals END CheckLiteral; BEGIN (*Get*) -->GetSy1 pos := nextPos; nextPos := bp; col := nextCol; nextCol := VAL(INTEGER, bp - lineStart); line := nextLine; nextLine := curLine; len := nextLen; nextLen := 0; apx := 0; state := start[ORD(ch)]; bp0 := bp; LOOP NextCh; INC(nextLen); CASE state OF -->GetSy2 ELSE sym := noSYMB; RETURN (*NextCh already done*) END END END Get; PROCEDURE GetString (pos: INT32; len: CARDINAL; VAR s: ARRAY OF CHAR); VAR i: CARDINAL; p: INT32; BEGIN IF len > HIGH(s) THEN len := HIGH(s) END; p := pos; i := 0; WHILE i < len DO s[i] := CharAt(p); INC(i); INC(p) END; s[len] := CHR(0); END GetString; PROCEDURE GetName (pos: INT32; len: CARDINAL; VAR s: ARRAY OF CHAR); VAR i: CARDINAL; p: INT32; BEGIN IF len > HIGH(s) THEN len := HIGH(s) END; p := pos; i := 0; WHILE i < len DO s[i] := CurrentCh(p); INC(i); INC(p) END; s[len] := CHR(0); END GetName; PROCEDURE CharAt (pos: INT32): CHAR; VAR ch: CHAR; BEGIN IF pos >= inputLen THEN RETURN EOF END; ch := buf[ORD(pos DIV BlkSize)]^[ORD(pos MOD BlkSize)]; IF ch # eof THEN RETURN ch ELSE RETURN EOF END END CharAt; PROCEDURE CapChAt (pos: INT32): CHAR; VAR ch: CHAR; BEGIN IF pos >= inputLen THEN RETURN EOF END; ch := CAP(buf[ORD(pos DIV BlkSize)]^[ORD(pos MOD BlkSize)]); IF ch # eof THEN RETURN ch ELSE RETURN EOF END END CapChAt; PROCEDURE Reset; VAR i, read: CARDINAL; BEGIN (*assert: src has been opened*) i := 0; inputLen := 0; REPEAT NEW(buf[i]); (* typed alloc: sets the block descriptor's count *) read := BlkSize; FileIO.ReadBytes(src, buf[i]^, read); INC(i); INC(inputLen, VAL(INT32, read)) UNTIL read # BlkSize; buf[i-1]^[read] := EOF; curLine := 1; lineStart := -2; bp := -1; oldEols := 0; apx := 0; errors := 0; posDepth := 0; NextCh; END Reset; PROCEDURE PushPos; (* Save the full scanner state (milestone 1 probe). *) BEGIN IF posDepth > HIGH(saveBp) THEN RETURN END; saveLastCh[posDepth] := lastCh; saveCh[posDepth] := ch; saveCurLine[posDepth] := curLine; saveLineStart[posDepth] := lineStart; saveApx[posDepth] := apx; saveOldEols[posDepth] := oldEols; saveBp[posDepth] := bp; saveBp0[posDepth] := bp0; saveLine[posDepth] := line; saveCol[posDepth] := col; saveLen[posDepth] := len; savePos[posDepth] := pos; saveNextLine[posDepth] := nextLine; saveNextCol[posDepth] := nextCol; saveNextLen[posDepth] := nextLen; saveNextPos[posDepth] := nextPos; saveErrors[posDepth] := errors; INC(posDepth) END PushPos; PROCEDURE PopPos; (* Restore the state saved by PushPos. *) BEGIN IF posDepth = 0 THEN RETURN END; DEC(posDepth); lastCh := saveLastCh[posDepth]; ch := saveCh[posDepth]; curLine := saveCurLine[posDepth]; lineStart := saveLineStart[posDepth]; apx := saveApx[posDepth]; oldEols := saveOldEols[posDepth]; bp := saveBp[posDepth]; bp0 := saveBp0[posDepth]; line := saveLine[posDepth]; col := saveCol[posDepth]; len := saveLen[posDepth]; pos := savePos[posDepth]; nextLine := saveNextLine[posDepth]; nextCol := saveNextCol[posDepth]; nextLen := saveNextLen[posDepth]; nextPos := saveNextPos[posDepth]; errors := saveErrors[posDepth] END PopPos; PROCEDURE DropPos; (* Discard the top PushPos snapshot without restoring it (the caller has chosen to keep the current scanner position, e.g. after a successful body skip). *) BEGIN IF posDepth > 0 THEN DEC(posDepth) END END DropPos; PROCEDURE SeekTo (p: INT32); (* Reposition the scanner to the token starting at buffer offset p (two-phase re-parse). Replays NextCh from the start so curLine / lineStart / lastCh match a fresh parse exactly; the buffer is in-memory so this is O(p) with no file I/O. Published pos / len / line / col still describe the previous token afterwards — the caller must Get immediately, exactly like the priming Get in Parse. *) VAR k: INT32; BEGIN curLine := 1; lineStart := -2; bp := -1; ch := EOF; lastCh := EOF; oldEols := 0; apx := 0; bp0 := p; k := 0; WHILE k <= p DO NextCh; INC(k) END END SeekTo; BEGIN -->initializations Error := Err; lastCh := EOF; END -->modulename. -->definitionDEFINITION MODULE -->modulename; (* Scanner generated by Coco/R - using the FileIO library supplied with this project. *) IMPORT FileIO; TYPE INT32 = FileIO.INT32 (* need 32 bit integers *); VAR src, lst: FileIO.File;(*source/list files. To be opened by the main pgm*) directory: ARRAY [0 .. 255] OF CHAR (*of source file*); line, col: INTEGER; (*line and column of current symbol*) len: CARDINAL; (*length of current symbol*) pos: INT32; (*file position of current symbol*) nextLine: INTEGER; (*line of lookahead symbol*) nextCol: INTEGER; (*column of lookahead symbol*) nextLen: CARDINAL; (*length of lookahead symbol*) nextPos: INT32; (*file position of lookahead symbol*) errors: INTEGER; (*number of detected errors*) Error: PROCEDURE ((*nr*)INTEGER, (*line*)INTEGER, (*col*)INTEGER, (*pos*)INT32); PROCEDURE Get (VAR sym: CARDINAL); (* Gets next symbol from source file *) PROCEDURE GetString (pos: INT32; len: CARDINAL; VAR name: ARRAY OF CHAR); (* Retrieves exact string of max length len from position pos in source file *) PROCEDURE GetName (pos: INT32; len: CARDINAL; VAR name: ARRAY OF CHAR); (* Retrieves name of symbol of length len at position pos in source file *) PROCEDURE CharAt (pos: INT32): CHAR; (* Returns exact character at position pos in source file *) PROCEDURE Reset; (* Reads and stores source file internally *) PROCEDURE PushPos; (* Save the full scanner state for a shadow skip (two-phase probe) *) PROCEDURE PopPos; (* Restore the state saved by PushPos *) PROCEDURE DropPos; (* Discard the top PushPos snapshot without restoring *) PROCEDURE SeekTo (p: INT32); (* Reposition the scanner to buffer offset p (two-phase re-parse); caller must Get immediately afterwards *) END -->modulename.