ANTLR 4使用听众的口译员

时间:2013-12-10 21:31:08

标签: java if-statement listener interpreter antlr4

是否可以使用侦听器而不是java中的访问者来评估antlr4中的IF语句?如果是这样,你能建议怎么做?

我正在尝试为我的语言翻译。我已经使用生成的antlr监听器来实现它。我已经完成了对表达式的语义分析和评估,现在我不知道如何评估IFWHILEFOR等函数调用。

我在antlr4中的语法不包括词汇规则:

grammar CodeCraftGrammar;

@header{
package gen;
}

program
    :  constantStatement* mainFunction functionDeclaration* EOF 
    ;
constantStatement 
    : ABSOLUTE dataType ID ASSIGN expression SEMI     
    ;
variableDeclaration 
    : dataType ID 
    ;
dataType
    : INT       
    | FLOAT     
    | CHAR     
    | STRING    
    | BOOLEAN   
    ;
functionDeclaration
    : returnType ID parameterList block
    ;
returnType
    : dataType #returnDataType
    | DARKNESS  #returnDarkness
    ;
parameterList
    : LPAREN parameter? (COMMA parameter)* RPAREN
    ;
parameter
    : dataType ID
    ;
block
    : LBRACE statement* RBRACE
    ;
mainFunction
    : DARKNESS MINE parameterList block
    ;

statement
    : block #blockStatement
    | variableDeclaration SEMI  #varDec
    | assignmentStatement SEMI  #assign
    | functionCallStatement SEMI #funcCall
    | ifStatement   #if
    | whileStatement    #while
    | doWhileStatement  #dowhile
    | forStatement  #for
    | returnStatement   #return
    | CHOKE SEMI    #choke
    ;
assignmentStatement
    : ID ASSIGN expression
    ;
functionCallStatement
    : ID actualParameters  #funcCallID
    | PRINT actualParameters   #funcCallPrint
    | PRINTLN actualParameters #funcCallPrintln
    ;
actualParameters
    : LPAREN expression? (COMMA expression)* RPAREN
    ;
ifStatement
    : WETHER condition block OTHERWISE block  #ifelse
    | WETHER condition block #ifonly
    ;
condition
    : LPAREN expression RPAREN  
    ;
whileStatement
    : UNTIL condition block
    ;
doWhileStatement
    : EXECUTE block UNTIL condition SEMI
    ;
forStatement
    : AS LPAREN assignmentStatement SEMI expression SEMI assignmentStatement RPAREN block
    ;
returnStatement
    : REPLY expression SEMI
    ;
expression
    : '!' expression #bangExpr
    | '(' expression ')'  #parensExpr
    | expression ('*'|'/'|'%') expression #multdivmodExpr
    | expression ('+'|'-') expression   #addminusExpr
    | expression ('>='|'<='|'<'|'>') expression  #relationalExpr
    | expression ('=='|'!=') expression               #equalityExpr
    | expression '&&' expression               #andExpr
    | expression '||' expression                #orExpr
    | IntegerLiteral #intExpr
    | BooleanLiteral #boolExpr
    | FloatingPointLiteral #floatExpr
    | StringLiteral #stringExpr
    | CharacterLiteral #charExpr
    | ID actualParameters #funcCallExpr
    | ID         #idExpr
    | NULL  #nullExpr
    ;

这是口译员开始的地方:

public Main(String code, String[] args,JTextArea ta)throws Exception {
        this.ta =ta;
        String inputFile = "src/sample_code.cc";
        InputStream is=null;
        if ( inputFile!=null ) {
            is = new FileInputStream(inputFile);
        }
        //is = new StringBufferInputStream(code);
        ANTLRInputStream input = new ANTLRInputStream(is);
        CodeCraftGrammarLexer lexer = new CodeCraftGrammarLexer(input);
        CodeCraftGrammarParser parser = new CodeCraftGrammarParser(new CommonTokenStream(lexer));
        parser.setBuildParseTree(true);

        ParseTree tree = parser.program();
        List<String> ruleNames = Arrays.asList(parser.getRuleNames());
        TreeViewer tv = new TreeViewer(ruleNames, tree);

        ParseTreeWalker walker = new ParseTreeWalker();

        FirstPass def = new FirstPass();
        walker.walk(def, tree);
        // create next phase and feed symbol table info from define to reference phase
        SecondPass ref = new SecondPass(def.globals, def.scopes);
        walker.walk(ref, tree);
    }

