You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在ANTLR词法分析器中通过计数BEGIN/END对条件切换模式?

在ANTLR中实现嵌套BEGIN/END的词法模式切换

完全可以通过计数BEGIN/END的嵌套层级来实现需求——只有当嵌套计数归零时,才执行popmode()切回外层模式。ANTLR的词法分析器支持在规则动作里维护状态,结合模式切换就能搞定这个场景,下面是具体实现方案:

核心实现步骤

1. 定义双层词法模式

先在外层默认模式(DEFAULT_MODE)里处理外层语法的关键字(比如小写的procedure、var、begin),同时匹配大写的BEGIN来触发模式切换:

// 外层默认模式
PROCEDURE : 'procedure';
VAR : 'var';
BEGIN_OUTER : 'begin';
END_OUTER : 'end';
// 匹配大写BEGIN,进入内层模式并初始化计数器
BEGIN_INNER : 'BEGIN' -> pushmode(INNER_MODE), {_ctx.beginCount = 1;};
// 外层其他规则(标识符、字面量等)
OUTER_IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*;
OUTER_WS : [ \t\r\n]+ -> skip;
// ...其他外层语法规则

2. 在内层模式维护嵌套计数

在内层模式(INNER_MODE)里,专门处理嵌套的BEGIN/END,同时把外层的关键字都当作普通标识符:

mode INNER_MODE;

// 遇到内层BEGIN,计数器加1
INNER_BEGIN : 'BEGIN' {_ctx.beginCount++;};
// 遇到内层END,计数器减1,归零时切回外层
INNER_END : 'END' {
    _ctx.beginCount--;
    if (_ctx.beginCount == 0) {
        popmode();
    }
};
// 内层所有标识符(包括外层关键字,比如procedure、begin)都按普通标识符处理
INNER_IDENTIFIER : [a-zA-Z_][a-zA-Z0-9_]*;
// 内层注释、空白符处理
INNER_COMMENT : '//' ~[\r\n]* -> skip;
INNER_WS : [ \t\r\n]+ -> skip;
// ...其他内层语法需要的规则(比如表达式、语句等)

3. 初始化计数器状态

你需要在ANTLR生成的词法分析器上下文里(或者自定义一个状态类)添加一个beginCount整数变量,初始值设为0。当匹配到外层的BEGIN_INNER时,把它设为1——因为第一个BEGIN已经触发了模式切换,后续嵌套的BEGIN会逐步累加计数。

适配你的语法示例

针对你给出的代码:

procedure Foobar(somethingHappens: boolean)
  var
      MyRecord: Record "Some Table";
      MyDecimal: Decimal;
      otherBoolean: Boolean;
  begin
      if (somethingHappens) then
      BEGIN
        // do some stuff
      END
      // do other stuff
  end;
  • 外层的procedure、var、begin、end会被正确识别为关键字
  • 大写的BEGIN触发进入内层模式,内层的END在计数归零时切回外层,中间的注释和代码都按内层语法处理,哪怕内层里再嵌套多层BEGIN/END也能正确计数

注意事项

  • 确保大小写区分:你的示例中外层用小写begin,内层用大写BEGIN,ANTLR默认大小写敏感,刚好符合这个需求,别误开启大小写不敏感模式
  • 覆盖所有字符类型:内层模式里要处理注释、空白符、字符串字面量等,避免词法分析器遇到未匹配的字符报错
  • 计数器状态要可靠:如果有异常情况(比如未闭合的BEGIN),可以在词法分析结束时检查计数器是否为0,做错误提示

内容的提问来源于stack exchange,提问作者WiredWiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 08:10:03