1# ----------------------------------------------------------------------------- 2# calc.py 3# 4# A simple calculator with variables. This is from O'Reilly's 5# "Lex and Yacc", p. 63. 6# ----------------------------------------------------------------------------- 7 8import sys 9sys.path.insert(0, "../..") 10 11if sys.version_info[0] >= 3: 12 raw_input = input 13 14tokens = ( 15 'NAME', 'NUMBER', 16) 17 18literals = ['=', '+', '-', '*', '/', '(', ')'] 19 20# Tokens 21 22t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 23 24 25def t_NUMBER(t): 26 r'\d+' 27 t.value = int(t.value) 28 return t 29 30t_ignore = " \t" 31 32 33def t_newline(t): 34 r'\n+' 35 t.lexer.lineno += t.value.count("\n") 36 37 38def t_error(t): 39 print("Illegal character '%s'" % t.value[0]) 40 t.lexer.skip(1) 41 42# Build the lexer 43import ply.lex as lex 44lex.lex() 45 46# Parsing rules 47 48precedence = ( 49 ('left', '+', '-'), 50 ('left', '*', '/'), 51 ('right', 'UMINUS'), 52) 53 54# dictionary of names 55names = {} 56 57 58def p_statement_assign(p): 59 'statement : NAME "=" expression' 60 names[p[1]] = p[3] 61 62 63def p_statement_expr(p): 64 'statement : expression' 65 print(p[1]) 66 67 68def p_expression_binop(p): 69 '''expression : expression '+' expression 70 | expression '-' expression 71 | expression '*' expression 72 | expression '/' expression''' 73 if p[2] == '+': 74 p[0] = p[1] + p[3] 75 elif p[2] == '-': 76 p[0] = p[1] - p[3] 77 elif p[2] == '*': 78 p[0] = p[1] * p[3] 79 elif p[2] == '/': 80 p[0] = p[1] / p[3] 81 82 83def p_expression_uminus(p): 84 "expression : '-' expression %prec UMINUS" 85 p[0] = -p[2] 86 87 88def p_expression_group(p): 89 "expression : '(' expression ')'" 90 p[0] = p[2] 91 92 93def p_expression_number(p): 94 "expression : NUMBER" 95 p[0] = p[1] 96 97 98def p_expression_name(p): 99 "expression : NAME" 100 try: 101 p[0] = names[p[1]] 102 except LookupError: 103 print("Undefined name '%s'" % p[1]) 104 p[0] = 0 105 106 107def p_error(p): 108 if p: 109 print("Syntax error at '%s'" % p.value) 110 else: 111 print("Syntax error at EOF") 112 113import ply.yacc as yacc 114yacc.yacc() 115 116while 1: 117 try: 118 s = raw_input('calc > ') 119 except EOFError: 120 break 121 if not s: 122 continue 123 yacc.parse(s) 124