public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { // For an empty PRINT command, just output a writeline and return. if (tokenMarker.Token == null) { interpreter.Console.OutputTextWriter.WriteLine(); return; } Token lastToken = null; while (tokenMarker.Token != null) { lastToken = tokenMarker.Token; switch (tokenMarker.Token) { case StringValueToken stringValueToken: case RealValueToken realValueToken: case IntegerValueToken integerValueToken: case UnaryMinusToken unaryMinusToken: case MinusToken minusToken: case PlusToken plusToken: case VariableNameToken variableToken: case FunctionToken functionToken: case FnToken userDefinedFunctionToken: case OpenParenToken openParenToken: var result = interpreter.ExpressionEvaluator.Evaluate(tokenMarker); WriteValue(interpreter, result); break; case SemicolonToken semiColonToken: tokenMarker.MoveNext(); break; case CommaToken commaToken: MoveToNextTabMargin(interpreter); tokenMarker.MoveNext(); break; case TabToken tabToken: tokenMarker.MoveNext(); tabToken.Execute(interpreter, tokenMarker); break; case SpcToken spcToken: tokenMarker.MoveNext(); spcToken.Execute(interpreter, tokenMarker); break; default: throw new Exceptions.SyntaxErrorException(); } // lastToken = tokenMarker.Token; // tokenMarker.MoveNext(); } if (!((lastToken is SemicolonToken) || (lastToken is CommaToken))) { interpreter.Console.OutputTextWriter.WriteLine(); } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { var variableNameToken = tokenMarker.Token as VariableNameToken; ValueTokenArray indicies = null; if (variableNameToken == null) { throw new Exceptions.SyntaxErrorException(); } if (tokenMarker.PeekNext() is OpenParenToken) { indicies = interpreter.ExpressionEvaluator.EvaluateVariableArrayAssignment(tokenMarker); } else { tokenMarker.MoveNext(); } var equalsToken = tokenMarker.Token; if (!(equalsToken is Operators.EqualToken)) { throw new Exceptions.SyntaxErrorException(); } if (tokenMarker.GetNextToken() == null) { throw new Exceptions.SyntaxErrorException(); } var result = interpreter.ExpressionEvaluator.Evaluate(tokenMarker); interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, indicies, result); }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { while (tokenMarker.Token != null) { if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } if (!(tokenMarker.PeekNext() is OpenParenToken)) { throw new Exceptions.SyntaxErrorException(); } var indicies = interpreter.ExpressionEvaluator.EvaluateVariableArrayAssignment(tokenMarker); interpreter.VariablesEnvironment.DimensionArrayVariable(variableNameToken, indicies); if (!(tokenMarker.Token is CommaToken)) { break; } tokenMarker.MoveNext(); } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { var variableNameTokens = new List <VariableNameToken>(); while (tokenMarker.Token != null) { if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } if (!((variableNameToken.VariableType == VariableValueType.IntegerNumber) || (variableNameToken.VariableType == VariableValueType.RealNumber))) { throw new Exceptions.TypeMismatchException(); } variableNameTokens.Add(variableNameToken); // Maybe add more variable names to the list if (tokenMarker.GetNextToken() is CommaToken) { tokenMarker.MoveNext(); continue; } } if (interpreter.ForNextLoops.Count == 0) { throw new Exceptions.NextWithoutForException(); } if (variableNameTokens.Count == 0) { ProcessForNextState(interpreter, interpreter.ForNextLoops.Peek()); return; } int variableNameIndex = 0; while (variableNameIndex < variableNameTokens.Count) { if (interpreter.ForNextLoops.TryPeek(out ForNextLoopState forNextState) == false) { throw new Exceptions.NextWithoutForException(); } bool forNextLoopDone = ProcessForNextState(interpreter, forNextState, variableNameTokens[variableNameIndex]); if (!forNextLoopDone) { return; } variableNameIndex += 1; } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { while (tokenMarker.Token != null) { ValueTokenArray indicies = null; if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } if (tokenMarker.PeekNext() is OpenParenToken) { indicies = interpreter.ExpressionEvaluator.EvaluateVariableArrayAssignment(tokenMarker); } else { tokenMarker.MoveNext(); } var valueToken = interpreter.ReadNextDataValue(); if (valueToken == null) { throw new Exceptions.OutOfDataException(); } switch (variableNameToken.VariableType) { case VariableValueType.String: break; case VariableValueType.RealNumber: float realValue = 0; var success = float.TryParse(((StringValueToken)valueToken).Value, out realValue); if (success == false) { throw new Exceptions.TypeMismatchException(); } valueToken = interpreter.TokensProvider.CreateRealValueToken(realValue); break; case VariableValueType.IntegerNumber: success = float.TryParse(((StringValueToken)valueToken).Value, out realValue); if (success == false) { throw new Exceptions.TypeMismatchException(); } // In Commodore BASIC, a READ of a number with a decimal into an integer number produces a zero. int intValue = (int)Math.Abs(realValue); if (realValue != intValue) { intValue = 0; } if (intValue < Int16.MinValue || intValue > Int16.MaxValue) { throw new Exceptions.OverflowException(); } valueToken = interpreter.TokensProvider.CreateIntegerValueToken((Int16)intValue); break; } interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, indicies, valueToken); if (tokenMarker.Token == null) { break; } if (!(tokenMarker.Token is CommaToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); // The next token should now be a variable name token } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { if (interpreter.InterpreterMode == InterpreterMode.Immmediate) { throw new Exceptions.IllegalDirectModeException(); } var variableNameTokens = new List <(VariableNameToken, ValueTokenArray)>(); while (tokenMarker.Token != null) { ValueTokenArray indicies = null; if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } if (tokenMarker.PeekNext() is OpenParenToken) { indicies = interpreter.ExpressionEvaluator.EvaluateVariableArrayAssignment(tokenMarker); } else { tokenMarker.MoveNext(); } if (tokenMarker.Token != null && !(tokenMarker.Token is CommaToken)) { throw new Exceptions.SyntaxErrorException(); } variableNameTokens.Add((variableNameToken, indicies)); } foreach (var(nameToken, indicies) in variableNameTokens) { var input = interpreter.Console.ReadChar(); switch (nameToken.VariableType) { case VariableValueType.String: string inputString = (input != null) ? input.ToString() : string.Empty; interpreter.VariablesEnvironment.SetVariableValue(nameToken, indicies, interpreter.TokensProvider.CreateStringValueToken(inputString)); break; case VariableValueType.RealNumber: float realValue; if (input == null) { realValue = 0; } else { if (input >= '0' && input <= '9') { realValue = (float)(input - '0'); } else { throw new Exceptions.SyntaxErrorException(); } } interpreter.VariablesEnvironment.SetVariableValue(nameToken, indicies, interpreter.TokensProvider.CreateRealValueToken(realValue)); break; case VariableValueType.IntegerNumber: Int16 intValue; if (input == null) { intValue = 0; } else { if (input >= '0' && input <= '9') { intValue = (Int16)(input - '0'); } else { throw new Exceptions.SyntaxErrorException(); } } interpreter.VariablesEnvironment.SetVariableValue(nameToken, indicies, interpreter.TokensProvider.CreateIntegerValueToken(intValue)); break; } if (input == null) { Thread.Sleep(100); } } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { var firstToken = tokenMarker.Token; if (firstToken == null) { throw new Exceptions.SyntaxErrorException(); } // Is there an input prompt? if (firstToken is StringValueToken stringValueToken) { interpreter.Console.OutputTextWriter.Write(stringValueToken.Value); interpreter.Console.OutputTextWriter.Write("? "); tokenMarker.MoveNext(); // Ensure a semicolon follows the input prompt. if ((tokenMarker.Token == null) || !(tokenMarker.Token is SemicolonToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); } else { interpreter.Console.OutputTextWriter.Write("? "); } // Now make a list of the variable names the input will be parsed into. var variableNameTokens = new List <(VariableNameToken, ValueTokenArray)>(); while (tokenMarker.Token != null) { if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } ValueTokenArray indicies = null; // For an array variable, get the array indicies. if (tokenMarker.PeekNext() is OpenParenToken) { indicies = interpreter.ExpressionEvaluator.EvaluateVariableArrayAssignment(tokenMarker); } else { tokenMarker.MoveNext(); } variableNameTokens.Add((variableNameToken, indicies)); if (tokenMarker.Token == null) { break; } // Make sure a comma is the next token if (!(tokenMarker.Token is CommaToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); } if (variableNameTokens.Count == 0) { throw new Exceptions.SyntaxErrorException(); } // Add default value for inputs var tokenResults = new List <ValueToken>(); foreach (var(variableNameToken, indicies) in variableNameTokens) { switch (variableNameToken.VariableType) { case VariableValueType.String: tokenResults.Add(interpreter.TokensProvider.CreateStringValueToken(string.Empty)); break; case VariableValueType.RealNumber: tokenResults.Add(interpreter.TokensProvider.CreateRealValueToken(0)); break; case VariableValueType.IntegerNumber: tokenResults.Add(interpreter.TokensProvider.CreateIntegerValueToken(0)); break; } } int tokenResultsIndex = 0; // Get input. Support the quirks of Microsoft's 6502 BASIC I could discover. bool getMoreInput = true; while (getMoreInput) { string inputLine = interpreter.Console.ReadLine()?.ToUpper(); if (inputLine == null) { // Probably received a Ctrl-C. interpreter.BreakDetected(); return; } /* A quirk of Microsoft BASIC's INPUT implementation is that pressing return without entering anything * uses the default or what has been previously input. */ if (inputLine.Length == 0) { getMoreInput = false; break; } int index = 0; bool parseSuccess = true; while (index < inputLine.Length && parseSuccess && tokenResultsIndex < tokenResults.Count) { parseSuccess = ParseNextInput(inputLine, index, out index, out string parsedInput, out ParseFailureReason parseFailureReason); // Still assign the input to a variable even if the parse failed. Another Microsoft BASIC quirk. bool assignmentSuccess = AssignInputToVariable(interpreter, variableNameTokens[tokenResultsIndex].Item1, variableNameTokens[tokenResultsIndex].Item2, parsedInput); if (!parseSuccess) { switch (parseFailureReason) { // Because characters followed a closing quote but shouldn't, write out a redo from start message and start over. case ParseFailureReason.CharactersAfterQuote: // Set to -1 since one will be added below to bring the index back to zero tokenResultsIndex = -1; interpreter.Console.OutputTextWriter.WriteLine($"{ErrorMessages.errorStart} {ErrorMessages.redoFromStart}"); break; // No error output for a colon, except when it involves the last result. case ParseFailureReason.Colon: if (tokenResultsIndex + 1 == tokenResults.Count) { interpreter.Console.OutputTextWriter.WriteLine($"{ErrorMessages.errorStart} {ErrorMessages.extraIgnored}"); } break; } } tokenResultsIndex += 1; } if (tokenResultsIndex < tokenResults.Count) { // Still need more input and no more input is on this line. Ask for more. if (index >= inputLine.Length) { interpreter.Console.OutputTextWriter.Write("?? "); continue; } } else { // For too much input, write out an extra ignored message. if (index < inputLine.Length) { interpreter.Console.OutputTextWriter.WriteLine($"{ErrorMessages.errorStart} {ErrorMessages.extraIgnored}"); } getMoreInput = false; } } }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { if (!(tokenMarker.Token is VariableNameToken variableNameToken)) { throw new Exceptions.SyntaxErrorException(); } if (variableNameToken.VariableType != VariableValueType.RealNumber) { throw new Exceptions.SyntaxErrorException(); } if (!(tokenMarker.GetNextToken() is EqualToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); NumericValueToken startValue; try { startValue = (NumericValueToken)interpreter.ExpressionEvaluator.Evaluate(tokenMarker); } catch (InvalidCastException) { throw new Exceptions.TypeMismatchException(); } if (!(tokenMarker.Token is ToToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); NumericValueToken endValue; try { endValue = (NumericValueToken)interpreter.ExpressionEvaluator.Evaluate(tokenMarker); } catch (InvalidCastException) { throw new Exceptions.TypeMismatchException(); } NumericValueToken stepValueToken = null; if (tokenMarker.Token != null) { if (!(tokenMarker.Token is StepToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); var result = interpreter.ExpressionEvaluator.Evaluate(tokenMarker); if (!(result is NumericValueToken)) { throw new Exceptions.TypeMismatchException(); } stepValueToken = (NumericValueToken)result; } else { // Default step is 1 or -1 // if (startValue.RealValue <= endValue.RealValue) stepValueToken = interpreter.TokensProvider.CreateRealValueToken(1); // else // stepValueToken = interpreter.TokensProvider.CreateRealValueToken(-1); } ForNextLoopState forNextLoopState; if (interpreter.InterpreterMode == InterpreterMode.Running) { var forNextMarker = interpreter.CopyCurrentStatementMarker(); // In immediate mode, FOR may not neccessarily be followed by a statement. if (forNextMarker.Valid) { forNextMarker.MoveToNextStatement(); } forNextLoopState = new ForNextLoopState(forNextMarker, variableNameToken, startValue, endValue, stepValueToken); } else { var index = interpreter.CurrentImmediateModeStatementMarker.StatementIndex; forNextLoopState = new ForNextLoopState(index, variableNameToken, startValue, endValue, stepValueToken); } interpreter.ForNextLoops.Push(forNextLoopState); interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, startValue); }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { var conditionToken = interpreter.ExpressionEvaluator.Evaluate(tokenMarker); if (!(conditionToken is NumericValueToken resultToken)) { throw new Exceptions.TypeMismatchException(); } // Condition evaluated to false. Skip to the next line. if (resultToken.IntValue == 0) { var nextLineMarker = interpreter.CopyCurrentStatementMarker(); nextLineMarker.MoveToNextLine(); interpreter.NextStatementMarker = nextLineMarker; return; } // Condition evaluated to true. Continue on... if (!((tokenMarker.Token is ThenToken) || tokenMarker.Token is GotoToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); if (tokenMarker.Token is NumericValueToken gotoLineValueToken) { var gotoLineMarker = interpreter.CreateStatementMarker(); gotoLineMarker.MoveToLine(gotoLineValueToken.IntValue); interpreter.NextStatementMarker = gotoLineMarker; return; } var commandToken = tokenMarker.Token as CommandToken; var variableNameToken = tokenMarker.Token as VariableNameToken; bool performMoveNext = true; if (commandToken == null && variableNameToken != null) { commandToken = (CommandToken)interpreter.TokensProvider.GetBuiltinToken("LET"); performMoveNext = false; } if (commandToken == null) { throw new Exceptions.SyntaxErrorException(); } // GOTO <linenumber> is fine, GOTO <command> is not! if (commandToken is GotoToken) { throw new Exceptions.SyntaxErrorException(); } // Execute the command following the THEN if (performMoveNext) { tokenMarker.MoveNext(); } commandToken.Execute(interpreter, tokenMarker); }
public override void Execute(Interpreter interpreter, TokenMarker tokenMarker) { var indexToken = interpreter.ExpressionEvaluator.Evaluate(tokenMarker); if (!(indexToken is NumericValueToken indexValueToken)) { throw new Exceptions.TypeMismatchException(); } var commandToken = tokenMarker.Token; if (!(commandToken is GosubToken || commandToken is GotoToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); var index = indexValueToken.IntValue; if (index < 0 || index > 255) { throw new Exceptions.IllegalQuantityException(); } if (index == 0) { return; } index -= 1; while (index > 0 && tokenMarker.Token != null) { var token = tokenMarker.Token; if (!(token is NumericValueToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); if (tokenMarker.Token == null) { break; } if (!(tokenMarker.Token is CommaToken)) { throw new Exceptions.SyntaxErrorException(); } tokenMarker.MoveNext(); index -= 1; } // Index was out of range. Continue on to the next statement. if (tokenMarker.Token == null) { return; } if (!(tokenMarker.Token is NumericValueToken lineNumberToken)) { throw new Exceptions.SyntaxErrorException(); } var lineNumber = lineNumberToken.IntValue; if (commandToken is GosubToken) { // Setup the return stack. var currentMarker = interpreter.CopyCurrentStatementMarker(); currentMarker.MoveToNextStatement(); interpreter.GosubMarkers.Push(currentMarker); } var gotoMarker = interpreter.CreateStatementMarker(); if (gotoMarker.MoveToLine(lineNumber) == false) { throw new Exceptions.UndefinedStatementException(); } interpreter.NextStatementMarker = gotoMarker; }