blob: 3332cc685f5fa5be1438e3dc3fe01d5de6e91171 [file] [log] [blame]
(* mcLexBuf.mod provides a buffer for the all the tokens created by m2.lex.
Copyright (C) 2015-2026 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU Modula-2; see the file COPYING3. If not see
<http://www.gnu.org/licenses/>. *)
IMPLEMENTATION MODULE mcLexBuf ;
IMPORT mcflex ;
FROM libc IMPORT strlen ;
FROM SYSTEM IMPORT ADDRESS ;
FROM Storage IMPORT ALLOCATE, DEALLOCATE ;
FROM DynamicStrings IMPORT string, InitString, InitStringCharStar, Equal, Mark, KillString ;
FROM FormatStrings IMPORT Sprintf1 ;
FROM nameKey IMPORT NulName, Name, makekey, keyToCharStar ;
FROM mcReserved IMPORT toktype ;
FROM mcComment IMPORT isProcedureComment, isBodyComment, isAfterComment, getContent ;
FROM mcPrintf IMPORT printf0, printf1, printf2, printf3 ;
FROM mcDebug IMPORT assert ;
CONST
MaxBucketSize = 100 ;
Debugging = FALSE ;
TYPE
sourceList = POINTER TO RECORD
left,
right: sourceList ;
name : String ;
line : CARDINAL ;
col : CARDINAL ;
END ;
tokenDesc = RECORD
token: toktype ;
str : Name ;
int : INTEGER ;
com : commentDesc ;
line : CARDINAL ;
col : CARDINAL ;
file : sourceList ;
END ;
tokenBucket = POINTER TO RECORD
buf : ARRAY [0..MaxBucketSize] OF tokenDesc ;
len : CARDINAL ;
next: tokenBucket ;
END ;
listDesc = RECORD
head,
tail : tokenBucket ;
lastBucketOffset: CARDINAL ;
END ;
VAR
procedureComment,
bodyComment,
afterComment : commentDesc ;
currentSource : sourceList ;
useBufferedTokens,
currentUsed : BOOLEAN ;
listOfTokens : listDesc ;
nextTokNo : CARDINAL ;
(*
debugLex - display the last, n, tokens.
*)
PROCEDURE debugLex (n: CARDINAL) ;
VAR
c,
i, o, t: CARDINAL ;
b : tokenBucket ;
BEGIN
IF nextTokNo > n
THEN
o := nextTokNo - n
ELSE
o := 0
END ;
i := 0 ;
REPEAT
t := o + i ;
IF nextTokNo = t
THEN
printf0 ("nextTokNo ")
END ;
b := findtokenBucket (t) ;
IF b = NIL
THEN
t := o + i ;
printf1 ("end of buf (%d is further ahead than the buffer contents)\n", t)
ELSE
c := o + i ;
printf2 ("entry %d %d ", c, t) ;
displayToken (b^.buf[t].token) ;
printf0 ("\n") ;
INC (i)
END
UNTIL b = NIL
END debugLex ;
(*
getProcedureComment - returns the procedure comment if it exists,
or NIL otherwise.
*)
PROCEDURE getProcedureComment () : commentDesc ;
BEGIN
RETURN procedureComment
END getProcedureComment ;
(*
getBodyComment - returns the body comment if it exists,
or NIL otherwise. The body comment is
removed if found.
*)
PROCEDURE getBodyComment () : commentDesc ;
VAR
b: commentDesc ;
BEGIN
b := bodyComment ;
bodyComment := NIL ;
RETURN b
END getBodyComment ;
(*
seekTo -
*)
PROCEDURE seekTo (t: CARDINAL) ;
VAR
b: tokenBucket ;
BEGIN
nextTokNo := t ;
IF t > 0
THEN
DEC (t) ;
b := findtokenBucket (t) ;
IF b = NIL
THEN
updateFromBucket (b, t)
END
END
END seekTo ;
(*
peeptokenBucket -
*)
PROCEDURE peeptokenBucket (VAR t: CARDINAL) : tokenBucket ;
VAR
ct : toktype ;
old,
n : CARDINAL ;
b, c: tokenBucket ;
BEGIN
ct := currenttoken ;
IF Debugging
THEN
debugLex (5)
END ;
old := getTokenNo () ;
REPEAT
n := t ;
b := findtokenBucket (n) ;
IF b = NIL
THEN
doGetToken ;
n := t ;
b := findtokenBucket (n) ;
IF (b = NIL) OR (currenttoken = eoftok)
THEN
(* bailing out. *)
nextTokNo := old + 1 ;
b := findtokenBucket (old) ;
updateFromBucket (b, old) ;
RETURN NIL
END
END ;
UNTIL (b # NIL) OR (currenttoken = eoftok) ;
t := n ;
nextTokNo := old + 1 ;
IF Debugging
THEN
printf2 ("nextTokNo = %d, old = %d\n", nextTokNo, old)
END ;
b := findtokenBucket (old) ;
IF Debugging
THEN
printf1 (" adjusted old = %d\n", old)
END ;
IF b # NIL
THEN
updateFromBucket (b, old)
END ;
IF Debugging
THEN
debugLex (5)
END ;
assert (ct = currenttoken) ;
RETURN b
END peeptokenBucket ;
(*
peepAfterComment - peeps ahead looking for an after statement comment. It stops at an END token
or if the line number changes.
*)
PROCEDURE peepAfterComment ;
VAR
oldTokNo,
t,
peep,
cno,
nextline,
curline : CARDINAL ;
b : tokenBucket ;
finished: BOOLEAN ;
BEGIN
oldTokNo := nextTokNo ;
cno := getTokenNo () ;
curline := tokenToLineNo (cno, 0) ;
nextline := curline ;
peep := 0 ;
finished := FALSE ;
REPEAT
t := cno + peep ;
b := peeptokenBucket (t) ;
IF (b = NIL) OR (currenttoken = eoftok)
THEN
finished := TRUE
ELSE
nextline := b^.buf[t].line ;
IF nextline = curline
THEN
CASE b^.buf[t].token OF
eoftok,
endtok : finished := TRUE |
commenttok: IF isAfterComment (b^.buf[t].com)
THEN
afterComment := b^.buf[t].com
END
ELSE
END
ELSE
finished := TRUE
END
END ;
INC (peep)
UNTIL finished ;
seekTo (oldTokNo)
END peepAfterComment ;
(*
getAfterComment - returns the after comment if it exists,
or NIL otherwise. The after comment is
removed if found.
*)
PROCEDURE getAfterComment () : commentDesc ;
VAR
a: commentDesc ;
BEGIN
peepAfterComment ;
a := afterComment ;
afterComment := NIL ;
RETURN a
END getAfterComment ;
(*
init - initializes the token list and source list.
*)
PROCEDURE init ;
BEGIN
currenttoken := eoftok ;
nextTokNo := 0 ;
currentSource := NIL ;
listOfTokens.head := NIL ;
listOfTokens.tail := NIL ;
useBufferedTokens := FALSE ;
procedureComment := NIL ;
bodyComment := NIL ;
afterComment := NIL ;
lastcomment := NIL
END init ;
(*
addTo - adds a new element to the end of sourceList, currentSource.
*)
PROCEDURE addTo (l: sourceList) ;
BEGIN
l^.right := currentSource ;
l^.left := currentSource^.left ;
currentSource^.left^.right := l ;
currentSource^.left := l ;
WITH l^.left^ DO
line := mcflex.getLineNo() ;
col := mcflex.getColumnNo()
END
END addTo ;
(*
subFrom - subtracts, l, from the source list.
*)
PROCEDURE subFrom (l: sourceList) ;
BEGIN
l^.left^.right := l^.right ;
l^.right^.left := l^.left
END subFrom ;
(*
newElement - returns a new sourceList
*)
PROCEDURE newElement (s: ADDRESS) : sourceList ;
VAR
l: sourceList ;
BEGIN
NEW (l) ;
IF l=NIL
THEN
HALT
ELSE
WITH l^ DO
name := InitStringCharStar (s) ;
left := NIL ;
right := NIL
END
END ;
RETURN l
END newElement ;
(*
newList - initializes an empty list with the classic dummy header element.
*)
PROCEDURE newList () : sourceList ;
VAR
l: sourceList ;
BEGIN
NEW (l) ;
WITH l^ DO
left := l ;
right := l ;
name := NIL
END ;
RETURN l
END newList ;
(*
checkIfNeedToDuplicate - checks to see whether the currentSource has
been used, if it has then duplicate the list.
*)
PROCEDURE checkIfNeedToDuplicate ;
VAR
l, h: sourceList ;
BEGIN
IF currentUsed
THEN
l := currentSource^.right ;
h := currentSource ;
currentSource := newList() ;
WHILE l#h DO
addTo (newElement (l^.name)) ;
l := l^.right
END
END
END checkIfNeedToDuplicate ;
(*
pushFile - indicates that, filename, has just been included.
*)
PROCEDURE pushFile (filename: ADDRESS) ;
VAR
l: sourceList ;
BEGIN
checkIfNeedToDuplicate ;
addTo (newElement (filename)) ;
IF Debugging
THEN
IF currentSource^.right#currentSource
THEN
l := currentSource ;
REPEAT
printf3 ('name = %s, line = %d, col = %d\n', l^.name, l^.line, l^.col) ;
l := l^.right
UNTIL l=currentSource
END
END
END pushFile ;
(*
popFile - indicates that we are returning to, filename, having finished
an include.
*)
PROCEDURE popFile (filename: ADDRESS) ;
VAR
l: sourceList ;
BEGIN
checkIfNeedToDuplicate ;
IF (currentSource#NIL) AND (currentSource^.left#currentSource)
THEN
l := currentSource^.left ; (* last element *)
subFrom (l) ;
DISPOSE (l) ;
IF (currentSource^.left#currentSource) AND
(NOT Equal(currentSource^.name, Mark (InitStringCharStar (filename))))
THEN
(* mismatch in source file names after preprocessing files *)
END
ELSE
(* source file list is empty, cannot pop an include.. *)
END
END popFile ;
(*
killList - kills the sourceList providing that it has not been used.
*)
PROCEDURE killList ;
VAR
l, k: sourceList ;
BEGIN
IF (NOT currentUsed) AND (currentSource#NIL)
THEN
l := currentSource ;
REPEAT
k := l ;
l := l^.right ;
DISPOSE (k)
UNTIL l=currentSource
END
END killList ;
(*
reInitialize - re-initialize the all the data structures.
*)
PROCEDURE reInitialize ;
VAR
s, t: tokenBucket ;
BEGIN
IF listOfTokens.head#NIL
THEN
t := listOfTokens.head ;
REPEAT
s := t ;
t := t^.next ;
DISPOSE (s) ;
UNTIL t=NIL ;
currentUsed := FALSE ;
killList
END ;
init
END reInitialize ;
(*
setFile - sets the current filename to, filename.
*)
PROCEDURE setFile (filename: ADDRESS) ;
BEGIN
killList ;
currentUsed := FALSE ;
currentSource := newList() ;
addTo (newElement (filename))
END setFile ;
(*
openSource - attempts to open the source file, s.
The success of the operation is returned.
*)
PROCEDURE openSource (s: String) : BOOLEAN ;
BEGIN
IF useBufferedTokens
THEN
getToken ;
RETURN TRUE
ELSE
IF mcflex.openSource (string (s))
THEN
setFile (string (s)) ;
syncOpenWithBuffer ;
getToken ;
RETURN TRUE
ELSE
RETURN FALSE
END
END
END openSource ;
(*
closeSource - closes the current open file.
*)
PROCEDURE closeSource ;
BEGIN
IF useBufferedTokens
THEN
WHILE currenttoken#eoftok DO
getToken
END
ELSE
(* a subsequent call to mcflex.OpenSource will really close the file *)
END
END closeSource ;
(*
resetForNewPass - reset the buffer pointers to the beginning ready for
a new pass
*)
PROCEDURE resetForNewPass ;
BEGIN
nextTokNo := 0 ;
useBufferedTokens := TRUE
END resetForNewPass ;
(*
displayToken -
*)
PROCEDURE displayToken (t: toktype) ;
BEGIN
CASE t OF
eoftok: printf0('eoftok\n') |
plustok: printf0('plustok\n') |
minustok: printf0('minustok\n') |
timestok: printf0('timestok\n') |
dividetok: printf0('dividetok\n') |
becomestok: printf0('becomestok\n') |
ambersandtok: printf0('ambersandtok\n') |
periodtok: printf0('periodtok\n') |
commatok: printf0('commatok\n') |
commenttok: printf0('commenttok\n') |
semicolontok: printf0('semicolontok\n') |
lparatok: printf0('lparatok\n') |
rparatok: printf0('rparatok\n') |
lsbratok: printf0('lsbratok\n') |
rsbratok: printf0('rsbratok\n') |
lcbratok: printf0('lcbratok\n') |
rcbratok: printf0('rcbratok\n') |
uparrowtok: printf0('uparrowtok\n') |
singlequotetok: printf0('singlequotetok\n') |
equaltok: printf0('equaltok\n') |
hashtok: printf0('hashtok\n') |
lesstok: printf0('lesstok\n') |
greatertok: printf0('greatertok\n') |
lessgreatertok: printf0('lessgreatertok\n') |
lessequaltok: printf0('lessequaltok\n') |
greaterequaltok: printf0('greaterequaltok\n') |
periodperiodtok: printf0('periodperiodtok\n') |
colontok: printf0('colontok\n') |
doublequotestok: printf0('doublequotestok\n') |
bartok: printf0('bartok\n') |
andtok: printf0('andtok\n') |
arraytok: printf0('arraytok\n') |
begintok: printf0('begintok\n') |
bytok: printf0('bytok\n') |
casetok: printf0('casetok\n') |
consttok: printf0('consttok\n') |
definitiontok: printf0('definitiontok\n') |
divtok: printf0('divtok\n') |
dotok: printf0('dotok\n') |
elsetok: printf0('elsetok\n') |
elsiftok: printf0('elsiftok\n') |
endtok: printf0('endtok\n') |
exittok: printf0('exittok\n') |
exporttok: printf0('exporttok\n') |
fortok: printf0('fortok\n') |
fromtok: printf0('fromtok\n') |
iftok: printf0('iftok\n') |
implementationtok: printf0('implementationtok\n') |
importtok: printf0('importtok\n') |
intok: printf0('intok\n') |
looptok: printf0('looptok\n') |
modtok: printf0('modtok\n') |
moduletok: printf0('moduletok\n') |
nottok: printf0('nottok\n') |
oftok: printf0('oftok\n') |
ortok: printf0('ortok\n') |
pointertok: printf0('pointertok\n') |
proceduretok: printf0('proceduretok\n') |
qualifiedtok: printf0('qualifiedtok\n') |
unqualifiedtok: printf0('unqualifiedtok\n') |
recordtok: printf0('recordtok\n') |
repeattok: printf0('repeattok\n') |
returntok: printf0('returntok\n') |
settok: printf0('settok\n') |
thentok: printf0('thentok\n') |
totok: printf0('totok\n') |
typetok: printf0('typetok\n') |
untiltok: printf0('untiltok\n') |
vartok: printf0('vartok\n') |
whiletok: printf0('whiletok\n') |
withtok: printf0('withtok\n') |
asmtok: printf0('asmtok\n') |
volatiletok: printf0('volatiletok\n') |
periodperiodperiodtok: printf0('periodperiodperiodtok\n') |
datetok: printf0('datetok\n') |
linetok: printf0('linetok\n') |
filetok: printf0('filetok\n') |
integertok: printf0('integertok\n') |
identtok: printf0('identtok\n') |
realtok: printf0('realtok\n') |
stringtok: printf0('stringtok\n')
ELSE
printf0 ('unknown tok (--fixme--)\n')
END
END displayToken ;
(*
updateFromBucket - updates the global variables: currenttoken,
currentstring, currentcolumn and currentinteger
from tokenBucket, b, and, offset.
*)
PROCEDURE updateFromBucket (b: tokenBucket; offset: CARDINAL) ;
BEGIN
WITH b^.buf[offset] DO
currenttoken := token ;
currentstring := keyToCharStar (str) ;
currentcolumn := col ;
currentinteger := int ;
currentcomment := com ;
IF currentcomment # NIL
THEN
lastcomment := currentcomment
END ;
IF Debugging
THEN
printf3 ('line %d (# %d %d) ', line, offset, nextTokNo)
END
END
END updateFromBucket ;
(*
getToken - gets the next token into currenttoken.
*)
PROCEDURE getToken ;
BEGIN
REPEAT
doGetToken ;
IF currenttoken = commenttok
THEN
IF isProcedureComment (currentcomment)
THEN
procedureComment := currentcomment ;
bodyComment := NIL ;
afterComment := NIL ;
ELSIF isBodyComment (currentcomment)
THEN
bodyComment := currentcomment ;
afterComment := NIL
ELSIF isAfterComment (currentcomment)
THEN
procedureComment := NIL ;
bodyComment := NIL ;
afterComment := currentcomment
END
END
UNTIL currenttoken # commenttok
END getToken ;
(*
doGetToken - fetch the next token into currenttoken.
*)
PROCEDURE doGetToken ;
VAR
a: ADDRESS ;
t: CARDINAL ;
b: tokenBucket ;
BEGIN
IF useBufferedTokens
THEN
t := nextTokNo ;
b := findtokenBucket (t) ;
updateFromBucket (b, t)
ELSE
IF listOfTokens.tail=NIL
THEN
a := mcflex.getToken () ;
IF listOfTokens.tail=NIL
THEN
HALT
END
END ;
IF nextTokNo>=listOfTokens.lastBucketOffset
THEN
(* nextTokNo is in the last bucket or needs to be read. *)
IF nextTokNo-listOfTokens.lastBucketOffset<listOfTokens.tail^.len
THEN
IF Debugging
THEN
printf0 ('fetching token from buffer (updateFromBucket)\n')
END ;
updateFromBucket (listOfTokens.tail,
nextTokNo-listOfTokens.lastBucketOffset)
ELSE
IF Debugging
THEN
printf0 ('calling flex to place token into buffer\n')
END ;
(* call the lexical phase to place a new token into the last bucket. *)
a := mcflex.getToken () ;
getToken ; (* and call ourselves again to collect the token from bucket. *)
RETURN
END
ELSE
IF Debugging
THEN
printf0 ('fetching token from buffer\n')
END ;
t := nextTokNo ;
b := findtokenBucket (t) ;
updateFromBucket (b, t)
END
END ;
IF Debugging
THEN
displayToken (currenttoken)
END ;
INC (nextTokNo)
END doGetToken ;
(*
syncOpenWithBuffer - synchronise the buffer with the start of a file.
Skips all the tokens to do with the previous file.
*)
PROCEDURE syncOpenWithBuffer ;
BEGIN
IF listOfTokens.tail#NIL
THEN
WITH listOfTokens.tail^ DO
nextTokNo := listOfTokens.lastBucketOffset+len
END
END
END syncOpenWithBuffer ;
(*
insertToken - inserts a symbol, token, infront of the current token
ready for the next pass.
*)
PROCEDURE insertToken (token: toktype) ;
BEGIN
IF listOfTokens.tail#NIL
THEN
WITH listOfTokens.tail^ DO
IF len>0
THEN
buf[len-1].token := token
END
END ;
addTokToList (currenttoken, NulName, 0, NIL,
getLineNo (), getColumnNo (), currentSource) ;
getToken
END
END insertToken ;
(*
insertTokenAndRewind - inserts a symbol, token, infront of the current token
and then moves the token stream back onto the inserted token.
*)
PROCEDURE insertTokenAndRewind (token: toktype) ;
BEGIN
IF listOfTokens.tail#NIL
THEN
WITH listOfTokens.tail^ DO
IF len>0
THEN
buf[len-1].token := token
END
END ;
addTokToList (currenttoken, NulName, 0, NIL,
getLineNo(), getColumnNo(), currentSource) ;
currenttoken := token
END
END insertTokenAndRewind ;
(*
getPreviousTokenLineNo - returns the line number of the previous token.
*)
PROCEDURE getPreviousTokenLineNo () : CARDINAL ;
BEGIN
RETURN getLineNo()
END getPreviousTokenLineNo ;
(*
getLineNo - returns the current line number where the symbol occurs in
the source file.
*)
PROCEDURE getLineNo () : CARDINAL ;
BEGIN
IF nextTokNo=0
THEN
RETURN 0
ELSE
RETURN tokenToLineNo (getTokenNo (), 0)
END
END getLineNo ;
(*
getColumnNo - returns the current column where the symbol occurs in
the source file.
*)
PROCEDURE getColumnNo () : CARDINAL ;
BEGIN
IF nextTokNo=0
THEN
RETURN 0
ELSE
RETURN tokenToColumnNo (getTokenNo (), 0)
END
END getColumnNo ;
(*
getTokenNo - returns the current token number.
*)
PROCEDURE getTokenNo () : CARDINAL ;
BEGIN
IF nextTokNo=0
THEN
RETURN 0
ELSE
RETURN nextTokNo-1
END
END getTokenNo ;
(*
findtokenBucket - returns the tokenBucket corresponding to the tokenNo.
*)
PROCEDURE findtokenBucket (VAR tokenNo: CARDINAL) : tokenBucket ;
VAR
b: tokenBucket ;
BEGIN
b := listOfTokens.head ;
WHILE b#NIL DO
WITH b^ DO
IF tokenNo<len
THEN
RETURN b
ELSE
DEC (tokenNo, len)
END
END ;
b := b^.next
END ;
RETURN NIL
END findtokenBucket ;
(*
tokenToLineNo - returns the line number of the current file for the
tokenNo. The depth refers to the include depth.
A depth of 0 is the current file, depth of 1 is the file
which included the current file. Zero is returned if the
depth exceeds the file nesting level.
*)
PROCEDURE tokenToLineNo (tokenNo: CARDINAL; depth: CARDINAL) : CARDINAL ;
VAR
b: tokenBucket ;
l: sourceList ;
BEGIN
b := findtokenBucket (tokenNo) ;
IF b=NIL
THEN
RETURN 0
ELSE
IF depth=0
THEN
RETURN b^.buf[tokenNo].line
ELSE
l := b^.buf[tokenNo].file^.left ;
WHILE depth>0 DO
l := l^.left ;
IF l=b^.buf[tokenNo].file^.left
THEN
RETURN 0
END ;
DEC (depth)
END ;
RETURN l^.line
END
END
END tokenToLineNo ;
(*
tokenToColumnNo - returns the column number of the current file for the
tokenNo. The depth refers to the include depth.
A depth of 0 is the current file, depth of 1 is the file
which included the current file. Zero is returned if the
depth exceeds the file nesting level.
*)
PROCEDURE tokenToColumnNo (tokenNo: CARDINAL; depth: CARDINAL) : CARDINAL ;
VAR
b: tokenBucket ;
l: sourceList ;
BEGIN
b := findtokenBucket (tokenNo) ;
IF b=NIL
THEN
RETURN 0
ELSE
IF depth=0
THEN
RETURN b^.buf[tokenNo].col
ELSE
l := b^.buf[tokenNo].file^.left ;
WHILE depth>0 DO
l := l^.left ;
IF l=b^.buf[tokenNo].file^.left
THEN
RETURN 0
END ;
DEC (depth)
END ;
RETURN l^.col
END
END
END tokenToColumnNo ;
(*
findFileNameFromToken - returns the complete FileName for the appropriate
source file yields the token number, tokenNo.
The, Depth, indicates the include level: 0..n
Level 0 is the current. NIL is returned if n+1
is requested.
*)
PROCEDURE findFileNameFromToken (tokenNo: CARDINAL; depth: CARDINAL) : String ;
VAR
b: tokenBucket ;
l: sourceList ;
BEGIN
b := findtokenBucket (tokenNo) ;
IF b=NIL
THEN
RETURN NIL
ELSE
l := b^.buf[tokenNo].file^.left ;
WHILE depth>0 DO
l := l^.left ;
IF l=b^.buf[tokenNo].file^.left
THEN
RETURN NIL
END ;
DEC (depth)
END ;
RETURN l^.name
END
END findFileNameFromToken ;
(*
getFileName - returns a String defining the current file.
*)
PROCEDURE getFileName () : String ;
BEGIN
RETURN findFileNameFromToken (getTokenNo (), 0)
END getFileName ;
PROCEDURE stop ; BEGIN END stop ;
(*
addTokToList - adds a token to a dynamic list.
*)
PROCEDURE addTokToList (t: toktype; n: Name;
i: INTEGER; comment: commentDesc;
l: CARDINAL; c: CARDINAL; f: sourceList) ;
VAR
b: tokenBucket ;
BEGIN
IF listOfTokens.head=NIL
THEN
NEW (listOfTokens.head) ;
IF listOfTokens.head=NIL
THEN
(* list error *)
END ;
listOfTokens.tail := listOfTokens.head ;
listOfTokens.tail^.len := 0
ELSIF listOfTokens.tail^.len=MaxBucketSize
THEN
assert (listOfTokens.tail^.next=NIL) ;
NEW (listOfTokens.tail^.next) ;
IF listOfTokens.tail^.next=NIL
THEN
(* list error *)
ELSE
listOfTokens.tail := listOfTokens.tail^.next ;
listOfTokens.tail^.len := 0
END ;
INC (listOfTokens.lastBucketOffset, MaxBucketSize)
END ;
WITH listOfTokens.tail^ DO
next := NIL ;
assert (len # MaxBucketSize) ;
WITH buf[len] DO
token := t ;
str := n ;
int := i ;
com := comment ;
line := l ;
col := c ;
file := f
END ;
INC (len)
END
END addTokToList ;
(*
isLastTokenEof - returns TRUE if the last token was an eoftok
*)
PROCEDURE isLastTokenEof () : BOOLEAN ;
VAR
t: CARDINAL ;
b: tokenBucket ;
BEGIN
IF listOfTokens.tail#NIL
THEN
IF listOfTokens.tail^.len=0
THEN
b := listOfTokens.head ;
IF b=listOfTokens.tail
THEN
RETURN FALSE
END ;
WHILE b^.next#listOfTokens.tail DO
b := b^.next
END ;
ELSE
b := listOfTokens.tail
END ;
WITH b^ DO
assert (len>0) ; (* len should always be >0 *)
RETURN buf[len-1].token=eoftok
END
END ;
RETURN FALSE
END isLastTokenEof ;
(* ***********************************************************************
*
* These functions allow m2.flex to deliver tokens into the buffer
*
************************************************************************* *)
(*
addTok - adds a token to the buffer.
*)
PROCEDURE addTok (t: toktype) ;
BEGIN
IF NOT ((t=eoftok) AND isLastTokenEof())
THEN
addTokToList (t, NulName, 0, NIL,
mcflex.getLineNo (), mcflex.getColumnNo (), currentSource) ;
currentUsed := TRUE
END
END addTok ;
(*
addTokCharStar - adds a token to the buffer and an additional string, s.
A copy of string, s, is made.
*)
PROCEDURE addTokCharStar (t: toktype; s: ADDRESS) ;
BEGIN
IF strlen(s)>80
THEN
stop
END ;
addTokToList (t, makekey (s), 0, NIL,
mcflex.getLineNo (), mcflex.getColumnNo (), currentSource) ;
currentUsed := TRUE
END addTokCharStar ;
(*
addTokInteger - adds a token and an integer to the buffer.
*)
PROCEDURE addTokInteger (t: toktype; i: INTEGER) ;
VAR
s: String ;
c,
l: CARDINAL ;
BEGIN
l := mcflex.getLineNo () ;
c := mcflex.getColumnNo () ;
s := Sprintf1 (Mark (InitString ('%d')), i) ;
addTokToList (t, makekey(string(s)), i, NIL, l, c, currentSource) ;
s := KillString (s) ;
currentUsed := TRUE
END addTokInteger ;
(*
addTokComment - adds a token to the buffer and a comment descriptor, com.
*)
PROCEDURE addTokComment (t: toktype; com: commentDesc) ;
BEGIN
addTokToList (t, NulName, 0, com,
mcflex.getLineNo (), mcflex.getColumnNo (), currentSource) ;
currentUsed := TRUE
END addTokComment ;
BEGIN
init
END mcLexBuf.