【题记·碎碎念】

斯坦福这门Compilers原本放在Coursera上,当年错过档期很是可惜,后来发现他们自己的MOOC站放了一个self paced版本,真是普大喜奔,趁着放假有空学学。

这门课的分量可以很轻,亦可很重。self-paced版本如果你只是看看视频,做做quiz,那么很简单,根据课程介绍,一个星期3小时就够了;而如果你要做programming assignments,老师给“有经验的”程序员预估6-10个小时/周的工作量。其实Coursera版写的是8-10 hours/week, 10-20 hours/week with PA,个人认为Coursera估得更准确。

前两周学完,我的感受是这门课如果不做编程作业,倒不如不学。做作业的过程既痛苦又兴奋,self-pace的一个最大问题是几乎没有进度差不多的同学来一起讨论,论坛上的信息也是零零散散,而且Edx平台的论坛比Coursera的论坛体验差太多了,因此查资料时新建浏览器标签开到电脑接近崩溃是常有的事情。

花了大把时间查的资料做完这次作业对我来说就没什么用了,想想很可惜,那么还是记下来给未来同学一个参考,我相信会有一定帮助。我在做作业的时候,也许是刚开始不适应的关系,一下子接触太多新概念有点overwhelming,花了两天时间看handout和Other Project Resources里的资料,我还是不明白第一次PA要做什么、怎么做,简直无从下手。

【上面都是废话,正题此处开始】:

我直接用老师提供的虚拟机,所以没有搭环境的环节。

第一周没有PA要提交,虚拟机下的PA1目录里有些示例程序,就让你走一走一下课程所使用的Cool语言的编译、运行流程。

从第二周开始有作业,需要提交的PA1实际在~/cool/assignments/PA2或PA2J目录里,其中PA2是C++版本,PA2J是Java版。

第一次作业是做一个词法分析器,lexical analyzer, also called a scanner。这其实是一件很琐碎的工作,而核心工作很单一:定义规则把源代码tokenize掉,所以大牛们做了一些工具来方便帮助你处理琐事,你可以专心写规则。

lexical analyzer generator的元老是lex,后来在其基础上发展出flex/jlex,分别对应C++和Java,(后来貌似又来了个jflex - -,这帮大佬起名字感觉是存心要绕死你)。

我选择了Java路线,官方资料可以在这里找到,这份文档必读

Jlex是一个辅助工具,你按照一定格式定义好规则,然后Jlex将你定义的规则转换为程序,这个自动生成的程序就是你的词法分析器,你把源代码喂给它,它就吐出一个一个的token,告诉你这个是关键字那个是标识符。

规则写在一个叫cool.lex的文本文件里,乍看上去格式很复杂,因为它居然还分四个区域,还带有各种稀奇古怪的形如%line的参数,细看其实不难,因为你的主要工作全部在"Rules"区完成,然后根据你的实现方式差异,你有可能需要在"Declarations"加上你的类/函数定义,可以在"Rules"区调用,然后在"Definitions"定义几个状态/正则别名。

所谓规则,其实就是正则表达式了,这东西如果之前从来没用过也不用怕,因为Jlex的正则语法很简单。PA2要做的事就是用正则匹配Cool程序源码里各个不同的元素,然后处理成下一阶段需要的格式。在开始做作业之前,可以看看这个例子,你将来要实现的东西差不多就长这样。

任务不难,难的是熟悉这个操作环境,还有老师给你写好的一大堆辅助类(暂时用不上几个),再加上handout有些地方实在写得语焉不详:看了两遍,只输了一条命令

make -f /usr/class/cs143/assignments/PA2J/Makefile

然后就抓瞎了,大脑直接idle了;cool.lex里的例子有注释等于没有,看不懂,一开始根本不知道怎么下手,连看资料都不知道从哪里看起。

好在有Google和Github两个神器,我直接找到了别人写好的答案……说实话,当时我有点想偷懒直接抄,反正这次PA的核心就是写一写正则表达式,原理懂了差不多得了,代码一粘一贴,分数到手,多好,但是……

嗯……满分63分只拿了9分……

好吧,还是得自己动手。

