什么是递归下降分析法

递归下降(Recursive Descent)分析法是确定的自上而下分析法,这种分析法要求文法是LL(1)文法。

  • 为每个非终结符编制一个递归下降分析procedure,每个函数名是相应的非终结符,函数体则是根据规则右部符号串的结构和顺序编写。
  • procedure相互递归调用。

递归下降文法的详细说明见龙书或者http://www.cs.binghamton.edu/~zdu/parsdemo/recintro.html

详细描述了递归下降和如何消除左递归。

对于递归下降文法的使用,一般软件有Yacc和Parse::RecDescent 等。

  1. Parse::RecDescent

Parse::RecDescent是一个轻量级的解析器,不仅轻量(只需要一个.pm文件),而且非常容易可视化和方便BNF的查看,同时在调试时,可以很明显的看到在给定输出下如何解析每个规则。文档可见:https://metacpan.org/pod/Parse::RecDescent

 

  1. Yacc

Yacc(Yet Another Compiler Compiler)是一个经典的生成词法分析器的工具。Yacc生成用C语言写成的词法解释器,需要与词法解析器Lex一起使用,然后把两部分分别生成的C程序一起编译。

从逻辑上是Lex->Yacc->BackendCompiler-linker的顺序。

在目前使用的linux系统上,Lex/Yacc实际上是使用的Flex&Bison工具,至于为什么Linux上的是Flex&Bison,历史问题可以自行探究,实际上Lex的作者包括Google的前CEO。对应关系是flex-lex,可以认为flex=Fast Lex,Bison=Yacc++。

网络上有很多Lex/Yacc的教程,说是需要使用Lex/Yacc来进行文本处理和程序的解析,很多的说法都来自于《flex&Bison》一书。以个人的经验来看,这本书的内容实在太过陈旧,目前简单的文本处理使用Python即可,复杂到需要一些编译的东西,首先Python自己本身就是个解析器,使用Python开发的各个语言的解析器也不少,使用很方便,如果需要对语言的特性有非常好的支持,使用Python调用clang/llvm的东西也非常方便,在今天,flex&Bison的主要用处是一个轻量级的编译器入门教程,相比Clang/llvm的庞大代码量和复杂的结构和API问题,flex&Bison作为教学使用还是不错的。

Flex&Bison安装问题

虽然有人说现在Linux相关公开发行版本中,默认安装Flex&Bison,但是经个人测试AWS提供的Ubuntu16.04系统中并没有提供相关的环境。需要使用来进行安装。

sudo apt-get install flex

sudo apt-get install bison

我本人在说Lex/Yacc或者Flex&Bison喜欢将其放在一起进行,实际上,他们都是独立的工具,可以单独使用。

Flex&Bison与正则表达式(Regular Expression

对于Flex&Bison的用户来说,必须要掌握词法和语法的规则,这个规则是由正则表达式和特定规则构造的。正则表达式是使用一些特殊字符描述的字符串,用来表示一种匹配的模式(pattern)。下面给出一些简单的元字符说明。具体来源不列,source中除了这部分以外,给的说法存在太多错误。

元字符

匹配内容

.

除了换行符之外的任意字符

\n

换行符

*

0次或者多次匹配

+

1次或者多次匹配

?

0次或者1次匹配

^

行首

$

行尾

a|b

a或者b

(ab)+

ab的一次或者多次匹配

“a+b”

a+b(字面意思)

[]

分组

 

Flex实现的wc使用说明

下面将首先介绍使用仅Flex来实现linux中的wc功能。(代码来源于《Flex&Bison》)

编写这样的一个文件,并将其命名为wc.l。

/*   wc.l   */
%{
int chars = 0;
int words = 0;
int lines = 0;
%}

%%

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

%%

main(int argc, char** argv)
{
    yylex();
    printf("%8d %8d %8d\n", chars, words, lines);
}

flex wc.l     //---generate lex.yy.c然后使用flex进行编译处理

gcc lex.yy.c -lfl -o a.out

 

首先说明编译和使用过程,再对flex&Bison的语法进行说明。

wc.l是lex(flex)的程序文件,如果用到了yacc(Bison)的话,一般以.y结尾。

lex程序文件经flex编译后,会生成lex.yy.c;yacc程序文件经Bison后,生成了yacc.tab.c(可能还会有yacc.tab.h文件),经过分别编译后,最后可以统一链接称为最终的目标文件。

因此一个典型的flex&Bison project的Makefile可以写成这样的:

LEX=flex
YACC=bison
CC=gcc
OBJECT=main.out   #object file

$(OBJECT): lex.yy.o yacc.tab.o
    $(CC) lex.yy.o yacc.tab.o -o $(OBJECT)

lex.yy.o: lex.yy.c yacc.tab.h
    $(CC) -c lex.yy.c

yacc.tab.o: yacc.tab.c
    $(CC) -c yacc.tab.c

yacc.tab.c yacc.tab.h: yacc.y
    $(YACC) -d yacc.y

lex.yy.c: wc.l
    $(LEX) wc.l

clean:
    @rm -f $(OBJECT) *.o
View Code

相关文章:

  • 2021-08-07
  • 2021-09-24
  • 2021-08-28
  • 2022-01-05
猜你喜欢
  • 2021-04-16
  • 2021-05-18
  • 2021-06-16
  • 2021-08-21
相关资源
相似解决方案