ANTLR 4:解析语法

时间:2016-07-06 20:16:12

标签: java antlr4

我想解析AppleSoft Basic脚本中的一些数据。 我选择ANTLR并下载这个语法:jvmBasic

我正在尝试提取没有参数的函数名称:

return parser.prog().line(0).amprstmt(0).statement().getText();

但它返回PRINT“HELLO”,例如除行号以外的完整表达式 这是我要解析的字符串:

  

10打印“你好!”

1 个答案:

答案 0 :(得分:1)

我认为这个问题实际上取决于你的ANTLR程序实现,但是如果你使用的是树木行者/监听器,你可能想要针对特定​​标记的规则而不是整个"语句"规则是循环的,包含许多类型的陈述:

//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类(如图所示here

示例:

-jvmBasicListener.java
-extended to jvmBasicCustomListener.java

void enterPrintstmt1(jvmBasicParser.Printstmt1Context ctx){
System.out.println(ctx.getText());
}

但是,如果所有这些都已设置并且您只想使用单行返回字符串值等,那么尝试通过寻址语句的子节点来访问较低级别的方法可能会工作amprstmt->语句 - > printstmt1->值:

 return  parser.prog().line().amprstmt(0).statement().printstmt1().getText();

可能只是稍微缩小我的答案,专门针对你的输入的规则" 10 PRINT" HELLO" "将是:

linenumber (contains Number) , statement->printstmt1 and statement->datastmt->datum (contains STRINGLITERAL)

因此,如上所示,亚麻布规则本身就存在,而另外两个定义文本的规则是语句的子句,它解释了在获取语句规则文本时输出除行号之外的所有内容。

解决其中的每一个并使用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().PR‌​INT().getText() - 对于PRINT,因为它在printstmt1中被隔离,但在规则中不包括CLR

parser.prog().line(0).amprstmt(0).statement().printstmt1().pr‌intlist().expression().getText() - 获取价值&#34;你好&#34;因为它是printstmt1规则中包含的表达式的一部分。

:)祝你好运