Пример #1
0
        /// <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);
        }
Пример #2
0
        /// <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);
        }
Пример #3
0
        /// <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);
        }