鱼C论坛

 找回密码
 立即注册
查看: 1373|回复: 1

[已解决]算术表达式求值(10以内整数)

[复制链接]
发表于 2022-4-29 17:21:07 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
【问题描述】假设一算术表达式的所有操作数均为10以内的整数,请编写代码实现表达式求值。

假设算术表达式满足:

(1) 小括号已匹配;

(2) 表达式无除0错误;

(3) 表达式中间没有多余的空格。

要求: 表达式计算的中间值可以是负数或者实数

【输入形式】第一行输入表达式字符串
【输出形式】第二行输出计算结果(保留两位小数)
【样例输入】(4+1*(5-2))-6/3
【样例输出】5.00
最佳答案
2022-4-30 13:45:11
先贴代码
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <ctype.h>

  4. enum {EMPTY = 256, ERROR, OK, NUM};

  5. int symbol;
  6. double value;

  7. int symbol_;
  8. double value_;

  9. void back(void) {
  10.     symbol_ = symbol;
  11.     value_ = value;
  12. }

  13. void next(void) {
  14.     if(symbol_ != 0) {
  15.         symbol = symbol_;
  16.         value = value_;
  17.         symbol_ = 0;
  18.         return;
  19.     }
  20.     symbol = getchar();
  21.     switch(symbol) {
  22.         case ' ':
  23.         case '\t':
  24.         case '\v':
  25.         case '\f':
  26.             return next();
  27.     }
  28.     if(!isdigit(symbol)) return;
  29.     ungetc(symbol, stdin);
  30.     int temp;
  31.     scanf("%d", &temp);
  32.     value = temp;
  33.     symbol = NUM;
  34.     return;
  35. }

  36. void factor(void) {
  37.     next();
  38.     if(symbol == NUM) return;
  39.     if(symbol != '(') goto err;
  40.     void expression(void);
  41.     expression();
  42.     if(symbol != NUM) goto err;
  43.     double temp = value;
  44.     next();
  45.     if(symbol != ')') goto err;
  46.     symbol = NUM;
  47.     value = temp;
  48.     return;
  49. err:
  50.     symbol = ERROR;
  51.     return;
  52. }

  53. void term(void) {
  54.     factor();
  55.     if(symbol != NUM) goto err;
  56.     double a = value;
  57.     next();
  58.     if(!(symbol == '*' || symbol == '/')) {
  59.         back();
  60.         symbol = NUM;
  61.         value = a;
  62.         return;
  63.     }
  64.     int op = symbol;
  65.     term();
  66.     if(symbol != NUM) goto err;
  67.     value = op == '*' ? a * value : a / value;
  68.     return;
  69. err:
  70.     symbol = ERROR;
  71.     return;
  72. }

  73. void expression(void) {
  74.     term();
  75.     if(symbol != NUM) goto err;
  76.     double a = value;
  77.     next();
  78.     if(!(symbol == '+' || symbol == '-')) {
  79.         back();
  80.         symbol = NUM;
  81.         value = a;
  82.         return;
  83.     }
  84.     int op = symbol;
  85.     expression();
  86.     if(symbol != NUM) goto err;
  87.     value = op == '+' ? a + value : a - value;
  88.     return;
  89. err:
  90.     symbol = ERROR;
  91.     return;
  92. }

  93. void line(void) {
  94.     next();
  95.     if(symbol == '\n') return;
  96.     back();
  97.     expression();
  98.     if(symbol == '\n') return;
  99.     if(symbol != NUM) goto err;
  100.     double a = value;
  101.     next();
  102.     if(symbol != '\n') goto err;
  103.     printf(">>> %lf\n", a);
  104.     return;
  105. err:
  106.     printf("错误的表达式!\n");
  107.     symbol = ERROR;
  108.     return;
  109. }

  110. void lines(void) {
  111.     next();
  112.     if(symbol == EOF) {
  113.         symbol = OK;
  114.         return;
  115.     }
  116.     back();
  117.     line();
  118.     //if(symbol == ERROR) return;
  119.     return lines();
  120. }

  121. bool start(void) {
  122.     lines();
  123.     if(symbol != OK) return false;
  124.     next();
  125.     if(symbol != EOF) return false;
  126.     return true;
  127. }

  128. int main(void) {
  129.     start();
  130.     return 0;
  131. }
