- 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/
在此处回答的另一个问题中,我发现了以下 JavaScript代码: function _dom_trackActiveElement(evt) { if (evt && evt.target)
if (A == 0) OR (B == 0) 怎么说? 最佳答案 只是为了讽刺: if (A === 0 || B === 0) 关于语法,我们在Stack Overflow上找到一个类似的问题:
var ret = [] ,xresult = document.evaluate(exp, rootEl, null, X
我一直在寻找一些类似于下例的 JavaScript。有人可以解释一下吗,因为我以前从未见过这样编写的 JavaScript。 “SomethingHere”和冒号代表什么?我习惯于看到函数 myFun
这是我的程序: delimiter // drop procedure if exists migContactToActor; create procedure migContactToActor(
我遇到了一个问题。我一直在使用 gcc 编译/汇编我的 C 代码一段时间,并且习惯了阅读 Intel 汇编语法。我在生成程序集文件时使用了 -masm=intel 标志。 但是最近因为公司迁移,拿到了
自上而下和自下而上语法有什么区别?举个例子就太好了。 最佳答案 首先,语法本身不是自上而下或自下而上的,解析器是(尽管有些语法可以被其中一个解析,但不能被另一个解析)。 从实践的角度来看,主要区别在于
我知道这是草率的代码,但它是: display dialog ("Start Screensaver. Please type: matrix, coffee, waffles, star, wate
这个问题已经有答案了: Giving name to a loop (6 个回答) 已关闭 8 年前。 我见过这个字符在 C# 中使用,就像 Java 中的扩展一样,但最近我在代码中发现了这个 loo
我正在尝试编写一个函数来检查字符串是否为回文,但我认为在使用字符串指针时存在一些错误。这段代码有什么问题? #include #include #define MAX 1000 int IsPalin
所以在this question我询问了一些 Javascript 是如何被压缩的。问题已得到解答,但以下片段让我非常困惑,以至于我不得不问另一个问题。在这里: for (Y = 0; $ = 'zx
假设我有一个接受这些参数的函数。 int create(Ptr * p,void * (*insert)(void *, void *)) { //return something later } 结
这个问题已经有答案了: Bitwise '&' operator (6 个回答) 已关闭 5 年前。 我在代码中找到了这个,但我从未遇到过像 & 这样的事情,仅 && if ((code & 1) =
我在处理继承类及其中的构造函数和方法的语法时遇到了问题。 我想实现一个类日期和一个子类 date_ISO,它们将按特定顺序设置给定的日、月、年,并通过一种方法将其写入字符串。我觉得我的基类日期工作正常
我正在尝试通过存储过程填充表,如下所示: SET @resultsCount = (SELECT COUNT(*) FROM tableA); SET @i = 0; WHILE @i THEN
谁能解释一下下面代码中的“<<”? mysql test<
刚刚开始学习 MySQL,这是一个菜鸟问题,也是我在 StackOverflow 上的第一个问题。 假设我有 12 个订单状态,我想从其中的 5 个中选择总计。我会使用: SELECT SUM(tot
我的编程背景是在学校学过一点Java。由于某些原因,JavaScript 语法往往让我感到困惑。下面的 JavaScript 代码是一种我不知道如何构成的语法模式: foo.ready = funct
我正在阅读 javascript 源代码,并且我以前没有编写过 javascript。我对它的一些语法感到困惑。 $(function () { window.onload=function
我什至不知道如何命名我想要的东西。那么让我举个例子来解释一下。 虽然火狐使用textContent,但其他浏览器支持innerText属性。顺便说一句,如果我使用了错误的术语,请纠正我。无论如何,到目
我是一名优秀的程序员,十分优秀!