Compiler Creation - [Illegal Character]: 'V' is not allowed

Hello,
I am creating a compiler using Python but I keep getting this strange error from my compiler (NOT python) the reason why it’s strange is because the way I formatted it shouldn’t give me an error

Anyways here’s the results:
Input: “@O 45 V ABC”;
Expected Output (Something like this): “OUTPUT: VAR ABC”
Actual Output: “[Illegal Character]: ‘V’ is not allowed”

Here’s the code:
shell.py (The script I’m running):

#===================================
#[SSP] BASIC PROGRAMMING LANGUAGE
#[PROJECT] START DATE: 12/11/2022
#Samm
#===================================
import ssp_basic

while True:
    text = input('SSP BASIC: ')
    if(text == "EXIT"):
        break
    result, error = ssp_basic.run(text)
    print(text)

    if(error):
        print(error)
    else:
        print(result)

ssp_basic.py:

#===================================
#[SSP] BASIC PROGRAMMING LANGUAGE
#[PROJECT] START DATE: 12/11/2022
#Samm
#===================================
DIGITS = '0123456789'

class Error:
    def __init__(self, error_name, details):
        self.error_name = error_name
        self.details = details

    def as_string(self):
        result = f'[{self.error_name}]: {self.details}'
        return result

    def __repr__(self):
        return self.as_string()

class IllegalCharError(Error):
    def __init__(self, details):
        super().__init__('Illegal Character', details)

TT_DEFINE               = 'DEFINE'
TT_INPUT                = 'INPUT'
TT_OUTPUT               = 'OUTPUT'
TT_VAR_SET              = 'SETVAR'
TT_ARR_SET              = 'SETARR'
TT_VAR_GET              = 'GETVAR'
TT_ARR_GET              = 'GETARR'
TT_IF                   = 'IF'
TT_ELSE                 = 'ELSE'
TT_WHILE                = 'WHILE'
TT_INT                  = 'INT'
TT_FLOAT                = 'FLOAT'
TT_BINARY               = 'BINARY'
TT_HEX                  = 'HEX'
TT_STR                  = 'STR'
TT_CHAR                 = 'CHAR'
TT_PLUS                 = 'PLUS'
TT_MINUS                = 'MINUS'
TT_MUL                  = 'MUL'
TT_DIV                  = 'DIV'
TT_LPAREN               = 'LPAREN'
TT_RPAREN               = 'RPAREN'
TT_COLON                = 'COLON'
TT_SEMI_COLON           = 'SEMICOLON'
#TT_COMMENT              = 'COMMENT'

class Token:
    def __init__(self, type_, values={None}):
        self.type = type_
        self.values = values

    def __repr__(self):
        if(self.values != None):
            return f'{self.type}: {self.values}'
        return f'{self.type}'

class Lexer:
    def __init__(self, text):
        self.text = text
        self.pos = -1
        self.current_char = None
        self.build_platform = 0
        self.vars = {None}
        self.advance()

    def advance(self):
        self.pos += 1
        self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
    
    def advance_multiple(self, advances):
        self.pos += advances
        self.current_char = self.text[self.pos] if self.pos < len(self.text) else None
    
    def make_tokens(self):
        tokens = []
        while(self.current_char != None):
            if(self.current_char in ' \t'):
                self.advance()
            elif(self.current_char in DIGITS):
                tokens.append(self.make_number)
                self.advance()
            elif(self.current_char == "#"):
                tokens.append(self.make_def)
                self.advance()
            elif(self.current_char == "@"):
                self.advance()
                if(self.current_char == 'I'):
                    tokens.append(self.make_input)
                    self.advance()
                elif(self.current_char == 'O'):
                    tokens.append(self.make_output)
                    self.advance()
                else:
                    char = self.current_char
                    self.advance()
                    return [], IllegalCharError("'" + char + "' is not allowed after IO (AKA '@')")
            elif(self.current_char == '!'): #Set variable or array
                self.advance()
                if(self.current_char == 'S'):
                    if(self.current_char == 'V'):
                        self.make_set_variable()
                    elif(self.current_char == 'A'):
                        self.make_set_array()
                    else:
                        char = self.current_char
                        self.advance()
                        return [], IllegalCharError("'" + char + "' is not allowed after VARIABLE TYPE (AKA '!')\nTypes Allowed: V - Variable, A - Array")
                elif(self.current_char == 'G'):
                    if(self.current_char == 'V'):
                        self.make_get_variable()
                    elif(self.current_char == 'A'):
                        self.make_get_array()
                    else:
                        char = self.current_char
                        self.advance()
                        return [], IllegalCharError("'" + char + "' is not allowed after VARIABLE TYPE (AKA '!')\nTypes Allowed: V - Variable, A - Array")
                else:
                    return [], IllegalCharError("'" + char + "' is not allowed after VARIABLE TYPE (AKA '!')\nTypes Allowed: S - Set, G - Get")
            elif(self.current_char == 'B'):
                tokens.append(self.make_bin_num)
                self.advance()
            elif(self.current_char == 'H'):
                tokens.append(self.make_hex_num)
                self.advance()
            elif(self.current_char == 'S'):
                tokens.append(self.make_str)
                self.advance()
            elif(self.current_char == 'C'):
                self.advance_multiple(2)
                tokens.append(Token(TT_CHAR, self.current_char))
                self.advance()
            elif(self.current_char == '+'):
                tokens.append(Token(TT_PLUS))
                self.advance()
            elif(self.current_char == '-'):
                tokens.append(Token(TT_MINUS))
                self.advance()
            elif(self.current_char == '*'):
                tokens.append(Token(TT_MUL))
                self.advance()
            elif(self.current_char == '/'):
                tokens.append(Token(TT_DIV))
                self.advance()
            elif(self.current_char == '('):
                tokens.append(Token(TT_LPAREN))
                self.advance()
            elif(self.current_char == ')'):
                tokens.append(Token(TT_RPAREN))
                self.advance()
            elif(self.current_char == '/'):
                self.advance()
                if(self.current_char == '/'):
                    while(self.current_char != '\n'):
                        self.advance()
                    
                    self.advance()
            else:
                char = self.current_char
                self.advance()
                return [], IllegalCharError("'" + char + "' is not allowed")
        return tokens, None

    def make_number(self):
        num_str = ''
        dot_count = 0

        while(self.current_char != None and self.current_char in DIGITS + '.'):
            if(self.current_char == '.'):
                if(dot_count == 1):
                    break
                dot_count += 1
                num_str += '.'
            else:
                num_str += self.current_char

            self.advance()

        if(dot_count == 0):
            return Token(TT_INT, int(num_str))
        else:
            return Token(TT_FLOAT, float(num_str))

    def make_input(self):
        input_src_num_str = ''

        self.advance()
        while(self.current_char != None and self.current_char in DIGITS):
            input_src_num_str += self.current_char

            self.advance()
        
        return Token(TT_INPUT, int(input_src_num_str))

    def make_output(self):
        output_src_num_str = ''

        self.advance()
        while(self.current_char != None and self.current_char.isspace() == True):
            self.advance()
        while(self.current_char != None and self.current_char.isspace() == False and self.current_char in DIGITS):
            output_src_num_str += self.current_char
            self.advance()

        while(self.current_char != None and self.current_char != ';'):
            if(self.current_char == 'V'):
                self.advance_multiple(2)
                output_var_num_str = ''
                while(self.current_char != None and self.current_char != ';'):
                    output_var_num_str += self.current_char
                    self.advance()
                return Token(TT_OUTPUT, int({output_src_num_str, 'VAR', output_var_num_str}))
            elif(self.current_char == 'N'):
                self.advance_multiple(2)
                output_data_num_str = ''
                while(self.current_char != None and self.current_char != ';'):
                    if(self.current_char in DIGITS):
                        output_data_num_str += self.current_char
                        self.advance()
                    else:
                        return [], IllegalCharError("'" + self.current_char + "' is not allowed, Must be a INTEGER or terminater (';')")
                return Token(TT_OUTPUT, int({output_src_num_str, 'NUM', int(output_data_num_str)}))
            self.advance()

        return [], IllegalCharError("'" + self.current_char + "' is not allowed when outputing at that stage")

    def make_def(self):
        def_str = ''

        self.advance()
        while(self.current_char != None and self.current_char != '\n'):
            def_str += self.current_char
            self.advance()
        
        if('BUILD_PLATFORM' in def_str):
            if('01' in def_str):
                self.build_platform = 1 #Arm Microcontroller (GNU)
            elif('02' in def_str):
                self.build_platform = 2

class NumberNode:
    def __init__(self, tok):
        self.tok = tok

    def __repr__(self):
        return f'{self.tok}'

class BinOpNode:
    def __init__(self, left_node, op_tok, right_node):
        self.left_node = left_node
        self.op_tok = op_tok
        self.right_node = right_node

    def __repr__(self):
        return f'({self.left_node}, {self.op_tok}, {self.right_node})'

class Parser:
    def __init__(self, tokens):
        self.tokens = tokens
        self.tok_index = 1
        self.advance()

    def advance(self):
        self.tok_index += 1
        if(self.token_index < len(self.tokens)):
            self.current_tok = self.tokens[self.tok_index]
        return self.current_tok

    def factor(self):
        tok = self.current_tok

        if(tok.type in (TT_INT, TT_FLOAT)):
            self.advance()
            return NumberNode(tok)

    def term(self):
        left = self.factor()

        while(self.current_tok in (TT_MUL, TT_DIV)):
            op_tok = self.current_tok
            self.advance()
            right = self.factor()
            left = BinOpNode(left, op_tok, right)

        return left

    def expr(self):
        pass

def run(text):
    lexer = Lexer(text)
    tokens, error = lexer.make_tokens()

    return tokens, error

Anyways if you think you might know how to fix this please tell me your idea
Thanks in advance!

-Samm

I would add print statements at key points to show the state of the parsing.
You should then be able to notice where code is not doing what you intended.

I think I figured it out it isn’t running this function on line 94: “tokens.append(self.make_output)” specifically: self.make_output
why?

Edit: Just figured it out I forgot the () noob mistake sorry

Glad you found it! I make “noob” mistakes all the time… :wink: