src/Expression.cc

changeset 119
bdf8d46c145f
parent 118
e3361cf7cbf4
child 120
5ea0faefa82a
--- a/src/Expression.cc	Sun Mar 30 21:35:06 2014 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,651 +0,0 @@
-#include "Expression.h"
-#include "DataBuffer.h"
-#include "Lexer.h"
-
-struct OperatorInfo
-{
-	ETokenType	token;
-	int			priority;
-	int			numoperands;
-	DataHeader	header;
-};
-
-static const OperatorInfo g_Operators[] =
-{
-	{TK_ExclamationMark,	0,		1,	DH_NegateLogical,	},
-	{TK_Minus,				0,		1,	DH_UnaryMinus,		},
-	{TK_Multiply,			10,		2,	DH_Multiply,		},
-	{TK_Divide,				10,		2,	DH_Divide,			},
-	{TK_Modulus,			10,		2,	DH_Modulus,			},
-	{TK_Plus,				20,		2,	DH_Add,				},
-	{TK_Minus,				20,		2,	DH_Subtract,		},
-	{TK_LeftShift,			30,		2,	DH_LeftShift,		},
-	{TK_RightShift,			30,		2,	DH_RightShift,		},
-	{TK_Lesser,				40,		2,	DH_LessThan,		},
-	{TK_Greater,			40,		2,	DH_GreaterThan,		},
-	{TK_AtLeast,			40,		2,	DH_AtLeast,			},
-	{TK_AtMost,				40,		2,	DH_AtMost,			},
-	{TK_Equals,				50,		2,	DH_Equals			},
-	{TK_NotEquals,			50,		2,	DH_NotEquals		},
-	{TK_Amperstand,			60,		2,	DH_AndBitwise		},
-	{TK_Caret,				70,		2,	DH_EorBitwise		},
-	{TK_Bar,				80,		2,	DH_OrBitwise		},
-	{TK_DoubleAmperstand,	90,		2,	DH_AndLogical		},
-	{TK_DoubleBar,			100,	2,	DH_OrLogical		},
-	{TK_QuestionMark,		110,	3,	(DataHeader) 0		},
-};
-
-// =============================================================================
-//
-Expression::Expression (BotscriptParser* parser, Lexer* lx, DataType reqtype) :
-	m_parser (parser),
-	m_lexer (lx),
-	m_type (reqtype)
-{
-	ExpressionSymbol* sym;
-
-	while ((sym = parseSymbol()) != null)
-		m_symbols << sym;
-
-	// If we were unable to get any expression symbols, something's wonky with
-	// the script. Report an error. mBadTokenText is set to the token that
-	// ParseSymbol ends at when it returns false.
-	if (m_symbols.isEmpty())
-		error ("unknown identifier '%1'", m_badTokenText);
-
-	adjustOperators();
-	verify();
-	evaluate();
-}
-
-// =============================================================================
-//
-Expression::~Expression()
-{
-	for (ExpressionSymbol* sym : m_symbols)
-		delete sym;
-}
-
-// =============================================================================
-//
-// Try to parse an expression symbol (i.e. an OPER_erator or OPER_erand or a colon)
-// from the lexer.
-//
-ExpressionSymbol* Expression::parseSymbol()
-{
-	int pos = m_lexer->position();
-	ExpressionValue* op = null;
-
-	if (m_lexer->next (TK_Colon))
-		return new ExpressionColon;
-
-	// Check for OPER_erator
-	for (const OperatorInfo& op : g_Operators)
-		if (m_lexer->next (op.token))
-			return new ExpressionOperator ((ExpressionOperatorType) (&op - &g_Operators[0]));
-
-	// Check sub-expression
-	if (m_lexer->next (TK_ParenStart))
-	{
-		Expression expr (m_parser, m_lexer, m_type);
-		m_lexer->mustGetNext (TK_ParenEnd);
-		return expr.getResult()->clone();
-	}
-
-	op = new ExpressionValue (m_type);
-
-	// Check function
-	if (CommandInfo* comm = findCommandByName (m_lexer->peekNextString()))
-	{
-		m_lexer->skip();
-
-		if (m_type != TYPE_Unknown && comm->returnvalue != m_type)
-			error ("%1 returns an incompatible data type", comm->name);
-
-		op->setBuffer (m_parser->parseCommand (comm));
-		return op;
-	}
-
-	// Check for variables
-	if (m_lexer->next (TK_DollarSign))
-	{
-		m_lexer->mustGetNext (TK_Symbol);
-		Variable* var = m_parser->findVariable (getTokenString());
-
-		if (var == null)
-			error ("unknown variable %1", getTokenString());
-
-		if (var->type != m_type)
-			error ("expression requires %1, variable $%2 is of type %3",
-				dataTypeName (m_type), var->name, dataTypeName (var->type));
-
-		if (var->isarray)
-		{
-			m_lexer->mustGetNext (TK_BracketStart);
-			Expression expr (m_parser, m_lexer, TYPE_Int);
-			expr.getResult()->convertToBuffer();
-			DataBuffer* buf = expr.getResult()->buffer()->clone();
-			buf->writeDWord (DH_PushGlobalArray);
-			buf->writeDWord (var->index);
-			op->setBuffer (buf);
-			m_lexer->mustGetNext (TK_BracketEnd);
-		}
-		elif (var->writelevel == WRITE_Constexpr)
-			op->setValue (var->value);
-		else
-		{
-			DataBuffer* buf = new DataBuffer (8);
-
-			if (var->IsGlobal())
-				buf->writeDWord (DH_PushGlobalVar);
-			else
-				buf->writeDWord (DH_PushLocalVar);
-
-			buf->writeDWord (var->index);
-			op->setBuffer (buf);
-		}
-
-		return op;
-	}
-
-	// Check for literal
-	switch (m_type)
-	{
-		case TYPE_Void:
-		case TYPE_Unknown:
-		{
-			error ("unknown identifier `%1` (expected keyword, function or variable)", getTokenString());
-			break;
-		}
-
-		case TYPE_Bool:
-		{
-			if (m_lexer->next (TK_True) || m_lexer->next (TK_False))
-			{
-				ETokenType tt = m_lexer->tokenType();
-				op->setValue (tt == TK_True ? 1 : 0);
-				return op;
-			}
-		}
-
-		case TYPE_Int:
-		{
-			if (m_lexer->next (TK_Number))
-			{
-				op->setValue (getTokenString().toLong());
-				return op;
-			}
-		}
-
-		case TYPE_String:
-		{
-			if (m_lexer->next (TK_String))
-			{
-				op->setValue (getStringTableIndex (getTokenString()));
-				return op;
-			}
-		}
-	}
-
-	m_badTokenText = m_lexer->token()->text;
-	m_lexer->setPosition (pos);
-	delete op;
-	return null;
-}
-
-// =============================================================================
-//
-// The symbol parsing process only does token-based checking for OPER_erators.
-// Thus ALL minus OPER_erators are actually unary minuses simply because both
-// have TK_Minus as their token and the unary minus is prior to the binary minus
-// in the OPER_erator table. Now that we have all symbols present, we can
-// correct cases like this.
-//
-void Expression::adjustOperators()
-{
-	for (auto it = m_symbols.begin() + 1; it != m_symbols.end(); ++it)
-	{
-		if ((*it)->type() != EXPRSYM_Operator)
-			continue;
-
-		ExpressionOperator* op = static_cast<ExpressionOperator*> (*it);
-
-		// Unary minus with a value as the previous symbol cannot really be
-		// unary; replace with binary minus.
-		if (op->id() == OPER_UnaryMinus && (*(it - 1))->type() == EXPRSYM_Value)
-			op->setID (OPER_Subtraction);
-	}
-}
-
-// =============================================================================
-//
-// Verifies a single value. Helper function for Expression::verify.
-//
-void Expression::tryVerifyValue (bool* verified, SymbolList::Iterator it)
-{
-	// If it's an unary OPER_erator we skip to its value. The actual OPER_erator will
-	// be verified separately.
-	if ((*it)->type() == EXPRSYM_Operator &&
-			g_Operators[static_cast<ExpressionOperator*> (*it)->id()].numoperands == 1)
-	{
-		++it;
-	}
-
-	int i = it - m_symbols.begin();
-
-	// Ensure it's an actual value
-	if ((*it)->type() != EXPRSYM_Value)
-		error ("malformed expression (symbol #%1 is not a value)", i);
-
-	verified[i] = true;
-}
-
-// =============================================================================
-//
-// Ensures the expression is valid and well-formed and not OMGWTFBBQ. Throws an
-// error if this is not the case.
-//
-void Expression::verify()
-{
-	if (m_symbols.size() == 1)
-	{
-		if (m_symbols[0]->type() != EXPRSYM_Value)
-			error ("bad expression");
-
-		return;
-	}
-
-	if (m_type == TYPE_String)
-		error ("Cannot perform OPER_erations on strings");
-
-	bool* verified = new bool[m_symbols.size()];
-	memset (verified, 0, m_symbols.size() * sizeof (decltype (*verified)));
-	const auto last = m_symbols.end() - 1;
-	const auto first = m_symbols.begin();
-
-	for (auto it = m_symbols.begin(); it != m_symbols.end(); ++it)
-	{
-		int i = (it - first);
-
-		if ((*it)->type() != EXPRSYM_Operator)
-			continue;
-
-		ExpressionOperator* op = static_cast<ExpressionOperator*> (*it);
-		int numoperands = g_Operators[op->id()].numoperands;
-
-		switch (numoperands)
-		{
-			case 1:
-			{
-				// Ensure that:
-				// -	unary OPER_erator is not the last symbol
-				// -	unary OPER_erator is succeeded by a value symbol
-				// -	neither symbol overlaps with something already verified
-				tryVerifyValue (verified, it + 1);
-
-				if (it == last || verified[i] == true)
-					error ("malformed expression");
-
-				verified[i] = true;
-				break;
-			}
-
-			case 2:
-			{
-				// Ensure that:
-				// -	binary OPER_erator is not the first or last symbol
-				// -	is preceded and succeeded by values
-				// -	none of the three tokens are already verified
-				//
-				// Basically similar logic as above.
-				if (it == first || it == last || verified[i] == true)
-					error ("malformed expression");
-
-				tryVerifyValue (verified, it + 1);
-				tryVerifyValue (verified, it - 1);
-				verified[i] = true;
-				break;
-			}
-
-			case 3:
-			{
-				// Ternary OPER_erator case. This goes a bit nuts.
-				// This time we have the following:
-				//
-				// (VALUE) ? (VALUE) : (VALUE)
-				//         ^
-				// --------/ we are here
-				//
-				// Check that the:
-				// -	questionmark OPER_erator is not misplaced (first or last)
-				// -	the value behind the OPER_erator (-1) is valid
-				// -	the value after the OPER_erator (+1) is valid
-				// -	the value after the colon (+3) is valid
-				// -	none of the five tokens are verified
-				//
-				tryVerifyValue (verified, it - 1);
-				tryVerifyValue (verified, it + 1);
-				tryVerifyValue (verified, it + 3);
-
-				if (it == first ||
-					it >= m_symbols.end() - 3 ||
-					verified[i] == true ||
-					verified[i + 2] == true ||
-					(*(it + 2))->type() != EXPRSYM_Colon)
-				{
-					error ("malformed expression");
-				}
-
-				verified[i] = true;
-				verified[i + 2] = true;
-				break;
-			}
-
-			default:
-				error ("WTF OPER_erator with %1 OPER_erands", numoperands);
-		}
-	}
-
-	for (int i = 0; i < m_symbols.size(); ++i)
-		if (verified[i] == false)
-			error ("malformed expression: expr symbol #%1 is was left unverified", i);
-
-	delete verified;
-}
-
-
-// =============================================================================
-//
-// Which operator to evaluate?
-//
-Expression::SymbolList::Iterator Expression::findPrioritizedOperator()
-{
-	SymbolList::Iterator	best = m_symbols.end();
-	int						bestpriority = __INT_MAX__;
-
-	for (SymbolList::Iterator it = m_symbols.begin(); it != m_symbols.end(); ++it)
-	{
-		if ((*it)->type() != EXPRSYM_Operator)
-			continue;
-
-		ExpressionOperator* op = static_cast<ExpressionOperator*> (*it);
-		const OperatorInfo* info = &g_Operators[op->id()];
-
-		if (info->priority < bestpriority)
-		{
-			best = it;
-			bestpriority = info->priority;
-		}
-	}
-
-	return best;
-}
-
-// =============================================================================
-//
-// Process the given OPER_erator and values into a new value.
-//
-ExpressionValue* Expression::evaluateOperator (const ExpressionOperator* op,
-											   const List<ExpressionValue*>& values)
-{
-	const OperatorInfo* info = &g_Operators[op->id()];
-	bool isconstexpr = true;
-	assert (values.size() == info->numoperands);
-
-	for (ExpressionValue* val : values)
-	{
-		if (val->isConstexpr() == false)
-		{
-			isconstexpr = false;
-			break;
-		}
-	}
-
-	// If not all of the values are constant expressions, none of them shall be.
-	if (isconstexpr == false)
-		for (ExpressionValue* val : values)
-			val->convertToBuffer();
-
-	ExpressionValue* newval = new ExpressionValue (m_type);
-
-	if (isconstexpr == false)
-	{
-		// This is not a constant expression so we'll have to use databuffers
-		// to convey the expression to bytecode. Actual value cannot be evaluated
-		// until Zandronum processes it at run-time.
-		newval->setBuffer (new DataBuffer);
-
-		if (op->id() == OPER_Ternary)
-		{
-			// There isn't a dataheader for ternary OPER_erator. Instead, we use DH_IfNotGoto
-			// to create an "if-block" inside an expression.
-			// Behold, big block of writing madness! :P
-			//
-			DataBuffer* buf = newval->buffer();
-			DataBuffer* b0 = values[0]->buffer();
-			DataBuffer* b1 = values[1]->buffer();
-			DataBuffer* b2 = values[2]->buffer();
-			ByteMark* mark1 = buf->addMark (""); // start of "else" case
-			ByteMark* mark2 = buf->addMark (""); // end of expression
-			buf->mergeAndDestroy (b0);
-			buf->writeDWord (DH_IfNotGoto); // if the first OPER_erand (condition)
-			buf->addReference (mark1); // didn't eval true, jump into mark1
-			buf->mergeAndDestroy (b1); // otherwise, perform second OPER_erand (true case)
-			buf->writeDWord (DH_Goto); // afterwards, jump to the end, which is
-			buf->addReference (mark2); // marked by mark2.
-			buf->adjustMark (mark1); // move mark1 at the end of the true case
-			buf->mergeAndDestroy (b2); // perform third OPER_erand (false case)
-			buf->adjustMark (mark2); // move the ending mark2 here
-
-			for (int i = 0; i < 3; ++i)
-				values[i]->setBuffer (null);
-		}
-		else
-		{
-			// Generic case: write all arguments and apply the OPER_erator's
-			// data header.
-			for (ExpressionValue* val : values)
-			{
-				newval->buffer()->mergeAndDestroy (val->buffer());
-
-				// Null the pointer out so that the value's destructor will not
-				// attempt to double-free it.
-				val->setBuffer (null);
-			}
-
-			newval->buffer()->writeDWord (info->header);
-		}
-	}
-	else
-	{
-		// We have a constant expression. We know all the values involved and
-		// can thus compute the result of this expression on compile-time.
-		List<int> nums;
-		int a;
-
-		for (ExpressionValue* val : values)
-			nums << val->value();
-
-		switch (op->id())
-		{
-			case OPER_Addition:				a = nums[0] + nums[1];					break;
-			case OPER_Subtraction:			a = nums[0] - nums[1];					break;
-			case OPER_Multiplication:		a = nums[0] * nums[1];					break;
-			case OPER_UnaryMinus:			a = -nums[0];							break;
-			case OPER_NegateLogical:		a = !nums[0];							break;
-			case OPER_LeftShift:			a = nums[0] << nums[1];					break;
-			case OPER_RightShift:			a = nums[0] >> nums[1];					break;
-			case OPER_CompareLesser:		a = (nums[0] < nums[1]) ? 1 : 0;		break;
-			case OPER_CompareGreater:		a = (nums[0] > nums[1]) ? 1 : 0;		break;
-			case OPER_CompareAtLeast:		a = (nums[0] <= nums[1]) ? 1 : 0;		break;
-			case OPER_CompareAtMost:		a = (nums[0] >= nums[1]) ? 1 : 0;		break;
-			case OPER_CompareEquals:		a = (nums[0] == nums[1]) ? 1 : 0;		break;
-			case OPER_CompareNotEquals:		a = (nums[0] != nums[1]) ? 1 : 0;		break;
-			case OPER_BitwiseAnd:			a = nums[0] & nums[1];					break;
-			case OPER_BitwiseOr:			a = nums[0] | nums[1];					break;
-			case OPER_BitwiseXOr:			a = nums[0] ^ nums[1];					break;
-			case OPER_LogicalAnd:			a = (nums[0] && nums[1]) ? 1 : 0;		break;
-			case OPER_LogicalOr:			a = (nums[0] || nums[1]) ? 1 : 0;		break;
-			case OPER_Ternary:				a = (nums[0] != 0) ? nums[1] : nums[2];	break;
-
-			case OPER_Division:
-			{
-				if (nums[1] == 0)
-					error ("division by zero in constant expression");
-
-				a = nums[0] / nums[1];
-				break;
-			}
-
-			case OPER_Modulus:
-			{
-				if (nums[1] == 0)
-					error ("modulus by zero in constant expression");
-
-				a = nums[0] % nums[1];
-				break;
-			}
-		}
-
-		newval->setValue (a);
-	}
-
-	// The new value has been generated. We don't need the old stuff anymore.
-	for (ExpressionValue* val : values)
-		delete val;
-
-	delete op;
-	return newval;
-}
-
-// =============================================================================
-//
-ExpressionValue* Expression::evaluate()
-{
-	SymbolList::Iterator it;
-
-	while ((it = findPrioritizedOperator()) != m_symbols.end())
-	{
-		int i = it - m_symbols.begin();
-		List<SymbolList::Iterator> OPER_erands;
-		ExpressionOperator* op = static_cast<ExpressionOperator*> (*it);
-		const OperatorInfo* info = &g_Operators[op->id()];
-		int lower, upper; // Boundaries of area to replace
-
-		switch (info->numoperands)
-		{
-			case 1:
-			{
-				lower = i;
-				upper = i + 1;
-				OPER_erands << it + 1;
-				break;
-			}
-
-			case 2:
-			{
-				lower = i - 1;
-				upper = i + 1;
-				OPER_erands << it - 1
-				         << it + 1;
-				break;
-			}
-
-			case 3:
-			{
-				lower = i - 1;
-				upper = i + 3;
-				OPER_erands << it - 1
-				         << it + 1
-				         << it + 3;
-				break;
-			}
-
-			default:
-				assert (false);
-		}
-
-		List<ExpressionValue*> values;
-
-		for (auto it : OPER_erands)
-			values << static_cast<ExpressionValue*> (*it);
-
-		// Note: @op and all of @values are invalid after this call.
-		ExpressionValue* newvalue = evaluateOperator (op, values);
-
-		for (int i = upper; i >= lower; --i)
-			m_symbols.removeAt (i);
-
-		m_symbols.insert (lower, newvalue);
-	}
-
-	assert (m_symbols.size() == 1 && m_symbols.first()->type() == EXPRSYM_Value);
-	ExpressionValue* val = static_cast<ExpressionValue*> (m_symbols.first());
-	return val;
-}
-
-// =============================================================================
-//
-ExpressionValue* Expression::getResult()
-{
-	return static_cast<ExpressionValue*> (m_symbols.first());
-}
-
-// =============================================================================
-//
-String Expression::getTokenString()
-{
-	return m_lexer->token()->text;
-}
-
-// =============================================================================
-//
-ExpressionOperator::ExpressionOperator (ExpressionOperatorType id) :
-	ExpressionSymbol (EXPRSYM_Operator),
-	m_id (id) {}
-
-// =============================================================================
-//
-ExpressionValue::ExpressionValue (DataType valuetype) :
-	ExpressionSymbol (EXPRSYM_Value),
-	m_buffer (null),
-	m_valueType (valuetype) {}
-
-// =============================================================================
-//
-ExpressionValue::~ExpressionValue()
-{
-	delete m_buffer;
-}
-
-// =============================================================================
-//
-void ExpressionValue::convertToBuffer()
-{
-	if (isConstexpr() == false)
-		return;
-
-	setBuffer (new DataBuffer);
-
-	switch (m_valueType)
-	{
-		case TYPE_Bool:
-		case TYPE_Int:
-			buffer()->writeDWord (DH_PushNumber);
-			buffer()->writeDWord (abs (value()));
-
-			if (value() < 0)
-				buffer()->writeDWord (DH_UnaryMinus);
-			break;
-
-		case TYPE_String:
-			buffer()->writeDWord (DH_PushStringIndex);
-			buffer()->writeDWord (value());
-			break;
-
-		case TYPE_Void:
-		case TYPE_Unknown:
-			assert (false);
-			break;
-	}
-}

mercurial