void VDScriptInterpreter::ExecuteLine(const char *s) {
	int t;

	mErrorExtraToken.clear();

	TokenBegin(s);

	while(t = Token()) {
		if (isExprFirstToken(t)) {
			TokenUnput(t);
			VDASSERT(mStack.empty());
			ParseExpression();

			VDASSERT(!mStack.empty());

			VDScriptValue& val = mStack.back();

			mStack.pop_back();
			VDASSERT(mStack.empty());

			if (Token() != ';')
				SCRIPT_ERROR(SEMICOLON_EXPECTED);
		} else if (t == TOK_DECLARE) {

			do {
				t = Token();

				if (t != TOK_IDENT)
					SCRIPT_ERROR(IDENTIFIER_EXPECTED);

				VariableTableEntry *vte = vartbl.Declare(szIdent);

				t = Token();

				if (t == '=') {
					ParseExpression();

					VDASSERT(!mStack.empty());
					vte->v = mStack.back();
					mStack.pop_back();

					t = Token();
				}

			} while(t == ',');

			if (t != ';')
				SCRIPT_ERROR(SEMICOLON_EXPECTED);

		} else
			SCRIPT_ERROR(PARSE_ERROR);
	}

	VDASSERT(mStack.empty());

	GC();
}
VDScriptValue VDScriptInterpreter::LookupRootVariable(char *szName) {
	VariableTableEntry *vte;

	if (vte = vartbl.Lookup(szName))
		return VDScriptValue(vte);

	if (!strcmp(szName, "Sylia"))
		return VDScriptValue(NULL, &obj_Sylia);

	const char *volatile _szName = szName;		// needed to fix exception handler, for some reason

	VDScriptValue ret;

	try {
		if (!lpRoothandler)
			SCRIPT_ERROR(VAR_NOT_FOUND);

		ret = lpRoothandler(this, szName, lpRoothandlerData);
	} catch(const VDScriptError& e) {
		if (e.err == VDScriptError::VAR_NOT_FOUND) {
			mErrorExtraToken = _szName;
			throw;
		}
	}

	return ret;
}
void VDScriptInterpreter::InvokeMethod(const VDScriptObject *obj, const char *name, int argc) {
	if (obj->func_list) {
		const VDScriptFunctionDef *sfd = obj->func_list;

		while(sfd->arg_list) {
			if (sfd->name && !strcmp(sfd->name, name)) {
				InvokeMethod(sfd, argc);
				return;
			}

			++sfd;
		}
	}

	SCRIPT_ERROR(OVERLOADED_FUNCTION_NOT_FOUND);
}
Exemple #4
0
VariableTableEntry *VariableTable::Declare(const char *szName) {
	VariableTableEntry *vte;
	long lHashVal = Hash(szName);
	long lNameLen;

	lNameLen	= strlen(szName);

	vte			= (VariableTableEntry *)varheap.Allocate(sizeof(VariableTableEntry) + lNameLen);
	if (!vte)
		SCRIPT_ERROR(OUT_OF_MEMORY);

	vte->next	= lpHashTable[lHashVal];
	vte->v		= VDScriptValue();
	strcpy(vte->szName, szName);

	lpHashTable[lHashVal] = vte;

	return vte;
}
void VDScriptInterpreter::Reduce() {
	const int op = mOpStack.back();
	mOpStack.pop_back();

	switch(op) {
	case '=':
		{
			VDScriptValue& v = mStack[mStack.size() - 2];

			if (!v.isVarLV())
				SCRIPT_ERROR(TYPE_OBJECT_REQUIRED);

			ConvertToRvalue();

			v.asVarLV()->v = mStack.back();
			mStack.pop_back();
		}
		break;
	case TOK_OR:		InvokeMethod(&obj_Sylia, "||", 2); break;
	case TOK_AND:		InvokeMethod(&obj_Sylia, "&&", 2); break;
	case '|':			InvokeMethod(&obj_Sylia, "|", 2); break;
	case '^':			InvokeMethod(&obj_Sylia, "^", 2); break;
	case '&':			InvokeMethod(&obj_Sylia, "&", 2); break;
	case TOK_EQUALS:	InvokeMethod(&obj_Sylia, "==", 2); break;
	case TOK_NOTEQ:		InvokeMethod(&obj_Sylia, "!=", 2); break;
	case '<':			InvokeMethod(&obj_Sylia, "<", 2); break;
	case '>':			InvokeMethod(&obj_Sylia, ">", 2); break;
	case TOK_LESSEQ:	InvokeMethod(&obj_Sylia, "<=", 2); break;
	case TOK_GRTREQ:	InvokeMethod(&obj_Sylia, ">=", 2); break;
	case '+':			InvokeMethod(&obj_Sylia, "+", 2); break;
	case '-':			InvokeMethod(&obj_Sylia, "-", 2); break;
	case '*':			InvokeMethod(&obj_Sylia, "*", 2); break;
	case '/':			InvokeMethod(&obj_Sylia, "/", 2); break;
	case '%':			InvokeMethod(&obj_Sylia, "%", 2); break;
	}
}
Exemple #6
0
/*
 * parse a function and its arguments and fill the structure
 */
