我认为这个问题确实取决于您的 ANTLR 程序实现,但如果您使用的是 treewalker/listener,您可能希望针对特定标记的规则而不是整个“语句”规则,该规则是循环的并且包含多种类型声明:
//each line can have one to many amprstmt's
line
: (linenumber ((amprstmt (COLON amprstmt?)*) | (COMMENT | REM)))
;
amprstmt
: (amperoper? statement) //encounters a statement here
| (COMMENT | REM)
;
//statements can be made of 1 to many sub statements
statement
: (CLS | LOAD | SAVE | TRACE | NOTRACE | FLASH | INVERSE | GR | NORMAL | SHLOAD | CLEAR | RUN | STOP | TEXT | HOME | HGR | HGR2)
| prstmt
| printstmt1 //the print rule
//MANY MANY OTHER RULES HERE TOO LONG TO PASTE........
;
//the example rule that occurs when the token's "print" is encountered
printstmt1
: (PRINT | QUESTION) printlist?
;
printlist
: expression (COMMA | SEMICOLON)? printlist*
;
从这里的 BNF 类型语法中可以看出,该语法中的语句规则包括 print 语句以及所有其他类型语句的规则,因此它将包含 10、PRINT 和 hello,然后返回带有getText() 方法,当您遇到任何这些情况时,除了 linenumber 之外的所有内容,它是语句规则之外的规则。
如果您想针对这些特定规则来处理遇到它们时发生的情况,您很可能希望通过扩展 jvmBasiListener 类来为 ANTLR 为每个规则生成的每个方法添加功能,如图所示 here
示例:
-jvmBasicListener.java
-extended to jvmBasicCustomListener.java
void enterPrintstmt1(jvmBasicParser.Printstmt1Context ctx){
System.out.println(ctx.getText());
}
但是,如果所有这些都已设置,并且您只想使用单行返回字符串值等,那么尝试通过寻址语句的子节点来访问较低级别的方法可能会起作用 amprstmt->statement- >printstmt1->值:
return parser.prog().line().amprstmt(0).statement().printstmt1().getText();
只是为了稍微缩小我的回答范围,专门针对您的输入“10 PRINT "HELLO"”的规则是:
linenumber (contains Number) , statement->printstmt1 and statement->datastmt->datum (contains STRINGLITERAL)
因此,如上所示,linenumber 规则是独立存在的,而定义文本的其他 2 个规则是语句的子级,这解释了在获取语句规则文本时输出除行号之外的所有内容。
解决每一个问题并使用 getText() 而不是诸如语句之类的包含规则可能会给您想要的结果。
我会更新以解决您的问题,因为答案可能会稍长一些,我认为处理特定规则而不是生成侦听器或访问者的最简单方法是在您的语法文件规则中执行如下操作:
printstmt1
: (PRINT | QUESTION) printlist? {System.out.println("Print"); //your java code }
;
这只会让您处理每个规则并执行您希望执行的任何 java 操作。然后,您可以简单地使用以下代码编译代码:
java -jar antlr-4.5.3-complete.jar jvmBasic.g4 -visitor
在此之后,您可以随心所欲地运行您的代码,这是一个示例:
import JVM1.jvmBasicLexer;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
public class Jvm extends jvmBasicBaseVisitor<Object> {
public static void main(String[] args) {
jvmBasicLexer lexer = new jvmBasicLexer(new ANTLRInputStream("10 PRINT \"Hello!\""));
jvmBasicParser parser = new jvmBasicParser(new CommonTokenStream(lexer));
ParseTree tree = parser.prog();
}
}
这个例子的输出就是:
Print
您还可以在语法中合并任何您喜欢的 Java 方法来处理遇到的每个规则,并开发您自己的类和方法来处理它或直接打印出结果。
更新
现在只是为了解决最新的问题:
parser.line().linenumber().getText() - 对于行号,因为行不是语句的一部分
parser.prog().line(0).amprstmt(0).statement().printstmt1().PRINT().getText() - 用于 PRINT,因为它在 printstmt1 中被隔离,但不包括规则中的 CLR
parser.prog().line(0).amprstmt(0).statement().printstmt1().printlist().expression().getText() - 获取值“hello”,因为它是 printstmt1 规则中包含的表达式的一部分。
:) 祝你好运