flex & bison 基础概述

自制编译器学习3:Flex和Bison简介 阅读详情
AI摘要

本文简要介绍了如何使用Flex生成词法分析器和Bison生成语法分析器,并通过实例展示了这两种工具的基础用法及协作流程。

1. 前言

限于作者能力水平,本文可能存在谬误,因此而给读者带来的损失,作者不做任何承诺。

2. 本文目标

. 简单介绍 flex 和 bison 的基础使用方法
. 简要分析 flex, bison 生成代码的工作流程

3. flex & bison

3.1 背景

本文所有分析,基于 Ubuntu 16 系统。

3.2 flex

3.1.1 flex 简介

flex用来生成词法分析器(lexical analysis, 或 scanner),而词法分析器的作用,简单来讲,就是将输入,按定义的正则表示式模式,解析分割成一个个记号(token)。

# 生成词法分析器
                             flex
XXX.l(词法分析器规则定义文件) ======> 词法分析器

# 通过词法分析器,将输入数据流,解析成一个个记号(tokens)
           词法分析器
输入数据流 ===========> 一个个记号(tokens)

3.1.2 flex 使用例子

(1) 初次使用,先运行如下命令安装 flex:

sudo apt-get install flex

(2) 编写 flex 程序(用来生成词法分析器的规则文件XXX.l)。
我们先来了解一下 flex 程序的编写规则,flex 程序分为3个部分:

定义部分:
包含选项(option),文字块,开始条件,转换等。
本部分中以空白行开头、或包含在%{和%}之间的部分,都会被原封不动的拷贝到C代码中。
%%
规则部分:
包含正则模式行和模式行匹配时执行的C代码。
以空白行开头、或包含在%{和%}之间的部分,都被认为是C代码,它们会被原封不动的拷贝到yylex()函数中。
大多数flex程序都具有二义性,即相同的输入,可能被多种模式不同的正则模式匹配。flex通过两个简单的规则来解决它:
. 词法分析器匹配输入时匹配尽可能多的字符串;
. 如果两个模式都可以匹配的话,匹配更早出现的模式。
%%
用户子程序部分:
这个部分通常包含在模式规则匹配时,执行的C代码调用的函数。
本部分会原封不动的拷贝到C代码中。

这3个部分,用2个%%分隔,前2个部分是必须的,但它们的内容可以为空,第3部分和它之前的%%可以省略。

了解 flex 程序的编写规则后,接下来,我们以一个统计字符数、单词数目、行数的 flex 程序为例,来演示一下flex的使用,flex 程序count-words.l如下:

%{
int chars = 0; /* 字符计数 */
int words = 0; /* 单词计数 */
int lines = 0; /* 行计数 */
%}

%%

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

%%

int main(int argc, char *argv[])
{
	yylex();

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

	return 0;
}

编写一个简单的 Makefile 来编译我们的词法分析器:

count-words: count-words.l
	flex --noyywrap count-words.l # 生成词法分析器代码 lex.yy.c
	gcc -o $@ lex.yy.c # 编译词法分析器 lex.yy.c 

clean:
	-rm -f lex.yy.c count-words

编译和运行:

make # 编译生成词法分析器程序 count-words
./count-words # 运行词法分析器,按 Ctrl + D 结束数据输入

测试中我们发现,词法分析器从标准输入接收数据,这是默认的行为。如果我们想改变该默认行为,转而将文件作为输入,只需按如下修改 flex 程序count-words.l就可以达到目标:

%option noyywrap

%{
/* 统计单个文件数据 */
int chars = 0;
int words = 0;
int lines = 0;

/* 统计所有文件数据 */
int total_chars = 0;
int total_words = 0;
int total_lines = 0;
%}

%%

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

%%

int main(int argc, char *argv[])
{
	int i;

	if (argc < 2) { /* 没有给定文件列表,仍然从标准输入获取数据 */
		yylex();
		printf("%8d%8d%8d\n", chars, words, lines);
		return 0;
	}

	/* 遍历所有输入文件,统计每一个文件的数据 */
	for (i = 1; i < argc; i++) {
		FILE *fp = fopen(argv[i], "r");

		if (!fp) {
			perror(argv[i]);
			return -1;
		}

		/* 复位当前文件的统计数据 */
		chars = words = lines = 0;
		
		yyrestart(fp); /* 调用 yyrestart() 接口重置词法分析器的输入流到文件 @argv[i] */
		yylex(); /* 调用词法分析器进行数据统计 */
		fclose(fp); /* 关闭当前文件 */
		printf("%8d%8d%8d %s\n", chars, words, lines, argv[i]);

		/* 记录当前文件的统计数据 */
		total_chars += chars;
		total_words += words;
		total_lines += lines;
	}

	if (argc > 1)
		printf("%8d%8d%8d total\n", total_chars, total_words, total_lines);

	return 0;
}

