请问我面临一个简单的问题..这是问题, 在我的lex文件中,我有类似的东西:
char *ptr_String;
"name = " { BEGIN sName; }
<sName>.+ {
ptr_String = (char *)calloc(strlen(yytext)+1, sizeof(char));
strcpy(ptr_String, yytext);
yylval.sValue = ptr_String;
return NAME;
}
现在在我的Yacc文件中,我有类似的内容:
stmt_Name:
NAME
{
/*Now here i need to get the matched string of <sName>.+ and measure it's length. */
/*The aim is simply outputing the name to the screen and storing the length in a global variable.
}
;
请提出任何建议? 非常感谢您的所有时间和帮助。
答案 0 :(得分:5)
Yacc堆栈上的值由YYSTYPE或%union
控制。当类型信息简单时使用YYSTYPE;当它很复杂时使用%union
。
我的一个语法包含:
struct Token
{
int toktype;
char *start;
char *end;
};
typedef struct Token Token;
#define YYSTYPE Token
出于各种原因(不一定是好的),我的语法使用手工制作的词法分析器而不是Lex。
在语法规则中,您将示例中的NAME等项称为$1
(其中实际数字取决于令牌在构成规则的令牌或终端列表中出现的位置)。
例如(相同的语法):
disconnect
: K_DISCONNECT K_CURRENT
{ conn->ctype = CONN_CURRENT; }
| K_DISCONNECT K_ALL
{ conn->ctype = CONN_ALL; }
| K_DISCONNECT K_DEFAULT
{ conn->ctype = CONN_DEFAULT; }
| K_DISCONNECT string
{ conn->ctype = CONN_STRING;
set_connection(conn, $2.start, $2.end);
}
;
和
load
: K_LOAD K_FROM opt_file_pipe string load_opt_list K_INSERT
{
set_string("load file", load->file, sizeof(load->file),
$4.start, $4.end);
load->stmt = $6.start;
}
;
我不知道看到手工制作的yylex()
的轮廓是否有帮助;在语法中,它是与yyparse()
在同一文件中的函数。
static const char *c_token; /* Where to start next token search */
static int yylex(void)
{
char buffer[MAX_LEXTOKENLENGTH];
const char *start;
if (c_token == 0)
abort();
if (bare_filename_ok)
start = scan_for_filename(c_token, &c_token);
else
start = sqltoken(c_token, &c_token);
yylval.start = CONST_CAST(char *, start);
yylval.end = CONST_CAST(char *, c_token);
if (*start == '\0')
{
yylval.toktype = 0;
return yylval.toktype;
}
set_token(buffer, sizeof(buffer), start, c_token);
#ifdef YYDEBUG
if (YYDEBUGVAR > 1)
printf("yylex(): token = %s\n", buffer);
#endif /* YYDEBUG */
/* printf("yylex(): token = %s\n", buffer); */
if (isalpha((unsigned char)buffer[0]) || buffer[0] == '_')
{
Keyword kw;
Keyword *p;
kw.keyword = buffer;
p = (Keyword *)bsearch(&kw, keylist, DIM(keylist), sizeof(Keyword),
kw_compare); /*=C++=*/
if (p == 0)
yylval.toktype = S_IDENTIFIER;
else
yylval.toktype = p->token;
}
else if (buffer[0] == '\'')
{
yylval.toktype = S_SQSTRING;
}
else if (buffer[0] == '"')
{
yylval.toktype = S_DQSTRING;
}
else if (isdigit((unsigned char)buffer[0]))
{
yylval.toktype = S_NUMBER;
}
else if (buffer[0] == '.' && isdigit((unsigned char)buffer[1]))
{
yylval.toktype = S_NUMBER;
}
......识别出各种单字符符号......
else if (buffer[0] == ':')
{
assert(buffer[1] == '\0');
yylval.toktype = C_COLON;
}
else
{
yylval.toktype = S_ERROR;
}
return yylval.toktype;
}
变量通常是一个全局变量 - 您的Yacc代码使用两种可能的声明之一:
extern char *yytext; /* Correct for Flex */
extern char yytext[]; /* Correct for traditional Lex */
其中哪些是正确的取决于您的Lex版本如何定义它。
如果您想添加一个长度(可能是yytextlen
),那么您可以定义这样一个变量并从yylex()
获得每次返回,以确保设置yytextlen
。或者,您可以安排语法拨打wwlex()
,而wwlex()
只需拨打:
int wwlex(void)
{
int rc = yylex();
yytextlen = strlen(yytext);
return rc;
}
或者您可以安排Lex使用重命名生成代码,并让Yacc继续调用yylex()
并将上面的代码提供为yylex()
并让它调用重命名的Lex函数。无论哪种方式都有效。