diff --git a/lib/simulate.lpc b/lib/simulate.lpc index f2d317a52ebaa3b0bfd89f4f31144b510b6a7423..80b96aac1be9381bcd90e4ce9385cd6a14e0d1c1 100644 --- a/lib/simulate.lpc +++ b/lib/simulate.lpc @@ -288,7 +288,7 @@ varargs mixed *sort_array(array foo,function cmp,mixed ... args) if(sizeof(foo)<2) return copy_value(foo); - if(!cmp) cmp=lambda(mixed a,mixed b) { return a > b; }; + if(!cmp) cmp=`>; a=sort_array(foo[0..sizeof(foo)/2-1],cmp,@args); b=sort_array(foo[sizeof(foo)/2..sizeof(foo)],cmp,@args); @@ -342,6 +342,7 @@ list mklist(mixed *a) void create() { add_efun("PI",3.1415926535897932384626433832795080); + add_efun("sum",`+); add_efun("capitalize",capitalize); add_efun("code_value",code_value); add_efun("exec","exec"); @@ -365,7 +366,7 @@ void create() add_efun("strstr",search); add_efun("sum_arrays",sum_arrays); add_efun("this_function",this_function); - add_efun("version",lambda() { return "uLPC v1.0E-11"; }); + add_efun("version",lambda() { return "uLPC v1.0E-10"; }); add_efun("write_file",write_file); add_efun("get_function",get_function); add_efun("regexp",regexp); diff --git a/src/add_efun.c b/src/add_efun.c index 86ce35af757739e48f461dcab760586326207fef..7c35fa8cf2ca8a271c10f01e4f3215617e40826b 100644 --- a/src/add_efun.c +++ b/src/add_efun.c @@ -53,7 +53,12 @@ void low_add_efun(struct lpc_string *name, struct svalue *fun) } -struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags) +struct callable *make_callable(c_fun fun, + char *name, + char *type, + INT16 flags, + optimize_fun optimize, + docode_fun docode) { struct callable *f; f=ALLOC_STRUCT(callable); @@ -62,6 +67,8 @@ struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags) f->name=make_shared_string(name); f->type=parse_type(type); f->flags=flags; + f->docode=docode; + f->optimize=optimize; return f; } @@ -72,7 +79,12 @@ void really_free_callable(struct callable *fun) free((char *)fun); } -void add_efun(char *name, c_fun fun, char *type, INT16 flags) +void add_efun2(char *name, + c_fun fun, + char *type, + INT16 flags, + optimize_fun optimize, + docode_fun docode) { struct svalue s; struct lpc_string *n; @@ -80,12 +92,17 @@ void add_efun(char *name, c_fun fun, char *type, INT16 flags) n=make_shared_string(name); s.type=T_FUNCTION; s.subtype=-1; - s.u.efun=make_callable(fun, name, type, flags); + s.u.efun=make_callable(fun, name, type, flags, optimize, docode); low_add_efun(n, &s); free_svalue(&s); free_string(n); } +void add_efun(char *name, c_fun fun, char *type, INT16 flags) +{ + add_efun2(name,fun,type,flags,0,0); +} + static void push_efun_entry(struct hash_entry *h) { struct efun *f; diff --git a/src/add_efun.h b/src/add_efun.h index f27b34a2c26e2c50f498e90f7a7ae251e7918b0d..2400328411ee9449f7a42355df66cce6c57c4fa6 100644 --- a/src/add_efun.h +++ b/src/add_efun.h @@ -17,6 +17,8 @@ struct efun }; typedef void (*c_fun)(INT32); +typedef int (*docode_fun)(node *n); +typedef void (*optimize_fun)(node *n); struct callable { @@ -25,13 +27,26 @@ struct callable struct lpc_string *type; struct lpc_string *name; INT16 flags; + optimize_fun optimize; + docode_fun docode; }; /* Prototypes begin here */ struct efun *lookup_efun(struct lpc_string *name); void low_add_efun(struct lpc_string *name, struct svalue *fun); -struct callable *make_callable(c_fun fun,char *name, char *type, INT16 flags); +struct callable *make_callable(c_fun fun, + char *name, + char *type, + INT16 flags, + optimize_fun optimize, + docode_fun docode); void really_free_callable(struct callable *fun); +void add_efun2(char *name, + c_fun fun, + char *type, + INT16 flags, + optimize_fun optimize, + docode_fun docode); void add_efun(char *name, c_fun fun, char *type, INT16 flags); void push_all_efuns_on_stack(); void cleanup_added_efuns(); diff --git a/src/builtin_efuns.c b/src/builtin_efuns.c index 28120bf6e97b1c5bbc78a19c1efe34fa3cc92246..aa094a6853eb609b693ce2cdb0eb4256d8416039 100644 --- a/src/builtin_efuns.c +++ b/src/builtin_efuns.c @@ -1234,6 +1234,8 @@ TYPEP(f_floatp, "floatp", T_FLOAT) void init_builtin_efuns() { + init_operators(); + add_efun("add_efun",f_add_efun,"function(string,void|mixed:void)",OPT_SIDE_EFFECT); add_efun("aggregate",f_aggregate,"function(mixed ...:mixed *)",OPT_TRY_OPTIMIZE); add_efun("aggregate_list",f_aggregate_list,"function(mixed ...:list)",OPT_TRY_OPTIMIZE); @@ -1286,7 +1288,7 @@ void init_builtin_efuns() add_efun("sizeof", f_sizeof, "function(string|list|array|mapping:int)",0); add_efun("sleep", f_sleep, "function(int:void)",OPT_SIDE_EFFECT); add_efun("stringp", f_stringp, "function(mixed:int)",0); - add_efun("sum",f_sum,"function(int ...:int)|function(float ...:float)|function(string,string|int|float ...:string)|function(string,string|int|float ...:string)|function(int|float,string,string|int|float:string)|function(array ...:array)|function(mapping ...:mapping)|function(list...:list)",0); + add_efun("this_object", f_this_object, "function(:object)",OPT_EXTERNAL_DEPEND); add_efun("throw",f_throw,"function(mixed:void)",0); add_efun("time",f_time,"function(void|int:int)",OPT_EXTERNAL_DEPEND); diff --git a/src/docode.c b/src/docode.c index 4421a16df0152421765eb630f62509ad121a7251..3eab7112dde70b57ecc162e3d8faf52295b0f619 100644 --- a/src/docode.c +++ b/src/docode.c @@ -389,7 +389,7 @@ static int do_docode2(node *n,int flags); #define DO_CODE_BLOCK(N) do_pop(do_docode(N,DO_NOT_COPY | DO_POP)) -static int do_docode(node *n,INT16 flags) +int do_docode(node *n,INT16 flags) { int i; int save_current_line=current_line; @@ -535,6 +535,9 @@ static int do_docode2(node *n,int flags) if(tmp2 < tmp1) tmp1=tmp2; + if(tmp1 == -1) + fatal("Unknown number of args in ? :\n"); + tmp2=do_jump_when_zero(CAR(n),-1); tmp3=do_docode(CADR(n), flags); @@ -873,26 +876,46 @@ static int do_docode2(node *n,int flags) return 1; case F_APPLY: - ins_f_byte(F_MARK); if(CAR(n)->token == F_CONSTANT) { - do_docode(CDR(n),0); - if(CAR(n)->u.sval.type == T_FUNCTION && - CAR(n)->u.sval.subtype != -1 && - CAR(n)->u.sval.u.object == &fake_object) + if(CAR(n)->u.sval.type == T_FUNCTION) { - ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.sval.subtype); - }else{ - tmp1=store_constant(& CAR(n)->u.sval, - !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND)); - ins_f_byte(F_MAX_OPCODE + tmp1); - if(n->type == void_type_string) return 0; + if(CAR(n)->u.sval.subtype == -1) /* driver fun? */ + { + if(!CAR(n)->u.sval.u.efun->docode || + !CAR(n)->u.sval.u.efun->docode(n)) + { + ins_f_byte(F_MARK); + do_docode(CDR(n),0); + tmp1=store_constant(& CAR(n)->u.sval, + !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND)); + ins_f_byte(F_MAX_OPCODE + tmp1); + } + if(n->type == void_type_string) return 0; + return 1; + }else{ + if(CAR(n)->u.sval.u.object == &fake_object) + { + ins_f_byte(F_MARK); + do_docode(CDR(n),0); + ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.sval.subtype); + return 1; + } + } } + + ins_f_byte(F_MARK); + do_docode(CDR(n),0); + tmp1=store_constant(& CAR(n)->u.sval, + !(CAR(n)->tree_info & OPT_EXTERNAL_DEPEND)); + ins_f_byte(F_MAX_OPCODE + tmp1); + return 1; } else if(CAR(n)->token == F_IDENTIFIER && ID_FROM_INT(& fake_program, CAR(n)->u.number)->flags & IDENTIFIER_FUNCTION) { + ins_f_byte(F_MARK); do_docode(CDR(n),0); ins_f_byte_with_numerical_arg(F_CALL_LFUN, CAR(n)->u.number); return 1; @@ -902,6 +925,7 @@ static int do_docode2(node *n,int flags) struct lpc_string *tmp; struct efun *fun; + ins_f_byte(F_MARK); tmp=make_shared_string("call_function"); if(!tmp) yyerror("No call_function efun."); fun=lookup_efun(tmp); diff --git a/src/docode.h b/src/docode.h index 78bf2f8230cc107c200ce8fb5e096f7fa476f7ba..8f87b05b8d3acf2e28f39b1ff45364cbcc71939f 100644 --- a/src/docode.h +++ b/src/docode.h @@ -6,6 +6,10 @@ #ifndef DOCODE_H #define DOCODE_H +#define DO_LVALUE 1 +#define DO_NOT_COPY 2 +#define DO_POP 4 + extern int store_linenumbers; extern int comp_stackp; extern INT32 comp_stack[COMPILER_STACK_SIZE]; @@ -14,12 +18,14 @@ extern INT32 comp_stack[COMPILER_STACK_SIZE]; void ins_byte(unsigned char b,int area); void ins_signed_byte(char b,int area); void ins_short(INT16 l,int area); -void ins_long(long l,int area); +void ins_long(INT32 l,int area); void ins_f_byte(unsigned int b); void push_address(); -void push_explicit(int address); -int pop_address(); +void push_explicit(INT32 address); +INT32 pop_address(); struct jump; +struct jump_list; +int do_docode(node *n,INT16 flags); int docode(node *n); void do_code_block(node *n); /* Prototypes end here */ diff --git a/src/interpret.c b/src/interpret.c index ce61e6db18369afc3424593b7008308c7ddab89d..117e643c83981cd708223deb820f1755a5fa65a8 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -797,14 +797,14 @@ static void eval_instruction(unsigned char *pc) COMPARISMENT(F_LT, is_lt(sp-2,sp-1)); COMPARISMENT(F_LE,!is_gt(sp-2,sp-1)); - CASE(F_ADD); f_sum(2); break; - CASE(F_SUBTRACT); f_subtract(); break; - CASE(F_AND); f_and(); break; - CASE(F_OR); f_or(); break; - CASE(F_XOR); f_xor(); break; - CASE(F_MULTIPLY); f_multiply(); break; - CASE(F_DIVIDE); f_divide(); break; - CASE(F_MOD); f_mod(); break; + CASE(F_ADD); f_add(2); break; + CASE(F_SUBTRACT); o_subtract(); break; + CASE(F_AND); o_and(); break; + CASE(F_OR); o_or(); break; + CASE(F_XOR); o_xor(); break; + CASE(F_MULTIPLY); o_multiply(); break; + CASE(F_DIVIDE); o_divide(); break; + CASE(F_MOD); o_mod(); break; CASE(F_PUSH_ARRAY); if(sp[-1].type!=T_ARRAY) error("Bad argument to @\n"); @@ -819,7 +819,7 @@ static void eval_instruction(unsigned char *pc) CASE(F_CAST); f_cast(); break; - CASE(F_RANGE); f_range(); break; + CASE(F_RANGE); o_range(); break; CASE(F_COPY_VALUE); copy_svalues_recursively_no_free(sp,sp-1,1,0); sp++; diff --git a/src/language.y b/src/language.y index 46739d6791214206fd05cc476215adeb0909cb67..fc5266f752b1943e5f17793573a8145276b60e2c 100644 --- a/src/language.y +++ b/src/language.y @@ -879,22 +879,22 @@ assoc_pair: expr0 ':' expr1 expr1: expr2 | expr1 F_LOR expr1 { $$=mknode(F_LOR,$1,$3); } | expr1 F_LAND expr1 { $$=mknode(F_LAND,$1,$3); } - | expr1 '|' expr1 { $$=mknode(F_OR,$1,$3); } - | expr1 '^' expr1 { $$=mknode(F_XOR,$1,$3); } - | expr1 '&' expr1 { $$=mknode(F_AND,$1,$3); } - | expr1 F_EQ expr1 { $$=mknode(F_EQ,$1,$3); } - | expr1 F_NE expr1 { $$=mknode(F_NE,$1,$3); } - | expr1 '>' expr1 { $$=mknode(F_GT,$1,$3); } - | expr1 F_GE expr1 { $$=mknode(F_GE,$1,$3); } - | expr1 '<' expr1 { $$=mknode(F_LT,$1,$3); } - | expr1 F_LE expr1 { $$=mknode(F_LE,$1,$3); } - | expr1 F_LSH expr1 { $$=mknode(F_LSH,$1,$3); } - | expr1 F_RSH expr1 { $$=mknode(F_RSH,$1,$3); } - | expr1 '+' expr1 { $$=mknode(F_ADD,$1,$3); } - | expr1 '-' expr1 { $$=mknode(F_SUBTRACT,$1,$3); } - | expr1 '*' expr1 { $$=mknode(F_MULTIPLY,$1,$3); } - | expr1 '%' expr1 { $$=mknode(F_MOD,$1,$3); } - | expr1 '/' expr1 { $$=mknode(F_DIVIDE,$1,$3); } + | expr1 '|' expr1 { $$=mkopernode("`|",$1,$3); } + | expr1 '^' expr1 { $$=mkopernode("`^",$1,$3); } + | expr1 '&' expr1 { $$=mkopernode("`&",$1,$3); } + | expr1 F_EQ expr1 { $$=mkopernode("`==",$1,$3); } + | expr1 F_NE expr1 { $$=mkopernode("`!=",$1,$3); } + | expr1 '>' expr1 { $$=mkopernode("`>",$1,$3); } + | expr1 F_GE expr1 { $$=mkopernode("`>=",$1,$3); } + | expr1 '<' expr1 { $$=mkopernode("`<",$1,$3); } + | expr1 F_LE expr1 { $$=mkopernode("`<=",$1,$3); } + | expr1 F_LSH expr1 { $$=mkopernode("`<<",$1,$3); } + | expr1 F_RSH expr1 { $$=mkopernode("`>>",$1,$3); } + | expr1 '+' expr1 { $$=mkopernode("`+",$1,$3); } + | expr1 '-' expr1 { $$=mkopernode("`-",$1,$3); } + | expr1 '*' expr1 { $$=mkopernode("`*",$1,$3); } + | expr1 '%' expr1 { $$=mkopernode("`%",$1,$3); } + | expr1 '/' expr1 { $$=mkopernode("`/",$1,$3); } ; expr2: expr3 @@ -906,8 +906,8 @@ expr2: expr3 | F_INC expr4 { $$=mknode(F_INC,$2,0); } | F_DEC expr4 { $$=mknode(F_DEC,$2,0); } | F_NOT expr2 { $$=mknode(F_NOT,$2,0); } - | '~' expr2 { $$=mknode(F_COMPL,$2,0); } - | '-' expr2 { $$=mknode(F_NEGATE,$2,0); } + | '~' expr2 { $$=mkopernode("`~",$2,0); } + | '-' expr2 { $$=mkopernode("`-",$2,0); } ; expr3: expr4 diff --git a/src/las.c b/src/las.c index 8d3d7f8a9b5bc6c2334c95c2dc975df12e1d86e5..9f3165bdcfd1a4927a7c644d66ad3effa277c3ee 100644 --- a/src/las.c +++ b/src/las.c @@ -67,12 +67,17 @@ int cdr_is_node(node *n) INT32 count_args(node *n) { + int a,b; if(!n) return 0; switch(n->token) { case F_VAL_LVAL: case F_ARG_LIST: - return count_args(CAR(n)) + count_args(CDR(n)); + a=count_args(CAR(n)); + if(a==-1) return -1; + b=count_args(CDR(n)); + if(b==-1) return -1; + return a+b; case F_CAST: if(n->type == void_type_string) @@ -98,6 +103,7 @@ INT32 count_args(node *n) int tmp1,tmp2; tmp1=count_args(CDAR(n)); tmp2=count_args(CDAR(n)); + if(tmp1==-1 || tmp2==-2) return -1; if(tmp1 < tmp2) return tmp1; return tmp2; } @@ -267,6 +273,14 @@ node *mkefuncallnode(char *function, node *args) return mkapplynode(mksvaluenode(&fun->function), args); } +node *mkopernode(char *oper_id, node *arg1, node *arg2) +{ + if(arg1 && arg2) + arg1=mknode(F_ARG_LIST,arg1,arg2); + + return mkefuncallnode(oper_id, arg1); +} + node *mklocalnode(int var) { node *res = mkemptynode(); diff --git a/src/las.h b/src/las.h index 2b73993e158ab69f76b0cae22ba855e86c95633c..3d99b7328a42511fa5c8c5a0f8a6f55213e87edb 100644 --- a/src/las.h +++ b/src/las.h @@ -85,6 +85,7 @@ node *mkintnode(int nr); node *mkfloatnode(FLOAT_TYPE foo); node *mkapplynode(node *func,node *args); node *mkefuncallnode(char *function, node *args); +node *mkopernode(char *oper_id, node *arg1, node *arg2); node *mklocalnode(int var); node *mkidentifiernode(int i); node *mkcastnode(struct lpc_string *type,node *n); diff --git a/src/lex.c b/src/lex.c index 16f024b5782e8a82218bed1e2f792c8fe9cbfa81..173b4655d5421270b31a15b3b25c2a491fbc92d4 100644 --- a/src/lex.c +++ b/src/lex.c @@ -808,12 +808,12 @@ static void do_define() if(e==argc) { push_string(s2); - if(sp[-2].type==T_STRING) f_add(); + if(sp[-2].type==T_STRING) f_add(2); } if(c=='\n' || c==MY_EOF) { push_string(make_shared_string(" ")); - if(sp[-2].type==T_STRING) f_add(); + if(sp[-2].type==T_STRING) f_add(2); break; } t=!!isidchar(c); @@ -1507,6 +1507,61 @@ static int do_lex2(int literal, YYSTYPE *yylval) case '{': case ';': case '}': return c; + + case '`': + { + char *tmp; + switch(GETC()) + { + case '+': tmp="`+"; break; + case '-': tmp="`-"; break; + case '/': tmp="`/"; break; + case '%': tmp="`%"; break; + case '*': tmp="`*"; break; + case '&': tmp="`&"; break; + case '|': tmp="`|"; break; + case '^': tmp="`^"; break; + case '~': tmp="`~"; break; + case '(': + if(GOBBLE(')')) { tmp="`()"; break; } + + default: + yyerror("Illegal ` identifier."); + tmp=""; + break; + + case '<': + if(GOBBLE('<')) { tmp="`<<"; break; } + if(GOBBLE('=')) { tmp="`<="; break; } + tmp="`<"; + break; + + case '>': + if(GOBBLE('>')) { tmp="`>>"; break; } + if(GOBBLE('=')) { tmp="`>="; break; } + tmp="`>"; + break; + + case '!': + if(GOBBLE('=')) { tmp="`!="; break; } + tmp="`!"; + break; + + case '=': + if(GOBBLE('=')) { tmp="`=="; break; } + tmp="`="; + break; + } + + if(literal) + { + yylval->str=buf; + }else{ + yylval->string=make_shared_string(tmp); + } + return F_IDENTIFIER; + } + default: if(isidchar(c)) @@ -1679,9 +1734,9 @@ static void calcB() { switch(lookahead) { - case '-': low_lex(); calcB(); f_negate(); break; - case F_NOT: low_lex(); calcB(); f_not(); break; - case '~': low_lex(); calcB(); f_compl(); break; + case '-': low_lex(); calcB(); o_negate(); break; + case F_NOT: low_lex(); calcB(); o_not(); break; + case '~': low_lex(); calcB(); o_compl(); break; default: calcC(); } } @@ -1693,9 +1748,9 @@ static void calcA() { switch(lookahead) { - case '/': low_lex(); calcB(); f_divide(); continue; - case '*': low_lex(); calcB(); f_multiply(); continue; - case '%': low_lex(); calcB(); f_mod(); continue; + case '/': low_lex(); calcB(); o_divide(); continue; + case '*': low_lex(); calcB(); o_multiply(); continue; + case '%': low_lex(); calcB(); o_mod(); continue; } break; } @@ -1709,8 +1764,8 @@ static void calc9() { switch(lookahead) { - case '+': low_lex(); calcA(); f_add(); continue; - case '-': low_lex(); calcA(); f_subtract(); continue; + case '+': low_lex(); calcA(); f_add(2); continue; + case '-': low_lex(); calcA(); o_subtract(); continue; } break; } @@ -1724,8 +1779,8 @@ static void calc8() { switch(lookahead) { - case F_LSH: low_lex(); calc9(); f_lsh(); continue; - case F_RSH: low_lex(); calc9(); f_rsh(); continue; + case F_LSH: low_lex(); calc9(); o_lsh(); continue; + case F_RSH: low_lex(); calc9(); o_rsh(); continue; } break; } @@ -1739,10 +1794,10 @@ static void calc7b() { switch(lookahead) { - case '<': low_lex(); calc8(); f_lt(); continue; - case '>': low_lex(); calc8(); f_gt(); continue; - case F_GE: low_lex(); calc8(); f_ge(); continue; - case F_LE: low_lex(); calc8(); f_le(); continue; + case '<': low_lex(); calc8(); f_lt(2); continue; + case '>': low_lex(); calc8(); f_gt(2); continue; + case F_GE: low_lex(); calc8(); f_ge(2); continue; + case F_LE: low_lex(); calc8(); f_le(2); continue; } break; } @@ -1756,8 +1811,8 @@ static void calc7() { switch(lookahead) { - case F_EQ: low_lex(); calc7b(); f_eq(); continue; - case F_NE: low_lex(); calc7b(); f_ne(); continue; + case F_EQ: low_lex(); calc7b(); f_eq(2); continue; + case F_NE: low_lex(); calc7b(); f_ne(2); continue; } break; } @@ -1771,7 +1826,7 @@ static void calc6() { low_lex(); calc7(); - f_and(); + o_and(); } } @@ -1783,7 +1838,7 @@ static void calc5() { low_lex(); calc6(); - f_xor(); + o_xor(); } } @@ -1795,7 +1850,7 @@ static void calc4() { low_lex(); calc5(); - f_or(); + o_or(); } } diff --git a/src/modules/files/efuns.c b/src/modules/files/efuns.c index b2172ad6c46cb9c7fcfcef448b50f3cfa35f9d78..28cf14afc282707d0759570bf5157b9cd7eab455 100644 --- a/src/modules/files/efuns.c +++ b/src/modules/files/efuns.c @@ -301,7 +301,7 @@ void f_exece(INT32 args) push_string(a->string); a->string->refs++; - f_sum(3); + f_add(3); env[e]=sp[-1].u.string->str; } diff --git a/src/operators.c b/src/operators.c index 9b18904820fe0128210ac8d8ace88ab00cf4d78b..ae7a11c3dae29f2b9ae71a5ef9ef4ab25cc5f3f9 100644 --- a/src/operators.c +++ b/src/operators.c @@ -16,25 +16,33 @@ #include "language.h" #include "memory.h" #include "error.h" - -#define COMPARISON(ID,EXPR) \ -void ID() \ -{ \ - int i=EXPR; \ +#include "docode.h" +#include "add_efun.h" + +#define COMPARISON(ID,NAME,EXPR) \ +void ID(INT32 args) \ +{\ + int i; \ + if(args > 2) \ + pop_n_elems(args-2); \ + else if(args < 2) \ + error("Too few arguments to %s\n",NAME); \ + 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)) -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) +void f_add(INT32 args) { INT32 e,size; TYPE_FIELD types; @@ -192,9 +200,51 @@ void f_sum(INT32 args) } } -void f_add() { f_sum(2); } +static int generate_sum(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),0); + return 1; + + case 2: + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_ADD); + return 1; + + default: + return 0; + } +} + +static int generate_comparison(node *n) +{ + if(count_args(CDR(n))==2) + { + do_docode(CDR(n),DO_NOT_COPY); + + if(CAR(n)->u.sval.u.efun->function == f_eq) + ins_f_byte(F_EQ); + else if(CAR(n)->u.sval.u.efun->function == f_ne) + ins_f_byte(F_NE); + else if(CAR(n)->u.sval.u.efun->function == f_lt) + ins_f_byte(F_LT); + else if(CAR(n)->u.sval.u.efun->function == f_le) + ins_f_byte(F_LE); + else if(CAR(n)->u.sval.u.efun->function == f_gt) + ins_f_byte(F_GT); + else if(CAR(n)->u.sval.u.efun->function == f_ge) + ins_f_byte(F_GE); + else + fatal("Couldn't generate comparison!\n"); + return 1; + } + return 0; +} + -void f_subtract() +void o_subtract() { if (sp[-2].type != sp[-1].type ) error("Subtract on different types.\n"); @@ -259,7 +309,35 @@ void f_subtract() } } -void f_and() +void f_minus(INT32 args) +{ + switch(args) + { + case 0: error("Too few arguments to `-\n"); + case 1: o_negate(); break; + case 2: o_subtract(); break; + default: error("Too many arguments to `-\n"); + } +} + +static int generate_minus(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_NEGATE); + return 1; + + case 2: + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_SUBTRACT); + return 1; + } + return 0; +} + +void o_and() { if(sp[-1].type != sp[-2].type) error("Bitwise and on different types.\n"); @@ -302,7 +380,36 @@ void f_and() } } -void f_or() +void f_and(INT32 args) +{ + switch(args) + { + case 0: error("Too few arguments to `&\n"); + case 1: return; + case 2: o_and(); return; + default: while(--args > 0) o_and(); + } +} + +static int generate_and(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),0); + return 1; + + case 2: + do_docode(CDR(n),0); + ins_f_byte(F_AND); + return 1; + + default: + return 0; + } +} + +void o_or() { if(sp[-1].type != sp[-2].type) error("Bitwise or on different types.\n"); @@ -346,7 +453,37 @@ void f_or() } } -void f_xor() +void f_or(INT32 args) +{ + switch(args) + { + case 0: error("Too few arguments to `|\n"); + case 1: return; + case 2: o_or(); return; + default: while(--args > 0) o_or(); + } +} + +static int generate_or(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),0); + return 1; + + case 2: + do_docode(CDR(n),0); + ins_f_byte(F_OR); + return 1; + + default: + return 0; + } +} + + +void o_xor() { if(sp[-1].type != sp[-2].type) error("Bitwise xor on different types.\n"); @@ -389,7 +526,36 @@ void f_xor() } } -void f_lsh() +void f_xor(INT32 args) +{ + switch(args) + { + case 0: error("Too few arguments to `^\n"); + case 1: return; + case 2: o_xor(); return; + default: while(--args > 0) o_xor(); + } +} + +static int generate_xor(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),0); + return 1; + + case 2: + do_docode(CDR(n),0); + ins_f_byte(F_XOR); + return 1; + + default: + return 0; + } +} + +void o_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"); @@ -397,7 +563,25 @@ void f_lsh() sp[-1].u.integer <<= sp[0].u.integer; } -void f_rsh() +void f_lsh(INT32 args) +{ + if(args != 2) + error("Bad number of args to `<<\n"); + o_lsh(); +} + +static int generate_lsh(node *n) +{ + if(count_args(CDR(n))==2) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_LSH); + return 1; + } + return 0; +} + +void o_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"); @@ -405,7 +589,25 @@ void f_rsh() sp[-1].u.integer >>= sp[0].u.integer; } -void f_multiply() +void f_rsh(INT32 args) +{ + if(args != 2) + error("Bad number of args to `>>\n"); + o_rsh(); +} + +static int generate_rsh(node *n) +{ + if(count_args(CDR(n))==2) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_RSH); + return 1; + } + return 0; +} + +void o_multiply() { switch(sp[-2].type) { @@ -441,7 +643,36 @@ void f_multiply() } } -void f_divide() +void f_multiply(INT32 args) +{ + switch(args) + { + case 0: error("Too few arguments to `*\n"); + case 1: return; + case 2: o_multiply(); return; + case 3: while(--args > 0) o_multiply(); + } +} + +static int generate_multiply(node *n) +{ + switch(count_args(CDR(n))) + { + case 1: + do_docode(CDR(n),0); + return 1; + + case 2: + do_docode(CDR(n),0); + ins_f_byte(F_MULTIPLY); + return 1; + + default: + return 0; + } +} + +void o_divide() { if(sp[-2].type!=sp[-1].type) error("Division on different types.\n"); @@ -479,7 +710,25 @@ void f_divide() } } -void f_mod() +void f_divide(INT32 args) +{ + if(args != 2) + error("Bad number of args to `/\n"); + o_divide(); +} + +static int generate_divide(node *n) +{ + if(count_args(CDR(n))==2) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_DIVIDE); + return 1; + } + return 0; +} + +void o_mod() { if(sp[-2].type != sp[-1].type) error("Modulo on different types.\n"); @@ -508,7 +757,25 @@ void f_mod() } } -void f_not() +void f_mod(INT32 args) +{ + if(args != 2) + error("Bad number of args to `%%\n"); + o_mod(); +} + +static int generate_mod(node *n) +{ + if(count_args(CDR(n))==2) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_MOD); + return 1; + } + return 0; +} + +void o_not() { if(sp[-1].type==T_INT) { @@ -521,13 +788,47 @@ void f_not() } } -void f_compl() +void f_not(INT32 args) +{ + if(args != 1) error("Bad number of args to `!\n"); + o_not(); +} + +static int generate_not(node *n) +{ + if(count_args(CDR(n))==1) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_NOT); + return 1; + } + return 0; +} + +void o_compl() { if (sp[-1].type != T_INT) error("Bad argument to ~\n"); sp[-1].u.integer = ~ sp[-1].u.integer; } -void f_negate() +void f_compl(INT32 args) +{ + if(args != 1) error("Bad number of args to `~\n"); + o_compl(); +} + +static int generate_compl(node *n) +{ + if(count_args(CDR(n))==1) + { + do_docode(CDR(n),DO_NOT_COPY); + ins_f_byte(F_COMPL); + return 1; + } + return 0; +} + +void o_negate() { switch(sp[-1].type) { @@ -544,8 +845,7 @@ void f_negate() } } - -void f_range() +void o_range() { INT32 from,to; if(sp[-2].type != T_INT) @@ -599,3 +899,38 @@ void f_range() error("[ .. ] can only be done on strings and arrays.\n"); } } + +void init_operators() +{ + + + add_efun2("`==",f_eq,"function(mixed,mixed:int)",0,0,generate_comparison); + add_efun2("`!=",f_ne,"function(mixed,mixed:int)",0,0,generate_comparison); + add_efun2("`<", f_lt,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison); + add_efun2("`<=",f_le,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison); + add_efun2("`>", f_gt,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison); + add_efun2("`>=",f_ge,"function(int,int:int)|function(float,float:int)|function(string,string:int)",0,0,generate_comparison); + + add_efun2("`+",f_add,"function(int ...:int)|function(float ...:float)|function(string,string|int|float ...:string)|function(string,string|int|float ...:string)|function(int|float,string,string|int|float:string)|function(array ...:array)|function(mapping ...:mapping)|function(list...:list)",0,0,generate_sum); + + add_efun2("`-",f_minus,"function(int:int)|function(float:float)|function(array,array:array)|function(mapping,mapping:mapping)|function(list,list:list)|function(float,float:float)|function(int,int:int)|function(string,string:string)",0,0,generate_minus); + + add_efun2("`&",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_and); + + add_efun2("`|",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_or); + + add_efun2("`^",f_and,"function(int...:int)|function(mapping...:mapping)|function(list...:list)|function(array...:array)",0,0,generate_xor); + + add_efun2("`<<",f_lsh,"function(int,int:int)",0,0,generate_lsh); + add_efun2("`>>",f_rsh,"function(int,int:int)",0,0,generate_rsh); + + add_efun2("`*",f_multiply,"function(int...:int)|function(float...:float)|function(string*,string:string)",0,0,generate_multiply); + + add_efun2("`/",f_divide,"function(int,int:int)|function(float,float:float)|function(string,string:string*)",0,0,generate_divide); + + add_efun2("`%",f_mod,"function(int,int:int)|function(float,float:float)",0,0,generate_mod); + + add_efun2("`!",f_not,"function(mixed:int)",0,0,generate_not); + add_efun2("`~",f_compl,"function(int:int)",0,0,generate_compl); + +} diff --git a/src/operators.h b/src/operators.h index a93a17f2b03a6457fbbeffa681f7c75f843ebbed..5870c4e35c9fd604b596936d80d9987bd13893d5 100644 --- a/src/operators.h +++ b/src/operators.h @@ -6,31 +6,41 @@ #ifndef OPERATORS_H #define OPERATORS_H -#define COMPARISON(ID,X) void ID(void); +#define COMPARISON(ID,NAME,X) void ID(INT32 num_arg); /* Prototypes begin here */ -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); -void f_add(); -void f_subtract(); -void f_and(); -void f_or(); -void f_xor(); -void f_lsh(); -void f_rsh(); -void f_multiply(); -void f_divide(); -void f_mod(); -void f_not(); -void f_compl(); -void f_negate(); -void f_is_equal(int args,struct svalue *argp); -void f_range(); +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_add(INT32 args); +void o_subtract(); +void f_minus(INT32 args); +void o_and(); +void f_and(INT32 args); +void o_or(); +void f_or(INT32 args); +void o_xor(); +void f_xor(INT32 args); +void o_lsh(); +void f_lsh(INT32 args); +void o_rsh(); +void f_rsh(INT32 args); +void o_multiply(); +void f_multiply(INT32 args); +void o_divide(); +void f_divide(INT32 args); +void o_mod(); +void f_mod(INT32 args); +void o_not(); +void f_not(INT32 args); +void o_compl(); +void f_compl(INT32 args); +void o_negate(); +void o_range(); +void init_operators(); /* Prototypes end here */ #undef COMPARISON