test_parser.pp 62 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985
  1. { This is a test-program for the fcl-passrc package (except writer-class).
  2. Please notice that i have done this to find out how good the parser workes,
  3. it is not thought to be a good example to use the fcl-passrc package but
  4. may give you hints on using it.
  5. It is done to test the source of these units for usability, completeness and
  6. bugs. It is base on the fcl-passrc exampe.
  7. It workes like a pretty-printer to compare the output of this program with
  8. the original code, but is not thought to be a real pretty-printer as
  9. e.g. the semicolons can sometimes not be set at the place they sould be
  10. (this imformation is not available from the parsing-engine, as a parser
  11. should only give you a positiv result if the source is valid, otherwise
  12. you get a negative result).
  13. Also the output is not always in the same order as in input as this
  14. information is not available easily.
  15. !!!Do not expect this program to produce executeable output!!!
  16. Status: -workes with one Unit or Program
  17. -Some type declarations missing
  18. -string[n] the [n] part missing -> missing in parser
  19. -array of const -> missing in parser
  20. -Hints deprecated, etc. missing sometimes
  21. -the parser splits x,y:atype
  22. x:atype
  23. y:atype
  24. i tryed to put them together again
  25. - () missing in statements: () expression and typecast
  26. -missing forward class declaration like x=class
  27. -incomplete !
  28. parser: -ugly ''' quotation from scanner, why not #39 ?
  29. -see comments in the program for hints
  30. -incomplete !
  31. Usage: call with one complete filename of a Unit or Program
  32. defaults for the parser are 'linux' and 'i386'
  33. Output: is 'pretty-printed' to stdout or unformated
  34. The unformated output is thought to be diffed with the original
  35. source to see differences caused by the parser (a tool to unformat
  36. a souce file is in progress but not finished jet).
  37. Bugs: 1. In case of unimplemented statements (like up to now asm) the parser
  38. cause a excemtion to abort the program hard.
  39. 2. Missing implementaion in this program should not print out anything
  40. or result in not pascal conform output.
  41. Hit: The parser uses directives given in the source file.
  42. Hints to read the code:
  43. There are comments in the code with hints and marks of possible bugs.
  44. During development some code was modified for true order output but the
  45. old code is still available as a comment as it is easier to understand.
  46. This is programmed using 'recursive' calls. Most options in functions are
  47. for printing the output.
  48. There is no writer-class used to keep it simple and see what is done.
  49. All output is produced by direct writing to stdout, this cause problems in
  50. furter development; a function result as string may be more usable.
  51. The parser was written to be used for unit interface and was expanded to
  52. work with program and implementation too. It does nearly no seperate
  53. things for programs, they are adapted to the unit scheme (see main).
  54. The order will change in following case:
  55. -function with forward declaration (also overloading etc.)
  56. Inheritance (only the important ones):
  57. TInterfaceSection, TImplementationSection, TProgramSection
  58. |
  59. TPasSection
  60. |
  61. TPasDeclarations
  62. |
  63. TPasElement
  64. |
  65. TPasElementBase
  66. |
  67. TObject
  68. TInitializationSection, TFinalizationSection
  69. |
  70. TPasImplBlock
  71. |
  72. TPasImplElement
  73. |
  74. TPasElement
  75. |
  76. TPasElementBase
  77. |
  78. TObject
  79. TPasProgram
  80. |
  81. TPasModule
  82. |
  83. TPasElement
  84. |
  85. TPasElementBase
  86. |
  87. TObject
  88. Dependance Structure :
  89. TPasPackage = class(TPasElement)
  90. |
  91. Modules: TList;
  92. TPasModule = class(TPasElement)
  93. |-InterfaceSection: TInterfaceSection;
  94. | |-Declarations -> forward part, unit only
  95. |
  96. |-ImplementationSection: TImplementationSection;
  97. | |-Declarations -> full declaration, unit and program
  98. | |-Functions: TList;
  99. | |-TPasFunction = class(TPasProcedureBase)
  100. | |-Body: TProcedureBody;
  101. | |-Declarations -> declaration and sub function
  102. | |-Body: TPasImplBlock; -> procedure block
  103. |
  104. |-InitializationSection: TInitializationSection;
  105. | |-TPasImplBlock.Elements: TList; -> main block
  106. |
  107. |-FinalizationSection: TFinalizationSection;
  108. |-TPasImplBlock.Elements: TList; -> unit only
  109. Declarations = class(TPasElement)
  110. |-Declarations: TList; -> the following are all in here
  111. |-ResStrings: TList;
  112. |-Types: TList;
  113. |-Consts: TList;
  114. |-Classes: TList;
  115. |-Functions: TList;
  116. |-Variables: TList;
  117. |-Properties: TList;
  118. }
  119. program test_parser1;
  120. {$mode objfpc}{$H+}
  121. uses SysUtils, Classes, PParser, PasTree;
  122. //# types the parser needs
  123. type
  124. { We have to override abstract TPasTreeContainer methods.
  125. See utils/fpdoc/dglobals.pp for an implementation of TFPDocEngine,
  126. a "real" engine. }
  127. TSimpleEngine = class(TPasTreeContainer)
  128. public
  129. function CreateElement(AClass: TPTreeElement; const AName: String;
  130. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  131. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  132. override;
  133. function FindElement(const AName: String): TPasElement; override;
  134. end;
  135. function TSimpleEngine.CreateElement(AClass: TPTreeElement; const AName: String;
  136. AParent: TPasElement; AVisibility: TPasMemberVisibility;
  137. const ASourceFilename: String; ASourceLinenumber: Integer): TPasElement;
  138. begin
  139. Result := AClass.Create(AName, AParent);
  140. Result.Visibility := AVisibility;
  141. Result.SourceFilename := ASourceFilename;
  142. Result.SourceLinenumber := ASourceLinenumber;
  143. end;
  144. function TSimpleEngine.FindElement(const AName: String): TPasElement;
  145. begin
  146. { dummy implementation, see TFPDocEngine.FindElement for a real example }
  147. Result := nil;
  148. end;
  149. //# main var
  150. var
  151. M: TPasModule;
  152. E: TPasTreeContainer;
  153. I: Integer;
  154. cmdl, TargetOS, TargetCPU : string;
  155. isim, //is Impleamentation, only for GetTPasProcedureBody
  156. Unformated:boolean; // no Formating in output
  157. //# tools
  158. function GetIndent(indent:integer):String;
  159. var i:integer;
  160. begin
  161. Result:='';
  162. if not Unformated then
  163. for i:=1 to indent do Result:=Result+' ';
  164. end;
  165. //delete ugly quoting '''STRING'''
  166. function DelQuot(s:String):String;
  167. var i:integer;
  168. const s1=#39#39#39;
  169. begin
  170. Result:='';
  171. i:=pos(s1,s);
  172. while i > 0 do
  173. begin
  174. if i > 0 then delete(s,i,2);
  175. i:=pos(s1,s);
  176. end;
  177. //if i > 0 then delete(s,i,2);
  178. Result:=s;
  179. end;
  180. //LeadingSpace only valid if Formated output (as this will be one line in output)
  181. //UnFormated: all is printed in a new line
  182. procedure WriteFmt(LeadingSpace:boolean; s:String; Semicolon:boolean);
  183. begin
  184. if Semicolon then s:=s+';';
  185. if Unformated then writeln(s)
  186. else if LeadingSpace then write(' ',s)
  187. else write(s);
  188. end;
  189. //# parsing output
  190. function GetTPasImplBlock(lb:TPasImplBlock; indent,declistby:integer;
  191. LastNoSem,NoFirstIndent:boolean):boolean; forward;
  192. function GetTPasImplElement(le:TPasImplElement; lindent:integer;
  193. lLastNoSem,NoFirstIndent:boolean):boolean; forward;
  194. procedure GetDecls(Decl:TPasDeclarations; indent:integer); forward;
  195. //procedure PrintDecls(Decl:TPasDeclarations; indent:integer); forward;
  196. //# most is for implementation or implblocks except the expr things
  197. function ReturnTPasMemberHints(h:TPasMemberHints):String;
  198. begin
  199. Result:='';
  200. if hDeprecated in h then Result:=' deprecated';
  201. if hLibrary in h then Result:=Result+' library';
  202. if hPlatform in h then Result:=Result+' platform';
  203. if hExperimental in h then Result:=Result+' experimental';
  204. if hUnimplemented in h then Result:=Result+' unimplemented';
  205. end;
  206. function GetTPasMemberHints(h:TPasMemberHints):Boolean;
  207. begin
  208. Result:=false;
  209. if hDeprecated in h then begin write(' deprecated'); Result:=true; end;
  210. if hLibrary in h then begin write(' library'); Result:=true; end;
  211. if hPlatform in h then begin write(' platform'); Result:=true; end;
  212. if hExperimental in h then begin write(' experimental'); Result:=true; end;
  213. if hUnimplemented in h then begin write(' unimplemented'); Result:=true; end;
  214. end;
  215. function GetTPasExprKind(lpek:TPasExprKind):String;
  216. begin
  217. Result:='';
  218. case lpek of
  219. pekIdent:Result:='ID';
  220. pekNumber:Result:='NUMBER';
  221. pekString:Result:='STRING';
  222. pekSet:Result:='SET';
  223. pekNil:Result:='NIL';
  224. pekBoolConst:Result:='BOOL';
  225. pekRange:Result:='RANGE';
  226. pekUnary:Result:='UNARY';
  227. pekBinary:Result:='BINARY';
  228. pekFuncParams:Result:='FUNCPAR';
  229. pekArrayParams:Result:='ARRAYPAR';
  230. pekListOfExp:Result:='EXPLIST';
  231. end;
  232. end;
  233. procedure GetTPasExpr(lex:TPasExpr);
  234. var lex1:TpasExpr;
  235. lpe:TParamsExpr;
  236. l:integer;
  237. lbk,rbk,sep:string;
  238. lav:TArrayValues;
  239. lrv:TRecordValues;
  240. rvi:TRecordValuesItem;
  241. function GetExpKind(ek:TPasExprKind; var lbrak,rbrak:string):string;
  242. begin
  243. lbrak:='';
  244. rbrak:='';
  245. Result:='';
  246. case ek of
  247. pekIdent:Result:='ID';
  248. pekNumber:Result:='NU';
  249. pekString:begin lbrak:=#39; rbrak:=#39; Result:=#39; end;
  250. pekSet:begin lbrak:='['; rbrak:=']'; Result:=','; end;
  251. pekNil:Result:='NIL';
  252. pekBoolConst:Result:='';
  253. pekRange:Result:='..';
  254. pekUnary:Result:='';
  255. pekBinary:Result:='';
  256. pekFuncParams:begin lbrak:='('; rbrak:=')'; Result:=','; end;
  257. pekArrayParams:begin lbrak:='['; rbrak:=']'; Result:=','; end;
  258. pekListOfExp:Result:=',';
  259. pekInherited:Result:=' InheriteD';
  260. pekSelf:Result:=' SelF';
  261. end;
  262. end;
  263. function GetOp(lop:TExprOpCode):string;
  264. begin
  265. Result:='';
  266. case lop of
  267. eopNone:Result:='';
  268. eopAdd:Result:='+';
  269. eopSubtract:Result:='-';
  270. eopMultiply:Result:='*';
  271. eopDivide:Result:='/';
  272. eopDiv:Result:=' div ';
  273. eopMod:Result:=' mod ';
  274. eopPower:Result:='^';
  275. eopShr:Result:=' shr ';
  276. eopSHl:Result:=' shl ';
  277. eopNot:Result:=' not ';
  278. eopAnd:Result:=' and ';
  279. eopOr:Result:=' or ';
  280. eopXor:Result:=' xor ';
  281. eopEqual:Result:='=';
  282. eopNotEqual:Result:='<>';
  283. eopLessThan:Result:='<';
  284. eopGreaterThan:Result:='>';
  285. eopLessthanEqual:Result:='<=';
  286. eopGreaterThanEqual:Result:='>=';
  287. eopIn:Result:=' in ';
  288. eopIs:Result:=' is ';
  289. eopAs:Result:=' as ';
  290. eopSymmetricaldifference:Result:='><';
  291. eopAddress:Result:='@';
  292. eopDeref:Result:='^';
  293. eopSubIdent:Result:='.';
  294. end;
  295. end;
  296. begin
  297. if lex is TBinaryExpr then //compined constants
  298. begin
  299. sep:=GetExpKind(lex.Kind,lbk,rbk);
  300. //write('|');
  301. write(lbk);
  302. GetTPasExpr(TBinaryExpr(lex).left);
  303. write(GetOp(TBinaryExpr(lex).OpCode));
  304. write(sep);
  305. GetTPasExpr(TBinaryExpr(lex).right);
  306. write(rbk);
  307. //write('|');
  308. //write(' [',lex.Name,' ',GetTPasExprKind(lex.Kind),']');
  309. end
  310. else
  311. begin
  312. //write('UNARY');
  313. if lex is TUnaryExpr then
  314. begin
  315. lex1:=TUnaryExpr(lex).Operand;
  316. if lex.OpCode = eopDeref then
  317. begin
  318. GetTPasExpr(lex1);
  319. write(GetOp(lex.OpCode)); //unary last, only: p^
  320. end
  321. else
  322. begin
  323. write(GetOp(lex.OpCode)); //unary first: -1
  324. GetTPasExpr(lex1);
  325. end;
  326. end;
  327. if lex is TPrimitiveExpr then write(TPrimitiveExpr(lex).Value) //simple constant
  328. else
  329. if lex is TBoolConstExpr then write(TBoolConstExpr(lex).Value)
  330. else
  331. if lex is TNilExpr then write('nil')
  332. else
  333. if lex is TInheritedExpr then write('Inherited ')
  334. else
  335. if lex is TSelfExpr then write('Self')
  336. else
  337. if lex is TParamsExpr then //writeln(param1,param2,..,paramn);
  338. begin
  339. //write(' PAREX ');
  340. lpe:=TParamsExpr(lex);
  341. GetTPasExpr(lpe.Value);
  342. if length(lpe.Params) >0 then
  343. begin
  344. sep:=GetExpKind(lpe.Kind,lbk,rbk);
  345. write(lbk); //write('(');
  346. for l:=0 to High(lpe.Params)-1 do
  347. begin
  348. GetTPasExpr(lpe.Params[l]);
  349. write(sep); //seperator
  350. end;
  351. GetTPasExpr(lpe.Params[High(lpe.Params)]);
  352. write(rbk);//write(')');
  353. end
  354. else
  355. begin //funcion()
  356. sep:=GetExpKind(lpe.Kind,lbk,rbk);
  357. write(lbk,rbk);
  358. end;
  359. end
  360. else if lex is TArrayValues then //const AnArrayConst: Array[1..3] of Integer = (1,2,3);
  361. begin
  362. write('(');
  363. lav:=TArrayValues(lex);
  364. if length(lav.Values) > 0 then
  365. begin
  366. for l:=0 to high(lav.Values)-1 do
  367. begin
  368. GetTPasExpr(TPasExpr(lav.Values[l]));
  369. write(',');
  370. end;
  371. GetTPasExpr(TPasExpr(lav.Values[high(lav.Values)]));
  372. end;
  373. write(')');
  374. end
  375. else if lex is TRecordValues then
  376. begin
  377. write('(');
  378. lrv:=TRecordValues(lex);
  379. if length(lrv.Fields) > 0 then
  380. begin
  381. for l:=0 to high(lrv.Fields)-1 do
  382. begin
  383. rvi:=TRecordValuesItem(lrv.Fields[l]);
  384. write(rvi.Name,':');
  385. GetTPasExpr(rvi.ValueExp);
  386. write(';');
  387. end;
  388. rvi:=TRecordValuesItem(lrv.Fields[high(lrv.Fields)]);
  389. write(rvi.Name,':');
  390. GetTPasExpr(rvi.ValueExp);
  391. end;
  392. write(')');
  393. end
  394. else
  395. begin
  396. //?
  397. //writeln('{ Unknown Expression: ');
  398. //if assigned(lex) then GetTPasExprKind(lex.Kind);
  399. //writeln('}');
  400. end;
  401. end;
  402. end;
  403. //NoFirstIndent only for block in case:
  404. procedure GetTPasSmt(lsmt:TPasImplStatement; lindent:integer; DoNoSem,NoFirstIndent:boolean);
  405. var l:integer;
  406. lics:TPasImplCaseStatement;
  407. DoSem:boolean;
  408. liwd:TPasImplWithDo;
  409. liwhd:TPasImplWhileDo;
  410. lieo:TPasImplExceptOn;
  411. lifl:TPasImplForLoop;
  412. lir:TPasImplRaise;
  413. s,s1:String;//s1 only first line of block statement
  414. begin
  415. DoSem:=true;
  416. s:=GetIndent(lindent);
  417. if NoFirstIndent then s1:=' ' else s1:=s;
  418. if lsmt is TPasImplSimple then
  419. begin
  420. write(s1); GetTPasExpr(TPasImplSimple(lsmt).expr);
  421. //DoSem:=true;
  422. end
  423. else if lsmt is TPasImplAssign then
  424. begin
  425. write(s1); GetTPasExpr(TPasImplAssign(lsmt).left);
  426. write(':= ');
  427. GetTPasExpr(TPasImplAssign(lsmt).right);
  428. //DoSem:=true;
  429. end
  430. else if lsmt is TPasImplCaseStatement then
  431. begin
  432. lics:=TPasImplCaseStatement(lsmt);
  433. if lics.Expressions.Count>0 then
  434. begin
  435. write(s);
  436. for l:=0 to lics.Expressions.Count-2 do
  437. write(DelQuot(lics.Expressions[l]),',');
  438. write(DelQuot(lics.Expressions[lics.Expressions.Count-1]),': '); // !!bug too much ' in expression
  439. //if not assigned(lics.Body) then writeln('TPasImplCaseStatement missing BODY');
  440. //if assigned(lics.Body) and (TPasImplBlock(lics.Body).Elements.Count >0) then
  441. // GetTPasImplBlock(TPasImplBlock(lics.Body),lindent+1,0,false,true)
  442. // else GetTPasImplBlock(TPasImplBlock(lics),lindent+1,0,false,true); // !!bug missing body, assigned but empty
  443. if assigned(lics.Body) then
  444. begin
  445. if not GetTPasImplElement(lics.Body,lindent+1,false,true) then ;//writeln(';');
  446. end
  447. else writeln(';');
  448. end;
  449. DoSem:=false;
  450. end
  451. else if lsmt is TPasImplWithDo then
  452. begin
  453. liwd:=TPasImplWithDo(lsmt); // !!Bug: missing with do at following with do !solved see Bug
  454. write(s1,'with ',liwd.Name);
  455. if liwd.Expressions.Count>0 then
  456. begin
  457. for l:=0 to liwd.Expressions.Count-2 do
  458. write(liwd.Expressions[l],',');
  459. write(liwd.Expressions[liwd.Expressions.Count-1]);
  460. end;
  461. writeln(' do');
  462. //if TPasImplBlock(liwd.Body).Elements.Count >0 then
  463. //GetTPasImplBlock(TPasImplBlock(liwd.Body),0); // !!Bug: BODY Not used
  464. //else
  465. GetTPasImplBlock(TPasImplBlock(liwd),lindent+1,0,false,false);
  466. DoSem:=false;
  467. end
  468. else if lsmt is TPasImplWhileDo then
  469. begin
  470. liwhd:=TPasImplWhileDo(lsmt);
  471. writeln(s1,'while ',DelQuot(liwhd.Condition),' do');
  472. //if not GetTPasImplBlock(TPasImplBlock(liwhd.Body),0) then // !!Bug: BODY Not used
  473. GetTPasImplBlock(TPasImplBlock(liwhd),lindent,0,DoNoSem,false); //OK for all constructs
  474. DoNoSem:=false; //?
  475. DoSem:=false;
  476. end
  477. else if lsmt is TPasImplExceptOn then
  478. begin
  479. lieo:=TPasImplExceptOn(lsmt);
  480. writeln(s,'on ',lieo.VariableName,': ',lieo.TypeName,' do');
  481. if TPasImplBlock(lieo.Body) is TPasImplRaise then
  482. begin
  483. write(s,'raise ');//raise is in TPasImplBlock in this case
  484. GetTPasImplBlock(TPasImplBlock(lieo.Body),lindent+1,0,false,true);
  485. end
  486. else GetTPasImplBlock(TPasImplBlock(lieo.Body),lindent+1,0,false,false);
  487. DoSem:=false;
  488. end
  489. else if lsmt is TPasImplForLoop then
  490. begin
  491. lifl:=TPasImplForLoop(lsmt);
  492. //TODO variable
  493. write(s1,'for ',lifl.VariableName,':= ',lifl.StartValue,' ');
  494. if lifl.Down then write('down');
  495. writeln('to ',lifl.EndValue,' do');
  496. GetTPasImplBlock(TPasImplBlock(lifl),lindent+1,0,false,false);
  497. DoSem:=false;
  498. end
  499. else if lsmt is TPasImplRaise then
  500. begin
  501. write(s1,'raise ');
  502. lir:=TPasImplRaise(lsmt);
  503. if not GetTPasImplBlock(TPasImplBlock(lir),lindent,0,DoNoSem,true) then
  504. writeln(';');
  505. DoNoSem:=false;
  506. DoSem:=false;
  507. end
  508. else
  509. begin
  510. if assigned(lsmt.Elements) then
  511. begin
  512. writeln('{ Unknown SMT(s): '); //,lsmt.Name,' ',lsmt.ElementTypeName);
  513. for l:=0 to lsmt.Elements.Count-1 do
  514. write(s,' SMT ',l,' ',TPasElement(lsmt.Elements[l]).Name);
  515. writeln('}');
  516. end;
  517. DoSem:=false;
  518. end;
  519. if not DoNoSem then
  520. begin
  521. if DoSem then writeln(';');
  522. end
  523. else writeln;
  524. end;
  525. //result: result of TPasImplBlock or valid element
  526. //NoFirstIndent only for block in case:
  527. function GetTPasImplElement(le:TPasImplElement; lindent:integer;
  528. lLastNoSem,NoFirstIndent:boolean):boolean;
  529. var liie:TPasImplIfElse;
  530. lico:TPasImplCaseOf;
  531. lice:TPasImplCaseElse;
  532. liru:TPasImplRepeatUntil;
  533. lit:TPasImplTry;
  534. //lic:TPasImplCommand;
  535. s,s1:String;//s1 only first line of block statement
  536. begin
  537. Result:=true;
  538. s:=GetIndent(lindent);
  539. if NoFirstIndent then s1:=' ' else s1:=s;
  540. if le is TPasImplStatement then
  541. begin
  542. if NoFirstIndent then lindent:=0;
  543. GetTPasSmt(TPasImplStatement(le),lindent+1,lLastNoSem,NoFirstIndent);
  544. end
  545. else if le is TPasImplIfElse then
  546. begin
  547. liie:=TPasImplIfElse(le);
  548. write(s1,'if ',DelQuot(liie.Condition),' then ');
  549. if assigned(liie.ElseBranch) then
  550. begin
  551. writeln;
  552. GetTPasImplElement(liie.IfBranch,lindent+1,true,false);
  553. writeln(s,'else');// {if}');
  554. GetTPasImplElement(liie.ElseBranch,lindent+1,lLastNoSem,false);
  555. end
  556. else
  557. begin //no else part
  558. if assigned(liie.IfBranch) then
  559. begin
  560. writeln;
  561. if not GetTPasImplElement(liie.IfBranch,lindent+1,false,false) then
  562. writeln(';');
  563. end
  564. else writeln(';'); //empty if then;
  565. end;
  566. end
  567. else if le is TPasImplCaseOf then
  568. begin
  569. lico:=TPasImplCaseOf(le);
  570. writeln(s1,'case ',lico.Expression,' of ');
  571. if assigned(lico.ElseBranch) then //workaround duplicate bug
  572. begin //reduce count of CaseOf as CaseElse is in there
  573. lice:=lico.ElseBranch;
  574. GetTPasImplBlock(TPasImplBlock(lico),lindent+1,1,false,false);
  575. end
  576. else GetTPasImplBlock(TPasImplBlock(lico),lindent+1,0,false,false); // !! else duplicate in here
  577. if assigned(lico.ElseBranch) then
  578. begin
  579. writeln(s,'else');//' {case}');
  580. lice:=lico.ElseBranch;
  581. GetTPasImplBlock(TPasImplBlock(lice),lindent+1,0,false,false);
  582. end;
  583. if lLastNoSem then writeln(s,'end')//' {case}')
  584. else writeln(s,'end;');// {case}');
  585. //Result:=false; ??? GetTPasImplBlock
  586. end
  587. else if le is TPasImplRepeatUntil then
  588. begin
  589. liru:=TPasImplRepeatUntil(le);
  590. writeln(s1,'repeat');
  591. GetTPasImplBlock(TPasImplBlock(liru),lindent+1,0,false,false);
  592. write(s,'until ',DelQuot(liru.Condition));
  593. if lLastNoSem then writeln
  594. else writeln(';');
  595. end
  596. else if le is TPasImplTryFinally then
  597. begin
  598. writeln(s,'finally');
  599. GetTPasImplBlock(TPasImplBlock(le),lindent+1,0,false,false);
  600. end
  601. else if le is TPasImplTryExcept then
  602. begin
  603. writeln(s,'except');
  604. GetTPasImplBlock(TPasImplBlock(le),lindent+1,0,false,false);
  605. end
  606. else if le is TPasImplTryExceptElse then
  607. begin
  608. writeln(s,'else');// {try}');
  609. GetTPasImplBlock(TPasImplBlock(le),lindent+1,0,false,false);
  610. end
  611. else if le is TPasImplTry then
  612. begin
  613. lit:=TPasImplTry(le);
  614. writeln(s1,'try');
  615. GetTPasImplBlock(TPasImplBlock(le),lindent+1,0,false,false);
  616. if assigned(lit.FinallyExcept) then
  617. GetTPasImplElement(TPasImplElement(lit.FinallyExcept),lindent+1,false,false);
  618. if assigned(lit.ElseBranch) then
  619. GetTPasImplElement(TPasImplElement(lit.ElseBranch),lindent+1,false,false);
  620. if lLastNoSem then writeln(s,'end')// {try} ') //there is no ImplBeginBlock
  621. else writeln(s,'end;');// {try} ');
  622. end
  623. else if le is TPasImplCommand then
  624. begin
  625. //ignore because empty
  626. // lic:=TPasImplCommand(le);
  627. // writeln(' CMD ',lic.Command,' ',lic.Name,' ',lic.ElementTypeName);
  628. end
  629. else if le is TPasImplLabelMark then
  630. begin
  631. writeln(s1,'label ',TPasImplLabelMark(le).LabelId,';');
  632. end
  633. else if le is TPasImplBlock then
  634. begin
  635. //IfElse, case:
  636. Result:=GetTPasImplBlock(TPasImplBlock(le),lindent+1,0,lLastNoSem,NoFirstIndent);
  637. end
  638. else
  639. begin
  640. Result:=false;
  641. //writeln(s,';');
  642. //writeln(' EL ',l);//,' ',le.Name)//,' ',le.ElementTypeName,' ',le.FullName);
  643. end;
  644. end;
  645. // indent: indent from page left side
  646. // DecListBy: dec(elements.count) because of case duplicate else bug
  647. // LastNoSem: only true on last expr before else in a if clause
  648. // NoFirstIndent: if line was started by other block like in case at -> 1:Noindent;
  649. // Result: true if elements not empty
  650. function GetTPasImplBlock(lb:TPasImplBlock; indent,declistby:integer;
  651. LastNoSem,NoFirstIndent:boolean):boolean;
  652. var l,n:integer;
  653. lbe:TPasImplElement;
  654. NoSem:boolean;
  655. ls:String;
  656. begin
  657. Result:=false;
  658. NoSem:=false;
  659. ls:=GetIndent(indent);
  660. if not assigned(lb) then exit;
  661. //if lb is TPasImplRaise then writeln('RAISE');
  662. if assigned(lb.Elements) then
  663. begin
  664. if lb is TPasImplBeginBlock then
  665. begin
  666. NoSem:=LastNoSem;
  667. LastNoSem:=false;
  668. if NoFirstIndent then
  669. begin
  670. writeln('begin');////NFI');
  671. NoFirstIndent:=false;
  672. end
  673. else writeln(ls,'begin');
  674. inc(indent);
  675. end;
  676. if lb.Elements.Count >0 then
  677. begin
  678. Result:=true;
  679. n:=lb.Elements.Count-1;
  680. //workaround CaseOf duplicate bug
  681. if (declistby >0)and(lb.Elements.Count >declistby) then dec(n,declistby);
  682. for l:=0 to n do
  683. begin
  684. lbe:=TPasImplElement(lb.Elements[l]);
  685. //write(l:2,'/',n:2,' '); //No of curent element, max element
  686. if ((l = 0)and NoFirstIndent) then
  687. begin //index0
  688. if l=n then GetTPasImplElement(lbe,0,LastNoSem,false)
  689. else GetTPasImplElement(lbe,0,false,false)
  690. end
  691. else if l<>n then GetTPasImplElement(lbe,indent,false,false) //other index
  692. else GetTPasImplElement(lbe,indent,LastNoSem,false); //indexn
  693. end;
  694. end
  695. else
  696. begin //block is empty
  697. //write(ls,' {!EMPTY!}');
  698. {if not NoSem then
  699. begin
  700. if lb is TPasImplBeginBlock then writeln //empty compound need no ;
  701. else writeln(';')
  702. end
  703. else
  704. writeln;}
  705. end;
  706. if lb is TPasImplBeginBlock then
  707. if not NoSem then writeln(ls,'end;')// {Block}')
  708. else writeln(ls,'end');// {Block}');
  709. end
  710. else
  711. writeln(';'); //writeln(' {!empty!};')
  712. end;
  713. //# Declarations (type,var,const,..)
  714. procedure GetTPasArrayType(lpat:TPasArrayType);
  715. begin
  716. if lpat.IsPacked then write('packed ');
  717. write('Array');
  718. if lpat.IndexRange <> '' then write('[',lpat.IndexRange,']');
  719. if assigned(lpat.ElType) then write(' of ',lpat.ElType.Name);
  720. // BUG: of const missing in Procedure ConstArrayArgProc(A: Array of const); pparser: 643
  721. end;
  722. //write out one variable or constant declaration, also used in types
  723. //In spite of the use of GetPasVariables this is still used !
  724. procedure GetTPasVar(lpv:TPasVariable; lindent:integer; NoLF:boolean);//BUG string[] pparser: 482
  725. var i,j:integer;
  726. //lppt:TPasProcedureType;
  727. //lpa:TPasArgument;
  728. //lpat:TPasArrayType;
  729. s,s1:string;
  730. prct:TPasRecordType;
  731. begin
  732. if not Assigned(lpv) then exit;
  733. s:=GetIndent(lindent);
  734. write(s,lpv.Name);//,' ',lpv.value,' ',lpv.Modifiers,' ',lpv.AbsoluteLocation);
  735. if assigned(lpv.VarType) then
  736. begin
  737. //if TPasType(lpa.ArgType).ElementTypeName <>'unresolved type reference' then
  738. //,TPasType(lpa.ArgType).Name,' ');//,TPasType(lpa.ArgType).FullName,TPasType(lpa.ArgType).ElementTypeName)
  739. // PParser 2099: ArgType := nil; if IsUntyped then => Arg.ArgType := ArgType;
  740. // else write(':? ');
  741. write(': ');
  742. if lpv.VarType is TPasArrayType then
  743. begin
  744. GetTPasArrayType(TPasArrayType(lpv.VarType));
  745. end
  746. else if lpv.VarType is TPasSetType then
  747. begin
  748. write('set of ',TPasSetType(lpv.VarType).EnumType.Name);
  749. end
  750. else
  751. begin
  752. if lpv.VarType is TPasPointerType then
  753. write('^',TPasPointerType(lpv.VarType).DestType.Name)
  754. else if lpv.VarType is TPasRecordType then //var record
  755. begin
  756. j:=lindent+Length(lpv.Name)+4;
  757. s1:=GetIndent(j);
  758. prct:=TPasRecordType(lpv.VarType);
  759. if prct.IsBitPacked then write('bitpacked ');
  760. if prct.IsPacked then write('packed ');
  761. writeln('Record');
  762. for i:=0 to prct.Members.Count-1 do
  763. begin
  764. GetTPasVar(TPasVariable(prct.Members[i]),j+1,false);
  765. end;
  766. write(s1,'end');
  767. end
  768. else
  769. begin
  770. write(TPasType(lpv.VarType).Name);
  771. //if TPasType(lpv.VarType) is TPasAliasType then write(TPasAliasType(lpv.VarType).Name);
  772. end;
  773. end;
  774. end;
  775. if lpv.Value <> '' then write('=',lpv.Value);
  776. if assigned(lpv.Expr) then // var ?, const AnArrayConst : Array[1..3] of Integer = (1,2,3);
  777. begin
  778. write('=');
  779. GetTPasExpr(lpv.Expr);
  780. end;
  781. if lpv.Modifiers <>'' then //Modifiers starts with ;
  782. begin
  783. write(' ',lpv.Modifiers,';');
  784. if GetTPasMemberHints(lpv.Hints) then write(';');
  785. end
  786. else
  787. begin
  788. GetTPasMemberHints(lpv.Hints);
  789. write(';');
  790. end;
  791. if not NoLF then writeln;
  792. end;
  793. //write out a list of variables only
  794. //more compact than the output of seperate calls of GetTPasVar
  795. procedure GetPasVariables(vl:TList; lindent:integer; NoLF,NoSEM:boolean);
  796. var v,i,j:integer;
  797. s,s1:string;
  798. prct:TPasRecordType;
  799. lpv:TPasVariable;
  800. same:boolean;
  801. samestr,tmpstr:Ansistring;
  802. samevar:array of integer;
  803. svi:integer;
  804. begin
  805. if vl.Count <= 0 then exit;
  806. s:=GetIndent(lindent);
  807. //> compare all variable types as string to find the ones with same type
  808. samestr:='';
  809. svi:=0;
  810. SetLength(samevar,vl.count);
  811. for v:=0 to vl.count-1 do
  812. begin
  813. tmpstr:='';
  814. same:=true;
  815. lpv:=TPasVariable(vl[v]);
  816. //write(s,lpv.Name);
  817. if assigned(lpv.VarType) then
  818. begin
  819. tmpstr:=tmpstr+': ';
  820. if lpv.VarType is TPasArrayType then
  821. begin
  822. //GetTPasArrayType(TPasArrayType(lpv.VarType));
  823. tmpstr:=tmpstr+'array'+TPasArrayType(lpv.VarType).IndexRange;
  824. if assigned(TPasArrayType(lpv.VarType).ElType) then
  825. tmpstr:=tmpstr+TPasArrayType(lpv.VarType).ElType.Name;
  826. end
  827. else if lpv.VarType is TPasSetType then
  828. begin
  829. tmpstr:=tmpstr+'set of '+TPasSetType(lpv.VarType).EnumType.Name;
  830. end
  831. else
  832. begin
  833. if lpv.VarType is TPasPointerType then
  834. tmpstr:=tmpstr+'^'+TPasPointerType(lpv.VarType).DestType.Name
  835. else if lpv.VarType is TPasRecordType then //var record
  836. begin
  837. prct:=TPasRecordType(lpv.VarType);
  838. if prct.IsBitPacked then tmpstr:=tmpstr+'bitpacked ';
  839. if prct.IsPacked then tmpstr:=tmpstr+'packed ';
  840. tmpstr:=tmpstr+'Record ';
  841. for i:=0 to prct.Members.Count-1 do
  842. begin
  843. //todo
  844. //GetTPasVar(TPasVariable(prct.Members[i]),j+1,false);
  845. end;
  846. tmpstr:=tmpstr+'end';
  847. end
  848. else
  849. begin
  850. tmpstr:=tmpstr+TPasType(lpv.VarType).Name;
  851. end;
  852. end;
  853. end
  854. else same:=false;
  855. if lpv.Value <> '' then same:=false;//=
  856. if assigned(lpv.Expr) then // var ?, const AnArrayConst : Array[1..3] of Integer = (1,2,3);
  857. begin
  858. same:=false;//=
  859. end;
  860. if lpv.Modifiers <>'' then //Modifiers starts with ;
  861. begin
  862. tmpstr:=tmpstr+' '+lpv.Modifiers+';';
  863. tmpstr:=tmpstr+ReturnTPasMemberHints(lpv.Hints);
  864. end
  865. else
  866. begin
  867. tmpstr:=tmpstr+ReturnTPasMemberHints(lpv.Hints);
  868. end;
  869. //if v = 0 then begin samestr:=tmpstr; end;
  870. if (not same)or(samestr <> tmpstr) then
  871. begin
  872. samestr:=tmpstr;
  873. inc(svi);
  874. end;
  875. samevar[v]:=svi;
  876. end;
  877. //compare <
  878. //now print them
  879. svi:=-1;
  880. for v:=0 to vl.count-1 do
  881. begin
  882. lpv:=TPasVariable(vl[v]);
  883. if not Assigned(lpv) then continue;
  884. if svi <> samevar[v] then
  885. begin
  886. svi:=samevar[v];
  887. if v>0 then writeln;
  888. write(s,lpv.Name);//variblenname
  889. end
  890. else write(lpv.Name);
  891. if (v < vl.Count-1)and(samevar[v+1]=svi) then write(',')
  892. else
  893. begin
  894. if assigned(lpv.VarType) then
  895. begin
  896. write(': ');
  897. if lpv.VarType is TPasArrayType then
  898. begin
  899. GetTPasArrayType(TPasArrayType(lpv.VarType));
  900. end
  901. else if lpv.VarType is TPasSetType then
  902. begin
  903. write('set of ',TPasSetType(lpv.VarType).EnumType.Name);
  904. end
  905. else
  906. begin
  907. if lpv.VarType is TPasPointerType then
  908. write('^',TPasPointerType(lpv.VarType).DestType.Name)
  909. else if lpv.VarType is TPasRecordType then //var record
  910. begin
  911. j:=lindent+Length(lpv.Name)+4;
  912. s1:=GetIndent(j);
  913. prct:=TPasRecordType(lpv.VarType);
  914. if prct.IsBitPacked then write('bitpacked ');
  915. if prct.IsPacked then write('packed ');
  916. writeln('Record');
  917. {for i:=0 to prct.Members.Count-1 do
  918. begin
  919. GetTPasVar(TPasVariable(prct.Members[i]),j+1,false);
  920. end;}
  921. if prct.Members.Count > 0 then
  922. GetPasVariables(prct.Members,j+1,false,false);
  923. write(s1,'end');
  924. end
  925. else
  926. begin
  927. write(TPasType(lpv.VarType).Name);
  928. end;
  929. end;
  930. end;
  931. if lpv.Value <> '' then write('=',lpv.Value);
  932. if assigned(lpv.Expr) then // var ?, const AnArrayConst : Array[1..3] of Integer = (1,2,3);
  933. begin
  934. write('=');
  935. GetTPasExpr(lpv.Expr);
  936. end;
  937. if lpv.Modifiers <>'' then //Modifiers starts with ;
  938. begin
  939. write(' ',lpv.Modifiers,';');
  940. if GetTPasMemberHints(lpv.Hints) then write(';');
  941. end
  942. else
  943. begin
  944. GetTPasMemberHints(lpv.Hints);
  945. if (v < vl.Count-1) then write(';')
  946. else if (not NoSEM) then write(';');
  947. end;
  948. //if not NoLF then writeln;
  949. end;
  950. end;
  951. if not NoLF then writeln;
  952. end;
  953. procedure GetTypes(pe:TPasElement; lindent:integer);
  954. var i,j,k:integer;
  955. s,s1,s2:string;
  956. pet:TPasEnumType;
  957. pev:TPasEnumValue;
  958. prt:TPasRangeType;
  959. prct:TPasRecordType;
  960. pv:TPasVariant;
  961. pst:TPasSetType;
  962. function GetVariantRecord(pe:TPasElement; lindent:integer):boolean;
  963. var i,j,k:integer;
  964. prct:TPasRecordType;
  965. pv:TPasVariant;
  966. s,s1:string;
  967. begin
  968. Result:=false;
  969. j:=lindent+Length(pe.Name)+2;
  970. s:=GetIndent(lindent);
  971. s1:=GetIndent(lindent+2);
  972. prct:=TPasRecordType(pe);
  973. {Now i use GetPasVariables for more compact output
  974. for i:=0 to prct.Members.Count-1 do
  975. begin
  976. GetTPasVar(TPasVariable(prct.Members[i]),1,true);
  977. end;}
  978. if prct.Members.Count > 0 then GetPasVariables(prct.Members,1,true,true);
  979. if assigned(prct.Variants) then
  980. begin
  981. Result:=true;
  982. writeln(';');
  983. write(s,'case ');
  984. if prct.VariantName <>'' then write(prct.VariantName,'=');
  985. write(TPasType(prct.VariantType).Name);
  986. writeln(' of');
  987. if assigned(prct.Variants)then
  988. if prct.Variants.Count >0 then
  989. begin
  990. for i:=0 to prct.Variants.Count-1 do
  991. begin
  992. pv:=TPasVariant(prct.Variants[i]);
  993. write(s1,pv.Name);
  994. for k:=0 to pv.Values.Count-1 do write(pv.Values[k]);
  995. write(': (');
  996. if GetVariantRecord(TPasElement(pv.Members),j+1) then
  997. writeln(s1,');')
  998. else writeln(');');
  999. end;
  1000. end;
  1001. end;
  1002. end;
  1003. begin
  1004. s:=GetIndent(lindent);
  1005. write(s,pe.Name,'=');
  1006. if pe is TPasArrayType then
  1007. begin
  1008. GetTPasArrayType(TPasArrayType(pe));
  1009. writeln(';');
  1010. end
  1011. else if pe is TPasEnumType then
  1012. begin
  1013. pet:=TPasEnumType(pe);
  1014. write('(');
  1015. if pet.Values.Count > 0 then
  1016. begin
  1017. for j:=0 to pet.Values.Count-2 do
  1018. begin
  1019. pev:=TPasEnumValue(pet.Values[j]);
  1020. write(pev.name,',');
  1021. //pev.Value ?
  1022. //pev.AssignedValue ?
  1023. //pev.IsValueUsed ?
  1024. end;
  1025. pev:=TPasEnumValue(pet.Values[pet.Values.Count-1]);
  1026. write(pev.name);
  1027. end;
  1028. writeln(');');
  1029. end
  1030. else if pe is TPasFileType then
  1031. begin
  1032. writeln('file of ',TPasFileType(pe).ElType.Name,';');
  1033. end
  1034. else if pe is TPasProcedureType then
  1035. begin
  1036. writeln('procedure');
  1037. end
  1038. else if pe is TPasPointerType then
  1039. begin
  1040. //writeln('pointer');
  1041. writeln('^',TPasPointerType(pe).DestType.Name,';');
  1042. end
  1043. else if pe is TPasRangeType then
  1044. begin
  1045. prt:=TPasRangeType(pe);
  1046. writeln(prt.RangeStart,'..',prt.RangeEnd,';');
  1047. end
  1048. else if pe is TPasRecordType then
  1049. begin
  1050. j:=lindent+Length(pe.Name)+2;
  1051. s1:=GetIndent(j);
  1052. s2:=GetIndent(j+1);
  1053. prct:=TPasRecordType(pe);
  1054. if prct.IsBitPacked then write('bitpacket ');
  1055. if prct.IsPacked then write('packet');
  1056. writeln('record');
  1057. {Now i use GetPasVariables for more compact output
  1058. for i:=0 to prct.Members.Count-1 do
  1059. begin
  1060. GetTPasVar(TPasVariable(prct.Members[i]),j+1,false);
  1061. end;}
  1062. GetPasVariables(prct.Members,j+2,false,false);
  1063. if assigned(prct.Variants) then
  1064. begin
  1065. write(s1,'case ');
  1066. if prct.VariantName <>'' then write(prct.VariantName,'=');
  1067. write(TPasType(prct.VariantType).Name);
  1068. writeln(' of');
  1069. if assigned(prct.Variants)then
  1070. if prct.Variants.Count >0 then
  1071. begin
  1072. for i:=0 to prct.Variants.Count-1 do
  1073. begin
  1074. pv:=TPasVariant(prct.Variants[i]);
  1075. write(s2,pv.Name);
  1076. for k:=0 to pv.Values.Count-1 do write(pv.Values[k]);
  1077. write(': (');
  1078. if GetVariantRecord(TPasElement(pv.Members),j+2) then
  1079. writeln(s2,');')
  1080. else writeln(');');
  1081. end;
  1082. end;
  1083. end;
  1084. writeln(s1,'end;');
  1085. end
  1086. else if pe is TPasSetType then
  1087. begin
  1088. pst:=TPasSetType(pe);
  1089. writeln('set of ',pst.EnumType.Name,';');
  1090. end
  1091. else if pe is TPasClassOfType then writeln('Class of ',TPasClassOfType(pe).DestType.Name,';')
  1092. else
  1093. begin
  1094. writeln('{ Unknown TYPE(s): ');
  1095. writeln(s,pe.Name);
  1096. writeln('}');
  1097. writeln;
  1098. end;
  1099. end;
  1100. function GetTPasArgumentAccess(acc:TArgumentAccess):String;
  1101. begin
  1102. Result:='';
  1103. case acc of
  1104. //argDefault:Result:='default'; //normal proccall is default
  1105. argConst:Result:='const';
  1106. argVar:Result:='var';
  1107. argOut:Result:='out';
  1108. end;
  1109. end;
  1110. procedure GetTCallingConvention(cc:TCallingConvention); //TODO: test it
  1111. begin
  1112. case cc of
  1113. //ccDefault:write(' default;'); //normal proccall is default
  1114. ccRegister:WriteFmt(true,'Register;',false);
  1115. ccPascal :WriteFmt(true,'Pascal;',false);
  1116. ccCDecl :WriteFmt(true,'CDecl;',false);
  1117. ccStdCall :WriteFmt(true,'StdCall;',false);
  1118. ccOldFPCCall:WriteFmt(true,'OldFPCall;',false);
  1119. ccSafeCall:WriteFmt(true,'SaveCall;',false);
  1120. end;
  1121. end;
  1122. procedure GetHiddenModifiers(Mfs:TProcedureModifiers);
  1123. begin
  1124. if pmInline in Mfs then WriteFmt(true,'inline;',false);
  1125. if pmAssembler in Mfs then WriteFmt(true,'assembler;',false);
  1126. if pmVarargs in Mfs then WriteFmt(true,'varargs;',false);
  1127. if pmCompilerProc in Mfs then WriteFmt(true,'compilerproc;',false);
  1128. if pmExtdecl in Mfs then WriteFmt(true,'extdecl;',false);
  1129. end;
  1130. procedure GetTPasProcedure(lpp:TPasProcedure; indent:integer);
  1131. var l:integer;
  1132. lppt:TPasProcedureType;
  1133. lpa:TPasArgument;
  1134. s:String;
  1135. same:boolean;
  1136. samevar:array of integer;//same index same type
  1137. aktaa:TArgumentAccess;
  1138. aktname,tmpname:String;
  1139. svi:integer;
  1140. begin
  1141. if not Assigned(lpp) then exit;
  1142. s:=GetIndent(indent);
  1143. if lpp is TPasConstructor then write(s,'Constructor ')
  1144. else if TPasElement(lpp) is TPasConstructorImpl then write(s,'Constructor ')
  1145. else if lpp is TPasDestructor then write(s,'Destructor ')
  1146. else if TPasElement(lpp) is TPasDestructorImpl then write(s,'Destructor ')
  1147. else if lpp is TPasClassProcedure then write(s,'Class Procedure ') //pparser.pp: 3221
  1148. else if lpp is TPasClassFunction then write(s,'Class Function ')
  1149. else if lpp is TPasFunction then write(s,'Function ')
  1150. else write(s,'Procedure ');
  1151. write(lpp.Name);//,' ',lpp.TypeName);
  1152. if assigned(lpp.ProcType) then
  1153. begin
  1154. lppt:=lpp.ProcType;
  1155. if assigned(lppt.Args) and (lppt.Args.Count > 0) then
  1156. begin
  1157. write('(');
  1158. if lppt.Args.Count > 0 then
  1159. begin
  1160. //produce more compact output than the commented block below
  1161. //>find same declaration
  1162. //look ahead what is the same
  1163. SetLength(samevar,lppt.Args.Count);
  1164. svi:=0;
  1165. aktname:='';
  1166. for l:=0 to lppt.Args.Count-1 do
  1167. begin
  1168. same:=true;
  1169. tmpname:='';
  1170. lpa:=TPasArgument(lppt.Args.Items[l]);
  1171. if assigned(lpa.ArgType) then
  1172. begin
  1173. if lpa.ArgType is TPasArrayType then
  1174. begin
  1175. if assigned(TPasArrayType(lpa.ArgType).ElType) then tmpname:=TPasArrayType(lpa.ArgType).ElType.Name;
  1176. end
  1177. else tmpname:=TPasType(lpa.ArgType).Name;
  1178. end;
  1179. if l=0 then begin aktaa:=lpa.Access; aktname:=tmpname; end;
  1180. if lpa.Access <> aktaa then begin same:=false; aktaa:=lpa.Access; end;//access type
  1181. if (tmpname = '')or(tmpname <> aktname) then begin same:=false; aktname:=tmpname; end;//type name
  1182. if lpa.Value <> '' then same:=false;//var=value
  1183. if not same then inc(svi);
  1184. samevar[l]:=svi;
  1185. end;
  1186. //find same declaration<
  1187. svi:=-1;
  1188. same:=false;
  1189. for l:=0 to lppt.Args.Count-1 do
  1190. begin
  1191. lpa:=TPasArgument(lppt.Args.Items[l]);
  1192. if svi <> samevar[l] then
  1193. begin
  1194. svi:=samevar[l];
  1195. if lpa.Access <> argDefault then write(GetTPasArgumentAccess(lpa.Access),' ');
  1196. write(lpa.Name);//variblenname
  1197. end
  1198. else write(lpa.Name);
  1199. if (l < lppt.Args.Count-1)and(samevar[l+1]=svi) then write(',')
  1200. else
  1201. begin
  1202. if assigned(lpa.ArgType) then
  1203. begin
  1204. write(': ');
  1205. if lpa.ArgType is TPasArrayType then
  1206. GetTPasArrayType(TPasArrayType(lpa.ArgType))
  1207. else write(TPasType(lpa.ArgType).Name);
  1208. end;
  1209. if lpa.Value <> '' then write('=',lpa.Value);
  1210. if l< lppt.Args.Count-1 then write('; ');
  1211. end;
  1212. end;
  1213. {//simple version duplicates declarations of same type
  1214. for l:=0 to lppt.Args.Count-1 do
  1215. begin
  1216. lpa:=TPasArgument(lppt.Args.Items[l]);
  1217. if lpa.Access <> argDefault then write(GetTPasArgumentAccess(lpa.Access),' ');
  1218. write(lpa.Name);//variblenname
  1219. if assigned(lpa.ArgType) then
  1220. begin
  1221. //if TPasType(lpa.ArgType).ElementTypeName <>'unresolved type reference' then
  1222. //,TPasType(lpa.ArgType).Name,' ');
  1223. //,TPasType(lpa.ArgType).FullName,TPasType(lpa.ArgType).ElementTypeName)
  1224. // PParser 2099: ArgType := nil; if IsUntyped then => Arg.ArgType := ArgType;
  1225. // else write(':? ');
  1226. write(': ');
  1227. if lpa.ArgType is TPasArrayType then
  1228. begin
  1229. GetTPasArrayType(TPasArrayType(lpa.ArgType));
  1230. end
  1231. else write(TPasType(lpa.ArgType).Name);
  1232. end;
  1233. if lpa.Value <> '' then write('=',lpa.Value);
  1234. if l< lppt.Args.Count-1 then write('; ');
  1235. end;}
  1236. end;
  1237. write(')');
  1238. end;
  1239. if lppt.IsOfObject then write(' of Object');
  1240. if (TPasElement(lpp) is TPasFunction)or(TPasElement(lpp) is TPasClassFunction) then
  1241. write(': ',TPasFunctionType(lpp.ProcType).ResultEl.ResultType.Name);
  1242. end;
  1243. //writeln(';');
  1244. WriteFmt(false,'',true);
  1245. if lpp.IsVirtual then WriteFmt(true,'virtual;',false);
  1246. if lpp.IsOverload then WriteFmt(true,'overload;',false);
  1247. if lpp.IsAbstract then WriteFmt(true,'abstract;',false);
  1248. if lpp.IsDynamic then WriteFmt(true,'dynamic;',false);
  1249. if lpp.IsOverride then WriteFmt(true,'override;',false);
  1250. if lpp.IsExported then WriteFmt(true,'exported;',false);
  1251. if lpp.IsExternal then WriteFmt(true,'external;',false);
  1252. //pparser 2360: everyting behind external is ignored !!!
  1253. if lpp.IsMessage then
  1254. begin
  1255. write('message ');
  1256. if lpp.MessageType = pmtString then writeln(false,lpp.MessageName,true)
  1257. else WriteFmt(false,lpp.MessageName,true);//pmtInteger
  1258. end;
  1259. if lpp.IsReintroduced then WriteFmt(true,'reintroduce;',false);
  1260. if lpp.IsStatic then WriteFmt(true,'static;',false);
  1261. if lpp.IsForward then WriteFmt(true,'forward;',false);
  1262. GetHiddenModifiers(lpp.Modifiers);
  1263. GetTCallingConvention(lpp.CallingConvention);
  1264. if GetTPasMemberHints(TPasElement(lpp).Hints) then WriteFmt(false,'',true); //BUG ? missing hints
  1265. if not Unformated then writeln;
  1266. end;
  1267. procedure GetTPasProcedureBody(pb:TProcedureBody; indent:integer);
  1268. var j:integer;
  1269. pd:TPasDeclarations;
  1270. pib:TPasImplBlock;
  1271. begin
  1272. if assigned(pb) then
  1273. begin
  1274. if assigned(pb.Body)then
  1275. begin
  1276. if assigned(TPasDeclarations(pb).Functions)then
  1277. begin
  1278. pd:=TPasDeclarations(pb);
  1279. if isim then
  1280. begin
  1281. //writeln;
  1282. GetDecls(pd,indent+1); //~recursion
  1283. //PrintDecls(pd,indent+1); //~recursion
  1284. end
  1285. else
  1286. if pd.Functions.Count >0 then //sub-functions
  1287. begin
  1288. for j:=0 to pd.Functions.Count-1 do
  1289. GetTPasProcedure(TPasProcedure(pd.Functions[j]),indent+1);
  1290. end;
  1291. end;
  1292. pib:=TPasImplBlock(pb.Body);
  1293. if assigned(pib) then
  1294. begin
  1295. GetTPasImplBlock(pib,indent,0,false,false); //indent depend on sub function level
  1296. if not Unformated then writeln; //('//block');
  1297. end;
  1298. end;
  1299. end;
  1300. end;
  1301. procedure GetTpasOverloadedProc(pop:TPasOverloadedProc; indent:integer);
  1302. var pp:TPasProcedure;
  1303. j:integer;
  1304. begin
  1305. if assigned(pop) then
  1306. begin
  1307. if pop.Overloads.Count >0 then
  1308. begin
  1309. for j:=0 to pop.Overloads.Count-1 do
  1310. begin
  1311. pp:=TPasProcedure(pop.Overloads[j]);
  1312. GetTPasProcedure(pp,indent);
  1313. GetTPasProcedureBody(pp.Body,indent);
  1314. end;
  1315. end;
  1316. end;
  1317. end;
  1318. function GetVisibility(v:TPasMemberVisibility):String;
  1319. begin
  1320. Result:='';
  1321. case v of
  1322. //visDefault:Result:='default';
  1323. visPrivate:Result:='private';
  1324. visProtected:Result:='protected';
  1325. visPublic:Result:='public';
  1326. visPublished:Result:='published';
  1327. visAutomated:Result:='automated';
  1328. visStrictPrivate:Result:='strictprivate';
  1329. visStrictProtected:Result:='strictprotected';
  1330. end;
  1331. end;
  1332. procedure GetTPasClass(pc:TPasClassType; indent:integer);
  1333. var j,l:integer;
  1334. s,s1,s2:String;
  1335. lpe:TPasElement;
  1336. lpp:TPasProperty;
  1337. lpa:TPasArgument;
  1338. vis:TPasMemberVisibility;
  1339. vars:TList;
  1340. IsVar:boolean;
  1341. procedure PrintVars;
  1342. begin
  1343. if vars.Count > 0 then GetPasVariables(vars,indent+1,false,false);
  1344. IsVar:=False;
  1345. vars.Clear;
  1346. end;
  1347. begin
  1348. if assigned(pc) then
  1349. begin
  1350. s:=GetIndent(indent);
  1351. if (pc.ObjKind=okGeneric) then
  1352. begin
  1353. write(s,'generic ',pc.Name);
  1354. for l:=0 to pc.GenericTemplateTypes.Count-1 do
  1355. begin
  1356. if l=0 then
  1357. Write('<')
  1358. else
  1359. Write(',');
  1360. Write(TPasGenericTemplateType(pc.GenericTemplateTypes[l]).Name);
  1361. end;
  1362. Write('> = ');
  1363. end
  1364. else
  1365. write(s,pc.Name,' = ');
  1366. if pc.IsPacked then write('packed ');
  1367. case pc.ObjKind of
  1368. okObject:write('Object');
  1369. okClass:write('Class');
  1370. okInterface:write('Interface');
  1371. okGeneric:write('class');
  1372. okspecialize : write('specialize');
  1373. end;
  1374. if assigned(pc.AncestorType) and (pc.AncestorType.ElementTypeName <> '') then
  1375. begin
  1376. if pc.ObjKind<>okspecialize then
  1377. write('(',pc.AncestorType.Name,')')
  1378. else
  1379. begin
  1380. write(' ',pc.AncestorType.Name);
  1381. for l:=0 to pc.GenericTemplateTypes.Count-1 do
  1382. begin
  1383. if l=0 then
  1384. Write('<')
  1385. else
  1386. Write(',');
  1387. Write(TPasGenericTemplateType(pc.GenericTemplateTypes[l]).Name);
  1388. end;
  1389. Write('>');
  1390. end;
  1391. end;
  1392. if pc.IsForward or pc.IsShortDefinition then //pparser.pp: 3417 :class(anchestor); is allowed !
  1393. begin
  1394. writeln(';');
  1395. exit;
  1396. end;
  1397. //Members: TList;
  1398. //InterfaceGUID: String;
  1399. //ClassVars: TList; //is this always empty ?
  1400. //Modifiers: TStringList;
  1401. //Interfaces: TList;
  1402. s1:=GetIndent(indent+1);
  1403. s2:=GetIndent(indent+2);
  1404. if pc.Members.Count > 0 then
  1405. begin
  1406. writeln;
  1407. vars:=TList.Create;
  1408. IsVar:=false;
  1409. for j:=0 to pc.Members.Count-1 do
  1410. begin
  1411. lpe:=TPasElement(pc.Members[j]);
  1412. //Class visibility, written on change
  1413. if j=0 then
  1414. begin
  1415. vis:=lpe.Visibility;
  1416. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1417. end
  1418. else
  1419. if vis <> lpe.Visibility then
  1420. begin
  1421. if IsVar then PrintVars;
  1422. if lpe.Visibility <> visDefault then //Class Function = visDefault
  1423. begin
  1424. vis:=lpe.Visibility;
  1425. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1426. end;
  1427. end;
  1428. if lpe is TPasOverloadedProc then
  1429. begin
  1430. if IsVar then PrintVars;
  1431. GetTPasOverloadedProc(TPasOverloadedProc(lpe),indent+2);
  1432. end
  1433. else if lpe is TPasProcedure then //TPasClassProcedure and
  1434. begin //TPasClassFunction are both child of TPasProcedure
  1435. if IsVar then PrintVars;
  1436. GetTPasProcedure(TPasProcedure(lpe),indent+2);
  1437. end
  1438. else if lpe is TPasProperty then
  1439. begin
  1440. if IsVar then PrintVars;
  1441. lpp:=TPasProperty(lpe);
  1442. write(s2,'property ',lpp.Name);
  1443. if lpp.Args.Count >0 then
  1444. begin
  1445. for l:=0 to lpp.Args.Count-1 do
  1446. begin
  1447. lpa:=TPasArgument(lpp.Args.Items[l]);
  1448. if GetTPasArgumentAccess(lpa.Access) <> '' then
  1449. write('[',GetTPasArgumentAccess(lpa.Access),' ',lpa.Name)
  1450. else write('[',lpa.Name); //variblename
  1451. if assigned(lpa.ArgType) then
  1452. begin
  1453. //if TPasType(lpa.ArgType).ElementTypeName <>'unresolved type reference' then
  1454. //,TPasType(lpa.ArgType).Name,' ');
  1455. //,TPasType(lpa.ArgType).FullName,TPasType(lpa.ArgType).ElementTypeName)
  1456. // PParser 2099: ArgType := nil; if IsUntyped then => Arg.ArgType := ArgType;
  1457. // else write(':? ');
  1458. write(': ');
  1459. if lpa.ArgType is TPasArrayType then
  1460. begin
  1461. GetTPasArrayType(TPasArrayType(lpa.ArgType));
  1462. end
  1463. else write(TPasType(lpa.ArgType).Name);
  1464. end;
  1465. if lpa.Value <> '' then write('=',lpa.Value);
  1466. write(']');
  1467. end;
  1468. end;//args
  1469. if assigned(lpp.VarType) then
  1470. begin
  1471. write(': ',TPasType(lpp.VarType).Name);
  1472. end;
  1473. if lpp.IndexValue <> '' then write(' Index ',lpp.IndexValue);
  1474. if lpp.ReadAccessorName <> '' then write(' Read ',lpp.ReadAccessorName);
  1475. if lpp.WriteAccessorName <> '' then write(' Write ',lpp.WriteAccessorName);
  1476. if lpp.ImplementsName <> '' then write(' Implements ',lpp.ImplementsName);
  1477. if lpp.IsDefault then write(' Default ',lpp.DefaultValue);
  1478. if lpp.IsNodefault then write(' NoDefault');
  1479. if lpp.StoredAccessorName <> '' then write(' Stored ',lpp.StoredAccessorName);
  1480. GetTPasMemberHints(lpp.Hints);
  1481. writeln(';');
  1482. end
  1483. else if lpe is TPasVariable then
  1484. begin
  1485. //this is done with printvars
  1486. //GetTPasVar(TPasVariable(lpe),indent+1,false);
  1487. IsVar:=true;
  1488. vars.add(lpe);
  1489. end
  1490. else
  1491. begin
  1492. if IsVar then PrintVars;
  1493. writeln('{ Unknown Declaration(s) in Class/Object/Interface: ');
  1494. writeln(s,lpe.Name);
  1495. writeln('}');
  1496. end;
  1497. end;
  1498. //writeln(s,'end;');//'//class');
  1499. if IsVar then PrintVars;
  1500. vars.free;
  1501. end
  1502. else writeln;//(';'); //x=class(y);
  1503. writeln(s,'end;');
  1504. end;
  1505. end;
  1506. procedure GetDecls(Decl:TPasDeclarations; indent:integer);
  1507. var i,j:integer;
  1508. pe:TPasElement;
  1509. pp:TPasProcedure;
  1510. ps:TPasSection;
  1511. s:string;
  1512. x:(None,ResStrings,Types,Consts,Classes,Functions,Variables,Properties);
  1513. l:TList;
  1514. procedure PrintVars;
  1515. begin
  1516. if l.Count > 0 then GetPasVariables(l,indent+1,false,false);
  1517. end;
  1518. begin
  1519. s:=GetIndent(indent);
  1520. x:=None;
  1521. if assigned(Decl)then
  1522. begin
  1523. l:=TList.Create;
  1524. pe:=TPasElement(Decl);
  1525. if pe is TPasSection then
  1526. begin
  1527. {(Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1528. (Decl is TProgramSection}
  1529. ps:=TPasSection(pe);
  1530. if ps.UsesList.Count >0 then
  1531. begin
  1532. write(s,'uses ');
  1533. ps:=TPasSection(Decl);
  1534. if not Unformated then begin writeln; write(s,' '); end;
  1535. for i:=0 to ps.UsesList.Count-2 do
  1536. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1537. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1538. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1539. if not Unformated then writeln;
  1540. end;
  1541. end;
  1542. if assigned(Decl.Declarations)and(Decl.Declarations.Count > 0) then
  1543. for j:=0 to Decl.Declarations.Count-1 do
  1544. begin
  1545. pe:=TPasElement(Decl.Declarations[j]);
  1546. if pe is TPasResString then
  1547. begin
  1548. if x = Variables then PrintVars;
  1549. if x <> ResStrings then
  1550. begin
  1551. if not Unformated then writeln;
  1552. writeln(s,'ResourceString');
  1553. x:=ResStrings;
  1554. end;
  1555. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Value),';'); //too much '''
  1556. end
  1557. else if pe is TPasConst then
  1558. begin
  1559. if x = Variables then PrintVars;
  1560. if x <> Consts then
  1561. begin
  1562. if not Unformated then writeln;
  1563. writeln(s,'const');
  1564. x:=Consts;
  1565. end;
  1566. GetTPasVar(TPasVariable(pe),indent+1,false);
  1567. end
  1568. else if pe is TPasVariable then
  1569. begin
  1570. if x <> Variables then
  1571. begin
  1572. if not Unformated then writeln;
  1573. writeln(s,'var');
  1574. x:=Variables;
  1575. l.Clear;
  1576. end;
  1577. l.Add(pe);
  1578. //this is done with printvars
  1579. //GetTPasVar(TPasVariable(pe),indent+1,false);
  1580. end
  1581. else if pe is TPasClassType then
  1582. begin
  1583. if x = Variables then PrintVars;
  1584. if x <> Types then
  1585. begin
  1586. if not Unformated then writeln;
  1587. writeln(s,'Type');
  1588. x:=Types;
  1589. end;
  1590. GetTPasClass(TPasClassType(pe),indent+1);
  1591. end
  1592. else if pe is TPasType then
  1593. begin
  1594. if x = Variables then PrintVars;
  1595. if x <> Types then
  1596. begin
  1597. if not Unformated then writeln;
  1598. writeln(s,'Type');
  1599. x:=Types;
  1600. end;
  1601. GetTypes(TPasElement(pe),indent+1);
  1602. end
  1603. else if pe is TPasProcedureBase then
  1604. begin
  1605. if x = Variables then PrintVars;
  1606. if (x <> Functions)and not Unformated then writeln;
  1607. x:=Functions;
  1608. if pe is TPasOverloadedProc then
  1609. begin
  1610. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1611. end
  1612. else
  1613. begin
  1614. pp:=TPasProcedure(pe);
  1615. GetTPasProcedure(pp,indent);
  1616. GetTPasProcedureBody(pp.Body,indent);
  1617. end;
  1618. end
  1619. else
  1620. begin
  1621. if x = Variables then PrintVars;
  1622. x:=None;
  1623. writeln('{ Unknown Declaration: ',pe.Name,' }');
  1624. end;
  1625. end;
  1626. if x = Variables then PrintVars;
  1627. l.Free;
  1628. end;
  1629. end;
  1630. {replaced by GetDecls
  1631. this does the same but not in true order
  1632. procedure PrintDecls(Decl:TPasDeclarations; indent:integer);
  1633. var i:integer;
  1634. pe:TPasElement;
  1635. pp:TPasProcedure;
  1636. ps:TPasSection;
  1637. s:string;
  1638. istype:boolean;
  1639. begin
  1640. istype:=false;
  1641. s:=GetIndent(indent);
  1642. if (Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1643. (Decl is TProgramSection) then
  1644. if TPasSection(Decl).UsesList.Count >0 then
  1645. begin
  1646. write(s,'uses ');
  1647. ps:=TPasSection(Decl);
  1648. if not Unformated then begin writeln; write(s,' '); end;
  1649. for i:=0 to ps.UsesList.Count-2 do
  1650. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1651. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1652. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1653. if not Unformated then writeln;
  1654. end;
  1655. if assigned(Decl.ResStrings) then
  1656. if Decl.ResStrings.Count >0 then
  1657. begin
  1658. writeln('ResourceString');
  1659. for i := 0 to Decl.ResStrings.Count - 1 do
  1660. begin
  1661. pe:=TPasElement(Decl.ResStrings[i]);
  1662. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Value),';'); //too much '''
  1663. end;
  1664. if not Unformated then writeln;
  1665. end;
  1666. if assigned(Decl.Consts)then
  1667. if Decl.Consts.Count >0 then
  1668. begin
  1669. writeln(s,'const');
  1670. for i:=0 to Decl.Consts.Count-1 do GetTPasVar(TPasVariable(Decl.Consts[i]),indent+1,false);
  1671. if not Unformated then writeln;
  1672. end;
  1673. if assigned(Decl.Types) then
  1674. if Decl.Types.Count >0 then
  1675. begin
  1676. writeln(s,'Type');
  1677. for i := 0 to Decl.Types.Count - 1 do
  1678. begin
  1679. GetTypes(TPasElement(Decl.Types[i]),indent+1);
  1680. end;
  1681. if not Unformated then writeln;
  1682. istype:=true;
  1683. end;
  1684. if assigned(Decl.Classes) then
  1685. if Decl.Classes.Count >0 then
  1686. begin
  1687. if not istype then writeln('Type');
  1688. for i := 0 to Decl.Classes.Count - 1 do
  1689. begin
  1690. pe:=TPasElement(Decl.Classes[i]);
  1691. GetTPasClass(TPasClassType(pe),indent+1);
  1692. if not Unformated then writeln;
  1693. end;
  1694. end;
  1695. if assigned(Decl.Variables)then
  1696. if Decl.Variables.Count >0 then
  1697. begin
  1698. writeln(s,'var');
  1699. //Now i use GetPasVariables for more compact output
  1700. //for i:=0 to Decl.Variables.Count-1 do GetTPasVar(TPasVariable(Decl.Variables[i]),indent+1,false);
  1701. GetPasVariables(Decl.Variables,indent+1,false,false);
  1702. if not Unformated then writeln;
  1703. end;
  1704. if assigned(Decl.Functions) then
  1705. begin
  1706. for i := 0 to Decl.Functions.Count - 1 do
  1707. begin
  1708. pe:=TPasElement(Decl.Functions[i]);
  1709. if pe is TPasOverloadedProc then
  1710. begin
  1711. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1712. end
  1713. else
  1714. begin
  1715. pp:=TPasProcedure(pe);
  1716. GetTPasProcedure(pp,indent);
  1717. GetTPasProcedureBody(pp.Body,indent);
  1718. end;
  1719. end;
  1720. end;
  1721. end; }
  1722. //# parameter
  1723. procedure PrintUsage;
  1724. begin
  1725. writeln('usage: test_parser1 <Options> <Commandline> File');
  1726. writeln;
  1727. writeln(' <Options> : Options for test_parser1');
  1728. writeln(' -u : Unformated output');
  1729. writeln(' -OS <os> : <os> = WINDOWS, LINUX (default), FREEBSD, NETBSD,');
  1730. writeln(' SUNOS, BEOS, QNX, GO32V2');
  1731. writeln(' -CPU <cpu> : <cpu> = i386 (default), x86_64');
  1732. writeln(' <Commandline> : is the commandline for the parser');
  1733. writeln(' -d<define> : <define> = Directive');
  1734. writeln(' -Fi<include_path> : <include_path> = ?');
  1735. writeln(' -I<include_path> : <include_path> = ?');
  1736. writeln(' -Sd : mode delphi');
  1737. writeln(' File : a pascal source file (Program or Unit)');
  1738. end;
  1739. procedure GetParam;
  1740. begin
  1741. if paramcount>0 then
  1742. begin
  1743. cmdl:='';
  1744. i:=1;
  1745. repeat
  1746. if paramstr(i) = '-h' then
  1747. begin
  1748. PrintUsage;
  1749. halt(0);
  1750. end
  1751. else if paramstr(i) = '-u' then Unformated:= true
  1752. else if paramstr(i) = '-OS' then
  1753. begin
  1754. if i < paramcount then
  1755. begin
  1756. inc(i);
  1757. TargetOS:=paramstr(i);
  1758. if (TargetOS = '')or(TargetOS[1] = '-') then halt(1);
  1759. end
  1760. else halt(1);
  1761. end
  1762. else if paramstr(i) = '-CPU' then
  1763. begin
  1764. if i < paramcount then
  1765. begin
  1766. inc(i);
  1767. TargetCPU:=paramstr(i);
  1768. if (TargetCPU = '')or(TargetCPU[1] = '-') then halt(1);
  1769. end
  1770. else halt(1);
  1771. end
  1772. else
  1773. cmdl:=cmdl+' '+paramstr(i);
  1774. inc(i);
  1775. until i > paramcount;
  1776. end;
  1777. if (Paramcount < 1)or(cmdl = '') then
  1778. begin
  1779. // remember to put the whole cmdline in quotes, and
  1780. // to always add some path options. Even if only -Fu. -Fi.
  1781. writeln('Error: No file for input given !');
  1782. PrintUsage;
  1783. halt(1);
  1784. end;
  1785. end;
  1786. //# *** main ***
  1787. begin
  1788. isim:=false;
  1789. Unformated:=false;//false to format output to be human readable
  1790. TargetOS:='linux';
  1791. TargetCPU:='i386';
  1792. GetParam;
  1793. //writeln(TargetOS,' ',TargetCPU,' ',cmdl);halt;
  1794. E := TSimpleEngine.Create;
  1795. try
  1796. try
  1797. M := ParseSource(E, cmdl ,TargetOS ,TargetCPU);
  1798. except
  1799. on excep:EParserError do
  1800. begin
  1801. writeln(excep.message,' line:',excep.row,' column:',excep.column,' file:',excep.filename);
  1802. raise;
  1803. end;
  1804. end;
  1805. if M is TPasProgram then
  1806. begin
  1807. writeln('Program ',M.Name,';');
  1808. if not Unformated then writeln;
  1809. if assigned(M.ImplementationSection) then
  1810. begin
  1811. isim:=true;
  1812. if not Unformated then writeln;
  1813. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1814. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1815. end;
  1816. if assigned(M.InitializationSection) then // MAIN BLOCK
  1817. begin
  1818. isim:=false;
  1819. if not Unformated then writeln;
  1820. writeln('begin');//writeln('begin {Begin MAIN Program}')
  1821. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1822. end;
  1823. end
  1824. else
  1825. begin
  1826. { Cool, we successfully parsed the unit.
  1827. Now output some info about it. }
  1828. writeln('Unit ',M.Name,';');
  1829. if not Unformated then writeln;
  1830. Writeln('Interface');
  1831. if not Unformated then writeln;
  1832. GetDecls(M.InterfaceSection as TPasDeclarations,0);
  1833. //PrintDecls(M.InterfaceSection as TPasDeclarations,0);
  1834. if assigned(M.ImplementationSection) then
  1835. begin
  1836. isim:=true;
  1837. if not Unformated then writeln;
  1838. Writeln('Implementation');
  1839. if not Unformated then writeln;
  1840. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1841. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1842. if TPasElement(M.ImplementationSection) is TPasImplElement then writeln('{MAIN}');
  1843. end;
  1844. if assigned(M.InitializationSection) then //is this begin .. end. of a unit too ?
  1845. begin
  1846. isim:=true;
  1847. if not Unformated then writeln;
  1848. Writeln('Initialization');
  1849. if not Unformated then writeln;
  1850. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1851. if assigned(M.FinalizationSection) then
  1852. begin
  1853. isim:=true;
  1854. if not Unformated then writeln;
  1855. Writeln('Finalization');
  1856. if not Unformated then writeln;
  1857. GetTPasImplBlock(M.FinalizationSection as TPasImplBlock,1,0,false,false);
  1858. end;
  1859. end;
  1860. end;
  1861. if not Unformated then writeln('end.')
  1862. else
  1863. begin
  1864. writeln('end');
  1865. writeln('.');
  1866. end;
  1867. FreeAndNil(M);
  1868. finally
  1869. FreeAndNil(E);
  1870. end;
  1871. end.