# -----------------------------------------------------------------------------
# calc.py
#
# A calculator parser that makes use of closures. The function make_calculator()
# returns a function that accepts an input string and returns a result.  All 
# lexing rules, parsing rules, and internal state are held inside the function.
# -----------------------------------------------------------------------------

import sys
sys.path.insert(0,"../..")

if sys.version_info[0] >= 3:
    raw_input = input

# Make a calculator function

def make_calculator():
    import ply.lex as lex
    import ply.yacc as yacc

    # ------- Internal calculator state

    variables = { }       # Dictionary of stored variables

    # ------- Calculator tokenizing rules

    tokens = (
        'NAME','NUMBER', 'times', 'divided_by', 'plus', 'plus_text', 'minus', 'minus_text', 'times_text', 'divided_by_text'
    )

    literals = ['=','+','-','*','/', '(',')']

    t_ignore = " \t"

    t_plus    = r'\+'
    t_plus_text =r'plus'
    t_minus   = r'-'
    t_minus_text   = r'minus'
    t_times   = r'\*'
    t_times_text   = r'times'
    t_divided_by  = r'/'
    t_divided_by_text  = r'divided_by'
    t_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'

    def t_NUMBER(t):
        r'\d+'
        t.value = int(t.value)
        return t

    def t_newline(t):
        r'\n+'
        t.lexer.lineno += t.value.count("\n")
    
    def t_error(t):
        print("Illegal character '%s'" % t.value[0])
        t.lexer.skip(1)
    
    # Build the lexer
    lexer = lex.lex()

    # ------- Calculator parsing rules

    precedence = (
        ('left','+','-'),
        ('left','plus','minus'),
        ('left','plus_text','minus_text'),
        ('left','times','divided_by'),
        ('left','*','/'),
        ('right','UMINUS'),
    )
#Changed here the assigment
    def p_statement_assign(p):
        'statement : expression times divided_by plus minus  expression'
        variables[p[1]] = p[3]
        p[0] = None

    def p_statement_expr(p):
        'statement : expression'
        p[0] = p[1]

# no commas in plus and plus_text

    def p_expression_binop(p):
        '''expression : expression '+' expression
                      | expression plus expression
                      | expression plus_text expression  
                      | expression '-' expression
                      | expression minus expression
                      | expression minus_text expression
                      | expression '*' expression
                      | expression times expression
                      | expression times_text expression
                      | expression divided_by expression
                      | expression divided_by_text expression
                      | expression '/' expression'''
        if p[2] ==   '+'  : p[0] = p[1] + p[3]
        elif p[2] == plus: p[0] = p[1] + p[3]
        elif p[2] == plus_text: p[0] = p[1] + p[3]
        elif p[2] == '-': p[0] = p[1] - p[3]
        elif p[2] == '*': p[0] = p[1] * p[3]
        elif p[2] == '/': p[0] = p[1] / p[3]

    def p_expression_uminus(p):
        "expression : '-' expression %prec UMINUS"
        p[0] = -p[2]

    def p_expression_group(p):
        "expression : '(' expression ')'"
        p[0] = p[2]

    def p_expression_number(p):
        "expression : NUMBER"
        p[0] = p[1]

    def p_expression_name(p):
        "expression : NAME"
        try:
            p[0] = variables[p[1]]
        except LookupError:
            print("Undefined name '%s'" % p[1])
            p[0] = 0

    def p_error(p):
        if p:
            print("Syntax error at '%s'" % p.value)
        else:
            print("Syntax error at EOF")


    # Build the parser
    parser = yacc.yacc()

    # ------- Input function 
    
    def input(text):
        result = parser.parse(text,lexer=lexer)
        return result

    return input

# Make a calculator object and use it
calc = make_calculator()

while True:
    try:
        s = raw_input(" Enter your input: calc > ")
    except EOFError:
        break
    r = calc(s)
    if r:
        print(r)

    
