Example #1
0
        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);
        }
Example #2
0
        void SetArrayVariableValue(VariableNameToken variableNameToken, ValueTokenArray indicies, ValueToken value)
        {
            switch (variableNameToken.VariableType)
            {
            case VariableValueType.String:
                var stringValueToken = (StringValueToken)value;
                SetStringArrayVariableValue(variableNameToken, indicies, stringValueToken);
                break;

            case VariableValueType.RealNumber:
                if (value is IntegerValueToken integerValueToken)
                {
                    value = new RealValueToken(integerValueToken.RealValue);
                }

                SetRealNumberArrayVariableValue(variableNameToken, indicies, (RealValueToken)value);
                break;

            case VariableValueType.IntegerNumber:
                if (value is RealValueToken realValueToken)
                {
                    IntegerValueToken.CheckValueBounds(realValueToken.RealValue);
                    value = new IntegerValueToken((Int16)realValueToken.IntValue);
                }
                SetIntegerNumberArrayVariableValue(variableNameToken, indicies, (IntegerValueToken)value);
                break;
            }
        }
Example #3
0
        void SetIntegerNumberArrayVariableValue(VariableNameToken variableNameToken, ValueTokenArray indicies, IntegerValueToken value)
        {
            if (integerVariableArray.TryGetValue(variableNameToken.Name, out var numberArray) == false)
            {
                numberArray = CreateIntegerNumberArrayVariable(variableNameToken,
                                                               ConvertTokensArrayToIntArray(indicies, AdjustDimensionForUndimensionedCreate));
            }

            numberArray.SetValue(ConvertTokensArrayToIntArray(indicies), value);
        }
Example #4
0
        void SetStringArrayVariableValue(VariableNameToken variableNameToken, ValueTokenArray indicies, StringValueToken value)
        {
            if (stringVariableArray.TryGetValue(variableNameToken.Name, out var stringArray) == false)
            {
                stringArray = CreateStringArrayVariable(variableNameToken,
                                                        ConvertTokensArrayToIntArray(indicies, AdjustDimensionForUndimensionedCreate));
            }

            stringArray.SetValue(ConvertTokensArrayToIntArray(indicies), value);
        }
Example #5
0
 public void SetVariableValue(VariableNameToken variableNameToken, ValueTokenArray indicies, ValueToken value)
 {
     if (indicies == null)
     {
         SetVariableValue(variableNameToken, value);
     }
     else
     {
         SetArrayVariableValue(variableNameToken, indicies, value);
     }
 }
Example #6
0
        int[] ConvertTokensArrayToIntArray(ValueTokenArray valueTokenArray, int adjustAmount = 0)
        {
            var length = valueTokenArray.Values.Length;

            int[] intArray = new int[length];
            for (int i = 0; i < length; i += 1)
            {
                intArray[i] = ((NumericValueToken)(valueTokenArray.Values[i])).IntValue + adjustAmount;
            }

            return(intArray);
        }
Example #7
0
        int[] ConvertTokensArrayToIntArray(ValueTokenArray valueTokenArray, Func <int, int> convertFunc)
        {
            var length = valueTokenArray.Values.Length;

            int[] intArray = new int[length];
            for (int i = 0; i < length; i += 1)
            {
                var value = ((NumericValueToken)(valueTokenArray.Values[i])).IntValue;
                intArray[i] = convertFunc(value);
            }

            return(intArray);
        }
Example #8
0
        ValueToken GetIntegerArrayValue(VariableNameToken variableNameToken, ValueTokenArray indicies)
        {
            if (integerVariableArray.TryGetValue(variableNameToken.Name, out var numberArray) == false)
            {
                numberArray = CreateIntegerNumberArrayVariable(variableNameToken,
                                                               ConvertTokensArrayToIntArray(indicies, AdjustDimensionForUndimensionedCreate));
            }

            var result = numberArray.GetValue(ConvertTokensArrayToIntArray(indicies));

            if (result == null)
            {
                result = interpreter.TokensProvider.CreateIntegerValueToken(0);
            }

            return(result);
        }
