草木瓜

本BLOG内容较杂且水平有限,切勿见怪

lw ID:liwei_cmg
183067次访问,排名364好友0人,关注者5
liwei_cmg的文章
原创 87 篇
翻译 0 篇
转载 12 篇
评论 474 篇
草木瓜的公告
全部文章列表链接
最近评论
dytyjk:老大有研究过twm-tg310吗?linux系统的,也不知是什么版本,只能玩java,参考moto系列的在卡上装loader,可卡上没有PlugCardDB文件,telnet也不行.最要命的是这手机没有资源管理器,往卡上装的文件除了媒体格式的可在相应程序下打开,其他文件在手机上一律看不到!就只能当传统手机用了吗?相当的郁闷!
xsd:哪里有层次模型数据库的代码?
test:mm
liwei_cmg:to nn16300

我想你说得应该是 编译一些可执行程序,这个就需要搭建交叉编译环境了,不知道如下系列文章是不是你所想要的效果。

深度剖析E680G开发一.所谓的交叉编译环境
...

最近没有登录,未及时回复,抱歉
cmg:楼上的兄弟,很遗憾,这是两年的dd了,后来就没有进一步继续了,不过有不少diy爱好者继续前进,也搞出了不少dd。
文章分类
收藏
    相册
    我的好友
    aresgj(RSS)
    小叶
    存档
    订阅我的博客
    XML聚合  FeedSky

    原创 Lex和Yacc应用方法(一).初识Lex收藏

    新一篇: Lex和Yacc应用方法(二).再识Lex与Yacc | 旧一篇: Linux手机DIY.内核初探.系统后台启动简单介绍

     Lex和Yacc应用方法(一).初识Lex

    草木瓜  20070301

    Lex(Lexical Analyzar 词法分析生成器),Yacc(Yet Another Compiler Compiler
    编译器代码生成器)是Unix下十分重要的词法分析,语法分析的工具。经常用于语言分
    析,公式编译等广泛领域。遗憾的是网上中文资料介绍不是过于简单,就是跳跃太大,
    入门参考意义并不大。本文通过循序渐进的例子,从0开始了解掌握Lex和Yacc的用法。

    <本系列文章的地址:http://blog.csdn.net/liwei_cmg/category/207528.aspx>

    一.Lex(Lexical Analyzar) 初步示例

    先看简单的例子(注:本文所有实例皆在RetHat Linux下完成):

    一个简单的Lex文件 exfirst.l 内容:

    %{
    #include "stdio.h"
    %}
    %%
    [\n]                  ;
    [0-9]+                printf("Int     : %s\n",yytext);
    [0-9]*\.[0-9]+        printf("Float   : %s\n",yytext);
    [a-zA-Z][a-zA-Z0-9]*  printf("Var     : %s\n",yytext);
    [\+\-\*\/\%]          printf("Op      : %s\n",yytext);
    .                     printf("Unknown : %c\n",yytext[0]);
    %%

    在命令行下执行命令flex解析,会自动生成lex.yy.c文件:
    [root@localhost liweitest]flex exfirst.l

    进行编译生成parser可执行程序:
    [root@localhost liweitest]cc -o parser lex.yy.c -ll

    [注意:如果不加-ll链结选项,cc编译时会出现以下错误,后面会进一步说明。]

    /usr/lib/gcc-lib/i386-redhat-linux/3.2.2/../../../crt1.o(.text+0x18): In function `_start':
    ../sysdeps/i386/elf/start.S:77: undefined reference to `main'
    /tmp/cciACkbX.o(.text+0x37b): In function `yylex':
    : undefined reference to `yywrap'
    /tmp/cciACkbX.o(.text+0xabd): In function `input':
    : undefined reference to `yywrap'
    collect2: ld returned 1 exit status


    创建待解析的文件 file.txt:

    title
    i=1+3.9;
    a3=909/6
    bcd=4%9-333

    通过已生成的可执行程序,进行文件解析。

    [root@localhost liweitest]# ./parser < file.txt
    Var     : title
    Var     : i
    Unknown : =
    Int     : 1
    Op      : +
    Float   : 3.9
    Unknown : ;
    Var     : a3
    Unknown : =
    Int     : 909
    Op      : /
    Int     : 6
    Var     : bcd
    Unknown : =
    Int     : 4
    Op      : %
    Int     : 9
    Op      : -
    Int     : 333

    到此Lex用法会有个直观的了解:

    1.定义Lex描述文件
    2.通过lex,flex工具解析成lex.yy.c文件
    3.使用cc编译lex.yy.c生成可执行程序


    再来看一个比较完整的Lex描述文件  exsec.l  :


    %{
    #include "stdio.h"
    int linenum;
    %}
    %%
    title                 showtitle();
    [\n]                  linenum++;
    [0-9]+                printf("Int     : %s\n",yytext);
    [0-9]*\.[0-9]+        printf("Float   : %s\n",yytext);
    [a-zA-Z][a-zA-Z0-9]*  printf("Var     : %s\n",yytext);
    [\+\-\*\/\%]          printf("Op      : %s\n",yytext);
    .                     printf("Unknown : %c\n",yytext[0]);
    %%
    showtitle()
    {
    printf("----- Lex Example -----\n");
    }

    int main()
    {
      linenum=0;
      yylex(); /* 进行分析 */
      printf("\nLine Count: %d\n",linenum);
      return 0;
    }
    int yywrap()
    {
    return 1;
    }

    进行解析编译:
    [root@localhost liweitest]flex exsec.l
    [root@localhost liweitest]cc -o parser lex.yy.c
    [root@localhost liweitest]./parser < file.txt

    ----- Lex Example -----
    Var     : i
    Unknown : =
    Int     : 1
    Op      : +
    Float   : 3.9
    Unknown : ;
    Var     : a3
    Unknown : =
    Int     : 909
    Op      : /
    Int     : 6
    Var     : bcd
    Unknown : =
    Int     : 4
    Op      : %
    Int     : 9
    Op      : -
    Int     : 333

    Line Count: 4

    这里就没有加-ll选项,但是可以编译通过。下面开始着重整理下Lex描述文件.l。


    二.Lex(Lexical Analyzar) 描述文件的结构介绍

    Lex工具是一种词法分析程序生成器,它可以根据词法规则说明书的要求来生成单词识
    别程序,由该程序识别出输入文本中的各个单词。 一般可以分为<定义部分><规则部
    分><用户子程序部分>。其中规则部分是必须的,定义和用户子程序部分是任选的。 


    (1)定义部分
    定义部分起始于 %{ 符号,终止于 %} 符号,其间可以是包括include语句、声明语句
    在内的C语句。这部分跟普通C程序开头没什么区别。
    %{
    #include "stdio.h"
    int linenum;
    %}

    (2) 规则部分
    规则部分起始于"%%"符号,终止于"%%"符号,其间则是词法规则。词法规则由模式和
    动作两部分组成。模式部分可以由任意的正则表达式组成,动作部分是由C语言语句组
    成,这些语句用来对所匹配的模式进行相应处理。需要注意的是,lex将识别出来的单
    词存放在yytext[]字符数据中,因此该数组的内容就代表了所识别出来的单词的内容。
    类似yytext这些预定义的变量函数会随着后面内容展开一一介绍。动作部分如果有多
    行执行语句,也可以用{}括起来。

    %%
    title                 showtitle();
    [\n]                  linenum++;
    [0-9]+                printf("Int     : %s\n",yytext);
    [0-9]*\.[0-9]+        printf("Float   : %s\n",yytext);
    [a-zA-Z][a-zA-Z0-9]*  printf("Var     : %s\n",yytext);
    [\+\-\*\/\%]          printf("Op      : %s\n",yytext);
    .                     printf("Unknown : %c\n",yytext[0]);
    %%

    A.规则部分的正则表达式

    规则部分是Lex描述文件中最为复杂的一部分,下面列出一些模式部分的正则表达式字
    符含义:

    A-Z, 0-9, a-z         构成模式部分的字符和数字。

    -                     指定范围。例如:a-z 指从 a 到 z 之间的所有字符。

    \                     转义元字符。用来覆盖字符在此表达式中定义的特殊意义,
                          只取字符的本身。
                         
    []                    表示一个字符集合。匹配括号内的任意字符。如果第一个字
                          符是^那么它表示否定模式。例如: [abC] 匹配 a, b, 和C
                          的任何一个。
                         
    ^                     表示否定。

    *                     匹配0个或者多个上述模式。
    +                     匹配1个或者多个上述模式。
    ?                     匹配0个或1个上述模式。

    $                     作为模式的最后一个字符时匹配一行的结尾。

    { }                   表示一个模式可能出现的次数。 例如: A{1,3} 表示 A 可
                         能出现1次或3次。[a-z]{5} 表示长度为5的,由a-z组成的
                         字符。此外,还可以表示预定义的变量。
                        
    .                     匹配任意字符,除了 \n。

    ( )                   将一系列常规表达式分组。如:{Letter}({Letter}|{Digit})*
    |                     表达式间的逻辑或。

    "一些符号"            字符的字面含义。元字符具有。如:"*" 相当于 [\*]。

    /                     向前匹配。如果在匹配的模式中的"/"后跟有后续表达式,
                          只匹配模版中"/"前面的部分。如:模式为 ABC/D 输入 ABCD,
                          时ABC会匹配ABC/D,而D会匹配相应的模式。输入ABCE的话,
                          ABCE就不会去匹配ABC/D。


    B.规则部分的优先级


    规则部分具有优先级的概念,先举个简单的例子:


    %{
    #include "stdio.h"
    %}
    %%
    [\n]                  ;
    A                     {printf("ONE\n");};
    AA                    {printf("TWO\n");};
    AAAA                  {printf("THREE\n");};
    %%

    此时,如果输入内容:

    [root@localhost liweitest]# cat file1.txt
    AAAAAAA

    [root@localhost liweitest]# ./parser < file1.txt
    THREE
    TWO
    ONE

    Lex分析词法时,是逐个字符进行读取,自上而下进行规则匹配的,读取到第一个A字符
    时,遍历后发现三个规则皆匹配成功,Lex会继续分析下去,读至第五个字符时,发现
    "AAAA"只有一个规则可用,即按行为进行处理,以此类推。可见Lex会选择最长的字符
    匹配规则。

    如果将规则
    AAAA                  {printf("THREE\n");};
    改为
    AAAAA                 {printf("THREE\n");};

     ./parser < file1.txt 输出结果为:
    THREE
    TWO


    再来一个特殊的例子:

    %%
    title                 showtitle();
    [a-zA-Z][a-zA-Z0-9]*  printf("Var     : %s\n",yytext);
    %%

    并输入title,Lex解析完后发现,仍然存在两个规则,这时Lex只会选择第一个规则,下面
    的则被忽略的。这里就体现了Lex的顺序优先级。把这个例子稍微改一下:

    %%
    [a-zA-Z][a-zA-Z0-9]*  printf("Var     : %s\n",yytext);
    title                 showtitle();
    %%

    Lex编译时会提示:warning, rule cannot be matched.这时处理title字符时,匹配
    到第一个规则后,第二个规则就无效了。

    再把刚才第一个例子修改下,加深下印象!

    %{
    #include "stdio.h"
    %}
    %%
    [\n]                  ;
    A                     {printf("ONE\n");};
    AA                    {printf("TWO\n");};
    AAAA                  {printf("THREE\n");};
    AAAA                  {printf("Cannot be executed!");};

    ./parser < file1.txt 显示效果是一样的,最后一项规则肯定是会忽略掉的。

     

    C.规则部分的使用变量

    且看下面示例:

    %{
    #include "stdio.h"
    int linenum;
    %}
    int                   [0-9]+
    float                 [0-9]*\.[0-9]+
    %%
    {int}                 printf("Int     : %s\n",yytext);
    {float}               printf("Float   : %s\n",yytext);
    .                     printf("Unknown : %c\n",yytext[0]);
    %%

    在%}和%%之间,加入了一些类似变量的东西,注意是没有;的,这表示int,float分
    别代指特定的含义,在两个%%之间,可以通过{int}{float}进行直接引用,简化模
    式定义。


    (3) 用户子程序部分

    最后一个%%后面的内容是用户子程序部分,可以包含用C语言编写的子程序,而这些子
    程序可以用在前面的动作中,这样就可以达到简化编程的目的。这里需要注意的是,
    当编译时不带-ll选项时,是必须加入main函数和yywrap(yywrap将下后面说明)。如:

    ...
    %%
    showtitle()
    {
    printf("----- Lex Example -----\n");
    }

    int main()
    {
      linenum=0;
      yylex(); /* 进行Lex分析 */
      printf("\nLine Count: %d\n",linenum);
      return 0;
    }
    int yywrap()
    {
    return 1;
    }


    三.Lex(Lexical Analyzar) 一些的内部变量和函数

    内部预定义变量:

    yytext   char *  当前匹配的字符串
    yyleng   int     当前匹配的字符串长度
    yyin     FILE *  lex当前的解析文件,默认为标准输出
    yyout    FILE *  lex解析后的输出文件,默认为标准输入
    yylineno int     当前的行数信息

    内部预定义宏:

    ECHO     #define ECHO fwrite(yytext, yyleng, 1, yyout)  也是未匹配字符的
             默认动作
            

    内部预定义的函数:

    int yylex(void)    调用Lex进行词法分析
    int yywrap(void)   在文件(或输入)的末尾调用。如果函数的返回值是1,就停止解
                       析。 因此它可以用来解析多个文件。代码可以写在第三段,这
                       样可以解析多个文件。 方法是使用 yyin 文件指针指向不同的
                       文件,直到所有的文件都被解析。最后,yywrap() 可以返回1
                       来表示解析的结束。
               
               
    lex和flex都是解析Lex文件的工具,用法相近,flex意为fast lexical analyzer generator。
    可以看成lex的升级版本。


    相关更多内容就需要参考flex的man手册了,十分详尽。

     

    四.关于Lex的一些综述

    Lex其实就是词法分析器,通过配置文件*.l,依据正则表达式逐字符去顺序解析文件,
    并动态更新内存的数据解析状态。不过Lex只有状态和状态转换能力。因为它没有堆栈,
    它不适合用于剖析外壳结构。而yacc增加了一个堆栈,并且能够轻易处理像括号这样的
    结构。Lex善长于模式匹配,如果有更多的运算要求就需要yacc了。

    发表于 @ 2007年03月15日 17:23:00|评论(loading...)|编辑

    新一篇: Lex和Yacc应用方法(二).再识Lex与Yacc | 旧一篇: Linux手机DIY.内核初探.系统后台启动简单介绍

    评论

    #yac 发表于2007-04-26 09:27:03  IP: 125.120.58.*
    草木瓜的yacc系列比起其他一些文章,详细多了,也容易理解!
    #Lincoln 发表于2007-07-27 18:12:24  IP: 81.168.243.*
    5c4b51c812a47a1d3f5549eafd4d6f20 KaiLutes GoodloeEliseo KeeganMaltese KeeganMaltese KaiLutes LandsKian ColemanBresler JohnathanWengerd KaiLutes RustyRinaldi d6d455521734c1493cac3c4ed034936b
    #Denzel 发表于2007-07-28 01:04:16  IP: 164.77.55.*
    b43e3e9231da15f99db8ac8e334fe24c CaleDalessandro BloomerHerman MarkGarett KoryMoos KoryMoos EllerbeeTucker AndreasMazzella AndreasMazzella SkylerGualtieri WhaleyYahir d891cbc338a7f37538d845cc1b8ace37
    #Jabari 发表于2007-08-15 21:43:38  IP: 84.123.181.*
    4417f2e0ddd2ae7bc7e8b1bd9cff8856 http://servo-motore-asincrono.errkvz.com/ http://film-ninfomane.dqjccd.com/ http://teatro-scala-milano-stagione-2006-2007.dqjccd.com/ http://download-giochi-educativi.dqjccd.com/ http://tempo-di-sport.dqjccd.com/ http://lodi-banca.errkvz.com/ http://foto-udine.dqjccd.com/ http://web-cam-prezzo.errkvz.com/ http://signorini-gianluca.dqjccd.com/ http://riconoscimento-urgenza.errkvz.com/ 0a62e025ec1c06708bf9b30208b63edd
    #Ramon 发表于2007-08-16 06:02:41  IP: 77.216.233.*
    17e4357049b9b9316abc20a95b700064 http://pesci-rari.fdohzk.com/ http://istituto-informa.hiehis.com/ http://case-napoli-in-vendita.fdohzk.com/ http://peso-lunghezza.hiehis.com/ http://centro-disturbo-comportamento-alimentare-udine.fdohzk.com/ http://un-uomo-solo-e-al-comando.hiehis.com/ http://presepe-di-gragnano.hiehis.com/ http://mobile-cucina-componibile.fdohzk.com/ http://carta-salerno.fdohzk.com/ http://cappa-aspiranti-nardi.hiehis.com/ 2b6d286e6c30e06d4735acf381be2354
    #Conner 发表于2007-08-18 05:01:07  IP: 190.22.12.*
    7aaa1bde4cade20e9139a6607298c7c8 LamontGosney AsmarJoel CreekMiles MylesApodaca GallegosKory IrvingKealoha KeatonLeone BurghardtJovany AsmarJoel IrvingKealoha c05ecd0f07e3d450a33a4c21d72f7092
    #Jarrod 发表于2007-09-04 02:39:18  IP: 69.254.186.*
    8cdc75c4567501748675d683d1ddd8ec japanese japanese japanese japanese japanese japanese japanese japanese japanese japanese ab92a454be843cc194dc5850abbf01b8
    #nmap 发表于2008-04-24 19:47:13  IP: 218.87.116.*
    呵呵,昨天参考木瓜的这篇好文,
    才学会用lex作词法分析,强烈推荐。
    :)
    #cmg 发表于2008-04-28 20:14:21  IP: 61.130.8.*
    呵呵,有兴趣可以写个代码模拟下lex和yacc,那样会了解的更多。
    #nmap 发表于2008-04-29 09:16:52  IP: 59.62.5.*
    好的,真是好建议。:)
    发表评论  


    登录
    Csdn Blog version 3.1a
    Copyright © 草木瓜