/* -*- c -*- * File: exprtool.c * Author: Igor Vlasenko <vlasenko@imath.kiev.ua> * Created: Mon Jul 25 15:29:17 2005 * * $Id$ */ /* #include "exprtool.h" #include <ctype.h> // for yylex alnum #include <stdio.h> // for printf */ #define EXPR_CHECK_NUMBER(exprobj, ptr) switch (ptr->type) { \ case EXPR_TYPE_INT: case EXPR_TYPE_DBL: break; \ case EXPR_TYPE_UPSTR: case EXPR_TYPE_PSTR: expr_to_num(exprobj, ptr); break; \ default: _tmplpro_expnum_debug(*ptr, "FATAL:internal expr type error. please report\n"); \ ptr->type = EXPR_TYPE_INT; \ } #define EXPR_CHECK_LOGICAL(exprobj, ptr) switch (ptr->type) { \ case EXPR_TYPE_INT: case EXPR_TYPE_DBL: break; \ case EXPR_TYPE_UPSTR: case EXPR_TYPE_PSTR: expr_to_bool(exprobj, ptr); break; \ default: _tmplpro_expnum_debug(*ptr, "FATAL:internal expr type error. please report\n"); \ ptr->type = EXPR_TYPE_INT; \ } static EXPR_char expr_to_int_or_dbl (struct expr_parser* exprobj, struct exprval* val1, struct exprval* val2) { EXPR_CHECK_NUMBER(exprobj, val1); EXPR_CHECK_NUMBER(exprobj, val2); if ((val1->type == EXPR_TYPE_INT) && (val2->type == EXPR_TYPE_INT)) return EXPR_TYPE_INT; if ((val1->type == EXPR_TYPE_DBL) && (val2->type == EXPR_TYPE_DBL)) return EXPR_TYPE_DBL; if (val1->type == EXPR_TYPE_INT) { val1->type=EXPR_TYPE_DBL; val1->val.dblval=(double) val1->val.intval; } if (val2->type == EXPR_TYPE_INT) { val1->type=EXPR_TYPE_DBL; val2->val.dblval=(double) val2->val.intval; } return EXPR_TYPE_DBL; } static EXPR_char expr_to_int_or_dbl_logop (struct expr_parser* exprobj, struct exprval* val1, struct exprval* val2) { EXPR_CHECK_LOGICAL(exprobj, val1); EXPR_CHECK_LOGICAL(exprobj, val2); if (val1->type == EXPR_TYPE_INT && val2->type == EXPR_TYPE_INT) return EXPR_TYPE_INT; if (val1->type == EXPR_TYPE_DBL && val2->type == EXPR_TYPE_DBL) return EXPR_TYPE_DBL; if (val1->type == EXPR_TYPE_INT) { val1->type=EXPR_TYPE_DBL; val1->val.dblval=(double) val1->val.intval; } if (val2->type == EXPR_TYPE_INT) { val1->type=EXPR_TYPE_DBL; val2->val.dblval=(double) val2->val.intval; } return EXPR_TYPE_DBL; } static EXPR_char expr_to_int_or_dbl_logop1 (struct expr_parser* exprobj, struct exprval* val1) { EXPR_CHECK_LOGICAL(exprobj, val1); return val1->type; } static EXPR_char expr_to_int_or_dbl1 (struct expr_parser* exprobj, struct exprval* val1) { EXPR_CHECK_NUMBER(exprobj, val1); return val1->type; } static void expr_to_dbl1 (struct expr_parser* exprobj, struct exprval* val1) { EXPR_CHECK_NUMBER(exprobj, val1); if (val1->type == EXPR_TYPE_INT) { val1->type=EXPR_TYPE_DBL; val1->val.dblval=(double) val1->val.intval; } } static void expr_to_int1 (struct expr_parser* exprobj, struct exprval* val1) { EXPR_CHECK_NUMBER(exprobj, val1); if (val1->type == EXPR_TYPE_DBL) { val1->type=EXPR_TYPE_INT; val1->val.intval=(EXPR_int64) val1->val.dblval; /* _tmplpro_expnum_debug(*val1, "WARN:converting to `int' from `double'"); */ } } static void expr_to_dbl (struct expr_parser* exprobj, struct exprval* val1, struct exprval* val2) { expr_to_dbl1(exprobj, val1); expr_to_dbl1(exprobj, val2); } static void expr_to_int (struct expr_parser* exprobj, struct exprval* val1, struct exprval* val2) { expr_to_int1(exprobj, val1); expr_to_int1(exprobj, val2); } #define EXPR_CHECK_STRING(pbuff, ptr) switch (ptr->type) { \ case EXPR_TYPE_PSTR: break; \ case EXPR_TYPE_UPSTR: ptr->val.strval=expr_unescape_pstring_val(pbuff,ptr->val.strval); break; \ case EXPR_TYPE_INT: ptr->val.strval=int_to_pstring(ptr->val.intval,pbuffer_string(pbuff),pbuffer_size(pbuff)); break; \ case EXPR_TYPE_DBL: ptr->val.strval=double_to_pstring(ptr->val.dblval,pbuffer_string(pbuff),pbuffer_size(pbuff)); break; \ default: _tmplpro_expnum_debug(*ptr, "FATAL:internal expr string error. please report\n"); \ } \ ptr->type = EXPR_TYPE_PSTR; static void expr_to_str (struct tmplpro_state* state, struct exprval* val1, struct exprval* val2) { EXPR_CHECK_STRING(&(state->expr_left_pbuffer), val1); EXPR_CHECK_STRING(&(state->expr_right_pbuffer), val2); } static void expr_to_str1 (struct tmplpro_state* state, struct exprval* val1) { EXPR_CHECK_STRING(&(state->expr_left_pbuffer), val1); } static int is_float_lex (char c) { return (c == '.' || isdigit (c)); } static struct exprval exp_read_number (struct expr_parser* exprobj, const char* *curposptr, const char* endchars) { char c = **curposptr; struct exprval retval; EXPR_int64 iretval=0; double dretval=0; EXPR_int64 offset=0; int sign=1; retval.type=EXPR_TYPE_INT; retval.val.intval=0; if ((*curposptr)<endchars && '-' == c) { sign=-1; c = *(++(*curposptr)); } if (! (c == '.' || isdigit (c))) return retval; /* double reader yylval.dblval=atof(fill_symbuf(is_float_lex).begin); return dblNUM; */ while ((*curposptr)<endchars && is_float_lex(c)) { if (c == '.') { if (retval.type == EXPR_TYPE_INT) { retval.type = EXPR_TYPE_DBL; dretval=iretval; offset=1; } else { /* (*curposptr)--; ??? */ log_expr(exprobj, TMPL_LOG_ERROR, "while reading number: %s\n", "uninspected declimal point"); retval.val.dblval=dretval*sign; retval.type=EXPR_TYPE_DBL; return retval; } } else { offset*=10; if (retval.type == EXPR_TYPE_INT) { iretval=iretval*10+c-'0'; } else { dretval=dretval*10+c-'0'; } } c = *(++(*curposptr)); } if (retval.type == EXPR_TYPE_INT) { retval.val.intval=iretval*sign; } else { if (offset) dretval/=offset; retval.val.dblval=dretval*sign; } return retval; } static void expr_to_num (struct expr_parser* exprobj, struct exprval* val1) { const char* curpos=val1->val.strval.begin; EXPR_char type = val1->type; if (type == EXPR_TYPE_PSTR || type == EXPR_TYPE_UPSTR) { if (NULL==curpos) { val1->type = EXPR_TYPE_INT; val1->val.intval = 0; } else { /* escaped string can't be read properly anyway */ *val1=exp_read_number (exprobj, &curpos, val1->val.strval.endnext); } } } static void expr_to_bool (struct expr_parser* exprobj, struct exprval* val1) { if (val1->type == EXPR_TYPE_PSTR || val1->type == EXPR_TYPE_UPSTR) { const char* begin=val1->val.strval.begin; const char* end=val1->val.strval.endnext; const char* curpos=begin; if (begin==end) { val1->type = EXPR_TYPE_INT; val1->val.intval = 0; } else { *val1=exp_read_number (exprobj, &curpos, end); if (val1->type == EXPR_TYPE_INT) { if (val1->val.intval || (curpos == end)) return; else val1->val.intval=1; /* strings are true in perl */ } else if (val1->type == EXPR_TYPE_DBL) { if (val1->val.dblval || (curpos == end)) return; else val1->val.dblval=1.0; /* strings are true in perl */ } } } } static void _tmplpro_expnum_debug (struct exprval val, char* msg) { tmpl_log(TMPL_LOG_DEBUG,"--> debug %s:type %c ",msg,val.type); if (val.type == EXPR_TYPE_INT) tmpl_log(TMPL_LOG_DEBUG,"ival=%" EXPR_PRId64 "\n",val.val.intval); else if (val.type == EXPR_TYPE_DBL) tmpl_log(TMPL_LOG_DEBUG,"dval=%f\n",val.val.dblval); else if (val.type == EXPR_TYPE_PSTR) { tmpl_log(TMPL_LOG_DEBUG,"pstr(%c):",(int) val.type); if (NULL==val.val.strval.begin) tmpl_log(TMPL_LOG_DEBUG,"{begin=NULL}"); if (NULL==val.val.strval.endnext) tmpl_log(TMPL_LOG_DEBUG,"{endnext=NULL}"); tmpl_log(TMPL_LOG_DEBUG,"sval=%.*s\n",(int)(val.val.strval.endnext-val.val.strval.begin),val.val.strval.begin); } else if (val.type == EXPR_TYPE_NULL) { tmpl_log(TMPL_LOG_DEBUG,"NULL\n"); if (NULL!=val.val.strval.begin) tmpl_log(TMPL_LOG_DEBUG,"{begin!=NULL}"); if (NULL!=val.val.strval.endnext) tmpl_log(TMPL_LOG_DEBUG,"{endnext!=NULL}"); } else { tmpl_log(TMPL_LOG_DEBUG,"unknown(%c) as ival=%" EXPR_PRId64 "\n",(int) val.type,val.val.intval); } } /* * checks if it is stringval and unescape it (copies to the buffer). * it implies that only one string at a time can use buffer. */ static PSTRING expr_unescape_pstring_val(pbuffer* pbuff, PSTRING val) { PSTRING retval; const char* curpos = val.begin; const char* endnext= val.endnext; char* buf=pbuffer_resize(pbuff, endnext-curpos+1); char* bufpos = buf; while (curpos < endnext) { if (*curpos == '\\') { *bufpos=*(++curpos); } else { *bufpos=*curpos; } curpos++; bufpos++; } retval.begin = buf; retval.endnext = bufpos; return retval; }