ANTLR中自定义语法分析过程

自定义语法分析过程

语法中嵌入动作

除了使用监听器和访问器,我们还可以手动实现对语法分析树的访问

例如要对如下三列文本进行识别,打印指定的列,例如第一列为parrt tombu bke,列之间以Tab分割

parrt Terence Parr 101
tombu Tom Burns 020
bke Kevin Edgar 008

在语法文件Rows.g4中添加一些自定义的动作,通过members将RowParser注入到生成的语法分析器类中

grammar Rows;

@parser::members { 
    int col;
    public RowsParser(TokenStream input, int col) { // custom constructor
        this(input);
        this.col = col;
    }
}

file: (row NL)+ ;

row
locals [int i=0]	//使用locals定义局部变量$i
    : (   STUFF
          {
          $i++;		
          if ( $i == col ) System.out.println($STUFF.text);		//$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

接下来在主程序中调用语法分析器,这里传入为RowsParser传入词法符号tokens和列号参数col,并且设置不自动生成语法分析树

public class Col {
    public static void main(String[] args) throws Exception {
        ANTLRInputStream input = new ANTLRInputStream(System.in);
        RowsLexer lexer = new RowsLexer(input);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        int col = Integer.valueOf(args[0]);
        
        RowsParser parser = new RowsParser(tokens, col); // 传递列好作为参数
        parser.setBuildParseTree(false); // 不需要自动生成语法树
        parser.file(); // parse
    }
}

构建项目并进行测试如下,可以看到输出了第一列的内容

D:\Code\antlr\demo\chapter4>antlr4 -no-listener Rows.g4

D:\Code\antlr\demo\chapter4>javac Rows*.java Col.java

D:\Code\antlr\demo\chapter4>java Col 1 < t.rows
parrt
tombu
bke
语义判定

通过表达式{$i<=$n}?可以对匹配条件进行判定,从而执行不同的语法分支

例如要对如下的数字序列进行匹配,第一个数字为2,则往后匹配两个数9、10,接下来为3,向后匹配三个数1、2、3

2 9 10 3 1 2 3

使用如下语法文件对数字序列进行匹配,通过判定表达式实现向后匹配n个整数

grammar Data;

file : group+ ;

group: INT sequence[$INT.int] ;

sequence[int n]
locals [int i = 1;]
     : ( {$i<=$n}? INT {$i++;} )* // 匹配n个整数
     ;
     
INT :   [0-9]+ ;             // match integers
WS  :   [ \t\n\r]+ -> skip ; // toss out all whitespace

词法分析器特性

孤岛语法:输入文件中包含多种语言,需要将模板表达式之外的文本按照不同方式处理。

ANTLR的词法分析模式(lexical model)可以对不同格式数据的文件进行处理,例如对XML文件进行处理时,当看到<时,词法分析器就会进入“标签内部”模式,看到>或者/>时就切回默认模式

重写输入流:TokenStreamRewriter可以对词法输入流进行修改之后再输出,它只是修改词法符号流的“视图”而非其本身的内容。如下所示为一个Java类的输入流中添加指定代码public static final long serialVersionUID = 1L;,重写监听器进入类的方法,在其中使用rewriter追加内容

import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.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);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值