//expression evaluations & calculator //BD 3 nov 2002 #ifndef D_CALC_INCLUDED #include #include "d_error.h" #include "d_funct.h" ////////////////////////////calculator///////////////// int dd_true(char *a) //false if zero or empty string { int i; char *e; i=strtod(a,&e); if(*e)i=1; return(i); } #define DOP_NOT_EQUAL 1 #define DOP_GLOBALADDRESS 2 #define DOP_DIV 3 #define DOP_LESS_EQUAL 4 #define DOP_MORE_EQUAL 5 #define DOP_EQUAL 6 #define DOP_AND 7 #define DOP_OR 8 int dd_calculator_operator(char *b) { int c; c=0; if(Gelijk(b,"+"))c='+'; if(Gelijk(b,"-"))c='-'; if(Gelijk(b,"!"))c='!'; if(Gelijk(b,"*"))c='*'; if(Gelijk(b,"&*"))c=DOP_GLOBALADDRESS; if(Gelijk(b,"/"))c='/'; if(Gelijk(b,"/%"))c=DOP_DIV; if(Gelijk(b,"%"))c='%'; if(Gelijk(b,"?"))c='?'; if(Gelijk(b,"^"))c='^'; if(Gelijk(b,"="))c='='; if(Gelijk(b,"<")) c='<'; if(Gelijk(b,">")) c='>'; if(Gelijk(b,"<=")) c=DOP_LESS_EQUAL; if(Gelijk(b,">=")) c=DOP_MORE_EQUAL; if(Gelijk(b,"==")) c=DOP_EQUAL; if(Gelijk(b,"!=")) c=DOP_NOT_EQUAL; if(Gelijk(b,"&&")) c=DOP_AND; if(Gelijk(b,"||")) c=DOP_OR; return(c); } void dd_expression_brackets(char *a) {//evaluates expression: identifyer or between brackets // isidentical to dd_expression() char dd_expression(); //predeclaration dd_expression(a); } ////////////////////expression///////////////////////////// char dd_nexttoken(char *g) //returns first char of next token, and token in g { d_parse_next(); if(g)Copy(d_parse_string,g); return(d_parse_string[0]); } ///////////// evaluators on order of precedence ////////////// void dd_expression_star(char *a) //pointer operator { void dd_call_by_name(); //predeclaration void dd_expression_unary();//predeclaration void dd_expression_push(); S_fifo rfifo; char h[StringSize], *hv; dd_expression_unary(h); hv=d_var_value_any(h); //try local, if not , global if(!hv)dd_runtime_error("variable %s not declared",h); //should also handle function calls if(!hv){S_clear(a);return;}; switch(hv[0]) { case'\004': //precompiled function call as in d_funct.h { switch(hv[1]) { case'\001': //single argument functions { char *(*hh)();char *errors; dd_expression_brackets(h); hh=(void *)atoi(hv+2); errors=(*hh)(h,a);if(errors)dd_runtime_error(errors,NULL); } break; case'\002': //multiple argument or result functions { char *(*hh)();char *errors; int count=0; S_fifo gfifo; S_fifo_init(&gfifo); S_fifo_init(&rfifo); while(dd_argument(count,h)) { S_fifo_write(&gfifo,h,1); count++; } hh=(void *)atoi(hv+2); errors=(*hh)(&gfifo,&rfifo);if(errors)dd_runtime_error(errors,NULL); if(S_fifo_cleanup(&gfifo)>0)dd_runtime_error("too many arguments in function call",NULL); //handle return values S_clear(a); count=0; while(S_fifo_read(&rfifo,h)) { if(count==0)Copy(h,a); else //to put in expressionfifo { dd_expression_push(","); dd_expression_push(h); } count++; } } break; default: dd_runtime_error("invalid call to compiled function",h); break; } } break; case'\001': //user defined function call { int count=0; S_fifo_init(&rfifo); dd_call_by_name(h,&rfifo); //handle return values S_clear(a); while(S_fifo_read(&rfifo,h)) { if(count==0)Copy(h,a); else //to put in expressionfifo { dd_expression_push(","); dd_expression_push(h); } count++; } } break; case'\002'://future use: pointers to native variables break; default: d_parse_preview(); if(Gelijk(d_parse_string,"=")) { d_parse_next(); dd_expression_brackets(a); d_var_push_any(h,a); } else Copy(hv,a); break; }//switch } void dd_expression_unary(char *a) {// unary operators int c; char h[StringSize]; S_clear(a); c=d_parse_preview(); if(S_cins(c,";,){}")){return;} if(c=='(') { dd_expression_brackets(a); } else { d_parse_next(); c=dd_calculator_operator(d_parse_string); switch(c) { //unary or pre-argument operators case'+': dd_expression_unary(h); S_dtos(d_atod(h),a); break; case'-': dd_expression_unary(h); S_dtos(-d_atod(h),a); break; case'!': // logical not dd_expression_unary(h); Copy(dd_true(h)?"0":"1",a); break; case'*': //variable or function call dd_expression_star(a); break; case DOP_GLOBALADDRESS: dd_expression_brackets(h); { char *hv, *hb; hb=d_var_local(h); hv=d_var_value(hb);if(!hv){hv=d_var_value(h);hb=h;} if(!hv)dd_runtime_error("variable %s not defined",h); Copy(hb?hb:"",a); } break; default: // just an identifyer Copy(d_parse_string,a); break; } }//else } void dd_expression_mult(char *a) {// recognizes multiplication of expressions int c;int tokensread=0; char h[StringSize]; S_clear(a); while(1) { c=d_parse_preview(); if(!tokensread)//ie first argument of multiplication { if(S_cins(c,");,{}"))return; dd_expression_unary(a); } else { if(S_cins(c,"();,{}"))return; switch(dd_calculator_operator(d_parse_string)) { // inbetween operators case'*': d_parse_next();dd_expression_unary(h)/*next argument of */; S_dtos(d_atod(a)*d_atod(h),a); break; case'/': d_parse_next();dd_expression_unary(h)/*next argument of */; S_dtos(d_atod(a)/d_atod(h),a); break; case DOP_DIV: //integer division d_parse_next();dd_expression_unary(h); S_itos((int)d_atod(a)/(int)d_atod(h),a); break; case'%': // integer modulo d_parse_next();dd_expression_unary(h); S_itos((int)d_atod(a)%(int)d_atod(h),a); break; default: //i.e. operator with lower precedence: exit return; break; } } tokensread++; } } void dd_expression_add(char *a) {// recognizes addition of expressions int c;int tokensread=0; char h[StringSize]; S_clear(a); while(1) { c=d_parse_preview(); if(!tokensread)//ie first arguments { if(S_cins(c,");,{}"))return; dd_expression_mult(a); } else { if(S_cins(c,"();,{}"))return; switch(dd_calculator_operator(d_parse_string)) { // inbetween operators case'+': d_parse_next();dd_expression_mult(h)/*next argument of */; S_dtos(d_atod(a)+d_atod(h),a); break; case'-': d_parse_next();dd_expression_mult(h)/*next argument of */; S_dtos(d_atod(a)-d_atod(h),a); break; default: //i.e. operator with lower precedence: exit return; break; } } tokensread++; } } void dd_expression_larger(char *a) {// recognizes larger/smaller expressions int c;int tokensread=0; char h[StringSize]; S_clear(a); while(1) { c=d_parse_preview(); if(!tokensread)//ie first arguments { if(S_cins(c,");,{}"))return; dd_expression_add(a); } else { if(S_cins(c,"();,{}"))return; switch(dd_calculator_operator(d_parse_string)) { // inbetween operators case'>': d_parse_next();dd_expression_add(h)/*next argument of */; // if(S_isnumber(h)&&S_isnumber(a)) S_copy(d_atod(a)>d_atod(h)?"1":"0",StringSize,a); // else // S_copy(S_gt(a,h)?"1":"0",StringSize,a); break; case'<': d_parse_next();dd_expression_add(h)/*next argument of */; // if(S_isnumber(h)&&S_isnumber(a)) S_copy(d_atod(a)=d_atod(h)?"1":"0",StringSize,a); break; default: //i.e. operator with lower precedence: exit return; break; } } tokensread++; } } void dd_expression_equal(char *a) {// recognizes equal / not equal expressions int c;int tokensread=0; char h[StringSize]; S_clear(a); while(1) { c=d_parse_preview(); if(!tokensread)//ie first arguments { if(S_cins(c,");,{}"))return; dd_expression_larger(a); } else { if(S_cins(c,"();,{}"))return; switch(dd_calculator_operator(d_parse_string)) { // inbetween operators case DOP_EQUAL: d_parse_next();dd_expression_larger(h)/*next argument of */; S_copy(d_atod(a)==d_atod(h)?"1":"0",StringSize,a); break; case DOP_NOT_EQUAL: d_parse_next();dd_expression_larger(h)/*next argument of */; S_copy(d_atod(a)!=d_atod(h)?"1":"0",StringSize,a); break; default: //i.e. operator with lower precedence: exit return; break; } } tokensread++; } } void dd_expression_and(char *a) {// recognizes and /or expressions int c;int tokensread=0; char h[StringSize]; S_clear(a); while(1) { c=d_parse_preview(); if(!tokensread)//ie first arguments { if(S_cins(c,");,{}"))return; dd_expression_equal(a); } else { if(S_cins(c,"();,{}"))return; switch(dd_calculator_operator(d_parse_string)) { // inbetween operators case DOP_AND: d_parse_next();dd_expression_equal(h)/*next argument of */; S_copy(dd_true(a)&&dd_true(h)?"1":"0",StringSize,a); break; case DOP_OR: d_parse_next();dd_expression_equal(h)/*next argument of */; S_copy(dd_true(a)||dd_true(h)?"1":"0",StringSize,a); break; default: //i.e. operator with lower precedence: exit return; break; } } tokensread++; } } void dd_expression_choice(char *a) {// look for ?: statement int c; char h[StringSize]; S_clear(a); dd_expression_and(a); //one level lower c=d_parse_preview(); if(c=='?') { int choice; choice=dd_true(a); d_parse_next();// the ? dd_expression_choice(h); if(choice)Copy(h,a); if(d_parse_next()!=':')dd_syntax_expected(":",d_parse_string); dd_expression_choice(h); if(!choice)Copy(h,a); } } S_fifo dd_expression_fifo; int dd_expression_fifo_initialized=0; void dd_expression_push(char *g) {S_fifo_write(&dd_expression_fifo,g,1);} ///////////////// dd_expression() //////////////////// char dd_expression(char *g) // //string result in g, but g may be NULL //return first character of g { char a[StringSize],h[StringSize]; char c; S_clear(a); //accumulator if(!dd_expression_fifo_initialized){S_fifo_init(&dd_expression_fifo);dd_expression_fifo_initialized=1;} if(S_fifo_read(&dd_expression_fifo,h)) { if(g)Copy(h,g); if(Gelijk(h,","))return(',');else return('a');//should be better making distinction of special chars }; c=d_parse_preview(); switch(c) { case'(': //string concatenation d_parse_next(); //the ( while(c=d_parse_preview(),c!='\0'&&c!=')') { dd_expression(h); S_sappend(a,h,StringSize); } d_parse_next(); //the closing ) break; case';':case',':case')':case'\0':case'{':case'}':case'=': d_parse_next(); Copy(d_parse_string,a); //return(c); // these standalone tokens always end expressions // also = break; default: // first higher precedence level dd_expression_choice(a); break; } if(g)Copy(a,g); //printf("[%s]",g); return(a[0]); } ////////////////////dd_argument() /////////////////////// int dd_argument(int number,char *h) //number: of sequence of arguments: 0: read first, +:read next, -1:read last //returns 0 if not valid argument is read, otherwise number+1; { char c, hulps[StringSize]; if(number==0) //read first argument and opening ( { if(d_parse_next()!='(')dd_syntax_expected("(",d_parse_string); dd_expression(h); if(Gelijk(h,")"))return(0); } else if(number== -1) //read last argument and closing ) { dd_expression(h); if(Gelijk(h,")")){dd_syntax_expected(",",h);return(0);} dd_expression(h); if(Gelijk(h,")"))dd_syntax_expected("argument",h); dd_expression(hulps); if(!Gelijk(hulps,")"))dd_syntax_expected("closing )",hulps); return(-1); } else { dd_expression(h); if(Gelijk(h,")"))return(0); if(Gelijk(h,","))dd_expression(h); else dd_syntax_expected(",",h); } return(number+1); } #define D_CALC_INCLUDED #endif