Bison/Flex语法问题:YAML枚举结构解析错误求助
问题分析与修复方案
首先先明确你的核心问题:当前语法完全忽略了YAML的缩进层级,把所有- Name: xxx都当成了上一个枚举的value_list元素,根本没区分开根枚举和子项的缩进差异——下一个根枚举的- Name和上一个枚举的Values子项缩进层级完全不同,本该触发新的枚举声明,却被误判成了子项。
下面是具体的修复步骤:
1. 先修改Flex,保留缩进信息
YAML的缩进是结构的核心,你之前直接跳过空格等于丢失了最关键的结构标记。调整Flex规则,把缩进、换行转成可识别的Token:
%% "-" { return TKN_DASH; } "Name:" { return TKN_NAME; } "Values:" { return TKN_VALUE; } \n { return TKN_NEWLINE; } ^[ \t]+ { yylval.integer = strlen(yytext); // 记录当前行的缩进长度 return TKN_INDENT; } ^[^ \t\n] { yyless(0); // 把行首非缩进字符放回流中,交给后续规则处理 return TKN_NON_INDENT_LINE_START; } // 保留原有规则 [0-9]+ { yylval.integer = atoi(yytext); return TKN_INTEGER; } "/*" { RemoveComment(); } [a-zA-Z0-9]*[a-zA-Z][_a-zA-Z0-9]* { strcpy(yylval.string, yytext); return TKN_IDENTIFIER; } [ \t] { /* 非行首的空格直接跳过 */ } ; %%
2. 调整Bison语法,加入层级控制
需要在Bison里维护当前缩进层级,通过缩进长度判断是新的根枚举还是上一个枚举的子项:
%{ #include <string.h> #define MAX_ENUMS 10 #define MAX_VALS_PER_ENUM 10 typedef struct { char enum_val[MAX_VALS_PER_ENUM][64]; } EnumVals; char enums_tbl[MAX_ENUMS][64]; EnumVals enum_vals[MAX_ENUMS]; int enums_cnt = 0; int vals_cnt = 0; int current_indent = 0; // 当前所在的缩进层级 %} %token TKN_DASH TKN_NAME TKN_VALUE TKN_INTEGER TKN_IDENTIFIER %token TKN_NEWLINE TKN_INDENT TKN_NON_INDENT_LINE_START %union { int integer; char string[64]; } %% prog: enum_list ; // 支持多个根枚举连续声明 enum_list: | enum_list enum_decl ; // 单个根枚举的完整结构:包含Name、Values块和对应的子项 enum_decl: TKN_DASH TKN_NAME TKN_IDENTIFIER TKN_NEWLINE TKN_INDENT TKN_VALUE TKN_NEWLINE TKN_INDENT value_list { strcpy(enums_tbl[enums_cnt++], $3); vals_cnt = 0; current_indent = 0; // 回到根层级,准备处理下一个枚举 } ; // Values下的子项列表,只会匹配缩进层级更高的项 value_list: value_list TKN_DASH TKN_NAME TKN_IDENTIFIER TKN_NEWLINE { strcpy(enum_vals[enums_cnt-1].enum_val[vals_cnt++], $4); } | TKN_DASH TKN_NAME TKN_IDENTIFIER TKN_NEWLINE { strcpy(enum_vals[enums_cnt-1].enum_val[vals_cnt++], $3); } ; %%
关键逻辑说明
- 缩进识别:通过
TKN_INDENT记录每行的缩进长度,根枚举的- Name缩进为0,其Values子项缩进更大,下一个根枚举的- Name又回到0级缩进,Bison就能通过这个差异区分开是新枚举还是子项。 - 语法结构明确化:把
prog改成支持多个枚举的列表,每个enum_decl明确包含Values块的缩进层级,确保value_list只会匹配Values下的子项,不会误吞下一个根枚举的内容。 - 层级重置:处理完一个枚举的子项后,把当前缩进层级重置为0,保证下一个根枚举的判断准确。
内容的提问来源于stack exchange,提问作者Max
相关产品推荐
相关产品推荐

