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) { if (tokenMarker.Token == null) { interpreter.Run(); return; } if (!(tokenMarker.Token is NumericValueToken numericValueToken)) { throw new Exceptions.SyntaxErrorException(); } if (tokenMarker.PeekNext() != null) { throw new Exceptions.SyntaxErrorException(); } interpreter.Run(numericValueToken.IntValue); }
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; } } }