在bison 2.6中无法访问令牌表yytname或者它已经消失了?

时间:2012-10-14 03:50:51

标签: bison flex-lexer

我正在构建资产xchange格式的解析器。我在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;
    }
}

gcc说YYNTOKENS和yytname都是未宣布的。那么令牌表最终被弃用和擦除了或者交易是什么?

3 个答案:

答案 0 :(得分:1)

Bison 2.6.2手册(PDF中的p82):

  

%token-table [指令]

     

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

     

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

     

当您指定%token-table时,Bison还会为宏生成宏定义   YYNTOKENSYYNNTSYYNRULESYYNSTATES

     

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

     

YYNNTS非终结符号的数量。

     

YYNRULES语法规则的数量,

     

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

看起来它应该在那里。

当我尝试一个简单的语法时,表格存在:

#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

这可确保定义令牌表。

答案 1 :(得分:1)

围绕'静态'问题有一种快速简便的方法。我试图用我的C到6502编译器打印一个人类可读的抽象语法树,其中包含每个非终端的字符串表示。这就是我做的......

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

%%
#include <stdio.h>

extern char yytext[];
extern int column;
const char ** token_table;
...

现在,在调用yyparse的main方法中,将yytname指定给token_table

int main(int argc, char ** argv) {
    FILE * myfile;
    yydebug = 1;
    token_table = yytname;
    ...

现在,只需将其声明为extern,就可以在任何编译单元中访问token_table,如:

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_table(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 = y.tab.h选项运行bison):

/* Tokens.  */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
   /* Put the tokens into the symbol table, so that GDB and other debuggers
      know about them.  */
   enum yytokentype {
     DOWHILE = 258,
     UAND = 259,
     UMULT = 260,
     ...

答案 2 :(得分:0)

避免静态符号问题的最简单方法是直接在野牛输入文件的第三部分#include词法分析器:

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

#include "lex.yy.c"

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

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