我是靠谱客的博主 超级故事,这篇文章主要介绍C语言 科学计算器 后缀表达式 解析字符串 仿JS的eval函数C语言 利用后缀表达式解析字符串,现在分享给大家,希望可以做个参考。

C语言 利用后缀表达式解析字符串

最近用98标准的C语言写了个解析字符串,类似于JavaScript中的eval函数,感觉挺实用(移植到了计算器上,可以画F(X,Y)==0这种图像了),特此分享一下,大家可以使用。

感谢这篇文章给的启发,不会转后缀表达式的可以看看这篇,写的很详细
https://www.cnblogs.com/chenying99/p/3675876.html

源代码在最底下!

功能就是:接受一个字符串(char*)表达式,返回表达式计算结果,float

1、支持的函数

逻辑表达式:

>,<,==(注意是双等于号),<=,>=,&(and),|(or),~(not)

数学运算符:

+,-,*,/,%(求模),^(乘方),!(阶乘),#(负号,一般会自动区分负号和减号)

符号:

括号,逗号

函数:

三角函数 sin(x) cos(x) tan(x) asin(x) acos(x) atan(x)
如果不在定义域则返回0

随机数 rand(x,y)(返回[x,y]间的整数,需要srand)

弧度转角度 deg(x) 角度转弧度 rad(x)

条件表达式 if(条件,x,y),其中当x非0,则返回表达式x的值,否则返回表达式y的值

对数 log(x,y)返回以x为底y的对数 ln(x)返回以e为底的自然对数

自然数的n次方 exp(x),返回e^x

最大最小值 max(x,y)返回表达式x和表达式y的较大的一个,min相反

取符号 sign(x) 如果x大于等于0,返回1,否则返回-1

四舍五入 round(x) 向下取整 floor(x)

绝对值 abs(x) 返回x的绝对值

开平方 sqrt(x) 返回x开平方的值
开n次方可以用运算符“ ^ ”代替

2、用法

#include<eval.c>
很简单,就一行
直接调用double eval(char* str);
其中str为表达式,以’ '结束

3、效果

计算0.5+6+3*5的结果为21.5
中间两行分别是中缀表达式和后缀表达式
在这里插入图片描述
计算sin(1.57)+cos(if(1>0,0,1))的结果为2.0(三角函数的精度不太好,凑合吧)
其中if(1>0,0,1),if函数接受3个参数,第一个参数是条件,显然条件成立,返回第二个参数(表达式)的结果的值,就是0,即计算sin(1.57)+cos(0)
在这里插入图片描述
注意到:sin在中缀表达式和后缀表达式被替换为了J
cos被替换为了K。
因为注意到单字符的方便性,就用replaceString()函数替换为单字符大写字符。所以,要注意不用让用户输入大写字母!
中间两行输出可以在代码中注释掉。

附几张移植到计算器上的解析字符串效果图
(画复杂函数图像的,例如sin(X)<cos(Y)这种函数的图像)

4、思路

这里我用例子解释。
假如用户输入“-sin(12.57)-cos(-6)”
规定:如果减号“-”出现在符号后面(不包括右括号)或者出现在字符串开头,就替换为负号“#”,负号是一元运算符,减号是二元运算符,所以有必要区分。
故原字符串被替换为“#sin(12.57)-cos(#6)”
由于sin,cos是多字符不好处理,则替换为单字符(这里我用A-Z),故替换为“#J(12.57)-K(#6)”
接下来只需要区分是符号还是数字即可。

