我想从 AppleSoft Basic 脚本中解析一些数据。 我选择 ANTLR 并下载这个语法:jvmBasic
我正在尝试提取不带参数的函数名称:
return parser.prog().line(0).amprstmt(0).statement().getText();
但它返回 PRINT"HELLO"例如除行号之外的完整表达式 这是我要解析的字符串:
10 PRINT "Hello!"
最佳答案
我认为这个问题实际上取决于您的 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() 方法,当您遇到这些情况时,除行号之外的所有内容(行号是语句规则之外的规则)。
如果您希望针对这些特定规则来处理遇到它们时发生的情况,您很可能希望通过扩展 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)
因此,如上所示,行号规则独立存在,定义文本的其他 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 规则中包含的表达式的一部分。
:)祝你好运
关于java - ANTLR 4 : Parsing grammar,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38232989/