Skip to content

词法语法分析器

https://blog.csdn.net/weixin_44007632/article/details/108666375

介绍

词法:lex flex

语法:Yacc Bison

lex 是本身有一个 flex.exe,你写。l 文件,这个 flex.exe,给你转为一个。c 文件,这个。c 你自己编译为 exe2,由这个 exe2 来做词法分析

Bison 一般配合 flex 使用,类似于上面,Bison 要求你写一个。y 文件,给你转化为。c 文件,这个。c 结合上面的。c,一起编译(自己用 gcc 编),能够形成一个 exe3,做语法+词法

Lex 新手框架

定义+规则+代码

Lex
%{
/*定义*/
%}
/*这里可以定义一些“变量”,变量使用时要拿{}包裹*/

%%

%%
/*上面%%中间是规则,但是 lex 的规则是没有注释的,所有注释本质都是写到 C 语言里的注释*/
/*代码*/
int main(int argc, char **argv)
{
  yylex();
  yywrap();
  return 0;
}
int yywrap()
{
	return 1;
}

规则

flex 对任何没有匹配到的字符,会自动做原样输出操作。因此,对于那些不需要将其输出,而是需要将其忽略的 pattern,应该进行匹配并做无操作处理。

规则 = 正则表达式 + 空格 + 动作

动作:C 代码、宏(自定义 or 预设)、函数(本质还是 C 代码,不过是调用定义部分定义的函数)

C 代码,一般用{ }包裹住

Lex
[a-zA-Z]+ {ECHO;}
"-" {return T_MINUS;}

ECHO 是 Flex 自定义的一个宏,等于、#define ECHO fprintf(yyout, "%s", yytext)

return T_MINUS ,这个本质是一个 C 代码作为动作,因为是 return XXX

T_MINUS 是一个 token,这时 flex 必须配合 bison 使用,bison 中定义的 token,能够在

正则表达式这里,使用 "" 来表示精确匹配

int {return INT}

"int" {return INT}

应该是一样的,不过建议是下面的

Bison 框架

在与 flex 一起使用时,L 文件的第三部分直接不写

Flex 的第一部分

Lex
%{
#include <stdio.h>
#include "y.tab.h"
void yyerror(char *);
%}
NUM [1-9]+[0-9]*|0

#include "y.tab.h"

要先编译 Y 文件,而编译 Y 文件后,y.tab.h 自动生成

Flex 的第二部分要变成

Lex
{NUM}		                return NUM;
"+"							return ADD;
"-"							return SUB;
"*"							return MUL;
"/"							return DIV;
[a-zA-Z_$]+[a-zA-Z_$0-9]*	return VAR;
\n                          return CR;
[ \t]+                     /* ignore whitespace */;

右侧 return 的 Token,实际上就在 y.tab.h

Bison 的第一部分

Bison
%{
#include <stdio.h>
#include <string.h>
int yylex(void);
void yyerror(char *);
%}

%token NUM ADD SUB MUL DIV VAR CR

%%

定义部分

通过%token 定义 token,token 会被翻译到 y.tab.h 中

Bison 的第二部分

expression: expression '+' expression {/*C 代码*/}
		  | expression '-' expression
		  | NUM
		  ;

通过 BNF 来表示产生式

其中的 : 相当于 产生式里的

即格式为

rule -> BNF action

Bison 的第三部分

void yyerror(char *str){
    fprintf(stderr,"error:%s\n",str);
}

int yywrap(){
    return 1;
}
int main()
{
    yyparse();
}

新手框架

Lex
%{
#include "y.tab.h"
/*有时候不叫 y.tab*/
void yyerror(char *);
%}

%%

%%
Bison
%{
int yylex(void);
void yyerror(char *);
%}
%token 

%%

%%
void yyerror(char *str){
    fprintf(stderr,"error:%s\n",str);
}

int yywrap(){
    return 1;
}
int main()
{
    yyparse();
}

计算器

Flex 返回的 token 本质是一个宏定义出的整数

这导致 Flex 无法直接给 Bison 返回一个整数

因此要使用 Bison 的全局变量 yylval

总之,你只要在 Flex 里,每次分析数值时,写入

sscanf(yytext,"%d",&yylval);

把 yylval 改写即可

而值有时是整数有时是小数,因此要在 Bison 定义处把 yylval 定义为 union

C
%union{
  int inum;
  double fnum;
  char c;
  char * string;
  //其余类型随意加
}

定义和规则补充

之前 Bison 的规则是

%token ADD

但是只能表示终结符

%token <inum> NUM

%type <inum> expression

这种结构表示,后面的符号的值,使用的是这个变量的值

type 提示一个非终结符

father-expression : expression SUB term {$$=$1-$3;}

inum