1 using System;
2 using System.IO;
3 using System.Collections;
4 using Span = System.Lex.Span;
5
6 namespace cmsx.assembly
7 {
8 public const int IS = 256;
9 public const int EXTERN = 257;
10 public const int LINKONCE = 258;
11 public const int FUNC = 259;
12 public const int ENDF = 260;
13 public const int STRUCT = 261;
14 public const int ENDS = 262;
15 public const int BYTE = 263;
16 public const int WYDE = 264;
17 public const int TETRA = 265;
18 public const int OCTA = 266;
19 public const int CODE = 267;
20 public const int DATA = 268;
21 public const int DEBUG = 269;
22 public const int LDA = 270;
23 public const int SET = 271;
24 public const int BSPEC = 272;
25 public const int ESPEC = 273;
26 public const int numInsts = ESPEC + 1;
27
28 public const ulong FILEINFO = 0u;
29 public const ulong FUNCINFO = 1u;
30 public const ulong LINEINFO = 2u;
31 public const ulong BEGINTRY = 3u;
32 public const ulong ENDTRY = 4u;
33 public const ulong CATCH = 5u;
34 public const ulong BEGINCLEANUP = 6u;
35 public const ulong ENDCLEANUP = 7u;
36
37 public class PseudoOpMap
38 {
39 static PseudoOpMap() : instance(new PseudoOpMap())
40 {
41 }
42 public static nothrow PseudoOpMap& Instance()
43 {
44 return *instance;
45 }
46 private PseudoOpMap()
47 {
48 codes["IS"] = IS;
49 codes["EXTERN"] = EXTERN;
50 codes["LINKONCE"] = LINKONCE;
51 codes["FUNC"] = FUNC;
52 codes["ENDF"] = ENDF;
53 codes["STRUCT"] = STRUCT;
54 codes["ENDS"] = ENDS;
55 codes["BYTE"] = BYTE;
56 codes["WYDE"] = WYDE;
57 codes["TETRA"] = TETRA;
58 codes["OCTA"] = OCTA;
59 codes[".CODE"] = CODE;
60 codes[".DATA"] = DATA;
61 codes[".DEBUG"] = DEBUG;
62 codes["LDA"] = LDA;
63 codes["SET"] = SET;
64 codes["BSPEC"] = BSPEC;
65 codes["ESPEC"] = ESPEC;
66 names[IS] = "IS";
67 names[EXTERN] = "EXTERN";
68 names[LINKONCE] = "LINKONCE";
69 names[FUNC] = "FUNC";
70 names[ENDF] = "ENDF";
71 names[STRUCT] = "STRUCT";
72 names[ENDS] = "ENDS";
73 names[BYTE] = "BYTE";
74 names[WYDE] = "WYDE";
75 names[TETRA] = "TETRA";
76 names[OCTA] = "OCTA";
77 names[CODE] = ".CODE";
78 names[DATA] = ".DATA";
79 names[DEBUG] = ".DEBUG";
80 names[LDA] = "LDA";
81 names[SET] = "SET";
82 names[BSPEC] = "BSPEC";
83 names[ESPEC] = "ESPEC";
84 for (const Pair<int, string>& codeName : names)
85 {
86 if (codeName.second.Length() > maxOpCodeNameLength)
87 {
88 maxOpCodeNameLength = cast<int>(codeName.second.Length());
89 }
90 }
91 }
92 public nothrow int GetCode(const string& name) const
93 {
94 HashMap<string, int>.ConstIterator it = codes.CFind(name);
95 if (it != codes.CEnd())
96 {
97 return it->second;
98 }
99 return -1;
100 }
101 public string GetName(int code) const
102 {
103 HashMap<int, string>.ConstIterator it = names.CFind(code);
104 if (it != names.CEnd())
105 {
106 return it->second;
107 }
108 else
109 {
110 throw Exception("name for code '" + ToString(code) + "' not found");
111 }
112 }
113 public int MaxOpCodeNameLength() const
114 {
115 return maxOpCodeNameLength;
116 }
117 private static UniquePtr<PseudoOpMap> instance;
118 private HashMap<string, int> codes;
119 private HashMap<int, string> names;
120 private int maxOpCodeNameLength;
121 }
122
123 public string GetOpCodeStr(int opCode)
124 {
125 if (opCode < 256)
126 {
127 return cmsx.machine.GetOpCodeName(cast<byte>(opCode));
128 }
129 else
130 {
131 return PseudoOpMap.Instance().GetName(opCode);
132 }
133 }
134
135 public abstract class Node
136 {
137 public nothrow Node(const Span& span_) : span(span_)
138 {
139 }
140 public virtual default ~Node();
141 public abstract void Accept(Visitor& visitor);
142 public Span span;
143 }
144
145 public abstract class Constant : Node
146 {
147 public nothrow Constant(const Span& span_) : base(span_)
148 {
149 }
150 }
151
152 public abstract class IntegralConstant : Constant
153 {
154 public nothrow IntegralConstant(const Span& span_, ulong value_) : base(span_), value(value_)
155 {
156 }
157 public ulong value;
158 }
159
160 public class DecimalConstant : IntegralConstant
161 {
162 public nothrow DecimalConstant(const Span& span_, ulong value_) : base(span_, value_)
163 {
164 }
165 public override void Accept(Visitor& visitor)
166 {
167 visitor.Visit(*this);
168 }
169 }
170
171 public class HexConstant : IntegralConstant
172 {
173 public nothrow HexConstant(const Span& span_, ulong value_) : base(span_, value_)
174 {
175 }
176 public override void Accept(Visitor& visitor)
177 {
178 visitor.Visit(*this);
179 }
180 }
181
182 public HexConstant* MakeHexConstant(const Span& span, const System.Lex.Token& token)
183 {
184 uchar* p = token.match.begin;
185 uchar* e = token.match.end;
186 if (p != e && *p == '#')
187 {
188 ++p;
189 }
190 string s = ToUtf8(ustring(p, e));
191 return new HexConstant(span, ParseHexULong(s));
192 }
193
194 public class CharacterConstant : Constant
195 {
196 public nothrow CharacterConstant(const Span& span_, uchar value_) : base(span_), value(value_)
197 {
198 }
199 public override void Accept(Visitor& visitor)
200 {
201 visitor.Visit(*this);
202 }
203 public uchar value;
204 }
205
206 public CharacterConstant* MakeCharConstant(const Span& span, const System.Lex.Token& token)
207 {
208 uchar* p = token.match.begin;
209 uchar* e = token.match.end;
210 if (p != e && *p == '\'')
211 {
212 ++p;
213 }
214 return new CharacterConstant(span, *p);
215 }
216
217 public class StringConstant : Constant
218 {
219 public nothrow StringConstant(const Span& span_, const ustring& value_) : base(span_), value(value_)
220 {
221 }
222 public override void Accept(Visitor& visitor)
223 {
224 visitor.Visit(*this);
225 }
226 public ustring value;
227 }
228
229 public StringConstant* MakeStringConstant(const Span& span, const System.Lex.Token& token)
230 {
231 uchar* p = token.match.begin;
232 uchar* e = token.match.end;
233 if (p != e && *p == '"')
234 {
235 ++p;
236 }
237 uchar* start = p;
238 uchar* end = p;
239 while (p != e && *p != '"')
240 {
241 ++p;
242 end = p;
243 }
244 if (p != e && *p == '"')
245 {
246 ++p;
247 }
248 if (p != e)
249 {
250 Error("invalid string constant", span);
251 }
252 return new StringConstant(span, ustring(start, end));
253 }
254
255 public class ClsIdConstant : Constant
256 {
257 public nothrow ClsIdConstant(const Span& span_, const string& typeId_) : base(span_), typeId(typeId_)
258 {
259 }
260 public override void Accept(Visitor& visitor)
261 {
262 visitor.Visit(*this);
263 }
264 public string typeId;
265 }
266
267 public ClsIdConstant* MakeClsIdConstant(const Span& span, const System.Lex.Token& token)
268 {
269 uchar* p = token.match.begin;
270 uchar* e = token.match.end;
271 uchar* start = p;
272 uchar* end = p;
273 if (p != e && *p == '$')
274 {
275 ++p;
276 if (p != e && *p == 'C')
277 {
278 ++p;
279 if (p != e && *p == 'L')
280 {
281 ++p;
282 if (p != e && *p == 'S')
283 {
284 ++p;
285 if (p != e && *p == 'I')
286 {
287 ++p;
288 if (p != e && *p == 'D')
289 {
290 ++p;
291 if (p != e && *p == '(')
292 {
293 ++p;
294 start = p;
295 while (p != e && *p != ')')
296 {
297 ++p;
298 end = p;
299 }
300 }
301 }
302 }
303 }
304 }
305 }
306 }
307 ustring s(start, end);
308 if (s.IsEmpty())
309 {
310 Error("invalid class identifier constant", span);
311 }
312 for (uchar c : s)
313 {
314 if (!IsAsciiHexDigit(c))
315 {
316 Error("invalid class identifier constant", span);
317 }
318 }
319 return new ClsIdConstant(span, ToUtf8(s));
320 }
321
322 public class SymbolNode : Node
323 {
324 public nothrow SymbolNode(const Span& span_, const string& name_, bool local_) : base(span_), name(name_), local(local_)
325 {
326 }
327 public override void Accept(Visitor& visitor)
328 {
329 visitor.Visit(*this);
330 }
331 public string name;
332 public bool local;
333 }
334
335 public SymbolNode* MakeLocalSymbolNode(const Span& span, const System.Lex.Token& token)
336 {
337 return new SymbolNode(span, ToUtf8(token.match.ToString()), true);
338 }
339
340 public SymbolNode* MakeSymbolNode(const Span& span, const System.Lex.Token& token)
341 {
342 return new SymbolNode(span, ToUtf8(token.match.ToString()), false);
343 }
344
345 public enum Direction
346 {
347 forward, backward
348 }
349
350 public class At : Node
351 {
352 public nothrow At(const Span& span_) : base(span_)
353 {
354 }
355 public override void Accept(Visitor& visitor)
356 {
357 visitor.Visit(*this);
358 }
359 }
360
361 public enum Operator : byte
362 {
363 unaryPlus, unaryMinus, complement, register, serial,
364 multiply, divide, fractionalDivide, modulus, shiftLeft, shiftRight, bitwiseAnd,
365 add, subtract, bitwiseOr, bitwiseXor
366 }
367
368 public class UnaryExpression : Node
369 {
370 public nothrow UnaryExpression(const Span& span_, Operator op_, Node* subject_) : base(span_), op(op_), subject(subject_)
371 {
372 }
373 public override void Accept(Visitor& visitor)
374 {
375 visitor.Visit(*this);
376 }
377 public Operator op;
378 public UniquePtr<Node> subject;
379 }
380
381 public class BinaryExpression : Node
382 {
383 public nothrow BinaryExpression(const Span& span_, Node* left_, Operator op_, Node* right_) : base(span_), left(left_), op(op_), right(right_)
384 {
385 }
386 public override void Accept(Visitor& visitor)
387 {
388 visitor.Visit(*this);
389 }
390 public Operator op;
391 public UniquePtr<Node> left;
392 public UniquePtr<Node> right;
393 }
394
395 public class ParenthesizedExpression : Node
396 {
397 public nothrow ParenthesizedExpression(const Span& span_, Node* subject_) : base(span_), subject(subject_)
398 {
399 }
400 public override void Accept(Visitor& visitor)
401 {
402 visitor.Visit(*this);
403 }
404 public UniquePtr<Node> subject;
405 }
406
407 public class OpCode : Node
408 {
409 public nothrow OpCode(const Span& span_, const string& name_) : base(span_), name(name_), value(-1)
410 {
411 }
412 public override void Accept(Visitor& visitor)
413 {
414 visitor.Visit(*this);
415 }
416 public string name;
417 public int value;
418 }
419
420 public nothrow OpCode* MakeOpCode(const Span& span, const ustring& name)
421 {
422 return new OpCode(span, ToUtf8(name));
423 }
424
425 public class OperandList : Node
426 {
427 public nothrow OperandList(const Span& span_, Node* firstOperand_) : base(span_)
428 {
429 operands.Add(UniquePtr<Node>(firstOperand_));
430 }
431 suppress OperandList(const OperandList&);
432 suppress void operator=(const OperandList&);
433 suppress OperandList(OperandList&&);
434 suppress void operator=(OperandList&&);
435 public void AddOperand(Node* operand)
436 {
437 operands.Add(UniquePtr<Node>(operand));
438 }
439 public override void Accept(Visitor& visitor)
440 {
441 visitor.Visit(*this);
442 }
443 public List<UniquePtr<Node>> operands;
444 }
445
446 public class Instruction : Node
447 {
448 public nothrow Instruction(const Span& span_, Node* label_, OpCode* opCode_, OperandList* operandList_) : base(span_), label(label_), opCode(opCode_), operandList(operandList_)
449 {
450 }
451 suppress Instruction(const Instruction&);
452 suppress void operator=(const Instruction&);
453 suppress Instruction(Instruction&&);
454 suppress void operator=(Instruction&&);
455 public override void Accept(Visitor& visitor)
456 {
457 visitor.Visit(*this);
458 }
459 public UniquePtr<Node> label;
460 public UniquePtr<OpCode> opCode;
461 public UniquePtr<OperandList> operandList;
462 }
463
464 Instruction* MakeModeInst(const Span& span, const System.Lex.Token& token)
465 {
466 ustring mode = ToLower(token.match.ToString());
467 if (mode == u"code")
468 {
469 return new Instruction(span, null, new OpCode(span, ".CODE"), null);
470 }
471 else if (mode == u"data")
472 {
473 return new Instruction(span, null, new OpCode(span, ".DATA"), null);
474 }
475 else if (mode == u"debug")
476 {
477 return new Instruction(span, null, new OpCode(span, ".DEBUG"), null);
478 }
479 else
480 {
481 return null;
482 }
483 }
484
485 public void ProcessAssemblyFile(int index, const string& assemblyFilePath, bool verbose, const string& outdir)
486 {
487 if (verbose)
488 {
489 Console.Out() << "> " << assemblyFilePath << endl();
490 }
491 List<UniquePtr<Instruction>> instructions;
492 AssemblyLexer lexer(ToUtf32(File.ReadAllText(assemblyFilePath)), assemblyFilePath, index);
493 ScopedAssemblyLexerPtr lexerPtr(&lexer);
494 AssemblyParser.Parse(lexer, &instructions);
495 string objectFilePath = Path.ChangeExtension(assemblyFilePath, ".o");
496 if (!outdir.IsEmpty())
497 {
498 objectFilePath = Path.Combine(outdir, Path.GetFileNameWithoutExtension(assemblyFilePath) + ".o");
499 }
500 Assembler assembler(objectFilePath);
501 assembler.Assemble(instructions);
502 cmsx.object.LinkInternal(assembler.objectFile);
503 assembler.objectFile.Finalize();
504 if (verbose)
505 {
506 Console.Out() << "==> " << objectFilePath << endl();
507 }
508 assembler.WriteObjectFile();
509 }
510 }