Реализация посетителя с использованием antlr для вложенной функции - PullRequest
0 голосов
/ 10 ноября 2019

Я новичок в Antlr. Я хотел знать, как переходить от одного парсера к каждому методу ввода, и я хотел, чтобы приведенная ниже реализация была выполнена с использованием Antlr4. У меня нижеописанные функции.

Ниже приведена ссылка на github проекта. 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)

И я храню метаданные функций следующим образом.

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.

, если входные данные примерно такие:

FUNCTION.concat(Function.substring(String,Integer,Integer),String)

Используя реализацию посетителя, я хотел проверить, является ли ввод действительным или нет для метаданных функций, хранящихся в карте. .

Ниже приведен лексер и парсер, который я использую:

Lexer MyFunctionsLexer.g4:

lexer grammar MyFunctionsLexer;

FUNCTION: 'FUNCTION';

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

DOT: '.';

COMMA: ',';

L_BRACKET: '(';

R_BRACKET: ')';

Parser MyFunctionsParser.g4:

parser grammar MyFunctionsParser;

options {
    tokenVocab=MyFunctionsLexer;
}

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

argument: (NAME | function);

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

Я использую Antlr4.

Ниже приведена реализация, которую я использую в соответствии с предлагаемым ответом.

Реализация для посетителя:

  public class FunctionValidateVisitorImpl extends MyFunctionsParserBaseVisitor<String> {

    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(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:

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:

lexer grammar MyFunctionsLexer;
FUNCTION: 'FUNCTION';
NAME: [A-Za-z0-9]+;
DOT: '.';
COMMA: ',';
L_BRACKET: '(';
R_BRACKET: ')';
WS : [ \t\r\n]+ -> skip;

Parser:

parser grammar MyFunctionsParser;
options { tokenVocab=MyFunctionsLexer; }
functions : function* EOF;
function : FUNCTION '.' NAME '(' (function | argument (',' argument)*) ')';
argument: (NAME | function);

Verbose Listener:

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

    }
}

Приведенный выше код (реализация посетителя) не работает, так как выдает синтаксическую ошибку, даже если введенные данные верны. Но я не понимаю, как проверить аргумент и тип вложенной функции. Вложенный уровень может быть любой длины.

...