Exemple #1
0
        void DoGoto(SourceLine line)
        {
            if (!line.OperandHasToken)
            {
                Assembler.Log.LogEntry(line, line.Instruction, "Destination not specified for \".goto\" directive.");
                return;
            }
            var gotoExp = line.OperandExpression;

            if (gotoExp.Equals(line.LabelName))
            {
                Assembler.Log.LogEntry(line, line.Instruction, "Destination cannot be the same line as \".goto\" directive.");
                return;
            }

            var iterCopy = new RandomAccessIterator <SourceLine>(Assembler.LineIterator);

            iterCopy.Reset();

            SourceLine currLine;

            while ((currLine = iterCopy.Skip(l => !l.LabelName.Equals(gotoExp))) != null)
            {
                if (currLine.InstructionName.Contains("=") ||
                    currLine.InstructionName.Equals(".equ") ||
                    currLine.Instruction.Equals(".let"))
                {
                    Assembler.Log.LogEntry(line, line.Instruction, $"\"{gotoExp}\" is not a valid destination.");
                    return;
                }
                if (iterCopy.Index >= Assembler.LineIterator.Index)
                {
                    Assembler.LineIterator.FastForward(iterCopy.Index);
                }
                else
                {
                    if (iterCopy.Index == 0)
                    {
                        Assembler.LineIterator.Reset();
                    }
                    else
                    {
                        Assembler.LineIterator.Rewind(iterCopy.Index);
                    }
                }
                return;
            }
            Assembler.Log.LogEntry(line, line.Instruction,
                                   $"Could not find destination \"{gotoExp}\".");
        }
