首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >ANTLR 4:语法分析

ANTLR 4:语法分析
EN

Stack Overflow用户
提问于 2016-07-06 20:16:11
回答 1查看 1.5K关注 0票数 0

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

我试图提取没有参数的函数名:

代码语言:javascript
复制
return parser.prog().line(0).amprstmt(0).statement().getText();

但是它返回打印“HELLO”,例如完全表达式,但这里的行号是我想解析的字符串:

10打印“你好!”

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-07-07 00:09:26

我认为这个问题实际上取决于您的ANTLR程序的实现,但是如果您使用的是一个树用户/侦听器,那么您可能希望针对特定标记的规则,而不是整个循环的“语句”规则,它包含许多类型的语句:

代码语言:javascript
复制
//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类型语法中可以看到,此语法中的语句规则包括打印语句的规则以及所有其他类型的语句,因此它将包含10、print和hello,并随后在遇到其中任何一个语句时,使用getText()方法返回文本,但行号除外,这是语句规则之外的规则。

如果您希望针对这些特定规则来处理遇到这些规则时所发生的事情,那么您很可能希望通过扩展jvmBasiListener类来为每个规则添加功能,如所示这里所示。

示例:

代码语言:javascript
复制
-jvmBasicListener.java
-extended to jvmBasicCustomListener.java

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

但是,如果所有这些都是安装的,并且您只是希望使用单行返回字符串值等,那么您就可以通过寻址语句的子节点来访问较低级别的方法,这样就可以使用amprstmt->语句->printstmt1 1->值:

代码语言:javascript
复制
 return  parser.prog().line().amprstmt(0).statement().printstmt1().getText();

为了稍微缩小我的回答范围,专门针对您输入的"10打印“"HELLO”的规则是:

代码语言:javascript
复制
linenumber (contains Number) , statement->printstmt1 and statement->datastmt->datum (contains STRINGLITERAL)

因此,正如上面所示,linenumber规则本身就存在,而定义文本的其他2个规则是语句的子规则,这解释了在获取语句规则文本时输出除行号以外的所有内容。

解决这些问题并使用getText()而不是语句之类的包含性规则可能会给出您想要的结果。

我将更新以解决您的问题,因为答案可能会稍长一些,在我看来,处理特定规则而不是生成侦听器或访问者的最简单方法是在语法文件规则中实现以下操作:

代码语言:javascript
复制
printstmt1
   : (PRINT | QUESTION) printlist? {System.out.println("Print"); //your java code }
   ;

这将只允许您处理每条规则,并执行您希望执行的任何java操作。然后,您可以简单地编译代码,如下所示:

代码语言:javascript
复制
java -jar antlr-4.5.3-complete.jar jvmBasic.g4 -visitor

在此之后,您可以简单地运行您希望的代码,下面是一个示例:

代码语言:javascript
复制
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();
    }

}

然后,该示例的输出将是公正的:

代码语言:javascript
复制
Print

您还可以将您喜欢的任何Java方法合并到语法中,以解决遇到的每条规则,或者开发您自己的类和方法来处理它,或者直接打印出结果。

更新

现在只想回答最新的问题:parser.line().linenumber().getText() -表示行号,因为行不是语句的一部分。

parser.prog().line(0).amprstmt(0).statement().printstmt1().PR‌​INT().getText() -由于打印是在printstmt1中隔离的,所以在规则中不包括CLR。

parser.prog().line(0).amprstmt(0).statement().printstmt1().pr‌intlist().expression().getText() -获得值"hello“,因为它是包含在printstmt1规则中的表达式的一部分。

*祝你好运

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/38232989

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档