ANTLR语法未定义EOF Token却触发EOF错误及解析规则问题
解答
1. 错误原因
调用parser.name()时,解析器已经消费了所有有效token("John"、空格、"Smith"),此时token流的指针停在了EOF位置。后续再调用parser.firstname()和parser.firstname()时,解析器试图从当前位置(EOF)匹配STRING token,但已经没有可用的token了,因此抛出“missing STRING”的错误。
ANTLR的CommonTokenStream是向前消费的,一旦解析器完成某个规则的匹配,token指针不会自动重置,重复调用解析方法不是正确的用法——解析器的设计是基于完整的语法树来获取结构信息。
2. 正确获取firstname和lastname的方式
你不需要重复调用解析器方法,而是应该从parser.name()返回的语法树节点中提取firstname和lastname的内容,具体有两种常用方式:
方式一:直接访问语法树子节点
解析得到的nameContext包含了对应的firstnameContext和lastnameContext,可以直接获取它们的文本:
var nameContext = parser.name(); var firstName = nameContext.firstname().GetText(); var lastName = nameContext.lastname().GetText(); Console.WriteLine("Person:"); Console.WriteLine($"firstname {firstName}"); Console.WriteLine($"lastname {lastName}");
方式二:使用ANTLR的访问器/监听器(推荐)
对于复杂语法,更规范的方式是实现gdxBaseVisitor或gdxBaseListener来遍历语法树,提取所需信息:
public class NameVisitor : gdxBaseVisitor<string> { public string FirstName { get; private set; } public string LastName { get; private set; } public override string VisitFirstname(gdxParser.FirstnameContext context) { FirstName = context.GetText(); return base.VisitFirstname(context); } public override string VisitLastname(gdxParser.LastnameContext context) { LastName = context.GetText(); return base.VisitLastname(context); } } // 使用示例 var visitor = new NameVisitor(); visitor.Visit(tree); Console.WriteLine("Person:"); Console.WriteLine($"firstname {visitor.FirstName}"); Console.WriteLine($"lastname {visitor.LastName}");
对应ANTLR书籍章节
在《The Definitive ANTLR 4 Reference》中:
- 关于语法树的基本使用和获取子节点,参考第4章 Parsing with ANTLR(解析器返回的上下文对象、获取节点文本等内容)。
- 关于访问器/监听器的使用,参考第5章 Building a Parse Tree and Walking It(遍历语法树的两种模式:访问器和监听器)。
内容的提问来源于stack exchange,提问作者Michael EstrinOne
相关产品推荐
相关产品推荐

