鱼C论坛

 找回密码
 立即注册
查看: 1161|回复: 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
先贴代码
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>

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

int symbol;
double value;

int symbol_;
double value_;

void back(void) {
    symbol_ = symbol;
    value_ = value;
}

void next(void) {
    if(symbol_ != 0) {
        symbol = symbol_;
        value = value_;
        symbol_ = 0;
        return;
    }
    symbol = getchar();
    switch(symbol) {
        case ' ':
        case '\t':
        case '\v':
        case '\f':
            return next();
    }
    if(!isdigit(symbol)) return;
    ungetc(symbol, stdin);
    int temp;
    scanf("%d", &temp);
    value = temp;
    symbol = NUM;
    return;
}

void factor(void) {
    next();
    if(symbol == NUM) return;
    if(symbol != '(') goto err;
    void expression(void);
    expression();
    if(symbol != NUM) goto err;
    double temp = value;
    next();
    if(symbol != ')') goto err;
    symbol = NUM;
    value = temp;
    return;
err:
    symbol = ERROR;
    return;
}

void term(void) {
    factor();
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(!(symbol == '*' || symbol == '/')) {
        back();
        symbol = NUM;
        value = a;
        return;
    }
    int op = symbol;
    term();
    if(symbol != NUM) goto err;
    value = op == '*' ? a * value : a / value;
    return;
err:
    symbol = ERROR;
    return;
}

void expression(void) {
    term();
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(!(symbol == '+' || symbol == '-')) {
        back();
        symbol = NUM;
        value = a;
        return;
    }
    int op = symbol;
    expression();
    if(symbol != NUM) goto err;
    value = op == '+' ? a + value : a - value;
    return;
err:
    symbol = ERROR;
    return;
}

void line(void) {
    next();
    if(symbol == '\n') return;
    back();
    expression();
    if(symbol == '\n') return;
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(symbol != '\n') goto err;
    printf(">>> %lf\n", a);
    return;
err:
    printf("错误的表达式!\n");
    symbol = ERROR;
    return;
}

void lines(void) {
    next();
    if(symbol == EOF) {
        symbol = OK;
        return;
    }
    back();
    line();
    //if(symbol == ERROR) return;
    return lines();
}

bool start(void) {
    lines();
    if(symbol != OK) return false;
    next();
    if(symbol != EOF) return false;
    return true;
}

int main(void) {
    start();
    return 0;
}

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

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

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

假设太多了,没意思

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

lines: (EMPTY)
     | line lines
     ;

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

expression: term
          | expression '+' term {$$ = $1 + $3;}
          | expression '-' term {$$ = $1 - $3;}
          ;

term: factor
    | term '*' factor {$$ = $1 * $3;}
    | term '/' factor {$$ = $1 / $3;}
    ;

factor: NUM
      | '(' expression ')' {$$ = $2;}
      ;

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

term: factor term_;
term_: (EMPTY)
     | '*' factor term_
     | '/' factor term_
     ;
编译原理教材中用的是这种方法
但是,为什么不能改成这样?
expression: term
          | term '+' expression {$$ = $1 + $3;}
          | term '-' expression {$$ = $1 - $3;}
          ;

term: factor
    | factor '*' term {$$ = $1 * $3;}
    | factor '/' term {$$ = $1 / $3;}
    ;
这样也没有左递归呀,上面的那个代码用的就是这种方法,到目前为止还没有发现 有什么问题

3. 照着这个文法,用递归下降分析,写代码
4. 调试,^_^
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

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

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

int symbol;
double value;

int symbol_;
double value_;

void back(void) {
    symbol_ = symbol;
    value_ = value;
}

void next(void) {
    if(symbol_ != 0) {
        symbol = symbol_;
        value = value_;
        symbol_ = 0;
        return;
    }
    symbol = getchar();
    switch(symbol) {
        case ' ':
        case '\t':
        case '\v':
        case '\f':
            return next();
    }
    if(!isdigit(symbol)) return;
    ungetc(symbol, stdin);
    int temp;
    scanf("%d", &temp);
    value = temp;
    symbol = NUM;
    return;
}

void factor(void) {
    next();
    if(symbol == NUM) return;
    if(symbol != '(') goto err;
    void expression(void);
    expression();
    if(symbol != NUM) goto err;
    double temp = value;
    next();
    if(symbol != ')') goto err;
    symbol = NUM;
    value = temp;
    return;
err:
    symbol = ERROR;
    return;
}

void term(void) {
    factor();
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(!(symbol == '*' || symbol == '/')) {
        back();
        symbol = NUM;
        value = a;
        return;
    }
    int op = symbol;
    term();
    if(symbol != NUM) goto err;
    value = op == '*' ? a * value : a / value;
    return;
err:
    symbol = ERROR;
    return;
}

void expression(void) {
    term();
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(!(symbol == '+' || symbol == '-')) {
        back();
        symbol = NUM;
        value = a;
        return;
    }
    int op = symbol;
    expression();
    if(symbol != NUM) goto err;
    value = op == '+' ? a + value : a - value;
    return;
err:
    symbol = ERROR;
    return;
}

void line(void) {
    next();
    if(symbol == '\n') return;
    back();
    expression();
    if(symbol == '\n') return;
    if(symbol != NUM) goto err;
    double a = value;
    next();
    if(symbol != '\n') goto err;
    printf(">>> %lf\n", a);
    return;
err:
    printf("错误的表达式!\n");
    symbol = ERROR;
    return;
}

void lines(void) {
    next();
    if(symbol == EOF) {
        symbol = OK;
        return;
    }
    back();
    line();
    //if(symbol == ERROR) return;
    return lines();
}

bool start(void) {
    lines();
    if(symbol != OK) return false;
    next();
    if(symbol != EOF) return false;
    return true;
}

int main(void) {
    start();
    return 0;
}

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

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

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

假设太多了,没意思

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

lines: (EMPTY)
     | line lines
     ;

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

expression: term
          | expression '+' term {$$ = $1 + $3;}
          | expression '-' term {$$ = $1 - $3;}
          ;

term: factor
    | term '*' factor {$$ = $1 * $3;}
    | term '/' factor {$$ = $1 / $3;}
    ;

factor: NUM
      | '(' expression ')' {$$ = $2;}
      ;

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

term: factor term_;
term_: (EMPTY)
     | '*' factor term_
     | '/' factor term_
     ;
编译原理教材中用的是这种方法
但是,为什么不能改成这样?
expression: term
          | term '+' expression {$$ = $1 + $3;}
          | term '-' expression {$$ = $1 - $3;}
          ;

term: factor
    | factor '*' term {$$ = $1 * $3;}
    | factor '/' term {$$ = $1 / $3;}
    ;
这样也没有左递归呀,上面的那个代码用的就是这种方法,到目前为止还没有发现 有什么问题

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

评分

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

查看全部评分

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-10-5 20:24

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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