c语言计算器实验

该文介绍了一个C语言实现的计算器实验,涉及词法分析、语法分析和表达式求值的过程。程序定义了结构体用于存储变量和表达式值,并提供了扫描输入、识别操作符、处理括号匹配及计算的功能。文章强调了合理设计和预先规划的重要性。
摘要由CSDN通过智能技术生成

计算器(Calculator)实验指南

  1. 前置知识
    如果你不了解 C 语⾔中的 struct, enum, union, typedef 的⽤法,请你⾸先查阅课本或其他资料再来阅读本实
    验指南。
    如果你的⽬标为 100 分,建议不要急于开始,⾸先阅读实验指南的全⽂以进⾏合理的顶层设计,这可能⽐在原来的基础
    上加东⻄更加节省时间。
  2. 总览
    在读⼊了每⼀⾏语句之后,我们可能需要依次进⾏以下步骤。
  3. 词法分析
  4. 语法分析 & 表达式求值
  5. 变量赋值
    ⼤家会在《编译原理》课程中学会真正的词法分析和语法分析。这⾥,我们⼤致描述⼀下这些步骤分别都是在做什么
    在这里插入图片描述
    在这里插入图片描述
    最终完成全部加分项, 得分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++;
//		printf("location %d\n", location);
		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; // 数字是否带负号 0 不带, 1 带
    int is_float = 0; // 数字是否是浮点数 0 不是, 1 是
    char temp_str[33] = "-";
    while((ch = input[index]) != '\n')
    {
         //printf("[读入部分] Index %d :%c \n", index, ch);
        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') // 解决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++;

        }
//        if(ch == '-')
//        {
//            if(index == 0 ){
//            	if(isdigit(input[1])){
//            		is_neg = 1;
//				}else{
//					tokens[token_id].type = '-';
//                    token_id++;	
//				}
//
//            }else{
//                int temp = tokens[token_id - 1].type;
//                if( temp == INT || temp == FLOAT || temp == VARIABLE){
//                    tokens[token_id].type = '-';
//                    token_id++;
//                }else{
//                    is_neg = 1;
//                }
//            }
//        }

        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)
{
//    printf("l %d r %d\n", l, r);
    int op = 0;
    Value error;
    error.type = ERROR;
    
    if(l > r){
        return error;
    }
    else if(l == r){
//        printf("l == r\n");
        if(tokens[l].type == INT){
            Value v;
            v.type = INT;
            v.val.iVal = atoi(tokens[l].str);
//            printf("v.val.iVal : %d\n", v.val.iVal);
            return v;
        }else if(tokens[l].type == FLOAT){
            Value v;
            v.type = FLOAT;
            v.val.fVal = atof(tokens[l].str);
//            printf("v.val.fVal : %f\n", v.val.fVal);
            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;
        }
    }
//    printf("[meetvalue] v1: type %c \t%d \t%f\n", v1.type, v1.val.iVal, v1.val.fVal);
//    printf("[meetvalue] v2: type %c \t%d \t%f\n", v2.type, v2.val.iVal, v2.val.fVal);
    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;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值