Получение написанного парсера - первый шаг.Отсюда, я предлагаю вам улучшить ваш operatorPrecedence
вызов (имя является старым и устаревшим, кстати, теперь он называется infixNotation
), чтобы pyparsing создавал вложенный набор узлов, который соответствует построению абстрактного синтаксического дерева (AST).Несмотря на то, что вам удалось запустить парсер, я должен сказать вам, что этот следующий шаг довольно большой.
Идея состоит в том, чтобы синтаксический анализатор возвращал вам не только строки или преобразованные целые и плавающие числа, но ифактические экземпляры классов.Это выглядело бы примерно так:
class AndOperation:
def __init__(self, tokens):
# tokens will look like [operand1, 'AND', operand2, 'AND', operand3, ...]
self._operands = tokens[::2]
class OrOperation:
def __init__(self, tokens):
# tokens will look like [operand1, 'OR', operand2, 'OR', operand3, ...]
self._operands = tokens[::2]
class NotOperation:
def __init__(self, tokens):
# tokens will look like ['NOT', operand]
self._operands = tokens[-1]
Затем вы добавили бы их в infixNotation как:
AND, OR, TRUE, FALSE = map(pp.Keyword, "AND OR TRUE FALSE".split())
boolean_term = TRUE | FALSE | ~(AND | OR) + pp.pyparsing_common.identifier
boolean_expr = pp.infixNotation(boolean_term,
[
('NOT', 1, pp.opAssoc.RIGHT, NotOperation),
('AND', 2, pp.opAssoc.LEFT, AndOperation),
('OR', 2, pp.opAssoc.LEFT, OrOperation),
])
Без добавленных действий разбора класса, разбор "P AND NOT Q" вернул бы:
[['P', 'AND', ['NOT', 'Q']]]
С добавленными классами анализ "P AND NOT Q" даст вам что-то вроде:
[AndOperation('P', NotOperation('Q'))]
На этом этапе вы можете выбрать, хотите ли вы добавить какую-либо формуevaluate()
или execute
метода для каждого класса xxxOperation для оценки выражения или, возможно, render
метода, если вы хотите просто вывести предложение SQL WHERE.
Например, render
для AndOperationдля создания SQL синтаксис WHERE может выглядеть следующим образом:
def render(self):
return ' AND '.join("'" + oper + "'" if isinstance(oper, str) else oper.render()
for oper in self.operands)
(Как отмечает Илья Эверила в своем комментарии, остерегайтесь проблем с внедрением SQL, когда работает , например, такое предложение WHERE напрямую - render()
в основном для визуализации и отладки)
В каталоге pyparsing repo examples
есть несколько примеров (https://github.com/pyparsing/pyparsing/tree/master/examples) - поиск вариантов использования infixNotation
, чтобы увидеть, как они выполняются.