我正在将SLY与Python结合使用,以相对简单的语法分析文本。我要分析的字符串包含使用AND或OR语句组合的某个系统的信号名称。也就是说,类似"(SIG1 OR SIG2 OR SIG3 OR SIG4 OR SIG5) AND SIG6"
。
数据的一个特征是,它将由一长串的信号进行“或”运算控制。到目前为止,我构建的解析器(请参阅下文)仅将OR或AND运算符理解为二进制,因此输出嵌套元组,如下所示:('AND', ('OR', ('OR', ('OR', ('OR', 'SIG1', 'SIG2'), 'SIG3'), 'SIG4'), 'SIG5'), 'SIG6')
给定OR语句的列表,最好将它们合并到任意长度的OR语句中:('AND', ('OR', 'SIG1', 'SIG2', 'SIG3', 'SIG4', 'SIG5'), 'SIG6')
我想我必须编辑解析器,但是我不知道怎么做,不胜感激您可以给我的任何指点。
class BoolLexer(Lexer):
tokens = { ID, LPAREN, RPAREN, AND, OR }
ignore = ' \t\n'
ID = r'[a-zA-Z_\.][a-zA-Z0-9_\.]*'
LPAREN = r'\('
RPAREN = r'\)'
ID['AND'] = AND
ID['OR'] = OR
class BoolParser(Parser):
tokens = BoolLexer.tokens
@_('expr AND term')
def expr(self, p):
return ('AND', p.expr, p.term)
@_('expr OR term')
def expr(self, p):
return ('OR', p.expr, p.term)
@_('term')
def expr(self, p):
return p.term
@_('ID')
def term(self, p):
return p.ID
@_('LPAREN expr RPAREN')
def term(self, p):
return p.expr
答案 0 :(得分:0)
您可以通过以下两种方法进行操作。如果要捕获所有情况(包括"(SIG1 OR SIG2) OR (SIG3 OR SIG4)"
),最直接的方法是先构建AST,然后递归遍历AST,从而简化每个节点。
您也可以在创建AST节点时进行简化,但这不会引起上述情况:
@_('expr OR term')
def expr(self, p):
if (isinstance(expr, tuple) and expr[0] is "OR"):
return p.expr + (p.term,)
else:
return ('OR', p.expr, p.term)
但是,由于第3行的测试,我发现这很丑陋。更干净的解决方案是将语法中的个案分开。 (请注意:就像您的语法一样,以下代码将AND
和OR
赋予相同的优先级,只需从左到右进行关联即可。这不是不是编写布尔表达式的常用方法。 )
@_('and_expr',
'or_expr',
'term)
def expr(self, p):
return p[0]
@_('term OR term')
def or_expr(self, p):
return ('OR', p.term0, p.term1)
@_('or_expr OR term')
def or_expr(self, p):
return p.or_expr + (p.term,)
@_('term AND term')
def and_expr(self, p):
return ('AND', p.term0, p.term1)
@_('and_expr AND term')
def and_expr(self, p):
return p.and_expr + (p.term,)
(我从未使用过SLY,也没有检查以上任何代码。如果它不起作用,请告诉我。)