复制代码


假设1. 小括号已匹配
我不做这个假设,如果括号不匹配,我写的这个程序会打印一个错误信息

假设3. 表达式中间没有多余的空格
要在程序中忽略这些多余的空格也不复杂呀,所以我写的这个程序依然不做这个假设

假设 所有操作数均为10以内的整数
这个假设没意思吧,就支持一位数字?你用scanf读取不就可以了

假设太多了,没意思

下面说一说这个代码的思路
1. 首先写出这个语言(表达式)的文法
  1. start: lines (EOF);

  2. lines: (EMPTY)
  3.      | line lines
  4.      ;

  5. line: expression '\n' {print(expression);}
  6.     | '\n'
  7.     | (ERROR) {printf("错误的表达式!\n");}
  8.     ;

  9. expression: term
  10.           | expression '+' term {$$ = $1 + $3;}
  11.           | expression '-' term {$$ = $1 - $3;}
  12.           ;

  13. term: factor
  14.     | term '*' factor {$$ = $1 * $3;}
  15.     | term '/' factor {$$ = $1 / $3;}
  16.     ;

  17. factor: NUM
  18.       | '(' expression ')' {$$ = $2;}
  19.       ;
复制代码


2. 消除左递归, 因为要使用递归下降分析
  1. expression: term expression_;
  2. expression_: (EMPTY)
  3.            | '+' term expression_
  4.            | '-' term expression_
  5.            ;

  6. term: factor term_;
  7. term_: (EMPTY)
  8.      | '*' factor term_
  9.      | '/' factor term_
  10.      ;
复制代码

编译原理教材中用的是这种方法
但是,为什么不能改成这样?
  1. expression: term
  2.           | term '+' expression {$$ = $1 + $3;}
  3.           | term '-' expression {$$ = $1 - $3;}
  4.           ;

  5. term: factor
  6.     | factor '*' term {$$ = $1 * $3;}
  7.     | factor '/' term {$$ = $1 / $3;}
  8.     ;
复制代码

这样也没有左递归呀,上面的那个代码用的就是这种方法,到目前为止还没有发现 有什么问题

3. 照着这个文法,用递归下降分析,写代码
4. 调试,^_^
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2022-4-30 13:45:11 | 显示全部楼层    本楼为最佳答案   
先贴代码
  1. #include <stdio.h>
  2. #include <stdbool.h>
  3. #include <ctype.h>

  4. enum {EMPTY = 256, ERROR, OK, NUM};

  5. int symbol;
  6. double value;

  7. int symbol_;
  8. double value_;

  9. void back(void) {
  10.     symbol_ = symbol;
  11.     value_ = value;
  12. }

  13. void next(void) {
  14.     if(symbol_ != 0) {
  15.         symbol = symbol_;
  16.         value = value_;
  17.         symbol_ = 0;
  18.         return;
  19.     }
  20.     symbol = getchar();
  21.     switch(symbol) {
  22.         case ' ':
  23.         case '\t':
  24.         case '\v':
  25.         case '\f':
  26.             return next();
  27.     }
  28.     if(!isdigit(symbol)) return;
  29.     ungetc(symbol, stdin);
  30.     int temp;
  31.     scanf("%d", &temp);
  32.     value = temp;
  33.     symbol = NUM;
  34.     return;
  35. }

  36. void factor(void) {
  37.     next();
  38.     if(symbol == NUM) return;
  39.     if(symbol != '(') goto err;
  40.     void expression(void);
  41.     expression();
  42.     if(symbol != NUM) goto err;
  43.     double temp = value;
  44.     next();
  45.     if(symbol != ')') goto err;
  46.     symbol = NUM;
  47.     value = temp;
  48.     return;
  49. err:
  50.     symbol = ERROR;
  51.     return;
  52. }

  53. void term(void) {
  54.     factor();
  55.     if(symbol != NUM) goto err;
  56.     double a = value;
  57.     next();
  58.     if(!(symbol == '*' || symbol == '/')) {
  59.         back();
  60.         symbol = NUM;
  61.         value = a;
  62.         return;
  63.     }
  64.     int op = symbol;
  65.     term();
  66.     if(symbol != NUM) goto err;
  67.     value = op == '*' ? a * value : a / value;
  68.     return;
  69. err:
  70.     symbol = ERROR;
  71.     return;
  72. }

  73. void expression(void) {
  74.     term();
  75.     if(symbol != NUM) goto err;
  76.     double a = value;
  77.     next();
  78.     if(!(symbol == '+' || symbol == '-')) {
  79.         back();
  80.         symbol = NUM;
  81.         value = a;
  82.         return;
  83.     }
  84.     int op = symbol;
  85.     expression();
  86.     if(symbol != NUM) goto err;
  87.     value = op == '+' ? a + value : a - value;
  88.     return;
  89. err:
  90.     symbol = ERROR;
  91.     return;
  92. }

  93. void line(void) {
  94.     next();
  95.     if(symbol == '\n') return;
  96.     back();
  97.     expression();
  98.     if(symbol == '\n') return;
  99.     if(symbol != NUM) goto err;
  100.     double a = value;
  101.     next();
  102.     if(symbol != '\n') goto err;
  103.     printf(">>> %lf\n", a);
  104.     return;
  105. err:
  106.     printf("错误的表达式!\n");
  107.     symbol = ERROR;
  108.     return;
  109. }

  110. void lines(void) {
  111.     next();
  112.     if(symbol == EOF) {
  113.         symbol = OK;
  114.         return;
  115.     }
  116.     back();
  117.     line();
  118.     //if(symbol == ERROR) return;
  119.     return lines();
  120. }

  121. bool start(void) {
  122.     lines();
  123.     if(symbol != OK) return false;
  124.     next();
  125.     if(symbol != EOF) return false;
  126.     return true;
  127. }

  128. int main(void) {
  129.     start();
  130.     return 0;
  131. }
