Пример здесь работает, но когда я собрал его вместе с решением для Bison: GLR-синтаксический анализ допустимого выражения завершается неудачно без сообщения об ошибке Я столкнулся со следующей проблемой:
переменная может быть определена более чем одним идентификатором.Вы можете иметь индекс массива или он может быть членом другого объекта.Я смоделировал эту ситуацию, имея другой нетерминал, такой как
lvalue
: TOK_IDENTIFIER
| lvalue '[' arithmeticexpression ']'
| lvalue '.' TOK_IDENTIFIER
Но когда у меня теперь есть
arithmeticexpression : lvalue
stringexpression : lvalue
и (попробуйте) получить доступ к объекту из нетерминального "lvalue"как и выше, я получаю ошибку сегментации.Таким образом, кажется, что метод здесь не работает для более сложных ситуаций.
Теперь я сделал то, что я получил доступ к объекту в семантическом действии и установил $$
в nullptr
, еслипеременная имеет неправильный тип.
arithmeticexpression
: lvalue
{
$$ = nullptr;
if(dynamic_cast<IntVariable*>($lvalue->getVariable()))
$$ = new ArithmeticExpressionIntVariable($lvalue);
}
Тогда мне нужно было распространить nullptr
(это довольно много дополнительного кода), как это
arithmeticexpression
...
| arithmeticexpression[left] '+' arithmeticexpressionM[right]
{
$$ = nullptr;
if($left && $right)
$$ = new ArithmeticExpressionPlus($left, $right);
}
Так что теперь, в
expression
: arithmeticexpression
| stringexpression
(note: I have "Expression* expr;" in the "%union{" declaration
and "%type <expression> expr" in the prologue)
У меня есть неоднозначность: один и тот же входной текст может быть проанализирован двумя разными способами, но только один из них будет иметь значение != nullptr
.На данный момент мне нужна пользовательская процедура слияния, которая в основном просто выбирает ненулевое значение.
Для этого я объявил об этом в прологе моего файла зубров, как это
static Expression* exprMerge (yy::semantic_type x0, yy::semantic_type x1);
и определил его в эпилоге следующим образом
static Expression* exprMerge (YYSTYPE x0, YYSTYPE x1) \
{
/* otherwise we'd have a legitimate ambiguity */
assert(!x0.expr || !x1.expr);
return x0.expr ? x0.expr : x1.expr;
}
наконец, мне пришлось сказать bison, чтобы использовать эту процедуру для устранения неоднозначности, используя
expression
: arithmeticexpression %merge <exprMerge>
| stringexpression %merge <exprMerge>
Честно говоря, я думаю, что этоэто довольно много усилий, которые не были бы необходимы, если бы семантические предикаты проверялись бизоном (по крайней мере те, которые стоят за правилом), когда он пытается объединить пути, а не исключать пути до того, как они объединятся.
Но, по крайней мере, это работает и требует гораздо меньше усилий, чем сбор токенов и их сортировка вручную, что было бы альтернативой.