$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 还有其他优点。例如,它不需要所有 ids(和 commas)都堆积在解析器的内部堆栈上等待最终的归约操作。

同样,您没有显示足够多的代码来了解您如何使用这些操作的结果。在我看来,您正在尝试创建一个全局变量链表,您将其 header 存储在一个全局变量中。 (mynotes 显然指向列表的尾部,所以它不能用于恢复头部。)如果是这样,那么上面的更改应该可以正常工作。但是将 varlist 的语义值做成列表 header 会更正常,避免使用全局变量。这将导致代码看起来更像这样:

varlist: id comma varlist  { $$ = append(, createtnode(.idcontext)); }
       | id                { $$ = append(newlist(), createtnode(.idcontext); }