修改后的问题
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);
}
;
And:
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 函数。无论哪种方式都有效。