【题记·碎碎念】

斯坦福这门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. ajax java base64 图片储存

    js代码 //利用formdata上传 var dataUrl = $('#canvas').getDataUrl(); var img = $('<img>').attr('src', ...

  2. js 打印星星金字塔

    /** * * 第一行: * * 第二行: *** * 第三行: ***** * 第四行: ******* * 第五行: ********* * */ document.write('<p al ...

  3. 过滤emoji表情

    str=str.replace(/\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff]/g, "");

  4. Perl的基本语法(转)

    (原文来自:http://www.jb51.net/shouce/perl.htm)

  5. mysql 求最小值/最大值

    计算所有人最低工资和最高工资,需分别用到min()和max()函数.(请注意,MIN和MAX函数会忽略NULL值) select min(sal) as min_sal , max(sal) as m ...

  6. Ubuntu14.04+Beanstalkd1.9最佳实践

    目录 [TOC] 1.基本概念 1.1.什么是Beanstalkd?   Beanstalkd 是一个轻量级消息中间件,它最大特点是将自己定位为基于管道 (tube) 和任务 (job) 的工作队列. ...

  7. Java--super关键字用法

    看了马老师的视频,百度了一下,随即敲了一些代码,super是超人,超级的意思,层面上理解为父类 class Person { Person(){             System.out.prin ...

  8. ORA-00907: 缺失右括号

    创建表时出现ORA-00907: 缺失右括号的情况 调整关键字的顺序 CREATE TABLE s_dept(ID PRIMARY KEY NOT NULL NUMBER(7),NAME NOT NU ...

  9. Redis -- 01 入门

    1. Redis是什么 与memcached 和 couchbase类似,redis是非常快速的基于内存的键值数据库,使用标准c编写,是使用最广泛的缓存中间件.利用Redis提供的五种基本数据类型(S ...

  10. ArcGis 字段计算表达式写法注意事项

    在ArcGis中,经常用到字段的计算.对于复杂的字段计算,需要写代码来实现,在使用ESRI.ArcGIS.DataManagementTools.CalculateField 类时,Python代码中 ...