《現代編譯原理》,俗稱,虎書。因為這本書對實踐的要求比較高,所以選擇了這本書來作為編譯原理的學習書籍,想一步一步的記錄下來,最終完成一個完整的編譯器。但是,一個人看書總是感覺很孤獨。今天看第一章的題目,看完了都不知道要干什么。無奈找了一本中文版的,翻譯的也不如人意,還不如看英文的。最后去晚上找了半天才找到別人寫的第一章作業運行后,才知道要實現什么功能。然后自己徒手開始寫,居然沒有邏輯bug的就完了。呵呵。突然感覺網上的資料太少,所以寫這一個系列的文章也想把志同道合的聚集起來,大家一起來討論虎書。本人畢業半年,有寫的不對還希望大家指正。
這本書的第一章,和其他外國書籍一樣,先是討論了一下本書的結構,需要有怎樣的基礎以及用到那些工具。然后介紹了編譯器的各個方面。就個人而言,像這種總結和概述的章我一般喜歡看完全書以后再回頭看看,那個時候就會對整本書有比較深刻的理解。但是這本書第一章給了一個小的練習,總結來說就是利用前面介紹的數據結構和文法規則創建一個計算print數量的函數和一個直線型程序語言翻譯器。程序很簡單,但是作為入門的練習,個人人為實在太好了。
第一,這個作業讓我開始關注編程語言本身。以前都是將程序語言作為整塊去理解,理解其表達的邏輯含義和功能。但是在寫這個程序的時候,它讓我開始關注語言的每一句成分。首先,語言最基本的成分可以籠統的分為兩類,語句(statement)和表達式(expression)。語句是執行完成后沒有任何數值的產生,例如打印語句,轉移語句,而表達式是有數值的產生的,算數操作,1+2 那么產生了3.
第二,我然我了解到編程語言是怎么從文本變化到樹狀結構,如何對樹狀結構進行操作得到最后的結果。對編譯器有了一個感性的了解。
一下是代碼:
計算print的數量
#ifndef MAXARGS_H_ #define MAXARGS_H_ #include "slp.h" int maxargs(A_exp) ; int maxargs(A_expList) ; int maxargs(A_stm a_stm) ; #endif
#include "maxargs.h" #include "slp.h" int maxargs(A_stm a_stm) { if (a_stm == NULL) { return 0 ; } switch(a_stm->kind) { case A_stm_::A_assignStm : return maxargs(a_stm->u.assign.exp) ; case A_stm_::A_printStm : return 1 + maxargs(a_stm->u.print.exps) ; case A_stm_::A_compoundStm: return maxargs(a_stm->u.compound.stm1) + maxargs(a_stm->u.compound.stm2) ; } return 0 ; } int maxargs(A_exp a_exp) { if (a_exp == NULL ) { return 0 ; } switch(a_exp->kind) { case A_exp_::A_opExp: return maxargs(a_exp->u.op.left) + maxargs(a_exp->u.op.right) ; case A_exp_::A_eseqExp: return maxargs(a_exp->u.eseq.stm) + maxargs(a_exp->u.eseq.exp) ; } return 0 ; } int maxargs(A_expList a_explist) { if (a_explist == NULL) { return 0 ; } switch(a_explist->kind) { case A_expList_::A_pairExpList : return maxargs(a_explist->u.pair.head)+maxargs(a_explist->u.pair.tail) ; case A_expList_::A_lastExpList: return maxargs(a_explist->u.last) ; } return 0 ; }
將語言解釋並且計算結果
#ifndef INTERPRETES_H_ #define INTERPRETES_H_ #include "util.h" #include "slp.h" typedef struct table *Table_ ; struct table { string id ; int value ; Table_ tail ; }; typedef struct intAndTable_ *intAndTable ; struct intAndTable_ { int i ; Table_ table ; }; Table_ interStm(A_stm stm , Table_ t) ; intAndTable interExp(A_exp exp , Table_ t) ; intAndTable interExpList(A_expList expList , Table_ t) ; Table_ update(Table_, string ,int ) ; int lookup(Table_ , string) ; #endif
#include "interprets.h" #include "util.h" #include "slp.h" #include <stdio.h> #include <stdlib.h> #include <string.h> Table_ Table(string id , int value , Table_ *tail) { Table_ t = Table_(malloc( sizeof(*t)) ); t->id = id ; t->value = value ; t->tail = t ; return t ; } Table_ interStm(A_stm stm , Table_ t) { if (stm == NULL ) { return NULL ; } Table_ table ; intAndTable itable; A_expList tmpExplist ; switch(stm->kind) { case A_stm_::A_compoundStm: table = interStm(stm->u.compound.stm1 , t) ; return interStm(stm->u.compound.stm2 , table) ; case A_stm_::A_printStm: tmpExplist = stm->u.print.exps ; while(1) { if (tmpExplist->kind == A_expList_::A_lastExpList) { itable = interExp(tmpExplist->u.last , t) ; printf(" %d" , itable->i) ; break ; } else { itable = interExp(tmpExplist->u.pair.head , t) ; printf(" %d" , itable->i) ; tmpExplist = tmpExplist->u.pair.tail ; } } printf("\n" ) ; return itable->table ; case A_stm_::A_assignStm: itable = interExp(stm->u.assign.exp ,t) ; table = update(itable->table , stm->u.assign.id , itable->i) ; return table ; } return NULL ; } intAndTable interExpList(A_expList expList , Table_ t) { if (expList == NULL) { return NULL ; } intAndTable tmp ; switch(expList->kind) { case A_expList_::A_lastExpList: tmp = interExp(expList->u.last , t) ; return tmp ; case A_expList_::A_pairExpList: tmp = interExp(expList->u.pair.head , t) ; tmp = interExpList(expList->u.pair.tail , tmp->table) ; return tmp ; } return NULL ; } intAndTable interExp(A_exp exp , Table_ t) { if ( exp == NULL ) { return NULL ; } intAndTable t1 = intAndTable(malloc( sizeof(*t))) ; int tmp ; switch(exp->kind) { case A_exp_::A_idExp: t1->i = lookup(t , exp->u.id) ; t1->table = t ; return t1 ; case A_exp_::A_numExp: t1->i = exp->u.num ; t1->table = t ; return t1 ; case A_exp_::A_opExp: t1 = interExp(exp->u.op.left , t) ; tmp = t1->i ; t1 = interExp(exp->u.op.right , t1->table) ; switch(exp->u.op.oper) { case A_plus: tmp += t1->i ; break ; case A_minus: tmp -= t1->i ; break ; case A_times: tmp *= t1->i ; break ; case A_div: tmp /= t1->i ; break ; } t1->i = tmp ; return t1 ; case A_exp_::A_eseqExp: t = interStm(exp->u.eseq.stm , t) ; t1 = interExp(exp->u.eseq.exp , t) ; return t1 ; } return NULL ; } Table_ update(Table_ t, string s ,int v) { Table_ t1 = Table_(malloc( sizeof(*t1))) ; t1->id = s ; t1->tail = t ; t1->value = v ; return t1 ; } int lookup(Table_ t, string c) { Table_ tmp = t ; while(tmp) { if (tmp->id == c) { return tmp->value ; } tmp = tmp->tail ; } return -1 ; }
這是主函數
/* This file is intentionally empty. You should fill it in with your solution to the programming exercise. */ #include "prog1.h" #include "slp.h" #include "util.h" #include "interprets.h" #include "maxargs.h" void main() { A_stm p ; p = prog() ; int a = maxargs(p) ; printf("the print number is %d\n" , a) ; Table_ t = NULL ; t = interStm(p , t) ; }
最后結果是 2 8 7 80
