2010-04-19 4 views
8

J'utilise GNU Bison 2.4.2 pour écrire une grammaire pour une nouvelle langue sur laquelle je travaille et j'ai une question. Quand je précise une règle, disons:Bison: jetons optionnels dans une seule règle

statement : T_CLASS T_IDENT '{' T_CLASS_MEMBERS '}' { 
      // create a node for the statement ... 
} 

Si j'ai une variante de la règle, par exemple

statement : T_CLASS T_IDENT T_EXTENDS T_IDENT_LIST '{' T_CLASS_MEMBERS '}' { 
      // create a node for the statement ... 
} 

Où (des règles du scanner flex):

"class"      return T_CLASS; 
"extends"     return T_EXTENDS; 
[a-zA-Z\_][a-zA-Z0-9\_]* return T_IDENT; 

(et T_IDENT_LIST est une règle pour les identifiants séparés par des virgules).

Existe-t-il un moyen de spécifier tout cela en une seule règle, en définissant en quelque sorte le "T_EXTENDS T_IDENT_LIST" comme facultatif? Je l'ai déjà essayé avec

T_CLASS T_IDENT (T_EXTENDS T_IDENT_LIST)? '{' T_CLASS_MEMBERS '}' { 
    // create a node for the statement ... 
} 

Mais Bison m'a donné une erreur.

Merci

Répondre

9

Pour faire une longue histoire courte, non. Bison ne traite que les grammaires LALR (1), ce qui signifie qu'il n'utilise qu'un seul symbole de lookahead. Qu'est-ce que vous avez besoin est quelque chose comme ceci:

statement: T_CLASS T_IDENT extension_list '{' ... 

extension_list: 
       | T_EXTENDS T_IDENT_LIST 
       ; 

Il existe d'autres générateurs d'analyseur qui fonctionnent avec des régles plus générales bien. Si ma mémoire est bonne, certains d'entre eux supportent des éléments optionnels relativement directement comme vous le demandez.

+0

C'était la solution pour écrire une seule règle sans le | :) Merci! –

+0

Cela n'a rien à voir avec LALR (1), puisque les deux sont LALR (1). C'est parce que la syntaxe d'entrée est BNF et non EBNF. –

+1

@ChrisDodd: Désolé, mais faux. Le problème ici est que, comme il l'a écrit, son analyseur devrait regarder devant trois symboles, à travers T_CLASS et T_IDENT pour voir si le symbole suivant était une variante '{' ou T_EXTENDS pour voir quelle 'déclaration' utiliser. C'est violer LALR (1). L'EBNF me semble être un véritable casse-tête - je ne vois rien qui ressemble à EBNF dans la question. –

0

Je pense que le plus que vous pouvez faire est

statement : T_CLASS T_IDENT '{' T_CLASS_MEMBERS '}' 
    | T_CLASS T_IDENT T_EXTENDS T_IDENT_LIST '{' T_CLASS_MEMBERS '}' { 
} 
0

Pourquoi ne pas simplement les séparer en utilisant l'opérateur choix (|)?

statement: 
    T_CLASS T_IDENT T_EXTENDS T_IDENT_LIST '{' T_CLASS_MEMBERS '}' 
    | T_CLASS T_IDENT '{' T_CLASS_MEMBERS '}' 

Je ne pense pas que vous pouvez le faire juste parce que c'est un LALR (1) analyseur bottom-up, vous auriez besoin de quelque chose de différent, comme un LL (k) (ANTLR?) Pour faire ce que vous voulez faire ..

Questions connexes