保留十六进制数字,以及仅包含A-F的文本

时间:2013-12-07 22:52:53

标签: bison flex-lexer

在其他更具体和无问题的问题中,我有以下词法规则:

[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”等大量字符串转换为hexdec值。

2 个答案:

答案 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位十六进制。