COOL编译器-第二次作业-parser(PA3)实现

注意: COOL编译器实现是一门网络公开课,地址是https://class.coursera.org/compilers/class/index,可能要FQ

可以在里面找到所需要的开发环境(虚拟机镜像等)和相关的资料说明.如果你感兴趣,可以一同学习

和讨论.

 

1. 作业目标

实现parser,给了两个工具,parser生成器--Bison和操作树结构的包parser的输出是一个abstract syntax tree(AST),

我们需要做的是结合AST构造的API,再使用Bison中的semantic actions来构建这个AST。

2. 参考资料

a. Cool语言的语法结构,在The Cool Reference Manual中

 cool syntax

b. 树结构的包的使用方法,在 Tour of Cool Support Code中

c. Bison官方文档,http://www.gnu.org/software/bison/manual/html_node/index.html#Top

3. 环境准备

copy作业文件夹:

  • cd 到你的到你的workspace下
  • make -f /usr/class/cs143/assignments/PA3/Makefile

4. 实际工作

修改cool.y,分为两个部分:

  • 声明部分基本完成,但还是需要做以下几个部分:

I. 为你引入的新的非终结符添加额外的类型声明;

II. 终结符的部分已经基本完成;

III. 需要操作符添加优先级声明;

  • rule部分,基本全部需要你完成。

5. 测试parser

make parser

./myparser -p good.cl //加上-p可以查看分析过程

#然后查看输出文件cool.output

使用./checkparser.sh good.cl命令来比对你实现的parser和正确parser之间

的分析结果的差异。

6. 关于输出的结构

输出的是一个AST,你的semanic actions也应该是在构造一个AST,它的根应该是program类型。

然后逐级向下构造各结点。

7. 关于错误处理

需要提供error非终结符,需要至少提供以下两种错误恢复功能:

a. 如果一个类的定义有语法错误,但这个类正确的结束定义了;而下一个类的定义是正确的,

parser能够跳过错误的类,重新从下一个正确的类开始分析。

b. 类似的,parser能够从feature中的error中恢复过来,继续分析下一个feature。

8. 注意事项

a. 关于优先级声明,只能用在表达式上。

b. let语法是二义性的语法,需要注意由它引起的shift-reduce冲突。可以利用bison中产生式的优先级声明

c. 注意注释掉所有print语句。。。


实践笔记:

  1. cool_tree.aps文件是各个树结点构造函数的声明文件,需要看一下
  2. cool_tree.cc文件包括着上面文件中函数的实现代码,而且还包括列表结点的操作
  3. 要注意结点构造构造函数所需要的参数,如上面的single_Cases所需要的是case类型,而真正生成case类型的函数是branch()函数,所以正确的写法应该是single_Cases(branch(id, type, expr))
  4. 每一个semantic action都包含两个步骤,首先,标记位置信息;然后,构造AST树结点。
  5. ID一定要以小写开头,TYPEID一定是大写开头
  6. 每一行不一定要用分号做结束。可以参考class和feature的语法
  7. 函数体中,出现单行expr时,不能加分号结尾。一定要加分号的话,需要用{}把expr括起来。
  8. 正确的reflexer, refparser等文件都在/home/compilers/cool/lib/.i686下可以找到
  9. 使用方法: reflexer good.cl | refparser
  10. 关于error处理,没有想像中复杂,只需要在expr分支下加一个error语句就可以,不用action;对应class,feature等的错误处理也可以相应进行
  11. 有一点需要注意,语法定义一定要使用左递归,原因不明....记住[formal, [,formal]*]定义一定要用左递归。。。。
  12. expr_list: expr_list ',' expr 而不能写成 expr_list: expr ',' expr_list
  13. 关于错误处理,单一地使用error是不足以达到恢复的效果,需要用error和其它的符号组成一个整体的错误处理语法,来达到跳过发生这行的效果
  14. 比如在let语法中需要加入error IN expr和error ',' expr_let_part_2这两个错误处理语法,来达到匹配整个出错的行,忽略它,进行下一行处理。
  15. 再如block语法中需要加入error ';'来达到匹配整个行的效果。
  16. 关于let语法,它是一个循环的语法,let x : int, y : int in x ==> let x :int in let y: int in x,在构造时需要把let语法分成三个部分:
  17. part1: let id : type [<- expr]
  18. part2: [,id : type[<-expr]]*
  19. part3: in expr

代码:

上文中提到的所有文件都在我的github里可以找到,其实也只需要看cool.y文件就可以了,所有的改动都是围绕这个文件:

https://github.com/hanks/Compiler

你可能感兴趣的:(parser)