2013-12-21 7 views
0

Вот упрощение моей рабочей EBNF грамматики:Как решить эту проблему S/R конфликт

%token NEWLINE BLOCK_MARK A 
%start file 

file: block+ NEWLINE*; 
block: BLOCK_MARK line; 
line: A+; 

И \ п и EOF выплюнуть NEWLINE как знак (так что один окончание NEWLINE не требуется до EOF). Он работает с потоком, как это:

BLOCK_MARK A A BLOCK_MARK A NEWLINE[actually EOF] 

Теперь я хочу иметь несколько line в block, по крайней мере, один является обязательным, а остальным разделено NEWLINE. Например .:

BLOCK_MARK A A NEWLINE A A BLOCK_MARK A A A EOF 

Я попытался сделать это:

file: block+ NEWLINE*; 
block: BLOCK_MARK line moreline*; 
line: A+; 
moreline: NEWLINE line; 

Но Jison жалуется на S/R конфликт, когда опережения является NEWLINE. Я предполагаю, что машина состояний запуталась, решив, является ли NEWLINE частью нового блока line или окончательного NEWLINE* в file (что необходимо, потому что файл может закончиться с NEWLINE/EOF).

Как это исправить?

+0

Одним из механизмов может быть прекращение обработки новых строк как EOF; они совсем не то же самое. Я более чем озадачен тем, как это работает. –

+0

@JonathanLeffler это наоборот, я рассматриваю EOF как NEWLINE. Я думаю, что я не единственный, кто делает это, чтобы сделать окончание NEWLINE не обязательным (так как EOF анализируется как NEWLINE). Изменение 'file' на' file: block + NEWLINE * EOF' не устраняет проблему и делает ее еще хуже, требуя как 'NEWLINE' (для' line'), так и 'EOF' (для' file') в качестве последних проанализированных токенов. – kaoD

ответ

1

Что нужно сделать, чтобы сделать новую строку ЧАСТЬ предыдущей строки, отложив сокращение всего, кроме строки, до тех пор, пока вы не увидите новую строку. Таким образом, вы в конечном итоге с:

file: block+ ; 
block: BLOCK_MARK line_nl+ line_nonl? | BLOCK_MARK line_nonl ; 
line_nl: line NEWLINE ; 
line_nonl: line ; 
line: A+ ; 

Теперь единственная проблема с вышеизложенным является то, что она не допускает никаких пустых строк (пустая строка будет синтаксической ошибкой). Но это то же самое, что и ваша оригинальная грамматика.

+0

Я думаю, что имеет смысл, спасибо! Я получил пустую строку в сканере (\ n + spits NEWLINE). – kaoD

+0

Woops, не решил всю проблему, так как это теперь не подходит для первоначального варианта использования (я думаю, что я наткнулся на это уже). 'BLOCK_MARK A BLOCK_MARK A EOF' терпит неудачу, но' NEWLINE' должен быть необходим только в том случае, если есть хотя бы две строки! Сравните с 'BLOCK_MARK NEWLINE A BLOCK_MARK A EOF', который отлично работает (потому что в' строке' есть хотя бы 'NEWLINE' или EOF). – kaoD

+1

Добавление дополнительного правила: 'block: BLOCK_MARK line_nonl;' должно исправить это. –

0

Основываясь на идее Криса Додда, но наоборот, как это было в моей попытке frist. Основная идея состояла только в том, чтобы удалить NEWLINE* по адресу file, который был уже покрыт в line.

file: block+; 
block: BLOCK_MARK line_nonl line_nl* NEWLINE?; 
line_nl: NEWLINE line_nonl; 
line_nonl: A+; 

Я думаю, что этот решает все случаи.