Пример #1
0
        /// <summary>
        /// Translates a Z80AsmParserErrorInfo instance into an error
        /// </summary>
        /// <param name="sourceItem">
        /// Source file information, to allow the error to track the filename the error occurred in
        /// </param>
        /// <param name="error">Error information</param>
        private void ReportError(SourceFileItem sourceItem, Z80AsmParserErrorInfo error)
        {
            var errInfo = new AssemblerErrorInfo(sourceItem, error);

            Output.Errors.Add(errInfo);
            ReportScopeError(errInfo.ErrorCode);
        }
Пример #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);
            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);
        }
Пример #3
0
 public AssemblerErrorInfo(SourceFileItem sourceItem, string errorCode, SourceLineBase line, params object[] parameters)
 {
     ErrorCode = errorCode;
     Line      = line?.SourceLine ?? 0;
     Column    = line?.FirstColumn ?? 0;
     Message   = Errors.GetMessage(ErrorCode, parameters);
     Filename  = sourceItem?.Filename;
 }
Пример #4
0
 /// <summary>
 /// Retrieves task-related comments from the parsed lines.
 /// </summary>
 /// <param name="sourceItem">The file that has been parsed</param>
 /// <param name="lines">Parsed lines</param>
 private void StoreTasks(SourceFileItem sourceItem, IEnumerable <SourceLineBase> lines)
 {
     foreach (var line in lines)
     {
         if (line.DefinesTask)
         {
             _output.Tasks.Add(new AssemblerTaskInfo(line.TaskDescription,
                                                     sourceItem.Filename, line.SourceLine));
         }
     }
 }
Пример #5
0
        public AssemblerErrorInfo(SourceFileItem sourceItem, Z80AsmParserErrorInfo syntaxErrorInfo)
        {
            var token = syntaxErrorInfo.Token.Trim();

            ErrorCode = token.Length == 0
                ? Errors.Z0101
                : Errors.Z0100;
            Line     = syntaxErrorInfo.SourceLine;
            Column   = syntaxErrorInfo.Position;
            Message  = Errors.GetMessage(ErrorCode, token);
            Filename = sourceItem.Filename;
        }
Пример #6
0
        /// <summary>
        /// Adds the specified item to the "Includes" list
        /// </summary>
        /// <param name="childItem">Included source file item</param>
        /// <returns>
        /// True, if including the child item is OK;
        /// False, if the inclusion would create a circular reference,
        /// or the child is already is in the list
        /// </returns>
        public bool Include(SourceFileItem childItem)
        {
            var current = this;

            while (current != null)
            {
                if (string.Compare(current.Filename, childItem.Filename, StringComparison.OrdinalIgnoreCase) == 0)
                {
                    return(false);
                }
                current = current.Parent;
            }
            if (ContainsInIncludeList(childItem))
            {
                return(false);
            }
            Includes.Add(childItem);
            childItem.Parent = this;
            return(true);
        }
Пример #7
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);
        }
Пример #8
0
 /// <summary>
 /// Translates a Z80AsmParserErrorInfo instance into an error
 /// </summary>
 /// <param name="sourceItem">
 /// Source file information, to allow the error to track the filename the error ocurred in
 /// </param>
 /// <param name="error">Error information</param>
 private void ReportError(SourceFileItem sourceItem, Z80AsmParserErrorInfo error)
 {
     _output.Errors.Add(new AssemblerErrorInfo(sourceItem, error));
 }
Пример #9
0
        /// <summary>
        /// Loads and parses the file according the the #include directive
        /// </summary>
        /// <param name="fileIndex">Include file index</param>
        /// <param name="incDirective">Directive with the file</param>
        /// <param name="sourceItem">Source file item</param>
        /// <param name="parsedLines">Collection of source code lines</param>
        private bool ApplyIncludeDirective(int fileIndex, IncludeDirective incDirective,
                                           SourceFileItem sourceItem,
                                           out List <SourceLineBase> parsedLines)
        {
            parsedLines = new List <SourceLineBase>();

            // --- Check the #include directive
            var filename = incDirective.Filename.Trim();

            if (filename.StartsWith("<") && filename.EndsWith(">"))
            {
                // TODO: System include file
                filename = filename.Substring(1, filename.Length - 2);
            }

            // --- Now, we have the file name, calculate the path
            if (sourceItem.Filename != NOFILE_ITEM)
            {
                // --- The file name is taken into account as relative
                var dirname = Path.GetDirectoryName(sourceItem.Filename) ?? string.Empty;
                filename = Path.Combine(dirname, filename);
            }

            // --- Check for file existence
            if (!File.Exists(filename))
            {
                ReportError(Errors.Z0300, incDirective, filename);
                return(false);
            }

            var fi       = new FileInfo(filename);
            var fullName = fi.FullName;

            // --- Check for repetition
            var childItem = new SourceFileItem(fullName);

            if (sourceItem.ContainsInIncludeList(childItem))
            {
                ReportError(Errors.Z0302, incDirective, filename);
                return(false);
            }

            // --- Check for circular reference
            if (!sourceItem.Include(childItem))
            {
                ReportError(Errors.Z0303, incDirective, filename);
                return(false);
            }

            // --- Now, add the included item to the output
            _output.SourceFileList.Add(childItem);

            // --- Read the include file
            string sourceText;

            try
            {
                sourceText = File.ReadAllText(filename);
            }
            catch (Exception ex)
            {
                ReportError(Errors.Z0301, incDirective, filename, ex.Message);
                return(false);
            }

            // --- Parse the file
            return(ExecuteParse(fileIndex, childItem, sourceText, out parsedLines));
        }
Пример #10
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 codelines
            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();

            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>();

            // --- Traverse through parsed lines
            var includeIndex = fileIndex;

            while (currentLineIndex < visitedLines.Lines.Count)
            {
                var line = visitedLines.Lines[currentLineIndex];
                if (line is ModelPragma modelPragma)
                {
                    ProcessModelPragma(modelPragma);
                }
                else if (line is IncludeDirective incDirective)
                {
                    includeIndex++;
                    // --- Parse the included file
                    if (ApplyIncludeDirective(includeIndex, incDirective, sourceItem,
                                              out var includedLines))
                    {
                        // --- Add the parse result of the include file to the result
                        parsedLines.AddRange(includedLines);
                    }
                }
                else if (line is Directive preProc)
                {
                    ApplyDirective(preProc, ifdefStack, ref processOps);
                }
                else if (processOps)
                {
                    line.FileIndex = fileIndex;
                    parsedLines.Add(line);
                }
                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);
        }
Пример #11
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);
        }
Пример #12
0
 /// <summary>
 /// Checks if this item already contains the specified child item in
 /// its "Includes" list
 /// </summary>
 /// <param name="childItem">Child item to check</param>
 /// <returns>
 /// True, if this item contains the child item;
 /// otherwise, false
 /// </returns>
 public bool ContainsInIncludeList(SourceFileItem childItem) =>
 Includes.Any(c => string.Compare(c.Filename, childItem.Filename,
                                  StringComparison.OrdinalIgnoreCase) == 0);