计算器(Calculator)实验指南
- 前置知识
如果你不了解 C 语⾔中的 struct, enum, union, typedef 的⽤法,请你⾸先查阅课本或其他资料再来阅读本实
验指南。
如果你的⽬标为 100 分,建议不要急于开始,⾸先阅读实验指南的全⽂以进⾏合理的顶层设计,这可能⽐在原来的基础
上加东⻄更加节省时间。 - 总览
在读⼊了每⼀⾏语句之后,我们可能需要依次进⾏以下步骤。 - 词法分析
- 语法分析 & 表达式求值
- 变量赋值
⼤家会在《编译原理》课程中学会真正的词法分析和语法分析。这⾥,我们⼤致描述⼀下这些步骤分别都是在做什么
最终完成全部加分项, 得分97
部分代码如下:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#define INT 73
#define FLOAT 70
#define VARIABLE 86
#define ERROR 1
typedef struct value {
int type;
union {
int iVal;
double fVal;
} val;
} Value;
typedef struct assignment {
char name[32];
Value val;
} Assignment;
Assignment assignment[300];
int assign_id = 0;
typedef struct token {
int type;
char str[32];
} Token;
Token tokens[200];
int token_id = 0;
int l, r;
void error();
Value eval(int l, int r);
int check_parentheses(int l, int r);
void print_token();
int check_minus(int l, int r);
int main_token(int l, int r);
Value meetValue(Value v1, Value v2, int op);
Value evalAssign(int l, int r);
void print_token(){
for(int i = 0; i < token_id; i++)
{
printf("token_id: %d type: %d %c str: %s\n", i, tokens[i].type, tokens[i].type, tokens[i].str);
}
}
void error(){
printf("Error\n");
}
Value evalAssign(int l, int r){
int exist = 0;
int location = 0;
for(int i = l; i <= r; i++)
{
if(tokens[i].type == '=')
{
if(tokens[i-1].type != VARIABLE){
Value error;
error.type = ERROR;
return error;
}
exist = 1;
location = i;
break;
}
}
if(exist){
exist = 0;
assign_id++;
strcpy(assignment[assign_id].name, tokens[location - 1].str);
assignment[assign_id].val = evalAssign(location + 1, r);
return assignment[assign_id].val;
}else{
return eval(l, r);
}
}
int scanner(char *input) {
char ch = 0;
int index = 0;
int i;
int is_neg = 0;
int is_float = 0;
char temp_str[33] = "-";
while((ch = input[index]) != '\n')
{
if(isalpha(ch) || ch == '_') {
i = 0;
while (isalnum(ch) || ch=='_') {
tokens[token_id].str[i] = ch;
i++;
index++;
ch = input[index];
}
tokens[token_id].str[i] = '\0';
tokens[token_id].type = VARIABLE;
token_id++;
}
if(isdigit(ch)){
if(ch == '0')
{
if(input[index+1] != '.'){
error();
return 1;
}
}
i = 0;
while(isdigit(ch) || ch == '.')
{
if(ch == '.') {
is_float = 1;
if(!isdigit(input[index+1])){
error();
return 1;
}
}
tokens[token_id].str[i] = ch;
i++;
index++;
ch = input[index];
}
if(is_float){
tokens[token_id].type = FLOAT;
is_float = 0;
}else{
tokens[token_id].type = INT;
}
if(is_neg){
strcpy(temp_str, tokens[token_id].str);
strcpy(tokens[token_id].str, "-");
strcat(tokens[token_id].str, temp_str);
is_neg = 0;
}
token_id++;
}
switch(ch){
case ' ':
break;
case '+':
tokens[token_id].type = '+';
token_id++;
break;
case '*':
tokens[token_id].type = '*';
token_id++;
break;
case '/':
tokens[token_id].type = '/';
token_id++;
break;
case '(':
tokens[token_id].type = '(';
token_id++;
break;
case ')':
tokens[token_id].type = ')';
token_id++;
break;
case '=':
tokens[token_id].type = '=';
token_id++;
break;
case '-':
tokens[token_id].type = '-';
token_id++;
break;
case '\n':
return 0;
case '\r':
break;
default:
if (ch != '\0'){
error();
return 1;
}
return 0;
}
index++;
}
return 0;
}
Value eval(int l, int r)
{
int op = 0;
Value error;
error.type = ERROR;
if(l > r){
return error;
}
else if(l == r){
if(tokens[l].type == INT){
Value v;
v.type = INT;
v.val.iVal = atoi(tokens[l].str);
return v;
}else if(tokens[l].type == FLOAT){
Value v;
v.type = FLOAT;
v.val.fVal = atof(tokens[l].str);
return v;
}else if(tokens[l].type == VARIABLE){
Value v;
int k = 0;
for(int i = 0; i <= assign_id; i++){
if(strcmp(tokens[l].str, assignment[i].name) == 0){
k = 1;
v.type = assignment[i].val.type;
if(v.type == FLOAT){
v.val.fVal = assignment[i].val.val.fVal;
}else{
v.val.iVal = assignment[i].val.val.iVal;
}
}
}
if(k == 0){
return error;
}else{
k = 0;
return v;
}
}else{
return error;
}
}
else if(check_parentheses(l, r) == 1){
return eval(l + 1, r - 1);
}
else if(check_minus(l, r) == 1){
Value a = eval(l+1, r);
a.val.fVal *= -1;
a.val.iVal *= -1;
return a;
}
else{
Value val1, val2;
op = main_token(l , r);
if(op == 999){
return error;
}
val1 = eval(l, op - 1);
val2 = eval(op + 1, r);
return meetValue(val1, val2, op);
}
}
int check_minus(int l, int r){
int op;
op = main_token(l , r);
if(op != 999){
return 0;
}
if(tokens[l].type == '-'){
if(l == 0 || tokens[l-1].type != VARIABLE || tokens[l-1].type != INT || tokens[l-1].type != FLOAT || tokens[l-1].type != ')'){
return 1;
}
}
return 0;
}
int main_token(int l, int r){
int flag = 0;
for(int i = r; i >= l; i--){
if(tokens[i].type == ')'){
flag = 1;
}
if(tokens[i].type == '(') {
flag = 0;
}
if (tokens[i].type == '+'){
if (flag == 0)
return i;
}else if(tokens[i].type == '-' && i != 0 && (tokens[i-1].type == VARIABLE||tokens[i-1].type == INT||tokens[i-1].type == FLOAT)){
if (flag == 0)
return i;
}
}
for(int i = r; i >= l; i--){
if(tokens[i].type == ')'){
flag = 1;
}
if(tokens[i].type == '(') {
flag = 0;
}
if (tokens[i].type == '*'||tokens[i].type == '/'){
if(flag == 0)
return i;
}
}
return 999;
}
Value meetValue(Value v1, Value v2, int op) {
Value v3;
v3.type = FLOAT;
Value error;
error.type = ERROR;
if (v1.type == ERROR || v2.type == ERROR) {
return error;
}
if (v1.type != v2.type) {
if (v1.type == INT) {
v3.val.fVal = v1.val.iVal;
v1 = v3;
}
if (v2.type == INT) {
v3.val.fVal = v2.val.iVal;
v2 = v3;
}
}
if (v1.type == INT) {
v3.type = INT;
switch (tokens[op].type) {
case '+':
v3.val.iVal = v1.val.iVal + v2.val.iVal;
return v3;
case '-':
v3.val.iVal = v1.val.iVal - v2.val.iVal;
return v3;
case '*':
v3.val.iVal = v1.val.iVal * v2.val.iVal;
return v3;
case '/':
if(v1.val.iVal % v2.val.iVal == 0){
v3.val.iVal = v1.val.iVal / v2.val.iVal;
}else{
v3.val.iVal = v1.val.iVal / v2.val.iVal;
}
return v3;
}
} else {
switch (tokens[op].type) {
case '+':
v3.val.fVal = v1.val.fVal + v2.val.fVal;
return v3;
case '-':
v3.val.fVal = v1.val.fVal - v2.val.fVal;
return v3;
case '*':
v3.val.fVal = v1.val.fVal * v2.val.fVal;
return v3;
case '/':
v3.val.fVal = v1.val.fVal / v2.val.fVal;
return v3;
}
}
return error;
}
int check_parentheses(int l, int r){
if(tokens[l].type == '(' && tokens[r].type == ')')
{
int i = 1;
for(int j = l + 1; j < r; j ++){
if(tokens[j].type == '(')
i++;
if(tokens[j].type == ')')
i--;
}
return i;
}else{
return 0;
}
}