예제 #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);
        }
예제 #2
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);
        }
예제 #3
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);
        }