2010-04-19 9 views
8

sto usando GNU Bison 2.4.2 per scrivere una grammatica per una nuova lingua su cui sto lavorando e ho una domanda. Quando ho specificare una regola, diciamo:Bison: token facoltativi in ​​una singola regola

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

Se ho una variazione sulla regola, per esempio

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

Dove (dalle regole scanner Flex):

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

(e T_IDENT_LIST è una regola per identificatori separati da virgole).

C'è un modo per specificare tutto questo solo in una regola, impostando in qualche modo "T_EXTENDS T_IDENT_LIST" come facoltativo? Ho già provato con

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

Ma Bisonte mi ha dato un errore.

Grazie

risposta

9

Per farla breve, no. Bison tratta solo grammatiche LALR (1), il che significa che usa solo un simbolo di lookahead. Quello che vi serve è qualcosa di simile:

statement: T_CLASS T_IDENT extension_list '{' ... 

extension_list: 
       | T_EXTENDS T_IDENT_LIST 
       ; 

Non ci sono altri generatori di parser che lavorano con le grammatiche più generali però. Se la memoria è utile, alcuni di essi supportano gli elementi opzionali in modo relativamente diretto come richiesto.

+0

Questa era la soluzione per scrivere una sola regola senza il | :) Grazie! –

+0

Non ha nulla a che fare con LALR (1), poiché entrambi sono LALR (1). È perché la sintassi di input è BNF e non EBNF. –

+1

@ChrisDodd: Siamo spiacenti, ma sbagliato. Il problema qui è che mentre lo scriveva, il suo parser avrebbe dovuto guardare avanti tre simboli, attraverso T_CLASS e T_IDENT per vedere se il prossimo simbolo era un '{' o T_EXTENDS per vedere quale variazione 'statement' usare. Questo sta violando LALR (1). EBNF mi sembra un'arma rossa completa - non vedo nulla che assomigli a EBNF ovunque nella domanda. –

0

penso che il massimo che può fare è

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

Perché non basta dividere con la scelta (|) operatore?

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

non credo che si può fare solo perché si tratta di un LALR (1) parser bottom-up, si avrebbe bisogno di qualcosa di diverso come un LL (k) (ANTLR?) Per fare quello che vuoi per fare ..