parser.pas 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670
  1. {
  2. $Id$
  3. Copyright (c) 1998-2002 by Florian Klaempfl
  4. This unit does the parsing process
  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. unit parser;
  19. {$i fpcdefs.inc}
  20. interface
  21. {$ifdef PREPROCWRITE}
  22. procedure preprocess(const filename:string);
  23. {$endif PREPROCWRITE}
  24. procedure compile(const filename:string);
  25. procedure initparser;
  26. procedure doneparser;
  27. implementation
  28. uses
  29. cutils,cclasses,
  30. globtype,version,tokens,systems,globals,verbose,
  31. symbase,symtable,symdef,symsym,
  32. fmodule,fppu,
  33. aasmbase,aasmtai,
  34. cgbase,
  35. script,gendef,
  36. {$ifdef BrowserLog}
  37. browlog,
  38. {$endif BrowserLog}
  39. {$ifdef UseExcept}
  40. tpexcept,
  41. {$endif UseExcept}
  42. {$ifdef GDB}
  43. gdb,
  44. {$endif GDB}
  45. comphook,
  46. scanner,scandir,
  47. pbase,ptype,psystem,pmodules,cresstr,cpuinfo;
  48. procedure initparser;
  49. begin
  50. { ^M means a string or a char, because we don't parse a }
  51. { type declaration }
  52. ignore_equal:=false;
  53. { we didn't parse a object or class declaration }
  54. { and no function header }
  55. testcurobject:=0;
  56. { Symtable }
  57. aktprocsym:=nil;
  58. aktprocdef:=nil;
  59. objectlibrary:=nil;
  60. current_module:=nil;
  61. compiled_module:=nil;
  62. procinfo:=nil;
  63. loaded_units:=TLinkedList.Create;
  64. usedunits:=TLinkedList.Create;
  65. { global switches }
  66. aktglobalswitches:=initglobalswitches;
  67. aktsourcecodepage:=initsourcecodepage;
  68. { initialize scanner }
  69. InitScanner;
  70. InitScannerDirectives;
  71. { scanner }
  72. c:=#0;
  73. pattern:='';
  74. orgpattern:='';
  75. current_scanner:=nil;
  76. { register all nodes }
  77. registernodes;
  78. { memory sizes }
  79. if heapsize=0 then
  80. heapsize:=target_info.heapsize;
  81. if stacksize=0 then
  82. stacksize:=target_info.stacksize;
  83. { open assembler response }
  84. GenerateAsmRes(outputexedir+'ppas');
  85. { open deffile }
  86. DefFile:=TDefFile.Create(outputexedir+inputfile+target_info.defext);
  87. { list of generated .o files, so the linker can remove them }
  88. SmartLinkOFiles:=TStringList.Create;
  89. end;
  90. procedure doneparser;
  91. begin
  92. { unload units }
  93. loaded_units.free;
  94. usedunits.free;
  95. { if there was an error in the scanner, the scanner is
  96. still assinged }
  97. if assigned(current_scanner) then
  98. begin
  99. current_scanner.free;
  100. current_scanner:=nil;
  101. end;
  102. { close scanner }
  103. DoneScanner;
  104. { close ppas,deffile }
  105. asmres.free;
  106. deffile.free;
  107. { free list of .o files }
  108. SmartLinkOFiles.Free;
  109. end;
  110. procedure default_macros;
  111. var
  112. hp : tstringlistitem;
  113. begin
  114. { commandline }
  115. hp:=tstringlistitem(initdefines.first);
  116. while assigned(hp) do
  117. begin
  118. current_scanner.def_macro(hp.str);
  119. hp:=tstringlistitem(hp.next);
  120. end;
  121. { set macros for version checking }
  122. current_scanner.set_macro('FPC_VERSION',version_nr);
  123. current_scanner.set_macro('FPC_RELEASE',release_nr);
  124. current_scanner.set_macro('FPC_PATCH',patch_nr);
  125. end;
  126. {$ifdef PREPROCWRITE}
  127. procedure preprocess(const filename:string);
  128. var
  129. i : longint;
  130. begin
  131. new(preprocfile,init('pre'));
  132. { default macros }
  133. current_scanner^.macros:=new(pdictionary,init);
  134. default_macros;
  135. { initialize a module }
  136. current_module:=new(pmodule,init(filename,false));
  137. main_module:=current_module;
  138. { startup scanner, and save in current_module }
  139. current_scanner:=new(pscannerfile,Init(filename));
  140. current_module.scanner:=current_scanner;
  141. { loop until EOF is found }
  142. repeat
  143. current_scanner^.readtoken;
  144. preprocfile^.AddSpace;
  145. case token of
  146. _ID :
  147. begin
  148. preprocfile^.Add(orgpattern);
  149. end;
  150. _REALNUMBER,
  151. _INTCONST :
  152. preprocfile^.Add(pattern);
  153. _CSTRING :
  154. begin
  155. i:=0;
  156. while (i<length(pattern)) do
  157. begin
  158. inc(i);
  159. if pattern[i]='''' then
  160. begin
  161. insert('''',pattern,i);
  162. inc(i);
  163. end;
  164. end;
  165. preprocfile^.Add(''''+pattern+'''');
  166. end;
  167. _CCHAR :
  168. begin
  169. case pattern[1] of
  170. #39 :
  171. pattern:='''''''';
  172. #0..#31,
  173. #128..#255 :
  174. begin
  175. str(ord(pattern[1]),pattern);
  176. pattern:='#'+pattern;
  177. end;
  178. else
  179. pattern:=''''+pattern[1]+'''';
  180. end;
  181. preprocfile^.Add(pattern);
  182. end;
  183. _EOF :
  184. break;
  185. else
  186. preprocfile^.Add(tokeninfo^[token].str)
  187. end;
  188. until false;
  189. { free scanner }
  190. dispose(current_scanner,done);
  191. current_scanner:=nil;
  192. { close }
  193. dispose(preprocfile,done);
  194. end;
  195. {$endif PREPROCWRITE}
  196. procedure compile(const filename:string);
  197. var
  198. { scanner }
  199. oldidtoken,
  200. oldtoken : ttoken;
  201. oldtokenpos : tfileposinfo;
  202. oldc : char;
  203. oldpattern,
  204. oldorgpattern : string;
  205. old_block_type : tblock_type;
  206. { symtable }
  207. oldrefsymtable,
  208. olddefaultsymtablestack,
  209. oldsymtablestack : tsymtable;
  210. oldaktprocsym : tprocsym;
  211. oldaktprocdef : tprocdef;
  212. oldoverloaded_operators : toverloaded_operators;
  213. { cg }
  214. oldparse_only : boolean;
  215. { asmlists }
  216. oldimports,
  217. oldexports,
  218. oldresource,
  219. oldrttilist,
  220. oldresourcestringlist,
  221. oldbsssegment,
  222. olddatasegment,
  223. oldcodesegment,
  224. oldexprasmlist,
  225. olddebuglist,
  226. oldwithdebuglist,
  227. oldconsts : taasmoutput;
  228. oldobjectlibrary : tasmlibrarydata;
  229. { resourcestrings }
  230. OldResourceStrings : tResourceStrings;
  231. { akt.. things }
  232. oldaktlocalswitches : tlocalswitches;
  233. oldaktmoduleswitches : tmoduleswitches;
  234. oldaktfilepos : tfileposinfo;
  235. oldaktpackenum,oldaktmaxfpuregisters : longint;
  236. oldaktalignment : talignmentinfo;
  237. oldaktoutputformat : tasm;
  238. oldaktspecificoptprocessor,
  239. oldaktoptprocessor : tprocessors;
  240. oldaktasmmode : tasmmode;
  241. oldaktinterfacetype: tinterfacetypes;
  242. oldaktmodeswitches : tmodeswitches;
  243. old_compiled_module : tmodule;
  244. oldaktdefproccall : tproccalloption;
  245. oldsourcecodepage : tcodepagestring;
  246. { will only be increased once we start parsing blocks in the }
  247. { implementation, so doesn't need to be saved/restored (JM) }
  248. { oldexceptblockcounter : integer; }
  249. oldstatement_level : integer;
  250. {$ifdef USEEXCEPT}
  251. {$ifndef Delphi}
  252. recoverpos : jmp_buf;
  253. oldrecoverpos : pjmp_buf;
  254. {$endif Delphi}
  255. {$endif useexcept}
  256. {$ifdef GDB}
  257. store_dbx : plongint;
  258. {$endif GDB}
  259. begin
  260. inc(compile_level);
  261. parser_current_file:=filename;
  262. old_compiled_module:=compiled_module;
  263. { save symtable state }
  264. oldsymtablestack:=symtablestack;
  265. olddefaultsymtablestack:=defaultsymtablestack;
  266. oldrefsymtable:=refsymtable;
  267. oldaktprocsym:=aktprocsym;
  268. oldaktprocdef:=aktprocdef;
  269. oldaktdefproccall:=aktdefproccall;
  270. move(overloaded_operators,oldoverloaded_operators,sizeof(toverloaded_operators));
  271. { save scanner state }
  272. oldc:=c;
  273. oldpattern:=pattern;
  274. oldorgpattern:=orgpattern;
  275. oldtoken:=token;
  276. oldidtoken:=idtoken;
  277. old_block_type:=block_type;
  278. oldtokenpos:=akttokenpos;
  279. oldsourcecodepage:=aktsourcecodepage;
  280. { save cg }
  281. oldparse_only:=parse_only;
  282. { save assembler lists }
  283. olddatasegment:=datasegment;
  284. oldbsssegment:=bsssegment;
  285. oldcodesegment:=codesegment;
  286. olddebuglist:=debuglist;
  287. oldwithdebuglist:=withdebuglist;
  288. oldconsts:=consts;
  289. oldrttilist:=rttilist;
  290. oldexprasmlist:=exprasmlist;
  291. oldimports:=importssection;
  292. oldexports:=exportssection;
  293. oldresource:=resourcesection;
  294. oldresourcestringlist:=resourcestringlist;
  295. oldobjectlibrary:=objectlibrary;
  296. OldResourceStrings:=ResourceStrings;
  297. { save akt... state }
  298. { handle the postponed case first }
  299. if localswitcheschanged then
  300. begin
  301. aktlocalswitches:=nextaktlocalswitches;
  302. localswitcheschanged:=false;
  303. end;
  304. oldaktlocalswitches:=aktlocalswitches;
  305. oldaktmoduleswitches:=aktmoduleswitches;
  306. oldaktalignment:=aktalignment;
  307. oldaktpackenum:=aktpackenum;
  308. oldaktmaxfpuregisters:=aktmaxfpuregisters;
  309. oldaktoutputformat:=aktoutputformat;
  310. oldaktoptprocessor:=aktoptprocessor;
  311. oldaktspecificoptprocessor:=aktspecificoptprocessor;
  312. oldaktasmmode:=aktasmmode;
  313. oldaktinterfacetype:=aktinterfacetype;
  314. oldaktfilepos:=aktfilepos;
  315. oldaktmodeswitches:=aktmodeswitches;
  316. oldstatement_level:=statement_level;
  317. { oldexceptblockcounter:=exceptblockcounter; }
  318. {$ifdef GDB}
  319. store_dbx:=dbx_counter;
  320. dbx_counter:=nil;
  321. {$endif GDB}
  322. { show info }
  323. Message1(parser_i_compiling,filename);
  324. { reset symtable }
  325. symtablestack:=nil;
  326. defaultsymtablestack:=nil;
  327. systemunit:=nil;
  328. refsymtable:=nil;
  329. aktprocsym:=nil;
  330. aktdefproccall:=initdefproccall;
  331. registerdef:=true;
  332. statement_level:=0;
  333. aktexceptblock:=0;
  334. exceptblockcounter:=0;
  335. aktmaxfpuregisters:=-1;
  336. fillchar(overloaded_operators,sizeof(toverloaded_operators),0);
  337. { reset the unit or create a new program }
  338. if assigned(current_module) then
  339. current_module.reset
  340. else
  341. begin
  342. current_module:=tppumodule.create(filename,'',false);
  343. main_module:=current_module;
  344. end;
  345. { a unit compiled at command line must be inside the loaded_unit list }
  346. if (compile_level=1) then
  347. loaded_units.insert(current_module);
  348. { Set the module to use for verbose }
  349. SetCompileModule(current_module);
  350. compiled_module:=current_module;
  351. current_module.in_compile:=true;
  352. { Load current state from the init values }
  353. aktlocalswitches:=initlocalswitches;
  354. aktmoduleswitches:=initmoduleswitches;
  355. aktmodeswitches:=initmodeswitches;
  356. {$IFDEF Testvarsets}
  357. aktsetalloc:=initsetalloc;
  358. {$ENDIF}
  359. aktalignment:=initalignment;
  360. aktpackenum:=initpackenum;
  361. aktoutputformat:=initoutputformat;
  362. set_target_asm(aktoutputformat);
  363. aktoptprocessor:=initoptprocessor;
  364. aktspecificoptprocessor:=initspecificoptprocessor;
  365. aktasmmode:=initasmmode;
  366. aktinterfacetype:=initinterfacetype;
  367. { startup scanner and load the first file }
  368. current_scanner:=tscannerfile.Create(filename);
  369. current_scanner.firstfile;
  370. current_module.scanner:=current_scanner;
  371. { macros }
  372. default_macros;
  373. { read the first token }
  374. current_scanner.readtoken;
  375. { init code generator for a new module }
  376. codegen_newmodule;
  377. { If the compile level > 1 we get a nice "unit expected" error
  378. message if we are trying to use a program as unit.}
  379. {$ifdef USEEXCEPT}
  380. if setjmp(recoverpos)=0 then
  381. begin
  382. oldrecoverpos:=recoverpospointer;
  383. recoverpospointer:=@recoverpos;
  384. {$endif USEEXCEPT}
  385. if (token=_UNIT) or (compile_level>1) then
  386. begin
  387. current_module.is_unit:=true;
  388. proc_unit;
  389. end
  390. else
  391. proc_program(token=_LIBRARY);
  392. {$ifdef USEEXCEPT}
  393. recoverpospointer:=oldrecoverpos;
  394. end
  395. else
  396. begin
  397. recoverpospointer:=oldrecoverpos;
  398. longjump_used:=true;
  399. end;
  400. {$endif USEEXCEPT}
  401. { clear memory }
  402. {$ifdef Splitheap}
  403. if testsplit then
  404. begin
  405. { temp heap should be empty after that !!!}
  406. codegen_donemodule;
  407. Releasetempheap;
  408. end;
  409. {$endif Splitheap}
  410. { restore old state, close trees, > 0.99.5 has heapblocks, so
  411. it's the default to release the trees }
  412. codegen_donemodule;
  413. { free ppu }
  414. if assigned(tppumodule(current_module).ppufile) then
  415. begin
  416. tppumodule(current_module).ppufile.free;
  417. tppumodule(current_module).ppufile:=nil;
  418. end;
  419. { free scanner }
  420. if assigned(current_scanner) then
  421. begin
  422. current_scanner.free;
  423. current_scanner:=nil;
  424. end;
  425. current_module.scanner:=nil;
  426. if (compile_level>1) then
  427. begin
  428. {$ifdef GDB}
  429. dbx_counter:=store_dbx;
  430. {$endif GDB}
  431. { restore scanner }
  432. c:=oldc;
  433. pattern:=oldpattern;
  434. orgpattern:=oldorgpattern;
  435. token:=oldtoken;
  436. idtoken:=oldidtoken;
  437. akttokenpos:=oldtokenpos;
  438. block_type:=old_block_type;
  439. current_scanner:=tscannerfile(old_compiled_module.scanner);
  440. if assigned(current_scanner) then
  441. parser_current_file:=current_scanner.inputfile.name^;
  442. { restore cg }
  443. parse_only:=oldparse_only;
  444. { restore asmlists }
  445. exprasmlist:=oldexprasmlist;
  446. datasegment:=olddatasegment;
  447. bsssegment:=oldbsssegment;
  448. codesegment:=oldcodesegment;
  449. consts:=oldconsts;
  450. debuglist:=olddebuglist;
  451. withdebuglist:=oldwithdebuglist;
  452. importssection:=oldimports;
  453. exportssection:=oldexports;
  454. resourcesection:=oldresource;
  455. rttilist:=oldrttilist;
  456. resourcestringlist:=oldresourcestringlist;
  457. { object data }
  458. ResourceStrings:=OldResourceStrings;
  459. objectlibrary:=oldobjectlibrary;
  460. { restore symtable state }
  461. refsymtable:=oldrefsymtable;
  462. symtablestack:=oldsymtablestack;
  463. defaultsymtablestack:=olddefaultsymtablestack;
  464. aktdefproccall:=oldaktdefproccall;
  465. aktprocsym:=oldaktprocsym;
  466. aktprocdef:=oldaktprocdef;
  467. move(oldoverloaded_operators,overloaded_operators,sizeof(toverloaded_operators));
  468. aktsourcecodepage:=oldsourcecodepage;
  469. aktlocalswitches:=oldaktlocalswitches;
  470. aktmoduleswitches:=oldaktmoduleswitches;
  471. aktalignment:=oldaktalignment;
  472. aktpackenum:=oldaktpackenum;
  473. aktmaxfpuregisters:=oldaktmaxfpuregisters;
  474. aktoutputformat:=oldaktoutputformat;
  475. set_target_asm(aktoutputformat);
  476. aktoptprocessor:=oldaktoptprocessor;
  477. aktspecificoptprocessor:=oldaktspecificoptprocessor;
  478. aktasmmode:=oldaktasmmode;
  479. aktinterfacetype:=oldaktinterfacetype;
  480. aktfilepos:=oldaktfilepos;
  481. aktmodeswitches:=oldaktmodeswitches;
  482. statement_level:=oldstatement_level;
  483. aktexceptblock:=0;
  484. exceptblockcounter:=0;
  485. end
  486. else
  487. begin
  488. parser_current_file:='';
  489. end;
  490. { Shut down things when the last file is compiled }
  491. if (compile_level=1) then
  492. begin
  493. { Close script }
  494. if (not AsmRes.Empty) then
  495. begin
  496. Message1(exec_i_closing_script,AsmRes.Fn);
  497. AsmRes.WriteToDisk;
  498. end;
  499. {$ifdef USEEXCEPT}
  500. if not longjump_used then
  501. {$endif USEEXCEPT}
  502. { do not create browsers on errors !! }
  503. if status.errorcount=0 then
  504. begin
  505. {$ifdef BrowserLog}
  506. { Write Browser Log }
  507. if (cs_browser_log in aktglobalswitches) and
  508. (cs_browser in aktmoduleswitches) then
  509. begin
  510. if browserlog.elements_to_list.empty then
  511. begin
  512. Message1(parser_i_writing_browser_log,browserlog.Fname);
  513. WriteBrowserLog;
  514. end
  515. else
  516. browserlog.list_elements;
  517. end;
  518. {$endif BrowserLog}
  519. { Write Browser Collections }
  520. do_extractsymbolinfo{$ifdef FPC}(){$endif};
  521. end;
  522. if current_module.in_second_compile then
  523. begin
  524. current_module.in_second_compile:=false;
  525. current_module.in_compile:=true;
  526. end
  527. else
  528. current_module.in_compile:=false;
  529. end;
  530. dec(compile_level);
  531. compiled_module:=old_compiled_module;
  532. {$ifdef USEEXCEPT}
  533. if longjump_used then
  534. longjmp(recoverpospointer^,1);
  535. {$endif USEEXCEPT}
  536. end;
  537. end.
  538. {
  539. $Log$
  540. Revision 1.42 2002-08-16 15:31:08 peter
  541. * fixed possible crashes with current_scanner
  542. Revision 1.41 2002/08/15 19:10:35 peter
  543. * first things tai,tnode storing in ppu
  544. Revision 1.40 2002/08/12 16:46:04 peter
  545. * tscannerfile is now destroyed in tmodule.reset and current_scanner
  546. is updated accordingly. This removes all the loading and saving of
  547. the old scanner and the invalid flag marking
  548. Revision 1.39 2002/08/12 15:08:40 carl
  549. + stab register indexes for powerpc (moved from gdb to cpubase)
  550. + tprocessor enumeration moved to cpuinfo
  551. + linker in target_info is now a class
  552. * many many updates for m68k (will soon start to compile)
  553. - removed some ifdef or correct them for correct cpu
  554. Revision 1.38 2002/08/11 14:28:19 peter
  555. * TScannerFile.SetInvalid added that will also reset inputfile
  556. Revision 1.37 2002/08/11 13:24:12 peter
  557. * saving of asmsymbols in ppu supported
  558. * asmsymbollist global is removed and moved into a new class
  559. tasmlibrarydata that will hold the info of a .a file which
  560. corresponds with a single module. Added librarydata to tmodule
  561. to keep the library info stored for the module. In the future the
  562. objectfiles will also be stored to the tasmlibrarydata class
  563. * all getlabel/newasmsymbol and friends are moved to the new class
  564. Revision 1.36 2002/08/09 19:15:41 carl
  565. - removed newcg define
  566. Revision 1.35 2002/07/20 17:16:03 florian
  567. + source code page support
  568. Revision 1.34 2002/07/01 18:46:24 peter
  569. * internal linker
  570. * reorganized aasm layer
  571. Revision 1.33 2002/05/18 13:34:11 peter
  572. * readded missing revisions
  573. Revision 1.32 2002/05/16 19:46:42 carl
  574. + defines.inc -> fpcdefs.inc to avoid conflicts if compiling by hand
  575. + try to fix temp allocation (still in ifdef)
  576. + generic constructor calls
  577. + start of tassembler / tmodulebase class cleanup
  578. Revision 1.30 2002/04/21 18:57:23 peter
  579. * fixed memleaks when file can't be opened
  580. Revision 1.29 2002/04/20 21:32:24 carl
  581. + generic FPC_CHECKPOINTER
  582. + first parameter offset in stack now portable
  583. * rename some constants
  584. + move some cpu stuff to other units
  585. - remove unused constents
  586. * fix stacksize for some targets
  587. * fix generic size problems which depend now on EXTEND_SIZE constant
  588. Revision 1.28 2002/04/19 15:46:02 peter
  589. * mangledname rewrite, tprocdef.mangledname is now created dynamicly
  590. in most cases and not written to the ppu
  591. * add mangeledname_prefix() routine to generate the prefix of
  592. manglednames depending on the current procedure, object and module
  593. * removed static procprefix since the mangledname is now build only
  594. on demand from tprocdef.mangledname
  595. Revision 1.27 2002/01/29 19:43:11 peter
  596. * update target_asm according to outputformat
  597. }