scanner.pas 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445
  1. {
  2. $Id$
  3. Copyright (c) 1993,97 by Florian Klaempfl
  4. This unit implements the scanner part and handling of the switches
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$ifdef tp}
  19. {$F+,N+,E+,R-}
  20. {$endif}
  21. unit scanner;
  22. interface
  23. uses
  24. cobjects,globals,files;
  25. const
  26. {$ifdef TP}
  27. maxmacrolen = 1024;
  28. {$else}
  29. maxmacrolen = 16*1024;
  30. {$endif}
  31. id_len = 14;
  32. Newline = #10;
  33. type
  34. ident = string[id_len];
  35. const
  36. max_keywords = 69;
  37. anz_keywords : longint = max_keywords;
  38. { the following keywords are no keywords in TP, they
  39. are internal procedures
  40. CONTINUE, DISPOSE, EXIT, FAIL, FALSE, NEW, SELF
  41. TRUE
  42. }
  43. { INLINE is a keyword in TP, but only an modifier in FPC }
  44. keyword : array[1..max_keywords] of ident = (
  45. { 'ABSOLUTE',}
  46. 'AND',
  47. 'ARRAY','AS','ASM',
  48. { 'ASSEMBLER',}
  49. 'BEGIN',
  50. 'CASE','CLASS',
  51. 'CONST','CONSTRUCTOR',
  52. 'DESTRUCTOR','DISPOSE','DIV','DO','DOWNTO','ELSE','END',
  53. 'EXCEPT',
  54. 'EXIT',
  55. { 'EXPORT',}
  56. 'EXPORTS',
  57. { 'EXTERNAL',}
  58. 'FAIL','FALSE',
  59. { 'FAR',}
  60. 'FILE','FINALLY','FOR',
  61. { 'FORWARD',}
  62. 'FUNCTION','GOTO','IF','IMPLEMENTATION','IN',
  63. 'INHERITED','INITIALIZATION',
  64. { 'INLINE',} {INLINE is a reserved word in TP. Why?}
  65. 'INTERFACE',
  66. { 'INTERRUPT',}
  67. 'IS',
  68. 'LABEL','LIBRARY','MOD',
  69. { 'NEAR',}
  70. 'NEW','NIL','NOT','OBJECT',
  71. 'OF','ON','OPERATOR','OR','OTHERWISE','PACKED',
  72. 'PROCEDURE','PROGRAM','PROPERTY',
  73. 'RAISE','RECORD','REPEAT','SELF',
  74. 'SET','SHL','SHR','STRING','THEN','TO',
  75. 'TRUE','TRY','TYPE','UNIT','UNTIL',
  76. 'USES','VAR',
  77. { 'VIRTUAL',}
  78. 'WHILE','WITH','XOR');
  79. keyword_token : array[1..max_keywords] of ttoken = (
  80. { _ABSOLUTE,}
  81. _AND,
  82. _ARRAY,_AS,_ASM,
  83. { _ASSEMBLER,}
  84. _BEGIN,
  85. _CASE,_CLASS,
  86. _CONST,_CONSTRUCTOR,
  87. _DESTRUCTOR,_DISPOSE,_DIV,_DO,_DOWNTO,
  88. _ELSE,_END,_EXCEPT,
  89. _EXIT,
  90. { _EXPORT,}
  91. _EXPORTS,
  92. { _EXTERNAL,}
  93. _FAIL,_FALSE,
  94. { _FAR,}
  95. _FILE,_FINALLY,_FOR,
  96. { _FORWARD,}
  97. _FUNCTION,_GOTO,_IF,_IMPLEMENTATION,_IN,
  98. _INHERITED,_INITIALIZATION,
  99. { _INLINE,}
  100. _INTERFACE,
  101. { _INTERRUPT,}
  102. _IS,
  103. _LABEL,_LIBRARY,_MOD,
  104. { _NEAR,}
  105. _NEW,_NIL,_NOT,_OBJECT,
  106. _OF,_ON,_OPERATOR,_OR,_OTHERWISE,_PACKED,
  107. _PROCEDURE,_PROGRAM,_PROPERTY,
  108. _RAISE,_RECORD,_REPEAT,_SELF,
  109. _SET,_SHL,_SHR,_STRING,_THEN,_TO,
  110. _TRUE,_TRY,_TYPE,_UNIT,_UNTIL,
  111. _USES,_VAR,
  112. { _VIRTUAL,}
  113. _WHILE,_WITH,_XOR);
  114. type
  115. pmacrobuffer = ^tmacrobuffer;
  116. tmacrobuffer = array[0..maxmacrolen-1] of char;
  117. ppreprocstack = ^tpreprocstack;
  118. tpreprocstack = object
  119. isifdef,
  120. accept : boolean;
  121. next : ppreprocstack;
  122. name : stringid;
  123. line_nb : longint;
  124. constructor init(ifdef,a:boolean;n:ppreprocstack);
  125. destructor done;
  126. end;
  127. var
  128. c : char;
  129. orgpattern,
  130. pattern : string;
  131. macrobuffer : ^tmacrobuffer;
  132. comment_level : word;
  133. inputbuffer : pchar;
  134. inputpointer : pchar;
  135. parse_types, { true, if type declarations are parsed }
  136. s_point : boolean;
  137. yylexcount,
  138. macropos,
  139. lastlinepos,
  140. lasttokenpos : longint;
  141. lastasmgetchar : char;
  142. preprocstack : ppreprocstack;
  143. {$ifdef UseTokenInfo}
  144. { type
  145. ttokeninfo = record
  146. token : ttoken;
  147. fi : tfileposinfo;
  148. end;
  149. ptokeninfo = ^ttokeninfo; }
  150. var tokenpos : tfileposinfo;
  151. {$endif UseTokenInfo}
  152. {public}
  153. procedure syntaxerror(const s : string);
  154. function yylex : ttoken;
  155. function asmgetchar : char;
  156. function get_current_col : longint;
  157. procedure get_cur_file_pos(var fileinfo : tfileposinfo);
  158. procedure set_cur_file_pos(const fileinfo : tfileposinfo);
  159. procedure InitScanner(const fn: string);
  160. procedure DoneScanner(testendif:boolean);
  161. { changes to keywords to be tp compatible }
  162. procedure change_to_tp_keywords;
  163. implementation
  164. uses
  165. dos,verbose,pbase,
  166. symtable,switches;
  167. var
  168. { this is usefull to get the write filename
  169. for the last instruction of an include file !}
  170. FileHasChanged : Boolean;
  171. status : tcompilestatus;
  172. {*****************************************************************************
  173. TPreProcStack
  174. *****************************************************************************}
  175. constructor tpreprocstack.init(ifdef,a:boolean;n:ppreprocstack);
  176. begin
  177. isifdef:=ifdef;
  178. accept:=a;
  179. next:=n;
  180. end;
  181. destructor tpreprocstack.done;
  182. begin
  183. end;
  184. procedure popstack;
  185. var
  186. hp : ppreprocstack;
  187. begin
  188. hp:=preprocstack^.next;
  189. dispose(preprocstack,done);
  190. preprocstack:=hp;
  191. end;
  192. {*****************************************************************************
  193. Helper routines
  194. *****************************************************************************}
  195. function is_keyword(var token : ttoken) : boolean;
  196. var
  197. high,low,mid : longint;
  198. begin
  199. low:=1;
  200. high:=anz_keywords;
  201. while low<high do
  202. begin
  203. mid:=(high+low+1) shr 1;
  204. if pattern<keyword[mid] then
  205. high:=mid-1
  206. else
  207. low:=mid;
  208. end;
  209. if pattern=keyword[high] then
  210. begin
  211. token:=keyword_token[high];
  212. is_keyword:=true;
  213. end
  214. else
  215. is_keyword:=false;
  216. end;
  217. procedure remove_keyword(const s : string);
  218. var
  219. i,j : longint;
  220. begin
  221. for i:=1 to anz_keywords do
  222. begin
  223. if keyword[i]=s then
  224. begin
  225. for j:=i to anz_keywords-1 do
  226. begin
  227. keyword[j]:=keyword[j+1];
  228. keyword_token[j]:=keyword_token[j+1];
  229. end;
  230. dec(anz_keywords);
  231. break;
  232. end;
  233. end;
  234. end;
  235. function get_current_col : longint;
  236. begin
  237. if lastlinepos<=lasttokenpos then
  238. get_current_col:=lasttokenpos-lastlinepos
  239. else
  240. get_current_col:=0;
  241. end;
  242. procedure inc_comment_level;
  243. begin
  244. inc(comment_level);
  245. if (comment_level>1) then
  246. Message1(scan_w_comment_level,tostr(comment_level));
  247. end;
  248. procedure dec_comment_level;
  249. begin
  250. if cs_tp_compatible in aktswitches then
  251. comment_level:=0
  252. else
  253. dec(comment_level);
  254. end;
  255. procedure syntaxerror(const s : string);
  256. begin
  257. Message2(scan_f_syn_expected,tostr(get_current_col),s);
  258. end;
  259. {*****************************************************************************
  260. Scanner
  261. *****************************************************************************}
  262. procedure reload;
  263. var
  264. readsize : word;
  265. i,saveline : longint;
  266. begin
  267. if not assigned(current_module^.current_inputfile) then
  268. internalerror(14);
  269. if current_module^.current_inputfile^.filenotatend then
  270. begin
  271. { load the next piece of source }
  272. blockread(current_module^.current_inputfile^.f,inputbuffer^,
  273. current_module^.current_inputfile^.bufsize-1,readsize);
  274. { Scan the buffer for #0 chars, which are not alllowed }
  275. if readsize > 0 then
  276. begin
  277. { force proper line counting }
  278. saveline:=current_module^.current_inputfile^.line_no;
  279. i:=0;
  280. inputpointer:=inputbuffer;
  281. while i<readsize do
  282. begin
  283. c:=inputpointer^;
  284. case c of
  285. #0 : Message(scan_f_illegal_char);
  286. #10,#13 : begin
  287. if (byte(c)+byte(inputpointer[1])=23) then
  288. begin
  289. inc(longint(inputpointer));
  290. inc(i);
  291. end;
  292. inc(current_module^.current_inputfile^.line_no);
  293. end;
  294. end;
  295. inc(i);
  296. inc(longint(inputpointer));
  297. end;
  298. current_module^.current_inputfile^.line_no:=saveline;
  299. end;
  300. inputbuffer[readsize]:=#0;
  301. inputpointer:=inputbuffer;
  302. { Set EOF when main source and at endoffile }
  303. if eof(current_module^.current_inputfile^.f) then
  304. begin
  305. current_module^.current_inputfile^.filenotatend:=false;
  306. if current_module^.current_inputfile^.next=nil then
  307. inputbuffer[readsize]:=#26;
  308. end;
  309. end
  310. else
  311. begin
  312. current_module^.current_inputfile^.close;
  313. { load next module }
  314. current_module^.current_inputfile:=current_module^.current_inputfile^.next;
  315. current_module^.current_index:=current_module^.current_inputfile^.ref_index;
  316. status.currentsource:=current_module^.current_inputfile^.name^+current_module^.current_inputfile^.ext^;
  317. inputbuffer:=current_module^.current_inputfile^.buf;
  318. inputpointer:=inputbuffer+current_module^.current_inputfile^.bufpos;
  319. end;
  320. { load next char }
  321. c:=inputpointer^;
  322. inc(longint(inputpointer));
  323. end;
  324. procedure linebreak;
  325. var
  326. cur : char;
  327. begin
  328. cur:=c;
  329. if (byte(inputpointer^)=0) and
  330. current_module^.current_inputfile^.filenotatend then
  331. begin
  332. reload;
  333. if byte(cur)+byte(c)<>23 then
  334. dec(longint(inputpointer));
  335. end
  336. else
  337. { Fix linebreak to be only newline (=#10) for all types of linebreaks }
  338. if (byte(inputpointer^)+byte(c)=23) then
  339. inc(longint(inputpointer));
  340. c:=newline;
  341. { Update Status and show status }
  342. with status do
  343. begin
  344. totalcompiledlines:=abslines;
  345. currentline:=current_module^.current_inputfile^.line_no
  346. +current_module^.current_inputfile^.line_count;
  347. { you call strcopy here at each line !!! }
  348. {currentsource:=current_module^.current_inputfile^.name^+current_module^.current_inputfile^.ext^;}
  349. totallines:=0;
  350. end;
  351. if compilestatusproc(status) then
  352. stop;
  353. inc(current_module^.current_inputfile^.line_no);
  354. inc(abslines);
  355. lastlinepos:=longint(inputpointer);
  356. end;
  357. procedure readchar;
  358. begin
  359. c:=inputpointer^;
  360. if c=#0 then
  361. reload
  362. else
  363. inc(longint(inputpointer));
  364. if c in [#10,#13] then
  365. linebreak;
  366. end;
  367. function readstring:string;
  368. var
  369. i : longint;
  370. begin
  371. i:=0;
  372. { 'in []' splitted, so it will be CMP's and no SET_IN_BYTE (PFV) }
  373. while (c in ['A'..'Z','a'..'z']) or (c in ['0'..'9','_']) do
  374. begin
  375. if i<255 then
  376. begin
  377. inc(i);
  378. readstring[i]:=c;
  379. end;
  380. { get next char }
  381. readchar;
  382. end;
  383. readstring[0]:=chr(i);
  384. end;
  385. function readid:string;
  386. begin
  387. readid:=upper(readstring);
  388. end;
  389. function readnumber:string;
  390. var
  391. base,
  392. i : longint;
  393. begin
  394. case c of
  395. '%' : begin
  396. readchar;
  397. base:=2;
  398. readnumber[1]:='%';
  399. i:=1;
  400. end;
  401. '$' : begin
  402. readchar;
  403. base:=16;
  404. readnumber[1]:='$';
  405. i:=1;
  406. end;
  407. else
  408. begin
  409. base:=10;
  410. i:=0;
  411. end;
  412. end;
  413. while ((base>=10) and (c in ['0'..'9'])) or
  414. ((base=16) and (c in ['A'..'F','a'..'f'])) or
  415. ((base=2) and (c in ['0'..'1'])) do
  416. begin
  417. if i<255 then
  418. begin
  419. inc(i);
  420. readnumber[i]:=c;
  421. end;
  422. { get next char }
  423. readchar;
  424. end;
  425. readnumber[0]:=chr(i);
  426. { was the next char a linebreak ? }
  427. { if c in [#10,#13] then
  428. linebreak; }
  429. end;
  430. function readval:longint;
  431. var
  432. l : longint;
  433. w : word;
  434. begin
  435. val(readnumber,l,w);
  436. readval:=l;
  437. end;
  438. function readcomment:string;
  439. var
  440. i : longint;
  441. begin
  442. i:=0;
  443. repeat
  444. case c of
  445. '}' : begin
  446. readchar;
  447. dec_comment_level;
  448. break;
  449. end;
  450. #26 : Message(scan_f_end_of_file);
  451. else
  452. begin
  453. if (i<255) then
  454. begin
  455. inc(i);
  456. readcomment[i]:=c;
  457. end;
  458. end;
  459. end;
  460. readchar;
  461. until false;
  462. readcomment[0]:=chr(i);
  463. end;
  464. procedure skipspace;
  465. begin
  466. while c in [' ',#9..#13] do
  467. begin
  468. readchar;
  469. {c:=inputpointer^;
  470. if c=#0 then
  471. reload
  472. else
  473. inc(longint(inputpointer));
  474. if c in [#10,#13] then
  475. linebreak; }
  476. end;
  477. end;
  478. procedure skipuntildirective;
  479. var
  480. found : longint;
  481. begin
  482. found:=0;
  483. repeat
  484. case c of
  485. #26 : Message(scan_f_end_of_file);
  486. '{' : begin
  487. if comment_level=0 then
  488. found:=1;
  489. inc_comment_level;
  490. end;
  491. '}' : begin
  492. dec_comment_level;
  493. found:=0;
  494. end;
  495. '$' : begin
  496. if found=1 then
  497. found:=2;
  498. end;
  499. else
  500. found:=0;
  501. end;
  502. readchar;
  503. {c:=inputpointer^;
  504. if c=#0 then
  505. reload
  506. else
  507. inc(longint(inputpointer));}
  508. until (found=2);
  509. end;
  510. {$i scandir.inc}
  511. procedure skipcomment;
  512. begin
  513. readchar;
  514. inc_comment_level;
  515. { handle compiler switches }
  516. if (c='$') then
  517. handledirectives;
  518. { handle_switches can dec comment_level, }
  519. while (comment_level>0) do
  520. begin
  521. case c of
  522. '{' : inc_comment_level;
  523. '}' : dec_comment_level;
  524. #26 : Message(scan_f_end_of_file);
  525. end;
  526. readchar;
  527. {c:=inputpointer^;
  528. if c=#0 then
  529. reload
  530. else
  531. inc(longint(inputpointer));}
  532. end;
  533. {if (c=#10) or (c=#13) then linebreak;}
  534. end;
  535. procedure skipdelphicomment;
  536. begin
  537. inc_comment_level;
  538. readchar;
  539. { this is currently not supported }
  540. if c='$' then
  541. Message(scan_e_wrong_styled_switch);
  542. { skip comment }
  543. while c<>newline do
  544. begin
  545. if c=#26 then
  546. Message(scan_f_end_of_file);
  547. readchar;
  548. end;
  549. dec_comment_level;
  550. end;
  551. procedure skipoldtpcomment;
  552. var
  553. found : longint;
  554. begin
  555. inc_comment_level;
  556. readchar;
  557. { this is currently not supported }
  558. if c='$' then
  559. Message(scan_e_wrong_styled_switch);
  560. { skip comment }
  561. while (comment_level>0) do
  562. begin
  563. found:=0;
  564. repeat
  565. case c of
  566. #26 : Message(scan_f_end_of_file);
  567. '*' : begin
  568. if found=3 then
  569. inc_comment_level
  570. else
  571. found:=1;
  572. end;
  573. ')' : begin
  574. if found=1 then
  575. begin
  576. dec_comment_level;
  577. if comment_level=0 then
  578. found:=2;
  579. end;
  580. end;
  581. '(' : found:=3;
  582. else
  583. found:=0;
  584. end;
  585. readchar;
  586. {c:=inputpointer^;
  587. if c=#0 then
  588. reload
  589. else
  590. inc(longint(inputpointer));}
  591. until (found=2);
  592. end;
  593. end;
  594. function yylex : ttoken;
  595. var
  596. y : ttoken;
  597. {$ifdef UseTokenInfo}
  598. fileindex,line,column : longint;
  599. {$endif UseTokenInfo}
  600. code : word;
  601. l : longint;
  602. mac : pmacrosym;
  603. hp : pinputfile;
  604. hp2 : pchar;
  605. {$ifdef UseTokenInfo}
  606. label
  607. exit_label;
  608. {$endif UseTokenInfo}
  609. begin
  610. {$ifdef UseTokenInfo}
  611. line:=current_module^.current_inputfile^.line_no;
  612. column:=get_current_col;
  613. fileindex:=current_module^.current_index;
  614. {$endif UseTokenInfo}
  615. { was the last character a point ? }
  616. { this code is needed because the scanner if there is a 1. found if }
  617. { this is a floating point number or range like 1..3 }
  618. if s_point then
  619. begin
  620. s_point:=false;
  621. if c='.' then
  622. begin
  623. readchar;
  624. {$ifndef UseTokenInfo}
  625. yylex:=POINTPOINT;
  626. exit;
  627. end;
  628. yylex:=POINT;
  629. exit;
  630. {$else UseTokenInfo}
  631. yylex:=POINTPOINT;
  632. goto exit_label;
  633. end;
  634. yylex:=POINT;
  635. goto exit_label;
  636. {$endif UseTokenInfo}
  637. end;
  638. repeat
  639. case c of
  640. '{' : skipcomment;
  641. ' ',#9..#13 : skipspace;
  642. else
  643. break;
  644. end;
  645. until false;
  646. lasttokenpos:=longint(inputpointer);
  647. {$ifdef UseTokenInfo}
  648. line:=current_module^.current_inputfile^.line_no;
  649. column:=get_current_col;
  650. fileindex:=current_module^.current_index;
  651. { will become line:=lasttokenpos ??;}
  652. {$endif UseTokenInfo}
  653. case c of
  654. '_','A'..'Z',
  655. 'a'..'z' : begin
  656. orgpattern:=readstring;
  657. pattern:=upper(orgpattern);
  658. if (length(pattern) in [2..id_len]) and is_keyword(y) then
  659. yylex:=y
  660. else
  661. begin
  662. { this takes some time ... }
  663. if support_macros then
  664. begin
  665. mac:=pmacrosym(macros^.search(pattern));
  666. if assigned(mac) and (assigned(mac^.buftext)) then
  667. begin
  668. { don't forget the last char }
  669. dec(longint(inputpointer));
  670. current_module^.current_inputfile^.bufpos:=inputpointer-inputbuffer;
  671. { this isn't a proper way, but ... }
  672. hp:=new(pinputfile,init('','Macro '+pattern,''));
  673. hp^.next:=current_module^.current_inputfile;
  674. current_module^.current_inputfile:=hp;
  675. status.currentsource:=current_module^.current_inputfile^.name^;
  676. current_module^.sourcefiles.register_file(hp);
  677. current_module^.current_index:=hp^.ref_index;
  678. { set an own buffer }
  679. getmem(hp2,mac^.buflen+1);
  680. current_module^.current_inputfile^.setbuf(hp2,mac^.buflen+1);
  681. inputbuffer:=current_module^.current_inputfile^.buf;
  682. { copy text }
  683. move(mac^.buftext^,inputbuffer^,mac^.buflen);
  684. { put end sign }
  685. inputbuffer[mac^.buflen+1]:=#0;
  686. { load c }
  687. c:=inputbuffer^;
  688. inputpointer:=inputbuffer+1;
  689. { handle empty macros }
  690. if c=#0 then
  691. reload;
  692. { play it again ... }
  693. inc(yylexcount);
  694. if yylexcount>16 then
  695. Message(scan_w_macro_deep_ten);
  696. {$ifdef TP}
  697. yylex:=yylex;
  698. {$else}
  699. yylex:=yylex();
  700. {$endif}
  701. { that's all folks }
  702. dec(yylexcount);
  703. exit;
  704. end;
  705. end;
  706. yylex:=ID;
  707. end;
  708. {$ifndef UseTokenInfo}
  709. exit;
  710. {$else UseTokenInfo}
  711. goto exit_label;
  712. {$endif UseTokenInfo}
  713. end;
  714. '$' : begin
  715. pattern:=readnumber;
  716. yylex:=INTCONST;
  717. {$ifndef UseTokenInfo}
  718. exit;
  719. {$else UseTokenInfo}
  720. goto exit_label;
  721. {$endif UseTokenInfo}
  722. end;
  723. '%' : begin
  724. pattern:=readnumber;
  725. yylex:=INTCONST;
  726. {$ifndef UseTokenInfo}
  727. exit;
  728. {$else UseTokenInfo}
  729. goto exit_label;
  730. {$endif UseTokenInfo}
  731. end;
  732. '0'..'9' : begin
  733. pattern:=readnumber;
  734. case c of
  735. '.' : begin
  736. readchar;
  737. if not(c in ['0'..'9']) then
  738. begin
  739. s_point:=true;
  740. yylex:=INTCONST;
  741. {$ifndef UseTokenInfo}
  742. exit;
  743. {$else UseTokenInfo}
  744. goto exit_label;
  745. {$endif UseTokenInfo}
  746. end;
  747. pattern:=pattern+'.';
  748. while c in ['0'..'9'] do
  749. begin
  750. pattern:=pattern+c;
  751. readchar;
  752. end;
  753. yylex:=REALNUMBER;
  754. {$ifndef UseTokenInfo}
  755. exit;
  756. {$else UseTokenInfo}
  757. goto exit_label;
  758. {$endif UseTokenInfo}
  759. end;
  760. 'e','E' : begin
  761. pattern:=pattern+'E';
  762. readchar;
  763. if c in ['-','+'] then
  764. begin
  765. pattern:=pattern+c;
  766. readchar;
  767. end;
  768. if not(c in ['0'..'9']) then
  769. Message(scan_f_illegal_char);
  770. while c in ['0'..'9'] do
  771. begin
  772. pattern:=pattern+c;
  773. readchar;
  774. end;
  775. yylex:=REALNUMBER;
  776. {$ifndef UseTokenInfo}
  777. exit;
  778. {$else UseTokenInfo}
  779. goto exit_label;
  780. {$endif UseTokenInfo}
  781. end;
  782. end;
  783. yylex:=INTCONST;
  784. {$ifndef UseTokenInfo}
  785. exit;
  786. {$else UseTokenInfo}
  787. goto exit_label;
  788. {$endif UseTokenInfo}
  789. end;
  790. ';' : begin
  791. readchar;
  792. yylex:=SEMICOLON;
  793. {$ifndef UseTokenInfo}
  794. exit;
  795. {$else UseTokenInfo}
  796. goto exit_label;
  797. {$endif UseTokenInfo}
  798. end;
  799. '[' : begin
  800. readchar;
  801. yylex:=LECKKLAMMER;
  802. {$ifndef UseTokenInfo}
  803. exit;
  804. {$else UseTokenInfo}
  805. goto exit_label;
  806. {$endif UseTokenInfo}
  807. end;
  808. ']' : begin
  809. readchar;
  810. yylex:=RECKKLAMMER;
  811. {$ifndef UseTokenInfo}
  812. exit;
  813. {$else UseTokenInfo}
  814. goto exit_label;
  815. {$endif UseTokenInfo}
  816. end;
  817. '(' : begin
  818. readchar;
  819. if c='*' then
  820. begin
  821. skipoldtpcomment;
  822. {$ifndef TP}
  823. yylex:=yylex();
  824. {$else TP}
  825. yylex:=yylex;
  826. {$endif TP}
  827. exit;
  828. end;
  829. yylex:=LKLAMMER;
  830. {$ifndef UseTokenInfo}
  831. exit;
  832. {$else UseTokenInfo}
  833. goto exit_label;
  834. {$endif UseTokenInfo}
  835. end;
  836. ')' : begin
  837. readchar;
  838. yylex:=RKLAMMER;
  839. {$ifndef UseTokenInfo}
  840. exit;
  841. {$else UseTokenInfo}
  842. goto exit_label;
  843. {$endif UseTokenInfo}
  844. end;
  845. '+' : begin
  846. readchar;
  847. if (c='=') and c_like_operators then
  848. begin
  849. readchar;
  850. yylex:=_PLUSASN;
  851. {$ifndef UseTokenInfo}
  852. exit;
  853. {$else UseTokenInfo}
  854. goto exit_label;
  855. {$endif UseTokenInfo}
  856. end;
  857. yylex:=PLUS;
  858. {$ifndef UseTokenInfo}
  859. exit;
  860. {$else UseTokenInfo}
  861. goto exit_label;
  862. {$endif UseTokenInfo}
  863. end;
  864. '-' : begin
  865. readchar;
  866. if (c='=') and c_like_operators then
  867. begin
  868. readchar;
  869. yylex:=_MINUSASN;
  870. {$ifndef UseTokenInfo}
  871. exit;
  872. {$else UseTokenInfo}
  873. goto exit_label;
  874. {$endif UseTokenInfo}
  875. end;
  876. yylex:=MINUS;
  877. {$ifndef UseTokenInfo}
  878. exit;
  879. {$else UseTokenInfo}
  880. goto exit_label;
  881. {$endif UseTokenInfo}
  882. end;
  883. ':' : begin
  884. readchar;
  885. if c='=' then
  886. begin
  887. readchar;
  888. yylex:=ASSIGNMENT;
  889. {$ifndef UseTokenInfo}
  890. exit;
  891. {$else UseTokenInfo}
  892. goto exit_label;
  893. {$endif UseTokenInfo}
  894. end;
  895. yylex:=COLON;
  896. {$ifndef UseTokenInfo}
  897. exit;
  898. {$else UseTokenInfo}
  899. goto exit_label;
  900. {$endif UseTokenInfo}
  901. end;
  902. '*' : begin
  903. readchar;
  904. if (c='=') and c_like_operators then
  905. begin
  906. readchar;
  907. yylex:=_STARASN;
  908. end else if c='*' then
  909. begin
  910. readchar;
  911. yylex:=STARSTAR;
  912. end
  913. else
  914. yylex:=STAR;
  915. {$ifndef UseTokenInfo}
  916. exit;
  917. {$else UseTokenInfo}
  918. goto exit_label;
  919. {$endif UseTokenInfo}
  920. end;
  921. '/' : begin
  922. readchar;
  923. case c of
  924. '=' : begin
  925. if c_like_operators then
  926. begin
  927. readchar;
  928. yylex:=_SLASHASN;
  929. {$ifndef UseTokenInfo}
  930. exit;
  931. {$else UseTokenInfo}
  932. goto exit_label;
  933. {$endif UseTokenInfo}
  934. end;
  935. end;
  936. '/' : begin
  937. skipdelphicomment;
  938. {$ifndef TP}
  939. yylex:=yylex();
  940. {$else TP}
  941. yylex:=yylex;
  942. {$endif TP}
  943. exit;
  944. end;
  945. end;
  946. yylex:=SLASH;
  947. {$ifndef UseTokenInfo}
  948. exit;
  949. {$else UseTokenInfo}
  950. goto exit_label;
  951. {$endif UseTokenInfo}
  952. end;
  953. '=' : begin
  954. readchar;
  955. yylex:=EQUAL;
  956. {$ifndef UseTokenInfo}
  957. exit;
  958. {$else UseTokenInfo}
  959. goto exit_label;
  960. {$endif UseTokenInfo}
  961. end;
  962. '.' : begin
  963. readchar;
  964. if c='.' then
  965. begin
  966. readchar;
  967. yylex:=POINTPOINT;
  968. {$ifndef UseTokenInfo}
  969. exit;
  970. {$else UseTokenInfo}
  971. goto exit_label;
  972. {$endif UseTokenInfo}
  973. end
  974. else
  975. yylex:=POINT;
  976. {$ifndef UseTokenInfo}
  977. exit;
  978. {$else UseTokenInfo}
  979. goto exit_label;
  980. {$endif UseTokenInfo}
  981. end;
  982. '@' : begin
  983. readchar;
  984. if c='@' then
  985. begin
  986. readchar;
  987. yylex:=DOUBLEADDR;
  988. end
  989. else
  990. yylex:=KLAMMERAFFE;
  991. {$ifndef UseTokenInfo}
  992. exit;
  993. {$else UseTokenInfo}
  994. goto exit_label;
  995. {$endif UseTokenInfo}
  996. end;
  997. ',' : begin
  998. readchar;
  999. yylex:=COMMA;
  1000. {$ifndef UseTokenInfo}
  1001. exit;
  1002. {$else UseTokenInfo}
  1003. goto exit_label;
  1004. {$endif UseTokenInfo}
  1005. end;
  1006. '''','#','^' : begin
  1007. if c='^' then
  1008. begin
  1009. readchar;
  1010. c:=upcase(c);
  1011. if not(block_type=bt_type) and (c in ['A'..'Z']) then
  1012. { if not(block_type=bt_type) and (c in [#64..#128]) then}
  1013. begin
  1014. pattern:=chr(ord(c)-64);
  1015. readchar;
  1016. end
  1017. else
  1018. begin
  1019. yylex:=CARET;
  1020. {$ifndef UseTokenInfo}
  1021. exit;
  1022. {$else UseTokenInfo}
  1023. goto exit_label;
  1024. {$endif UseTokenInfo}
  1025. end;
  1026. end
  1027. else
  1028. pattern:='';
  1029. repeat
  1030. case c of
  1031. '#' : begin
  1032. readchar; { read # }
  1033. valint(readnumber,l,code);
  1034. if (code<>0) or (l<0) or (l>255) then
  1035. Message(scan_e_illegal_char_const);
  1036. pattern:=pattern+chr(l);
  1037. end;
  1038. '''' : begin
  1039. repeat
  1040. readchar;
  1041. case c of
  1042. #26 : Message(scan_f_end_of_file);
  1043. newline : Message(scan_f_string_exceeds_line);
  1044. '''' : begin
  1045. readchar;
  1046. if c<>'''' then
  1047. break;
  1048. end;
  1049. end;
  1050. pattern:=pattern+c;
  1051. until false;
  1052. end;
  1053. '^' : begin
  1054. readchar;
  1055. if c<#64 then
  1056. c:=chr(ord(c)+64)
  1057. else
  1058. c:=chr(ord(c)-64);
  1059. pattern:=pattern+c;
  1060. readchar;
  1061. end;
  1062. else
  1063. break;
  1064. end;
  1065. until false;
  1066. { strings with length 1 become const chars }
  1067. if length(pattern)=1 then
  1068. yylex:=CCHAR
  1069. else
  1070. yylex:=CSTRING;
  1071. {$ifndef UseTokenInfo}
  1072. exit;
  1073. {$else UseTokenInfo}
  1074. goto exit_label;
  1075. {$endif UseTokenInfo}
  1076. end;
  1077. '>' : begin
  1078. readchar;
  1079. case c of
  1080. '=' : begin
  1081. readchar;
  1082. yylex:=GTE;
  1083. {$ifndef UseTokenInfo}
  1084. exit;
  1085. {$else UseTokenInfo}
  1086. goto exit_label;
  1087. {$endif UseTokenInfo}
  1088. end;
  1089. '>' : begin
  1090. readchar;
  1091. yylex:=_SHR;
  1092. {$ifndef UseTokenInfo}
  1093. exit;
  1094. {$else UseTokenInfo}
  1095. goto exit_label;
  1096. {$endif UseTokenInfo}
  1097. end;
  1098. '<' : begin { >< is for a symetric diff for sets }
  1099. readchar;
  1100. yylex:=SYMDIF;
  1101. {$ifndef UseTokenInfo}
  1102. exit;
  1103. {$else UseTokenInfo}
  1104. goto exit_label;
  1105. {$endif UseTokenInfo}
  1106. end;
  1107. end;
  1108. yylex:=GT;
  1109. {$ifndef UseTokenInfo}
  1110. exit;
  1111. {$else UseTokenInfo}
  1112. goto exit_label;
  1113. {$endif UseTokenInfo}
  1114. end;
  1115. '<' : begin
  1116. readchar;
  1117. case c of
  1118. '>' : begin
  1119. readchar;
  1120. yylex:=UNEQUAL;
  1121. {$ifndef UseTokenInfo}
  1122. exit;
  1123. {$else UseTokenInfo}
  1124. goto exit_label;
  1125. {$endif UseTokenInfo}
  1126. end;
  1127. '=' : begin
  1128. readchar;
  1129. yylex:=LTE;
  1130. {$ifndef UseTokenInfo}
  1131. exit;
  1132. {$else UseTokenInfo}
  1133. goto exit_label;
  1134. {$endif UseTokenInfo}
  1135. end;
  1136. '<' : begin
  1137. readchar;
  1138. yylex:=_SHL;
  1139. {$ifndef UseTokenInfo}
  1140. exit;
  1141. {$else UseTokenInfo}
  1142. goto exit_label;
  1143. {$endif UseTokenInfo}
  1144. end;
  1145. end;
  1146. yylex:=LT;
  1147. {$ifndef UseTokenInfo}
  1148. exit;
  1149. {$else UseTokenInfo}
  1150. goto exit_label;
  1151. {$endif UseTokenInfo}
  1152. end;
  1153. #26 : begin
  1154. yylex:=_EOF;
  1155. {$ifndef UseTokenInfo}
  1156. exit;
  1157. {$else UseTokenInfo}
  1158. goto exit_label;
  1159. {$endif UseTokenInfo}
  1160. end;
  1161. else
  1162. begin
  1163. Message(scan_f_illegal_char);
  1164. end;
  1165. end;
  1166. {$ifdef UseTokenInfo}
  1167. exit_label:
  1168. tokenpos.fileindex:=fileindex;
  1169. tokenpos.line:=line;
  1170. tokenpos.column:=column;
  1171. {$endif UseTokenInfo}
  1172. end;
  1173. function asmgetchar : char;
  1174. begin
  1175. if lastasmgetchar<>#0 then
  1176. begin
  1177. c:=lastasmgetchar;
  1178. lastasmgetchar:=#0;
  1179. end
  1180. else
  1181. readchar;
  1182. case c of
  1183. '{' : begin
  1184. skipcomment;
  1185. lastasmgetchar:=c;
  1186. asmgetchar:=';';
  1187. exit;
  1188. end;
  1189. '/' : begin
  1190. readchar;
  1191. if c='/' then
  1192. begin
  1193. skipdelphicomment;
  1194. asmgetchar:=';';
  1195. end
  1196. else
  1197. asmgetchar:='/';
  1198. lastasmgetchar:=c;
  1199. exit;
  1200. end;
  1201. '(' : begin
  1202. readchar;
  1203. if c='*' then
  1204. begin
  1205. skipoldtpcomment;
  1206. asmgetchar:=';';
  1207. end
  1208. else
  1209. asmgetchar:='(';
  1210. lastasmgetchar:=c;
  1211. exit;
  1212. end;
  1213. else
  1214. begin
  1215. asmgetchar:=c;
  1216. end;
  1217. end;
  1218. end;
  1219. procedure InitScanner(const fn: string);
  1220. var
  1221. d:dirstr;
  1222. n:namestr;
  1223. e:extstr;
  1224. begin
  1225. fsplit(fn,d,n,e);
  1226. current_module^.current_inputfile:=new(pinputfile,init(d,n,e));
  1227. current_module^.current_inputfile^.reset;
  1228. current_module^.sourcefiles.register_file(current_module^.current_inputfile);
  1229. current_module^.current_index:=current_module^.current_inputfile^.ref_index;
  1230. status.currentsource:=current_module^.current_inputfile^.name^+current_module^.current_inputfile^.ext^;
  1231. if ioresult<>0 then
  1232. Message(scan_f_cannot_open_input);
  1233. inputbuffer:=current_module^.current_inputfile^.buf;
  1234. reload;
  1235. preprocstack:=nil;
  1236. comment_level:=0;
  1237. lasttokenpos:=0;
  1238. lastlinepos:=0;
  1239. s_point:=false;
  1240. end;
  1241. procedure get_cur_file_pos(var fileinfo : tfileposinfo);
  1242. begin
  1243. fileinfo.line:=current_module^.current_inputfile^.line_no;
  1244. {fileinfo.fileindex:=current_module^.current_inputfile^.ref_index;}
  1245. { should allways be the same !! }
  1246. fileinfo.fileindex:=current_module^.current_index;
  1247. fileinfo.column:=get_current_col;
  1248. end;
  1249. procedure set_cur_file_pos(const fileinfo : tfileposinfo);
  1250. begin
  1251. current_module^.current_index:=fileinfo.fileindex;
  1252. current_module^.current_inputfile:=
  1253. pinputfile(current_module^.sourcefiles.get_file(fileinfo.fileindex));
  1254. current_module^.current_inputfile^.line_no:=fileinfo.line;
  1255. {fileinfo.fileindex:=current_module^.current_inputfile^.ref_index;}
  1256. { should allways be the same !! }
  1257. { fileinfo.column:=get_current_col; }
  1258. end;
  1259. procedure DoneScanner(testendif:boolean);
  1260. var
  1261. st : string[16];
  1262. begin
  1263. if (not testendif) then
  1264. begin
  1265. while assigned(preprocstack) do
  1266. begin
  1267. if preprocstack^.isifdef then
  1268. st:='$IF(N)(DEF)'
  1269. else
  1270. st:='$ELSE';
  1271. Message3(scan_e_endif_expected,st,preprocstack^.name,tostr(preprocstack^.line_nb));
  1272. popstack;
  1273. end;
  1274. end;
  1275. end;
  1276. procedure change_to_tp_keywords;
  1277. const
  1278. non_tp : array[0..13] of string[id_len] = (
  1279. 'AS','CLASS','EXCEPT','FINALLY','INITIALIZATION','IS',
  1280. 'ON','OPERATOR','OTHERWISE','PROPERTY','RAISE','TRY',
  1281. 'EXPORTS','LIBRARY');
  1282. var
  1283. i : longint;
  1284. begin
  1285. for i:=0 to 13 do
  1286. remove_keyword(non_tp[i]);
  1287. end;
  1288. procedure change_to_delphi_keywords;
  1289. {
  1290. const
  1291. non_tp : array[0..13] of string[id_len] = (
  1292. 'AS','CLASS','EXCEPT','FINALLY','INITIALIZATION','IS',
  1293. 'ON','OPERATOR','OTHERWISE','PROPERTY','RAISE','TRY',
  1294. 'EXPORTS','LIBRARY');
  1295. var
  1296. i : longint;
  1297. }
  1298. begin
  1299. {
  1300. for i:=0 to 13 do
  1301. remove_keyword(non_tp[i]);
  1302. }
  1303. end;
  1304. end.
  1305. {
  1306. $Log$
  1307. Revision 1.17 1998-05-06 08:38:47 pierre
  1308. * better position info with UseTokenInfo
  1309. UseTokenInfo greatly simplified
  1310. + added check for changed tree after first time firstpass
  1311. (if we could remove all the cases were it happen
  1312. we could skip all firstpass if firstpasscount > 1)
  1313. Only with ExtDebug
  1314. Revision 1.16 1998/05/04 17:54:28 peter
  1315. + smartlinking works (only case jumptable left todo)
  1316. * redesign of systems.pas to support assemblers and linkers
  1317. + Unitname is now also in the PPU-file, increased version to 14
  1318. Revision 1.15 1998/05/01 16:38:46 florian
  1319. * handling of private and protected fixed
  1320. + change_keywords_to_tp implemented to remove
  1321. keywords which aren't supported by tp
  1322. * break and continue are now symbols of the system unit
  1323. + widestring, longstring and ansistring type released
  1324. Revision 1.14 1998/04/30 15:59:42 pierre
  1325. * GDB works again better :
  1326. correct type info in one pass
  1327. + UseTokenInfo for better source position
  1328. * fixed one remaining bug in scanner for line counts
  1329. * several little fixes
  1330. Revision 1.13 1998/04/29 13:42:27 peter
  1331. + $IOCHECKS and $ALIGN to test already, other will follow soon
  1332. * fixed the wrong linecounting with comments
  1333. Revision 1.12 1998/04/29 10:34:04 pierre
  1334. + added some code for ansistring (not complete nor working yet)
  1335. * corrected operator overloading
  1336. * corrected nasm output
  1337. + started inline procedures
  1338. + added starstarn : use ** for exponentiation (^ gave problems)
  1339. + started UseTokenInfo cond to get accurate positions
  1340. Revision 1.11 1998/04/27 23:10:29 peter
  1341. + new scanner
  1342. * $makelib -> if smartlink
  1343. * small filename fixes pmodule.setfilename
  1344. * moved import from files.pas -> import.pas
  1345. }