亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關于我們
? 蟲蟲下載站

?? lex@yacc.txt

?? 從lex&yacc說到編譯器(二)flex的使用
?? TXT
字號:
從lex&yacc說到編譯器(二)flex的使用

[原創(chuàng)] tangl_99 2004-01-31 
--------------------------------------------------------------------------------
 
    看了第一篇的關于正則表達式的說明后,下面我們就來通過它,使用flex這個詞法治齬ぞ呃垂乖煳頤塹謀嘁肫韉拇史ǚ治銎鰲?
    關于lex的教程應該是很多,這里我就簡單地介紹一下,然后著重后面的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)用正則表達式寫好,然后作為lex的輸入文件,輸入命令flex xxx.l(xxx.l就是輸入文件),lex經(jīng)過處理后,就能得到一個名字叫l(wèi)ex.yy.c的C源代碼。這個C源代碼文件,就是我們的詞法掃描程序。通常lex為我們生成的詞法分析器的C源代碼都是十分復雜而且龐大的,我們一般根本不會去查看里面的代碼(放心好了,flex這個東西不會出錯的)。

    下面讓我們看看幾個我已經(jīng)使用過的幾個lex輸入文件。
    這是一個前段時間我為GBA上的一個RPG游戲寫的腳本引擎所使用的lex輸入文件(部分)

