如何使用 Gradle 2.10 将 ANTLR 词法分析器语法导入另一个语法?
How can I import an ANTLR lexer grammar into another grammar using Gradle 2.10?
我一直在通过 Terence Parr 的 The Definitive ANTLR 4 Reference 学习 ANTLR 4,到目前为止我一直在使用 Gradle 2.10 及其构建的- 在 ANTLR 插件中。但是,我在获取一些我从第 4 章第 38-41 页改编的代码以正确使用我的 Gradle 构建脚本时遇到了一些麻烦。 (我使用 Gradle 而不是直接使用 ANTLR 的原因是因为我想最终将 ANTLR 集成到我正在为我的论文制作的 Java 网络应用程序中,我非常喜欢为此使用一个构建工具,这样我就可以自动化 ANTLR-to-Java 代码生成过程并轻松管理我的依赖项。)
我创建了两个 ANTLR 4 语法(我已将其粘贴到这个问题的末尾):src/main/antlr/org/jbduncan/Expr.g4(标准语法)和src/main/antlr/org/jbduncan/CommonLexerRules.g4(词法分析器语法),其中 Expr.g4 取决于 CommonLexerRules.g4 通过 import CommonLexerRules
语句。但是,当我尝试使用 build.gradle 在命令行中 运行 gradlew generateGrammarSource
时(也与我的 [ 一起粘贴到这个问题的末尾=48=]gradle.properties), 我得到以下错误:
12:45:21: Executing external task 'generateGrammarSource'...
:generateGrammarSource
error(110): org\jbduncan\Expr.g4:3:7: can't find or load grammar CommonLexerRules
warning(125): org\jbduncan\Expr.g4:12:11: implicit definition of token NEWLINE in parser
warning(125): org\jbduncan\Expr.g4:13:6: implicit definition of token ID in parser
warning(125): org\jbduncan\Expr.g4:19:6: implicit definition of token INT in parser
:generateGrammarSource FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':generateGrammarSource'.
> There was 1 error during grammar generation
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 3.166 secs
There was 1 error during grammar generation
12:45:24: External task execution finished 'generateGrammarSource'.
查看此错误消息,在我看来 Gradle 的 ANTLR 插件能够找到 Expr.g4 但不知何故无法找到 CommonLexerRules.g4。
我尝试使用几个外部 Gradle 插件 (https://github.com/melix/antlr4-gradle-plugin and https://github.com/Abnaxos/gradle-antlr4-plugin) 而不是内置插件来解决这个错误,但是当我尝试每个插件时,它们介绍了他们自己无法解决的问题。
使用直接从 ANTLR 网站下载的 ANTLR 4.5.2 jar 可以让我毫无问题地编译我的两个语法,但正如我之前讨论的那样,这是一个非常不受欢迎的选择对我来说,因为我必须手动编译我的语法,而我相信 Gradle 可以自动为我完成。
我的问题是:如何解决上述错误并Gradle将我的词法分析器语法导入我的其他语法?
build.gradle
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'antlr'
sourceCompatibility = 1.8
targetCompatibility = 1.8
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
group = 'org.jbduncan'
version = '1.0-SNAPSHOT'
mainClassName = 'org.jbduncan.Application'
repositories {
jcenter()
}
dependencies {
antlr "org.antlr:antlr4:$antlrVersion"
compile "com.google.guava:guava:$guavaVersion"
testCompile "com.google.guava:guava-testlib:$guavaVersion"
testCompile "com.google.truth:truth:$truthVersion"
testCompile "junit:junit:$junitVersion"
}
// Send all generated source code to a directory other than build/, to workaround an issue in
// IntelliJ IDEA where it fails to recognise source files in build/.
def generatedJavaSourcesDir = 'src/generated/java'
generateGrammarSource {
arguments += ['-visitor']
outputDirectory = file(generatedJavaSourcesDir)
}
sourceSets {
main {
java {
srcDir generatedJavaSourcesDir
}
}
}
clean {
delete generatedJavaSourcesDir
}
task wrapper(type: Wrapper) {
distributionUrl = "http://services.gradle.org/distributions/gradle-$gradleVersion-bin.zip"
}
gradle.properties
gradleVersion=2.10
# Dependency versions
antlrVersion=4.5
guavaVersion=19.0
junitVersion=4.12
truthVersion=0.28
src/main/antlr/org/jbduncan/Expr.g4
grammar Expr;
import CommonLexerRules; // includes all rules from CommonLexerRules.g4
@header {
package org.jbduncan;
}
/** The start rule; begin parsing here. */
prog: stat+;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| NEWLINE # blank
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
MUL: '*'; // assigns token name to '*' used above in grammar
DIV: '/';
ADD: '+';
SUB: '-';
src/main/antlr/org/jbduncan/CommonLexerRules.g4
lexer grammar CommonLexerRules; // note "lexer grammar"
ID: [a-zA-Z]+ ; // match identifiers
INT: [0-9]+ ; // match integers
NEWLINE: '\r'? '\n' ; // return newlines to parser (is end-statement signal)
WS: [ \t] -> skip ; // toss out whitespace
src/main/java/org/jbduncan/Application.java
package org.jbduncan;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public final class Application {
public static void main(String[] args) throws IOException {
String inputFile = (args.length > 0) ? args[0] : null;
InputStream inputStream = (inputFile == null) ? System.in : new FileInputStream(inputFile);
ANTLRInputStream input = new ANTLRInputStream(inputStream);
ExprLexer lexer = new ExprLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExprParser parser = new ExprParser(tokens);
ParseTree tree = parser.prog(); // parse; start at prog
System.out.println(tree.toStringTree(parser)); // print tree as text
}
}
在 Gradle forum:
上发布问题后,我设法找到了问题的答案
generateGrammarSource {
arguments << "-lib" << "src/main/antlr/org/jbduncan"
}
其中 "src/main/antlr/org/jbduncan"
是你的 antlr .g4
库的路径。
我一直在通过 Terence Parr 的 The Definitive ANTLR 4 Reference 学习 ANTLR 4,到目前为止我一直在使用 Gradle 2.10 及其构建的- 在 ANTLR 插件中。但是,我在获取一些我从第 4 章第 38-41 页改编的代码以正确使用我的 Gradle 构建脚本时遇到了一些麻烦。 (我使用 Gradle 而不是直接使用 ANTLR 的原因是因为我想最终将 ANTLR 集成到我正在为我的论文制作的 Java 网络应用程序中,我非常喜欢为此使用一个构建工具,这样我就可以自动化 ANTLR-to-Java 代码生成过程并轻松管理我的依赖项。)
我创建了两个 ANTLR 4 语法(我已将其粘贴到这个问题的末尾):src/main/antlr/org/jbduncan/Expr.g4(标准语法)和src/main/antlr/org/jbduncan/CommonLexerRules.g4(词法分析器语法),其中 Expr.g4 取决于 CommonLexerRules.g4 通过 import CommonLexerRules
语句。但是,当我尝试使用 build.gradle 在命令行中 运行 gradlew generateGrammarSource
时(也与我的 [ 一起粘贴到这个问题的末尾=48=]gradle.properties), 我得到以下错误:
12:45:21: Executing external task 'generateGrammarSource'...
:generateGrammarSource
error(110): org\jbduncan\Expr.g4:3:7: can't find or load grammar CommonLexerRules
warning(125): org\jbduncan\Expr.g4:12:11: implicit definition of token NEWLINE in parser
warning(125): org\jbduncan\Expr.g4:13:6: implicit definition of token ID in parser
warning(125): org\jbduncan\Expr.g4:19:6: implicit definition of token INT in parser
:generateGrammarSource FAILED
FAILURE: Build failed with an exception.
* What went wrong:
Execution failed for task ':generateGrammarSource'.
> There was 1 error during grammar generation
* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.
BUILD FAILED
Total time: 3.166 secs
There was 1 error during grammar generation
12:45:24: External task execution finished 'generateGrammarSource'.
查看此错误消息,在我看来 Gradle 的 ANTLR 插件能够找到 Expr.g4 但不知何故无法找到 CommonLexerRules.g4。
我尝试使用几个外部 Gradle 插件 (https://github.com/melix/antlr4-gradle-plugin and https://github.com/Abnaxos/gradle-antlr4-plugin) 而不是内置插件来解决这个错误,但是当我尝试每个插件时,它们介绍了他们自己无法解决的问题。
使用直接从 ANTLR 网站下载的 ANTLR 4.5.2 jar 可以让我毫无问题地编译我的两个语法,但正如我之前讨论的那样,这是一个非常不受欢迎的选择对我来说,因为我必须手动编译我的语法,而我相信 Gradle 可以自动为我完成。
我的问题是:如何解决上述错误并Gradle将我的词法分析器语法导入我的其他语法?
build.gradle
apply plugin: 'java'
apply plugin: 'application'
apply plugin: 'antlr'
sourceCompatibility = 1.8
targetCompatibility = 1.8
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
group = 'org.jbduncan'
version = '1.0-SNAPSHOT'
mainClassName = 'org.jbduncan.Application'
repositories {
jcenter()
}
dependencies {
antlr "org.antlr:antlr4:$antlrVersion"
compile "com.google.guava:guava:$guavaVersion"
testCompile "com.google.guava:guava-testlib:$guavaVersion"
testCompile "com.google.truth:truth:$truthVersion"
testCompile "junit:junit:$junitVersion"
}
// Send all generated source code to a directory other than build/, to workaround an issue in
// IntelliJ IDEA where it fails to recognise source files in build/.
def generatedJavaSourcesDir = 'src/generated/java'
generateGrammarSource {
arguments += ['-visitor']
outputDirectory = file(generatedJavaSourcesDir)
}
sourceSets {
main {
java {
srcDir generatedJavaSourcesDir
}
}
}
clean {
delete generatedJavaSourcesDir
}
task wrapper(type: Wrapper) {
distributionUrl = "http://services.gradle.org/distributions/gradle-$gradleVersion-bin.zip"
}
gradle.properties
gradleVersion=2.10
# Dependency versions
antlrVersion=4.5
guavaVersion=19.0
junitVersion=4.12
truthVersion=0.28
src/main/antlr/org/jbduncan/Expr.g4
grammar Expr;
import CommonLexerRules; // includes all rules from CommonLexerRules.g4
@header {
package org.jbduncan;
}
/** The start rule; begin parsing here. */
prog: stat+;
stat: expr NEWLINE # printExpr
| ID '=' expr NEWLINE # assign
| NEWLINE # blank
;
expr: expr op=('*'|'/') expr # MulDiv
| expr op=('+'|'-') expr # AddSub
| INT # int
| ID # id
| '(' expr ')' # parens
;
MUL: '*'; // assigns token name to '*' used above in grammar
DIV: '/';
ADD: '+';
SUB: '-';
src/main/antlr/org/jbduncan/CommonLexerRules.g4
lexer grammar CommonLexerRules; // note "lexer grammar"
ID: [a-zA-Z]+ ; // match identifiers
INT: [0-9]+ ; // match integers
NEWLINE: '\r'? '\n' ; // return newlines to parser (is end-statement signal)
WS: [ \t] -> skip ; // toss out whitespace
src/main/java/org/jbduncan/Application.java
package org.jbduncan;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTree;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
public final class Application {
public static void main(String[] args) throws IOException {
String inputFile = (args.length > 0) ? args[0] : null;
InputStream inputStream = (inputFile == null) ? System.in : new FileInputStream(inputFile);
ANTLRInputStream input = new ANTLRInputStream(inputStream);
ExprLexer lexer = new ExprLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
ExprParser parser = new ExprParser(tokens);
ParseTree tree = parser.prog(); // parse; start at prog
System.out.println(tree.toStringTree(parser)); // print tree as text
}
}
在 Gradle forum:
上发布问题后,我设法找到了问题的答案generateGrammarSource {
arguments << "-lib" << "src/main/antlr/org/jbduncan"
}
其中 "src/main/antlr/org/jbduncan"
是你的 antlr .g4
库的路径。