学习使用flex

2023-11-06

会对flex做词法分析了解很多。

下面我通过一个例子来详细说明如何使用flex

根据所学的词法分析内容,利用flex构造PL/0语言的词法分析器。

既然是构造PL/0的词法分析器,那么我们有必要看一下pl0语言的简介和相应文法:

2        PL/0语言

Ⅰ.PL/0语言概述.

    PL/0语言是PASCAL语言的子集,它具备一般高级程序设计语言的典型特点。PL/0语言编译程序结构比较清晰,可读性强,充分体现了一个高级语言编译程序实现的基本组织、技术和步骤,是一个非常合适的小型编译程序的教学模型。

 

Ⅱ.PL/0语言文法描述.

   由于只是做PL/0的词法分析,因此这里只列出词法有关的内容,其余略过。

   下面用扩充的EBNF来进行表示:

   元符号说明:

‘< >’:用左右尖括号括起来的中文字表示语法构造成分,或称语法单位,是PL/0的非终结符

   ‘::=’:该符号的左部由右部定义。

   ‘|’:表示“或”,即作不可由多个右部定义。

   ‘{ }’:表示花括号内的语法成分可以重复。在不加上下界时可以重复0到任意次数,有上下界时为可重复次数的限制。

   ‘[ ]’:表示方括号内的成分为任选项。

   ‘()’:表示圆括号内的成分优先。

  

   PL/0语言文法的EBNF表示

   <常量定义>::=<标识符>=<无符号整数>

   <无符号数字>::=<数字>{<数字>}

   <标识符>::=<字母>{<字母>|<数字>}

   <加法运算符>::=+|-

   <乘法运算符>::=*|/

   <关系运算符>::==|#|<|<=|>|>=

   <分界符>::=(|)|,|;|.

 

接下来我们就要来看看lex究竟是什么东西了。

 

2        flex词法生成器

Ⅰ.flex概要.

flex是一个用于生成扫描器的工具,扫描器可识别文本中的词法模式。flex从给定的文件中读取,或者从标准输入中读取(当没有给定文件时)有关要生成的扫描器的说明。这种说明的格式是一对正规表达式和C代码,称之为规则。flex的输出是名为lexyy.c的C源程序,在lexyy.c中定义了一个名为yylex()的函数。lexyy.c可以被编译,并使用-lfl链接选项同flex库链接,以生成可执行文件。执行该文件,它会分析它的输入,察看是否满足正规表达式,只要它发现一个,就会执行相应的C代码。

 

Ⅱ. Flex运行与应用过程.

     Flex和lex的功能、结构几乎完全相同。Lex编译器接收lex源程序(该源程序是对要产生的词法分析器的说明和描述),由lex编译器处理lex源程序后产生一个词法分析器作为输出。一般说来,lex源程序经过Lex编译器处理后产生一个lexyy.c的程序,这就是对应的词法分析器程序,经过C编译器编译后就可以产生一个可执行程序。通过这个可执行程序我们就可以对相应的程序语言做词法分析

 

Ⅲ.flex语言及结构.

Flex源语言结构

说明部分      /* 包含模式宏定义和C语言的说明信息*/

%%

规则部分      /*  转换规则(一般还包含规则对应的动作)*/

%%

用户代码      /*  规则动作部分所需的辅助过程的C代码 */

Flex语言是对表示语言单词集的正规式的描述,以解决正规式规则输入问题。由上图可知Flex语言作为词法分析器自动构造的专用语言,其程序结构由三部分组成。其中,第一部分说明部分包含C代码、模式宏定义等。模式宏定义实际是对识别规则中出现的正规式的辅助的影。如语言的字母可定义为:

Letter [a-zA-Z]

数字可以定义为:

digit[0-9]

   除宏定义外,定义部分的其余代码必须用符号%{ 和 %} 括起来。另外,flex使用的C语言库文件和外部变量以及部分声明的函数,也应分别置于%{ 和 %} 之内。例如下面是一个flex语言的说明部分:

%{ 

#include<stdio.h>

#include<stdlib.h>

int flag;

void function( );

#define err -1

%}

digit[0-9]

letter[a-zA-Z]

newline [/n]

%%

注意:这里其标识符作用的%%和%{ 、%}必须要顶行写,另外,在其中也可以随意添加C语言的注释。

    第二部分,识别的规则部分是flex程序的主体部分。其一般形式是

             模式1   动作1

             模式2   动作2

                   ……

             模式n   模式n

