2012-04-10 26 views
5

Ho problemi con una semplice grammatica che ho creato per supportare le chiamate di funzione.
Sto usando il PHP_ParserGenerator basato sul limone di Greg.Problemi con grammatica di limone (precedenza?)

Questa è la parte rilevante della grammatica:

program ::= expr(A).      { $this->result = A; } 

value(A) ::= SIMPLE_STRING(B).    { A = B; } 
value(A) ::= NUMBER(B).      { A = B; } 
value(A) ::= CONTEXT_REFERENCE(B).   { A = B; } 

arg_list ::= arg_list SEPARATOR value(B). { $this->args[] = B; } 
arg_list ::= value(B).      { $this->args[] = B; } 
arg_list ::= . 

expr(A) ::= SIMPLE_STRING(B) PAREN_LEFT arg_list PAREN_RIGHT. { A = call_user_func_array(B, $this->args); } 

expr(A) ::= CONTEXT_REFERENCE(B). { 
    list($context, $key) = explode('.', B); 
    A = $this->context[$context][$key]; 
} 

Quando ho inizializzare il parser con un contesto di array('user' => array('name' => 'Dennis')); ed eseguire il seguente codice:

$parser->doParse(PelParser::CONTEXT_REFERENCE, 'user.name'); 
$parser->doParse(0, 0); 

Il $result è la seguente: ' Dennis'. La vita è bella.

Ma quando fornisco un CONTEXT_REFERENCE come argomento di una chiamata di funzione, non funziona:

$parser->doParse(PelParser::SIMPLE_STRING, 'str_replace'); 
$parser->doParse(PelParser::PAREN_LEFT, '('); 
$parser->doParse(PelParser::SIMPLE_STRING, 'e'); 
$parser->doParse(PelParser::SEPARATOR, ','); 
$parser->doParse(PelParser::NUMBER, 3); 
$parser->doParse(PelParser::SEPARATOR, ','); 
$parser->doParse(PelParser::CONTEXT_REFERENCE, 'user.name'); 
$parser->doParse(PelParser::PAREN_RIGHT, ')'); 
$parser->doParse(0, 0); 

Il $result è 'us3r.nam3'. Non del tutto come previsto. Per la cronaca, l'uscita prevista è ovviamente "D3nnis". (user.name prima viene sostituito con la stringa "Dennis" e successivamente passata alla funzione str_replace()).

Sospetto che abbia qualcosa a che fare con la precedenza. Ma non riesco a capire cosa dovrei cambiare per farlo. La scarsa documentazione di Lemon non è di grande aiuto.

Qualsiasi aiuto sarebbe molto apprezzato! Grazie

risposta

1

Mi sembra di aver trovato la risposta alla mia domanda.

Quando cambio la mia grammatica a:

program ::= expr(A).      { $this->result = A; } 

value(A) ::= SIMPLE_STRING(B).    { A = B; } 
value(A) ::= NUMBER(B).      { A = B; } 
value(A) ::= CONTEXT_REFERENCE(B). { 
    // B=='{context}.{name}' 
    list($context, $key) = explode('.', B); 
    A = $this->context[$context][$key]; 
} 

arg_list ::= arg_list SEPARATOR value(B). { $this->args[] = B; } 
arg_list ::= value(B).      { $this->args[] = B; } 
arg_list ::= . 

expr(A) ::= SIMPLE_STRING(B) PAREN_LEFT arg_list PAREN_RIGHT. { A = call_user_func_array(B, $this->args); } 

sembra funzionare come previsto.
Il problema era che ho creato un'ambiguità nella prima grammatica:

value(A) ::= CONTEXT_REFERENCE(B).   { A = B; } 

expr(A) ::= CONTEXT_REFERENCE(B). { 
    list($context, $key) = explode('.', B); 
    A = $this->context[$context][$key]; 
} 

Lascio la domanda e risposta qui in modo che altri potrebbero trarre beneficio dai miei errori :) Se qualcuno ha qualcosa da condividere, si prega di fare .