我正在尝试将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。
总而言之,我的问题是:
我如何将ANTLR生成的AST与JastAdd一起使用?
如何在ANTLR中使用ant?
是否有将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由于某种原因而无法运行?