public LexicalStateMachine()
        {
            CurrentState = LexicalMachineState.EMPTY;
            transitions  = new Dictionary <LexicalStateTransition, LexicalMachineState>
            {
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.DIGIT), LexicalMachineState.INT_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.LETTER), LexicalMachineState.VAR_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.QUOTE), LexicalMachineState.QUOTED_STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.SPECIAL), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.OPENING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.CLOSING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.DELIMITER), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.EMPTY, AtomType.CONTROL), LexicalMachineState.EMPTY },


                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.DIGIT), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.DELIMITER), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.LETTER), LexicalMachineState.STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.OPENING_PAR), LexicalMachineState.ARRAY_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.SPECIAL), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.VAR_TOKEN, AtomType.CONTROL), LexicalMachineState.EMPTY },

                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.DIGIT), LexicalMachineState.INT_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.SPECIAL), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.OPENING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.CLOSING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.DELIMITER), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.INT_TOKEN, AtomType.CONTROL), LexicalMachineState.EMPTY },

                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.LETTER), LexicalMachineState.STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.DIGIT), LexicalMachineState.STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.QUOTE), LexicalMachineState.STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.OPENING_PAR), LexicalMachineState.ARRAY_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.SPECIAL), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.CONTROL), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.STRING_TOKEN, AtomType.DELIMITER), LexicalMachineState.EMPTY },

                { new LexicalStateTransition(LexicalMachineState.QUOTED_STRING_TOKEN, AtomType.DIGIT), LexicalMachineState.QUOTED_STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.QUOTED_STRING_TOKEN, AtomType.LETTER), LexicalMachineState.QUOTED_STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.QUOTED_STRING_TOKEN, AtomType.DELIMITER), LexicalMachineState.QUOTED_STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.QUOTED_STRING_TOKEN, AtomType.SPECIAL), LexicalMachineState.QUOTED_STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.QUOTED_STRING_TOKEN, AtomType.QUOTE), LexicalMachineState.EMPTY },

                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.LETTER), LexicalMachineState.STRING_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.DIGIT), LexicalMachineState.INT_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.SPECIAL), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.OPENING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.CLOSING_PAR), LexicalMachineState.SPECIAL_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.DELIMITER), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.SPECIAL_TOKEN, AtomType.CONTROL), LexicalMachineState.EMPTY },

                { new LexicalStateTransition(LexicalMachineState.ARRAY_TOKEN, AtomType.DIGIT), LexicalMachineState.INDEX_OF_ARRAY_TOKEN },

                { new LexicalStateTransition(LexicalMachineState.INDEX_OF_ARRAY_TOKEN, AtomType.DIGIT), LexicalMachineState.INDEX_OF_ARRAY_TOKEN },
                { new LexicalStateTransition(LexicalMachineState.INDEX_OF_ARRAY_TOKEN, AtomType.CLOSING_PAR), LexicalMachineState.EMPTY },
                { new LexicalStateTransition(LexicalMachineState.INDEX_OF_ARRAY_TOKEN, AtomType.CONTROL), LexicalMachineState.EMPTY },
            };
        }
        public void MoveNext(AsciiAtom command)
        {
            LexicalMachineState nextState = GetNext(command.Category);

            if (nextState == LexicalMachineState.ARRAY_TOKEN && this.CurrentState == LexicalMachineState.VAR_TOKEN)
            {
                this.arrayToken = this.currentToken;
                this.ClearToken();
                this.CurrentState = nextState;

                return;
            }
            else if (this.CurrentState == LexicalMachineState.INDEX_OF_ARRAY_TOKEN && command.Category != AtomType.DIGIT)
            {
                this.indexOrSize = int.Parse(this.currentToken);
                this.ClearToken();
                this.OnTokenIdentified(command);
                this.CurrentState = nextState;

                return;
            }
            else if (nextState == LexicalMachineState.VAR_TOKEN && this.CurrentState == LexicalMachineState.EMPTY)
            {
                this.UpdateTokenState(command);
                this.CurrentState = nextState;

                return;
            }
            else if (nextState == LexicalMachineState.EMPTY && this.CurrentState == LexicalMachineState.VAR_TOKEN ||
                     nextState == LexicalMachineState.EMPTY && this.CurrentState == LexicalMachineState.QUOTED_STRING_TOKEN)
            {
                this.UpdateTokenState(command);
                this.OnTokenIdentified(command);
                this.ClearToken();

                this.CurrentState = nextState;

                return;
            }
            else if (nextState == LexicalMachineState.EMPTY && command.Category == AtomType.CONTROL ||
                     nextState == LexicalMachineState.EMPTY && this.CurrentState != LexicalMachineState.EMPTY ||
                     nextState == LexicalMachineState.SPECIAL_TOKEN &&
                     (this.CurrentState == LexicalMachineState.STRING_TOKEN || this.CurrentState == LexicalMachineState.INT_TOKEN || this.CurrentState == LexicalMachineState.SPECIAL_TOKEN) ||
                     this.CurrentState == LexicalMachineState.SPECIAL_TOKEN &&
                     (nextState == LexicalMachineState.INT_TOKEN || nextState == LexicalMachineState.STRING_TOKEN))
            {
                this.OnTokenIdentified(command);
                this.ClearToken();
            }

            this.UpdateTokenState(command);
            this.CurrentState = nextState;
        }
        public LexicalMachineState GetNext(AtomType command)
        {
            LexicalMachineState    nextState  = this.CurrentState;
            LexicalStateTransition transition = new LexicalStateTransition(CurrentState, command);

            if (!transitions.TryGetValue(transition, out nextState))
            {
                throw new Exception("Lexical: Invalid transition: " + CurrentState + " -> " + command);
            }

            Console.WriteLine("Lexical :" + this.CurrentState + " -> " + nextState + " : " + command.ToString());

            return(nextState);
        }
        public Token(LexicalMachineState state, string tokenString, AsciiAtom command)
        {
            this.Text = tokenString;

            if (state == LexicalMachineState.STRING_TOKEN)
            {
                this.Type = this.Text.ToUpper() switch
                {
                    "PRINT" => TokenType.PRINT,
                    "DIM" => TokenType.DIM,
                    "LET" => TokenType.LET,
                    "READ" => TokenType.READ,
                    "DATA" => TokenType.DATA,
                    "FOR" => TokenType.FOR,
                    "TO" => TokenType.TO,
                    "NEXT" => TokenType.NEXT,
                    "GO" => TokenType.GO,
                    "GOTO" => TokenType.GOTO,
                    "GOSUB" => TokenType.GOSUB,
                    "RETURN" => TokenType.RETURN,
                    "REM" => TokenType.REMARK,
                    "IF" => TokenType.IF,
                    "STEP" => TokenType.STEP,
                    "THEN" => TokenType.THEN,
                    "END" => TokenType.FINAL,
                    _ => TokenType.STRING
                };
            }
            else if (state == LexicalMachineState.INT_TOKEN)
            {
                this.Type = TokenType.INT;
            }
            else if (state == LexicalMachineState.SPECIAL_TOKEN)
            {
                this.Type = this.Text switch
                {
                    "=" => TokenType.EQUALS,
                    ":=" => TokenType.EQUALS,
                    ">" => TokenType.GREATER,
                    ">=" => TokenType.GREATER_OR_EQUAL,
                    "<" => TokenType.LESS,
                    "<=" => TokenType.LESS_OR_EQUAL,
                    "<>" => TokenType.NOT_EQUAL,
                    "(" => TokenType.OPENING_BRACES,
                    ")" => TokenType.CLOSING_BRACES,
                    "," => TokenType.COMMA,
                    "+" => TokenType.PLUS,
                    "-" => TokenType.MINUS,
                    "*" => TokenType.MULT,
                    "/" => TokenType.DIV,
                    _ => TokenType.ERROR
                };
            }
            else if (state == LexicalMachineState.VAR_TOKEN)
            {
                this.Type = TokenType.VAR;
            }
            else if (state == LexicalMachineState.QUOTED_STRING_TOKEN)
            {
                this.Type = TokenType.QUOTED_STRING;
            }
            else if (command.Category == AtomType.CONTROL)
            {
                this.Type = TokenType.END;
            }
            else
            {
                this.Type = TokenType.ERROR;
            }
        }
 public LexicalStateTransition(LexicalMachineState currentState, AtomType command)
 {
     this.CurrentState = currentState;
     this.Command      = command;
 }