Example #1
0
        void ScanBlock(RandomAccessIterator <SourceLine> lines)
        {
            var ix       = lines.Index;
            var line     = lines.Current;
            var closures = new Stack <Token>();

            closures.Push(line.Instruction);
            while (lines.MoveNext() && closures.Count > 0)
            {
                if (lines.Current.Instruction != null)
                {
                    if (lines.Current.Instruction.Name.Equals(_openClosures[closures.Peek().Name], Services.StringViewComparer))
                    {
                        closures.Pop();
                    }
                    else if (_openClosures.ContainsKey(lines.Current.Instruction.Name))
                    {
                        closures.Push(lines.Current.Instruction);
                    }
                }
            }
            if (closures.Count > 0)
            {
                throw new SyntaxException(closures.Peek(),
                                          $"Missing closure \"{_openClosures[closures.Peek().Name]}\" for directive \"{closures.Peek().Name}\".");
            }
            lines.SetIndex(ix);
        }
Example #2
0
        static string ScanTo(char previousChar,
                             RandomAccessIterator <char> iterator,
                             Func <char, char, char, bool> terminal)
        {
            var  tokenNameBuilder = new StringBuilder();
            char c = iterator.Current;

            tokenNameBuilder.Append(c);
            if (!terminal(previousChar, c, iterator.PeekNext()))
            {
                previousChar = c;
                c            = iterator.GetNext();
                while (!terminal(previousChar, c, iterator.PeekNext()))
                {
                    tokenNameBuilder.Append(c);
                    if (char.IsWhiteSpace(c))
                    {
                        break;
                    }
                    previousChar = c;
                    c            = iterator.GetNext();
                }
            }

            return(tokenNameBuilder.ToString());
        }
Example #3
0
 void DefineFunction(RandomAccessIterator <SourceLine> lines)
 {
     if (Services.CurrentPass == 0)
     {
         var line = lines.Current;
         if (_currentBlock != null)
         {
             throw new SyntaxException(line.Instruction, "Function definition block cannot be inside another block.");
         }
         if (line.Label == null)
         {
             throw new SyntaxException(line.Instruction, "Function name not specified");
         }
         var functionName = line.Label.Name;
         if (_functionDefs.ContainsKey(functionName))
         {
             throw new SyntaxException(line.Label, $"Function name \"{functionName}\" was previous declared.");
         }
         if (!Services.SymbolManager.SymbolIsValid(functionName))
         {
             throw new SyntaxException(line.Label, $"Invalid function name \"{functionName}\".");
         }
         _functionDefs.Add(functionName, new Function(line.Label.Name, line.Operands, lines, Services, Services.Options.CaseSensitive));
     }
     else
     {
         new FunctionBlock(Services, 1).SeekBlockEnd(lines);
     }
 }
Example #4
0
        /// <summary>
        /// Assemble the parsed <see cref="SourceLine"/>.
        /// </summary>
        /// <param name="line">The line to assembly.</param>
        /// <returns>The disassembly output from the assembly operation.</returns>
        /// <exception cref="BlockClosureException"/>
        /// <exception cref="DirectoryNotFoundException"/>
        /// <exception cref="DivideByZeroException"/>
        /// <exception cref="ExpressionException"/>
        /// <exception cref="FileNotFoundException"/>
        /// <exception cref="FormatException"/>
        /// <exception cref="InvalidPCAssignmentException"/>
        /// <exception cref="BlockAssemblerException"/>
        /// <exception cref="OverflowException"/>
        /// <exception cref="ProgramOverflowException"/>
        /// <exception cref="ReturnException"/>
        /// <exception cref="SectionException"/>
        /// <exception cref="SymbolException"/>
        /// <exception cref="SyntaxException"/>
        public string Assemble(RandomAccessIterator <SourceLine> lines)
        {
            var  first     = lines.Current;
            bool isSpecial = first.Label != null && first.Label.IsSpecialOperator();

            PCOnAssemble = Services.Output.LogicalPC;
            if (first.Label != null && !first.Label.Name.Equals("*"))
            {
                if (isSpecial)
                {
                    Services.SymbolManager.DefineLineReference(first.Label, PCOnAssemble);
                }
                else if (first.Instruction == null || !ExcludedInstructionsForLabelDefines.Contains(first.Instruction.Name))
                {
                    DefineLabel(first.Label, PCOnAssemble, true);
                }
            }
            if (first.Instruction != null)
            {
                return(OnAssemble(lines));
            }
            if (first.Label != null && !isSpecial)
            {
                var symbol = Services.SymbolManager.GetSymbol(first.Label, false);
                if (symbol != null && symbol.IsNumeric && symbol.StorageType == StorageType.Scalar && !double.IsNaN(symbol.NumericValue))
                {
                    return(string.Format(".{0}{1}",
                                         ((int)symbol.NumericValue).ToString("x4").PadRight(42),
                                         Services.Options.NoSource ? string.Empty : first.Source));
                }
            }
            return(string.Empty);
        }
Example #5
0
 /// <summary>
 /// Cleanup the current block's scope.
 /// </summary>
 /// <param name="iterator">The source line iterator.</param>
 public void PopScope(RandomAccessIterator <SourceLine> iterator)
 {
     SeekBlockEnd(iterator);
     if (_createScope)
     {
         Services.SymbolManager.PopScope();
     }
 }
Example #6
0
        /// <summary>
        /// Gets a string from the tokenized expression.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static string GetString(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            if (iterator.Current == null && !iterator.MoveNext())
            {
                return(string.Empty);
            }
            var token = iterator.Current;

            if (IsStringLiteral(iterator))
            {
                iterator.MoveNext();
                return(Regex.Unescape(token.Name.ToString()).TrimOnce('"'));
            }
            else if (token.Type == TokenType.Function && token.Name.Equals("format", services.StringComparison))
            {
                var str = GetFormatted(iterator, services);
                if (!string.IsNullOrEmpty(str) && Token.IsEnd(iterator.Current))
                {
                    return(str);
                }
            }
            else if (token.Type == TokenType.Function && token.Name.Equals("char", services.StringComparison))
            {
                var code = (int)services.Evaluator.Evaluate(iterator, 0, 0x10FFFF);
                return(char.ConvertFromUtf32(services.Encoding.GetCodePoint(code)));
            }
            else if (token.Type == TokenType.Operand &&
                     (char.IsLetter(token.Name[0]) || token.Name[0] == '_') &&
                     !services.Evaluator.IsReserved(token.Name))
            {
                var sym = services.SymbolManager.GetSymbol(token, services.CurrentPass > 0);
                if (sym == null)
                {
                    return(string.Empty);
                }
                if (sym.DataType == DataType.String)
                {
                    if ((!iterator.MoveNext() || Token.IsEnd(iterator.Current)) && sym.StorageType == StorageType.Scalar)
                    {
                        return(sym.StringValue.TrimOnce('"').ToString());
                    }
                    else if (sym.StorageType == StorageType.Vector && iterator.Current.Name.Equals("["))
                    {
                        var current   = iterator.Current;
                        var subscript = (int)services.Evaluator.Evaluate(iterator);
                        if (Token.IsEnd(iterator.Current))
                        {
                            if (subscript >= 0 && subscript < sym.StringVector.Count)
                            {
                                return(sym.StringVector[subscript].ToString());
                            }
                            throw new SyntaxException(current, "Index out of range.");
                        }
                    }
                }
            }
            throw new SyntaxException(token, "Type mismatch.");
        }
        public override void ExecuteDirective(RandomAccessIterator <SourceLine> iterator)
        {
            var line = iterator.Current;

            if (_ifTrue)
            {
                SeekBlockEnd(iterator);
            }
            else
            {
                while (line != null && !line.Instruction.Name.Equals(".endif", Services.StringComparison) && !_ifTrue)
                {
                    if (iterator.Current.Instruction == null)
                    {
                        continue;
                    }
                    var instruction = Services.Options.CaseSensitive ? line.Instruction.Name.ToString() :
                                      line.Instruction.Name.ToLower();
                    if (instruction.StartsWith(".if"))
                    {
                        EvaluateCondition(line);
                    }
                    else
                    {
                        if (!instruction.Equals(".endif"))
                        {
                            if (_elseEvaluated)
                            {
                                throw new SyntaxException(iterator.Current.Instruction,
                                                          $"Invalid use of \"{instruction}\" directive.");
                            }

                            _elseEvaluated = instruction.Equals(".else");

                            if (_elseEvaluated)
                            {
                                if (line.Operands.Count > 0)
                                {
                                    throw new SyntaxException(line.Operands[0], "Unexpected expression.");
                                }
                                break;
                            }
                            EvaluateCondition(line);
                        }
                    }
                    if (_ifTrue)
                    {
                        break;
                    }
                    SeekBlockDirectives(iterator, Reserved.GetReserved("Keywords").ToArray());
                    line = iterator.Current;
                }
                if (line == null)
                {
                    throw new SyntaxException(line.Instruction, $"Missing \".endif\" directive.");
                }
            }
        }
Example #8
0
        public double EvaluateFunction(RandomAccessIterator <Token> tokens)
        {
            tokens.MoveNext();
            var param = tokens.GetNext();

            if (param.Equals(")"))
            {
                throw new SyntaxException(param.Position, "Expected argument not provided.");
            }
            var symbolLookup = Services.SymbolManager.GetSymbol(param, false);

            if (symbolLookup == null)
            {
                if (param.Type != TokenType.Operand || !char.IsLetter(param.Name[0]) || param.Name[0] != '_')
                {
                    throw new SyntaxException(param.Position, "Function \"len\" expects a symbol.");
                }
                if (Services.CurrentPass > 0)
                {
                    throw new SymbolException(param, SymbolException.ExceptionReason.NotDefined);
                }
                Services.PassNeeded = true;
                return(0);
            }
            param = tokens.GetNext();
            if (!param.Name.Equals(")"))
            {
                param = tokens.GetNext();
                int subscript = -1;
                if (param.Name.Equals("["))
                {
                    subscript = (int)Services.Evaluator.Evaluate(tokens, 0, int.MaxValue);
                }
                if (subscript < 0 || !tokens.PeekNext().Equals(")"))
                {
                    throw new SyntaxException(param.Position, "Unexpected argument.");
                }
                if (symbolLookup.StorageType != StorageType.Vector)
                {
                    throw new SyntaxException(param.Position, "Type mismatch.");
                }
                if (symbolLookup.DataType == DataType.String)
                {
                    if (subscript >= symbolLookup.StringVector.Count)
                    {
                        throw new SyntaxException(param.Position, "Index out of range.");
                    }
                    return(symbolLookup.StringVector[subscript].Length);
                }
                if (subscript >= symbolLookup.NumericVector.Count)
                {
                    throw new SyntaxException(param.Position, "Index out of range.");
                }
                return(symbolLookup.NumericVector[subscript].Size());
            }
            return(symbolLookup.Length);
        }
Example #9
0
 /// <summary>
 /// Constructs a new instance of a <see cref="RandomAccessIterator{T}"/> class.
 /// </summary>
 /// <param name="iterator">An iterator from which to copy.</param>
 /// <exception cref="ArgumentNullException"></exception>
 public RandomAccessIterator(RandomAccessIterator <T> iterator)
 {
     if (iterator == null)
     {
         throw new ArgumentNullException();
     }
     _firstIndex = iterator._firstIndex;
     Index       = iterator.Index;
     _list       = iterator._list;
 }
