src/Expression.cc

changeset 107
55c2bcd8ed5c
parent 106
9174be9ac686
child 108
6409ece8297c
--- a/src/Expression.cc	Sun Feb 09 22:43:58 2014 +0200
+++ b/src/Expression.cc	Tue Feb 11 03:29:03 2014 +0200
@@ -75,114 +75,121 @@
 {
 	int pos = mLexer->GetPosition();
 	ExpressionValue* op = null;
-	enum ELocalException { failed };
+
+	if (mLexer->GetNext (tkColon))
+		return new ExpressionColon;
 
-	try
-	{
-		mLexer->MustGetNext (tkAny);
+	// Check for operator
+	for (const OperatorInfo& op : gOperators)
+		if (mLexer->GetNext (op.token))
+			return new ExpressionOperator ((EOperator) (&op - &gOperators[0]));
 
-		if (mLexer->GetTokenType() == tkColon)
-			return new ExpressionColon;
+	// Check sub-expression
+	if (mLexer->GetNext (tkParenStart))
+	{
+		Expression expr (mParser, mLexer, mType);
+		mLexer->MustGetNext (tkParenEnd);
+		return expr.GetResult()->Clone();
+	}
+
+	op = new ExpressionValue (mType);
 
-		// Check for operator
-		for (const OperatorInfo& op : gOperators)
-			if (mLexer->GetTokenType() == op.token)
-				return new ExpressionOperator ((EOperator) (&op - &gOperators[0]));
+	// Check function
+	if (CommandInfo* comm = FindCommandByName (mLexer->PeekNextString()))
+	{
+		mLexer->Skip();
+
+		if (mType != EUnknownType && comm->returnvalue != mType)
+			Error ("%1 returns an incompatible data type", comm->name);
+
+		op->SetBuffer (mParser->ParseCommand (comm));
+		return op;
+	}
 
-		// Check sub-expression
-		if (mLexer->GetTokenType() == tkParenStart)
-		{
-			Expression expr (mParser, mLexer, mType);
-			mLexer->MustGetNext (tkParenEnd);
-			return expr.GetResult()->Clone();
-		}
+	// Check for variables
+	if (mLexer->GetNext (tkDollarSign))
+	{
+		mLexer->MustGetNext (tkSymbol);
+		Variable* var = mParser->FindVariable (GetTokenString());
+
+		if (var == null)
+			Error ("unknown variable %1", GetTokenString());
+
+		if (var->type != mType)
+			Error ("expression requires %1, variable $%2 is of type %3",
+				GetTypeName (mType), var->name, GetTypeName (var->type));
 
-		op = new ExpressionValue (mType);
-
-		// Check function
-		if (CommandInfo* comm = FindCommandByName (GetTokenString()))
+		if (var->isarray)
 		{
-			if (mType != EUnknownType && comm->returnvalue != mType)
-				Error ("%1 returns an incompatible data type", comm->name);
+			mLexer->MustGetNext (tkBracketStart);
+			Expression expr (mParser, mLexer, EIntType);
+			expr.GetResult()->ConvertToBuffer();
+			DataBuffer* buf = expr.GetResult()->GetBuffer()->Clone();
+			buf->WriteDWord (dhPushGlobalArray);
+			buf->WriteDWord (var->index);
+			op->SetBuffer (buf);
+			mLexer->MustGetNext (tkBracketEnd);
+		}
+		elif (var->writelevel == Variable::WRITE_Constexpr)
+			op->SetValue (var->value);
+		else
+		{
+			DataBuffer* buf = new DataBuffer (8);
 
-			op->SetBuffer (mParser->ParseCommand (comm));
-			return op;
+			if (var->IsGlobal())
+				buf->WriteDWord (dhPushGlobalVar);
+			else
+				buf->WriteDWord (dhPushLocalVar);
+
+			buf->WriteDWord (var->index);
+			op->SetBuffer (buf);
 		}
 
-		// Check for variables
-		if (mLexer->GetTokenType() == tkDollarSign)
-		{
-			mLexer->MustGetNext (tkSymbol);
-			Variable* globalvar = mParser->FindVariable (GetTokenString());
-
-			if (globalvar == null)
-				Error ("unknown variable %1", GetTokenString());
+		return op;
+	}
 
-			if (globalvar->writelevel == Variable::WRITE_Constexpr)
-				op->SetValue (globalvar->value);
-			else
-			{
-				DataBuffer* buf = new DataBuffer (8);
-				buf->WriteDWord (dhPushGlobalVar);
-				buf->WriteDWord (globalvar->index);
-				op->SetBuffer (buf);
-			}
-
-			return op;
+	// Check for literal
+	switch (mType)
+	{
+		case EVoidType:
+		case EUnknownType:
+		{
+			Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString());
+			break;
 		}
 
-		EToken tt;
-
-		// Check for literal
-		switch (mType)
+		case EBoolType:
 		{
-			case EVoidType:
-			case EUnknownType:
+			if (mLexer->GetNext (tkTrue) || mLexer->GetNext (tkFalse))
 			{
-				Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString());
-				break;
+				EToken tt = mLexer->GetTokenType();
+				op->SetValue (tt == tkTrue ? 1 : 0);
+				return op;
 			}
+		}
 
-			case EBoolType:
+		case EIntType:
+		{
+			if (mLexer->GetNext (tkNumber))
 			{
-				if ((tt = mLexer->GetTokenType()) == tkTrue || tt == tkFalse)
-				{
-					op->SetValue (tt == tkTrue ? 1 : 0);
-					return op;
-				}
-			}
-			case EIntType:
-			{
-				if (mLexer->GetTokenType() != tkNumber)
-					throw failed;
-
 				op->SetValue (GetTokenString().ToLong());
 				return op;
 			}
+		}
 
-			case EStringType:
+		case EStringType:
+		{
+			if (mLexer->GetNext (tkString))
 			{
-				if (mLexer->GetTokenType() != tkString)
-					throw failed;
-
 				op->SetValue (GetStringTableIndex (GetTokenString()));
 				return op;
 			}
 		}
-
-		assert (false);
-		throw failed;
-	}
-	catch (ELocalException&)
-	{
-		// We use a local enum here since catch(...) would catch Error() calls.
-		mBadTokenText = mLexer->GetToken()->text;
-		mLexer->SetPosition (pos);
-		delete op;
-		return null;
 	}
 
-	assert (false);
+	mBadTokenText = mLexer->GetToken()->text;
+	mLexer->SetPosition (pos);
+	delete op;
 	return null;
 }
 
@@ -383,6 +390,7 @@
 {
 	const OperatorInfo* info = &gOperators[op->GetID()];
 	bool isconstexpr = true;
+	assert (values.Size() == info->numoperands);
 
 	for (ExpressionValue* val : values)
 	{
@@ -481,18 +489,22 @@
 			case opTernary:				a = (nums[0] != 0) ? nums[1] : nums[2];	break;
 
 			case opDivision:
+			{
 				if (nums[1] == 0)
 					Error ("division by zero in constant expression");
 
 				a = nums[0] / nums[1];
 				break;
+			}
 
 			case opModulus:
+			{
 				if (nums[1] == 0)
 					Error ("modulus by zero in constant expression");
 
 				a = nums[0] % nums[1];
 				break;
+			}
 		}
 
 		newval->SetValue (a);

mercurial