創作內容

5 GP

Lex Yacc LLVM 編譯器期末

作者:GJLMoTea│2018-07-03 01:44:23│巴幣:13│人氣:7370


介紹

flex(lexical analyzer generator) 格式如下
定義段落(include,存放digit[0-9],letter[A-za-z]、宣告等)
%%
  規則段落(符合樣式{做哪些動作})
%%
程式碼段落(fopen, printf等)


bison(syntactic analyzer generator,Bison為GNU版本的Yacc) 格式如下
%{
前導段落(include)
%}
Bison宣告段落(定義終端、非終端符號、優先順序)
%%
文法規則段落(語法規則 expr:expr '+' expr;)
%%
結尾段落(yylex, yyerror函式)




執行步驟

在Ubuntu上安裝 flex and bison

$ sudo apt-get install flex
(flex: fast lexical analyzer generator)


$ sudo apt-get install bison






sample檔裡面包括規則檔(lex.l、yacc.y 來定義token的樣式,當然是屬於陽春的版本)
以及一些簡單的C語言程式碼。

接下來要做的事情是,
把lex.l( lex.l 正規表示式表達token長的樣子) 丟到lex(語彙分析器的產生器,用來產生語彙分析器)來跑,產生出lex.yy.c
把yacc.y( yacc.y 是用CFG/BNF來描述語法的模樣) 丟到yacc(語法分析器的產生器,用來產生語法分析器)來跑,產生出y.tab.c
在編譯完lex.yy.c及y.tab.c檔後,產生出Scanner及Parser,
再來拿一些簡單的.c檔程式碼來測試 會不會通過(pass or fail)這個Scanner及Parser,
最後是拿正確的C程式碼



下載範例進行編譯

$ mkdir final
創建資料夾
將檔案(lex.l, yacc.y, sample1~7.c等sample檔)放入final資料夾中

$ cd final
進入檔案所在之資料夾中




Lex and Yacc

若要看簡易的Lex實作方式,可參考下列網址
能分析出程式碼中的  Keys(定義最基本的關鍵字 如int void main...)、Identifiers(變數名稱)、Operators(運算子)、Delemeters(分隔符號)、Literals(字串文字)
https://www.coders-hub.com/2013/05/c-code-for-lexical-analysis.html#.WL6vCRKGPUo


$ lex lex.l
用Lex對lex.l(規格檔)來編譯 產出lex.yy.c檔案
(lex.l為173行的正規表示式來表達token)  (lex.yy.c為2445行的C語言,用來定義token)


$ yacc yacc.y
用yacc對yacc.y來編譯 產出y.tab.c檔案
(yacc.c為435行的表達語法)  (y.tab.c為2024行的C語言,用來定義語法 符號 編號)
(在bison裡產生的C語言剖析原始程式中 符號以整數表示)


Compile 2 file
cc(c compiler)在linux中效果等同gcc(GNU compiler collection)
$ cc lex.yy.c y.tab.c -o Compile
編譯lex.yy.c及y.tab.c兩個檔案,產出檔名為Compile的一個可執行檔
(-o: 命名編譯後所產生出來的檔案名稱)


Test 測試
開始餵檔案給Compile測試
$ ./Compile < sample1.c 成功
$ ./Compile < sample2.c 錯誤
$ ./Compile < sample3.c 成功
$ ./Compile < sample4.c 錯誤
$ ./Compile < sample5.c 成功
$ ./Compile < sample6.c 錯誤
$ ./Compile < sample7.c 錯誤



發現error的地方: 偵測不出錯誤以及誤判正確

//使用雙斜線註解
使用未宣告的function;
宣告變數a做運算過後    再宣告變數b
x=y+-z(這個是對的)     x=y+-+-+-z(這個是對的) x=y+-*z(gcc會錯,Compile卻給對)

以上可以判斷此Scanner Parser尚有可以改進的地方








產生 Assembly code

以最快(偷懶)的方式產生 Assembly code
(這裡直接用GCC偷吃步方法產生出組合語言,
GCC是套完整的編譯器  已包含scanner parser,
即讓前面的Lex(scanner)和Yacc(parser)做白工)

$ gcc –S sample3.c
編譯出sample3.s的asm檔    -S代表編譯出中間碼(組合語言)
(因我在X64機器上執行,預設產生出來的組語為X64。參數 -masm=intel 可指定產生出X86組語)

$ cat  sample3.s
查看組合語言
結束這回合。





以踏實(所用所學 但是程序多)的方式產生Assembly code

若以下編譯過程中有出錯(套件未裝、參數下錯等),
再次編譯之前要先清除 build資料夾底下的CmakeCache.txt(參數設定檔)
以下的tar.xz檔  解壓完畢後可刪除

安裝LLVM前置步驟
$ sudo apt-get install g++ subversion cmake git
subversion:版本控制系統
cmake:跨平台自動化建構系統(類似make)



安裝LLVM 在這裡使用指定的舊版本

(下載LLVM)
$ wget http://llvm.org/releases/3.6.0/llvm-3.6.0.src.tar.xz
$ tar xf llvm-3.6.0.src.tar.xz
$ mv llvm-3.6.0.src llvm


