使用flex

Flex如何处理二义性模式:

1、词法分析器匹配输入时匹配尽可能多的字符串

2、如果两个模式都可以匹配的话,匹配在程序中更早出现的模式

上下文相关的记号

flex提供起始状态(start state)的概念,可以动态地开启和关闭针对特定模式的识别,对于处理上述上下文相关的情况比较有用。

Flex词法分析器中的文件IO操作

除非另行制定,否则flex词法分析器总是读取标准输入。

词法分析器总是通过名为yyin的文件句柄读取输入。

[[email protected] flex2]# more fb2-1.l
%option noyywrap

%{
    #include <string.h>
    int chars = 0;
    int lines = 0;
    int words = 0;
%}
%%
[a-zA-Z]+   { words++; chars += strlen(yytext); }
\n          { lines++; chars++; }
[ \t]       {}
.           { chars++; }

%%

int main(int argc, char**argv)
{
    if(argc>1)
    {
        yyin=fopen(argv[1],"r");

        if(yyin == NULL)
        {
            perror(argv[1]);
            return 1;
        }
    }

    yylex();

    printf("chars=%d,words=%d,lines=%d\n",chars,words,lines);

    return 0;
}

对应的Makefile:
[[email protected] flex2]# more Makefile
fb2-1:lex.yy.o
        gcc -o fb2-1 lex.yy.o -lfl

lex.yy.o:fb2-1.l
        flex fb2-1.l
        gcc -Wall -c -g lex.yy.c

clean:
        rm -rf lex.yy.* fb2-1

读取多个文件

flex提供yyrestart(f)例程,它使词法分析器读取标准输入输出文件f。

%option noyywrap
%{
#include <string.h>
int totchars = 0;
int totlines = 0;
int totwords = 0;

int chars = 0;
int lines = 0;
int words = 0;

%}
%%

[a-zA-Z]+  { chars += strlen(yytext); words++; }
[ \t]      { }
\n         { lines++; }
.          { chars++; }

%%
int main(int argc, char ** argv)
{
    if(argc<2)
    {
        yylex();
        printf("chars=%d,words=%d,lines=%d\n",chars,words,lines);
        return 0;
    }   

    int i;
    for(i=1; i<argc; i++)
    {
        FILE* f = fopen(argv[i],"r");

        if(f == NULL)
        {
            perror(argv[i]);
            return 1;
        }   

        yyrestart(f);

        yylex();

        totchars += chars;
        totlines += lines;
        totwords += words;

    }   

    printf("totchars=%d,totwords=%d,totlines=%d\n",totchars,totwords,totlines);

    return 0;
}

这个例子打开每个文件,使用yyrestart()把打开的文件作为词法分析器的输入,然后调用yylex()进行词法分析。

Flex词法分析器的IO结构

flex提供三层输入系统

从文件读取和从终端读取存在差异——预读机制

1、从文件读取,可以通过大段的读操作来提高工作效率

2、从终端读取,用户可能一次只输入一行,并且期望每行

flex词法分析器会检查当前其输入是否来自终端并决定使用哪一种读取方式。

flex词法分析器使用YY_BUFFER_STATE的数据结构处理输入,包含一个字符串缓冲区以及一些变量和标记。

可以指向所读取的文件的FILE*,也可以创建一个与文件无关的YY_BUFFER_STATE来分析已经在内存中的字符串。

默认的flex词法分析器的输入行为如下:

YY_BUFFER_STATE  bp;
extern FILE* yyin;

......任何第一次调用词法分析器之前所需要做的事情

if(!yyin) yyin = stdin; 默认输入设备是stdin

bp = yy_create_buffer(yyin, YY_BUF_SIZE); // YY_BUF_SIZE由flex定义,大小通常为16K

yy_switch_to_buffer()
yylex();或者yyparse()或者其他对词法分析器的调用

  

1、如果yyin没有设置,就把stdin设置给它

2、使用yy_create_buffer创建一个读取yyin的新缓冲区

3、使用yy_switch_to_buffer来让词法分析器从缓冲区读入,接着开始分析

4、当需要读取多个文件时,每打开一个文件就调用yyrestart(fp),把词法分析器的输入切换到标准输入输出文件fp

其他函数也可以用来创建分析区,包括yy_scan_string(“string”)——分析以空字符串结尾的字符串

和yy_scan_buffer(char *base,size)分析长度确定的数据流

出于最大灵活性的考虑,可以重新定义flex用于读取输入到当前缓冲区的宏:

#define  YY_INPUT(buf,result,max_size)