这是解析树中的第一个传递,它首先定义所有变量和函数:

public class FirstPass extends CodeCraftGrammarBaseListener{
    ParseTreeProperty<Scope> scopes = new ParseTreeProperty<Scope>();
    GlobalScope globals;
    Scope currentScope; // define symbols in this scope
    void saveScope(ParserRuleContext ctx, Scope s) { scopes.put(ctx, s); }

    public FirstPass(){
    }
    public void enterProgram(@NotNull ProgramContext ctx) {
        globals = new GlobalScope(null);
        currentScope = globals;
    }

    public void exitProgram(@NotNull ProgramContext ctx) {
        Main.displayScope(globals);
    }

    public void enterFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
        String name = ctx.ID().getText();
        int typeTokenType = ctx.returnType().start.getType(); //UNSURE
        Symbol.Type type = Main.getType(typeTokenType);
        // push new scope by making new one that points to enclosing scope
        FunctionSymbol function = new FunctionSymbol(name, type, currentScope);

        GlobalScope temp = (GlobalScope) currentScope;
        if(temp.symbols.containsKey(function.name)){
            //multiple function declaration in same global scope
            Main.error(ctx.ID().getSymbol(), "Function already declared: "+name);
        }//UNSURE should i let it continue saving in symbol table
        currentScope.define(function); // Define function in current scope
        saveScope(ctx, function); // Push: set function's parent to current
        currentScope = function; // Current scope is now function scope
        if(currentScope.getClass()==FunctionSymbol.class)
            currentScope = (FunctionSymbol)currentScope;
    }

    public void enterMainFunction(@NotNull MainFunctionContext ctx) {
        String name = ctx.MINE().getText();
        int typeTokenType = ctx.DARKNESS().getSymbol().getType(); //UNSURE
        Symbol.Type type = Main.getType(typeTokenType);
        // push new scope by making new one that points to enclosing scope
        FunctionSymbol function = new FunctionSymbol(name, type, currentScope);

        GlobalScope temp = (GlobalScope) currentScope;
        if(temp.symbols.containsKey(function.name)){
            //multiple function declaration in same global scope
            Main.error(ctx.MINE().getSymbol(), "Main already declared: "+name);
        }//UNSURE should i let it continue saving in symbol table
        currentScope.define(function); // Define function in current scope
        saveScope(ctx, function); // Push: set function's parent to current
        currentScope = function; // Current scope is now function scope
        if(currentScope.getClass()==FunctionSymbol.class)
            currentScope = (FunctionSymbol)currentScope;
    }

    public void exitFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
        Main.displayScope(currentScope);
        currentScope = currentScope.getEnclosingScope(); // pop scope
        if(currentScope.getClass()==GlobalScope.class)
            currentScope = (GlobalScope)currentScope;
    }

    public void exitMainFunction(@NotNull MainFunctionContext ctx) {
        Main.displayScope(currentScope);
        currentScope = currentScope.getEnclosingScope(); // pop scope
        if(currentScope.getClass()==GlobalScope.class)
            currentScope = (GlobalScope)currentScope;
    }

    public void enterBlock(CodeCraftGrammarParser.BlockContext ctx) {
        // push new local scope
        currentScope = new LocalScope(currentScope);
        currentScope = (LocalScope)currentScope;
        saveScope(ctx, currentScope);
    }

    public void exitBlock(CodeCraftGrammarParser.BlockContext ctx) {
        Main.displayScope(currentScope);
        currentScope = currentScope.getEnclosingScope(); // pop scope
        if(currentScope.getClass()==FunctionSymbol.class)
            currentScope = (FunctionSymbol)currentScope;
    }

    public void exitParameter(@NotNull ParameterContext ctx) {
        FunctionSymbol temp = (FunctionSymbol) currentScope;
        String name = ctx.ID().getText();
        if(temp.arguments.containsKey(name)){
            //multiple function declaration in same global scope
            Main.error(ctx.ID().getSymbol(), "Parameter already declared: "+name);
        }
        defineVar(ctx.dataType(), ctx.ID().getSymbol(),false);
    }

    public void exitVariableDeclaration(@NotNull VariableDeclarationContext ctx) {
        LocalScope temp = (LocalScope) currentScope;
        String name = ctx.ID().getText();
        if(temp.symbols.containsKey(name)){
            //multiple function declaration in same global scope
            Main.error(ctx.ID().getSymbol(), "Variable already declared: "+name);
        }
        defineVar(ctx.dataType(), ctx.ID().getSymbol(),false);
    }

    public void exitConstantStatement(@NotNull ConstantStatementContext ctx) {
        GlobalScope temp = (GlobalScope) currentScope;
        ConstantStatementContext ctx2 = ctx;

        String name = ctx2.ID().getText();
        if(temp.symbols.containsKey(name)){
            //multiple function declaration in same global scope
            Main.error(ctx2.ID().getSymbol(), "Constant already declared: "+name);
        }
        defineVar(ctx2.dataType(), ctx2.ID().getSymbol(),true);
    }

    void defineVar(CodeCraftGrammarParser.DataTypeContext typeCtx, Token nameToken, Boolean isConstant) {
        int typeTokenType = typeCtx.start.getType(); //UNSURE
        Symbol.Type type = Main.getType(typeTokenType);
        VariableSymbol var = new VariableSymbol(nameToken.getText(), type, isConstant);
        currentScope.define(var); // Define symbol in current scope
    }


}

第二遍:

public class SecondPass extends CodeCraftGrammarBaseListener{
    ParseTreeProperty<Scope> scopes;
    GlobalScope globals;
    Scope currentScope; // resolve symbols starting in this scope
    JTextArea ta;
    Stack<Symbol> stack = new Stack<Symbol>();
    Symbol op1,op2,ans;

    public SecondPass(GlobalScope globals, ParseTreeProperty<Scope> scopes) {
        this.scopes = scopes;
        this.globals = globals;
    }
    public void enterProgram(@NotNull ProgramContext ctx) {
        currentScope = globals;
    }

    public void enterFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
        currentScope = scopes.get(ctx);
    }
    public void exitFunctionDeclaration(@NotNull FunctionDeclarationContext ctx) {
        currentScope = currentScope.getEnclosingScope();
    }
    public void enterBlock(@NotNull BlockContext ctx) {
        currentScope = scopes.get(ctx);
    }
    public void exitBlock(@NotNull BlockContext ctx) {
        currentScope = currentScope.getEnclosingScope();
    }
    public void exitIf(@NotNull IfContext ctx) {

    }
    public void exitFuncCallID(@NotNull FuncCallIDContext ctx) {
        String funcName = ctx.ID().getText();
        Symbol meth = currentScope.resolve(funcName);
        if ( meth==null ) {
            Main.error(ctx.ID().getSymbol(), "no such function: "+funcName);
        }
        if ( meth instanceof VariableSymbol ) {
            Main.error(ctx.ID().getSymbol(), funcName+" is not a function");
        }
    }

    public void exitAssignmentStatement(AssignmentStatementContext ctx) {
        String name = ctx.ID().getSymbol().getText();
        Symbol var = currentScope.resolve(name);
        if ( var==null ) {
            Main.error(ctx.ID().getSymbol(), "no such variable: "+name);
        }
        if ( var instanceof FunctionSymbol ) {
            Main.error(ctx.ID().getSymbol(), name+" is not a variable");
        }

        Symbol x = stack.pop();
        System.out.println("==\n::assign value"+x.value + " assign type:" + x.type.toString());
        if(var.type == x.type){


            currentScope.resolve(name).value = x.value;
            System.out.println("assignment name:"+name +" value: "+currentScope.resolve(name).value+" type:"+currentScope.resolve(name).type+"===\n");
        }else if (var.type == Type.tFLOAT && x.type== Type.tINT){
            currentScope.resolve(name).value = x.asFloat();
            System.out.println("assignment name:"+name +" value: "+currentScope.resolve(name).value+" type:"+currentScope.resolve(name).type+"===\n");
        }else{
        }
    }
    public void exitFuncCallExpr(@NotNull FuncCallExprContext ctx) {
        String funcName = ctx.ID().getText();
        Symbol meth = currentScope.resolve(funcName);
        if ( meth==null ) {
            Main.error(ctx.ID().getSymbol(), "no such function: "+funcName);
        }
        if ( meth instanceof VariableSymbol ) {
            Main.error(ctx.ID().getSymbol(), funcName+" is not a function");
        }
        //#WHAT THE HECK 
    }
    public void exitBangExpr(@NotNull BangExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(0).getText();
        if(op1.isBoolean()){
            if (operator.equals("!")){
                ans = new Symbol(Type.tBOOLEAN, !op1.asBoolean());
            }
            stack.push(ans);
        }else{
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitOrExpr(@NotNull OrExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(1).getText();
        if(op1.isBoolean()&&op2.isBoolean()){
            if (operator.equals("||")){
                ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() || op1.asBoolean());
            }
            stack.push(ans);
        }else{
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitAndExpr(@NotNull AndExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(1).getText();
        if(op1.isBoolean()&&op2.isBoolean()){
            if (operator.equals("&&")){
                ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() && op1.asBoolean());
            }
            stack.push(ans);
        }else{
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitEqualityExpr(@NotNull EqualityExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(1).getText();
        if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
            if (operator.equals("==")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() == op1.asFloat());
            }else if (operator.equals("!=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() != op1.asFloat());
            }
            stack.push(ans);
        }else if(op1.isBoolean()&&op2.isBoolean()){
            if (operator.equals("==")){
                ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() == op1.asBoolean());
            }else if (operator.equals("!=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asBoolean() != op1.asBoolean());
            }
            stack.push(ans);
        }else if(op1.isString()&&op2.isString()){
            if (operator.equals("==")){
                ans = new Symbol(Type.tBOOLEAN, op2.asString() == op1.asString());
            }else if (operator.equals("!=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asString() != op1.asString());
            }
            stack.push(ans);
        }else if(op1.isChar()&&op2.isChar()){
            if (operator.equals("==")){
                ans = new Symbol(Type.tBOOLEAN, op2.asChar() == op1.asChar());
            }else if (operator.equals("!=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asChar() != op1.asChar());
            }
            stack.push(ans);
        }else{
            //error expression type mismatch
            //The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitRelationalExpr(@NotNull RelationalExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(1).getText();
        if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
            if (operator.equals(">")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() > op1.asFloat());
            }else if (operator.equals("<")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() < op1.asFloat());
            }else if (operator.equals(">=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() >= op1.asFloat());
            }else if (operator.equals("<=")){
                ans = new Symbol(Type.tBOOLEAN, op2.asFloat() <= op1.asFloat());
            }
            stack.push(ans);
        }else{
            //error expression type mismatch
            //The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitMultdivmodExpr(MultdivmodExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans=null;
        String operator = ctx.getChild(1).getText();
        if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
            if(op1.asFloat()==0 && (operator.equals("/")||operator.equals("%"))){
                //error div/mod by zero
                TerminalNode tn = (TerminalNode) ctx.getChild(1);
                String msg = "Arithmetic Error: " + operator +" by zero";
                Main.semanticError(tn.getSymbol(),msg);
            }else {
                if(op1.isFloat()||op2.isFloat()){ //push as float
                    if (operator.equals("*")){
                        ans = new Symbol(Type.tFLOAT, op2.asFloat() * op1.asFloat());
                    }else if(operator.equals("/")){
                        ans = new Symbol(Type.tFLOAT, op2.asFloat() / op1.asFloat());
                    }else if(operator.equals("%")){
                        ans = new Symbol(Type.tFLOAT, op2.asFloat() % op1.asFloat());
                    }
                }else{ //push as int
                    if (operator.equals("*")){
                        ans = new Symbol(Type.tINT, op2.asInt() * op1.asInt());
                    }else if(operator.equals("/")){
                        ans = new Symbol(Type.tINT, op2.asInt() / op1.asInt());
                    }else if(operator.equals("%")){
                        ans = new Symbol(Type.tINT, op2.asInt() % op1.asInt());
                    }
                }
                stack.push(ans);
            }
        }else{
            //error expression type mismatch
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }

    public void exitAddminusExpr(AddminusExprContext ctx) {
        Symbol op1 = stack.pop();
        Symbol op2 = stack.pop();
        Symbol ans;
        String operator = ctx.getChild(1).getText();
        if((op1.isFloat() || op1.isInt())&&(op2.isFloat() || op2.isInt())){
            if(op1.isFloat()||op2.isFloat()){ //push as float

                if (operator.equals("-")){
                    ans = new Symbol(Type.tFLOAT, op2.asFloat() - op1.asFloat());
                }else{
                    ans = new Symbol(Type.tFLOAT, op2.asFloat() + op1.asFloat());
                }
            }else{ //push as int
                if (operator.equals("-")){  
                    ans = new Symbol(Type.tINT, op2.asInt() -  op1.asInt());
                }
                else{
                    ans = new Symbol(Type.tINT, op2.asInt() + op1.asInt() );
                }
            }
            stack.push(ans);
        }else if(op1.isString() && op2.isString() && operator.equals("+")){
            ans = new Symbol(Type.tSTRING, op2.asString() + op1.asString());
            stack.push(ans);
        }else{
            //error expression type mismatch
            //The operator - is undefined for the argument type(s) java.lang.String, java.lang.String
            TerminalNode tn = (TerminalNode) ctx.getChild(1);
            String msg = "The operator " + operator +" is undefined for the argument type(s)" + op2 +", "+ op1;
            Main.semanticError(tn.getSymbol(),msg);
        }
    }
    public void exitNullExpr(NullExprContext ctx) {
        Symbol s = new Symbol(Type.tNULL,null);
        stack.push(s);
    }
    public void exitIdExpr(@NotNull CodeCraftGrammarParser.IdExprContext ctx) {
        String name = ctx.ID().getSymbol().getText();
        Symbol var = currentScope.resolve(name);
        if ( var==null ) {
            Main.semanticError(ctx.ID().getSymbol(), "no such variable: "+name);
        }else if ( var instanceof FunctionSymbol ) {
            Main.semanticError(ctx.ID().getSymbol(), name+" is not a variable");
        }else{
            stack.push(var);
        }
    }
    public void exitIntExpr(IntExprContext ctx) {
        String valueInString = ctx.IntegerLiteral().getSymbol().getText();
        Integer valueInInteger = Integer.valueOf(valueInString);
        Symbol s = new Symbol(Type.tINT,valueInInteger);
        stack.push(s);
    }
    public void exitFloatExpr(FloatExprContext ctx) {
        String valueInString = ctx.FloatingPointLiteral().getSymbol().getText();
        Float valueInFloat = Float.valueOf(valueInString);
        Symbol s = new Symbol(Type.tFLOAT,valueInFloat);
        stack.push(s);
    }
    public void exitBoolExpr(BoolExprContext ctx) {
        String value = ctx.BooleanLiteral().getSymbol().getText();  
        Symbol s = null;
        if("true".equals(value)){
            s = new Symbol(Type.tBOOLEAN,true);
        }else if("false".equals(value)){
            s = new Symbol(Type.tBOOLEAN,false);
        }
        stack.push(s);
    }
    public void exitStringExpr(StringExprContext ctx) {
        String value = ctx.StringLiteral().getSymbol().getText();
        Symbol s;
        if(value.length()==2){ //String is blank
            s = new Symbol(Type.tSTRING,"");
        }else{
            s = new Symbol(Type.tSTRING,value.substring(1, value.length()-1));
        }
        stack.push(s);
    }
    public void exitCharExpr(CharExprContext ctx) {
        String value = ctx.CharacterLiteral().getSymbol().getText();
        Symbol s = new Symbol(Type.tCHAR,value.charAt(1));
        stack.push(s);
    }   
}

1 个答案:

答案 0 :(得分:3)

使用侦听器接口评估IF语句将很困难,与侦听器接口一样,您将由Antlr树walker驱动,它以其所有者顺序传递AST树。但是,为了评估IF语句,您需要根据条件语句的评估结果来控制AST或部分AST的评估顺序。

我认为访问者界面更适合评估IF,For / While和函数调用。