将OR语句与Python SLY组合

时间:2019-04-09 20:57:45

标签: python parsing boolean

我正在将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

1 个答案:

答案 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行的测试,我发现这很丑陋。更干净的解决方案是将语法中的个案分开。 (请注意:就像您的语法一样,以下代码将ANDOR赋予相同的优先级,只需从左到右进行关联即可。这不是不是编写布尔表达式的常用方法。 )

@_('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,也没有检查以上任何代码。如果它不起作用,请告诉我。)