news 2026/9/24 5:34:12

基于 ANTLR4 的 Intel 8086 汇编语法解析实战:asm8086 文法与 CP/M-86 源码解析指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
基于 ANTLR4 的 Intel 8086 汇编语法解析实战:asm8086 文法与 CP/M-86 源码解析指南
  • 编程语言
  • 编译器
  • 开发工具

【免费下载链接】grammars-v4

Grammars written for ANTLR v4; expectation that the grammars are free of actions.

项目地址:https://gitcode.com/gh_mirrors/gr/grammars-v4
点击查看免费下载

导读

本文以 grammars-v4 仓库中的 asm/asm8086/README.md 及其核心文法文件 asm8086.g4 为主体,系统讲解如何用 ANTLR4 为 Intel 8086 汇编语言建立词法与语法模型,并以 CP/M-86 官方源码(BIOS、CBIOS、TRACK 等.A86文件)作为真实解析目标。读完本文,你将掌握该文法的整体结构、行级语法、汇编伪指令、表达式体系、寄存器与指令助记符覆盖范围、词法规则要点,以及如何在本仓库环境中对其实例源码执行构建与测试,为后续基于解析树实现反汇编、静态分析或源码检索工具打下基础。

一、项目背景与文法定位

Intel 8086 是 x86 指令集的开端,其汇编语言既被当年 CP/M-86、早期 DOS 系统广泛使用,也是理解现代 x86 工具链的重要历史标本。该仓库将这套汇编语法沉淀为一个无 action 的纯 ANTLR4 文法(符合 grammars-v4 仓库"期望文法不包含 action"的整体规范),存放于 asm/asm8086/。

目录核心文件如下:

  • asm8086.g4:词法 + 语法合一的 ANTLR4 文法(1112 行),覆盖 CP/M-86 汇编器所使用的 8086 指令集与汇编伪指令;
  • README.md:文法用途与来源说明;
  • examples/:9 个真实 CP/M-86 汇编源文件,作为解析与测试样例;
  • pom.xml:Maven 构建与自动测试配置;
  • desc.xml:文法元信息(ANTLR 版本要求与目标语言)。

从文法创建目的看,该文法是为解析 CP/M 操作系统源码而设计(见 asm/asm8086/README.md),其语法形态因此带有明显的 8086 时代汇编器风格:使用ORG/EQU/DB/DW/CSEG/DSEG/RB/RW/RS等传统伪指令,支持IF/ENDIF条件汇编,并允许一行内用!分隔多条指令。在仓库体系中,它隶属于 asm/ 聚合模块,与 asm6502、asm8080、asmZ80、nasm、masm 等汇编文法并列(见 asm/pom.xml),可作为"同一种 x86/其他处理器汇编文法横向对比"的参考实现。

二、文法总体骨架:prog → line

文法入口与行结构非常简洁,见 asm8086.g4:

grammar asm8086; options { caseInsensitive = true; } prog : line* EOF ; line : lbl? (assemblerdirective | instruction)? ('!' instruction)* EOL ; instruction : rep? opcode expressionlist? ;

三个要点:

  1. caseInsensitive = true(asm8086.g4):整个文法大小写不敏感,因此MOVmovMov均可被识别。这是 8086 汇编历史惯例的体现——传统汇编器普遍不区分大小写;
  2. prog由若干line组成并以EOF收尾,解析入口即prog
  3. line是基本单元:可选标签(lbl?)+ 可选的汇编伪指令或指令((assemblerdirective | instruction)?)+ 可选的!后续指令序列 + 行结束符EOL

三、行级语法:标签、指令与!多语句分隔符

3.1 标签(lbl)

lbl : label COLON? ;

标签可以带冒号也可以不带(COLON?),这贴合 8086 时代汇编器的习惯:init:old_disk:与裸标签均合法。在 examples/TRACK.A86 中可以看到大量此类用法,例如:

init: call clear_flags ; Initialize track buffering . . . jmp CCP_entry

3.2 一行内的多条指令:!分隔

line规则中的('!' instruction)*是这套 8086 汇编风格最鲜明的特征:允许用!在同一行书写多条指令。例如 examples/TRACK.A86 中:

