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<intstring>& 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<stringint>.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<intstring>.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<stringint> codes;
119         private HashMap<intstring> 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& spanconst 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(pe));
191         return new HexConstant(spanParseHexULong(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& spanconst 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& spanconst 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(spanustring(startend));
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& spanconst 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(startend);
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(spanToUtf8(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& spanconst System.Lex.Token& token)
336     {
337         return new SymbolNode(spanToUtf8(token.match.ToString())true);
338     }
339 
340     public SymbolNode* MakeSymbolNode(const Span& spanconst System.Lex.Token& token)
341     {
342         return new SymbolNode(spanToUtf8(token.match.ToString())false);
343     }
344 
345     public enum Direction
346     {
347         forwardbackward
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         unaryPlusunaryMinuscomplementregisterserial
364         multiplydividefractionalDividemodulusshiftLeftshiftRightbitwiseAnd
365         addsubtractbitwiseOrbitwiseXor
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& spanconst ustring& name)
421     {
422         return new OpCode(spanToUtf8(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& spanconst System.Lex.Token& token)
465     {
466         ustring mode = ToLower(token.match.ToString());
467         if (mode == u"code")
468         {
469             return new Instruction(spannullnew OpCode(span".CODE")null);
470         }
471         else if (mode == u"data")
472         {
473             return new Instruction(spannullnew OpCode(span".DATA")null);
474         }
475         else if (mode == u"debug")
476         {
477             return new Instruction(spannullnew OpCode(span".DEBUG")null);
478         }
479         else
480         {
481             return null;
482         }
483     }
484 
485     public void ProcessAssemblyFile(int indexconst string& assemblyFilePathbool verboseconst 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))assemblyFilePathindex);
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(outdirPath.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 }