Example #10
0
 /// <summary>
 /// Constructs a new instance of a <see cref="RandomAccessIterator{T}"/> class.
 /// </summary>
 /// <param name="iterator">An iterator from which to copy.</param>
 /// <param name="reset">Reset the copied indicator.</param>
 /// <exception cref="ArgumentNullException"></exception>
 public RandomAccessIterator(RandomAccessIterator <T> iterator, bool reset)
 {
     if (iterator == null)
     {
         throw new ArgumentNullException();
     }
     _firstIndex = iterator._firstIndex;
     _list       = iterator._list;
     _length     = iterator._length;
     Index       = reset ? _firstIndex : iterator.Index;
 }
Example #11
0
        /// <summary>
        /// Gets the formatted string from the tokenized expression.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static string GetFormatted(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            iterator.MoveNext();
            var format = iterator.GetNext();

            if (Token.IsEnd(format))
            {
                return(null);
            }
            string fmt;

            if (!format.IsDoubleQuote())
            {
                if (format.Type != TokenType.Function && !format.Name.Equals("format", services.StringComparison))
                {
                    return(null);
                }
                fmt = GetFormatted(iterator, services);
            }
            else
            {
                fmt = Regex.Unescape(format.Name.TrimOnce('"').ToString());
            }
            var parms = new List <object>();

            if (iterator.MoveNext())
            {
                while (!Token.IsEnd(iterator.GetNext()))
                {
                    if (ExpressionIsAString(iterator, services))
                    {
                        parms.Add(GetString(iterator, services));
                    }
                    else
                    {
                        var parmVal = services.Evaluator.Evaluate(iterator, false);
                        if (Regex.IsMatch(fmt, $"\\{{{parms.Count}(,-?\\d+)?:(d|D|x|X)\\d*\\}}"))
                        {
                            parms.Add((int)parmVal);
                        }
                        else
                        {
                            parms.Add(parmVal);
                        }
                    }
                }
            }
            if (parms.Count == 0)
            {
                return(fmt);
            }
            return(string.Format(fmt, parms.ToArray()));
        }
Example #12
0
 void DoPop(RandomAccessIterator <SourceLine> lines)
 {
     _currentBlock.PopScope(lines);
     _blocks.Pop();
     if (_blocks.Count > 0)
     {
         _currentBlock = _blocks.Peek();
     }
     else
     {
         _currentBlock = null;
     }
 }
Example #13
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}\".");
        }
Example #14
0
        public override void ExecuteDirective(RandomAccessIterator <SourceLine> lines)
        {
            var line = lines.Current;

            if (line.Operands.Count > 0)
            {
                throw new SyntaxException(line.Operands[0], "Unexpected expression.");
            }
            if (line.Instruction.Name.Equals(".endpage", Services.StringComparison))
            {
                if (!Services.PassNeeded && GetPage(Services.Output.LogicalPC - 1) != _page)
                {
                    Services.Log.LogEntry(line.Instruction, "Page boundary crossed.");
                }
            }
        }
Example #15
0
        /// <summary>
        /// Determines whether the tokenized expression is a string.
        /// </summary>
        /// <param name="iterator">The iterator to the tokenized expression.</param>
        /// <param name="services">The shared assembly services.</param>
        /// <returns></returns>
        public static bool ExpressionIsAString(RandomAccessIterator <Token> iterator, AssemblyServices services)
        {
            var token = iterator.Current;

            if (token.IsDoubleQuote())
            {
                return(token.Name.Length > 2 && Token.IsEnd(iterator.PeekNext()));
            }
            var ix     = iterator.Index;
            var result = false;

            if (token.Type == TokenType.Function &&
                (token.Name.Equals("format", services.StringComparison) || token.Name.Equals("char", services.StringComparison)))
            {
                iterator.MoveNext();
                var parms = Token.GetGroup(iterator);
                var last  = iterator.Current;
                result = Token.IsEnd(last);
                if (token.Name.Equals("char", services.StringComparison))
                {
                    result &= services.Evaluator.Evaluate(parms.GetIterator(), 0, 0x10FFFF).IsInteger();
                }
            }
            else if (token.Type == TokenType.Operand &&
                     (char.IsLetter(token.Name[0]) || token.Name[0] == '_') &&
                     !services.Evaluator.IsReserved(token.Name))
            {
                var sym = services.SymbolManager.GetSymbol(token, false);
                if (sym != null)
                {
                    if (iterator.MoveNext() && iterator.Current.Name.Equals("["))
                    {
                        var subscript = (int)services.Evaluator.Evaluate(iterator);
                        result = Token.IsEnd(iterator.Current) &&
                                 subscript >= 0 && subscript < sym.StringVector.Count;
                    }
                    else
                    {
                        result = Token.IsEnd(iterator.Current) &&
                                 sym.StorageType == StorageType.Scalar &&
                                 sym.DataType == DataType.String;
                    }
                }
            }
            iterator.SetIndex(ix);
            return(result);
        }
