📄 cal.c
字号:
//数学计算//
#include <CsAgb.h>
#include <variable.h>
#include <rb_stdio.h>
#include <rb_math.h>
#include <tree.h>
#include <math.h>
#include <rbasic.h>
#include <rb_string.h>
#include <strpro.h>
#define mathend 26
#define strpsta 27
const u8 rb_pri[7]={0,1,1,2,2,2,3};//运算优先级
double rb_cal(char *exp);
extern double math_fun(u8 id,char *par);
double strn_fun(u8 id,char *exp);
u8 is_opt(char ch)//是否为运算符
{
char opts[]="+-*/%^";
u8 i;
for (i=0;i<6;i++) if (ch==opts[i]) return i+1;//返回运算符代码
return 0;
}
u8 is_sbl(char ch)//是否为变量标识符
{
return (ch=='#' || ch=='$');
}
void exp_adj(char *exp)//表达式调整(去除首尾无用空白)
{
u8 i=0;
u8 start=0;
while (exp[start]==' ') start++;
if (start)
{
while (exp[start]!='\0')
{
exp[i]=exp[start];
i++;
start++;
}
exp[i]='\0';
}
i=str_len(exp)-1;
while (exp[i]==' ') i--;
exp[i+1]='\0';
}
/*u8 exp_check(char *exp)//表达式词法检测(括号的匹配与字符的检查,有误返回1)
{
u8 i=0;
u8 is_error=0;
int count=0;
int count1=0;
while (exp[i]!='\0')
{
if (exp[i]=='(') count++;
else if(exp[i]==')') count--;
else if(exp[i]=='[') count1++;
else if(exp[i]==']') count1--;
else
{
is_error=is_letter(exp[i])||is_number(exp[i])||is_opt(exp[i])||
is_sbl(exp[i])||exp[i]==' '||exp[i]==','||exp[i]=='\"'||exp[i]=='_'
||exp[i]=='.';
is_error=!is_error;
}
if (is_error) return 1;
if (count<0) return 1;//括号不配对
i++;
}
if (count || count1) return 1;
return 0;
}
*/
u8 get_word_type(char *exp)//获得单词类型(初步分类并不验证)
{
u8 len;
u8 type=0;
exp_adj(exp);
len=str_len(exp);
if (len==0) return 0;//错误!
type=is_opt(exp[0]);
if (len==1 && type) return type;//是运算符号,返回运算符代号
if (exp[0]=='(' && exp[len-1]==')') return 10;//是表达式
if (exp[len-1]==')') return 20;//是函数
if (is_number(exp[0]) || exp[0]=='-') return 30;//是数字
if (exp[len-1]==']') return 40;//是数组
return 50;//是变量名
}
u8 word_is_num(char *exp)//检查数字格式是否正确
{
u8 i=0;
u8 dot=0;
u8 index=0;
while (exp[i]!='\0')
{
if (exp[i]=='-')
{
if (!(i==0 || exp[i-1]=='e' || exp[i-1]=='E')) return 0;//非法符号
}
else if (exp[i]=='.') dot++;
else if (exp[i]=='e' || exp[i]=='E') {dot=(dot?dot:1);index++;}
else if (!is_number(exp[i])) return 0;
if (dot>1 || index>1) return 0;
i++;
}
if(!is_number(exp[i-1])) return 0;
return 1;//OK
}
double get_val(char *exp)//取得数值
{
u8 type=get_word_type(exp);
u8 len;
u8 vt=0;
u8 funid=0;
char fun[10];
switch(type)
{
case 50://是变量名
exp_adj(exp);
len=str_len(exp);
if (len==0 || exp[len-1]=='$' ||(len==1 && is_sbl(exp[0])))//空的变量名
{
rb_error=6;
return 0.0;
}
if (exp[len-1]=='#')//为整形变量
{
vt=1;
exp[len-1]='\0';
}
/*if (check_var_name(exp))//非法的变量名
{
rb_error=22;
return 0.0;
}*/
if (vt) return rb_get_int(exp);
return rb_get_float(exp);//取变量值
break;
case 30://是数字
if (word_is_num(exp)) return str_to_num(exp);
else
{
rb_error=6;
return 0.0;
}
break;
case 10://是表达式
len=str_len(exp);
exp[len-1]='\0';
exp[0]=' ';
return rb_cal(exp);
break;
case 20://函数调用
len=0;
while(exp[len]!='(' && exp[len]!='\0')//获得函数名
{
fun[len]=exp[len];
exp[len]=' ';
len++;
}
if (exp[len]!='(')//语法错误
{
rb_error=6;
return 0.0;
}
fun[len]='\0';
exp_adj(fun);
str_up(fun);
funid=is_keyword(rb_math_key,fun);
if (funid==0) {rb_error=6;return;}//找不到对应的数学函数
exp_adj(exp);
len=str_len(exp);
exp[0]=' ';
exp[len-1]=' ';
if (funid<=mathend) return math_fun(funid,exp);
return strn_fun(funid-strpsta+1,exp);
break;
case 40://数组的处理
len=0;
while(exp[len]!='[' && exp[len]!='\0')
{
fun[len]=exp[len];
exp[len]=' ';
len++;
}
if (exp[len]!='[' || len==0)//不配对
{
rb_error=6;
return 0.0;
}
vt=0;
if(fun[len-1]=='#')
{
vt=1;
fun[len-1]='\0';
}
else fun[len]='\0';
/*if(check_var_name(fun))//非法变量名
{
rb_error=22;
return 0.0;
}*/
exp[len]=' ';
len=str_len(exp);
exp[len-1]='\0';
exp_adj(exp);
len=(u8)rb_cal(exp);
if (vt) return rb_get_int_dim(fun,len);
return rb_get_float_dim(fun,len);
default://其它情况均视为语法错误
rb_error=6;
return 0.0;
}
}
double rb_cal(char *exp)//计算表达式的值
{
char temp[com_max_len];//单词暂存
u8 len=0;//单词长度
double value[12];//数据寄存器
u8 type[12];//数据类型(0-Num,1-Opt)
u8 tcp=0;//指针
u8 i=0;
u8 opt=0;
u8 flag;
u8 istr;
exp_adj(exp);
if (exp[0]=='-')
{
i++;
temp[0]='-';
len++;
}
while(exp[i]!='\0')
{
opt=is_opt(exp[i]);
if (exp[i]=='(')//括号配对
{
flag=1;
temp[len]=exp[i];
len++;
i++;
istr=0;
while(flag && exp[i]!='\0')
{
if (exp[i]=='(' && istr==0) flag++;
else if(exp[i]==')' && istr==0) flag--;
temp[len]=exp[i];
if (exp[i]=='\"') istr=!istr;
len++;
i++;
}
if (flag)//不配对
{
rb_error=6;
return 0.0;
}
}
else if(exp[i]=='[')//[]配对
{
flag=1;
istr=0;
temp[len]=exp[i];
len++;
i++;
while(flag)
{
if (exp[i]=='[' && istr==0) flag++;
else if(exp[i]==']' && istr==0) flag--;
temp[len]=exp[i];
if (exp[i]=='\"') istr=!istr;
len++;
i++;
}
if (flag)
{
rb_error=6;
return 0.0;
}
}
else if (opt)//是运算符
{
if (i==0 || is_opt(exp[i-1]))//语法错误
{
rb_error=6;
rb_say_error("SYNTAX ERROR!");
return 0;
}
temp[len]='\0';
len=0;
value[tcp]=get_val(temp);
type[tcp]=0;
tcp++;
if (tcp>2)//检查是否可先行运算
{
if (rb_pri[opt]<=rb_pri[type[tcp-2]])//先行运算
{
switch(type[tcp-2])//+-*/%^
{
case 1://+
value[tcp-3]=value[tcp-3]+value[tcp-1];
break;
case 2://-
value[tcp-3]=value[tcp-3]-value[tcp-1];
break;
case 3://*
value[tcp-3]=value[tcp-3]*value[tcp-1];
break;
case 4:///
if (value[tcp-1]==0.0)//除零
{
rb_error=23;
return 0.0;
}
value[tcp-3]=value[tcp-3]/value[tcp-1];
break;
case 5://%
value[tcp-3]=(int)value[tcp-3]%(int)value[tcp-1];
break;
case 6://^
value[tcp-3]=pow(value[tcp-3],value[tcp-1]);
break;
}
tcp=tcp-2;
}
}
type[tcp]=opt;
tcp++;
i++;
}
else
{
temp[len]=exp[i];
len++;
i++;
}
}
if (is_opt(exp[i-1]))//非法的运算符结束
{
rb_error=6;
rb_say_error("SYNTAX ERROR.");
return 0.0;
}
temp[len]='\0';
value[tcp]=get_val(temp);
if (tcp==0) return value[0];
tcp--;
i=1;
while(i)
{
switch(type[tcp])
{
case 1://+
value[tcp-1]=value[tcp-1]+value[tcp+1];
break;
case 2://-
value[tcp-1]=value[tcp-1]-value[tcp+1];
break;
case 3://*
value[tcp-1]=value[tcp-1]*value[tcp+1];
break;
case 4:///
if (value[tcp+1]==0.0)//除零
{
rb_error=23;
return 0.0;
}
value[tcp-1]=value[tcp-1]/value[tcp+1];
break;
case 5://%
value[tcp-1]=(int)value[tcp-1]%(int)value[tcp+1];
break;
case 6://^
value[tcp-1]=pow(value[tcp-1],value[tcp+1]);
break;
}
if (tcp==1) i=0;
else tcp=tcp-2;
}
return value[0];//返回运算结果
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -