编译器学习之 (三) : 抽象语法树的action

2017-09-26  本文已影响284人  sea_biscute

前言

之前的文章对于词法分析和语法分析规则进行了讲解,我们的目标 是解析代码并生成语法树,因此必须在识别出语句或表达式时添加生成语法树的代码.
为了达到上述目的,可以借助 action 功能,当 token 序列和语法规则匹配时就能够执行任意代码.
本文将对 action 的使用方法进行说明

action

可以通过在符号串内部添加{ }代码块,执行我们想要添加的一些特点操作,这些代码块被称为action,举例

 void defstruct(): {}
  {
      <STRUCT> name()
          {
          System.out.println(" 发现了结构体!"); }
      member_list()
          {
          System.out.println(" 发现了成员列表!"); }
      ";"
          {
          System.out.println(" 发现了分号!"); }
  }
非终端符号的规则定义

action的执行时机

终端符号被执行时,才会触发action,扫描终端符号不会触发action

需要注意“解析终端符号”和“扫描终端符号”是不同的.解析器会对 token 进行超前扫描,因此即便是写在 action 之后的 token,也完全有可能已经被扫描器读取进来了

例如下面的规则,在 action 执行时 <X> 和 <Y> 就已经被扫描进来了
LOOKAHEAD(2) { System.out.println("action executed"); } <X> <Y>

但解析器一定会在执行 action 之后再对 <X> 和 <Y> 进行解析

token类的属性

token类的属性

只需写“变量名 = 非终端符号”,就能获取终端符号和非终端符号的语义值

语义值

我们可以设置返回语义值的action

String name():
{
      Token tok; 
}
{
      tok=<IDENTIFIER> { return tok.image; }
}

action的执行次数

选择和action : 如果在所有选项的最后执行共通的action

  {
      Token x, y; 
  }
  {
      (x=<X> | y=<Y>)
          {
                if (x != null) {
                    System.out.println("X found.  image=" + x.image);
                }
                else {
                    System.out.println("Y found.  image=" + y.image);
                }
          }
   }
重复和action

每当发现 <X> 和 <Y>时都会执行

void iteration():
{
Token x, y; 
}
{
      (x=<X>  y=<Y>
          {
              System.out.println("x=" + x.image + "; y=" + y.image);
      } )*
}

只会执行一次

void iteration2():
{
Token x, y; 
}
{
      (x=<X>  y=<Y>)*
          {
              System.out.println("x=" + x.image + "; y=" + y.image);
          }
}

总结

上面介绍了action主要功能和获取语义值,本文的总结如下

上一篇 下一篇

猜你喜欢

热点阅读