LALR(1)语法分析生成器--xbytes
0.概述:
看了編譯器龍書和虎書后,自己手動寫了一個LALR(1)語法分析生成器,使用的語法文件格式和lemon的差不多。
程序里面很多的算法也都是摘錄自虎書,龍書雖然講的很詳細,但是真正動手寫的時候還是虎書上面的算法給力點。程序相對來說比較簡單,沒有做任何優化,如果看過虎書和龍書,看懂代碼難度不大。代碼文件bytes.hpp和bytes.cpp中是主要的代碼,TEMPLATE.hxx和TEMPLATE.cxx是語法分析生成器的模板文件。首先直接用make進行編譯,然后進入到test目錄中,運行生成器程序文件,參數是語法說明文件。執行成功后會生成會文件PARSER.hxx和PARSER.cxx,這兩個文件就是你需要的語法分析器了。下面是個簡單的實例說明下。
1.語法說明文件:
這里用一個簡單的計算器來說明語法說明文件的用法。下面是計算器的語法說明文件。
%include { #include <iostream> } %token { int } %syntax_error { std::cout << "Error: Syntax error.\n" << std::endl;} #left PLUS MINUS #left TIMES DIVprogram -> exp(A). { std::cout << "Result=" << A << std::endl; }exp(A) -> exp(B) MINUS exp(C). { A = B - C; std::cout << A << "=" << B << "-" << C << std::endl; } exp(A) -> exp(B) PLUS exp(C). { A = B + C; std::cout << A << "=" << B << "+" << C << std::endl; } exp(A) -> exp(B) TIMES exp(C). { A = B * C; std::cout << A << "=" << B << "*" << C << std::endl; } exp(A) -> exp(B) DIV exp(C). {if(C != 0){A = B / C;}else{std::cout << "Divide by zero." << std::endl;}std::cout << A << "=" << B << "/" << C << std::endl; }exp(A) -> INT(B). { A = B; std::cout << A << "=" << B << std::endl;}終結符:終結符的名稱只能由大寫字母組成,在生成PARSER.hxx文件中會包括所有終結符的枚舉定義。詞法分析器的分析結果要和這里定義的枚舉值一致。
非終結符:非終結符由小寫字母、下劃線組成,非終結符只存在于生成語法分析器的過程中。生成的語法分析器不會包括非終結符。
%include:這個說明符指定了生成的語法分析程序中要包含的頭文件,這個指示符的格式是后面必須用大括號。如果有多個頭文件可以用回車。
%token:這個是token結構的指示符,必須在大括號中指定,目前只支持內建的數據類型。
%syntax_error:語法分析過程中出現錯誤時,需要執行的代碼。
#left:左結合指示符。同時會指定優先級,越往后面的優先級越高。
#right:右結合指示符。同left一樣會指定優先級。
program:是語法開始指示符,語法說明文件必須指定program生成式,否則會報錯。
BNF范式(產生式):每個產生式必須以非終結符開始,以 . 符號結束。產生式中的每個非終結符都可以起別名,方便在語義代碼中使用,別名必須緊跟在非終結符后面,而且要括在小括號中。需要注意的是xbytes不支持,一行多個產生式,因此每行只能寫一個產生式。
語義代碼:每個產生式的后面可以在大括號中指定產生式的語義代碼。這個大括號要放到產生式最后的 . 點前面。語義代碼只要是C++或者C代碼就可以,沒有其他限制。
語法說明文件名:因為我寫的語法分析生成器的名字叫xbytes,所以我把語法說明文件的后綴名指定為.x。比如上面計算器的語法說明文件名:calculate.x 。當然這個文件的后綴名是可以隨便起的,即使沒有也沒有關系。
ACTION.txt:在生成語法分析器的同時,會生成一個名為ACTION.txt的文件。文件中以很友好的方式將語法分析器的動作表打印出來了??梢詭椭脩衾斫釲ALR(1)語法分析器的運作過程。
備注:在xbytes.cpp代碼文件中,包含許多dump_開頭的函數。這些函數可以輸出很多生成分析器過程中的數據。包括Symbol集合、規則集合、First集、Follow集、狀態集和動作表等。
2.語法分析器使用方式:
在根目錄下直接輸入 make 。編譯xbytes,生成的可執行程序會被移入test目錄中,進入test目錄,然后執行./x calculate.x 就可以生成,簡單計算器的語法分析程序了。使用這個程序的方式是自己寫一個main.cpp文件,文件內容如下:
#include "PARSER.hxx" #include <iostream>int main() {xbytes::parser p;//5 * 3 + 6 / 2 - 8p.eat(INT, 5);p.eat(TIMES, 0);p.eat(INT, 3);p.eat(PLUS, 0);p.eat(INT, 6);p.eat(DIV, 0);p.eat(INT, 2);p.eat(MINUS, 0);p.eat(INT, 8);p.eat(0, 0);return 0; }使用方式很簡單,首先要自己寫個詞法分析器,來進行詞法分析,然后將詞法分析得到的token一個個的喂給parser就可以了。parser::eat函數的第一個參數是token的類型,第二個參數是token的值。讀取結束后,最后寫入0,就是結束分析。
3.運行結果:
這里計算的是算式?5 * 3 + 6 / 2 - 8 的值。打印的是規約的過程,具體要打印的信息可以自己在語法說明文件的語義代碼中自己定制。
[kiven@localhost test]$ ./XP 5=5 3=3 15=5*3 6=6 2=2 3=6/2 18=15+3 8=8 10=18-8 Result=104.代碼:
目前的代碼我只在CentOS下面測試過,其他平臺沒有經過測試。代碼地址:https://github.com/kiven-li/xbytes
5.展望:
目前程序也僅僅只是能夠生成語法分析器,但是性能不是很好,實用性也不是很高。后續要優化下程序性能,token要支持自定義結構。
轉載于:https://www.cnblogs.com/kiven-code/p/4477587.html
總結
以上是生活随笔為你收集整理的LALR(1)语法分析生成器--xbytes的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MySQL数据类型char与varcha
- 下一篇: Mysql 替换字段的一部分内容