You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 05:37:18