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

我试图提取不带参数的函数名称:

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


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


10打印“您好!”

最佳答案

我认为这个问题确实取决于您的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)


因此,如上所示,linenumber规则是独立存在的,定义文本的其他2条规则是statement的子代,这解释了在获取statement rule文本时输出除行号以外的所有内容。

处理这些问题并使用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()-获取值“ hello”,因为它是包含在printstmt1规则中的表达式的一部分。

:) 祝好运

09-11 19:14
查看更多