主题:[讨论]我见过最牛B的程序
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// 任意输入一个数学函数的表达式,在输入自变量的值后,计算出数学函数表达式的值,这在很多情况下都会遇到。例如,一元函数y=2sinx+1,求x=5时的函数值y;或二元函数z=3cos(x+1)+y,求x=2,y=3时的函数值z;或三元函数q=2x+3y+sin(z+2x), 求x=1,y=2,z=3时的函数值q。
// 以下程序中的三个C函数float f(float x) 、float f(float x,float y)和float f(float x,float y,float z) 分别实现一元函数、二元函数和三元函数值的计算(因为这三个C函数的名字相同,都为f,只是参数个数不同,这用到了C++中函数重载的功能,所以要用C++编绎,即源程序文件的扩展名应取CPP)。
// 程序实现中用到了“编绎原理”中有关表达式编绎的知识,包括表达式的词法分析、语法分析和语义生成,有兴趣的读者请参阅有关书籍。
// 程序运行后,数学函数的输入格式采用C语言算术表达式的格式,例如对于一元函数y=2sinx+1,则输入2*sin(x)+1;对于二元函数z=3cos(x+1)+y,则输入3*cos(x+1)+y;对于三元函数q=2x+3(y-2)+sin(z+x),则输入2*x+3*(y-2)+sin(z+2*x)等等。
// 需要提醒读者注意的是,本程序的语法分析功能极其有限,仅仅提供了一个语法分析的C函数接口,有兴趣的读者可以自己添加语法分析代码。所以对错误的C语言表达式输入,大多不能报错。因此,使用时务必输入正确的C语言表达式。
// 下列程序是实现C语言算术表达式计算的函数,文件名取为 expressi .cpp。使用方式有二种,一是加入到读者的project 中;二是用 #include "expressi.cpp" 语句包含到读者的源程序文件中。本章的范例程序采用后者。所以,如果范例程序中有 #include "expressi.cpp" 语句,则读者应首先把以下程序输入到计算机中,并用文件名 expressi.cpp 存盘。
//
//////////////////////////////////////////////////////////////////////////////////////////////////
//计算C语言算术表达式程序,用于一元或多元函数值的计算
//
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <string.h>
#define ADD 0xff01
#define SUB 0xff02
#define MUL 0xff03
#define DIV 0xff04
#define LEFT_PARENTHESES 0xff05
#define RIGHT_PARENTHESES 0xff06
#define COMMA 0xff07
#define ADD1 0xff07
#define SUB1 0xff08
#define EQU 0xff09
#define SIN 0xff10
#define COS 0xff11
#define TAN 0xff12
#define ASIN 0xff13
#define ACOS 0xff14
#define ATAN 0xff15
#define EXP 0xff16
#define LOG 0xff17
#define POW 0xff18
#define SQRT 0xff19
#define FABS 0xff1a
#define FACTORIAL 0xff1b
#define MINUS 0xff1c
struct OPERATOR_FUNCTION_NAME_LIST{
char Name[32]; //操作符字符串名字
int Code; //代码
int Pri; //优先级
int NumOfOper; //操作数个数,即是几元操作符
}OF_Name[]={
{"+", 0xff01,1,2},
{"-", 0xff02,1,2},
{"*", 0xff03,2,2},
{"/", 0xff04,2,2},
{"(", 0xff05,4,0},
{")", 0xff06,0,0},
{",", 0xff07,0,0},
{"sin", 0xff10,3,1},
{"cos", 0xff11,3,1},
{"tan", 0xff12,3,1},
{"asin",0xff13,3,1},
{"acos",0xff14,3,1},
{"atan",0xff15,3,1},
{"exp", 0xff16,3,1},
{"log", 0xff17,3,1},
{"pow", 0xff18,3,2},
{"sqrt",0xff19,3,1},
{"fabs",0xff1a,3,1},
{"factorial", 0xff1b,3,1},
{"minus",0xff1c,5,1},
{"",0,0}
};
//阶乘函数
float Factorial(float n)
{
float Result,ftmp;
ftmp=n;
Result=1.;
while(ftmp>1.)
{
Result*=ftmp;
ftmp-=1.;
}
return(Result);
}
//表达式字符串中下一个单词长度
int NextWordLen(char e[])
{
int i;
if(e[0]=='+'||e[0]=='-'||e[0]=='*'||e[0]=='/'||
e[0]=='('||e[0]==')'||e[0]==',')
return 1;
else
{
i=0;
do{
++i;
}while(e[i]!='+'&&e[i]!='-'&&e[i]!='*'&&e[i]!='/'&&
e[i]!='('&&e[i]!=')'&&e[i]!=','&&e[i]!='\0');
return i;
}
}
//返回单词在操作符名字表中的下标值
int Check_OF_Name_List(char Word[])
{
int i;
i=0;
while(OF_Name[i].Name[0]!=0)
{
if(strcmp(Word,OF_Name[i].Name)==0)
return(OF_Name[i].Code); //注意,返回的是负数,请看前面OF_Name[i].Code中定义
++i;
}
return 1;
}
//返回单词在变量名表中下标,如果表中还没有,则加入这个单词
int CheckOrAddVarNameList(char Word[],char VarNameList[][32])
{
int i;
i=0;
while(VarNameList[i][0]!=0)
{
if(strcmp(Word,VarNameList[i])==0)
return(i);
++i;
}
strcpy(VarNameList[i],Word);
VarNameList[i+1][0]='\0';
return(i);
}
//格式化表达式,如单词用固定长的int数来表示
int GetFormated_C_Expression(char C_Expression[],int Fmt_C_Exp[],
char VarNameList[][32])
{
int i,i1,j,WordLen;
char Word[32];
i=0;
j=0;
while(C_Expression[i]!=0)
{
WordLen=NextWordLen(&C_Expression[i]);//取得下一个单词长度
strncpy(Word,&C_Expression[i],WordLen); //取出单词
Word[WordLen]='\0';
i1=Check_OF_Name_List(Word); //检查操作符表,返回下标
if(i1<0)
{ //单词是一个操作符
Fmt_C_Exp[j] = i1;
if(i1==SUB&&(Fmt_C_Exp[j-1]==LEFT_PARENTHESES||Fmt_C_Exp[j-1]==COMMA))
Fmt_C_Exp[j]=MINUS; // "-" 是不是一个负号而不是减号
}
else
Fmt_C_Exp[j]=CheckOrAddVarNameList(Word,VarNameList); //该单词是一个变量名,则放入变量名字表
++j;
i+=WordLen;//下一个单词起始位置
}
Fmt_C_Exp[j]=0xffff; //结束标志
return 0;
}
//返回操作符优先级
int OperNum(int Code)
{
int i;
i=0;
while(OF_Name[i].Code!=0)
{
if(Code==OF_Name[i].Code)
return(OF_Name[i].NumOfOper);
++i;
}
return 0;
}
//表达式是否符合C语言算术表达式,本函数有待改进,按理说用边词法分析边进行语法分析和检查
//比较好,但现在是事后分析一下有无错误,所以这一程序还不大经典。这是后来发现这一缺点。
int IsValidExpression(int Fmt_C_Exp[],char VarNameList[][32])
{
int i,Valid,Parentheses;
Parentheses=0;
Valid=0;
i=0;
while(Fmt_C_Exp[i]!=0xffff)
{
if(((Fmt_C_Exp[i]>=0xff01&&Fmt_C_Exp[i]<=0xff04)||Fmt_C_Exp[i]==MINUS)&&
(((Fmt_C_Exp[i-1]>=0xff01&&Fmt_C_Exp[i-1]<=0xff04)||Fmt_C_Exp[i-1]==MINUS)||
((Fmt_C_Exp[i+1]>=0xff01&&Fmt_C_Exp[i+1]<=0xff04)||Fmt_C_Exp[i+1]==MINUS)))
Valid=1;
if(Fmt_C_Exp[i]==LEFT_PARENTHESES)++Parentheses;
if(Fmt_C_Exp[i]==RIGHT_PARENTHESES)--Parentheses;
/*Other Invalid Case can be added here Or
rewrite this function at all by user!,
Otherwise,You must input a correct C_Expression!*/
/************************************/
++i;
}
if(Parentheses!=0)Valid=1;
return(Valid);
}
//返回优先数
int Pri(int Code)
{
int i;
i=0;
while(OF_Name[i].Code!=0)
{
if(Code==OF_Name[i].Code)
return(OF_Name[i].Pri);
++i;
}
return 0;
}
//实际得到4元组伪指令代码,用栈来实现的。
int GetOperatorSerials(int Fmt_C_Exp[],int OperatorSerials[][4],int VarP)
{
int OperP;
int i;
int O_Stack[200],O_P; //操作符栈
int V_Stack[200],V_P; //变量和常数栈
OperP=0;
O_P=0;
V_P=0;
i=0;
while(Fmt_C_Exp[i]!=0xffff)
{
if(Fmt_C_Exp[i]<2000&&Fmt_C_Exp[i]>=0)
{
V_Stack[V_P]=Fmt_C_Exp[i];
++V_P;
}
else
{
if(Fmt_C_Exp[i]!=LEFT_PARENTHESES)
while(O_P>0&&Pri(Fmt_C_Exp[i])<=Pri(O_Stack[O_P-1]))
{
if(O_Stack[O_P-1]==LEFT_PARENTHESES&&
Fmt_C_Exp[i]==RIGHT_PARENTHESES)
{
--O_P;
break;
}
if(O_Stack[O_P-1]!=LEFT_PARENTHESES)
{
switch(OperNum(O_Stack[O_P-1]))
{
case 0:
--O_P;
break;
case 1:
OperatorSerials[OperP][0]=O_Stack[O_P-1];
OperatorSerials[OperP][1]=V_Stack[V_P-1];
OperatorSerials[OperP][3]=VarP;
V_Stack[V_P-1]=VarP;
++VarP;
++OperP;
--O_P;
break;
case 2:
OperatorSerials[OperP][0]=O_Stack[O_P-1];
OperatorSerials[OperP][2]=V_Stack[V_P-1];
OperatorSerials[OperP][1]=V_Stack[V_P-2];
OperatorSerials[OperP][3]=VarP;
V_Stack[V_P-2]=VarP;
++VarP;
--V_P;
++OperP;
--O_P;
break;
}
}
else
break;
}
if(Fmt_C_Exp[i]!=RIGHT_PARENTHESES)
{
O_Stack[O_P]=Fmt_C_Exp[i];
++O_P;
}
}
++i;
}
OperatorSerials[OperP][0]=0;
return 0;
}
//变量名个数
int VarNameListLen(char VarNameList[][32])
{
int Length;
Length=0;
while(VarNameList[Length][0]!='\0') ++Length;
return(Length);
}
//生成4元组伪指令代码总程序
int MakeFunction(char C_Expression[],int OperatorSerials[][4],
char VarNameList[][32])
{
int Fmt_C_Exp[1000];
GetFormated_C_Expression(C_Expression,Fmt_C_Exp,VarNameList);
if(IsValidExpression(Fmt_C_Exp,VarNameList))return 1;
GetOperatorSerials(Fmt_C_Exp,OperatorSerials,VarNameListLen(VarNameList));
return 0;
}