不过既然有了分数,说明它的输入输出肯定是好的,这其实才是我们新手最棘手的问题啊,ok,仔细看来:

 <YYINITIAL>";"          { return new Symbol(TokenConstants.SEMI);  }

这是其中的一条规则,意思是在"YYINITIAL"这个状态下,如果遇到";"这个符号输入,那么就输出一个Symbol对象,{}保存你的处理策略。目测这个对象的constructor接受一个SEMI常量,跑到TokenConstants.java里面看了一下,这些常量都是int,形如

public static final int MULT = 27;

知道这个就很好办了,其他的规则都照葫芦画瓢,无非正则表达式复杂一点,有些情况换个类,加个参数。

在给Jlex的特别说明里(handout page 6)他写了,(编号是我加的):

1) The value returned by the
method CoolLexer.next token is an object of class java cup.runtime.Symbol. This object has
a field representing the syntactic category of a token. The syntactic codes for all tokens are defined in the file TokenConstants.java.

2) The component,
the semantic value or lexeme (if any), is also placed in a java cup.runtime.Symbol object

3) class identifiers, object identifiers, integers, and strings, the semantic value should be of type AbstractSymbol

(注意AbstractSymbol是个抽象类,你将来要用它的子类:IdSymbolIntSymbolStringSymbol,class identifiers, object identifiers要用IdSymbol,integer用IntSymbol,string用StringSymbol。文档在这里

其实就是告诉你,像上面那个例子一样,你的规则匹配中之后,要return一个Symbol对象,这个Symbol包含一个field代表你匹配中的token的分类或名字id,都在TokenConstants.java里定义好了,去找就是;另外一个field是semantic value,也要用Symbol来表示,但是对于3)里的这些token,semantic value要用AbstractSymbol类。注意Symbol和AbstractSymbol没有关系,甚至不在同一个包里,看文档就知道了。现在这些东西的关系不是很清楚无所谓,但再往后PA3等可能就要用到。

这一大段估计可以把人绕晕。反正我在搜到那个9分答案之前完全不理解它想说什么,代码其实很简单,如果token类型是identifier,那么就这样:

IdSymbol dummy = new IdSymbol(yytext(), yytext().length(), 0);
return new Symbol(TokenConstants.TYPEID, dummy);

也有这样做的(换一种Symbol类型,类似的套路)

IntTable table = new IntTable();
return new Symbol(TokenConstants.INT_CONST, table.addString(yytext()));

理由是IntTable.addString返回值就是一个IntSymbol。这些table在lexical analysis阶段暂时不用,所以可以弄些dummy值,constructor缺什么就给它喂什么,简单粗暴。

对了,状态有必要多说一句。在"directives"区域,你可以定义状态。语法如

%state COMMENT

进入注释以后,你就使用yybegin(COMMENT)进行状态转换,转换完之后可以用

<COMMENT>... {...}

这样的方式使用状态,表示在这种状态下才匹配这条规则,出注释切记要用yybegin(YYINITIAL)把状态转回来。另外在一条规则里,状态不是必须的,可以忽略,相当于任意状态都适用此规则。

YYINITIAL是Jlex隐含定义的常量,如果在lexer的整个运行过程中你没有进行过状态转换,那么全程都处于YYINITIAL状态下,详见Jlex文档第2.2.5节

对了还有,yytext()表示被当前规则匹配中的、预处理过的文本,可以用简单粗暴的方式查看...

System.err.println("processing: "+yytext());

这些例子举出来,这个作业可以被视为完成一半了,剩下的就是对照Cool_manual一个一个写规则。哪个TokenConstants对应哪个符号,我没有找到文档,你要是找到了请告诉我,不过从名字看并不难对应,查查字典多试一试吧。

当然有一些正则还是得花点时间动点脑筋的,必要的时候还需要写辅助类来处理字符串。

我在backslash上花费了较多时间,最后才通过的测试是"weirdcharcomment.cool",corner case无穷尽呐,更多的时候是按住葫芦起了瓢。

另外这个PDF可能会给一些启发。

最后晒一下分

