]>
Commit | Line | Data |
---|---|---|
1eee94d3 GM |
1 | (* CLexBuf.mod provides a lexical buffer for clex. |
2 | ||
83ffe9cd | 3 | Copyright (C) 2003-2023 Free Software Foundation, Inc. |
1eee94d3 GM |
4 | Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>. |
5 | ||
6 | This file is part of GNU Modula-2. | |
7 | ||
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) | |
11 | any later version. | |
12 | ||
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. | |
17 | ||
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/>. *) | |
21 | ||
22 | IMPLEMENTATION MODULE CLexBuf ; | |
23 | ||
24 | IMPORT cflex ; | |
25 | ||
26 | FROM SYSTEM IMPORT ADDRESS ; | |
27 | FROM Storage IMPORT ALLOCATE, DEALLOCATE ; | |
28 | FROM DynamicStrings IMPORT string, InitString, InitStringCharStar, Equal, Mark, KillString ; | |
29 | FROM FormatStrings IMPORT Sprintf1 ; | |
30 | FROM NameKey IMPORT Name, NulName, makekey, KeyToCharStar ; | |
31 | FROM M2Printf IMPORT printf0, printf1, printf2, printf3 ; | |
32 | FROM Assertion IMPORT Assert ; | |
33 | FROM SymbolKey IMPORT NulKey, SymbolTree, InitTree, DelSymKey, PutSymKey, GetSymKey ; | |
34 | FROM Indexing IMPORT Index, InitIndex, IsIndiceInIndex, GetIndice, PutIndice ; | |
35 | ||
36 | CONST | |
37 | MaxBucketSize = 100 ; | |
38 | Debugging = FALSE ; | |
39 | ||
40 | TYPE | |
41 | SourceList = POINTER TO sourcelist ; | |
42 | sourcelist = RECORD | |
43 | left, | |
44 | right: SourceList ; | |
45 | name : String ; | |
46 | line : CARDINAL ; | |
47 | END ; | |
48 | ||
49 | TokenDesc = RECORD | |
50 | token: toktype ; | |
51 | str : Name ; | |
52 | int : INTEGER ; | |
53 | line : CARDINAL ; | |
54 | file : SourceList ; | |
55 | END ; | |
56 | ||
57 | TokenBucket = POINTER TO tokenbucket ; | |
58 | tokenbucket = RECORD | |
59 | buf : ARRAY [0..MaxBucketSize] OF TokenDesc ; | |
60 | len : CARDINAL ; | |
61 | next: TokenBucket ; | |
62 | END ; | |
63 | ||
64 | ListDesc = RECORD | |
65 | head, | |
66 | tail : TokenBucket ; | |
67 | LastBucketOffset: CARDINAL ; | |
68 | END ; | |
69 | ||
70 | MacroArgs = POINTER TO macroargs ; | |
71 | macroargs = RECORD | |
72 | next: MacroArgs ; | |
73 | str : Name ; | |
74 | END ; | |
75 | ||
76 | Macro = POINTER TO macro ; | |
77 | macro = RECORD | |
78 | str : Name ; | |
79 | tokno : CARDINAL ; | |
80 | noArgs: CARDINAL ; | |
81 | args : MacroArgs ; | |
82 | END ; | |
83 | ||
84 | VAR | |
85 | CurrentSource : SourceList ; | |
86 | UseBufferedTokens, | |
87 | CurrentUsed : BOOLEAN ; | |
88 | ListOfTokens : ListDesc ; | |
89 | CurrentTokNo : CARDINAL ; | |
90 | MacroDefinitions : SymbolTree ; | |
91 | MacroIndex : Index ; | |
92 | DefineNo : CARDINAL ; | |
93 | EnabledMacros : BOOLEAN ; | |
94 | ||
95 | ||
96 | (* M A C R O *) | |
97 | ||
98 | (* | |
99 | EnableMacroSubstitutions - | |
100 | *) | |
101 | ||
102 | PROCEDURE EnableMacroSubstitutions (b: BOOLEAN) ; | |
103 | BEGIN | |
104 | EnabledMacros := b | |
105 | END EnableMacroSubstitutions ; | |
106 | ||
107 | ||
108 | (* | |
109 | IsMacroDefined - returns TRUE if macro, n, was defined. | |
110 | *) | |
111 | ||
112 | PROCEDURE IsMacroDefined (n: Name) : BOOLEAN ; | |
113 | VAR | |
114 | i: CARDINAL ; | |
115 | m: Macro ; | |
116 | BEGIN | |
117 | i := GetSymKey(MacroDefinitions, n) ; | |
118 | IF i=0 | |
119 | THEN | |
120 | RETURN( FALSE ) | |
121 | ELSE | |
122 | m := GetIndice(MacroIndex, i) ; | |
123 | IF m=NIL | |
124 | THEN | |
125 | RETURN( FALSE ) | |
126 | ELSE | |
127 | RETURN( TRUE ) | |
128 | END | |
129 | END | |
130 | END IsMacroDefined ; | |
131 | ||
132 | ||
133 | (* | |
134 | NoArgs - returns the number of arguments for macro, n. | |
135 | -1 if the macro does not exist | |
136 | *) | |
137 | ||
138 | PROCEDURE NoArgs (n: Name) : INTEGER ; | |
139 | VAR | |
140 | m: Macro ; | |
141 | i: CARDINAL ; | |
142 | BEGIN | |
143 | IF IsMacroDefined(n) | |
144 | THEN | |
145 | i := GetSymKey(MacroDefinitions, n) ; | |
146 | m := GetIndice(MacroIndex, i) ; | |
147 | RETURN( m^.noArgs ) | |
148 | ELSE | |
149 | RETURN( -1 ) | |
150 | END | |
151 | END NoArgs ; | |
152 | ||
153 | ||
154 | (* | |
155 | DefineMacro - defines macro, n, as defined to start at token, t. | |
156 | *) | |
157 | ||
158 | PROCEDURE DefineMacro (n: Name; t: CARDINAL) ; | |
159 | VAR | |
160 | m: Macro ; | |
161 | i: CARDINAL ; | |
162 | BEGIN | |
163 | NEW(m) ; | |
164 | WITH m^ DO | |
165 | str := n ; | |
166 | tokno := t ; | |
167 | noArgs := 0 ; | |
168 | args := NIL | |
169 | END ; | |
170 | UnDefineMacro(n) ; | |
171 | i := GetSymKey(MacroDefinitions, n) ; | |
172 | IF i=NulKey | |
173 | THEN | |
174 | PutSymKey(MacroDefinitions, n, DefineNo) ; | |
175 | i := DefineNo ; | |
176 | INC(DefineNo) | |
177 | END ; | |
178 | PutIndice(MacroIndex, i, m) | |
179 | END DefineMacro ; | |
180 | ||
181 | ||
182 | (* | |
183 | UnDefineMacro - | |
184 | *) | |
185 | ||
186 | PROCEDURE UnDefineMacro (n: Name) ; | |
187 | VAR | |
188 | m: Macro ; | |
189 | i: CARDINAL ; | |
190 | BEGIN | |
191 | IF IsMacroDefined(n) | |
192 | THEN | |
193 | i := GetSymKey(MacroDefinitions, n) ; | |
194 | m := GetIndice(MacroIndex, i) ; | |
195 | PutIndice(MacroIndex, i, NIL) ; | |
196 | DISPOSE(m) | |
197 | END | |
198 | END UnDefineMacro ; | |
199 | ||
200 | ||
201 | (* | |
202 | PushMacroDefinition - pushes the macro definition, n, onto the token stream. | |
203 | It returns TRUE if the macro was found and pushed. | |
204 | *) | |
205 | ||
206 | PROCEDURE PushMacroDefinition (n: Name) : BOOLEAN ; | |
207 | VAR | |
208 | m: Macro ; | |
209 | t: CARDINAL ; | |
210 | b: TokenBucket ; | |
211 | i: CARDINAL ; | |
212 | BEGIN | |
213 | IF EnabledMacros AND IsMacroDefined(n) | |
214 | THEN | |
215 | i := GetSymKey(MacroDefinitions, n) ; | |
216 | m := GetIndice(MacroIndex, i) ; | |
217 | WITH m^ DO | |
218 | IF tokno>0 | |
219 | THEN | |
220 | t := tokno ; | |
221 | LOOP | |
222 | b := FindTokenBucket(t) ; | |
223 | WITH b^.buf[t] DO | |
224 | IF token=endhashtok | |
225 | THEN | |
226 | RETURN( TRUE ) | |
227 | ELSE | |
228 | IF IsMacroDefined(str) AND (str#n) | |
229 | THEN | |
230 | IF PushMacroDefinition(str) | |
231 | THEN | |
232 | END | |
233 | ELSE | |
234 | AddTokToList(token, str, int, line, file) | |
235 | END | |
236 | END | |
237 | END ; | |
238 | INC(t) | |
239 | END | |
240 | END | |
241 | END ; | |
242 | RETURN( TRUE ) | |
243 | ELSE | |
244 | RETURN( FALSE ) | |
245 | END | |
246 | END PushMacroDefinition ; | |
247 | ||
248 | ||
249 | (* e n d o f M A C R O r o u t i n e s *) | |
250 | ||
251 | PROCEDURE stop ; BEGIN END stop ; | |
252 | ||
253 | (* | |
254 | Init - initializes the token list and source list. | |
255 | *) | |
256 | ||
257 | PROCEDURE Init ; | |
258 | BEGIN | |
259 | currenttoken := eoftok ; | |
260 | CurrentTokNo := 0 ; | |
261 | CurrentSource := NIL ; | |
262 | ListOfTokens.head := NIL ; | |
263 | ListOfTokens.tail := NIL ; | |
264 | UseBufferedTokens := FALSE ; | |
265 | InitTree(MacroDefinitions) ; | |
266 | EnabledMacros := TRUE ; | |
267 | DefineNo := 1 ; | |
268 | MacroIndex := InitIndex(1) | |
269 | END Init ; | |
270 | ||
271 | ||
272 | (* | |
273 | AddTo - adds a new element to the end of SourceList, CurrentSource. | |
274 | *) | |
275 | ||
276 | PROCEDURE AddTo (l: SourceList) ; | |
277 | BEGIN | |
278 | l^.right := CurrentSource ; | |
279 | l^.left := CurrentSource^.left ; | |
280 | CurrentSource^.left^.right := l ; | |
281 | CurrentSource^.left := l ; | |
282 | l^.left^.line := cflex.GetLineNo() | |
283 | END AddTo ; | |
284 | ||
285 | ||
286 | (* | |
287 | SubFrom - subtracts, l, from the source list. | |
288 | *) | |
289 | ||
290 | PROCEDURE SubFrom (l: SourceList) ; | |
291 | BEGIN | |
292 | l^.left^.right := l^.right ; | |
293 | l^.right^.left := l^.left | |
294 | END SubFrom ; | |
295 | ||
296 | ||
297 | (* | |
298 | NewElement - returns a new SourceList | |
299 | *) | |
300 | ||
301 | PROCEDURE NewElement (s: ADDRESS) : SourceList ; | |
302 | VAR | |
303 | l: SourceList ; | |
304 | BEGIN | |
305 | NEW(l) ; | |
306 | IF l=NIL | |
307 | THEN | |
308 | HALT | |
309 | ELSE | |
310 | WITH l^ DO | |
311 | name := InitStringCharStar(s) ; | |
312 | left := NIL ; | |
313 | right := NIL | |
314 | END | |
315 | END ; | |
316 | RETURN( l ) | |
317 | END NewElement ; | |
318 | ||
319 | ||
320 | (* | |
321 | NewList - initializes an empty list with the classic dummy header element. | |
322 | *) | |
323 | ||
324 | PROCEDURE NewList () : SourceList ; | |
325 | VAR | |
326 | l: SourceList ; | |
327 | BEGIN | |
328 | NEW(l) ; | |
329 | WITH l^ DO | |
330 | left := l ; | |
331 | right := l ; | |
332 | name := NIL | |
333 | END ; | |
334 | RETURN( l ) | |
335 | END NewList ; | |
336 | ||
337 | ||
338 | (* | |
339 | CheckIfNeedToDuplicate - checks to see whether the CurrentSource has | |
340 | been used, if it has then duplicate the list. | |
341 | *) | |
342 | ||
343 | PROCEDURE CheckIfNeedToDuplicate ; | |
344 | VAR | |
345 | l, h: SourceList ; | |
346 | BEGIN | |
347 | IF CurrentUsed | |
348 | THEN | |
349 | l := CurrentSource^.right ; | |
350 | h := CurrentSource ; | |
351 | CurrentSource := NewList() ; | |
352 | WHILE l#h DO | |
353 | AddTo(NewElement(l^.name)) ; | |
354 | l := l^.right | |
355 | END | |
356 | END | |
357 | END CheckIfNeedToDuplicate ; | |
358 | ||
359 | ||
360 | (* | |
361 | PushFile - indicates that, filename, has just been included. | |
362 | *) | |
363 | ||
364 | PROCEDURE PushFile (filename: ADDRESS) ; | |
365 | VAR | |
366 | l: SourceList ; | |
367 | BEGIN | |
368 | CheckIfNeedToDuplicate ; | |
369 | AddTo(NewElement(filename)) ; | |
370 | IF Debugging | |
371 | THEN | |
372 | IF CurrentSource^.right#CurrentSource | |
373 | THEN | |
374 | l := CurrentSource ; | |
375 | REPEAT | |
376 | printf2('name = %s, line = %d\n', l^.name, l^.line) ; | |
377 | l := l^.right | |
378 | UNTIL l=CurrentSource | |
379 | END | |
380 | END | |
381 | END PushFile ; | |
382 | ||
383 | ||
384 | (* | |
385 | PopFile - indicates that we are returning to, filename, having finished | |
386 | an include. | |
387 | *) | |
388 | ||
389 | PROCEDURE PopFile (filename: ADDRESS) ; | |
390 | VAR | |
391 | l: SourceList ; | |
392 | BEGIN | |
393 | CheckIfNeedToDuplicate ; | |
394 | IF (CurrentSource#NIL) AND (CurrentSource^.left#CurrentSource) | |
395 | THEN | |
396 | l := CurrentSource^.left ; (* last element *) | |
397 | SubFrom(l) ; | |
398 | DISPOSE(l) ; | |
399 | IF (CurrentSource^.left#CurrentSource) AND | |
400 | (NOT Equal(CurrentSource^.name, Mark(InitStringCharStar(filename)))) | |
401 | THEN | |
402 | (* mismatch in source file names after preprocessing files *) | |
403 | END | |
404 | ELSE | |
405 | (* source file list is empty, cannot pop an include.. *) | |
406 | END | |
407 | END PopFile ; | |
408 | ||
409 | ||
410 | (* | |
411 | KillList - kills the SourceList providing that it has not been used. | |
412 | *) | |
413 | ||
414 | PROCEDURE KillList ; | |
415 | VAR | |
416 | l, k: SourceList ; | |
417 | BEGIN | |
418 | IF (NOT CurrentUsed) AND (CurrentSource#NIL) | |
419 | THEN | |
420 | l := CurrentSource ; | |
421 | REPEAT | |
422 | k := l ; | |
423 | l := l^.right ; | |
424 | DISPOSE(k) | |
425 | UNTIL l=CurrentSource | |
426 | END | |
427 | END KillList ; | |
428 | ||
429 | ||
430 | (* | |
431 | ReInitialize - re-initialize the all the data structures. | |
432 | *) | |
433 | ||
434 | PROCEDURE ReInitialize ; | |
435 | VAR | |
436 | s, t: TokenBucket ; | |
437 | BEGIN | |
438 | IF ListOfTokens.head#NIL | |
439 | THEN | |
440 | t := ListOfTokens.head ; | |
441 | REPEAT | |
442 | s := t ; | |
443 | t := t^.next ; | |
444 | DISPOSE(s) ; | |
445 | UNTIL t=NIL ; | |
446 | CurrentUsed := FALSE ; | |
447 | KillList | |
448 | END ; | |
449 | Init | |
450 | END ReInitialize ; | |
451 | ||
452 | ||
453 | (* | |
454 | SetFile - sets the current filename to, filename. | |
455 | *) | |
456 | ||
457 | PROCEDURE SetFile (filename: ADDRESS) ; | |
458 | BEGIN | |
459 | KillList ; | |
460 | CurrentUsed := FALSE ; | |
461 | CurrentSource := NewList() ; | |
462 | AddTo(NewElement(filename)) | |
463 | END SetFile ; | |
464 | ||
465 | ||
466 | (* | |
467 | OpenSource - Attempts to open the source file, s. | |
468 | The success of the operation is returned. | |
469 | *) | |
470 | ||
471 | PROCEDURE OpenSource (s: String) : BOOLEAN ; | |
472 | BEGIN | |
473 | IF UseBufferedTokens | |
474 | THEN | |
475 | GetToken ; | |
476 | RETURN( TRUE ) | |
477 | ELSE | |
478 | IF cflex.OpenSource(string(s)) | |
479 | THEN | |
480 | SetFile(string(s)) ; | |
481 | SyncOpenWithBuffer ; | |
482 | GetToken ; | |
483 | RETURN( TRUE ) | |
484 | ELSE | |
485 | RETURN( FALSE ) | |
486 | END | |
487 | END | |
488 | END OpenSource ; | |
489 | ||
490 | ||
491 | (* | |
492 | CloseSource - closes the current open file. | |
493 | *) | |
494 | ||
495 | PROCEDURE CloseSource ; | |
496 | BEGIN | |
497 | IF UseBufferedTokens | |
498 | THEN | |
499 | WHILE currenttoken#eoftok DO | |
500 | GetToken | |
501 | END | |
502 | ELSE | |
503 | (* a subsequent call to cflex.OpenSource will really close the file *) | |
504 | END | |
505 | END CloseSource ; | |
506 | ||
507 | ||
508 | (* | |
509 | ResetForNewPass - reset the buffer pointers to the beginning ready for | |
510 | a new pass | |
511 | *) | |
512 | ||
513 | PROCEDURE ResetForNewPass ; | |
514 | BEGIN | |
515 | CurrentTokNo := 0 ; | |
516 | UseBufferedTokens := TRUE | |
517 | END ResetForNewPass ; | |
518 | ||
519 | ||
520 | (* | |
521 | DisplayToken - | |
522 | *) | |
523 | ||
524 | PROCEDURE DisplayToken ; | |
525 | VAR | |
526 | n: Name ; | |
527 | BEGIN | |
528 | cflex.CError(string(InitString('current token'))) ; | |
529 | IF currenttoken=identtok | |
530 | THEN | |
531 | n := makekey(currentstring) ; | |
532 | printf1('currenttoken = %a\n', n) | |
533 | ELSE | |
534 | CASE currenttoken OF | |
535 | ||
536 | eoftok : printf0('eoftok\n') | | |
537 | startok : printf0('*\n') | | |
538 | arrowtok : printf0('->\n') | | |
539 | structtok : printf0('struct\n') | | |
540 | lsbratok : printf0('[\n') | | |
541 | rsbratok : printf0(']\n') | | |
542 | lcbratok : printf0('{\n') | | |
543 | rcbratok : printf0('}\n') | | |
544 | lparatok : printf0('(\n') | | |
545 | rparatok : printf0(')\n') | | |
546 | semicolontok : printf0(';\n') | | |
547 | longtok : printf0('long\n') | | |
548 | inttok : printf0('int\n') | | |
549 | chartok : printf0('char\n') | | |
550 | enumtok : printf0('enum\n') | | |
551 | typedeftok : printf0('typedef\n') | | |
552 | floattok : printf0('float\n') | | |
553 | doubletok : printf0('double\n') | | |
554 | unsignedtok : printf0('unsigned\n') | | |
555 | consttok : printf0('const\n') | | |
556 | periodperiodperiodtok: printf0('...\n') | | |
557 | integertok : printf0('integer number\n') | | |
558 | hexintegertok : printf0('hexadecimal number\n') | | |
559 | octintegertok : printf0('octal number\n') | | |
560 | identtok : printf0('identifier\n') | | |
561 | realtok : printf0('real number\n') | | |
562 | conststringtok : printf0('constant string\n') | | |
563 | constchartok : printf0('constant char\n') | | |
564 | codetok : printf0('some C code\n') | | |
565 | starthashtok : printf0('start#\n') | | |
566 | endhashtok : printf0('end#\n') | | |
567 | definetok : printf0('define\n') | | |
568 | definedtok : stop ; printf0('defined\n') | | |
569 | undeftok : printf0('undef\n') | | |
570 | iftok : printf0('if\n') | | |
571 | elsetok : printf0('else\n') | | |
572 | endiftok : printf0('endif\n') | | |
573 | ifdeftok : printf0('ifdef\n') | | |
574 | ifndeftok : printf0('ifndef\n') | | |
575 | nottok : printf0('not\n') | | |
576 | includetok : printf0('include\n') | | |
577 | commatok : printf0('comma\n') | | |
578 | periodtok : printf0('period\n') | | |
579 | gretok : printf0('gre\n') | | |
580 | lesstok : printf0('less\n') | | |
581 | ortok : printf0('or\n') | | |
582 | andtok : printf0('and\n') | | |
583 | bartok : printf0('bar\n') | | |
584 | ambersandtok : printf0('ambersand\n') | | |
585 | shiftlefttok : printf0('shiftleft\n') | | |
586 | shiftrighttok : printf0('shiftright\n') | | |
587 | divtok : printf0('div\n') | | |
588 | modtok : printf0('mod\n') | | |
589 | sizeoftok : printf0('sizeof\n') | | |
590 | hattok : printf0('hat\n') | | |
591 | equaltok : printf0('equal\n') | | |
592 | notequaltok : printf0('notequal\n') | | |
593 | greequaltok : printf0('greequal\n') | | |
594 | lessequaltok : printf0('lessequal\n') | | |
595 | plustok : printf0('plus\n') | | |
596 | minustok : printf0('minus\n') | | |
597 | tildetok : printf0('tilde\n') | | |
598 | externtok : printf0('extern\n') | | |
599 | statictok : printf0('static\n') | | |
600 | autotok : printf0('auto\n') | | |
601 | registertok : printf0('register\n') | | |
602 | voidtok : printf0('void\n') | | |
603 | shorttok : printf0('short\n') | | |
604 | signedtok : printf0('signed\n') | | |
605 | uniontok : printf0('union\n') | | |
606 | colontok : printf0('colon\n') | | |
607 | becomestok : printf0('becomes\n') | | |
608 | volatiletok : printf0('volatile\n') | | |
609 | typetok : printf0('type\n') | |
610 | ||
611 | ELSE | |
612 | cflex.CError(string(InitString('unrecognised token'))) | |
613 | END | |
614 | END | |
615 | END DisplayToken ; | |
616 | ||
617 | ||
618 | (* | |
619 | GetToken - gets the next token into currenttoken. | |
620 | *) | |
621 | ||
622 | PROCEDURE GetToken ; | |
623 | VAR | |
624 | t: CARDINAL ; | |
625 | b: TokenBucket ; | |
626 | l: CARDINAL ; | |
627 | BEGIN | |
628 | IF UseBufferedTokens | |
629 | THEN | |
630 | t := CurrentTokNo ; | |
631 | b := FindTokenBucket(t) ; | |
632 | WITH b^.buf[t] DO | |
633 | currenttoken := token ; | |
634 | currentstring := KeyToCharStar(str) ; | |
635 | currentinteger := int ; | |
636 | IF Debugging | |
637 | THEN | |
638 | l := line | |
639 | END | |
640 | END ; | |
641 | IF Debugging | |
642 | THEN | |
643 | printf3('line %d (# %d %d) ', l, t, CurrentTokNo) ; | |
644 | DisplayToken | |
645 | END ; | |
646 | INC(CurrentTokNo) | |
647 | ELSE | |
648 | IF ListOfTokens.tail=NIL | |
649 | THEN | |
650 | cflex.AdvanceToken ; | |
651 | IF ListOfTokens.tail=NIL | |
652 | THEN | |
653 | HALT | |
654 | END | |
655 | END ; | |
656 | ||
657 | IF ListOfTokens.LastBucketOffset>CurrentTokNo | |
658 | THEN | |
659 | t := CurrentTokNo ; | |
660 | b := FindTokenBucket(t) ; | |
661 | WITH b^.buf[t] DO | |
662 | currenttoken := token ; | |
663 | currentstring := KeyToCharStar(str) ; | |
664 | currentinteger := int ; | |
665 | IF Debugging | |
666 | THEN | |
667 | l := line | |
668 | END | |
669 | END ; | |
670 | INC(CurrentTokNo) | |
671 | ELSE | |
672 | WITH ListOfTokens.tail^ DO | |
673 | IF CurrentTokNo-ListOfTokens.LastBucketOffset<len | |
674 | THEN | |
675 | WITH buf[CurrentTokNo-ListOfTokens.LastBucketOffset] DO | |
676 | currenttoken := token ; | |
677 | currentstring := KeyToCharStar(str) ; | |
678 | currentinteger := int | |
679 | END ; | |
680 | IF Debugging | |
681 | THEN | |
682 | (* printf1('# %d ', CurrentTokNo) ; *) | |
683 | DisplayToken | |
684 | END ; | |
685 | INC(CurrentTokNo) | |
686 | ELSE | |
687 | cflex.AdvanceToken ; | |
688 | GetToken ; | |
689 | (* printf0('\n'); cflex.CError(string(InitString('current token'))) ; *) | |
690 | END | |
691 | END | |
692 | END | |
693 | END | |
694 | END GetToken ; | |
695 | ||
696 | ||
697 | (* | |
698 | FlushTokens - removes the last token. | |
699 | *) | |
700 | ||
701 | PROCEDURE FlushTokens ; | |
702 | BEGIN | |
703 | INC(CurrentTokNo) | |
704 | END FlushTokens ; | |
705 | ||
706 | ||
707 | (* | |
708 | SyncOpenWithBuffer - synchronise the buffer with the start of a file. | |
709 | Skips all the tokens to do with the previous file. | |
710 | *) | |
711 | ||
712 | PROCEDURE SyncOpenWithBuffer ; | |
713 | BEGIN | |
714 | IF ListOfTokens.tail#NIL | |
715 | THEN | |
716 | WITH ListOfTokens.tail^ DO | |
717 | CurrentTokNo := ListOfTokens.LastBucketOffset+len | |
718 | END | |
719 | END | |
720 | END SyncOpenWithBuffer ; | |
721 | ||
722 | ||
723 | (* | |
724 | InsertToken - inserts a symbol, token, infront of the current token | |
725 | ready for the next pass. | |
726 | *) | |
727 | ||
728 | PROCEDURE InsertToken (token: toktype) ; | |
729 | BEGIN | |
730 | IF ListOfTokens.tail#NIL | |
731 | THEN | |
732 | WITH ListOfTokens.tail^ DO | |
733 | IF len>0 | |
734 | THEN | |
735 | buf[len-1].token := token | |
736 | END | |
737 | END ; | |
738 | AddTokToList(currenttoken, NulName, 0, GetLineNo(), CurrentSource) ; | |
739 | GetToken | |
740 | END | |
741 | END InsertToken ; | |
742 | ||
743 | ||
744 | (* | |
745 | InsertTokenAndRewind - inserts a symbol, token, infront of the current token | |
746 | and then moves the token stream back onto the inserted token. | |
747 | *) | |
748 | ||
749 | PROCEDURE InsertTokenAndRewind (token: toktype) ; | |
750 | BEGIN | |
751 | IF ListOfTokens.tail#NIL | |
752 | THEN | |
753 | WITH ListOfTokens.tail^ DO | |
754 | IF len>0 | |
755 | THEN | |
756 | buf[len-1].token := token | |
757 | END | |
758 | END ; | |
759 | AddTokToList(currenttoken, NulName, 0, GetLineNo(), CurrentSource) ; | |
760 | currenttoken := token | |
761 | END | |
762 | END InsertTokenAndRewind ; | |
763 | ||
764 | ||
765 | (* | |
766 | GetLineNo - returns the current line number where the symbol occurs in | |
767 | the source file. | |
768 | *) | |
769 | ||
770 | PROCEDURE GetLineNo () : CARDINAL ; | |
771 | BEGIN | |
772 | IF CurrentTokNo=0 | |
773 | THEN | |
774 | RETURN( 0 ) | |
775 | ELSE | |
776 | RETURN( TokenToLineNo(GetTokenNo(), 0) ) | |
777 | END | |
778 | END GetLineNo ; | |
779 | ||
780 | ||
781 | (* | |
782 | GetTokenNo - returns the current token number. | |
783 | *) | |
784 | ||
785 | PROCEDURE GetTokenNo () : CARDINAL ; | |
786 | BEGIN | |
787 | IF CurrentTokNo=0 | |
788 | THEN | |
789 | RETURN( 0 ) | |
790 | ELSE | |
791 | RETURN( CurrentTokNo-1 ) | |
792 | END | |
793 | END GetTokenNo ; | |
794 | ||
795 | ||
796 | (* | |
797 | FindTokenBucket - returns the TokenBucket corresponding to the TokenNo. | |
798 | *) | |
799 | ||
800 | PROCEDURE FindTokenBucket (VAR TokenNo: CARDINAL) : TokenBucket ; | |
801 | VAR | |
802 | b: TokenBucket ; | |
803 | BEGIN | |
804 | b := ListOfTokens.head ; | |
805 | WHILE b#NIL DO | |
806 | WITH b^ DO | |
807 | IF TokenNo<len | |
808 | THEN | |
809 | RETURN( b ) | |
810 | ELSE | |
811 | DEC(TokenNo, len) | |
812 | END | |
813 | END ; | |
814 | b := b^.next | |
815 | END ; | |
816 | RETURN( NIL ) | |
817 | END FindTokenBucket ; | |
818 | ||
819 | ||
820 | (* | |
821 | TokenToLineNo - returns the line number of the current file for the | |
822 | TokenNo. The depth refers to the include depth. | |
823 | A depth of 0 is the current file, depth of 1 is the file | |
824 | which included the current file. Zero is returned if the | |
825 | depth exceeds the file nesting level. | |
826 | *) | |
827 | ||
828 | PROCEDURE TokenToLineNo (TokenNo: CARDINAL; depth: CARDINAL) : CARDINAL ; | |
829 | VAR | |
830 | b: TokenBucket ; | |
831 | l: SourceList ; | |
832 | BEGIN | |
833 | b := FindTokenBucket(TokenNo) ; | |
834 | IF b=NIL | |
835 | THEN | |
836 | RETURN( 0 ) | |
837 | ELSE | |
838 | IF depth=0 | |
839 | THEN | |
840 | RETURN( b^.buf[TokenNo].line ) | |
841 | ELSE | |
842 | l := b^.buf[TokenNo].file^.left ; | |
843 | WHILE depth>0 DO | |
844 | l := l^.left ; | |
845 | IF l=b^.buf[TokenNo].file^.left | |
846 | THEN | |
847 | RETURN( 0 ) | |
848 | END ; | |
849 | DEC(depth) | |
850 | END ; | |
851 | RETURN( l^.line ) | |
852 | END | |
853 | END | |
854 | END TokenToLineNo ; | |
855 | ||
856 | ||
857 | (* | |
858 | FindFileNameFromToken - returns the complete FileName for the appropriate | |
859 | source file yields the token number, TokenNo. | |
860 | The, Depth, indicates the include level: 0..n | |
861 | Level 0 is the current. NIL is returned if n+1 | |
862 | is requested. | |
863 | *) | |
864 | ||
865 | PROCEDURE FindFileNameFromToken (TokenNo: CARDINAL; depth: CARDINAL) : String ; | |
866 | VAR | |
867 | b: TokenBucket ; | |
868 | l: SourceList ; | |
869 | BEGIN | |
870 | b := FindTokenBucket(TokenNo) ; | |
871 | IF b=NIL | |
872 | THEN | |
873 | RETURN( NIL ) | |
874 | ELSE | |
875 | l := b^.buf[TokenNo].file^.left ; | |
876 | WHILE depth>0 DO | |
877 | l := l^.left ; | |
878 | IF l=b^.buf[TokenNo].file^.left | |
879 | THEN | |
880 | RETURN( NIL ) | |
881 | END ; | |
882 | DEC(depth) | |
883 | END ; | |
884 | RETURN( l^.name ) | |
885 | END | |
886 | END FindFileNameFromToken ; | |
887 | ||
888 | ||
889 | (* | |
890 | GetFileName - returns a String defining the current file. | |
891 | *) | |
892 | ||
893 | PROCEDURE GetFileName () : String ; | |
894 | BEGIN | |
895 | RETURN( FindFileNameFromToken(GetTokenNo(), 0) ) | |
896 | END GetFileName ; | |
897 | ||
898 | ||
899 | (* | |
900 | AddTokToList - adds a token to a dynamic list. | |
901 | *) | |
902 | ||
903 | PROCEDURE AddTokToList (t: toktype; n: Name; | |
904 | i: INTEGER; l: CARDINAL; f: SourceList) ; | |
905 | BEGIN | |
906 | IF ListOfTokens.head=NIL | |
907 | THEN | |
908 | NEW(ListOfTokens.head) ; | |
909 | IF ListOfTokens.head=NIL | |
910 | THEN | |
911 | (* list error *) | |
912 | END ; | |
913 | ListOfTokens.tail := ListOfTokens.head ; | |
914 | ListOfTokens.tail^.len := 0 | |
915 | ELSIF ListOfTokens.tail^.len=MaxBucketSize | |
916 | THEN | |
917 | Assert(ListOfTokens.tail^.next=NIL) ; | |
918 | NEW(ListOfTokens.tail^.next) ; | |
919 | IF ListOfTokens.tail^.next=NIL | |
920 | THEN | |
921 | (* list error *) | |
922 | ELSE | |
923 | ListOfTokens.tail := ListOfTokens.tail^.next ; | |
924 | ListOfTokens.tail^.len := 0 | |
925 | END ; | |
926 | INC(ListOfTokens.LastBucketOffset, MaxBucketSize) | |
927 | END ; | |
928 | WITH ListOfTokens.tail^ DO | |
929 | next := NIL ; | |
930 | WITH buf[len] DO | |
931 | token := t ; | |
932 | str := n ; | |
933 | int := i ; | |
934 | line := l ; | |
935 | file := f | |
936 | END ; | |
937 | INC(len) | |
938 | END | |
939 | END AddTokToList ; | |
940 | ||
941 | ||
942 | (* | |
943 | IsLastTokenEof - returns TRUE if the last token was an eoftok | |
944 | *) | |
945 | ||
946 | PROCEDURE IsLastTokenEof () : BOOLEAN ; | |
947 | VAR | |
948 | b: TokenBucket ; | |
949 | BEGIN | |
950 | IF ListOfTokens.tail#NIL | |
951 | THEN | |
952 | IF ListOfTokens.tail^.len=0 | |
953 | THEN | |
954 | b := ListOfTokens.head ; | |
955 | IF b=ListOfTokens.tail | |
956 | THEN | |
957 | RETURN( FALSE ) | |
958 | END ; | |
959 | WHILE b^.next#ListOfTokens.tail DO | |
960 | b := b^.next | |
961 | END ; | |
962 | ELSE | |
963 | b := ListOfTokens.tail | |
964 | END ; | |
965 | WITH b^ DO | |
966 | RETURN( buf[len-1].token=eoftok ) | |
967 | END | |
968 | END ; | |
969 | RETURN( FALSE ) | |
970 | END IsLastTokenEof ; | |
971 | ||
972 | ||
973 | (* *********************************************************************** | |
974 | * | |
975 | * These functions allow c.flex to deliver tokens into the buffer | |
976 | * | |
977 | ************************************************************************* *) | |
978 | ||
979 | (* | |
980 | AddTok - adds a token to the buffer. | |
981 | *) | |
982 | ||
983 | PROCEDURE AddTok (t: toktype) ; | |
984 | BEGIN | |
985 | IF NOT ((t=eoftok) AND IsLastTokenEof()) | |
986 | THEN | |
987 | AddTokToList(t, NulName, 0, cflex.GetLineNo(), CurrentSource) ; | |
988 | CurrentUsed := TRUE | |
989 | END | |
990 | END AddTok ; | |
991 | ||
992 | ||
993 | (* | |
994 | AddTokCharStar - adds a token to the buffer and an additional string, s. | |
995 | A copy of string, s, is made. | |
996 | *) | |
997 | ||
998 | PROCEDURE AddTokCharStar (t: toktype; s: ADDRESS) ; | |
999 | BEGIN | |
1000 | IF (t=identtok) AND PushMacroDefinition(makekey(s)) | |
1001 | THEN | |
1002 | (* do nothing *) | |
1003 | ELSE | |
1004 | AddTokToList(t, makekey(s), 0, cflex.GetLineNo(), CurrentSource) ; | |
1005 | CurrentUsed := TRUE | |
1006 | END | |
1007 | END AddTokCharStar ; | |
1008 | ||
1009 | ||
1010 | (* | |
1011 | AddTokInteger - adds a token and an integer to the buffer. | |
1012 | *) | |
1013 | ||
1014 | PROCEDURE AddTokInteger (t: toktype; i: INTEGER) ; | |
1015 | VAR | |
1016 | s: String ; | |
1017 | lineno: CARDINAL ; | |
1018 | BEGIN | |
1019 | lineno := cflex.GetLineNo() ; | |
1020 | s := Sprintf1(Mark(InitString('%d')), lineno) ; | |
1021 | AddTokToList(t, makekey(string(s)), i, lineno, CurrentSource) ; | |
1022 | s := KillString(s) ; | |
1023 | CurrentUsed := TRUE | |
1024 | END AddTokInteger ; | |
1025 | ||
1026 | ||
1027 | BEGIN | |
1028 | Init | |
1029 | END CLexBuf. |