/***************************************************************** * LSC 2.0 * - square@cco.caltech.edu aka square@imperial.lp.mud * aka square@tmi2.lp.mud * * 4/25/92 - Start writing LSC. variable list based on a hash_table * 5/15/92 - switched to mapping for variable list (LSC 2.0) * thus reduce the file size to 22K :) * 5/15/92 - The bug that causes "/var{1}def" to give an error * has been fixed. * 5/17/92 - Flexible stack implemented * 5/19/92 - Array implemeted. Operations like +, -, * (intersection) * extract have meaning either in context of C or Boulean * Algebra * 5/23/92 - Break/continue implemented by using tokens * - lots of operators added * 5/25/92 - lots of game-related operators added * many of them support parse_command * 5/26/92 - primary support for mapping implemeted * - +, * has meaning for mapping * - boost the file size to 40K!!!! * 5/27/92 - Start building the concept of LSC objects. * 6/02/92 - a bug which stack up BREAKTOKEN in _pending_input fixed * 1/93 - modulization begun, first application written * (programmable shop) * 3/93 - second project, the ultimate tracer, begun * 3/12/93 - horrible bug in multi-tasking discovered! *****************************************************************/ #include <lsc.h> inherit LSC_MATH; #define THIS_FILE "u/s/square/lsc/lsc2" #define MAX_SPEED 10 #define MAXSTACK 500 #define MAP_SIZE 30 #define BREAKTOKEN "##" #define CONTTOKEN "#*" #define OBJTOKEN "**" /***********************/ /* compiler essentials */ /***********************/ mapping _varlist; static mapping _e_varlist; static mixed * _stack; static int _stack_ptr; static string _pending_input; /* waiting to be executed */ static int _pending_bracket; /* {} */ static int _pending_parenthese; /* () */ static int _pending_square_brk; /* [] */ int wait_time; /* wait time for each (_speed) executions */ int _speed; /* must always MAX_SPEED >= _speed >= 2 */ static int _counter; static object this_play; /* the master of this object */ static int pause_requested; static mixed stdout, stderr; /************************************/ /* multi-tasking and IPC essentials */ /************************************/ static string _process_id; /* process id, 0 for ROOT */ static object _parent, * _children; /* just like unix */ /* note: a child process's * _children is linked to parent's */ static int _status; /* process status */ static int _max_ch_size; /* NOTE: children can't spawn process */ static object active_child; /* set if its _* is called from child obj */ /********************************/ /* pre-definitions of functions */ /********************************/ int _pause(); int number_of_children(); string Parse_String(string str); varargs int Compile(mixed input); /********************************/ void pause() { _pause(); } int remove() { int i,n; if (!_process_id) { /* ROOT should kill its children first */ n = sizeof(_children); for(i=0;i<n;i++) if(_children[i]) _children[i]->remove(); } destruct(this_object()); return 1; } /* should be replaced by application */ void error(mixed str) { if (_parent && function_exists("error", _parent)) { _parent->error(_process_id+": "+str); } _status = ERROR; } /***********************/ /* some sets & queries */ /***********************/ void set_process_id(string str) { _process_id = str; } void set_parent(object ob) { this_play = _parent = ob; _e_varlist = (mapping) ob->query_varlist(); } void set_e_varlist(mapping varl) { _e_varlist = varl; } void set_this_play(object ob) { this_play = ob; } void set_active_child(object i) { if (i != this_object()) active_child = i; } void insert_input(string str) { if (active_child) { active_child->insert_input(str); return; } if (str == "" || !str) return; if (!_pending_input || _pending_input == "") _pending_input = str; else if (_pending_input[0]==' ' || str[strlen(str)-1]==' ') _pending_input = str + _pending_input; else _pending_input = str+" "+_pending_input; } mapping query_varlist() { return _varlist; } mixed * query_stack() { if (active_child) return (mixed *) active_child->query_stack(); return ( _stack_ptr > 0 ? _stack[0..(_stack_ptr-1)] : ({ }) ); } int query_stack_ptr() { if (active_child) return (int) active_child->query_stack_ptr(); return _stack_ptr; } string query_input() { return _pending_input; } int query__speed() { return _speed; } int query_wait_time() { return wait_time; } void set_wait_time(int i) { wait_time = i; } /* should be removed soon */ void set__speed(int n) { if (n<2) _speed = 2; else if(n>MAX_SPEED) _speed = MAX_SPEED; else _speed = n; } int query_status() { return _status; } object query_parent() { return _parent; } object query_this_play() { return this_play; } mixed query_process_id() { return _process_id; } string query_short() { return "A thought"; /* grin */ } /************/ /* Reset()s */ /************/ void Reset() { if (!this_play) this_play = this_player(); /* should be intelligence-dependent */ wait_time = 1; _speed = MAX_SPEED; _max_ch_size = _process_id==ROOT? 5 : 0 ; if (!_children && _process_id==ROOT) _children = allocate(_max_ch_size); _counter = 0; _pending_input = 0; _stack_ptr = 0; active_child = 0; if (!_varlist) _varlist = allocate_mapping(MAP_SIZE); if (!_stack) _stack = ({ } ); remove_call_out("Compile"); } void LSC_create() { seteuid(getuid(this_object())); if (LSC_CONSOLE=="") return; call_other(LSC_CONSOLE,"register_compiler", this_object()); } create() { LSC_create(); } /*****************************/ /* LSC operators definitions */ /*****************************/ int _clear() { int i; if (active_child) return (int) active_child->_clear(); _stack_ptr = 0; _pending_input = 0; _stack = ({ }); return 0; } int _clear_hash() { int i; if (active_child) return (int) active_child->_clear_hash(); _varlist = allocate_mapping(MAP_SIZE); return 0; } mixed Pop() { if (active_child) return (mixed) active_child->Pop(); if (_stack_ptr < 1) { error("Stack underflows."); return -1; } return _stack[--_stack_ptr]; /* predecrement */ } int _pop() { /* discard the top element */ Pop(); if (_status==ERROR) return -1; return 0; } int Push(mixed elt) { if (active_child) return (int) active_child->Push(elt); if (_stack_ptr >= MAXSTACK) { error("Stack overflows."); return -1; } if (sizeof(_stack) > _stack_ptr) _stack[_stack_ptr++] = elt; else { _stack+= ({ elt } ); _stack_ptr++; } return 0; } int _count() { if (active_child) return Push(active_child->query_stack_ptr()); return Push(_stack_ptr); } int Is_Block(mixed str) { if (!str || !stringp(str) || str=="") return 0; return str[0]=='{' && str[strlen(str)-1]=='}' ; } int Is_empty_block(string str) { string inside; int len; if (!Is_Block(str)) return -1; len = strlen(str); if (len < 3) return 1; sscanf(str,"{%s}",inside); while(sscanf(inside," %s",inside)); if (inside=="") return 1; return 0; } int Is_String(mixed str) { if (!str || !stringp(str) || str=="") return 0; return str[0]=='(' && str[strlen(str)-1]==')' ; } int Is_Object(mixed str) { if (!str || !stringp(str) || strlen(str)<3) return 0; return str[0..1]==OBJTOKEN; } int _add() { mixed i,j; i=Pop(); j=Pop(); if (pointerp(i)) { if( pointerp(j) ) { Push(j+i); return 0; } return Push( ({ j }) + (mixed*) i); } if (pointerp(j)) { return Push( (mixed *)j + ({ i }) ); } if (mapp(i) && mapp(j)) return Push( i + j); if (Is_String(i) || Is_String(j)) { string tmp1, tmp2; if (Is_String(i)) { if (strlen(i) <3) tmp1=""; else tmp1=i[1..strlen(i)-2]; } if (Is_String(j)) { if (strlen(j) <3) tmp2=""; else tmp2=j[1..strlen(j)-2]; } if (tmp1 && tmp2) { Push( "("+tmp2+tmp1+")" ); return 0; } else if (tmp1) { Push( "("+j+tmp1+")" ); return 0; } else if (tmp2) { Push( "("+tmp2+i+")" ); return 0; } } if (intp(i) && intp(j)) { Push(i+j); return 0; } error("Illegal addition."); return -1; } /* "j i sub" pushes (j-i) onto stack */ int _sub() { mixed i, j; i=Pop(); /* top */ j=Pop(); if (pointerp(j)) { if (pointerp(i)) { return Push( j - i); } return Push( (mixed *) j - ({ i } ) ); } if (!intp(i) || !intp(j)) { error("Illegal subtraction."); return -1; } return Push(j-i); /* below - above */ } /* "j i div" pushes (j/i) onto stack */ int _div() { mixed i, j; i=Pop(); /* top */ j=Pop(); if (!intp(i) || !intp(j)) { error("Illegal subtraction."); return -1; } if (!i) { error("division by zero."); return -1; } return Push(j/i); /* below - above */ } int _mul() { mixed i,j; int n; i=Pop(); j=Pop(); if (pointerp(i)) { if (pointerp(j)) { return Push(i-(i-j)); /* intersection */ } n = member_array(j,i); if (n==-1) { return Push( ({ }) ); } return Push( ({ j }) ); } if (pointerp(j)) { n = member_array(i,j); if (n==-1) { return Push( ({ }) ); } return Push( ({ i }) ); } if (mapp(i) && mapp(j)) return Push( j * i ); if (!intp(i) || !intp(j)) { error("Illegal multiplication."); return -1; } return Push(i*j); } int _neg() { mixed i; i=Pop(); if (!intp(i)) { error("_neg: illegal arg"); return -1; } Push(-i); } int _sqrt() { mixed i; i = Pop(); if (!intp(i) || i<0) { error("sqrt: illegal arg"); return -1; } Push(sqrt(i)); } int _mod() { mixed i,j; i=Pop(); j=Pop(); if (!intp(i) || !intp(j)) { error("_mod: illegal arg."); return -1; } return Push(j % i); } string SubStr(string str, string orig, string new) { string ret, front, back, tmp; if (!str || str=="" ) return ""; tmp = "%s"+orig+"%s"; ret=""; while(sscanf(str, tmp, front, back)) { if(!back) back=""; ret+= front+new; str=back; } return ret+str; } mixed Restore_String(mixed str) { if (!stringp(str)) return str; str = SubStr(str,"\\","\\\\"); str = SubStr(str,"(", "\\("); str = SubStr(str,")", "\\)"); str = SubStr(str,"[", "\\["); str = SubStr(str,"]", "\\]"); str = SubStr(str,"{", "\\{"); str = SubStr(str,"}", "\\}"); str = SubStr(str,"#", "\\#"); str = SubStr(str,"*", "\\*"); str = SubStr(str,"\n","\\n"); str = SubStr(str,"\t","\\t"); return "("+str+")"; } string Restore_Array(mixed * arry) { int i,n; string ret; ret = "["; n = sizeof(arry); for(i=0;i<n;i++) { if(pointerp(arry[i])) ret+=Restore_Array(arry[i]); else if(arry[i] && objectp(arry[i])) ret+=OBJTOKEN+file_name(arry[i]); else ret+=arry[i]; ret += " "; } return ret+"]"; } int _extract() { mixed start,end; mixed arry; int n; string tmp; end = Pop(); start = Pop(); arry = Pop(); if (!intp(end) || !intp(start)) { error("extract: 1st and 2nd must be integers"); return -1; } if (pointerp(arry)) { n = sizeof(arry); if (end <0) end += n; if (start<0) start+=n; if (end < start) { Push( ({ })); return 0; } if (start < 0 || start >= n || end < 0 || end >= n) { error("extract: out of range"); return -1; } return Push(arry[start..end]); } if (Is_String(arry)) { tmp = Parse_String(arry); n = strlen(tmp); if (end <0 ) end += n; if (start<0) start+=n; if (end < start) { Push("()"); return 0; } if (start < 0 || start >= n || end < 0 || end >= n) { error("extract: out of range:"+start+" to "+end+" range "+n); return -1; } return Push( Restore_String(tmp[start..end]) ); } error("extract: must be either array or string"); return -1; } void Def(mapping table, string varname, mixed above) { table[varname]=above; return 0; } int _def() { mixed below, above; string varname; above = Pop(); below = Pop(); if (!stringp(below) || !sscanf(below,"\/%s",varname) ) { error("_def: Illegal var format."); return -1; } Def(_varlist, varname, above); } int _edef() { mixed below, above; string varname; if (!_parent) return _def(); above = Pop(); below = Pop(); if (!stringp(below) || !sscanf(below,"\/%s",varname) ) { error("_edef: Illegal var format."); return -1; } Def(_e_varlist, varname,above); } int _isdef() { string varname; mixed data; data = Pop(); if (!stringp(data) || !sscanf(data,"\/%s",varname) ) { error("_isdef: Illegal var format."); return -1; } if (undefinedp(_varlist[varname])) Push(0); else Push(1); } int _isedef() { string varname; mixed data; if (!_parent) { Push(0); return 0; } data = Pop(); if (!stringp(data) || !sscanf(data,"\/%s",varname) ) { error("_isedef: Illegal var format."); return -1; } if (undefinedp(_e_varlist[varname])) Push(0); else Push(1); } int _undef() { string varname; mixed data; data = Pop(); if (!stringp(data) || !sscanf(data,"\/%s",varname) ) { error("_undef: Illegal var format."); return -1; } map_delete(_varlist, varname); } int _unedef() { string varname; mixed data, up, down; int i, hash_num, n; if (!_parent) { if (!_process_id) { /* really a <ROOT> */ return _undef(); } /* orphane */ Pop(); return 0; /* should I make it an error? */ } data = Pop(); if (!stringp(data) || !sscanf(data,"\/%s",varname) ) { error("_unedef: Illegal var format."); return -1; } map_delete(_e_varlist, varname); } int _load() { string varname; mixed data,what; data = Pop(); if (!stringp(data) || !sscanf(data,"\/%s",varname) ) { error("load: not a /variable format"); return -1; } if (!undefinedp(what = _varlist[varname])) { Push(what); return 0; } if (!undefinedp(what = _e_varlist[varname])) { Push(what); return 0; } error("load: variable "+varname+" not found"); return -1; } int _array() { mixed i, *j; i = Pop(); if (!intp(i) || i < 0) { error("array: illegal argument"); return -1; } j = allocate(i); return Push(j); } int _mapping() { mixed i; mapping j; i = Pop(); if (!intp(i) || i < 0) { error("mapping: illegal argument"); return -1; } j = allocate_mapping(i); return Push(j); } int _keys() { mixed i; i = Pop(); if (!mapp(i)) { error("keys: not a mapping"); return -1; } Push(keys(i)); } int _get() { mixed i, data, tmp; string tmpstr; int len; i = Pop(); data = Pop(); if (!intp(i) && !mapp(data)) { error("get: 1st must be int"); return -1; } if (Is_String(data)) { tmpstr = Parse_String(data); len = strlen(tmpstr); if (i<0) i+=len; if (i<0 || i>=len) { error("get: out of range"); return -1; } return Push("("+tmpstr[i]+")"); } if (pointerp(data)) { len = sizeof(data); if (i<0) i+=len; if (i<0 || i>=len) { error("get: out of range"); return -1; } return Push(data[i]); } if (mapp(data)) { return Push(data[i]); } error("get: not [array] nor (string)"); return -1; } int _put() { mixed i, what, data, tmp; string tmpdata, tmpwhat; int lendata, lenwhat; i = Pop(); what = Pop(); data = Pop(); if (!intp(i) && !mapp(data) ) { error("put: 1st must be int"); return -1; } if (Is_String(data)) { if (intp(what)) tmpwhat=""+what; else { if (!Is_String(what)) { error("put: 2nd is not (char) nor int"); return -1; } else { tmpwhat = Parse_String(what); } } lenwhat = strlen(tmpwhat); if (lenwhat>1) { error("put: chain substitution not yet possible"); return -1; } tmpdata = Parse_String(data); lendata = strlen(tmpdata); if (i<0) i+=lendata; if (i<0 || i>=lendata) { error("get: out of range"); return -1; } tmpdata[i]=tmpwhat[0]; return Push(Restore_String(tmpdata)); } if (pointerp(data)) { lendata = sizeof(data); if (i<0) i+=lendata; if (i<0 || i>=lendata) { error("get: out of range"); return -1; } data[i]=what; return Push(data); } if (mapp(data)) { data[i]=what; return Push(data); } error("put: not [array] nor (string)"); return -1; } int _aload() { int i,n; mixed data; data = Pop(); if (!pointerp(data)) { error("aload: illegal argument"); return -1; } n = sizeof(data); if (n+query_stack_ptr() > MAXSTACK) { error("aload: array too large to be contained in stack"); return -1; } for(i=0;i<n;i++) { Push(data[i]); } return Push(data); } int _astore() { int i,n; mixed data; data = Pop(); if (!pointerp(data)) { error("astore: 1st is not [array]"); return -1; } n = sizeof(data); if (query_stack_ptr() < n) { error("astore: not enough elements to fill array"); return -1; } for(i=n-1;i>=0;i--) data[i]=Pop(); return Push(data); } int _member_array() { mixed array; mixed item; array = Pop(); item = Pop(); if (!pointerp(array)) { error("member_array: 1st is not [array]"); return -1; } return Push( member_array(item, (mixed *) array) ); } int _exch() { mixed i,j; i = Pop(); j = Pop(); Push(i); Push(j); } int _dup() { mixed i; i = Pop(); Push(i); Push(i); } int _length() { mixed i; i = Pop(); if (Is_String(i)) { return Push(strlen(Parse_String(i))); } if (pointerp(i)) { return Push(sizeof(i)); } error("length: not (string) nor [array]"); } string Parse_String(string str) { int i,n; string tmp; for(i=1;i<(n=strlen(str)-1);i++) { if (str[i]=='\\') { tmp = str[0..(i-1)]; if (str[i+1]=='n') tmp += "\n"+str[(i+2)..n]; else if (str[i+1]=='t') tmp += "\t"+str[(i+2)..n]; else tmp += str[(1+i)..n]; str = tmp; } } return str[1..(n-1)]; } int Look_for_char(string str,int anti_char,int char) { int i,n, count; count = 0; n = strlen(str); for(i=0;i<n;i++) { if (str[i]=='\\') { if (i==(n-1)) continue; else i++; } else if (str[i]==anti_char) count++; else if (str[i]==char) { count--; if (!count) return i; } } return -1; } mixed * Parse_Array(string str) { string current, rest; int len, part, num; mixed * ret, data; ret = ({ } ); len = strlen(str); if (len<3) return ret; str = str[1..len-2]; while(str!="") { while(sscanf(str," %s",str)); if (str=="") break; len = strlen(str); if (str[0]=='(') { part = Look_for_char(str,'(',')'); if (part==-1) { error("Fatal: illegal array format "+str); return 0; } ret += ({ str[0..part] } ); str = part == len-1 ? "" : str[part+1..len-1]; continue; } if (str[0]=='[') { part = Look_for_char(str,'[',']'); if (part==-1) { error("Fatal: illegal array format "+str); return 0; } ret += Parse_Array(str[0..part]); str = part == len-1 ? "" : str[part+1..len-1]; continue; } if (str[0]=='{') { part = Look_for_char(str,'{','}'); if (part==-1) { error("Fatal: illegal array format "+str); return 0; } ret += ({ str[0..part] } ); str = part == len-1 ? "" : str[part+1..len-1]; continue; } if (sscanf(str,"%s %s",current, rest)!=2) { current = str; rest = ""; } if (sscanf(current,"%d",num)) { ret += ({ num } ); str = rest; continue; } if (!undefinedp(data=_varlist[current])) { ret += ({ data }); str = rest; continue; } if (_e_varlist && !undefinedp(data=_e_varlist[current])) { ret += ({ data }); str = rest; continue; } ret += ({ current } ); str = rest; } return ret; } int _exec() { mixed i; if (!Is_Block(i)) { error("exec: not a {block}"); return -1; } if (strlen(i)>2) insert_input( i[1..strlen(i)-2]); } int _randexec() { mixed i; i = Pop(); if (!pointerp(i)) { error("randexec: not an [array]"); return -1; } insert_input("exec"); return Push(i[random(sizeof(i))]); } /* cond { block } if */ int _if() { mixed blk; blk = Pop(); if(Pop()) { if (!Is_Block(blk)) { error("if: block missing"); return -1; } if (strlen(blk)>2) insert_input(blk[1..(strlen(blk)-2)]); } } int _ifelse() { mixed blkif, blkelse; blkelse = Pop(); blkif = Pop(); if (Pop()) { if (!Is_Block(blkif)) { error("ifelse: block missing"); return -1; } if (strlen(blkif)>2) insert_input(blkif[1..(strlen(blkif)-2)]); } else { if (!Is_Block(blkelse)) { error("ifelse: block missing"); return -1; } if (strlen(blkelse)>2) insert_input(blkelse[1..(strlen(blkelse)-2)]); } } int _while() { mixed blkif, blkdo; blkdo = Pop(); blkif = Pop(); if (!Is_Block(blkdo) || !Is_Block(blkif) ) { error("while: wrong argument type"); return -1; } if (Is_empty_block(blkif)) { error("while: empty condition block"); return -1; } insert_input( blkif[1..(strlen(blkif)-2)]+" "+CONTTOKEN+" {"+ blkdo[1..(strlen(blkdo)-2)] + " "+blkif+" "+blkdo+" wHILe } if "+ BREAKTOKEN); /* grin */ } /* i know that's ugly, but i don't want to have BREAKTOKEN stacked up in the _pending_input in an infinite loop */ int _wHILe() { mixed blkif, blkdo; blkdo = Pop(); blkif = Pop(); if (!Is_Block(blkdo) || !Is_Block(blkif) ) { error("while: wrong argument type"); return -1; } if (Is_empty_block(blkif)) { error("while: empty condition block"); return -1; } insert_input( blkif[1..(strlen(blkif)-2)]+" "+CONTTOKEN+" {"+ blkdo[1..(strlen(blkdo)-2)] + " "+blkif+" "+blkdo+" wHILe } if"); } int _forall() { mixed blk,data; string tmpstr; int n; blk = Pop(); data = Pop(); if (!Is_Block(blk)) { error("forall: 1st is not a {block}"); return -1; } if (Is_empty_block(blk)) { error("forall: empty block"); return -1; } if (Is_String(data)) { tmpstr = Parse_String(data); n = strlen(tmpstr); if (n<1) return 0; if (n==1) { insert_input(blk[1..strlen(blk)-2]+" "+CONTTOKEN+" "+ BREAKTOKEN); return Push(Restore_String(tmpstr)); } insert_input(blk[1..strlen(blk)-2]+" "+CONTTOKEN+" "+ Restore_String(tmpstr[1..n-1])+blk+" forall " +BREAKTOKEN); return Push(Restore_String( tmpstr[0..0] )); } /* I hate this ugly code!!! */ if (pointerp(data)) { n = sizeof(data); if (n<1) return 0; if (n==1) { insert_input(blk[1..strlen(blk)-2]+" "+CONTTOKEN+" "+ BREAKTOKEN); return 0; } insert_input(blk[1..strlen(blk)-2]+" "+CONTTOKEN+" "+ Restore_Array(data[1..n-1])+blk+" forall" +BREAKTOKEN); return Push(data[0]); } error("forall: 2nd is not (string) nor [array]"); return -1; } int _continue() { string tmp1,tmp2; if(sscanf(_pending_input,"%s "+CONTTOKEN+" %s",tmp1,tmp2)!=2) { error("continue: no loop to skip"); return -1; } _pending_input = tmp2; } int _exit() { string tmp1,tmp2; if(sscanf(_pending_input,"%s "+BREAKTOKEN+" %s",tmp1,tmp2)!=2) { error("exit: no loop to break out of"); return -1; } _pending_input = tmp2; } int _and() { Push(Pop() && Pop()); } int _or() { Push(Pop() || Pop()); } int _not() { Push(!Pop()); } int _eq() { Push(Pop() == Pop()); } int _ne() { Push(Pop() != Pop()); } /* "2 1 gt" pushes True (1) onto the stack */ int _gt() { mixed i,j; i = Pop(); j = Pop(); if (intp(i) && intp(j)) Push(i < j); else { error("gt: non-integer comparison"); return -1; } } int _lt() { mixed i,j; i = Pop(); j = Pop(); if (intp(i) && intp(j)) Push(i > j); else { error("lt: non-integer comparison"); return -1; } } int _ge() { mixed i,j; i = Pop(); j = Pop(); if (intp(i) && intp(j)) Push(i <= j); else { error("ge: non-integer comparison"); return -1; } } int _le() { mixed i,j; i = Pop(); j = Pop(); if (intp(i) && intp(j)) Push(i >= j); else { error("le: non-integer comparison"); return -1; } } string object_to_Object(mixed ob) { if (!ob || !objectp(ob)) return 0; return OBJTOKEN+file_name(ob); } object Object_to_object(string obstr) { if (!sscanf(obstr,OBJTOKEN+"%s",obstr)) return 0; return find_object(obstr); } int _random() { mixed i; i = Pop(); if (!intp(i)) { error("random: illegal argument"); return -1; } if (i<1) { error("random: unacceptable arg "+i); return -1; } Push(random(i)); } int _wtime() { mixed i; i = Pop(); if (i && !intp(i)) { error("wait_time: illegal argument"); return -1; } if (i<1) i = 1; if (active_child) active_child->set_wait_time(i); else set_wait_time(i); } int _pause() { if (active_child) return (int) active_child->_pause(); pause_requested = 1; return 0; } /* the max and min should depend on the cleverness of the monster */ int _speed() { mixed i; if (active_child) return (int) active_child->_speed(); i = Pop(); if (!i || !intp(i)) return 0; if (i>MAX_SPEED) _speed = MAX_SPEED; else if (i<2) _speed = 2; else _speed = i; } int _sleep() { mixed i,j; if (active_child) return (int) active_child->_sleep(); i=Pop(); j=wait_time; wait_time = i; _counter = -1; insert_input(""+j+" wtime"); } int _list_proc() { string todo, statstr; int i, n, stat; n = number_of_children(); if (!n) { insert_input("(This is the only task I'm doing.) say"); return 0; } todo="(I'm doing "+n+" additional tasks.) say ( # Id Status) say "; n = sizeof(_children); for (i=0;i<n;i++) { if (_children[i]) { stat = (int) _children[i]->query_status(); if (stat==IDLE) statstr="Idle"; else if (stat==RUNNING) statstr="Running"; else if (stat==INCOMPLETE_INPUT) statstr="Incmplt"; else if (stat==PAUSED) statstr="Paused"; else if (stat==ERROR) statstr="Error"; todo+=sprintf("(%2d %7s %8s) say ",i, _children[i]->query_process_id(),statstr); } } insert_input(todo); return 0; } object Find_process(mixed clue) { int i,n; if (intp(clue)) { if (clue<0 || clue>= sizeof(_children)) { return 0; } if (_children[clue]) { return _children[clue]; } return 0; } if (Is_String(clue)) { clue = clue[1..(strlen(clue)-2)]; n = sizeof(_children); for (i=0; i<n; i++) { if (_children[i] && (string) _children[i]->query_process_id()==clue) { return _children[i]; } } } if (objectp(clue)) { for(i=0;i<n;i++) if (clue==_children[i]) return _children[i]; } return 0; } int _pause_proc() { mixed data; int i,n; object child; data = Pop(); child = Find_process(data); if (!child) { error("pause_proc: no such process"); return -1; } child->pause(); } int _kill_proc() { mixed data; int i,n; object child; data = Pop(); child = Find_process(data); if (!child) { error("kill_proc: no such process"); return -1; } destruct(child); } /* similar to fork() in unix */ int _spawn() { mixed i, n, data; int j, num, hash_num, childnum; object child; string childname, varname, todo; if (active_child) return (int) active_child->_spawn(); i = Pop(); if (_process_id != ROOT) { error("_spawn: Child can't spawn process."); return -1; /* could be a restriction, but what the heck! */ } if ( (num=number_of_children()) >= _max_ch_size) { error("_spawn: Can't spawn anymore"); return -1; } if (!stringp(i) || strlen(i)<2) { error("_spawn: Invalid argument"); return -1; } for(j=0;j<sizeof(_children);j++) { if (!_children[j]) { childnum = j; break; } } if (Is_Block(i)) { childname = "proc "+childnum; todo = i[1..(strlen(i)-2)]; } else { if (!sscanf(i,"\/%s",varname) ) { error("spawn: Illegal var format."); return -1; } if (Find_process("("+varname+")")) { error("spawn: Identical process exists!"); return -1; } if (undefinedp(data=_varlist[varname]) ) { error("spawn: variable "+varname+" not found"); return -1; } if (!Is_Block(data)) { error("spawn: non-block data "+varname); return -1; } todo = data[1..(strlen(data)-2)]; } child = clone_object(THIS_FILE); export_uid(child); _children[childnum]=child; child->set_parent(this_object()); child->set_this_play(this_play); child->set_process_id(childname); child->set_children(_children); child->Reset(); child->set__speed(_speed); child->Compile(todo); _counter = 0; return 0; } int number_of_children() { int i,n, ret ; for (i=0,n=sizeof(_children); i<n; i++) { if (_children[i]) ret ++; } return ret; } void Next() { if (pause_requested) { pause_requested = 0; _status = PAUSED; return; } if (!_counter) call_out("Compile",wait_time); else Compile(); } varargs int Compile(mixed input) { mixed data; string rawstr, str, current, rest, tmp1,tmp2; int i,n, last, hash_num; int num; _status = RUNNING; if (input) { /* new command */ if (!stringp(input)) { error("Compile: only accepts strings"); return -1; } /* ignore comment lines */ while(sscanf(input," %s",input) || sscanf(input,"\t%s",input)); if (input!="" && input[0]=='%') input=""; if (sscanf(input,"%s"+CONTTOKEN,tmp1)) { if (tmp1!="" && tmp1[strlen(tmp1)-1]!='\\') { error("Compile: Cont. token "+CONTTOKEN+" found."); return -1; } } if (sscanf(input,"%s"+BREAKTOKEN,tmp1) ) { if (tmp1!="" && tmp1[strlen(tmp1)-1]!='\\') { error("Compile: break token "+BREAKTOKEN+" found."); return -1; } } if (sscanf(input,"%s"+OBJTOKEN,tmp1)) { if (tmp1!="" && tmp1[strlen(tmp1)-1]!='\\') { error("Compile: Obj token "+OBJTOKEN+" found."); return -1; } } /* append input to _pending_input */ if (!_pending_input || _pending_input=="") { _pending_input = input; } else if (_pending_input==" ") { _pending_input = " "+input; } else { n = strlen(_pending_input); if (_pending_input[n-1]==' ') _pending_input = _pending_input + input; else _pending_input = _pending_input+" "+input; } remove_call_out("Compile"); call_out("Compile", wait_time); return 0; } if(!_pending_input) { _status = IDLE; if (_process_id) destruct(this_object()); return 0; } remove_call_out("Compile"); while(sscanf(_pending_input," %s",_pending_input) || sscanf(_pending_input,"\t%s",_pending_input) ); if (_pending_input=="") { _pending_input = 0; _status = IDLE; if (_process_id) destruct(this_object()); return 0; } str = _pending_input; _pending_input=" "; _pending_bracket=0; _pending_parenthese=0; _counter = (_counter + 1) % _speed; if (str[0]=='(') { n=strlen(str); _pending_parenthese=1; last=0; for(i=1;i<n;i++) { if (str[i]=='\\') { if (i==(n-1)) continue; else i++; /* skip the next char */ } else if (str[i]=='(') _pending_parenthese++; else if (str[i]==')') { _pending_parenthese--; last = i; } if (!_pending_parenthese) break; } if (!_pending_parenthese) { if (last >= (n-1) ) { /* the whole string */ Push(str); _status = IDLE; return 0; } else { Push(str[0..last]); insert_input(str[(last+1)..(n-1)]); Next(); return 0; } } else { insert_input(str); _status = INCOMPLETE_INPUT; return 0; } } if (str[0]=='{') { n=strlen(str); _pending_bracket=1; last=0; for(i=1;i<n;i++) { if (str[i]=='\\') { if (i==(n-1)) continue; else i++; /* skip the next char */ } else if (str[i]=='{') _pending_bracket++; else if (str[i]=='}') { _pending_bracket--; last = i; } if (!_pending_bracket) break; } if (!_pending_bracket) { if (last >= (n-1) ) { Push(str); _status = IDLE; return 0; } else { Push(str[0..last]); insert_input(str[(last+1)..(n-1)]); Next(); return 0; } } else { insert_input(str); _status = INCOMPLETE_INPUT; return 0; } } if (str[0]=='[') { mixed arry; n=strlen(str); _pending_square_brk=1; last=0; for(i=1;i<n;i++) { if (str[i]=='\\') { if (i==(n-1)) continue; else i++; /* skip the next char */ } else if (str[i]=='[') _pending_square_brk++; else if (str[i]==']') { _pending_square_brk--; last = i; } if (!_pending_square_brk) break; } if (!_pending_square_brk) { if (last >= (n-1) ) { arry = Parse_Array(str); if (!arry) { _status = ERROR; return 0; } Push(arry); _status = IDLE; return 0; } else { arry = Parse_Array(str[0..last]); insert_input(str[(last+1)..(n-1)]); if (!arry) { _status = ERROR; return 0; } Push(arry); Next(); return 0; } } else { insert_input(str); _status = INCOMPLETE_INPUT; return 0; } } if(sscanf(str,"%s %s", current, rest)!=2) { current = str; rest = ""; } if (sscanf(current,"%s\{%s",tmp1,tmp2)==2) { current = tmp1; rest = "\{"+tmp2+" "+rest; } if (sscanf(current,"%s\[%s",tmp1,tmp2)==2) { current = tmp1; rest = "\["+tmp2+" "+rest; } if (sscanf(current,"%s\(%s",tmp1,tmp2)==2) { current = tmp1; rest = "\("+tmp2+" "+rest; } if (current==BREAKTOKEN || current==CONTTOKEN) { _pending_input=rest+_pending_input; Next(); return 0; } if (current[0]=='/') { if (strlen(current)==1) { error("Compile: missing variable id"); return -1; } Push(current); _pending_input=rest+_pending_input; Next(); return 0; } if (sscanf(current, "%d", num)) { Push(num); _pending_input=rest+_pending_input; Next(); return 0; } if (Is_Object(current) ) { Push(Object_to_object(current)); _pending_input=rest+_pending_input; Next(); return 0; } if (!undefinedp(data=_varlist[current]) || (_parent && !undefinedp(data=_e_varlist[current])) ) { if (Is_Block(data)) { if (strlen(data)>2) { insert_input(rest); insert_input(data[1..(strlen(data)-2)]); } else { _pending_input=rest+ _pending_input; } } else { Push(data); _pending_input = rest+_pending_input; } Next(); return 0; } if (current[0]>='a' && current[0]<='z') { /* necessary for child process */ if (_parent && function_exists("_"+current,_parent)) { _parent->set_active_child(this_object()); _pending_input=rest+_pending_input; if((int)call_other(_parent, "_"+current)==-1 || _status == ERROR) { _parent->set_active_child(0); return -1; } _parent->set_active_child(0); Next(); return 0; } if (function_exists("_"+current, this_object())) { _pending_input=rest+_pending_input; if((int)call_other(this_object(), "_"+current)==-1 || _status == ERROR ) { return -1; } Next(); return 0; } } /* couldn't find variable in memory */ error("Compile: Unknown variable/operation "+current); }