def p_procedure_name(p):
    '''procedure_name :  NAME'''
    p[0] = Node("procedure_name", p[1])

    table.define(p[1], 'integer', 'procedure')
    table.add_scope(p[1], 'function', 'integer')
    p[0].name = p[1]
def p_val_para_list(p):
    # 值传递
    '''val_para_list :  name_list
                    '''
    p[0] = Node("val_para_list", [p[1]])

    p[0].list = p[1].list
def p_else_clause(p):
    '''else_clause :  ELSE stmt
                |  empty'''
    if len(p) == 3:
        p[0] = Node("else_clause", [p[2]])
    else:
        p[0] = Node("else_clause", [p[1]])
def p_function_name(p):
    '''function_name : NAME '''
    p[0] = Node("function_name", p[1])

    table.define(p[1], 'integer', 'function')
    table.add_scope(p[1], 'function', 'integer')
    p[0].name = p[1]
def p_var_decl_list(p):
    '''var_decl_list :  var_decl_list  var_decl
                |  var_decl'''
    if len(p) == 3:
        p[0] = Node("var_decl_list", [p[1], p[2]])
    else:
        p[0] = Node("var_decl_list", [p[1]])
def p_case_expr_list(p):
    '''case_expr_list :  case_expr_list  case_expr
                |  case_expr'''
    if len(p) == 3:
        p[0] = Node("case_expr_list", [p[1], p[2]])
    else:
        p[0] = Node("case_expr_list", [p[1]])
def p_const_part(p):
    '''const_part :  CONST  const_expr_list
                |  empty'''
    if len(p) == 3:
        p[0] = Node("const_part", [p[2]])
    elif len(p) == 2:
        p[0] = Node("const_part", [])
def p_var_part(p):
    '''var_part :  VAR  var_decl_list
                |  empty'''
    if len(p) == 3:
        p[0] = Node("var_part", [p[2]])
    else:
        p[0] = Node("var_part", [p[1]])
def p_type_decl_list(p):
    '''type_decl_list :  type_decl_list  type_definition
                |  type_definition'''
    if len(p) == 3:
        p[0] = Node("type_decl_list", [p[1], p[2]])
    else:
        p[0] = Node("type_decl_list", [p[1]])
def p_type_decl(p):
    '''type_decl :  simple_type_decl
                |  array_type_decl
                |  record_type_decl'''
    p[0] = Node("type_decl", [p[1]])

    p[0].type = p[1].type
def p_type_part(p):
    '''type_part :  TYPE type_decl_list
                |  empty'''
    if len(p) == 3:
        p[0] = Node("type_part", [p[2]])
    else:
        p[0] = Node("type_part", [p[1]])
def p_const_value(p):
    '''const_value :  INTEGER
                |  REAL
                |  CHAR
                |  STRING
                |  SYS_CON
                | true
                | false'''
    p[0] = Node("const_value", p[1])

    p[0].value = p[1]

    if type(p[1]) == int:
        p[0].type = 'integer'

    elif type(p[1]) == float:
        p[0].type = 'real'

    elif type(p[1]) == str:
        p[0].type = 'char'

    if str(p[1]).lower() == 'true':
        p[0].type = 'boolean'
        p[0].value = True

    if str(p[1]).lower() == 'false':
        p[0].type = 'boolean'
        p[0].value = False
def p_const_expr_list(p):
    '''const_expr_list :  const_expr_list  const_expr
                |  const_expr'''
    if len(p) == 3:
        p[0] = Node("const_expr_list", [p[1], p[2]])
    elif len(p) == 2:
        p[0] = Node("const_expr_list", [p[1]])
def p_stmt(p):
    '''stmt :  stmt_label  non_label_stmt
            |  non_label_stmt'''
    if len(p) == 3:
        p[0] = Node("stmt", [p[2]])
    else:
        p[0] = Node("stmt", [p[1]])
def p_stmt_list(p):
    '''stmt_list :  stmt_list  stmt  SEMI
                |  empty'''
    if len(p) == 4:
        p[0] = Node("stmt_list", [p[1], p[2]])
    else:
        p[0] = Node("stmt_list", [p[1]])
def p_factor_not(p):
    '''factor :  NOT factor'''

    p[0] = Node("factor", [p[2]])

    symbol = table.get_temp(type_of_node(p[2]))
    emit('NOT', symbol, p[2])
    p[0].symbol = symbol
def p_factor_minus(p):
    '''factor :  MINUS factor'''

    p[0] = Node("factor", [p[2]])

    symbol = table.get_temp(type_of_node(p[2]))
    emit('-', symbol, 0, p[2])
    p[0].symbol = symbol
def p_while_label1(p):
    '''while_label1 :  '''
    p[0] = Node("", [])

    p[0].label1 = table.get_label()
    p[0].label3 = table.get_label()

    emit('LABEL', p[0].label1)
