browser.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. {
  2. $Id$
  3. Copyright (c) 1993-98 by the FPC development team
  4. Support routines for the browser
  5. This program is free software; you can redistribute it and/or modify
  6. it under the terms of the GNU General Public License as published by
  7. the Free Software Foundation; either version 2 of the License, or
  8. (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. ****************************************************************************
  17. }
  18. {$ifdef TP}
  19. {$N+,E+}
  20. {$endif}
  21. unit browser;
  22. interface
  23. uses
  24. cobjects,files;
  25. const
  26. {$ifdef TP}
  27. logbufsize = 1024;
  28. {$else}
  29. logbufsize = 16384;
  30. {$endif}
  31. type
  32. pref = ^tref;
  33. tref = object
  34. nextref : pref;
  35. posinfo : tfileposinfo;
  36. moduleindex : word;
  37. is_written : boolean;
  38. constructor init(ref:pref;pos:pfileposinfo);
  39. destructor done; virtual;
  40. function get_file_line : string;
  41. end;
  42. pbrowser=^tbrowser;
  43. tbrowser=object
  44. fname : string;
  45. logopen : boolean;
  46. stderrlog : boolean;
  47. f : file;
  48. elements_to_list : pstringqueue;
  49. buf : pchar;
  50. bufidx : longint;
  51. identidx : longint;
  52. constructor init;
  53. destructor done;
  54. procedure setfilename(const fn:string);
  55. procedure createlog;
  56. procedure flushlog;
  57. procedure addlog(const s:string);
  58. procedure addlogrefs(p:pref);
  59. procedure closelog;
  60. procedure ident;
  61. procedure unident;
  62. procedure browse_symbol(s : string);
  63. procedure list_elements;
  64. end;
  65. var
  66. browse : tbrowser;
  67. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  68. implementation
  69. uses
  70. comphook,globals,symtable,systems,verbose;
  71. {****************************************************************************
  72. TRef
  73. ****************************************************************************}
  74. constructor tref.init(ref :pref;pos : pfileposinfo);
  75. begin
  76. nextref:=nil;
  77. if assigned(pos) then
  78. posinfo:=pos^;
  79. if assigned(current_module) then
  80. moduleindex:=current_module^.unit_index;
  81. if assigned(ref) then
  82. ref^.nextref:=@self;
  83. is_written:=false;
  84. end;
  85. destructor tref.done;
  86. var
  87. inputfile : pinputfile;
  88. ref : pref;
  89. begin
  90. inputfile:=get_source_file(moduleindex,posinfo.fileindex);
  91. if inputfile<>nil then
  92. dec(inputfile^.ref_count);
  93. ref:=@self;
  94. if assigned(ref^.nextref) then
  95. dispose(ref^.nextref,done);
  96. nextref:=nil;
  97. end;
  98. function tref.get_file_line : string;
  99. var
  100. inputfile : pinputfile;
  101. begin
  102. get_file_line:='';
  103. inputfile:=get_source_file(moduleindex,posinfo.fileindex);
  104. if assigned(inputfile) then
  105. if status.use_gccoutput then
  106. get_file_line:=lower(inputfile^.name^)
  107. +':'+tostr(posinfo.line)+':'+tostr(posinfo.column)+':'
  108. else
  109. get_file_line:=inputfile^.name^
  110. +'('+tostr(posinfo.line)+','+tostr(posinfo.column)+')'
  111. else
  112. if status.use_gccoutput then
  113. get_file_line:='file_unknown:'
  114. +tostr(posinfo.line)+':'+tostr(posinfo.column)+':'
  115. else
  116. get_file_line:='file_unknown('
  117. +tostr(posinfo.line)+','+tostr(posinfo.column)+')'
  118. end;
  119. {****************************************************************************
  120. TBrowser
  121. ****************************************************************************}
  122. constructor tbrowser.init;
  123. begin
  124. fname:=FixFileName('browser.log');
  125. logopen:=false;
  126. elements_to_list:=new(pstringqueue,init);
  127. end;
  128. destructor tbrowser.done;
  129. begin
  130. if logopen then
  131. closelog;
  132. end;
  133. procedure tbrowser.setfilename(const fn:string);
  134. begin
  135. fname:=FixFileName(fn);
  136. end;
  137. procedure tbrowser.createlog;
  138. begin
  139. if logopen then
  140. closelog;
  141. assign(f,fname);
  142. {$I-}
  143. rewrite(f,1);
  144. {$I+}
  145. if ioresult<>0 then
  146. exit;
  147. logopen:=true;
  148. getmem(buf,logbufsize);
  149. bufidx:=0;
  150. identidx:=0;
  151. end;
  152. procedure tbrowser.flushlog;
  153. begin
  154. if logopen then
  155. if not stderrlog then
  156. blockwrite(f,buf^,bufidx)
  157. else
  158. begin
  159. buf[bufidx]:=#0;
  160. {$ifndef TP}
  161. write(stderr,buf);
  162. {$else TP}
  163. write(buf);
  164. {$endif TP}
  165. end;
  166. bufidx:=0;
  167. end;
  168. procedure tbrowser.closelog;
  169. begin
  170. if logopen then
  171. begin
  172. flushlog;
  173. close(f);
  174. freemem(buf,logbufsize);
  175. logopen:=false;
  176. end;
  177. end;
  178. procedure tbrowser.list_elements;
  179. begin
  180. stderrlog:=true;
  181. getmem(buf,logbufsize);
  182. logopen:=true;
  183. while not elements_to_list^.empty do
  184. browse_symbol(elements_to_list^.get);
  185. flushlog;
  186. logopen:=false;
  187. freemem(buf,logbufsize);
  188. stderrlog:=false;
  189. end;
  190. procedure tbrowser.addlog(const s:string);
  191. begin
  192. if not logopen then
  193. exit;
  194. { add ident }
  195. if identidx>0 then
  196. begin
  197. if bufidx+identidx>logbufsize then
  198. flushlog;
  199. fillchar(buf[bufidx],identidx,' ');
  200. inc(bufidx,identidx);
  201. end;
  202. { add text }
  203. if bufidx+length(s)>logbufsize-2 then
  204. flushlog;
  205. move(s[1],buf[bufidx],length(s));
  206. inc(bufidx,length(s));
  207. { add crlf }
  208. buf[bufidx]:=target_os.newline[1];
  209. inc(bufidx);
  210. if length(target_os.newline)=2 then
  211. begin
  212. buf[bufidx]:=target_os.newline[2];
  213. inc(bufidx);
  214. end;
  215. end;
  216. procedure tbrowser.addlogrefs(p:pref);
  217. var
  218. ref : pref;
  219. begin
  220. ref:=p;
  221. Ident;
  222. while assigned(ref) do
  223. begin
  224. Browse.AddLog(ref^.get_file_line);
  225. ref:=ref^.nextref;
  226. end;
  227. Unident;
  228. end;
  229. procedure tbrowser.browse_symbol(s : string);
  230. var
  231. sym,symb : psym;
  232. symt : psymtable;
  233. hp : pmodule;
  234. ss : string;
  235. p : byte;
  236. procedure next_substring;
  237. begin
  238. p:=pos('.',s);
  239. if p>0 then
  240. begin
  241. ss:=copy(s,1,p-1);
  242. s:=copy(s,p+1,255);
  243. end
  244. else
  245. begin
  246. ss:=s;
  247. s:='';
  248. end;
  249. end;
  250. begin
  251. symt:=symtablestack;
  252. next_substring;
  253. sym:=symt^.search(ss);
  254. if not assigned(sym) then
  255. begin
  256. symt:=nil;
  257. { try all loaded_units }
  258. hp:=pmodule(loaded_units.first);
  259. while assigned(hp) do
  260. begin
  261. if hp^.modulename^=ss then
  262. begin
  263. symt:=hp^.symtable;
  264. break;
  265. end;
  266. hp:=pmodule(hp^.next);
  267. end;
  268. if not assigned(symt) then
  269. begin
  270. addlog('!!!Symbol '+ss+' not found !!!');
  271. exit;
  272. end
  273. else
  274. begin
  275. next_substring;
  276. sym:=symt^.search(ss);
  277. end;
  278. end;
  279. if (sym^.typ=unitsym) and (s<>'') then
  280. begin
  281. symt:=punitsym(sym)^.unitsymtable;
  282. next_substring;
  283. sym:=symt^.search(ss);
  284. end;
  285. while assigned(sym) and (s<>'') do
  286. begin
  287. next_substring;
  288. case sym^.typ of
  289. typesym :
  290. begin
  291. if ptypesym(sym)^.definition^.deftype in [recorddef,objectdef] then
  292. begin
  293. if ptypesym(sym)^.definition^.deftype=recorddef then
  294. symt:=precdef(ptypesym(sym)^.definition)^.symtable
  295. else
  296. symt:=pobjectdef(ptypesym(sym)^.definition)^.publicsyms;
  297. sym:=symt^.search(ss);
  298. end;
  299. end;
  300. varsym :
  301. begin
  302. if pvarsym(sym)^.definition^.deftype in [recorddef,objectdef] then
  303. begin
  304. if pvarsym(sym)^.definition^.deftype=recorddef then
  305. symt:=precdef(pvarsym(sym)^.definition)^.symtable
  306. else
  307. symt:=pobjectdef(pvarsym(sym)^.definition)^.publicsyms;
  308. sym:=symt^.search(ss);
  309. end;
  310. end;
  311. procsym :
  312. begin
  313. symt:=pprocsym(sym)^.definition^.parast;
  314. symb:=symt^.search(ss);
  315. if not assigned(symb) then
  316. begin
  317. symt:=pprocsym(sym)^.definition^.parast;
  318. sym:=symt^.search(ss);
  319. end
  320. else
  321. sym:=symb;
  322. end;
  323. {else
  324. sym^.add_to_browserlog;}
  325. end;
  326. end;
  327. if assigned(sym) then
  328. sym^.add_to_browserlog
  329. else
  330. addlog('!!!Symbol '+ss+' not found !!!');
  331. end;
  332. procedure tbrowser.ident;
  333. begin
  334. inc(identidx,2);
  335. end;
  336. procedure tbrowser.unident;
  337. begin
  338. dec(identidx,2);
  339. end;
  340. {****************************************************************************
  341. Helpers
  342. ****************************************************************************}
  343. function get_source_file(moduleindex,fileindex : word) : pinputfile;
  344. var
  345. hp : pmodule;
  346. f : pinputfile;
  347. begin
  348. hp:=pmodule(loaded_units.first);
  349. while assigned(hp) and (hp^.unit_index<>moduleindex) do
  350. hp:=pmodule(hp^.next);
  351. get_source_file:=nil;
  352. if not assigned(hp) then
  353. exit;
  354. f:=pinputfile(hp^.sourcefiles.files);
  355. while assigned(f) do
  356. begin
  357. if f^.ref_index=fileindex then
  358. begin
  359. get_source_file:=f;
  360. exit;
  361. end;
  362. f:=pinputfile(f^.ref_next);
  363. end;
  364. end;
  365. begin
  366. browse.init
  367. end.
  368. {
  369. $Log$
  370. Revision 1.7 1998-09-21 08:45:05 pierre
  371. + added vmt_offset in tobjectdef.write for fututre use
  372. (first steps to have objects without vmt if no virtual !!)
  373. + added fpu_used field for tabstractprocdef :
  374. sets this level to 2 if the functions return with value in FPU
  375. (is then set to correct value at parsing of implementation)
  376. THIS MIGHT refuse some code with FPU expression too complex
  377. that were accepted before and even in some cases
  378. that don't overflow in fact
  379. ( like if f : float; is a forward that finally in implementation
  380. only uses one fpu register !!)
  381. Nevertheless I think that it will improve security on
  382. FPU operations !!
  383. * most other changes only for UseBrowser code
  384. (added symtable references for record and objects)
  385. local switch for refs to args and local of each function
  386. (static symtable still missing)
  387. UseBrowser still not stable and probably broken by
  388. the definition hash array !!
  389. Revision 1.6 1998/09/01 07:54:16 pierre
  390. * UseBrowser a little updated (might still be buggy !!)
  391. * bug in psub.pas in function specifier removed
  392. * stdcall allowed in interface and in implementation
  393. (FPC will not yet complain if it is missing in either part
  394. because stdcall is only a dummy !!)
  395. Revision 1.5 1998/06/13 00:10:04 peter
  396. * working browser and newppu
  397. * some small fixes against crashes which occured in bp7 (but not in
  398. fpc?!)
  399. Revision 1.4 1998/06/11 10:11:57 peter
  400. * -gb works again
  401. Revision 1.3 1998/05/20 09:42:32 pierre
  402. + UseTokenInfo now default
  403. * unit in interface uses and implementation uses gives error now
  404. * only one error for unknown symbol (uses lastsymknown boolean)
  405. the problem came from the label code !
  406. + first inlined procedures and function work
  407. (warning there might be allowed cases were the result is still wrong !!)
  408. * UseBrower updated gives a global list of all position of all used symbols
  409. with switch -gb
  410. Revision 1.2 1998/04/30 15:59:39 pierre
  411. * GDB works again better :
  412. correct type info in one pass
  413. + UseTokenInfo for better source position
  414. * fixed one remaining bug in scanner for line counts
  415. * several little fixes
  416. }