parser.pas 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 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. {$ifdef tp}
  19. {$E+,N+,D+,F+}
  20. {$endif}
  21. unit parser;
  22. interface
  23. procedure compile(const filename:string;compile_system:boolean);
  24. procedure initparser;
  25. implementation
  26. uses
  27. dos,cobjects,globals,scanner,systems,symtable,tree,aasm,
  28. types,strings,pass_1,hcodegen,files,verbose,script,import
  29. {$ifdef i386}
  30. ,i386
  31. ,cgi386
  32. ,cgai386
  33. ,tgeni386
  34. ,aopt386
  35. {$endif i386}
  36. {$ifdef m68k}
  37. ,m68k
  38. ,cg68k
  39. ,tgen68k
  40. ,cga68k
  41. {$endif m68k}
  42. { parser units }
  43. ,pbase,pmodules,pdecl,
  44. { assembling & linking }
  45. assemble,
  46. link;
  47. { dummy variable for search when calling exec }
  48. var
  49. file_found : boolean;
  50. procedure readconstdefs;
  51. begin
  52. s32bitdef:=porddef(globaldef('longint'));
  53. u32bitdef:=porddef(globaldef('ulong'));
  54. cstringdef:=pstringdef(globaldef('string'));
  55. clongstringdef:=pstringdef(globaldef('longstring'));
  56. cansistringdef:=pstringdef(globaldef('ansistring'));
  57. cwidestringdef:=pstringdef(globaldef('widestring'));
  58. cchardef:=porddef(globaldef('char'));
  59. {$ifdef i386}
  60. c64floatdef:=pfloatdef(globaldef('s64real'));
  61. {$endif}
  62. {$ifdef m68k}
  63. c64floatdef:=pfloatdef(globaldef('s32real'));
  64. {$endif m68k}
  65. s80floatdef:=pfloatdef(globaldef('s80real'));
  66. s32fixeddef:=pfloatdef(globaldef('cs32fixed'));
  67. voiddef:=porddef(globaldef('void'));
  68. u8bitdef:=porddef(globaldef('byte'));
  69. u16bitdef:=porddef(globaldef('word'));
  70. booldef:=porddef(globaldef('boolean'));
  71. voidpointerdef:=ppointerdef(globaldef('void_pointer'));
  72. cfiledef:=pfiledef(globaldef('file'));
  73. end;
  74. procedure initparser;
  75. begin
  76. forwardsallowed:=false;
  77. { ^M means a string or a char, because we don't parse a }
  78. { type declaration }
  79. block_type:=bt_general;
  80. ignore_equal:=false;
  81. { we didn't parse a object or class declaration }
  82. { and no function header }
  83. testcurobject:=0;
  84. { create error defintion }
  85. generrordef:=new(perrordef,init);
  86. symtablestack:=nil;
  87. { a long time, this was forgotten }
  88. aktprocsym:=nil;
  89. current_module:=nil;
  90. loaded_units.init;
  91. usedunits.init;
  92. end;
  93. { moved out to save stack }
  94. var
  95. addparam : string;
  96. procedure compile(const filename:string;compile_system:boolean);
  97. var
  98. hp : pmodule;
  99. old_comp_unit : boolean;
  100. { some variables to save the compiler state }
  101. oldtoken : ttoken;
  102. {$ifdef UseTokenInfo}
  103. oldtokenpos : tfileposinfo;
  104. {$endif UseTokenInfo}
  105. oldpattern : stringid;
  106. oldpreprocstack : ppreprocstack;
  107. oldorgpattern,oldprocprefix : string;
  108. old_block_type : tblock_type;
  109. oldinputbuffer,
  110. oldinputpointer : pchar;
  111. olds_point,oldparse_only : boolean;
  112. oldc : char;
  113. oldcomment_level : word;
  114. oldimports,oldexports,oldresource,oldrttilist,
  115. oldbsssegment,olddatasegment,oldcodesegment,
  116. oldexprasmlist,olddebuglist,
  117. oldinternals,oldexternals,oldconsts : paasmoutput;
  118. oldnextlabelnr : longint;
  119. oldswitches : Tcswitches;
  120. oldmacros,oldrefsymtable,oldsymtablestack : psymtable;
  121. procedure def_macro(const s : string);
  122. var
  123. mac : pmacrosym;
  124. begin
  125. mac:=pmacrosym(macros^.search(s));
  126. if mac=nil then
  127. begin
  128. mac:=new(pmacrosym,init(s));
  129. Message1(parser_m_macro_defined,mac^.name);
  130. macros^.insert(mac);
  131. end;
  132. mac^.defined:=true;
  133. end;
  134. procedure set_macro(const s : string;value : string);
  135. var
  136. mac : pmacrosym;
  137. begin
  138. mac:=pmacrosym(macros^.search(s));
  139. if mac=nil then
  140. begin
  141. mac:=new(pmacrosym,init(s));
  142. macros^.insert(mac);
  143. end
  144. else
  145. begin
  146. if assigned(mac^.buftext) then
  147. freemem(mac^.buftext,mac^.buflen);
  148. end;
  149. Message2(parser_m_macro_set_to,mac^.name,value);
  150. mac^.buflen:=length(value);
  151. getmem(mac^.buftext,mac^.buflen);
  152. move(value[1],mac^.buftext^,mac^.buflen);
  153. mac^.defined:=true;
  154. end;
  155. procedure define_macros;
  156. var
  157. hp : pstring_item;
  158. begin
  159. hp:=pstring_item(commandlinedefines.first);
  160. while assigned(hp) do
  161. begin
  162. def_macro(hp^.str^);
  163. hp:=pstring_item(hp^.next);
  164. end;
  165. { set macros for version checking }
  166. set_macro('FPC_VERSION',version_nr);
  167. set_macro('FPC_RELEASE',release_nr);
  168. set_macro('FPC_PATCH',patch_nr);
  169. end;
  170. label
  171. done;
  172. begin {compile}
  173. inc(compile_level);
  174. { save old state }
  175. { save symtable state }
  176. oldsymtablestack:=symtablestack;
  177. symtablestack:=nil;
  178. oldrefsymtable:=refsymtable;
  179. refsymtable:=nil;
  180. oldprocprefix:=procprefix;
  181. old_comp_unit:=comp_unit;
  182. { a long time, this was only in init_parser
  183. but it should be reset to zero for each module }
  184. aktprocsym:=nil;
  185. { first, we assume a program }
  186. if not(assigned(current_module)) then
  187. begin
  188. current_module:=new(pmodule,init(filename,false));
  189. main_module:=current_module;
  190. end;
  191. { save scanner state }
  192. oldmacros:=macros;
  193. oldpattern:=pattern;
  194. oldtoken:=token;
  195. {$ifdef UseTokenInfo}
  196. oldtokenpos:=tokenpos;
  197. {$endif UseTokenInfo}
  198. oldorgpattern:=orgpattern;
  199. old_block_type:=block_type;
  200. oldpreprocstack:=preprocstack;
  201. oldinputbuffer:=inputbuffer;
  202. oldinputpointer:=inputpointer;
  203. olds_point:=s_point;
  204. oldc:=c;
  205. oldcomment_level:=comment_level;
  206. oldparse_only:=parse_only;
  207. { save assembler lists }
  208. olddatasegment:=datasegment;
  209. oldbsssegment:=bsssegment;
  210. oldcodesegment:=codesegment;
  211. olddebuglist:=debuglist;
  212. oldexternals:=externals;
  213. oldinternals:=internals;
  214. oldconsts:=consts;
  215. oldrttilist:=rttilist;
  216. oldexprasmlist:=exprasmlist;
  217. oldimports:=importssection;
  218. oldexports:=exportssection;
  219. oldresource:=resourcesection;
  220. oldswitches:=aktswitches;
  221. oldnextlabelnr:=nextlabelnr;
  222. Message1(parser_i_compiling,filename);
  223. InitScanner(filename);
  224. aktswitches:=initswitches;
  225. { we need this to make the system unit }
  226. if compile_system then
  227. aktswitches:=aktswitches+[cs_compilesystem];
  228. aktpackrecords:=initpackrecords;
  229. { init code generator for a new module }
  230. codegen_newmodule;
  231. macros:=new(psymtable,init(macrosymtable));
  232. define_macros;
  233. { startup scanner }
  234. token:=yylex;
  235. reset_gdb_info;
  236. { init asm writing }
  237. datasegment:=new(paasmoutput,init);
  238. codesegment:=new(paasmoutput,init);
  239. bsssegment:=new(paasmoutput,init);
  240. debuglist:=new(paasmoutput,init);
  241. externals:=new(paasmoutput,init);
  242. internals:=new(paasmoutput,init);
  243. consts:=new(paasmoutput,init);
  244. rttilist:=new(paasmoutput,init);
  245. importssection:=nil;
  246. exportssection:=nil;
  247. resourcesection:=nil;
  248. { global switches are read, so further changes aren't allowed }
  249. current_module^.in_main:=true;
  250. { open assembler response }
  251. if (compile_level=1) then
  252. AsmRes.Init('ppas');
  253. { if the current file isn't a system unit }
  254. { the the system unit will be loaded }
  255. if not(cs_compilesystem in aktswitches) then
  256. begin
  257. { should be done in unit system (changing the field system_unit)
  258. FK
  259. }
  260. hp:=loadunit(upper(target_info.system_unit),true,true);
  261. systemunit:=hp^.symtable;
  262. readconstdefs;
  263. { we could try to overload caret by default }
  264. symtablestack:=systemunit;
  265. { if POWER is defined in the RTL then use it for starstar overloading }
  266. getsym('POWER',false);
  267. if assigned(srsym) and (srsym^.typ=procsym) and
  268. (overloaded_operators[STARSTAR]=nil) then
  269. overloaded_operators[STARSTAR]:=pprocsym(srsym);
  270. end
  271. else
  272. begin
  273. { create definitions for constants }
  274. registerdef:=false;
  275. s32bitdef:=new(porddef,init(s32bit,$80000000,$7fffffff));
  276. u32bitdef:=new(porddef,init(u32bit,0,$ffffffff));
  277. cstringdef:=new(pstringdef,init(255));
  278. { should we give a length to the default long and ansi string definition ?? }
  279. clongstringdef:=new(pstringdef,longinit(-1));
  280. cansistringdef:=new(pstringdef,ansiinit(-1));
  281. cwidestringdef:=new(pstringdef,wideinit(-1));
  282. cchardef:=new(porddef,init(uchar,0,255));
  283. {$ifdef i386}
  284. c64floatdef:=new(pfloatdef,init(s64real));
  285. s80floatdef:=new(pfloatdef,init(s80real));
  286. {$endif}
  287. {$ifdef m68k}
  288. c64floatdef:=new(pfloatdef,init(s32real));
  289. if (cs_fp_emulation in aktswitches) then
  290. s80floatdef:=new(pfloatdef,init(s32real))
  291. else
  292. s80floatdef:=new(pfloatdef,init(s80real));
  293. {$endif}
  294. s32fixeddef:=new(pfloatdef,init(f32bit));
  295. { some other definitions }
  296. voiddef:=new(porddef,init(uvoid,0,0));
  297. u8bitdef:=new(porddef,init(u8bit,0,255));
  298. u16bitdef:=new(porddef,init(u16bit,0,65535));
  299. booldef:=new(porddef,init(bool8bit,0,1));
  300. voidpointerdef:=new(ppointerdef,init(voiddef));
  301. cfiledef:=new(pfiledef,init(ft_untyped,nil));
  302. systemunit:=nil;
  303. end;
  304. registerdef:=true;
  305. { current return type is void }
  306. procinfo.retdef:=voiddef;
  307. { reset lexical level }
  308. lexlevel:=0;
  309. { parse source }
  310. {***BUGFIX}
  311. if (token=_UNIT) or (compile_level>1) then
  312. begin
  313. {If the compile level > 1 we get a nice "unit expected" error
  314. message if we are trying to use a program as unit.}
  315. proc_unit;
  316. if current_module^.compiled then
  317. goto done;
  318. comp_unit:=true;
  319. end
  320. else
  321. begin
  322. proc_program(token=_LIBRARY);
  323. comp_unit:=false;
  324. end;
  325. { Why? The definition of Pascal requires that everything
  326. after 'end.' is ignored!
  327. if not(cs_tp_compatible in aktswitches) then
  328. consume(_EOF); }
  329. if errorcount=0 then
  330. begin
  331. if current_module^.uses_imports then
  332. importlib^.generatelib;
  333. GenerateAsm(filename);
  334. if smartlink then
  335. begin
  336. Linker.SetLibName(FileName);
  337. Linker.MakeStaticLibrary(SmartLinkPath(FileName),SmartLinkFilesCnt);
  338. end;
  339. { add the files for the linker from current_module, this must be
  340. after the makestaticlibrary, because it will add the library
  341. name (PFV) }
  342. addlinkerfiles(current_module);
  343. { Check linking => we are at first level in compile }
  344. if (compile_level=1) then
  345. begin
  346. if not comp_unit then
  347. begin
  348. if (cs_no_linking in initswitches) then
  349. externlink:=true;
  350. if Linker.ExeName='' then
  351. Linker.SetExeName(FileName);
  352. Linker.MakeExecutable;
  353. end;
  354. end;
  355. end
  356. else
  357. begin
  358. Message1(unit_e_total_errors,tostr(errorcount));
  359. Message(unit_f_errors_in_unit);
  360. end;
  361. { clear memory }
  362. {$ifdef Splitheap}
  363. if testsplit then
  364. begin
  365. { temp heap should be empty after that !!!}
  366. codegen_donemodule;
  367. Releasetempheap;
  368. end;
  369. {else
  370. codegen_donemodule;}
  371. {$endif Splitheap}
  372. { restore old state }
  373. { if already compiled jumps directly here }
  374. done:
  375. { close trees }
  376. if dispose_asm_lists then
  377. begin
  378. dispose(datasegment,Done);
  379. dispose(codesegment,Done);
  380. dispose(bsssegment,Done);
  381. dispose(debuglist,Done);
  382. dispose(externals,Done);
  383. dispose(internals,Done);
  384. dispose(consts,Done);
  385. end;
  386. reset_gdb_info;
  387. { restore symtable state }
  388. {$ifdef UseBrowser}
  389. if (compile_level>1) then
  390. { we want to keep the current symtablestack }
  391. {$endif UseBrowser}
  392. begin
  393. refsymtable:=oldrefsymtable;
  394. symtablestack:=oldsymtablestack;
  395. end;
  396. procprefix:=oldprocprefix;
  397. { close the inputfiles }
  398. {$ifndef UseBrowser}
  399. { but not if we want the names for the browser ! }
  400. current_module^.sourcefiles.done;
  401. {$endif not UseBrowser}
  402. { restore scanner state }
  403. pattern:=oldpattern;
  404. token:=oldtoken;
  405. {$ifdef UseTokenInfo}
  406. tokenpos:=oldtokenpos;
  407. {$endif UseTokenInfo}
  408. orgpattern:=oldorgpattern;
  409. block_type:=old_block_type;
  410. comp_unit:=old_comp_unit;
  411. { call donescanner before restoring preprocstack, because }
  412. { donescanner tests for a empty preprocstack }
  413. { and can also check for unused macros }
  414. donescanner(current_module^.compiled);
  415. dispose(macros,done);
  416. macros:=oldmacros;
  417. preprocstack:=oldpreprocstack;
  418. aktswitches:=oldswitches;
  419. inputbuffer:=oldinputbuffer;
  420. inputpointer:=oldinputpointer;
  421. s_point:=olds_point;
  422. c:=oldc;
  423. comment_level:=oldcomment_level;
  424. parse_only:=oldparse_only;
  425. { restore asmlists }
  426. datasegment:=olddatasegment;
  427. bsssegment:=oldbsssegment;
  428. codesegment:=oldcodesegment;
  429. debuglist:=olddebuglist;
  430. externals:=oldexternals;
  431. internals:=oldinternals;
  432. importssection:=oldimports;
  433. exportssection:=oldexports;
  434. resourcesection:=oldresource;
  435. nextlabelnr:=oldnextlabelnr;
  436. exprasmlist:=oldexprasmlist;
  437. consts:=oldconsts;
  438. nextlabelnr:=oldnextlabelnr;
  439. if (compile_level=1) then
  440. begin
  441. if (not AsmRes.Empty) then
  442. begin
  443. Message1(exec_i_closing_script,AsmRes.Fn);
  444. AsmRes.WriteToDisk;
  445. end;
  446. end;
  447. dec(compile_level);
  448. end;
  449. end.
  450. {
  451. $Log$
  452. Revision 1.15 1998-05-11 13:07:54 peter
  453. + $ifdef NEWPPU for the new ppuformat
  454. + $define GDB not longer required
  455. * removed all warnings and stripped some log comments
  456. * no findfirst/findnext anymore to remove smartlink *.o files
  457. Revision 1.14 1998/05/06 18:36:53 peter
  458. * tai_section extended with code,data,bss sections and enumerated type
  459. * ident 'compiled by FPC' moved to pmodules
  460. * small fix for smartlink
  461. Revision 1.13 1998/05/06 08:38:42 pierre
  462. * better position info with UseTokenInfo
  463. UseTokenInfo greatly simplified
  464. + added check for changed tree after first time firstpass
  465. (if we could remove all the cases were it happen
  466. we could skip all firstpass if firstpasscount > 1)
  467. Only with ExtDebug
  468. Revision 1.12 1998/05/04 17:54:28 peter
  469. + smartlinking works (only case jumptable left todo)
  470. * redesign of systems.pas to support assemblers and linkers
  471. + Unitname is now also in the PPU-file, increased version to 14
  472. Revision 1.11 1998/05/01 16:38:45 florian
  473. * handling of private and protected fixed
  474. + change_keywords_to_tp implemented to remove
  475. keywords which aren't supported by tp
  476. * break and continue are now symbols of the system unit
  477. + widestring, longstring and ansistring type released
  478. Revision 1.10 1998/05/01 07:43:56 florian
  479. + basics for rtti implemented
  480. + switch $m (generate rtti for published sections)
  481. Revision 1.9 1998/04/30 15:59:40 pierre
  482. * GDB works again better :
  483. correct type info in one pass
  484. + UseTokenInfo for better source position
  485. * fixed one remaining bug in scanner for line counts
  486. * several little fixes
  487. Revision 1.8 1998/04/29 10:33:55 pierre
  488. + added some code for ansistring (not complete nor working yet)
  489. * corrected operator overloading
  490. * corrected nasm output
  491. + started inline procedures
  492. + added starstarn : use ** for exponentiation (^ gave problems)
  493. + started UseTokenInfo cond to get accurate positions
  494. Revision 1.7 1998/04/27 23:10:28 peter
  495. + new scanner
  496. * $makelib -> if smartlink
  497. * small filename fixes pmodule.setfilename
  498. * moved import from files.pas -> import.pas
  499. Revision 1.6 1998/04/21 10:16:48 peter
  500. * patches from strasbourg
  501. * objects is not used anymore in the fpc compiled version
  502. Revision 1.5 1998/04/10 14:41:43 peter
  503. * removed some Hints
  504. * small speed optimization for AsmLn
  505. Revision 1.4 1998/04/08 16:58:03 pierre
  506. * several bugfixes
  507. ADD ADC and AND are also sign extended
  508. nasm output OK (program still crashes at end
  509. and creates wrong assembler files !!)
  510. procsym types sym in tdef removed !!
  511. Revision 1.3 1998/04/07 22:45:04 florian
  512. * bug0092, bug0115 and bug0121 fixed
  513. + packed object/class/array
  514. }