如何在ANTLR中获取完整的用户编写语句(包括空格)

时间:2013-09-23 18:25:12

标签: antlr

我从Java语言定义中得到了一个“语句”定义如下。

statement
: block
|   ASSERT expression (':' expression)? ';'
|   'if' parExpression statement ('else' statement)?
|   'for' '(' forControl ')' statement
|   'while' parExpression statement
|   'do' statement 'while' parExpression ';'
|   'try' block
    ( catches 'finally' block
    | catches
    | 'finally' block
    )
|   'switch' parExpression switchBlock
|   'synchronized' parExpression block
|   'return' expression? ';'
|   'throw' expression ';'
|   'break' Identifier? ';'
|   'continue' Identifier? ';'
|   ';'
|   statementExpression ';'
|   Identifier ':' statement
;

在执行解析器时,我还要打印完整的用户编写的语句(包含语句中的空格),例如:

Object o = Ma.addToObj(r1);
if(h.isFull() && !h.contains(true)) h.update(o);

但是当我在“exitStatement”中使用函数“getText()”时,我只能获取删除了所有空格的语句,例如:

Objecto=Ma.addToObj(r1);
if(h.isFull()&&!h.contains(true))h.update(o);

如何以简单的方式获取完整的用户编写语句(包含语句中的空格)?非常感谢!

完整代码如下:

public class PrintStatements {
public static class GetStatements extends sdlParserBaseListener {
    StringBuilder statements = new StringBuilder();
     public void exitStatement(sdlParserParser.StatementContext ctx){               
            statements.append(ctx.getText());
            statements.append("\n");                        
        }
}


public static void main(String[] args) throws Exception{

String inputFile = null;
if ( args.length>0 ) inputFile = args[0];
InputStream is = System.in;
if ( inputFile!=null ) {
    is = new FileInputStream(inputFile);
}
ANTLRInputStream input = new ANTLRInputStream(is);
sdlParserLexer lexer = new sdlParserLexer(input);
CommonTokenStream tokens = new CommonTokenStream(lexer);
sdlParserParser parser = new sdlParserParser(tokens);
ParseTree tree = parser.s();

// create a standard ANTLR parse tree walker
ParseTreeWalker walker = new ParseTreeWalker();
// create listener then feed to walker
GetStatements loader = new GetStatements();
walker.walk(loader, tree);        // walk parse tree   

System.out.println(loader.statements.toString());
}
}

4 个答案:

答案 0 :(得分:7)

我通过在语句的上层使用tokens.getText()解决了这个问题,如下所示:

public void exitE(sdlParserParser.EContext ctx) {
    TokenStream tokens = parser.getTokenStream();
    String Stmt = null;
    Stmt = tokens.getText(ctx.statement());
                ...

}

答案 1 :(得分:0)

我对ANTLR很新,所以也许我错了......

我不知道这样做的简单方法,但你可以尝试这样的事情。 在你的语法文件中,你可能有这样的东西:

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') 
{   
    if (!preserveWhitespacesAndComments) {
      skip();
    } else {
       $channel = HIDDEN;
    }
}

此词法分析器规则告诉解析器忽略空格。更确切地说,这些令牌是在HIDDEN通道上发送的(解析器看不到它们)。如果你评论这行代码

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') 
{   
    if (!preserveWhitespacesAndComments) {
    //   skip();
    } else {
      //  $channel = HIDDEN;
    }
}

所有空格都将被发送到解析器,但是您需要重写解析器规则,以便他可以在任何地方获得空格。

Object(EXPECT WHITESPACE)o(EXPECT WHITESPACE)=(EXPECT WHITESPACE)Ma.addToObj(r1);

否则解析器将报告错误。

答案 2 :(得分:0)

您需要以下两种方法之一:

  • 为语句解析接受的第一个和最后一个标记获取文件位置数据的能力(词法或树节点应该这样做),并转到源文件,然后提取文本。这将为您提供原始的空白。
  • 一个prettyprinter,它将从AST重新生成文本,插入适当的whitespacing。请参阅我的答案,了解如何构建一个漂亮的打印机here

答案 3 :(得分:0)

就Antlr4和Python3而言,code如下所示:

def exitSomeDecl(self, ctx: yourParser.SomeDeclContext):
    start_index = ctx.start.tokenIndex
    stop_index = ctx.stop.tokenIndex
    user_text = self.token_stream.getText(interval=(start_index, stop_index))

此处,self.token_stream: CommonTokenStream在init期间分配:

    input_stream = FileStream(file_name)
    lexer = sdplLexer(input_stream)
    token_stream = CommonTokenStream(lexer)