bool ProcessForNextState(Interpreter interpreter, ForNextLoopState forNextState, VariableNameToken variableNameToken = null) { // For NEXT with a variable name, check the variable name matches the one stored in the stack // if (variableNameToken != null && (forNextState.VariableNameToken.Name != variableNameToken.Name)) // throw new Exceptions.NextWithoutForException(); if (variableNameToken != null && (forNextState.VariableNameToken.Name != variableNameToken.Name)) { /* Get Calendar from David Ahl's BASIC Computer Games to work without producing * a NEXT WITHOUT FOR error. If the variable in NEXT [x] is not on top of the stack * like it should be, then pop variables off the stack until a name match is found. * If still no match, only then produce a NEXT WITHOUT FOR error. This supports the case * where the program GOTOs out of an inner loop to an outer loop. */ interpreter.ForNextLoops.Pop(); while (interpreter.ForNextLoops.Count > 0) { forNextState = interpreter.ForNextLoops.Peek(); if (forNextState.VariableNameToken.Name == variableNameToken.Name) { break; } // Discard this loop and try matching the next one interpreter.ForNextLoops.Pop(); } if (interpreter.ForNextLoops.Count == 0) { throw new Exceptions.NextWithoutForException(); } } var newValue = forNextState.CurrentValue.RealValue + forNextState.StepValue.RealValue; bool forNextLoopIsDone = false; if (forNextState.StepValue.RealValue >= 0) { forNextLoopIsDone = (newValue > forNextState.EndValue.RealValue); } else { forNextLoopIsDone = (newValue < forNextState.EndValue.RealValue); } if (forNextLoopIsDone) { interpreter.ForNextLoops.Pop(); return(true); } #if false // If done, pop the stack and return true if (forNextState.StartValue.RealValue <= forNextState.EndValue.RealValue) { if (newValue > forNextState.EndValue.RealValue) { interpreter.ForNextLoops.Pop(); return(true); } } else { var endValue = forNextState.EndValue.RealValue; bool isLessThan = (newValue < endValue); if (newValue > forNextState.EndValue.RealValue) { interpreter.ForNextLoops.Pop(); return(true); } } #endif // Keep going, set the NEXT variable and goto the first statement after the FOR forNextState.CurrentValue = interpreter.TokensProvider.CreateRealValueToken(newValue); interpreter.VariablesEnvironment.SetVariableValue(forNextState.VariableNameToken, forNextState.CurrentValue); if (forNextState.LoopMarker != null) { // If in immediate mode, there may be no valid statement to loop to. if (forNextState.LoopMarker.Valid) { var forNextStatement = new StatementMarker(forNextState.LoopMarker); interpreter.NextStatementMarker = forNextStatement; } } else { var index = forNextState.ImmediateModeStatementIndex; interpreter.CurrentImmediateModeStatementMarker.MoveTo(index); } // Not done return(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); }