Beispiel #1
0
        public void InterpretLine(List <Statement> statement)
        {
            if (InterpreterMode == InterpreterMode.Running)
            {
                return;
            }

            ContinueRunning = true;
            CurrentImmediateModeStatementMarker = new ImmediateModeStatementMarker(statement);

            try
            {
                while (CurrentImmediateModeStatementMarker.Valid && CurrentImmediateModeStatementMarker.StatementIndex < statement.Count)
                {
                    var currentStatement     = CurrentImmediateModeStatementMarker.Statement;
                    var commandToken         = currentStatement.Tokens[0] as Commands.CommandToken;
                    var isVariableAssignment = currentStatement.Tokens[0] is VariableNameToken;

                    if (commandToken == null && !isVariableAssignment)
                    {
                        throw new SyntaxErrorException();
                    }

                    CurrentCommandToken = commandToken;

                    TokenMarker marker = new TokenMarker(currentStatement.Tokens);
                    if (isVariableAssignment)
                    {
                        commandToken = (CommandToken)TokensProvider.GetBuiltinToken("LET");
                    }
                    else
                    {
                        marker.MoveNext();
                    }

                    commandToken.Execute(this, marker);

                    CurrentImmediateModeStatementMarker.MoveToNextStatement();
                }
            }
            catch (RetroBASIC.Exceptions.RetroBASICException basicException)
            {
                ExpressionEvaluator.Clear();
                string outputMessage = $"{ErrorMessages.errorStart} {basicException.Message}{ErrorMessages.error}";
                Console.OutputTextWriter.WriteLine();
                Console.OutputTextWriter.WriteLine(outputMessage);
            }
            finally
            {
                ContinueRunning = false;
                CurrentImmediateModeStatementMarker = null;
                InterpreterMode = InterpreterMode.Immmediate;
            }
        }
        // Evalute the X(A,...Z ) part of the expression LET X(A,...Z)=[expression].
        public ValueTokenArray EvaluateVariableArrayAssignment(TokenMarker tokenMarker)
        {
            if (!(tokenMarker.Token is VariableNameToken))
            {
                throw new Exceptions.SyntaxErrorException();
            }

            // Push the token and a custom action to be performed when the closing ")" is evaluated.
            operatorTokens.Push(tokenMarker.Token);
            operatorActions.Push(x => EvaluateVariableAssignmentToken(x));
            arrayCount.Push(0);

            tokenMarker.MoveNext();

            // Have the Evaluate function return when the closing ")" is evaluated.
            var result = EvaluateInternal(tokenMarker, () => (this.arrayCount.Count > 0));

            return((ValueTokenArray)result);
        }
