FoxIntermediateObjectFile.Mod 18 KB

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