J'essaye de construire un analyseur pour un DSL que je construis en utilisant Irony dans .NET et j'ai trouvé un problème que je n'arrive pas à contourner. Depuis qu'il gère BNF, je pense que toute solution BNF sera utile.Faire face à l'ambiguïté dans la grammaire BNF
J'ai l'entrée suivante:
$10 yesterday at drug store
Avec la grammaire suivante:
<expr> :== unit | expr + unit
<unit> :== money | date | location
<date> : == yesterday|today|tomorrow
<location> :== .* | <preposition> .*
<preposition> :== at
<money> :== ((\$)?\d*((\.*)\d*)*\,?\d{1,2})
Il fonctionne comme un charme avec cette entrée. Je reçois exactement le résultat que je voulais qui est:
Money Amount: 10
Date: Yesterday
Location: Drug Store
Cependant, si je change l'ordre de l'entrée comme suit
$10 at drug store yesterday
en raison de réduire les étapes qu'il ne me donne la même sortie. La sortie devient:
Money amount: 10
Location: Drug Store Yesterday
Je me demandais s'il y a moyen de faire en sorte que Lieu (qui est un match de regex vraiment large) est évaluée uniquement lorsque tous les autres jetons sont capturés et rien d'autre est laissé.
Toute aide est appréciée.
Merci!
Edit: Titre Mise à jour selon la suggestion
Ce n'est pas vraiment une question à propos de BNF, en soi. Dans une grammaire BNF, il n'y a pas de notion de "préséance" des règles. Ce que vous avez est une grammaire ambiguë; c'est-à-dire qu'il y a plus d'une dérivation de certaines chaînes dans votre langue. La seule façon pour BNF de résoudre ce problème est de proposer une grammaire sans ambiguïté, ce qui n'est pas toujours possible. Dans votre cas, la manière évidente d'essayer d'obtenir une grammaire non ambiguë est de définir afin que les chaînes contenant des éléments tels que "hier" soient capturées et non acceptées comme des emplacements valides. –
Patrick87
Merci @ Patrick87 pour le commentaire. En supposant que j'ai plus qu'hier pour "ignorer" dans la définition, comment suggérez-vous que je le fasse? Y a-t-il un moyen de dire "assortir ceci et exclure tout cela"? –
tucaz
Il existe des moyens faciles et des moyens difficiles de le faire; les moyens faciles dépendent des capacités de votre syntaxe regex, et les méthodes difficiles fonctionnent pour toutes les expressions régulières mais, eh bien, prenez un peu de travail à faire. Vous devriez vérifier votre syntaxe regex pour les opérateurs/opérations comme "set difference/except", "union", "intersection", "complement", etc. Si vous pouvez le faire, c'est facile; Sinon, vous devrez vous asseoir, construire un DFA acceptant les chaînes que vous voulez rejeter, construire le complément DFA, puis créer une regex basée sur ceci. Certains outils automatisés peuvent exister pour rendre ce processus moins douloureux. – Patrick87