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 'PLUS', 'MINUS', 'TIMES', 'DIVIDE', 'EQUALS', 17 'LPAREN', 'RPAREN', 18) 19 20# Tokens 21 22t_PLUS = r'\+' 23t_MINUS = r'-' 24t_TIMES = r'\*' 25t_DIVIDE = r'/' 26t_EQUALS = r'=' 27t_LPAREN = r'\(' 28t_RPAREN = r'\)' 29t_NAME = r'[a-zA-Z_][a-zA-Z0-9_]*' 30 31 32def t_NUMBER(t): 33 r'\d+' 34 try: 35 t.value = int(t.value) 36 except ValueError: 37 print("Integer value too large %s" % t.value) 38 t.value = 0 39 return t 40 41t_ignore = " \t" 42 43 44def t_newline(t): 45 r'\n+' 46 t.lexer.lineno += t.value.count("\n") 47 48 49def t_error(t): 50 print("Illegal character '%s'" % t.value[0]) 51 t.lexer.skip(1) 52 53# Build the lexer 54import ply.lex as lex 55lex.lex(optimize=1) 56 57# Parsing rules 58 59precedence = ( 60 ('left', 'PLUS', 'MINUS'), 61 ('left', 'TIMES', 'DIVIDE'), 62 ('right', 'UMINUS'), 63) 64 65# dictionary of names 66names = {} 67 68 69def p_statement_assign(t): 70 'statement : NAME EQUALS expression' 71 names[t[1]] = t[3] 72 73 74def p_statement_expr(t): 75 'statement : expression' 76 print(t[1]) 77 78 79def p_expression_binop(t): 80 '''expression : expression PLUS expression 81 | expression MINUS expression 82 | expression TIMES expression 83 | expression DIVIDE expression''' 84 if t[2] == '+': 85 t[0] = t[1] + t[3] 86 elif t[2] == '-': 87 t[0] = t[1] - t[3] 88 elif t[2] == '*': 89 t[0] = t[1] * t[3] 90 elif t[2] == '/': 91 t[0] = t[1] / t[3] 92 elif t[2] == '<': 93 t[0] = t[1] < t[3] 94 95 96def p_expression_uminus(t): 97 'expression : MINUS expression %prec UMINUS' 98 t[0] = -t[2] 99 100 101def p_expression_group(t): 102 'expression : LPAREN expression RPAREN' 103 t[0] = t[2] 104 105 106def p_expression_number(t): 107 'expression : NUMBER' 108 t[0] = t[1] 109 110 111def p_expression_name(t): 112 'expression : NAME' 113 try: 114 t[0] = names[t[1]] 115 except LookupError: 116 print("Undefined name '%s'" % t[1]) 117 t[0] = 0 118 119 120def p_error(t): 121 if t: 122 print("Syntax error at '%s'" % t.value) 123 else: 124 print("Syntax error at EOF") 125 126import ply.yacc as yacc 127yacc.yacc(optimize=1) 128 129while 1: 130 try: 131 s = raw_input('calc > ') 132 except EOFError: 133 break 134 yacc.parse(s) 135