FoxIntermediateParser.Mod 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623
  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. Position = Basic.Position;
  11. (** the intermediate code parser **)
  12. IntermediateCodeParser* = OBJECT
  13. CONST
  14. Trace = FALSE;
  15. Strict = TRUE;
  16. VAR
  17. diagnostics: Diagnostics.Diagnostics;
  18. error: BOOLEAN;
  19. token: Scanner.Token;
  20. scanner: Scanner.AssemblerScanner;
  21. system: Global.System;
  22. PROCEDURE &Init*(diagnostics: Diagnostics.Diagnostics; s: Global.System);
  23. BEGIN
  24. ASSERT(s # NIL); (* a default system object is required in case there is no platform directive *)
  25. SELF.diagnostics := diagnostics;
  26. system := s;
  27. error := FALSE
  28. END Init;
  29. PROCEDURE Error(pos: Position; CONST msg: ARRAY OF CHAR);
  30. BEGIN
  31. error := TRUE;
  32. Basic.Error(diagnostics, scanner.source^,pos,msg);
  33. D.Update;
  34. IF Trace THEN D.TraceBack END
  35. END Error;
  36. PROCEDURE NextToken;
  37. BEGIN error := error OR ~scanner.GetNextToken(token)
  38. END NextToken;
  39. PROCEDURE ThisSymbol(x: Scanner.Symbol): BOOLEAN;
  40. BEGIN
  41. IF ~error & (token.symbol = x) THEN NextToken; RETURN TRUE ELSE RETURN FALSE END;
  42. END ThisSymbol;
  43. PROCEDURE GetIdentifier(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  44. BEGIN
  45. pos := token.position;
  46. IF token.symbol # Scanner.Identifier THEN RETURN FALSE
  47. ELSE COPY(token.identifierString,identifier); NextToken; RETURN TRUE
  48. END;
  49. END GetIdentifier;
  50. PROCEDURE ExpectSymbol(x: Scanner.Symbol): BOOLEAN;
  51. VAR
  52. s: MessageString;
  53. BEGIN
  54. IF ThisSymbol(x) THEN RETURN TRUE
  55. ELSE
  56. s := "expected symbol "; Strings.Append(s,Scanner.symbols[x]); Strings.Append(s," but got "); Strings.Append(s,Scanner.symbols[token.symbol]);
  57. Error(token.position, s);RETURN FALSE
  58. END;
  59. END ExpectSymbol;
  60. PROCEDURE ThisIdentifier(CONST this: ARRAY OF CHAR): BOOLEAN;
  61. BEGIN
  62. IF ~error & (token.symbol = Scanner.Identifier) & (this = token.identifierString) THEN NextToken; RETURN TRUE ELSE RETURN FALSE END;
  63. END ThisIdentifier;
  64. PROCEDURE ExpectAnyIdentifier(VAR pos: Position; VAR identifier: ARRAY OF CHAR): BOOLEAN;
  65. BEGIN
  66. IF ~GetIdentifier(pos,identifier)THEN Error(pos,"identifier expected"); RETURN FALSE
  67. ELSE RETURN TRUE
  68. END;
  69. END ExpectAnyIdentifier;
  70. PROCEDURE ExpectIntegerWithSign(VAR integer: LONGINT): BOOLEAN;
  71. VAR
  72. result, isNegated: BOOLEAN;
  73. BEGIN
  74. isNegated := ThisSymbol(Scanner.Minus);
  75. IF ExpectSymbol(Scanner.Number) & (token.numberType = Scanner.Integer) THEN
  76. IF isNegated THEN
  77. integer := -token.integer
  78. ELSE
  79. integer := token.integer
  80. END;
  81. result := TRUE
  82. ELSE
  83. result := FALSE
  84. END;
  85. RETURN result
  86. END ExpectIntegerWithSign;
  87. PROCEDURE ExpectIntegerWithoutSign(VAR integer: LONGINT): BOOLEAN;
  88. VAR
  89. result: BOOLEAN;
  90. BEGIN
  91. IF ExpectSymbol(Scanner.Number) & (token.numberType = Scanner.Integer) THEN
  92. integer := token.integer;
  93. result := TRUE
  94. ELSE
  95. result := FALSE
  96. END;
  97. RETURN result
  98. END ExpectIntegerWithoutSign;
  99. PROCEDURE IgnoreNewLines;
  100. BEGIN
  101. WHILE ThisSymbol(Scanner.Ln) DO END;
  102. END IgnoreNewLines;
  103. (* expect the newline or end-of-text token *)
  104. PROCEDURE ExpectLineDelimiter(): BOOLEAN;
  105. BEGIN
  106. IF ~error & ((token.symbol = Scanner.Ln) OR (token.symbol = Scanner.EndOfText)) THEN
  107. NextToken;
  108. RETURN TRUE
  109. ELSE
  110. Error(token.position, "end of line/text expected");
  111. RETURN FALSE
  112. END;
  113. END ExpectLineDelimiter;
  114. (** parse an optional line number **)
  115. PROCEDURE ParseLineNumber(expectedLineNumber: LONGINT);
  116. VAR
  117. positionOfLine: Position;
  118. specifiedLineNumber: LONGINT;
  119. message, tempString: MessageString;
  120. BEGIN
  121. IF Trace THEN D.String(">>> ParseLineNumber"); D.Ln END;
  122. positionOfLine := token.position;
  123. IF ThisSymbol(Scanner.Number) THEN (* note: line numbers are optional *)
  124. specifiedLineNumber := token.integer;
  125. IF ExpectSymbol(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: Position; 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 := token.position;
  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 := ThisSymbol(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 ThisSymbol(Scanner.Colon) THEN
  176. IF ExpectIntegerWithSign(integer) THEN
  177. symbolOffset := integer
  178. ELSE
  179. Error(token.position, "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 token.symbol = Scanner.String THEN
  187. (* string constant *)
  188. IntermediateCode.InitString(operand, token.string);
  189. NextToken
  190. ELSE
  191. (* immediate values/numbers *)
  192. isNegated := ThisSymbol(Scanner.Minus);
  193. IF ThisSymbol(Scanner.Number) THEN
  194. CASE token.numberType OF
  195. | Scanner.Integer:
  196. IF isNegated THEN someLongint := -token.integer ELSE someLongint := token.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 := - token.hugeint ELSE someHugeint := token.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 := -token.real ELSE someLongreal := token.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 ThisSymbol(Scanner.Plus) THEN
  238. IF ExpectIntegerWithoutSign(integer) THEN
  239. IntermediateCode.SetOffset(operand, integer)
  240. ELSE
  241. Error(token.position, "invalid offset")
  242. END
  243. ELSIF ThisSymbol(Scanner.Minus) THEN
  244. IF ExpectIntegerWithoutSign(integer) THEN
  245. IntermediateCode.SetOffset(operand, -integer)
  246. ELSE
  247. Error(token.position, "invalid offset")
  248. END
  249. END;
  250. (* wrap memory operand around current operand if necessary *)
  251. IF isMemoryOperand & ExpectSymbol(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: Position;
  264. operandNumber: LONGINT;
  265. operand: IntermediateCode.Operand;
  266. operands: ARRAY 3 OF IntermediateCode.Operand;
  267. operandType: IntermediateCode.Type;
  268. identifier, message, tempString: SyntaxTree.IdentifierString;
  269. BEGIN
  270. IF Trace THEN D.String(">>> ParseInstruction"); D.Ln END;
  271. positionOfInstruction := token.position;
  272. IF ExpectAnyIdentifier(positionOfInstruction, identifier) THEN
  273. (* TODO: detect labels of the form << labelName: >> *)
  274. opCode := IntermediateCode.FindMnemonic(identifier);
  275. IF opCode = IntermediateCode.None THEN
  276. Error(positionOfInstruction, "unknown mnemonic")
  277. ELSE
  278. (* consume all operands *)
  279. IntermediateCode.InitType(operandType, IntermediateCode.SignedInteger, 32); (* defaults *)
  280. IntermediateCode.InitOperand(operands[0]);
  281. IntermediateCode.InitOperand(operands[1]);
  282. IntermediateCode.InitOperand(operands[2]);
  283. operandNumber := 0;
  284. IF ~ThisSymbol(Scanner.Ln) & ~ThisSymbol(Scanner.EndOfText) THEN
  285. REPEAT
  286. positionOfOperand := token.position;
  287. IF operandNumber > 2 THEN
  288. Error(positionOfInstruction, "instruction has too many operands")
  289. ELSE
  290. ParseOperand(operand, sectionList);
  291. IF ~error THEN
  292. IF Strict & ~IntermediateCode.CheckOperand(operand, opCode, operandNumber, message) THEN
  293. Strings.Append(message, " @ operand ");
  294. Strings.IntToStr(operandNumber + 1, tempString); Strings.Append(message, tempString);
  295. Error(positionOfOperand, message)
  296. END;
  297. operands[operandNumber] := operand;
  298. INC(operandNumber)
  299. END
  300. END
  301. UNTIL error OR ~ThisSymbol(Scanner.Comma);
  302. IF ~error & ExpectLineDelimiter() THEN END
  303. END;
  304. IF ~error THEN
  305. IntermediateCode.InitInstruction(instruction, positionOfInstruction, opCode, operands[0], operands[1], operands[2]);
  306. IF Strict & ~IntermediateCode.CheckInstruction(instruction, message) THEN
  307. Error(positionOfInstruction, message)
  308. END
  309. END
  310. END;
  311. END
  312. END ParseInstruction;
  313. (** parse the content of an intermediate code section
  314. note: 'sectionList' is the list where referenced sections are found/to be created
  315. **)
  316. PROCEDURE ParseSectionContent*(scanner: Scanner.AssemblerScanner; section: IntermediateCode.Section; sectionList: Sections.SectionList);
  317. VAR
  318. instruction: IntermediateCode.Instruction;
  319. lineNumber: LONGINT;
  320. BEGIN
  321. IF Trace THEN D.Ln; D.String(">>> ParseSectionContent"); D.Ln END;
  322. SELF.scanner := scanner;
  323. IgnoreNewLines;
  324. lineNumber := 0;
  325. WHILE ~error & (token.symbol # Scanner.Period) & (token.symbol # Scanner.EndOfText) DO
  326. (* consume optional line number *)
  327. ParseLineNumber(lineNumber);
  328. IF ~error THEN
  329. ParseInstruction(instruction, sectionList);
  330. IF ~error THEN
  331. IF Trace THEN IntermediateCode.DumpInstruction(D.Log, instruction); D.Ln; END;
  332. section.Emit(instruction);
  333. INC(lineNumber)
  334. END;
  335. END;
  336. IgnoreNewLines
  337. END
  338. END ParseSectionContent;
  339. (** parse a list of section properties **)
  340. PROCEDURE ParseSectionProperties(VAR section: IntermediateCode.Section);
  341. VAR
  342. positionOfProperty: Position; integer: LONGINT;
  343. BEGIN
  344. IF Trace THEN D.Ln; D.String(">>> ParseSectionProperties"); D.Ln END;
  345. WHILE ~error & (token.symbol # Scanner.EndOfText) & (token.symbol # Scanner.Ln) DO
  346. positionOfProperty := token.position;
  347. (* fingerprint *)
  348. IF ThisIdentifier("fingerprint") & ExpectSymbol(Scanner.Equal) THEN
  349. IF ExpectIntegerWithSign(integer) THEN
  350. IF (section.fingerprint # 0) & (section.fingerprint # integer) THEN
  351. Error(positionOfProperty, "incompatible fingerprint");
  352. ELSE
  353. section.SetFingerprint(integer);
  354. END
  355. ELSE
  356. Error(positionOfProperty, "invalid fingerprint")
  357. END
  358. (* position *)
  359. ELSIF ThisIdentifier("aligned") & ExpectSymbol(Scanner.Equal) THEN
  360. IF ExpectIntegerWithSign(integer) THEN
  361. section.SetPositionOrAlignment(FALSE, integer)
  362. ELSE
  363. Error(positionOfProperty, "invalid alignment")
  364. END
  365. (* fixed position *)
  366. ELSIF ThisIdentifier("fixed") & ExpectSymbol(Scanner.Equal) THEN
  367. IF ExpectIntegerWithSign(integer) THEN
  368. section.SetPositionOrAlignment(TRUE, integer)
  369. ELSE
  370. Error(positionOfProperty, "invalid fixed postion")
  371. END
  372. (* unit size of the section in bits *)
  373. ELSIF ThisIdentifier("unit") & ExpectSymbol(Scanner.Equal) THEN
  374. IF ExpectIntegerWithSign(integer) THEN
  375. section.SetBitsPerUnit(integer) (* overwrite default unit size *)
  376. ELSE
  377. Error(positionOfProperty, "invalid unit size")
  378. END
  379. (* total size of the section in units *)
  380. ELSIF ThisIdentifier("size") & ExpectSymbol(Scanner.Equal) THEN
  381. IF ExpectIntegerWithSign(integer) THEN
  382. (* nothing to do (this property is ignored, since the size is calculated from the actual content) *)
  383. ELSE
  384. Error(positionOfProperty, "invalid size")
  385. END
  386. ELSE
  387. Error(positionOfProperty, "invalid property")
  388. END
  389. END
  390. END ParseSectionProperties;
  391. (** parse the content of an intermediate code module **)
  392. PROCEDURE ParseModuleContent*(scanner: Scanner.AssemblerScanner ; module: Sections.Module (* sectionList: Sections.SectionList; VAR moduleName: SyntaxTree.IdentifierString; VAR backend: Backend.Backend; loader: ModuleLoader*) ): BOOLEAN;
  393. VAR
  394. pos, positionOfDirective:Position;
  395. identifier: Scanner.IdentifierString;
  396. afterModuleDirective, afterImportsDirective, afterFirstSection, isExternalSection: BOOLEAN;
  397. sectionType: SHORTINT;
  398. section: IntermediateCode.Section;
  399. name: Basic.SegmentedName;
  400. moduleName: SyntaxTree.IdentifierString;
  401. BEGIN
  402. IF Trace THEN D.Ln; D.String(">>> ParseModuleContent"); D.Ln END;
  403. moduleName := "";
  404. (*NEW(imports, 128);*)
  405. ASSERT(scanner # NIL);
  406. SELF.scanner := scanner;
  407. NextToken; (* read first token *)
  408. (* go through directives *)
  409. afterModuleDirective := FALSE;
  410. afterImportsDirective := FALSE;
  411. afterFirstSection := FALSE;
  412. IgnoreNewLines;
  413. WHILE ~error & (token.symbol # Scanner.EndOfText) DO
  414. positionOfDirective := token.position;
  415. IF ExpectSymbol(Scanner.Period) & ExpectAnyIdentifier(pos, identifier) THEN
  416. (* 'module' directive *)
  417. IF identifier = "module" THEN
  418. IF afterModuleDirective THEN
  419. Error(positionOfDirective, "multiple module directives");
  420. ELSIF ExpectAnyIdentifier(pos, identifier) & ExpectLineDelimiter() THEN
  421. moduleName := identifier;
  422. module.SetModuleName(identifier);
  423. afterModuleDirective := TRUE;
  424. END
  425. (* 'platform' directive *)
  426. ELSIF identifier = "platform" THEN
  427. IF ~afterModuleDirective THEN
  428. Error(positionOfDirective, "platform directive must be preceeded by module directive")
  429. ELSIF ExpectAnyIdentifier(pos, identifier) & ExpectLineDelimiter() THEN
  430. module.SetPlatformName(identifier);
  431. (*! check against used backend *)
  432. ELSIF afterFirstSection THEN
  433. Error(positionOfDirective, "platform directive not before all sections")
  434. END
  435. (* 'imports' directive *)
  436. ELSIF identifier = "imports" THEN
  437. IF ~afterModuleDirective THEN
  438. Error(positionOfDirective, "import directive must be preceeded by module directive")
  439. ELSIF afterImportsDirective THEN
  440. Error(positionOfDirective, "multiple import directives")
  441. ELSIF afterFirstSection THEN
  442. Error(positionOfDirective, "import directive not before all sections")
  443. ELSE
  444. REPEAT
  445. IF ExpectAnyIdentifier(positionOfDirective, identifier) THEN
  446. module.imports.AddName(identifier);
  447. (*
  448. IF ~loader(identifier) THEN Error(positionOfDirective, "could not import") END;
  449. *)
  450. END
  451. UNTIL error OR ~ThisSymbol(Scanner.Comma);
  452. IF ExpectLineDelimiter() THEN
  453. afterImportsDirective := TRUE
  454. END
  455. END
  456. (* section *)
  457. ELSE
  458. (* determine if section is external *)
  459. IF identifier = "external" THEN
  460. positionOfDirective := token.position;
  461. IF ExpectSymbol(Scanner.Period) & ExpectAnyIdentifier(pos, identifier) THEN END;
  462. isExternalSection := TRUE
  463. ELSE
  464. isExternalSection := FALSE
  465. END;
  466. IF ~error THEN
  467. IF identifier = "code" THEN sectionType := Sections.CodeSection
  468. ELSIF identifier = "const" THEN sectionType := Sections.ConstSection
  469. ELSIF identifier = "var" THEN sectionType := Sections.VarSection
  470. ELSIF identifier = "bodycode" THEN sectionType := Sections.BodyCodeSection
  471. ELSIF identifier = "inlinecode" THEN sectionType := Sections.InlineCodeSection
  472. ELSIF identifier = "initcode" THEN sectionType := Sections.InitCodeSection
  473. ELSE Error(positionOfDirective, "invalid directive or section type")
  474. END;
  475. IF ~error & ~afterModuleDirective THEN
  476. Error(positionOfDirective, "module directive expected first")
  477. END;
  478. IF ~error THEN
  479. IF ExpectAnyIdentifier(pos, identifier) THEN
  480. Basic.ToSegmentedName(identifier, name);
  481. section := IntermediateCode.NewSection(module.allSections, sectionType, name, NIL, TRUE); (* keeps section if already present *)
  482. (* set default unit size for the platform, which depends on the section type *)
  483. IF (sectionType = Sections.VarSection) OR (sectionType = Sections.ConstSection) THEN
  484. section.SetBitsPerUnit(system.dataUnit)
  485. ELSE
  486. section.SetBitsPerUnit(system.codeUnit)
  487. END;
  488. ASSERT(section.bitsPerUnit # Sections.UnknownSize);
  489. (* consume optional section properties *)
  490. ParseSectionProperties(section);
  491. IF ~error & ExpectLineDelimiter() THEN
  492. ParseSectionContent(scanner, section, module.allSections);
  493. afterFirstSection := TRUE
  494. END
  495. END
  496. END
  497. END
  498. END
  499. END;
  500. IgnoreNewLines;
  501. END;
  502. RETURN ~error
  503. END ParseModuleContent;
  504. (** parse an entire intermediate code module **)
  505. PROCEDURE ParseModule*(system: Global.System): Sections.Module;
  506. VAR
  507. result: Sections.Module;
  508. BEGIN
  509. NEW(result, NIL, system); (* note: 1. there is no syntax tree module, 2. the system object to be used is not yet known *)
  510. IF ParseModuleContent(scanner, result (* result.allSections, moduleName, backend, loader *)) THEN
  511. IF Trace THEN
  512. D.String("++++++++++ PARSED MODULE '"); D.String(result.moduleName); D.String("' ++++++++++"); D.Ln;
  513. result.Dump(D.Log)
  514. END
  515. ELSE
  516. result := NIL
  517. END
  518. END ParseModule;
  519. END IntermediateCodeParser;
  520. PROCEDURE ParseReader*(reader: Streams.Reader; diagnostics: Diagnostics.Diagnostics; module: Sections.Module): BOOLEAN;
  521. VAR
  522. assemblerScanner: Scanner.AssemblerScanner;
  523. intermediateCodeParser: IntermediateCodeParser;
  524. BEGIN
  525. assemblerScanner := Scanner.NewAssemblerScanner("",reader,0,diagnostics);
  526. NEW(intermediateCodeParser, diagnostics, module.system);
  527. RETURN intermediateCodeParser.ParseModuleContent(assemblerScanner, module)
  528. END ParseReader;
  529. PROCEDURE ParseFile*(CONST pathName, moduleName: ARRAY OF CHAR; system: Global.System; diagnostics: Diagnostics.Diagnostics): Sections.Module;
  530. VAR
  531. filename: Files.FileName;
  532. assemblerScanner: Scanner.AssemblerScanner;
  533. intermediateCodeParser: IntermediateCodeParser;
  534. reader: Streams.Reader;
  535. msg: ARRAY 128 OF CHAR;
  536. module: Sections.Module;
  537. BEGIN
  538. (* open corresponding intermediate code file *)
  539. Files.JoinExtension(moduleName, IntermediateCodeExtension, filename);
  540. IF pathName # "" THEN Files.JoinPath(pathName, filename, filename) END;
  541. reader := Basic.GetFileReader(filename);
  542. IF Trace THEN D.String("FoxIntermediateCodeParser.ParseFile "); D.String(filename); D.Ln END;
  543. IF reader = NIL THEN
  544. msg := "failed to open ";
  545. Strings.Append(msg, filename);
  546. Basic.Error(diagnostics, filename, Basic.invalidPosition, msg);
  547. RETURN NIL
  548. ELSE
  549. NEW(module, NIL, system);
  550. IF ParseReader(reader, diagnostics, module) THEN
  551. RETURN module
  552. ELSE
  553. RETURN NIL
  554. END;
  555. END;
  556. END ParseFile;
  557. END FoxIntermediateParser.