Example #16
0
        /// <summary>
        /// Creates a new instance of the Function class.
        /// </summary>
        /// <param name="name">The function's name.</param>
        /// <param name="parameterList">The list of parameters for the function.</param>
        /// <param name="iterator">The <see cref="SourceLine"/> iterator to traverse to define the function block.</param>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        /// <param name="caseSensitive">Determines whether to compare the passed parameters
        /// to the source block's own defined parameters should be case-sensitive.</param>
        /// <exception cref="SyntaxException"></exception>
        public Function(StringView name,
                        List <Token> parameterList,
                        RandomAccessIterator <SourceLine> iterator,
                        AssemblyServices services,
                        bool caseSensitive)
            : base(parameterList,
                   caseSensitive)
        {
            Name          = name;
            _services     = services;
            _definedLines = new List <SourceLine>();
            SourceLine line;

            while ((line = iterator.GetNext()) != null)
            {
                if (line.Label != null && line.Label.Name.Equals("+"))
                {
                    _services.Log.LogEntry(line.Label,
                                           "Anonymous labels are not supported inside functions.", false);
                }
                if (line.Instruction != null)
                {
                    if (line.Instruction.Name.Equals(".global", _services.StringViewComparer))
                    {
                        throw new SyntaxException(line.Instruction,
                                                  $"Directive \".global\" not allowed inside a function block.");
                    }
                    if (line.Instruction.Name.Equals(".endfunction", _services.StringViewComparer))
                    {
                        if (line.Operands.Count > 0)
                        {
                            throw new SyntaxException(line.Operands[0],
                                                      "Unexpected expression found after \".endfunction\" directive.");
                        }
                        break;
                    }
                }
                _definedLines.Add(line);
            }
            if (line == null)
            {
                throw new SyntaxException(iterator.Current.Instruction,
                                          "Function definition does not have a closing \".endfunction\" directive.");
            }
        }
Example #17
0
        /// <summary>
        /// Seeks the <see cref="SourceLine"/> containing the
        /// first instance one of the directives in the block.
        /// </summary>
        /// <param name="iterator">The source line iterator.</param>
        /// <param name="directives">An array of directives, one of which to seek in the block.</param>
        protected void SeekBlockDirectives(RandomAccessIterator <SourceLine> iterator, StringView[] directives)
        {
            var line = iterator.Current;

            if (!line.Instruction.Name.Equals(BlockClosure, Services.StringComparison))
            {
                var blockClose = BlockClosure;

                var keywordsNotToSkip = new List <StringView>(directives)
                {
                    blockClose
                };
                keywordsNotToSkip.AddRange(BlockOpens.Select(bo => new StringView(bo)));

                var opens = 1;
                while (opens != 0)
                {
                    line = iterator.FirstOrDefault(l => l.Instruction != null && keywordsNotToSkip.Contains(l.Instruction.Name, Services.StringViewComparer));
                    if (line == null)
                    {
                        throw new BlockClosureException(BlockOpens.First());
                    }

                    if (BlockOpens.Contains(line.Instruction.Name.ToString(), Services.StringComparer))
                    {
                        opens++;
                    }

                    if (opens < 2 && directives.Contains(line.Instruction.Name, Services.StringViewComparer))
                    {
                        break;
                    }

                    if (line.Instruction.Name.Equals(blockClose, Services.StringComparison))
                    {
                        opens--;
                    }
                }
            }
        }
Example #18
0
        protected override string OnAssemble(RandomAccessIterator <SourceLine> lines)
        {
            var line = lines.Current;

            if (Reserved.IsOneOf("CPU", line.Instruction.Name))
            {
                var iterator = line.Operands.GetIterator();
                if (!iterator.MoveNext() || !StringHelper.IsStringLiteral(iterator) || iterator.PeekNext() != null)
                {
                    Services.Log.LogEntry(line.Instruction,
                                          "String expression expected.");
                }
                else
                {
                    CPU = iterator.Current.Name.ToString().TrimOnce('"');
                    OnSetCpu();
                }
                return(string.Empty);
            }
            Evaluations[0] = Evaluations[1] = Evaluations[2] = double.NaN;
            return(AssembleCpuInstruction(line));
        }
Example #19
0
        /// <summary>
        /// Gets a grouping of tokens.
        /// </summary>
        /// <param name="tokens">The iterator to the full token expression.</param>
        /// <returns>The grouped tokens</returns>
        public static IEnumerable <Token> GetGroup(RandomAccessIterator <Token> tokens)
        {
            var list = new List <Token> {
                tokens.Current
            };
            var open   = tokens.Current.Name;
            var closed = OpenClose[open];
            var opens  = 1;

            while (tokens.MoveNext() && opens > 0)
            {
                list.Add(tokens.Current);
                if (tokens.Current.Name.Equals(open))
                {
                    opens++;
                }
                else if (tokens.Current.Name.Equals(closed))
                {
                    opens--;
                }
            }
            return(list);
        }
Example #20
0
        double CallFunction(RandomAccessIterator <Token> tokens, bool returnValueExpected)
        {
            var functionToken = tokens.Current;
            var functionName  = functionToken.Name;

            tokens.MoveNext();
            var   evalParms = new List <object>();
            Token token     = tokens.GetNext();

            while (!token.Name.Equals(")"))
            {
                if (token.IsSeparator())
                {
                    tokens.MoveNext();
                }
                if (StringHelper.ExpressionIsAString(tokens, Services))
                {
                    evalParms.Add(StringHelper.GetString(tokens, Services));
                }
                else
                {
                    evalParms.Add(Services.Evaluator.Evaluate(tokens, false));
                }
                token = tokens.Current;
            }
            Services.SymbolManager.PushScopeEphemeral();
            var value = _functionDefs[functionName].Invoke(evalParms);

            Services.SymbolManager.PopScopeEphemeral();
            if (double.IsNaN(value) && returnValueExpected)
            {
                throw new ReturnException(functionToken.Position,
                                          $"Function name \"{functionName}\" did not return a value.");
            }
            return(value);
        }
Example #21
0
        protected override string OnAssemble(RandomAccessIterator <SourceLine> lines)
        {
            var line        = lines.Current;
            var instruction = line.Instruction.Name.ToLower();
            var iterator    = line.Operands.GetIterator();

            switch (instruction)
            {
            case ".assert":
                DoAssert(line);
                break;

            case ".bank":
                SetBank(line);
                break;

            case ".warnif":
            case ".errorif":
                ThrowConditional(line);
                break;

            case ".echo":
            case ".error":
            case ".warn":
                if (instruction.Equals(".echo"))
                {
                    if (iterator.MoveNext() && StringHelper.ExpressionIsAString(iterator, Services))
                    {
                        Output(line, StringHelper.GetString(iterator, Services));
                    }
                    else if (Services.Evaluator.ExpressionIsCondition(line.Operands.GetIterator()))
                    {
                        Output(line, Services.Evaluator.EvaluateCondition(iterator, false).ToString());
                    }
                    else
                    {
                        Output(line, Services.Evaluator.Evaluate(iterator, false, Evaluator.CbmFloatMinValue, Evaluator.CbmFloatMaxValue).ToString());
                    }
                }
                else if (iterator.MoveNext() && StringHelper.ExpressionIsAString(iterator, Services))
                {
                    Output(line, StringHelper.GetString(iterator, Services));
                }
                else
                {
                    Services.Log.LogEntry(line.Instruction, "String expression expected.");
                }
                if (iterator.Current != null)
                {
                    throw new SyntaxException(iterator.Current, "Unexpected expression.");
                }
                break;

            case ".eor":
                SetEor(line);
                break;

            case ".forcepass":
                if (line.Operands.Count > 0)
                {
                    Services.Log.LogEntry(line.Operands[0], "Unexpected expression.");
                }
                else if (Services.CurrentPass == 0)
                {
                    Services.PassNeeded = true;
                }
                break;

            case ".invoke":
                InvokeFunction(line);
                break;

            case ".proff":
            case ".pron":
                if (line.Operands.Count > 0)
                {
                    Services.Log.LogEntry(line.Operands[0], "Unexpected expression.");
                }
                else
                {
                    Services.PrintOff = instruction.Equals(".proff");
                }
                break;

            case ".dsection":
                DefineSection(line);
                break;

            case ".section":
                return(SetSection(line));

            case ".format":
            case ".target":
                if (Services.CurrentPass == 0)
                {
                    if (Services.Output.HasOutput)
                    {
                        Services.Log.LogEntry(line.Instruction, "Cannot specify target format after assembly has started.");
                    }
                    else
                    {
                        if (!iterator.MoveNext() || !StringHelper.ExpressionIsAString(iterator, Services))
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "Expression must be a string.");
                        }
                        else if (!string.IsNullOrEmpty(Services.OutputFormat))
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "Output format was previously specified.");
                        }
                        else
                        {
                            Services.SelectFormat(StringHelper.GetString(iterator, Services));
                        }
                        if (iterator.Current != null)
                        {
                            Services.Log.LogEntry(iterator.Current, "Unexpected expression.");
                        }
                    }
                    if (instruction.Equals(".target"))
                    {
                        Services.Log.LogEntry(line.Instruction,
                                              "\".target\" is deprecated. Use \".format\" instead.", false);
                    }
                }
                break;

            default:
                InitMem(line);
                break;
            }
            return(string.Empty);
        }
Example #22
0
 public void InvokeFunction(RandomAccessIterator <Token> tokens) => CallFunction(tokens, false);
Example #23
0
 public double EvaluateFunction(RandomAccessIterator <Token> tokens) => CallFunction(tokens, true);
Example #24
0
        string DoGoto(RandomAccessIterator <SourceLine> lines)
        {
            var line = lines.Current;

            if (line.Operands.Count == 0)
            {
                throw new SyntaxException(line.Instruction.Position,
                                          "Destination not specified for \".goto\" directive.");
            }

            var gotoExp = line.Operands[0].Name;

            if ((!char.IsLetter(gotoExp[0]) && gotoExp[0] != '_') || line.Operands.Count > 1)
            {
                Services.Log.LogEntry(line.Operands[0],
                                      "\".goto\" operand must be a label.");
            }
            else if (line.Label != null && gotoExp.Equals(line.Label.Name, Services.StringViewComparer))
            {
                Services.Log.LogEntry(line.Instruction,
                                      "Destination cannot be the same line as \".goto\" directive.");
            }
            else
            {
                var        iterCopy = new RandomAccessIterator <SourceLine>(lines, true);
                SourceLine currLine;
                if ((currLine = iterCopy.FirstOrDefault(l =>
                {
                    if (l.Instruction != null && _openClosures.ContainsKey(l.Instruction.Name))
                    {
                        if (l.Instruction.Name.Equals(".function", Services.StringComparison))
                        {
                            throw new SyntaxException(l.Instruction, "Function block cannot be inside another block.");
                        }
                        // leap over any blocks we find along the way we are not currently in.
                        if (!_blocks.Any(b => b.Index == iterCopy.Index))
                        {
                            GetProcessor(l, iterCopy.Index).SeekBlockEnd(iterCopy);
                        }
                        return(false);
                    }
                    return(l.Label != null && l.Label.Name.Equals(gotoExp, Services.StringViewComparer));
                })) != null)
                {
                    if (currLine.Instruction != null &&
                        (currLine.Instruction.Name.Contains('=') ||
                         currLine.Instruction.Name.Equals(".equ", Services.StringComparison) ||
                         currLine.Instruction.Name.Equals(".global", Services.StringComparison)
                        )
                        )
                    {
                        Services.Log.LogEntry(line.Instruction,
                                              $"\"{gotoExp}\" is not a valid destination.");
                    }
                    else
                    {
                        while (_currentBlock != null)
                        {
                            // if where we landed lies outside of the current block scope
                            // we need to pop out of that scope.
                            _currentBlock.SeekBlockEnd(lines);
                            if (iterCopy.Index > _currentBlock.Index)
                            {
                                // did we land in a place still within the block scope?
                                if (iterCopy.Index > lines.Index)
                                {
                                    // no, pop out
                                    DoPop(lines);
                                }
                                else
                                {
                                    // we're still within the current block, don't pop it
                                    break;
                                }
                            }
                            else
                            {
                                // we went backwards, pop out of current scope
                                DoPop(lines);
                            }
                        }
                        if (iterCopy.Index >= lines.Index)
                        {
                            lines.FastForward(iterCopy.Index);
                        }
                        else if (iterCopy.Index == 0)
                        {
                            lines.Reset();
                        }
                        else
                        {
                            lines.Rewind(iterCopy.Index - 1);
                        }
                    }
                }
                else
                {
                    Services.Log.LogEntry(line.Instruction,
                                          $"Could not find destination \"{gotoExp}\".");
                }
            }
            return(string.Empty);
        }
Example #25
0
        protected override string OnAssemble(RandomAccessIterator <SourceLine> lines)
        {
            var line = lines.Current;

            if (Reserved.IsOneOf("Goto", line.Instruction.Name))
            {
                return(DoGoto(lines));
            }

            if (Reserved.IsOneOf("Functional", line.Instruction.Name))
            {
                if (line.Instruction.Name.Equals(".function", Services.StringComparison))
                {
                    DefineFunction(lines);
                }
                else if (_currentBlock != null)
                {
                    throw new SyntaxException(line.Instruction.Position,
                                              "Directive \".endfunction\" can only be made inside function block.");
                }
                return(string.Empty);
            }
            if (_openClosures.ContainsKey(line.Instruction.Name))
            {
                var block = GetProcessor(line, lines.Index);
                if (_blocks.Count == 0)
                {
                    ScanBlock(lines);
                }
                _blocks.Push(block);
                _currentBlock = block;
            }
            if (line.Instruction.Name.Equals(".block", Services.StringComparison) && line.Label != null)
            {
                DefineLabel(line.Label, PCOnAssemble, false);
            }

            var isBreakCont = Reserved.IsOneOf("BreakContinue", line.Instruction.Name);

            if (_currentBlock == null || (!isBreakCont && !_currentBlock.IsReserved(line.Instruction.Name)))
            {
                throw new SyntaxException(line.Instruction.Position,
                                          $"\"{line.Instruction.Name}\" directive must come inside a block.");
            }

            if (isBreakCont)
            {
                if (line.Operands.Count > 0)
                {
                    throw new SyntaxException(line.Operands[0], "Unexpected expression.");
                }
                var isBreak = line.Instruction.Name.Equals(".break", Services.StringComparison);
                if ((!_currentBlock.AllowContinue && line.Instruction.Name.Equals(".continue", Services.StringComparison)) ||
                    (!_currentBlock.AllowBreak && isBreak))
                {
                    while (_currentBlock != null)
                    {
                        var allowBreak = false;
                        _currentBlock.SeekBlockEnd(lines);
                        if (isBreak)
                        {
                            allowBreak = _currentBlock.AllowBreak;
                        }
                        else if (!isBreak && _currentBlock.AllowContinue)
                        {
                            break;
                        }
                        DoPop(lines);
                        if (isBreak && allowBreak)
                        {
                            return(string.Empty);
                        }
                    }
                    if (_currentBlock == null)
                    {
                        var err = isBreak ? "break" : "continue";
                        throw new SyntaxException(line.Instruction.Position,
                                                  $"No enclosing loop out of which to {err}.");
                    }
                }
                else if (isBreak)
                {
                    DoPop(lines);
                    return(string.Empty);
                }
                else
                {
                    _currentBlock.SeekBlockEnd(lines);
                }
            }
            _currentBlock.ExecuteDirective(lines);
            if (lines.Current.Instruction != null && lines.Current.Instruction.Name.Equals(_currentBlock.BlockClosure, Services.StringComparison))
            {
                DoPop(lines);
            }
            if (line.Label != null)
            {
                return($".{Services.Output.LogicalPC,-42:x4}{line.Source.Substring(line.Label.Position - 1, line.Label.Name.Length)}");
            }
            return(string.Empty);
        }
Example #26
0
 /// <summary>
 /// Assemble the collection of parsed <see cref="SourceLine"/> objects. This method must be inherited.
 /// </summary>
 /// <param name="lines">A <see cref="RandomAccessIterator{T}"/> of source lines.</param>
 /// <returns>The disassembly output from the assembly operation.</returns>
 /// <exception cref="BlockClosureException"/>
 /// <exception cref="DirectoryNotFoundException"/>
 /// <exception cref="DivideByZeroException"/>
 /// <exception cref="ExpressionException"/>
 /// <exception cref="FileNotFoundException"/>
 /// <exception cref="FormatException"/>
 /// <exception cref="InvalidPCAssignmentException"/>
 /// <exception cref="BlockAssemblerException"/>
 /// <exception cref="OverflowException"/>
 /// <exception cref="ProgramOverflowException"/>
 /// <exception cref="ReturnException"/>
 /// <exception cref="SectionException"/>
 /// <exception cref="SymbolException"/>
 /// <exception cref="SyntaxException"/>
 protected abstract string OnAssemble(RandomAccessIterator <SourceLine> lines);