修改后重新编译运行:

make
./count-words a.txt b.txt # a.txt, b.txt 作为输入

如果不指定输入(具体是修改yyin全局变量),程序默认使用标准输入;如果要修改输入,我们可以通过yyrestart()修改。

3.1.3 flex 生成代码流程简析

通常,我们有必要简单的分析下 flex 生成的代码,以帮助我们理解和更好的使用工具。下面简要分析 flex 生成代码的工作流程:

/* 
 * 在分析具体代码前,我们先聊一下 flex 的 fl 库。
 * flex工具带有一个微型的 fl 库,它定义了 main(), yywrap() 接口。 其中:
 *  . main() 函数调用 yylex() 做词法分析;
 *  . yywrap() 简单地返回 1。
 *    yywrap() 的作用是,在yylex()发现到达输入数据末尾时,调用 yywrap(),看是否还有数据,如果有,yywrap() 应该
 *    返回0,否则返回1。
 *
 * 如果我们的flex程序,不自己实现 main() 和 yywrap(),则在编译时,可以给 gcc 指定 -lfl 选项。另外,可以通过给 
 * flex 传递 --noyywrap 选项,或者在 flex 程序中,指定 %option noyywrap 来告诉flex ,我们不调用 yywrap() ,
 * 以此来屏蔽编译链接报错。
 */
/* 接下来,进入具体的代码流程分析 */
main()
	yylex() /* 进入词法分析器入口 */
		/* yylex() 初次调用的初始化。后续 yylex() 调用会在之前的上下文下继续工作。 */
		if ( !(yy_init) )
		{
			(yy_init) = 1;
			...
			if ( ! (yy_start) )
				(yy_start) = 1;	/* first start state */
				
			if ( ! yyin ) /* 没有设定输入, 默认将 stdin 作为输入 */
				yyin = stdin;
				
			if ( ! yyout ) /* 没有设定输出, 默认将 stdout 作为输入 */
				yyout = stdout;
				
			/* 输入缓冲初始化 */
			if ( ! YY_CURRENT_BUFFER ) {
				yyensure_buffer_stack (); /* 创建 yy_buffer_state 输入缓冲管理对象指针栈 */
				YY_CURRENT_BUFFER_LVALUE =
					yy_create_buffer(yyin,YY_BUF_SIZE ); /* 创建栈顶 YY_BUF_SIZE 大小的输入缓冲 */
			}
			
			/*
		 	 * 获取栈顶输入缓冲如下状态:
		 	 * . yy_n_chars: 读到栈顶输入缓冲空间的字符个数
		 	 * . yytext, yy_c_buf_p: 栈顶输入缓冲空间当前位置指针(char *)
		 	 * . yyin: 输入缓冲输入文件
		 	 * . yy_hold_char: 栈顶输入缓冲空间当前字符
		 	 */
			yy_load_buffer_state( );
		}
		
		/* 扫描循环,直到输入结束 */
		while ( /*CONSTCOND*/1 )		/* loops until end-of-file is reached */
		{
			/* 正则匹配状态机循环 */
			yy_current_state = (yy_start);
		yy_match:
			do {
				YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
				...
				yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
				++yy_cp;
			}
			while ( yy_base[yy_current_state] != 17 );
			
			...
			
			/* 一个正则模式匹配完成的后惯例动作:
			 * yytext: 当前正则模式匹配的内容
			 * yyleng: 当前正则模式匹配内容长度
			 * yy_hold_char: 当前正则模式匹配内容的最后一个字符(也即当前字符)
			 * *yy_cp = '\0';
			 * yy_c_buf_p: 下一个待解析字符位置指针
			 */
			YY_DO_BEFORE_ACTION;
		do_action:	/* This label is used only to access EOF actions. */
			/* 状态机正则匹配结束,按匹配的正则做用户定义的动作 */
			switch ( yy_act )
			{ /* beginning of action switch */
			...
			case 1:
				YY_RULE_SETUP
#line 18 "calculator.l"
				{ return ADD; } /* 正则模式匹配时,执行的C代码 */
				YY_BREAK
			...
			default:
				YY_FATAL_ERROR(
					"fatal flex scanner internal error--no action found" );
			}
		}

