← 都来码← 文档索引COBOL原文English

COBOL

两种书写格式都收(经典固定格式与自由格式,自动判别)。执行模型是 COBOL 的段落与落穿:主流程把每段按顺序 CALL 一遍,PERFORM 就是 CALL。

「完整运算 + 控制流 + 段落 / PERFORM + 库调用」齐备,CALL "ui_2d_clear" USING … 能够到 ui_*。

在手机上怎么跑

vml run examples/cobol/demo/fizzbuzz.cob

编译要等一会儿(C 那种要一两分钟,脚本类语言几秒)。程序跑起来后屏幕底部就是手柄,方向键 + 四个动作键都在;点右上角返回可以回到命令行。

写法要点

示例

文件演示什么
demo/fizzbuzz.cobFizzBuzz(PERFORM VARYING + COMPUTE 取余 + IF)
demo/hello.cob固定格式的最小程序
demo/report.cob小报表(PIC X(n) 定长补空格 + 数值排版 + 累加)

实测踩过的坑


下面的内容是从 VML 源码里直接带的(third_party/vml/VMLPrepares/CobolCompiler/): README 讲这个前端支持什么、怎么编;语言规范 讲语法本身。上游一改,这里重新生成就是最新的。

语言规范

COBOL 子集语言规格

面向写程序的人:本前端收什么写法、那些写法是什么语义、哪些地方会跟标准 COBOL 不一样。实现细节见 README.md,接线见 INTEGRATION.md。

版本:v1(2026-10-13)· 扩展名 .cob(也收 .cbl)· 探针 scripts/vml-cobol-probe/run.sh


版本:v1.0 | 日期:2026-10-13 | 修订者:深圳市探索智能科技有限公司

规范标准

字段值
目标标准COBOL-85 子集
发布年份1985
完成度子集(未逐项统计)
测试28 通过 / 0 失败 / 4 已知红

关键字

ACCEPT ADD ADVANCING AFTER ALL ALTER AND ANY ASCENDING AT BEFORE BINARY BLANK BY CALL CLOSE COMMUNICATION COMP COMP-1 COMP-2 COMP-3 COMP-4 COMPUTE CONTENT CONTINUE CORR CORRESPONDING DATA DELETE DELIMITED DESCENDING DISPLAY DIVIDE DIVISION ELSE END END-ACCEPT END-ADD END-CALL END-COMPUTE END-DISPLAY END-DIVIDE END-EVALUATE END-IF END-MULTIPLY END-PERFORM END-STRING END-SUBTRACT ENTER ENVIRONMENT EQUAL ERROR EVALUATE EXIT EXTERNAL FILE FILLER FROM GIVING GLOBAL GO GOBACK GREATER HIGH-VALUE HIGH-VALUES IDENTIFICATION IF INITIAL INITIALIZE INSPECT INTO INVALID IS JUSTIFIED KEY LESS LINKAGE LOCAL-STORAGE LOW-VALUE LOW-VALUES MERGE MOVE MULTIPLY NEXT NO NOT NULL NULLS OCCURS OF ON OPEN OR OTHER PACKED-DECIMAL PERFORM PIC PICTURE PROCEDURE PROGRAM PROGRAM-ID QUOTE QUOTES READ REDEFINES REFERENCE RELEASE REMAINDER REPORT RETURN RETURNING REWRITE ROUNDED RUN SCREEN SEARCH SECTION SENTENCE SET SIGN SIZE SORT SPACE SPACES START STOP STRING SUBTRACT TEST THAN THEN THROUGH THRU TIMES TO TRUE UNSTRING UNTIL UPON USAGE USING VALUE VALUES VARYING WHEN WITH WORKING-STORAGE WRITE ZERO ZEROES ZEROS

概述

支持 COBOL-85 子集,编译为 VML 汇编代码。源码先经 CobolSourceFormat 把物理行折叠成逻辑行(固定格式的 1–6 列序号区、第 7 列指示符、A 区 / B 区、第 73–80 列按标准丢弃、- 续行,与自由格式,两种自动判别、也可被 >>SOURCE FORMAT IS FREE|FIXED 显式覆盖),再交给词法器;由于 COBOL 的分词不靠标点(MOVE 1 TO X ADD 1 TO Y. 可以连着写),解析器靠「下一个词是不是动词 / 子句词」来判定语句边界,未实现的动词响亮报错、不静默跳过。数值一律 32 位整数,库靠 Lib/cobol/builtin.vml 里的 .linked 自动挂上。

支持的语言特性

本前端接受的语言特性按下方原有章节组织,每节都写明「收什么写法、是什么语义」:

详见下方各节。

1. 两种书写格式

COBOL 有两种源码版式,本前端自动判别、两种都收。