(下載Clang 我們所用到的工具) 在LLVM -> tools資料夾底下
Clang是什麼?Clang 是一个 C++ 编写、基于 LLVM、发布于 LLVM BSD 许可证下的 C / C++ / Objective C / Objective C++ 编译器 (難怪clang叫c lang)
$ cd llvm/tools
$ wget http://llvm.org/releases/3.6.0/cfe-3.6.0.src.tar.xz
$ tar xf cfe-3.6.0.src.tar.xz
$ mv cfe-3.6.0.src clang


(下載Extra 我們所用到的額外套件) 在LLVM -> tools -> clang -> tools資料夾底下
$ cd ~/llvm/tools/clang/tools
$ wget http://llvm.org/releases/3.6.0/clang-tools-extra-3.6.0.src.tar.xz
$ tar xf clang-tools-extra-3.6.0.src.tar.xz
$ mv clang-tools-extra-3.6.0.src extra


(Compiler RT) 在llvm -> project資料夾底下
$ cd ~/llvm/projects
$ wget http://llvm.org/releases/3.6.0/compiler-rt-3.6.0.src.tar.xz
$ tar xf compiler-rt-3.6.0.src.tar.xz
$ mv compiler-rt-3.6.0.src compiler-rt



Configure配置參數
$ cd ~/llvm
$ mkdir build
$ cd build

執行configure調配參數
$ ../configure --prefix=/usr/clang --enable-optimized --enable-targets=host --disable-compiler-version-checks


Make進行編譯
$ sudo make
(要等一段時間)
$ sudo make install

(其實一開始以為Nothing to be done是失敗了)





Libcxx
(下載Libcxx) 在home資料夾底下
$ cd
$ svn co http://llvm.org/svn/llvm-project/libcxx/trunk libcxx
$ cd libcxx/

$ mkdir build
$ cd build
$ export PATH=/usr/clang/bin:$PATH
(Libcxx是GCC編譯器的一部份,透過以下指令去找到並在後續的指令中include進去)
$ echo | g++ -Wp,-v -x c++ - -fsyntax-only



轉中間代碼
$ Clang -S -emit-llvm sample3.c
產生出 sample3.ll檔
$ cat sample3.ll


由中間代碼轉組合語言
$ llc sample3.ll
產生出sample3.s檔
$ cat sample3.s

收工,結束此回合。






另外,這是主線版本(源代碼下載)的LLVM、Clang下載方法:
$ svn co http://llvm.org/svn/llvm-project/llvm/trunk llvm
svn:subversion的基本指令
co:CheckOut(取得檔案)
trunk:主線版本
(下載完後多了個llvm的資料夾)
進入llvm的tools資料夾後 下載Clang
$ cd llvm
$ cd tools
$ svn co http://llvm.org/svn/llvm-project/cfe/trunk clang


另外as (assembly) 跟 nasm(sudo apt-get install nasm)這兩種指令也可以由組合語言轉成可執行檔,不過因為沒有深入研究,詳見:
$ as --help
$ nasm -h




在此次編譯器實作過程中遇到的麻煩(bug and debug):
1. The LLVM project no longer supports building with configure & make. Please migrate to the CMake-based build system.
新版本僅支援Cmake
2. 遇到外部目錄的問題 (does not appear to contain CMakeLists.txt.)
3. 未安裝 Compiler-RT (跨平台代碼產生的輔助函式庫)


引用網址:https://home.gamer.com.tw/TrackBack.php?sn=4043752
All rights reserved. 版權所有,保留一切權利

相關創作

留言共 3 篇留言


請問一下有 exe
.l和.c檔案嗎

07-03 22:59

GJLMoTea
什麼意思?
是指 https://github.com/gjlmotea/Compiler-sample 這個嗎07-04 20:10
♙♲⚙\~O_O~/⚙♲♙
// 針對 "發現error的地方" 回應
我發現是不是沒有 symbol table ?
這樣只有 context free ,又根據你定義在 lex.l (line 49) 的 unary_operator 中有 '*' ,但沒有檢查 z 的型態,故沒有辦法報錯。
同理,沒有 symbol table ,使用未宣告的東西不會報錯,。

05-08 05:21

GJLMoTea
謝謝指點!05-09 00:42
賴桑
不錯耶!巴哈姆特我用了那麼久,寫這種軟體工程方面的文章超少,大大有當時的上課講義可以私我喔?

07-25 17:39

GJLMoTea
07-31 17:02
我要留言提醒:您尚未登入,請先登入再留言

5喜歡★GJLMoTea 可決定是否刪除您的留言,請勿發表違反站規文字。

前一篇:開箱 - 夏普 空氣清淨... 後一篇:Call by valu...

追蹤私訊切換新版閱覽

作品資料夾

bingh21《鬼神之亂》
西洋版呂布,布萊克出征聯合軍,面對同床異夢的對手,他想出了什麼詭計?看更多我要大聲說昨天22:51


face基於日前微軟官方表示 Internet Explorer 不再支援新的網路標準,可能無法使用新的應用程式來呈現網站內容,在瀏覽器支援度及網站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業系統版本才可使用)

face我們了解您不想看到廣告的心情⋯ 若您願意支持巴哈姆特永續經營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】