在其他更具体和无问题的问题中,我有以下词法规则:
[a-zA-Z][a-zA-Z0-9]+ {
yylval.string = strdup(yytext);
return FILENAME;
}
/* 32-bit numbers */
[a-fA-F0-9]{1,8} {
std::stringstream ssh;
ssh << std::hex << yytext;
ssh >> yylval.u32.hex;
std::stringstream ssd;
ssd << std::dec << yytext;
ssd >> yylval.u32.dec;
return NUMBER;
}
“NUMBER”规则已经是一个kludge,因为我无法区分我正在实现的语法中的HEX和DEC基数。十六进制数字没有前缀,它都是基于上下文的。所以在解析器规则中,我只选择我知道需要的结构中的数字。
似乎我需要进一步扩展它。我有一个“文件名”类型,它只是任何字母数字字符串,至少以字母字符开头,后跟任何字母数字(如上所定义)。问题是,像fffff
这样的文件名导致错误的解析。感觉就像我可以解决这个问题的唯一方法就是将NUMBER和FILENAME组合成类似ALPHANUMERIC
的东西,我会做类似的事情:
/* 32-bit numbers, strings, sigh... */
[a-zA-Z0-9]{1,8} {
std::stringstream ssh;
ssh << std::hex << yytext;
ssh >> yylval.alphanumeric.hex;
std::stringstream ssd;
ssd << std::dec << yytext;
ssd >> yylval.alphanumeric.dec;
yylval.alphanumeric.string = strdup(yytext);
return ALPHANUMERIC;
}
然后我会在解析器中有一点聪明并检查初始alpha,并使用正确的struct字段。
这是一种常见的妥协吗?感觉不对,lexing越自由,我敢肯定我会创造一些漏洞,我没有测试它会失败或捕获太多的漏洞。我最终会将“hello”等大量字符串转换为hex
和dec
值。
答案 0 :(得分:1)
通常的方法是对可能发生的不同类别的令牌使用不同的弹性规则,使用A_OR_B标记来处理可能有两种不同的事物:
[0-9]+ {
yylval.u32 = strtol(yytext, 0, 10);
return NUMBER; }
[a-fA-F][a-fA-F0-9]* {
yylval.string = strdup(yytext);
return NUMBER_OR_NAME; }
[a-fA-F0-9]+ {
yylval.u32 = strtol(yytext, 0, 16);
return NUMBER; }
[a-zA-Z][a-zA-Z0-9]* {
yylval.string = strdup(yytext);
return NAME; }
Flex将始终尝试匹配最长匹配,但是当多个模式匹配相同长度时,它将匹配第一个匹配。
在解析器中,您使用以下规则:
name: NAME | NUMBER_OR_NAME ;
number: NUMBER | NUMBER_OR_NAME { $$ = strtol($1, 0, 16); free($1); } ;
答案 1 :(得分:0)
我会选择dec和hex的区分,如hexnumber和decnumber,但纯粹基于上下文,你必须定义一些约束,比如文件名必须使用至少9个字符,因为这不是有效的32位十六进制。