$1 在 yacc 中意味着什么,我怎样才能得到它的值
what does $1 means in yacc, and how can I get its value
我想完成对 varlist 声明的解析,
像 varlist:id 逗号 varlist|id。
这时候我需要设置一个关于var
的列表。
所以我写了这段代码:
varlist: id comma varlist{ createtnode(.idcontext);}
|id{createtnode(.idcontext);};
但是我发现.idcontext
不是那个idcontext
我想要哪个应该是这个id token的idcontext。
现在,.idcontext
就是这句话'varlist'。没有代码操作,此语法可以正常工作。
typedef struct{
int* TC;
int* FC;
}boolcode;
typedef struct {
char* idcontext;
int constvalue;
int chain;
boolcode ftentry;
}includes;
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef struct{
int classify;
includes unique;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
VARList: IDENcode COMMA VARList{
if(YYDEBUG)
{printf("6\n");
printf("%s\n",.idcontext);
}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
}|IDENcode{
if(YYDEBUG)
{printf("7\n");printf("%s\n",.idcontext);}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
};
等待识别的单词:
a,b,c,d
printf()
函数的结果:
7
d:
6
c,d:
6
b,c,d:
6
a,b,c,d:enter code here
这个程序的真正问题在这个问题中是看不到的,因为错误在你的词法扫描器中。
你没有在问题中包含 flex 文件,但有理由猜测它包含如下内容:
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = yytext; /* INCORRECT */
return IDENcode;
}
应该是
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = strdup(yytext);
return IDENcode;
}
yytext
指向扫描器的内部缓冲区,每次调用扫描器时都会修改其内容。您看到的是这个问题的轻微版本,因为您的输入非常短;如果输入足够长以至于 yylex
需要从输入文件重新填充缓冲区,那么您会在 idcontext
字段中看到完整的垃圾。如果你想稍后使用这个字符串,你需要复制它(然后你需要记住 free()
当你不再需要它时复制它,这可能有点挑战。)
另一个可能的问题 -- 老实说,我不知道您是否认为这是一个问题,因为您没有指定您 期望 从调试跟踪中得到什么输出-- 是你的 right-recursive 规则:
varlist: id comma varlist { createtnode(.idcontext); }
| id { createtnode(.idcontext); }
最终以相反的顺序在 id
上调用 createtnode
,因为 当规则匹配时 执行野牛减少操作。像这样使用 right-recursion 意味着要执行的第一个 varlist
操作实际上对应于最后一个 id
.
如果你想让动作从左到右执行,你需要使用left-recursion:
varlist: varlist comma id { createtnode(.idcontext); } /* See below */
| id { createtnode(.idcontext); }
Left-recursion 还有其他优点。例如,它不需要所有 id
s(和 comma
s)都堆积在解析器的内部堆栈上等待最终的归约操作。
同样,您没有显示足够多的代码来了解您如何使用这些操作的结果。在我看来,您正在尝试创建一个全局变量链表,您将其 header 存储在一个全局变量中。 (mynotes
显然指向列表的尾部,所以它不能用于恢复头部。)如果是这样,那么上面的更改应该可以正常工作。但是将 varlist
的语义值做成列表 header 会更正常,避免使用全局变量。这将导致代码看起来更像这样:
varlist: id comma varlist { $$ = append(, createtnode(.idcontext)); }
| id { $$ = append(newlist(), createtnode(.idcontext); }
我想完成对 varlist 声明的解析,
像 varlist:id 逗号 varlist|id。
这时候我需要设置一个关于var
的列表。
所以我写了这段代码:
varlist: id comma varlist{ createtnode(.idcontext);}
|id{createtnode(.idcontext);};
但是我发现.idcontext
不是那个idcontext
我想要哪个应该是这个id token的idcontext。
现在,.idcontext
就是这句话'varlist'。没有代码操作,此语法可以正常工作。
typedef struct{
int* TC;
int* FC;
}boolcode;
typedef struct {
char* idcontext;
int constvalue;
int chain;
boolcode ftentry;
}includes;
/* Value type. */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef struct{
int classify;
includes unique;
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif
VARList: IDENcode COMMA VARList{
if(YYDEBUG)
{printf("6\n");
printf("%s\n",.idcontext);
}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
}|IDENcode{
if(YYDEBUG)
{printf("7\n");printf("%s\n",.idcontext);}
varlistnode* newvar=malloc(sizeof(varlistnode));
newvar->varname=.idcontext;
newvar->value=0;
newvar->next=NULL;
mynotes->next=newvar;
mynotes=mynotes->next;
};
等待识别的单词:
a,b,c,d
printf()
函数的结果:
7
d:
6
c,d:
6
b,c,d:
6
a,b,c,d:enter code here
这个程序的真正问题在这个问题中是看不到的,因为错误在你的词法扫描器中。
你没有在问题中包含 flex 文件,但有理由猜测它包含如下内容:
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = yytext; /* INCORRECT */
return IDENcode;
}
应该是
[[:alpha:]_][[:alnum:]_]* { yylval.unique.idcontext = strdup(yytext);
return IDENcode;
}
yytext
指向扫描器的内部缓冲区,每次调用扫描器时都会修改其内容。您看到的是这个问题的轻微版本,因为您的输入非常短;如果输入足够长以至于 yylex
需要从输入文件重新填充缓冲区,那么您会在 idcontext
字段中看到完整的垃圾。如果你想稍后使用这个字符串,你需要复制它(然后你需要记住 free()
当你不再需要它时复制它,这可能有点挑战。)
另一个可能的问题 -- 老实说,我不知道您是否认为这是一个问题,因为您没有指定您 期望 从调试跟踪中得到什么输出-- 是你的 right-recursive 规则:
varlist: id comma varlist { createtnode(.idcontext); }
| id { createtnode(.idcontext); }
最终以相反的顺序在 id
上调用 createtnode
,因为 当规则匹配时 执行野牛减少操作。像这样使用 right-recursion 意味着要执行的第一个 varlist
操作实际上对应于最后一个 id
.
如果你想让动作从左到右执行,你需要使用left-recursion:
varlist: varlist comma id { createtnode(.idcontext); } /* See below */
| id { createtnode(.idcontext); }
Left-recursion 还有其他优点。例如,它不需要所有 id
s(和 comma
s)都堆积在解析器的内部堆栈上等待最终的归约操作。
同样,您没有显示足够多的代码来了解您如何使用这些操作的结果。在我看来,您正在尝试创建一个全局变量链表,您将其 header 存储在一个全局变量中。 (mynotes
显然指向列表的尾部,所以它不能用于恢复头部。)如果是这样,那么上面的更改应该可以正常工作。但是将 varlist
的语义值做成列表 header 会更正常,避免使用全局变量。这将导致代码看起来更像这样:
varlist: id comma varlist { $$ = append(, createtnode(.idcontext)); }
| id { $$ = append(newlist(), createtnode(.idcontext); }