Example #1
0
ExpType CExpression::TypeCheck()
{
	int step = 0;
	if (ExpTree)
		delete ExpTree;
	ExpTree = DoTree(step);
	Evaluate(&constantValue);
	return constantValue.Type();
}
void CExpression::ParseTokenStream()
{
	// Make the tree
	int step = 0;
	pExpressionOwner = NULL;
	ExpTree = DoTree(step);
	ExpTree = PostSortTree(ExpTree);

	// Determine if the overall expression is constant, collapsing constant parts along
	// the way.
	isConstant = ExpTree->Constant();

	// If constant, get the constant value.
	if (isConstant) {
		CollapseConstantTree(ExpTree);
		ExpTree->Evaluate(&constantValue);
	}
}
ExpPart* CExpression::DoBrackets(int& step)
{
	ExpPart* brackets;

	Depth++;

	// Step over left bracket
	step++;
	brackets = DoTree(step);
//	brackets = PostSortTree(brackets);

	Depth--;

	// Step over right bracket
	step++;


	return brackets;

}
// Do Tree:  convert token stream to expression tree
ExpPart* CExpression::DoTree(int& step, bool unaryMode)
{
	ExpPart* LeftPart = NULL;
	ExpPart* Brackets = NULL;
	bool Bracketing; // Brackets override the operator precedentation

	// Too lazy to scope each case label lol
	ExpInteger* pInt;
	ExpFloat* pFloat;
	ExpString* pStr;
	ExpIdent* pIdent;
	ExpAdd* pAdd;
	ExpSubtract* pSub;
	ExpMultiply* pMult;
	ExpDivide* pDiv;
	ExpMod* pMod;
	ExpPower* pPow;
	ExpDot* pDot;
	ExpSin* pSin;
	ExpCos* pCos;
	ExpTan* pTan;
	ExpSqrt* pSqrt;
	ExpFuncInt* pFuncInt;
	ExpFuncFloat* pFuncFloat;
	ExpFuncStr* pFuncStr;
	ExpEqual* pEqual;
	ExpNotEqual* pNotEqual;
	ExpLess* pLess;
	ExpLessEqual* pLessEqual;
	ExpGreater* pGreater;
	ExpGreaterEqual* pGreaterEqual;
	ExpAnd* pAnd;
	ExpOr* pOr;
	ExpConditional* pConditional;
	ExpAsin* pAsin;
	ExpAcos* pAcos;
	ExpAtan* pAtan;
	ExpAbs* pAbs;
	ExpExp* pExp;
	ExpLn* pLn;
	ExpLog10* pLog10;
	ExpCeil* pCeil;
	ExpRound* pRound;
	ExpRandom* pRandom;
	ExpLen* pLen;
	ExpArray* pArray;
	ExpAt* pAt;
	ExpVariableName* pVariableName;
	bool dotIdentifier;

	while (step < toks.size()) {

		const Token& curTok = toks[step];

		if (curTok.t == T_NULL)
			break;

		Bracketing = false;

		switch (curTok.t) {

			//////////////////////
			// Operands
			//
			// Operands are simply kept to one side until we find an
			// operator to do something with.

		case T_INTEGER:
			
			pInt = NEW_UNARY_EXP(ExpInteger, pInt);
			pInt->value = curTok.iValue;

			// Return on close bracket or comma
			CHECK_TERMINATE();

			break;

		case T_FLOAT:

			pFloat = NEW_UNARY_EXP(ExpFloat, pFloat);
			pFloat->value = curTok.fValue;

			// Return on close bracket or comma
			CHECK_TERMINATE();

			break;

		case T_STRINGLITERAL:

			pStr = NEW_UNARY_EXP(ExpString, pStr);
			pStr->value = curTok.str;

			// Return on close bracket or comma
			CHECK_TERMINATE();

			break;

		case T_VARIABLENAME:
			{

			pVariableName = NEW_UNARY_EXP(ExpVariableName, pVariableName);

			CString name = curTok.str;
			name.MakeLower();

			// Lookup the private variable index
			if (pExpressionOwner != NULL)
				pVariableName->index = find_index(pExpressionOwner->privateVars.begin(), pExpressionOwner->privateVars.end(), name);
			else {
				vector<CString>::iterator it = pRuntime->globalNames.begin();
				vector<CString>::iterator end = pRuntime->globalNames.end();

				for ( ; it != end; it++) {
					CString curName = *it;
					curName.MakeLower();

					if (curName == name) {
						pVariableName->index = it - pRuntime->globalNames.begin();
						break;
					}
				}
			}

			pVariableName->pOwnerType = pExpressionOwner;
			
			// Return on close bracket or comma
			CHECK_TERMINATE();

			break;
			}

		case T_LEFTCURLY:

			pArray = NEW_UNARY_EXP(ExpArray, pArray);

			// NEW_UNARY_EXP increments step, but we want to put it back, because the loop
			// below expects to start on {
			step--;

			// Loop until all elements collected
			while (toks[step].t != T_RIGHTCURLY && step < toks.size()) {

				step++;		// Step over { or ,

				// Obtain element
				ExpPart* element = DoTree(step);

				// Add to elements
				pArray->expElements.push_back(element);

			}

			// Step over }
			step++;

			// Resize the evaluation buffer
			pArray->arr.resize(pArray->expElements.size());

			CHECK_TERMINATE();

			break;


			//////////////////////
			// Operators

		case T_ADD:
			
			pAdd = NEW_BINARY_EXP(ExpAdd, pAdd);

			// If child operator is lower precedence, this node must swap places with the child
			if (HasPrecedence(pAdd, pAdd->r))
				return SwapTree(pAdd);

			return pAdd;

		case T_SUBTRACT:

			pSub = NEW_BINARY_EXP(ExpSubtract, pSub);

			if (HasPrecedence(pSub, pSub->r))
				return SwapTree(pSub);

			return pSub;

		case T_MULTIPLY:

			pMult = NEW_BINARY_EXP(ExpMultiply, pMult);

			if (HasPrecedence(pMult, pMult->r))
				return SwapTree(pMult);

			return pMult;

		case T_DIVIDE:

			pDiv = NEW_BINARY_EXP(ExpDivide, pDiv);

			if (HasPrecedence(pDiv, pDiv->r) || SamePrecedence(pDiv, pDiv->r))
				return SwapTree(pDiv);
			
			// Force left-to-right evaluation
			/*
			if (SamePrecedence(pDiv, pDiv->r))
				SwapRightToLeft(pDiv);
			*/

			return pDiv;

		case T_MOD:

			pMod = NEW_BINARY_EXP(ExpMod, pMod);

			if (HasPrecedence(pMod, pMod->r))
				return SwapTree(pMod);

			// Force left-to-right evaluation
			if (SamePrecedence(pMod, pMod->r))
				SwapRightToLeft(pMod);

			return pMod;

		case T_POWER:

			pPow = NEW_BINARY_EXP(ExpPower, pPow);

			if (HasPrecedence(pPow, pPow->r))
				return SwapTree(pPow);

			// Force left-to-right evaluation
			if (SamePrecedence(pPow, pPow->r))
				SwapRightToLeft(pPow);

			return pPow;

		case T_AT:

			pAt = NEW_BINARY_EXP(ExpAt, pAt);

			if (HasPrecedence(pAt, pAt->r))
				return SwapTree(pAt);

			// Force left-to-right evaluation
			if (SamePrecedence(pAt, pAt->r))
				SwapRightToLeft(pAt);

			return pAt;

		case T_EQUAL:

			pEqual = NEW_BINARY_EXP(ExpEqual, pEqual);

			if (HasPrecedence(pEqual, pEqual->r))
				return SwapTree(pEqual);

			return pEqual;

		case T_NOTEQUAL:

			pNotEqual = NEW_BINARY_EXP(ExpNotEqual, pNotEqual);

			if (HasPrecedence(pNotEqual, pNotEqual->r))
				return SwapTree(pNotEqual);

			return pNotEqual;

		case T_LESS:

			pLess = NEW_BINARY_EXP(ExpLess, pLess);

			if (HasPrecedence(pLess, pLess->r))
				return SwapTree(pLess);

			return pLess;

		case T_LESSEQUAL:

			pLessEqual = NEW_BINARY_EXP(ExpLessEqual, pLessEqual);

			if (HasPrecedence(pLessEqual, pLessEqual->r))
				return SwapTree(pLessEqual);

			return pLessEqual;

		case T_GREATER:

			pGreater = NEW_BINARY_EXP(ExpGreater, pGreater);

			if (HasPrecedence(pGreater, pGreater->r))
				return SwapTree(pGreater);

			return pGreater;

		case T_GREATEREQUAL:

			pGreaterEqual = NEW_BINARY_EXP(ExpGreaterEqual, pGreaterEqual);

			if (HasPrecedence(pGreaterEqual, pGreaterEqual->r))
				return SwapTree(pGreaterEqual);

			return pGreaterEqual;

		case T_AND:

			pAnd = NEW_BINARY_EXP(ExpAnd, pAnd);

			if (HasPrecedence(pAnd, pAnd->r))
				return SwapTree(pAnd);

			return pAnd;

		case T_OR:

			pOr = NEW_BINARY_EXP(ExpOr, pOr);

			if (HasPrecedence(pOr, pOr->r))
				return SwapTree(pOr);

			return pOr;

		case T_CONDITIONAL:

			// a ? b : c
			pConditional = new ExpConditional;
			pConditional->t = T_CONDITIONAL;
			pConditional->pCExp = this;
			pConditional->bracketdepth = Depth;
			pConditional->a = LeftPart;	// Get condition part (a)
			step++;

			// Get TRUE part (b)
			/*if (toks[step].t == T_LEFTBRACKET)
				pConditional->b = DoBrackets(step);
			else*/
				pConditional->b = DoTree(step);
				pConditional->b = PostSortTree(pConditional->b);

			// Step over colon
			step++;

			// Get FALSE part (c)
			/*if (toks[step].t == T_LEFTBRACKET)
				pConditional->c = DoBrackets(step);
			else*/
				pConditional->c = DoTree(step);
				pConditional->c = PostSortTree(pConditional->c);

			// (never has precedence)

			return pConditional;

			// Identifier, eg. call without a dot: Object Object(5) MouseX
		case T_IDENTIFIER:
			{

			// Idents cause variability
			isConstant = false;

			pIdent = NEW_UNARY_EXP(ExpIdent, pIdent);
			pIdent->ident = curTok.str;
			pIdent->pRuntime = pRuntime;
			pIdent->pSystemObject = &(pRuntime->system);
			pIdent->numParams = 0;
			pIdent->paramsEnd = pIdent->parameters;

			for (int x = 0; x < CRUNTIME_MAX_PARAMS; x++)
				pIdent->expParamList[x].eType = EXPTYPE_NULL;

			// This will store the correct OID for this name, else -1 and load an expression routine
			LookupIdentifier(curTok.str, pIdent);

			// Check for OID caller match
			pIdent->isCallerOid = (pIdent->oid == this->oidCaller);

			// True if dot precedes this identifier (bit of a hack, but hey)
			// We can't check for unary mode, because unary operators use it and it would break "sin Array(1)"
			dotIdentifier = false;
			if (step > 1) if (toks[step-2].t == T_DOT) dotIdentifier = true;

			// Save expression owner for variable name translation.  Don't change the owner type if
			// this identifier is an expression name.
			if (!dotIdentifier) {
				if (pIdent->oid == -1)
					pExpressionOwner = NULL;
				else
					pExpressionOwner = pRuntime->objects[pIdent->oid];
			}

			// Cursor is currently on token after identifier (NEW_UNARY_EXP increments).
			// Check for left bracket & parameters if not part of a dot identifier (ie the x of object.x)
			if (step < toks.size() && !dotIdentifier) if (toks[step].t == T_LEFTBRACKET) {

				// While we're not on the closing bracket
				while (toks[step].t != T_RIGHTBRACKET && step < toks.size()) {

					// Step over left bracket/comma
					step++;

					// Obtain this parameter's tree, closing on the comma
					ExpPart* param = DoTree(step);
					param = PostSortTree(param);

					pIdent->parameters[pIdent->numParams++] = param;
					pIdent->paramsEnd = pIdent->parameters + pIdent->numParams;
				}

				// Step over right bracket
				step++;
			}

			// Now we have params parsed, but if this isn't a system expression, there isn't yet a routine stored for it.
			// This means it is the default return format, eg. Array(5).  Use the Default Return Value address.
			if (pIdent->oid > -1) {
				pIdent->pType = pRuntime->pOid(pIdent->oid);
				pIdent->pTypeInstances = &(pIdent->pType->instances);
				pIdent->routine = &CRunObject::ReturnDefaultValue;
			}
			else
				pIdent->pType = NULL;

			pIdent->hasParameters = pIdent->numParams > 0;

			// Return on close bracket or comma
			CHECK_TERMINATE();

			// Return if function call (followed by lbracket)
			if (toks[step].t == T_LEFTBRACKET)
				return LeftPart;

			break;
			}

		case T_DOT:

			// Plugin returns cause variability
			isConstant = false;

			pDot = new ExpDot;
			pDot->t = T_DOT;
			// Object name part
			pDot->l = (ExpIdent*)LeftPart;
			pDot->pCExp = this;
			pDot->pRuntime = pRuntime;
			pDot->bracketdepth = Depth;
			pDot->oid = ((ExpIdent*)(pDot->l))->oid;
			pDot->pType = pRuntime->objects[pDot->oid];
			pDot->pTypeInstances = &(pDot->pType->instances);
			pDot->unnamedExp = false;
			pDot->numParams = 0;
			pDot->paramsEnd = pDot->parameters;

			// Save owner type for variable name translation
			pExpressionOwner = pDot->pType;

			for (int x = 0; x < CRUNTIME_MAX_PARAMS; x++)
				pDot->expParamList[x].eType = EXPTYPE_NULL;

			step++;

			// Check for OID match
			pDot->isCallerOid = (pDot->oid == this->oidCaller);
				
			// Brackets not allowed after dot.  Obtain expression name part.
			pDot->r = (ExpIdent*)DoTree(step, true);

			// Now obtain a list of the parameters.  We are pointing after the expression
			// name part, i.e. after:   obj.exp [->] ( params ...
			// So if parameters exist, this is a left bracket.
			if (step < toks.size()) if (toks[step].t == T_LEFTBRACKET) {

				// While we're not on the closing bracket
				while (toks[step].t != T_RIGHTBRACKET && step < toks.size()) {

					// Step over left bracket/comma
					step++;

					// Obtain this parameter's tree, closing on the comma
					ExpPart* param = DoTree(step);
					param = PostSortTree(param);
					pDot->parameters[pDot->numParams++] = param;
					pDot->paramsEnd = pDot->parameters + pDot->numParams;
				}

				// Step over right bracket
				step++;
			}

			// Has parameters?
			pDot->hasParameters = pDot->numParams > 0;

			// Dot will have precedence over most operators
			if (HasPrecedence(pDot, pDot->r)) {

				ExpPart* newParent = SwapTree(pDot);

				// Look up the plugin expression routine
				LookupPluginExpression(((ExpIdent*)(pDot->l))->oid, ((ExpIdent*)(pDot->r))->ident, pDot);

				return newParent;
			}

			// Look up the plugin expression routine
			LookupPluginExpression(((ExpIdent*)(pDot->l))->oid, ((ExpIdent*)(pDot->r))->ident, pDot);

			//return pDot;
			LeftPart = pDot;

			CHECK_TERMINATE();

			break;

			//////////////////////
			// Unary operators

		case T_SIN:

			pSin = NEW_UNARY_OPERATOR(ExpSin, pSin);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_COS:

			pCos = NEW_UNARY_OPERATOR(ExpCos, pCos);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_TAN:

			pTan = NEW_UNARY_OPERATOR(ExpTan, pTan);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_SQRT:

			pSqrt = NEW_UNARY_OPERATOR(ExpSqrt, pSqrt);

			// Return on close bracket
			/*
			if (step >= toks.size())
				return LeftPart;
			if (toks[step].t == T_RIGHTBRACKET)
				return LeftPart;
				*/
			CHECK_TERMINATE();

			break;

		case T_FUNC_INT:

			pFuncInt = NEW_UNARY_OPERATOR(ExpFuncInt, pFuncInt);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_FUNC_FLOAT:

			pFuncFloat = NEW_UNARY_OPERATOR(ExpFuncFloat, pFuncFloat);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_FUNC_STR:

			pFuncStr = NEW_UNARY_OPERATOR(ExpFuncStr, pFuncStr);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_ASIN:

			pAsin = NEW_UNARY_OPERATOR(ExpAsin, pAsin);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_ACOS:

			pAcos = NEW_UNARY_OPERATOR(ExpAcos, pAcos);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_ATAN:

			pAtan = NEW_UNARY_OPERATOR(ExpAtan, pAtan);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_ABS:

			pAbs = NEW_UNARY_OPERATOR(ExpAbs, pAbs);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_EXP:

			pExp = NEW_UNARY_OPERATOR(ExpExp, pExp);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_LN:

			pLn = NEW_UNARY_OPERATOR(ExpLn, pLn);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_LOG10:

			pLog10 = NEW_UNARY_OPERATOR(ExpLog10, pLog10);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_CEIL:

			pCeil = NEW_UNARY_OPERATOR(ExpCeil, pCeil);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_ROUND:

			pRound = NEW_UNARY_OPERATOR(ExpRound, pRound);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_RANDOM:

			pRandom = NEW_UNARY_OPERATOR(ExpRandom, pRandom);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_LEN:

			pLen = NEW_UNARY_OPERATOR(ExpLen, pLen);

			// Return on close bracket
			CHECK_TERMINATE();

			break;

		case T_LEFTBRACKET:

			// THIS WILL BE CALLED ALWAYS NOW!!!
			//step++;
			//TOTIGS: Everywhere else you call DoBracket you dont add 1 to the step...
			// resulting in like 2 brackets omfg
			LeftPart = DoBrackets(step);

			if (unaryMode) return LeftPart;

			CHECK_TERMINATE()
			break;
			

		case T_NULL:
			step++;
			break;

		default:
				throw runtime_error("Syntax error in an expression.  Please report this bug.");

		}//switch
	}//while

	return LeftPart;
}
Example #5
0
// Tokenise a user's typed expression string
void CExpression::ParseUserString(const char* exp, int* pchpos, bool editorMode)
{
	toks.clear();

	whitespaceCount = 0;

	// Loop every char
	for (int i = 0; exp[i] != NULL; i++) {

		if (pchpos) *pchpos = i;

		char NextCh = exp[i+1];
		char CurCh = exp[i];
		char PrevCh = exp[(i == 0 ? 0 : i-1)];
		char strbuf[128];

		// Check this char
		switch (exp[i]) {

		case '+':
			AppendToken(T_ADD, "+");
			break;
		case '-':

			// If previous token is not operand, use as negative sign
			// Fix 25/4/07: random(4) - random(5) interprets '-' as integer: explicit check for right bracket
			if (toks.size() == 0 || ((!TokenFitsRule(toks.back().t, T_ANY_VALUE) || toks.back().t == T_LEFTBRACKET) && toks.back().t != T_RIGHTBRACKET)) {

				i += ConsumeDigits(strbuf, &(exp[i]));

				// Contains a dot: float
				if (StrContains(strbuf, '.'))
					AppendToken(T_FLOAT, strbuf);
				else	// Else integer
					AppendToken(T_INTEGER, strbuf);
			}
			else
				AppendToken(T_SUBTRACT, "-");

			break;
		case '*':
			AppendToken(T_MULTIPLY, "*");
			break;
		case '/':
			AppendToken(T_DIVIDE, "/");
			break;
		case '^':
			AppendToken(T_POWER, "^");
			break;
		case '%':
			AppendToken(T_MOD, "%");
			break;
		case '(':
			AppendToken(T_LEFTBRACKET, "(");
			break;
		case ')':
			AppendToken(T_RIGHTBRACKET, ")");
			break;
		case '{':
			AppendToken(T_LEFTCURLY, "{");
			break;
		case '}':
			AppendToken(T_RIGHTCURLY, "}");
			break;
		case '@':
			AppendToken(T_AT, "@");
			break;
		case ',':
			AppendToken(T_COMMA, ",");
			break;
		case '.':
			AppendToken(T_DOT, ".");
			break;
		case '"':
			i += AppendString(&(exp[i]), editorMode);
			break;
		case '\'':
			i += AppendString(&(exp[i]), editorMode, true);
			break;
		case '=':
			AppendToken(T_EQUAL, "=");
			break;
		case '<':
			if (NextCh == '=') {
				AppendToken(T_LESSEQUAL, "<=");
				i++;
			}
			else if (NextCh == '>') {
				AppendToken(T_NOTEQUAL, "<>");
				i++;
			}
			else
				AppendToken(T_LESS, "<");
			break;
		// Alternative not equal operator != <>
		case '!':
			if (NextCh == '=') {
				AppendToken(T_NOTEQUAL, "!=");
				i++;
			}
			else
				NotifyError("Syntax error: '!'");
			break;
		case '&':
			AppendToken(T_AND, "&");
			break;
		case '|':
			AppendToken(T_OR, "|");
			break;
		case '>':
			if (NextCh == '=') {
				AppendToken(T_GREATEREQUAL, ">=");
				i++;
			}
			else
				AppendToken(T_GREATER, ">");
			break;
		case '?':
			AppendToken(T_CONDITIONAL, "?");
			break;
		case ':':
			AppendToken(T_COLON, ":");
			break;
		default:

			// Parse numbers and idents
			if (IsChAlphaNumeric(CurCh))
				i += ConsumeAppendIdentifier(strbuf, &(exp[i]));

			// Skip over whitespace
			else if (IsWhitespace(CurCh)) {

				// In editor mode add a T_WHITESPACE token
				if (editorMode) {
					Token t;
					t.length = 0;
					t.t = T_WHITESPACE;

					while (IsWhitespace(exp[i])) {
						t.str += exp[i];
						i++;
					}

					// We want the next for loop iteration to see the next char
					i--;

					toks.push_back(t);
				}

				// Add to last token length
				if (toks.size() > 0)
					toks[toks.size() - 1].length++;
			}
			// Else unknown character
			else {
				string error = "Unknown character '";
				error += CurCh;
				error += "'";
				throw runtime_error(error.c_str());
			}
		}//switch

	}//for

	// Only perform preprocessing when not in edittime mode
	if (!editorMode)
		PreProcessTokStream();


	///////////////////////////
	// Final step:  parse to tree

	// Determine if the overall expression is constant, collapsing constant parts along
	// the way.
	// Runtime only
#ifdef RUNTIME
	// Make the tree
	int step = 0;
	ExpTree = DoTree(step);

	isConstant = ExpTree->Constant();

	// If constant, get the constant value.
	if (isConstant) {
		CollapseConstantTree(ExpTree);
		ExpTree->Evaluate(&constantValue);
	}
#endif

}