- implemented arrays, don't quite work 100% yet

Tue, 11 Feb 2014 03:29:03 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Tue, 11 Feb 2014 03:29:03 +0200
changeset 107
55c2bcd8ed5c
parent 106
9174be9ac686
child 108
6409ece8297c

- implemented arrays, don't quite work 100% yet
- restructured Expression::ParseSymbol, local exception no longer needed

src/Expression.cc file | annotate | diff | comparison | revisions
src/LexerScanner.cc file | annotate | diff | comparison | revisions
src/Parser.cc file | annotate | diff | comparison | revisions
src/Parser.h file | annotate | diff | comparison | revisions
src/Tokens.h file | annotate | diff | comparison | revisions
--- 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);
--- a/src/LexerScanner.cc	Sun Feb 09 22:43:58 2014 +0200
+++ b/src/LexerScanner.cc	Tue Feb 11 03:29:03 2014 +0200
@@ -40,7 +40,6 @@
 	">>=",
 	"==",
 	"!=",
-	"[]",
 	"+=",
 	"-=",
 	"*=",
--- a/src/Parser.cc	Sun Feb 09 22:43:58 2014 +0200
+++ b/src/Parser.cc	Tue Feb 11 03:29:03 2014 +0200
@@ -178,6 +178,9 @@
 				ParseFuncdef();
 				break;
 
+			case tkSemicolon:
+				break;
+
 			default:
 			{
 				// Check for labels
@@ -206,12 +209,15 @@
 				DataBuffer* b = ParseStatement();
 
 				if (b == false)
+				{
+					mLexer->GetNext();
 					Error ("unknown token `%1`", GetTokenString());
+				}
 
 				buffer()->MergeAndDestroy (b);
 				mLexer->MustGetNext (tkSemicolon);
+				break;
 			}
-			break;
 		}
 	}
 
@@ -328,6 +334,7 @@
 {
 	Variable* var = new Variable;
 	var->origin = mLexer->DescribeCurrentPosition();
+	var->isarray = false;
 	const bool isconst = mLexer->GetNext (tkConst);
 	mLexer->MustGetAnyOf ({tkInt, tkStr, tkVoid});
 
@@ -338,6 +345,15 @@
 	mLexer->MustGetNext (tkSymbol);
 	String name = GetTokenString();
 
+	if (mLexer->GetNext (tkBracketStart))
+	{
+		mLexer->MustGetNext (tkBracketEnd);
+		var->isarray = true;
+
+		if (isconst)
+			Error ("arrays cannot be const");
+	}
+
 	for (Variable* var : SCOPE(0).globalVariables + SCOPE(0).localVariables)
 	{
 		if (var->name == name)
@@ -368,7 +384,7 @@
 		else
 		{
 			// TODO: might need a VM-wise oninit for this...
-			Error ("const variables must be constexpr for now");
+			Error ("const variables must be constexpr");
 		}
 	}
 
@@ -989,11 +1005,10 @@
 					comm->name, comm->GetSignature());
 
 			break;
-			curarg++;
 		}
 
 		if (curarg >= comm->args.Size())
