⇤ ← Revisão 1e 2005-03-22 13:38:29
3894
Comentário:
|
3894
converted to 1.6 markup
|
Nenhuma diferença encontrada! |
Receita: MiniCalculadora
Apresento aqui um código de uma mini calculadora. O intuito é demonstrar o método de parsing top-down para tratamento de gramáticas.
A gramática dessa calculadora é bem simples:
expr -> term + term | term - term | nome = expr
term -> prim * prim | prim / prim
prim -> ( expr ) | num | nome
Lá vai ela:
Código
1 # -*- encoding: iso-8859-1 -*-
2
3 """ Mini-calculadora, feita como exercício em Python """
4
5 class CalcError(Exception):
6 pass
7
8 class Calc(object):
9 """ Implementa todo o processo da calculadora, desde a leitura até o parsing. """
10
11 TOK_IMPR, TOK_FIM, TOK_NOME, TOK_NUM = range(4)
12
13 def __init__(self, entrada):
14 """ Inicializa a calculadora.
15 entrada deve ser um objeto que tenha o método read().
16 """
17 self.entrada = entrada
18 self.cur_tok = Calc.TOK_IMPR
19 self.num_value = 0.0
20 self.str_value = ''
21 self.values = { 'pi': 3.14156 }
22 import re
23 self.letras = re.compile('[a-zA-Z]')
24 self.numeros = re.compile('[0-9\.]')
25
26
27 def run(self):
28 while self.cur_tok != Calc.TOK_FIM:
29 try:
30 valor = self.expr()
31 if valor is not None:
32 print valor
33 except CalcError, msg:
34 print "Erro:", msg
35
36 def expr(self):
37 esq = self.term()
38 while self.cur_tok in ('+', '-', '\n'):
39 if self.cur_tok == '+':
40 esq += self.term()
41 elif self.cur_tok == '-':
42 esq -= self.term()
43 else:
44 break
45 if self.cur_tok == Calc.TOK_FIM:
46 return None
47 return esq
48
49 def term(self):
50 esq = self.prim()
51 while self.cur_tok in ('*', '/'):
52 if self.cur_tok == '*':
53 esq *= self.prim()
54 else:
55 v = self.prim()
56 if v == 0.0:
57 raise CalcError, "Divisão por Zero"
58 else:
59 esq /= v
60 return esq
61
62 def prim(self):
63 self.next_token()
64 v = 0.0
65 if self.cur_tok == Calc.TOK_NOME:
66 nome = self.str_value
67 self.next_token()
68 if self.cur_tok == '=':
69 v = self.expr()
70 self.values[nome] = v
71 return v
72 else:
73 v = self.values.get(nome, 0.0)
74 return v
75 elif self.cur_tok == Calc.TOK_NUM:
76 v = self.num_value
77 elif self.cur_tok == '(':
78 v = self.expr()
79 if self.cur_tok != ')':
80 raise CalcError, "')' esperado"
81 elif self.cur_tok == Calc.TOK_FIM:
82 return 0
83 else:
84 raise CalcError, "Token inesperado"
85 self.next_token()
86 return v
87
88 def next_token(self):
89 if not hasattr(self,'ch'):
90 ch = ' '
91 while ch in (' ', '\t'):
92 ch = self.entrada.read(1)
93 else:
94 ch = self.ch
95
96 if self.numeros.match(ch):
97 pontos = ch == '.' and 1 or 0
98 s = ''
99 while self.numeros.match(ch):
100 s += ch
101 ch = self.entrada.read(1)
102 if ch == '.':
103 pontos += 1
104 if pontos > 1:
105 raise CalcError, "Valor ponto flutuante inválido"
106 self.num_value = float(s)
107 self.cur_tok = Calc.TOK_NUM
108 elif self.letras.match(ch):
109 s = ''
110 while self.letras.match(ch):
111 s += ch
112 ch = self.entrada.read(1)
113 self.str_value = s
114 self.cur_tok = Calc.TOK_NOME
115 elif len(ch) == 0:
116 self.cur_tok = Calc.TOK_FIM
117 else:
118 self.cur_tok = ch
119 if ch == '\n':
120 if hasattr(self,'ch'):
121 del self.ch
122 return
123 ch = sys.stdin.read(1)
124
125 while ch in (' ', '\t'):
126 ch = sys.stdin.read(1)
127
128 self.ch = ch
129
130 if __name__ == "__main__":
131 import sys
132 calc = Calc(sys.stdin)
133 calc.run()
Exemplo de Uso
$ python calc.py x = 1.5 + 3.0 4.5 z = x + .5 5.0
Volta para CookBook.
João Paulo F Farias