Flex C++中yytext函数复制内容异常的技术求助
Flex中yytext无法正确复制变量名的问题排查与解决
问题描述
使用Flex+Yacc开发时,遇到yytext无法正确捕获变量名的问题:变量名以@开头,这本身不影响解析,但符号表中仅能正确保存逗号后的变量名,其余情况(如分号、括号前的变量)都将分隔符(;、)、,)当成变量名存入,导致符号表数据错误。
相关代码
.l文件核心代码
progr: declaratii bloc {printf("program corect sintactic\n");} ; declaratii : declaratie ';' | declaratii declaratie ';' | declaratii structura | declaratii clasa ';' | declaratii function | function | clasa ';' | structura ; declaratie : INT var_int | INT lista_int | CHAR var_char | CHAR lista_char | FLOAT var_float | FLOAT lista_float | STRING var_string | STRING lista_string | BOOL var_bool | BOOL lista_bool ; lista_int : ID '(' lista_param_int ')' {add("lista", "int");} | ID '(' ')' {add("lista", "int");} | lista_int ',' ID '(' lista_param_int ')' {add("lista", "int");} | lista_int ',' ID '(' ')' {add("lista", "int");} ; var_int : ID {add("var", "int");} | var_int ',' ID {add("var", "int");} ; lista_param_int : INT ID | lista_param_int ',' INT ID ; lista_char : ID '(' lista_param_char ')' {add("lista", "char");} | ID '(' ')' {add("lista", "char");} | lista_char ',' ID '(' lista_param_char ')' {add("lista", "char");} | lista_char ',' ID '(' ')' {add("lista", "char");} ; void add(char * tip, char * tipDate){ symbol_table[contor].nume = strdup(yytext) ; symbol_table[contor].tip = tip; symbol_table[contor].tipDate = tipDate; contor++; }
输入文本
class Test{ private: int @x; public: int @z; protected: char @o; int @tr2; protected: float @k; int @dasdas(int @var23); }; struct structura{ char @nume; char @tip; }; float functie($int @var0 : char @sir : bool @binar){ $int @var1; $@var1 := 1; $if'(@var1 :== 1){ @var1 := 2; if'(@var1 :== 2){ @var1 := 3; } } $@var1 := 8; $int @var2; $int @var3, @var4; $@var2 := 6; } int @a, @b, @c; int @xz, @dsada; int @d(), @xsadas(int @arata); char @c; begin_progr @a := 3; if'(@a :== 3){ @a := 2; } end_progr
错误输出
nume tip tipDate ; var int ; var int ; var char ; var int ; var float ) lista int ; var char ; var char : var int : var char ) var bool ; var int ; var int , var int @var4 var int , var int @b var int @c var int , var int @dsada var int ) lista int ) lista int ; var char
原因分析
yytext是Flex内部的缓冲区指针,它始终指向当前刚匹配完成的Token。而Yacc的动作是在整个规则匹配完成后才执行,此时Flex已经读取了下一个Token(比如分号、逗号、括号),yytext已经被更新为下一个Token的内容,导致动作中调用strdup(yytext)时,复制的是分隔符而非目标变量名。
比如在规则var_int : ID {add(...);}中,当执行add时,Flex已经匹配了ID后面的分号,yytext此时指向分号,而非之前的ID。
解决方案
通过Yacc的语义值传递保存Token内容,避免依赖yytext的即时值:
1. 修改Yacc定义,添加语义值存储
在Yacc文件的开头定义语义值联合体,并声明ID的语义类型:
%union { char* str; } %token <str> ID %token INT CHAR FLOAT STRING BOOL CLASS STRUCT FUNCTION BEGIN_PROGR END_PROGR // 其他Token声明...
2. 修改Flex规则,保存ID的字符串值
在Flex的匹配规则中,将ID的内容复制到语义值中,再返回Token:
@[a-zA-Z0-9]+ { yylval.str = strdup(yytext); return ID; }
3. 修改Yacc规则动作,使用语义值而非yytext
更新所有调用add的动作,传递ID的语义值:
var_int : ID {add("var", "int", $1);} | var_int ',' ID {add("var", "int", $3);} ; lista_int : ID '(' lista_param_int ')' {add("lista", "int", $1);} | ID '(' ')' {add("lista", "int", $1);} | lista_int ',' ID '(' lista_param_int ')' {add("lista", "int", $3);} | lista_int ',' ID '(' ')' {add("lista", "int", $3);} ; lista_param_int : INT ID {add("var", "int", $2);} | lista_param_int ',' INT ID {add("var", "int", $4);} ;
4. 修改add函数,接收变量名参数
更新add函数,直接使用传入的变量名字符串:
void add(char * tip, char * tipDate, char* nume){ symbol_table[contor].nume = nume; symbol_table[contor].tip = tip; symbol_table[contor].tipDate = tipDate; contor++; }
5. 注意内存管理
由于使用了strdup,后续需要在合适的时机(比如符号表销毁时)释放这些字符串,避免内存泄漏。
内容的提问来源于stack exchange,提问作者fabi
相关产品推荐
相关产品推荐