其实 yylex() 的工作逻辑很简单,可以总结如下:

while (1)
	从输入读取数据
	按正则模式匹配输入数据
	如果有匹配的模式,执行匹配模式的C代码
	否则,报错

注意到,yylex() 是有返回值的,不出错的情形下,它返回匹配模式的 token ,这就是它可以和 bison 生成代码一起协作的基础。

3.1.4 flex 小结

上面我们简单介绍了 flex 的基础用法,但很多时候,这些并不足够。下面列举几个对我们日常很常见也很有用的 flex 用法。

3.1.4.1 option 选项

(1) 生成可重入词法分析器。

一方面,生成的词法分析器代码,有很多全局变量; 另一方面,在词法分析器入口 yylex() 返回后,下一次调用会接着使用上一次运行后的上下文继续执行。以上两点,不能满足要求可重入的调用的上下文。此时,我们可以通过%option reentrant 选项来生成可重入的词法分析器。此时,我们通过如下代码片段构建可重入的词法分析器:

yyscan_t scanner;

yylex_init(&scanner) / yylex_init_extra(extra, &scanner); /* 创建词法分析器上下文 */
while (yylex(scanner)) { /* 基于独立的上下文进行词法分析 */
	...
}
yylex_destroy(scanner); /* 销毁词法分析器上下文 */

(2) 改变生成代码函数名。

我们有时候可能不想使用 yylex() 等其它词法分析器接口名,可以通过%option prefix="XXX"作为词法分析器接口名前缀。如:%option prefix="parse_events_",那生成代码中,yylex() 则变为 parse_events_lex(),当然,还有更多函数名的变换。

(3) 自动维护行号代码。

我们可以自己在规则中,更新 yylineno 来维护行号。当然,也可以通过 %option yylineno选项,让 flex 帮我们自动生成行号维护代码。

(4) 与 bison 协同工作选项。

默认生成的代码,yylex() 函数是没有参数的,除了可以通过%option reentrant选项来增加词法分析器的上下文参数外,我们还可以通过%option bison-bridge和%option bison-locations来改变 yylex() 原型:

%option bison-bridge: 为 yylex() 增加参数 YYSTYPE *yylval_param, 用来记录词法分析器解析的 token 的值。
%option bison-locations: 为 yylex() 增加参数 YYLTYPE *yylloc_param, 用来存储行列信息。

如果有以下选项配置:

%option reentrant
%option bison-bridge
%option bison-locations
...
%%
...
%%
...

则生成的 yylex() 函数原型为:

int yylex(YYSTYPE *yylval_param, YYLTYPE *yylloc_param, yyscan_t yyscanner);
3.1.4.2 定义

类似于C中的宏定义,主要是将正则规则中重复的部分抽离出来,免得重写。我们看一个例子:

group		[^,{}/]*[{][^}]*[}][^,{}/]*
%%
{group}		{
			BEGIN(INITIAL);
			REWIND(0);
		}
%%
...

上例中,在第一部分定义了 group ,然后再第二部分规则中引用,使用 {} 括起来。

3.1.4.3 定义特定状态下才会执行的规则

%x IFILE

%%