Beispiel #3
0
        public ValueToken ReadNextDataValue()
        {
            if (DataTokenMarker == null)
            {
                FindDataStatement();
                if (DataStatementMarker.Valid == false)
                {
                    return(null);
                }

                DataTokenMarker = new TokenMarker(DataStatementMarker.Statement.Tokens);
                DataTokenMarker.MoveNext();
            }

            if (DataTokenMarker.Token == null)
            {
                while (DataTokenMarker.Token == null)
                {
                    DataStatementMarker.MoveToNextStatement();
                    FindDataStatement();

                    if (DataStatementMarker.Valid == false)
                    {
                        return(null);
                    }

                    DataTokenMarker = new TokenMarker(DataStatementMarker.Statement.Tokens);
                    DataTokenMarker.MoveNext();
                }
            }

            var result = (ValueToken)DataTokenMarker.Token;

            DataTokenMarker.MoveNext();
            if (DataTokenMarker.Token is CommaToken)
            {
                DataTokenMarker.MoveNext();
            }

            return(result);
        }
        private ValueToken EvaluateInternal(TokenMarker tokenMarker, Func <bool> ContinueIfTrue = null)
        {
            Token token     = null;
            Token prevToken = null;

            if (ContinueIfTrue == null)
            {
                ContinueIfTrue = () => true;
            }

            while (tokenMarker.Token != null && ContinueIfTrue())
            {
                prevToken = token;
                token     = tokenMarker.Token;
                tokenMarker.MoveNext();

                // Push a number on to the result stack.
                if (token is ValueToken valueToken)
                {
                    if (prevToken != null && ((prevToken is VariableNameToken) || (prevToken is CloseParenToken)))
                    {
                        // A variable token directly follows a quote. Let the caller decide if this an error.
                        tokenMarker.MovePrev();
                        break;
                    }

                    valueTokens.Push(valueToken);
                    continue;
                }

                // Return value of the variable
                if (token is VariableNameToken variableNameToken)
                {
                    // Make sure the previous token was an operator, if not let the caller decide if it's an error
                    if (prevToken != null && ((prevToken is VariableNameToken) || (prevToken is ValueToken)))
                    {
                        tokenMarker.MovePrev();
                        break;
                    }

                    var nextToken = tokenMarker.Token;
                    if (nextToken == null || !(nextToken is OpenParenToken))
                    {
                        // For non-array variables, get the value now and push the resultt.
                        var value = interpreterEnvironment.GetVariableValue(variableNameToken);
                        valueTokens.Push(value);
                        continue;
                    }
                    // For array variables, push the token and setup for evaluation later.
                    operatorTokens.Push(token);
                    operatorActions.Push(x => EvaluateGetArrayVariableToken(x));
                    arrayCount.Push(0);
                    continue;
                }

                // Push opening brack to operator stack
                if (token is OpenParenToken)
                {
                    operatorTokens.Push(token);
                    continue;
                }

                // Handle Unary operators
                if ((prevToken == null || prevToken is OperatorToken || prevToken is OpenParenToken) &&
                    token is OperatorToken)
                {
                    switch (token)
                    {
                    // Push the unary minus token
                    case MinusToken minusToken:
                        token = tokensProvider.UnaryMinusToken;
                        operatorTokens.Push(token);
                        operatorActions.Push(x => EvaluateUnaryOperatorToken(x));
                        continue;

                    // A unary plus does nothing, so also do nothing.
                    case PlusToken plusToken:
                        continue;

                    default:
                        throw new Exceptions.SyntaxErrorException();
                    }
                }

                // If a closing parenthesis is found, solve until opening brace
                if (token is CloseParenToken)
                {
                    if (operatorTokens.Count > 0)
                    {
                        /* Evaluate the expression back to the opening brace or last comma
                         * to properly handle Fn(x-1, x-2) */
                        FinishEvaluatingExpressionChunk();

                        // Remove opening brace
                        operatorTokens.Pop();

                        if (arrayCount.Count > 0 && operatorTokens.TryPeek(out Token topToken) &&
                            ((topToken is FunctionToken) || (topToken is VariableNameToken)))
                        {
                            if (prevToken is CommaToken)
                            {
                                // Not in a function or in an array dimension, so let the caller decide if this is an error.
                                tokenMarker.MovePrev();
                                break;
                            }
                            // Found a closing parenthesis for a function or an array variable. Add one to the array count.
                            var count = arrayCount.Pop();
                            arrayCount.Push(count + 1);
                            // Now remove the operator token and call the lambda function to finish
                            // evaluating the function or array reference.
                            PerformEvaluationAction();
                        }

                        continue;
                    }

                    // Too many closing parenthesis is a syntax error.
                    throw new Exceptions.SyntaxErrorException();
                }

                // As long as precedence allows, evaluate the operator tokens.
                while (operatorTokens.TryPeek(out Token stackToken) &&
                       (stackToken is OperatorToken operatorStackToken) &&
                       (token is OperatorToken currentOperatorToken) &&
                       operatorStackToken.Precedence >= currentOperatorToken.Precedence)
                {
                    PerformEvaluationAction();
                    continue;
                }

                // Handle a comma in a function parameter or a dimension
                if (token is CommaToken)
                {
                    if (arrayCount.Count > 0)
                    {
                        /* Evaluate the expression back to the opening brace or last comma
                         * to properly handle Fn(x-1, x-2) */
                        FinishEvaluatingExpressionChunk();

                        var count = arrayCount.Pop();
                        arrayCount.Push(count + 1);
                        continue;
                    }
                    else
                    {
                        // Let the caller decide if this is an error
                        tokenMarker.MovePrev();
                        break;
                    }
                }

                // Setup evaluation of a function
                if (token is FunctionToken)
                {
                    if (tokenMarker.Token == null || !(tokenMarker.Token is OpenParenToken))
                    {
                        throw new Exceptions.SyntaxErrorException();
                    }

                    // Add the token to the stack and setup to finish the function evaluation.
                    arrayCount.Push(0); // args count
                    operatorTokens.Push(token);
                    operatorActions.Push((x) => EvaluateFunctionToken(x));
                    continue;
                }

                //Setup evaluation of a user defined function
                if (token is FnToken)
                {
                    if (tokenMarker.Token is WhitespacesToken)
                    {
                        tokenMarker.MoveNext();
                    }

                    if (tokenMarker.Token == null || !(tokenMarker.Token is VariableNameToken userDefinedFunctionName))
                    {
                        throw new Exceptions.SyntaxErrorException();
                    }

                    tokenMarker.MoveNext();

                    arrayCount.Push(0);
                    operatorTokens.Push(userDefinedFunctionName);
                    operatorActions.Push((x) => EvaluateUserDefinedFunctionToken(x));

                    continue;
                }

                // Push an operator token on to the operator tokens stack
                if (token is OperatorToken)
                {
                    operatorTokens.Push(token);
                    // Setup to finish evaluating an operator.
                    operatorActions.Push((x) => EvaluateBinaryOperatorToken(x));
                    continue;
                }

                // An unrecognized token. Let the caller decide what to do about it, if anything.
                // Move tokenMarker back by one since it had already been bumped up by one
                // above and it should be pointing at the unrecognized character.
                tokenMarker.MovePrev();
                break;
            }

            // Finishing evaluating all the pending operations. FinishPendingOperations()
            while (operatorTokens.TryPeek(out Token lastOperator))
            {
                // Check for non-matching right parenthesis
                if (lastOperator is OpenParenToken)
                {
                    throw new Exceptions.SyntaxErrorException();
                }
                PerformEvaluationAction();
            }

            var finalResult = valueTokens.Pop();

            return(finalResult);
        }
