can';无法访问bison 2.6中的令牌表yytname,或者它已经不存在了?

can';无法访问bison 2.6中的令牌表yytname,或者它已经不存在了?,bison,flex-lexer,Bison,Flex Lexer,我正在为资产交换格式构建一个解析器。我在bison文件中包含了%token table指令,但是,从flex代码中,我无法访问该表或与之相关的常量。即在尝试编译此代码时: Frame|FrameTransformMatrix|Mesh|MeshNormals|MeshMaterialList|Material { printf("A keyword: %s\n", yytext); yylval.charptr_type = yytext; int i; for

我正在为资产交换格式构建一个解析器。我在bison文件中包含了%token table指令,但是,从flex代码中,我无法访问该表或与之相关的常量。即在尝试编译此代码时:

Frame|FrameTransformMatrix|Mesh|MeshNormals|MeshMaterialList|Material {
    printf("A keyword: %s\n", yytext);
    yylval.charptr_type = yytext;

    int i;
    for (i = 0; i < YYNTOKENS; i++)
    {
        if (yytname[i] != 0
            && yytname[i][0] == '"'
            && !strncmp(yytname[i] + 1, yytext, strlen(yytext))
            && yytname[i][strlen(yytext) + 1] == '"'
            && yytname[i][strlen(yytext) + 2] == 0)
            return i;
    }
}
框架|框架变换矩阵|网格|网格法线|网格材质列表|材质{
printf(“关键字:%s\n”,yytext);
yylval.charptr_type=yytext;
int i;
对于(i=0;i

gcc表示,YYNTOKENS和yytname都未申报。那么,代币表最终被弃用并删除了吗?或者是怎么回事?

野牛2.6.2手册说(PDF第82页):

%令牌表
[指令]

在解析器实现文件中生成令牌名称数组。名称 数组是
yytname
yytname[i]
是其内部野牛令牌的令牌的名称 代码编号为
i
。yytname的前三个元素对应于预定义的 令牌“
$end
”、“
error
”和“
$undefined
”;这些符号之后是在中定义的符号 语法文件

表中的名称包括表示中的令牌所需的所有字符 野牛对于单字符文字和文字字符串,这包括 引用字符和任何转义序列。例如,野牛是单一字符 literal
“+”
对应一个三个字符的名称,用C表示为
“+”
;和 Bison两个字符的文字字符串
“\\/”
对应一个五个字符的名称, 在C中表示为
“\\\\\\/\”

当您指定%token table时,Bison还会为宏生成宏定义
YYNTOKENS
yynts
YYNRULES
,以及
YYNSTATES

YYNTOKENS
最高的令牌号,加上一个

yynts
非终端符号的数量

YYNRULES
语法规则的数量

YYNSTATES
解析器状态的数量(参见第104页第5.5节[解析器状态])

看起来它应该在那里

当我尝试一个简单的语法时,桌子出现了:

#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
static const char *const yytname[] =
{
  "$end", "error", "$undefined", "ABSINTHE", "NESTLING", "$accept",
  "anything", 0
};
#endif
注:该表为静态表;如果您试图从文件外部访问它,那将不起作用

源代码中有一个较早的小节:

/* Enabling the token table.  */
#ifndef YYTOKEN_TABLE
# define YYTOKEN_TABLE 1
#endif

这确保了令牌表的定义。

有一种快速简便的方法解决“静态”问题。我试图为我的C到6502编译器打印一个可读的抽象语法树,其中包含每个非终端的字符串表示。这就是我所做的

在上一节的.y文件中,创建一个名为token_table的非静态变量

%%
#include <stdio.h>

extern char yytext[];
extern int column;
const char ** token_table;
...
int main(int argc, char ** argv) {
    FILE * myfile;
    yydebug = 1;
    token_table = yytname;
    ...
现在,您只需将token_表声明为extern即可访问任何编译单元中的token_表,如中所示:

extern const char ** token_table;

/* Using it later in that same compilation unit */
printf("%s", token_table[DOWHILE - 258 + 3]); /* prints "DOWHILE" */
对于AST中的每个节点,如果将y.tab.h中的yytokentype值分配给它,只需减去258,再加上3,就可以索引到token_表(yytname)中。您必须减去258 b/c,这是yytokentype开始枚举的位置,并且必须添加3 b/c yytname在表的开头添加三个保留符号($end、$error)和“$undefined”)

例如,我生成的bison文件具有:

static const char *const yytname[] =
{
    "$end", "error", "$undefined", "DOWHILE", "UAND", "UMULT", "UPLUS",
    "UMINUS", "UBANG", "UTILDE", "ARR", "NOOP", "MEMBER", "POSTINC",
    ...
以及defines头(使用--defines=y.tab.h选项运行bison):


避免静态符号问题的最简单方法是将lexer直接包含在bison输入文件的第三部分中:

/* token declarations and such */
%%
/* grammar rules */
%%

#include "lex.yy.c"

int main() {
  /* the main routine that calls yyparse */
}

然后您只需编译.tab.c文件,这就是您所需要的。

所以我想如果它是静态的,那么我的lexer代码需要在生成的Bison代码中?。。。医生说你可以把Flex和Bison一起使用。但通常的使用方法是让bison生成头并将其包含在flex生成器文件中。如果我错了,请纠正我:然后,如果我有单独的flex和bison文件并在以后通过gcc链接它们,我需要返回一个通用关键字标记并在flex代码中设置yylval,然后在bison中创建一个泛型产品,如果有泛型关键字,我将检索yyval以查看发生了什么?然而,如果lexer代码也在bison文件中,那么直接访问该表的唯一方法是?是的,顺便说一句,你是对的。。我检查了错误的文件(在切换到%token table之前的a.tab.c)。但是。。我想我刚刚从文档中了解到,table选项应该与Flex一起使用。Flex词法分析器通常不需要tokenname表。您需要Bison生成的
grammar.tab.h
文件或其等效文件。通常,令牌名称不一定与所分析的源代码中令牌的拼写相同。也就是说,许多语法在标记名称前面使用前缀,例如
KW\u
,因此
KW\u SYMBOL
可能是分析器扫描的源代码中
SYMBOL
的标记。
yytnames
中的名称将是
KW_符号';词法分析器将查找
symbol`。
/* token declarations and such */
%%
/* grammar rules */
%%

#include "lex.yy.c"

int main() {
  /* the main routine that calls yyparse */
}