#include "value.h" #include "tokentable.h" #include "main.h" #include "Structures.h" #include "command.h" extern "C"{ #include <math.h> #include <errno.h> #include <stdio.h> char *crypt (char*, char*); } #pragma implementation #define MAXStrRep_SIZE (SHRT_MAX - 125) // where the hell is this defined? #define SET_ERROR(es) \ if (error_string && !(*error_string)) \ *error_string = new String(es); int depth_found_at; /** vs, VS_COUT, VS_UNCOUNT are for memory leak hunting. **/ /** uncomment these to get a shitload of numbers you don\'t understand **/ //int vs; #define VS_COUNT /* cout<<(long)this<<" "<<(int)type<<": "<<++vs<<"\n"; */ #define VS_UNCOUNT /* cout<<(long)this<<" "<<(int)type<<": "<<--vs<<"\n"; */ Value::Value (long inclass, Value* inval){ type = USER; user = new User_Defined (inclass, inval); use_count = 1; VS_COUNT } Value::Value (Value* inclass, Value* inval){ if (inclass->type != OBJ) {err = E_TYPE; type = ERR;} else {if (inclass->obj < 0) {err = E_TYPE; type = ERR;} else {user = new User_Defined (inclass->obj , inval); type = USER;}} use_count = 1; VS_COUNT } Value::Value(String* instring, Value_Type vtype){ type = vtype; str = instring; if (vtype == SYM) *str = upcase (*str); use_count = 1; VS_COUNT } Value::Value(char* instring, Value_Type vtype){ type = vtype; str = new String(instring); if (vtype == SYM) *str = upcase (*str); use_count = 1; VS_COUNT } Value::Value (ifstream* infile){ char ch; if (infile->fail()) {type = ERR; err = E_BAD_FILE;} else {type = STR; str = new String; while ((infile->get (ch)) && (str->length() < MAXStrRep_SIZE)) {*str += ch; if (str->length() >= (MAXStrRep_SIZE - 1)) {delete str; type = ERR; err = E_LENGTH; return;}}} delete infile; use_count = 1; VS_COUNT } Value::Value (FILE* infile){ int i; if (!infile) {type = ERR; err = E_BAD_FILE; return;} type = STR; str = new String; while ((i = getc (infile)) >= 0 && (str->length() < MAXStrRep_SIZE)) *str += (char)i; fclose (infile); use_count = 1; VS_COUNT } Value::Value(int number, Value_Type vtype){ type = vtype; num = number; use_count = 1; VS_COUNT } Value::Value(Val_List *inlist, Value_Type vtype){ type = vtype; list = inlist; use_count = 1; VS_COUNT } Value::Value(Value *inlist, int begin, int end){ int i; if (inlist->type != LIST && inlist->type != SUBR && inlist->type != STR) {err = E_TYPE; type = ERR; use_count = 1; VS_COUNT return;} switch (inlist->type) {case LIST: i = inlist->list->length(); break; case SUBR: i = inlist->sub->get_length(); break; case STR: i = inlist->str->length(); break;} if (i < begin || i < end || begin < 1 || begin > end) {err = E_RANGE; type = ERR; use_count = 1; VS_COUNT return;} switch (inlist->type) {case LIST: case SUBR: type = SUBR; sub = new Subrange (inlist, begin, end); break; case STR: type = STR; str = new String (inlist->str->through (end-1)); *str = str->from (begin-1); break;} use_count = 1; VS_COUNT } Value::Value(Method* inmeth){ type = MTHD; mthd = inmeth; use_count = 1; VS_COUNT } Value::Value(float inreal){ type = REAL; real = inreal; use_count = 1; VS_COUNT } Value::~Value(){ VS_UNCOUNT FREE_VAL; } int Value::boolean_val(){ switch (type) {case NUM: return num; case OBJ: return db->obj_exists (obj); case REAL: return (real != (float)0); case LIST: return (int)list; case STR: return str->length(); case SUBR: case SYM: case MTHD: case USER: return 1; default: return 0;} } void Value::tonum (String** error_string){ int temp = INT_MIN; String err_string; switch (type) {case LIST: case EXPR: case SYM: case RESERVED: case MTHD: case SUBR: case USER: err_string = "tonum expects REAL, STRING, NUM, ERR or OBJ ... received "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; break; case REAL: num = (int)real; type = NUM; break; case STR: sscanf ((char*)str->chars() , "%i" , &temp); if (temp == INT_MIN) {err_string = "string \""; err_string += *str; err_string += "\" passed to 'tonum' doesn't contain a number"; SET_ERROR(err_string); FREE_VAL; type = ERR; err = E_DIV_BY_ZERO;} else {FREE_VAL; type = NUM; num = temp;} break; case NUM: case ERR: case OBJ: type = NUM; break; default: type = ERR; err = E_BUG_IN_TONUM;} } void Value::toreal (String** error_string){ float temp = 0; String err_string; switch (type) {case LIST: case EXPR: case SYM: case RESERVED: case MTHD: case ERR: case OBJ: case SUBR: case USER: err_string = "toreal expects REAL, NUM or STRING ... received "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; break; case REAL: break; case NUM: real = (float) num; type = REAL; break; case STR: sscanf ((char*)str->chars() , "%f" , &temp); delete str; type = REAL; real = temp; break; default: type = ERR; err = E_BUG_IN_TOREAL;} } void Value::toerr (){ String err_string; switch (type) {case NUM: if (num < 0) err = -1; break; case ERR: break; case MTHD: case LIST: case STR: case SYM: case EXPR: case RESERVED: case REAL: case SUBR: case USER: FREE_VAL; err = E_TYPE; break; default: err = E_BUG_IN_TOERR;} type = ERR; } void Value::toobj (String** error_string){ String err_string; switch (type) {case NUM: case OBJ: type = OBJ; return; default: err_string = "toobj expects a NUMBER or OBJECT, received a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} } void Value::format (int tab, int columns){ String *temp_str; Val_List *templist; int i; switch (type) {case SUBR: subr_to_list(); case LIST: case EXPR: if (!list) str = new String (type==LIST ? "'()" : "()"); else {temp_str = list->format (tab, columns); if (type==LIST) temp_str->prepend("'"); delete list; str = temp_str;} break; case MTHD: if (mthd->symlist) temp_str = mthd->symlist->tostr(); else temp_str = new String ("()"); temp_str->prepend ("(method "); (*temp_str) += "\n"; for (i=0 ; i<tab+2 ; i++) *temp_str += ' '; mthd->expr->format(tab+2); *temp_str += *mthd->expr->str; (*temp_str) += ")\n"; FREE_VAL; type = STR; str = temp_str; break; default: tostr ();} type = STR; } void Value::tostr (String** error_string){ char temp[20]; String *temp_str; Val_List *templist; switch (type) {case SUBR: subr_to_list(); case LIST: case EXPR: if (!list) str = new String (type==LIST ? "'()" : "()"); else {temp_str = list->tostr(); if (type==LIST) temp_str->prepend("'"); delete list; str = temp_str;}; break; case RESERVED: str = new String (tokentable[reserved].symbol); break; case STR: str->gsub ("\\" , "\001"); str->gsub ("\"" , "\\\""); str->gsub ("\n" , "\\n"); str->gsub ("\001" , "\\\\"); str->prepend ("\""); *str += "\""; break; case SYM: break; case NUM: sprintf (temp , "%i", num); str = new String (temp); break; case OBJ: sprintf (temp , "#%i", num); str = new String (temp); break; case ERR: sprintf (temp , "!%i", num); str = new String (temp); break; case REAL: sprintf (temp , "%.3f" , real); str = new String (temp); break; case USER: temp_str = user->tostr(); FREE_VAL; str = temp_str; break; case MTHD: if (mthd->symlist) temp_str = mthd->symlist->tostr(); else temp_str = new String ("()"); temp_str->prepend ("(method "); (*temp_str) += " "; if (mthd->expr) {mthd->expr->tostr(); (*temp_str) += *(mthd->expr->str); (*temp_str) += ")";} else {(*temp_str) += "()";} FREE_VAL; str = temp_str; type = STR; break; default: err = E_BUG_IN_TOSTR; type = ERR; return;} type = STR; }; void Value::tolist(Val_List* cdr){ Val_List* templist; if (type == SUBR) subr_to_list(); if (cdr) templist = new Val_List (copy(), cdr); else templist = new Val_List (copy()); FREE_VAL; list = templist; type = LIST; } void Value::toexpr(Val_List* cdr){ tolist(cdr); type = EXPR; } void Value::subr_to_list (){ Val_List* templist; if (type == SUBR) {templist = sub->copy_full_list(); delete sub; list = templist; type = LIST;} } Value* Value::grab(){ use_count++; return this; } void Value::release(){ if (this && (! (-- use_count))) delete this; } Value* Value::copy(){ Value* temp; switch (type) {case NUM: case OBJ: case ERR: case RESERVED: temp = new Value (num , type); break; case REAL: temp = new Value (real); break; case STR: case SYM: temp = new Value ((new String (*str)), type); break; case USER: temp = new Value (user->get_type(), user->get_val()); break; case LIST: case EXPR: if (! list) temp = new Value (list, type); else {temp = new Value (list->copy(), type);} break; case MTHD: temp = new Value (mthd->copy()); break; case SUBR: temp = sub->copy_full_val(); /** do i need to copy it? hmmm. **/ /** later, change this to just make another subrange ***/ break; default: temp = new Value (E_BUG_IN_COPY , ERR);} return temp; } Value* Value::ensure_clean(){ if (use_count > 1) {use_count--; return copy();} if (type == SUBR) subr_to_list(); else if (type == LIST || type == EXPR) {list->ensure_clean();} return this; } void Value::concat (Val_List* inlist){ if (type == SUBR) subr_to_list(); if (type!= LIST && type != EXPR) {FREE_VAL; delete inlist; err = E_TYPE; return;} list->cat(inlist); } Value* Value::nth (int i){ switch (type) {case LIST: case EXPR: return list->nth(i); case SUBR: return sub->nth(i);} return NULL; } Value* Value::car (String** error_string){ Value* temp; String err_string; switch (type) {case LIST: case EXPR: case SUBR: if (temp = nth (1)) return temp->grab(); else {err_string = "attempting to take 'car' of an empty LIST"; SET_ERROR(err_string); return new Value (E_RANGE , ERR);}} err_string = "car expects a LIST, received a "; err_string += type_strings[type]; SET_ERROR(err_string); return new Value (E_TYPE , ERR); } Value* Value::index (Value* i, String** error_string){ Value* temp; String err_string; if (i->type != NUM) {err_string = "index expects a NUMBER as the first argument, received a "; err_string += type_strings[i->type]; SET_ERROR(err_string); return new Value (E_TYPE , ERR);} if (type != LIST && type != EXPR && type != SUBR) {err_string = "index expects a LIST as the second argument, received a "; err_string += type_strings[type]; SET_ERROR(err_string); return new Value (E_TYPE , ERR);} temp = nth (i->num); if (!temp || i->num < 1) {err_string = "attempted to take index "; concat_num (err_string, i->num); err_string += " of a "; concat_num (err_string, list->length()); err_string += " element list"; SET_ERROR(err_string); return new Value (E_RANGE , ERR);} return temp->grab(); } void Value::tolength (String** error_string){ int i; String err_string; if (type != LIST && type != EXPR && type != STR && type != SUBR && type != SYM) {err_string = "length expects a LIST, STRING, or SYMBOL, received a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} i = get_length(); FREE_VAL; type = NUM; num = i; } int Value::get_length (){ int i; switch (type) {case LIST: case EXPR: i = list->length(); break; case STR: i = str->length(); break; case SUBR: i = sub->get_length(); break; default: i = -1;} return i; } void Value::insert (Value* inval, int position, String** error_string){ Val_List* templist; String err_string; if ((type == STR && inval->type != STR) || (type != LIST && type != EXPR && type != STR && type != SUBR)) {err_string = "insert expects a LIST or STRING, received a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} switch (type) {case SUBR: subr_to_list(); case LIST: case EXPR: if ((list->length()+1) < position || position < 1) {err_string = "attempting to insert beyond the range of a LIST"; SET_ERROR(err_string); FREE_VAL; err = E_RANGE; return;} list = list->insert (inval , position); return; case STR: if ((str->length()+1) < position || position < 1) {err_string = "attempting to insert beyond the length of a STRING"; SET_ERROR(err_string); FREE_VAL; err = E_RANGE; return;} cat (str->before(position-1), *inval->str, str->from(position-1), *str);} } void Value::increment (){ if (type != NUM) {FREE_VAL; err = E_TYPE; return;} num++; } void Value::square_root(String** error_string){ String err_string; switch (type) {case NUM: real = (float)num; case REAL: if (real < 0) {err_string = "attempted to take the square root of a negative NUMBER"; SET_ERROR(err_string); type = ERR; err = E_DIV_BY_ZERO; return;} type = REAL; real = sqrt(real); break; default: err_string = "square-root expects a NUMBER or REAL, received a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; type = ERR; err = E_TYPE;} } void Value::add (Value* invar, String** error_string){ Val_List* templist; String* tempstring, err_string; if (! ((type == SUBR && invar->type == LIST) || (type == LIST && invar->type == SUBR) || (type == SUBR && invar->type == SUBR))) if (invar->type != type || type == OBJ || type == ERR || type == RESERVED || type == SYM || type == EXPR) {err_string = "invalid attempt to add/concat a "; err_string += type_strings[type]; err_string += " with a "; err_string += type_strings[invar->type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} switch (type) {case NUM: num = (invar->num + num); break; case REAL: real += invar->real; break; case STR: if ((str->length() + invar->str->length()) >= MAXStrRep_SIZE) {FREE_VAL; err = E_LENGTH; err_string = "concatenating strings would produce a too long string"; return;} str->prepend (*(invar->str)); break; case SUBR: subr_to_list(); case LIST: if (!list) list = ((invar->type == LIST) ? invar->list->copy() : invar->sub->copy_full_list()); else {templist = ((invar->type == LIST) ? invar->list->copy() : invar->sub->copy_full_list()); if (templist) {templist->cat (list); list = templist;}} break; default: type = ERR; err = E_BUG_IN_ADD;} } void Value::subtract (Value* invar, String** error_string){ String err_string; if (invar->type != type || (type != NUM && type != REAL)) {err_string = "invalid attempt to subtract a "; err_string += type_strings[invar->type]; err_string += " from a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} switch (type) {case NUM: num -= invar->num; break; case REAL: real -= invar->real; break;} } void Value::div (Value* invar, String** error_string){ String err_string; if (invar->type != type || (type != NUM && type != REAL)) {err_string = "invalid attempt to divide a "; err_string += type_strings[invar->type]; err_string += " by a "; err_string += type_strings[type]; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} switch (type) {case NUM: if (!invar->num) {err_string = "division by zero not allowed"; SET_ERROR(err_string); err = E_DIV_BY_ZERO; type = ERR; return;} num = num / invar->num; break; case REAL: if (invar->real == (float)0) {err_string = "division by zero not allowed"; SET_ERROR(err_string); err = E_DIV_BY_ZERO; type = ERR; return;} real = real / invar->real; break;} } void Value::mod (Value* invar, String** error_string){ String err_string; if (invar->type != type || type != NUM) {err_string = "invalid attempt to modulo divide (%) a "; err_string += type_strings[invar->type]; err_string += " by a "; err_string += type_strings[type]; err_string += " (both arguments must be NUMBERS)"; SET_ERROR(err_string); FREE_VAL; err = E_TYPE; return;} if (!invar->num) {err_string = "modulo division by zero not allowed"; SET_ERROR(err_string); err = E_DIV_BY_ZERO; type = ERR; return;} num = num % invar->num; } void Value::mul (Value* invar, String** error_string){ String err_string; if (invar->type != type || (type != NUM && type != REAL)) {err_string = "invalid attempt to multiply a "; err_string += type_strings[invar->type]; err_string += " by a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; err = E_TYPE; return;} switch (type) {case NUM: num = num * invar->num; break; case REAL: real = real * invar->real; break;} } int Value::compare (Value* inval){ if (type == SUBR) subr_to_list(); if (inval->type == SUBR) inval->subr_to_list(); if (type != inval->type) {return INT_MAX;} switch (type) {case NUM: case ERR: case OBJ: case RESERVED: return (num - inval->num); case REAL: /** compares after truncating past two digits **/ return (int)((inval->num * 100 - num * 100) / 100); case STR: return (fcompare (*str , *(inval->str))); case SYM: return (fcompare (*sym , *(inval->sym))); case USER: return INT_MAX; case LIST: return (list->compare (inval->list));} return INT_MAX; } void Value::equal (Value* inval, String** error_string){ int ret; String err_string; ret = compare (inval); if (ret == INT_MAX) {err_string = "invalid attempt to check equality (=) between a "; err_string += type_strings[inval->type]; err_string += " and a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; type = ERR; err = E_INCOMPATIBLE_TYPES;} else {FREE_VAL; if (!ret) {type = NUM; num = 1;} else {type = LIST; list = NULL;}} } void Value::less_than (Value* inval, String** error_string){ int ret; String err_string; ret = compare (inval); if (ret == INT_MAX) {err_string = "invalid attempt to compare (<) a "; err_string += type_strings[inval->type]; err_string += " and a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; type = ERR; err = E_INCOMPATIBLE_TYPES;} else {FREE_VAL; if (ret < 0 && ret > INT_MIN) {type = NUM; num = 0 - ret;} else {type = LIST; list = NULL;}} } void Value::less_than_equal (Value* inval, String** error_string){ int ret; String err_string; ret = compare (inval); if (ret == INT_MAX) {err_string = "invalid attempt to compare (<=) a "; err_string += type_strings[inval->type]; err_string += " and a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; type = ERR; err = E_INCOMPATIBLE_TYPES;} else {FREE_VAL; if (ret <= 0 && ret > INT_MIN) {type = NUM; num = 1;} else {type = LIST; list = NULL;}} } void Value::greater_than_equal (Value* inval, String** error_string){ int ret; String err_string; ret = compare (inval); if (ret == INT_MAX) {err_string = "invalid attempt to compare (<=) a "; err_string += type_strings[inval->type]; err_string += " and a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; type = ERR; err = E_INCOMPATIBLE_TYPES;} else {FREE_VAL; if (ret >= 0 && ret > INT_MIN) {type = NUM; num = 1;} else {type = LIST; list = NULL;}} } void Value::not (String** error_string){ long temp = 1; String err_string; Value_Type ntype = NUM; switch (type) {case ERR: break; case SYM: case USER: case SUBR: FREE_VAL; type = LIST; list = NULL; return; case STR: if (str->length()) {FREE_VAL; type = LIST; list = NULL; return;} break; case LIST: if (list) {FREE_VAL; type = LIST; list = NULL; return;} break; case NUM: if (num) {FREE_VAL; type = LIST; list = NULL; return;} break; default: err_string = "invalid type received by not: "; err_string += type_strings[type]; SET_ERROR (err_string); ntype = ERR; temp = E_TYPE;} FREE_VAL; type = ntype; num = temp; } void Value::greater_than (Value* inval, String** error_string){ int ret; String err_string; ret = compare (inval); if (ret == INT_MAX) {err_string = "invalid attempt to compare (>) a "; err_string += type_strings[inval->type]; err_string += " and a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; type = ERR; err = E_INCOMPATIBLE_TYPES;} else {FREE_VAL; if (ret > 0) {type = NUM; num = 0 - ret;} else {type = LIST; list = NULL;}} } Value* get_time(){ return new Value (time ((time_t*)0)); } Value* get_random(){ return new Value (rand ()); } Value* reg_split(Value* regstring, Value* bigstring){ String subs; Regex* rx; int i; Val_List* temp_list = NULL; // cout << "ENTERING REG_SPLIT [" << *(regstring->str) << "] [" // << *(bigstring->str) << "]\n"; if (! valid_regexp (regstring->str)) {return new Value (E_INVALID_REGEXP , ERR);} rx = new Regex (regstring->str->chars()); if ((! bigstring->str->length())|| ((i = bigstring->str->index (*rx)) < 0)) return new Value ((Val_List*)NULL); subs = bigstring->str->through (*rx); if (!i && !subs.length()) return new Value ((Val_List*)NULL); temp_list = new Val_List (new Value (new String (bigstring->str->after (subs)))); temp_list = new Val_List (new Value (new String (subs.from(i))), temp_list); temp_list = new Val_List (new Value (new String (subs.before (i))), temp_list); delete rx; // cout << "EXITTING REG_SPLIT\n"; return new Value (temp_list); } char* Value::pack_value (char* buf){ long i; *buf = (char) type; buf++; switch (type) {case NUM: case OBJ: case ERR: case RESERVED: PACK_INT(buf , num); buf += sizeof (long); break; case STR: case SYM: strcpy (buf , str->chars()); buf += str->length() + 1; break; case REAL: PACK_FLOAT(buf, real); buf += sizeof (float); break; case MTHD: buf = mthd->pack_method (buf); break; case USER: i = user->get_type(); PACK_INT (buf, i); buf = user->get_val()->pack_value (buf + sizeof (long)); break; case SUBR: subr_to_list(); *(buf-1) = (char) LIST; case LIST: case EXPR: if (list) {i = list->length(); PACK_INT(buf, i); buf += sizeof (long); buf = list->pack_list (buf);} else {i = 0; PACK_INT(buf , i); buf += sizeof (float);} break; default: cout << "ERROR in packing value ... invalid type found";} return buf; } Value* unpack_value (char** temp_bufptr){ char* buf, type; Value* retval; Val_List* cdr; String* tempstring; long i, j, k; float flt; buf = *temp_bufptr; type = (*buf); buf++; switch (type) {case STR: case SYM: tempstring = new String (buf); buf += tempstring->length() + 1; retval = new Value (tempstring, (Value_Type)type); break; case NUM: case OBJ: case ERR: case RESERVED: UNPACK_INT (buf , i); retval = new Value (i , (Value_Type)type); buf += sizeof (long); break; case USER: UNPACK_INT (buf, i); buf += sizeof(long); retval = new Value (i, unpack_value(&buf)); break; case REAL: UNPACK_FLOAT (buf, flt); buf += sizeof (float); retval = new Value (flt); break; case MTHD: UNPACK_INT (buf, i); buf += sizeof (long); for (j = 0 , cdr = NULL ; j<i ; j++) {tempstring = new String (++buf); k = tempstring->length(); cdr = new Val_List (new Value (tempstring, SYM), cdr); buf += tempstring->length() + 1;} retval = new Value (new Method (cdr , unpack_value (&buf))); break; case LIST: case EXPR: UNPACK_INT (buf, i); buf += sizeof (long); for (j = 0 , cdr = NULL ; j<i ; j++) cdr = new Val_List (unpack_value (&buf), cdr); retval = new Value (cdr , (Value_Type)type); break; default: cout << "ERROR in unpacking value ... invalid type found.\n"; retval = NULL;} *temp_bufptr = buf; return retval; } void Value::encryption (String** error_string){ char *temp, salt[3]; String err_string; if (type != STR) {err_string = "crypt requires a STRING, received a "; err_string += type_strings[type]; SET_ERROR (err_string); FREE_VAL; err = E_TYPE; return;} salt[2] = '\0'; if (str->length() < 2) {salt[0] = 'A'; salt[1] = 'A';} else {salt[0] = str->chars()[0]; salt[1] = str->chars()[1];} temp = crypt ((char*)str->chars(), salt); delete str; str = new String (temp); } int Value::ok_clause(){ switch (type) {case STR: return 1; case SYM: return is_command_constant (sym); case LIST: case EXPR: return list->ok_clause();} return 0; } String* Value::command_match (String& pattern){ String* tempstring; int nonspace = 0; if (type != STR || pattern.index (*str) != 0) while (pattern.index(" ", nonspace) == nonspace) nonspace++; switch (type) {case STR: if (str->length() == 0) return new String; if (pattern.index(*str, nonspace) == nonspace) return new String (*str); break; case SYM: if (tempstring = match_command_constant (sym, pattern.from(nonspace))) return tempstring; break; case LIST: case EXPR: if (list->length() && list->elem->get_type() == RESERVED) switch (list->elem->reserved) {case OR: return list->next->command_match_OR (pattern); case BEFORE: return list->next->elem->command_match_BEFORE (pattern.from(nonspace));} break; default: break;} return NULL; } String* Value::command_match_BEFORE (String& pattern){ String* retval; Regex* re; int qpos = 0, spos; if (pattern.index("\"") == 0) if ((qpos = pattern.index("\"", 1)) > -1) qpos++; spos = -1; switch (type) {case STR: spos = pattern.index (*str, qpos); break; case SYM: if (re = get_command_constant (sym)) spos = pattern.index (*re, qpos); default: break;} if (spos > -1) {retval = new String (pattern.before (spos)); while (retval->length() && retval->elem(retval->length()-1) == ' ') *retval = retval->before (retval->length()-1); return retval;} return NULL; } Value* Value::implode (Value* separator, String** error_string){ String err_string, *retval=NULL; Val_List* listptr; retval = new String; for (listptr = list ; listptr && (listptr->elem->get_type() == STR) ; listptr = listptr->next) {*retval += *listptr->elem->str; if (listptr->next) *retval += *separator->str;} if (!listptr) return new Value (retval); err_string = "you can only implode a list of strings."; SET_ERROR (err_string); delete retval; return new Value (E_TYPE , ERR); } int Value::obj_val(){ return (type==OBJ ? obj : -1); } void Value::print_val (){ /** converts to string first ... **/ int i; format (0, 75); cout << *str; } /************************************************************** ******* class Value_Stack declarations: ********************** ***************************************************************/ Value_Stack::Value_Stack(int isize){ allocated = isize; vstack = new Value* [isize]; scope_level = new int [isize]; current_scope = 0; depth = 0; scope_depth = 0; }; Value_Stack::~Value_Stack(){ while (depth) vstack [--depth] -> release(); delete scope_level; delete vstack; }; void Value_Stack::push_val (Value* someval){ scope_level[depth] = current_scope; vstack[depth++] = someval->grab(); scope_depth++; if (depth == allocated) grow(); } Value* Value_Stack::pop_val (){ if (depth) {scope_depth--; return vstack[--depth];} /**** caller is responsible for deleting ****/ else {return new Value (E_STACK_UN, ERR);} } Value* Value_Stack::peek (){ if (depth) {return vstack[depth-1];} else {return new Value (E_STACK_UN, ERR);} } void Value_Stack::push_scope (void){ current_scope++; scope_depth = 0; } void Value_Stack::pop_scope (void){ int i; while (scope_depth) (pop_val())->release(); current_scope--; for (i=depth-1 ; i>=0 && scope_level [i] == current_scope ; i-- , scope_depth++); } Value* Value_Stack::peek_scope_bottom (void){ if (!scope_depth) return (Value*)NULL; return vstack [depth - scope_depth]; } Value** Value_Stack::pointer_scope_bottom (void){ if (!scope_depth) return (Value**)NULL; return &(vstack [depth - scope_depth]); } Value* Value_Stack::highest_not_anon (Value* anon){ int i; for (i=depth ; i ;) if (vstack[--i] != anon) {depth_found_at = i; return vstack[i];} depth_found_at = -1; return NULL; } void Value_Stack::grow (int by){ Value** temp_vstack = new Value* [allocated + by]; int* temp_scope_level = new int [allocated+by]; int i; for (i=0 ; i<depth ; i++) {temp_vstack[i] = vstack[i]; temp_scope_level[i] = scope_level[i];} allocated += by; delete vstack; delete scope_level; vstack = temp_vstack; scope_level = temp_scope_level; } void concat_num (String& instring, int num){ char charblock[12]; sprintf (charblock , "%d", num); instring += charblock; }