2017-10-28 88 views
0

我想知道如何在语法分析过程中检查所有路径在函数中的返回值。所以说,在词法Antlr检查范围内的返回语句

RETURN: 'return'; 
PRINT: 'print'; 
IF:'if'; 
ELSE: 'else'; 
THEN:'then'; 
PLUS: '+'; 
MINUS:'-'; 
EQUALS: '=='; 
DIGIT: '0'..'9'; 
OPEN:'{'; 
CLOSE:'}'; 
STRING: [a..zA..Z]+; 
SEMICOLON: ';'; 

和解析器我有以下

function: STRING OPEN statement CLOSE 
statement: RETURN expr | PRINT expr | IF expr THEN statement ELSE statement | statement SEMICOLON statement; 
expr: DIGIT| expr PLUS expr | expr MINUS expr | expr EQUALS expr; 

我的问题是,一个有效的功能应该有后return语句并没有什么。 所以一个有效的是

test { return 2+2 } 

test{ if 2 == 2 then return 2 else return 3 } 

无效的人会在有返回后可达代码。例如。

test{return 2; print 3} 

我该如何去检查返回语句后没有任何东西?

我主要的Java方法看起来是这样的:

MyLexer mylexer = new MyLexer(new ANTLRInputStream(System.in)); 
CommonTokenStream toks = new CommonTokenStream(mylexer); 
MyParser parser = new MyParser(tokens); 
ParseTree parseTree = parser.program(); 
+1

有没有办法通过语法来执行这一点。您可以在语义操作中检查它,但通常不会在解析器中检查它,而是在语义分析阶段检查它。 – sepp2k

+0

非常感谢你 –

+0

@ sepp2k:为什么你不能用语法强制执行?这是一个简单的句法特征。 – rici

回答

0

我不是专家,也从未使用错误报告直到今天,但如果你只是想一个错误列表,你可以做以下,灵感来自The Definitive ANTLR 4 Reference的第9章。

文件Question.g4

grammar Question; 

/* Detecting invalid input after a return statement. */ 

question 
@init {System.out.println("Question last update 1302");} 
    : function+ EOF 
    ; 

function 
    : STRING OPEN statement_block CLOSE 
    ; 

statement_block 
    : statement* if_last? return_statement 
    ; 

statement 
    : PRINT expr 
    | IF expr THEN statement ELSE statement 
    | statement SEMICOLON statement 
    ; 

if_last 
    : IF expr THEN statement_block ELSE statement* 
    ; 

return_statement 
    : RETURN expr 
    ; 

expr 
    : DIGIT 
    | expr PLUS expr 
    | expr MINUS expr 
    | expr EQUALS expr 
    ; 

CLOSE : '}' ; 
ELSE : 'else' ; 
EQUALS : '==' ; 
IF  : 'if' ; 
MINUS : '-' ; 
OPEN : '{' ; 
PLUS : '+' ; 
PRINT : 'print' ; 
RETURN : 'return' ; 
THEN : 'then' ; 

DIGIT  : [0-9] ; 
STRING : [a-zA-Z]+ ; 
SEMICOLON : ';' ; 

WS : [ \r\n\t] -> channel(HIDDEN) ; 

文件MyListener.java

public class MyListener extends QuestionBaseListener { 
    QuestionParser parser; 
    public MyListener(QuestionParser parser) { this.parser = parser; } 

    public void exitFunction(QuestionParser.FunctionContext ctx) { 
     System.out.println(">>> in MyListener for function"); 
     System.out.println(parser.getTokenStream().getText(ctx)); 
    } 
} 

文件test.java

import org.antlr.v4.runtime.*; 

import org.antlr.v4.runtime.tree.*; 
import java.io.FileInputStream; 
import java.io.InputStream; 
import java.io.IOException; 
import java.util.*; 