old_disk: mov bl,cpm_disk ! mov bh,0 mov dl,4 ! shl bx,dl ; times 16

以及:

mov bx,ds ! mov es,bx ; destination is our data segment mov cx,host_spt ! cld ; set length and direction

这种写法用于节省行数、提高列表文件密度,是 CP/M 汇编源码的常见风格,文法对此做了专门支持。

3.3 指令(instruction)

instruction : rep? opcode expressionlist? ;
  • 可选的前缀rep(REP/REPE/REPNE/REPNZ/REPZ,见 asm8086.g4)用于串操作指令;
  • 后接opcode与可选的expressionlist(逗号分隔的表达式列表,见 asm8086.g4),例如mov si,offset track_bufferdiv cx

四、汇编伪指令(Assembler Directives)全解

assemblerdirective规则(asm8086.g4)收录了 CP/M 汇编器的核心伪指令,逐一拆解如下:

伪指令文法规则语义示例(取自 examples)
ORGORG expression设置后续代码/数据的起始地址bios_code equ 2500h(配合 EQU)
ENDEND标记汇编结束源码末尾
EQUname EQU expression符号常量定义host_sectsiz equ 1024
DB/DW/DDDB/DW/DD expressionlist定义字节 / 字 / 双字数据bdos_int equ 224(配合 EQU 定义)
RB/RW/RSname? RB/RW/RS expression保留字节 / 字 / 字符串存储区cpm_disk rb 1cpm_track rw 1
CSEG/DSEGCSEG/DSEG expression?声明代码段 / 数据段dseg
IF/ENDIFIF assemblerexpression/ENDIF条件汇编IF not loader_bios...ENDIF
TITLETITLE string_设置列表文件标题title '8086 Disk I/O Drivers'
INCLUDEINCLUDE name包含另一个源文件INCLUDE equates.inc
.DOT当前地址 / 其它点号起始的伪指令列表输出中常见

4.1 存储区保留指令 RB / RW / RS

RBRWRS是这套文法相对独特的伪指令(对应 CP/M 汇编器的 "Reserve Byte / Word / String"),其表达式可以是任意算术表达式。在 examples/TRACK.A86 的数据段末尾,它们被用来按需动态计算缓冲区大小:

dseg cpm_disk rb 1 cpm_track rw 1 cpm_sec rw 1 dma_offset rw 1 dma_segment rw 1 dma_longword equ dword ptr dma_offset ... sec_flags rb host_spt ; bit 0 of each byte on indicates ; corresponding host sector has been ; updated and needs writing. track_buffer rb host_sectsiz * host_spt

注意track_buffer rb host_sectsiz * host_sptrb的表达式可以引用前面EQU定义的符号并做乘法运算,这要求表达式解析必须支持完整的算术求值(见下一节)。

4.2 条件汇编 IF / ENDIF

IF后面接的是专门的条件汇编表达式:

if_ : IF assemblerexpression ; assemblerexpression : assemblerterm (assemblerlogical assemblerterm)* | RP assemblerexpression LP ; assemblerlogical : EQ | NE ; assemblerterm : name | number | NOT assemblerterm ;

IF表达式支持EQ/NE比较、NOT取反以及括号分组。例如 examples/BIOS.A86 中的典型写法:

IF not loader_bios ;--------------------------------------------- bios_code equ 2500h ccp_offset equ 0000h bdos_ofst equ 0B06h ;BDOS entry point ;--------------------------------------------- ENDIF ;not loader_bios IF loader_bios ;--------------------------------------------- bios_code equ 1200h ;start of LDBIOS ccp_offset equ 0003h ;base of CPMLOADER bdos_ofst equ 0406h ;stripped BDOS entry ;--------------------------------------------- ENDIF ;loader_bios

以及 examples/TRACK.A86 中基于常量判断的:

if (host_fsn ne 0) sub ax,host_fsn ; correct if we start with sector one endif

五、表达式系统:从算术运算到寻址模式

表达式的递归结构定义在 asm8086.g4:

expression : multiplyingExpression (sign multiplyingExpression)* ; multiplyingExpression : argument ((STAR | SLASH | MOD | AND) argument)* ; argument : number | dollar | register_ | name | string_ | RP expression LP | (number | name)? LB expression RB_ | ptr expression | NOT expression | OFFSET expression | LENGTH expression | register_ COLON expression ; ptr : (BYTE | WORD | DWORD)? PTR ;

5.1 运算符优先级

  • 优先级最低的是加减(sign,即+/-);
  • 更高一层是乘除与模/位与:*/MODAND
  • 一元运算NOTOFFSETLENGTH作用在表达式上;
  • 括号( ... )可任意嵌套。

例如 examples/TRACK.A86 中的mov dl,4 ! shl bx,dl ; times 16以及add si,axmov cx,host_sectsiz等,均落在上述表达式的覆盖范围内。

5.2 特殊操作数

argument覆盖了 8086 汇编中最常见的操作数形态:

  • number:立即数(词法细节见第七节);
  • dollar$,即当前位置计数器(asm8086.g4);
  • register_:寄存器直接寻址;
  • name:符号(标号或变量名);
  • string_:单引号字符串(如title '8086 Disk I/O Drivers');
  • (number | name)? LB expression RB_带基址/变址的存储器寻址,例如sec_flags[BX]mov bl,[BX]
  • ptr expression类型强制转换,如dword ptr dma_offset(examples/TRACK.A86),支持BYTE/WORD/DWORD三种前缀;
  • OFFSET expression:取偏移地址,如mov si,offset track_buffer
  • LENGTH expression:取长度;
  • register_ COLON expression段覆盖前缀,如les di,dma_longword隐含的 ES:DI 语义在源码中体现为mov bl,[BX]这类带段寄存器的书写。

六、寄存器与指令助记符覆盖

6.1 寄存器集合

register_规则(asm8086.g4)覆盖了 8086 的全部常用寄存器:

  • 8 位:AH AL BH BL CH CL DH DL
  • 16 位通用:AX BX CX DXCI DI BP SP
  • 段寄存器与指令指针:CS DS ES SSIP

一个值得注意的实现细节:文法将源寄存器SI建模为词法记号CI(词法规则见 asm8086.g4,规则文本为'CI' : 'CI')。由于整条文法开启了caseInsensitive'CI'记号可以匹配源码中的si/SI(例如 examples/TRACK.A86 中的lds si,dma_longword)。从源码结构看,这应是历史命名(C 源寄存器 / 某种方言)留下的记号名,使用时只需知道解析树中的CI记号对应SI寄存器即可。

6.2 指令助记符

opcode规则(asm8086.g4)逐一列举了 8086 指令集的助记符,按功能可归纳为:

  • 数据传送MOVPUSHPOPPUSHFPOPFXCHGXLATLEALDSLESINOUTLAHFSAHF
  • 算术运算ADDADCSUBSBBINCDECNEGCMPMULIMULDIVIDIVDAADASAAAAASAAMAADCBWCWD
  • 逻辑与移位ANDORXORNOTTESTSHLSHRSALSARROLRORRCLRCR
  • 串操作MOVSMOVSBMOVSWCMPSCMPSB/CMPSW)、SCASB/SCASWLODSB/LODSWSTOSB/STOSW
  • 控制转移JMP(含JMPF/JMPS)、CALLRET/RETN/RETF、全部条件跳转JA/JAE/JB/JBE/JC/JE/JG/JGE/JL/JLE/JNA/JNAE/JNB/JNBE/JNC/JNE/JNG/JNGE/JNL/JNLE/JNO/JNP/JNS/JNZ/JO/JP/JPE/JPO/JS/JZ/JCXZ、循环指令LOOP/LOOPE/LOOPNE/LOOPNZ/LOOPZ
  • 标志与处理器控制CLCCLDCLICMCSTCSTDSTIHLTNOPWAITESCLOCKIRETINTOINT
  • 扩展/保留SALC等少见助记符也被收录。

配合rep前缀(REP/REPE/REPNE/REPNZ/REPZ),典型串操作如rep movsw(examples/TRACK.A86 的 read/write 例程)可以被完整解析。

七、词法规则要点

词法规则定义了指令、符号、数字与注释的精确外形,见 asm8086.g4:

NAME : [.A-Z] [A-Z0-9."_]* ; NUMBER : [0-9A-F]+ 'H'? ; STRING : '\u0027' ~'\u0027'* '\u0027' ; COMMENT : ';' ~ [\r\n]* -> skip ; EOL : [\r\n]+ ; WS : [ \t] -> skip ;
  • NUMBER[0-9A-F]+ 'H'?是这套文法的特色——它天然支持十六进制数(可带H后缀,如0DAh0B06h2500h,大小写不敏感下h亦可),同时也接受纯十进制数字串(不带H时按十进制理解)。这与 8086 汇编"十六进制必须带 H 后缀"的书写惯例完全一致;
  • NAME:标识符以点号或字母开头,可包含字母、数字、点号、下划线与双引号,因此dma_longwordtrack_bufferhost_sectsiz * host_spt中的符号均可识别;
  • STRING:单引号字符串,用于TITLE等伪指令;
  • COMMENT;到行尾为注释并直接跳过(-> skip),例如 examples 中大量; save the selected drive注释;
  • EOL[\r\n]+作为行终结符,支持 CRLF 与 LF;WS仅跳过空格与制表符,换行不作为空白跳过,而是作为结构性的EOL——这是整个line规则得以成立的前提。

符号类词法记号还包括* / $ + - ! : . ( ) , ; [ ](STAR、SLASH、DOLLAR、PLUS、MINUS、NOT_、COLON、DOT、RP、LP、COMMA、SEMI、LB、RB_ 等,见 asm8086.g4),其中NOT_对应!字符,用于line中的多语句分隔与表达式取反。

八、真实示例解读:examples 目录与 CP/M-86 源码

examples/ 收录了 9 个来自 CP/M-86 源码发行版的真实.A86汇编文件,均是该文法的直接解析对象:

  • BIOS.A86:面向 iSBC 86/12 单板机与 iSBC 204 软盘控制器的 CP/M-86 BIOS,包含大量EQU常量、IF/ENDIF条件汇编与TITLE
  • CBIOS.A86:定制版 BIOS;
  • LDBIOS.A86 与 LDCPM.A86、LDCOPY.A86:加载器 BIOS 相关例程;
  • COPYDISK.A86:磁盘复制工具;
  • ROM.A86 与 TBIOS.A86:ROM 化与终端 BIOS;
  • TRACK.A86:轨道缓冲(Track Buffering)例程,是理解本文法全部特性的最佳样例——它同时用到了equdsegrb/rwdbif/endif!多语句、rep movswoffsetdword ptr[BX]索引寻址、段覆盖等全部核心语法要素。

以 TRACK.A86 的flush_buffer例程为例,可以看到文法与真实源码的完整对应:

flush_buffer: test wr_flag,1 ; see if we have anything to write jz no_flush ; no, skip scanning for dirty sectors mov bx,0 ; start at host sector 0 mov cx,host_spt ; for host_spt sectors... next_sect: test sec_flags[BX],1 ; see if this sector has been changed jz not_updated ; no, leave it alone mov sec_flags[BX],0 ; zero the flag for next time push bx ; save the registers push cx mov cur_sec,bx ; save host sector number mov ax,host_sectsiz mul bx ; make track buffer offset add ax,offset track_buffer ; make direct pointer mov cur_dma,ax ; save for write routine call sector_write pop cx pop bx not_updated: inc bx loop next_sect no_flush: mov wr_flag,0 ; clear the dirty buffer flag ret

其中test sec_flags[BX],1对应(number | name)? LB expression RB_寻址,add ax,offset track_buffer对应OFFSET expressionjz/jnz/loop等全部落在opcode列表内,;注释被词法规则直接跳过。

九、构建、生成与自动化测试

9.1 Maven 构建配置

asm/asm8086/pom.xml 是标准的 grammars-v4 模块配置,使用antlr4-maven-plugin生成解析器,并开启 visitor 与 listener 两种遍历模式:

<plugin> <groupId>org.antlr</groupId> <artifactId>antlr4-maven-plugin</artifactId> <configuration> <sourceDirectory>${basedir}</sourceDirectory> <includes> <include>asm8086.g4</include> </includes> <visitor>true</visitor> <listener>true</listener> </configuration> </plugin>

生成解析器后,即可用prog作为入口规则对任意 8086 汇编源文件构造解析树,并基于生成的Asm8086Parser/Asm8086Lexer编写 visitor 或 listener 实现语义分析。

9.2 自动测试:antlr4test-maven-plugin

同文件还集成了antlr4test-maven-plugin,对 examples/ 下的全部样例执行回归解析:

<plugin> <groupId>com.khubla.antlr</groupId> <artifactId>antlr4test-maven-plugin</artifactId> <configuration> <verbose>false</verbose> <showTree>false</showTree> <entryPoint>prog</entryPoint> <grammarName>asm8086</grammarName> <exampleFiles>examples/</exampleFiles> </configuration> </plugin>

即在模块目录下执行mvn test,插件会以prog为入口规则逐一解析examples/中的 9 个.A86文件,任何语法不匹配都会导致测试失败。这意味着仓库自身就是该文法正确性的回归测试集。

9.3 版本与目标语言要求

desc.xml 声明:

  • ANTLR 版本^4.10(即 4.10 及以上版本);
  • 目标语言:CSharp、Cpp、Dart、Go、Java、JavaScript、TypeScript、Antlr4ng、PHP、Python3。

因此,在满足 ANTLR 4.10+ 的前提下,同一文法可以生成上述任一目标语言的解析器,便于在各自技术栈中复用。

十、使用建议与已知实现细节

  1. 入口规则:解析任何 8086 汇编文件请以prog为入口;构建工具链或静态分析程序时,优先遍历line节点以保持"一行一节点"的结构化视图;
  2. 大小写不敏感:由于caseInsensitive = true,输出的记号名统一为大写,词法错误提示也以此为准;
  3. SI寄存器的记号名是CI:在 visitor/listener 中处理寄存器时应留意这一历史遗留命名(见第六节);
  4. !分隔:一行内多个指令在解析树中体现为同一line节点下的多个instruction子节点,遍历时勿遗漏('!' instruction)*部分;
  5. 表达式求值:伪指令(RB/RW/RS/DB/DW/DD/ORG/EQU)的表达式可以是含符号引用的完整算术式(如track_buffer rb host_sectsiz * host_spt),如需计算实际布局,应在语义阶段维护符号表并对表达式树求值;
  6. 局限:该文法为纯语法层实现,不含任何语义 action,也不做指令合法性/寄存器类型检查,这些需要在使用方(visitor/listener)中自行实现——这也正是 grammars-v4 仓库"grammars free of actions"设计哲学的体现。

结语

asm8086 文法以不到 1200 行的 ANTLR4 定义,完整承载了 Intel 8086 指令集、CP/M 汇编器伪指令体系与真实历史源码(CP/M-86 BIOS/TRACK 等)的全部语法要素,是研究 x86 汇编历史、构建复古系统解析工具或学习 ANTLR4 文法设计的优质范本。借助其内置的 Maven 测试配置,任何对该文法的修改都能立刻通过 9 个真实源码样例得到回归验证。若需进一步了解仓库整体文法生态,可参考 asm/readme.md 及根目录 README.md。

  • 编程语言
  • 编译器
  • 开发工具

【免费下载链接】grammars-v4

Grammars written for ANTLR v4; expectation that the grammars are free of actions.

项目地址:https://gitcode.com/gh_mirrors/gr/grammars-v4
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/24 5:33:57

办公AI实测:从文档生成到会议闭环保,选型避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 5:27:19

从零搭建Node网页服务:环境配置、核心实现与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/24 5:23:42

成都展览工厂展厅装修设计,企业展厅展馆一站式落地

在品牌价值愈发受到重视的时代&#xff0c;展厅展馆早已不再是简单的陈列空间&#xff0c;而是企业传递品牌理念、展示技术实力、承载企业文化、接待客商洽谈、开展内部文化教育的核心载体。一个高品质的展厅&#xff0c;需要内容叙事、空间美学、智能科技、工程施工多方协同&a…

作者头像 李华
网站建设 2026/9/24 5:21:11

Python毕设选题推荐:基于 Python 的轻量化学生健康管理 Web 系统的设计与实现 基于 Python 的校园健康信息统计管理系统【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华
网站建设 2026/9/24 5:05:42

若依二开不碰Flowable,自研轻量审批流实战指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华