import lexer

loop_program = '''x1 := 2;
x2 := 3;
x3 := x2 + 0;
LOOP x1 DO
    x2 := x3 + 1;
    x3 := x2 + 0
END;
x0 := x2 + 0'''


def process_assignment(token_queue, position, value_list, forbidden_identifiers):
    identifier_1 = token_queue[position].v
    if identifier_1 in forbidden_identifiers:
        raise Exception("Identifier " + identifier_1 + "ist bereits in Loop vorhanden und darf nicht verwendet werden.")
    if not token_queue[position + 1].k == 'EQUALS':
        raise SyntaxError(":= in Zuweisung erwartet.")

    if identifier_1 in value_list:
        value_1 = value_list.get(identifier_1)
    else:
        value_1 = 0

    if token_queue[position + 2].k == 'NUMBER':
        value_1 += int(token_queue[position + 2].v)
        value_list.update({identifier_1: value_1})
        return position+3, value_list

    if not token_queue[position + 2].k == 'IDENTIFIER':
        raise SyntaxError("IDENTIFIER in Zuweisung erwartet.")
    identifier_2 = token_queue[position + 2].v
    if identifier_2 in forbidden_identifiers:
        raise Exception("Identifier " + identifier_2 + " ist bereits in Loop vorhanden und darf nicht verwendet werden.")

    if identifier_2 in value_list:
        value_2 = value_list.get(identifier_2)
    else:
        value_2 = 0

    if not token_queue[position + 4].k == 'NUMBER':
        raise SyntaxError("NUMBER in Zuweisung erwartet.")
    if token_queue[position + 3].k == 'PLUS':
        value_1 = value_2 + int(token_queue[position + 4].v)
    elif token_queue[position + 3].k == 'MINUS':
        value_1 = max(0, value_2 + token_queue[position + 4].v)
    else:
        raise SyntaxError("PLUS oder MINUS in Zuweisung erwartet.")
    value_list.update({identifier_1: value_1})
    return position + 5, value_list

def process_loop(token_queue, position, value_list, forbidden_identifiers):
    identifier_token = token_queue[position+1]
    if not identifier_token.k == 'IDENTIFIER':
        raise SyntaxError('IDENTIFIER in LOOP erwartet.')
    if not token_queue[position+2].k == 'DO':
        raise SyntaxError('DO in LOOP erwartet.')

    number_of_loops = int(value_list.get(identifier_token.v))
    saved_position = position + 3
    forbidden_identifiers.append(identifier_token.v)
    for index in range(number_of_loops):
        position = saved_position
        end_found = False
        while(not end_found):
            position, value_list = process_program(token_queue, position, value_list, forbidden_identifiers)
            if token_queue[position].k == 'SEMICOLON':
                position = position + 1
                continue
            elif token_queue[position].k == 'END':
                end_found = True
            else: raise SyntaxError("SEMICOLON oder END erwartet.")
    return position+1, value_list

def process_program(token_queue, position, value_list, forbidden_identifiers):
    current_key = token_queue[position].k
    if current_key == 'IDENTIFIER':
        try:
            current_position, values = process_assignment(token_queue, position, value_list, forbidden_identifiers)
        except IndexError:
            raise Exception("Frühzeitiges Ende einer Zuweisung.")
    elif current_key == 'LOOP':
        try:
            current_position, values = process_loop(token_queue, position, value_list, forbidden_identifiers)
        except IndexError:
            raise Exception("Frühzeitiges Ende eines LOOPs")
    else:
        raise SyntaxError("Keine passende Anweisung gefunden")
    return current_position, values

def interpret(program):
    tokens = lexer.tokenize(program)
    current_position = 0
    values = {}
    forbidden_identifiers = []
    while current_position < len(tokens):
        current_position, values = process_program(tokens, current_position, values, forbidden_identifiers)
        if current_position < len(tokens) and not tokens[current_position].k == 'SEMICOLON':
            raise SyntaxError("Semicolon erwartet")
        else:
            current_position = current_position + 1
    if "x0" in values:
        return values.get("x0")
    return 0

print(interpret(loop_program))