在antlr访问者模式中,如何从一种方法导航到另一种方法 [英] In antlr visitor pattern how to navigate from one method to another

查看:65
本文介绍了在antlr访问者模式中,如何从一种方法导航到另一种方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是Antlr的新手,我想知道如何从解析每个输入的方法进行导航,我想使用Antlr4完成以下实现.我具有下面编写的功能.

I am a newbie to Antlr I wanted to know how to navigate from one parse the enter each method and I wanted the below implementation to be done using Antlr4. I am having the below-written functions.

下面是项目的github链接. https://github.com/VIKRAMAS/AntlrNestedFunctionParser/tree/master

Below is the github link of project. https://github.com/VIKRAMAS/AntlrNestedFunctionParser/tree/master

1. FUNCTION.add(Integer a,Integer b)
2. FUNCTION.concat(String a,String b)
3. FUNCTION.mul(Integer a,Integer b)

我正在像这样存储函数元数据.

And I am storing the functions metadata like this.

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");

其中Integer:Integer,Integer表示Integer是返回类型,函数将接受的输入参数是Integer,Integer.

Where, Integer:Integer,Integer represents Integer is the return type and input params the function will accespts are Integer,Integer.

如果输入是这样的

FUNCTION.concat(Function.substring(String,Integer,Integer),String)
or
FUNCTION.concat(Function.substring("test",1,1),String)

使用访问者实现,我想根据存储在地图中的功能元数据检查输入是否有效.

Using the visitor implementation I wanted to check whether the input is validate or not against the functions metadata stored in map.

下面是我正在使用的词法分析器和解析器:

Below is the lexer and parser that I'm using:

Lexer MyFunctionsLexer.g4:

lexer grammar MyFunctionsLexer;

FUNCTION: 'FUNCTION';

NAME: [A-Za-z0-9]+;

DOT: '.';

COMMA: ',';

L_BRACKET: '(';

R_BRACKET: ')';

解析器MyFunctionsParser.g4:

parser grammar MyFunctionsParser;

options {
    tokenVocab=MyFunctionsLexer;
}

function : FUNCTION '.' NAME '('(function | argument (',' argument)*)')';

argument: (NAME | function);

WS : [ \t\r\n]+ -> skip;

我正在使用Antlr4.

I am using Antlr4.

以下是我根据建议的答案使用的实现.

Below is the implementation I'm using as per the suggested answer.

访客实施: 公共类FunctionValidateVisitorImpl扩展了MyFunctionsParserBaseVisitor {

Visitor Implementation: public class FunctionValidateVisitorImpl extends MyFunctionsParserBaseVisitor {

    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);
    }


}

Testcalss:

Testcalss:

public class FunctionValidate {


    public static void main(String[] args) {
        String input = "FUNCTION.concat(FUNCTION.substring(String,Integer,Integer),String)";
        ANTLRInputStream str = new ANTLRInputStream(input);
        MyFunctionsLexer lexer = new MyFunctionsLexer(str);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        MyFunctionsParser parser = new MyFunctionsParser(tokens);
        parser.removeErrorListeners(); // remove ConsoleErrorListener 
        parser.addErrorListener(new VerboseListener()); // add ours
        FunctionsContext tree = parser.functions();
        FunctionValidateVisitorImpl visitor = new FunctionValidateVisitorImpl();
        visitor.visit(tree);
    }


}

词法分析器:

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);

    }
}

输出: 由于未打印System.out.println("entered the visitFunctions::");语句,因此未进入访客实现.我无法通过使用visit方法来遍历子节点.

Output: It is not entering visitor implementation as it is not printing System.out.println("entered the visitFunctions::"); statement. I am not able to walk through the child nodes by using visit method.

推荐答案

您在生成的解析器和运行时之间存在版本偏差.此外,您生成的.java文件中存在版本偏差,就像您下载并运行了两个Antlr工具版本(4.4和4.7.2)一样,一次不使用-visitor选项,然后再次使用它. MyFunctionsParser.java的源代码在AntlrNestedFunctionParser\FunctionValidator\target\generated-sources\antlr4\com\functionvalidate\validate中.在文件顶部,显示为

You have a version skew between your generated parser and the runtime. Further, you have a version skew in your generated .java files, as though you downloaded and ran two Antlr tool versions (4.4 and 4.7.2), once without the -visitor option, then again with it. The source for MyFunctionsParser.java is in AntlrNestedFunctionParser\FunctionValidator\target\generated-sources\antlr4\com\functionvalidate\validate. At the top of the file, it says

// 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,可在AntlrNestedFunctionParser\FunctionValidator中的pom.xml中进行设置.至少在两个位置定义了MyFunctionsLexer.tokens,这是您知道的.我不熟悉与pom.xml关联的Antlr构建规则,但是生成的内容很烂(这就是为什么我为Antlr for C#编写了自己的构建规则和编辑器的原因).确保完全清理目标目录,生成干净的最新.java文件,并且使用的是正确的Antlr运行时4.7.2.

The runtime is 4.7.2, which you state in pom.xml in AntlrNestedFunctionParser\FunctionValidator. There's MyFunctionsLexer.tokens defined in at least two locations, which one you are picking up, who knows. I'm not familiar with the Antlr build rules associated with the pom.xml, but what was generated is a mess (which is why I wrote my own build rules and editor for Antlr for C#). Make sure you clean the target directory completely, generate clean fresh up-to-date .java files, and you are using the right Antlr runtime 4.7.2.

这篇关于在antlr访问者模式中,如何从一种方法导航到另一种方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