其中模式是对要分析语言的单词的描述,用正规表达式表示。动作是与匹配的模式对应的,一般用C代码(这要看相应的支持平台)表示对模式处理的动作。当识别出某个模式的单词后,词法分析器(flex)要做的动作就是执行相应的程序。详细的模式这里不再给出,flex手册会有比较详细的定义。

    第三部分,即用户代码定义部分,它是对模式进行处理的C函数、主函数等。作为辅助过程它是支持规则动作部分所需要的处理过程,是对规则部分中动作的补充。这些过程如果不是C的库函数,必须给出具体的定义,然后分别编译且与生成的词法分析器装配在一起。

    需要说明的一点是,定义部分和用户代码部分是任选的,规则部分则是必须的。

 

 Ⅳ.lexyy.c的全局变量和函数.

     需要说明的是在flex生成的lexyy.c中,里面是有一些是本身就定义好的一些变量和函数,这些变量和函数对我们完成词法分析的操作有很大的帮助,这里主要介绍这次实验要用到的和常用的一些函数和变量。

     File*yyin   /* 指向词法分析器要接收的待分析程序的指针。如果不指定则默认指向标准输入终端(键盘)。如果我们待分析的程序是文件形式我们可以将这个指针指向该文件的地址指针。 */

File*yyout  /* 同上,唯一不同是该指针指向输出的文件。默认指向标准输出终端(屏幕)。我们可通过重定向该指针改变输出流方向。 */

char*yytext  /* 指向识别的单词的地址;用来保存扫描一次匹配的字符串。*/

int yyleng    /* 匹配的字符串中字符的个数。*/

 

函数

ECHO  /* flex的默认动作,一般来说是输出字符串 */

yywrap() /* 扫描一次完后要调用的函数,返回一个值,当这个值为1的时候分flex就不再继续扫描。*/

yyrestart() /* 重新定向flex的输入 */

当然还有其它很多的函数,比如yymore()、相容分组、条件模式、宏等,这里由于本次实验没有用到,因此不再详细给出。具体可以查看flex手册。

 

Ⅴ.flex词法分析产生器实现概述。

   词法分析器自动生成器的核心是lex编译器,lex编译器的功能是对某语言单词集描述的lex源程序,将其变换为一个能识别该语言单词的词法分析器。而该词法分析器像有限自动机一样取识别处理单词。

   基于lex源程序,lex编译器的实现步骤大致是:

   ⑴对lex源程序识别规则中的每个pi构造一个相应的NFA  Ni。

     ⑵引入唯一初态S,从初态S通过ε弧将所有NFA  Ni(i=1,…,n)连接成新的NFA N’。⑴、⑵两步实际是完成从正规表达式到非确定有限自动机的构造。

   ⑶对NFA  N’确定化,产生DFA  N。

   ⑷DFA  N 最小化。

   ⑸给出控制程序。控制程序的作用是激活有限自动机,即控制输入字符串在有限自动机上运行,一旦达到终态,即识别出lex源程序模式描述的某个单词,转去调用相应的动作部分就可以了。

 

到这里我想应该对flex都有了一定了解了吧,现在我们就开始着手编写flex分析pl/0的输入文件lex.l文件,实际上这个文件的作用就是如何识别pl/0的词法,也就是识别pl/0词法规则的说明文件。从上面讲的我们知道这样的一个文件分为3部分,下面我来详细说明每一部分:


 ㈠说明部分.

      由于词法分析最后的结果是一个二元组,并且本次实验只是给出一个形式化的显示,但是为了更加的形象,因此我用了一个struct结构来描述这个二元组,并且当分析完后将token存放到这个二元组中。另外还有一个函数print()的声明,该函数的主要作用是输出识别到的token。另外还定义一些辅助操作的变量。例如用于读写文件的指针,保存行号、token数目、错误操作符数目的变量。

      接下来是PL/0词法的描述,用正规表达式书写:

      digit         [0-9]     /*数字从0-9*/

letter        [a-zA-Z]  /*字母接受a-z的大小写,同时本程序定义PL/0语言大小写敏感;*/

number        {digit}+  /*无符号整数*/

identifier    {letter}({letter}|{digit})*  /*标识符*/

wrongid       ({digit}+){letter}({letter}|{digit})*   /*错误的id,形如123a等*/

newline       [/n]  /*新行*/

