FoxSections.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488
  1. MODULE FoxSections; (** AUTHOR "fof"; PURPOSE "support for code sections and references"; *)
  2. IMPORT SyntaxTree := FoxSyntaxTree,Streams,Global := FoxGlobal,Formats := FoxFormats, Basic := FoxBasic, Strings, ObjectFile;
  3. CONST
  4. (* section categories *)
  5. EntryCodeSection*=ObjectFile.EntryCode;
  6. ExitCodeSection*=ObjectFile.ExitCode;
  7. InitCodeSection*=ObjectFile.InitCode;
  8. BodyCodeSection*=ObjectFile.BodyCode;
  9. CodeSection*=ObjectFile.Code;
  10. VarSection*=ObjectFile.Data;
  11. ConstSection*=ObjectFile.Const;
  12. InlineCodeSection*=10;
  13. UnknownSectionType*= 11;
  14. LineCommentStart*="; ";
  15. (* gensam *)
  16. UnknownSize* = -1;
  17. UndefinedFinalPosition* = -1;
  18. TYPE
  19. Identifier*=ObjectFile.Identifier;
  20. SectionName*= ObjectFile.SegmentedName;
  21. Section*=OBJECT
  22. VAR
  23. name-: SectionName; (* name of this section (globally unique-name derived from symbol name) *)
  24. type-: SHORTINT; (* CodeSection, InlineCodeSection, ... *)
  25. fixed-: BOOLEAN; (* whether the position of the section is fixed, as opposed to being restricted by an alignment *)
  26. positionOrAlignment-: LONGINT; (* the alignment OR the position *)
  27. fingerprint-: Basic.Fingerprint; (* fingerprint of the corresponding syntax tree node *)
  28. bitsPerUnit-: LONGINT; (* the unit size given in bits *)
  29. symbol-: SyntaxTree.Symbol; (* corresponding symbol in AST *)
  30. offset-: LONGINT;
  31. (* for linking *)
  32. isReachable-: BOOLEAN;
  33. PROCEDURE & InitSection*(type: SHORTINT; CONST n: ObjectFile.SegmentedName; symbol: SyntaxTree.Symbol);
  34. BEGIN
  35. name := n;
  36. SELF.symbol := symbol;
  37. SELF.type := type;
  38. offset := 0;
  39. fixed := FALSE;
  40. positionOrAlignment := 1;
  41. fingerprint := 0;
  42. bitsPerUnit := UnknownSize;
  43. END InitSection;
  44. PROCEDURE IsCode*(): BOOLEAN;
  45. BEGIN
  46. RETURN type IN {EntryCodeSection .. CodeSection};
  47. END IsCode;
  48. PROCEDURE SetOffset*(offset: LONGINT);
  49. BEGIN SELF.offset := offset;
  50. END SetOffset;
  51. PROCEDURE SetReachability*(isReachable: BOOLEAN);
  52. BEGIN SELF.isReachable := isReachable
  53. END SetReachability;
  54. PROCEDURE SetBitsPerUnit*(bitsPerUnit: LONGINT);
  55. BEGIN SELF.bitsPerUnit := bitsPerUnit
  56. END SetBitsPerUnit;
  57. PROCEDURE IsAligned*(): BOOLEAN;
  58. BEGIN RETURN ~fixed & (positionOrAlignment > 1)
  59. END IsAligned;
  60. PROCEDURE SetPositionOrAlignment*(isFixed: BOOLEAN; positionOrAlignment: LONGINT);
  61. BEGIN
  62. SELF.fixed := isFixed;
  63. SELF.positionOrAlignment := positionOrAlignment
  64. END SetPositionOrAlignment;
  65. PROCEDURE GetSize*(): LONGINT;
  66. BEGIN RETURN UnknownSize
  67. END GetSize;
  68. PROCEDURE SetFingerprint*(fingerprint: Basic.Fingerprint);
  69. BEGIN SELF.fingerprint := fingerprint
  70. END SetFingerprint;
  71. (** change the type of a section **)
  72. PROCEDURE SetType*(type: SHORTINT);
  73. BEGIN SELF.type := type
  74. END SetType;
  75. PROCEDURE Dump*(w: Streams.Writer);
  76. BEGIN
  77. w.String(".");
  78. CASE type OF
  79. | EntryCodeSection: w.String("entrycode")
  80. | ExitCodeSection: w.String("exitcode")
  81. | CodeSection: w.String("code")
  82. | BodyCodeSection: w.String("bodycode")
  83. | InlineCodeSection: w.String("inlinecode")
  84. | VarSection: w.String("var");
  85. | ConstSection: w.String("const");
  86. | InitCodeSection: w.String("initcode");
  87. ELSE
  88. w.String("UNDEFINED")
  89. END;
  90. w.String(" ");
  91. DumpName(w);
  92. (* positional restrictions *)
  93. IF fixed THEN
  94. w.String(" fixed="); w.Int(positionOrAlignment, 0)
  95. ELSIF positionOrAlignment > 1 THEN
  96. w.String(" aligned="); w.Int(positionOrAlignment, 0)
  97. END;
  98. IF fingerprint # 0 THEN w.String(" fingerprint="); w.Hex(fingerprint, 0) END;
  99. IF bitsPerUnit # UnknownSize THEN w.String(" unit="); w.Int(bitsPerUnit, 0) END;
  100. (* note: this information is actually redundant *)
  101. IF GetSize() # UnknownSize THEN w.String(" size="); w.Int(GetSize(), 0) END;
  102. w.Update
  103. END Dump;
  104. PROCEDURE WriteRaw*(w: Streams.Writer);
  105. BEGIN
  106. w.RawInt(type);
  107. Basic.WriteSegmentedName(w,name);
  108. w.RawBool(fixed);
  109. w.RawLInt(positionOrAlignment);
  110. w.RawHInt(fingerprint);
  111. w.RawLInt(bitsPerUnit);
  112. END WriteRaw;
  113. PROCEDURE DumpName*(w: Streams.Writer);
  114. BEGIN
  115. Basic.WriteSegmentedName(w,name);
  116. END DumpName;
  117. END Section;
  118. CommentStr* = POINTER TO ARRAY OF CHAR;
  119. Comment* = OBJECT
  120. VAR str-: CommentStr; strLen: LONGINT; pos-: LONGINT; nextComment-: Comment;
  121. PROCEDURE &Init*(pos: LONGINT);
  122. BEGIN
  123. SELF.pos := pos;
  124. NEW(str,32); strLen := 0;
  125. str[0] := 0X;
  126. END Init;
  127. PROCEDURE Append(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT);
  128. PROCEDURE Resize(newLen: LONGINT);
  129. VAR new: CommentStr; i: LONGINT;
  130. BEGIN
  131. NEW(new,newLen);
  132. FOR i := 0 TO strLen-1 DO
  133. new[i] := str[i]
  134. END;
  135. str := new
  136. END Resize;
  137. BEGIN
  138. INC(len,ofs);
  139. ASSERT(LEN(buf) >= len);
  140. WHILE (ofs < len) & (buf[ofs] # 0X) DO
  141. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  142. str[strLen] := buf[ofs];
  143. INC(ofs); INC(strLen);
  144. END;
  145. IF LEN(str) <= strLen THEN Resize(2*strLen) END;
  146. str[strLen] := 0X;
  147. END Append;
  148. PROCEDURE Dump*(w: Streams.Writer);
  149. VAR i: LONGINT;ch: CHAR; newln: BOOLEAN;
  150. BEGIN
  151. IF w IS Basic.Writer THEN w(Basic.Writer).BeginComment; w(Basic.Writer).IncIndent; END;
  152. w.String("; ");
  153. i := 0; ch := str[i]; newln := FALSE;
  154. WHILE(ch#0X) DO
  155. IF (ch = 0DX) OR (ch = 0AX) THEN newln := TRUE
  156. ELSE
  157. IF newln THEN w.Ln; w.String(LineCommentStart); newln := FALSE; END;
  158. w.Char(ch);
  159. END;
  160. INC(i); ch := str[i];
  161. END;
  162. IF w IS Basic.Writer THEN w(Basic.Writer).EndComment; w(Basic.Writer).DecIndent;END;
  163. (*w.Update;*)
  164. END Dump;
  165. END Comment;
  166. GetPCProcedure=PROCEDURE{DELEGATE}(): LONGINT;
  167. CommentWriter*= OBJECT (Streams.Writer)
  168. VAR
  169. firstComment-,lastComment-: Comment; comments-: LONGINT;
  170. getPC: GetPCProcedure;
  171. PROCEDURE AppendToLine*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: WORD );
  172. VAR pos: LONGINT;
  173. BEGIN
  174. IF len = 0 THEN RETURN END;
  175. pos := getPC();
  176. IF lastComment = NIL THEN
  177. NEW(lastComment,pos); firstComment := lastComment;
  178. ELSIF (lastComment.pos # pos) THEN
  179. NEW(lastComment.nextComment,pos);
  180. lastComment := lastComment.nextComment;
  181. END;
  182. lastComment.Append(buf,ofs,len)
  183. END AppendToLine;
  184. PROCEDURE Ln*;
  185. BEGIN
  186. Ln^;
  187. (*Update;*)
  188. END Ln;
  189. PROCEDURE Reset*;
  190. BEGIN
  191. firstComment := NIL; lastComment := NIL; comments := 0;
  192. Reset^;
  193. END Reset;
  194. PROCEDURE & InitCommentWriter*(getPC: GetPCProcedure);
  195. BEGIN
  196. SELF.getPC := getPC;
  197. InitWriter(AppendToLine,256);
  198. firstComment := NIL; lastComment := NIL; comments := 0;
  199. END InitCommentWriter;
  200. END CommentWriter;
  201. SectionLookup = OBJECT(Basic.HashTable); (* SyntaxTree.Symbol _> Symbol *)
  202. VAR
  203. PROCEDURE GetSection(symbol: SyntaxTree.Symbol):Section;
  204. VAR p: ANY;
  205. BEGIN
  206. p := Get(symbol);
  207. IF p # NIL THEN
  208. ASSERT(p(Section).symbol = symbol);
  209. RETURN p(Section);
  210. ELSE
  211. RETURN NIL
  212. END;
  213. END GetSection;
  214. PROCEDURE PutSection(symbol: SyntaxTree.Symbol; section: Section);
  215. BEGIN
  216. Put(symbol,section);
  217. END PutSection;
  218. END SectionLookup;
  219. SectionNameLookup = OBJECT(Basic.HashTableSegmentedName); (* SyntaxTree.Symbol _> Symbol *)
  220. PROCEDURE GetSection(CONST name: Basic.SegmentedName):Section;
  221. VAR p: ANY;
  222. BEGIN
  223. p := Get(name);
  224. IF p # NIL THEN RETURN p(Section) ELSE RETURN NIL END;
  225. END GetSection;
  226. PROCEDURE PutSection(CONST name:Basic.SegmentedName; section: Section);
  227. BEGIN
  228. Put(name, section);
  229. END PutSection;
  230. END SectionNameLookup;
  231. (** a list of sections
  232. note: a section may be part of multiple lists in this implementation
  233. **)
  234. SectionList* = OBJECT(Basic.List)
  235. VAR
  236. lookup: SectionLookup;
  237. lookupName: SectionNameLookup;
  238. PROCEDURE & InitListOfSections*;
  239. BEGIN
  240. NEW(lookup, 128);
  241. NEW(lookupName, 128);
  242. InitList(128) (* initializer of general list *)
  243. END InitListOfSections;
  244. PROCEDURE GetSection*(index: LONGINT): Section;
  245. VAR
  246. any: ANY;
  247. BEGIN
  248. any := Get(index);
  249. RETURN any(Section)
  250. END GetSection;
  251. PROCEDURE SetSection*(index: LONGINT; section: Section);
  252. BEGIN
  253. Set(index, section)
  254. END SetSection;
  255. (* note: this procedure cannot be called "Add" as it was the case in the old section list implementation *)
  256. PROCEDURE AddSection*(section: Section);
  257. BEGIN
  258. (* assert that the section is not already present *)
  259. ASSERT((FindBySymbol(section.symbol) = NIL) & (FindByName(section.name) = NIL));
  260. IF section.symbol # NIL THEN (* special case, may not be added to lookup list *)
  261. lookup.PutSection(section.symbol, section)
  262. END;
  263. IF section.name[0] >= 0 THEN
  264. lookupName.PutSection(section.name, section);
  265. END;
  266. Add(section)
  267. END AddSection;
  268. (** finds a section with a certain AST symbol **)
  269. PROCEDURE FindBySymbol*(CONST symbol: SyntaxTree.Symbol): Section;
  270. BEGIN
  271. IF symbol = NIL THEN
  272. RETURN NIL
  273. ELSE
  274. RETURN lookup.GetSection(symbol)
  275. END
  276. END FindBySymbol;
  277. (** finds a section with a certain name **)
  278. PROCEDURE FindByName*(CONST name: Basic.SegmentedName): Section;
  279. BEGIN
  280. RETURN lookupName.GetSection(name)
  281. END FindByName;
  282. PROCEDURE Dump*(w: Streams.Writer);
  283. VAR
  284. i: LONGINT;
  285. section: Section;
  286. BEGIN
  287. FOR i := 0 TO Length() - 1 DO
  288. section := GetSection(i);
  289. section.Dump(w); w.Ln
  290. END;
  291. END Dump;
  292. PROCEDURE WriteRaw*(w: Streams.Writer);
  293. VAR
  294. i: LONGINT;
  295. section: Section;
  296. BEGIN
  297. FOR i := 0 TO Length() - 1 DO
  298. section := GetSection(i);
  299. section.WriteRaw(w);
  300. END;
  301. END WriteRaw;
  302. END SectionList;
  303. NameEntry = POINTER TO RECORD
  304. name: SyntaxTree.IdentifierString;
  305. END;
  306. (* TODO: efficient implementation using hash table *)
  307. NameList* = OBJECT(Basic.List)
  308. PROCEDURE AddName*(CONST moduleName: ARRAY OF CHAR);
  309. VAR entry: NameEntry;
  310. BEGIN
  311. NEW(entry);
  312. COPY(moduleName, entry.name);
  313. Add(entry)
  314. END AddName;
  315. PROCEDURE GetName*(index: LONGINT): SyntaxTree.IdentifierString;
  316. VAR any: ANY;
  317. BEGIN
  318. any := Get(index);
  319. ASSERT(any IS NameEntry);
  320. RETURN any(NameEntry).name
  321. END GetName;
  322. PROCEDURE ContainsName*(name: SyntaxTree.IdentifierString): BOOLEAN;
  323. VAR i: LONGINT;
  324. BEGIN
  325. FOR i := 0 TO Length() - 1 DO
  326. IF name = GetName(i) THEN RETURN TRUE END
  327. END;
  328. RETURN FALSE
  329. END ContainsName;
  330. END NameList;
  331. (** output of (intermediate) code generation **)
  332. Module* = OBJECT (Formats.GeneratedModule)
  333. VAR
  334. allSections-: SectionList;
  335. importedSections-: SectionList; (* necessary for binary object file format, for reference to symbol *)
  336. platformName-: SyntaxTree.IdentifierString;
  337. imports-: NameList;
  338. PROCEDURE & Init*(module: SyntaxTree.Module; system: Global.System);
  339. BEGIN
  340. Init^(module,system);
  341. NEW(allSections);
  342. NEW(importedSections);
  343. NEW(imports, 128);
  344. END Init;
  345. (*
  346. PROCEDURE SetSections*(sections: SectionList);
  347. BEGIN SELF.allSections := sections
  348. END SetSections;
  349. *)
  350. PROCEDURE SetImports*(imports: NameList);
  351. BEGIN SELF.imports := imports
  352. END SetImports;
  353. PROCEDURE SetPlatformName*(CONST platformName: ARRAY OF CHAR);
  354. BEGIN COPY(platformName, SELF.platformName)
  355. END SetPlatformName;
  356. PROCEDURE Dump*(w: Streams.Writer);
  357. VAR
  358. dump: Basic.Writer;
  359. name: SyntaxTree.IdentifierString;
  360. i: LONGINT;
  361. BEGIN
  362. dump := Basic.GetWriter(w);
  363. (* dump module directive *)
  364. dump.String(".module ");
  365. dump.String(moduleName); dump.Ln;
  366. dump.Ln;
  367. (* dump platform directive *)
  368. IF platformName # "" THEN
  369. dump.String(".platform ");
  370. dump.String(platformName); dump.Ln;
  371. dump.Ln
  372. END;
  373. (* dump imports directive *)
  374. IF imports.Length() > 0 THEN
  375. dump.String(".imports ");
  376. FOR i := 0 TO imports.Length() - 1 DO
  377. IF i # 0 THEN dump.String(", ") END;
  378. name := imports.GetName(i);
  379. IF name = "" THEN
  380. dump.String("<import failed>")
  381. ELSE
  382. dump.String(name)
  383. END
  384. END;
  385. dump.Ln; dump.Ln
  386. END;
  387. (* dump all sections *)
  388. allSections.Dump(w)
  389. END Dump;
  390. END Module;
  391. PROCEDURE DumpFiltered*(w: Streams.Writer; module: Module; CONST filter: ARRAY OF CHAR);
  392. VAR
  393. i: LONGINT;
  394. section: Section;
  395. name: ObjectFile.SectionName;
  396. BEGIN
  397. FOR i := 0 TO module.allSections.Length() - 1 DO
  398. section := module.allSections.GetSection(i);
  399. ObjectFile.SegmentedNameToString(section.name,name);
  400. IF Strings.Match(filter, name) THEN section.Dump(w); w.Ln; END
  401. END
  402. END DumpFiltered;
  403. PROCEDURE NewCommentWriter*(getPC: GetPCProcedure): CommentWriter;
  404. VAR c: CommentWriter;
  405. BEGIN
  406. NEW(c,getPC); RETURN c
  407. END NewCommentWriter;
  408. END FoxSections.