test_parser.pp 62 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989
  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: TFPList;
  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: TFPList;
  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: TFPList; -> main block
  106. |
  107. |-FinalizationSection: TFinalizationSection;
  108. |-TPasImplBlock.Elements: TFPList; -> unit only
  109. Declarations = class(TPasElement)
  110. |-Declarations: TFPList; -> the following are all in here
  111. |-ResStrings: TFPList;
  112. |-Types: TFPList;
  113. |-Consts: TFPList;
  114. |-Classes: TFPList;
  115. |-Functions: TFPList;
  116. |-Variables: TFPList;
  117. |-Properties: TFPList;
  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:TFPList; 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. function GetTPasArgumentAccess(acc:TArgumentAccess):String;
  954. begin
  955. Result:='';
  956. case acc of
  957. //argDefault:Result:='default'; //normal proccall is default
  958. argConst:Result:='const';
  959. argVar:Result:='var';
  960. argOut:Result:='out';
  961. end;
  962. end;
  963. procedure GetTPasProcedureType(lppt:TPasProcedureType; indent:integer);
  964. Var
  965. l : integer;
  966. lpa:TPasArgument;
  967. samevar:array of integer;//same index same type
  968. aktaa:TArgumentAccess;
  969. svi:integer;
  970. same:boolean;
  971. aktname,tmpname:String;
  972. begin
  973. if assigned(lppt.Args) and (lppt.Args.Count > 0) then
  974. begin
  975. write('(');
  976. if lppt.Args.Count > 0 then
  977. begin
  978. //produce more compact output than the commented block below
  979. //>find same declaration
  980. //look ahead what is the same
  981. SetLength(samevar,lppt.Args.Count);
  982. svi:=0;
  983. aktname:='';
  984. for l:=0 to lppt.Args.Count-1 do
  985. begin
  986. same:=true;
  987. tmpname:='';
  988. lpa:=TPasArgument(lppt.Args.Items[l]);
  989. if assigned(lpa.ArgType) then
  990. begin
  991. if lpa.ArgType is TPasArrayType then
  992. begin
  993. if assigned(TPasArrayType(lpa.ArgType).ElType) then tmpname:=TPasArrayType(lpa.ArgType).ElType.Name;
  994. end
  995. else tmpname:=TPasType(lpa.ArgType).Name;
  996. end;
  997. if l=0 then begin aktaa:=lpa.Access; aktname:=tmpname; end;
  998. if lpa.Access <> aktaa then begin same:=false; aktaa:=lpa.Access; end;//access type
  999. if (tmpname = '')or(tmpname <> aktname) then begin same:=false; aktname:=tmpname; end;//type name
  1000. if lpa.Value <> '' then same:=false;//var=value
  1001. if not same then inc(svi);
  1002. samevar[l]:=svi;
  1003. end;
  1004. //find same declaration<
  1005. svi:=-1;
  1006. same:=false;
  1007. for l:=0 to lppt.Args.Count-1 do
  1008. begin
  1009. lpa:=TPasArgument(lppt.Args.Items[l]);
  1010. if svi <> samevar[l] then
  1011. begin
  1012. svi:=samevar[l];
  1013. if lpa.Access <> argDefault then write(GetTPasArgumentAccess(lpa.Access),' ');
  1014. write(lpa.Name);//variblenname
  1015. end
  1016. else write(lpa.Name);
  1017. if (l < lppt.Args.Count-1)and(samevar[l+1]=svi) then write(',')
  1018. else
  1019. begin
  1020. if assigned(lpa.ArgType) then
  1021. begin
  1022. write(': ');
  1023. if lpa.ArgType is TPasArrayType then
  1024. GetTPasArrayType(TPasArrayType(lpa.ArgType))
  1025. else write(TPasType(lpa.ArgType).Name);
  1026. end;
  1027. if lpa.Value <> '' then write('=',lpa.Value);
  1028. if l< lppt.Args.Count-1 then write('; ');
  1029. end;
  1030. end;
  1031. write(')');
  1032. end;
  1033. end;
  1034. if (lppt is TPasFunctionType) then
  1035. write(': ',TPasFunctionType(lppt).ResultEl.ResultType.Name);
  1036. if lppt.IsOfObject then
  1037. write(' of Object');
  1038. end;
  1039. procedure GetTypes(pe:TPasElement; lindent:integer);
  1040. var i,j,k:integer;
  1041. s,s1,s2:string;
  1042. pet:TPasEnumType;
  1043. pev:TPasEnumValue;
  1044. prt:TPasRangeType;
  1045. prct:TPasRecordType;
  1046. pv:TPasVariant;
  1047. pst:TPasSetType;
  1048. function GetVariantRecord(pe:TPasElement; lindent:integer):boolean;
  1049. var i,j,k:integer;
  1050. prct:TPasRecordType;
  1051. pv:TPasVariant;
  1052. s,s1:string;
  1053. begin
  1054. Result:=false;
  1055. j:=lindent+Length(pe.Name)+2;
  1056. s:=GetIndent(lindent);
  1057. s1:=GetIndent(lindent+2);
  1058. prct:=TPasRecordType(pe);
  1059. {Now i use GetPasVariables for more compact output
  1060. for i:=0 to prct.Members.Count-1 do
  1061. begin
  1062. GetTPasVar(TPasVariable(prct.Members[i]),1,true);
  1063. end;}
  1064. if prct.Members.Count > 0 then GetPasVariables(prct.Members,1,true,true);
  1065. if assigned(prct.Variants) then
  1066. begin
  1067. Result:=true;
  1068. writeln(';');
  1069. write(s,'case ');
  1070. if prct.VariantName <>'' then write(prct.VariantName,'=');
  1071. write(TPasType(prct.VariantType).Name);
  1072. writeln(' of');
  1073. if assigned(prct.Variants)then
  1074. if prct.Variants.Count >0 then
  1075. begin
  1076. for i:=0 to prct.Variants.Count-1 do
  1077. begin
  1078. pv:=TPasVariant(prct.Variants[i]);
  1079. write(s1,pv.Name);
  1080. for k:=0 to pv.Values.Count-1 do write(pv.Values[k]);
  1081. write(': (');
  1082. if GetVariantRecord(TPasElement(pv.Members),j+1) then
  1083. writeln(s1,');')
  1084. else writeln(');');
  1085. end;
  1086. end;
  1087. end;
  1088. end;
  1089. begin
  1090. s:=GetIndent(lindent);
  1091. write(s,pe.Name,'=');
  1092. if pe is TPasArrayType then
  1093. begin
  1094. GetTPasArrayType(TPasArrayType(pe));
  1095. writeln(';');
  1096. end
  1097. else if pe is TPasEnumType then
  1098. begin
  1099. pet:=TPasEnumType(pe);
  1100. write('(');
  1101. if pet.Values.Count > 0 then
  1102. begin
  1103. for j:=0 to pet.Values.Count-2 do
  1104. begin
  1105. pev:=TPasEnumValue(pet.Values[j]);
  1106. write(pev.name,',');
  1107. //pev.Value ?
  1108. //pev.AssignedValue ?
  1109. //pev.IsValueUsed ?
  1110. end;
  1111. pev:=TPasEnumValue(pet.Values[pet.Values.Count-1]);
  1112. write(pev.name);
  1113. end;
  1114. writeln(');');
  1115. end
  1116. else if pe is TPasFileType then
  1117. begin
  1118. writeln('file of ',TPasFileType(pe).ElType.Name,';');
  1119. end
  1120. else if pe is TPasProcedureType then
  1121. begin
  1122. if pe is TPasFunctionType then
  1123. Write('function ')
  1124. else
  1125. Write('procedure ');
  1126. GetTPasProcedureType(TPasProcedureType(pe), lindent);
  1127. Writeln(';');
  1128. end
  1129. else if pe is TPasPointerType then
  1130. begin
  1131. //writeln('pointer');
  1132. writeln('^',TPasPointerType(pe).DestType.Name,';');
  1133. end
  1134. else if pe is TPasRangeType then
  1135. begin
  1136. prt:=TPasRangeType(pe);
  1137. writeln(prt.RangeStart,'..',prt.RangeEnd,';');
  1138. end
  1139. else if pe is TPasRecordType then
  1140. begin
  1141. j:=lindent+Length(pe.Name)+2;
  1142. s1:=GetIndent(j);
  1143. s2:=GetIndent(j+1);
  1144. prct:=TPasRecordType(pe);
  1145. if prct.IsBitPacked then write('bitpacket ');
  1146. if prct.IsPacked then write('packet');
  1147. writeln('record');
  1148. {Now i use GetPasVariables for more compact output
  1149. for i:=0 to prct.Members.Count-1 do
  1150. begin
  1151. GetTPasVar(TPasVariable(prct.Members[i]),j+1,false);
  1152. end;}
  1153. GetPasVariables(prct.Members,j+2,false,false);
  1154. if assigned(prct.Variants) then
  1155. begin
  1156. write(s1,'case ');
  1157. if prct.VariantName <>'' then write(prct.VariantName,'=');
  1158. write(TPasType(prct.VariantType).Name);
  1159. writeln(' of');
  1160. if assigned(prct.Variants)then
  1161. if prct.Variants.Count >0 then
  1162. begin
  1163. for i:=0 to prct.Variants.Count-1 do
  1164. begin
  1165. pv:=TPasVariant(prct.Variants[i]);
  1166. write(s2,pv.Name);
  1167. for k:=0 to pv.Values.Count-1 do write(pv.Values[k]);
  1168. write(': (');
  1169. if GetVariantRecord(TPasElement(pv.Members),j+2) then
  1170. writeln(s2,');')
  1171. else writeln(');');
  1172. end;
  1173. end;
  1174. end;
  1175. writeln(s1,'end;');
  1176. end
  1177. else if pe is TPasSetType then
  1178. begin
  1179. pst:=TPasSetType(pe);
  1180. writeln('set of ',pst.EnumType.Name,';');
  1181. end
  1182. else if pe is TPasClassOfType then writeln('Class of ',TPasClassOfType(pe).DestType.Name,';')
  1183. else if pe is tPasAliasType then
  1184. begin
  1185. pe:=tPasAliasType(PE).DestType;
  1186. write(PE.name);
  1187. if pe is tPasStringType then
  1188. begin
  1189. if (TPasStringType(PE).LengthExpr<>'') then
  1190. Write('[',TPasStringType(PE).LengthExpr,']');
  1191. end;
  1192. Writeln(';');
  1193. end
  1194. else if pe is tPasUnresolvedTypeRef then writeln(TPasUnresolvedTypeRef(PE).name,';')
  1195. else
  1196. begin
  1197. writeln('{ Unknown TYPE(s): ');
  1198. writeln(s,pe.Name,' ',pe.classname);
  1199. writeln('}');
  1200. writeln;
  1201. end;
  1202. end;
  1203. procedure GetTCallingConvention(cc:TCallingConvention); //TODO: test it
  1204. begin
  1205. case cc of
  1206. //ccDefault:write(' default;'); //normal proccall is default
  1207. ccRegister:WriteFmt(true,'Register;',false);
  1208. ccPascal :WriteFmt(true,'Pascal;',false);
  1209. ccCDecl :WriteFmt(true,'CDecl;',false);
  1210. ccStdCall :WriteFmt(true,'StdCall;',false);
  1211. ccOldFPCCall:WriteFmt(true,'OldFPCall;',false);
  1212. ccSafeCall:WriteFmt(true,'SaveCall;',false);
  1213. end;
  1214. end;
  1215. procedure GetHiddenModifiers(Mfs:TProcedureModifiers);
  1216. begin
  1217. if pmInline in Mfs then WriteFmt(true,'inline;',false);
  1218. if pmAssembler in Mfs then WriteFmt(true,'assembler;',false);
  1219. if pmVarargs in Mfs then WriteFmt(true,'varargs;',false);
  1220. if pmCompilerProc in Mfs then WriteFmt(true,'compilerproc;',false);
  1221. if pmExtdecl in Mfs then WriteFmt(true,'extdecl;',false);
  1222. end;
  1223. procedure GetTPasProcedure(lpp:TPasProcedure; indent:integer);
  1224. var l:integer;
  1225. lppt:TPasProcedureType;
  1226. s:String;
  1227. begin
  1228. if not Assigned(lpp) then exit;
  1229. s:=GetIndent(indent);
  1230. if lpp is TPasConstructor then write(s,'Constructor ')
  1231. else if TPasElement(lpp) is TPasConstructorImpl then write(s,'Constructor ')
  1232. else if lpp is TPasDestructor then write(s,'Destructor ')
  1233. else if TPasElement(lpp) is TPasDestructorImpl then write(s,'Destructor ')
  1234. else if lpp is TPasClassProcedure then write(s,'Class Procedure ') //pparser.pp: 3221
  1235. else if lpp is TPasClassFunction then write(s,'Class Function ')
  1236. else if lpp is TPasFunction then write(s,'Function ')
  1237. else write(s,'Procedure ');
  1238. write(lpp.Name);//,' ',lpp.TypeName);
  1239. if assigned(lpp.ProcType) then
  1240. begin
  1241. lppt:=lpp.ProcType;
  1242. GetTPasProcedureType(lppt,Indent);
  1243. end;
  1244. //writeln(';');
  1245. WriteFmt(false,'',true);
  1246. if lpp.IsVirtual then WriteFmt(true,'virtual;',false);
  1247. if lpp.IsOverload then WriteFmt(true,'overload;',false);
  1248. if lpp.IsAbstract then WriteFmt(true,'abstract;',false);
  1249. if lpp.IsDynamic then WriteFmt(true,'dynamic;',false);
  1250. if lpp.IsOverride then WriteFmt(true,'override;',false);
  1251. if lpp.IsExported then WriteFmt(true,'exported;',false);
  1252. if lpp.IsExternal then WriteFmt(true,'external;',false);
  1253. //pparser 2360: everyting behind external is ignored !!!
  1254. if lpp.IsMessage then
  1255. begin
  1256. write('message ');
  1257. if lpp.MessageType = pmtString then writeln(false,lpp.MessageName,true)
  1258. else WriteFmt(false,lpp.MessageName,true);//pmtInteger
  1259. end;
  1260. if lpp.IsReintroduced then WriteFmt(true,'reintroduce;',false);
  1261. if lpp.IsStatic then WriteFmt(true,'static;',false);
  1262. if lpp.IsForward then WriteFmt(true,'forward;',false);
  1263. GetHiddenModifiers(lpp.Modifiers);
  1264. GetTCallingConvention(lpp.CallingConvention);
  1265. if GetTPasMemberHints(TPasElement(lpp).Hints) then WriteFmt(false,'',true); //BUG ? missing hints
  1266. if not Unformated then writeln;
  1267. end;
  1268. procedure GetTPasProcedureBody(pb:TProcedureBody; indent:integer);
  1269. var j:integer;
  1270. pd:TPasDeclarations;
  1271. pib:TPasImplBlock;
  1272. begin
  1273. if assigned(pb) then
  1274. begin
  1275. if assigned(pb.Body)then
  1276. begin
  1277. if assigned(TPasDeclarations(pb).Functions)then
  1278. begin
  1279. pd:=TPasDeclarations(pb);
  1280. if isim then
  1281. begin
  1282. //writeln;
  1283. GetDecls(pd,indent+1); //~recursion
  1284. //PrintDecls(pd,indent+1); //~recursion
  1285. end
  1286. else
  1287. if pd.Functions.Count >0 then //sub-functions
  1288. begin
  1289. for j:=0 to pd.Functions.Count-1 do
  1290. GetTPasProcedure(TPasProcedure(pd.Functions[j]),indent+1);
  1291. end;
  1292. end;
  1293. pib:=TPasImplBlock(pb.Body);
  1294. if assigned(pib) then
  1295. begin
  1296. GetTPasImplBlock(pib,indent,0,false,false); //indent depend on sub function level
  1297. if not Unformated then writeln; //('//block');
  1298. end;
  1299. end;
  1300. end;
  1301. end;
  1302. procedure GetTpasOverloadedProc(pop:TPasOverloadedProc; indent:integer);
  1303. var pp:TPasProcedure;
  1304. j:integer;
  1305. begin
  1306. if assigned(pop) then
  1307. begin
  1308. if pop.Overloads.Count >0 then
  1309. begin
  1310. for j:=0 to pop.Overloads.Count-1 do
  1311. begin
  1312. pp:=TPasProcedure(pop.Overloads[j]);
  1313. GetTPasProcedure(pp,indent);
  1314. GetTPasProcedureBody(pp.Body,indent);
  1315. end;
  1316. end;
  1317. end;
  1318. end;
  1319. function GetVisibility(v:TPasMemberVisibility):String;
  1320. begin
  1321. Result:='';
  1322. case v of
  1323. //visDefault:Result:='default';
  1324. visPrivate:Result:='private';
  1325. visProtected:Result:='protected';
  1326. visPublic:Result:='public';
  1327. visPublished:Result:='published';
  1328. visAutomated:Result:='automated';
  1329. visStrictPrivate:Result:='strictprivate';
  1330. visStrictProtected:Result:='strictprotected';
  1331. end;
  1332. end;
  1333. procedure GetTPasClass(pc:TPasClassType; indent:integer);
  1334. var j,l:integer;
  1335. s,s1,s2:String;
  1336. lpe:TPasElement;
  1337. lpp:TPasProperty;
  1338. lpa:TPasArgument;
  1339. vis:TPasMemberVisibility;
  1340. vars:TFPList;
  1341. IsVar:boolean;
  1342. procedure PrintVars;
  1343. begin
  1344. if vars.Count > 0 then GetPasVariables(vars,indent+1,false,false);
  1345. IsVar:=False;
  1346. vars.Clear;
  1347. end;
  1348. begin
  1349. if assigned(pc) then
  1350. begin
  1351. s:=GetIndent(indent);
  1352. if (pc.ObjKind=okGeneric) then
  1353. begin
  1354. write(s,'generic ',pc.Name);
  1355. for l:=0 to pc.GenericTemplateTypes.Count-1 do
  1356. begin
  1357. if l=0 then
  1358. Write('<')
  1359. else
  1360. Write(',');
  1361. Write(TPasGenericTemplateType(pc.GenericTemplateTypes[l]).Name);
  1362. end;
  1363. Write('> = ');
  1364. end
  1365. else
  1366. write(s,pc.Name,' = ');
  1367. if pc.IsPacked then write('packed ');
  1368. case pc.ObjKind of
  1369. okObject:write('Object');
  1370. okClass:write('Class');
  1371. okInterface:write('Interface');
  1372. okGeneric:write('class');
  1373. okspecialize : write('specialize');
  1374. end;
  1375. if assigned(pc.AncestorType) and (pc.AncestorType.ElementTypeName <> '') then
  1376. begin
  1377. if pc.ObjKind<>okspecialize then
  1378. write('(',pc.AncestorType.Name,')')
  1379. else
  1380. begin
  1381. write(' ',pc.AncestorType.Name);
  1382. for l:=0 to pc.GenericTemplateTypes.Count-1 do
  1383. begin
  1384. if l=0 then
  1385. Write('<')
  1386. else
  1387. Write(',');
  1388. Write(TPasGenericTemplateType(pc.GenericTemplateTypes[l]).Name);
  1389. end;
  1390. Write('>');
  1391. end;
  1392. end;
  1393. if pc.IsForward or pc.IsShortDefinition then //pparser.pp: 3417 :class(anchestor); is allowed !
  1394. begin
  1395. writeln(';');
  1396. exit;
  1397. end;
  1398. //Members: TFPList;
  1399. //InterfaceGUID: String;
  1400. //ClassVars: TFPList; //is this always empty ?
  1401. //Modifiers: TStringList;
  1402. //Interfaces: TFPList;
  1403. s1:=GetIndent(indent+1);
  1404. s2:=GetIndent(indent+2);
  1405. if pc.Members.Count > 0 then
  1406. begin
  1407. writeln;
  1408. vars:=TFPList.Create;
  1409. IsVar:=false;
  1410. for j:=0 to pc.Members.Count-1 do
  1411. begin
  1412. lpe:=TPasElement(pc.Members[j]);
  1413. //Class visibility, written on change
  1414. if j=0 then
  1415. begin
  1416. vis:=lpe.Visibility;
  1417. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1418. end
  1419. else
  1420. if vis <> lpe.Visibility then
  1421. begin
  1422. if IsVar then PrintVars;
  1423. if lpe.Visibility <> visDefault then //Class Function = visDefault
  1424. begin
  1425. vis:=lpe.Visibility;
  1426. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1427. end;
  1428. end;
  1429. if lpe is TPasOverloadedProc then
  1430. begin
  1431. if IsVar then PrintVars;
  1432. GetTPasOverloadedProc(TPasOverloadedProc(lpe),indent+2);
  1433. end
  1434. else if lpe is TPasProcedure then //TPasClassProcedure and
  1435. begin //TPasClassFunction are both child of TPasProcedure
  1436. if IsVar then PrintVars;
  1437. GetTPasProcedure(TPasProcedure(lpe),indent+2);
  1438. end
  1439. else if lpe is TPasProperty then
  1440. begin
  1441. if IsVar then PrintVars;
  1442. lpp:=TPasProperty(lpe);
  1443. write(s2,'property ',lpp.Name);
  1444. if lpp.Args.Count >0 then
  1445. begin
  1446. for l:=0 to lpp.Args.Count-1 do
  1447. begin
  1448. lpa:=TPasArgument(lpp.Args.Items[l]);
  1449. if GetTPasArgumentAccess(lpa.Access) <> '' then
  1450. write('[',GetTPasArgumentAccess(lpa.Access),' ',lpa.Name)
  1451. else write('[',lpa.Name); //variblename
  1452. if assigned(lpa.ArgType) then
  1453. begin
  1454. //if TPasType(lpa.ArgType).ElementTypeName <>'unresolved type reference' then
  1455. //,TPasType(lpa.ArgType).Name,' ');
  1456. //,TPasType(lpa.ArgType).FullName,TPasType(lpa.ArgType).ElementTypeName)
  1457. // PParser 2099: ArgType := nil; if IsUntyped then => Arg.ArgType := ArgType;
  1458. // else write(':? ');
  1459. write(': ');
  1460. if lpa.ArgType is TPasArrayType then
  1461. begin
  1462. GetTPasArrayType(TPasArrayType(lpa.ArgType));
  1463. end
  1464. else write(TPasType(lpa.ArgType).Name);
  1465. end;
  1466. if lpa.Value <> '' then write('=',lpa.Value);
  1467. write(']');
  1468. end;
  1469. end;//args
  1470. if assigned(lpp.VarType) then
  1471. begin
  1472. write(': ',TPasType(lpp.VarType).Name);
  1473. end;
  1474. if lpp.IndexValue <> '' then write(' Index ',lpp.IndexValue);
  1475. if lpp.ReadAccessorName <> '' then write(' Read ',lpp.ReadAccessorName);
  1476. if lpp.WriteAccessorName <> '' then write(' Write ',lpp.WriteAccessorName);
  1477. if lpp.ImplementsName <> '' then write(' Implements ',lpp.ImplementsName);
  1478. if lpp.IsDefault then write(' Default ',lpp.DefaultValue);
  1479. if lpp.IsNodefault then write(' NoDefault');
  1480. if lpp.StoredAccessorName <> '' then write(' Stored ',lpp.StoredAccessorName);
  1481. GetTPasMemberHints(lpp.Hints);
  1482. writeln(';');
  1483. end
  1484. else if lpe is TPasVariable then
  1485. begin
  1486. //this is done with printvars
  1487. //GetTPasVar(TPasVariable(lpe),indent+1,false);
  1488. IsVar:=true;
  1489. vars.add(lpe);
  1490. end
  1491. else
  1492. begin
  1493. if IsVar then PrintVars;
  1494. writeln('{ Unknown Declaration(s) in Class/Object/Interface: ');
  1495. writeln(s,lpe.Name);
  1496. writeln('}');
  1497. end;
  1498. end;
  1499. //writeln(s,'end;');//'//class');
  1500. if IsVar then PrintVars;
  1501. vars.free;
  1502. end
  1503. else writeln;//(';'); //x=class(y);
  1504. writeln(s,'end;');
  1505. end;
  1506. end;
  1507. procedure GetDecls(Decl:TPasDeclarations; indent:integer);
  1508. var i,j:integer;
  1509. pe:TPasElement;
  1510. pp:TPasProcedure;
  1511. ps:TPasSection;
  1512. s:string;
  1513. x:(None,ResStrings,Types,Consts,Classes,Functions,Variables,Properties);
  1514. l:TFPList;
  1515. procedure PrintVars;
  1516. begin
  1517. if l.Count > 0 then GetPasVariables(l,indent+1,false,false);
  1518. end;
  1519. begin
  1520. s:=GetIndent(indent);
  1521. x:=None;
  1522. if assigned(Decl)then
  1523. begin
  1524. l:=TFPList.Create;
  1525. pe:=TPasElement(Decl);
  1526. if pe is TPasSection then
  1527. begin
  1528. {(Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1529. (Decl is TProgramSection}
  1530. ps:=TPasSection(pe);
  1531. if ps.UsesList.Count >0 then
  1532. begin
  1533. write(s,'uses ');
  1534. ps:=TPasSection(Decl);
  1535. if not Unformated then begin writeln; write(s,' '); end;
  1536. for i:=0 to ps.UsesList.Count-2 do
  1537. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1538. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1539. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1540. if not Unformated then writeln;
  1541. end;
  1542. end;
  1543. if assigned(Decl.Declarations)and(Decl.Declarations.Count > 0) then
  1544. for j:=0 to Decl.Declarations.Count-1 do
  1545. begin
  1546. pe:=TPasElement(Decl.Declarations[j]);
  1547. if pe is TPasResString then
  1548. begin
  1549. if x = Variables then PrintVars;
  1550. if x <> ResStrings then
  1551. begin
  1552. if not Unformated then writeln;
  1553. writeln(s,'ResourceString');
  1554. x:=ResStrings;
  1555. end;
  1556. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Value),';'); //too much '''
  1557. end
  1558. else if pe is TPasConst then
  1559. begin
  1560. if x = Variables then PrintVars;
  1561. if x <> Consts then
  1562. begin
  1563. if not Unformated then writeln;
  1564. writeln(s,'const');
  1565. x:=Consts;
  1566. end;
  1567. GetTPasVar(TPasVariable(pe),indent+1,false);
  1568. end
  1569. else if pe is TPasVariable then
  1570. begin
  1571. if x <> Variables then
  1572. begin
  1573. if not Unformated then writeln;
  1574. writeln(s,'var');
  1575. x:=Variables;
  1576. l.Clear;
  1577. end;
  1578. l.Add(pe);
  1579. //this is done with printvars
  1580. //GetTPasVar(TPasVariable(pe),indent+1,false);
  1581. end
  1582. else if pe is TPasClassType then
  1583. begin
  1584. if x = Variables then PrintVars;
  1585. if x <> Types then
  1586. begin
  1587. if not Unformated then writeln;
  1588. writeln(s,'Type');
  1589. x:=Types;
  1590. end;
  1591. GetTPasClass(TPasClassType(pe),indent+1);
  1592. end
  1593. else if pe is TPasType then
  1594. begin
  1595. if x = Variables then PrintVars;
  1596. if x <> Types then
  1597. begin
  1598. if not Unformated then writeln;
  1599. writeln(s,'Type');
  1600. x:=Types;
  1601. end;
  1602. GetTypes(TPasElement(pe),indent+1);
  1603. end
  1604. else if pe is TPasProcedureBase then
  1605. begin
  1606. if x = Variables then PrintVars;
  1607. if (x <> Functions)and not Unformated then writeln;
  1608. x:=Functions;
  1609. if pe is TPasOverloadedProc then
  1610. begin
  1611. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1612. end
  1613. else
  1614. begin
  1615. pp:=TPasProcedure(pe);
  1616. GetTPasProcedure(pp,indent);
  1617. GetTPasProcedureBody(pp.Body,indent);
  1618. end;
  1619. end
  1620. else
  1621. begin
  1622. if x = Variables then PrintVars;
  1623. x:=None;
  1624. writeln('{ Unknown Declaration: ',pe.Name,' }');
  1625. end;
  1626. end;
  1627. if x = Variables then PrintVars;
  1628. l.Free;
  1629. end;
  1630. end;
  1631. {replaced by GetDecls
  1632. this does the same but not in true order
  1633. procedure PrintDecls(Decl:TPasDeclarations; indent:integer);
  1634. var i:integer;
  1635. pe:TPasElement;
  1636. pp:TPasProcedure;
  1637. ps:TPasSection;
  1638. s:string;
  1639. istype:boolean;
  1640. begin
  1641. istype:=false;
  1642. s:=GetIndent(indent);
  1643. if (Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1644. (Decl is TProgramSection) then
  1645. if TPasSection(Decl).UsesList.Count >0 then
  1646. begin
  1647. write(s,'uses ');
  1648. ps:=TPasSection(Decl);
  1649. if not Unformated then begin writeln; write(s,' '); end;
  1650. for i:=0 to ps.UsesList.Count-2 do
  1651. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1652. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1653. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1654. if not Unformated then writeln;
  1655. end;
  1656. if assigned(Decl.ResStrings) then
  1657. if Decl.ResStrings.Count >0 then
  1658. begin
  1659. writeln('ResourceString');
  1660. for i := 0 to Decl.ResStrings.Count - 1 do
  1661. begin
  1662. pe:=TPasElement(Decl.ResStrings[i]);
  1663. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Value),';'); //too much '''
  1664. end;
  1665. if not Unformated then writeln;
  1666. end;
  1667. if assigned(Decl.Consts)then
  1668. if Decl.Consts.Count >0 then
  1669. begin
  1670. writeln(s,'const');
  1671. for i:=0 to Decl.Consts.Count-1 do GetTPasVar(TPasVariable(Decl.Consts[i]),indent+1,false);
  1672. if not Unformated then writeln;
  1673. end;
  1674. if assigned(Decl.Types) then
  1675. if Decl.Types.Count >0 then
  1676. begin
  1677. writeln(s,'Type');
  1678. for i := 0 to Decl.Types.Count - 1 do
  1679. begin
  1680. GetTypes(TPasElement(Decl.Types[i]),indent+1);
  1681. end;
  1682. if not Unformated then writeln;
  1683. istype:=true;
  1684. end;
  1685. if assigned(Decl.Classes) then
  1686. if Decl.Classes.Count >0 then
  1687. begin
  1688. if not istype then writeln('Type');
  1689. for i := 0 to Decl.Classes.Count - 1 do
  1690. begin
  1691. pe:=TPasElement(Decl.Classes[i]);
  1692. GetTPasClass(TPasClassType(pe),indent+1);
  1693. if not Unformated then writeln;
  1694. end;
  1695. end;
  1696. if assigned(Decl.Variables)then
  1697. if Decl.Variables.Count >0 then
  1698. begin
  1699. writeln(s,'var');
  1700. //Now i use GetPasVariables for more compact output
  1701. //for i:=0 to Decl.Variables.Count-1 do GetTPasVar(TPasVariable(Decl.Variables[i]),indent+1,false);
  1702. GetPasVariables(Decl.Variables,indent+1,false,false);
  1703. if not Unformated then writeln;
  1704. end;
  1705. if assigned(Decl.Functions) then
  1706. begin
  1707. for i := 0 to Decl.Functions.Count - 1 do
  1708. begin
  1709. pe:=TPasElement(Decl.Functions[i]);
  1710. if pe is TPasOverloadedProc then
  1711. begin
  1712. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1713. end
  1714. else
  1715. begin
  1716. pp:=TPasProcedure(pe);
  1717. GetTPasProcedure(pp,indent);
  1718. GetTPasProcedureBody(pp.Body,indent);
  1719. end;
  1720. end;
  1721. end;
  1722. end; }
  1723. //# parameter
  1724. procedure PrintUsage;
  1725. begin
  1726. writeln('usage: test_parser1 <Options> <Commandline> File');
  1727. writeln;
  1728. writeln(' <Options> : Options for test_parser1');
  1729. writeln(' -u : Unformated output');
  1730. writeln(' -OS <os> : <os> = WINDOWS, LINUX (default), FREEBSD, NETBSD,');
  1731. writeln(' SUNOS, BEOS, QNX, GO32V2');
  1732. writeln(' -CPU <cpu> : <cpu> = i386 (default), x86_64');
  1733. writeln(' <Commandline> : is the commandline for the parser');
  1734. writeln(' -d<define> : <define> = Directive');
  1735. writeln(' -Fi<include_path> : <include_path> = ?');
  1736. writeln(' -I<include_path> : <include_path> = ?');
  1737. writeln(' -Sd : mode delphi');
  1738. writeln(' File : a pascal source file (Program or Unit)');
  1739. end;
  1740. procedure GetParam;
  1741. begin
  1742. if paramcount>0 then
  1743. begin
  1744. cmdl:='';
  1745. i:=1;
  1746. repeat
  1747. if paramstr(i) = '-h' then
  1748. begin
  1749. PrintUsage;
  1750. halt(0);
  1751. end
  1752. else if paramstr(i) = '-u' then Unformated:= true
  1753. else if paramstr(i) = '-OS' then
  1754. begin
  1755. if i < paramcount then
  1756. begin
  1757. inc(i);
  1758. TargetOS:=paramstr(i);
  1759. if (TargetOS = '')or(TargetOS[1] = '-') then halt(1);
  1760. end
  1761. else halt(1);
  1762. end
  1763. else if paramstr(i) = '-CPU' then
  1764. begin
  1765. if i < paramcount then
  1766. begin
  1767. inc(i);
  1768. TargetCPU:=paramstr(i);
  1769. if (TargetCPU = '')or(TargetCPU[1] = '-') then halt(1);
  1770. end
  1771. else halt(1);
  1772. end
  1773. else
  1774. cmdl:=cmdl+' '+paramstr(i);
  1775. inc(i);
  1776. until i > paramcount;
  1777. end;
  1778. if (Paramcount < 1)or(cmdl = '') then
  1779. begin
  1780. // remember to put the whole cmdline in quotes, and
  1781. // to always add some path options. Even if only -Fu. -Fi.
  1782. writeln('Error: No file for input given !');
  1783. PrintUsage;
  1784. halt(1);
  1785. end;
  1786. end;
  1787. //# *** main ***
  1788. begin
  1789. isim:=false;
  1790. Unformated:=false;//false to format output to be human readable
  1791. TargetOS:='linux';
  1792. TargetCPU:='i386';
  1793. GetParam;
  1794. //writeln(TargetOS,' ',TargetCPU,' ',cmdl);halt;
  1795. E := TSimpleEngine.Create;
  1796. try
  1797. try
  1798. M := ParseSource(E, cmdl ,TargetOS ,TargetCPU);
  1799. except
  1800. on excep:EParserError do
  1801. begin
  1802. writeln(excep.message,' line:',excep.row,' column:',excep.column,' file:',excep.filename);
  1803. raise;
  1804. end;
  1805. end;
  1806. if M is TPasProgram then
  1807. begin
  1808. writeln('Program ',M.Name,';');
  1809. if not Unformated then writeln;
  1810. if assigned(M.ImplementationSection) then
  1811. begin
  1812. isim:=true;
  1813. if not Unformated then writeln;
  1814. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1815. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1816. end;
  1817. if assigned(M.InitializationSection) then // MAIN BLOCK
  1818. begin
  1819. isim:=false;
  1820. if not Unformated then writeln;
  1821. writeln('begin');//writeln('begin {Begin MAIN Program}')
  1822. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1823. end;
  1824. end
  1825. else
  1826. begin
  1827. { Cool, we successfully parsed the unit.
  1828. Now output some info about it. }
  1829. writeln('Unit ',M.Name,';');
  1830. if not Unformated then writeln;
  1831. Writeln('Interface');
  1832. if not Unformated then writeln;
  1833. GetDecls(M.InterfaceSection as TPasDeclarations,0);
  1834. //PrintDecls(M.InterfaceSection as TPasDeclarations,0);
  1835. if assigned(M.ImplementationSection) then
  1836. begin
  1837. isim:=true;
  1838. if not Unformated then writeln;
  1839. Writeln('Implementation');
  1840. if not Unformated then writeln;
  1841. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1842. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1843. if TPasElement(M.ImplementationSection) is TPasImplElement then writeln('{MAIN}');
  1844. end;
  1845. if assigned(M.InitializationSection) then //is this begin .. end. of a unit too ?
  1846. begin
  1847. isim:=true;
  1848. if not Unformated then writeln;
  1849. Writeln('Initialization');
  1850. if not Unformated then writeln;
  1851. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1852. if assigned(M.FinalizationSection) then
  1853. begin
  1854. isim:=true;
  1855. if not Unformated then writeln;
  1856. Writeln('Finalization');
  1857. if not Unformated then writeln;
  1858. GetTPasImplBlock(M.FinalizationSection as TPasImplBlock,1,0,false,false);
  1859. end;
  1860. end;
  1861. end;
  1862. if not Unformated then writeln('end.')
  1863. else
  1864. begin
  1865. writeln('end');
  1866. writeln('.');
  1867. end;
  1868. FreeAndNil(M);
  1869. finally
  1870. FreeAndNil(E);
  1871. end;
  1872. end.