static void Main(string[] args) { /* * Set up options for the assembler. */ var opt = new AssemblerOptions() { LanguageOptions = DasmGrammar.Options.Extended, }; var showHelp = false; var os = new OptionSet() { {"t|target=", "target {PATH} for output", a => opt.TargetPath = a}, {"f|format=", "target {FORMAT}; one of: " + AssemblerOptions.FormatNames, a => opt.TargetFormatFrom(a)}, {"std", "stick to standard language", a => opt.LanguageOptions = DasmGrammar.Options.Standard}, {"s|symbols", "output symbol list to TARGET.lst", a => opt.DumpSymbols = (a != null)}, {"help", "show this message and exit", a => showHelp = a != null}, }; var files = new List<string>(); try { files = os.Parse(args); } catch (OptionException e) { Console.Error.WriteLine(e.Message); } if (files.Count == 0 || showHelp) { ShowHelp(os); return; } if (opt.TargetPath == null) { opt.TargetPath = System.IO.Path.ChangeExtension(files[0], "dcpu"); } opt.SourceFilePaths.AddRange(files); /* * Do the assemble thing. */ var asm = new Assembler(); try { asm.Assemble(opt); } catch (Codegen.CodegenException e) { Console.Error.WriteLine(e.Message); } }
/// <summary> /// Performs assembly based on the given options object. /// </summary> public void Assemble(AssemblerOptions options) { if (options.SourceFilePaths.Count == 0) throw new ArgumentOutOfRangeException("No source files specified."); if (options.SourceFilePaths.Count > 1) throw new ArgumentOutOfRangeException("Can only assemble one source file right now."); /* * Parse the source file. */ var sourceFilePath = options.SourceFilePaths[0]; ParseTreeNode rootNode = null; { var src = ReadFile(sourceFilePath); var g = new DasmGrammar(options.LanguageOptions); var ld = new LanguageData(g); var p = new Parser(ld); var pt = p.Parse(src, sourceFilePath); // Emit error messages. if (pt.ParserMessages.Count > 0) { foreach (var msg in pt.ParserMessages) Error(sourceFilePath, msg.Location, msg.Message); throw new CodegenException("Compilation failed."); } rootNode = pt.Root; } /* * Do codegen. */ DasmCodegen.CgResult cgr; { var cg = new DasmCodegen(); cgr = cg.CgProgram(rootNode); } /* * Write the output file. */ using (var target = OpenFile(options.TargetPath, FileMode.Create)) { switch (options.TargetFormat) { case ImageFormat.Binary: foreach (var word in cgr.Image) { target.WriteByte((byte)(word & 0xFF)); target.WriteByte((byte)(word >> 8)); } break; case ImageFormat.Hexadecimal: { const int HexWidth = 8; using (var tw = new StreamWriter(target)) { for (var i = 0; i < cgr.Image.Length; ++i) { tw.Write(string.Format("{0:x4}", cgr.Image[i])); tw.Write(i % HexWidth == (HexWidth - 1) ? tw.NewLine : " "); } tw.WriteLine(); } } break; case ImageFormat.HexWithAddress: { const int HexWidth = 8; using (var tw = new StreamWriter(target)) { for (var i = 0; i < cgr.Image.Length; ++i) { if (i % HexWidth == 0) tw.Write(string.Format("{0:x4} ", i)); tw.Write(string.Format("{0:x4}", cgr.Image[i])); tw.Write(i % HexWidth == (HexWidth - 1) ? tw.NewLine : " "); } tw.WriteLine(); } } break; case ImageFormat.AssemblyHex: { const int HexWidth = 8; using (var tw = new StreamWriter(target)) { for (var i = 0; i < cgr.Image.Length; ++i) { if (i % HexWidth == 0) tw.Write("dat "); tw.Write(string.Format("0x{0:x4}", cgr.Image[i])); tw.Write( (i % HexWidth == (HexWidth - 1)) || (i + 1 == cgr.Image.Length) ? tw.NewLine : ", "); } tw.WriteLine(); } } break; default: throw new InvalidOperationException(); } } /* * Generate symbol map. */ if (options.DumpSymbols) { using (var f = OpenFile( Path.ChangeExtension(options.TargetPath, "sym"), FileMode.Create)) { { using (var tw = new StreamWriter(f)) { foreach (var label in cgr.Labels) tw.WriteLine("{0:X4} {1} {2}", label.Value, label.Type.ToShorthand(), label.Name); } } } } }