Stanford CS1 Compilers PA2J notes的更多相关文章

  1. (转)Awesome Courses

    Awesome Courses  Introduction There is a lot of hidden treasure lying within university pages scatte ...

  2. batch gradient descent(批量梯度下降) 和 stochastic gradient descent(随机梯度下降)

    批量梯度下降是一种对参数的update进行累积,然后批量更新的一种方式.用于在已知整个训练集时的一种训练方式,但对于大规模数据并不合适. 随机梯度下降是一种对参数随着样本训练,一个一个的及时updat ...

  3. Some notes in Stanford CS106A(4)

    1.x++ is a method , the return value is x. (post increment) ++x is also a method , the return value ...

  4. Some notes in Stanford CS106A(3)

    1.If ( str1==str2 ) means if str1 and str2 are refers to the same OBJECT. But when compare string , ...

  5. Some notes in Stanford CS106A(2)

    1.Local variable(local) ex. int i = 0; factorial(i); the "i" outside the method factorial( ...

  6. Some notes in Stanford CS106A(1)

    Karel world 1.During make a divider operation --int x=5; double y = x/2  =>  y=2 we need sth as a ...

  7. Latex Notes

    latex Table of Contents 1. Presentation/Slides with Beamer 2. Drawing in LaTex With TikZ 3. Tracked ...

  8. Machine Learning Algorithms Study Notes(3)--Learning Theory

    Machine Learning Algorithms Study Notes 高雪松 @雪松Cedro Microsoft MVP 本系列文章是Andrew Ng 在斯坦福的机器学习课程 CS 22 ...

  9. Machine Learning Algorithms Study Notes(2)--Supervised Learning

    Machine Learning Algorithms Study Notes 高雪松 @雪松Cedro Microsoft MVP 本系列文章是Andrew Ng 在斯坦福的机器学习课程 CS 22 ...

随机推荐

  1. JavaScript侧边悬浮框

    <script> window.onscroll=function(){ var oDiv=document.getElementById('div1'); var scrollTop=d ...

  2. ASCII电脑编码

    Bin Dec Hex 缩写/字符 解释 0000 0000 0 00 NUL(null) 空字符 0000 0001 1 01 SOH(start of headline) 标题开始 0000 00 ...

  3. 在linux中使用cmake编译运行cocos2d-x 3.4 projects

    原因: 由于不想在真机环境和 ide中调试环境, 只想在linux端进行 调试和运行, 需要使用cmake对现有的游戏进行编译(cocos2dx-lua 3.4) 修改步骤: 1.修改framewor ...

  4. Hammer.js--转载自李林峰的园子

    一.前言 移动端框架当前还处在初级阶段,但相对于移动端的应用来说已经有很长时间了.虽然暂时还没有PC端开发的需求量大,但移动端的Web必然是一种趋势,在接触移动端脚本的过程中,最开始想到的是juqer ...

  5. R 在linux redhat 6.5的编译安装过程

    下载源码包 在http://cran.r-project.org/mirrors.html,选择一个国内镜像下载需要的版本,比如:http://mirror.lzu.edu.cn/CRAN/src/b ...

  6. 关于 一开始不懂得 hosts配置。

    是转载别人的. 原文: http://my.oschina.net/cxz001/blog/298228   感谢分享: 一开始抄着陪着win下的hosts文件.然后配置  apache中的hosts ...

  7. 手机设备连接eclipse的问题

    因为现在测试到的机型也没几台,很多都是直接能连接上eclipse,但是有些Android太“个性”所以遇到有一两台手机直接插上是不能连接到eclipse的:好了:解决问题把:首先我们需要知道连接的前提 ...

  8. 卡尔曼滤波器 Kalman Filter (转载)

    在学习卡尔曼滤波器之前,首先看看为什么叫“卡尔曼”.跟其他著名的理论(例如傅立叶变换,泰勒级数等等)一样,卡尔曼也是一个人的名字,而跟他们不同的是,他是个现代人! 卡 尔曼全名Rudolf Emil ...

  9. c# List去重

    1 list如果数据是值类型,比如list<int> 这种,添加linq之后就可以使用list = list.Distinct().ToList(); 2 如果是数据是引用类型,比如中间是 ...

  10. rabbitmq 重复ACK导致消息丢失

    rabbitmq 重复确认导致消息丢失 背景 rabbitmq 在应用场景中,大多采用工作队列 work-queue的模式. 在一个常见的工作队列模式中,消费者 worker 将不断的轮询从队列中拉取 ...