读入#是符号
读入J是符号
读入(是符号(以上都是转后缀表达式的标准操作,不再赘述,详细可见开头推荐的博客)
读入1是数字,不确定是不是一个完整的数字,则存在number里,
读入2是数字,将原来的number*10+2。
读入.表明接下来的数字是小数部分了。
读入5,number+=pow(10,-1)*5
读入7,number+=pow(10,-2)*7
当读入符号或者到字符串末尾时,讲存的数字保存下来,并且清空。
以此类推

这样子符号和数字就被区分开了,并且转为后缀表达式了。
接下来就只需要运行后缀表达式的求值和控制好优先级了。
因为我这个算法的特殊性,以下的奇葩写法也能计算出正确结果:

sin7
7sin
(7)sin

如有需要,请读者自行编写语法分析。

5、源代码(符合c98标准)

详细请阅读代码中的注释

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
#include <stdio.h> #include <math.h> #include <string.h> #include <stdlib.h> /** * Developed by sandyz987 * Function 'eval' * @param Expression string (chars' length <= MAX_SIZE) * @return Answer : double * @isError 0:no error 1:wrong number of decimal points 2:can't get top item at an empty stack 3:can't pop item at an empty stack(number of brackets is invalid?) * 4:can't get priority 5:too many arguments 6:unexpect character 7:wrong number of arguments 8:math error */ #define PI 3.141592653 #define MAX_SIZE 1024 #define MAX_SIGN_NUM 26 #define MIN_NUM 1.0e-7 char *functionName[MAX_SIGN_NUM] = {">=", "<=", "!=", "==", ">", "<", "asin", "acos", "atan","sin", "cos", "tan", "rand", "deg", "if", "rad", "log", "ln", "exp", "min", "max", "sign", "round", "floor", "abs", "sqrt"}; char nameTran[MAX_SIGN_NUM] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; int namePriority[MAX_SIGN_NUM] = {2,2,2,2,2,2,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8};//function's priority int nameArgNum[MAX_SIGN_NUM] = {2,2,2,2,2,2,1,1,1,1,1,1,2,1,3,1,2,1,1,2,2,1,1,1,1,1};//Number of arguments char operator[] = {'+','-','*','/','^','!','%','(',')',',','&','|','~','#'}; int priority[] = {3,3,4,4,5,5,5,-4,-5,-1,1,0,5,8};//Operator' priority int operatorArgNum[] = {2,2,2,2,2,1,2,0,0,1,2,2,1,1};//Number of arguments //I didn't use the struct to build a stack because pointer can reduce readability. char operatorS[MAX_SIZE] = {0};//Operator stack int operatorSTop = -1; int isError = 0;//0=no error typedef struct sign{ int isOperator;//If isOperator == 0 use the num, else use the opera double num; char opera; } SIGN; SIGN signs[MAX_SIZE];int signsSize = 0;//To save the "infix expression" by using "struct SIGN" SIGN reverseSigns[MAX_SIZE];int reverseSignsSize = 0;//To save the "Postfix Expression" /* * Example: * if user input str = "1+2*3" * the signs(Stack) store 5 item : [isOperator=0,num=1,opera=''],[isOperator=1,num=0,opera='+'],[isOperator=0,num=2,opera=''],[isOperator=1,num=0,opera='*'],[isOperator=0,num=3,opera=''] * the reverseSigns(Stack) store 5 item : [isOperator=0,num=2,opera=''],[isOperator=0,num=3,opera=''],[isOperator=1,num=0,opera='*'],[isOperator=0,num=1,opera=''],[isOperator=1,num=0,opera='+'] */ int getPriority(char c){ int i; for(i = 0; i < sizeof(operator); i++){ if(operator[i] == c){ return priority[i]; } } for(i = 0; i < sizeof(nameTran); i++){ if(nameTran[i] == c){ return namePriority[i]; } } isError = 4; return 0; } void pushSignOpera(char c){ signs[signsSize].isOperator = 1; signs[signsSize].opera = c; signsSize++; } void pushSignNum(double n){ signs[signsSize].isOperator = 0; signs[signsSize].num = n; signsSize++; } void pushReverseOpera(char c){ reverseSigns[reverseSignsSize].isOperator = 1; reverseSigns[reverseSignsSize].opera = c; reverseSignsSize++; } void pushReverseNum(double n){ reverseSigns[reverseSignsSize].isOperator = 0; reverseSigns[reverseSignsSize].num = n; reverseSignsSize++; } void deleteReverseItem(int pos){ int i; for (i = pos + 1; i < reverseSignsSize; i++) { reverseSigns[i-1] = reverseSigns[i]; } reverseSignsSize--; } void insertReverseNum(int pos, double n){ int i; for (i = reverseSignsSize - 1; i >= pos; i--) { reverseSigns[i+1] = reverseSigns[i]; } reverseSigns[pos].isOperator = 0; reverseSigns[pos].num = n; reverseSignsSize++; } int isNumber(char c){ return (c>='0'&&c<='9')||(c=='.'); } int isOperator(char c){ int flag = 0,i; for(i = 0; i<sizeof(operator); i++){ if (c == operator[i]){ flag = 1; } } for(i = 0; i<sizeof(nameTran); i++){ if (c == nameTran[i]){ flag = 1; } } return flag; } void pushOpera(char opera){//Operator stack operatorS[++operatorSTop] = opera; } int isNotEmptyOperaS(){ return operatorSTop != -1; } char popOpera(){ return operatorS[operatorSTop--]; } char getTopOpera(){ if (operatorSTop != -1){ return operatorS[operatorSTop]; } else{ isError = 2; return ''; } } void replaceString(char s[], int pos, int len, char s1[]){//Replace the s from pos to len with s2 int i; char s2[1000]; int lenS1 = (int)strlen(s1); int lenS = (int)strlen(s); int j; //copy s to s2 and clear the s for (i = 0; i < lenS; i++) { s2[i] = s[i]; } memset(s,'',sizeof(*s)); for (i = 0; i < pos; ++i) { s[i] = s2[i]; } for (i = pos; i < pos + lenS1; i++) { s[i] = s1[i - pos]; } j = pos + lenS1; for (i = pos + len; i < lenS; i++){ s[j++] = s2[i]; } s[j] = ''; } void tranString(char s[]){//Format string. For example "sin(3.14)+abs(-1)" is format to "J(3.14)+Y(-1)" int pos = 0; int i; while (pos < strlen(s)){ for (i = 0; i < MAX_SIGN_NUM; i++) { if(pos + (int)strlen(functionName[i]) <= (int)strlen(s)){ char tmp[20]; memset(tmp,'',sizeof(tmp)); strncpy(tmp,s + pos ,strlen(functionName[i])); if(strcmp(functionName[i], tmp) == 0){ char tmpChar[2] = {'', ''}; tmpChar[0] = nameTran[i]; replaceString(s, pos, (int)strlen(functionName[i]), tmpChar); } } } pos++; } if(s[0] == '-'){//decide whether the '-' is '#' char tmpChar[2] = {'#', ''}; replaceString(s, 0, 1, tmpChar); } pos = 1; while (pos < strlen(s)){//decide whether the '-' is '#' if(isOperator(s[pos - 1]) && s[pos] == '-' && s[pos-1]!=')'){ char tmpChar[2] = {'#', ''}; replaceString(s, pos, 1, tmpChar); } pos++; } } int getOperaArgNum(char op){//Get operator's number of arguments. int i; for (i = 0; i < sizeof(nameTran); ++i) { if(nameTran[i] == op){ return nameArgNum[i]; } } for (i = 0; i < sizeof(operator); ++i) { if(operator[i] == op){ return operatorArgNum[i]; } } isError = 6; return 0; } int long fact(int n){//return the number's factor if (n < 0) return -1; if (n > 1) return fact(n - 1) * n; else return n; } double calculate(double *n, char op, int num){//Arguments are in *n. op is the operator. num is the number of arguments switch (op) { case ',': return n[num - 1]; case '#': return -n[num - 1]; case '+': return n[num - 1] + n[num - 2]; case '-': return n[num - 1] - n[num - 2]; case '*': return n[num - 1] * n[num - 2]; case '/': return n[num - 2] != 0 ? n[num - 1] / n[num - 2] : (isError = 8, 0); case '%': return (double)((int)n[num - 1] % (int)n[num - 2]); case '^': return pow(n[num - 1] , n[num - 2]); case '!': return fact((int)n[num - 1]); case '&': return fabs(n[num - 1]) >= MIN_NUM && fabs(n[num - 2]) >= MIN_NUM; case '|': return fabs(n[num - 1]) >= MIN_NUM || fabs(n[num - 2]) >= MIN_NUM; case '~': return fabs(n[num - 1]) <= MIN_NUM; case 'A': return n[num - 1] >= n[num - 2]; case 'B': return n[num - 1] <= n[num - 2]; case 'C': return fabs(n[num - 1] - n[num - 2]) >= MIN_NUM; case 'D': return fabs(n[num - 1] - n[num - 2]) <= MIN_NUM; case 'E': return n[num - 1] > n[num - 2]; case 'F': return n[num - 1] < n[num - 2]; case 'G': return n[num - 1] <= 1 && n[num - 1] >= -1 ? asin(n[num - 1]) : (isError = 8, 0); case 'H': return n[num - 1] <= 1 && n[num - 1] >= -1 ? acos(n[num - 1]) : (isError = 8, 0); case 'I': return atan(n[num - 1]); case 'J': return sin(n[num - 1]); case 'K': return cos(n[num - 1]); case 'L': return tan(n[num - 1]); case 'M': return n[num - 1] >= 0 && n[num - 2] >= 0 && n[num - 2] - n[num - 1] >= 1 ? (rand() % ((int)n[num - 2] - (int)n[num - 1]) + 1) + (int)n[num - 1] : (isError = 8, 0); case 'N': return n[num - 1] / PI * 180.0; case 'O': return fabs(n[num - 1]) >= MIN_NUM ? n[num - 2] : n[num - 3] ; case 'P': return n[num - 1] / 180.0 * PI; case 'Q': return n[num - 1] != 1 && n[num - 1] > 0 && n [num - 2] > 0 ? log(n[num - 2]) / log(n[num - 1]) : (isError = 8, 0); case 'R': return n[num - 1] > 0 ? log(n[num - 1]) : (isError = 8, 0); case 'S': return exp(n[num - 1]); case 'T': return n[num - 1] <= n[num - 2] ? n[num - 1] : n[num - 2]; case 'U': return n[num - 1] <= n[num - 2] ? n[num - 2] : n[num - 1]; case 'V': return n[num - 1] >= 0 ? 1 : -1; case 'W': return (double)(int)(n[num - 1] + 0.5); case 'X': return (double)(int)(n[num - 1]); case 'Y': return n[num - 1] >= 0 ? n[num - 1] : - n[num - 1]; case 'Z': return n[num - 1] >= 0 ? sqrt(n[num - 1]) : (isError = 8, 0) ; default://not find the operator isError = 6; return 0.0f; } } void calculateOpera(char op, int pos){//Change the reverseSigns(stack) when calculating int num = getOperaArgNum(op); int i; double n[10] = {0}; int size = 0; double ans; if (pos >= num){ for (i = 0; i < num; ++i) { if(reverseSigns[pos - 1 - i].isOperator != 1){ n[size++] = reverseSigns[pos - 1 - i].num; } else{ isError = 7; break; } deleteReverseItem(pos - i); } deleteReverseItem(pos - i); ans = calculate(n, op, num); insertReverseNum(pos - num, ans); }else { isError = 7; } } double eval(char s[]){ double number = 0; int numberUsed = 0; int numberPoint = 0; int i; operatorSTop = -1; signsSize = 0; reverseSignsSize = 0; srand(0);//set srand! isError = 0; //tranString(s); !!!!You must decide whether use "tranString" function here or before eval() execute. Because tranString() use too much time. while(*s != ''){ if (isNumber(*s)){ numberUsed = 1; if (*s == '.'){ if (numberPoint != 0){ isError = 1; } numberPoint = 1; s++; continue; } if(numberPoint == 0){ number *= 10.0; number += *s - '0'; }else{ number += pow(10,-(numberPoint++)) * (*s - '0'); } } if (isOperator(*s)){ if (numberUsed == 1){ numberUsed = 0; pushSignNum(number); number = 0; numberPoint = 0; } pushSignOpera(*s); } s++; } if(numberUsed != 0){ pushSignNum(number); } if(isError){ return 0.0f; } //start calculating the sign stack for(i = 0; i < signsSize; i++){ SIGN sign = signs[i]; if(sign.isOperator != 1){ //is number pushReverseNum(sign.num); }else{ //is operator if(sign.opera == '('){ pushOpera(sign.opera); }else if(sign.opera == ')'){ while(getTopOpera() != '('){ if(isNotEmptyOperaS()){ pushReverseOpera(popOpera()); } else{ isError = 3; break; } } if(isNotEmptyOperaS()){ popOpera(); } }else{ while(isNotEmptyOperaS() && getPriority(getTopOpera()) >= getPriority(sign.opera)){ pushReverseOpera(popOpera()); } pushOpera(sign.opera); } } } while (isNotEmptyOperaS()){ char tmp = popOpera(); if(tmp != '(' && tmp != ')'){ pushReverseOpera(tmp); } } //===========================up --This code block is to test print the "infix expression" and the "Postfix Expression" // for(i = 0; i < signsSize; i++){ // if(!signs[i].isOperator){ // printf("%f,",signs[i].num); // }else{ // printf("%c,",signs[i].opera); // } // } // printf("n"); // for(i = 0; i < reverseSignsSize; i++){ // if(!reverseSigns[i].isOperator){ // printf("%f,",reverseSigns[i].num); // }else{ // printf("%c,",reverseSigns[i].opera); // } // } // printf("n"); //============================down --This code block is to test print the "infix expression" and the "Postfix Expression" //start calculate the expression by reverse (Postfix) expression while(!isError){ int pos = -1; for (i = 0; i < reverseSignsSize; i++) { if(reverseSigns[i].isOperator == 1){ pos = i; break; } } if(pos == -1){ break; }else{ calculateOpera(reverseSigns[i].opera, pos); } } if(isError){ return 0.0f; } if(reverseSignsSize != 1){ isError = 5; return 0.0f; } else{ return reverseSigns[0].num; } } int main(){ char s[100]; scanf("%s",s); tranString(s); printf("%f",eval(s)); return 0; }

最后,如果我的文章帮到你了的话,欢迎收藏点赞关注,谢谢!

最后

以上就是超级故事最近收集整理的关于C语言 科学计算器 后缀表达式 解析字符串 仿JS的eval函数C语言 利用后缀表达式解析字符串的全部内容,更多相关C语言内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(77)

评论列表共有 0 条评论

立即
投稿
返回
顶部