Java 在antlr访问者模式中,如何从一个方法导航到另一个方法
我是Antlr的新手,我想知道如何从一个解析中导航entereach方法,我想使用Antlr4完成下面的实现。我有下面的书面功能Java 在antlr访问者模式中,如何从一个方法导航到另一个方法,java,antlr4,Java,Antlr4,我是Antlr的新手,我想知道如何从一个解析中导航entereach方法,我想使用Antlr4完成下面的实现。我有下面的书面功能 下面是该项目的github链接 我像这样存储函数元数据 Map<String,String> map=new HashMap<>(); map.put("FUNCTION.add","Integer:Integer,Integer"); map.put("FUNCTION.concat","String:Stri
下面是该项目的github链接 我像这样存储函数元数据
Map<String,String> map=new HashMap<>();
map.put("FUNCTION.add","Integer:Integer,Integer");
map.put("FUNCTION.concat","String:String,String");
map.put("FUNCTION.mul","Integer:Integer,Integer");
使用visitor实现,我想根据map中存储的函数元数据检查输入是否有效
下面是我正在使用的词法分析器和解析器:
Lexer MyFunctionsLexer.g4:
lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Za-z0-9]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
parser grammar MyFunctionsParser;
options {
tokenVocab=MyFunctionsLexer;
}
function : FUNCTION '.' NAME '('(function | argument (',' argument)*)')';
argument: (NAME | function);
WS : [ \t\r\n]+ -> skip;
解析器MyFunctionsParser.g4:
lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Za-z0-9]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
parser grammar MyFunctionsParser;
options {
tokenVocab=MyFunctionsLexer;
}
function : FUNCTION '.' NAME '('(function | argument (',' argument)*)')';
argument: (NAME | function);
WS : [ \t\r\n]+ -> skip;
我正在使用Antlr4
下面是我根据建议的答案使用的实现
访客实施:
公共类FunctionValidateVisitorImpl扩展MyFunctionsArbaseVisitor{
Map<String, String> map = new HashMap<String, String>();
public FunctionValidateVisitorImpl()
{
map.put("FUNCTION.add", "Integer:Integer,Integer");
map.put("FUNCTION.concat", "String:String,String");
map.put("FUNCTION.mul", "Integer:Integer,Integer");
map.put("FUNCTION.substring", "String:String,Integer,Integer");
}
@Override
public String visitFunctions(@NotNull MyFunctionsParser.FunctionsContext ctx) {
System.out.println("entered the visitFunctions::");
for (int i = 0; i < ctx.getChildCount(); ++i)
{
ParseTree c = ctx.getChild(i);
if (c.getText() == "<EOF>")
continue;
String top_level_result = visit(ctx.getChild(i));
System.out.println(top_level_result);
if (top_level_result == null)
{
System.out.println("Failed semantic analysis: "+ ctx.getChild(i).getText());
}
}
return null;
}
@Override
public String visitFunction( MyFunctionsParser.FunctionContext ctx) {
// Get function name and expected type information.
String name = ctx.getChild(2).getText();
String type=map.get("FUNCTION." + name);
if (type == null)
{
return null; // not declared in function table.
}
String result_type = type.split(":")[0];
String args_types = type.split(":")[1];
String[] expected_arg_type = args_types.split(",");
int j = 4;
ParseTree a = ctx.getChild(j);
if (a instanceof MyFunctionsParser.FunctionContext)
{
String v = visit(a);
if (v != result_type)
{
return null; // Handle type mismatch.
}
} else {
for (int i = j; i < ctx.getChildCount(); i += 2)
{
ParseTree parameter = ctx.getChild(i);
String v = visit(parameter);
if (v != expected_arg_type[(i - j)/2])
{
return null; // Handle type mismatch.
}
}
}
return result_type;
}
@Override
public String visitArgument(ArgumentContext ctx){
ParseTree c = ctx.getChild(0);
if (c instanceof TerminalNodeImpl)
{
// Unclear if what this is supposed to parse:
// Mutate "1" to "Integer"?
// Mutate "Integer" to "String"?
// Or what?
return c.getText();
}
else
return visit(c);
}
}
Lexer:
lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Za-z0-9]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
WS : [ \t\r\n]+ -> skip;
解析器:
parser grammar MyFunctionsParser;
options { tokenVocab=MyFunctionsLexer; }
functions : function* EOF;
function : FUNCTION '.' NAME '(' (function | argument (',' argument)*) ')';
argument: (NAME | function);
详细侦听器:
public class VerboseListener extends BaseErrorListener {
@Override
public void syntaxError(Recognizer<?, ?> recognizer, Object offendingSymbol, int line, int charPositionInLine, String msg, RecognitionException e) {
List<String> stack = ((Parser)recognizer).getRuleInvocationStack();
Collections.reverse(stack);
throw new FunctionInvalidException("line "+line+":"+charPositionInLine+" at "+ offendingSymbol+": "+msg);
}
}
公共类VerboseListener扩展BaseErrorListener{
@凌驾
public void syntaxError(识别器识别器,对象违规符号,int行,int charPositionInLine,字符串msg,识别异常e){
列表堆栈=((解析器)识别器).getRuleInvocationStack();
集合。反向(堆栈);
抛出新函数invalidexception(“行”+line+:“+charPositionInLine+”位于“+officingsymbol+”:“+msg”);
}
}
输出:
它没有进入visitor实现,因为它没有打印
System.out.println(“已输入visitFunctions::”);
语句。我无法使用visit方法遍历子节点。生成的解析器和运行时之间存在版本偏差。此外,生成的.java文件中存在版本偏差,就好像下载并运行了两个Antlr工具版本(4.4和4.7.2),一次不使用-visitor
选项,然后再次使用它。MyFunctionsParser.java的源代码位于antlNestedFunctionParser\FunctionValidator\target\generated sources\antlr4\com\functionvalidate\validate
中。文件顶部显示
// Generated from MyFunctionsParser.g4 by ANTLR 4.4
MyFunctionsParserVisitor.java
的源代码是
// Generated from com\functionvalidate\validate\MyFunctionsParser.g4 by ANTLR 4.7.2
运行时是4.7.2,您可以在
AntlNestedFunctionParser\FunctionValidator
的pom.xml
中声明它。至少在两个位置定义了MyFunctionsLexer.token
,谁知道您正在选择哪一个。我不熟悉与pom.xml
相关联的Antlr构建规则,但它是什么Rated是一个烂摊子(这就是我为Antlr for C#编写自己的构建规则和编辑器的原因)。请确保完全清理目标目录,生成干净的最新.java文件,并且使用正确的Antlr运行时4.7.2。我不知道这是否是问题所在,但在“@Override public String visitFunctions”中使用了“@NotNull”(@NotNull MyFunctionsParser.FunctionsContext ctx)”。在生成的文件MyFunctionsParserBaseListener.java中,声明为“@Override public void enterFunctions(MyFunctionsParser.FunctionsContext ctx){}”。请尝试删除“@NotNull”,然后重新编译并运行。它可能会调用MyFunctionParserBaseSelistener中定义的存根。此外,您可能希望在visitFunctions()中添加println()调用MyFunctionParserBaseListener.java生成的文件,以便查看它是否调用该函数而不是重写。下面是project的github链接。我已删除@NotNull,但它仍然不工作,谢谢它工作!!如何在函数中接受零参数现在它工作了,但每次运行它都会给出顶级结果-->null Failed语义分析:FUNCTION.concat(FUNCTION.substring(String,Integer,Integer),String)您的访问者代码使用==和!=运算符比较字符串。在Java中,使用equals()。使用调试器将帮助您清除程序中的逻辑错误。感谢您,它正在工作!!,如何接受具有零参数的函数,
// Generated from com\functionvalidate\validate\MyFunctionsParser.g4 by ANTLR 4.7.2