<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    迷途書童

    敏感、勤學(xué)、多思
    隨筆 - 77, 文章 - 4, 評論 - 86, 引用 - 0
    數(shù)據(jù)加載中……

    從lex&yacc說到編譯器(2.flex的使用)

    看了第一篇的關(guān)于正則表達(dá)式的說明后,下面我們就來通過它,使用flex這個詞法分析工具來構(gòu)造我們的編譯器的詞法分析器.

    關(guān)于lex的教程應(yīng)該是很多,這里我就簡單地介紹一下,然后著重后面的lex和yacc的配合使用以及其技巧.所以,如果你不看了后還是不太明白lex或者yacc的使用,請你自己上網(wǎng)去查查,這方面的教程是很多的.我知道的一篇常見的就是

    Yacc 與 Lex 快速入門
    Lex 與 Yacc 介紹

    它的作者就是Ashish Bansal.

    Flex就是fast lex的意思.而lex就是Lexical Analyzar的意思.flex可以在cygwin或者gnupro中找到.它是unix的一個工具,屬于GNU組織產(chǎn)品.網(wǎng)上也可以找到單獨可以在windows下用的版本.

    我們一般把我們的詞法掃描程序要掃描的一些單詞(token)用正則表達(dá)式寫好,然后作為lex的輸入文件,輸入命令flex xxx.l(xxx.l就是輸入文件),lex經(jīng)過處理后,就能得到一個名字叫l(wèi)ex.yy.c的C源代碼.這個C源代碼文件,就是我們的詞法掃描程序.通常lex為我們生成的詞法分析器的C源代碼都是十分復(fù)雜而且龐大的,我們一般根本不會去查看里面的代碼(放心好了,flex這個東西不會出錯的)

    下面讓我們看看幾個我已經(jīng)使用過的幾個lex輸入文件.

    這是一個前段時間我為GBA上的一個RPG游戲?qū)懙哪_本引擎所使用的lex輸入文件(部分)

    2.1

    %{

    /* need this for the call to atof() below */

    #i nclude <stdio.h>

    #i nclude <stdlib.h>

    #i nclude <math.h>

    #i nclude "globals.h"

    %}

    digit??????? [0-9]

    number?????? ("-"|"+")?{digit}+

    hexnumber??? "0x"({digit}|[a-fA-F])+

    letter?????? [a-zA-Z]

    identifier?? ({letter}|_)({number}|{letter}|_)*

    newline????? [\n]

    whitespace?? [ \t]+

    string?????? \"[^"]*\"

    comment????? "#"[^#]*"#"

    %%

    {string}???? { return VM_STRING;??????? }

    "Logo"?????? { return VMIN_LOGO; }

    "FaceIn"???? { return VMIN_FACEIN; }

    "FaceOut"??? { return VMIN_FACEOUT; }

    "LoadTile"?? { return VMIN_LOAD_TILE;?? }

    "CreateRole" { return VMIN_CREATE_ROLE; }

    "ReleaseRole" { return VMIN_RELEASE_ROLE;}

    "CreateMap"? { return VMIN_CREATE_MAP;? }

    "ReleaseMAP" { return VMIN_RELEASE_MAP;}

    "ShowBitmap" { return VMIN_SHOWBITMAP;? }

    "CreateDialog" { return VMIN_CREATE_DIALOG; }

    "ReleaseDialog" { return VMIN_RELEASE_DIALOG;}

    "Fight"????? { return VMIN_FIGHT;?????? }

    "Delay"????? { return VMIN_DELAY;?????? }

    "PressA"???? { return VMIN_PRESS_A;???? }

    "PressB"???? { return VMIN_PRESS_B;???? }

    "PressR"???? { return VMIN_PRESS_R;???? }

    "PressL"???? { return VMIN_PRESS_L;???? }

    "PressStart" { return VMIN_PRESS_START; }

    "PressSelect" { return VMIN_PRESS_SELECT;}

    {number}???? { return VM_NUMBER;??????? }

    {whitespace} { /* skip whitespace */??? }

    {identifier} { return VM_ID;??????????? }

    {newline}??? ;

    .??????????? ;

    %%

    int yywrap()

    {

    ????? return 1;

    }

    這里的lex輸入文件一共有三個部分,用%%分開.第一部分中的%{和}%中的內(nèi)容就是直接放在lex輸出C代碼中的頂部.我們通過它可以來定義一些所需要的宏,函數(shù)和include一些頭文件等等.我的這個lex輸入文件中也沒什么特別的東西,就是常規(guī)的C源文件的include頭文件

    %{

    /* need this for the call to atof() below */

    #i nclude <stdio.h>

    #i nclude <stdlib.h>

    #i nclude <math.h>

    #i nclude "globals.h"

    %}

    第一部分中,除了前面的%{和}%包含的部分,下面的就是正則表達(dá)式的定義.

    看了第一篇的正則表達(dá)式,這樣你就能夠在這里派上用場了.

    讓我們來看看我這里定義的正則表達(dá)式:

    digit??????? [0-9]

    number?????? ("-"|"+")?{digit}+

    hexnumber??? "0x"({digit}|[a-fA-F])+

    letter?????? [a-zA-Z]

    identifier?? ({letter}|_)({number}|{letter}|_)*

    newline????? [\n]

    whitespace?? [ \t]+

    string?????? \"[^"]*\"

    comment????? "#"[^#]*"#"

    digit就不用說了,就是0-9的阿拉伯?dāng)?shù)字定義,第一篇文章中也舉了這個例子.number就是digit的1到無限次的重復(fù),再在其前面加上”+”和”-“符號.

    注意:

    “a”: 即使a是元字符,它仍是字符a

    \a: 當(dāng)a是元字符時候,為字符a

    a?: 一個可選的a,也就是說可以是a,也可以沒有a

    a|b: a或b

    (a): a本身

    [abc]: 字符a,b或c中的任一個

    [a-d]: a,b,d或者d中的任一個

    [^ab]: 除了a或b外的任何一個字符

    .: 除了新行之外的任一個字符

    {xxx}: 名字xxx表示的正則表達(dá)式

    這里需要特別說明的就是

    newline????? [\n]

    newline就是新行,這里我使用了[]把\n換行號括起來.因為如果我直接用\n表示的話,那么按照上面的規(guī)則,那就會看成\和n兩個字符,所以我使用了[\n].有些時候newline也被寫成[\n]|[\r\n].因為在文本文件中,一般換行一次,那么就是一個\n(0xA),可是在二進制文件中,換行有時候又是\r\n(0xD,0xA)一共兩個字符號.

    第二部分就是定義掃描到正則表達(dá)式的動作.

    這些動作其實就是C代碼,它們將會被鑲嵌在lex輸出的C文件中的yylex()函數(shù)中.

    上面的例子的動作其實十分平常,就是返回一個值.

    我們在外部使用這個lex為我們生成C代碼的時候,只需要使用它的int yylex()函數(shù).當(dāng)我們使用一次yylex(),那么就會自動去掃描一個匹配的正則表達(dá)式,然后完成它相應(yīng)的動作.這里的動作都是返回一值,那么yylex就會返回這個值.通常默認(rèn)yylex返回0時候,表示文件掃描結(jié)束,所以你的動作中最好不要返回0,以免發(fā)生沖突.當(dāng)然,動作中也可以不返回一值,那么yylex就會完成這個動作后自動掃描下一個可以被匹配的字符串,一直到掃描到文件結(jié)束.

    當(dāng)掃描到一個可以被匹配的字符串,那么這個時候,全局變量yytext就等于這個字符串

    請大家一定記住這些正則表達(dá)式的順序.

    如果出現(xiàn)一個字符串,可以同時匹配多個正則表達(dá)式,那么它將會被定義在前面的正則表達(dá)式匹配.所以我一般把字符串string定義在最前面.

    如果文件中的字符沒有被lex輸入文件中任何一個字符匹配,那么它會自動地被標(biāo)準(zhǔn)輸出.所以大家一定要記住在每個正則表達(dá)式處理完畢后,一定要加上{newline}和.這兩個正則表達(dá)式的動作.

    ,讓我們看看lex為我們輸出C文件中提供一些常量

    Lex 變量

    yyin

    FILE* 類型。 它指向 lexer 正在解析的當(dāng)前文件。

    yyout

    FILE* 類型。 它指向記錄 lexer 輸出的位置。 缺省情況下,yyin 和 yyout 都指向標(biāo)準(zhǔn)輸入和輸出。

    yytext

    匹配模式的文本存儲在這一變量中(char*)。

    yyleng

    給出匹配模式的長度。

    yylineno

    提供當(dāng)前的行數(shù)信息。(lexer不一定支持。)

    2.2

    這是<<編譯原理與實踐>>書中配套的源代碼的lex輸入文件.大家可以參考一下,作者為它自己定義的一個Tiny C編譯所做的詞法掃描器.

    /****************************************************/

    /* File: tiny.l???????????????????????????????????? */

    /* Lex specification for TINY?????????????????????? */

    /* Compiler Construction: Principles and Practice?? */

    /* Kenneth C. Louden??????????????????????????????? */

    /****************************************************/

    %{

    #i nclude "globals.h"

    #i nclude "util.h"

    #i nclude "scan.h"

    /* lexeme of identifier or reserved word */

    char tokenString[MAXTOKENLEN+1];

    %}

    digit?????? [0-9]

    number????? {digit}+

    letter????? [a-zA-Z]

    identifier? {letter}+

    newline???? \n

    whitespace? [ \t]+

    %%

    "if"??????????? {return IF;}

    "then"????????? {return THEN;}

    "else"????????? {return ELSE;}

    "end"?????????? {return END;}

    "repeat"??????? {return REPEAT;}

    "until"???????? {return UNTIL;}

    "read"????????? {return READ;}

    "write"???????? {return WRITE;}

    ":="??????????? {return ASSIGN;}

    "="???????????? {return EQ;}

    "<"???????????? {return LT;}

    "+"???????????? {return PLUS;}

    "-"???????????? {return MINUS;}

    "*"????? ???????{return TIMES;}

    "/"???????????? {return OVER;}

    "("???????????? {return LPAREN;}

    ")"???????????? {return RPAREN;}

    ";"???????????? {return SEMI;}

    {number}??????? {return NUM;}

    {identifier}??? {return ID;}

    {newline}?????? {lineno++;}

    {whitespace}??? {/* skip whitespace */}

    "{"???????????? { char c;

    ????????????????? do

    ????????????????? { c = input();

    ??????????????????? if (c == EOF) break;

    ??????????????????? if (c == '\n') lineno++;

    ????????????????? } while (c != '}');

    ??????????????? }

    .?????????? ????{return ERROR;}

    %%

    TokenType getToken(void)

    { static int firstTime = TRUE;

    ? TokenType currentToken;

    ? if (firstTime)

    ? { firstTime = FALSE;

    ??? lineno++;

    ??? yyin = source;

    ??? yyout = listing;

    ? }

    ? currentToken = yylex();

    ? strncpy(tokenString,yytext,MAXTOKENLEN);

    ? if (TraceScan) {

    ??? fprintf(listing,"\t%d: ",lineno);

    ??? printToken(currentToken,tokenString);

    ? }

    ? return currentToken;

    }

    這里有點不同的就是,作者用了另外一個getToken函數(shù)來代替yylex作為外部輸出函數(shù).其中g(shù)etToken里面也使用了lex默認(rèn)的輸出函數(shù)yylex(),同時還做了一些其它的事情.不過我建議大家不要像作者那樣另外寫自己的結(jié)果輸出函數(shù),因為在后面,需要和yacc搭配工作的時候,yacc生成的語法分析程序只認(rèn)名字叫yylex()的詞法結(jié)果輸出函數(shù).

    if (firstTime)

    ? { firstTime = FALSE;

    ??? lineno++;

    ??? yyin = source;

    ??? yyout = listing;

    ? }

    posted on 2006-05-06 16:15 迷途書童 閱讀(916) 評論(0)  編輯  收藏 所屬分類: 編譯原理

    主站蜘蛛池模板: 亚洲免费在线观看视频| 精品亚洲永久免费精品| 亚洲精品国产国语| 57pao国产成视频免费播放| 久久精品国产精品亚洲色婷婷| 99精品免费视品| 亚洲国产另类久久久精品小说| a毛片免费全部播放完整成| 亚洲线精品一区二区三区| 色播在线永久免费视频网站| 亚洲狠狠婷婷综合久久久久| 久久精品乱子伦免费| 亚洲欧洲在线观看| 在线观看免费人成视频| 亚洲一区二区三区免费观看| 韩国欧洲一级毛片免费| 国产亚洲福利一区二区免费看| 内射无码专区久久亚洲| 一区二区免费电影| 亚洲av不卡一区二区三区| 国产精品入口麻豆免费观看| 亚洲伊人久久大香线蕉AV| 大学生一级特黄的免费大片视频 | 美女视频黄a视频全免费网站色| 国产一级高清免费观看| fc2成年免费共享视频网站| 亚洲AV午夜成人影院老师机影院| 99免费在线观看视频| 亚洲人成网亚洲欧洲无码| 国产乱弄免费视频| 久久精品无码免费不卡| 亚洲自偷自拍另类12p| 久久精品女人天堂AV免费观看| 麻豆安全免费网址入口| 亚洲国产AV无码专区亚洲AV| 两个人的视频高清在线观看免费| 瑟瑟网站免费网站入口| 亚洲视频免费一区| 成人免费无码精品国产电影| 国色精品va在线观看免费视频| 亚洲中文无码永久免|