Intel 8080 汇编语法解析基于 ANTLR4 的 asm8080 文法解析 CP/M 源码实战【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4导读本文围绕 grammars-v4 仓库中的 asm8080 ANTLR4 文法展开该文法专为解析 Intel 8080 汇编文件而设计其创建初衷是解析 CP/M 操作系统的汇编源代码。读完本文你将掌握asm8080 文法的整体结构与语法规则、表达式求值与操作数解析机制、伪指令与宏指令覆盖范围、在 Maven 工程中生成解析器并运行测试的完整流程以及如何基于该文法构建自己的 8080 汇编解析工具。一、项目背景与目标1.1 文法定位asm8080.g4 是 grammars-v4 仓库中针对 Intel 8080 微处理器汇编语言编写的 ANTLR4 文法。与仓库中其他汇编文法如 asm8086、asmZ80、asm6502同属于 asm 目录每个文法子目录均遵循文法文件 desc.xml pom.xml examples的统一结构。从文法头部注释可以看出其设计动机Created for the purpose of parsing the CP/M Source code即该文法的首要目标是解析 CP/M 操作系统2.2 与 3.0 版本的官方汇编源码这类源码采用 Digital Research 风格的汇编器语法包含大量宏、条件汇编、表达式求值等特性对解析器有较高要求。1.2 关键设计决策caseInsensitive文法在options块中声明了大小写不敏感模式options { caseInsensitive true; }这符合 8080 汇编的书写惯例——CP/M 时代的源码中指令助记符、寄存器名、标签、伪指令混合使用大写和小写例如MOV与mov、EQU与equ均合法大小写不敏感选项保证了两者都能被正确识别。二、文法整体结构解析2.1 顶层规则与行的组成prog : EOL* ((line EOL)* line EOL*)? EOF ; line : lbl? (instruction | directive | macrocall) (! (instruction | directive | macrocall)?)* comment? | lbl comment? | comment ;顶层规则prog允许空文件仅由换行符EOL和EOF组成也允许任意数量的line。line规则反映了 8080 汇编源代码行的典型结构可选的标签lbl标签后冒号:可选兼容LABEL:与LABEL两种写法一条主体语句可以是机器指令instruction、伪指令directive或宏调用macrocall可选的!分隔符用于在同一行内连接多条语句这是 CP/M 汇编器支持的紧凑写法可选的注释comment。2.2 语句分类指令 / 伪指令 / 宏调用instruction : opcode expressionlist? ; macrocall : name expressionlist? ; directive : argument? assemblerdirective expressionlist? ;三类语句共享助记符 操作数列表的基本形态操作数列表由逗号分隔expressionlist : expression (, expression)* ;instruction的操作数位置是OPCODE词法记号见 2.4macrocall则把第一个记号解析为普通标识符name这是宏调用与指令在语法层面上的关键区分——凡是OPCODE词法表中未收录的助记符都被视为宏名。directive中伪指令之前还可以出现可选参数argument例如条件汇编IF后接条件表达式。三、表达式求值体系从操作数到完整运算符栈asm8080 文法最值得称道的部分是它完整实现了 8080 汇编操作数的表达式求值。expression规则构建了一个覆盖全部优先级层次的表达式语法树expression : orExpression (( | | | | | | OP_GT | OP_LT | OP_GE | OP_LE | OP_NE | OP_EQ) orExpression)? ; orExpression : xorExpression (OP_OR xorExpression)* ; xorExpression : andExpression (OP_XOR andExpression)* ; andExpression : addExpression (OP_AND addExpression)* ; addExpression : shiftExpression (( | -) shiftExpression)* ; shiftExpression : modExpression ((OP_SHL | OP_SHR) modExpression)* ; multiplyingExpression : unaryExpression ((* | /) unaryExpression)* ; unaryExpression : OP_NOT unaryExpression | OP_HIGH unaryExpression | OP_LOW unaryExpression | - unaryExpression | unaryExpression | argument ;3.1 运算符优先级层次从低到高依次为比较运算及关键字形式EQNEGTLTGELE→ 逻辑或OR→ 逻辑异或XOR→ 逻辑与AND→ 加减-→ 移位SHLSHR→ 乘除*/→ 一元运算NOTHIGHLOW与正负号。以 CP/M 3 引导加载器源码 OS1BOOT.ASM 中的实际用法为例true equ not false testing equ false ;if true, then go to mon80 on errors bdos equ 806hbias ;entry to dos for calls bdosl equ bdose-cpmb bdoss equ bdosl/128 ;number of sectors in dos bdos0 equ 25 ;number of bdos sectors on track 0 bdos1 equ bdoss-bdos0 ;number of sectors on track 1这些表达式涵盖了一元NOT、加减、除法以及符号引用均可被上述规则链完整解析。3.2 一元运算符 HIGH / LOW / NOTHIGH和LOW是 8080 汇编中常用的取字节操作分别取 16 位地址的高、低字节NOT为逻辑取反。它们在文法中作为一元前缀运算符递归出现可以叠加使用。3.3 操作数原子的种类argument规则定义了操作数的全部原子形态argument : number | opcode | register_ | dollar | name | string_ | ( expression ) ;number数值字面量见 4.4opcode/register_指令助记符和寄存器名本身也可作为操作数例如DB指令中存放MOV等指令字节码的场景很常见dollar$表示当前地址计数器location counter如 CPM22.ASM 中ENDMOD EQU ($ AND 0FF00H)100H的用法name符号引用标签、EQU 定义的常量等string_字符串字面量( expression )括号表达式支持任意嵌套。四、词法规则深度剖析4.1 伪指令表 ASSEMBLER_DIRECTIVEASSEMBLER_DIRECTIVE : ORG | END | EQU | DB | DW | DS | IF | ELSE | ENDIF | SET | TITLE | $TITLE | NAME | CSEG | DSEG | ASEG | PUBLIC | EXTRN | MACRO | ENDM | EXITM | REPT | MACLIB ;该表覆盖了三类伪指令数据与定位ORG设置起始地址、END源文件结束、EQU常量定义、DB/DW定义字节/字、DS保留存储区、SET可重定义常量条件汇编与列表控制IF/ELSE/ENDIF条件汇编块、TITLE/$TITLE页面标题、NAME模块名模块化与宏CSEG/DSEG/ASEG代码段/数据段/绝对段、PUBLIC/EXTRN符号导出与外部引用、MACRO/ENDM/EXITM宏定义与退出、REPT重复块、MACLIB宏库引入。在 CPM22.ASM 中EQU、ORG、DB、DW被大量使用例如MEM EQU 62 ;for a 62k system (TS802 TEST - WORKS OK). IOBYTE EQU 3 ;i/o definition byte. ORG (MEM-7)*1024 INBUFF DB 127 ;length of input buffer. INPOINT DW INBUFF2;input line pointer注意这里EQU右侧的(MEM-7)*1024恰好印证了括号表达式与乘法的解析能力。4.2 表达式运算符关键字先于 NAME 声明OP_NOT : NOT ; OP_HIGH: HIGH; OP_LOW : LOW ; OP_AND : AND ; OP_OR : OR ; OP_XOR : XOR ; OP_SHL : SHL ; OP_SHR : SHR ; OP_MOD : MOD ; OP_GT : GT ; OP_LT : LT ; OP_GE : GE ; OP_LE : LE ; OP_NE : NE ; OP_EQ : EQ ;文法注释给出了这些关键字必须排在NAME之前的理由由于 8080 指令集中存在SHLD、ORI、ANA这类以SHL/OR/AND开头的助记符ANTLR 的词法最长匹配longest-match机制仍能保证SHLD整体被识别为OPCODE而不会被拆成SHLD。关键字规则前置是为了让独立的NOT、SHL等记号优先于NAME被识别。4.3 寄存器表 REGISTERREGISTER : A | B | C | D | E | H | L | PC | SP ;覆盖 8080 的 8 位通用寄存器A、B、C、D、E、H、L以及 16 位专用寄存器 PC程序计数器与 SP栈指针。由于caseInsensitive true小写形式同样有效。4.4 助记符表 OPCODEOPCODE规则完整收录了 Intel 8080 的全部指令集按功能可分为数据传输MOV、MVI、LDA、STA、LDAX、STAX、LHLD、SHLD、LXI、PUSH、POP、XTHL、SPHL、PCHL、XCHG算术与逻辑ADD、ADC、SUB、SBB、INR、DCR、CMP、ANA、ORA、XRA、DAD、DAA以及立即数形式ADI、ACI、SUI、SBI、CPI、ANI、ORI、XRI跳转/调用/返回无条件JMP/CALL/RET以及全部条件形式JNZ/JZ/JNC/JC/JPO/JPE/JP/JM、CNZ/CZ/CNC/CC/CPO/CPE/CP/CM、RNZ/RZ/RNC/RC/RPO/RPE/RP/RM栈与机器控制RST、IN、OUT、EI、DI、HLT、NOP、CMC、STC、CMA、RAL、RAR、RLC、RRC。4.5 标识符与数值字面量NAME : [A-Z?] [A-Z0-9.$?]* ; NUMBER : $? [0-9A-F] [0-9A-F$]* H? ;NAME允许以字母、?PL/I 风格外部符号如?bdos或开头$允许出现在名称内部如sta$ret、rsx$chain这类 CP/M 内部符号但不能作为首字符从而与表示当前地址的独立$记号区分开来。这在文法注释中有明确说明。NUMBER的形态直接来自 8080 汇编的数值书写惯例十六进制数以H结尾如5CH、0FFH也可以$前缀开头十进制、二进制如0101B等书写形式同样落入该规则。注意 CPM22.ASM 中DB 0,0,0,...与DB Copyright混用的场景分别命中NUMBER与STRING。4.6 注释、字符串、空白与其他COMMENT : ; ~ [\r\n]* | * * ~ [\r\n]* ; STRING : \u0027 (\u0027\u0027 | ~\u0027)* \u0027 ; EOL : [\r\n] ; WS : [ \t] - skip ; ARTIFACT : [\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\uffff] - skip ;COMMENT支持两种注释前缀分号;与星号*CP/M 汇编器兼容形式如** comment。*后要求至少两个*避免与乘号*冲突——这是通过* *的写法实现的STRING以单引号\u0027定界内部使用双单引号转义表示字面单引号对应 CP/M 源码中常见的DB its写法同时允许单引号内直接出现$等字符WS跳过空格与制表符ARTIFACT规则负责丢弃源码中可能存在的控制字符与高位字符等二进制伪影保证解析器对老旧源码的鲁棒性。五、标签解析允许标签与指令、寄存器重名lbl : label :? ; label : name | register_ | assemblerdirective ;label规则值得注意它不仅能由普通NAME构成还允许标签与寄存器名REGISTER或伪指令名ASSEMBLER_DIRECTIVE同名。这正是解析真实 8080 汇编源码的现实需求——例如 CP/M 源码中大量存在SET、ENDMOD这样的标签其中SET同时是伪指令关键字见 AS2SCAN.ASM 中SETT EQU 0101B ;SET的用法以及SET0:、SETUP:等标签文法通过把label与directive作为line的并列分支来解决这种歧义。六、工程配置与测试6.1 Maven 构建配置asm8080/pom.xml 声明了该文法模块的完整构建与测试方案使用antlr4-maven-plugin从asm8080.g4生成解析器代码同时开启 visitor 与 listener 两种遍历模式visitortrue/visitor、listenertrue/listener使用antlr4test-maven-plugin进行自动化测试入口规则为prog测试文件扩展名为.ASM测试目录为examples/。6.2 测试样例集examples 目录包含两组真实世界测试语料CPM22.ASMCP/M 2.2 操作系统完整源码约 3700 行涵盖 EQU 常量定义、ORG 定位、DB/DW 数据定义、子程序注释风格等全部语法要素cpm3_srcCP/M 3.0Plus源码包含AS0COM.ASM~AS6MAIN.ASM等汇编器自身模块、BIOS/BDOS/CCP 相关模块如OS1BOOT.ASM、OS2CCP.ASM、OS3BDOS.ASM、OS4BIOS.ASM以及CPM3ASM1.SUB等 SUBMIT 批处理文件。这些样例验证了文法对真实历史代码的解析能力——尤其是TITLE ...见 AS0COM.ASM 首行、条件汇编IF/ENDIF见 OS1BOOT.ASM 中if testing ... endif结构、嵌套表达式ENDMOD EQU ($ AND 0FF00H)100H等特性。6.3 支持的生成目标desc.xml 声明了该文法支持的目标语言CSharp、Cpp、Dart、Go、Java、JavaScript、PHP、Python3、TypeScript 以及 Antlr4ngANTLR 版本要求为^4.10。这意味着通过 ANTLR 工具链同一份文法可以在上述任意目标语言中生成 8080 汇编解析器。6.4 运行测试在仓库根目录执行 Maven 测试命令即可验证文法mvn -pl asm/asm8080 testantlr4test 插件会以prog为入口规则逐个解析examples/下所有.ASM文件任何无法解析的源码都会导致测试失败。七、基于该文法的二次开发指引7.1 生成解析器确保已安装 ANTLR4 工具版本 ≥ 4.10然后执行antlr4 -visitor -listener asm8080.g4生成 Java 解析器后即可在自定义程序中加载asm8080Lexer/asm8080Parser。由于文法不含任何 action符合 grammars-v4 仓库文法中不含动作的约定生成的代码是纯粹的数据驱动解析器便于在任意目标语言中复用。7.2 解析器骨架示例import org.antlr.v4.runtime.*; import org.antlr.v4.runtime.tree.*; CharStream input CharStreams.fromFileName(CPM22.ASM); asm8080Lexer lexer new asm8080Lexer(input); CommonTokenStream tokens new CommonTokenStream(lexer); asm8080Parser parser new asm8080Parser(tokens); ParseTree tree parser.prog(); // 入口规则 ParseTreeWalker.DEFAULT.walk(new asm8080BaseListener(), tree);基于生成的asm8080BaseVisitor/asm8080BaseListener可以进一步实现符号表收集遍历EQU/label、代码重定位解析ORG与$、宏展开等工具链功能。表达式规则链expression→unaryExpression→argument为在 visitor 中实现操作数求值提供了天然的结构支撑。八、总结asm8080 文法的价值在于它以真实历史源码CP/M 2.2 与 3.0为测试基准完整覆盖了 Intel 8080 指令集、Digital Research 汇编器风格的伪指令与宏语法、以及全套表达式运算符。无论是研究古董操作系统源码、开发 8080 交叉汇编工具还是学习如何为语法复杂、惯例繁多的汇编语言设计 ANTLR4 文法这份文法都是极具参考价值的起点——其 README.md、文法源文件 与 测试样例 均可直接在仓库中查阅与复用。【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址: https://gitcode.com/gh_mirrors/gr/grammars-v4创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
