如何仅用(f)lex分词含连续单引号的单引号包裹字符串?
仅用Flex处理单引号包裹且内部重复单引号转义的字符串分词
完全可以只靠Flex完成这类字符串的分词,不用把拆分的片段传给Bison组装。核心思路是利用Flex的起始状态隔离字符串扫描逻辑,再通过动作代码直接处理内部重复的单引号,输出完整的字符串字面量token。
具体实现示例
首先定义排他性起始状态(进入该状态后仅执行对应前缀的规则):
%x STRING
然后编写扫描规则:
/* 匹配字符串起始单引号,进入STRING状态并开始累积字符 */ ' { BEGIN(STRING); yymore(); } /* 在STRING状态内的规则 */ <STRING>'{2} { /* 遇到两个连续单引号,直接累积(后续统一替换成单个) */ yymore(); } <STRING>[^']+ { /* 匹配非单引号的字符串内容,直接累积 */ yymore(); } <STRING>' { /* 遇到单个单引号,说明字符串结束,回到初始状态 */ BEGIN(INITIAL); /* 处理字符串内容:去掉首尾单引号,将内部''替换为' */ int input_len = yyleng; // 估算结果长度:最多比原长度少 (input_len-2)/2(每两个单引号减一个) char *processed_str = malloc(input_len); if (!processed_str) { /* 内存分配失败处理 */ exit(1); } int src_idx = 1, dest_idx = 0; // 跳过开头的单引号,遍历到结尾的单引号前 while (src_idx < input_len - 1) { if (yytext[src_idx] == '\'' && yytext[src_idx+1] == '\'') { processed_str[dest_idx++] = '\''; src_idx += 2; } else { processed_str[dest_idx++] = yytext[src_idx++]; } } processed_str[dest_idx] = '\0'; // 将处理后的字符串绑定到语义值,返回字符串token yylval.str = processed_str; return STRING_LITERAL; } /* 处理未闭合的字符串错误 */ <STRING>\n { fprintf(stderr, "错误:第%d行字符串未闭合\n", yylineno); BEGIN(INITIAL); }
关键逻辑说明
yymore():让Flex把当前匹配到的字符追加到yytext中,而不是重置,这样整个从起始'到结束'的所有字符会被一次性收集。- 字符串处理动作:在扫描到结束'后,手动遍历
yytext,跳过首尾的单引号,遇到连续两个'就替换成单个,最终生成符合要求的字符串内容。 - 排他性起始状态
%x STRING:确保进入字符串扫描状态后,不会误触发其他规则,避免干扰。
注意事项
- 内存管理:示例中用
malloc分配了processed_str,后续需要在Bison或者业务代码中释放,避免内存泄漏。 - 跨行字符串:如果你的语言允许字符串跨行,可以移除
<STRING>\n的错误规则,或者根据需求调整换行处理逻辑。
内容的提问来源于stack exchange,提问作者DYZ
相关产品推荐
相关产品推荐