int encode_function(char *string, struct filter_op *fop)
{
   char *str = strdup(string);
   int ret = -ENOTFOUND;
   char *name, *args;
   int nargs = 0, i;
   char **dec_args = NULL;
   char *tok;

   memset(fop, 0, sizeof(struct filter_op));
   
   /* get the name of the function */
   name = ec_strtok(string, "(", &tok);
   /* get all the args */
   args = name + strlen(name) + 1;

   /* analyze the arguments */
   dec_args = decode_args(args, &nargs);

   /* this fop is a function */
   fop->opcode = FOP_FUNC;

   /* check if it is a known function */
   if (!strcmp(name, "search")) {
      if (nargs == 2) {
         /* get the level (DATA or DECODED) */
         if (encode_offset(dec_args[0], fop) == ESUCCESS) {
            /* encode offset wipe the fop !! */
            fop->opcode = FOP_FUNC;
            fop->op.func.op = FFUNC_SEARCH;
            fop->op.func.string = (u_char*)strdup(dec_args[1]);
            fop->op.func.slen = strescape((char*)fop->op.func.string, (char*)fop->op.func.string);
            ret = ESUCCESS;
         } else
            SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "regex")) {
      if (nargs == 2) {
         int err;
         regex_t regex;
         char errbuf[100];
         
         /* get the level (DATA or DECODED) */
         if (encode_offset(dec_args[0], fop) == ESUCCESS) {
            /* encode offset wipe the fop !! */
            fop->opcode = FOP_FUNC;
            fop->op.func.op = FFUNC_REGEX;
            fop->op.func.string = (u_char*)strdup(dec_args[1]);
            fop->op.func.slen = strescape((char*)fop->op.func.string, (char*)fop->op.func.string);
            ret = ESUCCESS;
         } else
            SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);

         /* check if the regex is valid */
         err = regcomp(&regex, (const char*)fop->op.func.string, REG_EXTENDED | REG_NOSUB | REG_ICASE );
         if (err) {
            regerror(err, &regex, errbuf, sizeof(errbuf));
            SCRIPT_ERROR("%s", errbuf);
         } 
         
         regfree(&regex);
                        
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "pcre_regex")) {
#ifndef HAVE_PCRE
      WARNING("The script contains pcre_regex, but you don't have support for it.");
#else
      pcre *pregex;
      const char *errbuf = NULL;
      int erroff;
      
      if (nargs == 2) {
                     
         /* get the level (DATA or DECODED) */
         if (encode_offset(dec_args[0], fop) == ESUCCESS) {
            /* encode offset wipe the fop !! */
            fop->opcode = FOP_FUNC;
            fop->op.func.op = FFUNC_PCRE;
            fop->op.func.string = strdup(dec_args[1]);
            fop->op.func.slen = strlen(fop->op.func.string);
            ret = ESUCCESS;
         } else
            SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);

         /* check if the pcre is valid */
         pregex = pcre_compile(fop->op.func.string, 0, &errbuf, &erroff, NULL );
         if (pregex == NULL)
            SCRIPT_ERROR("%s\n", errbuf);

         pcre_free(pregex);
      } else if (nargs == 3) {
            
         fop->opcode = FOP_FUNC;
         fop->op.func.op = FFUNC_PCRE;
         /* substitution always at layer DATA */
         fop->op.func.level = 5;
         fop->op.func.string = strdup(dec_args[1]);
         fop->op.func.slen = strlen(fop->op.func.string);
         fop->op.func.replace = strdup(dec_args[2]);
         fop->op.func.rlen = strlen(fop->op.func.replace);
         ret = ESUCCESS;
         
         /* check if the pcre is valid */
         pregex = pcre_compile(fop->op.func.string, 0, &errbuf, &erroff, NULL );
         if (pregex == NULL)
            SCRIPT_ERROR("%s\n", errbuf);

         pcre_free(pregex);
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
#endif
   } else if (!strcmp(name, "replace")) {
      if (nargs == 2) {
         fop->op.func.op = FFUNC_REPLACE;
         /* replace always operate at DATA level */
         fop->op.func.level = 5;
         fop->op.func.string = (u_char*)strdup(dec_args[0]);
         fop->op.func.slen = strescape((char*)fop->op.func.string, (char*)fop->op.func.string);
         fop->op.func.replace = (u_char*)strdup(dec_args[1]);
         fop->op.func.rlen = strescape((char*)fop->op.func.replace, (char*)fop->op.func.replace);
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "inject")) {
      if (nargs == 1) {
         fop->op.func.op = FFUNC_INJECT;
         /* inject always operate at DATA level */
         fop->op.func.level = 5;
         fop->op.func.string = (u_char*)strdup(dec_args[0]);
         fop->op.func.slen = strlen((const char*)fop->op.func.string);
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "execinject")) {
      if (nargs == 1) {
         fop->op.func.op = FFUNC_EXECINJECT;
         /* execinject always operate at DATA level */
         fop->op.func.level = 5;
         fop->op.func.string = (u_char*)strdup(dec_args[0]);
         fop->op.func.slen = strlen((const char*)fop->op.func.string);
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "log")) {
      if (nargs == 2) {
         /* get the level (DATA or DECODED) */
         if (encode_offset(dec_args[0], fop) == ESUCCESS) {
            /* encode offset wipe the fop !! */
            fop->opcode = FOP_FUNC;
            fop->op.func.op = FFUNC_LOG;
            fop->op.func.string = (u_char*)strdup(dec_args[1]);
            fop->op.func.slen = strlen((const char*)fop->op.func.string);
            ret = ESUCCESS;
         } else
            SCRIPT_ERROR("Unknown offset %s ", dec_args[0]);
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "drop")) {
      if (nargs == 0) {
         fop->op.func.op = FFUNC_DROP;
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "kill")) {
      if (nargs == 0) {
         fop->op.func.op = FFUNC_KILL;
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "msg")) {
      if (nargs == 1) {
         fop->op.func.op = FFUNC_MSG;
         fop->op.func.string = (u_char*)strdup(dec_args[0]);
         fop->op.func.slen = strescape((char*)fop->op.func.string, (char*)fop->op.func.string);
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "exec")) {
      if (nargs == 1) {
         fop->op.func.op = FFUNC_EXEC;
         fop->op.func.string = (u_char*)strdup(dec_args[0]);
         fop->op.func.slen = strlen((const char*)fop->op.func.string);
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   } else if (!strcmp(name, "exit")) {
      if (nargs == 0) {
         fop->opcode = FOP_EXIT;
         ret = ESUCCESS;
      } else
         SCRIPT_ERROR("Wrong number of arguments for function \"%s\" ", name);
   }

   /* free the array */
   for (i = 0; i < nargs; i++)
      SAFE_FREE(dec_args[i]);
      
   SAFE_FREE(dec_args);
   SAFE_FREE(str);
   return ret;
}
int VDScriptInterpreter::Token() {
	static char hexdig[]="0123456789ABCDEF";
	char *s,c;

	if (tokhold) {
		int t = tokhold;
		tokhold = 0;
		return t;
	}

	do {
		c=*tokstr++;
	} while(c && isspace((unsigned char)c));

	if (!c) {
		--tokstr;

		return 0;
	}

	// C++ style comment?

	if (c=='/')
		if (tokstr[0]=='/') {
			while(*tokstr) ++tokstr;

			return 0;		// C++ comment
		} else
			return '/';

	// string?

	if (c=='"') {
		const char *s = tokstr;
		char *t;
		long len_adjust=0;

		while((c=*tokstr++) && c!='"') {
			if (c=='\\') {
				c = *tokstr++;
				if (!c) SCRIPT_ERROR(PARSE_ERROR);
				else {
					if (c=='x') {
						if (!isxdigit((unsigned char)tokstr[0]) || !isxdigit((unsigned char)tokstr[1]))
							SCRIPT_ERROR(PARSE_ERROR);
						tokstr+=2;
						len_adjust += 2;
					}
					++len_adjust;
				}
			}
		}

		tokslit = strheap.Allocate(tokstr - s - 1 - len_adjust);
		t = *tokslit;
		while(s<tokstr-1) {
			int val;

			c = *s++;

			if (c=='\\')
				switch(c=*s++) {
				case 'a': *t++='\a'; break;
				case 'b': *t++='\b'; break;
				case 'f': *t++='\f'; break;
				case 'n': *t++='\n'; break;
				case 'r': *t++='\r'; break;
				case 't': *t++='\t'; break;
				case 'v': *t++='\v'; break;
				case 'x':
					val = strchr(hexdig,toupper(s[0]))-hexdig;
					val = (val<<4) | (strchr(hexdig,toupper(s[1]))-hexdig);
					*t++ = val;
					s += 2;
					break;
				default:
					*t++ = c;
				}
			else
				*t++ = c;
		}
		*t=0;

		if (!c) --tokstr;

		return TOK_STRING;
	}

	// unescaped string?
	if ((c=='u' || c=='U') && *tokstr == '"') {
		const char *s = ++tokstr;

		while((c=*tokstr++) && c != '"')
			;

		if (!c) {
			--tokstr;
			SCRIPT_ERROR(PARSE_ERROR);
		}

		size_t len = tokstr - s - 1;

		const VDStringA strA(VDTextWToU8(VDTextAToW(s, len)));

		len = strA.size();

		tokslit = strheap.Allocate(len);
		memcpy(*tokslit, strA.data(), len);
		(*tokslit)[len] = 0;

		return TOK_STRING;
	}

	// look for variable/keyword

	if (isIdentFirstChar(c)) {
		s = szIdent;

		*s++ = c;
		while(isIdentNextChar(c = *tokstr++)) {
			if (s>=szIdent + MAX_IDENT_CHARS)
				SCRIPT_ERROR(IDENT_TOO_LONG);

			*s++ = c;
		}

		--tokstr;
		*s=0;

		if (!strcmp(szIdent, "declare"))
			return TOK_DECLARE;
		else if (!strcmp(szIdent, "true"))
			return TOK_TRUE;
		else if (!strcmp(szIdent, "false"))
			return TOK_FALSE;
		else if (!strcmp(szIdent, "int"))
			return TOK_INT;
		else if (!strcmp(szIdent, "long"))
			return TOK_LONG;
		else if (!strcmp(szIdent, "double"))
			return TOK_DOUBLE;

		return TOK_IDENT;
	}

	// test for number: decimal (123), octal (0123), or hexadecimal (0x123)

	if (isdigit((unsigned char)c)) {
		sint64 v = 0;

		if (c=='0' && tokstr[0] == 'x') {

			// hex (base 16)
			++tokstr;

			while(isxdigit((unsigned char)(c = *tokstr++))) {
				v = v*16 + (strchr(hexdig, toupper(c))-hexdig);
			}

		} else if (c=='0' && isdigit((unsigned char)tokstr[0])) {
			// octal (base 8)
			while((c=*tokstr++)>='0' && c<='7')
				v = v*8 + (c-'0');
		} else {
			// check for float
			const char *s = tokstr;
			while(*s) {
				if (*s == '.' || *s == 'e' || *s == 'E') {
					// It's a float -- parse and return.

					--tokstr;
					tokdval = strtod(tokstr, (char **)&tokstr);
					return TOK_DBLVAL;
				}

				if (!isdigit((unsigned char)*s))
					break;
				++s;
			}

			// decimal
			v = (c-'0');
			while(isdigit((unsigned char)(c=*tokstr++)))
				v = v*10 + (c-'0');
		}
		--tokstr;

		if (v > 0x7FFFFFFF) {
			toklval = v;
			return TOK_LONGVAL;
		} else {
			tokival = (int)v;
			return TOK_INTVAL;
		}
	}

	// test for symbols:
	//
	//	charset:	+-*/<>=!&|^[]~;%(),
	//	solitary:	+-*/<>=!&|^[]~;%(),
	//	extra:		!= <= >= == && ||
	//
	//	the '/' is handled above for comment handling

	if (c=='!')
		if (tokstr[0] == '=') { ++tokstr; return TOK_NOTEQ;  } else return '!';

	if (c=='<')
		if (tokstr[0] == '=') { ++tokstr; return TOK_LESSEQ; } else return '<';

	if (c=='>')
		if (tokstr[0] == '=') { ++tokstr; return TOK_GRTREQ; } else return '>';

	if (c=='=')
		if (tokstr[0] == '=') { ++tokstr; return TOK_EQUALS; } else return '=';

	if (c=='&')
		if (tokstr[0] == '&') { ++tokstr; return TOK_AND;    } else return '&';

	if (c=='|')
		if (tokstr[0] == '|') { ++tokstr; return TOK_OR;     } else return '|';

	if (strchr("+-*^[]~;%(),.",c))
		return c;

	SCRIPT_ERROR(PARSE_ERROR);
}
void VDScriptInterpreter::InvokeMethod(const VDScriptFunctionDef *sfd, int pcount) {
	VDScriptValue *params = NULL;
	
	if (pcount)
		params = &mStack[mStack.size() - pcount];

	// convert params to rvalues
	for(int j=0; j<pcount; ++j) {
		VDScriptValue& parm = params[j];

		if (parm.isVarLV())
			parm = parm.asVarLV()->v;
	}

	mpCurrentInvocationMethod = sfd;
	mMethodArgumentCount = pcount;

	// If we were passed a function name, attempt to match our parameter
	// list to one of the overloaded function templates.
	//
	// 0 = void, v = value, i = int, . = varargs
	//
	// <return value><param1><param2>...
	const char *name = sfd->name;

	// Yes, goto's are usually considered gross... but I prefer
	// cleanly labeled goto's to excessive boolean variable usage.
	const VDScriptFunctionDef *sfd_best = NULL;

	int *best_scores = (int *)_alloca(sizeof(int) * (pcount + 1));
	int *current_scores = (int *)_alloca(sizeof(int) * (pcount + 1));
	int best_promotions = 0;
	bool ambiguous = false;

	while(sfd->arg_list && (sfd->name == name || !sfd->name)) {
		const char *s = sfd->arg_list+1;
		VDScriptValue *csv = params;
		bool better_conversion;
		int current_promotions = 0;

		// reset current scores to zero (default)
		memset(current_scores, 0, sizeof(int) * (pcount + 1));

		enum {
			kConversion = -2,
			kEllipsis = -3
		};

		for(int i=0; i<pcount; ++i) {
			const char c = *s++;

			if (!c)
				goto arglist_nomatch;

			switch(c) {
			case 'v':
				break;
			case 'i':
				if (csv->isLong() || csv->isDouble())
					current_scores[i] = kConversion;
				else if (!csv->isInt())
					goto arglist_nomatch;
				break;
			case 'l':
				if (csv->isDouble())
					current_scores[i] = kConversion;
				else if (csv->isInt())
					++current_promotions;
				else if (!csv->isLong())
					goto arglist_nomatch;
				break;
			case 'd':
				if (csv->isInt() || csv->isLong())
					++current_promotions;
				else if (!csv->isDouble())
					goto arglist_nomatch;
				break;
			case 's':
				if (!csv->isString()) goto arglist_nomatch;
				break;
			case '.':
				--s;			// repeat this character
				break;
			default:
				SCRIPT_ERROR(EXTERNAL_ERROR);
			}
			++csv;
		}

		// check if we have no parms left, or only an ellipsis
		if (*s == '.' && !s[1]) {
			current_scores[pcount] = kEllipsis;
		} else if (*s)
			goto arglist_nomatch;

		// do check for better match
		better_conversion = true;

		if (sfd_best) {
			better_conversion = false;
			for(int i=0; i<=pcount; ++i) {		// we check one additional parm, the ellipsis parm
				// reject if there is a worse conversion than the best match so far
				if (current_scores[i] < best_scores[i]) {
					goto arglist_nomatch;
				}

				// add +1 if there is a better match
				if (current_scores[i] > best_scores[i])
					better_conversion = true;
			}

			// all things being equal, choose the method with fewer promotions
			if (!better_conversion) {
				if (current_promotions < best_promotions)
					better_conversion = true;
				else if (current_promotions == best_promotions)
					ambiguous = true;
			}
		}

		if (better_conversion) {
			std::swap(current_scores, best_scores);
			sfd_best = sfd;
			best_promotions = current_promotions;
			ambiguous = false;
		}

arglist_nomatch:
		++sfd;
	}

	if (!sfd_best)
		SCRIPT_ERROR(OVERLOADED_FUNCTION_NOT_FOUND);
	else if (ambiguous)
		SCRIPT_ERROR(AMBIGUOUS_CALL);

	// Make sure there is room for the return value.
	int stackcount = pcount;

	if (!stackcount) {
		++stackcount;
		mStack.push_back(VDScriptValue());
	}

	// coerce arguments
	VDScriptValue *const argv = &*(mStack.end() - stackcount);
	const char *const argdesc = sfd_best->arg_list + 1;

	for(int i=0; i<pcount; ++i) {
		VDScriptValue& a = argv[i];
		switch(argdesc[i]) {
		case 'i':
			if (a.isLong())
				a = VDScriptValue((int)a.asLong());
			else if (a.isDouble())
				a = VDScriptValue((int)a.asDouble());
			break;
		case 'l':
			if (a.isInt())
				a = VDScriptValue((sint64)a.asInt());
			else if (a.isDouble())
				a = VDScriptValue((sint64)a.asDouble());
			break;
		case 'd':
			if (a.isInt())
				a = VDScriptValue((double)a.asInt());
			else if (a.isLong())
				a = VDScriptValue((double)a.asLong());
			break;
		}
	}

	// invoke
	mpCurrentInvocationMethodOverload = sfd_best;
	sfd_best->func_ptr(this, argv, pcount);
	mStack.resize(mStack.size() + 1 - stackcount);
	if (sfd_best->arg_list[0] == '0')
		mStack.back() = VDScriptValue();
}
void VDScriptInterpreter::ParseValue() {
	int t = Token();

	if (t=='(') {
		t = Token();

		if (t == TOK_INT) {
			if (Token() != ')')
				SCRIPT_ERROR(CLOSEPARENS_EXPECTED);

			ParseExpression();

			VDScriptValue& v = mStack.back();

			if (v.isDouble())
				v = (int)v.asDouble();
			else if (v.isLong())
				v = (int)v.asLong();
			else if (!v.isInt())
				SCRIPT_ERROR(CANNOT_CAST);
		} else if (t == TOK_LONG) {
			if (Token() != ')')
				SCRIPT_ERROR(CLOSEPARENS_EXPECTED);

			ParseExpression();

			VDScriptValue& v = mStack.back();

			if (v.isDouble())
				v = (sint64)v.asDouble();
			else if (v.isInt())
				v = (sint64)v.asInt();
			else if (!v.isLong())
				SCRIPT_ERROR(CANNOT_CAST);
		} else if (t == TOK_DOUBLE) {
			if (Token() != ')')
				SCRIPT_ERROR(CLOSEPARENS_EXPECTED);

			ParseExpression();

			VDScriptValue& v = mStack.back();

			if (v.isInt())
				v = (double)v.asInt();
			else if (v.isLong())
				v = (double)v.asLong();
			else if (!v.isDouble())
				SCRIPT_ERROR(CANNOT_CAST);
		} else {
			TokenUnput(t);

			ParseExpression();

			if (Token() != ')')
				SCRIPT_ERROR(CLOSEPARENS_EXPECTED);
		}
	} else if (t==TOK_IDENT) {
		mStack.push_back(LookupRootVariable(szIdent));
	} else if (t == TOK_INTVAL)
		mStack.push_back(VDScriptValue(tokival));
	else if (t == TOK_LONGVAL)
		mStack.push_back(VDScriptValue(toklval));
	else if (t == TOK_DBLVAL)
		mStack.push_back(VDScriptValue(tokdval));
	else if (t == TOK_STRING)
		mStack.push_back(VDScriptValue(tokslit));
	else if (t=='!' || t=='~' || t=='-' || t=='+') {
		ParseValue();

		switch(t) {
		case '!':		InvokeMethod(&obj_Sylia, "!", 1); break;
		case '~':		InvokeMethod(&obj_Sylia, "~", 1); break;
		case '+':		InvokeMethod(&obj_Sylia, "+", 1); break;
		case '-':		InvokeMethod(&obj_Sylia, "-", 1); break;
			break;
		default:
			SCRIPT_ERROR(PARSE_ERROR);
		}
	} else if (t == TOK_TRUE)
		mStack.push_back(VDScriptValue(1));
	else if (t == TOK_FALSE)
		mStack.push_back(VDScriptValue(0));
	else
		SCRIPT_ERROR(PARSE_ERROR);
}
Exemple #10
0
void VDScriptInterpreter::ParseExpression() {
	int depth = 0;
	int t;
	bool need_value = true;

	for(;;) {
		if (need_value) {
			ParseValue();
			need_value = false;
		}

		t = Token();

		if (!t || t==')' || t==']' || t==',' || t==';') {
			TokenUnput(t);
			break;
		}

		VDScriptValue& v = mStack.back();

		if (t=='.') {			// object indirection operator (object -> member)
			ConvertToRvalue();

			if (!v.isObject()) {
				SCRIPT_ERROR(TYPE_OBJECT_REQUIRED);
			}

			if (Token() != TOK_IDENT)
				SCRIPT_ERROR(OBJECT_MEMBER_NAME_REQUIRED);

			try {
				VDScriptValue v2 = LookupObjectMember(v.asObjectDef(), v.asObjectPtr(), szIdent);

				if (v2.isVoid()) {
					mErrorObject = v;
					SCRIPT_ERROR(MEMBER_NOT_FOUND);
				}

				v = v2;
			} catch(const VDScriptError& e) {
				mErrorObject = v;
				throw;
			}

		} else if (t == '[') {	// array indexing operator (object, value -> value)
			// Reduce lvalues to rvalues

			ConvertToRvalue();

			if (!v.isObject())
				SCRIPT_ERROR(TYPE_OBJECT_REQUIRED);

			ParseExpression();
			InvokeMethod((mStack.end() - 2)->asObjectDef(), "[]", 1);

			VDASSERT(mStack.size() >= 2);
			mStack.erase(mStack.end() - 2);

			if (Token() != ']')
				SCRIPT_ERROR(CLOSEBRACKET_EXPECTED);
		} else if (t == '(') {	// function indirection operator (method -> value)
			ConvertToRvalue();	// can happen if a method is assigned

			const VDScriptValue fcall(mStack.back());
			mStack.pop_back();

			mStack.push_back(VDScriptValue(fcall.u.method.p, fcall.thisPtr));

			int pcount = 0;

			t = Token();
			if (t != ')') {
				TokenUnput(t);

				for(;;) {
					ParseExpression();
					++pcount;
					
					t = Token();

					if (t==')')
						break;
					else if (t!=',')
						SCRIPT_ERROR(FUNCCALLEND_EXPECTED);
				}
			}

			InvokeMethod(fcall.u.method.pfn, pcount);

			VDASSERT(mStack.size() >= 2);
			mStack.erase(mStack.end() - 2);
		} else {
			int prec = ExprOpPrecedence(t) + ExprOpIsRightAssoc(t);

			while(depth > 0 && ExprOpPrecedence(mOpStack.back()) >= prec) {
				--depth;
				Reduce();
			}

			mOpStack.push_back(t);
			++depth;

			need_value = true;
		}
	}

	// reduce until no ops are left
	while(depth-- > 0)
		Reduce();
}