Ваша проблема проистекает из того факта, что '(' может быть началом либо первой альтернативы для c2
, либо последней альтернативы для atom
. Просто, например, с учетом ввода типа ((x+y) > (a+b))
, первого открытияparen - это начало c2
, а второе - начало atom
. [edit: И синтаксический анализатор не имеет указания, по какому пути идти дальше, до какой-то произвольной точки позже - например, он не можетЗнайте, что первое открытое имя - это начало c2
, пока оно не встретит >
. Например, если бы вместо этого было *
, то оба открывающих скобки были бы началами atom
с.]
Один из возможных способов справиться с этим - объединить правила для арифметических и логических выражений, поэтому у вас есть только одно правило с '(' expression ')
, а expression
может быть арифметическим или логическим. Это часто, однако,побочным эффектом является довольно свободная типизация с относительно свободным преобразованием между арифметическими и булевыми выражениями (по крайней мере, на уровне парсера - вы можете затем использовать enforce типы жестко, как вам нравится в семантике).
Редактировать: Например, в Pascal правила запускаются примерно так (упрощенно):
expression: simple_expression ( rel_op simple_expression )*
simple_expression: ( '+' | '-')? term ( ('+' | '-' | 'or' ) term )*
term: factor ( ( '/' | '*' | 'div' | 'mod' | 'and') factor )*
factor: constant | variable | function_call | '(' expression ')' | 'not' factor