先贴代码#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. 调试,^_^
|