/// <summary> /// This method compiles the passed Z80 Assembly code into Z80 /// binary code. /// </summary> /// <param name="sourceItem"></param> /// <param name="sourceText">Source code text</param> /// <param name="options"> /// Compilation options. If null is passed, the compiler uses the /// default options /// </param> /// <exception cref="ArgumentNullException"></exception> /// <returns> /// Output of the compilation /// </returns> private AssemblerOutput DoCompile(SourceFileItem sourceItem, string sourceText, AssemblerOptions options = null) { // --- Init the compilation process if (sourceText == null) { throw new ArgumentNullException(nameof(sourceText)); } _options = options ?? new AssemblerOptions(); ConditionSymbols = new HashSet <string>(_options.PredefinedSymbols); CurrentModule = Output = new AssemblerOutput(sourceItem); CompareBins = new List <BinaryComparisonInfo>(); // --- Do the compilation phases if (!ExecuteParse(0, sourceItem, sourceText, out var lines) || !EmitCode(lines) || !FixupSymbols() || !CompareBinaries()) { // --- Compilation failed, remove segments Output.Segments.Clear(); } PreprocessedLines = lines; // --- Create symbol map Output.CreateSymbolMap(); return(Output); }
/// <summary> /// This method compiles the passed Z80 Assembly code into Z80 /// binary code. /// </summary> /// <param name="sourceItem"></param> /// <param name="sourceText">Source code text</param> /// <param name="options"> /// Compilation options. If null is passed, the compiler uses the /// default options /// </param> /// <exception cref="ArgumentNullException"></exception> /// <returns> /// Output of the compilation /// </returns> private AssemblerOutput DoCompile(SourceFileItem sourceItem, string sourceText, AssemblerOptions options = null) { // --- Init the compilation process if (sourceText == null) { throw new ArgumentNullException(nameof(sourceText)); } _options = options ?? new AssemblerOptions(); ConditionSymbols = new HashSet <string>(_options.PredefinedSymbols); _output = new AssemblerOutput(sourceItem); // --- Do the compilation phases if (!ExecuteParse(0, sourceItem, sourceText, out var lines) || !EmitCode(lines) || !FixupSymbols()) { // --- Compilation failed, remove segments _output.Segments.Clear(); } PreprocessedLines = lines; return(_output); }
/// <summary> /// Parses the source code passed to the compiler /// </summary> /// <param name="fileIndex">Source file index</param> /// <param name="sourceItem">Source file item</param> /// <param name="sourceText">Source text to parse</param> /// <param name="parsedLines"></param> /// <returns>True, if parsing was successful</returns> private bool ExecuteParse(int fileIndex, SourceFileItem sourceItem, string sourceText, out List <SourceLineBase> parsedLines) { // --- No lines has been parsed yet parsedLines = new List <SourceLineBase>(); // --- Parse all source code lines var inputStream = new AntlrInputStream(sourceText); var lexer = new Z80AsmLexer(inputStream); var tokenStream = new CommonTokenStream(lexer); var parser = new Z80AsmParser(tokenStream); var context = parser.compileUnit(); var visitor = new Z80AsmVisitor(inputStream); visitor.Visit(context); var visitedLines = visitor.Compilation; // --- Store any tasks defined by the user StoreTasks(sourceItem, visitedLines.Lines); // --- Collect syntax errors foreach (var error in parser.SyntaxErrors) { ReportError(sourceItem, error); } // --- Exit if there are any errors if (Output.ErrorCount != 0) { return(false); } // --- Now, process directives and the .model pragma var currentLineIndex = 0; var ifdefStack = new Stack <bool?>(); var processOps = true; parsedLines = new List <SourceLineBase>(); var anyProcessed = false; // --- Traverse through parsed lines while (currentLineIndex < visitedLines.Lines.Count) { var line = visitedLines.Lines[currentLineIndex]; switch (line) { case ZxBasicPragma _: { if (anyProcessed) { ReportError(Errors.Z0450, line); break; } _options.UseCaseSensitiveSymbols = true; _options.ProcExplicitLocalsOnly = true; _options.FlexibleDefPragmas = true; CurrentModule = Output = new AssemblerOutput(sourceItem, true); Output.SourceType = "zxbasic"; anyProcessed = true; break; } case ModelPragma modelPragma: ProcessModelPragma(modelPragma); anyProcessed = true; break; case IncludeDirective incDirective: { // --- Parse the included file if (ApplyIncludeDirective(incDirective, sourceItem, out var includedLines)) { // --- Add the parse result of the include file to the result parsedLines.AddRange(includedLines); anyProcessed = true; } break; } case LineDirective lineDirective: // TODO: Process a #line directive break; case Directive preProc: ApplyDirective(preProc, ifdefStack, ref processOps); anyProcessed = true; break; default: { if (processOps) { line.FileIndex = fileIndex; line.MacroSourceText = sourceText.Substring(line.FirstPosition, line.LastPosition - line.FirstPosition + 1); parsedLines.Add(line); anyProcessed = true; } break; } } currentLineIndex++; } // --- Check if all #if and #ifdef has a closing #endif tag if (ifdefStack.Count > 0 && visitedLines.Lines.Count > 0) { ReportError(Errors.Z0062, visitedLines.Lines.Last()); } return(Output.ErrorCount == 0); }