编写自己的Shell解释器-3[转]
實現shell實例
程序主框架
???????主程序很簡單,它在做一些必要的初始化工作之后,進入這樣一個循環:
u???????打印提示符并等待用戶輸入
u???????獲取用戶輸入
u???????分析用戶輸入
u???????解釋執行;
如果用戶輸入 logout或者 exit 之后,才退出這個循環。
用類似偽代碼的形式表示如下:
while(1) {
???????print_prompt();
???????get_input();
???????parse_input();
???????if(“logout” || “exit”)
??????????????break;
???????do_cmd();
}
?
讀取用戶輸入
如何獲取用戶輸入?一種方法是通過 getchar() 從標準輸入每次讀一個字符,如果讀到的字符是 ‘\n’,說明用戶鍵入了回車鍵,那么就把此前讀到的字符串作為用戶輸入的命令。
代碼如下:
?
int len = 0;
int ch;
char buf[300];
?
ch = getchar();
while(len < BUFSIZ && ch != '\n') {
???????buf[len++] = ch;
???????ch = getchar();
}
if(len == BUFSIZ) {
???????printf("command is too long\n");
???????break;
}
buf[len] = '\n';
len++;
buf[len] = 0;
?
但是,我們注意到,在 bash 中,可以用“<-”和“->”鍵在命令行中左右移動,可以用上下鍵調用以前使用的命令,可以用退格鍵來刪除一個字符,還可以用 tab 鍵來進行命令行補全。我們的shell如果也要支持這些功能,那么就必須對這些鍵進行處理。這樣僅僅對用戶輸入的讀取就非常麻煩了。
實際上,任何需要一個獲取用戶輸入的程序,都會涉及到同樣的問題,如何象bash 那樣處理鍵盤?GNU readline 庫就是專門解決這個問題的,它把對鍵盤的操作完全封裝起來,對外只提供一個簡單的調用接口。有了它,對鍵盤的處理就不再讓人頭疼了。
關于 readline 庫的詳細信息,可以通過 man readline 來看它的幫助頁面。在我們的 shell 程序中,我是這樣來使用 readline的。
?
char* line;
char prompt[200];
while(1) {
???????set_prompt(prompt);
???????if(!(line = readline(prompt)))
??????????????break;
???????。。。。。。
}
?
首先通過 set_prompt() 來設置要輸出的提示符,然后以提示符作為參數調用 readline(),這個函數等待用戶輸入,并動態創建一塊內存來保存用戶輸入的數據,可以通過返回的指針 line 得到這塊內存。在每次處理完用戶輸入的命令之后,我們必須自己負責來釋放這塊內存。
有了 readline 之后,我們就可以象 bash 那樣使用鍵盤了。
在通過 readline 獲取用戶輸入之后,下一步就是對用戶輸入的命令進行分析。
?
命令行分析
對命令行的分析,實際上是一個詞法分析過程。學過編譯原理的朋友,都聽說過 lex 和yacc 的大名,它們分別是詞法分析和語法分析工具。Lex 和 yacc 都有GNU的版本(open source 的思想實在是太偉大了,什么好東東都有免費的用),分別是 flex 和 bison。
所謂“工欲善其事,必先利其器”,既然有這么好的工具,那我們就不必辛辛苦苦自己進行詞法分析了。對,我們要用 lex 來完成枯燥的命令行詞法分析工作。
“去買本《lex與yacc》(中國電力出版社)來看吧。第一次學當然稍微有點難度,不過一旦掌握了,以后再碰到類似問題,就可以多一個利器,可以節省勞動力了。
在我們的這個 shell 程序中,用 flex 來完成詞法分析工作。相對語法分析來說,詞法分析要簡單的多。由于我們只是做一個簡單的 shell,因此并沒有用到語法分析,而實際上在 bash 的實現代碼中,就用到了語法分析和 yacc。
關于 lex 的細節,在這里我就不能多說了。Lex程序,通常分為三個部分,其中進行語法分析工作的就是它的第二部分: “規則”。規則定義了在詞法分析過程中,遇到什么樣的情況,應該如何處理。
詞法分析的思路,就是根據前面定義的“shell語法規范”來把用戶輸入的命令行拆解成
首先,我們要把用戶輸入的命令,以空白字符(tab鍵或者空格)分隔成一個個的參數,并把這些參數保存到一個參數數組中。但是,這其中有幾種特殊情況。
一、如果遇到的字符是“;”、“>”、“<”或“|”,由于這些符號是管道或者列表中所用到的分隔符,因此必須把它們當作一個單獨的參數。
二、以雙引號(”)括起來的字符串要作為一個單獨的參數,即使其中出現了空白字符、“;”、“>”、“<”、“|”。其實,在POSIX標準中,對引號的處理相當復雜,不僅包括雙引號(”),還有單引號(’)、反引號(`),在什么情況下,應該用什么樣的引號以及對引號中的字符串應該如何解釋,都有一大堆的條款。我們這里只是處理一種極簡單的情況。
?
其次,如果我們遇到換行符(’\n’),那么就結束本次命令行分析。根據前面定義的 shell 語法規范,最上層的是列表命令,因此下一步是把所有的參數作為一個列表命令來處理。
轉載于:https://www.cnblogs.com/aoogur/archive/2008/12/05/1348723.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的编写自己的Shell解释器-3[转]的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: sql server系统表详细说明(二)
- 下一篇: CodeSmith使用笔记