c - Flex 和 Bison 逻辑运算符语法错误
问题描述
我对 Flex 和野牛很陌生,我正在做一个比较数字的应用程序。如果 a > b 它将返回 0 并且 a < b 将返回 1 但是,当涉及 &、|、== 时我遇到了问题,这是我的输出示例:
>> a = 5
5
>> b = 8
8
>> a < b & a < b
1
>> syntax error
我不知道如何解决这个问题。这是编译器的一些抱怨:
[tpham14@linux5 ~/331] make -f mymake calc
bison -d -o y.tab.c -v calc.y
calc.y: warning: 16 shift/reduce conflicts [-Wconflicts-sr]
calc.y: warning: 6 reduce/reduce conflicts [-Wconflicts-rr]
cc -c -o y.tab.o y.tab.c
cc -c -o lex.yy.o lex.yy.c
cc -o calc y.tab.o lex.yy.o
这是我的 calc.y 文件:
%{
#include "calc.h"
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
/************************************************************************
* Defines a yacc grammar for a simple calculator using infix
* notation. WHen executed, the calculator enters a loop in
* which it prints the prompt >>, reads a toplevel expression
* terminated by a newline, and prints its value. Operators
* include +, -, *, and = (assignment). Note that all
* expressions return values, even assignment. Parentheses
* can be used to override operator precedence and
* associativity rules. Based on zcalc by ruiz@capsl.udel.edu
************************************************************************/
int yylex();
int yyparse();
%}
/*
Th union directive specifies the collection of tpes our grammar
deals with -- just doubles and pointers to symbol table entries.
*/
%union {
double dval;
struct symtab *symp;
}
/*
Declare the token types and any associated value types. We made
EQ a token in calc.l because otherwise '=' and '==' would clash.
*/
%token <symp> NAME
%token <dval> NUMBER
%token EQ
%token GT
%token LT
%token OR
%token AND
%token NOT
%token IF
%token ELSE
/* The folowing declarations specify the precidence and associativity
of our operators. The operators -, +, * and / to be left
associative, * and EQ to be right associative and UMINUS to be
non-associative (since it is a unary operator). The '=' operator
has the lowest precedence and UMINUS the highest.
*/
%right '=' /*lowest precedence*/
%right EQ GT LT
%left '-' '+'
%left '*' '/'
%left '&'
%nonassoc OR AND NOT
%nonassoc IF
%nonassoc ELSE
%nonassoc UMINUS /* highest precedence */
/*
Declare the type of expression to be a dval (double).
*/
%type <dval> expr
%type <dval> smallexprs
%%
/*
Here are our grammar rules. a session is a sequence of lines. A
toplevel is just an expr (print its value followed by two
newlines and the prompt >>) or a '? (print help) or a '.' (exit).
An expr can be a number, name, the sum of two exprs, ...
*/
session: /* empty */
|session toplevel '\n'
;
toplevel: expr { printf("%g\n\n>> ", $1); }
| /*empty*/
| '?' { printHelp(); printf("\n>> "); }
| '.' { printf("Exiting 331 calc\n"); exit(1); }
expr: smallexprs { $$ = $1; }
| NAME { $$ = $1->value; }
| NAME '=' expr { $1->value = $3; $$ = $3; }
| IF expr expr expr { if($2 == 1) $$ = $3; else $$ = $4; }
| smallexprs AND smallexprs { $$ = $1 && $3; }
| smallexprs OR smallexprs { $$ = $1 || $3; }
| smallexprs EQ smallexprs { $$ = $1 == $3; }
| expr GT expr { $$ = $1 > $3; }
| expr LT expr { $$ = $1 < $3; }
| expr '+' expr { $$ = $1 + $3; }
| expr '-' expr { $$ = $1 - $3; }
| expr '*' expr { $$ = $1 * $3; }
| expr '/' expr { $$ = $1 / $3; }
smallexprs: NUMBER { $$ = $1; }
| IF smallexprs smallexprs smallexprs { if($2 == 1) $$ = $3; else $$ = $4; }
| smallexprs EQ smallexprs { $$ = $1 == $3; }
| smallexprs GT smallexprs { $$ = $1 > $3; }
| smallexprs LT smallexprs { $$ = $1 < $3; }
| smallexprs '+' smallexprs { $$ = $1 + $3; }
| smallexprs '-' smallexprs { $$ = $1 - $3; }
| smallexprs '*' smallexprs { $$ = $1 * $3; }
| smallexprs '/' smallexprs { $$ = $1 / $3; }
| '~' smallexprs %prec UMINUS { $$ = -$2; }
| '(' smallexprs ')' { $$ = $2; }
%%
struct symtab *
symlook(s)
char *s;
{
char *p;
struct symtab *sp;
/* given the name of a symbol, scan the symbol table and
either return the entry with matching name or add it
to the next free cell in the symbol table. */
for(sp = symtab; sp < &symtab[SYMBOLTABLESIZE]; sp++) {
/* If the symbol table entry has a name and its equal
to the one we are looking for, return this entry */
if (sp->name && !strcmp(sp->name, s))
return sp;
/* If the name is empty then this entry is free, so the
symbol must not be in the table and we can add it here
and return this entry. */
if (!sp->name) {
sp->name = strdup(s);
return sp;
}
}
/* We searched the entire symbol table and neither found
the symbol or an unused entry. So the table must be
full. Sigh. */
yyerror("The symbol table is full, sorry...\n");
exit(1);
}
void printHelp()
{ /* print calculator help and return */
printf("Enter an expression in infix notation followed by a newline.\n");
printf("Operators include +, -, * and =. Defined functions include\n");
printf("sqrt, exp and log. You can assign a variable using the =\n");
printf("operator. Type . to exit. Syntax errors will terminate the\n");
printf("program, so be careful.\n");
}
/* If error prints error and Do not accept to signify bad syntax in
program */
void yyerror(char *msg) /* yacc error function */
{
printf("%s \n" , msg);
}
int yywrap(){return 1;}
int main()
{ /* print herald and call parser */
printf("331 Calculator\n(type ? for help and . to exit)\n\n>> ");
yyparse();
return 0;
}
下面是我的 calc.l 文件:
%{
#include "y.tab.h"
#include "calc.h"
#include <math.h>
/************************************************************************
A lexical scanner to recognize numbers, symbols and the EQ
operator. When a NUMBER is found, its value is set is set to the
appropriate float. When a NAME is found, an entry in symbol table is
created (with initial value 0.0) and the token's value is a pointer to
this entry. If a '==' sequence is seen, it is returned as a token
EQ. Spaces and tabs are ignored. Any other characters, including
a newline, are passed on as their own tokens. Based on the zcalc
calculator by ruiz@capsl.udel.edu
************************************************************************/
%}
D [0-9]
A [a-zA-Z]
AD [a-zA-Z0-9]
%%
({D}+|({D}*\.{D}+)([eE][-+]?{D}+)?) {yylval.dval = atof(yytext); return NUMBER;}
if {return IF;}
or {return OR;}
and {return AND;}
not {return NOT;}
{A}{AD}* {struct symtab *sp = symlook(yytext); yylval.symp = sp; return NAME;}
"==" {return EQ;}
">" {return GT;}
"<" {return LT;}
[ \t] ;
\n |
. return yytext[0];
%%
下面是我的 calc.h 文件:
#define SYMBOLTABLESIZE 30
/* An entry in the symbol table has a name, a pointer to a function,
and a numeric value. */
struct symtab {
char *name;
double (*funcptr)();
double value;
} symtab[SYMBOLTABLESIZE];
struct symtab *symlook();
void printHelp();
void yyerror();
解决方案
语法错误没有规则匹配或包含 &
&& 标记在您的 lex 规范中定义为“和”,您应该检查
a < b and a < b
或将 lex 规范更改为
&& { return AND;}
|| { return OR;}
! { return NOT;}
在 GT 移位后,通过 Px 减少,因为 smallexprs Follow 包含 GT,类似地用于 LT、+、-、*。(6 班次/减少冲突)
expr: smallexprs --- Px
smallexprs: smallexprs .GT smallexprs ---Sy
expr: smallexprs EQ smallexprs .
smallexprs: smallexprs EQ smallexprs .
减少/减少对 expr 和 smallexprs 的关注的冲突(6 减少/减少冲突)
推荐阅读
- algorithm - 有效地在由整数重复子字符串形成的字符串中查找字符
- bash - 如何先扩展字符串然后评估?
- jquery - 将 div 定位到展开到顶部
- python - python import swig库失败,动态模块未定义init函数
- css - CSS 不工作/在 Codepen 反应笔上加载
- postgresql - Odoo V12 CE 分段错误(核心转储)在安装 Odoo 12 后创建数据库时面临此问题
- python - 如果滚动 7 天间隔中出现的次数大于 x,则熊猫计数
- php - laravel 5.7 中的 mysqli multi_query
- php - 如何设置 Laravel 和 Vuejs 可以访问的全局变量?
- google-chrome - WebSocket 握手期间出错:net::ERR_INVALID_HTTP_RESPONSE - chrome 升级到 72