Объединение операторов OR с Python SLY - PullRequest
0 голосов
/ 09 апреля 2019

Я использую 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, объединенных вместе,было бы неплохо объединить их в операторах ИЛИ произвольной длины: ('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 голосов
/ 10 апреля 2019

Вы можете сделать это несколькими способами. Самое простое, если вы хотите отловить все случаи (включая, например, "(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 и не проверял ни один из приведенных выше кодов. Если он не работает, дайте мне знать.)

...