2
0

FoxIntermediateObjectFile.Mod 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551
  1. MODULE FoxIntermediateObjectFile; (** AUTHOR ""; PURPOSE "Intermediate Object File Writer"; *)
  2. IMPORT
  3. Formats := FoxFormats, Sections := FoxSections, IntermediateCode := FoxIntermediateCode, ObjectFile,
  4. Files, Strings, Options, Diagnostics, SymbolFileFormat := FoxTextualSymbolFile, Streams, Basic := FoxBasic,
  5. SyntaxTree := FoxSyntaxTree, D := Debugging, Global := FoxGlobal, Parser := FoxIntermediateParser, Commands, KernelLog, Backend := FoxBackend;
  6. CONST
  7. Trace = FALSE;
  8. DeveloperVersion=TRUE;
  9. Version=2;
  10. TYPE ObjectFileFormat* = OBJECT (Formats.ObjectFileFormat)
  11. VAR prefix, extension: Files.FileName; textual: BOOLEAN;
  12. PROCEDURE & InitObjectFileFormat*;
  13. BEGIN
  14. Init;
  15. prefix := ""; extension := ".Fil";
  16. END InitObjectFileFormat;
  17. PROCEDURE ExportModuleTextual(module: Sections.Module; writer: Streams.Writer);
  18. VAR
  19. section: Sections.Section;
  20. intermediateCodeSection: IntermediateCode.Section;
  21. i: LONGINT;
  22. BEGIN
  23. (* prepare sections for output *)
  24. FOR i := 0 TO module.allSections.Length() - 1 DO
  25. section := module.allSections.GetSection(i);
  26. ASSERT(section IS IntermediateCode.Section);
  27. intermediateCodeSection := section(IntermediateCode.Section);
  28. intermediateCodeSection.SetResolved(NIL); (* remove generated binary code *)
  29. intermediateCodeSection.DeleteComments (* remove comments *)
  30. END;
  31. module.Dump(writer)
  32. END ExportModuleTextual;
  33. PROCEDURE ExportModuleBinary(module: Sections.Module; w: Streams.Writer; poolMap: ObjectFile.PoolMap);
  34. VAR
  35. section: Sections.Section;
  36. intermediateCodeSection: IntermediateCode.Section;
  37. PROCEDURE SectionName(sectionName: ObjectFile.SegmentedName);
  38. VAR name: ObjectFile.SectionName; i,num: LONGINT;
  39. BEGIN
  40. i := 0;
  41. REPEAT
  42. num := poolMap.Get(sectionName[i]);
  43. w.RawNum(num);
  44. INC(i);
  45. UNTIL (i = LEN(sectionName)) OR (num < 0);
  46. END SectionName;
  47. PROCEDURE WriteOperand(CONST operand: IntermediateCode.Operand);
  48. PROCEDURE Type(t: IntermediateCode.Type);
  49. BEGIN
  50. w.RawSInt(t.form);
  51. w.RawInt(t.sizeInBits);
  52. END Type;
  53. PROCEDURE RegisterClass(c: IntermediateCode.RegisterClass);
  54. BEGIN
  55. w.RawSInt(c.class);
  56. w.RawInt(c.number);
  57. END RegisterClass;
  58. BEGIN
  59. Type(operand.type);
  60. w.RawNum(operand.mode);
  61. CASE operand.mode OF
  62. IntermediateCode.Undefined:
  63. |IntermediateCode.ModeMemory:
  64. IF operand.register # IntermediateCode.None THEN
  65. w.RawNum(0);
  66. w.RawNum(operand.register);
  67. w.RawNum(operand.offset);
  68. ELSIF operand.symbol.name # "" THEN
  69. w.RawNum(1);
  70. SectionName(operand.symbol.name);
  71. w.RawNum(operand.symbolOffset);
  72. w.RawNum(operand.offset);
  73. ELSE
  74. w.RawNum(2);
  75. w.RawHInt(operand.intValue)
  76. END;
  77. |IntermediateCode.ModeRegister:
  78. w.RawNum(operand.register);
  79. RegisterClass(operand.registerClass);
  80. w.RawNum(operand.offset);
  81. |IntermediateCode.ModeImmediate:
  82. IF operand.symbol.name # "" THEN
  83. w.RawNum(0);
  84. SectionName(operand.symbol.name);
  85. w.RawNum(operand.symbolOffset);
  86. w.RawNum(operand.offset);
  87. ELSE
  88. w.RawNum(1);
  89. IF operand.type.form IN IntermediateCode.Integer THEN
  90. w.RawHInt(operand.intValue);
  91. ELSE
  92. w.RawLReal(operand.floatValue);
  93. END;
  94. END;
  95. |IntermediateCode.ModeString:
  96. w.RawNum(Strings.Length(operand.string^));
  97. w.RawString(operand.string^);
  98. |IntermediateCode.ModeNumber:
  99. w.RawHInt(operand.intValue);
  100. END;
  101. END WriteOperand;
  102. PROCEDURE WriteInstruction(CONST instr: IntermediateCode.Instruction);
  103. BEGIN
  104. w.RawNum(instr.opcode);
  105. IF instr.opcode = IntermediateCode.special THEN w.RawNum(instr.subtype) END;
  106. WriteOperand(instr.op1);
  107. WriteOperand(instr.op2);
  108. WriteOperand(instr.op3);
  109. END WriteInstruction;
  110. PROCEDURE WriteSection(section: IntermediateCode.Section);
  111. VAR i: LONGINT;
  112. BEGIN
  113. w.RawLInt(section.type);
  114. SectionName(section.name);
  115. w.RawBool(section.fixed);
  116. w.RawNum(section.positionOrAlignment);
  117. w.RawNum(section.fingerprint);
  118. w.RawNum(section.bitsPerUnit);
  119. w.RawNum(section.pc);
  120. FOR i := 0 TO section.pc-1 DO
  121. WriteInstruction(section.instructions[i]);
  122. END;
  123. END WriteSection;
  124. PROCEDURE SectionList(list: Sections.SectionList);
  125. VAR section: Sections.Section;i: LONGINT;
  126. BEGIN
  127. w.RawNum(list.Length());
  128. FOR i := 0 TO list.Length() - 1 DO
  129. section := list.GetSection(i);
  130. WriteSection(section(IntermediateCode.Section));
  131. END;
  132. END SectionList;
  133. PROCEDURE Imports(imports: Sections.NameList);
  134. VAR name: SyntaxTree.IdentifierString;i: LONGINT;
  135. BEGIN
  136. w.RawNum(imports.Length());
  137. FOR i := 0 TO imports.Length()-1 DO
  138. name := imports.GetName(i);
  139. w.RawString(name);
  140. END;
  141. END Imports;
  142. BEGIN
  143. w.RawString(module.moduleName);
  144. w.RawString(module.platformName);
  145. Imports(module.imports);
  146. SectionList(module.allSections);
  147. END ExportModuleBinary;
  148. PROCEDURE Export*(module: Formats.GeneratedModule; symbolFileFormat: Formats.SymbolFileFormat): BOOLEAN;
  149. VAR
  150. filename: Files.FileName;
  151. file: Files.File;
  152. writer: Files.Writer;
  153. poolMap: ObjectFile.PoolMap;
  154. BEGIN
  155. IF Trace THEN D.String(">>> export intermediate object file"); D.Ln END;
  156. IF ~(module IS Sections.Module) THEN
  157. Basic.Error(diagnostics, module.moduleName, Basic.invalidPosition, "generated module format does not match object file format");
  158. RETURN FALSE;
  159. END;
  160. IF prefix # "" THEN Files.JoinPath(prefix, module.moduleName, filename); ELSE COPY (module.moduleName, filename); END;
  161. Files.JoinExtension(filename, extension, filename);
  162. IF Trace THEN D.String(">>> filename: "); D.String(filename); D.Ln END;
  163. file := Files.New(filename);
  164. IF file = NIL THEN
  165. Basic.Error(diagnostics, module.moduleName, Basic.invalidPosition, "failed to open object file for writting");
  166. RETURN FALSE
  167. END;
  168. Files.OpenWriter(writer, file, 0);
  169. IF textual THEN
  170. WriteHeader(writer, FALSE, module(Sections.Module).allSections, poolMap);
  171. ExportModuleTextual(module(Sections.Module),writer);
  172. ELSE
  173. WriteHeader(writer, TRUE, module(Sections.Module).allSections, poolMap);
  174. ExportModuleBinary(module(Sections.Module),writer, poolMap);
  175. END;
  176. writer.Update;
  177. file.Update;
  178. Files.Register(file);
  179. RETURN TRUE
  180. END Export;
  181. PROCEDURE ImportModuleBinary(r: Streams.Reader; module: Sections.Module; system: Global.System; poolMap: ObjectFile.PoolMap): BOOLEAN;
  182. VAR
  183. section: Sections.Section;
  184. name: ObjectFile.SectionName;
  185. addressType: IntermediateCode.Type;
  186. PROCEDURE SectionName(VAR sectionName: ObjectFile.SegmentedName);
  187. VAR name: ObjectFile.SectionName; i, num: LONGINT;
  188. BEGIN
  189. i := 0;
  190. REPEAT
  191. r.RawNum(num);
  192. sectionName[i] := poolMap.Get(num);
  193. INC(i);
  194. UNTIL (i = LEN(sectionName)) OR (num < 0);
  195. WHILE i < LEN(sectionName) DO
  196. sectionName[i] := -1; INC(i);
  197. END;
  198. END SectionName;
  199. PROCEDURE ReadOperand(VAR operand: IntermediateCode.Operand);
  200. VAR type: IntermediateCode.Type; mode, subMode: LONGINT; register: LONGINT; registerClass: IntermediateCode.RegisterClass;
  201. offset: LONGINT; int: HUGEINT; real: LONGREAL; name: ObjectFile.SegmentedName; symbolOffset: LONGINT;
  202. string: Strings.String; len: LONGINT;
  203. symbolSection: Sections.Section;
  204. PROCEDURE Type(VAR t: IntermediateCode.Type);
  205. VAR form: SHORTINT; sizeInBits: INTEGER;
  206. BEGIN
  207. r.RawSInt(form);
  208. r.RawInt(sizeInBits);
  209. IntermediateCode.InitType(t, form, sizeInBits)
  210. END Type;
  211. PROCEDURE RegisterClass(VAR c: IntermediateCode.RegisterClass);
  212. VAR class: SHORTINT; number: INTEGER;
  213. BEGIN
  214. r.RawSInt(class);
  215. r.RawInt(number);
  216. IntermediateCode.InitRegisterClass(c, class, number)
  217. END RegisterClass;
  218. BEGIN
  219. Type(type);
  220. IntermediateCode.SetType(operand, type);
  221. r.RawNum(mode);
  222. CASE mode OF
  223. IntermediateCode.Undefined:
  224. IntermediateCode.InitOperand(operand); (* no operand *)
  225. |IntermediateCode.ModeMemory:
  226. r.RawNum(subMode);
  227. IF subMode = 0 THEN
  228. r.RawNum(register);
  229. r.RawNum(offset);
  230. IntermediateCode.InitRegister(operand, addressType, IntermediateCode.GeneralPurposeRegister, register);
  231. ELSIF subMode = 1 THEN
  232. SectionName(name);
  233. r.RawNum(symbolOffset);
  234. r.RawNum(offset);
  235. IntermediateCode.InitAddress(operand, addressType, name, 0, symbolOffset);
  236. ELSE
  237. offset := 0;
  238. ASSERT(subMode = 2);
  239. r.RawHInt(int);
  240. IntermediateCode.InitImmediate(operand, addressType, int);
  241. END;
  242. IntermediateCode.InitMemory(operand, type, operand, offset);
  243. |IntermediateCode.ModeRegister:
  244. r.RawNum(register); RegisterClass(registerClass); r.RawNum(offset);
  245. IntermediateCode.InitRegister(operand, type, registerClass, register);
  246. IntermediateCode.AddOffset(operand, offset);
  247. |IntermediateCode.ModeImmediate:
  248. r.RawNum(subMode);
  249. IF subMode = 0 THEN (* ?? *)
  250. SectionName(name);
  251. r.RawNum(symbolOffset);
  252. r.RawNum(offset);
  253. IntermediateCode.InitAddress(operand, type, name, 0, symbolOffset);
  254. IntermediateCode.AddOffset(operand, offset);
  255. ELSE
  256. ASSERT(subMode = 1);
  257. IF operand.type.form IN IntermediateCode.Integer THEN
  258. r.RawHInt(int);
  259. IntermediateCode.InitImmediate(operand, type, int);
  260. ELSE
  261. r.RawLReal(real);
  262. IntermediateCode.InitFloatImmediate(operand, type, real);
  263. END;
  264. END;
  265. |IntermediateCode.ModeString:
  266. r.RawNum(len);
  267. NEW(string, len);
  268. r.RawString(string^);
  269. IntermediateCode.InitString(operand, string);
  270. |IntermediateCode.ModeNumber:
  271. r.RawHInt(int);
  272. IntermediateCode.InitNumber(operand, int)
  273. END;
  274. END ReadOperand;
  275. PROCEDURE ReadInstruction(section: IntermediateCode.Section);
  276. VAR opcode, subtype: LONGINT; instruction: IntermediateCode.Instruction; op1, op2, op3: IntermediateCode.Operand;
  277. BEGIN
  278. r.RawNum(opcode);
  279. IF opcode = IntermediateCode.special THEN r.RawNum(subtype) END;
  280. ReadOperand(op1);
  281. ReadOperand(op2);
  282. ReadOperand(op3);
  283. IntermediateCode.InitInstruction(instruction, Basic.invalidPosition, SHORTINT(opcode), op1, op2, op3);
  284. IntermediateCode.SetSubType(instruction, SHORTINT(subtype));
  285. section.Emit(instruction);
  286. END ReadInstruction;
  287. PROCEDURE ReadSection(sectionList: Sections.SectionList);
  288. VAR section: IntermediateCode.Section;
  289. isDefinition: BOOLEAN;
  290. name: Basic.SegmentedName;
  291. symbol: SyntaxTree.Symbol;
  292. comment: BOOLEAN;
  293. type: LONGINT;
  294. fixed: BOOLEAN;
  295. positionOrAlignment, fingerprint, bitsPerUnit: LONGINT;
  296. pc,i: LONGINT;
  297. BEGIN
  298. r.RawLInt(type);
  299. SectionName(name);
  300. r.RawBool(fixed);
  301. r.RawNum(positionOrAlignment);
  302. r.RawNum(fingerprint);
  303. r.RawNum(bitsPerUnit);
  304. section := IntermediateCode.NewSection(sectionList, SHORTINT(type), name, NIL, FALSE); (* keeps section if already present *)
  305. IF bitsPerUnit < 0 THEN (* unknown *)
  306. IF (type = Sections.VarSection) OR (type = Sections.ConstSection) THEN
  307. bitsPerUnit := system.dataUnit
  308. ELSE
  309. (*bitsPerUnit := system.codeUnit*)
  310. (*Unit is already set.*)
  311. END;
  312. END;
  313. section.SetBitsPerUnit(bitsPerUnit);
  314. section.SetFingerprint(fingerprint);
  315. section.SetPositionOrAlignment(fixed, positionOrAlignment);
  316. r.RawNum(pc);
  317. FOR i := 0 TO pc-1 DO
  318. ReadInstruction(section);
  319. END;
  320. END ReadSection;
  321. PROCEDURE SectionList(list: Sections.SectionList);
  322. VAR section: Sections.Section; length,i: LONGINT;
  323. BEGIN
  324. r.RawNum(length);
  325. FOR i := 0 TO length - 1 DO
  326. ReadSection(list);
  327. END;
  328. END SectionList;
  329. PROCEDURE Imports(imports: Sections.NameList);
  330. VAR name: SyntaxTree.IdentifierString; length,i: LONGINT;
  331. BEGIN
  332. r.RawNum(length);
  333. FOR i := 0 TO length-1 DO
  334. r.RawString(name);
  335. imports.AddName(name);
  336. END;
  337. END Imports;
  338. BEGIN
  339. addressType := IntermediateCode.UnsignedIntegerType(system.addressSize);
  340. r.RawString(name); module.SetModuleName(name);
  341. r.RawString(name); module.SetPlatformName(name);
  342. Imports(module.imports);
  343. SectionList(module.allSections);
  344. RETURN TRUE
  345. END ImportModuleBinary;
  346. PROCEDURE ImportModuleTextual(r: Streams.Reader; module: Sections.Module; system: Global.System): BOOLEAN;
  347. BEGIN
  348. RETURN Parser.ParseReader(r, diagnostics, module)
  349. END ImportModuleTextual;
  350. PROCEDURE Import*(CONST moduleName: ARRAY OF CHAR; system: Global.System): Sections.Module;
  351. VAR module: Sections.Module; file: Files.File; reader: Files.Reader; binary: BOOLEAN; filename: Files.FileName; poolMap: ObjectFile.PoolMap;
  352. BEGIN
  353. IF prefix # "" THEN Files.JoinPath(prefix, moduleName, filename); ELSE COPY (moduleName, filename); END;
  354. Files.JoinExtension(filename, extension, filename);
  355. file := Files.Old(filename);
  356. IF file = NIL THEN RETURN NIL END;
  357. NEW(reader, file, 0);
  358. ReadHeader(reader, binary, poolMap);
  359. NEW(module, NIL, system);
  360. IF binary & ImportModuleBinary(reader, module, system, poolMap) OR ~binary & ImportModuleTextual(reader, module, system) THEN
  361. RETURN module
  362. ELSE
  363. RETURN NIL
  364. END;
  365. END Import;
  366. PROCEDURE DefineOptions* (options: Options.Options);
  367. BEGIN
  368. options.Add(0X,"objectFileExtension",Options.String);
  369. options.Add(0X,"objectFilePrefix",Options.String);
  370. options.Add(0X,"textualObjectFile",Options.Flag);
  371. END DefineOptions;
  372. PROCEDURE GetOptions* (options: Options.Options);
  373. BEGIN
  374. IF ~options.GetString("objectFileExtension",extension) THEN extension := "Fil"; END;
  375. IF ~options.GetString("objectFilePrefix",prefix) THEN prefix := ""; END;
  376. textual := options.GetFlag("textualObjectFile");
  377. END GetOptions;
  378. PROCEDURE DefaultSymbolFileFormat*(): Formats.SymbolFileFormat;
  379. BEGIN RETURN SymbolFileFormat.Get();
  380. END DefaultSymbolFileFormat;
  381. PROCEDURE GetExtension*(VAR ext: ARRAY OF CHAR);
  382. BEGIN COPY(extension, ext)
  383. END GetExtension;
  384. PROCEDURE SetExtension*(CONST ext: ARRAY OF CHAR);
  385. BEGIN COPY(ext, extension)
  386. END SetExtension;
  387. END ObjectFileFormat;
  388. PROCEDURE Get*(): Formats.ObjectFileFormat;
  389. VAR intermediateObjectFileFormat: ObjectFileFormat;
  390. BEGIN NEW(intermediateObjectFileFormat); RETURN intermediateObjectFileFormat
  391. END Get;
  392. PROCEDURE ReadHeader(reader: Streams.Reader; VAR binary: BOOLEAN; VAR poolMap: ObjectFile.PoolMap);
  393. VAR ch: CHAR; version: LONGINT; string: ARRAY 32 OF CHAR; i,j,pos,size: LONGINT; name: ObjectFile.SectionName;
  394. BEGIN
  395. reader.String(string);
  396. binary := string="FoxILB";
  397. IF ~binary THEN ASSERT(string="FoxILT") END;
  398. reader.SkipWhitespace;
  399. reader.Char(ch); ASSERT(ch='v');
  400. reader.Int(version,FALSE);
  401. IF version < Version THEN KernelLog.String("warning: old object file encountered"); KernelLog.Ln END;
  402. reader.Char(ch); ASSERT(ch='.');
  403. IF ~binary THEN reader.SkipWhitespace
  404. ELSE
  405. NEW(poolMap, 64);
  406. poolMap.Read(reader);
  407. END;
  408. END ReadHeader;
  409. PROCEDURE WriteHeader(writer: Streams.Writer; binary: BOOLEAN; sections: Sections.SectionList; VAR poolMap: ObjectFile.PoolMap);
  410. VAR p1,p2, size,i: LONGINT; section: Sections.Section; fixups: LONGINT; fixupList: ObjectFile.Fixups;
  411. PROCEDURE ProcessOperand(CONST operand: IntermediateCode.Operand);
  412. BEGIN
  413. IF operand.symbol.name # "" THEN
  414. poolMap.PutSegmentedName(operand.symbol.name)
  415. END;
  416. END ProcessOperand;
  417. PROCEDURE ProcessInstruction(CONST instruction: IntermediateCode.Instruction);
  418. BEGIN
  419. ProcessOperand(instruction.op1);
  420. ProcessOperand(instruction.op2);
  421. ProcessOperand(instruction.op3);
  422. END ProcessInstruction;
  423. PROCEDURE ProcessSection(section: IntermediateCode.Section);
  424. VAR i: LONGINT; index: LONGINT;
  425. BEGIN
  426. IF section.resolved # NIL THEN
  427. poolMap.PutSegmentedName(section.name);
  428. FOR i := 0 TO section.pc-1 DO
  429. ProcessInstruction(section.instructions[i]);
  430. END;
  431. END;
  432. END ProcessSection;
  433. BEGIN
  434. IF binary THEN writer.String("FoxILB");
  435. ELSE writer.String("FoxILT");
  436. END;
  437. writer.Char(' ');
  438. writer.Char('v'); writer.Int(Version,0); writer.Char(".");
  439. IF ~binary THEN writer.Ln
  440. ELSE
  441. NEW(poolMap,512);
  442. poolMap.BeginWriting(writer);
  443. FOR i := 0 TO sections.Length()-1 DO
  444. section := sections.GetSection(i);
  445. ProcessSection(section(IntermediateCode.Section));
  446. END;
  447. poolMap.EndWriting;
  448. END;
  449. END WriteHeader;
  450. (* test code to display --not public *)
  451. PROCEDURE Show*(context: Commands.Context);
  452. VAR
  453. fileName: Files.FileName; file: Files.File; reader: Files.Reader; writer: Streams.Writer;
  454. section: ObjectFile.Section; binary: BOOLEAN; poolMap, poolMapDummy: ObjectFile.PoolMap;
  455. objectFile: ObjectFileFormat; module: Sections.Module; backend: Backend.Backend;
  456. extension: Files.FileName;
  457. BEGIN
  458. IF DeveloperVersion THEN
  459. IF context.arg.GetString(fileName) THEN
  460. backend := Backend.GetBackendByName("TRM");
  461. Files.SplitExtension(fileName, fileName, extension);
  462. NEW(objectFile);
  463. IF extension # "" THEN objectFile.SetExtension(extension) END;
  464. module := objectFile.Import(fileName, backend.GetSystem());
  465. writer := Basic.GetWriter(Basic.GetDebugWriter(fileName));
  466. objectFile.ExportModuleTextual(module, writer);
  467. writer.Update;
  468. ELSE
  469. context.error.String("no file specificed"); context.error.Ln
  470. END;
  471. ELSE HALT(200)
  472. END;
  473. END Show;
  474. END FoxIntermediateObjectFile.
  475. SystemTools.FreeDownTo FoxIntermediateObjectFile ~
  476. FoxIntermediateObjectFile.Show Builtins ~
  477. (* test code to compare ..
  478. backend: Backend.Backend;
  479. IF prefix # "" THEN Files.JoinPath(prefix, module.moduleName, filename); ELSE COPY (module.moduleName, filename); END;
  480. Files.JoinExtension(filename, "fil2", filename);
  481. file := Files.New(filename);
  482. backend := Backend.GetBackendByName("TRM");
  483. Files.OpenWriter(writer, file, 0);
  484. module := Import(module.moduleName, backend.GetSystem());
  485. ExportModuleTextual(module(Sections.Module), writer);
  486. writer.Update;
  487. Files.Register(file);
  488. *)