从头开始搭建算术表达式解析器,第一部分

本文介绍了一个用C++实现的表达式解析和运算系统,支持变量、函数及多种运算符。通过定义不同的结构体来处理数值、变量、单参数函数、双参数函数和赋值操作,并使用二叉树而非后缀表达式数组来组织表达式。

我几年前初学C++的时候,曾经花了很长时间实现了表达式的解析和运算,支持函数和变量,还可以进行求导等操作,是我比较得意的成果,现在一翻看,却觉得满头雾水,大概是当初没有注释的习惯,又习惯于把大段大段的代码都塞在一个函数里吧。

这次决定重新进行一次实现,算是复习一下语法,也会使用一些最近才掌握的技巧。

这个文件用来声明所需的各种数据类型,我采用虚函数来实现运算,也就是说数值和变量也有求值运算。可以看到我用了联合来节省空间。

不打算使用后缀表达式数组来计算,而使用二叉树,二叉树的好处是,如果需要可以方便的实现懒惰求值、求导。当然这个就不打算这么做了,只是复习么。

/*
0	1	2	3	4	5	6	7	8	9
左括号	逗号	右括号	数值	变量	函数1p	函数2p	算符1p	算符2p	赋值符
*/

typedef double  *Addrs;
typedef double (*Fun1p)(double);
typedef double (*Fun2p)(double,double);

enum AtomType{Is_Empty,Is_Lquot,Is_Comma,Is_Rquot,Is_Value,Is_Param,Is_Fun1p,Is_Fun2p,Is_Opr1p,Is_Opr2p,Is_Setvr};

struct myFac
{
	union
	{
		char opr[8];
		double *adr;
		double  vlu;
		Fun1p   fc1;
		Fun2p   fc2;
	};
	virtual double get()
	{
		return 0;
	}
	virtual double run(double x)
	{
		return 0 && x;
	}
	virtual double run(double x,double y)
	{
		return 0 && x && y;
	}
	virtual double set(double &x,double y)
	{
		return 0 && x && y;
	}
};
struct myValue:myFac
{
	virtual double get()
	{
		return vlu;
	}
};
struct myParam:myFac
{
	virtual double get()
	{
		return *adr;
	}
};
struct myOpr1p:myFac
{
	virtual double run(double x)
	{
		switch(opr[0])
		{
			case '+':return x;
			case '-':return -x;
			case '!':return x?0:1;
			case '#':return x?1:0;
			case '$':return x<0?-x:x;
			case '@':return x<0?-1:x>0?1:0;
		}
		return 0;
	}
};
struct myFun1p:myFac
{
	virtual double run(double x)
	{
		return fc1(x);
	}
};
struct myOpr2p:myFac
{
	virtual double run(double x,double y)
	{
		switch(opr[0])
		{
			case '+':return x+y;
			case '-':return x-y;
			case '*':return x*y;
			case '/':return x/y;
			case '=':return x==y;
			case '!':return x!=y;
			case '&':return (bool)x && (bool)y;
			case '|':return (bool)x || (bool)y;
			case '>':return (opr[1]=='=')?(x>=y):(x>y);
			case '<':return (opr[1]=='=')?(x<=y):(x<y);
		}
		return 0;
	}
};
struct myFun2p:myFac
{
	virtual double run(double x,double y)
	{
		return fc2(x,y);
	}
};
struct mySetvr:myFac
{
	virtual double set(double x,double y)
	{
		switch(opr[0])
		{
			case '=':x=y;break;
			case '+':x+=y;break;
			case '-':x-=y;break;
			case '*':x*=y;break;
			case '/':x/=y;break;
		}
		return x;
	}
};
struct Atom
{
	AtomType type;
	myFac   *data;
	Atom    *Lsun;
	Atom    *Rsun;
	Atom()
	{
		type=Is_Empty;
		data=NULL;
		Lsun=NULL;
		Rsun=NULL;
	}
	~Atom()
	{
		if(data)delete data;
	}
};
void Remove(Atom *(&root))
{
	if(root)
	{
		Remove(root->Lsun);
		Remove(root->Rsun);
		delete root;
		root=NULL;
	}
}
struct Lequ
{
	Atom *equ;
	Lequ *lst;
	Lequ *nxt;
	Lequ()
	{
		equ=NULL;
		lst=NULL;
		nxt=NULL;
	}
	~Lequ()
	{
		if(equ)Remove(equ);
	}
};
void Remove(Lequ *(&root))
{
	Lequ *sp,*md;
	sp=root;
	while(sp)
	{
		md=sp->nxt;
		delete sp;
		sp=md;
	}
}


转载于:https://my.oschina.net/liudiwu/blog/83611

毕业论文引言 随着计算机技术的发展普及,计算机已经成为各行业最基本的工具之一,迅速进入千家万户。因此,掌握计算机应用的基本技能成为新世纪人才不可缺少的基本素质之一。为使计算机能正常工作, 除了构成计算机各个组成部分的物理设备外, 一般说来, 还必须要有指挥计算机“做什么”和“如何做”的“程序”。程序及其有关文档构成计算机软件, 其中用以书写计算机软件的语言称为计算机程序设计语言。 1 计算机程序设计语言简介 计算机程序设计语言是计算机可以识别的语言,用于描述解决问题的方法,供计算机阅读和执行,通常简称为编程语言,是一组用来定义计算机程序的语法规则。它是一种被标准化的交流技巧,用来向计算机发出指令。一种计算机语言让程序员能够准确地定义计算机所需要使用的数据,并精确地定义在不同情况下所应当采取的行动。使用程序设计语言往往使程序员能够比使用机器语言更准确地表达他们所想表达的目的。对那些从事计算机科学的人来说,懂得程序设计语言是十分重要的,因为所有的程序都需要程序设计语言才能完成,而计算机的工作是用程序来控制的,离开了程序,计算机将一事无成。 2 开发背景及意义 现有计算器不能计算表达式,这是一个缺陷,为此,开发了一个能直接计算表达式的计算器,这为计算提高了更大的方便,可以大幅度提高计算效率。 第二章 第三章 第一节 递归下降法的描述 3.1.1实现思想 它的主要原理是,对每个非终极符按其产生式结构构造相应语法分析子程序,其中终极符产生匹配命令,而非终极符则产生过程调用命令。因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。其中子程序的结构产生式结构几乎是一致的。文法中每个非终结符对应一个递归过程(子程序),每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选式时能够按LL(1)形式可唯一地确定选择某个候选式进行推导。 3.1.2算法的特点 递归下降法是语法分析中最易懂的一种方法。递归下降法要满足的条件:假设A的全部产生式为Aα1|α2|……|αn ,则必须满足如下条件才能保证可以唯一的选择合适的产生式 predict(Aαi)∩predict(Aαj)=Φ,当i≠j. 3.1.3构造递归下降语法分析程序 采用了递归子程序方法进行语法分析,对文法中的每个非终极符号按其产生式结构产生相应的语法分析子程序,完成相应的识别任务。其中终结符产生匹配命令,非终结符则产生调用命令。每次进入子程序之前都预先读入一个单词。因为使用了递归下降方法,所以程序结构和层次清晰明了,易于手工实现,且时空效率较高。实际的语法分析工作,从调用总程序的分析子程序开始,根据产生式进行递归调用各个分析子程序。 第二节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值