15
15
v7.0 : using ASTs represent the operator-operand model of arithmetic expressions.
16
16
v8.0 : support unary operators (+, -)
17
17
v9.0 : support to handle python assignment statements.
18
+ v10.0 : handle variable not defined error
18
19
"""
19
20
20
21
import keyword
21
22
from abs_syntax_tree import BinOp , Num , UnaryOp , Var , NoOp , Compound , Assign
22
- from sip_token import Token
23
+ from spi_token import Token
24
+ from spi_symbol import VarSymbol , SymbolTable
23
25
24
26
25
- INTEGER , PLUS , EOF , MINUS , MUL , DIV , LPAREN , RPAREN , ID , ASSIGN , REPL = 'INTEGER' , 'PLUS' , 'EOF' , 'MINUS' , 'MUL' , 'DIV' , 'LPAREN' , 'RPAREN' , 'ID' , 'ASSIGN' , 'REPL'
27
+ INTEGER , FLOAT , PLUS , EOF , MINUS , MUL , DIV , LPAREN , RPAREN , ID , ASSIGN , REPL = 'INTEGER' , 'FLOAT ' , 'PLUS' , 'EOF' , 'MINUS' , 'MUL' , 'DIV' , 'LPAREN' , 'RPAREN' , 'ID' , 'ASSIGN' , 'REPL'
26
28
PYTHON_RESERVED_KEYWORDS = {key : Token (key , key ) for key in keyword .kwlist }
27
29
28
30
class Analyzer (object ):
@@ -55,13 +57,21 @@ def peek(self):
55
57
else :
56
58
return self .text [peek_pos ]
57
59
58
- def integer (self ):
60
+ def number (self ):
59
61
"""return a multi-digit integer"""
60
62
result = ''
61
63
while self .current_char is not None and self .current_char .isdigit ():
62
64
result += self .current_char
63
65
self .advance ()
64
- return int (result )
66
+ if self .current_char == '.' :
67
+ result += self .current_char
68
+ self .advance ()
69
+ while self .current_char is not None and self .current_char .isdigit ():
70
+ result += self .current_char
71
+ self .advance ()
72
+ return float (result )
73
+ else :
74
+ return int (result )
65
75
66
76
def identifier (self ):
67
77
"""return a multi-digit identifier"""
@@ -81,7 +91,8 @@ def get_next_token(self):
81
91
self .skip_whitespace ()
82
92
continue
83
93
if self .current_char .isdigit ():
84
- return Token (INTEGER , self .integer ())
94
+ number = self .number ()
95
+ return Token (INTEGER , number ) if isinstance (number , int ) else Token (FLOAT , number )
85
96
if self .current_char == '+' :
86
97
self .advance ()
87
98
return Token (PLUS , '+' )
@@ -228,6 +239,9 @@ def factor(self):
228
239
elif self .current_token .type == INTEGER :
229
240
self .eat (INTEGER )
230
241
return Num (token )
242
+ elif self .current_token .type == FLOAT :
243
+ self .eat (FLOAT )
244
+ return Num (token )
231
245
elif self .current_token .type == LPAREN :
232
246
self .eat (LPAREN )
233
247
node = self .expr ()
@@ -317,12 +331,75 @@ def visit(self, node):
317
331
318
332
def interpret (self ):
319
333
tree = self .parser .parse ()
334
+ symbol_builder = SymbolTableBuilder ()
335
+ symbol_builder .visit (tree )
320
336
return self .visit (tree )
321
337
322
338
339
+ class SymbolTableBuilder (NodeVisitor ):
340
+ def __init__ (self ):
341
+ self .symtab = SymbolTable ()
342
+
343
+ def visit_BinOp (self , node ):
344
+ self .visit (node .left )
345
+ self .visit (node .right )
346
+
347
+ def visit_Num (self , node ):
348
+ pass
349
+
350
+ def visit_UnaryOp (self , node ):
351
+ self .visit (node .expr )
352
+
353
+ def visit_Compound (self , node ):
354
+ for child in node .children :
355
+ self .visit (child )
356
+
357
+ def visit_NoOp (self , node ):
358
+ pass
359
+
360
+ def visit_VarDecl (self , node ):
361
+ type_name = node .type_node .value
362
+ type_symbol = self .symtab .lookup (type_name )
363
+ var_name = node .var_node .value
364
+ var_symbol = VarSymbol (var_name , type_symbol )
365
+ self .symtab .define (var_symbol )
366
+
367
+ def visit_Assign (self , node ):
368
+ # python代码中赋值就是定义,没有声明
369
+ var_name = node .left .value
370
+ var_symbol = VarSymbol (var_name , None )
371
+ self .symtab .define (var_symbol )
372
+ self .visit (node .right )
373
+
374
+ def visit_Var (self , node ):
375
+ var_name = node .value
376
+ var_symbol = self .symtab .lookup (var_name )
377
+ if var_symbol is None :
378
+ raise NameError (repr (var_name ))
379
+
380
+ def visit (self , node ):
381
+ if isinstance (node , BinOp ):
382
+ return self .visit_BinOp (node )
383
+ elif isinstance (node , Num ):
384
+ return self .visit_Num (node )
385
+ elif isinstance (node , UnaryOp ):
386
+ return self .visit_UnaryOp (node )
387
+ elif isinstance (node , Var ):
388
+ return self .visit_Var (node )
389
+ elif isinstance (node , Assign ):
390
+ return self .visit_Assign (node )
391
+ elif isinstance (node , Compound ):
392
+ return self .visit_Compound (node )
393
+ elif isinstance (node , NoOp ):
394
+ return self .visit_NoOp (node )
395
+
396
+
397
+
323
398
def main ():
324
399
import sys
325
- text = open (sys .argv [1 ], 'r' ).read ()
400
+ py_file = sys .argv [1 ]
401
+ # py_file = 'assignments.txt'
402
+ text = open (py_file , 'r' ).read ()
326
403
print (f"begin parse input: { text } " )
327
404
lexer = Analyzer (text )
328
405
parser = Parser (lexer )
0 commit comments