gpt4 book ai didi

c - 在 yacc 中解析赋值语句时出现语法错误

转载 作者:太空宇宙 更新时间:2023-11-04 03:49:34 26 4
gpt4 key购买 nike

[注意作业]

当我尝试运行测试用例时,我需要一个提示来说明为什么以下代码会失败:int a = 3; 所有代码编译时都没有警告或错误,并且可以看出结构是正确的。我觉得一定是assignment的规则有问题。

错误消息说:错误:第 1 行符号“a”处的语法错误

这是 .lex 文件:

%{

#include "calc.h"
#include "symbol-table.h"
#include "tok.h"
int yyerror(char *s);
int yylinenum = 1;
%}

digit [0-9]
int_const {digit}+
float_const {digit}+[.]{digit}+
id [a-zA-Z]+[a-zA-Z0-9]*

%%

{int_const} { yylval.int_val = atoi(yytext); return INTEGER_LITERAL; }
{float_const} { yylval.float_val = atof(yytext); return FLOAT_LITERAL; }
"=" { yylval.str_val = strdupclean(yylval.str_val, yytext); return EQUALS; }
"+" { yylval.str_val = strdupclean(yylval.str_val, yytext); return PLUS; }
"*" { yylval.str_val = strdupclean(yylval.str_val, yytext); return MULT; }
"-" { yylval.str_val = strdupclean(yylval.str_val, yytext); return MINUS; }
"/" { yylval.str_val = strdupclean(yylval.str_val, yytext); return DIV; }
"(" { yylval.str_val = strdupclean(yylval.str_val, yytext); return OPAREN; }
")" { yylval.str_val = strdupclean(yylval.str_val, yytext); return CPAREN; }
";" { yylval.str_val = strdupclean(yylval.str_val, yytext); return SEMIC; }
"sqrt" { yylval.str_val = strdupclean(yylval.str_val, yytext); return SQRT; }
{id} { yylval.str_val = strdupclean(yylval.str_val, yytext);
/*HINT: One way to simplify parsing is to have lex return what
* type of variable we have. IVAR = int, FVAR = float
* UVAR = unknown var.
* Naturally, you may use your own solution.
*/
if (strcmp(yylval.str_val, "int")) {return IVAR;}
else if (strcmp(yylval.str_val, "float")) {return FVAR;}
else {return UVAR;}
}

[ \t]* {}
[\n] { yylinenum++; }

. { yyerror("Unknown Symbol"); exit(1); }
%%

这是 yacc 文件:

%{
#include "calc.h"
#include "symbol-table.h"
int yyerror(char *s);
int yylex(void);
%}

%union{
int int_val;
float float_val;
char* str_val;
}

%start input

%token <int_val> INTEGER_LITERAL
%token <float_val> FLOAT_LITERAL
%token <float_val> SQRT
%token OPAREN CPAREN SEMIC IVAR FVAR UVAR
%type <int_val> int_exp
%type <float_val> float_exp
%type <str_val> IVAR FVAR UVAR
%right EQUALS /*right associative, everything on the right side of the = should be evaluated and stored*/
%left PLUS MINUS/*The order matters, by listing PLUS/MIUS first and then MULT/DIV we are */
%left MULT DIV /*telling yacc to evaluate MULTs & DIVs before PLUSes and MINUSes*/

%%

input: /*empty*/
| int_exp { printf("Result %d\n", $1); }
| float_exp { printf("Result %f\n", $1); }
| assignment { printf("Result \n"); }
;

int_exp: INTEGER_LITERAL { $$ = $1; }
| int_exp PLUS int_exp { $$ = $1 + $3; }
| int_exp MULT int_exp { $$ = $1 * $3; }
| int_exp MINUS int_exp { $$ = $1 - $3; }
| int_exp DIV int_exp { $$ = $1 / $3; }
| OPAREN int_exp CPAREN { $$ = $2; }
;