Exemple #2
0
        /// <summary>
        /// Parses the source string into a tokenized <see cref="SourceLine"/> collection.
        /// </summary>
        /// <param name="fileName">The source file's path/name.</param>
        /// <param name="source">The source string.</param>
        /// <returns>A collection of <see cref="SourceLine"/>s whose components are
        /// properly tokenized for further evaluation and assembly.</returns>
        /// <exception cref="ExpressionException"/>
        public static IEnumerable <SourceLine> Parse(string fileName, string source)
        {
            var   iterator = new RandomAccessIterator <char>(source.ToCharArray());
            Token rootParent, currentParent;
            Token token = null;

            Reset();

            Token currentOpen = null;
            int   currentLine = 1, lineNumber = currentLine;

            // lineIndex is the iterator index at the start of each line for purposes of calculating token
            // positions. sourceLindeIndex is the iterator index at the start of each new line
            // of source. Usually lineIndex and sourceLindeIndex are the same, but for those source lines
            // whose source code span multiple lines, they will be different.
            int lineIndex = -1, opens = 0, sourceLineIndex = lineIndex;

            var  lines        = new List <SourceLine>();
            char previousChar = iterator.Current;

            while (iterator.GetNext() != EOF)
            {
                if (iterator.Current != NewLine && iterator.Current != ':' && iterator.Current != ';')
                {
                    try
                    {
                        token = ParseToken(previousChar, token, iterator);
                        if (token != null)
                        {
                            previousChar   = iterator.Current;
                            token.Parent   = currentParent;
                            token.Position = iterator.Index - lineIndex - token.Name.Length + 1;
                            if (token.OperatorType == OperatorType.Open || token.OperatorType == OperatorType.Closed || token.OperatorType == OperatorType.Separator)
                            {
                                if (token.OperatorType == OperatorType.Open)
                                {
                                    opens++;
                                    currentParent.AddChild(token);
                                    currentOpen       =
                                        currentParent = token;
                                    AddBlankSeparator();
                                }
                                else if (token.OperatorType == OperatorType.Closed)
                                {
                                    if (currentOpen == null)
                                    {
                                        throw new ExpressionException(token, $"Missing opening for closure \"{token.Name}\"");
                                    }

                                    // check if matching ( to )
                                    if (!Groups[currentOpen.Name].Equals(token.Name))
                                    {
                                        throw new ExpressionException(token, $"Mismatch between \"{currentOpen.Name}\" in column {currentOpen.Position} and \"{token.Name}\"");
                                    }

                                    // go up the ladder
                                    currentOpen = currentParent = token.Parent = currentOpen.Parent;

                                    while (currentOpen != null && currentOpen.OperatorType != OperatorType.Open)
                                    {
                                        currentOpen = currentOpen.Parent;
                                    }
                                    opens--;
                                }
                                else
                                {
                                    currentParent = currentParent.Parent;
                                    currentParent.AddChild(token);
                                    currentParent = token;
                                }
                            }
                            else if (token.Type == TokenType.Instruction)
                            {
                                while (currentParent.Parent != rootParent)
                                {
                                    currentParent = currentParent.Parent;
                                }
                                currentParent.AddChild(token);
                                AddBlankSeparator();
                                AddBlankSeparator();
                            }
                            else
                            {
                                currentParent.AddChild(token);
                            }
                        }
                    }
                    catch (ExpressionException ex)
                    {
                        Assembler.Log.LogEntry(fileName, lineNumber, ex.Position, ex.Message);
                    }
                    if (iterator.PeekNext() == NewLine)
                    {
                        iterator.MoveNext();
                    }
                }
                if (iterator.Current == ';')
                {
                    _ = iterator.Skip(c => c != NewLine && (c != ':' || Assembler.Options.IgnoreColons) && c != EOF);
                }


                if (iterator.Current == NewLine || iterator.Current == ':' || iterator.Current == EOF)
                {
                    previousChar = iterator.Current;

                    /* A new source line is when:
                     * 1. A line termination character (New Line, colon, EOF) is encountered
                     * 2. And either there are no more characters left or the most recent token created
                     * 3. Is not a binary operator nor it is a comma separator.
                     */
                    var newLine = iterator.Current == EOF ||
                                  (opens == 0 &&
                                   (token == null ||
                                    (token.OperatorType != OperatorType.Binary &&
                                     token.OperatorType != OperatorType.Open &&
                                     !token.Name.Equals(",")
                                    )
                                   )
                                  );
                    if (iterator.Current == NewLine)
                    {
                        currentLine++;
                    }
                    if (newLine)
                    {
                        var newSourceLine = new SourceLine(fileName, lineNumber, GetSourceLineSource(), rootParent.Children[0]);
                        lines.Add(newSourceLine);
                        if (Assembler.Options.WarnLeft && newSourceLine.Label != null && newSourceLine.Label.Position != 1)
                        {
                            Assembler.Log.LogEntry(newSourceLine, newSourceLine.Label, "Label is not at the beginning of the line.", false);
                        }
                        Reset();
                        lineNumber = currentLine;
                    }
                    else
                    {
                        token = null;
                    }
                    lineIndex = iterator.Index;
                    if (newLine)
                    {
                        sourceLineIndex = iterator.Index;
                    }
                }
            }
            if (currentOpen != null && currentOpen.OperatorType == OperatorType.Open)
            {
                Assembler.Log.LogEntry(fileName, 1, currentOpen.LastChild.Position, $"End of source reached without finding closing \"{Groups[currentOpen.Name]}\".");
            }

            if (token != null)
            {
                lines.Add(new SourceLine(fileName, lineNumber, GetSourceLineSource(), rootParent.Children[0]));
            }

            return(lines);

            void AddBlankSeparator()
            {
                var sepToken = new Token()
                {
                    Type         = TokenType.Operator,
                    OperatorType = OperatorType.Separator,
                    Name         = string.Empty,
                    Position     = token == null ? 1 : token.Position,
                    Children     = new List <Token>()
                };

                currentParent.AddChild(sepToken);
                currentParent = sepToken;
            }

            string GetSourceLineSource()
            {
                if (iterator.Index > sourceLineIndex + 1)
                {
                    return(source.Substring(sourceLineIndex + 1, iterator.Index - sourceLineIndex - 1));
                }
                return(string.Empty);
            }

            void Reset()
            {
                currentParent          =
                    rootParent         = new Token();
                currentParent.Children = new List <Token>();
                AddBlankSeparator();
                AddBlankSeparator();
                token = null;
            }
        }