def p_factor_1(p):
    '''factor :    LP  expression  RP '''
    p[0] = Node("factor", [p[2]])

    if hasattr(p[2], 'symbol'):
        p[0].symbol = p[2].symbol
    else:
        p[0].value = p[2].value
        p[0].type = p[2].type
def p_if_label1(p):
    '''if_label1 :  '''

    p[0] = Node("", [])

    p[0].label2 = table.get_label()
    p[0].label3 = table.get_label()

    emit('BEQ', p[0].label2, p[-2], False)
def p_factor_array(p):
    '''factor : NAME LB expression RB '''
    # FIXME: 这个地方只有可能是在右边的数组索引,而不是左边的,所以将内容载入到临时变量里面吧
    p[0] = Node("p_factor_array", [p[3]])
    # FIXME: 也需要创建一个临时变量

    symbol = table.get_identifier(p[1])
    symbol = table.get_temp(type_of_node(symbol))
    emit('LOADREF', symbol, p[1], p[3])
    p[0].symbol = symbol
def p_routine_part(p):
    '''routine_part :  routine_part  function_decl
                |  routine_part  procedure_decl
                |  function_decl
                |  procedure_decl
                | empty'''
    if len(p) == 3:
        p[0] = Node("routine_part", [p[1], p[2]])
    else:
        p[0] = Node("routine_part", [p[1]])
def p_factor_name(p):
    '''factor :  NAME'''
    p[0] = Node('factor', [p[1]])

    symbol = table.get_identifier(p[1])

    if symbol.var_function == 'function':
        if table.scope().name.endswith('.' + symbol.name):
            symbol = table.get_identifier('_return')

    p[0].symbol = symbol
def p_array_type_decl(p):
    '''array_type_decl :  ARRAY  LB  INTEGER  DOTDOT  INTEGER  RB  OF  type_decl'''
    #         0             1    2      3       4        5     6   7       8
    # TODO 只支持常数中的整数,并且是单维
    # '''array_type_decl :  ARRAY  LB  simple_type_decl  RB  OF  type_decl'''
    p[0] = Node("array_type_decl", [p[3], p[5], p[8]])

    symbol = table.get_temp('array', 'type', {
        'data_type': p[8].type,
        'dimension': [(p[3], p[5])]
    })
    p[0].type = symbol.name
def p_for_label1(p):
    '''for_label1 :  '''
    p[0] = Node("", [])

    symbol = table.get_identifier(p[-6])
    emit('+', symbol, p[-4], 0)

    p[0].label1 = table.get_label()
    p[0].label2 = table.get_label()
    p[0].symbol = symbol

    emit('LABEL', p[0].label1)
def p_factor_2(p):
    '''factor : NAME  DOT  NAME'''

    p[0] = Node("p_factor_1", [p[1], p[2], p[3]])
    symbol = table.get_identifier(p[1])
    params = symbol.get_params()
    try:
        symbol = table.get_temp(
            [a_tuple for a_tuple in params if a_tuple[0] == p[3]][0][1])
    except IndexError:
        raise ValueError("Dot index error")
    emit('LOADREF', symbol, p[1], p[3])
    p[0].symbol = symbol
def p_expr(p):
    '''expr :  expr  PLUS  term
                |  expr  MINUS  term
                |  expr  OR  term
                |  term'''
    if len(p) == 2:
        p[0] = Node("expr-term", [p[1]])

        if hasattr(p[1], 'symbol'):
            p[0].symbol = p[1].symbol
        else:
            p[0].value = p[1].value
            p[0].type = p[1].type

    else:
        p[0] = Node("expr-expr", [p[1], p[3]])

        if p[2] == 'or':
            symbol = table.get_temp('boolean')
        else:
            print(type_of_node(p[1]))
            print(type_of_node(p[3]))

            if type_of_node(p[1]) == 'real' or type_of_node(p[3]) == 'real':
                symbol = table.get_temp('real')
            else:
                symbol = table.get_temp('integer')

        emit(p[2], symbol, p[1], p[3])
        p[0].symbol = symbol
def p_function_head(p):
    '''function_head :  FUNCTION  function_name  parameters  COLON  simple_type_decl '''
    p[0] = Node("function_head", [p[3], p[5]])

    for name, type, reference in p[3].list:
        table.define(name, type, reference=reference)
    table.define('_return', p[5].type, 'var', p[3].list)

    table.scope().return_type = p[5].type
    table.get_identifier(p[2].name).type = p[5].type
    table.get_identifier(p[2].name).params = p[3].list

    symbol = table.get_identifier('_return')
    p[0].symbol = symbol
    emit("LABEL", p[2].name, table.scope().name)
def p_if_label2(p):
    '''if_label2 :  '''

    p[0] = Node("", [])

    emit('JMP', p[-2].label3)
    emit('LABEL', p[-2].label2)
def p_proc_stmt_read(p):
    '''proc_stmt : READ  LP  factor  RP'''
    p[0] = Node("proc_stmt", [p[3]])

    if hasattr(p[3], 'symbol'):
        emit("INPUT", p[3].symbol)
    else:
        raise ValueError("destination is not variable")