Example #27
0
        public override void ExecuteDirective(RandomAccessIterator <SourceLine> lines)
        {
            var line = lines.Current;

            if (line.Instruction.Name.Equals(".endswitch", Services.StringComparison))
            {
                return;
            }
            CaseBlock <string> stringBlock  = null;
            CaseBlock <double> numericBlock = null;
            SwitchContext      context      = null;
            var it = line.Operands.GetIterator();

            if (it.MoveNext())
            {
                if (StringHelper.ExpressionIsAString(it, Services))
                {
                    context = new SwitchContext(StringHelper.GetString(it, Services));
                }
                else
                {
                    context = new SwitchContext(Services.Evaluator.Evaluate(it, false));
                }
                if (it.Current != null)
                {
                    throw new SyntaxException(it.Current, "Unexpected expression.");
                }
            }
            if (context == null)
            {
                string error;
                if (line.Operands.Count == 0)
                {
                    error = "Expression must follow \".switch\" directive.";
                }
                else
                {
                    error = "Expression must be a valid symbol or an expression.";
                }
                Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position, error);
                return;
            }
            var defaultIndex = -1;

            if (!string.IsNullOrEmpty(context.StringValue))
            {
                stringBlock = new CaseBlock <string>();
            }
            else
            {
                numericBlock = new CaseBlock <double>();
            }
            while ((line = lines.GetNext()) != null &&
                   (line.Instruction == null || !line.Instruction.Name.Equals(".endswitch", Services.StringComparison)))
            {
                if (line.Instruction != null)
                {
                    if (line.Instruction.Name.Equals(".case", Services.StringComparison))
                    {
                        if (defaultIndex > -1)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "\".case\" directive cannot follow a \".default\" directive.");
                        }
                        else if (stringBlock?.FallthroughIndex > -1 || numericBlock?.FallthroughIndex > -1)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "\".case\" does not fall through.");
                        }
                        else if (line.Operands.Count == 0)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "Expression expected.");
                        }
                        else
                        {
                            var iterator = line.Operands.GetIterator();
                            if (stringBlock != null)
                            {
                                if (!StringHelper.ExpressionIsAString(iterator, Services))
                                {
                                    Services.Log.LogEntry(line.Filename, line.LineNumber, line.Operands[0].Position,
                                                          "String expression expected.");
                                }
                                else
                                {
                                    stringBlock.Cases.Add(StringHelper.GetString(iterator, Services));
                                }
                            }
                            else
                            {
                                numericBlock?.Cases.Add(Services.Evaluator.Evaluate(iterator));
                            }
                            if (iterator.Current != null)
                            {
                                throw new SyntaxException(iterator.Current, "Unexpected expression.");
                            }
                        }
                    }
                    else if (Reserved.IsOneOf("BreakContReturn", line.Instruction.Name))
                    {
                        if ((stringBlock?.Cases.Count == 0 || numericBlock?.Cases.Count == 0) &&
                            defaultIndex < 0)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  $"\"{line.Instruction}\" directive must follow a \".case\" or \".default\" directive.");
                        }
                        else
                        {
                            if (line.Instruction.Name.Equals(".return", Services.StringComparison) &&
                                (stringBlock?.FallthroughIndex < 0 || numericBlock?.FallthroughIndex < 0))
                            {
                                if (stringBlock != null)
                                {
                                    stringBlock.FallthroughIndex = lines.Index;
                                }
                                if (numericBlock != null)
                                {
                                    numericBlock.FallthroughIndex = lines.Index;
                                }
                            }
                            else if (!line.Instruction.Name.Equals(".return", Services.StringComparison) && line.Operands.Count > 0)
                            {
                                throw new SyntaxException(line.Operands[0], "Unexpected expression.");
                            }
                            context.AddBlock(stringBlock);
                            context.AddBlock(numericBlock);
                            Services.SymbolManager.PopScope();
                            if (stringBlock != null)
                            {
                                stringBlock = new CaseBlock <string>();
                            }
                            else
                            {
                                numericBlock = new CaseBlock <double>();
                            }
                        }
                    }
                    else if (line.Instruction.Name.Equals(".default", Services.StringComparison))
                    {
                        if (line.Operands.Count > 0)
                        {
                            throw new SyntaxException(line.Operands[0], "Unexpected expression.");
                        }
                        if (defaultIndex > -1)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                                  "There can only be one \".default\" directive in a switch block.");
                        }
                        else
                        {
                            defaultIndex = lines.Index + 1;
                        }
                    }
                    else if (line.Label != null)
                    {
                        Services.Log.LogEntry(line.Filename, line.LineNumber, line.Label.Position,
                                              "Label cannot be defined inside a switch block.");
                    }
                    else
                    {
                        if ((stringBlock?.Cases.Count == 0 || numericBlock?.Cases.Count == 0) && defaultIndex < 0)
                        {
                            Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position, "\".case\" or \".default\" directive expected");
                        }
                        else if (stringBlock?.FallthroughIndex < 0 || numericBlock?.FallthroughIndex < 0)
                        {
                            if (stringBlock != null)
                            {
                                stringBlock.FallthroughIndex = lines.Index;
                            }
                            if (numericBlock != null)
                            {
                                numericBlock.FallthroughIndex = lines.Index;
                            }
                        }
                    }
                }
            }
            if (line != null)
            {
                if (defaultIndex < 0 || !context.AnyCaseDefined())
                {
                    if (defaultIndex >= 0)
                    {
                        Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                              "Only a default case was specified.", false);
                    }
                    else if (!context.AnyCaseDefined())
                    {
                        Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                              "Switch statement did not encounter any cases to evaluate.");
                        return;
                    }
                    else
                    {
                        Services.Log.LogEntry(line.Filename, line.LineNumber, line.Instruction.Position,
                                              "Switch statement does not have a default case.", false);
                    }
                }
                var fallthroughIndex = context.GetFallthroughIndex();
                if (fallthroughIndex < 0)
                {
                    fallthroughIndex = defaultIndex;
                }

                if (fallthroughIndex > -1)
                {
                    lines.Rewind(fallthroughIndex - 1);
                }
                Services.SymbolManager.PushScope(lines.Index.ToString());
            }
        }
