造个轮子--用Python写个编程语言-逻辑运算
@[TOC]
前言
在上一篇文章里面,实现了基本的变量,并且详细地阐述了基本原理,所以的话,这里要实现的就是这个判断,由于架子基本上打好了,后面的操作无法就是确定这个AST的一个执行顺序,也就是我们希望解释器执行的一个情况。
那么这里要实现的效果是这样的:
这里的实现的话,就比较简单了,如果前面理解的话,只是多了些操作的东西而已。
关键词
那么老规矩,我们需要先来定义我们的关键词。
先定义我们的类型,和合法的字符:
TT_INT = "整数"
TT_FLOAT = "浮点数"
TT_PLUS = "加号"
TT_DIV = "除号"
TT_MINUS = "减号"
TT_LPAREN = "左括号"
TT_RPAREN = "右括号"
TT_POW = '次幂'
TT_MUL = "乘"
TT_EOF = 'EOF'
TT_IDENTIFIER = '设'
TT_KEYWORD = '关键字'
TT_EQ = '赋值'
TT_EE = '等于'
TT_NE = '不等于'
TT_LT = '小于'
TT_GT = '大于'
TT_LTE = '小于等于'
TT_GTE = '大于等于'
KEYWORDS = [
'设',
'且',
'或',
'否'
]
解析token
之后的话,是解析我们的token,这里的话,完全是老规矩。
主要是这里,我们有>=,<=这种字符,我们要进行处理
那么这块的话,主要是这几个方法:
def make_not_equals(self):
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
return Token(TT_NE, pos_start=pos_start, pos_end=self.pos), None
self.advance()
return None, ExpectedCharError(pos_start, self.pos, "'=' (after '!')")
def make_equals(self):
tok_type = TT_EQ
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
tok_type = TT_EE
return Token(tok_type, pos_start=pos_start, pos_end=self.pos)
def make_less_than(self):
tok_type = TT_LT
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
tok_type = TT_LTE
return Token(tok_type, pos_start=pos_start, pos_end=self.pos)
def make_greater_than(self):
tok_type = TT_GT
pos_start = self.pos.copy()
self.advance()
if self.current_char == '=':
self.advance()
tok_type = TT_GTE
return Token(tok_type, pos_start=pos_start, pos_end=self.pos)
通过这几个方法我们就可以实现这个效果。完成<=,>=这样的关键字的Token的生成
解析器
之后的话,就是我们的语法解析器了。
在这里的话,核心代码的修改主要在这块:
这块的话,前面重复过多次了,就不重复说明了。
def arith_expr(self):
return self.bin_op(self.term, (TT_PLUS, TT_MINUS))
def comp_expr(self):
res = ParseResult()
if self.current_tok.matches(TT_KEYWORD, '否'):
op_tok = self.current_tok
res.register_advancement()
self.advance()
node = res.register(self.comp_expr())
if res.error: return res
return res.success(UnaryOpNode(op_tok, node))
node = res.register(self.bin_op(self.arith_expr, (TT_EE, TT_NE, TT_LT, TT_GT, TT_LTE, TT_GTE)))
if res.error:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected int, float, identifier, '+', '-', '(' or 'NOT'"
))
return res.success(node)
def expr(self):
res = ParseResult()
if self.current_tok.matches(TT_KEYWORD, '设'):
res.register_advancement()
self.advance()
if self.current_tok.type != TT_IDENTIFIER:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected identifier"
))
var_name = self.current_tok
res.register_advancement()
self.advance()
if self.current_tok.type != TT_EQ:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected '='"
))
res.register_advancement()
self.advance()
expr = res.register(self.expr())
if res.error: return res
return res.success(VarAssignNode(var_name, expr))
node = res.register(self.bin_op(self.comp_expr, ((TT_KEYWORD, '且'), (TT_KEYWORD, '或'))))
if res.error:
return res.failure(InvalidSyntaxError(
self.current_tok.pos_start, self.current_tok.pos_end,
"Expected 'VAR', int, float, identifier, '+', '-', '(' or 'NOT'"
))
return res.success(node)
解释器
最后是我们的解释器。在这里我们需要为这种新加如的节点进行处理,所以核心是加入新的处理函数。
def get_comparison_eq(self, other):
if isinstance(other, Number):
return Number(int(self.value == other.value)).set_context(self.context), None
def get_comparison_ne(self, other):
if isinstance(other, Number):
return Number(int(self.value != other.value)).set_context(self.context), None
def get_comparison_lt(self, other):
if isinstance(other, Number):
return Number(int(self.value < other.value)).set_context(self.context), None
def get_comparison_gt(self, other):
if isinstance(other, Number):
return Number(int(self.value > other.value)).set_context(self.context), None
def get_comparison_lte(self, other):
if isinstance(other, Number):
return Number(int(self.value <= other.value)).set_context(self.context), None
def get_comparison_gte(self, other):
if isinstance(other, Number):
return Number(int(self.value >= other.value)).set_context(self.context), None
def anded_by(self, other):
if isinstance(other, Number):
return Number(int(self.value and other.value)).set_context(self.context), None
def ored_by(self, other):
if isinstance(other, Number):
return Number(int(self.value or other.value)).set_context(self.context), None
def notted(self):
return Number(1 if self.value == 0 else 0).set_context(self.context), None
def copy(self):
copy = Number(self.value)
copy.set_pos(self.pos_start, self.pos_end)
copy.set_context(self.context)
return copy
那么在这里的话,我们就完成了基本这个逻辑运算了。因为核心的原理我们已经说清楚了,我们所有的代码基本上就是为指定的语法规则服务。比较核心的在这里,其实是AST的构建,而AST核心的是对语法规则的构建定义。这影响到你的代码到底如何执行递归,递归执行的顺序到底是怎么样的。
语法表示
所以在这块的话,我们现在来看到最新的语法表示:
expr : KEYWORD:VAR IDENTIFIER EQ expr
: comp-expr ((KEYWORD:AND|KEYWORD:OR) comp-expr)*
comp-expr : NOT comp-expr
: arith-expr ((EE|LT|GT|LTE|GTE) arith-expr)*
arith-expr : term ((PLUS|MINUS) term)*
term : factor ((MUL|DIV) factor)*
factor : (PLUS|MINUS) factor
: power
power : atom (POW factor)*
atom : INT|FLOAT|IDENTIFIER
: LPAREN expr RPAREN