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

如何在ANTLR中获得完整的用户编写语句(包括空格),antlr,Antlr,我有一个来自Java语言定义的“语句”定义,如下所示 statement : block | ASSERT expression (':' expression)? ';' | 'if' parExpression statement ('else' statement)? | 'for' '(' forControl ')' statement | 'while' parExpression statement | 'do' statement 'while' parExp

我有一个来自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()”时,我只能得到删除了所有空格的语句,例如:

Object o = Ma.addToObj(r1);
if(h.isFull() && !h.contains(true)) h.update(o);
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());
}
}
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))

我是ANTLR的新手,所以可能我有点不对劲

我不知道简单的方法,但你可以试试这样的方法。 在语法文件中,您可能有如下内容:

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') 
{   
    if (!preserveWhitespacesAndComments) {
      skip();
    } else {
       $channel = HIDDEN;
    }
}
public void exitE(sdlParserParser.EContext ctx) {
    TokenStream tokens = parser.getTokenStream();
    String Stmt = null;
    Stmt = tokens.getText(ctx.statement());
                ...

}
这个lexer规则告诉解析器忽略空白。更确切地说,这些令牌是在隐藏通道上发送的(解析器看不到它们)。如果您对这行代码进行注释

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') 
{   
    if (!preserveWhitespacesAndComments) {
    //   skip();
    } else {
      //  $channel = HIDDEN;
    }
}
所有的空白都将被发送到解析器,但您需要重写解析器规则,这样他就可以在任何地方看到空白

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

否则解析器将报告错误。

您需要两件事之一:

  • 能够获取语句解析所接受的第一个和最后一个标记的文件位置数据(词素或树节点都可以),然后转到源文件并提取文本。这将得到原始的空白
  • 预打印程序,它将从AST中重新生成文本,并插入适当的空格。请参阅我关于如何构建预打印程序的答案

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

WS  :  (' '|'\r'|'\t'|'\u000C'|'\n') 
{   
    if (!preserveWhitespacesAndComments) {
      skip();
    } else {
       $channel = HIDDEN;
    }
}
public void exitE(sdlParserParser.EContext ctx) {
    TokenStream tokens = parser.getTokenStream();
    String Stmt = null;
    Stmt = tokens.getText(ctx.statement());
                ...

}

就Antlr4和Python3而言,其外观如下:

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());
}
}
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\u流:CommonTokenStream
在初始化期间分配:

    input_stream = FileStream(file_name)
    lexer = sdplLexer(input_stream)
    token_stream = CommonTokenStream(lexer)
可能重复的