如何避免在不使用 python sly 中的 say 函数的情况下打印变量?
How to avoid printing a variable without using the say function in python sly?
所以我正在使用 python 包 sly,它有一个词法分析器和解析器 class。我正在制作自己的编程语言 NoobPy。所以目前,代码将打开 test.noob 并读取每一行并解析它。现在,如果我要定义一个变量,比方说 x
,只需在一行中写入 x
,它就会打印出来,而我不希望这样。我希望它只有在我创建的 say
函数中传递时才打印。
词法分析器class
class NoobpyLexer(Lexer):
tokens = {NUMBER, STRING, FALSE, TRUE, NAME, WHILE, IF, ELSE, SAY,
PLUS, MINUS, TIMES, DIVIDE, ASSIGN,
EQ, LT, LE, GT, GE, NEQ}
literals = {'(', ')', ':'}
# String containing ignored characters
ignore = ' \t'
# Regular expression rules for tokens
STRING = r'\".*?\"'
PLUS = r'\+'
MINUS = r'-'
TIMES = r'\*'
DIVIDE = r'/'
EQ = r'=='
NEQ = r'!='
ASSIGN = r'='
LE = r'<='
GE = r'>='
LT = r'<'
GT = r'>'
@_(r'\d+')
def NUMBER(self, t):
t.value = int(t.value)
return t
# @_(r'^((true$|false$)$)')
# def BOOL(self, t):
# return t
@_(r'true')
def TRUE(self, t):
return t
@_(r'false')
def FALSE(self, t):
return t
# Identifiers and keywords
NAME = r'\b(?!((true$|false$)$)\b)\w+' # [a-zA-Z_][a-zA-Z0-9_]*$
NAME['if'] = IF
NAME['else'] = ELSE
NAME['while'] = WHILE
NAME['say'] = SAY
ignore_comment = r'\#.*'
# Line number tracking
@_(r'\n+')
def ignore_newline(self, t):
self.lineno += t.value.count('\n')
def error(self, t):
print("t: ", t)
print('Line %d: Bad character %r' % (self.lineno, t.value[0]))
self.index += 1
解析器class
class NoobpyParser(Parser):
# Get the token list from the lexer (required)
tokens = NoobpyLexer.tokens
log = logging.getLogger()
log.setLevel(logging.ERROR)
# debugfile = 'parser.out'
precedence = (
('left', PLUS, MINUS),
('left', TIMES, DIVIDE),
('right', UMINUS)
)
def __init__(self):
self.variables = {}
@_('')
def statement(self, p):
pass
@_('SAY expr')
def statement(self, p):
return 'say', p.expr
@_('NAME')
def expr(self, p):
return 'var', p.NAME
@_('var_assign')
def statement(self, p):
return p.var_assign
@_('NAME ASSIGN expr')
def var_assign(self, p):
return 'var_assign', p.NAME, p.expr
@_('expr')
def statement(self, p):
return p.expr
@_('expr PLUS expr')
def expr(self, p):
return 'add', p.expr0, p.expr1
@_('expr MINUS expr')
def expr(self, p):
return 'sub', p.expr0, p.expr1
@_('expr TIMES expr')
def expr(self, p):
return 'mul', p.expr0, p.expr1
@_('expr DIVIDE expr')
def expr(self, p):
return 'div', p.expr0, p.expr1
@_('MINUS expr %prec UMINUS')
def expr(self, p):
expression = list(p.expr)
if isinstance(expression[1], tuple):
res = 0
for i in expression[1]:
res += i
expression[1] = res
expression[1] = -expression[1]
return expression
@_('expr EQ expr')
def expr(self, p):
return 'eq', p.expr0, p.expr1
@_('"(" expr ")"')
def expr(self, p):
return p.expr
@_('NUMBER')
def expr(self, p):
return 'num', p.NUMBER
@_('STRING')
def expr(self, p):
return 'str', p.STRING
@_('TRUE')
def expr(self, p):
return p.TRUE
@_('FALSE')
def expr(self, p):
return p.FALSE
执行class
class NoobpyExecute:
def __init__(self, tree, variables):
self.variables = variables
result = self.walkTree(tree)
if result is None:
pass
elif result is not None and type(result) in [int, float]:
print(result)
elif isinstance(result, str):
print(result)
elif isinstance(result, bool):
if result is True:
print("true")
else:
print("false")
def walkTree(self, node):
if isinstance(node, int):
return node
if isinstance(node, str):
return node
if node is None:
return None
if node[0] == 'say':
return self.walkTree(node[1])
if node[0] == 'num':
return node[1]
if node[0] == 'str':
return node[1]
if node[0] == 'eq':
return self.walkTree(node[1]) == self.walkTree(node[2])
if node[0] == 'add':
return self.walkTree(node[1]) + self.walkTree(node[2])
elif node[0] == 'sub':
return self.walkTree(node[1]) - self.walkTree(node[2])
elif node[0] == 'mul':
return self.walkTree(node[1]) * self.walkTree(node[2])
elif node[0] == 'div':
return self.walkTree(node[1]) / self.walkTree(node[2])
if node[0] == 'var_assign':
self.variables[node[1]] = self.walkTree(node[2])
if node[0] == 'var':
try:
return self.variables[node[1]]
except LookupError:
print("Undefined name '{}'".format(node[1]))
return 0
这个:
if __name__ == '__main__':
lexer = NoobpyLexer()
parser = NoobpyParser()
variables = {}
args = argparse.ArgumentParser()
args.add_argument(metavar='filename', dest="filename", type=str, help='name of the file you want to run')
args = args.parse_args()
with open(args.filename) as file:
for line in file.readlines():
tree = parser.parse(lexer.tokenize(line))
NoobpyExecute(tree, variables)
示例test.noob
x = 2
x
^ 打印 2
在你的 NoobPy
构造函数中,你打印出评估语法树的结果(除非它是 None,如果你评估一个赋值就会发生):
if result is None:
pass
elif result is not None and type(result) in [int, float]:
print(result)
elif isinstance(result, str):
print(result)
elif isinstance(result, bool):
if result is True:
print("true")
else:
print("false")
撇开所有可以简化的事实不谈,代码似乎清楚地表明了打印评估结果的意图。如果你现在不想打印求值结果,你就不应该打印求值结果。
当您在树中看到 say
函数时,您 return 计算其参数的结果:
if node[0] == 'say':
return self.walkTree(node[1])
如果您希望 say
函数具有打印其参数求值结果的效果,您应该打印其参数求值结果而不是 return其论点的评估结果(或 returning 结果,取决于您认为 say
的语义)。
所以我正在使用 python 包 sly,它有一个词法分析器和解析器 class。我正在制作自己的编程语言 NoobPy。所以目前,代码将打开 test.noob 并读取每一行并解析它。现在,如果我要定义一个变量,比方说 x
,只需在一行中写入 x
,它就会打印出来,而我不希望这样。我希望它只有在我创建的 say
函数中传递时才打印。
词法分析器class
class NoobpyLexer(Lexer):
tokens = {NUMBER, STRING, FALSE, TRUE, NAME, WHILE, IF, ELSE, SAY,
PLUS, MINUS, TIMES, DIVIDE, ASSIGN,
EQ, LT, LE, GT, GE, NEQ}
literals = {'(', ')', ':'}
# String containing ignored characters
ignore = ' \t'
# Regular expression rules for tokens
STRING = r'\".*?\"'
PLUS = r'\+'
MINUS = r'-'
TIMES = r'\*'
DIVIDE = r'/'
EQ = r'=='
NEQ = r'!='
ASSIGN = r'='
LE = r'<='
GE = r'>='
LT = r'<'
GT = r'>'
@_(r'\d+')
def NUMBER(self, t):
t.value = int(t.value)
return t
# @_(r'^((true$|false$)$)')
# def BOOL(self, t):
# return t
@_(r'true')
def TRUE(self, t):
return t
@_(r'false')
def FALSE(self, t):
return t
# Identifiers and keywords
NAME = r'\b(?!((true$|false$)$)\b)\w+' # [a-zA-Z_][a-zA-Z0-9_]*$
NAME['if'] = IF
NAME['else'] = ELSE
NAME['while'] = WHILE
NAME['say'] = SAY
ignore_comment = r'\#.*'
# Line number tracking
@_(r'\n+')
def ignore_newline(self, t):
self.lineno += t.value.count('\n')
def error(self, t):
print("t: ", t)
print('Line %d: Bad character %r' % (self.lineno, t.value[0]))
self.index += 1
解析器class
class NoobpyParser(Parser):
# Get the token list from the lexer (required)
tokens = NoobpyLexer.tokens
log = logging.getLogger()
log.setLevel(logging.ERROR)
# debugfile = 'parser.out'
precedence = (
('left', PLUS, MINUS),
('left', TIMES, DIVIDE),
('right', UMINUS)
)
def __init__(self):
self.variables = {}
@_('')
def statement(self, p):
pass
@_('SAY expr')
def statement(self, p):
return 'say', p.expr
@_('NAME')
def expr(self, p):
return 'var', p.NAME
@_('var_assign')
def statement(self, p):
return p.var_assign
@_('NAME ASSIGN expr')
def var_assign(self, p):
return 'var_assign', p.NAME, p.expr
@_('expr')
def statement(self, p):
return p.expr
@_('expr PLUS expr')
def expr(self, p):
return 'add', p.expr0, p.expr1
@_('expr MINUS expr')
def expr(self, p):
return 'sub', p.expr0, p.expr1
@_('expr TIMES expr')
def expr(self, p):
return 'mul', p.expr0, p.expr1
@_('expr DIVIDE expr')
def expr(self, p):
return 'div', p.expr0, p.expr1
@_('MINUS expr %prec UMINUS')
def expr(self, p):
expression = list(p.expr)
if isinstance(expression[1], tuple):
res = 0
for i in expression[1]:
res += i
expression[1] = res
expression[1] = -expression[1]
return expression
@_('expr EQ expr')
def expr(self, p):
return 'eq', p.expr0, p.expr1
@_('"(" expr ")"')
def expr(self, p):
return p.expr
@_('NUMBER')
def expr(self, p):
return 'num', p.NUMBER
@_('STRING')
def expr(self, p):
return 'str', p.STRING
@_('TRUE')
def expr(self, p):
return p.TRUE
@_('FALSE')
def expr(self, p):
return p.FALSE
执行class
class NoobpyExecute:
def __init__(self, tree, variables):
self.variables = variables
result = self.walkTree(tree)
if result is None:
pass
elif result is not None and type(result) in [int, float]:
print(result)
elif isinstance(result, str):
print(result)
elif isinstance(result, bool):
if result is True:
print("true")
else:
print("false")
def walkTree(self, node):
if isinstance(node, int):
return node
if isinstance(node, str):
return node
if node is None:
return None
if node[0] == 'say':
return self.walkTree(node[1])
if node[0] == 'num':
return node[1]
if node[0] == 'str':
return node[1]
if node[0] == 'eq':
return self.walkTree(node[1]) == self.walkTree(node[2])
if node[0] == 'add':
return self.walkTree(node[1]) + self.walkTree(node[2])
elif node[0] == 'sub':
return self.walkTree(node[1]) - self.walkTree(node[2])
elif node[0] == 'mul':
return self.walkTree(node[1]) * self.walkTree(node[2])
elif node[0] == 'div':
return self.walkTree(node[1]) / self.walkTree(node[2])
if node[0] == 'var_assign':
self.variables[node[1]] = self.walkTree(node[2])
if node[0] == 'var':
try:
return self.variables[node[1]]
except LookupError:
print("Undefined name '{}'".format(node[1]))
return 0
这个:
if __name__ == '__main__':
lexer = NoobpyLexer()
parser = NoobpyParser()
variables = {}
args = argparse.ArgumentParser()
args.add_argument(metavar='filename', dest="filename", type=str, help='name of the file you want to run')
args = args.parse_args()
with open(args.filename) as file:
for line in file.readlines():
tree = parser.parse(lexer.tokenize(line))
NoobpyExecute(tree, variables)
示例test.noob
x = 2
x
^ 打印 2
在你的 NoobPy
构造函数中,你打印出评估语法树的结果(除非它是 None,如果你评估一个赋值就会发生):
if result is None:
pass
elif result is not None and type(result) in [int, float]:
print(result)
elif isinstance(result, str):
print(result)
elif isinstance(result, bool):
if result is True:
print("true")
else:
print("false")
撇开所有可以简化的事实不谈,代码似乎清楚地表明了打印评估结果的意图。如果你现在不想打印求值结果,你就不应该打印求值结果。
当您在树中看到 say
函数时,您 return 计算其参数的结果:
if node[0] == 'say':
return self.walkTree(node[1])
如果您希望 say
函数具有打印其参数求值结果的效果,您应该打印其参数求值结果而不是 return其论点的评估结果(或 returning 结果,取决于您认为 say
的语义)。