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