antlr-tour-action&语法断言&xml&TokenStreamRewriter&写入其他channel
actions和属性
members在解析文件中添加了RowsParser,然后传入TokenStream和一个col自义的数字
row中判断,如果i和col相等就打印出内容
grammar Rows;
@parser::members { // add members to generated RowsParser
    int col;
    public RowsParser(TokenStream input, int col) { // custom constructor
        this(input);
        this.col = col;
    }
}
file: (row NL)+ ;
row
locals [int i=0]
    : (   STUFF
          {
          $i++;
          if ( $i == col ) System.out.println($STUFF.text);
          }
      )+
    ;
TAB  :  '\t' -> skip ;   // match but don't pass to the parser
NL   :  '\r'? '\n' ;     // match and pass to the parser
STUFF:  ~[\t\r\n]+ ;     // match any chars except tab, newline
Semantic Predicates语法断言
输入一串数字:2 9 10 3 1 2 3
第一个数字是2,把后续的9.10分一组
再一个数字是3,把后续的1,2,3分一组
grammar Data;
file : group+ ;
group: INT sequence[$INT.int] ;
sequence[int n]
locals [int i = 1;]
: ( {$i<=$n}? INT {$i++;} )* // match n integers
;
INT : [0-9]+ ; // match integers
WS : [ \t\n\r]+ -> skip ; // toss out all whitespace
其他特性
在同一个文件中,处理不同的语法
island grammars
xml就是一个很好的例子,在遇到<>标签中的内容是一种语法,之外的内容是另一种语法;
lexer grammar XMLLexer;
// Default "mode": Everything OUTSIDE of a tag
OPEN        :   '<'                 -> pushMode(INSIDE) ;
COMMENT     :   '<!--' .*? '-->'    -> skip ;
EntityRef   :   '&' [a-z]+ ';' ;
TEXT        :   ~('<'|'&')+ ;           // match any 16 bit char minus < and &
// ----------------- Everything INSIDE of a tag ---------------------
mode INSIDE;
CLOSE       :   '>'                 -> popMode ; // back to default mode
SLASH_CLOSE :   '/>'                -> popMode ;
EQUALS      :   '=' ;
STRING      :   '"' .*? '"' ;
SlashName   :   '/' Name ;
Name        :   ALPHA (ALPHA|DIGIT)* ;
S           :   [ \t\r\n]           -> skip ;
fragment
ALPHA       :   [a-zA-Z] ;
fragment
DIGIT       :   [0-9] ;
重写输入流
在每个语法前面加上一个序列化的编号,不需要修改语言文件;使用内置的TokenStreamRewriter
public class InsertSerialIDListener extends JavaBaseListener {
    TokenStreamRewriter rewriter;
    public InsertSerialIDListener(TokenStream tokens) {
        rewriter = new TokenStreamRewriter(tokens);
    }
    @Override
    public void enterClassBody(JavaParser.ClassBodyContext ctx) {
        String field = "\n\tpublic static final long serialVersionUID = 1L;";
        rewriter.insertAfter(ctx.start, field);
    }
}
主函数
    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);
        JavaLexer lexer = new JavaLexer(input);
		CommonTokenStream tokens = new CommonTokenStream(lexer);
        JavaParser parser = new JavaParser(tokens);
        ParseTree tree = parser.compilationUnit(); // parse
        ParseTreeWalker walker = new ParseTreeWalker(); // create standard walker
        InsertSerialIDListener extractor = new InsertSerialIDListener(tokens);
        walker.walk(extractor, tree); // initiate walk of tree with listener
        // print back ALTERED stream
        System.out.println(extractor.rewriter.getText());
    }
把tokens发送到另一个channel
之前写的interface extractor把方法的空白和注释都保留了;
保留注释和空白的方法是把它们发送到一个hidden channel;
java语法中如下
COMMENT
: '/*' .*? '*/' -> channel(HIDDEN) // match anything between /* and */
;
WS : [ \r\t\u000C\n]+ -> channel(HIDDEN)
;
-> channel(HIDDEN)词法就像-> skip一样
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号