如何在编译器项目中优雅放置大常量矩阵以提升可读性?
优化编译器预计算表可读性的几种方案
针对你遇到的13×13算符分析表可读性差的问题,这里有几个实用的优化方向:
方案一:用枚举+指定初始化器(C99及以上)
先把所有行/列对应的符号定义成枚举,然后用指定初始化器明确每个元素对应的列,不用靠注释和位置对应,代码逻辑一目了然:
// 定义所有Token类型,对应矩阵的行和列索引 typedef enum { TOKEN_PLUS, // + TOKEN_MINUS, // - TOKEN_MUL, // * TOKEN_DIV, // / TOKEN_EQ, // == TOKEN_REL, // <,>,<=,... TOKEN_LOGIC, // and/or TOKEN_NOT, // ! TOKEN_LPAREN, // ( TOKEN_RPAREN, // ) TOKEN_INT, // i(整数) TOKEN_BOOL, // b(布尔) TOKEN_EOF, // $(结束符) TOKEN_COUNT // 用于校验矩阵大小,避免越界 } TokenType; // 预计算值的常量定义(根据你的实际需求替换) #define PREC_LT 0 // 左移/优先级低 #define PREC_EQ 1 // 相等/同级 #define PREC_GT 2 // 右移/优先级高 // 用枚举索引定义表,每个元素明确对应列 const Table_contents_T precedence_table[TOKEN_COUNT][TOKEN_COUNT] = { // 行:+ { [TOKEN_PLUS] = PREC_EQ, [TOKEN_MINUS] = PREC_EQ, [TOKEN_MUL] = PREC_LT, [TOKEN_DIV] = PREC_LT, [TOKEN_EQ] = PREC_LT, [TOKEN_REL] = PREC_LT, [TOKEN_LOGIC] = PREC_LT, [TOKEN_NOT] = PREC_LT, [TOKEN_LPAREN] = PREC_LT, [TOKEN_RPAREN] = PREC_GT, [TOKEN_INT] = PREC_GT, [TOKEN_BOOL] = PREC_GT, [TOKEN_EOF] = PREC_GT }, // 行:- { [TOKEN_PLUS] = PREC_EQ, [TOKEN_MINUS] = PREC_EQ, [TOKEN_MUL] = PREC_LT, [TOKEN_DIV] = PREC_LT, [TOKEN_EQ] = PREC_LT, [TOKEN_REL] = PREC_LT, [TOKEN_LOGIC] = PREC_LT, [TOKEN_NOT] = PREC_LT, [TOKEN_LPAREN] = PREC_LT, [TOKEN_RPAREN] = PREC_GT, [TOKEN_INT] = PREC_GT, [TOKEN_BOOL] = PREC_GT, [TOKEN_EOF] = PREC_GT }, // 剩余行按照同样格式补充即可 };
这种方式的好处是:不用数元素位置,修改某个元素时直接找对应的枚举名,注释也可以大幅简化,同时枚举定义能统一所有符号的索引,避免手动计数出错。
方案二:统一排版对齐(兼容旧C标准)
如果不能用C99的指定初始化器,就把每个元素单独占一行,对齐注释,让每行的对应关系清晰可见:
// 预计算值常量定义 #define PREC_LT 0 #define PREC_EQ 1 #define PREC_GT 2 const Table_contents_T precedence_table[13][13] = { // + 行:对应列 → + - * / == <>=... and/or ! ( ) i b $ { PREC_EQ, // + vs + PREC_EQ, // + vs - PREC_LT, // + vs * PREC_LT, // + vs / PREC_LT, // + vs == PREC_LT, // + vs <>=... PREC_LT, // + vs and/or PREC_LT, // + vs ! PREC_LT, // + vs ( PREC_GT, // + vs ) PREC_GT, // + vs i PREC_GT, // + vs b PREC_GT // + vs $ }, // - 行 { PREC_EQ, // - vs + PREC_EQ, // - vs - PREC_LT, // - vs * PREC_LT, // - vs / PREC_LT, // - vs == PREC_LT, // - vs <>=... PREC_LT, // - vs and/or PREC_LT, // - vs ! PREC_LT, // - vs ( PREC_GT, // - vs ) PREC_GT, // - vs i PREC_GT, // - vs b PREC_GT // - vs $ }, // 剩余行按同样格式补充 };
这种方式通过统一的换行和注释对齐,解决了原代码中换行混乱、注释错位的问题,查看和修改时能快速定位到对应位置。
方案三:脚本生成代码(适合大型/频繁修改的表)
如果这个表需要频繁调整,或者后续可能扩展,建议用脚本生成C代码:
- 把表格数据整理成CSV格式(天然的表格结构,可读性极强):
,+,-,*,/,==,<>=...,and/or,!,(,),i,b,$ +,EQ,EQ,LT,LT,LT,LT,LT,LT,LT,GT,GT,GT,GT -,EQ,EQ,LT,LT,LT,LT,LT,LT,LT,GT,GT,GT,GT *,GT,GT,EQ,EQ,LT,LT,LT,LT,LT,GT,GT,GT,GT /,GT,GT,EQ,EQ,LT,LT,LT,LT,LT,GT,GT,GT,GT ==,GT,GT,GT,GT,EQ,EQ,LT,LT,LT,GT,GT,GT,GT <>=...,GT,GT,GT,GT,EQ,EQ,LT,LT,LT,GT,GT,GT,GT and/or,GT,GT,GT,GT,GT,GT,EQ,LT,LT,GT,GT,GT,GT !,LT,LT,LT,LT,LT,LT,LT,EQ,LT,GT,GT,GT,GT (,LT,LT,LT,LT,LT,LT,LT,LT,LT,EQ,LT,LT,LT ),GT,GT,GT,GT,GT,GT,GT,GT,XX,GT,GT,GT,GT i,GT,GT,GT,GT,GT,GT,GT,GT,XX,GT,XX,XX,GT b,GT,GT,GT,GT,GT,GT,GT,GT,XX,GT,XX,XX,GT $,LT,LT,LT,LT,LT,LT,LT,LT,LT,LT,LT,LT,XX
- 写一个简单的Python脚本读取CSV,生成对应的C代码:
import csv # 预计算值映射 PREC_MAP = { "LT": "PREC_LT", "EQ": "PREC_EQ", "GT": "PREC_GT", "XX": "0" # 占位符,根据实际情况替换 } with open("precedence_table.csv", "r") as f: reader = csv.reader(f) headers = next(reader) rows = list(reader) # 生成C代码 print("// 自动生成的算符优先级表,请勿手动修改") print("const Table_contents_T precedence_table[13][13] = {") for row in rows: token = row[0] print(f" // {token} 行") print(" {") for col_idx, val in enumerate(row[1:]): col_token = headers[col_idx+1] print(f" {PREC_MAP[val]}, // {token} vs {col_token}") print(" },") print("};")
运行脚本就能得到格式规范的C代码,后续修改表格只需要调整CSV文件,完全避免手动修改代码时的错误。
内容的提问来源于stack exchange,提问作者Matyáš Ott
相关产品推荐
相关产品推荐

