LEX, YACC

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

http://www.ibm.com/developerworks/cn/linux/l-lexyac.html

http://www.ibm.com/developerworks/cn/linux/sdk/lex/index.html

http://wenku.baidu.com/view/188c4493daef5ef7ba0d3c7a.html

http://wenku.baidu.com/view/a4434174f46527d3240ce0b4.html


从下列地方可以等到lex 和yacc 工具:

● Mortice Kern System (MKS),在 www.mks.com,

● GNU flex 和 bison,在 www.gnu.org ,

● Ming,在 www.mingw.org,

● Cygwin,在 www.cygwin.org

“lex”和“yacc”这两个名字所代表的也包括这些工具的 GNU 版本 flex 和 bison


终端和非终端符号, 在BNF中使用

  • 终端符号 : 代表一类在语法结构上等效的标记。 终端符号有三种类型:
    • 命名标记: 这些由 %token 标识符来定义。 按照惯例,它们都是大写。lexer 返回命名标记。
    • 字符标记 : 字符常量的写法与 C 相同。例如, -- 就是一个字符标记。
    • 字符串标记 : 写法与 C 的字符串常量相同。例如,"<<" 就是一个字符串标记。
  • 非终端符号 : 是一组非终端符号和终端符号组成的符号。 按照惯例,它们都是小写。

C语言的例子:

http://www.quut.com/c/ANSI-C-grammar-y-1998.html#external-declaration

http://www.quut.com/c/ANSI-C-grammar-l-1998.html


一、词法分析器生成工具 Lex

Lex 为词法分析器或扫描器生成C程序代码。

  • 使用DFA引擎,匹配正则表达式匹配输入的字符串并且把它们转换成对应的标记,此标记称为终结符(terminals)或者 记号(tokens),可以给yacc使用。
  • 如果两个范式匹配相同的字符串,就会使用匹配长度最长的范式。如果两者匹配的长度相同,就会选用第一个列出的范式。
  • 一个 Lex 程序分为三个段:第一段是 C 和 Lex 的全局声明,第二段包括模式(C 代码),第三段是补充的 C 函数。
  • 第一段中:出现在%{%}之间的部分之间复制到文件lex.yy.c中,它们不当做正则表达式处理。
  • 尽管 lex 和 yacc 几乎总是被同时提到,但是它们可以单独使用。有很多非常有趣、完全用 lex 编写的小程序。使用 yacc 而 不使用 lex 的程序比较罕见。下面是可以单独执行的一个lex例子,此例子中:
             如果是lex程序,则可能有如下说明:

第一段只有C的全局声明;没有token匹配定义;没有include yacc生成的头文件,此文件可能包含命名标记token的定义;

第二段没有return token 终结符给yacc使用;

第三段必须手动添加yywrap定义;如果和yacc联合使用,则main函数转移到yacc中。main在lex中调用yylex,而在yacc中则调用yyparse,其间接调用yylex。

注意:lex程序的默认输入为stdin。

%{
int nchar, nword, nline;
%}
%%
\n { nline++; nchar++; }
[^ \t\n]+ { nword++, nchar += yyleng; }
. { nchar++; }
%%
int main(void) {
yylex();
printf("%d\t%d\t%d\n", nchar, nword, nline);
return 0;
}
int yywrap()
{
return 1;
}


Lex 变量

  • yyin FILE* 类型。 它指向 lexer 正在解析的当前文件。默认为标准输入。
  • yyout FILE* 类型。 它指向记录 lexer 输出的位置。 缺省情况下,yyin 和 yyout 都指向标准输入和输出。
  • yytext 匹配模式的文本存储在这一变量中(char*)。
  • yyleng 给出匹配模式的长度。
  • yylineno 提供当前的行数信息。 (lexer不一定支持。)
Lex 函数
  • yylex()        这一函数开始分析。 它由 Lex 自动生成。
  • yywrap() 这一函数在文件(或输入)的末尾调用。 如果函数的返回值是1,就停止解析。 因此它可以用来解析多个文件。 代码可以写在第三段,这就能够解析多个文件。 方法是使用 yyin 文件指针(见上表)指向不同的文件,直到所有的文件都被解析。 最后,yywrap() 可以返回 1 来表示解析的结束。
  • yyless(int n) 这一函数可以用来送回除了前n 个字符外的所有读出标记。
  • yymore() 这一函数告诉 Lexer 将下一个标记附加到当前标记后。


个人使用心得:

lex文件:

    • 其有正则表达式,比yacc文件的规则好使用,个人感觉。。。
    • 不能有空格,必须顶行写;
    • 使用变量必须用大括号括起来;
    • 不能有注释;
    • ABNF中描述需要进行转换,如:

filtercomp     = and / or  --> filtercomp     {and} | {or}

filterlist     = 1*filter  --> filterlist     {filter}+

EXCLAMATION    = %x21 ; exclamation mark ("!")  --> EXCLAMATION    \x21

UTF2    = %xC2-DF UTF0  --> UTF2    [\xC2-\xDF]{UTF0} 


二、yacc(Yet Another Compiler Compiler),是一个经典的生成语法分析器的工具

  • Yacc 的 GNU 版叫做 Bison。
  • Yacc 文件有 .y 后缀。
  • yacc 的文法由一个使用BNF文法(BackusNaur form)的变量描述。 BNF 文法规则最初由 JohnBackus和 Peter Naur 发明,并且用于描述Algol60语言。 BNF 能够用于表达上下文无关语言。
  • yacc的输入是巴科斯范式(BNF)表达的语法规则以及语法规约的处理代码,Yacc输出的是基于表驱动的编译器,包含输入的语法规约的处理代码部分。
  • yacc是开发编译器的一个有用的工具,采用LALR(1)语法分析方法。
  • Yacc为语法分析器或剖析器生成C程序代码。 Yacc使用特定的语法规则以便解释从Lex 得到的标记并且生成一棵语法树。
  • 是Unix/Linux上一个用来生成编译器的编译器(编译器代码生成器)。yacc生成的编译器主要是用C语言写成的语法解析器(Parser),需要与词法解析器Lex一起使用,再把两部份产生出来的C程序一并编译。yacc本来只在Unix系统上才有,但现时已普遍移植往Windows及其他平台。
  • Yacc 程序也用双百分号分为三段。 它们是:声明、语法规则和 C 代码。 
  • 每个 Yacc 声明段声明了终端符号和非终端符号(标记)的名称,还可能描述操作符优先级和针对不同符号的数据类型。 
  • yacc 文件的第一部分定义了解析器将要处理和生成的对象。在一些情况下,它可以是空的, 但是更常见的是,它应该至少包含一些%token 指令。这些 指令用来定义 lexer 可以返回的记号。当使用 -d 选项来运行 yacc 时,它会生成一个定义常量的头文件。
  • %token --- terminate字符
  • %type  --- 非terminate字符
  • %union  --- 定义yystype
  • %left
  • %right
  • %noassoc
三、下面是一个yacc和lex结合的例子:
lex file
要求所有定义必须顶格对齐;
如果没有声明yylval,则采用默认值;

%{
        #include "y.tab.h"
        #include <stdio.h>
        #include <string.h>
        extern char* yylval;
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval = strdup(yytext);
 return NAME; }
{eq} { return EQ; }
{age} { yylval = strdup(yytext);
return AGE;}
%%
int yywrap(){
  return 1;
}

yacc file

要求%%,%{,%}必须顶格对齐

当yacc发现一个解析错误,默认动作是调用yyerror

定义三个token,在lex中被return。

%{
       typedef char* string;
        #define YYSTYPE string
%}
        %token NAME EQ AGE
%%
        file : record file
        | record
        ;
        record : NAME EQ AGE {
        printf("%s is %s years old!!!\n", $1, $3); }
%%
        int main()
        {
        yyparse();
        return 0;
        }
        int yyerror(char *msg)
        {
        printf("Error encountered: %s \n", msg);}

执行cat y.tab.h
#ifndef YYERRCODE
#define YYERRCODE 256
#endif

#define NAME 257
#define EQ 258
#define AGE 259

执行步骤:

yacc -d file.y

lex file.l

cc lex.yy.c y.tab.c -o file.exe

执行结果:

a=5
a is 5 years old!!!

afds = 32
  afds is 32 years old!!!

a=32
a is 32 years old!!!

tt=

fd
Error encountered: syntax error

四、修改后的例子

yacc文件

%union会生成为yylval的定义

#define NUMBER 257
#define NAME 258
#define EQ 259
#define AGE 260
typedef union {
        long    value;
        char *p;
} YYSTYPE;
extern YYSTYPE yylval;


%union {
        long    value;
        char *p;
}
%token <value>  NUMBER
%token <p> NAME EQ AGE
%%
        file : record file
        | record
        record : NAME EQ NUMBER {
        printf("%s is %d years old!!!\n", $1, $3); }
%%
        int main()
        {
        yyparse();
        return 0;
        }
        int yyerror(char *msg)
        {
        printf("Error encountered: %s \n", msg);}


lex文件

删除了yylval声明



%{
        #include "y.tab.h"
        #include <stdio.h>
        #include <string.h>
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval.p = strdup(yytext);
 return NAME; }
{eq} { return EQ; yylval.p = strdup(yytext);}
{age}   {
                yylval.value = strtol(yytext, 0, 10);
                return NUMBER;
        }
%%
int yywrap(){
  return 1;
}
%{
        #include "y.tab.h"
        #include <stdio.h>
        #include <string.h>
%}
char [A-Za-z]
num [0-9]
eq [=]
name {char}+
age {num}+
%%
{name} { yylval.p = strdup(yytext);
 return NAME; }
{eq} { return EQ; yylval.p = strdup(yytext);}
{age}   {
                yylval.value = strtol(yytext, 0, 10);
                return NUMBER;
        }
%%
int yywrap(){
  return 1;}



在lex和yacc文件中声明、定义函数;

在lex文件中一般需要执行yylval = strdup(yytext); 这个yylval需要在yacc中delete。

在yacc文件中一般需要执行字符串串联,如$1和$2需要串起来,采用strdup存储到$$中,否则无法向上反馈。

调试方法,lex文件编译时lex -d file.l;而yacc文件的main中定义yy_flex_debug = 1;这样cc编译才能通过!

lex文件过滤掉空格等,否则有时有莫名其妙的空格打印。[ \t\v\n\f] {}

为了检测出不应该出现的字符,lex文件最后加:.   {return ERROR;}匹配检查,但同时要过滤掉“\0" {}匹配动作,否则总是失败。













































        
LexYacc从入门到精通(4)-能够使用C++的LexYacc框架 能够使用C++的LexYacc框架 本文版权归熊春雷所有 ,我的邮箱:pandaxcl@163.com>,欢迎大家我讨论计算机方面 的问题,在我的博客上 面还写了很多其他的文档,有空来看看哦。如果转载,请保留此版权信息,并注 明出处。谢谢:) 摘要 写这一章的目的就是为了能够提供一个能够使用C++特色的LexYacc框架,这个 阅读详情

相关推荐

LexYacc应用方法(二).再识LexYacc

LexYacc应用方法(二).再识LexYacc草木瓜  20070314早在二十世记七十年代之前,编写编译器一直是一个非常费时的工作。但到了1975这一年这一切却发生了重大转变,首先Stephen C. Johnson Lesk在贝尔实验室完成了Yacc开发,为了配合yacc更好的协作, Mike LeskEric Schmidt又完成了lex。从而Lexyacc成为计算机编译领

草木瓜 1万+

yacc文法规则解决运算符优先级

把上一个博文的程序扩展成支持加减乘除的

nosources的专栏 5115

LexYacc使用教程(九).Windows下使用LexYacc

LexYacc应用方法(九).Windows下使用LexYacc草木瓜  20070904一、序    不想LexYacc系列的最后一篇文章竟如此“难产”,已时隔三个月之久。不由慨叹自由可支配时间是如此之少,如此岂不谓新时代的“奴隶”~    罢罢罢,闲话少叙,回归正题,本文主要介绍在Windows下如何去使用LexYacc,以作为本系列文章的终结。    二、方法介绍  

草木瓜 2万+

Yacc介绍与使用

概念 •什么是YACCyacc(Yet Another Compiler Compiler),是Unix/Linux上一个用来生成编译器的编译器(编译器代码生成器). 使用巴克斯范式(BNF)定义语法,能处理上下文无关文法(context-free)。出现在每个产生式左边(left-hand side:lhs)的符号是非终端符号,出现在产生式右边(right-hand side:

yuucyf的专栏 5万+

yacc使用说明

yacc是一个语法分析程序的自动生成器。 yacc文件构成说明部分<br />%%<br />规则部分<br />%%<br />程序部分<br />%%"%{"与"%}"是说明部分的起始符与结束符。 终端非终端符号终端符号:代表一类在语法结构上等效的标记。<br />终端符号有三种类型: <br /> 命名标记:这些由 %token 标识符来定义。按照惯例,它们都是大写。 <br /> 字符标记:字符常量的写法与 C 相同。例如, -- 就是一个字符标记。 <br /> 字符串标记:写法与 C 的字符

bluebubble的专栏 1667

MySQL 源码|60 - 保留字函数名的存储解析逻辑|V20240826

在文件中,定义了宏,接受一个字符串参数X,返回用逗号分隔的字符串自身(X) 字符串的长度,用于构造参数。在sql/lex.h文件中,定义了宏。因为仅在文件中被定义,所以在其他绝大部分场景下,宏接受一个整型参数A,并返回参数A本身。用于在文件中不再需要引用sql_yacc.h。#else#endif利用以上两个宏,在sql/lex.h文件中,还定义了SYMSYM_FNSYM_HKSYM_H这 4 个宏用于定义不同类型的SYMBOL,其中的SG_HINTS即枚举类型SYM_GROUP中的成员。

长行 667

LEXYACC简介

Lex工具 -------     Lex工具是一种词法分析程序生成器,它可以根据词法规则说明书的要求来生成单词识别程序,由该程序识别出输入文本中的各个单词。 1、lex程序的结构 -定义部分 -规则部分 -用户子程序部分 其中规则部分是必须的,定义用户子程序部分是任选的。 (1) 定义部分      定义部分起始于"%{"符号,终止于"%}"符号,其间可以是包括include语句、声明语句在内的C语句。 %{ #include "stdio.h" #include "y.tab.h" extern in

xiaoxiaofengqi的专栏 5453

yacc lex c 注释_LexYACC详解

原文:https://www.cnblogs.com/hdk1993/p/4922866.html注:1)修正了原文中有问题的代码;2)补充了YY_INPUT等内容。一、简介只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一个Lex,Bison则是GNU版本的Y...

weixin_39632397的博客 1464

YaccLex 快速入门

简介: Lex Yacc 是 UNIX 两个非常重要的、功能强大的工具。事实上, 如果你熟练掌握 Lex Yacc 的话,它们的强大功能使创建 FORTRAN C 的编译器如同儿戏。本文详细的讨论了编写自己的语言编译器所 用到的这两种工具,包括常规表达式、声明、匹配模式、变量、Yacc 语 法解析器代码。最后,本文解释了怎样把 Lex Yacc 结合起来。

红孩儿编程大师 4490

LexYacc的结合

LexYacc的结合用LexYacc结合起来使用可以很方便的生成一个新语言的编译程序,不过现在很多国内的图书里面对它们的介绍是分开的,单独的介绍也是比较含糊,不是很清晰。把他们如何结合的介绍更是少的可怜。我用他们做了一个能识别整型数值的加、减、乘、除的编译程序。把我的心得写在下面,供大家参考。首先,我就不介绍Lex的语法规则了,因为在一些书上这些是重点介绍的内容,我先把Lex的源程序写在下

vrix的专栏 2618

lexyacc程序学习(4)——lexyacc的使用

一个程序通常在每次返回一个标记时都要调用yylex()函数。只有在文件结束或者出现错误标记时才会终止。 一个由yacc生成的分析器调用yylex()函数来获得标记。yylex()可以由Lex来生成或完全由自己来编写。对于由Lex生成的lexer来说,要yacc结合使用,每当Lex中匹配一个模式时都必须返回一个标记。因此Lex中匹配模式时的动作一般格式为: {pattern} { /* do smthg*/ return TOKEN_NAME; } 于是 Yacc 就会获得返回的标记。当 Yacc

wang_yr的博客 1145

能够使用C++的LexYacc框架

能够使用C++的LexYacc框架<br />写这一章的目的就是为了能够提供一个能够使用C++特色的LexYacc框架,这个框架同前一章的目的一样,也是仅仅为了能够提供一个什么也不作的框架程序,当时有点不同的就是:这个新的框架使用了C++语法,能够使用所有的C++特色,包括STL的强劲算法容器,还有各式各样的C++库。采用C++的目的就是为了能够快速的编码来完成自己需要完成的任务。<br />在编码词法分析语法分析程序的时候经常会编写一些链表容器,实际上这些链表容器在C++语言函数库里面都已经有

Skai_CSDN的专栏 2244

LexYacc应用方法(一).初识Lex

 LexYacc应用方法(一).初识Lex草木瓜  20070301Lex(Lexical Analyzar 词法分析生成器),Yacc(Yet Another Compiler Compiler编译器代码生成器)是Unix下十分重要的词法分析,语法分析的工具。经常用于语言分析,公式编译等广泛领域。遗憾的是网上中文资料介绍不是过于简单,就是跳跃太大,入门参考意义并不大。本文通过循序渐进的

草木瓜 5万+

LexYacc入门

原文地址:http://coanor.blog.hexun.com/38241166_d.html   1. 简介 只要你在Unix环境中写过程序,你必定会邂逅神秘的Lex&YACC,就如GNU/Linux用户所熟知的Flex&Bison,这里的Flex就是由Vern Paxon实现的一个Lex,Bison则是GNU版本的YACC.在此我们将统一称呼这些程序为LexYACC.新版本的程序是

雜貨鋪 2107

【PLY】LexYacc简单示例

PLY是流行的编译器构造工具lexyacc的纯python实现。 PLY官方文档:http://www.dabeaz.com/ply/ PLY文档翻译:https://qyliang.blog.csdn.net/article/details/97686897 PLY由两个单独的模块组成lex.py yacc . py 。都可以在名为ply的Python包中找到。 lex.py模块用于将输入的...

土豆洋芋山药蛋的博客 3043

Lex/Yacc 初识Lex

因工作需要接触了一下LexYacc,个人感觉挺有趣的,所以就写下来了。 LexLexical的缩写,大概就可以理解为词汇提取。 Yacc是Yet another compiler compiler, 可以翻译为“还有另一个编译器的编译器”,挺拗口的,不过没关系,先不管它。 安装LexYacc LexYacc是一种标准,当然会有很多的实现了,其中有2个是免费的(好像还有商业版本),那

zj510的专栏 5070

LexYacc从入门到精通(3)--一个极其简单的lexyacc程序

一个极其简单的lexyacc程序 本文版权归熊春雷所有 ,我的邮箱:pandaxcl@163.com>,欢迎大家我讨论计算机方面 的问题,在我的博客上 面还写了很多其他的文档,有空来看看哦。如果转载,请保留此版权信息,并注 明出处。谢谢:) 摘要 在本章中,将会首先给出一个最基本的lexyacc联合使用的框架,这个基本框架

2万+

编译原理——Lexyacc的安装

Lexyacc的安装 Linux用户 LexYacc可以直接从终端安装,命令: apt install flex bison 部分系统可能还需要手动安装 gcc make 等工具,请自行测试。 安装完成后,在终端输入以下命令,若可以正确显示出版本号,则安装成功。 gcc --version lex --version yacc --version 如图所示:(图片来源网络)...

budding0828 1万+

基于Lex Yacc 的 C 语言编译器

一、编译器及其工作流程         编 译器,是将便于人编写,阅读,维护的高级计算机语言翻译为计算机能识别,运行的低级机器语言的程序。编译器将源程序(Source program)作为输入,翻译产生使用目标语言(Target language)的等价程序。源程序一般为高级语言(High-level language),如Pascal,C++等,而目标语言则是汇编语言或目标机器的目

carltraveler的专栏 4458
上一篇: BNF, ABNF, EBNF, TBNF
下一篇: 正则表达式, NFA, DFA, AC多模匹配算法
避趋之
博客等级 码龄19年 67粉丝 122原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值