Я хотел сделать ридер, который читает файлы конфигурации, похожие на файлы 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» содержат эпсилон-продукцию. Я пробовал переставлять элементы в постановках, но у меня возникают только конфликты (r/r или s/r, в зависимости от того, что я сделал), если я полностью не уберу эпсилон из своей грамматики. Это устраняет проблему, но... в моей логике один из 'OptionsList' или 'OptionGroup' должен содержать эпсилон, иначе моя цель по принятию пустых файлов не будет достигнута.
Мой генератор синтаксического анализатора использует метод LR(1), поэтому я подумал, что могу использовать эпсилон-продукцию в своей грамматике. Кажется, я хорош в написании генераторов, но не в построении безошибочных грамматик :(.
Должен ли я забыть об эпсилонах? Или моя грамматика принимает пустые входные данные, даже если нет производства эпсилон?