Ваше правило lex ("[0-9A-Za-z_]+")
будет соответствовать (только) буквальной строке [0-9A-Za-z_]+
- избавьтесь от символов "
, чтобы иметь шаблон, соответствующий любому идентификатору или номеру.
ВашКод yacc не соответствует вашему лекс-коду для пунктуации - код lex возвращает AND
для &
, в то время как код yacc ожидает &
- поэтому либо измените код lex, чтобы он возвратил '&'
, либо измените yaccкод для использования токена AND
и аналогично для |
, (
и )
.Вы также можете игнорировать пробелы в лекс-коде (вместо того, чтобы рассматривать их как ошибки).У вас также нет правила lex для сопоставления и возврата '\n'
, даже если вы используете это в своей грамматике yacc.
В противном случае ваш код yacc корректен, но неоднозначен, что дает вам сдвиг / уменьшение конфликтов.Это потому, что ваша грамматика неоднозначна - входные данные типа a&b|c
могут быть проанализированы как (a&b)|c
или a&(b|c)
.Вам нужно решить, как устранить эту неоднозначность, и отразить это в вашей грамматике - либо с помощью большего количества нетерминалов, либо с помощью встроенной поддержки приоритетов yacc для устранения такого рода двусмысленности.Если вы вставите объявления:
%left '|'
%left '&'
в верхней части вашего файла yacc, это разрешит неоднозначность, сделав &
и |
левоассоциативными, а &
более высоким приоритетом, чем |
, что было бы нормальной интерпретацией.
Редактировать
Теперь у вас проблема в том, что вы никогда не определяете YYSTYPE (ни напрямую, ни с помощью% union) в вашем.y файл, и вы никогда не устанавливаете yylval в вашем .l файле.Первая проблема означает, что $1
и т. Д. Являются просто int
с, а не указателями (поэтому нет смысла пытаться печатать их с помощью %s
- вы должны получить предупреждение от вашего компилятора C по этому поводу).Вторая проблема означает, что они никогда не имеют значения в любом случае, так что это просто всегда значение по умолчанию 0 неинициализированной глобальной переменной
Самое простое решение - добавить
%union {
const char *name;
}
%token <name> VAR LB RB LN
%left <name> AND OR
%left <name> EQ
%type <name> expr
в началофайла YACC.Затем измените все правила lex на что-то вроде
([A-Za-z0-9_]+) { yylval.name = strdup(yytext); return VAR;}
Наконец, вам также нужно изменить действия зубров для expr, чтобы установить $$
, например:
| LB exp RB { asprintf(&$$, "%s %s %s",$1,$2,$3); printf("abstract: %s\n", $$); }
Thisбудет, по крайней мере, работать, хотя будет пропускать много памяти для выделенных строк.
Последняя проблема, с которой вы столкнулись, состоит в том, что ваше правило line
соответствует только одной строке, поэтому вторая строка ввода вызывает ошибку,Вам нужно рекурсивное правило, например:
line: /* empty */
| line exp LN { printf....