Непосредственная проблема заключается в том, что вы return
от FILEID
продукции. return
возвращает, поэтому синтаксический разбор завершается возвращенным значением. Обычно семантические правила должны обеспечивать их результат, присваивая переменной $$
. (Это не обязательно для «правил единицы», где справа есть только один символ: перед выполнением действия парсер делает $$ = $1
, поэтому, если это то, что вы хотите, вы можете просто оставить действие, как вы это делаете в ваших двух FILEID
правил.)
Кроме того, ваш expressions
производство ничего не делать с $2
, так что даже если вы исправили первую проблему, вы бы еще видеть только один e
в результате.
Неверный товар expressions
, так как для каждого требуется дополнительный токен EOF
, в дополнение к EOF от базового футляра.Рассмотрим, как работают производства:
expressions -> e expressions EOF
-> e e expressions EOF EOF
-> e e e expressions EOF EOF EOF
-> e e e EOF EOF EOF EOF
Лично я предложил бы использовать левую рекурсию вместо правой рекурсию. Партизаны снизу вверх, такие как jison, предпочитают левую рекурсию, и это обычно приводит к более естественным семантическим правилам, как в этом случае.
Наконец, вам нужно вернуть окончательное значение, когда вы действительно достигнете конца ввода. В jison обычно требуется явное правило запуска, семантическое действие которого равно return
.
Итак, при всем этом помните, что давайте попробуем это: (Я изменил имена некоторых не-терминалов и опустил FILEID
, потому что традиционно использовать нижний регистр для нетерминалов и верхних частот, чехол для терминалов)
%start prog
%%
prog : exprs EOF { return $1; }
;
exprs : { $$ = []; }
| exprs expr { $$.push($2); }
;
expr : file_id
| STRING
;
file_id: FILEVERSION NUMBER { $$ = $1 + $2; }
;
Одно замечание о вашем регулярном выражении для соответствующих строк:
\"(\\.|[^"])*\" return 'STRING'
Хотя это, очевидно, работает в JavaScript (в основном, смотри ниже), я t будет отображаться ошибка в flex (или совместимая с Posix библиотека регулярных выражений). Он в основном работает в javascript, потому что jouncript регулярного выражения чередует оператор |
приказал; если первая альтернатива совпадает, вторая альтернатива никогда не используется, если остальная часть шаблона не соответствует (и в этом случае ошибка будет вызвана).
Но в (f) lex оператор чередования замечает все подходящие альтернативы и в конечном итоге выбирает максимально возможное совпадение. Результатом является то, что при совпадении "\\"..."
, флекс будет соответствовать маркер до тех пор, третьей цитаты, используя [^"]
в соответствии с первым \, а затем \\.
, чтобы соответствовать \". Это позволяет ему продолжать искать для закрытие цитаты.
это легко написать регулярное выражение, так что он будет работать с любым семантическим, и я настоятельно рекомендую делать это в случае, если вы когда-либо хотите перейти на другой генератор синтаксических анализаторов, просто гарантируя, что \ не соответствует [^"]
:
\"(\\.|[^\\"])*\" return 'STRING'
Это изменение также исправить тонкую ошибку, даже в JavaScript, что "\"
считается действительной строкой маркера, если это последняя строка в поле ввода. В этом случае, JavaScript будет первым использовать \\.
, чтобы соответствовать \", но как только он делает, что он не найдет никакого закрывающую кавычку. Он будет возвращаться назад и попытаться соответствие с [^"]
, который будет соответствовать \, что позволяет цитата, чтобы затем была признана закрывающей цитатой.
Вау, большое вам спасибо за этот ясный и всеобъемлющий ответ! – tomvodi