跟我一塊兒寫編譯器(一)——lex&yacc【原創】

聲      明:原創文章,轉載註明出處http://www.cnblogs.com/lucasysfeng/p/4842310.html  html

 

第一節、工欲善其事,必先利其器。

  筆者不會過多地陳述理論,而是但願經過實踐還原一個C編譯器的完成過程。正則表達式

  先來看一個簡單的源文件main.c:函數

#include <stdio.h>

int main()
{
     printf(「Hello World\n」);
     return 0;
}

  咱們會用gcc main.c生成可執行文件a.out, 那麼問題來了,gcc是如何識別include int main printf return這些詞彙的呢,又是如何根據這些詞彙作出相應操做的呢?答案是使用lex和yacc.學習

  lex 表明 lexical analyzar(詞法分析器),yacc 表明 yet another compiler compiler(編譯器代碼生成器)。lex和yacc在UNIX下分別叫flex和bison. 簡單地理解下lex&yacc, lex詞法分析器,讀取文件中的關鍵詞(後面說到的token標記其實可看作關鍵詞);而後把關鍵詞遞交給yacc,yacc對一些關鍵詞進行匹配,看它們是否符合必定的語法邏輯,若是符合就進行相應動做flex

  咱們使用lex&yacc寫編譯器,因此先來學習下lex&yacc吧。this

 

第二節、一個簡單的lex程序。

  跟着筆者將下面的程序編譯運行一遍,相信你會有所收穫。spa

1. 程序代碼。htm

  文件名:test.l
/* 第一段 */ 
%{
    int chars = 0;
    int words = 0;
    int lines = 0;
%}

/* 第二段 */  
%%
[a-zA-Z]+  { words++; chars += strlen(yytext); }
\n         { chars++; lines++; }
.          { chars++; }
%%

/* 第三段 */  
main(int argc, char **argv)
{
    yylex();
    printf("%8d%8d%8d\n", lines, words, chars);
}

分析:blog

  這段lex程序的做用是:根據輸入的字符串,輸出其行數、單詞數和字符的個數。token

(1) %%把文件分爲3段,第一段是c和lex的全局聲明,第二段是規則段,第三段是c代碼。

(2) 第一段的c代碼要用%{和%}括起來,第三段的c代碼不用。

(3) 第二段是規則段,[a-zA-Z]+  \n   . 是正則表達式,表示匹配的內容,{}內的是c編寫的動做。

  上面程序中yytext是lex變量,匹配模式的文本存儲在這一變量中。yylex()這一函數開始分析,它由lex自動生成。關於lex變量和函數後續介紹,這裏只是經過簡單的lex程序來認識lex. 

二、按照下面過程編譯運行。

#flex test.l

#gcc lex.yy.c –lfl

#./a.out

而後輸入一段文字,按ctrl+d結束輸入,則會輸出行數,單詞數和字符的個數。

編譯過程和運行結果等見下圖:

image

 

第三節、lex進階。

  修改第二節程序,將正則表達式放在全局聲明中,使邏輯更清晰。

%{
int chars = 0;
int words = 0;
int lines = 0;
%}

mywords	[a-zA-Z]+ 
mylines	\n 
mychars	.  

%%
{mywords}  { words++; chars += strlen(yytext); }
{mylines}  { chars++; lines++; }
{mychars}  { chars++; }
%%

main(int argc, char **argv)
{
  yylex();
  printf("%8d%8d%8d\n", lines, words, chars);
}

  編譯運行同第二節。

 

第四節、lex再進階—循環掃描。

  下面給出一個lex程序,這個程序在掃描到 +  或 - 時作一個特殊輸出。當調用yylex()函數時,若掃描到return對應的標記時,yylex返回,且值就爲return後的值;若沒掃描到return對應的標記,yylex繼續執行,不返回。下次調用自動從前一次的掃描位置處開始。

%{
enum yytokentype
{
    ADD = 259,
    SUB = 260,
};
%}
 
myadd   "+"
mysub   "-"
myother .
 
%%
{myadd}    { return ADD; }
{mysub}    { return SUB; }
{myother}  { printf("Mystery character\n"); }
%%
 
main(int argc, char **argv)
{
    int tok;
 
    while (tok = yylex())
    {                           
        if (tok == ADD || tok == SUB)
        {
            printf("meet + or -\n");
        }
        else
        {
            printf("this else statement will not be printed, \
                   because if yylex return,the retrun value must be ADD or SUB.");
        }
    }
}

 編譯同上,運行結果見下圖:

image

   

  到如今,僅僅介紹了lex,後續會介紹yacc.

相關文章
相關標籤/搜索