1 (* mcLexBuf.mod provides a buffer for the all the tokens created by m2.lex.
3 Copyright (C) 2015-2024 Free Software Foundation, Inc.
4 Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
6 This file is part of GNU Modula-2.
8 GNU Modula-2 is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GNU Modula-2 is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GNU Modula-2; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. *)
22 IMPLEMENTATION MODULE mcLexBuf
;
26 FROM libc
IMPORT strlen
;
27 FROM SYSTEM
IMPORT ADDRESS
;
28 FROM Storage
IMPORT ALLOCATE
, DEALLOCATE
;
29 FROM DynamicStrings
IMPORT string
, InitString
, InitStringCharStar
, Equal
, Mark
, KillString
;
30 FROM FormatStrings
IMPORT Sprintf1
;
31 FROM nameKey
IMPORT NulName
, Name
, makekey
, keyToCharStar
;
32 FROM mcReserved
IMPORT toktype
;
33 FROM mcComment
IMPORT isProcedureComment
, isBodyComment
, isAfterComment
, getContent
;
34 FROM mcPrintf
IMPORT printf0
, printf1
, printf2
, printf3
;
35 FROM mcDebug
IMPORT assert
;
43 sourceList
= POINTER TO RECORD
61 tokenBucket
= POINTER TO RECORD
62 buf
: ARRAY [0..MaxBucketSize
] OF tokenDesc
;
70 lastBucketOffset
: CARDINAL ;
76 afterComment
: commentDesc
;
77 currentSource
: sourceList
;
79 currentUsed
: BOOLEAN ;
80 listOfTokens
: listDesc
;
81 nextTokNo
: CARDINAL ;
85 debugLex - display the last, n, tokens.
88 PROCEDURE debugLex (n
: CARDINAL) ;
105 printf0 ("nextTokNo ")
107 b
:= findtokenBucket (t
) ;
111 printf1 ("end of buf (%d is further ahead than the buffer contents)\n", t
)
114 printf2 ("entry %d %d ", c
, t
) ;
115 displayToken (b^.buf
[t
].token
) ;
124 getProcedureComment - returns the procedure comment if it exists,
128 PROCEDURE getProcedureComment () : commentDesc
;
130 RETURN procedureComment
131 END getProcedureComment
;
135 getBodyComment - returns the body comment if it exists,
136 or NIL otherwise. The body comment is
140 PROCEDURE getBodyComment () : commentDesc
;
154 PROCEDURE seekTo (t
: CARDINAL) ;
162 b
:= findtokenBucket (t
) ;
165 updateFromBucket (b
, t
)
175 PROCEDURE peeptokenBucket (VAR t
: CARDINAL) : tokenBucket
;
187 old
:= getTokenNo () ;
190 b
:= findtokenBucket (n
) ;
195 b
:= findtokenBucket (n
) ;
196 IF (b
= NIL) OR (currenttoken
= eoftok
)
199 nextTokNo
:= old
+ 1 ;
200 b
:= findtokenBucket (old
) ;
201 updateFromBucket (b
, old
) ;
205 UNTIL (b #
NIL) OR (currenttoken
= eoftok
) ;
207 nextTokNo
:= old
+ 1 ;
210 printf2 ("nextTokNo = %d, old = %d\n", nextTokNo
, old
)
212 b
:= findtokenBucket (old
) ;
215 printf1 (" adjusted old = %d\n", old
)
219 updateFromBucket (b
, old
)
225 assert (ct
= currenttoken
) ;
227 END peeptokenBucket
;
231 peepAfterComment - peeps ahead looking for an after statement comment. It stops at an END token
232 or if the line number changes.
235 PROCEDURE peepAfterComment
;
246 oldTokNo
:= nextTokNo
;
247 cno
:= getTokenNo () ;
248 curline
:= tokenToLineNo (cno
, 0) ;
249 nextline
:= curline
;
254 b
:= peeptokenBucket (t
) ;
255 IF (b
= NIL) OR (currenttoken
= eoftok
)
259 nextline
:= b^.buf
[t
].line
;
260 IF nextline
= curline
262 CASE b^.buf
[t
].token
OF
265 endtok
: finished
:= TRUE |
266 commenttok
: IF isAfterComment (b^.buf
[t
].com
)
268 afterComment
:= b^.buf
[t
].com
279 END peepAfterComment
;
283 getAfterComment - returns the after comment if it exists,
284 or NIL otherwise. The after comment is
288 PROCEDURE getAfterComment () : commentDesc
;
294 afterComment
:= NIL ;
296 END getAfterComment
;
300 init - initializes the token list and source list.
305 currenttoken
:= eoftok
;
307 currentSource
:= NIL ;
308 listOfTokens.head
:= NIL ;
309 listOfTokens.tail
:= NIL ;
310 useBufferedTokens
:= FALSE ;
311 procedureComment
:= NIL ;
313 afterComment
:= NIL ;
319 addTo - adds a new element to the end of sourceList, currentSource.
322 PROCEDURE addTo (l
: sourceList
) ;
324 l^.right
:= currentSource
;
325 l^.left
:= currentSource^.left
;
326 currentSource^.left^.right
:= l
;
327 currentSource^.left
:= l
;
329 line
:= mcflex.
getLineNo() ;
330 col
:= mcflex.
getColumnNo()
336 subFrom - subtracts, l, from the source list.
339 PROCEDURE subFrom (l
: sourceList
) ;
341 l^.left^.right
:= l^.right
;
342 l^.right^.left
:= l^.left
347 newElement - returns a new sourceList
350 PROCEDURE newElement (s
: ADDRESS
) : sourceList
;
360 name
:= InitStringCharStar (s
) ;
370 newList - initializes an empty list with the classic dummy header element.
373 PROCEDURE newList () : sourceList
;
388 checkIfNeedToDuplicate - checks to see whether the currentSource has
389 been used, if it has then duplicate the list.
392 PROCEDURE checkIfNeedToDuplicate
;
398 l
:= currentSource^.right
;
400 currentSource
:= newList() ;
402 addTo (newElement (l^.name
)) ;
406 END checkIfNeedToDuplicate
;
410 pushFile - indicates that, filename, has just been included.
413 PROCEDURE pushFile (filename
: ADDRESS
) ;
417 checkIfNeedToDuplicate
;
418 addTo (newElement (filename
)) ;
421 IF currentSource^.right#currentSource
425 printf3 ('name = %s, line = %d, col = %d\n', l^.name
, l^.line
, l^.col
) ;
427 UNTIL l
=currentSource
434 popFile - indicates that we are returning to, filename, having finished
438 PROCEDURE popFile (filename
: ADDRESS
) ;
442 checkIfNeedToDuplicate
;
443 IF (currentSource#
NIL) AND (currentSource^.left#currentSource
)
445 l
:= currentSource^.left
; (* last element *)
448 IF (currentSource^.left#currentSource
) AND
449 (NOT Equal(currentSource^.name
, Mark (InitStringCharStar (filename
))))
451 (* mismatch in source file names after preprocessing files *)
454 (* source file list is empty, cannot pop an include.. *)
460 killList - kills the sourceList providing that it has not been used.
467 IF (NOT currentUsed
) AND (currentSource#
NIL)
474 UNTIL l
=currentSource
480 reInitialize - re-initialize the all the data structures.
483 PROCEDURE reInitialize
;
487 IF listOfTokens.head#
NIL
489 t
:= listOfTokens.head
;
495 currentUsed
:= FALSE ;
503 setFile - sets the current filename to, filename.
506 PROCEDURE setFile (filename
: ADDRESS
) ;
509 currentUsed
:= FALSE ;
510 currentSource
:= newList() ;
511 addTo (newElement (filename
))
516 openSource - attempts to open the source file, s.
517 The success of the operation is returned.
520 PROCEDURE openSource (s
: String
) : BOOLEAN ;
527 IF mcflex.
openSource (string (s
))
529 setFile (string (s
)) ;
541 closeSource - closes the current open file.
544 PROCEDURE closeSource
;
548 WHILE currenttoken#eoftok
DO
552 (* a subsequent call to mcflex.OpenSource will really close the file *)
558 resetForNewPass - reset the buffer pointers to the beginning ready for
562 PROCEDURE resetForNewPass
;
565 useBufferedTokens
:= TRUE
566 END resetForNewPass
;
573 PROCEDURE displayToken (t
: toktype
) ;
577 eoftok
: printf0('eoftok\n') |
578 plustok
: printf0('plustok\n') |
579 minustok
: printf0('minustok\n') |
580 timestok
: printf0('timestok\n') |
581 dividetok
: printf0('dividetok\n') |
582 becomestok
: printf0('becomestok\n') |
583 ambersandtok
: printf0('ambersandtok\n') |
584 periodtok
: printf0('periodtok\n') |
585 commatok
: printf0('commatok\n') |
586 commenttok
: printf0('commenttok\n') |
587 semicolontok
: printf0('semicolontok\n') |
588 lparatok
: printf0('lparatok\n') |
589 rparatok
: printf0('rparatok\n') |
590 lsbratok
: printf0('lsbratok\n') |
591 rsbratok
: printf0('rsbratok\n') |
592 lcbratok
: printf0('lcbratok\n') |
593 rcbratok
: printf0('rcbratok\n') |
594 uparrowtok
: printf0('uparrowtok\n') |
595 singlequotetok
: printf0('singlequotetok\n') |
596 equaltok
: printf0('equaltok\n') |
597 hashtok
: printf0('hashtok\n') |
598 lesstok
: printf0('lesstok\n') |
599 greatertok
: printf0('greatertok\n') |
600 lessgreatertok
: printf0('lessgreatertok\n') |
601 lessequaltok
: printf0('lessequaltok\n') |
602 greaterequaltok
: printf0('greaterequaltok\n') |
603 periodperiodtok
: printf0('periodperiodtok\n') |
604 colontok
: printf0('colontok\n') |
605 doublequotestok
: printf0('doublequotestok\n') |
606 bartok
: printf0('bartok\n') |
607 andtok
: printf0('andtok\n') |
608 arraytok
: printf0('arraytok\n') |
609 begintok
: printf0('begintok\n') |
610 bytok
: printf0('bytok\n') |
611 casetok
: printf0('casetok\n') |
612 consttok
: printf0('consttok\n') |
613 definitiontok
: printf0('definitiontok\n') |
614 divtok
: printf0('divtok\n') |
615 dotok
: printf0('dotok\n') |
616 elsetok
: printf0('elsetok\n') |
617 elsiftok
: printf0('elsiftok\n') |
618 endtok
: printf0('endtok\n') |
619 exittok
: printf0('exittok\n') |
620 exporttok
: printf0('exporttok\n') |
621 fortok
: printf0('fortok\n') |
622 fromtok
: printf0('fromtok\n') |
623 iftok
: printf0('iftok\n') |
624 implementationtok
: printf0('implementationtok\n') |
625 importtok
: printf0('importtok\n') |
626 intok
: printf0('intok\n') |
627 looptok
: printf0('looptok\n') |
628 modtok
: printf0('modtok\n') |
629 moduletok
: printf0('moduletok\n') |
630 nottok
: printf0('nottok\n') |
631 oftok
: printf0('oftok\n') |
632 ortok
: printf0('ortok\n') |
633 pointertok
: printf0('pointertok\n') |
634 proceduretok
: printf0('proceduretok\n') |
635 qualifiedtok
: printf0('qualifiedtok\n') |
636 unqualifiedtok
: printf0('unqualifiedtok\n') |
637 recordtok
: printf0('recordtok\n') |
638 repeattok
: printf0('repeattok\n') |
639 returntok
: printf0('returntok\n') |
640 settok
: printf0('settok\n') |
641 thentok
: printf0('thentok\n') |
642 totok
: printf0('totok\n') |
643 typetok
: printf0('typetok\n') |
644 untiltok
: printf0('untiltok\n') |
645 vartok
: printf0('vartok\n') |
646 whiletok
: printf0('whiletok\n') |
647 withtok
: printf0('withtok\n') |
648 asmtok
: printf0('asmtok\n') |
649 volatiletok
: printf0('volatiletok\n') |
650 periodperiodperiodtok
: printf0('periodperiodperiodtok\n') |
651 datetok
: printf0('datetok\n') |
652 linetok
: printf0('linetok\n') |
653 filetok
: printf0('filetok\n') |
654 integertok
: printf0('integertok\n') |
655 identtok
: printf0('identtok\n') |
656 realtok
: printf0('realtok\n') |
657 stringtok
: printf0('stringtok\n')
660 printf0 ('unknown tok (--fixme--)\n')
666 updateFromBucket - updates the global variables: currenttoken,
667 currentstring, currentcolumn and currentinteger
668 from tokenBucket, b, and, offset.
671 PROCEDURE updateFromBucket (b
: tokenBucket
; offset
: CARDINAL) ;
673 WITH b^.buf
[offset
] DO
674 currenttoken
:= token
;
675 currentstring
:= keyToCharStar (str
) ;
676 currentcolumn
:= col
;
677 currentinteger
:= int
;
678 currentcomment
:= com
;
679 IF currentcomment #
NIL
681 lastcomment
:= currentcomment
685 printf3 ('line %d (# %d %d) ', line
, offset
, nextTokNo
)
688 END updateFromBucket
;
692 getToken - gets the next token into currenttoken.
699 IF currenttoken
= commenttok
701 IF isProcedureComment (currentcomment
)
703 procedureComment
:= currentcomment
;
705 afterComment
:= NIL ;
706 ELSIF isBodyComment (currentcomment
)
708 bodyComment
:= currentcomment
;
710 ELSIF isAfterComment (currentcomment
)
712 procedureComment
:= NIL ;
714 afterComment
:= currentcomment
717 UNTIL currenttoken # commenttok
722 doGetToken - fetch the next token into currenttoken.
725 PROCEDURE doGetToken
;
734 b
:= findtokenBucket (t
) ;
735 updateFromBucket (b
, t
)
737 IF listOfTokens.tail
=NIL
739 a
:= mcflex.
getToken () ;
740 IF listOfTokens.tail
=NIL
745 IF nextTokNo
>=listOfTokens.lastBucketOffset
747 (* nextTokNo is in the last bucket or needs to be read. *)
748 IF nextTokNo
-listOfTokens.lastBucketOffset
<listOfTokens.tail^.len
752 printf0 ('fetching token from buffer (updateFromBucket)\n')
754 updateFromBucket (listOfTokens.tail
,
755 nextTokNo
-listOfTokens.lastBucketOffset
)
759 printf0 ('calling flex to place token into buffer\n')
761 (* call the lexical phase to place a new token into the last bucket. *)
762 a
:= mcflex.
getToken () ;
763 getToken
; (* and call ourselves again to collect the token from bucket. *)
769 printf0 ('fetching token from buffer\n')
772 b
:= findtokenBucket (t
) ;
773 updateFromBucket (b
, t
)
778 displayToken (currenttoken
)
785 syncOpenWithBuffer - synchronise the buffer with the start of a file.
786 Skips all the tokens to do with the previous file.
789 PROCEDURE syncOpenWithBuffer
;
791 IF listOfTokens.tail#
NIL
793 WITH listOfTokens.tail^
DO
794 nextTokNo
:= listOfTokens.lastBucketOffset
+len
797 END syncOpenWithBuffer
;
801 insertToken - inserts a symbol, token, infront of the current token
802 ready for the next pass.
805 PROCEDURE insertToken (token
: toktype
) ;
807 IF listOfTokens.tail#
NIL
809 WITH listOfTokens.tail^
DO
812 buf
[len
-1].token
:= token
815 addTokToList (currenttoken
, NulName
, 0, NIL,
816 getLineNo (), getColumnNo (), currentSource
) ;
823 insertTokenAndRewind - inserts a symbol, token, infront of the current token
824 and then moves the token stream back onto the inserted token.
827 PROCEDURE insertTokenAndRewind (token
: toktype
) ;
829 IF listOfTokens.tail#
NIL
831 WITH listOfTokens.tail^
DO
834 buf
[len
-1].token
:= token
837 addTokToList (currenttoken
, NulName
, 0, NIL,
838 getLineNo(), getColumnNo(), currentSource
) ;
839 currenttoken
:= token
841 END insertTokenAndRewind
;
845 getPreviousTokenLineNo - returns the line number of the previous token.
848 PROCEDURE getPreviousTokenLineNo () : CARDINAL ;
851 END getPreviousTokenLineNo
;
855 getLineNo - returns the current line number where the symbol occurs in
859 PROCEDURE getLineNo () : CARDINAL ;
865 RETURN tokenToLineNo (getTokenNo (), 0)
871 getColumnNo - returns the current column where the symbol occurs in
875 PROCEDURE getColumnNo () : CARDINAL ;
881 RETURN tokenToColumnNo (getTokenNo (), 0)
887 getTokenNo - returns the current token number.
890 PROCEDURE getTokenNo () : CARDINAL ;
902 findtokenBucket - returns the tokenBucket corresponding to the tokenNo.
905 PROCEDURE findtokenBucket (VAR tokenNo
: CARDINAL) : tokenBucket
;
909 b
:= listOfTokens.head
;
922 END findtokenBucket
;
926 tokenToLineNo - returns the line number of the current file for the
927 tokenNo. The depth refers to the include depth.
928 A depth of 0 is the current file, depth of 1 is the file
929 which included the current file. Zero is returned if the
930 depth exceeds the file nesting level.
933 PROCEDURE tokenToLineNo (tokenNo
: CARDINAL; depth
: CARDINAL) : CARDINAL ;
938 b
:= findtokenBucket (tokenNo
) ;
945 RETURN b^.buf
[tokenNo
].line
947 l
:= b^.buf
[tokenNo
].file^.left
;
950 IF l
=b^.buf
[tokenNo
].file^.left
963 tokenToColumnNo - returns the column number of the current file for the
964 tokenNo. The depth refers to the include depth.
965 A depth of 0 is the current file, depth of 1 is the file
966 which included the current file. Zero is returned if the
967 depth exceeds the file nesting level.
970 PROCEDURE tokenToColumnNo (tokenNo
: CARDINAL; depth
: CARDINAL) : CARDINAL ;
975 b
:= findtokenBucket (tokenNo
) ;
982 RETURN b^.buf
[tokenNo
].col
984 l
:= b^.buf
[tokenNo
].file^.left
;
987 IF l
=b^.buf
[tokenNo
].file^.left
996 END tokenToColumnNo
;
1000 findFileNameFromToken - returns the complete FileName for the appropriate
1001 source file yields the token number, tokenNo.
1002 The, Depth, indicates the include level: 0..n
1003 Level 0 is the current. NIL is returned if n+1
1007 PROCEDURE findFileNameFromToken (tokenNo
: CARDINAL; depth
: CARDINAL) : String
;
1012 b
:= findtokenBucket (tokenNo
) ;
1017 l
:= b^.buf
[tokenNo
].file^.left
;
1020 IF l
=b^.buf
[tokenNo
].file^.left
1028 END findFileNameFromToken
;
1032 getFileName - returns a String defining the current file.
1035 PROCEDURE getFileName () : String
;
1037 RETURN findFileNameFromToken (getTokenNo (), 0)
1041 PROCEDURE stop
; BEGIN END stop
;
1045 addTokToList - adds a token to a dynamic list.
1048 PROCEDURE addTokToList (t
: toktype
; n
: Name
;
1049 i
: INTEGER; comment
: commentDesc
;
1050 l
: CARDINAL; c
: CARDINAL; f
: sourceList
) ;
1054 IF listOfTokens.head
=NIL
1056 NEW (listOfTokens.head
) ;
1057 IF listOfTokens.head
=NIL
1061 listOfTokens.tail
:= listOfTokens.head
;
1062 listOfTokens.tail^.len
:= 0
1063 ELSIF listOfTokens.tail^.len
=MaxBucketSize
1065 assert (listOfTokens.tail^.next
=NIL) ;
1066 NEW (listOfTokens.tail^.next
) ;
1067 IF listOfTokens.tail^.next
=NIL
1071 listOfTokens.tail
:= listOfTokens.tail^.next
;
1072 listOfTokens.tail^.len
:= 0
1074 INC (listOfTokens.lastBucketOffset
, MaxBucketSize
)
1076 WITH listOfTokens.tail^
DO
1078 assert (len # MaxBucketSize
) ;
1094 isLastTokenEof - returns TRUE if the last token was an eoftok
1097 PROCEDURE isLastTokenEof () : BOOLEAN ;
1102 IF listOfTokens.tail#
NIL
1104 IF listOfTokens.tail^.len
=0
1106 b
:= listOfTokens.head
;
1107 IF b
=listOfTokens.tail
1111 WHILE b^.next#listOfTokens.tail
DO
1115 b
:= listOfTokens.tail
1118 assert (len
>0) ; (* len should always be >0 *)
1119 RETURN buf
[len
-1].token
=eoftok
1123 END isLastTokenEof
;
1126 (* ***********************************************************************
1128 * These functions allow m2.flex to deliver tokens into the buffer
1130 ************************************************************************* *)
1133 addTok - adds a token to the buffer.
1136 PROCEDURE addTok (t
: toktype
) ;
1138 IF NOT ((t
=eoftok
) AND isLastTokenEof())
1140 addTokToList (t
, NulName
, 0, NIL,
1141 mcflex.
getLineNo (), mcflex.
getColumnNo (), currentSource
) ;
1148 addTokCharStar - adds a token to the buffer and an additional string, s.
1149 A copy of string, s, is made.
1152 PROCEDURE addTokCharStar (t
: toktype
; s
: ADDRESS
) ;
1158 addTokToList (t
, makekey (s
), 0, NIL,
1159 mcflex.
getLineNo (), mcflex.
getColumnNo (), currentSource
) ;
1161 END addTokCharStar
;
1165 addTokInteger - adds a token and an integer to the buffer.
1168 PROCEDURE addTokInteger (t
: toktype
; i
: INTEGER) ;
1174 l
:= mcflex.
getLineNo () ;
1175 c
:= mcflex.
getColumnNo () ;
1176 s
:= Sprintf1 (Mark (InitString ('%d')), i
) ;
1177 addTokToList (t
, makekey(string(s
)), i
, NIL, l
, c
, currentSource
) ;
1178 s
:= KillString (s
) ;
1184 addTokComment - adds a token to the buffer and a comment descriptor, com.
1187 PROCEDURE addTokComment (t
: toktype
; com
: commentDesc
) ;
1189 addTokToList (t
, NulName
, 0, com
,
1190 mcflex.
getLineNo (), mcflex.
getColumnNo (), currentSource
) ;