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