calc.py revision 4479
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
112632Sstever@eecs.umich.edutokens = (
122632Sstever@eecs.umich.edu    'NAME','NUMBER',
132632Sstever@eecs.umich.edu    )
142632Sstever@eecs.umich.edu
154479Sbinkertn@umich.eduliterals = ['=','+','-','*','/', '(',')']
164479Sbinkertn@umich.edu
172632Sstever@eecs.umich.edu# Tokens
182632Sstever@eecs.umich.edu
192632Sstever@eecs.umich.edut_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
202632Sstever@eecs.umich.edu
212632Sstever@eecs.umich.edudef t_NUMBER(t):
222632Sstever@eecs.umich.edu    r'\d+'
232632Sstever@eecs.umich.edu    try:
242632Sstever@eecs.umich.edu        t.value = int(t.value)
252632Sstever@eecs.umich.edu    except ValueError:
262632Sstever@eecs.umich.edu        print "Integer value too large", t.value
272632Sstever@eecs.umich.edu        t.value = 0
282632Sstever@eecs.umich.edu    return t
292632Sstever@eecs.umich.edu
302632Sstever@eecs.umich.edut_ignore = " \t"
312632Sstever@eecs.umich.edu
322632Sstever@eecs.umich.edudef t_newline(t):
332632Sstever@eecs.umich.edu    r'\n+'
344479Sbinkertn@umich.edu    t.lexer.lineno += t.value.count("\n")
352632Sstever@eecs.umich.edu
362632Sstever@eecs.umich.edudef t_error(t):
372632Sstever@eecs.umich.edu    print "Illegal character '%s'" % t.value[0]
384479Sbinkertn@umich.edu    t.lexer.skip(1)
392632Sstever@eecs.umich.edu
402632Sstever@eecs.umich.edu# Build the lexer
414479Sbinkertn@umich.eduimport ply.lex as lex
422632Sstever@eecs.umich.edulex.lex()
432632Sstever@eecs.umich.edu
442632Sstever@eecs.umich.edu# Parsing rules
452632Sstever@eecs.umich.edu
462632Sstever@eecs.umich.eduprecedence = (
474479Sbinkertn@umich.edu    ('left','+','-'),
484479Sbinkertn@umich.edu    ('left','*','/'),
492632Sstever@eecs.umich.edu    ('right','UMINUS'),
502632Sstever@eecs.umich.edu    )
512632Sstever@eecs.umich.edu
522632Sstever@eecs.umich.edu# dictionary of names
532632Sstever@eecs.umich.edunames = { }
542632Sstever@eecs.umich.edu
554479Sbinkertn@umich.edudef p_statement_assign(p):
564479Sbinkertn@umich.edu    'statement : NAME "=" expression'
574479Sbinkertn@umich.edu    names[p[1]] = p[3]
582632Sstever@eecs.umich.edu
594479Sbinkertn@umich.edudef p_statement_expr(p):
602632Sstever@eecs.umich.edu    'statement : expression'
614479Sbinkertn@umich.edu    print p[1]
622632Sstever@eecs.umich.edu
634479Sbinkertn@umich.edudef p_expression_binop(p):
644479Sbinkertn@umich.edu    '''expression : expression '+' expression
654479Sbinkertn@umich.edu                  | expression '-' expression
664479Sbinkertn@umich.edu                  | expression '*' expression
674479Sbinkertn@umich.edu                  | expression '/' expression'''
684479Sbinkertn@umich.edu    if 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]
714479Sbinkertn@umich.edu    elif p[2] == '/': p[0] = p[1] / p[3]
722632Sstever@eecs.umich.edu
734479Sbinkertn@umich.edudef p_expression_uminus(p):
744479Sbinkertn@umich.edu    "expression : '-' expression %prec UMINUS"
754479Sbinkertn@umich.edu    p[0] = -p[2]
762632Sstever@eecs.umich.edu
774479Sbinkertn@umich.edudef p_expression_group(p):
784479Sbinkertn@umich.edu    "expression : '(' expression ')'"
794479Sbinkertn@umich.edu    p[0] = p[2]
802632Sstever@eecs.umich.edu
814479Sbinkertn@umich.edudef p_expression_number(p):
824479Sbinkertn@umich.edu    "expression : NUMBER"
834479Sbinkertn@umich.edu    p[0] = p[1]
842632Sstever@eecs.umich.edu
854479Sbinkertn@umich.edudef p_expression_name(p):
864479Sbinkertn@umich.edu    "expression : NAME"
872632Sstever@eecs.umich.edu    try:
884479Sbinkertn@umich.edu        p[0] = names[p[1]]
892632Sstever@eecs.umich.edu    except LookupError:
904479Sbinkertn@umich.edu        print "Undefined name '%s'" % p[1]
914479Sbinkertn@umich.edu        p[0] = 0
922632Sstever@eecs.umich.edu
934479Sbinkertn@umich.edudef p_error(p):
944479Sbinkertn@umich.edu    print "Syntax error at '%s'" % p.value
952632Sstever@eecs.umich.edu
964479Sbinkertn@umich.eduimport ply.yacc as yacc
972632Sstever@eecs.umich.eduyacc.yacc()
982632Sstever@eecs.umich.edu
992632Sstever@eecs.umich.eduwhile 1:
1002632Sstever@eecs.umich.edu    try:
1012632Sstever@eecs.umich.edu        s = raw_input('calc > ')
1022632Sstever@eecs.umich.edu    except EOFError:
1032632Sstever@eecs.umich.edu        break
1044479Sbinkertn@umich.edu    if not s: continue
1052632Sstever@eecs.umich.edu    yacc.parse(s)
106