我想传递令牌的实际字符串。如果我有一个名为ID的令牌,那么我希望我的yacc文件实际知道调用了什么ID。我必须使用yylval将字符串传递给flex文件中的yacc文件。我该怎么做?
答案 0 :(得分:16)
通过yylval返回字符串或任何复杂类型的关键是yacc在y.tab.h文件中创建的YYSTYPE联合。 YYSTYPE是一个联合,其中包含yacc源文件中定义的每种令牌类型的成员。例如,要返回与yacc源文件中的SYMBOL标记关联的字符串,请使用yacc源文件中的%union 声明此YYSTYPE联合:
/*** Yacc's YYSTYPE Union ***/
/* The yacc parser maintains a stack (array) of token values while
it is parsing. This union defines all the possible values tokens
may have. Yacc creates a typedef of YYSTYPE for this union. All
token types (see %type declarations below) are taken from
the field names of this union. The global variable yylval which lex
uses to return token values is declared as a YYSTYPE union.
*/
%union {
long int4; /* Constant integer value */
float fp; /* Constant floating point value */
char *str; /* Ptr to constant string (strings are malloc'd) */
exprT expr; /* Expression - constant or address */
operatorT *operatorP; /* Pointer to run-time expression operator */
};
%type <str> SYMBOL
然后在LEX源文件中有一个与SYMBOL令牌匹配的模式。与该规则关联的代码负责返回表示SYMBOL的实际字符串。您不能只是将指针传递给yytext缓冲区,因为它是一个静态缓冲区,可以为匹配的每个标记重用。要返回匹配的文本,必须使用_strdup()在堆上复制静态yytext缓冲区,并通过yyval.str传递指向此字符串的指针。然后是yacc规则,它与SYMBOL令牌的责任相匹配,即当它完成时释放堆分配的字符串。
[A-Za-z_][A-Za-z0-9_]* {{
int i;
/*
* condition letter followed by zero or more letters
* digits or underscores
* Convert matched text to uppercase
* Search keyword table
* if found
* return <keyword>
* endif
*
* set lexical value string to matched text
* return <SYMBOL>
*/
/*** KEYWORDS and SYMBOLS ***/
/* Here we match a keywords or SYMBOL as a letter
* followed by zero or more letters, digits or
* underscores.
*/
/* Convert the matched input text to uppercase */
_strupr(yytext); /* Convert to uppercase */
/* First we search the keyword table */
for (i = 0; i<NITEMS(keytable); i++) {
if (strcmp(keytable[i].name, yytext)==0)
return (keytable[i].token);
}
/* Return a SYMBOL since we did not match a keyword */
yylval.str=_strdup(yytext);
return (SYMBOL);
}}
答案 1 :(得分:7)
请参阅the Flex manual section on Interfacing with YACC。
15与Yacc接口
flex的主要用途之一是作为a yacc的伴侣 分析器生成。 yacc解析器期望 调用名为yylex()的例程 找到下一个输入令牌。例程 应该返回的类型 下一个令牌以及任何 全局yylval中的关联值。 要使用flex和yacc,可以指定 yacc的`-d'选项来指示它 生成文件y.tab.h 包含所有的定义 yacc输入中出现的%令牌。 然后,此文件包含在flex中 扫描器。例如,如果其中之一 令牌是TOK_NUMBER,是其中的一部分 扫描仪可能看起来像:
%{ #include "y.tab.h" %} %% [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
答案 2 :(得分:3)
设置背景
语法分析(检查输入文本是否遵循指定的语法)包含两个阶段:
在执行阶段1 时,给定输入流,每次调用yylex()都会标识一个标记(一个字符串),yytext指向该字符串的第一个字符。例如:使用输入流“int x = 10;”并且使用符合C语言的标记化的lex规则,然后对yylex()的前5次调用将识别以下5个标记“int”,“x”,“=”,“10”,“;”每次yytext都指向返回令牌的第一个字符。
阶段2 ,解析器(您提到的yacc)是一个程序,每次调用此yylex函数获取一个令牌并使用这些令牌来查看它是否符合规则一个语法。这些对yylex的调用将返回令牌作为一些整数代码。例如,在前面的示例中,对yylex()的前5次调用可能会将以下整数返回给解析器:TYPE,ID,EQ_OPERATOR和INTEGER(其实际整数值在某些头文件中定义)。
现在所有解析器都可以看到那些整数代码,这些代码有时可能没用。例如,在运行示例中,您可能希望将TYPE与int,ID关联到某个符号表指针,将INTEGER关联到十进制10.为方便起见,yylex返回的每个标记与另一个默认类型为int的VALUE关联,但是你可能有自定义类型。在lex环境中,此VALUE作为yylval访问。
例如,再次根据运行示例,yylex可能具有以下规则来标识10
[0-9]+ { yylval.intval = atoi(yytext); return INTEGER; }
,然后确定x
[a-zA-Z][a-zA-Z0-9]* {yylval.sym_tab_ptr = SYM_TABLE(yytext); return ID;}
请注意,我在这里定义了VALUE(或yylval)类型作为包含int(intval)和int *指针(sym_tab_ptr)的联合。
但是在yacc世界中,这个VALUE被识别/访问为$ n。例如,请考虑以下yacc规则来标识特定的赋值语句
TYPE ID '=' VAL: { //In this action part of the yacc rule, use $2 to get the symbol table pointer associated with ID, use $4 to get decimal 10.}
回答您的问题
如果您想在yacc世界中访问某个令牌(与lex世界相关)的yytext值,请使用该旧朋友VALUE如下: