手把手教你做一個 C 語言編譯器(1):設計
阿新 • • 發佈:2018-12-29
本章是“手把手教你構建 C 語言編譯器”系列的第二篇,我們要從整體上講解如何設計我們的 C 語言編譯器。
本系列:
首先要說明的是,雖然標題是編譯器,但實際上我們構建的是 C 語言的直譯器,這意味著我們可以像執行指令碼一樣去執行 C 語言的原始碼檔案。這麼做的理由有兩點:
- 直譯器與編譯器僅在程式碼生成階段有區別,而其它方面如詞法分析、語法分析是一樣的。
- 直譯器需要我們實現自己的虛擬機器與指令集,而這部分能幫助我們瞭解計算機的工作原理。
編譯器的構建流程
一般而言,編譯器的編寫分為 3 個步驟:
- 詞法分析器,用於將字串轉化成內部的表示結構。
- 語法分析器,將詞法分析得到的標記流(token)生成一棵語法樹。
- 目的碼的生成,將語法樹轉化成目的碼。
已經有許多工具能幫助我們處理階段1和2,如 flex 用於詞法分析,bison 用於語法分析。只是它們的功能都過於強大,遮蔽了許多實現上的細節,對於學習構建編譯器幫助不大。所以我們要完全手寫這些功能。
所以我們會根據下面的流程:
- 構建我們自己的虛擬機器以及指令集。這後生成的目的碼便是我們的指令集。
- 構建我們的詞法分析器
- 構建語法分析器
編譯器的框架
我們的編譯器主要包括 4 個函式:
next()
用於詞法分析,獲取下一個標記,它將自動忽略空白字元。program()
語法分析的入口,分析整個 C 語言程式。expression(level)
eval()
虛擬機器的入口,用於解釋目的碼。
這裡有一個單獨用於解析“表示式”的函式 expression
是因為表示式在語法分析中相對獨立並且比較複雜,所以我們將它單獨作為一個模組(函式)。
因為我們的原始碼看起來就像是:
C1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162 | #include <stdio.h>#include <stdlib.h>#include <memory.h>#include <string.h>inttoken;// current tokenchar*src,*old_src;// pointer to source code string;intpoolsize;// default size of text/data/stackintline;// line numbervoidnext(){token=*src++;return;}voidexpression(intlevel){// do nothing}voidprogram(){next();// get next tokenwhile(token>0){printf("token is: %c\n",token);next();}}inteval(){// do nothing yetreturn0;}intmain(intargc,char**argv){inti,fd;argc--;argv++;poolsize=256*1024;// arbitrary sizeline=1;if((fd=open(*argv,0))<0){printf("could not open(%s)\n",*argv);return-1;}if(!(src=old_src=malloc(poolsize))){printf("could not malloc(%d) for source area\n",poolsize);return-1;}// read the source fileif((i=read(fd,src,poolsize-1))<=0){printf("read() returned %d\n",i);return-1;}src[i]=0;// add EOF characterclose(fd);program();returneval();} |
上面的程式碼看上去挺複雜,但其實內容不多,就是讀取一個原始碼檔案,逐個讀取每個字元,並輸出每個字元。這裡重要的是注意每個函式的作用,後面的文章中,我們將逐個填充每個函式的功能,最終構建起我們的編譯器。
本節的程式碼可以在 Github 上下載,也可以直接 clone
1 | git clone-bstep-0https://github.com/lotabout/write-a-C-interpreter |
這樣我們就有了一個最簡單的編譯器:什麼都不幹的編譯器,下一章中,我們將實現其中的eval
函式,即我們自己的虛擬機器。
打賞支援我寫出更多好文章,謝謝!
打賞作者
打賞支援我寫出更多好文章,謝謝!
任選一種支付方式