public class test { 
    public static class UnderlineListener extends BaseErrorListener { 
     public void syntaxError(Recognizer<?, ?> recognizer, 
           Object offendingSymbol, 
           int line, int charPositionInLine, 
           String msg, 
           RecognitionException e) 
     { 
      System.err.println("line " + line + ":" + charPositionInLine + " " + msg); 
      underlineError(recognizer,(Token)offendingSymbol, 
       line, charPositionInLine); 
     } 

     protected void underlineError(Recognizer recognizer, 
             Token offendingToken, int line, 
             int charPositionInLine) { 
      CommonTokenStream tokens = 
       (CommonTokenStream)recognizer.getInputStream(); 
      String input = tokens.getTokenSource().getInputStream().toString(); 
      String[] lines = input.split("\n"); 
      String errorLine = lines[line - 1]; 
      System.err.println(errorLine); 
      for (int i=0; i<charPositionInLine; i++) System.err.print(" "); 
      int start = offendingToken.getStartIndex(); 
      int stop = offendingToken.getStopIndex(); 
      if (start>=0 && stop>=0) { 
       for (int i=start; i<=stop; i++) System.err.print("^"); 
      } 
      System.err.println(); 
     } 
    } 

    public static void main(String[] args) throws IOException { 
     ANTLRInputStream input = new ANTLRFileStream(args[0]); 
     QuestionLexer lexer = new QuestionLexer(input); 
     CommonTokenStream tokens = new CommonTokenStream(lexer); 
     QuestionParser parser = new QuestionParser(tokens); 
     parser.removeErrorListeners(); // remove ConsoleErrorListener 
     parser.addErrorListener(new UnderlineListener()); // add ours 
     ParseTree tree = parser.question(); 
     System.out.println("---parsing ended"); 
     ParseTreeWalker walker = new ParseTreeWalker(); 
     MyListener my_listener = new MyListener(parser); 
     System.out.println(">>>> about to walk"); 
     walker.walk(my_listener, tree); 
    } 
} 

文件t.text

test { return 2+2 } 
test { if 2 == 2 then return 2 else return 3 } 
test { if 2 == 2 then print 2 else print 3 return 4 } 
test {return 2; print 3} 
test { if 2 == 2 then return 2; abc else return 3; def } 
test { if 2 == 2 then if 6 then print 6 else print 3 else if 5 then 
print 1; print 2 else print 3 return 4 } 

执行:

$ java test t.text 
Question last update 1302 
line 4:14 mismatched input ';' expecting {'}', '==', '-', '+'} 
test {return 2; print 3} 
      ^
line 5:30 mismatched input ';' expecting {'else', '==', '-', '+'} 
test { if 2 == 2 then return 2; abc else return 3; def } 
          ^
line 5:49 mismatched input ';' expecting {'}', '==', '-', '+'} 
test { if 2 == 2 then return 2; abc else return 3; def } 
               ^
---parsing ended 
>>>> about to walk 
>>> in MyListener for function 
test { return 2+2 } 
>>> in MyListener for function 
test { if 2 == 2 then return 2 else return 3 } 
>>> in MyListener for function 
test { if 2 == 2 then print 2 else print 3 return 4 } 
>>> in MyListener for function 
test {return 2; print 3} 
>>> in MyListener for function 
test { if 2 == 2 then return 2; abc else return 3; def } 
>>> in MyListener for function 
test { if 2 == 2 then if 6 then print 6 else print 3 else if 5 then print 1; print 2 else print 3 return 4 } 
+0

这要求所有if块在最后有一个return语句,即使if语句不是函数中的最后一个语句。如果'if'的两种情况都有一个return语句并且'if'后面有一个语句,它也不会产生错误。要在语法中实际解决这个问题,你需要对出现在函数末尾的ifs和不存在ifs的规则采用不同的规则。你还需要考虑到,如果最后没有结束,可能会在某个情况下返回,但不是两者(至少这是明智的规则以及它在其他语言中的工作原理)。 – sepp2k

+0

@ sepp2k对,更新一个案例。如果他对此解决方案感兴趣,我将离开OP提供所有案例。但正如您在第一条评论中所建议的那样,最好在语义分析阶段进行分析。 – BernardK