请问我面临一个简单的问题..这是问题,在我的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;
}
Run Code Online (Sandbox Code Playgroud)
现在在我的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.
}
;
Run Code Online (Sandbox Code Playgroud)
请问有什么建议?非常感谢您的所有时间和帮助.
Yacc堆栈上的值由YYSTYPE或%union
.当类型信息简单时使用YYSTYPE; 使用%union
时很复杂.
我的一个语法包含:
struct Token
{
int toktype;
char *start;
char *end;
};
typedef struct Token Token;
#define YYSTYPE Token
Run Code Online (Sandbox Code Playgroud)
由于各种原因(不一定是好的),我的语法使用手工制作的词法分析器而不是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);
}
;
Run Code Online (Sandbox Code Playgroud)
和:
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;
}
;
Run Code Online (Sandbox Code Playgroud)
我不知道看到手工制作的轮廓是否有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;
}
Run Code Online (Sandbox Code Playgroud)
...识别出各种单字符符号......
else if (buffer[0] == ':')
{
assert(buffer[1] == '\0');
yylval.toktype = C_COLON;
}
else
{
yylval.toktype = S_ERROR;
}
return yylval.toktype;
}
Run Code Online (Sandbox Code Playgroud)
该变量通常是一个全局变量 - 您的Yacc代码使用两种可能的声明之一:
extern char *yytext; /* Correct for Flex */
extern char yytext[]; /* Correct for traditional Lex */
Run Code Online (Sandbox Code Playgroud)
其中哪些是正确的取决于您的Lex版本如何定义它.
如果你想添加一个长度(也许yytextlen
),那么你可以定义这样一个变量并从yylex()
确保yytextlen
设置的每个返回.或者,你可以安排你的语法来打电话wwlex()
,你wwlex()
只需:
int wwlex(void)
{
int rc = yylex();
yytextlen = strlen(yytext);
return rc;
}
Run Code Online (Sandbox Code Playgroud)
或者您可以安排Lex生成具有重命名的代码,并让Yacc继续调用yylex()
并提供上面的代码,yylex()
并让它调用重命名的Lex函数.无论哪种方式都有效.