Beispiel #5
0
        protected void InterpetLines()
        {
            InterpreterMode = InterpreterMode.Running;
            ContinueRunning = true;

            try
            {
                while (ContinueRunning)
                {
                    var currentStatement = CurrentStatementMarker.Statement;
                    if (currentStatement == null)
                    {
                        break;
                    }

                    var commandToken         = currentStatement.Tokens[0] as Commands.CommandToken;
                    var isVariableAssignment = (currentStatement.Tokens[0] as VariableNameToken) != null;

                    if (commandToken == null && !isVariableAssignment)
                    {
                        throw new SyntaxErrorException();
                    }

                    CurrentCommandToken = commandToken;

                    TokenMarker marker = new TokenMarker(currentStatement.Tokens);
                    if (isVariableAssignment)
                    {
                        commandToken = TokensProvider.GetBuiltinToken("LET") as Commands.CommandToken;
                    }
                    else
                    {
                        marker.MoveNext();
                    }
#if DEBUG
                    if (CurrentStatementMarker.LineNumber == 630)
                    {
                        CurrentStatementMarker = CurrentStatementMarker;
                    }

                    if (CurrentStatementMarker.LineNumber == 770)
                    {
                        CurrentStatementMarker = CurrentStatementMarker;
                    }
#endif

                    commandToken.Execute(this, marker);

                    if (!ContinueRunning)
                    {
                        break;
                    }

                    CurrentCommandToken = null;

                    if (NextStatementMarker != null)
                    {
                        CurrentStatementMarker.MoveTo(NextStatementMarker);
                        NextStatementMarker = null;
                    }
                    else
                    {
                        CurrentStatementMarker.MoveToNextStatement();
                    }

                    if (CurrentStatementMarker.Valid == false)
                    {
                        ContinueRunning = false;
                    }
                }
            }
            catch (RetroBASIC.Exceptions.RetroBASICException basicException)
            {
                string outputMessage = $"{ErrorMessages.errorStart} {basicException.Message}{ErrorMessages.error}{ErrorMessages.inMsg}{CurrentStatementMarker.LineNumber}";
                Console.OutputTextWriter.WriteLine();
                Console.OutputTextWriter.WriteLine(outputMessage);
            }
            finally
            {
                ContinueRunning = false;
                InterpreterMode = InterpreterMode.Immmediate;
            }
        }