例2.1
%{
/* need this for the call to atof() below */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "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 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "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      "#"[^#]*"#"

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

“a” : 即使a是元字符,它仍是字符a
\a    : 當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表示的正則表達式

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

    第二部分就是定義掃描到正則表達式的動作。
    這些動作其實就是C代碼,它們將會被鑲嵌在lex輸出的C文件中的yylex()函數(shù)中。
    上面的例子的動作其實十分平常,就是返回一個值。
    我們在外部使用這個lex為我們生成C代碼的時候,只需要使用它的int yylex()函數(shù)。當我們使用一次yylex(),那么就會自動去掃描一個匹配的正則表達式,然后完成它相應的動作。這里的動作都是返回一值,那么yylex就會返回這個值。通常默認yylex返回0時候,表示文件掃描結束,所以你的動作中最好不要返回0,以免發(fā)生沖突。當然,動作中也可以不返回一值,那么yylex就會完成這個動作后自動掃描下一個可以被匹配的字符串,一直到掃描到文件結束。
    當掃描到一個可以被匹配的字符串,那么這個時候,全局變量yytext就等于這個字符串

    請大家一定記住這些正則表達式的順序。
    如果出現(xiàn)一個字符串,可以同時匹配多個正則表達式,那么它將會被定義在前面的正則表達式匹配。所以我一般把字符串string定義在最前面。
    如果文件中的字符沒有被lex輸入文件中任何一個字符匹配,那么它會自動地被標準輸出。所以大家一定要記住在每個正則表達式處理完畢后,一定要加上{newline}和.這兩個正則表達式的動作。

    好,讓我們看看lex為我們輸出C文件中提供一些常量
Lex 變量
yyin FILE* 類型。它指向 lexer 正在解析的當前文件。 
yyout FILE* 類型。它指向記錄 lexer 輸出的位置。
缺省情況下,yyin 和 yyout 都指向標準輸入和輸出。 
yytext 匹配模式的文本存儲在這一變量中(char*)。 
yyleng 給出匹配模式的長度。 
yylineno 提供當前的行數(shù)信息。(lexer不一定支持。) 


例2.2
    這是《編譯原理與實踐》書中配套的源代碼的lex輸入文件。大家可以參考一下,作者為它自己定義的一個Tiny C編譯所做的詞法掃描器。
/****************************************************/
/* File: tiny.l                                     */
/* Lex specification for TINY                       */
/* Compiler Construction: Principles and Practice   */
/* Kenneth C. Louden                                */
/****************************************************/

%{
#include "globals.h"
#include "util.h"
#include "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ù)。其中getToken里面也使用了lex默認的輸出函數(shù)yylex(),同時還做了一些其它的事情。不過我建議大家不要像作者那樣另外寫自己的結果輸出函數(shù),因為在后面,需要和yacc搭配工作的時候,yacc生成的語法分析程序只認名字叫yylex()的詞法結果輸出函數(shù)。
if (firstTime) {
    firstTime = FALSE;
    lineno++;
    yyin = source;
    yyout = listing;
}
    其中的yyin,yyout,source,listing都是FILE*類型。yyin就是要lex生成的詞法掃描程序要掃描的文件,yyout就是基本輸出文件(其實我們通常都不用yyout,即使要生成一些輸出信息,我們都是自己通過fprintf來輸出)。
"{"             { char c;
                  do
                  { c = input();
                    if (c == EOF) break;
                    if (c == '\n') lineno++;
                  } while (c != '}');
                }
    其中,作者的這個Tiny C是以{}來包括注釋信息。作者并沒有寫出注釋信息的正則表達式,但是它可以通過檢索“{”,然后用lex內(nèi)部函數(shù)input()一一檢查 { 后面的字符是不是 } 來跳過注釋文字。(C語言的/* */注釋文字正則表達式十分難寫,所以很多時候我們都用這種方法直接把它的DFA(掃描自動機)寫出來)。

    本文就是通過簡單地舉出兩個比較實際的例子來講解flex輸入文件的。再次說明,如果你是第一次接觸lex,那么請看看前面我推薦的文章,你可以在IBM的開發(fā)者網(wǎng)上查到。下一篇關于yacc于BNF文法的說明也是如此。請大家先參考一下其它標準的教程。 

?? 快捷鍵說明

復制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
成人免费看视频| 欧美日韩一区二区三区免费看| 9色porny自拍视频一区二区| 欧美日韩一区视频| 久久久久久久久久久久久女国产乱| 亚洲宅男天堂在线观看无病毒| 美腿丝袜亚洲综合| 欧美在线观看视频一区二区| 国产免费成人在线视频| 午夜精品久久久久久久久久久| 成人综合在线视频| 欧美一级欧美一级在线播放| 樱桃视频在线观看一区| 国产乱码一区二区三区| 在线电影一区二区三区| 一区二区三区欧美激情| 成人午夜免费电影| 精品乱人伦一区二区三区| 午夜精品久久久久久久久久久 | a在线播放不卡| 久久综合九色综合久久久精品综合| 亚洲一区二区影院| 色又黄又爽网站www久久| 国产视频一区在线播放| 国产乱人伦精品一区二区在线观看 | 色综合久久综合网欧美综合网| 久久亚洲一级片| 美女www一区二区| 欧美高清视频一二三区 | 天天综合网 天天综合色| 色偷偷成人一区二区三区91| 中文字幕亚洲一区二区va在线| 国产综合色在线| 久久久精品蜜桃| 国产精品一区二区久久不卡 | 欧美午夜电影网| 樱桃国产成人精品视频| 色哟哟一区二区在线观看| 亚洲欧美精品午睡沙发| 91丨九色丨黑人外教| 亚洲天堂成人网| 欧美无乱码久久久免费午夜一区 | 天天亚洲美女在线视频| 欧美日韩国产影片| 欧美bbbbb| 26uuu国产在线精品一区二区| 久久91精品国产91久久小草| 久久久久久麻豆| 成人av免费在线观看| 中文字幕五月欧美| 欧美亚洲国产一区在线观看网站 | 极品少妇xxxx精品少妇| 久久一区二区三区四区| 国产成人鲁色资源国产91色综 | 不卡的av电影| 夜夜夜精品看看| 日韩午夜电影av| 激情综合色综合久久综合| 国产精品久久网站| 91福利国产精品| 麻豆精品在线看| 欧美国产综合一区二区| 91国偷自产一区二区使用方法| 亚洲成人动漫精品| 久久精品视频网| 91行情网站电视在线观看高清版| 日韩精品五月天| 中文字幕久久午夜不卡| 欧美三级资源在线| 精品一区二区在线免费观看| 国产精品美女一区二区三区| 欧美三级视频在线| 国产乱子伦视频一区二区三区| 亚洲男人的天堂在线观看| 91精品啪在线观看国产60岁| 国产成人精品一区二区三区四区| 亚洲一区在线免费观看| 久久在线观看免费| 日本二三区不卡| 韩国成人在线视频| 亚洲一区免费在线观看| 久久久久久久久久久久久女国产乱 | 国产精品主播直播| 亚洲一二三区不卡| 国产精品视频看| 精品久久久久久最新网址| 99精品黄色片免费大全| 麻豆精品在线视频| 亚洲国产中文字幕| 国产欧美日韩不卡| 欧美一区二区视频网站| 91久久精品一区二区三| 国产91丝袜在线18| 久久精品国产精品亚洲综合| 亚洲综合视频在线| 国产精品不卡在线观看| 久久综合久久鬼色中文字| 7777精品伊人久久久大香线蕉完整版 | 91亚洲精华国产精华精华液| 精品一区二区三区在线视频| 亚洲大片精品永久免费| 亚洲手机成人高清视频| 国产人成亚洲第一网站在线播放| 欧美一卡2卡3卡4卡| 欧美日韩一区小说| 色视频成人在线观看免| 成人avav影音| 国产麻豆成人精品| 激情成人综合网| 久久精品99国产精品日本| 日韩va亚洲va欧美va久久| 亚洲国产中文字幕| 亚洲成人午夜电影| 亚洲国产精品久久久久婷婷884| 亚洲九九爱视频| 亚洲精品一二三| 亚洲黄网站在线观看| 亚洲三级电影全部在线观看高清| 国产精品成人免费| 亚洲欧美偷拍三级| 亚洲一区中文在线| 天天影视网天天综合色在线播放| 亚洲成人av资源| 秋霞影院一区二区| 激情图片小说一区| 成人动漫一区二区三区| av不卡免费电影| 91久久国产最好的精华液| 色妹子一区二区| 欧美日韩久久一区二区| 欧美欧美欧美欧美首页| 欧美日韩二区三区| 日韩视频国产视频| 久久伊人蜜桃av一区二区| 国产婷婷一区二区| 曰韩精品一区二区| 日韩高清不卡一区二区| 久99久精品视频免费观看| 国产精品白丝jk白祙喷水网站 | 国产日韩亚洲欧美综合| 国产精品丝袜一区| 亚洲综合一区二区| 日本欧美在线看| 国产精品一区二区x88av| 国产91露脸合集magnet| 一本色道久久综合亚洲91| 欧美日韩不卡视频| 国产亚洲欧美一区在线观看| 中文字幕亚洲综合久久菠萝蜜| 一区二区国产视频| 蜜桃一区二区三区四区| 国产不卡高清在线观看视频| 91小视频免费看| 欧美一级国产精品| 国产精品久久久久影院老司| 亚洲一区二区三区四区的| 精品系列免费在线观看| 91小宝寻花一区二区三区| 日韩视频免费观看高清完整版| 中文字幕亚洲综合久久菠萝蜜| 午夜视频一区在线观看| 成人妖精视频yjsp地址| 欧美日韩激情一区二区三区| 久久精品欧美一区二区三区麻豆 | 欧美激情中文不卡| 丝袜美腿亚洲一区二区图片| 国产成人在线影院| 欧美精三区欧美精三区| 国产精品视频九色porn| 美女网站在线免费欧美精品| 9色porny自拍视频一区二区| 欧美白人最猛性xxxxx69交| 一区二区三区在线观看动漫| 国产精品69久久久久水密桃| 欧美色网一区二区| 国产精品久久三| 国产高清在线精品| 欧美一区二区在线不卡| 亚洲综合免费观看高清在线观看| 国产iv一区二区三区| 欧美一区二区三级| 一区二区三区.www| 99久久久国产精品| 国产偷国产偷亚洲高清人白洁| 日本女人一区二区三区| 91黄色免费网站| 亚洲欧美另类久久久精品2019| 国产乱码精品一区二区三| 日韩欧美亚洲一区二区| 亚洲bdsm女犯bdsm网站| 欧日韩精品视频| 一区二区三区资源| 一本久久a久久免费精品不卡| 欧美经典一区二区| 国产成人av影院| 国产精品视频线看| 不卡在线视频中文字幕| 国产精品久久久久一区二区三区| 成人免费视频caoporn| 国产欧美一区二区三区鸳鸯浴|