2012-04-10 12 views
5

Tengo problemas con una gramática simple que he creado para admitir llamadas a funciones.
Estoy usando el PHP_ParserGenerator basado en limón de Greg.Problemas con la gramática de limón (¿prioridad?)

Esta es la parte relevante de la gramática:

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]; 
} 

Cuando inicializar el analizador con un contexto de array('user' => array('name' => 'Dennis')); y ejecute el siguiente código:

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

El $result es el siguiente: ' Dennis '. La vida es buena.

Pero cuando suministrar una CONTEXT_REFERENCE como argumento de una llamada de función, que no funciona:

$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); 

El $result es 'us3r.nam3'. No del todo como se esperaba Para el registro, el resultado esperado es, por supuesto, 'D3nnis'. (user.name primero se reemplaza con la cadena 'Dennis' y luego pasa a la función str_replace()).

Sospecho que tiene algo que ver con la precedencia. Pero no puedo imaginarme qué debería cambiar para hacer esto. La muy escasa documentación de Lemon no es de gran ayuda.

¡Cualquier ayuda sería muy apreciada! Gracias

Respuesta

1

Parece que he encontrado la respuesta a mi pregunta.

Cuando cambio mi gramática 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); } 

parece que funciona como se esperaba.
El problema era que yo creé una ambigüedad en la primera gramática:

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

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

Voy a dejar la pregunta y respuesta aquí para que otros puedan beneficiarse de mis errores :) Si alguien tiene algo que compartir, por favor haga .