src/Parser.cc

changeset 91
427eb377d53e
parent 89
029a330a9bef
child 92
3a00d396bce2
--- a/src/Parser.cc	Mon Feb 03 11:23:56 2014 +0200
+++ b/src/Parser.cc	Mon Feb 03 20:12:44 2014 +0200
@@ -34,6 +34,7 @@
 #include "Containers.h"
 #include "Lexer.h"
 #include "DataBuffer.h"
+#include "Expression.h"
 
 #define SCOPE(n) (mScopeStack[mScopeCursor - n])
 
@@ -1134,143 +1135,6 @@
 }
 
 // ============================================================================
-// Parses an expression, potentially recursively
-//
-DataBuffer* BotscriptParser::ParseExpression (EType reqtype)
-{
-	DataBuffer* retbuf = new DataBuffer (64);
-
-	// Parse first operand
-	retbuf->MergeAndDestroy (ParseExprValue (reqtype));
-
-	// Parse any and all operators we get
-	int oper;
-
-	while ( (oper = ParseOperator (true)) != -1)
-	{
-		// We peeked the operator, move forward now
-		mLexer->Skip();
-
-		// Can't be an assignement operator, those belong in assignments.
-		if (IsAssignmentOperator (oper))
-			Error ("assignment operator inside expression");
-
-		// Parse the right operand.
-		mLexer->MustGetNext();
-		DataBuffer* rb = ParseExprValue (reqtype);
-
-		if (oper == OPER_TERNARY)
-		{
-			// Ternary operator requires - naturally - a third operand.
-			mLexer->MustGetNext (tkColon);
-			mLexer->MustGetNext();
-			DataBuffer* tb = ParseExprValue (reqtype);
-
-			// It also is handled differently: there isn't a dataheader for ternary
-			// operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this.
-			// Behold, big block of writing madness! :P
-			ByteMark* mark1 = retbuf->AddMark (""); // start of "else" case
-			ByteMark* mark2 = retbuf->AddMark (""); // end of expression
-			retbuf->WriteDWord (dhIfNotGoto); // if the first operand (condition)
-			retbuf->AddReference (mark1); // didn't eval true, jump into mark1
-			retbuf->MergeAndDestroy (rb); // otherwise, perform second operand (true case)
-			retbuf->WriteDWord (dhGoto); // afterwards, jump to the end, which is
-			retbuf->AddReference (mark2); // marked by mark2.
-			retbuf->AdjustMark (mark1); // move mark1 at the end of the true case
-			retbuf->MergeAndDestroy (tb); // perform third operand (false case)
-			retbuf->AdjustMark (mark2); // move the ending mark2 here
-		}
-		else
-		{
-			// write to buffer
-			retbuf->MergeAndDestroy (rb);
-			retbuf->WriteDWord (GetDataHeaderByOperator (null, oper));
-		}
-	}
-
-	return retbuf;
-}
-
-// ============================================================================
-// Parses an operator string. Returns the operator number code.
-//
-#define ISNEXT(C) (mLexer->PeekNextString (peek ? 1 : 0) == C)
-
-int BotscriptParser::ParseOperator (bool peek)
-{
-	String oper;
-
-	if (peek)
-		oper += mLexer->PeekNextString();
-	else
-		oper += GetTokenString();
-
-	if (-oper == "strlen")
-		return OPER_STRLEN;
-
-	// Check one-char operators
-	bool equalsnext = ISNEXT ("=");
-
-	int o =	(oper == "=" && !equalsnext) ? OPER_ASSIGN :
-			(oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN :
-			(oper == "<" && !equalsnext && !ISNEXT ("<")) ? OPER_LESSTHAN :
-			(oper == "&" && !ISNEXT ("&")) ? OPER_BITWISEAND :
-			(oper == "|" && !ISNEXT ("|")) ? OPER_BITWISEOR :
-			(oper == "+" && !equalsnext) ? OPER_ADD :
-			(oper == "-" && !equalsnext) ? OPER_SUBTRACT :
-			(oper == "*" && !equalsnext) ? OPER_MULTIPLY :
-			(oper == "/" && !equalsnext) ? OPER_DIVIDE :
-			(oper == "%" && !equalsnext) ? OPER_MODULUS :
-			(oper == "^") ? OPER_BITWISEEOR :
-			(oper == "?") ? OPER_TERNARY :
-			-1;
-
-	if (o != -1)
-	{
-		return o;
-	}
-
-	// Two-char operators
-	oper += mLexer->PeekNextString (peek ? 1 : 0);
-	equalsnext = mLexer->PeekNextString (peek ? 2 : 1) == ("=");
-
-	o =	(oper == "+=") ? OPER_ASSIGNADD :
-		(oper == "-=") ? OPER_ASSIGNSUB :
-		(oper == "*=") ? OPER_ASSIGNMUL :
-		(oper == "/=") ? OPER_ASSIGNDIV :
-		(oper == "%=") ? OPER_ASSIGNMOD :
-		(oper == "==") ? OPER_EQUALS :
-		(oper == "!=") ? OPER_NOTEQUALS :
-		(oper == ">=") ? OPER_GREATERTHANEQUALS :
-		(oper == "<=") ? OPER_LESSTHANEQUALS :
-		(oper == "&&") ? OPER_AND :
-		(oper == "||") ? OPER_OR :
-		(oper == "<<" && !equalsnext) ? OPER_LEFTSHIFT :
-		(oper == ">>" && !equalsnext) ? OPER_RIGHTSHIFT :
-		-1;
-
-	if (o != -1)
-	{
-		mLexer->MustGetNext();
-		return o;
-	}
-
-	// Three-char opers
-	oper += mLexer->PeekNextString (peek ? 2 : 1);
-	o =	oper == "<<=" ? OPER_ASSIGNLEFTSHIFT :
-		oper == ">>=" ? OPER_ASSIGNRIGHTSHIFT :
-		-1;
-
-	if (o != -1)
-	{
-		mLexer->MustGetNext();
-		mLexer->MustGetNext();
-	}
-
-	return o;
-}
-
-// ============================================================================
 //
 String BotscriptParser::ParseFloat()
 {
@@ -1291,124 +1155,6 @@
 }
 
 // ============================================================================
-// Parses a value in the expression and returns the data needed to push
-// it, contained in a data buffer. A value can be either a variable, a command,
-// a literal or an expression.
-//
-DataBuffer* BotscriptParser::ParseExprValue (EType reqtype)
-{
-	DataBuffer* b = new DataBuffer (16);
-	ScriptVariable* g;
-
-	// Prefixing "!" means negation.
-	bool negate = TokenIs (tkExclamationMark);
-
-	if (negate) // Jump past the "!"
-		mLexer->Skip();
-
-	if (TokenIs (tkParenStart))
-	{
-		// Expression
-		mLexer->MustGetNext();
-		DataBuffer* c = ParseExpression (reqtype);
-		b->MergeAndDestroy (c);
-		mLexer->MustGetNext (tkParenEnd);
-	}
-	else if (CommandInfo* comm = FindCommandByName (GetTokenString()))
-	{
-		delete b;
-
-		// Command
-		if (reqtype && comm->returnvalue != reqtype)
-			Error ("%1 returns an incompatible data type", comm->name);
-
-		b = ParseCommand (comm);
-	}
-	else if (ConstantInfo* constant = FindConstant (GetTokenString()))
-	{
-		// Type check
-		if (reqtype != constant->type)
-			Error ("constant `%1` is %2, expression requires %3\n",
-				constant->name, GetTypeName (constant->type),
-				GetTypeName (reqtype));
-
-		switch (constant->type)
-		{
-			case EBoolType:
-			case EIntType:
-			{
-				b->WriteDWord (dhPushNumber);
-				b->WriteDWord (constant->val.ToLong());
-				break;
-			}
-
-			case EStringType:
-			{
-				b->WriteStringIndex (constant->val);
-				break;
-			}
-
-			case EVoidType:
-			case EUnknownType:
-				break;
-		}
-	}
-	else if ((g = FindGlobalVariable (GetTokenString())))
-	{
-		// Global variable
-		b->WriteDWord (dhPushGlobalVar);
-		b->WriteDWord (g->index);
-	}
-	else
-	{
-		// If nothing else, check for literal
-		switch (reqtype)
-		{
-			case EVoidType:
-			case EUnknownType:
-			{
-				Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString());
-				break;
-			}
-
-			case EBoolType:
-			case EIntType:
-			{
-				mLexer->TokenMustBe (tkNumber);
-
-				// All values are written unsigned - thus we need to write the value's
-				// absolute value, followed by an unary minus for negatives.
-				b->WriteDWord (dhPushNumber);
-
-				long v = GetTokenString().ToLong();
-				b->WriteDWord (static_cast<word> (abs (v)));
-
-				if (v < 0)
-					b->WriteDWord (dhUnaryMinus);
-
-				break;
-			}
-
-			case EStringType:
-			{
-				// PushToStringTable either returns the string index of the
-				// string if it finds it in the table, or writes it to the
-				// table and returns it index if it doesn't find it there.
-				mLexer->TokenMustBe (tkString);
-				b->WriteStringIndex (GetTokenString());
-				break;
-			}
-		}
-	}
-
-	// Negate it now if desired
-	if (negate)
-		b->WriteDWord (dhNegateLogical);
-
-	return b;
-}
-
-// ============================================================================
 // Parses an assignment. An assignment starts with a variable name, followed
 // by an assignment operator, followed by an expression value. Expects current
 // token to be the name of the variable, and expects the variable to be given.
@@ -1479,6 +1225,15 @@
 
 // ============================================================================
 //
+void BotscriptParser::ParseExpression (EType reqtype)
+{
+	Expression expr (this, reqtype, mLexer);
+	expr.GetResult()->ConvertToBuffer();
+	buffer()->MergeAndDestroy (expr.GetResult()->GetBuffer());
+}
+
+// ============================================================================
+//
 DataBuffer* BotscriptParser::ParseStatement()
 {
 	if (FindConstant (GetTokenString())) // There should not be constants here.

mercurial