在Yacc中,我编写了一个解析器,它应该识别一个数字或字符串,并将其分配给我创建的NAME
令牌。似乎工作在于变量被赋值,如果我打印它们的值,它们是正确的。但是,一旦Yacc移动到下一个标记,就会擦除值,就像从未分配变量一样。规则NAME '=' NAME
是在规则中分配的地方,但在其他地方没有。将一个NAME
/变量的值复制到另一个时,这只是一个问题。在底部是我所指的内容的照片,这是我的代码:
%{
#include "ch3hdr.h"
#include <stdio.h>
int yylex(void);
void yyerror(char *);
%}
%union {
char* str;
double dval;
struct symtab *symp;
}
%token <symp> NAME
%token <dval> NUMBER
%token <str> STRING
%left '-' '+'
%left '*' '/'
%nonassoc UMINUS
%type <dval> numexpr
%type <str> strexpr
%%
statement_list: statement '\n'
| statement_list statement '\n'
;
statement: NAME '=' numexpr { $1->num = $3; $1->type = NUM; }
| NAME '=' strexpr { $1->str = $3; $1->type = STR; }
| NAME '=' NAME {
$1 = $3;
switch($3->type)
{
case NUM:
{
$1->num = $3->num;
$1->type = NUM;
break;
}
case STR:
{
$1->str = $3->str;
$1->type = STR;
break;
}
default: yyerror("Declaration invalid\n"); break;
}
}
| NAME {
switch($1->type)
{
case NUM: fprintf(stderr, "num = %g\n", $1->num); break;
case STR: fprintf(stderr, "str = %s\n", $1->str); break;
default: fprintf(stderr, "var not defined %g\n", $1->num); break;
}
}
| numexpr { fprintf(stderr, "numexpr = %g\n", $1); }
| strexpr { fprintf(stderr, "strexpr = %s\n", $1); }
;
numexpr: numexpr '+' numexpr { $$ = $1 + $3; // where $1 is first entered token
// $3 is next token after "="
}
| numexpr '-' numexpr { $$ = $1 - $3; }
| numexpr '*' numexpr { $$ = $1 * $3; }
| numexpr '/' numexpr
{
if($3 == 0.0)
yyerror("divide by zero");
else
$$ = $1 / $3;
}
| '-' numexpr %prec UMINUS { $$ = -$2; }
| '(' numexpr ')' { $$ = $2; }
| NUMBER
| NAME '(' numexpr ')' { $$ = ($1->funcptr)($3); }
;
strexpr: STRING
;
%%
void yyerror(char *str)
{
fprintf(stderr, "Error %s", str);
}
struct symtab *symlook(char *s) {
char *p;
struct symtab *sp;
for(sp = symtab; sp < &symtab[NSYMS]; sp++) {
/* is it already here? */
if(sp->name && !strcmp(sp->name, s))
return sp;
if(!sp->name) { /* is it free */
sp->name = strdup(s);
return sp;
}
/* otherwise continue to next */
}
yyerror("Too many symbols");
exit(1); /* cannot continue */
} /* symlook */
void addfunc(char *name, double (*func)())
{
struct symtab *sp = symlook(name);
sp->funcptr = func;
}
int main() {
extern double sqrt(), exp(), log();
addfunc("sqrt", sqrt);
addfunc("exp", exp);
addfunc("log", log);
yyparse();
return 0;
}
%{
#include "simple.tab.h"
#include "ch3hdr.h"
#include <math.h>
%}
%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?) {
yylval.dval = atof(yytext);
return NUMBER;
}
[ \t] ; /* ignore whitespace */
[A-Za-z][A-Za-z0-9]* {
yylval.symp = symlook(yytext);
return NAME;
}
\"[^"\n]*["\n] {
yylval.str = yytext;
return STRING;
}
"$" return 0; /* logical EOF */
\n |
. return yytext[0];
%%
#include <stdlib.h>
#include <string.h>
#define NSYMS 20
typedef enum
{
NUM = 1,
STR = 2
} TYPE;
struct symtab
{
char *name;
// ptr to C function to call if this entry is a fucntion name
double (*funcptr)();
double value;
double num;
char* str;
TYPE type;
} symtab[NSYMS];
struct symtab *symlook();
答案 0 :(得分:2)
问题在于词法分析器规则:
yylval.str = yytext;
这只是将指针复制到将来某个时候会被覆盖的数据。您需要复制数据:
yylval.str = strdup(yytext);
这将造成内存泄漏,除非您在完成它后立即发出相应的free()
,有时在解析阶段或之后。
答案 1 :(得分:1)
问题是你在yytext
中返回Simple.l
,假设它的值保持不变。它不会,因为它是词法分析器的内部值,并且每次调用yylex
时都会更新。
我看到来自词法分析器的这个块:
\"[^"\n]*["\n] {
yylval.str = yytext;
return STRING;
}
在yacc语法中,使用该值而不复制,例如,
case STR:
{
$1->str = $3->str;
$1->type = STR;
break;
}
偶尔会出现这种情况,但上次我回答时(在 Bison token is rest of the string 中),我发现没有合适的接受答案将此标记为副本。