Я пытаюсь ввести новую языковую конструкцию в большую / сложную грамматику. Я знаю, что это сделает синтаксис неоднозначным, но я надеюсь разрешить это с помощью правила «максимальное жаворонок». То есть сначала поставьте мою конструкцию, чтобы она воспринималась по предпочтению. У меня есть некоторый успех, но других частей дерева не так много. Подумайте:
( 1, 2, 3 ) // triple
( 4, 5 ) // twople
( 6 ) // *not* a oneple, see below
() // zerople
(7 + 8) * 9 // single parens used to override usual precedence
( (( 7 + 8 )) * 9 ) // currently this means the same, but nobody would write that!
(( 6 )) // I want to be a oneple
( ( 6 ) ) // this also a oneple
( ( ( 6 ) ) ) // this also a oneple with a superfluous pair of parens, ambiguous
(( ( 6 ) )) // superflous parens are innermost
( (( 6 )) ) // superfluous parens are outermost
((7 + 8) * (9 + 10)) // not a oneple, despite the (( ... ))
Эти три примера с 6
в трех парах паренсов неоднозначны, меня не волнует, какая из них занимает грамматика, они семантически одинаковы. По правилу «максимального жаворонка» он должен принимать середину трех, то есть оставлять самые внутренние паренны за лишние.
Лексер принимает каждый (
, )
в качестве отдельного токена. В настоящее время синтаксический анализатор принимает (
(
(
6 )
)
)
как эквивалент 6
(где он анализируется как expr
/ int
) - то есть то, что сделала грамматика прежде чем я попытался изменить его.
Грамматика имеет много уровней токенов, определенных другими токенами. Некоторые выражения в некоторых контекстах распознают двойные скобки ОК. Других не так много (и это трудно свести к примеру разумного размера). Существуют ли какие-либо общие приемы, позволяющие уговорить бизонов на максимальный вкус?
Addit: Эта неоднозначность аналогична известной неоднозначности на самом первом языке использования BNF: ALGOL 60
if cond1 then
if cond2 then blah2
else blah3; // is this on cond2 False or cond1 False?
Это было решено, сказав, что else
присоединяется к самому внутреннему if/then
, который еще не получил else
, то есть к cond2
False в этом случае; оставляя cond1
без else
ветви. (У Алгола не было «правила офсайда», слава богу!)
Addit2: ОК, по многочисленным просьбам код ya cc до того, как я начал вносить поправки, равен здесь (Теперь вы собираетесь wi sh, который вы никогда не спрашивали.) Это, например, работает в правиле aexp
(средняя строка - мой мод)
| '(' exp ')' {$$ = gc3($2);}
| '(' '(' exp ')' ')' {$$ = gc5(buildTuple(cons($3,NIL)));} /* ADC Apr-2020 */
| '(' exps2 ')' {$$ = gc3(buildTuple($2));}
Эта строка не работает - в правиле apat
pat
продолжает анализироваться как обычный шаблон с несколькими скобками.
apat : NUMLIT {$$ = $1;}
| var {$$ = $1;}
| '(' '(' pat ')' ')' {$$ = gc5(buildTuple(singleton($3)));} /* ADC Apr-2020 */
| apat_vI {$$ = $1;}
;
Я попытался вставить эту строку во все виды мест вверх и вниз по дереву из pat
; Я даже пытался поставить его в нескольких постановках одновременно, что выглядит довольно хитро. Парсер, похоже, постоянно игнорирует это.
Спасибо за ответ @Chris Dodd. Я думал, что, несмотря на это, приводя к ошибкам сдвига / уменьшения, я читал в других SO-ответах, что бизон «делает правильные вещи» - то есть, если вы поставите одно произведение выше другого, оно предпочтет это сначала.