学习写一下简单的解释器,没有实现栈式运算,没有三角函数,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)))
当然和真正的计算器还是有些差距,只当学习用。
递归实现简单说一下机制:
- 先语法分析,把输入分成+-*/(),sin,cos,tan,cot,log和数等标记;
- 再根据函数和()构成一个树,函数和()构成树的父结节,+-*/和数是叶子节点,同一级的节点用数组按顺序储存,这里也可以用二叉树储存;
- 求值的时候用的是递归,为了简单没有转成栈,先求函数和()内值,其中函数也会分为,先求()内值,再求函数值,
- 最后这样同一级数组就变换成简单的四则运算,按其优先级计算即成,求完的都会被删除掉,最后只留下根结点。
栈实现简单说一下机制:
- 压栈( 表示开始
- 先语法分析,把输入分成+-*/(),sin,cos,tan,cot,log和数等标记;
- 上面所得准备压栈
- 如果是+-*/等运算符,若栈顶有同级表达式,则比较栈顶同级表达式的运算符,若栈顶同级表达式的运算符等级优先级高,则计算栈顶表达式,直到把栈顶同级表达式中运算符优先级比它高的表达式全都计算完,再压栈;否则直接压入。
- 如果是 ) 或 文档输入结束 , 则检测栈顶的是否是函数,是函数则计算函数, 否则,直接计算与前面的与之相对应的( 之间的表达式的值
- 再到第二步,直到没有输入为止
栈实现的版本代码:
//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