每当词法分析器的输入缓冲区为空时,调用YY_INPUT,buf是缓冲区,maxsize是缓冲区大小,而result则迎来放置实际读取的长度,如果位于EOF,则result等于0.

flex提供两个在动作代码中比较有用的宏:input()和 unput()

每次input()的调用将返回输入流的下一个字符,可以帮助读取一小段输入而不用定义相应的模式

每次对unput(c)的调用把字符c推回到输入流。

输入管理的三个层次是:

1、设置yyin来读取所需文件

2、创建并使用YY_BUFFER_STATE输入缓冲区

3、重定义YY_INPUT

Flex词法分析器的输出

默认的规则:所有没有被匹配的输入都拷贝到yyout

flex允许在添加%option nodefault,使它不要添加默认的规则

这样输入无法被给定的规则完全匹配时,词法分析器可以报告一个错误。

建议总是使用。

起始状态和嵌套输入文件

例子需求:

处理嵌套的包含文件并且打印它们,在打印的时候每行前加上行号。

这个程序需要维护一个包含嵌套输入文件和行号的堆栈,在每次遇到一个#include时压入当前文件和行号信息,在处理完包含文件后再把它们从堆栈弹出。

起始状态,允许指定在特定时刻哪些模式可以被来用匹配。

在靠近文件顶端的%x 行把IFILE定义为起始状态

可以定义任意多的起始状态

%option noyywrap
%option yylineno
%option nodefault

%x IFILE

%{
    struct bufstack{
        struct bufstack* prev; /*上一个文件信息*/
        YY_BUFFER_STATE bs; /*保持的缓冲区*/

        int lineno; /*保持的行号*/
        char* filename; /*文件名*/
        FILE* f; /*当前的文件句柄*/
    }* curbs = 0;

    char* curfilename;

    int newfile(char *fn);
    int popfile(void);
%}

%%

