Example #1
0
        public double CallFunction(Token function, Token parameters, bool returnValueExpected)
        {
            if (!_functionDefs.ContainsKey(function.Name))
            {
                throw new ExpressionException(function.Position, $"Unknown function name \"{function.Name}\".");
            }

            var evalParms = new List <object>(parameters.Children.Count);

            foreach (Token parm in from parm in parameters.Children
                     where parm.HasChildren
                     select parm)
            {
                if (parm.ToString().EnclosedInDoubleQuotes())
                {
                    evalParms.Add(parm.ToString());
                }
                else
                {
                    evalParms.Add(Evaluator.Evaluate(parm));
                }
            }
            // save pre-call context
            var returnIndex = Assembler.LineIterator.Index;
            BlockProcessorBase lastBlock = _currentBlock;

            Assembler.SymbolManager.PushScopeEphemeral();

            var fcnBlock = new FunctionBlock(Assembler.LineIterator.Current, BlockType.Functional);

            _blocks.Push(fcnBlock);
            _currentBlock = fcnBlock;

            // invoke the function, get the return
            var value = _functionDefs[function.Name].Invoke(this, evalParms);

            // restore context post-call
            while (_currentBlock != lastBlock)
            {
                _currentBlock.SeekBlockEnd();
                PopBlock();
            }
            Assembler.SymbolManager.PopScope();
            Assembler.LineIterator.SetIndex(returnIndex);

            if (double.IsNaN(value) && returnValueExpected)
            {
                throw new ExpressionException(function.Position, $"Function \"{function.Name}\" did not return a value.");
            }

            return(value);
        }
Example #2
0
 void DoPop(RandomAccessIterator <SourceLine> lines)
 {
     _currentBlock.PopScope(lines);
     _blocks.Pop();
     if (_blocks.Count > 0)
     {
         _currentBlock = _blocks.Peek();
     }
     else
     {
         _currentBlock = null;
     }
 }
Example #3
0
 void PopBlock()
 {
     if (!Assembler.CurrentLine.InstructionName.Equals(_currentBlock.Directive.Closure))
     {
         Assembler.Log.LogEntry(Assembler.CurrentLine, Assembler.CurrentLine.Instruction,
                                $"Missing closure for \"{_currentBlock.Directive.Open}\" directive.");
         _currentBlock = null;
     }
     else
     {
         DoPop();
     }
 }
Example #4
0
 void DoPop()
 {
     if (_currentBlock != null)
     {
         _currentBlock.Pop();
     }
     _blocks.Pop();
     if (_blocks.Count > 0)
     {
         _currentBlock = _blocks.Peek();
     }
     else
     {
         _currentBlock = null;
     }
 }
Example #5
0
        /// <summary>
        /// Constructs a new instance of a block assembler.
        /// </summary>
        /// <param name="services">The shared <see cref="AssemblyServices"/> object.</param>
        public BlockAssembler(AssemblyServices services)
            : base(services)
        {
            _blocks       = new Stack <BlockProcessorBase>();
            _functionDefs = new Dictionary <StringView, Function>(services.StringViewComparer);

            _currentBlock = null;

            _openClosures = new Dictionary <StringView, StringView>(services.StringViewComparer)
            {
                { ".block", ".endblock" },
                { ".for", ".next" },
                { ".foreach", ".next" },
                { ".function", ".endfunction" },
                { ".if", ".endif" },
                { ".ifdef", ".endif" },
                { ".ifndef", ".endif" },
                { ".namespace", ".endnamespace" },
                { ".page", ".endpage" },
                { ".repeat", ".endrepeat" },
                { ".switch", ".endswitch" },
                { ".while", ".endwhile" }
            };

            Reserved.DefineType("Functional",
                                ".function", ".endfunction");

            Reserved.DefineType("NonOpens",
                                ".break", ".case", ".continue", ".default", ".endblock", ".endif",
                                ".endfunction", ".endpage", ".endnamespace", ".endrepeat", ".endswitch",
                                ".endwhile", ".else", ".elseif", ".elseifdef", ".elseifdef", ".elseifndef", ".next");

            Reserved.DefineType("BreakContinue", ".break", ".continue");

            Reserved.DefineType("Goto", ".goto");

            ExcludedInstructionsForLabelDefines.Add(".function");
            ExcludedInstructionsForLabelDefines.Add(".block");

            Services.Evaluator.AddFunctionEvaluator(this);

            Services.IsReserved.Add(s => _functionDefs.ContainsKey(s));
        }
Example #6
0
        /// <summary>
        /// Constructs a new instance of the multiline assembler class.
        /// </summary>
        public MultiLineAssembler()
        {
            _blocks = new Stack <BlockProcessorBase>();

            _functionDefs = new Dictionary <string, Function>();

            _currentBlock = null;

            Reserved.DefineType("Scope", ".block", ".endblock");

            Reserved.DefineType("Conditional",
                                ".if", ".ifdef", ".ifndef", ".else", ".elseif",
                                ".elseifdef", ".elseifndef", ".endif");

            Reserved.DefineType("SwitchCase",
                                ".switch", ".case", ".default", ".endswitch");

            Reserved.DefineType("Functional",
                                ".function", ".endfunction", ".invoke", ".return");

            Reserved.DefineType("ForNext", ".for", ".next");

            Reserved.DefineType("While", ".while", ".endwhile");

            Reserved.DefineType("Repeat", ".repeat", ".endrepeat");

            Reserved.DefineType("BreakContinue", ".break", ".continue");

            Reserved.DefineType("Page", ".page", ".endpage");

            Reserved.DefineType("GotoEnd", ".goto", ".end");

            Evaluator.AddFunctionEvaluator(this);

            Assembler.PassChanged += CheckCurrentLineAtPass;
        }
