Je travaille sur un simple SQL Sélectionnez comme une requête de requête et je dois pouvoir capturer les sous-couches pouvant survenir à certains endroits littéralement. J'ai trouvé que Lexer States est la meilleure solution et a pu faire un POC en utilisant des accolades bouclées pour marquer le début et la fin. Cependant, les sous-sollicitations seront délimitées par des parenthèses, non des bouclés et que la parenthèse peut également se produire à d'autres endroits, donc je ne peux donc pas être l'état avec chaque paren ouvert. Cette information est facilement disponible avec l'analyseur. J'espérais donc appeler commencer et mettre fin à des emplacements appropriés dans les règles d'analyse. Cela n'a toutefois pas fonctionné car Lexer semble goûter à la fois le flux à la fois, et les jetons sont donc générés dans l'état initial. Y a-t-il une solution de contournement pour ce problème? Voici un aperçu de ce que j'ai essayé de faire:
@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
3 Réponses :
Puisque personne n'a de réponse, il m'a bugié de trouver une solution de contournement et voici un piratage laids utilisant la récupération d'erreur et le redémarrage ().
Cette réponse ne peut être partiellement utile que partiellement utile, mais je suggérerais également de regarder la section "6.11 actions intégrées" de la documentation de plie (http://www.dabeaz.com/ply/ply.html). En un mot, il est possible d'écrire des règles de grammaire dans lesquelles les actions se produisent à mi-règle. Cela ressemblerait quelque chose de similaire à celui-ci:
def p_somerule(p): '''somerule : A B possible_sub_query LBRACE sub_query RBRACE''' def p_possible_sub_query(p): '''possible_sub_query :''' ... # Check if the last token read was LBRACE. If so, flip lexer state # Sadly, it doesn't seem that the token is easily accessible. Would have to hack it if last_token == 'LBRACE': p.lexer.begin('SUBQUERY')
Merci pour le pointeur des actions DMBDED, il a l'air très prometteur. Cependant, dans votre exemple, nous sommes censés vérifier le jeton Lookahead au lieu du dernier jeton? Le dernier jeton serait B code>, mais le lookahead serait
lgramse code> non?
Basé sur la réponse de l'auteur de pli, j'ai proposé cette meilleure solution. Je dois encore savoir comment retourner la sous-requête comme jeton, mais le reste semble beaucoup mieux et ne doit plus être considéré comme un hack.
def start_subquery(lexer): lexer.code_start = lexer.lexpos # Record the starting position lexer.level = 1 lexer.begin("subquery") def end_subquery(lexer): lexer.begin("INITIAL") def get_subquery(lexer): value = lexer.lexdata[lexer.code_start:lexer.code_end-1] lexer.lineno += value.count('\n') return value @lex.TOKEN(r"\(") def t_subquery_OPAR(t): lexer.level += 1 @lex.TOKEN(r"\)") def t_subquery_CPAR(t): lexer.level -= 1 if lexer.level == 0: lexer.code_end = lexer.lexpos # Record the ending position return t @lex.TOKEN(r".") def t_subquery_anychar(t): pass def p_value_subquery(p): """ value : check_subquery_start OPAR check_subquery_end CPAR """ p[0] = "( " + get_subquery(p.lexer) + " )" def p_check_subquery_start(p): """ check_subquery_start : """ # Here last_token would be yacc's lookahead. if last_token.type == "OPAR": start_subquery(p.lexer) def p_check_subquery_end(p): """ check_subquery_end : """ # Here last_token would be yacc's lookahead. if last_token.type == "CPAR": end_subquery(p.lexer) last_token = None def p_error(p): global subquery_retry_pos if p is None: print >> sys.stderr, "ERROR: unexpected end of query" else: print >> sys.stderr, "ERROR: Skipping unrecognized token", p.type, "("+ \ p.value+") at line:", p.lineno, "and column:", find_column(p.lexer.lexdata, p) # Just discard the token and tell the parser it's okay. yacc.errok() def get_token(): global last_token last_token = lexer.token() return last_token def parse_query(input, debug=0): lexer.input(input) return parser.parse(input, tokenfunc=get_token, debug=0)