calc.py revision 2632
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
82632Sstever@eecs.umich.edutokens = (
92632Sstever@eecs.umich.edu    'NAME','NUMBER',
102632Sstever@eecs.umich.edu    'PLUS','MINUS','TIMES','DIVIDE','EQUALS',
112632Sstever@eecs.umich.edu    'LPAREN','RPAREN',
122632Sstever@eecs.umich.edu    )
132632Sstever@eecs.umich.edu
142632Sstever@eecs.umich.edu# Tokens
152632Sstever@eecs.umich.edu
162632Sstever@eecs.umich.edut_PLUS    = r'\+'
172632Sstever@eecs.umich.edut_MINUS   = r'-'
182632Sstever@eecs.umich.edut_TIMES   = r'\*'
192632Sstever@eecs.umich.edut_DIVIDE  = r'/'
202632Sstever@eecs.umich.edut_EQUALS  = r'='
212632Sstever@eecs.umich.edut_LPAREN  = r'\('
222632Sstever@eecs.umich.edut_RPAREN  = r'\)'
232632Sstever@eecs.umich.edut_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
242632Sstever@eecs.umich.edu
252632Sstever@eecs.umich.edudef t_NUMBER(t):
262632Sstever@eecs.umich.edu    r'\d+'
272632Sstever@eecs.umich.edu    try:
282632Sstever@eecs.umich.edu        t.value = int(t.value)
292632Sstever@eecs.umich.edu    except ValueError:
302632Sstever@eecs.umich.edu        print "Integer value too large", t.value
312632Sstever@eecs.umich.edu        t.value = 0
322632Sstever@eecs.umich.edu    return t
332632Sstever@eecs.umich.edu
342632Sstever@eecs.umich.edut_ignore = " \t"
352632Sstever@eecs.umich.edu
362632Sstever@eecs.umich.edudef t_newline(t):
372632Sstever@eecs.umich.edu    r'\n+'
382632Sstever@eecs.umich.edu    t.lineno += t.value.count("\n")
392632Sstever@eecs.umich.edu
402632Sstever@eecs.umich.edudef t_error(t):
412632Sstever@eecs.umich.edu    print "Illegal character '%s'" % t.value[0]
422632Sstever@eecs.umich.edu    t.skip(1)
432632Sstever@eecs.umich.edu
442632Sstever@eecs.umich.edu# Build the lexer
452632Sstever@eecs.umich.eduimport lex
462632Sstever@eecs.umich.edulex.lex(optimize=1)
472632Sstever@eecs.umich.edu
482632Sstever@eecs.umich.edu# Parsing rules
492632Sstever@eecs.umich.edu
502632Sstever@eecs.umich.eduprecedence = (
512632Sstever@eecs.umich.edu    ('left','PLUS','MINUS'),
522632Sstever@eecs.umich.edu    ('left','TIMES','DIVIDE'),
532632Sstever@eecs.umich.edu    ('right','UMINUS'),
542632Sstever@eecs.umich.edu    )
552632Sstever@eecs.umich.edu
562632Sstever@eecs.umich.edu# dictionary of names
572632Sstever@eecs.umich.edunames = { }
582632Sstever@eecs.umich.edu
592632Sstever@eecs.umich.edudef p_statement_assign(t):
602632Sstever@eecs.umich.edu    'statement : NAME EQUALS expression'
612632Sstever@eecs.umich.edu    names[t[1]] = t[3]
622632Sstever@eecs.umich.edu
632632Sstever@eecs.umich.edudef p_statement_expr(t):
642632Sstever@eecs.umich.edu    'statement : expression'
652632Sstever@eecs.umich.edu    print t[1]
662632Sstever@eecs.umich.edu
672632Sstever@eecs.umich.edudef p_expression_binop(t):
682632Sstever@eecs.umich.edu    '''expression : expression PLUS expression
692632Sstever@eecs.umich.edu                  | expression MINUS expression
702632Sstever@eecs.umich.edu                  | expression TIMES expression
712632Sstever@eecs.umich.edu                  | expression DIVIDE expression'''
722632Sstever@eecs.umich.edu    if t[2] == '+'  : t[0] = t[1] + t[3]
732632Sstever@eecs.umich.edu    elif t[2] == '-': t[0] = t[1] - t[3]
742632Sstever@eecs.umich.edu    elif t[2] == '*': t[0] = t[1] * t[3]
752632Sstever@eecs.umich.edu    elif t[2] == '/': t[0] = t[1] / t[3]
762632Sstever@eecs.umich.edu    elif t[2] == '<': t[0] = t[1] < t[3]
772632Sstever@eecs.umich.edu
782632Sstever@eecs.umich.edudef p_expression_uminus(t):
792632Sstever@eecs.umich.edu    'expression : MINUS expression %prec UMINUS'
802632Sstever@eecs.umich.edu    t[0] = -t[2]
812632Sstever@eecs.umich.edu
822632Sstever@eecs.umich.edudef p_expression_group(t):
832632Sstever@eecs.umich.edu    'expression : LPAREN expression RPAREN'
842632Sstever@eecs.umich.edu    t[0] = t[2]
852632Sstever@eecs.umich.edu
862632Sstever@eecs.umich.edudef p_expression_number(t):
872632Sstever@eecs.umich.edu    'expression : NUMBER'
882632Sstever@eecs.umich.edu    t[0] = t[1]
892632Sstever@eecs.umich.edu
902632Sstever@eecs.umich.edudef p_expression_name(t):
912632Sstever@eecs.umich.edu    'expression : NAME'
922632Sstever@eecs.umich.edu    try:
932632Sstever@eecs.umich.edu        t[0] = names[t[1]]
942632Sstever@eecs.umich.edu    except LookupError:
952632Sstever@eecs.umich.edu        print "Undefined name '%s'" % t[1]
962632Sstever@eecs.umich.edu        t[0] = 0
972632Sstever@eecs.umich.edu
982632Sstever@eecs.umich.edudef p_error(t):
992632Sstever@eecs.umich.edu    print "Syntax error at '%s'" % t.value
1002632Sstever@eecs.umich.edu
1012632Sstever@eecs.umich.eduimport yacc
1022632Sstever@eecs.umich.eduyacc.yacc(optimize=1)
1032632Sstever@eecs.umich.edu
1042632Sstever@eecs.umich.eduwhile 1:
1052632Sstever@eecs.umich.edu    try:
1062632Sstever@eecs.umich.edu        s = raw_input('calc > ')
1072632Sstever@eecs.umich.edu    except EOFError:
1082632Sstever@eecs.umich.edu        break
1092632Sstever@eecs.umich.edu    yacc.parse(s)
1102632Sstever@eecs.umich.edu
111