Example #7
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 #8
0
        protected override string OnAssembleLine(SourceLine line)
        {
            if (line.InstructionName.Equals(".end"))
            {
                while (Assembler.LineIterator.MoveNext())
                {
                }
                return(string.Empty);
            }
            if (Reserved.IsOneOf("Functional", line.InstructionName))
            {
                if (line.InstructionName.Equals(".function"))
                {
                    DefineFunction(line);
                }
                else if (line.InstructionName.Equals(".invoke"))
                {
                    if (!line.OperandHasToken)
                    {
                        Assembler.Log.LogEntry(line, line.Operand, "Missing function name from invocation directive.");
                    }
                    else
                    {
                        var fcnName = line.Operand.Children[0].Children[0].Name;
                        if (line.Operand.Children[0].Children.Count > 2 ||
                            line.Operand.Children[0].Children[0].OperatorType != OperatorType.Function)
                        {
                            Assembler.Log.LogEntry(line, line.Operand.LastChild, "Bad function call.");
                        }
                        else if (!_functionDefs.ContainsKey(fcnName))
                        {
                            Evaluator.Evaluate(line.Operand.Children[0]);
                        }
                        else
                        {
                            _ = CallFunction(line.Operand.Children[0].Children[0],
                                             line.Operand.Children[0].Children[1],
                                             false);
                        }
                    }
                }
                else
                {
                    Assembler.Log.LogEntry(line, line.Instruction, $"Directive \"{line.InstructionName}\" can only be made inside function block.");
                }
                return(string.Empty);
            }
            if (_blockOpenTypes.ContainsKey(line.InstructionName))
            {
                BlockProcessorBase block;
                BlockType          type = _blockOpenTypes[line.InstructionName];
                switch (type)
                {
                case BlockType.ForNext:
                    block = new ForNextBlock(line, type);
                    break;

                case BlockType.Repeat:
                    block = new RepeatBlock(line, type);
                    break;

                case BlockType.Conditional:
                case BlockType.ConditionalDef:
                case BlockType.ConditionalNdef:
                    block = new ConditionalBlock(line, type);
                    break;

                case BlockType.Scope:
                    block = new ScopeBlock(line, type);
                    break;

                case BlockType.Goto:
                    DoGoto(line);
                    return(string.Empty);

                case BlockType.Page:
                    block = new PageBlockProcessor(line, type);
                    break;

                case BlockType.Switch:
                    block = new SwitchBlock(line, type);
                    break;

                default:
                    block = new WhileBlock(line, type);
                    break;
                }
                _blocks.Push(block);
                _currentBlock = block;
            }
            if (_currentBlock != null)
            {
                if (Assembler.CurrentLine.InstructionName.Equals(".break") ||
                    Assembler.CurrentLine.InstructionName.Equals(".continue"))
                {
                    var contBreakLine = Assembler.LineIterator.Current;
                    if (!_currentBlock.AllowContinue && contBreakLine.InstructionName.Equals(".continue"))
                    {
                        _currentBlock.SeekBlockEnd();
                        while (_currentBlock != null)
                        {
                            _currentBlock.SeekBlockEnd();
                            if (_currentBlock.AllowContinue)
                            {
                                break;
                            }
                            else
                            {
                                PopBlock();
                            }
                        }
                        if (_currentBlock == null)
                        {
                            Assembler.Log.LogEntry(contBreakLine, contBreakLine.Instruction,
                                                   "No enclosing loop out of which to continue.");
                            return(string.Empty);
                        }
                    }
                    else if (!_currentBlock.AllowBreak && contBreakLine.InstructionName.Equals(".break"))
                    {
                        _currentBlock.SeekBlockEnd();
                        while (_currentBlock != null)
                        {
                            _currentBlock.SeekBlockEnd();
                            if (_currentBlock.AllowBreak)
                            {
                                PopBlock();
                                return(string.Empty);
                            }
                            else
                            {
                                PopBlock();
                            }
                        }
                        if (_currentBlock == null)
                        {
                            Assembler.Log.LogEntry(contBreakLine, contBreakLine.Instruction,
                                                   "No enclosing loop out of which to break.");
                            return(string.Empty);
                        }
                    }
                    else
                    {
                        _currentBlock.SeekBlockEnd();
                        if (contBreakLine.Instruction.Equals(".break"))
                        {
                            return(string.Empty);
                        }
                    }
                }
                _currentBlock.ExecuteDirective();

                if (Assembler.CurrentLine == null ||
                    Assembler.CurrentLine.InstructionName.Equals(BlockDirective.Directives[_currentBlock.Type].Closure))
                {
                    if (Assembler.CurrentLine == null)
                    {
                        line = SourceLineHelper.GetLastInstructionLine();
                        Assembler.Log.LogEntry(line,
                                               $"Missing closure for \"{BlockDirective.Directives[_currentBlock.Type].Open}\" directive.", true);
                    }
                    DoPop();
                }
            }
            else
            {
                Assembler.Log.LogEntry(line, line.Instruction.Position, $"\"{line.InstructionName}\" directive must come inside a block.");
            }
            if (line.Label != null)
            {
                return($".{Assembler.Output.LogicalPC,-42:x4}{line.UnparsedSource.Substring(line.Label.Position - 1, line.Label.Name.Length)}");
            }
            return(string.Empty);
        }