whitespace    [/t]+ /*制表符*/

    

    ㈡规则部分.

      由于说明部分我们已经定义好无符号整数和标识符的正规表达时,并且用了一个别名,而保留字和运算符、分界符比较少,因此规则部分我们就直接根据每个模式写出要执行的对应的动作。在这里我定义的动作就是先将每种单词分种类,然后同一种给一个整数最为代号,然后在print()函数中根据这个代号输出相应的属性。因此动作部分的主要处理工作就是赋值,调用print()函数。

例如: {identifier}       {value=1;print();}

      详细的PL/0词法的保留字、分界符、运算符见后面的附录。

  

 ㈢用户代码.

   用户代码部分主要包括三个函数:

   主函数main()  //给出源文件输入输出的方向,调用扫描器等;

   输出处理函数print()//主要功能就是输出二元组;

   yywrap()   //自带函数,用来结束扫描;

 

此外,要注意:

要注意空格和制表符,因为在源程序中为了排版等不可避免的存在空格和制表符,但是在实际的词法分析中它们是没有具体意义的,因此读到空格或指标符的时候要“吃掉”他们。

注意newline。newline就是换行符,但我们读到换行符的时候,应当对其执行空格和制表符的操作(“吃掉”),但是我们要统计行数,应此我们设立一个变量每当读到一个换行符的时候就递增1。

另外,lex在读到匹配模式的单词后就执行模式对应的动作,但是它会默认地将不匹配的单词输出,因此我们要对分析语言没有的符号进行另外的处理(例如打印出错等)。

 

 

下面是我写的一个pl/0用flex分析生成词法分析器的文件:

%{
#include<stdio.h>
#include<stdlib.h>
void print();                            //输出token序列;
void main(int argc,char*argv[]);         //主函数;
struct token{                            //二元组;
      char*idproperty;    //token属性值;
      char*idname;    //识别的token名字;
}entity[1000];     //定义1000个这样的token,大小可改变;
char*filename;                           //保存结果的文件名;
int errnum=0;     //错误token的数目;
int value;     //属性值int型;
int linenum=1;     //行数;
int count=0;     //token的个数;
int flag=0;
FILE*fpin;     //测试文件指针;
FILE*fpout;     //结果文件指针;
%}
digit         [0-9]
letter        [a-zA-Z]
number        {digit}+
identifier    {letter}({letter}|{digit})*
wrongid       ({digit}+){letter}({letter}|{digit})*
newline       [/n]
whitespace    [/t]+
%%
"procedure" |
"call"  |        
"begin"  | 
"end"  | 
"var"  | 
"const"  | 
"if"  | 
"then"  | 
"while"  | 
"do"  | 
"read"  | 
"write"  | 
"odd"    {value=0;print();}
{identifier}   {value=1;print();}
{wrongid}   {value=6;print();}
{number}   {value=2;print();}
"+"|"-"|"*"|"/"          {value=3;print();}
"<>"  | 
">="  | 
"<="  | 
":="  | 
"="|"#"|"<"|">"          {value=4;print();}
"("|")"|","|";" |
"."                             {value=5;print();}
{newline}   {linenum+=1;}
{whitespace}   {;}
" "    {;}
.    {value=7;print();}
%%
int yywrap()
{  
    fclose(fpin);
    return 1;
}

void print()
{
    count+=1;
    if(flag!=1){
       if((fpout=fopen(filename,"a"))==NULL){
           printf("cannot write the file /n");
           exit(0);
       }
    }
    if(value<=5){
       switch(value){
             case 0:entity[count-1].idproperty="BasicKey";break;
             case 1:entity[count-1].idproperty="identifier";break;
             case 2:entity[count-1].idproperty="number";break;
             case 3:entity[count-1].idproperty="arithmetic-op";break;
             case 4:entity[count-1].idproperty="relation-op";break;
             case 5:entity[count-1].idproperty="boundary-op";break;
       }
       entity[count-1].idname=yytext;
       fprintf(fpout,"%d < %s , %s > /n",count,entity[count-1].idname,entity[count-1].idproperty);
    }else{
         errnum+=1;
         switch(value){
               case 6:entity[count-1].idproperty="Mixed number and letter:";break;
               case 7:entity[count-1].idproperty="Unkown operator:";break;
         }
         entity[count-1].idname=yytext;
         fprintf(fpout,"%d [line:%d]:%s/"%s/" /n",count,linenum,entity[count-1].idproperty,entity[count-1].idname);
    }
    if(flag!=1)fclose(fpout);
}

void main(int argc,char*argv[])
{
    if(argc==1){
      printf("please input the PL//0 program(ctrl+z to end) /n");
      flag=1;
      fpin=stdin;
      fpout=stdout;
    }
    if(argc==2)argv[2]="defresult.txt";
    filename=argv[2];
    if(flag!=1){
       if((fpin=fopen(argv[1],"r"))==NULL){
           printf("cannot open the file /n");
           exit(0);
       }
    }
    yyin=fpin;
    yylex();
    if(flag!=1){
       if((fpout=fopen(filename,"a"))==NULL){
           printf("cannot write the file /n");
           exit(0);
       }
    }
    fprintf(fpout,"/n");
    fprintf(fpout,"%d symbol(s) found. /n %d error(s) found. /n",count,errnum);
    fprintf(fpout,"======================================================================= /n");
    if(flag!=1)fclose(fpout);
    yywrap();


}

 


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/litchh/archive/2004/07/14/40983.aspx

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

学习使用flex 的相关文章

  • PHP:尝试让 fgets() 在 CRLF、CR 和 LF 上触发

    我正在使用 proc open 和 fgets stdout 读取 PHP 中的流 尝试获取传入的每一行 许多 Linux 程序 包管理器 wget rsync 仅使用 CR 回车 字符来表示定期 就地 更新的行 例如下载进度 我希望在这些
  • 如何使用 DOCX4J 在 docx 文件生成中应用新行

    根据我看过的教程 我学习了如何在生成 docx 文件时添加文本 但每次我添加一行文本 我注意到第一行文本和第二行文本之间总是有一个空格 就像按两次回车键一样 我知道主要原因是每次添加一行文本时 我都会使用一个段落 一个段落在另一个段落之后以
  • preg_match_all 和引号内的换行符

    另一个菜鸟正则表达式问题 问题 我可能做了一些愚蠢的事情 所以我想我应该利用 SO 常客的聪明才智 尝试匹配换行符 但前提是它们出现在双引号或单引号内 我还想捕获引号之间但不包含换行符的字符串 好的 这就是我得到的 有输出 下面是我想要得到
  • 为什么应该使用 strtok(line, "\n") **不** 来去除 fgets() 留下的换行符

    fgets 是读取一行输入的安全函数 但它存储new line byte n 如果适合 则从数组中的文件中读取 在许多 如果不是大多数 情况下 这new line在进一步处理该行内容之前必须将其删除 可以使用几种简单的方法来实现这一点 但我
  • 仅替换多个新行

    我正在尝试做一些不寻常的事情 我想用两条新行替换多条新行 类似的问题还有很多 但不完全是 请参阅 Hello n n nWorld n n n n 应该成为 Hello n nWorld n n 然而这 Hello nWorld n 应该保
  • Java FileWriter如何写入下一行

    我使用下面的代码将记录写入文件 记录可以写入文件中 但附加在一行中 每次我调用此方法示例 你好世界你好世界你好世界你好世界 如何修改代码 使输出如下所示 以便在读取文本时我可以使用 line hasNextLine 进行检查 你好世界你好世
  • 我的代码在输出前面打印一个新行[关闭]

    Closed 这个问题需要调试细节 help minimal reproducible example 目前不接受答案 我正在编写代码 但遇到了问题 我的代码在输出前面打印了一个新行 我想避免这种情况 这是我的代码 if movieName
  • 如何使用 Vim 根据模式将文本拆分为多行?

    假设你有这样的文本 name1 John age1 41 name2 Jane age2 32 name3 Mike age3 36 并且您希望将每一行分成两行以给出如下结果 name1 John age1 41 name2 Jane ag
  • pyparsing 和换行符

    我刚开始pyparsing我有换行问题 我的语法是 from pyparsing import newline LineEnd Literal n leaveWhitespace minus Literal plus Literal lpa
  • 为什么 Ruby 的“gets”包含结束换行符?

    我从不需要我得到的结尾换行符gets 有一半的时间我忘记了chomp它是一种痛苦 为什么它在那里 Like puts 听起来很相似 它被设计为与线条一起工作 使用 n特点 gets接受一个可选参数 用于 分割 输入 或 只是读取直到它到达
  • .NET 的 Environment.NewLine 的 R 等效项

    是否有 R 等效项环境 NewLine https msdn microsoft com en us library system environment newline v vs 110 aspx在 NET 中 我正在寻找一个角色对象 它
  • 为什么 Vim 会在文件末尾添加新行?

    我经常使用 Wordpress 有时我会临时更改 Wordpress 核心文件 以便了解正在发生的情况 尤其是在调试时 今天我有一个小小的惊喜 当我准备将更改提交到 git 存储库时 我注意到git status正在将 WordPress
  • Android:避免在 TextView 字符串部分中断行[重复]

    这个问题在这里已经有答案了 我想避免在字符串的特定部分断行 假设我们有这个字符串 Speed m s 理想的情况是根本不跳转并将完整的字符串放在一行中 或者如果需要跳转 则以这种方式 Speed m s 我想避免的是这样的事情 Speed
  • 在 Replace() 表达式中添加换行符

    我正在尝试使用回归模型中的相关数据来注释 ggplot 中的图 我已遵循建议在这个帖子中 https stackoverflow com questions 7549694 ggplot2 adding regression line eq
  • Powershell Clear-Host 保留缓冲区的替代方案

    我想要像 Clear Host 这样的东西 但想要回滚 到目前为止 我所做的基本上就是添加换行符 直到屏幕清晰为止 尽管当我这样做时 光标开始在页面底部书写 正如预期的那样 尽管不是期望的 我希望从页面顶部开始书写 对于菜单等 这是很自然的
  • 在 HTML 中呈现字符串并保留空格和换行符

    我有一个带有详细信息页面的 MVC3 应用程序 作为其中的一部分 我有一个包含空格和换行符的描述 从数据库检索 当它被渲染时 新行和空格将被 html 忽略 我想对这些空格和新行进行编码 以便它们不会被忽略 你是怎样做的 我尝试了 HTML
  • 在 Perl 中正确检测文件的行结尾?

    问题 我有在 Windows 和 nix 上生成的数据 大部分为 CSV 格式 并且大部分在 nix 上处理 Windows 使用 CRLF 作为行结束符 Unix 使用 LF 对于任何特定文件 我不知道它是否有 windows 或 nix
  • 在 Vim 中将 DOS/Windows 行结尾转换为 Linux 行结尾

    如果我打开在 Windows 中创建的文件 所有行都以 M 如何一次性删除这些字符 dos2unix https sourceforge net projects dos2unix是一个可以执行此操作的命令行实用程序 In Vim s M
  • 拆分为不同的换行符

    现在我正在做一个split在字符串上并假设用户的换行符是 r n像这样 string split r n 我想做的事分为两部分 r n要不就 n 那么正则表达式将如何分割其中的任何一个呢 你试过了吗 r n The 使得 r选修的 用法示例
  • 为什么我的 Apache2::Log 输出用 \n 替换换行符?

    我在 apache2 mod perl 下设置了多个虚拟主机 我用的是ErrorLog指令为每个虚拟主机获取单独的错误日志 仅当我使用 Apache2 Log 时 这才按预期工作 警告 只会记录到常规错误日志中 这样就可以了 最后 但还存在

