487 lines
17 KiB
Markdown
487 lines
17 KiB
Markdown
# COBOL Test Data Generator — 环境搭建与运行指南
|
||
|
||
## 1. 系统概述
|
||
|
||
COBOL 测试数据生成器(cobol-java-v3)是一个 Python 工具链,用于解析 COBOL 程序、提取控制流结构、生成覆盖所有分支的测试数据,并输出为固定的 flat file 格式供 GnuCOBOL 编译运行。
|
||
|
||
系统支持两条平行的测试管道:**非 DB 管道**(flat file I-O 程序 → cobc 编译运行 → 二进制比对)和 **DB 管道**(EXEC SQL 程序 → gixpp ESQL 预处理 → cobc + libgixsql 编译运行 → SQLite 表比对),自动根据源码中是否包含 `EXEC SQL` 路由到对应管道。
|
||
|
||
### 核心能力
|
||
|
||
| 能力 | 说明 |
|
||
|------|------|
|
||
| 解析 COBOL DATA DIVISION | Lark 语法 (Earley parser) → 字段定义 |
|
||
| 解析 COBOL PROCEDURE DIVISION | 行级状态机 → 决策点树 + EXEC SQL 抽取 |
|
||
| 分支覆盖数据生成 | 每决策点生成 True/False 路径 → 记录 |
|
||
| Flat file + SQLite DB 双输出 | 非 DB 程序→二进制 flat file;DB 程序→flat file + SQLite 表行 |
|
||
| GnuCOBOL 编译运行 (非 DB) | 测试数据 → `cobc` 编译 → 运行 → 二进制比对 |
|
||
| gixsql 编译运行 (DB) | `gixpp` ESQL 预处理 → `cobc -l gixsql` 编译 → SQLite 运行 → 表比对 |
|
||
| 覆盖率报告 (gcov) | `--gcov` 模式下编译带 `-g --coverage`,合并后生成 HTML 报告 |
|
||
|
||
---
|
||
|
||
## 2. 必要条件
|
||
|
||
### 2.1 硬件要求
|
||
|
||
| 项目 | 最低 | 推荐 |
|
||
|------|------|------|
|
||
| CPU | 2 cores | 4+ cores |
|
||
| 内存 | 4 GB | 8 GB |
|
||
| 磁盘 | 500 MB | 2 GB |
|
||
| OS | Windows 10/11 64-bit | Windows 11 |
|
||
|
||
### 2.2 软件要求
|
||
|
||
| 软件 | 版本 | 用途 |
|
||
|------|------|------|
|
||
| **Python** | 3.12+ | 运行测试数据生成器 |
|
||
| **GnuCOBOL (cobc)** | 3.2.0 (GC32-BDB-SP1) | 编译 COBOL 程序 & 运行时验证(DB 管道需要含 SQLite 支持的版本) |
|
||
| **gixsql** | 已 vendored (`gixsql/`) | ESQL 预处理器 (`gixpp.exe`) + 运行时 DLL (`libgixsql.dll`),DB 管道必备 |
|
||
| **Git** | 任意 | 拉取代码 |
|
||
|
||
### 2.3 Python 依赖
|
||
|
||
```
|
||
lark>=1.1.0 # Lark Earley parser (DATA DIVISION 解析)
|
||
pathlib>=1.0.1 # 路径处理
|
||
pyyaml>=6.0 # YAML 配置加载(DB 管道:per-program schema)
|
||
```
|
||
|
||
安装命令:
|
||
```bash
|
||
pip install lark pathlib pyyaml
|
||
```
|
||
|
||
### 2.4 GnuCOBOL 安装
|
||
|
||
GnuCOBOL 3.2.0 (OpenCOBOL) 需要单独安装。
|
||
|
||
**下载**:
|
||
- GnuCOBOL 3.2 Windows 二进制包
|
||
- 推荐: GC32-BDB-SP1 版本(含 DB2/SQLite 支持)
|
||
|
||
**安装后确认**:
|
||
```bash
|
||
cobc --version
|
||
# 输出示例: cobc (GnuCOBOL) 3.2.0
|
||
```
|
||
|
||
**环境变量**:
|
||
```bash
|
||
# cobc 需要在 PATH 中
|
||
# 典型路径: C:\GnuCOBOL\bin
|
||
# 或自定义安装路径
|
||
|
||
# COB_LIBRARY_PATH — 运行时 DLL 搜索路径
|
||
# 非 DB 管道:子程序 DLL 目录(如 cobol-tna-system\bin)
|
||
# DB 管道:必须包含 gixsql\lib\(libgixsql.dll, libgcc_s_dw2-1.dll 等)
|
||
# 如: set COB_LIBRARY_PATH=D:\cobol-java\cobol-java-v3\gixsql\lib
|
||
|
||
# GIXSQL_DB_PATH — DB 管道 SQLite 数据库路径(默认 C:\Temp\gix\)
|
||
# 如: set GIXSQL_DB_PATH=C:\Temp\gix
|
||
```
|
||
|
||
---
|
||
|
||
## 3. 环境搭建步骤
|
||
|
||
### 3.1 安装 Python 3.12+
|
||
|
||
```bash
|
||
# 下载: https://www.python.org/downloads/
|
||
# 安装时勾选 "Add Python to PATH"
|
||
python --version
|
||
# Python 3.12.x
|
||
|
||
pip install lark pathlib pyyaml
|
||
```
|
||
|
||
### 3.2 安装 GnuCOBOL 3.2
|
||
|
||
1. 下载 GC32-BDB-SP1 包
|
||
2. 解压到 `D:\360安全浏览器下载\GC32-BDB-SP1-rename-7z-to-exe\`
|
||
3. 将 `bin\` 子目录添加到系统 PATH
|
||
4. 验证:
|
||
```bash
|
||
cobc --version
|
||
# cobc (GnuCOBOL) 3.2.0
|
||
```
|
||
|
||
### 3.3 克隆代码
|
||
|
||
```bash
|
||
cd D:\
|
||
git clone https://gittea.dev/hangshuo652/cobol-java-v3.git
|
||
# 或从已有仓库拉取
|
||
cd D:\cobol-java\cobol-java-v3
|
||
git pull
|
||
```
|
||
|
||
### 3.4 验证安装
|
||
|
||
```bash
|
||
cd D:\cobol-java\cobol-java-v3
|
||
python -c "from cobol_testgen import extract_structure; print('OK')"
|
||
# 输出: OK
|
||
```
|
||
|
||
---
|
||
|
||
## 4. 目录结构
|
||
|
||
```
|
||
cobol-java-v3/
|
||
├── cobol_testgen/ # 核心代码
|
||
│ ├── __init__.py # 公开 API (extract_structure, generate_data) + DB 自动路由
|
||
│ ├── read.py # 预处理器 + DATA DIVISION 解析 + EXEC SQL INCLUDE 解决
|
||
│ ├── core.py # 旧 PROCEDURE DIVISION 解析器 + EXEC SQL 抽取
|
||
│ ├── cond.py # 条件解析器
|
||
│ ├── coverage.py # 覆盖率统计 (+ gcov HTML 报告)
|
||
│ ├── design_mcdc.py # 线性路径枚举 (O(N) 替代 O(2^N))
|
||
│ ├── pipeline_bridge.py # 新旧解析器桥接层
|
||
│ ├── procedure_parser.py # 新 PROCEDURE DIVISION 解析器
|
||
│ ├── flatfile.py # Flat file 写入器
|
||
│ ├── design.py # 值生成 + 约束应用
|
||
│ ├── to_sql.py # SQL 约束解析 + DB 行生成 (DB 管道)
|
||
│ ├── models.py # 数据模型 (BrSeq, BrIf, BrEval...)
|
||
│ ├── grammar.lark # DATA DIVISION Lark 语法
|
||
│ └── procedure_grammar.lark # PROCEDURE DIVISION Lark 语法 (实验性)
|
||
├── orchestrator_db.py # DB 6 步管道编排 (GixsqlOrchestrator)
|
||
├── runners/ # 编译运行引擎
|
||
│ ├── cobol_runner.py # 标准 GnuCOBOL runner(非 DB)
|
||
│ ├── gixsql_runner.py # gixpp + cobc runner(DB)
|
||
│ ├── native_java_runner.py # 原生 Java runner
|
||
│ ├── spark_java_runner.py # Spark Java runner
|
||
│ ├── data_writer.py # 测试数据写入器
|
||
│ └── runner.py # 基类
|
||
├── config/
|
||
│ ├── program_schema.py # DB 程序 schema 加载器
|
||
│ └── programs/ # per-program YAML 配置(6 个 DB 程序)
|
||
│ ├── KIN02UPD.yaml
|
||
│ ├── KIN03EXP.yaml
|
||
│ ├── KIN06CLD.yaml
|
||
│ ├── KIN08DBU.yaml
|
||
│ ├── KIN09CSV.yaml
|
||
│ └── ZAN06UPD.yaml
|
||
├── gixsql/ # 已 vendored ESQL 工具链
|
||
│ ├── bin/gixpp.exe # ESQL 预处理器
|
||
│ └── lib/*.dll # 运行时 (libgixsql, libgixsql-sqlite, libgcc 等)
|
||
├── test-data/ # 测试套件
|
||
│ ├── s15_coverage_verification.py # 基础覆盖率验证 (8种控制结构)
|
||
│ ├── s19_final_bridge_test.py # 桥接器验证
|
||
│ ├── s21_cond_fix_verify.py # 条件解析验证
|
||
│ ├── s25_per_program_report.py # 每程序详细报告
|
||
│ ├── s26_regression_check.py # 回归检查
|
||
│ └── s30_db_e2e.py # DB 端到端测试 (ZAN06UPD)
|
||
├── diagnose_db2.py # DB 全流程诊断脚本
|
||
├── diagnose_kind8dbrun.py # DB 单步诊断 (仅编译运行)
|
||
├── SETUP.md # 本文件
|
||
└── docs/ # 设计文档
|
||
└── runtime/ # 运行产物(测试数据、输入文件、覆盖率报告,已 gitignore)
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 运行测试
|
||
|
||
### 5.1 快速验证(10 秒)
|
||
|
||
```bash
|
||
cd D:\cobol-java\cobol-java-v3
|
||
python test-data/s15_coverage_verification.py
|
||
```
|
||
|
||
期望输出:
|
||
```
|
||
S15: 17 PASS / 0 FAIL
|
||
```
|
||
|
||
### 5.2 完整 43 程序覆盖率报告(2-3 分钟)
|
||
|
||
```bash
|
||
python test-data/s25_per_program_report.py
|
||
```
|
||
|
||
期望输出末尾:
|
||
```
|
||
100%: 43 programs
|
||
TOTAL 3178 3178 100%
|
||
```
|
||
|
||
### 5.3 回归快速检查(2 分钟)
|
||
|
||
```bash
|
||
python test-data/s26_regression_check.py
|
||
```
|
||
|
||
期望输出:
|
||
```
|
||
Total: 3178/3178 = 100.00%
|
||
ALL 43/43 AT 100% — NO REGRESSIONS
|
||
```
|
||
|
||
### 5.4 指定 COPYBOOK 目录
|
||
|
||
如果 COBOL 程序依赖 COPYBOOK,需要在调用 `generate_data` 时指定 `copybook_dirs`:
|
||
|
||
```python
|
||
from cobol_testgen import extract_structure, generate_data
|
||
|
||
src = open("program.cbl", encoding="utf-8").read()
|
||
st = extract_structure(src)
|
||
recs = generate_data(src, st, copybook_dirs=["path/to/copybooks"])
|
||
```
|
||
|
||
### 5.5 DB 端到端测试(5 分钟)
|
||
|
||
DB 管道需要使用 `cobol-tna-system` 同级项目中的 DB 程序(含 `EXEC SQL` 的 COBOL 源码):
|
||
|
||
```bash
|
||
# 1. 确认同级目录存在 cobol-tna-system
|
||
dir ..\cobol-tna-system
|
||
|
||
# 2. 设置环境变量
|
||
set COB_LIBRARY_PATH=<proj_dir>\gixsql\lib
|
||
mkdir C:\Temp\gix 2>nul
|
||
set GIXSQL_DB_PATH=C:\Temp\gix
|
||
|
||
# 3. 运行 DB 端到端测试 (ZAN06UPD - 6 步管线: 编译→生成数据→运行→提取→Java→比对)
|
||
python test-data\s30_db_e2e.py
|
||
```
|
||
|
||
期望输出末尾:
|
||
```
|
||
COVERAGE: DB pipeline E2E PASSED
|
||
```
|
||
|
||
### 5.6 DB 单程序运行
|
||
|
||
```bash
|
||
# 自动路由: 源码含 EXEC SQL → DB 管道,否则走非 DB 管道
|
||
python -m cobol_testgen ..\cobol-tna-system\src\ZAN06UPD.cbl
|
||
|
||
# 带 gcov 覆盖率收集 (编译带 -g --coverage,生成 HTML 报告)
|
||
python -m cobol_testgen --gcov ..\cobol-tna-system\src\KIN08DBU.cbl runtime\
|
||
```
|
||
|
||
DB 管道会自动加载 `config/programs/<PROGRAM_ID>.yaml` 中的表定义、子程序列表、运行场景(normal/collision/abnormal),多场景运行的 gcov 覆盖率会被合并输出。
|
||
|
||
---
|
||
|
||
## 6. 关键 API
|
||
|
||
### 6.1 extract_structure(cobol_source)
|
||
|
||
**输入**: COBOL 程序源码文本
|
||
**返回**: dict — 包含总分支数、决策点列表、分支树对象等
|
||
|
||
```python
|
||
st = extract_structure(src)
|
||
branches = st["total_branches"] # 总分支数
|
||
dps = st["decision_points"] # 决策点列表
|
||
tree = st["branch_tree_obj"] # 分支树对象
|
||
```
|
||
|
||
### 6.2 generate_data(cobol_source, structure, copybook_dirs=None)
|
||
|
||
**输入**:
|
||
- `cobol_source`: COBOL 程序原始源码(未预处理)
|
||
- `structure`: extract_structure 返回的 dict
|
||
- `copybook_dirs`: COPYBOOK 搜索路径列表(可选)
|
||
|
||
**返回**: list[dict] — 每条记录包含所有字段的值
|
||
|
||
```python
|
||
recs = generate_data(src, st)
|
||
# 或带 COPYBOOK 目录
|
||
recs = generate_data(src, st, copybook_dirs=["./cpy", "../common/copybooks"])
|
||
```
|
||
|
||
### 6.3 覆盖率数据
|
||
|
||
`generate_data` 执行后,`structure` 对象包含 `coverage` 键:
|
||
|
||
```python
|
||
cov = st["coverage"]
|
||
total = cov["total"] # 总分支数
|
||
covered = cov["covered"] # 覆盖分支数
|
||
pct = cov["pct"] # 覆盖率百分比
|
||
dps = cov["decision_points"] # 各决策点明细
|
||
```
|
||
|
||
---
|
||
|
||
## 7. DB 管道概述
|
||
|
||
系统包含两条平行管道,根据 COBOL 源码是否包含 `EXEC SQL` 自动路由:
|
||
|
||
| 方面 | 非 DB 管道 | DB 管道 |
|
||
|------|------------|---------|
|
||
| **入口** | `main.py` → `orchestrator.py` | Python CLI 自动检测 `EXEC SQL` → `orchestrator_db.py: GixsqlOrchestrator` |
|
||
| **编译器** | `cobc -E` + 标准编译 | `gixpp.exe` (ESQL 预处理) + `cobc -l gixsql` |
|
||
| **运行时** | 平面二进制文件 (I-O) | SQLite DB (EXEC SQL) + 平面文件 (顺序 I-O) |
|
||
| **数据生成** | 分支覆盖记录集 | 分支覆盖记录集 + SQLite 表行 (按 WHERE 约束生成) |
|
||
| **程序配置** | 无 | `config/programs/<ID>.yaml` (表定义、子程序、场景) |
|
||
| **验证** | 二进制平面文件比对 | SQLite 表行比对 + Java 中间 JSON (W01.json) |
|
||
| **覆盖率** | 静态分支覆盖 | 动态 gcov 覆盖率 (跨场景合并) |
|
||
| **Java 集成** | Native Java / Spark Java | Java 读取中间 JSON |
|
||
|
||
### 7.1 DB 管道 6 步流程
|
||
|
||
| 步骤 | 方法 | 说明 |
|
||
|------|------|------|
|
||
| **1** | `step1_setup_environment` | gixpp ESQL 预处理 → cobc 编译(链接 libgixsql),避免中文路径问题 |
|
||
| **2** | `step2_generate_inputs` | 解析 COBOL → 分支覆盖数据 + SQLite 表行(含正/异常场景) |
|
||
| **3** | `step3_run_cobol` | 运行编译后 .exe(GIXSQL_DB_PATH 环境变量),收集 gcov |
|
||
| **4** | `step4_extract_intermediate` | 读取 SQLite 表 → 中间 JSON(W01.json,供 Java 消费) |
|
||
| **5** | `step5_run_java` | 执行 Java JAR,以中间 JSON 为输入 |
|
||
| **6** | `step6_verify` | Java 输出 vs COBOL 预期值比对 |
|
||
|
||
### 7.2 前置条件
|
||
|
||
- **`cobol-tna-system` 同级项目**: DB 程序源码需位于 `../cobol-tna-system/src/`(或通过 `config/programs/*.yaml` 配置路径)
|
||
- **`config/programs/<PROGRAM_ID>.yaml`**: 每个 DB 程序必须有对应的 YAML schema,定义:
|
||
- `db_tables`: 表名、列类型、主键
|
||
- `subprograms`: 子程序列表(编译时链接)
|
||
- `runs`: 运行场景(normal / collision / abnormal),每种场景可配置不同的 sysin 和预期输出
|
||
- **`C:\Temp\gix\`**: SQLite 数据库存放目录(由 `GIXSQL_DB_PATH` 指定)
|
||
- **`COB_LIBRARY_PATH`**: 必须包含 `gixsql/lib/`(运行时载入 `libgixsql.dll`)
|
||
|
||
---
|
||
|
||
## 8. 运行条件明细(同事配置检查清单)
|
||
|
||
### 必须满足
|
||
|
||
- [ ] Python 3.12+ 已安装,在 PATH 中
|
||
- [ ] `pip install lark` 执行成功
|
||
- [ ] GnuCOBOL (cobc) 3.2.0 已安装,在 PATH 中
|
||
- [ ] `cobc --version` 输出正常
|
||
- [ ] 无防火墙阻止 `gittea.dev` 的 git 访问
|
||
- [ ] `D:\` 盘有至少 500MB 空闲
|
||
|
||
### 如果使用 GnuCOBOL 编译运行
|
||
|
||
- [ ] `cobc` 命令可用(`which cobc` 或 `where cobc`)
|
||
- [ ] 子程序 DLL 路径在 `COB_LIBRARY_PATH` 环境中
|
||
- [ ] EXEC SQL 需要 SQLite3 支持(GC32-BDB-SP1 版本含)
|
||
|
||
### DB 管道额外检查
|
||
|
||
- [ ] `gixsql/bin/gixpp.exe` 存在(vendored ESQL 预处理器)
|
||
- [ ] `COB_LIBRARY_PATH` 包含 `<proj>/gixsql/lib/`(运行时 DLL)
|
||
- [ ] `GIXSQL_DB_PATH` 已设置(如 `C:\Temp\gix`),目录存在
|
||
- [ ] `config/programs/<ID>.yaml` 存在(per-program schema)
|
||
- [ ] `../cobol-tna-system/` 同级目录存在(DB 程序源码)
|
||
- [ ] `pip install pyyaml` 执行成功
|
||
|
||
### 常见问题
|
||
|
||
| 问题 | 原因 | 解决 |
|
||
|------|------|------|
|
||
| `ModuleNotFoundError: No module named 'lark'` | 缺少 Lark | `pip install lark` |
|
||
| `cobc: command not found` | GnuCOBOL 不在 PATH | 添加 `bin\` 到 PATH |
|
||
| `Errno 13 Permission denied` | 文件权限 | 以管理员运行或修改文件权限 |
|
||
| `gbk codec can't decode byte` | 编码问题 | 设置 `PYTHONIOENCODING=utf-8` |
|
||
| `name 'pp_str' is not defined` | 报告脚本 Bug | 已修复,git pull 最新代码 |
|
||
| `EXEC SQL ... not supported` | 需要 DB2/SQLite | 用 GC32-BDB-SP1 版本 GnuCOBOL |
|
||
| `gixpp: command not found` | gixsql/bin 不在 PATH | `$env:PATH += ";<proj>\\gixsql\\bin"` |
|
||
| `Cannot load libgixsql.dll` | COB_LIBRARY_PATH 未设置 | `$env:COB_LIBRARY_PATH = "<proj>\\gixsql\\lib"` |
|
||
| `GIXSQL_DB_PATH not set` | SQLite 路径未指定 | `mkdir C:\Temp\gix -Force; $env:GIXSQL_DB_PATH = "C:\Temp\gix"` |
|
||
| `config/programs/<ID>.yaml not found` | DB 程序缺少 schema | 补充对应 YAML 配置文件 |
|
||
|
||
---
|
||
|
||
## 9. 测试基准程序说明
|
||
|
||
系统包含两套测试基准程序:
|
||
|
||
### 电信计费系统 (37 程序)
|
||
|
||
```
|
||
路径: D:\cobol-java\cobol-test-programs/
|
||
COPYBOOK: common/copybooks/
|
||
类型: Matching / KeyBreak / Division / CSV / Sort 等
|
||
```
|
||
|
||
### 勤怠管理系统 (22 程序)
|
||
|
||
```
|
||
路径: D:\cobol-java\cobol-tna-system/
|
||
COPYBOOK: cpy/
|
||
子程序: sub/*.cbl → bin/*.dll
|
||
类型: 日企勤怠管理 (打工统计)
|
||
DB 程序 (EXEC SQL): KIN02UPD, KIN03EXP, KIN06CLD, KIN08DBU, KIN09CSV, ZAN06UPD — 共 6 个
|
||
非 DB 程序: KIN01INP, KIN04CHK, KIN05MAT, KIN07DAI, ZAN01CHK–ZAN05CAL, KYU01CVT–KYU09MRG — 共 16 个
|
||
```
|
||
|
||
---
|
||
|
||
## 10. 快速启动脚本
|
||
|
||
### Windows (batch)
|
||
|
||
```batch
|
||
@echo off
|
||
cd /d D:\cobol-java\cobol-java-v3
|
||
echo === COBOL Test Data Generator ===
|
||
echo [1/3] Checking dependencies...
|
||
python -c "import lark" 2>nul || pip install lark
|
||
echo [2/3] Running regression test...
|
||
python test-data\s15_coverage_verification.py
|
||
if %errorlevel% neq 0 echo FAILED && exit /b 1
|
||
echo [3/3] Running full coverage report...
|
||
set PYTHONIOENCODING=utf-8
|
||
python test-data\s25_per_program_report.py
|
||
echo === DONE ===
|
||
```
|
||
|
||
### Linux/macOS
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
cd /path/to/cobol-java-v3
|
||
echo "=== COBOL Test Data Generator ==="
|
||
echo "[1/3] Checking dependencies..."
|
||
python3 -c "import lark" 2>/dev/null || pip3 install lark
|
||
echo "[2/3] Running regression test..."
|
||
python3 test-data/s15_coverage_verification.py
|
||
if [ $? -ne 0 ]; then echo "FAILED"; exit 1; fi
|
||
echo "[3/3] Running full coverage report..."
|
||
PYTHONIOENCODING=utf-8 python3 test-data/s25_per_program_report.py
|
||
echo "=== DONE ==="
|
||
```
|
||
|
||
---
|
||
|
||
## 11. 版本信息
|
||
|
||
| 版本 | 日期 | 说明 |
|
||
|:----:|:----:|------|
|
||
| v3.0 | 2026-06-25 | 当前版本。43/43 程序 100% 分支覆盖 |
|
||
| v2.0 | 2026-06-20 | 新 PROCEDURE DIVISION 解析器 + 线性路径枚举 |
|
||
| v1.0 | 2026-06-14 | 初始版本,BrParser regex 解析器 |
|
||
|
||
---
|
||
|
||
## 附录:覆盖率数据验证方法
|
||
|
||
系统使用三层验证确保覆盖率数据真实:
|
||
|
||
1. **S15 测试**: 8 个手动构建的 COBOL 片段,每个决策点的手工分支数与系统检测数逐一对比
|
||
2. **所有约束通过 _match_constraint 精确匹配**:约束侧和解析侧的字段名都会去掉下标后再比较
|
||
3. **无条件 fallback 已全部移除**:没有 "任何路径到达就标记全部" 的逻辑
|
||
|
||
```python
|
||
# coverage.py 中 _mark_if 的真实覆盖逻辑(无 fallback):
|
||
def _mark_if(dp, cons):
|
||
# 只有约束侧字段名 == 解析侧字段名时标记覆盖
|
||
# 加了防御性下标剥离
|
||
if _match_constraint(c, simple):
|
||
dp.active_branches.add('T' if c[3] else 'F')
|
||
elif _match_constraint(c, inv_simple):
|
||
dp.active_branches.add('F')
|
||
# 没有任何 else + unconditional add
|
||
```
|