创建 ANTLR4 语法文件
ANTLR4 使用 .g4
文件来定义语法,如下图
lexer grammar Comments;
import Symbol;
BLOCK_COMMENT: '/*' .*? '*/' -> channel(HIDDEN);
INLINE_COMMENT: '--' ~[\r\n]* ('\r'? '\n' | EOF) -> channel(HIDDEN);
生成解析器和词法分析器类
**使用 **maven
命令 工具生成 词法分析器类
、语法分析器类
和抽象语法树(AST)访问类
mvn clean process-sources
编写 Java 代码
public class OracleSQLParser implements ISQLParser {
@NonNull
protected final CommonTokenStream tokenStream;
@NonNull
protected final OracleStatementParser parser;
@NonNull
protected final SQLParserOption option;
public OracleSQLParser(@NonNull String sql, @NonNull SQLParserOption option) {
// String `SQL`转 `Stream`
CharStream input = CharStreams.fromString(sql);
// 创建词法分析器
OracleStatementLexer lexer = new OracleStatementLexer(input);
// 创建 token 流
tokenStream = new CommonTokenStream(lexer);
// 创建语法分析器
parser = new OracleStatementParser(tokenStream);
this.option = option;
}
@NonNull
@Override
public Parser getParser() {
return parser;
}
}
SQL
转 Stream
CharStream input = CharStreams.fromString(sql);
创建词法分析器
OracleStatementLexer lexer = new OracleStatementLexer(input);
创建语法分析器
parser = new OracleStatementParser(tokenStream);
语法树访问
为了处理和解析语法树,我们需要实现一个语法树访问者类
定义语法树访问者类
public class OracleASTNodeBuildVisitor extends OracleStatementBaseVisitor<ISQLDataNode> implements ISQLASTNodeBuildVisitor {
@NonNull
private final List<ISQLStatement> statements;
@NonNull
private final TokenStream tokenStream;
@NonNull
private final Set<Token> visitHiddenTokens;
@NonNull
private final SQLParserOption option;
public OracleASTNodeBuildVisitor(@NonNull final List<ISQLStatement> statements,
@NonNull final TokenStream tokenStream,
@NonNull final SQLParserOption option) {
this.statements = statements;
this.tokenStream = tokenStream;
this.visitHiddenTokens = new LinkedHashSet<>();
this.option = option;
}
@Override
public void addVisitHiddenToken(@NonNull Token token) {
visitHiddenTokens.add(token);
}
@Override
public Set<Token> getVisitHiddenTokens() {
return visitHiddenTokens;
}
@Override
public ISQLDataNode visitExecute(ExecuteContext ctx) {
ISQLStatement preStatement = null;
for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree child = ctx.getChild(i);
// EOF
if (isEOF(child)) {
continue;
}
ISQLDataNode childSQLNode = child.accept(this);
if (childSQLNode == null) {
continue;
}
if (childSQLNode.isISQLStatement()) {
ISQLStatement statement = (ISQLStatement) childSQLNode;
beforeAddStatement(statement);
statements.add(statement);
preStatement = statement;
} else if (childSQLNode.isSQLTerminalNode()) {
SQLTerminalNode terminalNode = (SQLTerminalNode) childSQLNode;
if (preStatement != null) {
if (terminalNode.isSemi()) {
preStatement.setAfterSemi(terminalNode);
} else if (terminalNode.isSlash()) {
preStatement.setAfterSlash(terminalNode);
}
}
}
}
return null;
}
private void beforeAddStatement(@NonNull ISQLStatement statement) {
// pretty
statement.setFormatKind(option.getFormatKind());
}
}
调用语法树访问者类
// 转换 自定义 AST
@NonNull
@Override
public List<ISQLStatement> parseStatements() {
List<ISQLStatement> statements = new ArrayList<>();
OracleASTNodeBuildVisitor visitor = new OracleASTNodeBuildVisitor(statements, tokenStream, option);
parser.execute().accept(visitor);
return statements;
}
总结
通过以上步骤,你可以在 Java 中使用 ANTLR4 构建和使用解析器。ANTLR4 提供了强大的工具和灵活的语法定义方式,使得构建复杂语言处理器变得相对简单。希望这篇文章对你有所帮助