calc.py revision 6498
16157Snate@binkert.org# -----------------------------------------------------------------------------
26157Snate@binkert.org# calc.py
36157Snate@binkert.org#
46157Snate@binkert.org# A simple calculator with variables.   This is from O'Reilly's
56157Snate@binkert.org# "Lex and Yacc", p. 63.
66157Snate@binkert.org# -----------------------------------------------------------------------------
76157Snate@binkert.org
86157Snate@binkert.orgimport sys
96157Snate@binkert.orgsys.path.insert(0,"../..")
106157Snate@binkert.org
116157Snate@binkert.orgif sys.version_info[0] >= 3:
126157Snate@binkert.org    raw_input = input
136157Snate@binkert.org
146157Snate@binkert.orgtokens = (
156157Snate@binkert.org    'NAME','NUMBER',
166157Snate@binkert.org    )
176157Snate@binkert.org
186157Snate@binkert.orgliterals = ['=','+','-','*','/', '(',')']
196157Snate@binkert.org
206157Snate@binkert.org# Tokens
216157Snate@binkert.org
226157Snate@binkert.orgt_NAME    = r'[a-zA-Z_][a-zA-Z0-9_]*'
236157Snate@binkert.org
246157Snate@binkert.orgdef t_NUMBER(t):
256157Snate@binkert.org    r'\d+'
266157Snate@binkert.org    t.value = int(t.value)
276157Snate@binkert.org    return t
286157Snate@binkert.org
296157Snate@binkert.orgt_ignore = " \t"
306157Snate@binkert.org
316157Snate@binkert.orgdef t_newline(t):
326157Snate@binkert.org    r'\n+'
336157Snate@binkert.org    t.lexer.lineno += t.value.count("\n")
346157Snate@binkert.org
356157Snate@binkert.orgdef t_error(t):
366157Snate@binkert.org    print("Illegal character '%s'" % t.value[0])
376157Snate@binkert.org    t.lexer.skip(1)
386157Snate@binkert.org
396157Snate@binkert.org# Build the lexer
406157Snate@binkert.orgimport ply.lex as lex
416157Snate@binkert.orglex.lex()
426157Snate@binkert.org
436157Snate@binkert.org# Parsing rules
446157Snate@binkert.org
456157Snate@binkert.orgprecedence = (
466157Snate@binkert.org    ('left','+','-'),
476157Snate@binkert.org    ('left','*','/'),
486157Snate@binkert.org    ('right','UMINUS'),
496157Snate@binkert.org    )
506157Snate@binkert.org
51# dictionary of names
52names = { }
53
54def p_statement_assign(p):
55    'statement : NAME "=" expression'
56    names[p[1]] = p[3]
57
58def p_statement_expr(p):
59    'statement : expression'
60    print(p[1])
61
62def p_expression_binop(p):
63    '''expression : expression '+' expression
64                  | expression '-' expression
65                  | expression '*' expression
66                  | expression '/' expression'''
67    if p[2] == '+'  : p[0] = p[1] + p[3]
68    elif p[2] == '-': p[0] = p[1] - p[3]
69    elif p[2] == '*': p[0] = p[1] * p[3]
70    elif p[2] == '/': p[0] = p[1] / p[3]
71
72def p_expression_uminus(p):
73    "expression : '-' expression %prec UMINUS"
74    p[0] = -p[2]
75
76def p_expression_group(p):
77    "expression : '(' expression ')'"
78    p[0] = p[2]
79
80def p_expression_number(p):
81    "expression : NUMBER"
82    p[0] = p[1]
83
84def p_expression_name(p):
85    "expression : NAME"
86    try:
87        p[0] = names[p[1]]
88    except LookupError:
89        print("Undefined name '%s'" % p[1])
90        p[0] = 0
91
92def p_error(p):
93    if p:
94        print("Syntax error at '%s'" % p.value)
95    else:
96        print("Syntax error at EOF")
97
98import ply.yacc as yacc
99yacc.yacc()
100
101while 1:
102    try:
103        s = raw_input('calc > ')
104    except EOFError:
105        break
106    if not s: continue
107    yacc.parse(s)
108