天天看點

LEX學習 第二節

版權聲明:您好,轉載請留下本人部落格的位址,謝謝 https://blog.csdn.net/hongbochen1223/article/details/45726355

接着第一節中的第一個示例,我們擴充第二個示例,将詞法分析程式擴充為識别不同的詞性。

下面是程式示例:

%{
/*
 * 擴充第一個示例以識别其他的詞性
 *
 */
%}

%%
[ \t ]+  /* 忽略空白 */;
is |
am |
are |
were |
was |
be |
being |
been |
do |
does |
did |
will |
would |
should |
can |
could |
has |
had |
go {printf("%s: is a verb",yytext);}

very |
simply |
gently |
quietly |
calmly |
angrily {printf("%s: is an adverb",yytext);}

to |
from |
behind |
above |
below |
between {printf("%s: is a preposition",yytext);}

if |
then |
and |
but |
or {printf("%s: is a conjunction",yytext);}

their |
my |
your |
his |
her |
its {printf("%s : is an adjection",yytext);}

I |
you |
he |
she |
we |
they {printf("%s: is a pronoun",yytext);}

[a-zA-Z]+ {
    printf("%s: do not recognize,mignt be a noun",yytext);
}

.| {ECHO; /* 通常的預設狀态 */}

%%

int main()
{
    yylex();
    return 0;
}

int yywrap()
{
    return 1;
}           

第二個示例實際上與第一個沒有什麼不同,僅僅就是列出了比前面更多的單詞,原則上可以擴充這個示例為任意多的單詞。但是這樣感覺有些笨拙,如果是單詞比較多的話,就需要将所有的單詞都要列出來,如果能夠有一個單詞表,能夠實時的添加新的單詞的話,擴充性上就會好很多。下面我們再擴充一下,就是在詞法分析程式運作時從輸入檔案中讀取聲明的單詞時允許動态的聲明詞性。聲明行以詞性的名稱開始,後面跟着要聲明的單詞。例如:

聲明4個名詞和3個動詞:

noun dog cat horse cow

verb chew eat lick

該單詞表在lex和yacc中就是一個簡單的符号表,添加符号表可以完全改變詞性文法分析程式,不必在詞法分析程式中為每個要比對的單詞放置獨立的模式,隻要有一個比對任意單詞的模式,再查閱符号表就能決定所找到的詞性。由于詞性引入了一個聲明行,是以他們現在是”保留字“。對于每一個保留字仍然有一個獨立的lex模式。還必須添加符号表維護例程。add_word()表示添加單詞,lookup_word()表示查詢單詞。

同時在程式代碼中需要一個state變量用來記錄是查找單詞還是添加單詞。無論如何隻要我們看到以詞性名字開始的行,就可以知道狀态為添加單詞,每次看到\n的時候,都切換回正常的查找狀态。

下面是程式的實作:

%{
    /*
     * 帶符号表的單詞識别程式
     */
    enum{
        LOOKUP = 0, /* 預設-查找而不是定義 */
        VERB,
        ADJ,
        ADV,
        NOUN,
        PREP,
        PRON,       
        CONJ    
    };

    int state;

    int add_word(int type,char *word);
    int lookup_word(char *word);
%}

%%

 {state = LOOKUP;} /* 行結束,傳回預設狀态 */
    /* 無論何時return wp->word_type,行都以保留的詞性名字開始 */
    /* 開始定義該類型的單詞 */
^verb {state = VERB; }
^adj  {state = ADJ;  }
^adv  {state = ADV;  }
^noun {state = NOUN; }
^prep {state = PREP; }
^pron {state = PRON; }

[a-zA-Z]+ {
    /* 一個标準的單詞,定義他或查找它 */
    if(state != LOOKUP){
        /* 定義目前單詞 */
        add_word(state,yytext);
    }else{
        switch(lookup_word(yytext)){
            case VERB: printf("%s: verb",yytext); break;
            case ADJ:  printf("%s: adjective",yytext); break;
            case ADV: printf("%s: adverb",yytext); break;
            case NOUN: printf("%s: noun",yytext); break;
            case PREP: printf("%s: preposition",yytext); break;
            case PRON: printf("%s: pronoun",yytext); break;
            case CONJ: printf("%s: conjunction",yytext); break;
            default:
                printf("%s: do not recognize",yytext);
                break;
        }
    }
}
. /* 忽略其他return wp->word_type的東西 */

%%

int main()
{
    yylex();
    return 0;
}

/* 定義一個單詞和類型的連結清單 */
struct word{
    char *word_name;
    int word_type;
    struct word *next;
};

struct word *word_list; /* 單詞連結清單中的第一個元素 */
extern void *malloc();

int add_word(int type,char *word)
{
    struct word *wp;

    if(lookup_word(word) != LOOKUP){
        printf("!! warning: word %s already defined",word);
        return 0;
    }

    /* 單詞不在那裡,配置設定一個新的條目并将它連結到連結清單上 */
    wp = (struct word *)malloc(sizeof(struct word));
    wp->next = word_list;

    /* 還必須複制單詞本身 */
    wp->word_name = (char *)malloc(strlen(word)+1);
    strcpy(wp->word_name,word);
    wp->word_type = type;
    word_list = wp;
    return 1;  /* 添加成功 */
}

int lookup_word(char *word)
{
    struct word *wp = word_list;

    /* 向下搜尋清單以尋找單詞 */
    for(;wp;wp = wp->next){
        if(strcmp(wp->word_name,word) == 0)
            return wp->word_type;
    }
    return LOOKUP;
}

int yywrap()
{
    return 1;
}
           

下面是我的程式的輸出結果: