--- 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);