-			Error ("too many arguments passed to %1\n\tusage is: %2",
+			Error ("too many arguments (%3) passed to %1\n\tusage is: %2",
 				comm->name, comm->GetSignature());
 
 		r->MergeAndDestroy (ParseExpression (comm->args[curarg].type, true));
@@ -1096,36 +1111,43 @@
 
 // ============================================================================
 //
+struct AssignmentDataHeaderInfo
+{
+	EAssignmentOperator	op;
+	EDataHeader			local;
+	EDataHeader			global;
+	EDataHeader			array;
+};
+
+const AssignmentDataHeaderInfo gAssignmentDataHeaders[] =
+{
+	{ EAssign,			dhAssignLocalVar,	dhAssignGlobalVar,		dhAssignGlobalArray },
+	{ EAssignAdd,		dhAddLocalVar,		dhAddGlobalVar,			dhAddGlobalArray },
+	{ EAssignSub,		dhSubtractLocalVar,	dhSubtractGlobalVar,	dhSubtractGlobalArray },
+	{ EAssignMul,		dhMultiplyLocalVar,	dhMultiplyGlobalVar,	dhMultiplyGlobalArray },
+	{ EAssignDiv,		dhDivideLocalVar,	dhDivideGlobalVar,		dhDivideGlobalArray },
+	{ EAssignMod,		dhModLocalVar,		dhModGlobalVar,			dhModGlobalArray },
+	{ EAssignIncrement,	dhIncreaseLocalVar,	dhIncreaseGlobalVar,	dhIncreaseGlobalArray },
+	{ EAssignDecrement,	dhDecreaseLocalVar,	dhDecreaseGlobalVar,	dhDecreaseGlobalArray },
+};
+
 EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, Variable* var)
 {
-	if (var->IsGlobal())
+	for (const auto& a : gAssignmentDataHeaders)
 	{
-		switch (op)
-		{
-			case EAssign:			return dhAssignGlobalVar;
-			case EAssignAdd:		return dhAddGlobalVar;
-			case EAssignSub:		return dhSubtractGlobalVar;
-			case EAssignMul:		return dhMultiplyGlobalVar;
-			case EAssignDiv:		return dhDivideGlobalVar;
-			case EAssignMod:		return dhModGlobalVar;
-			case EAssignIncrement:	return dhIncreaseGlobalVar;
-			case EAssignDecrement:	return dhDecreaseGlobalVar;
-		}
+		if (a.op != op)
+			continue;
+
+		if (var->isarray)
+			return a.array;
+
+		if (var->IsGlobal())
+			return a.global;
+
+		return a.local;
 	}
 
-	switch (op)
-	{
-		case EAssign:			return dhAssignLocalVar;
-		case EAssignAdd:		return dhAddLocalVar;
-		case EAssignSub:		return dhSubtractLocalVar;
-		case EAssignMul:		return dhMultiplyLocalVar;
-		case EAssignDiv:		return dhDivideLocalVar;
-		case EAssignMod:		return dhModLocalVar;
-		case EAssignIncrement:	return dhIncreaseLocalVar;
-		case EAssignDecrement:	return dhDecreaseLocalVar;
-	}
-
-	assert (false);
+	Error ("WTF: couldn't find data header for operator #%1", op);
 	return (EDataHeader) 0;
 }
 
@@ -1137,14 +1159,23 @@
 //
 DataBuffer* BotscriptParser::ParseAssignment (Variable* var)
 {
+	DataBuffer* retbuf = new DataBuffer;
+	DataBuffer* arrayindex = null;
+
 	if (var->writelevel != Variable::WRITE_Mutable)
+		Error ("cannot alter read-only variable $%1", var->name);
+
+	if (var->isarray)
 	{
-		Error ("cannot alter read-only variable $%1", var->name);
+		mLexer->MustGetNext (tkBracketStart);
+		Expression expr (this, mLexer, EIntType);
+		expr.GetResult()->ConvertToBuffer();
+		arrayindex = expr.GetResult()->GetBuffer()->Clone();
+		mLexer->MustGetNext (tkBracketEnd);
 	}
 
 	// Get an operator
 	EAssignmentOperator oper = ParseAssignmentOperator();
-	DataBuffer* retbuf = new DataBuffer;
 
 	if (mCurrentMode == ETopLevelMode)
 		Error ("can't alter variables at top level");
@@ -1156,6 +1187,9 @@
 		retbuf->MergeAndDestroy (expr);
 	}
 
+	if (var->isarray)
+		retbuf->MergeAndDestroy (arrayindex);
+
 #if 0
 	// <<= and >>= do not have data headers. Solution: expand them.
 	// a <<= b -> a = a << b
--- a/src/Parser.h	Sun Feb 09 22:43:58 2014 +0200
+++ b/src/Parser.h	Tue Feb 11 03:29:03 2014 +0200
@@ -107,6 +107,7 @@
 	EWritability	writelevel;
 	int				value;
 	String			origin;
+	bool			isarray;
 
 	inline bool IsGlobal() const
 	{
@@ -134,6 +135,7 @@
 	EScopeType					type;
 	DataBuffer*					buffer1;
 	int							globalVarIndexBase;
+	int							globalArrayIndexBase;
 	int							localVarIndexBase;
 
 	// switch-related stuff
@@ -141,6 +143,7 @@
 	List<CaseInfo>				cases;
 	List<Variable*>				localVariables;
 	List<Variable*>				globalVariables;
+	List<Variable*>				globalArrays;
 };
 
 // ============================================================================
--- a/src/Tokens.h	Sun Feb 09 22:43:58 2014 +0200
+++ b/src/Tokens.h	Tue Feb 11 03:29:03 2014 +0200
@@ -39,7 +39,6 @@
 	tkRightShiftAssign,
 	tkEquals,
 	tkNotEquals,
-	tkBrackets,
 	tkAddAssign,
 	tkSubAssign,
 	tkMultiplyAssign,

mercurial