test_parser.pp 61 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969
  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(TPasExpr(lics.Expressions[l]).GetDeclaration(True)),',');
  438. write(DelQuot(TPasExpr(lics.Expressions[lics.Expressions.Count-1]).GetDeclaration(True)),': '); // !!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(TPasExpr(liwd.Expressions[l]).GetDeclaration(true),',');
  459. write(TPasExpr(liwd.Expressions[liwd.Expressions.Count-1]).GetDeclaration(true));
  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.Variable.Name,':= ',lifl.StartExpr.GetDeclaration(True),' ');
  494. if lifl.Down then write('down');
  495. writeln('to ',lifl.EndExpr.GetDeclaration(True),' 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.VariantEl.GetDeclaration(True) <>'' then write(prct.VariantEl.GetDeclaration(True),'=');
  1071. write(TPasType(prct.VariantEl).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(TPasElement(pv.Values[k]).GetDeclaration(true));
  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.VariantEl.Name <>'' then write(prct.VariantEl.Name,'=');
  1158. write(TPasType(prct.VariantEl).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(TPasElement(pv.Values[k]).GetDeclaration(true));
  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. end;
  1222. procedure GetTPasProcedure(lpp:TPasProcedure; indent:integer);
  1223. var l:integer;
  1224. lppt:TPasProcedureType;
  1225. s:String;
  1226. begin
  1227. if not Assigned(lpp) then exit;
  1228. s:=GetIndent(indent);
  1229. if lpp is TPasConstructor then write(s,'Constructor ')
  1230. else if TPasElement(lpp) is TPasConstructorImpl then write(s,'Constructor ')
  1231. else if lpp is TPasDestructor then write(s,'Destructor ')
  1232. else if TPasElement(lpp) is TPasDestructorImpl then write(s,'Destructor ')
  1233. else if lpp is TPasClassProcedure then write(s,'Class Procedure ') //pparser.pp: 3221
  1234. else if lpp is TPasClassFunction then write(s,'Class Function ')
  1235. else if lpp is TPasFunction then write(s,'Function ')
  1236. else write(s,'Procedure ');
  1237. write(lpp.Name);//,' ',lpp.TypeName);
  1238. if assigned(lpp.ProcType) then
  1239. begin
  1240. lppt:=lpp.ProcType;
  1241. GetTPasProcedureType(lppt,Indent);
  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:TFPList;
  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. write(ObjKindNames[pc.ObjKind]);
  1368. if assigned(pc.AncestorType) and (pc.AncestorType.ElementTypeName <> '') then
  1369. begin
  1370. write('(',pc.AncestorType.Name,')');
  1371. end;
  1372. if pc.IsForward or pc.IsShortDefinition then //pparser.pp: 3417 :class(anchestor); is allowed !
  1373. begin
  1374. writeln(';');
  1375. exit;
  1376. end;
  1377. //Members: TFPList;
  1378. //InterfaceGUID: String;
  1379. //ClassVars: TFPList; //is this always empty ?
  1380. //Modifiers: TStringList;
  1381. //Interfaces: TFPList;
  1382. s1:=GetIndent(indent+1);
  1383. s2:=GetIndent(indent+2);
  1384. if pc.Members.Count > 0 then
  1385. begin
  1386. writeln;
  1387. vars:=TFPList.Create;
  1388. IsVar:=false;
  1389. for j:=0 to pc.Members.Count-1 do
  1390. begin
  1391. lpe:=TPasElement(pc.Members[j]);
  1392. //Class visibility, written on change
  1393. if j=0 then
  1394. begin
  1395. vis:=lpe.Visibility;
  1396. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1397. end
  1398. else
  1399. if vis <> lpe.Visibility then
  1400. begin
  1401. if IsVar then PrintVars;
  1402. if lpe.Visibility <> visDefault then //Class Function = visDefault
  1403. begin
  1404. vis:=lpe.Visibility;
  1405. if GetVisibility(vis) <> '' then writeln(s1,GetVisibility(vis));
  1406. end;
  1407. end;
  1408. if lpe is TPasOverloadedProc then
  1409. begin
  1410. if IsVar then PrintVars;
  1411. GetTPasOverloadedProc(TPasOverloadedProc(lpe),indent+2);
  1412. end
  1413. else if lpe is TPasProcedure then //TPasClassProcedure and
  1414. begin //TPasClassFunction are both child of TPasProcedure
  1415. if IsVar then PrintVars;
  1416. GetTPasProcedure(TPasProcedure(lpe),indent+2);
  1417. end
  1418. else if lpe is TPasProperty then
  1419. begin
  1420. if IsVar then PrintVars;
  1421. lpp:=TPasProperty(lpe);
  1422. write(s2,'property ',lpp.Name);
  1423. if lpp.Args.Count >0 then
  1424. begin
  1425. for l:=0 to lpp.Args.Count-1 do
  1426. begin
  1427. lpa:=TPasArgument(lpp.Args.Items[l]);
  1428. if GetTPasArgumentAccess(lpa.Access) <> '' then
  1429. write('[',GetTPasArgumentAccess(lpa.Access),' ',lpa.Name)
  1430. else write('[',lpa.Name); //variblename
  1431. if assigned(lpa.ArgType) then
  1432. begin
  1433. //if TPasType(lpa.ArgType).ElementTypeName <>'unresolved type reference' then
  1434. //,TPasType(lpa.ArgType).Name,' ');
  1435. //,TPasType(lpa.ArgType).FullName,TPasType(lpa.ArgType).ElementTypeName)
  1436. // PParser 2099: ArgType := nil; if IsUntyped then => Arg.ArgType := ArgType;
  1437. // else write(':? ');
  1438. write(': ');
  1439. if lpa.ArgType is TPasArrayType then
  1440. begin
  1441. GetTPasArrayType(TPasArrayType(lpa.ArgType));
  1442. end
  1443. else write(TPasType(lpa.ArgType).Name);
  1444. end;
  1445. if lpa.Value <> '' then write('=',lpa.Value);
  1446. write(']');
  1447. end;
  1448. end;//args
  1449. if assigned(lpp.VarType) then
  1450. begin
  1451. write(': ',TPasType(lpp.VarType).Name);
  1452. end;
  1453. if lpp.IndexValue <> '' then write(' Index ',lpp.IndexValue);
  1454. if lpp.ReadAccessorName <> '' then write(' Read ',lpp.ReadAccessorName);
  1455. if lpp.WriteAccessorName <> '' then write(' Write ',lpp.WriteAccessorName);
  1456. if lpp.ImplementsName <> '' then write(' Implements ',lpp.ImplementsName);
  1457. if lpp.IsDefault then write(' Default ',lpp.DefaultValue);
  1458. if lpp.IsNodefault then write(' NoDefault');
  1459. if lpp.StoredAccessorName <> '' then write(' Stored ',lpp.StoredAccessorName);
  1460. GetTPasMemberHints(lpp.Hints);
  1461. writeln(';');
  1462. end
  1463. else if lpe is TPasVariable then
  1464. begin
  1465. //this is done with printvars
  1466. //GetTPasVar(TPasVariable(lpe),indent+1,false);
  1467. IsVar:=true;
  1468. vars.add(lpe);
  1469. end
  1470. else
  1471. begin
  1472. if IsVar then PrintVars;
  1473. writeln('{ Unknown Declaration(s) in Class/Object/Interface: ');
  1474. writeln(s,lpe.Name);
  1475. writeln('}');
  1476. end;
  1477. end;
  1478. //writeln(s,'end;');//'//class');
  1479. if IsVar then PrintVars;
  1480. vars.free;
  1481. end
  1482. else writeln;//(';'); //x=class(y);
  1483. writeln(s,'end;');
  1484. end;
  1485. end;
  1486. procedure GetDecls(Decl:TPasDeclarations; indent:integer);
  1487. var i,j:integer;
  1488. pe:TPasElement;
  1489. pp:TPasProcedure;
  1490. ps:TPasSection;
  1491. s:string;
  1492. x:(None,ResStrings,Types,Consts,Classes,Functions,Variables,Properties);
  1493. l:TFPList;
  1494. procedure PrintVars;
  1495. begin
  1496. if l.Count > 0 then GetPasVariables(l,indent+1,false,false);
  1497. end;
  1498. begin
  1499. s:=GetIndent(indent);
  1500. x:=None;
  1501. if assigned(Decl)then
  1502. begin
  1503. l:=TFPList.Create;
  1504. pe:=TPasElement(Decl);
  1505. if pe is TPasSection then
  1506. begin
  1507. {(Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1508. (Decl is TProgramSection}
  1509. ps:=TPasSection(pe);
  1510. if ps.UsesList.Count >0 then
  1511. begin
  1512. write(s,'uses ');
  1513. ps:=TPasSection(Decl);
  1514. if not Unformated then begin writeln; write(s,' '); end;
  1515. for i:=0 to ps.UsesList.Count-2 do
  1516. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1517. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1518. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1519. if not Unformated then writeln;
  1520. end;
  1521. end;
  1522. if assigned(Decl.Declarations)and(Decl.Declarations.Count > 0) then
  1523. for j:=0 to Decl.Declarations.Count-1 do
  1524. begin
  1525. pe:=TPasElement(Decl.Declarations[j]);
  1526. if pe is TPasResString then
  1527. begin
  1528. if x = Variables then PrintVars;
  1529. if x <> ResStrings then
  1530. begin
  1531. if not Unformated then writeln;
  1532. writeln(s,'ResourceString');
  1533. x:=ResStrings;
  1534. end;
  1535. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Expr.GetDeclaration(false)),';'); //too much '''
  1536. end
  1537. else if pe is TPasConst then
  1538. begin
  1539. if x = Variables then PrintVars;
  1540. if x <> Consts then
  1541. begin
  1542. if not Unformated then writeln;
  1543. writeln(s,'const');
  1544. x:=Consts;
  1545. end;
  1546. GetTPasVar(TPasVariable(pe),indent+1,false);
  1547. end
  1548. else if pe is TPasVariable then
  1549. begin
  1550. if x <> Variables then
  1551. begin
  1552. if not Unformated then writeln;
  1553. writeln(s,'var');
  1554. x:=Variables;
  1555. l.Clear;
  1556. end;
  1557. l.Add(pe);
  1558. //this is done with printvars
  1559. //GetTPasVar(TPasVariable(pe),indent+1,false);
  1560. end
  1561. else if pe is TPasClassType then
  1562. begin
  1563. if x = Variables then PrintVars;
  1564. if x <> Types then
  1565. begin
  1566. if not Unformated then writeln;
  1567. writeln(s,'Type');
  1568. x:=Types;
  1569. end;
  1570. GetTPasClass(TPasClassType(pe),indent+1);
  1571. end
  1572. else if pe is TPasType then
  1573. begin
  1574. if x = Variables then PrintVars;
  1575. if x <> Types then
  1576. begin
  1577. if not Unformated then writeln;
  1578. writeln(s,'Type');
  1579. x:=Types;
  1580. end;
  1581. GetTypes(TPasElement(pe),indent+1);
  1582. end
  1583. else if pe is TPasProcedureBase then
  1584. begin
  1585. if x = Variables then PrintVars;
  1586. if (x <> Functions)and not Unformated then writeln;
  1587. x:=Functions;
  1588. if pe is TPasOverloadedProc then
  1589. begin
  1590. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1591. end
  1592. else
  1593. begin
  1594. pp:=TPasProcedure(pe);
  1595. GetTPasProcedure(pp,indent);
  1596. GetTPasProcedureBody(pp.Body,indent);
  1597. end;
  1598. end
  1599. else
  1600. begin
  1601. if x = Variables then PrintVars;
  1602. x:=None;
  1603. writeln('{ Unknown Declaration: ',pe.Name,' }');
  1604. end;
  1605. end;
  1606. if x = Variables then PrintVars;
  1607. l.Free;
  1608. end;
  1609. end;
  1610. {replaced by GetDecls
  1611. this does the same but not in true order
  1612. procedure PrintDecls(Decl:TPasDeclarations; indent:integer);
  1613. var i:integer;
  1614. pe:TPasElement;
  1615. pp:TPasProcedure;
  1616. ps:TPasSection;
  1617. s:string;
  1618. istype:boolean;
  1619. begin
  1620. istype:=false;
  1621. s:=GetIndent(indent);
  1622. if (Decl is TInterfaceSection)or(Decl is TImplementationSection) or
  1623. (Decl is TProgramSection) then
  1624. if TPasSection(Decl).UsesList.Count >0 then
  1625. begin
  1626. write(s,'uses ');
  1627. ps:=TPasSection(Decl);
  1628. if not Unformated then begin writeln; write(s,' '); end;
  1629. for i:=0 to ps.UsesList.Count-2 do
  1630. if UpCase(TPasElement(ps.UsesList[i]).Name) = 'SYSTEM' then continue //do not print system
  1631. else write(TPasElement(ps.UsesList[i]).Name,','); //as it is added by parser
  1632. writeln(TPasElement(ps.UsesList[ps.UsesList.Count-1]).Name,';');
  1633. if not Unformated then writeln;
  1634. end;
  1635. if assigned(Decl.ResStrings) then
  1636. if Decl.ResStrings.Count >0 then
  1637. begin
  1638. writeln('ResourceString');
  1639. for i := 0 to Decl.ResStrings.Count - 1 do
  1640. begin
  1641. pe:=TPasElement(Decl.ResStrings[i]);
  1642. writeln(s,pe.Name,'=',DelQuot(TPasResString(pe).Value),';'); //too much '''
  1643. end;
  1644. if not Unformated then writeln;
  1645. end;
  1646. if assigned(Decl.Consts)then
  1647. if Decl.Consts.Count >0 then
  1648. begin
  1649. writeln(s,'const');
  1650. for i:=0 to Decl.Consts.Count-1 do GetTPasVar(TPasVariable(Decl.Consts[i]),indent+1,false);
  1651. if not Unformated then writeln;
  1652. end;
  1653. if assigned(Decl.Types) then
  1654. if Decl.Types.Count >0 then
  1655. begin
  1656. writeln(s,'Type');
  1657. for i := 0 to Decl.Types.Count - 1 do
  1658. begin
  1659. GetTypes(TPasElement(Decl.Types[i]),indent+1);
  1660. end;
  1661. if not Unformated then writeln;
  1662. istype:=true;
  1663. end;
  1664. if assigned(Decl.Classes) then
  1665. if Decl.Classes.Count >0 then
  1666. begin
  1667. if not istype then writeln('Type');
  1668. for i := 0 to Decl.Classes.Count - 1 do
  1669. begin
  1670. pe:=TPasElement(Decl.Classes[i]);
  1671. GetTPasClass(TPasClassType(pe),indent+1);
  1672. if not Unformated then writeln;
  1673. end;
  1674. end;
  1675. if assigned(Decl.Variables)then
  1676. if Decl.Variables.Count >0 then
  1677. begin
  1678. writeln(s,'var');
  1679. //Now i use GetPasVariables for more compact output
  1680. //for i:=0 to Decl.Variables.Count-1 do GetTPasVar(TPasVariable(Decl.Variables[i]),indent+1,false);
  1681. GetPasVariables(Decl.Variables,indent+1,false,false);
  1682. if not Unformated then writeln;
  1683. end;
  1684. if assigned(Decl.Functions) then
  1685. begin
  1686. for i := 0 to Decl.Functions.Count - 1 do
  1687. begin
  1688. pe:=TPasElement(Decl.Functions[i]);
  1689. if pe is TPasOverloadedProc then
  1690. begin
  1691. GetTpasOverloadedProc(TPasOverloadedProc(pe),indent);
  1692. end
  1693. else
  1694. begin
  1695. pp:=TPasProcedure(pe);
  1696. GetTPasProcedure(pp,indent);
  1697. GetTPasProcedureBody(pp.Body,indent);
  1698. end;
  1699. end;
  1700. end;
  1701. end; }
  1702. //# parameter
  1703. procedure PrintUsage;
  1704. begin
  1705. writeln('usage: test_parser1 <Options> <Commandline> File');
  1706. writeln;
  1707. writeln(' <Options> : Options for test_parser1');
  1708. writeln(' -u : Unformated output');
  1709. writeln(' -OS <os> : <os> = WINDOWS, LINUX (default), FREEBSD, NETBSD,');
  1710. writeln(' SUNOS, BEOS, QNX, GO32V2');
  1711. writeln(' -CPU <cpu> : <cpu> = i386 (default), x86_64');
  1712. writeln(' <Commandline> : is the commandline for the parser');
  1713. writeln(' -d<define> : <define> = Directive');
  1714. writeln(' -Fi<include_path> : <include_path> = ?');
  1715. writeln(' -I<include_path> : <include_path> = ?');
  1716. writeln(' -Sd : mode delphi');
  1717. writeln(' File : a pascal source file (Program or Unit)');
  1718. end;
  1719. procedure GetParam;
  1720. begin
  1721. if paramcount>0 then
  1722. begin
  1723. cmdl:='';
  1724. i:=1;
  1725. repeat
  1726. if paramstr(i) = '-h' then
  1727. begin
  1728. PrintUsage;
  1729. halt(0);
  1730. end
  1731. else if paramstr(i) = '-u' then Unformated:= true
  1732. else if paramstr(i) = '-OS' then
  1733. begin
  1734. if i < paramcount then
  1735. begin
  1736. inc(i);
  1737. TargetOS:=paramstr(i);
  1738. if (TargetOS = '')or(TargetOS[1] = '-') then halt(1);
  1739. end
  1740. else halt(1);
  1741. end
  1742. else if paramstr(i) = '-CPU' then
  1743. begin
  1744. if i < paramcount then
  1745. begin
  1746. inc(i);
  1747. TargetCPU:=paramstr(i);
  1748. if (TargetCPU = '')or(TargetCPU[1] = '-') then halt(1);
  1749. end
  1750. else halt(1);
  1751. end
  1752. else
  1753. cmdl:=cmdl+' '+paramstr(i);
  1754. inc(i);
  1755. until i > paramcount;
  1756. end;
  1757. if (Paramcount < 1)or(cmdl = '') then
  1758. begin
  1759. // remember to put the whole cmdline in quotes, and
  1760. // to always add some path options. Even if only -Fu. -Fi.
  1761. writeln('Error: No file for input given !');
  1762. PrintUsage;
  1763. halt(1);
  1764. end;
  1765. end;
  1766. //# *** main ***
  1767. begin
  1768. isim:=false;
  1769. Unformated:=false;//false to format output to be human readable
  1770. TargetOS:='linux';
  1771. TargetCPU:='i386';
  1772. GetParam;
  1773. //writeln(TargetOS,' ',TargetCPU,' ',cmdl);halt;
  1774. E := TSimpleEngine.Create;
  1775. try
  1776. try
  1777. M := ParseSource(E, cmdl ,TargetOS ,TargetCPU,False);
  1778. except
  1779. on excep:EParserError do
  1780. begin
  1781. writeln(excep.message,' line:',excep.row,' column:',excep.column,' file:',excep.filename);
  1782. raise;
  1783. end;
  1784. end;
  1785. if M is TPasProgram then
  1786. begin
  1787. writeln('Program ',M.Name,';');
  1788. if not Unformated then writeln;
  1789. if assigned(M.ImplementationSection) then
  1790. begin
  1791. isim:=true;
  1792. if not Unformated then writeln;
  1793. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1794. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1795. end;
  1796. if assigned(M.InitializationSection) then // MAIN BLOCK
  1797. begin
  1798. isim:=false;
  1799. if not Unformated then writeln;
  1800. writeln('begin');//writeln('begin {Begin MAIN Program}')
  1801. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1802. end;
  1803. end
  1804. else
  1805. begin
  1806. { Cool, we successfully parsed the unit.
  1807. Now output some info about it. }
  1808. writeln('Unit ',M.Name,';');
  1809. if not Unformated then writeln;
  1810. Writeln('Interface');
  1811. if not Unformated then writeln;
  1812. GetDecls(M.InterfaceSection as TPasDeclarations,0);
  1813. //PrintDecls(M.InterfaceSection as TPasDeclarations,0);
  1814. if assigned(M.ImplementationSection) then
  1815. begin
  1816. isim:=true;
  1817. if not Unformated then writeln;
  1818. Writeln('Implementation');
  1819. if not Unformated then writeln;
  1820. GetDecls(M.ImplementationSection as TPasDeclarations,0);
  1821. //PrintDecls(M.ImplementationSection as TPasDeclarations,0);
  1822. if TPasElement(M.ImplementationSection) is TPasImplElement then writeln('{MAIN}');
  1823. end;
  1824. if assigned(M.InitializationSection) then //is this begin .. end. of a unit too ?
  1825. begin
  1826. isim:=true;
  1827. if not Unformated then writeln;
  1828. Writeln('Initialization');
  1829. if not Unformated then writeln;
  1830. GetTPasImplBlock(M.InitializationSection as TPasImplBlock,1,0,false,false);
  1831. end;
  1832. if assigned(M.FinalizationSection) then
  1833. begin
  1834. isim:=true;
  1835. if not Unformated then writeln;
  1836. Writeln('Finalization');
  1837. if not Unformated then writeln;
  1838. GetTPasImplBlock(M.FinalizationSection as TPasImplBlock,1,0,false,false);
  1839. end;
  1840. end;
  1841. if not Unformated then writeln('end.')
  1842. else
  1843. begin
  1844. writeln('end');
  1845. writeln('.');
  1846. end;
  1847. FreeAndNil(M);
  1848. finally
  1849. FreeAndNil(E);
  1850. end;
  1851. end.