Я очень плохо знаком с pyparsing и Python, так что это предупреждение о том, что я могу что-то делать действительно неправильно.
То, что я пытаюсь сделать, - это создать синтаксический анализатор SQL и построить дерево с узлами, по которым я затем смогу ходить.
Я пытаюсь скопировать подобные вещи из файла грамматики yacc / bison:
| scalar_exp '^' scalar_exp
{ $$ = new QgsSearchTreeNode(QgsSearchTreeNode::opPOW, $1, $3);
joinTmpNodes($$,$1,$3); }
Это код, который у меня есть в Python:
LPAR = Suppress('(')
RPAR = Suppress(')')
COMMA = Suppress(',')
AND = CaselessKeyword('AND')
ASC = CaselessKeyword('ASC')
DESC = CaselessKeyword('DESC')
ON = CaselessKeyword('ON')
USING = CaselessKeyword("USING")
INNER = CaselessKeyword("INNER")
JOIN = CaselessKeyword("JOIN")
AS = CaselessKeyword("AS")
NOT = CaselessKeyword("NOT")
SELECT = CaselessKeyword("SELECT")
FROM = CaselessKeyword("FROM")
WHERE = CaselessKeyword("WHERE")
GROUP = CaselessKeyword("GROUP")
BY = CaselessKeyword("BY")
ORDER = CaselessKeyword("ORDER")
LIMIT = CaselessKeyword("LIMIT")
BETWEEN = CaselessKeyword("BETWEEN")
UNARY = 1
BINARY = 2
TERNARY = 3
keyword = MatchFirst(( ASC, DESC, ON, USING, INNER,
JOIN, AS, NOT, SELECT, FROM, WHERE, GROUP, BY,
ORDER, BY, LIMIT,BETWEEN))
identifier = ~keyword + Word(alphas, alphanums+"_")
collation_name = identifier.copy()
column_name = Suppress('[') + ~keyword + Word(alphas, alphanums+"_") + Suppress(']')
column_alias = identifier.copy()
table_name = identifier.copy()
table_alias = identifier.copy()
index_name = identifier.copy()
function_name = identifier.copy()
parameter_name = identifier.copy()
expr = Forward().setName("expression")
select_stmt = Forward().setName("select statement")
integer = Regex(r"[+-]?\d+")
numeric_literal = Regex(r"\d+(\.\d*)?([eE][+-]?\d+)?")
string_literal = QuotedString("'")
literal_value = ( numeric_literal | string_literal)
expr_term = (
function_name + LPAR + Optional(delimitedList(expr)) + RPAR |
literal_value |
identifier |
column_name
)
expr << operatorPrecedence(expr_term,
[
(oneOf('- + ~') | NOT, UNARY, opAssoc.LEFT, setObject),
('||', BINARY, opAssoc.LEFT),
(oneOf('* / %'), BINARY, opAssoc.LEFT,setObject),
(oneOf('+ -'), BINARY, opAssoc.LEFT),
(oneOf('<< >> & |'), BINARY, opAssoc.LEFT),
(oneOf('< <= > >='), BINARY, opAssoc.LEFT),
(oneOf('= == != <>') , BINARY, opAssoc.LEFT),
('||', BINARY, opAssoc.LEFT),
((BETWEEN,AND), TERNARY, opAssoc.LEFT),
])
ordering_term = expr + Optional(ASC | DESC)
join_constraint = ON + expr('join_expression')
join_op = COMMA | (INNER + JOIN)
join_source = Forward()
single_source = ( table_name("table") +
Optional(Optional(AS) + table_alias("table_alias")))
join_source << single_source + Group(ZeroOrMore(join_op + single_source + Optional(join_constraint)))("join")
result_column = "*" | table_name + "." + "*" | (expr + Optional(Optional(AS) + column_alias))
select_core = (SELECT + Group(delimitedList(result_column))("columns") +
Optional(FROM + join_source).setParseAction(setObject) +
Optional(WHERE + expr("where_expr")) +
Optional(GROUP + BY + Group(delimitedList(ordering_term)("group_by_terms")))
)
select_stmt << (select_core + ZeroOrMore(select_core) +
Optional(ORDER + BY + Group(delimitedList(ordering_term))("order_by_terms"))
)
примечание: это урезанная версия select_parser.py Пола Макгуайра
Я думаю, что должен использовать setParseAction, но когда я делаю это, я всегда получаю None для токенов в методе, который я вызываю. Я получаю полную строку и местоположение, но никаких токенов.
Где лучше всего вызвать setParseAction для копирования логики yacc / bison?