- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
[注意作业]
当我尝试运行测试用例时,我需要一个提示来说明为什么以下代码会失败: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 值,这意味着如果字符串比较相等,则 strcmp
为 false
,否则为 true
。所以 token int
不会生成 token 值 IVAL
。
但无论如何,我认为这并不是您真正想要做的。您的讲师关于让词法分析器返回与标记的已知数据类型相对应的标记类型的提示是指在符号表中查找变量并返回与变量声明相对应的标记类型。它不是指识别保留字 int
和 float
,这应该使用简单的词法分析器规则来完成,就像您对保留字 sqrt
.
正如所写,您的语法不允许表达式使用变量,因此(即使在您修复了我提到的错误之后),以下操作也会失败:
int b = 0;
int a = b + 3;
因为 b
不会被识别为 int_exp
。正是在这种情况下,教师的提示才适用。 (尽管就个人而言,我建议采用不同的方式。)
最后,我不知道 strdupclean
的作用,但我推测它涉及制作 yytext
的副本。对于运算符标记(+
、-
等)或保留字,这几乎肯定是不必要的,因为您永远不会引用这些的“语义值” token 。 (作为证据,您没有声明任何这些标记甚至具有语义类型。)不必要的复制确实有成本,特别是如果您需要清理为副本分配的内存。
祝你好运。
关于c - 在 yacc 中解析赋值语句时出现语法错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21800758/
如何使用 yyparse() 编译、链接和调用不同的 YACC 语法在一个程序中? 最佳答案 对每个单独的 yacc 语法生成使用 -p 选项 -p prefix Use pr
我正在为类项目工作,我们必须在其中构建解析器。我们目前正处于在 yacc 中构建解析器的阶段。目前让我感到困惑的是,我读到您需要为每个非终结符分配一个类型。在某些情况下,虽然我会有类似的东西: ...
我有一个关于 yacc 编译器的问题。我不编译简单的 yacc 语法。这是代码部分: /*anbn_0.y */ %token A B %% start: anbn '\n' {printf(" is
我正在使用 Yacc 和 lex 来解析 C 类型语言, 我已经使用 C++ 构建了数据结构。 一切正常,但我无法在 main.cpp 中使用 yyin 读取输入文件。 以下是代码: 请帮忙 ! #i
每当找到一些正则表达式时,我都会使用 lex 来执行一些代码, Yacc 还能做更多的事情吗?如果是,那是什么? 最佳答案 lex 和 yacc 通常一起使用。这就是您通常使用以下两种方式构建应用程序
我是 lex 和 yacc 以及编译器设计的新手。我想知道符号表是在哪个阶段(词汇、句法或任何其他阶段)以及如何生成的? 我可以简单描述一下 y.output 文件,该文件是通过向 yacc 提供 -
我正在 yacc 中处理一个项目并且遇到了 shift/reduce 错误,但我不知道为什么我会得到它。我一直在查看 y.output 文件,但不太确定如何阅读它。我的 y.output 文件超出了
我是 yacc/lex 的新手,我正在开发一个由其他人编写的解析器。我注意到,当找到未定义的标记时,解析器返回错误并停止。有没有一种简单的方法可以让它完全忽略它无法解析的行并继续进行下一个? 最佳答案
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
嗨,我正在学习 Lex 和 yacc。我创建了以下 lex 程序。 %{ #include %} %% [0123456789]+ printf("NUMBER\n"); [a-
莱克斯部分: %% [0-9]+ { yyval = atoi (yytext); return num; } %% 雅克部分: %token num %% exp:num '+' num ; {$$
问题 我正在尝试使用 Python Lex-Yacc (PLY) 实现容错解析器,但在输入字符串末尾使用错误恢复规则时遇到问题。 如何从意外的输入结束中恢复? 示例 此示例语法生成以下形式的字符串 A
我有两个带有函数 xxlex() 和 yylex() 的 lex 文件,还有一个 yacc语法文件。我希望语法规则始终调用 xxlex()。但是 xlex() 只被调用一次,我希望它总是被调用。我该怎
我正在尝试使用 PLY (python implementation of yacc) 编写一个相当简单的语法,并且在我想要的时候让 yacc 减少标记字符串时遇到困难。 我想解释一系列采用不同类型参
notype_declarator: notype_declarator '(' parmlist_or_identifiers %prec '.' { $$ = bui
已关闭。这个问题是 off-topic 。目前不接受答案。 想要改进这个问题吗? Update the question所以它是on-topic用于堆栈溢出。 已关闭12 年前。 Improve th
拜托,我面临一个简单的问题..这就是问题所在,在我的 lex 文件中,我有类似的内容: char *ptr_String; "name = " { BEGIN sName; } .+ {
关闭。这个问题是off-topic .它目前不接受答案。 想改善这个问题吗? Update the question所以它是 on-topic对于堆栈溢出。 9年前关闭。 Improve this q
嗨,我正在尝试运行 R. Levine 所著的 lex 和 yacc 书中的 John 代码,我已经使用命令在 Linux 中编译了 lex 和 yacc 程序 lex example.l yacc
我想传递 token 的实际字符串。如果我有一个名为ID的 token ,那么我希望我的yacc文件实际知道称为什么ID。我必须将使用yylval的字符串从flex文件传递到yacc文件。我怎么做?
我是一名优秀的程序员,十分优秀!