устранение неоднозначности грамматики bison / yacc

#parsing #compiler-construction #yacc #bison #lalr

#синтаксический анализ #компилятор-конструирование #yacc #bison #lalr

Вопрос:

У меня есть следующая грамматика bison (как часть более сложной грамматики):

 expression:
    IDENTIFIER
    | CONST
    | LAMBDA match_block
;
match_block:
    pattern '=' expression
    | match_block '|' pattern '=' expression
;
pattern:
    IDENTIFIER
    | CONST
;
  

которые описывают выражения, содержащие идентификаторы, константы и лямбда-функции с сопоставлением с шаблоном, который выглядит следующим образом:

lambda 0 = 1
     | 1 = 2
     | x = x

Проблема заключается в конфликте сдвига / уменьшения на 1, вызванном неоднозначностью вложенных совпадений, как в следующем примере:

lambda 0 = 1
     | x = lambda 1 = 2
                | y = 4

Правило заключается в том, что блок совпадений относится к ближайшей функции, как показано с отступом в примере выше.

Мои вопросы - как я могу переписать эту грамматику, чтобы устранить эту двусмысленность (без использования директив %left % right yacc)?

Ответ №1:

Если вы всегда хотите, чтобы | привязывалось к ближайшему LAMBDA , это в основном просто означает, что вы можете иметь только LAMBDA в ПОСЛЕДНЕМ | предложении match_block :

 non_lambda_expression:
    IDENTIFIER
    | CONST
;
expression:
    non_lambda_expression
    | LAMBDA match_block
;
non_lambda_match_block:
    pattern '=' non_lambda_expression
    | non_lambda_match_block '|' pattern '=' non_lambda_expression
;
match_block:
    pattern '=' expression
    | non_lambda_match_block '|' pattern '=' expression
;
pattern:
    IDENTIFIER
    | CONST
;
  

По сути, вы разделяете expression и match_block на две версии - ту, которая допускает лямбды, и ту, которая этого не делает, - и используете соответствующую в каждом месте, чтобы избежать двусмысленности.

Комментарии:

1. Большое спасибо! Я видел один пример устранения неоднозначности ранее в dragon book (для "dangling else"), но я не смог сделать это с помощью этой грамматики.

2. @SJ: по сути, это точно такой же шаблон, как и в случае с висячим else - приведенное выше преобразование совпадает с тем, что описано в книге Dragon, с той лишь разницей, что перед окончательным lambda может быть несколько не-lambda match_blocks