12632Sstever@eecs.umich.edu# -----------------------------------------------------------------------------
22632Sstever@eecs.umich.edu# calc.py
32632Sstever@eecs.umich.edu#
42632Sstever@eecs.umich.edu# A simple calculator with variables.   This is from O'Reilly's
52632Sstever@eecs.umich.edu# "Lex and Yacc", p. 63.
62632Sstever@eecs.umich.edu# -----------------------------------------------------------------------------
72632Sstever@eecs.umich.edu
84479Sbinkertn@umich.eduimport sys
94479Sbinkertn@umich.edusys.path.insert(0,"../..")
104479Sbinkertn@umich.edu
116498Snate@binkert.orgif sys.version_info[0] >= 3:
126498Snate@binkert.org    raw_input = input
136498Snate@binkert.org
142632Sstever@eecs.umich.edutokens = (
152632Sstever@eecs.umich.edu    'NAME','NUMBER',
162632Sstever@eecs.umich.edu    )
172632Sstever@eecs.umich.edu
184479Sbinkertn@umich.eduliterals = ['=','+','-','*','/', '(',')']
194479Sbinkertn@umich.edu
202632Sstever@eecs.umich.edu# Tokens
212632Sstever@eecs.umich.edu
222632Sstever@eecs.umich.edut_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
232632Sstever@eecs.umich.edu
242632Sstever@eecs.umich.edudef t_NUMBER(t):
252632Sstever@eecs.umich.edu    r'\d+'
266498Snate@binkert.org    t.value = int(t.value)
272632Sstever@eecs.umich.edu    return t
282632Sstever@eecs.umich.edu
292632Sstever@eecs.umich.edut_ignore = " \t"
302632Sstever@eecs.umich.edu
312632Sstever@eecs.umich.edudef t_newline(t):
322632Sstever@eecs.umich.edu    r'\n+'
334479Sbinkertn@umich.edu    t.lexer.lineno += t.value.count("\n")
346498Snate@binkert.org
352632Sstever@eecs.umich.edudef t_error(t):
366498Snate@binkert.org    print("Illegal character '%s'" % t.value[0])
374479Sbinkertn@umich.edu    t.lexer.skip(1)
386498Snate@binkert.org
392632Sstever@eecs.umich.edu# Build the lexer
404479Sbinkertn@umich.eduimport ply.lex as lex
412632Sstever@eecs.umich.edulex.lex()
422632Sstever@eecs.umich.edu
432632Sstever@eecs.umich.edu# Parsing rules
442632Sstever@eecs.umich.edu
452632Sstever@eecs.umich.eduprecedence = (
464479Sbinkertn@umich.edu    ('left','+','-'),
474479Sbinkertn@umich.edu    ('left','*','/'),
482632Sstever@eecs.umich.edu    ('right','UMINUS'),
492632Sstever@eecs.umich.edu    )
502632Sstever@eecs.umich.edu
512632Sstever@eecs.umich.edu# dictionary of names
522632Sstever@eecs.umich.edunames = { }
532632Sstever@eecs.umich.edu
544479Sbinkertn@umich.edudef p_statement_assign(p):
554479Sbinkertn@umich.edu    'statement : NAME "=" expression'
564479Sbinkertn@umich.edu    names[p[1]] = p[3]
572632Sstever@eecs.umich.edu
584479Sbinkertn@umich.edudef p_statement_expr(p):
592632Sstever@eecs.umich.edu    'statement : expression'
606498Snate@binkert.org    print(p[1])
612632Sstever@eecs.umich.edu
624479Sbinkertn@umich.edudef p_expression_binop(p):
634479Sbinkertn@umich.edu    '''expression : expression '+' expression
644479Sbinkertn@umich.edu                  | expression '-' expression
654479Sbinkertn@umich.edu                  | expression '*' expression
664479Sbinkertn@umich.edu                  | expression '/' expression'''
674479Sbinkertn@umich.edu    if p[2] == '+'  : p[0] = p[1] + p[3]
684479Sbinkertn@umich.edu    elif p[2] == '-': p[0] = p[1] - p[3]
694479Sbinkertn@umich.edu    elif p[2] == '*': p[0] = p[1] * p[3]
704479Sbinkertn@umich.edu    elif p[2] == '/': p[0] = p[1] / p[3]
712632Sstever@eecs.umich.edu
724479Sbinkertn@umich.edudef p_expression_uminus(p):
734479Sbinkertn@umich.edu    "expression : '-' expression %prec UMINUS"
744479Sbinkertn@umich.edu    p[0] = -p[2]
752632Sstever@eecs.umich.edu
764479Sbinkertn@umich.edudef p_expression_group(p):
774479Sbinkertn@umich.edu    "expression : '(' expression ')'"
784479Sbinkertn@umich.edu    p[0] = p[2]
792632Sstever@eecs.umich.edu
804479Sbinkertn@umich.edudef p_expression_number(p):
814479Sbinkertn@umich.edu    "expression : NUMBER"
824479Sbinkertn@umich.edu    p[0] = p[1]
832632Sstever@eecs.umich.edu
844479Sbinkertn@umich.edudef p_expression_name(p):
854479Sbinkertn@umich.edu    "expression : NAME"
862632Sstever@eecs.umich.edu    try:
874479Sbinkertn@umich.edu        p[0] = names[p[1]]
882632Sstever@eecs.umich.edu    except LookupError:
896498Snate@binkert.org        print("Undefined name '%s'" % p[1])
904479Sbinkertn@umich.edu        p[0] = 0
912632Sstever@eecs.umich.edu
924479Sbinkertn@umich.edudef p_error(p):
936498Snate@binkert.org    if p:
946498Snate@binkert.org        print("Syntax error at '%s'" % p.value)
956498Snate@binkert.org    else:
966498Snate@binkert.org        print("Syntax error at EOF")
972632Sstever@eecs.umich.edu
984479Sbinkertn@umich.eduimport ply.yacc as yacc
992632Sstever@eecs.umich.eduyacc.yacc()
1002632Sstever@eecs.umich.edu
1012632Sstever@eecs.umich.eduwhile 1:
1022632Sstever@eecs.umich.edu    try:
1032632Sstever@eecs.umich.edu        s = raw_input('calc > ')
1042632Sstever@eecs.umich.edu    except EOFError:
1052632Sstever@eecs.umich.edu        break
1064479Sbinkertn@umich.edu    if not s: continue
1072632Sstever@eecs.umich.edu    yacc.parse(s)
108