Example #28
0
 /// <summary>
 /// Construct a new instance of a symbol class.
 /// </summary>
 /// <param name="tokens">The tokenized expression of the symbol definition.</param>
 /// <param name="eval">The <see cref="Evaluator"/> to evaluate the expression.</param>
 public Symbol(RandomAccessIterator <Token> tokens, Evaluator eval)
     : this(tokens, eval, true)
 {
 }
Example #29
0
        /// <summary>
        /// Construct a new instance of a symbol class.
        /// </summary>
        /// <param name="tokens">The tokenized expression of the symbol definition.</param>
        /// <param name="eval">The <see cref="Evaluator"/> to evaluate the expression.</param>
        /// <param name="isMutable">The symbol's mutability flag.</param>
        public Symbol(RandomAccessIterator <Token> tokens, Evaluator eval, bool isMutable)
            : this()
        {
            IsMutable   = isMutable;
            StorageType = StorageType.Vector;

            var opens = 1;
            var token = tokens.GetNext();

            if (TokenType.End.HasFlag(token.Type))
            {
                throw new SyntaxException(token.Position, "Expression expected.");
            }

            if (StringHelper.IsStringLiteral(tokens))
            {
                DataType = DataType.String;
            }
            else
            {
                DataType = DataType.Numeric;
            }

            int index = 0;

            while (opens > 0)
            {
                if (token.Type == TokenType.Open && token.Name.Equals("["))
                {
                    opens++;
                }
                else if (token.Name.Equals("]"))
                {
                    opens--;
                }
                else
                {
                    if (DataType == DataType.String)
                    {
                        if (!StringHelper.IsStringLiteral(tokens))
                        {
                            throw new SyntaxException(token.Position, "Type mismatch.");
                        }
                        StringVector.Add(index++, token.Name.TrimOnce('"'));
                        token = tokens.GetNext();
                        if (token.Name.Equals("]"))
                        {
                            opens--;
                        }
                    }
                    else
                    {
                        NumericVector.Add(index++, eval.Evaluate(tokens, false));
                        token = tokens.Current;
                        if (token.Name.Equals("]"))
                        {
                            continue;
                        }
                    }
                }
                token = tokens.GetNext();
            }
        }
Example #30
0
        double EvaluateSymbol(RandomAccessIterator <Token> tokens)
        {
            var token     = tokens.Current;
            var subscript = -1;
            var converted = double.NaN;
            var isString  = token.IsDoubleQuote();

            if (char.IsLetter(token.Name[0]) || token.Name[0] == '_')
            {
                var next = tokens.GetNext();
                if (next != null && next.IsOpen() && next.Name.Equals("["))
                {
                    subscript = (int)Evaluator.Evaluate(tokens, 0, int.MaxValue);
                }
                var symbol = SymbolManager.GetSymbol(token, CurrentPass > 0);
                if (symbol == null)
                {
                    if (token.Line.Label != null && token.Line.Label.Name.Equals(token.Name, StringViewComparer))
                    {
                        throw new SymbolException(token, SymbolException.ExceptionReason.NotDefined);
                    }
                    PassNeeded = true;
                    return(0x100);
                }
                if (subscript >= 0)
                {
                    if (symbol.StorageType != StorageType.Vector)
                    {
                        throw new SyntaxException(token.Position, "Type mismatch.");
                    }
                    if ((symbol.IsNumeric && subscript >= symbol.NumericVector.Count) ||
                        (!symbol.IsNumeric && subscript >= symbol.StringVector.Count))
                    {
                        throw new SyntaxException(token.Position, "Index was out of range.");
                    }
                    if (symbol.IsNumeric)
                    {
                        return(symbol.NumericVector[subscript]);
                    }
                    token    = new Token(symbol.StringVector[subscript], TokenType.Operand);
                    isString = true;
                }
                else if (symbol.IsNumeric)
                {
                    if (symbol.DataType == DataType.Address && symbol.Bank != Output.CurrentBank)
                    {
                        return((int)symbol.NumericValue | (symbol.Bank * 0x10000));
                    }
                    return(symbol.NumericValue);
                }
                else
                {
                    token    = new Token(symbol.StringValue, TokenType.Operand);
                    isString = true;
                }
            }
            if (isString || token.IsQuote())
            {
                // is it a string literal?
                var literal = token.IsQuote() ? token.Name.TrimOnce(token.Name[0]).ToString() : token.Name.ToString();
                if (string.IsNullOrEmpty(literal))
                {
                    throw new SyntaxException(token.Position, "Cannot evaluate empty string.");
                }
                literal = Regex.Unescape(literal);
                if (!isString)
                {
                    var charsize = 1;
                    if (char.IsSurrogate(literal[0]))
                    {
                        charsize++;
                    }
                    if (literal.Length > charsize)
                    {
                        throw new SyntaxException(token.Position, "Invalid char literal.");
                    }
                }
                // get the integral equivalent from the code points in the string
                converted = Encoding.GetEncodedValue(literal);
            }
            else if (token.Name.Equals("*"))
            {    // get the program counter
                converted = Output.LogicalPC;
            }
            else if (token.Name[0].IsSpecialOperator())
            {    // get the special character value
                if (token.Name[0] == '+' && CurrentPass == 0)
                {
                    converted  = Output.LogicalPC;
                    PassNeeded = true;
                }
                else
                {
                    converted = SymbolManager.GetLineReference(token.Name, token);
                    if (double.IsNaN(converted))
                    {
                        var reason = token.Name[0] == '+' ? SymbolException.ExceptionReason.InvalidForwardReference :
                                     SymbolException.ExceptionReason.InvalidBackReference;
                        throw new SymbolException(token, reason);
                    }
                }
            }
            if (double.IsNaN(converted))
            {
                throw new ExpressionException(token.Position,
                                              $"\"{token.Name}\" is not a expression.");
            }
            return(converted);
        }