【发布时间】:2022-06-16 00:29:53
【问题描述】:
我正在学习编写解释器的教程,以创建我自己的编程语言。我做了与教程相同的事情,但我的代码没有按预期工作,它返回一个错误,这个:
Traceback (most recent call last):
File "/home/ricky/PycharmProjects/interpreter/shell.py",
line 6, in <module>
result, error = bs.run('<stdin>', text)
File "/home/ricky/PycharmProjects/interpreter/basic.py",
line 232, in run
ast = parser.parse()
File "/home/ricky/PycharmProjects/interpreter/basic.py",
line 189, in parse
res = self.expr()
File "/home/ricky/PycharmProjects/interpreter/basic.py",
line 204, in expr
return self.bin_op(self.term(), (TT_PLUS, TT_MINUS))
File "/home/ricky/PycharmProjects/interpreter/basic.py",
line 201, in term
return self.bin_op(self.factor(), (TT_MUL, TT_DIV))
File "/home/ricky/PycharmProjects/interpreter/basic.py", line 207, in bin_op
left = func()
TypeError: 'NumberNode' object is not callable
这是代码(2个文件),抱歉太长了:
#######################################
# CONSTANTS
#######################################
DIGITS = '0123456789'
#######################################
# ERRORS
#######################################
class Error:
def __init__(self, pos_start, pos_end, error_name, details):
self.pos_start = pos_start
self.pos_end = pos_end
self.error_name = error_name
self.details = details
def as_string(self):
result = f'{self.error_name}: {self.details}\n'
result += f'File {self.pos_start.fn}, line {self.pos_start.ln + 1}'
return result
class InvalidChar(Error):
def __init__(self, pos_start, pos_end, details):
super().__init__(pos_start, pos_end, 'Invalid Character', details)
#######################################
# POSITION
#######################################
class Position:
def __init__(self, idx, ln, col, fn, ftxt):
self.idx = idx
self.ln = ln
self.col = col
self.fn = fn
self.ftxt = ftxt
def advance(self, current_char):
self.idx += 1
self.col += 1
if current_char == '\n':
self.ln += 1
self.col = 0
return self
def copy(self):
return Position(self.idx, self.ln, self.col, self.fn, self.ftxt)
#######################################
# TOKENS
#######################################
TT_INT = 'INT'
TT_FLOAT = 'FLOAT'
TT_PLUS = 'PLUS'
TT_MINUS = 'MINUS'
TT_MUL = 'MUL'
TT_DIV = 'DIV'
TT_LPAREN = 'LPAREN'
TT_RPAREN = 'RPAREN'
class Token:
def __init__(self, type_, value=None):
self.type = type_
self.value = value
def __repr__(self):
if self.value: return f'{self.type}:{self.value}'
return f'{self.type}'
#######################################
# LEXER
#######################################
class Lexer:
def __init__(self, fn, text):
self.fn = fn
self.text = text
self.pos = Position(-1, 0, -1, fn, text)
self.current_char = None
self.advance()
def advance(self):
self.pos.advance(self.current_char)
self.current_char = self.text[self.pos.idx] if self.pos.idx < len(self.text) else None
def make_tokens(self):
tokens = []
while self.current_char != None:
if self.current_char in ' \t':
self.advance()
elif self.current_char in DIGITS:
tokens.append(self.make_number())
elif self.current_char == '+':
tokens.append(Token(TT_PLUS))
self.advance()
elif self.current_char == '-':
tokens.append(Token(TT_MINUS))
self.advance()
elif self.current_char == '*':
tokens.append(Token(TT_MUL))
self.advance()
elif self.current_char == '/':
tokens.append(Token(TT_DIV))
self.advance()
elif self.current_char == '(':
tokens.append(Token(TT_LPAREN))
self.advance()
elif self.current_char == ')':
tokens.append(Token(TT_RPAREN))
self.advance()
else:
pos_start = self.pos.copy()
char = self.current_char
self.advance()
return [], InvalidChar(pos_start, self.pos, "'" + char + "'")
return tokens, None
def make_number(self):
num_str = ''
dot_count = 0
while self.current_char != None and self.current_char in DIGITS + '.':
if self.current_char == '.':
if dot_count == 1: break
dot_count += 1
num_str += '.'
else:
num_str += self.current_char
self.advance()
if dot_count == 0:
return Token(TT_INT, int(num_str))
else:
return Token(TT_FLOAT, float(num_str))
#######################################
# NODES
#######################################
class NumberNode:
def __init__(self, tok):
self.tok = tok
def __repr__(self):
return f'{self.tok}'
class BinOpNode:
def __init__(self, lnode, op_tok, rnode):
self.lnode = lnode
self.op_tok = op_tok
self.rnode = rnode
def __repr__(self):
return f'({self.lnode}, {self.op_tok}, {self.rnode})'
#######################################
# PARSER
#######################################
class Parser:
def __init__(self, tokens):
self.tokens = tokens
self.tok_idx = -1
self.advance()
def advance(self):
self.tok_idx += 1
if self.tok_idx < len(self.tokens):
self.cur_tok = self.tokens[self.tok_idx]
return self.cur_tok
#############################################################
def parse(self):
res = self.expr()
return res
def factor(self):
tok = self.cur_tok
if tok.type in (TT_INT, TT_FLOAT):
self.advance()
node = NumberNode(tok)
return node
def term(self):
return self.bin_op(self.factor(), (TT_MUL, TT_DIV))
def expr(self):
return self.bin_op(self.term(), (TT_PLUS, TT_MINUS))
def bin_op(self, func, ops):
left = func()
while self.cur_tok.type in ops:
op_tok = self.cur_tok
self.advance()
right = func()
left = BinOpNode(left, op_tok, right)
return left
#############################################################
#######################################
# RUN
#######################################
def run(fn, text):
# Generate Tokens
lexer = Lexer(fn, text)
tokens, error = lexer.make_tokens()
if error: return None, error
# Generate AST
parser = Parser(tokens)
ast = parser.parse()
return ast, None
第二个文件:
import basic as bs # basic.py is the first file
while True:
text = input('Basic > ')
if text == 'exit': break
result, error = bs.run('<stdin>', text)
if error: print(error.as_string())
else: print(result)
(我不知道如何使用语法高亮,对不起)
【问题讨论】:
-
您可能希望将
self.factor而非self.factor()传递给self.bin_op(基于参数名称,假设参数是函数/可调用的)。 -
你有教程的链接吗?您可能没有正确复制某些内容。我怀疑应该是
left = func没有()。
标签: python