FoxIntermediateParser.Mod 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630
  1. MODULE FoxIntermediateParser;
  2. IMPORT
  3. Strings, Diagnostics, D := Debugging, SyntaxTree := FoxSyntaxTree, Scanner := FoxScanner, Sections := FoxSections,
  4. IntermediateCode := FoxIntermediateCode, Basic := FoxBasic, Streams, Files, Global := FoxGlobal;
  5. CONST
  6. IntermediateCodeExtension = "Fil"; (* TODO: move to a better place *)
  7. Trace=FALSE;
  8. TYPE
  9. MessageString= ARRAY 256 OF CHAR;
  10. (** the intermediate code parser **)
  11. IntermediateCodeParser* = OBJECT
  12. CONST
  13. Trace = FALSE;
  14. Strict = TRUE;
  15. VAR
  16. diagnostics: Diagnostics.Diagnostics;
  17. error: BOOLEAN;
  18. symbol: Scanner.Symbol;
  19. scanner: Scanner.AssemblerScanner;
  20. system: Global.System;
  21. PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics; s: Global.System);
  22. BEGIN
  23. ASSERT(s # NIL); (* a default system object is required in case there is no platform directive *)
  24. SELF.diagnostics := diagnostics;
  25. system := s;
  26. error := FALSE
  27. END Init;
  28. PROCEDURE Error(pos: LONGINT; CONST msg: ARRAY OF CHAR);
  29. BEGIN
  30. error := TRUE;
  31. IF diagnostics # NIL THEN
  32. diagnostics.Error(scanner.source^,pos,Diagnostics.Invalid,msg);
  33. END;
  34. D.Update;
  35. IF Trace THEN D.TraceBack END
  36. END Error;
  37. PROCEDURE NextSymbol;
  38. BEGIN error := error OR ~scanner.GetNextSymbol(symbol)
  39. END NextSymbol;
  40. PROCEDURE ThisToken(x: LONGINT): BOOLEAN;
  41. BEGIN
  42. IF ~error & (symbol.token = x) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
  43. END ThisToken;
  44. PROCEDURE GetIdentifier(VAR pos: LONGINT; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  45. BEGIN
  46. pos := symbol.start;
  47. IF symbol.token # Scanner.Identifier THEN RETURN FALSE
  48. ELSE COPY(symbol.identifierString,identifier); NextSymbol; RETURN TRUE
  49. END;
  50. END GetIdentifier;
  51. PROCEDURE ExpectToken(x: LONGINT): BOOLEAN;
  52. VAR
  53. s: MessageString;
  54. BEGIN
  55. IF ThisToken(x) THEN RETURN TRUE
  56. ELSE
  57. s := "expected token "; Strings.Append(s,Scanner.tokens[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.tokens[symbol.token]);
  58. Error(symbol.start, s);RETURN FALSE
  59. END;
  60. END ExpectToken;
  61. PROCEDURE ThisIdentifier(CONST this: ARRAY OF CHAR): BOOLEAN;
  62. BEGIN
  63. IF ~error & (symbol.token = Scanner.Identifier) & (this = symbol.identifierString) THEN NextSymbol; RETURN TRUE ELSE RETURN FALSE END;
  64. END ThisIdentifier;
  65. PROCEDURE ExpectAnyIdentifier(VAR pos: LONGINT; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  66. BEGIN
  67. IF ~GetIdentifier(pos,identifier)THEN Error(pos,"identifier expected"); RETURN FALSE
  68. ELSE RETURN TRUE
  69. END;
  70. END ExpectAnyIdentifier;
  71. PROCEDURE ExpectIntegerWithSign(VAR integer: LONGINT): BOOLEAN;
  72. VAR
  73. result, isNegated: BOOLEAN;
  74. BEGIN
  75. isNegated := ThisToken(Scanner.Minus);
  76. IF ExpectToken(Scanner.Number) & (symbol.numberType = Scanner.Integer) THEN
  77. IF isNegated THEN
  78. integer := -symbol.integer
  79. ELSE
  80. integer := symbol.integer
  81. END;
  82. result := TRUE
  83. ELSE
  84. result := FALSE
  85. END;
  86. RETURN result
  87. END ExpectIntegerWithSign;
  88. PROCEDURE ExpectIntegerWithoutSign(VAR integer: LONGINT): BOOLEAN;
  89. VAR
  90. result: BOOLEAN;
  91. BEGIN
  92. IF ExpectToken(Scanner.Number) & (symbol.numberType = Scanner.Integer) THEN
  93. integer := symbol.integer;
  94. result := TRUE
  95. ELSE
  96. result := FALSE
  97. END;
  98. RETURN result
  99. END ExpectIntegerWithoutSign;
  100. PROCEDURE IgnoreNewLines;
  101. BEGIN
  102. WHILE ThisToken(Scanner.Ln) DO END;
  103. END IgnoreNewLines;
  104. (* expect the newline or end-of-text symbol *)
  105. PROCEDURE ExpectLineDelimiter(): BOOLEAN;
  106. BEGIN
  107. IF ~error & ((symbol.token = Scanner.Ln) OR (symbol.token = Scanner.EndOfText)) THEN
  108. NextSymbol;
  109. RETURN TRUE
  110. ELSE
  111. Error(symbol.start, "end of line/text expected");
  112. RETURN FALSE
  113. END;
  114. END ExpectLineDelimiter;
  115. (** parse an optional line number **)
  116. PROCEDURE ParseLineNumber(expectedLineNumber: LONGINT);
  117. VAR
  118. positionOfLine, specifiedLineNumber: LONGINT;
  119. message, tempString: MessageString;
  120. BEGIN
  121. IF Trace THEN D.String(">>> ParseLineNumber"); D.Ln END;
  122. positionOfLine := symbol.start;
  123. IF ThisToken(Scanner.Number) THEN (* note: line numbers are optional *)
  124. specifiedLineNumber := symbol.integer;
  125. IF ExpectToken(Scanner.Colon) THEN
  126. IF Strict & (specifiedLineNumber # expectedLineNumber) THEN
  127. message := "invalid code line number (";
  128. Strings.IntToStr(specifiedLineNumber, tempString); Strings.Append(message, tempString);
  129. Strings.Append(message, " instead of ");
  130. Strings.IntToStr(expectedLineNumber, tempString); Strings.Append(message, tempString);
  131. Strings.Append(message, ")");
  132. Error(positionOfLine, message)
  133. END
  134. END
  135. END
  136. END ParseLineNumber;
  137. (** parse an intermediate code operand **)
  138. PROCEDURE ParseOperand(VAR operand: IntermediateCode.Operand; sectionList: Sections.SectionList);
  139. VAR
  140. positionOfOperand, pos, registerNumber, symbolOffset, someLongint, integer: LONGINT;
  141. someHugeint: HUGEINT;
  142. hasTypeDescriptor, isMemoryOperand, lastWasIdentifier, isNegated: BOOLEAN;
  143. someLongreal: LONGREAL;
  144. identifier: SyntaxTree.IdentifierString;
  145. type: IntermediateCode.Type;
  146. sectionOfSymbol: Sections.Section;
  147. name: Basic.SegmentedName;
  148. registerClass: IntermediateCode.RegisterClass;
  149. BEGIN
  150. IF Trace THEN D.String(">>> ParseOperand"); D.Ln END;
  151. positionOfOperand := symbol.start;
  152. (* defaults *)
  153. hasTypeDescriptor := FALSE;
  154. isMemoryOperand := FALSE;
  155. (* consume optional type description *)
  156. lastWasIdentifier := GetIdentifier(pos, identifier);
  157. IF lastWasIdentifier & IntermediateCode.DenotesType(identifier, type) THEN
  158. hasTypeDescriptor := TRUE;
  159. lastWasIdentifier := GetIdentifier(pos, identifier)
  160. END;
  161. (* consume optional memory operand bracket *)
  162. IF ~lastWasIdentifier THEN
  163. isMemoryOperand := ThisToken(Scanner.LeftBracket);
  164. lastWasIdentifier := GetIdentifier(pos, identifier)
  165. END;
  166. IF lastWasIdentifier THEN
  167. IF IntermediateCode.DenotesRegister(identifier, registerClass, registerNumber) THEN
  168. (* register *)
  169. IntermediateCode.InitRegister(operand, type, registerClass, registerNumber);
  170. ELSE
  171. (* TODO: handle assembly constants *)
  172. (* symbol name *)
  173. symbolOffset := 0;
  174. (* consume optional symbol offset *)
  175. IF ThisToken(Scanner.Colon) THEN
  176. IF ExpectIntegerWithSign(integer) THEN
  177. symbolOffset := integer
  178. ELSE
  179. Error(symbol.start, "invalid symbol offset")
  180. END
  181. END;
  182. IF Trace THEN D.String(">>> symbol detected"); D.Ln END;
  183. Basic.ToSegmentedName(identifier, name);
  184. IntermediateCode.InitAddress(operand, IntermediateCode.UnsignedIntegerType(system.addressSize), name, 0, symbolOffset)
  185. END
  186. ELSIF symbol.token = Scanner.String THEN
  187. (* string constant *)
  188. IntermediateCode.InitString(operand, symbol.string);
  189. NextSymbol
  190. ELSE
  191. (* immediate values/numbers *)
  192. isNegated := ThisToken(Scanner.Minus);
  193. IF ThisToken(Scanner.Number) THEN
  194. CASE symbol.numberType OF
  195. | Scanner.Integer:
  196. IF isNegated THEN someLongint := -symbol.integer ELSE someLongint := symbol.integer END;
  197. IF ~hasTypeDescriptor THEN
  198. (* if no type description was included: use number type *)
  199. IntermediateCode.InitNumber(operand, someLongint);
  200. ELSIF type.form = IntermediateCode.Float THEN
  201. ASSERT(hasTypeDescriptor);
  202. IntermediateCode.InitFloatImmediate(operand, type, REAL(someLongint))
  203. ELSE
  204. ASSERT(hasTypeDescriptor & (type.form IN IntermediateCode.Integer));
  205. IntermediateCode.InitImmediate(operand, type, someLongint)
  206. END
  207. | Scanner.Hugeint:
  208. IF isNegated THEN someHugeint := - symbol.hugeint ELSE someHugeint := symbol.hugeint END;
  209. IF ~hasTypeDescriptor THEN
  210. (* if no type description was included: use number type *)
  211. IntermediateCode.InitNumber(operand, someHugeint)
  212. ELSIF type.form = IntermediateCode.Float THEN
  213. ASSERT(hasTypeDescriptor);
  214. IntermediateCode.InitFloatImmediate(operand, type, REAL(someHugeint))
  215. ELSE
  216. ASSERT(hasTypeDescriptor & (type.form IN IntermediateCode.Integer));
  217. IntermediateCode.InitImmediate(operand, type, someHugeint)
  218. END
  219. | Scanner.Real, Scanner.Longreal:
  220. IF isNegated THEN someLongreal := -symbol.real ELSE someLongreal := symbol.real END;
  221. (* if no type description was included: use float type with same amount of bits as address type *)
  222. IF ~hasTypeDescriptor THEN
  223. IntermediateCode.InitType(type, IntermediateCode.Float, INTEGER(system.addressSize))
  224. END;
  225. IF type.form IN IntermediateCode.Integer THEN
  226. Error(positionOfOperand, "floating point immediate value not applicable")
  227. ELSE
  228. IntermediateCode.InitFloatImmediate(operand, type, someLongreal)
  229. END
  230. ELSE HALT(100)
  231. END
  232. ELSE
  233. Error(positionOfOperand, "invalid operand")
  234. END
  235. END;
  236. (* consume optional offset given in system units *)
  237. IF ThisToken(Scanner.Plus) THEN
  238. IF ExpectIntegerWithoutSign(integer) THEN
  239. IntermediateCode.SetOffset(operand, integer)
  240. ELSE
  241. Error(symbol.start, "invalid offset")
  242. END
  243. ELSIF ThisToken(Scanner.Minus) THEN
  244. IF ExpectIntegerWithoutSign(integer) THEN
  245. IntermediateCode.SetOffset(operand, -integer)
  246. ELSE
  247. Error(symbol.start, "invalid offset")
  248. END
  249. END;
  250. (* wrap memory operand around current operand if necessary *)
  251. IF isMemoryOperand & ExpectToken(Scanner.RightBracket) THEN
  252. IntermediateCode.SetType(operand, IntermediateCode.UnsignedIntegerType(system.addressSize)); (* set the type of the inner operand to the platform's address type *)
  253. IF ~hasTypeDescriptor THEN
  254. IntermediateCode.InitType(type, IntermediateCode.SignedInteger, INTEGER(system.addressSize)) (* default: signed integer type of address size *)
  255. END;
  256. IntermediateCode.InitMemory(operand, type, operand, 0) (* TODO: add offset? *)
  257. END
  258. END ParseOperand;
  259. (** parse an intermediate code instruction **)
  260. PROCEDURE ParseInstruction(VAR instruction: IntermediateCode.Instruction; sectionList: Sections.SectionList);
  261. VAR
  262. opCode: SHORTINT;
  263. positionOfInstruction, positionOfOperand, operandNumber: LONGINT;
  264. operand: IntermediateCode.Operand;
  265. operands: ARRAY 3 OF IntermediateCode.Operand;
  266. operandType: IntermediateCode.Type;
  267. identifier, message, tempString: SyntaxTree.IdentifierString;
  268. BEGIN
  269. IF Trace THEN D.String(">>> ParseInstruction"); D.Ln END;
  270. positionOfInstruction := symbol.start;
  271. IF ExpectAnyIdentifier(positionOfInstruction, identifier) THEN
  272. (* TODO: detect labels of the form << labelName: >> *)
  273. opCode := IntermediateCode.FindMnemonic(identifier);
  274. IF opCode = IntermediateCode.None THEN
  275. Error(positionOfInstruction, "unknown mnemonic")
  276. ELSE
  277. (* consume all operands *)
  278. IntermediateCode.InitType(operandType, IntermediateCode.SignedInteger, 32); (* defaults *)
  279. IntermediateCode.InitOperand(operands[0]);
  280. IntermediateCode.InitOperand(operands[1]);
  281. IntermediateCode.InitOperand(operands[2]);
  282. operandNumber := 0;
  283. IF ~ThisToken(Scanner.Ln) & ~ThisToken(Scanner.EndOfText) THEN
  284. REPEAT
  285. positionOfOperand := symbol.start;
  286. IF operandNumber > 2 THEN
  287. Error(positionOfInstruction, "instruction has too many operands")
  288. ELSE
  289. ParseOperand(operand, sectionList);
  290. IF ~error THEN
  291. IF Strict & ~IntermediateCode.CheckOperand(operand, opCode, operandNumber, message) THEN
  292. Strings.Append(message, " @ operand ");
  293. Strings.IntToStr(operandNumber + 1, tempString); Strings.Append(message, tempString);
  294. Error(positionOfOperand, message)
  295. END;
  296. operands[operandNumber] := operand;
  297. INC(operandNumber)
  298. END
  299. END
  300. UNTIL error OR ~ThisToken(Scanner.Comma);
  301. IF ~error & ExpectLineDelimiter() THEN END
  302. END;
  303. IF ~error THEN
  304. IntermediateCode.InitInstruction(instruction, positionOfInstruction, opCode, operands[0], operands[1], operands[2]);
  305. IF Strict & ~IntermediateCode.CheckInstruction(instruction, message) THEN
  306. Error(positionOfInstruction, message)
  307. END
  308. END
  309. END;
  310. END
  311. END ParseInstruction;
  312. (** parse the content of an intermediate code section
  313. note: 'sectionList' is the list where referenced sections are found/to be created
  314. **)
  315. PROCEDURE ParseSectionContent*(scanner: Scanner.AssemblerScanner; section: IntermediateCode.Section; sectionList: Sections.SectionList);
  316. VAR
  317. instruction: IntermediateCode.Instruction;
  318. lineNumber: LONGINT;
  319. BEGIN
  320. IF Trace THEN D.Ln; D.String(">>> ParseSectionContent"); D.Ln END;
  321. SELF.scanner := scanner;
  322. IgnoreNewLines;
  323. lineNumber := 0;
  324. WHILE ~error & (symbol.token # Scanner.Period) & (symbol.token # Scanner.EndOfText) DO
  325. (* consume optional line number *)
  326. ParseLineNumber(lineNumber);
  327. IF ~error THEN
  328. ParseInstruction(instruction, sectionList);
  329. IF ~error THEN
  330. IF Trace THEN IntermediateCode.DumpInstruction(D.Log, instruction); D.Ln; END;
  331. section.Emit(instruction);
  332. INC(lineNumber)
  333. END;
  334. END;
  335. IgnoreNewLines
  336. END
  337. END ParseSectionContent;
  338. (** parse a list of section properties **)
  339. PROCEDURE ParseSectionProperties(VAR section: IntermediateCode.Section);
  340. VAR
  341. positionOfProperty, integer: LONGINT;
  342. BEGIN
  343. IF Trace THEN D.Ln; D.String(">>> ParseSectionProperties"); D.Ln END;
  344. WHILE ~error & (symbol.token # Scanner.EndOfText) & (symbol.token # Scanner.Ln) DO
  345. positionOfProperty := symbol.start;
  346. (* fingerprint *)
  347. IF ThisIdentifier("fingerprint") & ExpectToken(Scanner.Equal) THEN
  348. IF ExpectIntegerWithSign(integer) THEN
  349. IF (section.fingerprint # 0) & (section.fingerprint # integer) THEN
  350. Error(positionOfProperty, "incompatible fingerprint");
  351. ELSE
  352. section.SetFingerprint(integer);
  353. END
  354. ELSE
  355. Error(positionOfProperty, "invalid fingerprint")
  356. END
  357. (* position *)
  358. ELSIF ThisIdentifier("priority") & ExpectToken(Scanner.Equal) THEN
  359. IF ExpectIntegerWithSign(integer) THEN
  360. section.SetPriority(SHORT(integer));
  361. ELSE
  362. Error(positionOfProperty," invalid priority")
  363. END;
  364. (* alignment *)
  365. ELSIF ThisIdentifier("aligned") & ExpectToken(Scanner.Equal) THEN
  366. IF ExpectIntegerWithSign(integer) THEN
  367. section.SetPositionOrAlignment(FALSE, integer)
  368. ELSE
  369. Error(positionOfProperty, "invalid alignment")
  370. END
  371. (* fixed position *)
  372. ELSIF ThisIdentifier("fixed") & ExpectToken(Scanner.Equal) THEN
  373. IF ExpectIntegerWithSign(integer) THEN
  374. section.SetPositionOrAlignment(TRUE, integer)
  375. ELSE
  376. Error(positionOfProperty, "invalid fixed postion")
  377. END
  378. (* unit size of the section in bits *)
  379. ELSIF ThisIdentifier("unit") & ExpectToken(Scanner.Equal) THEN
  380. IF ExpectIntegerWithSign(integer) THEN
  381. section.SetBitsPerUnit(integer) (* overwrite default unit size *)
  382. ELSE
  383. Error(positionOfProperty, "invalid unit size")
  384. END
  385. (* total size of the section in units *)
  386. ELSIF ThisIdentifier("size") & ExpectToken(Scanner.Equal) THEN
  387. IF ExpectIntegerWithSign(integer) THEN
  388. (* nothing to do (this property is ignored, since the size is calculated from the actual content) *)
  389. ELSE
  390. Error(positionOfProperty, "invalid size")
  391. END
  392. ELSE
  393. Error(positionOfProperty, "invalid property")
  394. END
  395. END
  396. END ParseSectionProperties;
  397. (** parse the content of an intermediate code module **)
  398. PROCEDURE ParseModuleContent*(scanner: Scanner.AssemblerScanner ; module: Sections.Module (* sectionList: Sections.SectionList; VAR moduleName: SyntaxTree.IdentifierString; VAR backend: Backend.Backend; loader: ModuleLoader*) ): BOOLEAN;
  399. VAR
  400. pos, positionOfDirective: LONGINT;
  401. identifier: Scanner.IdentifierString;
  402. afterModuleDirective, afterImportsDirective, afterFirstSection, isExternalSection: BOOLEAN;
  403. sectionType: SHORTINT;
  404. section: IntermediateCode.Section;
  405. name: Basic.SegmentedName;
  406. moduleName: SyntaxTree.IdentifierString;
  407. BEGIN
  408. IF Trace THEN D.Ln; D.String(">>> ParseModuleContent"); D.Ln END;
  409. moduleName := "";
  410. (*NEW(imports, 128);*)
  411. ASSERT(scanner # NIL);
  412. SELF.scanner := scanner;
  413. NextSymbol; (* read first symbol *)
  414. (* go through directives *)
  415. afterModuleDirective := FALSE;
  416. afterImportsDirective := FALSE;
  417. afterFirstSection := FALSE;
  418. IgnoreNewLines;
  419. WHILE ~error & (symbol.token # Scanner.EndOfText) DO
  420. positionOfDirective := symbol.start;
  421. IF ExpectToken(Scanner.Period) & ExpectAnyIdentifier(pos, identifier) THEN
  422. (* 'module' directive *)
  423. IF identifier = "module" THEN
  424. IF afterModuleDirective THEN
  425. Error(positionOfDirective, "multiple module directives");
  426. ELSIF ExpectAnyIdentifier(pos, identifier) & ExpectLineDelimiter() THEN
  427. moduleName := identifier;
  428. module.SetModuleName(identifier);
  429. afterModuleDirective := TRUE;
  430. END
  431. (* 'platform' directive *)
  432. ELSIF identifier = "platform" THEN
  433. IF ~afterModuleDirective THEN
  434. Error(positionOfDirective, "platform directive must be preceeded by module directive")
  435. ELSIF ExpectAnyIdentifier(pos, identifier) & ExpectLineDelimiter() THEN
  436. module.SetPlatformName(identifier);
  437. (*! check against used backend *)
  438. ELSIF afterFirstSection THEN
  439. Error(positionOfDirective, "platform directive not before all sections")
  440. END
  441. (* 'imports' directive *)
  442. ELSIF identifier = "imports" THEN
  443. IF ~afterModuleDirective THEN
  444. Error(positionOfDirective, "import directive must be preceeded by module directive")
  445. ELSIF afterImportsDirective THEN
  446. Error(positionOfDirective, "multiple import directives")
  447. ELSIF afterFirstSection THEN
  448. Error(positionOfDirective, "import directive not before all sections")
  449. ELSE
  450. REPEAT
  451. IF ExpectAnyIdentifier(positionOfDirective, identifier) THEN
  452. module.imports.AddName(identifier);
  453. (*
  454. IF ~loader(identifier) THEN Error(positionOfDirective, "could not import") END;
  455. *)
  456. END
  457. UNTIL error OR ~ThisToken(Scanner.Comma);
  458. IF ExpectLineDelimiter() THEN
  459. afterImportsDirective := TRUE
  460. END
  461. END
  462. (* section *)
  463. ELSE
  464. (* determine if section is external *)
  465. IF identifier = "external" THEN
  466. positionOfDirective := symbol.start;
  467. IF ExpectToken(Scanner.Period) & ExpectAnyIdentifier(pos, identifier) THEN END;
  468. isExternalSection := TRUE
  469. ELSE
  470. isExternalSection := FALSE
  471. END;
  472. IF ~error THEN
  473. IF identifier = "code" THEN sectionType := Sections.CodeSection
  474. ELSIF identifier = "const" THEN sectionType := Sections.ConstSection
  475. ELSIF identifier = "var" THEN sectionType := Sections.VarSection
  476. ELSIF identifier = "bodycode" THEN sectionType := Sections.BodyCodeSection
  477. ELSIF identifier = "inlinecode" THEN sectionType := Sections.InlineCodeSection
  478. ELSIF identifier = "initcode" THEN sectionType := Sections.InitCodeSection
  479. ELSE Error(positionOfDirective, "invalid directive or section type")
  480. END;
  481. IF ~error & ~afterModuleDirective THEN
  482. Error(positionOfDirective, "module directive expected first")
  483. END;
  484. IF ~error THEN
  485. IF ExpectAnyIdentifier(pos, identifier) THEN
  486. Basic.ToSegmentedName(identifier, name);
  487. section := IntermediateCode.NewSection(module.allSections, sectionType, name, NIL, TRUE); (* keeps section if already present *)
  488. (* set default unit size for the platform, which depends on the section type *)
  489. IF (sectionType = Sections.VarSection) OR (sectionType = Sections.ConstSection) THEN
  490. section.SetBitsPerUnit(system.dataUnit)
  491. ELSE
  492. section.SetBitsPerUnit(system.codeUnit)
  493. END;
  494. ASSERT(section.bitsPerUnit # Sections.UnknownSize);
  495. (* consume optional section properties *)
  496. ParseSectionProperties(section);
  497. IF ~error & ExpectLineDelimiter() THEN
  498. ParseSectionContent(scanner, section, module.allSections);
  499. afterFirstSection := TRUE
  500. END
  501. END
  502. END
  503. END
  504. END
  505. END;
  506. IgnoreNewLines;
  507. END;
  508. RETURN ~error
  509. END ParseModuleContent;
  510. (** parse an entire intermediate code module **)
  511. PROCEDURE ParseModule*(system: Global.System): Sections.Module;
  512. VAR
  513. result: Sections.Module;
  514. BEGIN
  515. NEW(result, NIL, system); (* note: 1. there is no syntax tree module, 2. the system object to be used is not yet known *)
  516. IF ParseModuleContent(scanner, result (* result.allSections, moduleName, backend, loader *)) THEN
  517. IF Trace THEN
  518. D.String("++++++++++ PARSED MODULE '"); D.String(result.moduleName); D.String("' ++++++++++"); D.Ln;
  519. result.Dump(D.Log)
  520. END
  521. ELSE
  522. result := NIL
  523. END
  524. END ParseModule;
  525. END IntermediateCodeParser;
  526. PROCEDURE ParseReader*(reader: Streams.Reader; diagnostics: Diagnostics.Diagnostics; module: Sections.Module): BOOLEAN;
  527. VAR
  528. assemblerScanner: Scanner.AssemblerScanner;
  529. intermediateCodeParser: IntermediateCodeParser;
  530. BEGIN
  531. NEW(assemblerScanner, "", reader, 0, diagnostics);
  532. NEW(intermediateCodeParser, diagnostics, module.system);
  533. RETURN intermediateCodeParser.ParseModuleContent(assemblerScanner, module)
  534. END ParseReader;
  535. PROCEDURE ParseFile*(CONST pathName, moduleName: ARRAY OF CHAR; system: Global.System; diagnostics: Diagnostics.Diagnostics): Sections.Module;
  536. VAR
  537. filename: Files.FileName;
  538. assemblerScanner: Scanner.AssemblerScanner;
  539. intermediateCodeParser: IntermediateCodeParser;
  540. reader: Streams.Reader;
  541. msg: ARRAY 128 OF CHAR;
  542. module: Sections.Module;
  543. BEGIN
  544. (* open corresponding intermediate code file *)
  545. Files.JoinExtension(moduleName, IntermediateCodeExtension, filename);
  546. IF pathName # "" THEN Files.JoinPath(pathName, filename, filename) END;
  547. reader := Basic.GetFileReader(filename);
  548. IF Trace THEN D.String("FoxIntermediateCodeParser.ParseFile "); D.String(filename); D.Ln END;
  549. IF reader = NIL THEN
  550. msg := "failed to open ";
  551. Strings.Append(msg, filename);
  552. diagnostics.Error(filename, Diagnostics.Invalid, Diagnostics.Invalid, msg);
  553. RETURN NIL
  554. ELSE
  555. NEW(module, NIL, system);
  556. IF ParseReader(reader, diagnostics, module) THEN
  557. RETURN module
  558. ELSE
  559. RETURN NIL
  560. END;
  561. END;
  562. END ParseFile;
  563. END FoxIntermediateParser.