5267b71995-08-09Fredrik Hübinette (Hubbe) #include <math.h> #include "global.h" #include "interpret.h" #include "svalue.h" #include "list.h" #include "mapping.h" #include "array.h" #include "stralloc.h" #include "opcodes.h" #include "operators.h" #include "language.h" #include "memory.h" #include "error.h" #define COMPARISON(ID,EXPR) \ void ID() \ { \ int i=EXPR; \ pop_n_elems(2); \ sp->type=T_INT; \ sp->u.integer=i; \ sp++; \ } COMPARISON(f_eq, is_eq(sp-2,sp-1)) COMPARISON(f_ne,!is_eq(sp-2,sp-1)) COMPARISON(f_lt, is_lt(sp-2,sp-1)) COMPARISON(f_le,!is_gt(sp-2,sp-1)) COMPARISON(f_gt, is_gt(sp-2,sp-1)) COMPARISON(f_ge,!is_lt(sp-2,sp-1)) void f_sum(INT32 args) { INT32 e,size; TYPE_FIELD types; types=0; for(e=-args;e<0;e++) types|=1<<sp[e].type; switch(types) { default: if(args) { switch(sp[-args].type) { case T_OBJECT: case T_PROGRAM: case T_FUNCTION: error("Bad argument 1 to summation\n"); } } error("Incompatible types to sum() or +\n"); return; /* compiler hint */ case BIT_STRING: { struct lpc_string *r; char *buf; if(args==1) return; size=0; for(e=-args;e<0;e++) size+=sp[e].u.string->len; if(args==2) { r=add_shared_strings(sp[-2].u.string,sp[-1].u.string); }else{ r=begin_shared_string(size); buf=r->str; for(e=-args;e<0;e++) { MEMCPY(buf,sp[e].u.string->str,sp[e].u.string->len); buf+=sp[e].u.string->len; } r=end_shared_string(r); } for(e=-args;e<0;e++) { free_string(sp[e].u.string); } sp-=args; push_string(r); break; } case BIT_STRING | BIT_INT: case BIT_STRING | BIT_FLOAT: case BIT_STRING | BIT_FLOAT | BIT_INT: { struct lpc_string *r; char *buf,*str; size=0; for(e=-args;e<0;e++) { switch(sp[e].type) { case T_STRING: size+=sp[e].u.string->len; break; case T_INT: size+=14; break; case T_FLOAT: size+=22; break; } } str=buf=xalloc(size+1); size=0; for(e=-args;e<0;e++) { switch(sp[e].type) { case T_STRING: MEMCPY(buf,sp[e].u.string->str,sp[e].u.string->len); buf+=sp[e].u.string->len; break; case T_INT: sprintf(buf,"%ld",sp[e].u.integer); buf+=strlen(buf); break; case T_FLOAT: sprintf(buf,"%f",(double)sp[e].u.float_number); buf+=strlen(buf); break; } } r=make_shared_binary_string(str,buf-str); free(str); pop_n_elems(args); push_string(r); break; } case BIT_INT: size=0; for(e=-args; e<0; e++) size+=sp[e].u.integer; sp-=args-1; sp[-1].u.integer=size; break; case BIT_FLOAT: { FLOAT_TYPE sum; sum=0.0; for(e=-args; e<0; e++) sum+=sp[e].u.float_number; sp-=args-1; sp[-1].u.float_number=sum; break; } case BIT_ARRAY: { struct array *a; a=add_arrays(sp-args,args); pop_n_elems(args); push_array(a); break; } case BIT_MAPPING: { struct mapping *m; m = add_mappings(sp - args, args); pop_n_elems(args); push_mapping(m); break; } case BIT_LIST: { struct list *l; l = add_lists(sp - args, args); pop_n_elems(args); push_list(l); break; } } } void f_add() { f_sum(2); } void f_subtract() { if (sp[-2].type != sp[-1].type ) error("Subtract on different types.\n"); switch(sp[-1].type) { case T_ARRAY: { struct array *a; check_array_for_destruct(sp[-2].u.array); check_array_for_destruct(sp[-1].u.array); a = subtract_arrays(sp[-2].u.array, sp[-1].u.array); pop_n_elems(2); push_array(a); return; } case T_MAPPING: { struct mapping *m; m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping,OP_SUB); pop_n_elems(2); push_mapping(m); return; } case T_LIST: { struct list *l; l=merge_lists(sp[-2].u.list, sp[-1].u.list, OP_SUB); pop_n_elems(2); push_list(l); return; } case T_FLOAT: sp--; sp[-1].u.float_number -= sp[0].u.float_number; return; case T_INT: sp--; sp[-1].u.integer -= sp[0].u.integer; return; case T_STRING: { struct lpc_string *s,*ret; sp--; s=make_shared_string(""); ret=string_replace(sp[-1].u.string,sp[0].u.string,s); free_string(sp[-1].u.string); free_string(sp[0].u.string); free_string(s); sp[-1].u.string=ret; return; } default: error("Bad argument 1 to subtraction.\n"); } } void f_and() { if(sp[-1].type != sp[-2].type) error("Bitwise and on different types.\n"); switch(sp[-2].type) { case T_INT: sp--; sp[-1].u.integer &= sp[0].u.integer; break; case T_MAPPING: { struct mapping *m; m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_AND); pop_n_elems(2); push_mapping(m); return; } case T_LIST: { struct list *l; l=merge_lists(sp[-2].u.list, sp[-1].u.list, OP_AND); pop_n_elems(2); push_list(l); return; } case T_ARRAY: { struct array *a; a=and_arrays(sp[-2].u.array, sp[-1].u.array); pop_n_elems(2); push_array(a); return; } default: error("Bitwise and on illegal type.\n"); } } void f_or() { if(sp[-1].type != sp[-2].type) error("Bitwise or on different types.\n"); switch(sp[-2].type) { case T_INT: sp--; sp[-1].u.integer |= sp[0].u.integer; break; case T_MAPPING: { struct mapping *m; m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_OR); pop_n_elems(2); push_mapping(m); return; } case T_LIST: { struct list *l; l=merge_lists(sp[-2].u.list, sp[-1].u.list, OP_OR); pop_n_elems(2); push_list(l); return; } case T_ARRAY: { struct array *a; a=merge_array_without_order(sp[-2].u.array, sp[-1].u.array, OP_OR); pop_n_elems(2); push_array(a); return; } default: error("Bitwise or on illegal type.\n"); } } void f_xor() { if(sp[-1].type != sp[-2].type) error("Bitwise xor on different types.\n"); switch(sp[-2].type) { case T_INT: sp--; sp[-1].u.integer ^= sp[0].u.integer; break; case T_MAPPING: { struct mapping *m; m=merge_mappings(sp[-2].u.mapping, sp[-1].u.mapping, OP_XOR); pop_n_elems(2); push_mapping(m); return; } case T_LIST: { struct list *l; l=merge_lists(sp[-2].u.list, sp[-1].u.list, OP_XOR); pop_n_elems(2); push_list(l); return; } case T_ARRAY: { struct array *a; a=merge_array_without_order(sp[-2].u.array, sp[-1].u.array, OP_XOR); pop_n_elems(2); push_array(a); return; } default: error("Bitwise xor on illegal type.\n"); } } void f_lsh() { if(sp[-2].type != T_INT) error("Bad argument 1 to <<\n"); if(sp[-1].type != T_INT) error("Bad argument 2 to <<\n"); sp--; sp[-1].u.integer <<= sp[0].u.integer; } void f_rsh() { if(sp[-2].type != T_INT) error("Bad argument 1 to >>\n"); if(sp[-1].type != T_INT) error("Bad argument 2 to >>\n"); sp--; sp[-1].u.integer >>= sp[0].u.integer; } void f_multiply() { switch(sp[-2].type) { case T_ARRAY: if(sp[-1].type!=T_STRING) { error("Bad argument 2 to multiply.\n"); }else{ struct lpc_string *ret; sp--; ret=implode(sp[-1].u.array,sp[0].u.string); free_string(sp[0].u.string); free_array(sp[-1].u.array); sp[-1].type=T_STRING; sp[-1].u.string=ret; return; } case T_FLOAT: if(sp[-1].type!=T_FLOAT) error("Bad argument 2 to multiply.\n"); sp--; sp[-1].u.float_number *= sp[0].u.float_number; return; case T_INT: if(sp[-1].type!=T_INT) error("Bad argument 2 to multiply.\n"); sp--; sp[-1].u.integer *= sp[0].u.integer; return; default: error("Bad argument 1 to multiply.\n"); } } void f_divide() { if(sp[-2].type!=sp[-1].type) error("Division on different types.\n"); switch(sp[-2].type) { case T_STRING: { struct array *ret; sp--; ret=explode(sp[-1].u.string,sp[0].u.string); free_string(sp[-1].u.string); free_string(sp[0].u.string); sp[-1].type=T_ARRAY; sp[-1].u.array=ret; return; } case T_FLOAT: if(sp[-1].u.float_number == 0.0) error("Division by zero.\n"); sp--; sp[-1].u.float_number /= sp[0].u.float_number; return; case T_INT: if (sp[-1].u.integer == 0) error("Division by zero\n"); sp--; sp[-1].u.integer /= sp[0].u.integer; return; default: error("Bad argument 1 to divide.\n"); } } void f_mod() { if(sp[-2].type != sp[-1].type) error("Modulo on different types.\n"); switch(sp[-1].type) { case T_FLOAT: { FLOAT_TYPE foo; if(sp[-1].u.float_number == 0.0) error("Modulo by zero.\n"); sp--; foo=sp[-1].u.float_number / sp[0].u.float_number; foo=sp[-1].u.float_number - sp[0].u.float_number * floor(foo); sp[-1].u.float_number=foo; return; } case T_INT: if (sp[-1].u.integer == 0) error("Modulo by zero.\n"); sp--; sp[-1].u.integer %= sp[0].u.integer; return; default: error("Bad argument 1 to modulo.\n"); } } void f_not() { if(sp[-1].type==T_INT) { sp[-1].u.integer = !sp[-1].u.integer; }else{ pop_stack(); sp->type=T_INT; sp->u.integer=0; sp++; } } void f_compl() { if (sp[-1].type != T_INT) error("Bad argument to ~\n"); sp[-1].u.integer = ~ sp[-1].u.integer; } void f_negate() { switch(sp[-1].type) { case T_FLOAT: sp[-1].u.float_number=-sp[-1].u.float_number; return; case T_INT: sp[-1].u.integer = - sp[-1].u.integer; return; default: error("Bad argument to unary minus\n"); } } void f_range() { INT32 from,to; if(sp[-2].type != T_INT) error("Bad argument 1 to [ .. ]\n"); if(sp[-1].type != T_INT) error("Bad argument 2 to [ .. ]\n"); from=sp[-2].u.integer; if(from<0) from=0; to=sp[-1].u.integer; if(to<from-1) to=from-1; sp-=2; switch(sp[-1].type) { case T_STRING: { struct lpc_string *s; if(to>=sp[-1].u.string->len-1) { if(from==0) return; to=sp[-1].u.string->len-1; if(from>to+1) from=to+1; } s=make_shared_binary_string(sp[-1].u.string->str+from,to-from+1); free_string(sp[-1].u.string); sp[-1].u.string=s; break; } case T_ARRAY: { struct array *a; if(to>=sp[-1].u.array->size-1) { to=sp[-1].u.array->size-1; if(from>to+1) from=to+1; } a=slice_array(sp[-1].u.array,from,to+1); free_array(sp[-1].u.array); sp[-1].u.array=a; break; } default: error("[ .. ] can only be done on strings and arrays.\n"); } }