"Правило бесполезно в парсере" с двумя операторами подряд
Я хочу написать грамматику с оператором, подобным оператору двоеточия Matlab, где "a:b" и "a:b:c" означают несколько разные вещи. И я бы предпочел, чтобы оператор был неассоциативным, так как "a:b:c:d" и т. д. не имело бы смысла.
Вот урезанная версия моей грамматики, чтобы показать, как я пытался это сделать:
%union {
int ival;
}
%token tINT
%nonassoc ':'
%%
program: { }
| expression ';' { }
expression: tINT { }
| expression ':' expression { }
| expression ':' expression ':' expression { }
По какой-то причине Бизон игнорирует второе правило двоеточия, сообщая следующее:
test.y:16.13-56: warning: rule useless in parser due to conflicts [-Wother]
| expression ':' expression ':' expression { }
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Почему Бизон не понимает, чего я хочу здесь, и как я могу измениться? моя грамматика так работает?
Edit: в случае, если это поможет, выход из "bison-v" содержит
State 7
4 expression: expression . ':' expression
4 | expression ':' expression .
5 | expression . ':' expression ':' expression
5 | expression ':' expression . ':' expression
':' error (nonassociative)
$default reduce using rule 4 (expression)
Хотя я все еще не понимаю, почему Бизон не должен этого допустить, и как это решить.3 ответа:
Вы указали, что оператор': 'неассоциативен. Удалите это, и вместо этого вы получите ожидаемые конфликты из A: B:C, которые можно разобрать как один из A:B:C, (A:B): C и A: (B: C).
Но поскольку вы хотите, чтобы он был неассоциативным, вот один из способов:%token tINT %% program: { } | colonexpression ';' { } ; colonexpression: expression { } | expression ':' expression ':' expression { } | expression ':' expression { } ; expression: tINT { } ; %%
Ах! После долгих мучений я наконец нашел способ, который работает и все еще позволяет мне использовать приоритет "правильным" способом, хотя он требует, чтобы я назначил приоритет всем терминалам, которые могут появиться в выражении, если я хочу избежать тонн предупреждений shift/reduce. Кроме того, ему нужен фиктивный маркер, чтобы придать правилу с одним двоеточием соответствующий приоритет (немного ниже, чем':', чтобы избежать понятного конфликта shift-reduce).
Я не совсем доволен тем, что должен назначьте приоритет терминалам типа tINT, поскольку в моей реальной грамматике есть куча таких вещей, но я полагаю, что это придется сделать, если никто не имеет лучшей идеи.
%union { int ival; } %token tINT %precedence nCOLON %nonassoc ':' %precedence tINT %% expression: tINT { } | expression_colon expression %prec nCOLON { } | expression_colon expression ':' expression { } expression_colon: expression ':'
Не могли бы вы просто сделать его левоассоциативным с соответствующим приоритетом, а затем, как часть вашего кода действия, выдать ошибку, если там больше 2 двоеточий? То есть, не пытайтесь обрабатывать это в грамматике, но сделайте это семантическим ограничением, применяемым в коде C.
Я думаю о чем-то вроде этого-это чистый псевдокод, заметьте, потому что я понятия не имею, какое дерево синтаксического анализа вы строите, но давайте предположим, что вы строите абстрактное синтаксическое дерево. --
expression : expression ':' expression { if (Head($1) == DoubleColon) yyerror("Three-colon expressions are not allowed."); else if (Head($1) == Colon) $$ = DoubleColon(element_of($1, 1), element_of($1, 2), $3); else $$ = Colon($1, $3); }
В зависимости от того, как вы обрабатываете скобки, это может быть немного сложнее. (То есть, если вы кодируете их явно в дереве синтаксического анализа, вы можете использовать описанную выше технику, но в противном случае вам понадобится способ отличить
Это интересная проблема. Я столкнулся с этим в синтаксическом анализаторе, который я писал, и я никогда не мог прийти к общему решению. В моем случае два двоеточия имели разные контексты и разные прецеденты. Это похоже на что-то автомат сокращения сдвига должен быть в состоянии это сделать, но не ясно, как сказать зубру, чтобы он сгенерировал нужные вам таблицы переходов. В конце концов, я должен был решить ее с помощью взлома лексера, который вызывает обратно в синтаксический анализатор, чтобы сделать "имитированный синтаксический анализ", метод, который Bison 3.0 использует в своей функции LAC.(a:b):c
отa:b:c
.)