为 Bison 使用字符串 return 值的正确方法是什么?
What is the proper way to use string return value for Bison?
从构成 Bison 找到的规则的一个或多个标记中获取结果字符串的正确方法是什么?
timer:
TILDE amount {
printf("Timer: Amount:%s\n", );
$$ = ;
}
| TILDE WORD amount {
printf("Timer: %s Amount:%s\n",, );
// make timer string
$$ = malloc(strlen() + strlen() + 10);
sprintf($$, "%s %s", , );
free();
free();
}
| TILDE MULTIWORD amount {
printf("Timer: %s Amount:%s\n",, );
// make timer string
$$ = malloc(strlen() + strlen() + 10);
sprintf($$, "%s %s", , );
free();
}
;
time、amount、WORD都是string类型,MULTIWORD也是。
例如,如果第一个规则匹配,意味着有一个波浪线“~”和一个数量,通常是字符串格式的数字,如“3”,那么获取结果值的最佳方式是什么,即'timer' 是否只有金额的值?
如果第二条规则匹配,我将如何将 WORD 和金额添加到一个字符串中并将它们放入 $$ 值中。
我在 Bison 文档中找不到任何关于此的内容。
编辑:忘记提及问题。打印出来的字符串不仅仅是我想要传递的内容。例如,金额定义为:
amount:
// an empty amount - for one word timers
LCURL RCURL {
$$ = malloc(5);
$$[0] = ' ';
$$[1] = '[=12=]';
}
| LCURL NUMBER RCURL {
// get string for amount
$$ = malloc(100);
sprintf($$, "%.3lf", );
}
| LCURL NUMBER UNIT RCURL {
// get string for amount
// remove % from unit
$$ = malloc(100 + strlen() + 5);
sprintf($$, "%.3lf %s", , );
}
| LCURL WORD RCURL {
$$ = ;
}
| LCURL WORD UNIT RCURL {
$$ = malloc(strlen() + strlen() + 5);
sprintf($$, "%s%s", , );
}
| LCURL MULTIWORD RCURL {
$$ = ;
}
| LCURL MULTIWORD UNIT RCURL {
$$ = malloc(strlen() + strlen() + 5);
sprintf($$, "%s%s", , );
}
;
当我将 $2 放入字符串中时,它还会在其后面包含 RCURL。这会导致大量随机字符串和不正确的解析。
完整的词法分析器文件:
%{
#include "Cooklang.tab.h"
#include <stdlib.h>
void showError();
%}
SYMB_CHAR "$"|"="|"+"|"-"|"_"|"*"|"`"
PUNC_CHAR "!"|"?"|","|"."|"/"|"&"|"("|")"|":"
NEW_LINE "\n"
WHITE_SPACE " "|"\t"
ALPHA_CHAR [a-zA-Z]
COOKLANG_CHAR ">"|"|"|"~"|"@"|"#"|":"|"{"|"}"|"%"
ZERO "0"
NON_ZERO_DIGIT [0-9]
DIGIT ({ZERO}|{NON_ZERO_DIGIT}){WHITE_SPACE}*
INTEGER ({ZERO}|({NON_ZERO_DIGIT}{DIGIT}*)){WHITE_SPACE}*
DECIMAL {INTEGER}"."{INTEGER}{WHITE_SPACE}*
FRACTIONAL {INTEGER}{WHITE_SPACE}*"/"{WHITE_SPACE}*{INTEGER}{WHITE_SPACE}*
WORD ({ALPHA_CHAR}|{DIGIT}|{SYMB_CHAR})+{WHITE_SPACE}*
HWORD "#"{WORD}
ATWORD "@"{WORD}
MULTIWORD {WORD}{2,}
UNIT "%"{WHITE_SPACE}*({MULTIWORD}*|{PUNC_CHAR}*)?
%%
[ \t]
"{" {return LCURL;}
"}" {return RCURL;}
"~" {return TILDE;}
{ATWORD} { yytext++;
yylval.string = yytext;
return ATWORD;
}
{HWORD} { yytext++;
yylval.string = yytext;
return HWORD;
}
{UNIT} { yytext++;
yylval.string = yytext;
return UNIT;}
{DIGIT} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{INTEGER} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{DECIMAL} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{FRACTIONAL} { char * tok = strtok(yytext, "/");
double first = strtod(tok, NULL);
tok = strtok(NULL, "/");
double second = strtod(tok, NULL);
double final = first/second;
yylval.number = final;
return NUMBER;}
{WORD} { yylval.string = yytext;
return WORD;
}
{MULTIWORD} { yylval.string = yytext;
return MULTIWORD;
}
{PUNC_CHAR} { yylval.character = yytext[0];
printf("char: |%c|", yytext[0]);
return PUNC_CHAR; }
{NEW_LINE} {return NL;}
%%
int main( int argc, char ** argv ){
++argv;
--argc;
if( argc > 0 ){
yyin = fopen(argv[0], "r");
} else {
yyin = stdin;
}
yyparse();
yylex();
printf("\n");
return 0;
}
此词法分析器操作不正确:
yylval.string = yytext; /* NEVER do this */
yytext
是指向词法分析器拥有的临时存储缓冲区的指针。它的内容仅在下一次调用词法分析器之前有效;在那之后,指针可能不再有效(如果缓冲区被重新分配)或者内容将发生变化。
所以你必须复制yytext
指向的字符串,如果你需要它比词法分析器动作更持久(如果你想传递字符串,你当然需要到解析器)。
如果你有strdup
(或包含一个实现),你可以只使用yylval.string = strdup(yytext)
,或者你可以自己动态分配存储;如果您选择后一种解决方案,请记住 yyleng
包含文本的长度,因此不需要 strlen
:
/* +1 for the null terminator */
yylval.string = malloc(yyleng + 1);
/* should check for allocation failure */
memcpy(yylval.string, yytext, yyleng + 1);
当您不再需要时,请不要忘记free()
副本。
从构成 Bison 找到的规则的一个或多个标记中获取结果字符串的正确方法是什么?
timer:
TILDE amount {
printf("Timer: Amount:%s\n", );
$$ = ;
}
| TILDE WORD amount {
printf("Timer: %s Amount:%s\n",, );
// make timer string
$$ = malloc(strlen() + strlen() + 10);
sprintf($$, "%s %s", , );
free();
free();
}
| TILDE MULTIWORD amount {
printf("Timer: %s Amount:%s\n",, );
// make timer string
$$ = malloc(strlen() + strlen() + 10);
sprintf($$, "%s %s", , );
free();
}
;
time、amount、WORD都是string类型,MULTIWORD也是。
例如,如果第一个规则匹配,意味着有一个波浪线“~”和一个数量,通常是字符串格式的数字,如“3”,那么获取结果值的最佳方式是什么,即'timer' 是否只有金额的值?
如果第二条规则匹配,我将如何将 WORD 和金额添加到一个字符串中并将它们放入 $$ 值中。 我在 Bison 文档中找不到任何关于此的内容。
编辑:忘记提及问题。打印出来的字符串不仅仅是我想要传递的内容。例如,金额定义为:
amount:
// an empty amount - for one word timers
LCURL RCURL {
$$ = malloc(5);
$$[0] = ' ';
$$[1] = '[=12=]';
}
| LCURL NUMBER RCURL {
// get string for amount
$$ = malloc(100);
sprintf($$, "%.3lf", );
}
| LCURL NUMBER UNIT RCURL {
// get string for amount
// remove % from unit
$$ = malloc(100 + strlen() + 5);
sprintf($$, "%.3lf %s", , );
}
| LCURL WORD RCURL {
$$ = ;
}
| LCURL WORD UNIT RCURL {
$$ = malloc(strlen() + strlen() + 5);
sprintf($$, "%s%s", , );
}
| LCURL MULTIWORD RCURL {
$$ = ;
}
| LCURL MULTIWORD UNIT RCURL {
$$ = malloc(strlen() + strlen() + 5);
sprintf($$, "%s%s", , );
}
;
当我将 $2 放入字符串中时,它还会在其后面包含 RCURL。这会导致大量随机字符串和不正确的解析。
完整的词法分析器文件:
%{
#include "Cooklang.tab.h"
#include <stdlib.h>
void showError();
%}
SYMB_CHAR "$"|"="|"+"|"-"|"_"|"*"|"`"
PUNC_CHAR "!"|"?"|","|"."|"/"|"&"|"("|")"|":"
NEW_LINE "\n"
WHITE_SPACE " "|"\t"
ALPHA_CHAR [a-zA-Z]
COOKLANG_CHAR ">"|"|"|"~"|"@"|"#"|":"|"{"|"}"|"%"
ZERO "0"
NON_ZERO_DIGIT [0-9]
DIGIT ({ZERO}|{NON_ZERO_DIGIT}){WHITE_SPACE}*
INTEGER ({ZERO}|({NON_ZERO_DIGIT}{DIGIT}*)){WHITE_SPACE}*
DECIMAL {INTEGER}"."{INTEGER}{WHITE_SPACE}*
FRACTIONAL {INTEGER}{WHITE_SPACE}*"/"{WHITE_SPACE}*{INTEGER}{WHITE_SPACE}*
WORD ({ALPHA_CHAR}|{DIGIT}|{SYMB_CHAR})+{WHITE_SPACE}*
HWORD "#"{WORD}
ATWORD "@"{WORD}
MULTIWORD {WORD}{2,}
UNIT "%"{WHITE_SPACE}*({MULTIWORD}*|{PUNC_CHAR}*)?
%%
[ \t]
"{" {return LCURL;}
"}" {return RCURL;}
"~" {return TILDE;}
{ATWORD} { yytext++;
yylval.string = yytext;
return ATWORD;
}
{HWORD} { yytext++;
yylval.string = yytext;
return HWORD;
}
{UNIT} { yytext++;
yylval.string = yytext;
return UNIT;}
{DIGIT} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{INTEGER} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{DECIMAL} { yylval.number = strtod(yytext, NULL); return NUMBER;}
{FRACTIONAL} { char * tok = strtok(yytext, "/");
double first = strtod(tok, NULL);
tok = strtok(NULL, "/");
double second = strtod(tok, NULL);
double final = first/second;
yylval.number = final;
return NUMBER;}
{WORD} { yylval.string = yytext;
return WORD;
}
{MULTIWORD} { yylval.string = yytext;
return MULTIWORD;
}
{PUNC_CHAR} { yylval.character = yytext[0];
printf("char: |%c|", yytext[0]);
return PUNC_CHAR; }
{NEW_LINE} {return NL;}
%%
int main( int argc, char ** argv ){
++argv;
--argc;
if( argc > 0 ){
yyin = fopen(argv[0], "r");
} else {
yyin = stdin;
}
yyparse();
yylex();
printf("\n");
return 0;
}
此词法分析器操作不正确:
yylval.string = yytext; /* NEVER do this */
yytext
是指向词法分析器拥有的临时存储缓冲区的指针。它的内容仅在下一次调用词法分析器之前有效;在那之后,指针可能不再有效(如果缓冲区被重新分配)或者内容将发生变化。
所以你必须复制yytext
指向的字符串,如果你需要它比词法分析器动作更持久(如果你想传递字符串,你当然需要到解析器)。
如果你有strdup
(或包含一个实现),你可以只使用yylval.string = strdup(yytext)
,或者你可以自己动态分配存储;如果您选择后一种解决方案,请记住 yyleng
包含文本的长度,因此不需要 strlen
:
/* +1 for the null terminator */
yylval.string = malloc(yyleng + 1);
/* should check for allocation failure */
memcpy(yylval.string, yytext, yyleng + 1);
当您不再需要时,请不要忘记free()
副本。