ANTLR中如何为多行语句复用解析规则?报错求助
解决ANTLR多行语句解析错误的方案
我帮你梳理下问题根源和解决办法:
问题核心原因
你遇到的错误line 2:0 extraneous input 'SafetyGoal' expecting {, 'AND', 'OR'},本质是入口规则调用错误:
你在代码里调用的是parser.expr(),但这个规则只能解析单个表达式。当输入有多行多个独立的顶层元素(比如第二行的SafetyGoal)时,解析完第一个expr后,剩余输入无法被expr规则匹配,因此抛出“多余输入”的错误。
你的语法里其实定义了正确的顶层规则condition((expr+)? EOF),但它的设计存在缺陷:没有明确支持多个独立表达式的分隔逻辑(比如换行),而且你也没在代码里调用它。
步骤1:修正语法规则
调整语法,明确支持多行独立语句,同时修复几个小问题:
grammar Condition; // 顶层规则:处理整个输入,允许多个语句(每行一个) condition : (statement NEWLINE*)+ EOF | EOF; // 单个语句对应原来的表达式 statement : expr; // 保留原表达式逻辑,修复重复的标签名 expr : expr And expr # andExpr | expr Or expr # orExpr | LPar expr RPar # parExpr | prop MIN Numerical expr # eqExpr | prop some expr # someExpr | prop only expr # onlyExpr | prop value dataValue # valueExpr | id # idExpr | not id # notExpr; // 原规则重复使用idExpr标签,改为notExpr区分 id : Identifier; prop: Identifier; dataValue: Identifier; /* Lexical Tokens */ And : 'AND'; Or : 'OR'; LPar : '('; RPar : ')'; Equals : '='; some : 'some'; only : 'only'; MIN : 'MIN'; value: 'value'; not: 'not'; NEWLINE: '\n'; // 不再跳过换行,用作语句分隔符 Numerical : [1-9] [0-9]*; Data : 'true' | 'false' | 'A' | 'B' | 'C' | 'D' ; // 修复原写法:[true]是字符集,改为字符串字面量 Identifier : [a-zA-Z_] [a-zA-Z0-9_]*; WhiteSpace : [ \t\r]+ -> channel(HIDDEN); // 移除换行,交给NEWLINE处理 InvalidChar : .;
关键修改点:
- 新增
statement规则,将每行视为一个独立语句 - 顶层
condition规则改为匹配多个statement,用换行分隔 - 修复
Data规则的错误写法(原[true]会匹配单个t/r/u/e字符) - 修复
expr规则里重复的标签名,避免ANTLR编译报错 - 不再跳过换行,而是将其作为语句分隔符保留
步骤2:修正调用代码
将入口规则从expr()改为顶层的condition(),这样才能解析整个多行输入:
Stream<String> stream = Files.lines(Paths.get("C:\\test\\RulesTest.txt"), StandardCharsets.UTF_8); stream.forEach(s -> contentBuilder.append(s).append("\n")); String input = contentBuilder.toString(); InputStream inStream = new ByteArrayInputStream(input.getBytes(StandardCharsets.UTF_8)); org.antlr.v4.runtime.ANTLRInputStream in = new org.antlr.v4.runtime.ANTLRInputStream(inStream); System.out.println("These are the lines:" + contentBuilder); ConditionLexer lexer = new ConditionLexer(in); org.antlr.v4.runtime.CommonTokenStream tokens = new org.antlr.v4.runtime.CommonTokenStream(lexer); ConditionParser parser = new ConditionParser(tokens); ParseTree tree = parser.condition(); // 这里改为调用condition()而非expr() MyVisitor vis = new MyVisitor(); vis.visit(tree);
额外说明
如果你的多行输入是单个跨多行的表达式(比如一个长表达式拆成多行书写),那不需要修改语法,只需要把入口规则改成parser.condition()即可——因为原condition规则已经包含EOF,且空格(含换行)会被隐藏通道处理,跨多行的表达式会被正确解析。
内容的提问来源于stack exchange,提问作者visraj
相关产品推荐
相关产品推荐