^"#"[ \t]*include[ \t]*[\"<]    { BEGIN IFILE; }/*第一个模式匹配#include语句,知道遇到文件名之前的双引号或者<号,得到匹配后,词法分析器会切换到IFILE状态*/

<IFILE>[^ \t\n \">]+             {
                                  //匹配文件名,直到遇到引号、空白字符或者行结束符,文件名传递给newfile
                                  //基于函数input读取include后面剩余的部分,当词法分析器从包含文件返回时,
                                  //可以直接从下一行读取
                                  int c; while((c=input()) && c!=‘\n‘);

                                  yylineno++;

                                  if(!newfile(yytext))
                                      yyterminate();

                                  BEGIN INITIAL;
                                }               

<IFILE>.|\n                      { //匹配不规范的情况
                                    fprintf(stderr,"%4d bad include file",yylineno);}

<<EOF>>                         {
                                    //特殊匹配模式,匹配输入文件的结束
                                    if(!popfile())
                                       yyterminate();

                                }
^.                              { fprintf(stdout,"%4d %s",yylineno,yytext);}
^\n                             { fprintf(stdout,"%4d %s",yylineno++,yytext);}
\n                              { ECHO; yylineno++; }
.                               { ECHO; }

%%

int main(int argc, char**argv)
{
    if(argc<2)
        fprintf(stderr,"need file name\n.");

    if(newfile(argv[1]))
        yylex();

    return 0;

}

/*
*维护一个bufstack结构的链表,每个bufstack都有一个例程指向前一个bufstack的指针
*/
int newfile(char *fn)
{

    FILE*f = fopen(fn,"r");
    struct bufstack * bs =(struct bufstack*)malloc(sizeof(struct bufstack));

    if(!f)  { perror(fn);return 0;}
    if(!bs) { perror("malloca");exit(1);}

    /*记住当前状态*/
    if(curbs) curbs->lineno = yylineno;
    bs->prev = curbs;

    /*建立当前文件信息*/

    bs->bs = yy_create_buffer(f,YY_BUF_SIZE);
    bs->f = f;
    bs->filename = fn;
    //恢复到前一个缓冲区
    yy_switch_to_buffer(bs->bs);
    curbs = bs;
    yylineno = 1;
    curfilename = fn;
    return 1;
}

int popfile(void)
{
    struct bufstack *bs = curbs;
    struct bufstack *prevbs;

    if(!bs) return 0;

    /*删除当前文件信息*/
    fclose(bs->f);
    yy_delete_buffer(bs->bs);

    /*切回上一个文件*/
    prevbs = bs->prev;
    free(bs);

    if(!prevbs) return 0;

    yy_switch_to_buffer(prevbs->bs);
    curbs = prevbs;
    yylineno = curbs->lineno;
    curfilename = curbs->filename;
    return 1;
}

  

使用flex

时间: 2024-08-29 20:00:43

使用flex的相关文章

css3 flex盒子布局

<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title></title> <style type="text/css"> *{ margin: 0; padding: 0; } .nav{ display: -webkit-flex; background-color: lightgreen; height: 100px

flex布局

一.Flex布局是什么? Flex是Flexible Box的缩写,意为"弹性布局",用来为盒状模型提供最大的灵活性. 任何一个容器都可以指定为Flex布局. .box{ display: flex; } 行内元素也可以使用Flex布局. .box{ display: inline-flex; } Webkit内核的浏览器,必须加上-webkit前缀. .box{ display: -webkit-flex; /* Safari */ display: flex; } 注意,设为Fle

Flex 实现表格布局 (微信小程序)

微信小程序自己开发了一套 wxml + wxss,对许多 HTML 标签和 CSS 属性不支持. 不支持 table 标签,推荐使用 flex 布局. 自然而然的想法:flex 嵌套,效果还不错,贴代码如下: <view id="panel" class="flex-column"> <view class="flex-cell flex-row"> <text class="flex-cell flex-

FLEX布局的一些问题和解决方法

前言 露珠最近研究了一下flex的布局方式,发现项w3c推出的这套布局解决方案对于日益复杂的前端开发布局来说是确实是一利器,并且在不同的屏幕上实现了真正的响应式布局:不再单纯地依赖百分比和float的强拼硬凑来达到设计需求,在各个屏幕上显示效果友好,弹性的伸缩元素,简洁易维护的代码.只可惜,这位老兄有一位致命的缺点----除了chrome外几乎所有手机上浏览器都没有兼容它!!,或者支持程度大不一样!这样开发人员头疼的问题就来了,刚刚在手机上忽略掉IE这个强盗的兼容问题,又来一个?!.flex的优

弹性盒模型flex

弹性盒子模型 布局方案 传统的布局方案大多采用div+css+float+position+display来实现,但是随着css3中弹性盒子模型的推出,在前端布局方案中就又多出了一项彪悍的选项.而因为最近在研究小程序,发现中间使用弹性盒子布局效果更好效率更高一点,所以就将之前学习弹性盒模型的相关知识点整理出来,给大家分享. 弹性盒模型flex布局介绍 弹性盒模型(flexbox)又称为弹性布局,是css3中新提出的一种布局方式,通过弹性布局,可以让子元素自动调整宽度和高度,从而达到很好的填充任何

CSS3布局之flex布局效果

<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> *{ margin: 0; padding: 0; } .container{ width: 1000px; margin:0 auto; } he

flex布局帮助你快速实现布局

flex布局可以帮我们快速布局一些区块,实现你想要的效果,不用再去float,position之类的.我们在布局网页的时候很多时候都是一些特殊布局,flex就能帮我快速去布局,不需要去定位. 任何一个盒子都可以指定为flex布局,但是要注意,设为 Flex 布局以后,子元素的float.clear和vertical-align属性将失效. 下面我们看看我们网站经常遇到实例:我们要让图片,文字居中并且都贴底部布局,以往的经验会,父容器设置text-align:center,但是垂直方向就很繁琐了,

CSS3 flexbox 布局 ---- flex项目属性介绍

现在介绍用在flex项目上的css 属性,html结构还是用ul, li 结构,不过内容改成1,2,3, 样式的话,直接把给 ul 设display:flex 变成flex 容器,默认主轴的方向为水平方向.index.html <ul> <li>1</li> <li>2</li> <li>3</li> </ul> index.css ul { display: flex; width: 600px; borde

flex 布局教程

网页布局(layout)是 CSS 的一个重点应用. 布局的传统解决方案,基于盒状模型,依赖 display 属性 + position属性 + float属性.它对于那些特殊布局非常不方便,比如,垂直居中就不容易实现. 2009年,W3C 提出了一种新的方案----Flex 布局,可以简便.完整.响应式地实现各种页面布局.目前,它已经得到了所有浏览器的支持,这意味着,现在就能很安全地使用这项功能. Flex 布局将成为未来布局的首选方案.本文介绍它的语法,下一篇文章给出常见布局的 Flex 写

flex兼容性问题

flex于众多手机的兼容方案 如果项目使用构建工具,可加autoprefixer来处理,[autoprefixer使用指南](https://github.com/postcss/autoprefixer) 纯手写css兼容代码 /*display: flex;写法*/ span { display: -webkit-box; display: -webkit-flex; display: -ms-flexbox; display: flex; } /*justify-content: cent