Lex与Yacc学习(八)之变量和有类型的标记(扩展计算器)

变量和有类型的标记

下一步扩展计算器来处理具有单个字母名字的变量,因为只有26个字母 (目前只关心小写字母),所以我们能在26个条目的数组(称它为vbltable)中存储变量。

为了使得计算器更加有用,也可以扩展它来处理多个表达式(每行一个)和使用浮点值。

具有变量和实值的计算器词法ch3-03.l

%{
	#include "ch3-03.tab.h"
	#include <math.h>
	extern double vbltable[26];
%}
%%
([0-9]+|([0-9]*\.[0-9]+)([eE][-+]?[0-9]+)?)	{
		yylval.dval = atof(yytext);
		return NUMBER;
	}
[ \t]	;		/*忽略空白*/
[a-z]	{	yylval.vblno = yytext[0] - 'a';
			return NAME;
		}
"$"		{	return 0; /*输入结束*/ }
\n		|
.		return yytext[0];
%%

具有变量和实值的计算器语法ch3-03.y

%{
	double vbltable[26];
%}

%union {
		double dval;
		int vblno;
	}
%token	<vblno> NAME
%token	<dval>	NUMBER
%left 	'-' '+'
%left	'*'	'/'
%nonassoc 	UMINUS

%type <dval> expression

%%
statement_list: statement '\n'
	|	statement_list statement '\n'
statement:	NAME '=' expression		{vbltable[$1] = $3; }
	|	expression		{ printf("= %g\n", $1); }
	;

expression:	expression '+' expression	{ $$ = $1 + $3; }
	|		expression '-' expression	{ $$ = $1 - $3; }
	|		expression '*' expression   { $$ = $1 * $3; }
	|		expression '/' expression
						{
							if($3 == 0.0)
								yyerror("divide by zero");
							else
								$$ = $1 / $3;
						}
	|	'-' expression %prec UMINUS {$$ = -$2;}
	|	'(' expression ')'	{$$ = $2; }
	|	NUMBER			{ $$ = $1; }
	|	NAME			{ $$ = vbltable[$1]; }
	;
%%

int main()
{
	yyparse();
	return 0;
}

int yyerror(char *s)
{
	printf("%s\n",s);
	return 0;
}

编译运行结果

时间: 2024-10-10 13:47:48

Lex与Yacc学习(八)之变量和有类型的标记(扩展计算器)的相关文章

Lex与Yacc学习(一)之环境配置篇

Abstract 在开发程序的过程中经常会遇到文本解析的问题,例如:解析 C 语言源程序,编写 脚本引擎等等,解决这种文本解析的方法有很多,一种方法就是自己手动用 C 或者 C++直接编写解析程序,这对于简单格式的文本信息来说,不会是什么问题,但是 对于稍微复杂一点的文本信息的解析来说,手工编写解析器将会是一件漫长痛苦 而容易出错的事情.本系列文档就是专门用来由浅入深的介绍两个有名的 Unix 工 具 Lex 和 Yacc,并会一步一步的详细解释如何用这两个工具来实现我们想要的任何 功能的解析程

C++ Primer 学习笔记_5_变量和基本类型(续2)

 变量和基本类型 七.枚举 枚举不但定义了整数常量集,并且还把它们聚集成组. 枚举与简单的const常量相比孰优孰劣, 通过以下一段代码. 一看便知: [cpp] view plaincopyprint? enum {input, output, append}; const int input = 0; const int output = 1; const int append = 2; enum {input, output, append}; const int input = 0;

C++ Primer 学习笔记_3_变量和基本类型

 变量和基本类型 引言: 1.各种程序设计语言都具有许多各具特色的特征,这些特征决定了用每种语言适合开发哪些类型的应用程序. 2.大多数现代现代程序设计语言都采用两种方式扩充语言的基本特征集:允许程序员通过自定义数据类型扩充该语言:提供一组库例程,这些例程定义了一些并非内置在语言中的实用函数和数据类型. 3.C++是静态类型语言,支持在编译时执行类型检查. 4.包括C++在内的其他语言允许程序员定义的类型不仅有数据还包含操作! 5.掌握C++的第一步就是学习语言的基本知识和标准库! 6.类型

C++ Primer 学习笔记_4_变量和基本类型(续1)

 变量和基本类型 四.const限定符 [cpp] view plaincopyprint? #include <iostream> int main() { //for循环语句存在两个问题 for (int index = 0;index != 512; ++index) { //... } return 0; } /* *1.程序的可读性:存在魔数512[魔数:他的意义在上下文中并没有体现出来,好像这个数是魔术般变出来的] *2.程序的可维护性... */ #include <i

Lex与Yacc学习(三)之符号表

符号表 列举单词表的方式虽然简单但是不全面,如果在词法分析程序运行时可以构建一个单词表,那么就可以在添加新的单词时不用修改词法分析程序. 下面示例便利用符号表实现,即在词法分析程序运行时从输入文件中读取声明的单词时允许动态的声明单词.声明以词性的名字开始,后面跟着要声明的单词. 添加符号表可以完全的改变词法分析程序,不必在词法分析程为每个要匹配的单词放置独立的模式,只要有一个匹配任意单词的模式,再查阅符号表就能决定所找到的词性. lex程序ch1-04.l %{ /* *带符号表的词法分析程序

Lex与Yacc学习(九)之Yacc语法

Yacc语法 本文讨论yacc语法的格式并描述可用的各种特征和选项 yacc语法结构 yacc语法包括三部分:定义段.规则段和用户子例程段 ...定义段... %% ...规则段... %% ...用户子例程段... 各部分由以两个百分号开头的行分开,尽管某一个部分可以为空,但是前两部分是必须的,第三部分和前面的百分号可以省略. 符号 yacc 语法由符号组成,即语法的"词".符号是一串不以数字开头的字母.数字.句点和下划线.符号error专用于错误恢复,另外,yacc对任何符号都不会

Lex与Yacc学习(七)之环境配置另一种方式

必备工具 flex-2.5.4a-1.exe   和  bison-2.4.1-setup.exe   以及 cygwin2.738 的安装文件,下载地址 http://download.csdn.net/detail/fly_yr/8385245 flex与bison安装 运行flex-2.5.4a-1.exe  和  bison-2.4.1-setup.exe 文件安装至D:\Software Files\GnuWin32下,然后按配置环境变量: 将路径 D:\Software Files\

Lex与Yacc学习(四)之Lex规范

Lex规范的结构 lex程序由三部分组成:定义段.规则段和用户子例程序段 ...定义段... %% ...规则段... %% ...用户子例程序段... 这些部分由以两个百分号组成的行分隔开.尽管某一部分可以为空,但前两部分是必须的,第三部分和前面的%%行可以忽略. 定义段 定义段包括文字块.定义.内部表声明.起始条件和转换. 以空白开头的行被逐字拷贝到C文件中,通常,这用于包含包围在/*和*/中的注释,一般前面有空白. 规则段 规则段包含模式行和C代码,以空白开始的行或者包围在%{和%}中的内

Lex与Yacc学习(五)之正则表达式篇

正则表达式语法 lex模式是由编辑程序和实用程序使用的正则表达式的扩展版本.正则表达式由常规字符(代表它们本身)和元字符(在一种模式中具有特殊含义)组成. 元字符 . . 匹配除了换行符 \n 之外的任意单个字符 [] [] 匹配括号中字符的任意一个.用"-"(短划线)指示字符的范围,例如[0-9]指10个数字中的任意一个.如果开括号之后的第一个字符是短划线或者闭括号,那么它就不能被解释为元字符.如果第一个字符是抑扬字符" ^ ",那么它的含义就变为匹配括号内字符以