固定格式(经典)
列号  123456|7|8...........11|12.....................72|73..80
含义  序号区 |指示符|  A 区      |        B 区            | 丢弃
自由格式

代码从第 1 列(或缩进几格)开始,按空白分词。注释是 *>。

判别规则(可反证)

扫所有非空行,任意一行的第 1–6 列出现字母 ⇒ 自由格式;否则 ⇒ 固定格式。

理由:固定格式的代码必然在第 8 列以后,1–6 列不会有字母;自由格式必然从第 1 列附近开始。带序号的固定格式(000100 IDENTIFICATION …)1–6 列是数字 ⇒ 仍是固定格式。

强制指定(自动判别猜错时的出口,取文件里第一个出现的):

>>SOURCE FORMAT IS FREE
>>SOURCE FORMAT IS FIXED

2. 程序结构

       IDENTIFICATION DIVISION.
       PROGRAM-ID. 名字.
       DATA DIVISION.
       WORKING-STORAGE SECTION.
       01 数据名 PIC 图象.      *> 数据项
       77 独立项 PIC 图象.
       PROCEDURE DIVISION.
       段落名.                    *> 段落("名字." 单独一行)
           语句…
           STOP RUN.

3. 数据项与 PIC

       01 WS-N    PIC 9(3).            *> 3 位整数
       01 WS-NAME PIC X(10).           *> 10 个字符(定长)
       01 WS-AMT  PIC S9(5)V99.        *> 带符号 + 隐含小数(见第 7 节)
       01 WS-CNT  PIC 9(3) VALUE 0.    *> 带初值

