2011-07-21 3 views
3

Cette question peut sembler un peu confuse. J'utilise Flex pour passer des jetons à Bison. Le comportement que je souhaite est que Flex corresponde à l'expression régulière la plus longue et passe ce jeton (cela fonctionne comme cela), mais si ce jeton ne fonctionne pas avec la grammaire, il correspond à la deuxième expression régulière la plus longue et passe ce jeton. J'ai du mal à trouver un moyen de créer ce comportement. Comment pourrais-je y arriver?Comment faire pour tester la seconde expression régulière correspondante la plus longue?

Pour clarifier les choses, par exemple, que j'ai deux règles:

"//" return TOKEN_1; 
"///" return TOKEN_2; 

Compte tenu de la chaîne "///", je voudrais que ce premier passage TOKEN_2 (il fait). Si TOKEN_2 ne correspond pas à la grammaire spécifiée dans Bison, il passe alors TOKEN_1 (ce qui est également valide).

Comment est-ce que je peux créer ce comportement?

+0

Je travaille avec un fichier volumineux et n'utilise pas de système avec un terminal. Il m'est donc difficile de vérifier les choses à l'aide d'un exemple simple. Ce n'est pas le comportement par défaut, n'est-ce pas? –

+0

Voulez-vous cela pour un ensemble spécifique de règles, ou pour toutes les règles en général? Si ce dernier, je serais surpris si vous avez accompli cela en utilisant flex. S'il s'agit d'un ensemble spécifique de règles, vous pouvez et devriez refactoriser les règles. – Kizaru

+0

Cette situation de jeton ne concerne que deux jetons différents. Fondamentalement, c'est j'essaye de traiter un commentaire comme un type spécifique de commentaire, mais si cela cause un problème alors juste le traiter comme un commentaire régulier. Il serait très difficile de refactoriser mes règles de cette manière, et si je pouvais obtenir ce jeton en passant la méthode au travail, je pense que ce serait beaucoup plus simple. –

Répondre

0

Désolé mais vous ne pouvez pas faire cela. Je ne sais pas vraiment combien de flex parle aux bisons. Je sais qu'il existe un mode pour l'analyse syntaxique REPL et je sais qu'il existe un autre mode qui analyse tout.

Vous devrez respecter la règle. Par exemple au lieu de // et/vous écrivez une règle qui accepte /// alors une autre qui suppose /// signifie // /. Mais cela devient salissant et je l'ai fait seulement dans un cas spécifique dans mon code.

3

En flex, vous pouvez avoir une règle qui essaie de faire quelque chose, mais échoue et tente la deuxième meilleure règle à l'aide de la REJECT macro:

REJET Dirige le scanner pour procéder à la « deuxième meilleure "règle qui correspond à l'entrée (ou préfixe de l'entrée). La règle est choisie comme décrite ci-dessus dans "Comment l'entrée est appariée", et yytext et yyleng mis en place de façon appropriée. Il peut correspondre à autant de texte que la règle initialement choisie mais est apparu plus tard dans le fichier d'entrée flex , ou dans celui contenant moins de texte.

(source: The Flex Manual Page). Donc, pour répondre à votre question sur l'obtention de la deuxième expression la plus longue, vous pouvez le faire en utilisant REJECT (bien que vous deviez faire attention, car il pourrait juste choisir quelque chose de la même longueur avec la même priorité).

Notez que flex fonctionnera plus lentement avec REJECT étant utilisé car il a besoin de maintenir une logique supplémentaire pour "retomber" à des allumettes plus mauvaises à tout moment. Je suggère seulement d'utiliser ceci s'il n'y a pas d'autre moyen de résoudre votre problème.

+0

Merci ... c'est utile et semble être sur la bonne voie. Cependant, comment REJECT pourrait-il savoir que le jeton a déclenché une erreur dans la règle dans Bison? –

0

Je voudrais juste que le lexer scanne deux jetons // et / et que l'analyseur traite les cas où ils sont censés être considérés comme un jeton, ou séparés. C'est à dire. une règle de grammaire commençant par /// peut être refactorisée en une règle commençant par // et /. En d'autres termes, ne pas avoir un TOKEN_2 du tout.Dans les mêmes cas, ce genre de chose peut être délicat, car l'analyseur LARL (1) n'a qu'un jeton de lookahead. Il doit faire un changement ou réduire la décision basée sur voir le // seulement, sans tenir compte du / qui suit.

J'ai eu une idée pour résoudre cela avec une approche hacky impliquant un lien lexical, mais il s'est avéré irréalisable.

Le défaut principal avec l'idée est qu'il n'y a aucun moyen facile de faire une récupération d'erreur dans yacc qui est cachée à l'utilisateur. Si une erreur de syntaxe est déclenchée, cela est visible. La fonction yyerror peut contenir un hack pour essayer de cacher cela, mais il manque les informations de contexte. En d'autres termes, vous ne pouvez pas vraiment utiliser les actions d'erreur Yacc pour déclencher une recherche backtracking pour une autre analyse.

0

Ceci est difficile pour bison/yacc à traiter, car il ne fait pas de retour en arrière. Même si vous utilisez un générateur d'analyseur backtracking comme btyacc, cela n'aide pas vraiment, sauf s'il retourne aussi à travers le lexer (ce qui nécessiterait probablement un générateur d'analyseur avec lexeur intégré.)

Ma suggestion serait de reconnaître le lexer une barre oblique immédiatement suivie d'une barre oblique spécialement et retourner un jeton différent:

\//\/  return SLASH; 
\/   return '/'; /* not needed if you have the catch-all rule: */ 
.   return *yytext; 

maintenant, vous devez « assembler » « jetons » que les non-terminaux multi-slash dans la Grammer.

single_slash: SLASH | '/' ; 
double_slash: SLASH SLASH | SLASH '/' ; 
triple_slash: SLASH SLASH SLASH | SLASH SLASH '/' ; 

Cependant, vous allez maintenant vous trouverez probablement avoir des conflits dans la grammaire en raison de la 1-token préanalyse ne pas être suffisant. Vous pouvez être en mesure de résoudre ceux-ci en utilisant btyacc ou l'option %glr-parser de bison.

Questions connexes