^"#"[ \t]*include[ \t]*[\"<] { BEGIN IFILE; }

<IFILE>[^ \t\n\">]+	{
						{
							int c;
							while ((c = input()) && c != '\n');
						}
						yylineno++;
						if (!newfile(yytext))
							yyterminate(); /* no such file */
						BEGIN INITIAL;
					}

<IFILE>.|\n			{
						fprintf(stderr, "%4d bad include line\n", yylineno);
						yyterminate();
					}

<<EOF>>				{ if (!popfile()) yyterminate(); }

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

%%
...

上面我们通过 %x 定义了一个 exclusive 的状态 IFILE,在该状态下,只有以 <IFILE> 开头的规则才会被执行,它用来解析 #include 预处理符号。其中,特殊符号<<EOF>>表示遇到文件结尾;词法分析器用 input() 从输入读取一个字符,yylineno 记录行号,yytext 记录当前匹配的文本,ECHO 回显匹配的文本。
词法分析器的初始状态为INITIAL(即0),可以通过YY_START或YYSTATE获取当前状态,通过BEGIN来切换当前状态,如上例中的BEGIN IFILE;来切换词法分析器的状态为IFILE,在状态IFILE下,只有以<IFILE>开头的规则才会被执行。
另外还可以通过%s定义可共享状态。假设我们通过%s SS定义了状态SS,和%x定义不同的是,除了将<SS>开头的规则限制在只能在SS状态下执行外,而剩余的其它规则,也可以在SS状态下执行。
通常来讲,%x是更加有用的,因为它将分析限制于特定的上下文,这可以简化我们词法分析器的设计。

3.2 bison

3.2.1 bison 简介

bison 基于给定的语法,来生成一个可以识别这个语法中有效语句的语法分析器。我们简单的看一下语法分析器的生成流程:

# 生成语法分析器
       bison -d
XXX.y ==========> XXX.tab.l, XXX.tab.h

# 与词法分析器协作分析语法
                      tokens
                 ----------------
                |                |
                |                V
            词法分析器        语法分析器
                ^                |   
                |                V
            输入数据流      合乎语法的语句

3.2.2 flex + bison 使用例子

(1) 初次使用,先运行如下命令安装 bison:

sudo apt-get install bison

(2) 编写 bison 程序。
我们先来说一下 bison 程序(XXX.y)的编写规则,bison 程序分为3个部分:

定义部分:
包含选项(option),文字块(%{和%}、%code),声明(%union,%start,%token,%type,%left,%right,%nonassoc等)。
%%
规则部分:
包含语法规则和规则匹配时执行的C代码。
%{和%}之间的部分,原封不动的拷贝到 yyparse() 中。
%%
用户子程序部分:
这个部分通常包含语法规则匹配时,执行的C代码调用的函数。
本部分原封不动的拷贝到C代码中。

这3个部分,用2个%%分隔,前2个部分是必须的,但它们的内容可以为空,第3部分和它之前的%%可以省略。
接下来,我们一个简单计算器为例,构建计算器的 flex 和 bison 程序如下。

%{
/*
 * calculator.l
 */

#include "calculator.tab.h"
%}

%%

"+"	{ return ADD; }
"-"	{ return SUB; }
"*"	{ return MUL; }
"/"	{ return DIV; }
"|"	{ return ABS; }
"("	{ return OP; }
")"	{ return CP; }
[0-9]+	{ yylval = atoi(yytext); return NUMBER; }

\n	{ return EOL; }
"//".*
[ \t]	{ /* ignore white space */ }
.	{ printf("Mystery character %c\n", *yytext); }

%%

其中 yylval 记录当前识别到的 token 的值,可以导出给语法分析器使用。

%{
/*
 * calculator.y
 */

#include <stdio.h>

extern int yylex(void);

void yyerror(char *s);
%}

/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%token EOL

%%

callist: /* nothing */
 | callist exp EOL { printf(" = %d\n", $2); }
 ;

exp: factor
 | exp ADD factor { $$ = $1 + $3; }
 | exp SUB factor { $$ = $1 - $3; }
 ;

factor: term
 | factor MUL term { $$ = $1 * $3; }
 | factor DIV term { $$ = $1 / $3; }
 ;

term: NUMBER
 | ABS term { $$ = $2 >= 0? $2 : - $2; }
 | OP exp CP { $$ = $2; }
 ;

%%

int main(int argc, char *argv[])
{
	yyparse();
}

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

上面 bison 程序中的 $$, $1,... 等是用描述每条语法规则中语法符号的值,$$ 表示规则左边符号的值,$1,$2,...依次表示规则右边第1个,第2个,...符号的值。
接下来编写用来编译的 Makefile :

calculator: calculator.l calculator.y
	bison -d calculator.y
	flex calculator.l
	gcc -o calculator calculator.tab.c lex.yy.c -lfl

clean:
	-rm -f calculator lex.yy.c *.tab.*

编译运行:

make # 编译生成计算器程序 calculator
./calculator # 运行计算器程序,按 Ctrl + D 结束数据输入

3.2.3 flex 与 bison 协作流程简析

main() /* calculator.tab.c: bison -d 生成的代码 */
	yyparse()
		...
		yychar = YYEMPTY; /* Cause a token to be read.  */
		goto yysetstate;
		...
	yynewstate: /* 下一状态 */
	/* In all cases, when you get here, the value and location stacks
	   have just been pushed.  So pushing a state here evens the stacks.  */
		yyssp++;
	
	yysetstate:
		...
		yyn = yypact[yystate];
		...
		if (yychar == YYEMPTY)
		{
			YYDPRINTF ((stderr, "Reading a token: "));
			yychar = yylex (); /* 调用词法分析器解析一个token */
				/* 
				 * 参看 3.1.3 小节,词法分析器工作流程
				 */
		}
		
		...
		
		/* Discard the shifted token.  */
		yychar = YYEMPTY;
		yystate = yyn;
		YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
		*++yyvsp = yylval;
		YY_IGNORE_MAYBE_UNINITIALIZED_END
	
		goto yynewstate; /* 进入下一分析状态 */

3.2.4 bison 小结

上面我们简单介绍了 bison 的基础用法,但很多时候,这些并不足够。下面列举几个对我们日常很常见也很有用的 bison 用法。

3.2.4.1 option 选项

(1) 要求 bison 版本。

%require "2.4"
%%
...
%%
...

(2) 自定义语法分析器入口 yyparse() 函数原型。

默认生成语法分析器入口 yyparse() 函数是没有参数的,但有时候,我们需要给它传递参数,这时我们可以通过%parse-param选项来自定义参数列表。如:

%parse-param {void *_parse_state}
%parse-param {void *scanner}
%%
...
%%
...

则 yyparse() 函数的原型定义为:

int yyparse (void *_parse_state, void *scanner);

(3) 生成可重入的语法分析器。

%define api.pure
%%
...
%%
...

还可以使用%pure-parser代替%define api.pure。这两个选项通常结合%parse-param使用,给 yyparse() 传递参数。

(4) 定义词法分析器解析符号的ID。

/* declare tokens */
%token NUMBER
%token ADD SUB MUL DIV ABS
%token OP CP
%token EOL

%%
...
%%
...

上面的 bison 程序,会在 *.tab.h 中对应生成如下的 token 定义:

#ifndef YYTOKENTYPE
# define YYTOKENTYPE
  enum yytokentype
  {
    NUMBER = 258,
    ADD = 259,
    SUB = 260,
    MUL = 261,
    DIV = 262,
    ABS = 263,
    OP = 264,
    CP = 265,
    EOL = 266
  };
#endif

%token 用来定义 token 编号,给词法分析器的 token 编号。bison 以 258 为生成符号的起始编号,避免和 ascii 值冲突。另一种 token 编号的使用方法是单引号内含字符的方式,如 ‘+’ ,则用 + 的 ascii 值作为其 token 编号,不必额外定义。

(5) 定义语法分析器规则中符号的数值类型。

在语法分析的规则中,有时候需要通过 %union 指定符号的数值类型。我们看个简单的例子:

%union {
  struct ast *a;
  double d;
}

/* declare tokens */
%token <d> NUMBER
%token EOL

%type <a> exp factor term

%%
...
%%
...

其中,用 %union 声明被转化为如下C代码段:

/* Value type.  */
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED

union YYSTYPE
{
#line 8 "calculator.y" /* yacc.c:1909  */

	struct ast *a;
	double d;

#line 64 "calculator.tab.h" /* yacc.c:1909  */
};

typedef union YYSTYPE YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define YYSTYPE_IS_DECLARED 1
#endif

也即定义为 YYSTYPE 类型。如果不声明%union,则 YYSTYPE 定义为 int 。声明%token <d> NUMBER表示,语法符号NUMBER的数据类型为,声明%union中,数据成员d的数据类型double;声明%type <a> exp factor term表示,语法符号exp,factor,term的数据类型为,声明%union中,数据成员a的数据类型struct ast *。

语法会存在二义性,简单来讲,语法二义性就是一段输入,可匹配到不同的语法规则情形。本文对语法的二义性未做描述。

4. 后记

人的精力时间总是有限的,我认为我们学习一样技能,总是、也应该是出于某种目的的。对于那些有明显规律的(可用正则表达式和语法描述的)输入,flex 和 bison 可以极大地提高我们的生产效率、代码的可维护性。对于更加复杂的输入,手工编写的代码,阅读、调试困难,可维护度、扩展性极差,这时候应该利用 flex 和 bison,它们都是久经历史考验的,只要能正确设计正则规则、语法规则,它们就能帮我们保证程序的正确性和效率。
本文仅对 flex 和 bison 做了简单基础性地描述,更多的细节,以及对齐内部的实现原理等方面未做展开,读者可阅读后面的资料,进行补充。

5. 推荐阅读 & 参考资料

参考资料:

[1]《flex & bison》, John R. Levine
[2] [flex](https://www.gnu.org/savannah-checkouts/gnu/www/software/flex/flex.html)
[3] [GNU Bison](https://www.gnu.org/software/bison/)

推荐阅读:

《A Retargetable C Compiler_Design and Implementation》
《Advanced Compiler Design and Implementation》
《Building an Optimizing Compiler》
《Compiler Construction Principles And Practice》
《Compiler Design in C》
《Compilers Principles Techniques and Tools》
《Crafting a Compiler》
《Engineering a Compiler》
《Introduction to Compiler Construction》
《Language Implementation Patterns》
《Modern Compiler Implementation in C》
《Modern Compiler Design》
《Programming Language Pragmatics》
《The Implementation of Functional Programming Languages》
《计算机程序的构造和解释》
flex&bison编写语法分析器 问题总结 这次实验碰到了许多问题,前后花了好几天的时间,做完后感觉收获颇多。 问题1:字符串指针的内存分配 char* p1="Linwhite"; char* p2; p2=p1; p1初始化时分配了内存空间,p2=p1将p2指向p1指向的内存空间,即p1和p2指向同一内存。 yytext是一个字符指针,它的值是当前扫描到的词。词法分析开始时,yytext指向一块内存(缓冲区)的首 阅读详情

相关推荐

简单用用flex和bison

参考博文: https://www.ibm.com/developerworks/cn/linux/sdk/lex/ https://www.jianshu.com/p/8da9ed3d30a7 https://www.jianshu.com/p/ee814a020624 flex:词法分析器会将输入序列与定义的常规表达式匹配,匹配往往会返回标记。 bison:语法分析器在查看到某个标记序列时,可能会触发某些动作,这便是语法。 bas.y通过yacc会生成y.tab.c包含了标记序列的语法规则,y.tab

pourtheworld的博客 2099

《Flex 与 Bison》学习笔记

第一部分 简单了解Flex和Bison 1、Flex 和 Bison 简介 Flex和Bison(前身分别为Lex和Yacc),是Linux下两个用来生成程序的工具,它们生成的程序分别叫做词法分析器和语法分析器。词法分析把输入分割成一个个有意义的词块,称为记号(token);语法分析则确定这些记号是如何彼此关联的。 举个例子:Flex文件定义pattern(什么是黄豆,什么是绿豆……),输入文件(一袋豆子)通过Flex处理(词法分析),将输入划分为一段段的token(将输入的豆子一个个摘出来),从而执行不同

qq_39632811的博客 8208

Flex & Bison

文件结构 Flex和Bison的源代码文件都是由定义,规则,用户自定义函数三部分组成的,结构如下 { definitions } %% { rules } %% { user subroutes } 联合使用Flex和Bison Flex和Bison各有一份自己的源代码,比如lexical.l和syntax.y,分别定义词法规则和语法规则,这两份源代码经过各自的处理后,分别生成一份词法分析器和语...

Wir müssen wissen, wir werden wissen. 1705

Flex&Bison 简单入门

Flex&amp;Bison 简单入门 Ref: 《flex与bison(中文版)》 1. Flex&amp;Bison安装 安装flex sudo apt install flex 安装bison sudo apt install bison 安装gcc(若缺少) sudo apt-get install -y build-essential 2. Flex&amp;Bison使用 2.1 第一个flex程序 Flex程序 例1-1: 字数统计 fb1-1.l /* 正如Unix

LostUnravel的博客 3942

编译原理——基于LR分析表编写语法分析器与基于WINDOWS下FLEX与BISON的计算器实现

文章目录一、概述二、基于LR分析表编写语法分析器2.1 需求描述2.2 实现流程2.3 C++ 源码2.4 测试样例三、基于WINDOWS下FLEX与BISON的计算器实现3.1 需求描述3.2 Flex 源码3.3 Bison 源码3.4 测试样例四、相关草图4.1 可识别活前缀的 DFA 草图4.2 改进后的 SLR(1) 分析表草图 一、概述   本篇博文主要提供 基于LR分析表编写语法分析...

Coder Yang 2467

开源数显表

开源数显表,广泛应用于车床、铣床、磨床、镗床、火花机、线切割等。市面上此类液晶数显表多数都是基于此项目。 一、基本配置 硬件 主控:STM32F407VGT6 LCD:群创AT070TN92 显示驱动:RA8875 光栅尺:3 x 输入(X/Y/Z) 串口:1 x MAX3232 继电器:2 x 输出 存储:AT24C64 模拟输入:LM324C 电源:AC 220V 软件 工程版本:Keil 5 STM32库:V1.4.0 图形界面:uCGUI 多语言支持:中文、英文 二、项目文

m0_70934529的博客 435

flex与bison

flex与bison flex与bison简介 词法分析与语法分析 flex用作词法分析,而bison用作语法分析。词法分析把输入分解成一个个有意义的词块,称作token;语法分析则确定这些词块彼此之间如何关联(使用语法树表达)。比如: A = B + C; flex将其分解成A、=、B、+、C和;;接着bison将其确定为一个表达式,并对其建模成表达式树,简化如下 ...

CrazyHeroZK的专栏 1万+

LLM大模型-vLLM本地部署全流程:Windows WSL2环境安装、HuggingFace与Modelscope模型加载与本地运行、Docker化部署与镜像分发

vLLM本地部署大模型方案 vLLM是一款高性能大模型推理引擎,通过PagedAttention技术显著提升吞吐量和内存效率,支持低成本、高并发的本地部署。 核心优势: 性能卓越:吞吐量远超同类方案,支持连续批处理等高级功能 成本优化:减少GPU服务器需求 兼容性强:提供类OpenAI的简洁API 部署步骤: 硬件准备:需NVIDIA GPU(如A100/3090),显存≥模型参数量×2(7B模型需14GB) 软件环境: Linux系统或Windows WSL2 安装CUDA 12.1+和Python 3.

2202_75674969的博客 4568

编译原理 · Flex & Bison 入门到实战教学

本文是一篇关于编译原理中Flex和Bison工具的实战教学文章,主要面向已学习过编译原理理论、希望动手实践的读者。文章分为五个部分: 整体概述:介绍编译器工作流程中词法分析(Flex实现)和语法分析(Bison实现)的作用及工具关系。 Flex词法分析器详解: 讲解Flex文件的三大结构(定义段、规则段、用户代码段) 核心正则表达式语法和内置变量 提供简单Token识别、关键字与标识符区分等实例 Bison语法分析器详解: 说明Bison文件结构 解释终结符/非终结符/产生式 包含四则运算和变量赋值等进阶实

2401_88644562的博客 521

亚马逊SP-API授权实战:从OAuth流程到Refresh Token获取

本文详细解析了亚马逊SP-API授权流程,从OAuth认证到Refresh Token获取的全过程。通过实战经验分享,帮助开发者快速掌握Marketplace Appstore、Website Workflow和自行授权三种方式,解决常见错误如MD5100和MD9999,并提供了安全存储Refresh Token的最佳实践。

weixin_30379531的博客 518

RT-Thread stm32h7使用串口DMA

stm32h7在rtthread中无法使用串口DMA,通过更改驱动代码使其支持串口DMA

qq_35141454的博客 2286

初识 flex & bison

flex和bison经常结合使用,分别用于词法分析和语法分析。flex):flex用于生成词法分析器或者说是扫描器(scanner)。它将输入的文本分解为称为"tokens"的序列。每个 token 都有一个特定的意义,例如一个数字、一个变量名或一个操作符。bison):bison用于生成语法分析器或称为解析器(parser)。它的任务是根据由flex产生的 tokens 来确保输入遵循某种给定的语法,并从中生成一个通常的抽象语法树 (AST) 或其他中间表示。

青衫客36的博客 2510

AI 模型训练核心方法论:零基础也能落地的 8 个关键阶段

本文是为 AI 零基础学习者打造的模型训练入门指南,以生活化语言拆解核心概念,规避专业术语壁垒。内容先通俗阐释模型训练、监督学习、数据集划分等基础概念,再按问题定义、数据准备、模型选择、环境搭建、训练、评估、调参、部署 8 个阶段,拆解完整训练流程,搭配 PyTorch 代码示例与实战案例,同时提供资源预算、常见问题解决方案及学习路径。指南强调数据的核心重要性,推荐新手优先使用迁移学习和免费 GPU 资源,兼顾理论与实操,帮助学习者快速上手,避开训练误区,独立完成从模型搭建到部署的全流程。

weixin_52741870的博客 469

bison & flex

来自: http://hi.baidu.com/bihailan/blog/item/f12e78c82b2ae21c7e3e6ff8.html bison 是替代yacc的语法分析程序生成器. yacc是 Yet Another Compiler Compiler的缩写. bison又是什么呐 是一个生成可以分析文本文件结构的程序的程序. 用户不用直接编写程序而只用确定好如何分析这些文

HEN_MAN的专栏 2356

Android12 适配 usb 触屏

在 Android 系统中,输入设备 IDC(Input Device Configuration)设备描述文件(.idc)是用于配置和定义输入设备行为和属性的文本文件。 该文件通常在`/system/usr/idc/` 或 `/vendor/usr/idc/`,具体位置因芯片厂商SDK而异。一般情况此类文件是预置到系统,开发者 root 权限才能修改这些文件。输入设备 IDC 设备描述文件在 Android 系统中起到了识别、配置、映射和定制输入设备的作用,使得系统能够准确解析和处理各种输入设备的事件,提

weixin_35723192的博客 1234

【WRF-Chem教程-附录B】使用 MOZART 与WRF-Chem

使用MOZART与WRF-Chem

WW、forever的博客 242

3.05 flex和bison进阶,产生C++语法分析器

bison C++版本的语法分析器都是可重入的,所以bison为语法分析器创建了一个类。在使用可重入的语法分析器时,程序员可以创建他所需要数量的实例,然后传入在另一个类中保存的每个实例的应用数据。点击查看这篇文章,其中包含有关可重入语法分析器的信息。 每次创建C++ 版本的语法分析器时,bison会创建四个头文件:location.hh和position.hh用来定义位置结构,stack.hh定义内部语法分析器堆栈,以及一个定义语法分析器自生的头文件。前三个头文件内容并不会变化,最后一个头文件则包含该语法分

ronnie88597的博客 6732

YOLOv11改进 | Neck篇 | 独创HFPN利用分层特征融合块HFFB模块融合多层次特征改进yolov11(全网独家创新)

本文给大家带来的最新改进是利用分层特征融合块HFFB创新yolov11的neck部分我称之为HFPN,这个模块可以融合局部特征、全局特征、中间特征将三种特征融合在一起辅助yolov11进行检测,经过我的设计分为三种可以针对大目标、小目标、标准目标的检测方式均不同,大家可以根据自己的数据集进行不同的选择,本文的内容为我独家创新。YOLOv11改进系列专栏——本专栏持续复习各种顶会内容——科研必备目录一、本文介绍二、原理介绍三、核心代码四、添加方法4.1 修改一4.2 修改二4.3 修改三4.4 修改四。

Snu77的博客 5210

Flex & Bison 开始

Flex 与 Bison 是为编译器和解释器的编程人员特别设计的工具,本文旨在让大家了解它们,以及它们能帮助我们完成什么样的工作。

GoCoding 840

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

linux--Flex and Bison

linux--Bison12参考 1 2 参考 1、Bison 3.4 2、GNU Operating System 3、

天道酬勤 8233

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

flex & bison

flex yytext是匹配的字符串,yyleng是该字符串的长度 scan的规则: If action code returns, scanning resumes on the next call to yylex(); if it doesn’t return, scanning resumes immediately. 统计代码行数,字符数,数字字符数 %{ #include &lt;...

tailuzhecom的博客 456

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

词法分析flex & 语法分析bison

flex&bison

errorr0 3890

flex和bison笔记

flex和bison工具的使用

WenBayBay的博客 979

Win flex-bison 的简单使用

Win flex-bison 提供了 flex bison for Windows 的另外一种移植,将GNU m4宏处理器源代码集成进win flex-bison,不依赖Msys,Msys2,Cygwin 提供的模拟类Unix运行环境,不依赖GNU m4宏处理器便可生成C目标文件。 sourceforge.net/projects/winflexbison/ Win flex-bison is a port Flex & Bison tools to the Windows platform

gocad的专栏 1万+

flex+bison运行测试一个小例子

要测试运行实例的话,前提是保证配好环境变量。环境变量具体配置通过查阅其他博客完成了,接下来演示如何查看是否配置成功: ①进入cmd,输入flex --version ②输入bison --version 我使用codeblocks进行后面的编译,所以先对codeblocks进行一些配置。进入cb:设置-&gt;编译器 点击右边的小三角,拖到最右边: 进入高级选项,会弹出一个确认框,确认: 对.l进行配置:在Source ext.的下拉框中选择l,表示将针对flex文件进行配置,宏命令行下面的编辑框中会显.

qq_41857397的博客 1306
上一篇: Linux驱动: rtc子系统
下一篇: Linux: Jump label实现简析
JiMoKuangXiangQu
博客等级 码龄14年 1110粉丝 235原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值