图象串支持:9(数字)、X/A(字符)、S(符号)、V(隐含小数位)、Z/*(编辑位)以及重复次数 (n);其余编辑符号(B / , + - $)认得出但不改变长度语义。

数值项是 4 字节整数;字符项是定长缓冲,初值按 COBOL 惯例补空格到 n。 VALUE 的初值也照此处理:01 S PIC X(5) VALUE "AB". 打印出来是 AB (5 格)。

4. 语句

赋值与算术
           MOVE 5 TO WS-N.
           MOVE "AB" TO WS-NAME.          *> 短串补空格到定长
           MOVE WS-N TO WS-NAME.          *> 数值 → 字符(转成文字)
           MOVE WS-NAME TO WS-N.          *> 字符 → 数值(解析回整数)
           COMPUTE WS-N = (A + B) * 2.    *> 支持 + - * / ** 与括号、优先级
           ADD 5 TO WS-N.                 *> WS-N = WS-N + 5
           ADD 3 5 TO WS-N.               *> WS-N = WS-N + 3 + 5
           ADD 5 TO WS-N GIVING WS-M.     *> WS-M = WS-N + 5(WS-N 不变)
           SUBTRACT 3 FROM WS-N.          *> WS-N = WS-N - 3
           MULTIPLY 2 BY WS-N.            *> WS-N = WS-N * 2
           DIVIDE 2 INTO WS-N.            *> WS-N = WS-N / 2(整除)
           DIVIDE 7 BY 3 GIVING WS-M.     *> WS-M = 7 / 3 = 2

有 GIVING 时目标只被写入;没有 GIVING 时目标自身参与运算 —— 这条是 COBOL 的原义,别记反。

输出
           DISPLAY "TOTAL=" WS-N.        *> 逐项连着打,末尾换行
           DISPLAY "X" WITH NO ADVANCING.  *> 不换行

DISPLAY 的各个操作数之间不加空格(COBOL 就是这样,要空格就自己写进字面量)。

条件
           IF A > B THEN DISPLAY "BIG" ELSE DISPLAY "SMALL" END-IF.
           IF A = 1 THEN DISPLAY "ONE".        *> 句点收尾(老式写法)也认

关系运算符两种写法都收:= < > <= >= <>,以及 IS [NOT] EQUAL TO / IS GREATER THAN / IS LESS THAN。条件可以 AND / OR / NOT 组合、可加括号。裸操作数当条件(IF FLAG)按"非 0 即真"处理。

分支
           EVALUATE K
               WHEN 1   DISPLAY "ONE"
               WHEN 3   DISPLAY "THREE"
               WHEN OTHER DISPLAY "OTHER"
           END-EVALUATE.
循环与段落调用
           PERFORM 段落.                                   *> 调用一次,到段落末尾返回
           PERFORM A THRU B.                               *> 跑 A…B 之间每一段
           PERFORM 段落 UNTIL WS-I > 10.                    *> 先测后做(COBOL 默认)
           PERFORM 段落 VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 10.
           PERFORM 3 TIMES … END-PERFORM.                   *> 行内块,跑 3 次

⚠ 循环变量结束时是"最后一次的值 + 一步"(UNTIL WS-I > 5 跑完 1..5 之后 WS-I = 6)—— 这是 COBOL 的定义(先加步长再判条件),不是缺陷。

段落与"落穿"

COBOL 的段落是顺次执行的:从第一段开始,一段完了接着下一段,除非 STOP RUN / GOBACK / PERFORM 让控制流离开。

       PROCEDURE DIVISION.
       P1.
           ADD 1 TO N.
       P2.
           ADD 10 TO N.          *> 不写 PERFORM,主流程也会从 P1 落到这里
           STOP RUN.

PERFORM P 则只跑 P、跑完就返回(不会落穿到 P 的下一段)。

字符串拼接
           STRING "HELLO" DELIMITED BY SIZE "WORLD" DELIMITED BY SIZE INTO WS-S.

DELIMITED BY 后面写什么目前都按 SIZE(整段)处理 —— BY SPACE 那种"遇空格截断"还没做。

调库(CALL)
           CALL "abs" USING -9 GIVING WS-R.        *> math 库
           CALL "strlen" USING WS-NAME GIVING WS-R.  *> string 库
           CALL "ui_2d_clear" USING WS-COLOR.       *> 宿主绘图接口

CALL "名字" USING a b 就是把实参按顺序递给那个库函数(VML 的 __stdcall 约定),返回值(若有)在 GIVING 那一项里。这是 COBOL 够到 ui_* / tty_* / 全部共享库的门。 默认自动挂上的库见 Lib/cobol/builtin.vml(含 vmlui / tty / vml3d)。

输入
           ACCEPT WS-N.        *> 数值项:读一个整数
           ACCEPT WS-NAME.     *> 字符项:读一行
结束

STOP RUN.(结束程序)/ GOBACK. / EXIT. / CONTINUE.(空语句)。段落里也能用 STOP RUN —— 从 PERFORM 里进来的一样会真正结束进程。

5. 注释

位置写法
固定格式整行第 7 列写 * 或 /
固定格式调试行第 7 列写 D/d(当注释)
行内(两种格式)*> 起,到行尾为止
自由格式整行行首(任意缩进)写 *>

⚠ 字符串字面量里的 *> 是正文,不是注释(DISPLAY "A*>B" 打的是 A*>B)。

6. 数字与取整

7. 已知限制(与标准 COBOL 的差异)

限制表现判据
定标小数(V)不做换算PIC 9(2)V99 只当整数用;COMPUTE P = 10 / 4 得 2(标准 COBOL 得 2.50)bugs/vml_cobol_bugs/cb01
OCCURS 表不支持T(1) 与 T(2) 打到同一个格子(有警告),数组语义全无cb02
MOVE CORRESPONDING 不支持编译期报错(不猜)cb03
STRING … DELIMITED BY SPACE/字面量一律按 SIZE(整段)处理cb04
COPY 不展开认得出库名,但不真把副本插进来—
文件 I/O / 排序 / 检查OPEN/READ/WRITE/CLOSE/SORT/SEARCH/INSPECT/UNSTRING 编译期报"还不支持"—
COMP-3 打包十进制认得出子句,但按普通整数存—
SECTION 的段级 PERFORMSECTION 头当段落头处理;PERFORM 段名 只跑段内第一段—
ACCEPT … FROM 环境名FROM 后面整段被忽略(只从标准输入读)—

这些都在 bugs/vml_cobol_bugs/COBOL问题清单.md 里逐条登记(含复现与实测数字)。

8. 完整的可运行例子

third_party/vml/Examples/cobol/demo/:

文件演示
hello.cob固定格式的最小程序
fizzbuzz.cobPERFORM VARYING + 嵌套 IF + 取余
report.cob定长字符项补空格 + 数值排版 + 累加

编译器 README

COBOL 编译器(子集)

路径:third_party/vml/VMLPrepares/CobolCompiler/ 扩展名:.cob(也收 .cbl) 语言库:Lib/cobol/(builtin.vml) 完成度:能写一般程序(完整运算 + 控制流 + 函数调用 + 段落/PERFORM + 库调用) 探针:scripts/vml-cobol-probe/run.sh —— 通过 28 / 失败 0 / 已知红 4(2026-10-13 实测;28 = 27 条语言判据 + 1 条载体判据)


一、这个前端收什么

能力支持情况
固定格式(1–6 列序号区 / 7 列指示符 / 8–72 列代码)✅ 自动判别,见下
自由格式(第 1 列起写代码)✅ 自动判别;>>SOURCE FORMAT IS FREE/FIXED 可强制
第 7 列 * / 整行注释、D 调试行✅
第 7 列 - 续行✅(字符串字面量可以断在续行上)
行内注释 *>✅(引号内的 *> 不算)
第 73–80 列按标准丢弃✅
IDENTIFICATION / DATA / PROCEDURE DIVISION✅
WORKING-STORAGE SECTION / 77 级独立项✅
PIC:9 X A S V Z * + 重复 (n)✅ 解析;V 的定标只记账(见「已知限制」)
VALUE 初值(数值/字符串/表意常量)✅
MOVE(数值↔数值 / 字符→数值 / 数值→字符,字符项按 COBOL 语义补空格)✅
COMPUTE dst = expr(+ - * / ** 与括号、优先级)✅
ADD / SUBTRACT / MULTIPLY / DIVIDE(含 GIVING)✅
DISPLAY(多项、WITH NO ADVANCING、UPON)✅
IF … THEN … ELSE … END-IF / 句点收尾两种写法✅
EVALUATE … WHEN … WHEN OTHER … END-EVALUATE(含 EVALUATE TRUE)✅
PERFORM 段 / PERFORM A THRU B✅
PERFORM 段 UNTIL 条件(先测后做,COBOL 默认)✅
PERFORM 段 VARYING i FROM a BY b UNTIL c(可嵌套)✅
PERFORM n TIMES … END-PERFORM(行内块)✅
STRING … DELIMITED BY SIZE … INTO …✅
CALL "名字" USING … GIVING …(够到 ui_* / tty_* / 共享库)✅
ACCEPT(数值项走 input_int、字符项走 gets)✅
STOP RUN / GOBACK / EXIT / CONTINUE / NEXT SENTENCE✅
段落顺次执行(落穿) —— COBOL 的执行模型✅
段落里直接 STOP RUN(从 PERFORM 里也能真正结束进程)✅

尚未支持(每条都在 bugs/vml_cobol_bugs/ 有对应判据,见 COBOL问题清单.md):定标小数(V)的算术、OCCURS 表、MOVE CORRESPONDING、COPY 展开、 STRING … DELIMITED BY SPACE/字面量、文件 I/O(OPEN/READ/WRITE)、 COMP-3 打包十进制、SORT/SEARCH/INSPECT/UNSTRING、SECTION 的段级 PERFORM 语义。


二、两个格式怎么判

SourceFormat.cs 里的规则(纯函数,探针直接压):

扫一遍非空物理行,只要有一行的第 1–6 列出现了字母 ⇒ 自由格式;否则 ⇒ 固定格式。

判错的出口:文件里写 >>SOURCE FORMAT IS FREE / >>SOURCE FORMAT IS FIXED(取第一个出现的)。

三、执行模型(COBOL 段落语义,逐条对应)

main:  CALL 段1 ; CALL 段2 ; … ; 退出       ← 这就是 COBOL 的"顺次执行/落穿"
段i:   序言 ; 语句… ; 尾声(RET)              ← 每个段落都是一段带返回的子程序
PERFORM P          ⇒ CALL P
PERFORM A THRU B   ⇒ CALL A ; CALL B         ← 区间内每一段都跑,区间外的不跑

这套映射是精确的,不是近似:COBOL 里"落穿"与"PERFORM 会返回"本来是一对矛盾,用「主流程把每段 CALL 一遍 + 每段各自 RET」正好同时表达出来(判据:20-fallthrough.cob 压落穿、17-perform-thru.cob 压 THRU 的区间边界)。

四、数据与调用约定

五、构建与运行

开发期 csproj 是 Exe(发行时改回 Library,见 INTEGRATION.md):

# 端到端跑一个用例(内联标准库,产物可被 vmlcli 直接汇编运行)
dotnet run --project third_party/vml/VMLPrepares/CobolCompiler -- prog.cob -o prog.vml

# 看词法器真正读到了什么(固定格式列裁剪 / PIC 图象串现形用)
dotnet run --project third_party/vml/VMLPrepares/CobolCompiler -- --tokens prog.cob

# 把标准库**内联**进产物(开发期探针用;见 run.sh 的说明)
dotnet run --project third_party/vml/VMLPrepares/CobolCompiler -- --inline prog.cob -o prog.vml

# 判据
scripts/vml-cobol-probe/run.sh

六、文件

文件作用
SourceFormat.cs物理行 → 逻辑行(固定/自由判别、列裁剪、续行、行内注释)—— 纯函数
Lexer.cs记号化(含 PIC 图象串的整体读取)
Parser.cs语法 → AST(子句词/动词两张表管"一句话到哪儿结束")
CodeGenerator.csAST → VML
CobolCompiler.cs / CobolPlugin.cs / Program.cs三条对外入口 / 插件 / CLI
COBOL_LANGUAGE_SPEC.md语言子集规格(给用户看的:能写什么、写出来是什么语义)
INTEGRATION.md接线清单(哪个文件加哪一行)