A: B C($) ;
Для частичной совсместимости с yacc вы можете оставлять пробелы между : и первым символом, но при уловии что в конце каждого правила стоит ;. Кроме того программа игнорирует %% и все незнакомые конструкции.
E: E + E {$$=$1+$1}
E: E(A) + E(B) {$$=$A+$B}
E: - E {$$=-$E}
Если действие начинается со знаков $$=, то можно обойтись опустить два символа и начать выражение просто со знака равенства:
E: - E {=-$E}
кроме того если действия записаны в подобном виде, то оптимизатор, преобразуя грамматику может подставлять одни действия в другие.
stmt: if e stmt(a) {$$=$a}
| if e stmt(a) else stmt(b) {$$=$a+$b}
-
можно указать несколько расслоений в разных местах одной строки. Они все сработают по очереди, дополняя друг друга.
A: B [ C ]?
A: B [ C ]+
но система в эти вопросы не вмешавается. Так что конструкции надо применять в умом.
stmt: if expr stmt %<
| if expt stmt else stmt
Здесь %< указывает что даную граматику надо сворачивать сразу, не создавая кофликта переноса и свёртки. Что в данном случае
приведёт к свертке первой строки до того как будет прочитано else. И вобщем-то конешно приведёт к ошибке, если этот else всё таки есть.
stmt: if expr stmt %>
| if expt stmt else stmt
Здесь %> указывает что даную граматику надо переносить, не создавая кофликта переноса и свёртки.
Что вобщем-то всё равно произойдёт в случае конликта переноса/свертки. Но так будет коректнее.
expr: num
| - expr %<
| expr - expr
| expr * expr
в данном случае можно не указывать ядру что - это унарный оператор. Если не указать ни команду, ни унарность оператора, то граматика
откомпилируется без конфликтов, но работать станет не совсем как надо. В выражении - num * num она попытается выполнить умножение раньше минуса,
поскольку у него наверняка задан наибольший приоритет.
expr: num
| expr + expr
| ( expr($) )
в данном случае $ указывает, что строка просто возвращает значение данного элемента (в данном случае он второй по счёту).
Т.е. просто создаётся действие, которое делает нужное присваивание (в будушем это будет на уровне автомата).
%def_type <int:value> - токены по умолчанию имеют тип int (хотя и так имеют). value - название поля в структуре (указывать не обязательно).
%type <Var*:var> var_name var_list var_dec_list
Допустимы переводы строки между словами. Так же возможна сокращённая запись:
%~ name var_name {free($$)}
%usewords ; [ ] - позволяет использовать указанные символы или строки, как строки, не экранируя кавычками
%pair ( ) [ ] { }
%define ==:eq <=:le