Проблемы с лимонной грамматикой (приоритет?)

У меня проблемы с простой грамматикой, которую я создал для поддержки вызовов функций.
Я использую основанный на лимоне PHP_ParserGenerator от Грега.

Это соответствующая часть грамматики:

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

Когда я инициализирую парсер с контекстом array('user' => array('name' => 'Dennis')); и выполните следующий код:

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

$result выглядит следующим образом: "Деннис". Жизнь хороша.

Но когда я предоставляю CONTEXT_REFERENCE в качестве аргумента для вызова функции, он не работает:

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

$result это "us3r.nam3". Не совсем так, как ожидалось. Для записи, ожидаемый результат, конечно, "D3nnis". (user.name сначала заменяется строкой 'Dennis', а затем передается str_replace() функция).

Я подозреваю, что это как-то связано с приоритетом. Но я не могу понять, что я должен изменить, чтобы сделать это. Очень редкая документация по Lemon не очень помогает.

Любая помощь будет принята с благодарностью! Спасибо

1 ответ

Решение

Кажется, я нашел ответ на свой вопрос.

Когда я изменяю свою грамматику на:

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

Кажется, работает как ожидалось.
Проблема была в том, что я создал двусмысленность в первой грамматике:

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

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

Я оставлю вопрос и отвечу здесь, чтобы другие могли извлечь выгоду из моих ошибок:) Если кому-то есть, чем поделиться, пожалуйста, сделайте.

Другие вопросы по тегам