6

我有一个来自 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

4 回答 4

7

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

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

}
于 2013-11-03T22:12:41.550 回答
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);

否则解析器会报错。

于 2013-09-25T13:04:01.890 回答
0

您需要以下两件事之一:

  • 能够获取语句解析接受的第一个和最后一个标记的文件位置数据(词位或树节点应该这样做),然后转到源文件并提取文本。这将为您提供原始空白。
  • 一个漂亮的打印机,它将从 AST 重新生成文本,插入适当的空白。请参阅我关于如何在此处构建漂亮打印机的 SO 答案。
于 2013-09-25T14:19:46.483 回答
0

在 Antlr4 和 Python3 方面,代码如下:

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是在初始化期间分配的:

    input_stream = FileStream(file_name)
    lexer = sdplLexer(input_stream)
    token_stream = CommonTokenStream(lexer)
于 2016-10-28T17:55:43.043 回答