float_exp: FLOAT_LITERAL { $$ = $1; }
| float_exp PLUS float_exp { $$ = $1 + $3; }
| float_exp MULT float_exp { $$ = $1 * $3; }
| float_exp MINUS float_exp { $$ = $1 - $3; }
| float_exp DIV float_exp { $$ = $1 / $3; }
| int_exp PLUS float_exp { $$ = (float)$1 + $3; }
| int_exp MULT float_exp { $$ = (float)$1 * $3; }
| int_exp MINUS float_exp { $$ = (float)$1 - $3; }
| int_exp DIV float_exp { $$ = (float)$1 / $3; }
| float_exp PLUS int_exp { $$ = (float)$1 + $3; }
| float_exp MULT int_exp { $$ = (float)$1 * $3; }
| float_exp MINUS int_exp { $$ = (float)$1 - $3; }
| float_exp DIV int_exp { $$ = (float)$1 / $3; }
| OPAREN float_exp CPAREN { $$ = $2; }
| SQRT OPAREN float_exp CPAREN { $$ = sqrt((double)$3); }
| SQRT OPAREN int_exp CPAREN { $$ = sqrt((double)$3); }
;

assignment: UVAR EQUALS float_exp SEMIC { //if UVAR exists and is float, update value
//if UVAR doesn't exist, error: unknown type
symbol_table_node *n1 = symbol_table_find( $1, *st);
if(n1) {
if(n1->type == FLOAT_TYPE) {
n1->val.float_val = $3;
} else {
//error
}
//error, variable not defined
//if UVAR is not float, error: illegal assignment
}
}
| UVAR EQUALS int_exp SEMIC {
symbol_table_node *n1 = symbol_table_find( $1, *st);
if(n1) {
if(n1->type == INT_TYPE) {
n1->val.int_val = $3;
} else {
//error
}
}
}
| IVAR UVAR EQUALS int_exp SEMIC { //UVAR should not be in symbol table
if(symbol_table_find($2, *st)) {
//error
} else {
//how to handle errors?
symbol_table_add_i($2, $4, *st);
}
}
| FVAR UVAR EQUALS float_exp SEMIC {
if(symbol_table_find($2, *st)) {

} else {
symbol_table_add_f($2, $4, *st);
}
}
;

%%

int yyerror(char *s){
extern int yylinenum; /* defined and maintained in lex.c*/
extern char *yytext; /* defined and maintained in lex.c*/

printf("ERROR: %s at symbol \"%s\" on line %d\n", s, yytext, yylinenum);
return -1;
}

最佳答案

这个错误很简单:

if (strcmp(yylval.str_val, "int"))

并没有按照您的想法行事。 strcmp 如果两个字符串相等则返回 0,如果第一个字符串在字典序上较早则返回负值,如果第一个字符串在字典序上较晚则返回正值。用作 bool 值,这意味着如果字符串比较相等,则 strcmpfalse,否则为 true。所以 token int 不会生成 token 值 IVAL

但无论如何,我认为这并不是您真正想要做的。您的讲师关于让词法分析器返回与标记的已知数据类型相对应的标记类型的提示是指在符号表中查找变量并返回与变量声明相对应的标记类型。它不是指识别保留字 intfloat,这应该使用简单的词法分析器规则来完成,就像您对保留字 sqrt.

正如所写,您的语法不允许表达式使用变量,因此(即使在您修复了我提到的错误之后),以下操作也会失败:

int b = 0;
int a = b + 3;

因为 b 不会被识别为 int_exp。正是在这种情况下,教师的提示才适用。 (尽管就个人而言,我建议采用不同的方式。)

最后,我不知道 strdupclean 的作用,但我推测它涉及制作 yytext 的副本。对于运算符标记(+- 等)或保留字,这几乎肯定是不必要的,因为您永远不会引用这些的“语义值” token 。 (作为证据,您没有声明任何这些标记甚至具有语义类型。)不必要的复制确实有成本,特别是如果您需要清理为副本分配的内存。

祝你好运。

关于c - 在 yacc 中解析赋值语句时出现语法错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21800758/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com