Я хотел создать ридер, который читает файлы конфигурации, аналогичные INI-файлам для mswin. Это упражнение, чтобы научить себя, используя генератор лексера / парсера, который я сделал. Грамматика:
%lexer
HEADER ::= "\\[[0-9a-zA-Z]+\\]"
TRUE ::= "yes|true"
FALSE ::= "no|false"
ASSIGN ::= "="
OPTION_NAME ::= "[a-zA-Z][0-9a-zA-Z]*"
INT ::= "[0-9]+"
STRING ::= "\"(\\\"|[^\"])*\""
CODE ::= "<{(.*)}>"
BLANK ::= "[ \t\f]+" :ignore
COMMENT ::= "#[^\n\r]*(\r|\n)?" :ignore
NEWLINE ::= "\r|\n"
%parser
Options ::= OptionGroup Options | OptionGroup | @epsilon@
OptionGroup ::= HEADER NEWLINE OptionsList
OptionsList ::= Option NEWLINE OptionsList | Option
Option ::= OPTION_NAME ASSIGN OptionValue
OptionValue ::= TRUE | FALSE | INT | STRING | CODE
Проблема заключается в @epsilon@
продукции. Я добавил его, потому что хочу, чтобы мой читатель также принимал пустые файлы. Но у меня возникают конфликты, когда «OptionsList» или «OptionGroup» содержат продукцию epsilon. Я пытался переставить элементы в продуктах, но у меня возникают только конфликты (r / r или s / r, в зависимости от того, что я сделал), если я не удаляю эпсилон полностью из моей грамматики. Это устраняет проблему, но ... в моих логиках c один из 'OptionsList' или 'OptionGroup' должен содержать эпсилон, иначе моя цель принять пустые файлы не будет достигнута.
Мой генератор синтаксических анализаторов использует метод LR (1), поэтому я подумал, что могу использовать в своей грамматике произведения epsilon. Кажется, я хорош в написании генераторов, но не в построении безошибочных грамматик :(.
Должен ли я забыть о эпсилонах? Или моя грамматика принимает пустые входные данные, даже если нет производства эпсилонов?