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); }
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); }
public ValueToken Evaluate(TokenMarker tokenMarker) { return(EvaluateInternal(tokenMarker)); }
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; } }