Я пытаюсь использовать систему JastAdd с генератором синтаксического анализатора ANTLR (v4.7.2). Я использовал его с JJTree / JavaCC, в котором JJTree автоматически создает AST, но я хочу использовать ANTLR, потому что считаю документацию более надежной, а систему в целом более надежной. Однако я не могу понять, как связать AST, сгенерированный ANTLR, с JastAdd. Я также новичок в использовании этих ANTLR, JastAdd и ANT, поэтому, если я сделал или сказал что-то глупое, пожалуйста, будьте терпеливы.
В течение нескольких дней я искал примеры использования ANTLR с JastAdd, но не нашел ни одного. Я полагаю, что это должно быть возможно, поскольку JastAdd упоминает, что с ним можно использовать любой генератор синтаксического анализатора на основе Java.
Я уже знаю, как построить AST (из этого поста: Как создать AST с ANTLR4? ), и сделал это для очень простой грамматики, чтобы начать развивать понимание. Я не понимаю, как связать AST, сгенерированный в моем коде ANTLR, с JastAdd.
Я попытался выяснить, как это сделать при использовании JavaCC / JJTree, чтобы посмотреть, смогу ли я выяснить, как это делается. Из того, что я могу сказать, имена классов узлов AST, генерируемых JJTree, должны совпадать с именами нетерминалов в файле .ast, который используется JastAdd для создания классов для каждого типа узла. Я верю в это, потому что под заголовком «Parsing» в README (http://jastadd.org/releases/jastadd2/R20130412/readme.php), JastAdd упоминается «JavaCC и его расширение для построения деревьев, JJTree, используются для синтаксического анализа. Они предполагают, что верхние классы называются Node и SimpleNode. Обычно JJTree генерирует свои собственные подклассы узла AST, но мы «обманываем» его, чтобы вместо этого использовать классы AST, сгенерированные JastAdd (генерируя их перед запуском JavaCC / JJTree). «Поэтому я дал те же имена моим классам, которые представляют узлы AST и нетерминалы в файле .ast (за исключением нетерминалов, начинающихся с abstract operand
в строках 5-7 ArithmeticParser.ast, поскольку они не являются узлами, но вы не можете представлять выбор между токенами в файле .ast в любом насколько я могу судить иначе. Я не слишком уверен, как справиться с этим, может быть, мне нужно добавить больше классов AST?). Но я не могу сказать, есть ли что-то еще, что мне нужно сделать, чтобы связать их
Еще одна вещь, которую я увидел в README под заголовком «Понимание реализации», заключается в том, что JastAdd создает частичный AST из файла .ast, затем в конечном итоге файлы аспектов .jrag добавляются в AST, и в конце AST классы генерируются. Несколько вещей смущают меня по этому поводу:
(1) Здесь ничего не говорится об использовании AST, сгенерированного любым используемым генератором синтаксического анализатора (будь то ANTLR, JJTree / JavaCC и т. Д.), Поэтому я не совсем понимаю, как это работает в JastAdd.
(2) Если мы генерируем классы AST в конце, как он начинает строить AST до этого?
Я также хочу использовать ant для сборки проекта (и не знаю, что делать, чтобы собрать проект вручную). Я посмотрел файл build.xml примера построения дерева (http://jastadd.cs.lth.se/examples/CalcTree/index.html),) и попытался адаптировать его для использования с ANTLR, но мне это не удалось. Я получаю следующую ошибку: /Users/Blake/Documents/Dataview_Files/GrammarExANTLR/build.xml:34: Unable to determine generated class
.
Я прочитал то, что мне удалось найти об этом в Интернете ( Почему моя задача Ant по сборке ANTLR завершается с ошибкой «Невозможно определить сгенерированный класс»? * ) и (http://palove.kadeco.sk/itblog/posts/40). В первой ссылке есть комментарий:
"Если вы выполняете ant -diagnostics в своей оболочке, в списке 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.
Итак, чтобы подвести итог, мои вопросы:
Как я могу использовать мой AST, сгенерированный с помощью ANTLR с JastAdd?
Как я могу использовать муравья с ANTLR?
Есть ли примеры использования 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>
ant приводит к тому, что JastAdd по какой-то причине не запускается?