Я работаю над простым SQL-выбором, таким как синтаксический анализатор запросов, и мне нужно иметь возможность буквально захватывать подзапросы, которые могут возникать в определенных местах. Я обнаружил, что состояния лексера — лучшее решение, и смог выполнить POC, используя фигурные скобки, чтобы отметить начало и конец. Однако подзапросы будут ограничены круглыми скобками, а не фигурными скобками, и скобки могут встречаться и в других местах, поэтому я не могу быть состоянием для каждого открытого скобки. Эта информация легкодоступна с помощью синтаксического анализатора, поэтому я надеялся вызвать начало и конец в соответствующих местах в правилах синтаксического анализатора. Однако это не сработало, потому что лексер, похоже, токенизирует поток сразу, и поэтому токены генерируются в начальном состоянии. Есть ли обходной путь для этой проблемы? Вот в общих чертах то, что я пытался сделать:
def p_value_subquery(p):
"""
value : start_sub end_sub
"""
p[0] = "( " + p[1] + " )"
def p_start_sub(p):
"""
start_sub : OPAR
"""
start_subquery(p.lexer)
p[0] = p[1]
def p_end_sub(p):
"""
end_sub : CPAR
"""
subquery = end_subquery(p.lexer)
p[0] = subquery
Функции start_subquery() и end_subquery() определены следующим образом:
def start_subquery(lexer):
lexer.code_start = lexer.lexpos # Record the starting position
lexer.level = 1
lexer.begin('subquery')
def end_subquery(lexer):
value = lexer.lexdata[lexer.code_start:lexer.lexpos-1]
lexer.lineno += value.count('\n')
lexer.begin('INITIAL')
return value
Лексические токены нужны просто для обнаружения закрывающей скобки:
@lex.TOKEN(r"\(")
def t_subquery_SUBQST(t):
lexer.level += 1
@lex.TOKEN(r"\)")
def t_subquery_SUBQEN(t):
lexer.level -= 1
@lex.TOKEN(r".")
def t_subquery_anychar(t):
pass
Буду признателен за любую помощь.