可以将ANTLR与JastAdd一起使用吗?

时间:2019-06-17 23:33:16

标签: ant antlr antlr4

我正在尝试将JastAdd系统与ANTLR(v4.7.2)解析器生成器一起使用。我在JJTree / JavaCC中使用了它,在JJTree / JavaCC中JJTree自动构建AST,但是我想使用ANTLR,因为我发现文档更加健壮,整个系统也更加健壮。但是,我不知道如何将ANTLR生成的AST链接到JastAdd。我对使用这些ANTLR,JastAdd和ANT还是很陌生,因此,如果我做过或说过一些愚蠢的事情,请耐心等待。

几天来,我一直在寻找将ANTLR与JastAdd结合使用的示例,但没有找到任何示例。我认为这是有可能的,因为JastAdd提到任何基于Java的解析器生成器都可以使用它。 我已经知道如何构建AST(来自这篇文章:How to create AST with ANTLR4?),并且这样做是为了使一个非常简单的语法开始形成理解。我不明白的是如何将我的ANTLR代码中生成的AST链接到JastAdd。

在尝试使用JavaCC / JJTree时,我尝试研究如何完成此操作,以查看是否可以完成操作。据我所知,JJTree生成的AST节点的类名必须与.ast文件中的非终端名相同,JastAdd使用该文件为每种类型的节点创建类。我之所以这样认为,是因为在README(http://jastadd.org/releases/jastadd2/R20130412/readme.php)的“解析”标题下,JastAdd提到:“ JavaCC及其树构建扩展JJTree用于解析。它们假定使用称为Node和SimpleNode的顶级类。通常,JJTree会生成自己的AST节点子类,但我们“愚弄”它来使用JastAdd生成的AST类(通过在运行JavaCC / JJTree之前生成它们)。因此,我为代表AST节点的类和.ast文件中的非终端使用了相同的名称(除了ArithmeticParser.ast的第5-7行中从abstract operand延伸的非终端,因为它们不是节点,但据我所知,您无法以任何其他方式在.ast文件中的标记之间做出选择。我不太确定如何处理此问题,也许我需要添加更多AST类?)。但是我真的无法确定是否还需要做其他任何操作来将它们链接起来?

我在自述文件中“实现的理解”标题下看到的另一件事是JastAdd从.ast文件创建了部分AST,然后最终将.jrag方面文件添加到AST中,最后是AST类生成。有几件事使我感到困惑: (1)这与使用由任何正在使用的解析器生成器(例如ANTLR,JJTree / JavaCC等)生成的AST无关,因此我并不真正了解JastAdd的工作原理。 (2)如果最终要生成AST类,那么在此之前如何开始构建AST?

我还想使用ant来构建项目(并且不知道该如何手动构建项目)。我查看了树构建示例(http://jastadd.cs.lth.se/examples/CalcTree/index.html)的build.xml文件,并尝试对其进行修改以与ANTLR一起使用,但是我一直没有成功。我收到以下错误:/Users/Blake/Documents/Dataview_Files/GrammarExANTLR/build.xml:34: Unable to determine generated class

我已经阅读了一些关于网上(Why does my ANTLR build Ant task fail with "Unable to determine generated class"?和(http://palove.kadeco.sk/itblog/posts/40)的知识。在第一个链接中,有一个注释:

  

“如果在外壳上进行ant-诊断,则在ANT_HOME / lib jar列表下应该只有ant-antlr.jar和ant-antlr3.jar。如果还有antlr2?.jar,请尝试将其删除。 ”

我这样做了,但我只有ant-antlr.jar,没有ant-antlr2.jar,ant-antlr3.jar或ant-antlr4.jar。有谁知道我在哪里可以得到ant-antlr4.jar(如果存在)? 我还无法构建项目,这进一步阻止了我深入研究将AST链接到JastAdd。

总而言之,我的问题是:

  1. 我如何将ANTLR生成的AST与JastAdd一起使用?

  2. 如何在ANTLR中使用ant?

  3. 是否有将ANTLR与JastAdd结合使用的示例?

我不确定需要什么代码,因此我将发布一些内容并添加可能需要的其他内容。

语法(ArithmeticParser.g4):


/** TOKENS - name must begin with uppercase letter */
// must wrap in () to use -> skip command
WHITESPACE : (' ' | '\t' | '\n' | '\r') -> skip;
EQ : 'equals' | '=' | '->';
OPERATOR : PLUS | MINUS | MULT | DIV | MOD | EXP ;
// these are fragments, meaning they can only be used by LEXER not PARSER
fragment PLUS : 'plus' | '+';
fragment MINUS : 'minus' | '-';
fragment MULT : 'times' | '*';
fragment DIV : 'divby' | '/';
fragment MOD : 'mod' | '%';
fragment EXP : 'pow' | '^';
INT : DIGIT;
fragment DIGIT : [0-9]+;
ID : [a-zA-Z] IDTAIL*;
fragment IDTAIL : [a-zA-Z] | [0-9];

/** Production rules - name must begin with lowercase letter */
root : '<BEGIN' statement+ 'END>' EOF;
statement : (assignment | arithmeticExpression) ';';
assignment : ID EQ arithmeticExpression;
arithmeticExpression : lOp = (INT | ID) OPERATOR rOp = (INT | ID);

ArithmeticParser.ast

RootNode ::= StatementNode*;
abstract StatementNode;
AssignmentNode:StatementNode ::= <ID> ArithmeticExpressionNode;
ArithmeticExpressionNode:StatementNode ::= lOp:operand <OPERATOR> rOp:operand;
abstract operand;
intOp:operand ::= <INT>;
idOp:operand ::= <ID>;

与节点类型相对应的类:

/**
 * Required as superclass of all nodes for AstBuilderVisitor class
 */
abstract class AstNode { }

class RootNode extends AstNode {
    // children nodes of the root node
    ArrayList<StatementNode> statementList;
    public RootNode() {
        this.statementList = new ArrayList<>();
        System.out.println("\tNEW RootNode successfully created");
    }
}

abstract class StatementNode extends AstNode { }

class AssignmentNode extends StatementNode {
    String id;
    ArithmeticExpressionNode arithmeticExpression;

    AssignmentNode(String id, ArithmeticExpressionNode arithmeticExpression) {
        this.id = id;
        this.arithmeticExpression = arithmeticExpression;
        System.out.println("\tNEW AssignmentNode: id = " + id);
    }
}

class ArithmeticExpressionNode extends StatementNode {
    char operator;
    char lOpType, rOpType;
    String lOp, rOp;

    public ArithmeticExpressionNode(char operator, char lOpType, char rOpType, String lOp, String rOp) {
        this.operator = operator;
        this.lOpType = lOpType;
        this.rOpType = rOpType;
        this.lOp = lOp;
        this.rOp = rOp;
        System.out.println("\tNEW ArithmeticExpressionNode: " + lOp + " "  + operator + " " + rOp);
    }
}

最后是build.xml文件:

<!-- A project is one or more targets that executes tasks. This project
     has three targets: build, clean, and test. The build target is
     set as the default target and used if no target is supplied. -->
<project name="Compiler" default="build" basedir=".">

    <!-- The name used for the ANTLR files  -->
    <property name="parser.name" value="ArithmeticParser"/>

    <!-- The directory where generated files will be stored -->
    <property name="package" value="AST"/>

    <!-- The directory where tools like ANTLR and jastadd are stored. -->
    <property name="tools" value="tools"/>

    <!-- The JastAdd ANT task -->
    <taskdef classname="jastadd.JastAddTask" name="jastadd" classpath="${tools}/jastadd2.jar" />

    <!-- gen:
      - Creates a directory for generated files.
      - Generates the AST classes using jastadd.
      - Generates the parser using antlr. -->
    <target name="gen">
        <mkdir dir="${package}"/>
        <jastadd package="${package}" jjtree="false" grammar="${parser.name}">
            <fileset dir=".">
                <include name="**/*.ast"/>
                <include name="**/*.jrag"/>
                <include name="**/*.jadd"/>
            </fileset>
        </jastadd>
        <antlr
                target="${parser.name}.g4"
                outputdirectory="${package}"
        />
    </target>

    <!-- build: (automatically runs "gen" if needed)
      - compiles all java files
      - intended to be used from the command line
        (in Eclipse you don't need this target since Eclipse compiles
        java files automatically)
      - you can change "javac1.4" to "jikes" for faster compilation -->
    <target name="build" depends="gen">
        <javac
                compiler="javac1.4"
                srcdir="."
                classpath="${tools}/junit.jar"
        />
    </target>

    <!-- clean:
      - deletes the directory holding generated files
      - deletes all .class files (recursively) -->
    <target name="clean">
        <delete dir="${package}"/>
        <delete>
            <fileset dir="." includes="**/*.class"/>
        </delete>
    </target>
</project>

编辑:好的,我找到了一种方法,以便在build.xml中替换

<antlr
    target="${parser.name}.g4"
    outputdirectory="${package}"
/>

<java jar="tools/antlr-4.7.2-complete.jar" fork="true">
    <arg value="-o"/>
    <arg value="."/>
    <arg value="${parser.name}.g4"/>
</java>

所以现在antlr运行了。但是现在JastAdd根本没有运行。我不确定为什么会这样。如果存在ant-antlr4.jar仍然有用。我想知道是否仅使用此<java>蚂蚁任务会导致JastAdd由于某种原因而无法运行?

0 个答案:

没有答案