复制代码


假设1. 小括号已匹配
我不做这个假设,如果括号不匹配,我写的这个程序会打印一个错误信息

假设3. 表达式中间没有多余的空格
要在程序中忽略这些多余的空格也不复杂呀,所以我写的这个程序依然不做这个假设

假设 所有操作数均为10以内的整数
这个假设没意思吧,就支持一位数字?你用scanf读取不就可以了

假设太多了,没意思

下面说一说这个代码的思路
1. 首先写出这个语言(表达式)的文法
  1. start: lines (EOF);

  2. lines: (EMPTY)
  3.      | line lines
  4.      ;

  5. line: expression '\n' {print(expression);}
  6.     | '\n'
  7.     | (ERROR) {printf("错误的表达式!\n");}
  8.     ;

  9. expression: term
  10.           | expression '+' term {$$ = $1 + $3;}
  11.           | expression '-' term {$$ = $1 - $3;}
  12.           ;

  13. term: factor
  14.     | term '*' factor {$$ = $1 * $3;}
  15.     | term '/' factor {$$ = $1 / $3;}
  16.     ;

  17. factor: NUM
  18.       | '(' expression ')' {$$ = $2;}
  19.       ;
复制代码


2. 消除左递归, 因为要使用递归下降分析
  1. expression: term expression_;
  2. expression_: (EMPTY)
  3.            | '+' term expression_
  4.            | '-' term expression_
  5.            ;

  6. term: factor term_;
  7. term_: (EMPTY)
  8.      | '*' factor term_
  9.      | '/' factor term_
  10.      ;
复制代码

编译原理教材中用的是这种方法
但是,为什么不能改成这样?
  1. expression: term
  2.           | term '+' expression {$$ = $1 + $3;}
  3.           | term '-' expression {$$ = $1 - $3;}
  4.           ;

  5. term: factor
  6.     | factor '*' term {$$ = $1 * $3;}
  7.     | factor '/' term {$$ = $1 / $3;}
  8.     ;
复制代码

这样也没有左递归呀,上面的那个代码用的就是这种方法,到目前为止还没有发现 有什么问题

3. 照着这个文法,用递归下降分析,写代码
4. 调试,^_^

评分

参与人数 1荣誉 +5 鱼币 +5 收起 理由
傻眼貓咪 + 5 + 5 鱼C有你更精彩^_^

查看全部评分

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-4-24 10:25

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表