2
$Id: scanner.pas,v 1.1.2.5 2000/12/18 18:00:54 peter Exp $
3
Copyright (c) 1998-2000 by Florian Klaempfl
5
This unit implements the scanner part and handling of the switches
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 2 of the License, or
10
(at your option) any later version.
12
This program is distributed in the hope that it will be useful,
13
but WITHOUT ANY WARRANTY; without even the implied warranty of
14
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
GNU General Public License for more details.
17
You should have received a copy of the GNU General Public License
18
along with this program; if not, write to the Free Software
19
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21
****************************************************************************
37
globtype,version,tokens,
38
cobjects,globals,verbose,comphook,files;
46
preprocbufsize=32*1024;
52
tcommentstyle = (comment_none,comment_tp,comment_oldtp,comment_delphi,comment_c);
54
pmacrobuffer = ^tmacrobuffer;
55
tmacrobuffer = array[0..maxmacrolen-1] of char;
57
preproctyp = (pp_ifdef,pp_ifndef,pp_if,pp_ifopt,pp_else);
58
ppreprocstack = ^tpreprocstack;
59
tpreprocstack = object
65
constructor init(atyp:preproctyp;a:boolean;n:ppreprocstack);
69
pscannerfile = ^tscannerfile;
71
inputfile : pinputfile; { current inputfile list }
73
inputbuffer, { input buffer }
78
lastlinepos : longint;
80
lasttokenpos : longint; { token }
86
lastasmgetchar : char;
87
ignoredirectives : tstringcontainer; { ignore directives, used to give warnings only once }
88
preprocstack : ppreprocstack;
89
invalid : boolean; { flag if sourcefiles have been destroyed ! }
90
in_asm_string : boolean;
91
constructor init(const fn:string);
93
{ File buffer things }
94
function openinputfile:boolean;
95
procedure closeinputfile;
96
function tempopeninputfile:boolean;
97
procedure tempcloseinputfile;
98
procedure saveinputfile;
99
procedure restoreinputfile;
101
procedure addfile(hp:pinputfile);
103
procedure insertmacro(const macname:string;p:pchar;len:longint);
105
procedure gettokenpos;
106
procedure inc_comment_level;
107
procedure dec_comment_level;
108
procedure illegal_char(c:char);
109
procedure end_of_file;
110
procedure checkpreprocstack;
111
procedure poppreprocstack;
112
procedure addpreprocstack(atyp : preproctyp;a:boolean;const s:string;w:longint);
113
procedure elsepreprocstack;
116
procedure readstring;
117
procedure readnumber;
118
function readid:string;
119
function readval:longint;
120
function readcomment:string;
121
function readstate:char;
123
procedure skipuntildirective;
124
procedure skipcomment;
125
procedure skipdelphicomment;
126
procedure skipoldtpcomment;
128
function readpreproc:ttoken;
129
function asmgetchar:char;
132
ppreprocfile=^tpreprocfile;
138
constructor init(const fn:string);
140
procedure Add(const s:string);
149
current_scanner : pscannerfile;
150
aktcommentstyle : tcommentstyle; { needed to use read_comment from directives }
152
preprocfile : ppreprocfile; { used with only preprocessing }
161
systems,symtable,switches
166
{*****************************************************************************
168
*****************************************************************************}
171
{ use any special name that is an invalid file name to avoid problems }
172
preprocstring : array [preproctyp] of string[7]
173
= ('$IFDEF','$IFNDEF','$IF','$IFOPT','$ELSE');
176
function is_keyword(const s:string):boolean;
178
low,high,mid : longint;
180
if not (length(s) in [2..tokenidlen]) then
185
low:=ord(tokenidx^[length(s),s[1]].first);
186
high:=ord(tokenidx^[length(s),s[1]].last);
189
mid:=(high+low+1) shr 1;
190
if pattern<tokeninfo^[ttoken(mid)].str then
195
is_keyword:=(pattern=tokeninfo^[ttoken(high)].str) and
196
(tokeninfo^[ttoken(high)].keyword in aktmodeswitches);
200
{*****************************************************************************
201
Preprocessor writting
202
*****************************************************************************}
204
constructor tpreprocfile.init(const fn:string);
212
Comment(V_Fatal,'can''t create file '+fn);
213
getmem(buf,preprocbufsize);
214
settextbuf(f,buf^,preprocbufsize);
221
destructor tpreprocfile.done;
224
freemem(buf,preprocbufsize);
228
procedure tpreprocfile.add(const s:string);
233
procedure tpreprocfile.addspace;
250
{*****************************************************************************
252
*****************************************************************************}
254
constructor tpreprocstack.init(atyp : preproctyp;a:boolean;n:ppreprocstack);
262
destructor tpreprocstack.done;
267
{****************************************************************************
269
****************************************************************************}
271
constructor tscannerfile.init(const fn:string);
273
inputfile:=do_openinputfile(fn);
274
if assigned(current_module) then
275
current_module^.sourcefiles^.register_file(inputfile);
284
block_type:=bt_general;
291
ignoredirectives.init;
293
in_asm_string:=false;
295
if not openinputfile then
296
Message1(scan_f_cannot_open_input,fn);
298
{ process first read char }
307
destructor tscannerfile.done;
311
if status.errorcount=0 then
313
{ close file, but only if we are the first compile }
314
{ probably not necessary anymore with invalid flag PM }
315
if not current_module^.in_second_compile then
317
if not inputfile^.closed then
321
ignoredirectives.done;
325
function tscannerfile.openinputfile:boolean;
327
openinputfile:=inputfile^.open;
329
inputbuffer:=inputfile^.buf;
330
inputpointer:=inputfile^.buf;
331
inputstart:=inputfile^.bufstart;
339
procedure tscannerfile.closeinputfile;
353
function tscannerfile.tempopeninputfile:boolean;
355
tempopeninputfile:=inputfile^.tempopen;
357
inputbuffer:=inputfile^.buf;
358
inputpointer:=inputfile^.buf;
359
inputstart:=inputfile^.bufstart;
363
procedure tscannerfile.tempcloseinputfile;
365
inputfile^.setpos(inputstart+(inputpointer-inputbuffer));
366
inputfile^.tempclose;
374
procedure tscannerfile.saveinputfile;
376
inputfile^.saveinputpointer:=inputpointer;
377
inputfile^.savelastlinepos:=lastlinepos;
378
inputfile^.saveline_no:=line_no;
382
procedure tscannerfile.restoreinputfile;
384
inputpointer:=inputfile^.saveinputpointer;
385
lastlinepos:=inputfile^.savelastlinepos;
386
line_no:=inputfile^.saveline_no;
387
if not inputfile^.is_macro then
388
parser_current_file:=inputfile^.name^;
392
procedure tscannerfile.nextfile;
394
to_dispose : pinputfile;
396
if assigned(inputfile^.next) then
398
if inputfile^.is_macro then
399
to_dispose:=inputfile
402
{ we can allways close the file, no ? }
404
inputfile:=inputfile^.next;
405
if assigned(to_dispose) then
406
dispose(to_dispose,done);
412
procedure tscannerfile.addfile(hp:pinputfile);
418
{ load new inputfile }
423
procedure tscannerfile.reload;
427
{ when nothing more to read then leave immediatly, so we
428
don't change the aktfilepos and leave it point to the last
430
if (c=#26) and (not assigned(next)) then
433
{ still more to read?, then change the #0 to a space so its seen
434
as a seperator, this can't be used for macro's which can change
435
the place of the #0 in the buffer with tempopen }
436
if (c=#0) and (bufsize>0) and
437
not(inputfile^.is_macro) and
438
(inputpointer-inputbuffer<bufsize) then
441
inc(longint(inputpointer));
444
{ can we read more from this file ? }
445
if (c<>#26) and (not endoffile) then
450
inputstart:=bufstart;
455
if cs_asm_source in aktglobalswitches then
456
inputfile^.setline(line_no,bufstart);
461
{ load eof position in tokenpos/aktfilepos }
465
{ no next module, than EOF }
466
if not assigned(inputfile^.next) then
471
{ load next file and reopen it }
475
Message1(scan_t_back_in,inputfile^.name^);
479
inc(longint(inputpointer));
480
until c<>#0; { if also end, then reload again }
485
procedure tscannerfile.insertmacro(const macname:string;p:pchar;len:longint);
489
{ save old postion and decrease linebreak }
492
dec(longint(inputpointer));
494
{ create macro 'file' }
495
{ use special name to dispose after !! }
496
hp:=do_openinputfile('_Macro_.'+macname);
504
inputstart:=bufstart;
512
inc(longint(inputpointer));
516
procedure tscannerfile.gettokenpos;
517
{ load the values of tokenpos and lasttokenpos }
519
lasttokenpos:=inputstart+(inputpointer-inputbuffer);
520
tokenpos.line:=line_no;
521
tokenpos.column:=lasttokenpos-lastlinepos;
522
tokenpos.fileindex:=inputfile^.ref_index;
523
aktfilepos:=tokenpos;
527
procedure tscannerfile.inc_comment_level;
529
oldaktfilepos : tfileposinfo;
531
if (m_nested_comment in aktmodeswitches) then
535
if (comment_level>1) then
537
oldaktfilepos:=aktfilepos;
538
gettokenpos; { update for warning }
539
Message1(scan_w_comment_level,tostr(comment_level));
540
aktfilepos:=oldaktfilepos;
545
procedure tscannerfile.dec_comment_level;
547
if (m_nested_comment in aktmodeswitches) then
554
procedure tscannerfile.linebreak;
558
oldaktfilepos : tfileposinfo;
562
if (byte(inputpointer^)=0) and not(endoffile) then
566
if byte(cur)+byte(c)<>23 then
567
dec(longint(inputpointer));
571
{ Fix linebreak to be only newline (=#10) for all types of linebreaks }
572
if (byte(inputpointer^)+byte(c)=23) then
573
inc(longint(inputpointer));
576
{ increase line counters }
577
lastlinepos:=bufstart+(inputpointer-inputbuffer);
579
{ update linebuffer }
580
if cs_asm_source in aktglobalswitches then
581
inputfile^.setline(line_no,lastlinepos);
582
{ update for status and call the show status routine,
583
but don't touch aktfilepos ! }
584
oldaktfilepos:=aktfilepos;
585
oldtokenpos:=tokenpos;
586
gettokenpos; { update for v_status }
587
inc(status.compiledlines);
589
aktfilepos:=oldaktfilepos;
590
tokenpos:=oldtokenpos;
595
procedure tscannerfile.illegal_char(c:char);
599
if c in [#32..#255] then
602
s:='#'+tostr(ord(c));
603
Message2(scan_f_illegal_char,s,'$'+hexstr(ord(c),2));
607
procedure tscannerfile.end_of_file;
610
Message(scan_f_end_of_file);
614
procedure tscannerfile.checkpreprocstack;
616
{ check for missing ifdefs }
617
while assigned(preprocstack) do
619
Message3(scan_e_endif_expected,preprocstring[preprocstack^.typ],preprocstack^.name,tostr(preprocstack^.line_nb));
625
procedure tscannerfile.poppreprocstack;
629
if assigned(preprocstack) then
631
Message1(scan_c_endif_found,preprocstack^.name);
632
hp:=preprocstack^.next;
633
dispose(preprocstack,done);
637
Message(scan_e_endif_without_if);
641
procedure tscannerfile.addpreprocstack(atyp : preproctyp;a:boolean;const s:string;w:longint);
643
preprocstack:=new(ppreprocstack,init(atyp,((preprocstack=nil) or preprocstack^.accept) and a,preprocstack));
644
preprocstack^.name:=s;
645
preprocstack^.line_nb:=line_no;
646
if preprocstack^.accept then
647
Message2(w,preprocstack^.name,'accepted')
649
Message2(w,preprocstack^.name,'rejected');
653
procedure tscannerfile.elsepreprocstack;
655
if assigned(preprocstack) then
657
preprocstack^.typ:=pp_else;
658
preprocstack^.line_nb:=line_no;
659
if not(assigned(preprocstack^.next)) or (preprocstack^.next^.accept) then
660
preprocstack^.accept:=not preprocstack^.accept;
661
if preprocstack^.accept then
662
Message2(scan_c_else_found,preprocstack^.name,'accepted')
664
Message2(scan_c_else_found,preprocstack^.name,'rejected');
667
Message(scan_e_endif_without_if);
671
procedure tscannerfile.readchar;
677
inc(longint(inputpointer));
686
procedure tscannerfile.readstring;
703
inc(longint(inputpointer));
710
pattern[i]:=chr(ord(c)-32)
713
inc(longint(inputpointer));
731
setlength(orgpattern,i);
732
setlength(pattern,i);
734
orgpattern[0]:=chr(i);
738
orgpattern[0]:=chr(i);
744
procedure tscannerfile.readnumber;
768
while ((base>=10) and (c in ['0'..'9'])) or
769
((base=16) and (c in ['A'..'F','a'..'f'])) or
770
((base=2) and (c in ['0'..'1'])) do
782
inc(longint(inputpointer));
784
{ was the next char a linebreak ? }
792
setlength(pattern,i);
802
function tscannerfile.readid:string;
809
function tscannerfile.readval:longint;
820
function tscannerfile.readcomment:string;
828
if aktcommentstyle=comment_tp then
831
if aktcommentstyle=comment_tp then
835
if comment_level=0 then
841
if aktcommentstyle=comment_oldtp then
851
{ Add both characters !!}
864
{ Not old TP comment, so add...}
887
inc(longint(inputpointer));
888
if c in [#10,#13] then
893
setlength(readcomment,i);
895
readcomment[0]:=chr(i);
898
readcomment[0]:=chr(i);
903
function tscannerfile.readstate:char;
910
current_scanner^.skipspace;
911
current_scanner^.readid;
915
if pattern='OFF' then
920
if not (state in ['+','-']) then
921
Message(scan_e_wrong_switch_toggle);
926
procedure tscannerfile.skipspace;
928
while c in [' ',#9..#13] do
934
inc(longint(inputpointer));
946
procedure tscannerfile.skipuntildirective;
950
next_char_loaded : boolean;
951
oldcommentstyle : tcommentstyle;
954
next_char_loaded:=false;
956
oldcommentstyle:=aktcommentstyle;
963
if not(m_nested_comment in aktmodeswitches) or
964
(comment_level=0) then
967
aktcommentstyle:=comment_tp;
984
if not incomment then
998
next_char_loaded:=true;
1015
aktcommentstyle:=comment_oldtp;
1020
aktcommentstyle:=oldcommentstyle;
1024
next_char_loaded:=true;
1029
if next_char_loaded then
1030
next_char_loaded:=false
1037
inc(longint(inputpointer));
1048
{****************************************************************************
1049
Include directive scanning/parsing
1050
****************************************************************************}
1055
{****************************************************************************
1057
****************************************************************************}
1059
procedure tscannerfile.skipcomment;
1061
aktcommentstyle:=comment_tp;
1064
{ handle compiler switches }
1067
{ handle_switches can dec comment_level, }
1068
while (comment_level>0) do
1071
'{' : inc_comment_level;
1072
'}' : dec_comment_level;
1079
inc(longint(inputpointer));
1086
aktcommentstyle:=comment_none;
1090
procedure tscannerfile.skipdelphicomment;
1092
aktcommentstyle:=comment_delphi;
1095
{ this is currently not supported }
1097
Message(scan_e_wrong_styled_switch);
1106
aktcommentstyle:=comment_none;
1110
procedure tscannerfile.skipoldtpcomment;
1114
aktcommentstyle:=comment_oldtp;
1117
{ this is currently not supported }
1121
while (comment_level>0) do
1137
if found in [1,4] then
1140
if comment_level=0 then
1163
inc(longint(inputpointer));
1171
aktcommentstyle:=comment_none;
1176
{****************************************************************************
1178
****************************************************************************}
1180
procedure tscannerfile.readtoken;
1183
low,high,mid : longint;
1186
asciinr : string[6];
1190
if localswitcheschanged then
1192
aktlocalswitches:=nextaktlocalswitches;
1193
localswitcheschanged:=false;
1195
{ was there already a token read, then return that token }
1196
if nexttoken<>NOTOKEN then
1203
{ Skip all spaces and comments }
1210
if parapreprocess then
1213
preprocfile^.eolfound:=true
1215
preprocfile^.spacefound:=true;
1224
{ Save current token position, for EOF its already loaded }
1228
{ Check first for a identifier/keyword, this is 20+% faster (PFV) }
1229
if c in ['A'..'Z','a'..'z','_'] then
1234
{ keyword or any other known token,
1235
pattern is always uppercased }
1236
if (pattern[1]<>'_') and (length(pattern) in [2..tokenidlen]) then
1238
low:=ord(tokenidx^[length(pattern),pattern[1]].first);
1239
high:=ord(tokenidx^[length(pattern),pattern[1]].last);
1242
mid:=(high+low+1) shr 1;
1243
if pattern<tokeninfo^[ttoken(mid)].str then
1248
if pattern=tokeninfo^[ttoken(high)].str then
1250
if tokeninfo^[ttoken(high)].keyword in aktmodeswitches then
1251
if tokeninfo^[ttoken(high)].op=NOTOKEN then
1254
token:=tokeninfo^[ttoken(high)].op;
1255
idtoken:=ttoken(high);
1258
{ Only process identifiers and not keywords }
1261
{ this takes some time ... }
1262
if (cs_support_macro in aktmoduleswitches) then
1264
mac:=pmacrosym(macros^.search(pattern));
1265
if assigned(mac) and (assigned(mac^.buftext)) then
1267
insertmacro(pattern,mac^.buftext,mac^.buflen);
1268
{ handle empty macros }
1278
{ play it again ... }
1280
if yylexcount>16 then
1281
Message(scan_w_macro_deep_ten);
1283
{ that's all folks }
1306
if (m_tp in aktmodeswitches) then
1319
if (c in ['.','e','E']) then
1321
{ first check for a . }
1325
{ is it a .. from a range? }
1331
nexttoken:=_POINTPOINT;
1338
nexttoken:=_RECKKLAMMER;
1342
{ insert the number after the . }
1343
pattern:=pattern+'.';
1344
while c in ['0'..'9'] do
1350
{ E can also follow after a point is scanned }
1351
if c in ['e','E'] then
1353
pattern:=pattern+'E';
1355
if c in ['-','+'] then
1360
if not(c in ['0'..'9']) then
1362
while c in ['0'..'9'] do
1385
token:=_LECKKLAMMER;
1392
token:=_RECKKLAMMER;
1409
token:=_LECKKLAMMER;
1427
if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
1440
if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
1466
if (c='=') and (cs_support_c_operators in aktmoduleswitches) then
1488
if (cs_support_c_operators in aktmoduleswitches) then
1526
token:=_RECKKLAMMER;
1543
token:=_KLAMMERAFFE;
1560
if (block_type=bt_type) or
1562
(lasttoken=_RKLAMMER) or (lasttoken=_RECKKLAMMER) or (lasttoken=_CARET) then
1570
pattern:=chr(ord(c)+64)
1572
pattern:=chr(ord(c)-64);
1582
readchar; { read # }
1585
readchar; { read leading $ }
1587
while (upcase(c) in ['A'..'F','0'..'9']) and (length(asciinr)<6) do
1596
while (c in ['0'..'9']) and (length(asciinr)<6) do
1602
valint(asciinr,m,code);
1603
if (asciinr='') or (code<>0) or
1604
(m<0) or (m>255) then
1605
Message(scan_e_illegal_char_const);
1606
pattern:=pattern+chr(m);
1616
Message(scan_f_string_exceeds_line);
1642
{ strings with length 1 become const chars }
1643
if length(pattern)=1 then
1667
begin { >< is for a symetric diff for sets }
1719
function tscannerfile.readpreproc:ttoken;
1725
'_','0'..'9' : begin
1734
readpreproc:=_LKLAMMER;
1738
readpreproc:=_RKLAMMER;
1746
readpreproc:=_MINUS;
1754
readpreproc:=_SLASH;
1758
readpreproc:=_EQUAL;
1775
readpreproc:=_UNEQUAL;
1781
else readpreproc:=_LT;
1795
function tscannerfile.asmgetchar : char;
1797
if lastasmgetchar<>#0 then
1804
if in_asm_string then
1852
$Log: scanner.pas,v $
1853
Revision 1.1.2.5 2000/12/18 18:00:54 peter
1854
* skipuntildirective fix
1856
Revision 1.1.2.4 2000/12/16 15:30:12 peter
1857
* fixed parsing of comments in string with skipuntildirective
1859
Revision 1.1.2.3 2000/11/30 00:33:34 pierre
1860
* fix for web bug 1229
1862
Revision 1.1.2.2 2000/08/12 15:29:52 peter
1863
* patch from Gabor for IDE to support memory stream reading
1865
Revision 1.1.2.1 2000/08/08 19:19:11 peter
1866
* only report illegal directives once
1868
Revision 1.1 2000/07/13 06:29:56 michael
1871
Revision 1.116 2000/07/08 18:03:11 peter
1872
* undid my previous commit, because it breaks some code
1874
Revision 1.115 2000/07/08 16:22:30 peter
1875
* also support string parsing in skipuntildirective for fpc modes
1877
Revision 1.114 2000/06/30 20:23:38 peter
1878
* new message files layout with msg numbers (but still no code to
1879
show the number on the screen)
1881
Revision 1.113 2000/06/18 18:05:54 peter
1882
* no binary value reading with % if not fpc mode
1883
* extended illegal char message with the char itself (Delphi like)
1885
Revision 1.112 2000/06/09 21:35:37 peter
1886
* fixed parsing of $if preproc function
1888
Revision 1.111 2000/05/03 14:36:58 pierre
1889
* fix for tests/test/testrang.pp bug
1891
Revision 1.110 2000/04/08 20:18:53 michael
1892
* Fixed bug in readcomment that was dropping * characters
1894
Revision 1.109 2000/03/13 21:21:57 peter
1895
* ^m support also after a string
1897
Revision 1.108 2000/03/12 17:53:16 florian
1898
* very small change to scanner ...
1900
Revision 1.107 2000/02/29 23:59:47 pierre
1903
Revision 1.106 2000/02/28 17:23:57 daniel
1904
* Current work of symtable integration committed. The symtable can be
1905
activated by defining 'newst', but doesn't compile yet. Changes in type
1906
checking and oop are completed. What is left is to write a new
1907
symtablestack and adapt the parser to use it.
1909
Revision 1.105 2000/02/09 13:23:03 peter
1912
Revision 1.104 2000/01/30 19:28:25 peter
1913
* fixed filepos when eof is read, it'll now stay on the eof position
1915
Revision 1.103 2000/01/07 01:14:38 peter
1916
* updated copyright to 2000
1918
Revision 1.102 1999/12/02 17:34:34 peter
1919
* preprocessor support. But it fails on the caret in type blocks
1921
Revision 1.101 1999/11/15 17:52:59 pierre
1922
+ one field added for ttoken record for operator
1923
linking the id to the corresponding operator token that
1924
can now now all be overloaded
1925
* overloaded operators are resetted to nil in InitSymtable
1926
(bug when trying to compile a uint that overloads operators twice)
1928
Revision 1.100 1999/11/06 14:34:26 peter
1929
* truncated log to 20 revs
1931
Revision 1.99 1999/11/03 23:44:28 peter
1932
* fixed comment level counting after directive
1934
Revision 1.98 1999/11/02 15:05:08 peter
1935
* fixed oldtp comment parsing
1937
Revision 1.97 1999/10/30 12:32:30 peter
1938
* fixed line counter when the first line had #10 only. This was buggy
1939
for both the main file as for include files
1941
Revision 1.96 1999/09/27 23:40:10 peter
1942
* fixed macro within macro endless-loop
1944
Revision 1.95 1999/09/03 10:02:48 peter
1945
* $IFNDEF is 7 chars and not 6 chars
1947
Revision 1.94 1999/09/02 18:47:47 daniel
1948
* Could not compile with TP, some arrays moved to heap
1949
* NOAG386BIN default for TP
1950
* AG386* files were not compatible with TP, fixed.
1952
Revision 1.93 1999/08/30 10:17:58 peter
1953
* fixed crash in psub
1954
* ansistringcompare fixed
1957
Revision 1.92 1999/08/06 13:11:44 michael
1958
* Removed C style comments.
1960
Revision 1.91 1999/08/05 16:53:11 peter
1961
* V_Fatal=1, all other V_ are also increased
1962
* Check for local procedure when assigning procvar
1963
* fixed comment parsing because directives
1964
* oldtp mode directives better supported
1965
* added some messages to errore.msg
1967
Revision 1.90 1999/08/04 13:03:05 jonas
1968
* all tokens now start with an underscore
1969
* PowerPC compiles!!
1971
Revision 1.89 1999/07/29 11:43:22 peter
1972
* always output preprocstack when unexpected eof is found
1973
* fixed tp7/delphi skipuntildirective parsing
1975
Revision 1.88 1999/07/24 11:20:59 peter
1976
* directives are allowed in (* *)
1977
* fixed parsing of (* between conditional code