Example #9
0
        ValueToken GetStringArrayValue(VariableNameToken variableNameToken, ValueTokenArray indicies)
        {
            if (stringVariableArray.TryGetValue(variableNameToken.Name, out var stringArray) == false)
            {
                stringArray = CreateStringArrayVariable(variableNameToken,
                                                        ConvertTokensArrayToIntArray(indicies, AdjustDimensionForUndimensionedCreate));
            }

            var result = stringArray.GetValue(ConvertTokensArrayToIntArray(indicies));

            if (result == null)
            {
                result = interpreter.TokensProvider.CreateStringValueToken(string.Empty);
            }

            return(result);
        }
Example #10
0
        public ValueToken GetArrayVariableValue(VariableNameToken variableNameToken, ValueTokenArray indicies)
        {
            switch (variableNameToken.VariableType)
            {
            case VariableValueType.String:
                return(GetStringArrayValue(variableNameToken, indicies));

            case VariableValueType.RealNumber:
                return(GetRealArrayValue(variableNameToken, indicies));

            case VariableValueType.IntegerNumber:
                return(GetIntegerArrayValue(variableNameToken, indicies));

            default:
                throw new NotImplementedException();
            }
        }
        // Convert the indicies portion of an array variable into an array of values.
        ValueTokenArray EvaluateVariableAssignmentToken(Token token)
        {
            var variableNameToken = (VariableNameToken)token;
            var argsCount         = arrayCount.Pop();

            var args = new ValueToken[argsCount];

            // The arguments are popped in reverse order,
            // so it's easier to store them in the array in reverse order too.
            while (argsCount > 0)
            {
                argsCount -= 1;
                var arg = valueTokens.Pop();
                args[argsCount] = arg;
            }

            var result = new ValueTokenArray(args);

            return(result);
        }
Example #12
0
        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
            }
        }
Example #13
0
        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);
                }
            }
        }
Example #14
0
        bool AssignInputToVariable(Interpreter interpreter, VariableNameToken variableNameToken, ValueTokenArray indicies, string parsedInput)
        {
            switch (variableNameToken.VariableType)
            {
            case VariableValueType.String:
                StringValueToken stringValueToken;

                // Strip the quotes before setting the value to the variable.
                if (parsedInput.StartsWith('\"'))
                {
                    int endIndex = parsedInput.Length;
                    if (parsedInput[endIndex - 1] == '\"')
                    {
                        endIndex -= 1;
                    }
                    stringValueToken = interpreter.TokensProvider.CreateStringValueToken(parsedInput.Substring(1, endIndex - 1 - 1));
                }
                else
                {
                    stringValueToken = interpreter.TokensProvider.CreateStringValueToken(parsedInput);
                }

                interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, indicies, stringValueToken);

                return(true);

            case VariableValueType.RealNumber:
                // If the string starts with a quote, it's an error.
                // ... even if what's in quotes can parse to a number
                if (parsedInput[0] == '\"')
                {
                    return(false);
                }

                // If the conversion fails, it's an error.
                if (float.TryParse(parsedInput, out float realValue) == false)
                {
                    return(false);
                }

                var realValueToken = interpreter.TokensProvider.CreateRealValueToken(realValue);
                interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, indicies, realValueToken);

                break;

            case VariableValueType.IntegerNumber:
                // If the string starts with a quote, it's an error.
                // ... even if what's in quotes can parse to a number
                if (parsedInput[0] == '\"')
                {
                    return(false);
                }

                // If the conversion fails, it's an error.
                if (Int16.TryParse(parsedInput, out Int16 intValue) == false)
                {
                    return(false);
                }

                var intValueToken = interpreter.TokensProvider.CreateIntegerValueToken(intValue);
                interpreter.VariablesEnvironment.SetVariableValue(variableNameToken, indicies, intValueToken);
                break;
            }
            return(true);
        }
Example #15
0
        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;
                }
            }
        }
Example #16
0
        public void DimensionArrayVariable(VariableNameToken variableNameToken, ValueTokenArray valueTokens)
        {
            var dimensions = ConvertTokensArrayToIntArray(valueTokens, 1);

            CreateArrayVariable(variableNameToken, dimensions);
        }