随机推荐

  • 7-52 两个有序链表序列的交集 (20 分)(思路加详解尾插法)come Boby!

    一 题目 已知两个非降序链表序列S1与S2 设计函数构造出S1与S2的交集新链表S3 输入格式 输入分两行 分别在每行给出由若干个正整数构成的非降序序列 用 1表示序列的结尾 1不属于这个序列 数字用空格间隔 输出格式 在一行中输出两个输入
  • 浅谈5G 与4G的区别

    5G 顺势而生 应用广泛 包含诸多的进步 但未来依然可期 期望6G 7G 8G等等 前提 了解5G 技术 有必要了解一下 1G 2G 2 5G 3G 4G技术 1G 到4G之间的技术我们称之为蜂窝移动网路系统 正所谓长江后浪推前浪 一代更比
  • sql-labs 29 waf 绕过参数污染

    HTTP参数污染 HTTP Parameter Pollution 攻击者通过在HTTP请求中插入特定的参数来发起攻击 如果Web应用中存在这样的漏洞 可以被攻击者利用来进行客户端或者服务器端的攻击 waf服务器 tomcat 只解析重复参
  • 前端自适应布局

    在前端开发中 我们不可避免要面临适配问题 本文将介绍几种适配方式 一 px和em 1 1 px 1 2 em 二 rem 2 1 rem原理 2 2 rem如何计算的 2 3 rem使用 三 使用插件px2rem转换 3 1 原理和优点 3
  • MySQL笔记(五)使用python调用数据库进行操作

    python 访问数据库流程 在pycharm中下载pymysql 打开数据库视图 相当去navicat 设置数据库 使用python对数据库进行操作 Python2中使用的是MySQLdb模块 from pymysql import de
  • 图结构与图算法综述

    图结构与图算法综述 图结构以及图算法 无向图 有向图和网络能运用很多常用的图算法 这些算法包括 各种遍历算法 这些遍历类似于树的遍历 寻找最短路径的算法 寻找网络中最低代价路径的算法 回答一些简单相关问题 例如 图是否是连通的 图中两个顶点
  • Oracle数据库基础知识

    1 Oracle 数据库服务器体系所包含的三种主要结构是 内存结构 进程结构 存储结构 2 安装 11gR2 数据库要经过哪几个主要阶段 Grid基础架构安装 数据库软件安装 DBCA创建数据库 3 数据库实例所必须的后台进程包括 DBWn
  • QT——实战动态链接库调用

    如何在Debug模式下调用外部的动态链接库 首先在工程文件夹下 通过右键可以选择添加后 进入下图界面 选中外部库 点击下一步 选择所要调用的外部库文件debug生成的buliding文件里的libxxxxx a文件 如下图所示 点击下一步
  • 移动端中的坑和 vue中事件修饰符详解(stop, prevent, self, once, capture, passive)

    stop 是阻止冒泡行为 不让当前元素的事件继续往外触发 如阻止点击div内部事件 触发div事件 prevent 是阻止事件本身行为 如阻止超链接的点击跳转 form表单的点击提交 self 是只有是自己触发的自己才会执行 如果接受到内部
  • Eclipse 运行web项目 HTTP404错误

    Eclipse 引入web项目后 run as on server tomcat启动成功 但网页提示404 问题排查 404 服务器找不到资源 首先检查Eclipse部署路径 是否部署了资源文件 查找部署路径 发现该路经下只有一个WEB I
  • QT 计算两个日期时间差?(时间转时间戳)

    时间戳时间转换工具 时间换算工具 1 得出的结果单位是 天 不足一天为0 没有半天的说法 QDateTime time1 QDateTime fromString 2022 4 25 16 40 02 yyyy MM dd HH mm ss
  • CMake中option和cmake_dependent_option的使用

    CMake中的option命令为用户提供可以选择的布尔选项 boolean option 其格式如下 option
  • centos7.4中安装Apache服务

    安装Apache服务 大家好 今天我们在cenots7 4中安装一个web服务Apache 接下来我们先来简单了解一下Apache服务吧 Apache Http server是开源软件项目的杰出代表 基于标准的http网络协议提供网页浏览服
  • 黄鱼车

    本文转载至 http www zynews com news 2010 12 19 content 788498 htm 文 佘建民 有交关外地朋友问我迭个老上海 为啥上海人拿三轮脚踏货车叫作 黄鱼车 对这个疑问 现借 上海闲话 一角 讲讲
  • 【C++】内存管理初阶

    1 C C 内存管理 1 C C 内存分布 int globalVar 1 static int staticGlobalVar 1 void Test static int staticVar 1 int localVar 1 int n
  • 游戏数据库设计经验

    一 游戏模板数据库设计特点 软件行业一般数据库设计原则 保持数据的完整性一致性 避免数据冗余 范式设计 但游戏领域的游戏模板表设计上还需要考虑这些特点 1 1 对游戏程序只读 游戏程序只需要考虑读取性能 不需要过多考虑修改性能 1 2 数据
  • 【代码审计】模板注入

    0x00 介绍 这里主要学习下 FreeMarker 模板注入 FreeMarker 是一款模板引擎 FreeMarker 模板文件与 HTML 一样都是静态页面 当用户访问页面时 FreeMarker 引擎会进行解析并动态替换模板中的内容
  • 学一点Ceph知识:初识Ceph

    Ceph是什么 Ceph是一个开源的分布式存储系统 可大规模扩展 高性能 无单点故障 在普通的服务器上可以支持到PB级容量 商用机器上支持的容量可以达到EB级别 Ceph的竞争力 市面上提供云存储的分布式系统如阿里云的OSS 底层存储框架为
  • 深度学习语义分割(二)SegNet论文解读

    SegNet是是第一次在语义分割中应用编码器 解码器 encoder decoder 的结构 其中 编码器使用池化层逐渐缩减输入数据的空间维度 而解码器通过反卷积层等网络层逐步恢复目标的细节和相应的空间维度 从编码器到解码器之间 通常存在直
  • 学习使用flex

    会对flex做词法分析了解很多 下面我通过一个例子来详细说明如何使用flex 根据所学的词法分析内容 利用flex构造PL 0语言的词法分析器 既然是构造PL 0的词法分析器 那么我们有必要看一下pl0语言的简介和相应文法 2 PL 0语言