antlr 在一段字符可被多个 terminal node 匹配时的行为

antlr 在一段字符可被多个 terminal node 匹配时的行为

考虑下面一段 antlr 语法

STRING: [a-zA-Z0-9]+;
NUMBER: [0-9]+;
NEWLINE: '\r'? '\n';

root: id title EOF;

id: 'id:' NUMBER NEWLINE;
title: 'title:' STRING NEWLINE;

我们希望 id: 后面只存在数字,而 title: 后买可存在数字或字母,因而定义了 NUMBERSTRING 两个 terminal node 规则
然而这一段语法并不能正常工作

这就需要了解 antlr 解析的流程,其中与我们这个问题相关的有这两部分:

  • lexing:将输入的文本解析为一个个 token,进而构建一个 token stream 来作下面的处理
  • parsing:将 token 构建成 parse tree

对于 lexing:

  • 所有以大写字母开头规则对应着 parse tree 中的 terminal node,有且只有它们被用来进行 lexing,这些规则是 lexer rule
  • antlr 会找到一个以当前的位置为起点、极长的、满足任意 lexer rule 的字符串,也就是如果将找到的这个字符串长度再加一,那么不存在任何 lexer rule
  • 如果只有一个 lexer rule 能和这个字符串匹配,那么本次匹配找到的 token 自然就是这个 lexer rule 对应的 token
  • 如果有多个,那么找到的 token 是按照语法文件定义顺序第一个 lexer rule 对应的 token

因此,title: abc12345abc12345 可以被 STRING 匹配,而 id: 12345 仍然会被 STRING 匹配,因为 STRING 被定义在 NUMBER 前面。而 id 这条规则又要求匹配一个 NUMBER,这样就造成了错误
如果把 NUMBERSTRING 的顺序调换,那么 title: 12345 又会匹配到 NUMBER,依然存在错误

正确做法:

  • 让所有 lexer rule 不交,转而使用非终止节点对应的规则,并允许其匹配多个 lexer rule,例如:string: (LETTER | DIGIT)+; number: DIGIT+;
  • 将规则分散到多个语法文件中,再导入
posted @   suxxsfe  阅读(39)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· .NET Core 中如何实现缓存的预热?
· 三行代码完成国际化适配,妙~啊~
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?

This blog has running: 1856 days 2 hours 4 minutes 16 seconds

Copyright © 2025 suxxsfe
Powered by .NET 9.0 on Kubernetes
点击右上角即可分享
微信分享提示