Я использую СЛИ с Python для анализа текста с относительно простой грамматикой. Строки, которые я хотел бы проанализировать, содержат имена сигналов из определенной системы, объединенные с помощью операторов AND или OR. То есть что-то вроде "(SIG1 OR SIG2 OR SIG3 OR SIG4 OR SIG5) AND SIG6"
.
Одной из характеристик данных является то, что в них преобладают длинные списки сигналов, объединенных по ИЛИ. Синтаксический анализатор, который я построил до сих пор (см. Ниже), понимает только операторы ИЛИ или И как двоичные, и поэтому выводит вложенный кортеж, подобный следующему:
Учитывая список операторов, объединенных ИЛИ, было бы неплохо объединить их в операторы ИЛИ произвольной длины: ('AND', ('OR', ('OR', ('OR', ('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
Вы можете сделать это несколькими способами. Самый простой способ, если вы хотите уловить все случаи (включая, например, "(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 и не проверял приведенный выше код. Если он не работает, дайте мне знать.)
Спасибо. Это сработало. В вашем первом блоке кода есть небольшая ошибка - строка 4: должно быть возвращено p.expr + (p.term,) У меня небольшие трудности с отслеживанием логики во втором блоке кода, но это связано с моим незнание парсеров. Спасибо за вашу помощь.