在antlr访问者模式中,如何从一种方法导航到另一种方法 [英] In antlr visitor pattern how to navigate from one method to another
问题描述
我是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屋!