Java 在antlr访问者模式中,如何从一个方法导航到另一个方法

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

我是Antlr的新手,我想知道如何从一个解析中导航entereach方法,我想使用Antlr4完成下面的实现。我有下面的书面功能


下面是该项目的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