ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

VBA 条件编译(Conditional Compilation)ANTLR4 语法解析:vba_cc 语法深入解析与实践

VBA 条件编译(Conditional Compilation)ANTLR4 语法解析:vba_cc 语法深入解析与实践 编程语言编译器开发工具【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址https://gitcode.com/gh_mirrors/gr/grammars-v4点击查看免费下载本文基于 ANTLR v4 开源语法仓库 grammars-v4 中的vba/vba_cc子项目系统讲解如何用 ANTLR4 语法解析 Visual Basic for ApplicationsVBA文件中的条件编译代码段。读者将掌握 vba_cc 语法的整体结构与规则设计思路、#Const/#If/#ElseIf/#Else/#End If指令的完整文法定义、条件编译表达式的运算符体系与优先级建模方式以及如何结合仓库内的示例与 Maven 测试配置快速验证该语法。背景为什么需要单独的 vba_cc 语法在 vba/vba7_1/README.md 中明确说明VBA 7.1 主语法vbaLexer.g4/vbaParser.g4会忽略条件编译语句This grammar ignores conditional-compilation statements。而 vba_cc 语法正是为此设计的补充The vba_cc grammar can be used against vba files to analyze that portion of the code.也就是说两条语法的分工是vba7_1解析 VBA 代码的主体过程、语句、表达式、类型声明等vba_cc专门针对.bas/.frm/.cls等 VBA 源文件抽取并分析其中的条件编译代码段conditional compilation包括条件编译常量声明和条件编译分支指令。vba_cc 语法声明Derived from the Visual Basic 7.1 language reference即其规则结构以微软 Visual Basic 语言规范MS-VBAL为蓝本实现覆盖规范中编号为3.4 Conditional Compilation、3.4.1 Conditional Compilation Const Directive、3.4.2 Conditional Compilation If Directives以及5.6.16.2 Conditional Compilation Expressions等章节的内容。vba_cc 语法整体结构语法入口定义在 vba/vba_cc/vba_cc.g4根规则startRule的组成如下startRule : (proceduralModuleHeader | classFileHeader) conditionalModuleBody NEWLINE* EOF ;规则读取顺序为可选的文件头.bas模块通常以Attribute VB_Name ...开头proceduralModuleHeader.cls/.frm类文件通常以VERSION x.x Class开头classFileHeader条件编译模块主体conditionalModuleBody结尾允许若干空行NEWLINE*并必须以文件结束符EOF收束。对应示例 vba/vba_cc/examples/cc.bas 的第一行正是Attribute VB_Name CCTEST文件头的两条规则定义如下proceduralModuleHeader : ATTRIBUTE VB_NAME STRINGLITERAL ; classFileHeader : VERSION FLOATLITERAL CLASS? ;proceduralModuleHeader匹配Attribute VB_Name 模块名模块名必须是STRINGLITERAL带引号字符串classFileHeader匹配VERSION 浮点数 CLASS其中CLASS关键字可选——这覆盖了类模块与窗体文件两种头部形式。条件编译模块主体与逻辑行conditionalModuleBody与块结构的核心定义logicalLine : NEWLINE WS? (~(CONST | IF | ELSEIF | ELSE | NEWLINE) (~(NEWLINE))*)?; conditionalModuleBody: ccBlock; ccBlock: (ccConst | ccIfBlock | logicalLine);ccBlock是模块主体的骨架由ccConst条件编译常量声明、ccIfBlock条件编译 If 块和普通logicalLine普通代码行三者的任意组合重复组成logicalLine用于吞掉不属于条件编译指令的普通 VBA 代码行例如示例中的Open pth for output as #ff、Print #ff, cont、Close #ff。它的否定式字符类~(CONST | IF | ELSEIF | ELSE | NEWLINE)确保只有当一行不以#Const、#If、#ElseIf、#Else开头时才会被当作普通逻辑行消费从而把条件编译指令与普通代码精确区分开。条件编译常量指令#Const语法规则ccConst对应 MS-VBAL 规范的 3.4.1 节ccConst: NEWLINE CONST ccVarLhs ccExpression COMMENT?; ccVarLhs: name;它要求一条#Const指令的形态为NEWLINE #Const 名字 条件编译表达式 [注释]?指令前必须有换行NEWLINE作为语句边界CONST词法符号定义为#CONST由于 grammar 选项caseInsensitive true#Const、#CONST、#const均可匹配等号左侧是变量名ccVarLhs右侧是ccExpression条件编译表达式行尾允许跟一个可选的COMMENT单引号注释。name规则区分未带类型后缀与带类型后缀的名字name : untypedName | typedName ; untypedName : IDENTIFIER | FOREIGN_NAME ; typedName : IDENTIFIER typeSuffix ; typeSuffix : | % | # | ! | | $ | ^ ;untypedName接受普通标识符IDENTIFIER[A-Z][A-Z0-9_]*或方括号转义名FOREIGN_NAME[ ~[...]* ]用于包含空格或关键字的名字typedName支持 VBA 的类型声明字符后缀Long、%Integer、#Double、!Single、Currency、$String、^LongLong64 位。示例文件中的典型常量声明#Const conDebug 1会被解析为ccConstccVarLhs conDebugccExpression 1INTEGERLITERAL。条件编译分支指令#If / #ElseIf / #Else / #End If规则ccIfBlock对应 MS-VBAL 规范的 3.4.2 节它完整描述了条件编译分支块的嵌套结构ccIfBlock : ccIf ccBlock? ccElseifBlock* ccElseBlock? ccEndif; ccIf: NEWLINE IF ccExpression THEN COMMENT?; ccElseifBlock: ccElseif ccBlock?; ccElseif: NEWLINE ELSEIF ccExpression THEN COMMENT?; ccElseBlock: ccElse ccBlock?; ccElse: NEWLINE ELSE COMMENT?; ccEndif: NEWLINE ENDIF COMMENT?;块结构的语法语义ccIf至少一个换行后跟IF#IF、一个条件表达式、THEN可选尾随注释每个分支主体ccBlock?都是可选的?表示零或一次因此允许出现空分支块ccElseifBlock*#ElseIf分支可以出现任意多次ccElseBlock?#Else分支至多出现一次ccEndif以ENDIF结束。ENDIF词法符号同时接受两种写法ENDIF : #END IF | #ENDIF ;这覆盖了#End If带空格与#Endif不带空格两种常见写法。对应示例 vba/vba_cc/examples/cc.bas 中的嵌套结构可以直观验证上述规则#If conDebuge 1 Then Run debug code Debug.Print oops #Elseif conDebug 1 Then Debug.Print help #Else #If Cdbl(Abs(conDebug)) (1 Mod 3) Then foo 2 #Endif #End If这里外层ccIfBlock内含#Else分支而#Else分支体内又嵌套了一个完整的ccIfBlock正好印证了ccBlock的递归组合能力。示例文件还特意包含了两处空分支块用例用于验证块可选规则 The blocks can each be empty. #if Win64 Then #Elseif Win32 Then #Else #Endif The blocks can each be empty. #if 1 / 2 .5 Then foo 4 #Endif第一段中#If Win64 Then、#Elseif Win32 Then、#Else、#Endif的各分支体均为空语法仍能正确接受第二段则演示了纯算术关系表达式1 / 2 .5作为条件的场景。条件编译表达式ccExpression条件编译表达式的规则位于ccExpression对应 MS-VBAL 规范 5.6.16.2 节。它采用 ANTLR4 的左递归 优先级分层方式建模各备选分支按优先级从低到高排列ccExpression : literalExpression # LiteralExpress | reservedKeywords # IdentifierExpression | IDENTIFIER # IdentifierExpression | ( ccExpression ) # ParenthesizedExpression | ccExpression (^) ccExpression # ArithmeticExpression | - ccExpression # UnaryMinusExpression | ccExpression (* | /) ccExpression # ArithmeticExpression | ccExpression \\ ccExpression # ArithmeticExpression | ccExpression MOD ccExpression # ArithmeticExpression | ccExpression ( | -) ccExpression # ArithmeticExpression | ccExpression ccExpression # ConcatExpression | ccExpression (EQ | NEQ | GT | GEQ | LEQ | LT | LIKE) ccExpression # RelationExpression | ccFunc ( ccExpression ) # IndexExpression | NOT ccExpression # NotOperatorExpression | ccExpression AND ccExpression # booleanExpression | ccExpression OR ccExpression # booleanExpression | ccExpression XOR ccExpression # booleanExpression | ccExpression EQV ccExpression # booleanExpression | ccExpression IMP ccExpression # booleanExpression ;从规则顺序可以还原出 VBA 条件编译表达式的优先级层次由高到低优先级运算符 / 构造标签Alternative最高字面量、保留关键字、标识符LiteralExpress / IdentifierExpression括号( expr )ParenthesizedExpression幂^ArithmeticExpression一元负号-exprUnaryMinusExpression乘除*/整除\取模MODArithmeticExpression加减-ArithmeticExpression字符串连接ConcatExpression关系比较LIKERelationExpression函数调用ccFunc( expr )IndexExpression逻辑非NOT exprNotOperatorExpression最低逻辑与 / 或 / 异或 / 等值 / 蕴含ANDORXOREQVIMPbooleanExpression值得注意的细节整除用反斜杠\\表示与 VBA 的\整除运算符对应关系运算符同时兼容非标准变体写法例如GEQ同时接受与LEQ接受与NEQ接受与体现了对真实代码宽容度的考虑在此上下文中被定义为字符串连接运算符ConcatExpression而非十六进制前缀——十六进制字面量由词法层HEXLITERAL处理MOD、AND、OR、XOR、EQV、IMP、LIKE、NOT均以关键字形式内联在文法中。字面量类型literalExpression支持 VBA 条件编译允许的六类字面量literalExpression : BOOLEANLITERAL | FLOATLITERAL | INTEGERLITERAL | STRINGLITERAL | DATELITERAL | EMPTY_ | NULL_ | NOTHING ;BOOLEANLITERALTRUE/FALSEFLOATLITERAL浮点字面量支持尾缀!Single、#Double、Currency以及D/E指数记法INTEGERLITERAL十进制、H十六进制HEXLITERAL、O/八进制OCTLITERAL三种进制支持%、、^类型尾缀STRINGLITERAL双引号字符串允许转义表示内嵌引号DATELITERAL#日期/时间#形式的日期字面量日期部分支持数字与英文月份名含缩写MAY被有意排除以避免歧义时间部分支持AM/PM标记特殊标识符EMPTY_、NULL_、NOTHING分别对应EMPTY、NULL、NOTHING。条件编译函数ccFunc定义了条件编译表达式中允许调用的内建转换/数学函数集合ccFunc : INT | FIX | ABS | SGN | LEN | LENB | CBOOL | CBYTE | CCUR | CDATE | CDBL | CINT | CLNG | CLNGLNG | CLNGPTR | CSNG | CSTR | CVAR ;即Int、Fix、Abs、Sgn、Len、LenB以及类型转换函数CBool、CByte、CCur、CDate、CDbl、CInt、CLng、CLngLng、CLngPtr、CSng、CStr、CVar。这与 VBA 规范中对条件编译表达式允许使用的函数集合保持一致。示例中的Cdbl(Abs(conDebug))正是ccFunc与嵌套表达式的组合用法。条件编译保留关键字reservedKeywords定义了 VBA 条件编译中最常用的编译平台/版本判断变量reservedKeywords : WIN16_ | WIN32_ | WIN64_ | VBA6 | VBA7 | MAC ;对应词法符号分别为WIN16、WIN32、WIN64、VBA6、VBA7、MAC。这些是条件编译表达式里可直接使用的预定义编译常量标识符例如示例中的#If Win64 Then/#Elseif Win32 Then。词法设计要点Lexervba_cc 的词法规则在 vba/vba_cc/vba_cc.g4 后半部分几个值得关注的设计点caseInsensitive true整个语法大小写不敏感#IF、#if、#If均视为同一符号指令记号均为#前缀CONST#CONST、IF#IF、ELSEIF#ELSEIF、ELSE#ELSE、ENDIF#END IF/#ENDIF——与 VBA 源文件中条件编译指令的#前缀写法严格对应NEWLINE匹配[\r\n\u2028\u2029]并保留在语法规则中作为语句边界VBA 规范要求指令必须位于行首因此换行是结构性记号而非单纯空白WS进入channel(HIDDEN)隐藏通道不会出现在语法树中但不会影响 NEWLINE 所承载的结构语义COMMENT以单引号起始直到行尾允许出现在各指令行末尾IDENTIFIER仅匹配以字母开头的[A-Z][A-Z0-9_]*而FOREIGN_NAME匹配方括号括起的任意内容用于处理[My Name]这类转义标识符。用 Maven 与示例文件验证语法vba_cc 是一个标准的 ANTLR4 Maven 模块构建配置见 vba/vba_cc/pom.xml语法生成使用antlr4-maven-pluginsourceDirectory指向模块根目录只包含vba_cc.g4一个语法文件并开启visitor与listener生成选项分别生成vba_ccVisitor、vba_ccBaseVisitor、vba_ccListener、vba_ccBaseListener便于用户用 Visitor 或 Listener 模式遍历条件编译语法树测试驱动使用com.khubla.antlr:antlr4test-maven-plugin入口规则为startRule语法名vba_cc测试样例目录为examples/。执行 Maven 测试即可自动对examples/下的每个示例文件进行解析验证生成目标desc.xml 声明支持CSharp;Cpp;Dart;Go;Java;JavaScript;Python3;TypeScript等多语言 Target。仓库内提供了一份完整的测试样例 vba/vba_cc/examples/cc.bas它几乎覆盖了语法的全部特性标准模块头Attribute VB_Name、#Const常量声明、带注释的#If ... Then、多个#ElseIf、带嵌套#If的#Else分支、#End If/#Endif两种结尾写法、空分支块、Win64/Win32平台关键字、函数调用Cdbl(Abs(...))、整除与取模1 Mod 3、浮点比较1 / 2 .5以及普通代码行Open/Print/Close语句与条件编译指令的混合。验证方式在模块目录内执行# 生成解析器并运行示例测试 mvn testantlr4test-maven-plugin会依次解析examples/下的样例若全部通过说明语法规则与样例匹配否则会在verbose输出中给出失败信息与期望语法树。使用场景与局限vba_cc 语法的典型使用场景包括条件编译代码静态分析针对 VB6 / VBA 工程.bas、.frm、.cls抽取#Const与#If分支结构评估不同编译平台Win16/Win32/Win64、VBA 版本VBA6/VBA7与 Mac 环境下的代码分支覆盖情况与 vba7_1 主语法配合先用 vba7_1 分析 VBA 主体代码、再用 vba_cc 分析条件编译片段从而获得完整的源代码结构视图作为实现参考本语法以 MS-VBAL 规范的 3.4、5.6.16.2 等章节为蓝本是学习如何把规范中的条件编译文法翻译为 ANTLR4 左递归优先级文法的现成范例。需要注意的局限README 与源码中均有体现vba_cc 只分析条件编译相关的那部分代码结构普通 VBA 语句在logicalLine中被整体吞掉、不做细分解析因此不能替代vba7_1 主语法完成完整语法分析vba7_1 主语法明确忽略条件编译语句若直接用 vba7_1 解析含#If的文件这些指令会按普通内容处理或产生偏差这正是需要两个语法配合的原因语法基于 VBA 7.1 语言参考实现覆盖的是规范定义的书写形式实际工程代码中的异常排版需要依赖NEWLINE、WS等规则的结构化处理来容错。小结vba_cc 是 grammars-v4 仓库中针对 VBA 条件编译代码段的专用 ANTLR4 语法它以上下文无关文法完整覆盖了#Const常量声明、#If / #ElseIf / #Else / #End If分支块、条件编译表达式算术、关系、字符串连接与逻辑运算、内建函数与平台保留关键字并通过caseInsensitive、NEWLINE结构化边界与隐藏通道 WS 的设计贴合 VBA 规范的真实书写规则。配合 cc.bas 示例与 pom.xml 中的 antlr4test 配置开发者可以快速验证语法并在此基础上实现条件编译代码的解析、分析与版本/平台适配工具。赞分享编程语言编译器开发工具【免费下载链接】grammars-v4Grammars written for ANTLR v4; expectation that the grammars are free of actions.项目地址https://gitcode.com/gh_mirrors/gr/grammars-v4点击查看免费下载相关推荐lo 库 MaxIndexBy 详解基于自定义比较函数同时获取最大值与其下标lo 库 MaxIndexBy 详解基于自定义比较函数同时获取最大值与其下标 MaxIndexBy 是 loA Lodash style Go librar编程语言编译器开发工具ANTLR4语法文件结构深度解析ANTLR4语法文件结构深度解析 ANTLR4作为一款强大的语法分析器生成工具其核心在于语法文件的编写。本文将全面解析ANTLR4语法文件的结构组成帮助开发开发工具编程语言编译器MASM 汇编语言 ANTLR4 语法解析asmMASM 语法文件结构与实战示例详解MASM 汇编语言 ANTLR4 语法解析asmMASM 语法文件结构与实战示例详解 本文基于 grammars v4 仓库中 asm/asmMASM 目录下编程语言编译器开发工具上一篇Cabal Desktop 项目安装与使用教程下一篇SRL-PHP测试驱动开发如何为自定义正则模式编写单元测试创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表