Stanford CS1 Compilers PA2J notes

【題記·碎碎念】html

斯坦福這門Compilers本來放在Coursera上,當年錯過檔期非常惋惜,後來發現他們本身的MOOC站放了一個self paced版本,真是普大喜奔,趁着放假有空學學。java

這門課的份量能夠很輕,亦可很重。self-paced版本若是你只是看看視頻,作作quiz,那麼很簡單,根據課程介紹,一個星期3小時就夠了;而若是你要作programming assignments,老師給「有經驗的」程序員預估6-10個小時/周的工做量。其實Coursera版寫的是8-10 hours/week, 10-20 hours/week with PA,我的認爲Coursera估得更準確。程序員

前兩週學完,個人感覺是這門課若是不作編程做業,倒不如不學。作做業的過程既痛苦又興奮,self-pace的一個最大問題是幾乎沒有進度差很少的同窗來一塊兒討論,論壇上的信息也是零零散散,並且Edx平臺的論壇比Coursera的論壇體驗差太多了,所以查資料時新建瀏覽器標籤開到電腦接近崩潰是常有的事情。web

花了大把時間查的資料作完此次做業對我來講就沒什麼用了,想一想很惋惜,那麼仍是記下來給將來同窗一個參考,我相信會有必定幫助。我在作做業的時候,也許是剛開始不適應的關係,一會兒接觸太多新概念有點overwhelming,花了兩天時間看handout和Other Project Resources裏的資料,我仍是不明白第一次PA要作什麼、怎麼作,簡直無從下手。正則表達式

 

【上面都是廢話,正題此處開始】:編程

我直接用老師提供的虛擬機,因此沒有搭環境的環節。瀏覽器

第一週沒有PA要提交,虛擬機下的PA1目錄裏有些示例程序,就讓你走一走一下課程所使用的Cool語言的編譯、運行流程。app

從第二週開始有做業,須要提交的PA1實際在~/cool/assignments/PA2或PA2J目錄裏,其中PA2是C++版本,PA2J是Java版。ide

第一次做業是作一個詞法分析器,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,仔細看來:

1 <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可能會給一些啓發。

最後曬一下分

相關文章
相關標籤/搜索