1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289
|
/* -*- 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;
}
|