简单的四则运算计算器 C 语言

        学习写一下简单的解释器,没有实现栈式运算,没有三角函数,log, pow 之类运算,加上这些理论上不难。发了一点时间把三角函数,log, pow 还是加上。

        再加上一个栈实现的版本,用来比较。

代码在:

https://gitee.com/jhkwei/cal.git

支持输入格式样式如下:

cos(sin(3.14/2)+1+(2*3))+(1+2)*(2-4)+(1*(1+2*(1+2)))

当然和真正的计算器还是有些差距,只当学习用。

递归实现简单说一下机制:

  1. 先语法分析,把输入分成+-*/(),sin,cos,tan,cot,log和数等标记;
  2. 再根据函数和()构成一个树,函数和()构成树的父结节,+-*/和数是叶子节点,同一级的节点用数组按顺序储存,这里也可以用二叉树储存;
  3. 求值的时候用的是递归,为了简单没有转成栈,先求函数和()内值,其中函数也会分为,先求()内值,再求函数值,
  4. 最后这样同一级数组就变换成简单的四则运算,按其优先级计算即成,求完的都会被删除掉,最后只留下根结点。

栈实现简单说一下机制:

  1. 压栈( 表示开始
  2. 先语法分析,把输入分成+-*/(),sin,cos,tan,cot,log和数等标记;
  3. 上面所得准备压栈
  4. 如果是+-*/等运算符,若栈顶有同级表达式,则比较栈顶同级表达式的运算符,若栈顶同级表达式的运算符等级优先级高,则计算栈顶表达式,直到把栈顶同级表达式中运算符优先级比它高的表达式全都计算完,再压栈;否则直接压入。
  5. 如果是 ) 或 文档输入结束 ,  则检测栈顶的是否是函数,是函数则计算函数, 否则,直接计算与前面的与之相对应的( 之间的表达式的值
  6. 再到第二步,直到没有输入为止

栈实现的版本代码:

//CalLex.h
#ifndef CALLEX_H
#define CALLEX_H
 
 enum CalLexToken{
    Lex_Nil,
    Lex_Eof,
    Lex_Begin,
    Lex_End,
    Lex_Plus,
    Lex_Minus,
    Lex_Mutil,
    Lex_Div,
    Lex_Pow,
    Lex_Number,
    Lex_Cos,
    Lex_Sin,
    Lex_Tan,
    Lex_Cot,
    Lex_Log
};
 
struct Token{
    enum CalLexToken type;
    double d;
};
 
struct Lex{
    char *data;
    int size;
    char *p;
};
 
struct Lex *lex_init(char *data, int size);
 
void lex_exit(struct Lex *lex);
 
enum CalLexToken lex_item(struct Lex *lex,struct Token *token);
 
char lex_getNext(struct Lex *lex);
 
void lex_putBack(struct Lex *lex);
 
 
#endif // CALLEX_H

//CalLex.c
#include "CalLex.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
 
struct Lex *lex_init(char *data, int size)
{
    if(size <= 0){
         return  NULL;
    }
    struct Lex *lex = (struct Lex *)calloc(1 ,sizeof(*lex));
    assert(lex);
    lex->data = (char *)calloc(1, size+1);
    assert(lex->data);
    memcpy(lex->data, data, size);
    lex->size = size;
    lex->p = lex->data;
    return  lex;
}
 
void lex_exit(struct Lex *lex)
{
    if(lex == NULL){
        return;
    }
    if(lex->data){
        free(lex->data);
    }
    free(lex);
}
 
enum CalLexToken lex_readNumber(struct Lex *lex,struct Token *token, char c)
{
    double ll  = 0;
    token->d = 0;
    if(isdigit(c)){
        ll = c - '0';
        while(1){
            c = lex_getNext(lex);
            if(isdigit(c)){
                 ll = ll * 10 + (c - '0');
            }else{
                if(c != '.'){
                    lex_putBack(lex);
                }
                break;
            }
        }
    }
    double ls  = 0;
    int count = 10;
    if(c == '.'){
        c = lex_getNext(lex);
        if(!isdigit(c)){
            lex_putBack(lex);
        }else{
            ls = c - '0';
            while(1){
                c = lex_getNext(lex);
                if(isdigit(c)){
                    ls = ls * 10 + (c - '0');
                    count *= 10;
                }else{
                    lex_putBack(lex);
                    break;
                }
            }
        }
    }
    token->d = ll + (ls*1.0000f/count);
    return Lex_Number;
}

enum CalLexToken lex_readFun(struct Lex *lex, char c)
{
    char name[4] = {0};
    int count = 0;
    name[count] = c;
    count++;
    while(count < 3){
        char n = lex_getNext(lex);
        if(n == '\0'){
            printf("function name error\n");
            return  Lex_Nil;
        }
        if(isalpha(n)){
            name[count] = n;
            count++;
        }else{
            printf("function name error\n");
            return Lex_Nil;
        }
    }
    if(!strcmp(name,"cos")){
        return Lex_Cos;
    }
    if(!strcmp(name,"sin")){
        return Lex_Sin;
    }
    if(!strcmp(name,"tan")){
        return Lex_Tan;
    }
    if(!strcmp(name,"cot")){
        return Lex_Cot;
    }
    if(!strcmp(name,"log")){
        return Lex_Log;
    }
    printf("unknown function name\n");
    return Lex_Nil;
}
 
enum CalLexToken lex_item(struct Lex *lex,struct Token *token)
{
    while(1){
        char c = lex_getNext(lex);
        switch (c) {
            case '\0':return Lex_Eof;
            case '(':return  Lex_Begin;
            case ')':return  Lex_End;
            case '+':return  Lex_Plus;
            case '-':return  Lex_Minus;
            case '*':return  Lex_Mutil;
            case '/':return  Lex_Div;
            case '^':return  Lex_Pow;
            default:
            {
                if(isspace(c)){
                    break;
                }else if(isalpha(c)){
                    return lex_readFun(lex, c);
                }else{
                    return lex_readNumber(lex, token, c);
                }
            }
        }
    }
    return  Lex_Nil;
}
 
char lex_getNext(struct Lex *lex)
{
    
    return *lex->p++;
  
}
 
void lex_putBack(struct Lex *lex)
{
    lex->p--;
}
//List.h
#ifndef LIST_H
#define LIST_H

struct List{
   int num;
   void **list;
    int len;
};
 
struct List *list_new();
void list_free(struct List *list);
void list_resize(struct List *list, int size);
void list_appand(struct List *list, void *data);
void *list_at(struct List *list, int index);
void list_removeAt(struct List *list, int index);

int list_size(struct List *list);
int list_isEmpty(struct List *list);
void *list_pop(struct List *list);

#endif 
//List.c
#include "List.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
 
struct List *list_new()
{
    struct List *list = (struct List *)calloc(1, sizeof(*list));
    assert(list);
    list->list = (void **)calloc(4, sizeof(void *));
    list->len = 4;
    list->num = 0;
    return  list;
}
 
void list_free(struct List *list)
{
    assert(list);
    if(list->list){
        free(list->list);
    }
    free(list);
}
 
void list_resize(struct List *list, int size)
{
    int len = 4;
    while(len < size){
        len *= 2;
    }
    void **ll = (void **)calloc(len, sizeof(void *));
    assert(ll);
    if(list->list){
        int i;
        for(i = 0;i < list->num;i++){
            ll[i] = list->list[i];
        }
        free(list->list);
        list->list = NULL;
    }
    list->list = ll;
    list->len = len;
}
 
void list_appand(struct List *list, void *data)
{
    if(list->num + 1 >= list->len){
        list_resize(list, list->num+1);
    }
    list->list[list->num] = data;
    list->num++;
}
 
void *list_at(struct List *list, int index)
{
    if(index >= 0 && index < list->num){
        return list->list[index];
    }else if(index < 0 && list->num + index >= 0){
        return list->list[list->num+index];
    }
    return NULL;
}
 
void list_removeAt(struct List *list, int index)
{
    if(index < 0 || index >= list->num){
        return;
    }
    int i;
    for(i = index; i < list->num;i++){
        list->list[i] = list->list[i+1];
    }
    list->num--;
    list->list[list->num] = NULL;
}

int list_size(struct List *list)
{
    return list->num;
}

int list_isEmpty(struct List *list)
{
    return  list->num == 0;
}

void *list_pop(struct List *list)
{
    if(list_isEmpty(list)){
        return NULL;
    }
    list->num--;
    void *data = list->list[list->num];
    return data;
}
//CalParse.h
#ifndef LEXPASER_H
#define LEXPASER_H


double cal_parser(char *data, int size);


#endif // LEXPASER_H

//LexPaser.c
#include "CalPaser.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "List.h"
#include <math.h>

#include "CalLex.h"
#include "List.h"


struct Cal{
    struct List *list;
    double result;
    int erron;
};

static struct Cal *cal_init();

static void cal_exit(struct Cal *cal);

static void cal_dumpList(struct Cal *cal);

int caltree_isBegin(struct Token *node)
{
    if(node == NULL){
        return 0;
    }
    return node->type == Lex_Begin;
}

int caltree_isEnd(struct Token *node)
{
    if(node == NULL){
        return 0;
    }
    return node->type == Lex_End || node->type == Lex_Eof;
}

int caltree_isNumber(struct Token *node)
{
    if(node == NULL){
        return 0;
    }
    return node->type == Lex_Number;
}

int calTree_isfunction(struct Token *node)
{
    if(node == NULL){
        return 0;
    }
    switch (node->type) {

        case   Lex_Cos:
        case   Lex_Sin:
        case   Lex_Tan:
        case   Lex_Cot:
        case   Lex_Log:
            return 1;
        default:
            return 0;
    }
}

int calTree_isOption(struct Token *node)
{
    if(node == NULL){
        return 0;
    }
    switch (node->type) {
        case   Lex_Plus:
        case   Lex_Minus:
        case   Lex_Mutil:
        case   Lex_Div:
        case   Lex_Pow:
            return 1;
        default:
            return 0;
    }
}

double cal_funtion(struct Token *token, double value){


    double outvalue;
    switch (token->type) {
        case Lex_Cos: outvalue = cos(value);break;
        case Lex_Sin: outvalue = sin(value);break;
        case Lex_Tan: outvalue = tan(value);break;
        case Lex_Cot: outvalue = tan(M_PI/2-value);break;
        case Lex_Log: outvalue = log(value);break;
    default:
        printf("this function is unknown\n");
        return -1;
    }

    return outvalue;
}

struct Cal *cal_init()
{
    struct Cal *cal = (struct Cal *)calloc(1, sizeof(*cal));
    assert(cal);
    cal->list = list_new();
    return  cal;
}

void cal_exit(struct Cal *cal)
{
    if(cal->list){
        list_free(cal->list);
    }
    free(cal);
}


int cal_check(struct Token *a, struct Token *b, struct Token *c)
{
    (void )a;
    (void )c;
    if (b->type == Lex_Div && c->d == 0) {
        return 0;
    }else{
        return 1;
    }
}

double cal_subItem(struct Token *a, struct Token *b, struct Token *c)
{
    switch (b->type) {
        case Lex_Plus: return  a->d + c->d;
        case Lex_Minus:return  a->d - c->d;
        case Lex_Mutil:return  a->d * c->d;
        case Lex_Div:  return  a->d / c->d;
        default: return pow(a->d, c->d);
    }
}

int cal_setValue(struct Token *node,double value)
{
    node->type = Lex_Number;
    node->d = value;
    return 0;
}

int cal_optionPriority(struct Token *a, struct Token *b)
{

    enum CalLexToken at;
    enum CalLexToken bt;
    at = a->type;
    bt = b->type;
    //int proi[Lex_Log+1] = {0,1,2,2,3,3,4,4,5,6};
    //int la = proi[at];
    //int lb = proi[bt];
    //return la >= lb;

    if(at == Lex_Pow){
        return 1;
    }
    if(bt == Lex_Pow){
        return 0;
    }
    if(at == Lex_Div || at == Lex_Mutil){
        return 1;
    }
    if(bt == Lex_Div || bt == Lex_Mutil){
        return 0;
    }

    return 1;
}


int cal_staticItem(struct Cal *cal){
    int i;
     struct Token *list[3] = {0};
     for(i = 0; i < 3;i++){
         list[i] = (struct Token *)list_at(cal->list, -i-1);
     }
     if(!caltree_isNumber(list[0])){
         return -1;
     }
     if(calTree_isOption(list[1])){
         if(caltree_isNumber(list[2])){
             if(!cal_check(list[2], list[1], list[0])){
                 printf("error: div by 0\n");
                 return -1;
             }

             double value = cal_subItem(list[2], list[1], list[0]);
             cal_setValue(list[2], value);
             list_pop(cal->list);
             list_pop(cal->list);
             free(list[0]);
             free(list[1]);
             return 1;
         }else{
             if(list[1]->type == Lex_Plus){
                 cal_setValue(list[1], list[0]->d);
                 list_pop(cal->list);
                 free(list[0]);
                 return 1;
             }else if(list[1]->type == Lex_Minus){
                 cal_setValue(list[1], -list[0]->d);
                 list_pop(cal->list);
                 free(list[0]);
                 return 1;
             }else{
                 return -1;
             }
         }
     }else if(caltree_isBegin(list[1]) && calTree_isfunction(list[2])){
         double value = cal_funtion(list[2], list[0]->d);
         cal_setValue(list[2], value);
         list_pop(cal->list);
         list_pop(cal->list);
         free(list[0]);
         free(list[1]);
         return 0;
     }else if(caltree_isBegin(list[1])){
         cal_setValue(list[1], list[0]->d);
         list_pop(cal->list);
         free(list[0]);
         return 0;
     }
     return  0;
}

int cal_addOption(struct Cal *cal, struct Token *node)
{
	while(1){
		int i;
		struct Token *list[3] = {0};
		for(i = 0; i < 3;i++){
			list[i] = (struct Token *)list_at(cal->list, -i-1);
		}
		if(caltree_isNumber(list[0])){
			if(calTree_isOption(list[1]) && caltree_isNumber(list[2])){
				if(cal_optionPriority(list[1], node)){
					if(cal_staticItem(cal) < 0){
						return -1;
					}
				}else{
					list_appand(cal->list, node);
					return 0;
				}
			}else{
				list_appand(cal->list, node);
				return 0;
			}
		}else if(caltree_isBegin(list[0])){
			list_appand(cal->list, node);
			return 0;
		}else{
			return -1;
		}
	}
	return 0;
}

int cal_static(struct Cal *cal, struct Token *node)
{
    if(caltree_isNumber(node)){
        list_appand(cal->list, node);
    }else if(calTree_isOption(node)){
        return cal_addOption(cal,node);
    }else if(caltree_isBegin(node)){
        list_appand(cal->list, node);
    }else if(calTree_isfunction(node)){
        list_appand(cal->list, node);
    }else if(caltree_isEnd(node)){
        int result;
        while((result = cal_staticItem(cal) ) == 1){
            ;
        }
        free(node);
        return result;
    }
    return 0;
}

int cal_addItem(struct Cal *cal, struct Token *token)
{
    struct Token *node = (struct Token *)calloc(1, sizeof(*node));
    *node = *token;
    int result = cal_static(cal, node);
    if(result < 0){
        cal_dumpList(cal);
    }
    return result;
}

void cal_dumpList(struct Cal *cal)
{
    int i;
    int num = list_size(cal->list);
    for(i = 0;i < num;i++){
        struct Token *token = (struct Token *)list_at(cal->list,i);
        switch (token->type) {
            case Lex_Plus: printf("+"); break;
            case Lex_Minus:printf("-"); break;
            case Lex_Mutil:printf("*"); break;
            case Lex_Div:printf("/"); break;
            case Lex_Pow:printf("^"); break;
            case Lex_Number:printf("%f",token->d); break;
            case Lex_Cos:printf("cos");break;
            case Lex_Sin:printf("sin");break;
            case Lex_Tan:printf("tan");break;
            case Lex_Cot:printf("cot");break;
            case Lex_Log:printf("log");break;
            case Lex_Begin: printf("(");break;
            case Lex_End: printf(")"); break;
            default:
                break;
        }
    }
    printf("\n");
}

double cal_parser(char *data, int size)
{
    double result = 0;
    struct Cal *cal = cal_init();
    struct Lex *lex = lex_init(data, size);
    if(lex == NULL){
        return -1;
    }
    struct Token token;
    token.type = Lex_Begin;
    cal_addItem(cal, &token);
    int flag = 0;
    while(1){
        token.d = 0;
        enum CalLexToken type = lex_item(lex, &token);
        token.type = type;
        if(type == Lex_Nil){
            flag = 1;
            break;
        }
        if(cal_addItem(cal, &token) < 0){
            flag = 1;
            break;
        }
        if(type == Lex_Eof){
            break;
        }
    }

   if(flag == 0 && list_size(cal->list) == 1){
       struct Token *node = (struct Token *)list_at(cal->list, 0);
       result = node->d;
       printf("result=%f\n", result);
   }else{
       printf("cal has error\n");
   }

    cal_exit(cal);
    lex_exit(lex);
    return result;
}
#include <string.h>
#include <stdio.h>
#include "CalPaser.h"


int main(int argc, char *argv[])
{

    if(argc > 1){

	    double value = cal_parser(argv[1], strlen(argv[1]));
	    printf("value:%f\n", value);

    }else{
          char buf[] = "cos(3.14*2)+sin(3.14/2+3.14/2)+5+1+1+3+6*2*(1+2*(2+2))*(1+2)";
        //char buf[] = "cos(3.14*2)+sin(3.14/2+3.14/2)+5";
        double value = cal_parser(buf, strlen(buf));
        printf("value:%f\n", value);

    }
    return 0;
}

递归代码如下:


//LexParse.h
#ifndef LEXPASER_H
#define LEXPASER_H

#include "CalLex.h"
#include "List.h"

struct CalTree{
    struct Token token;
    struct List *list;
    struct CalTree *parent;
};
 
struct CalTree *caltree_new();
void caltree_free(struct CalTree *tree);
struct CalTree * caltree_add(struct CalTree *tree,struct Token *token);
int caltee_num(struct CalTree *tree);
struct Token *caltree_child(struct CalTree *tree, int index);
int caltree_remove(struct CalTree *tree, int index);
int caltree_remove_num(struct CalTree *tree, int index,int num);
 
int cal_parser(char *data, int size);
 
#endif // LEXPASER_H
//List.h
#ifndef LIST_H
#define LIST_H

struct List{
   int num;
   void **list;
    int len;
};
 
struct List *list_new();
void list_free(struct List *list);
void list_resize(struct List *list, int size);
void list_appand(struct List *list, void *data);
void *list_at(struct List *list, int index);
void list_removeAt(struct List *list, int index);

#endif // LIST_H

//LexPaser.c
#include "LexPaser.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include "List.h"
#include <math.h>

static int cal(struct CalTree *root);
static void dump(struct CalTree *tree);

struct CalTree *caltree_new()
{
    struct CalTree *tree = (struct CalTree *)calloc(1 ,sizeof(*tree));
    assert(tree);
    tree->list = list_new();
    return tree;
}
 
void caltree_free(struct CalTree *tree)
{
    int i;
    struct List *list = tree->list;
    for(i = 0;i < list->num;i++){
        caltree_free((struct CalTree *)list->list[i]);
    }
    list_free(list);
    free(tree);
}
 
int caltee_num(struct CalTree *tree)
{
    return tree->list->num;
}
 
struct CalTree *caltree_add(struct CalTree *tree,struct Token *token)
{
    struct CalTree *treeSub =  caltree_new();
    treeSub->token = *token;
    treeSub->parent = tree;
    list_appand(tree->list, treeSub);
    return treeSub;
}
 
struct CalTree *caltree_at(struct CalTree *root, int index)
{
    return   (struct CalTree *)list_at(root->list,index);
}
 
struct Token *caltree_child(struct CalTree *tree, int index)
{
    struct CalTree *treeSub = (struct CalTree *)list_at(tree->list,index);
    if(treeSub){
        return &treeSub->token;
    }else{
        return NULL;
    }
}
 
int caltree_remove(struct CalTree *tree, int index)
{
    struct CalTree *treeSub = (struct CalTree *)list_at(tree->list,index);
    if(treeSub){
        caltree_free(treeSub);
        list_removeAt(tree->list, index);
    }
    return 0;
}
 
int caltree_remove_num(struct CalTree *tree, int index,int num)
{
    while (num-- > 0) {
        caltree_remove(tree, index);
    }
    return 0;
}
 
int isOpt(struct CalTree *root, enum CalLexToken type)
{
    return  (root->token.type == type);
}
 
int isNumber(struct Token *token)
{
    return token->type == Lex_Number;
}
 
int calCheck(struct CalTree *a, struct CalTree *b, struct CalTree *c)
{
    (void )a;
    (void )c;
    if (b->token.type == Lex_Div && c->token.d == 0) {
        return 0;
    }else{
        return 1;
    }
}
 
double calSubItem(struct CalTree *a, struct CalTree *b, struct CalTree *c)
{
    switch (b->token.type) {
        case Lex_Plus:return  a->token.d + c->token.d;
        case Lex_Minus:return  a->token.d - c->token.d;
        case Lex_Mutil:return  a->token.d * c->token.d;
        case Lex_Div:  return  a->token.d / c->token.d;
        default: return pow(a->token.d, c->token.d);
    }
}
 
int isPrev(struct CalTree *a, struct CalTree *b)
{
    enum CalLexToken at,bt;
    at = a->token.type;
    bt = b->token.type;
 
    if(at == Lex_Div || at == Lex_Mutil || at == Lex_Pow){
        return 1;
    }
    if(bt == Lex_Div || bt == Lex_Mutil || at == Lex_Pow){
        return 0;
    }
 
    return 1;
}
 
void cal_setNumber(struct CalTree *node, double value)
{
    node->token.d = value;
    node->token.type = Lex_Number;
}

int cal_isFun(enum CalLexToken type)
{
    if(type == Lex_Cos){
        return 1;
    }
    if(type == Lex_Sin){
        return 1;
    }
    if(type == Lex_Tan){
        return 1;
    }
    if(type == Lex_Cot){
        return 1;
    }
    if(type == Lex_Log){
        return 1;
    }

    return 0;
}


int cal_fun(struct CalTree *root){

    int num = caltee_num(root);
    if(num != 1){
        printf("no child\n");
        return -1;
    }
    struct CalTree *child = (struct CalTree *)list_at(root->list, 0);
    if(cal(child) < 0){
         printf("child cal error\n");
        return -1;
    }
    child = (struct CalTree *)list_at(root->list, 0);
    double value;
    switch (root->token.type) {
        case Lex_Cos: value = cos(child->token.d);break;
        case Lex_Sin: value = sin(child->token.d);break;
        case Lex_Tan: value = tan(child->token.d);break;
        case Lex_Cot: value = tan(M_PI/2-child->token.d);break;
        case Lex_Log: value = log(child->token.d);break;
    default:
        printf("this function is unknown\n");
        return -1;
    }
    list_removeAt(root->list, 0);
    cal_setNumber(root,value);
    return 0;
}
 
int cal(struct CalTree *root)
{
    int i;
    struct Token *token;
    int num = caltee_num(root);
    for(i = 0;i < num;i++){
        token = caltree_child(root, i);
        if(cal_isFun(token->type)){
            if(cal_fun((struct CalTree *)list_at(root->list, i)) < 0){
                return -1;
            }
        }else if(token->type == Lex_Begin && cal((struct CalTree *)list_at(root->list, i)) < 0){
             return -1;
        }
    }
    if(num == 0){
        if(!isNumber(&root->token)){
            return -1;
        }else{
            return 0;
        }
    }
 
    for(i = 0;i < num - 1;i++){
        token = caltree_child(root, i);
        struct Token *token2 = caltree_child(root, i+1);
        if(isNumber(token) == isNumber(token2)){
            return -1;
        }
    }
    while(1){
        num = caltee_num(root);
        struct CalTree *a[5] = {0};
        for(i = 0;i < 5;i++){
             a[i] = caltree_at(root,i);
        }
        if(num == 1){
            if(!isNumber(&a[0]->token)){
                 return -1;
            }
            root->token = a[0]->token;
            caltree_remove(root, 0);
            return 0;
        }else if(num == 2){
            if(isOpt(a[0], Lex_Plus) && isOpt(a[1], Lex_Number)){
                cal_setNumber(root, a[1]->token.d);
            }else if(isOpt(a[0], Lex_Minus) && isOpt(a[1], Lex_Number)){
 
                cal_setNumber(root, -a[1]->token.d);
            }else{
                return -1;
            }
            caltree_remove_num(root, 0, 2);
            return 0;
        }else if(num == 3){
            if(!isOpt(a[0], Lex_Number)){
                return -1;
            }
            if(!calCheck(a[0],a[1],a[2])){
                return -1;
            }
            cal_setNumber(root, calSubItem(a[0],a[1],a[2]));
            caltree_remove_num(root, 0, 3);
            return 0;
        }else if(num == 4){
            if(isOpt(a[0], Lex_Number)){
                return -1;
            }
            if(isOpt(a[0], Lex_Plus)){
                cal_setNumber(a[0], a[1]->token.d);
                caltree_remove_num(root, 1, 1);
            }else if(isOpt(a[0], Lex_Minus)){
                cal_setNumber(a[0], -a[1]->token.d);
                caltree_remove_num(root, 1, 1);
            }else{
                return -1;
            }
        }else if(num >= 5){
            if(!isOpt(a[0], Lex_Number)){
                if(isOpt(a[0], Lex_Plus)){
                    cal_setNumber(a[0], a[1]->token.d);
                    caltree_remove_num(root, 1, 1);
                }else if(isOpt(a[0], Lex_Minus)){
                    cal_setNumber(a[0], -a[1]->token.d);
                    caltree_remove_num(root, 1, 1);
                }else{
                    return -1;
                }
            }else{
                if(isPrev(a[1], a[3])){
                    cal_setNumber(a[0], calSubItem(a[0],a[1],a[2]));
                    caltree_remove_num(root, 1, 2);
                }else{
                    cal_setNumber(a[2], calSubItem(a[2],a[3],a[4]));
                    caltree_remove_num(root, 3, 2);
                }
            }
        }else{
            return -1;
        }
    }
    return 0;
}
 

void dumpSub(struct CalTree *tree)
{
    int num = caltee_num(tree);
    int i;
    for(i = 0;i < num;i++){
        dump(caltree_at(tree, i));
    }
}

void dump(struct CalTree *tree)
{
    switch (tree->token.type) {
        case Lex_Plus: printf("+"); break;
        case Lex_Minus:printf("-"); break;
        case Lex_Mutil:printf("*"); break;
        case Lex_Div:printf("/"); break;
        case Lex_Pow:printf("^"); break;
        case Lex_Number:printf("%f",tree->token.d); break;
        case Lex_Cos:printf("cos");dumpSub(tree);break;
        case Lex_Sin:printf("sin");dumpSub(tree);break;
        case Lex_Tan:printf("tan");dumpSub(tree);break;
        case Lex_Cot:printf("cot");dumpSub(tree);break;
        case Lex_Log:printf("log");dumpSub(tree);break;
        case Lex_Begin:{
            printf("(");
            int num = caltee_num(tree);
            int i;
            for(i = 0;i < num;i++){
                dump(caltree_at(tree, i));
            }
            printf(")");
            break;
        }
        default:
            break;
    }
}
void cal_dump(struct CalTree *root)
{
    dump(root);
    printf("\n");
}
 
double cal_getResult(struct CalTree *root)
{
    return root->token.d;
}

int cal_parser(char *data, int size)
{
    struct Lex *lex = lex_init(data, size);
    if(lex == NULL){
        return 0;
    }
    struct CalTree *curr;
    struct CalTree *root = caltree_new();
    root->token.type = Lex_Begin;
    curr = root;
    while(1){
        struct Token token;
        enum CalLexToken type = lex_item(lex, &token);
        token.type = type;
        if(type == Lex_Nil){
            return -1;
        }
        if(type == Lex_Eof){
            break;
        }
        if(type == Lex_Begin){
            curr = caltree_add(curr, &token);
        }else if(cal_isFun(type)){
            curr = caltree_add(curr, &token);
        }else if(type == Lex_End){
            curr = curr->parent;
            if(cal_isFun(curr->token.type)){
               curr = curr->parent;
            }
        }else{
            caltree_add(curr, &token);
        }
    }
    cal_dump(root);
    if(cal(root) == 0){
        printf("%f\n", cal_getResult(root));
    }else{
        printf("cal error\n");
    }
    caltree_free(root);
 
    return 0;
 
}
//List.c
#include "List.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
 
struct List *list_new()
{
    struct List *list = (struct List *)calloc(1, sizeof(*list));
    assert(list);
    list->list = (void **)calloc(4, sizeof(void *));
    list->len = 4;
    list->num = 0;
    return  list;
}
 
void list_free(struct List *list)
{
    assert(list);
    if(list->list){
        free(list->list);
    }
    free(list);
}
 
void list_resize(struct List *list, int size)
{
    int len = 4;
    while(len < size){
        len *= 2;
    }
    void **ll = (void **)calloc(len, sizeof(void *));
    assert(ll);
    if(list->list){
        int i;
        for(i = 0;i < list->num;i++){
            ll[i] = list->list[i];
        }
        free(list->list);
        list->list = NULL;
    }
    list->list = ll;
    list->len = len;
}
 
void list_appand(struct List *list, void *data)
{
    if(list->num + 1 >= list->len){
        list_resize(list, list->num+1);
    }
    list->list[list->num] = data;
    list->num++;
}
 
void *list_at(struct List *list, int index)
{
    if(index >= 0 && index < list->num){
        return list->list[index];
    }
    return NULL;
}
 
void list_removeAt(struct List *list, int index)
{
    if(index < 0 || index >= list->num){
        return;
    }
    int i;
    for(i = index; i < list->num;i++){
        list->list[i] = list->list[i+1];
    }
    list->num--;
    list->list[list->num] = NULL;
}

//main.c
#include "LexPaser.h"
#include <string.h>

int main(){
    //char buf[]="1+2+5+8*5+(5+5)*4*(5*(1+2)+5)";
    char buf[]="cos(sin(3.14159)*1000)+1+2+5+8*5+(5+5)*4*(5*(1+2)+5)";
    cal_parser(buf, strlen(buf));
    return 0;
}


//Makefile

CC=gcc

%.o:%.c
	$(CC) -c -o $@ $^

main:CalLex.o LexPaser.o List.o Test.o
	$(CC) -o $@ $^ -lm

                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值