- now compiles again, further work on expressions (proper parsing + assignment operator handling (albeit unrelated) + operator adjusting)

Tue, 04 Feb 2014 02:28:33 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Tue, 04 Feb 2014 02:28:33 +0200
changeset 92
3a00d396bce2
parent 91
427eb377d53e
child 93
11a24b697f43

- now compiles again, further work on expressions (proper parsing + assignment operator handling (albeit unrelated) + operator adjusting)

CMakeLists.txt file | annotate | diff | comparison | revisions
src/Expression.cc file | annotate | diff | comparison | revisions
src/Expression.h file | annotate | diff | comparison | revisions
src/Parser.cc file | annotate | diff | comparison | revisions
src/Parser.h file | annotate | diff | comparison | revisions
--- a/CMakeLists.txt	Mon Feb 03 20:12:44 2014 +0200
+++ b/CMakeLists.txt	Tue Feb 04 02:28:33 2014 +0200
@@ -5,6 +5,7 @@
 	src/Commands.cc
 	src/DataBuffer.cc
 	src/Events.cc
+	src/Expression.cc
 	src/Format.cc
 	src/Lexer.cc
 	src/LexerScanner.cc
--- a/src/Expression.cc	Mon Feb 03 20:12:44 2014 +0200
+++ b/src/Expression.cc	Tue Feb 04 02:28:33 2014 +0200
@@ -54,7 +54,7 @@
 
 // =============================================================================
 //
-Expression::Expression (BotscriptParser* parser, EType reqtype, Lexer* lx) :
+Expression::Expression (BotscriptParser* parser, Lexer* lx, EType reqtype) :
 	mParser (parser),
 	mLexer (lx),
 	mType (reqtype),
@@ -68,8 +68,46 @@
 	if (mSymbols.IsEmpty())
 		Error ("Expected expression");
 
+	AdjustOperators();
+
+	for (ExpressionSymbol* sym : mSymbols)
+	{
+		switch (sym->GetType())
+		{
+			case ExpressionSymbol::eOperatorSymbol:
+			{
+				Print ("\t- Operator: %1\n", static_cast<ExpressionOperator*> (sym)->GetID());
+				break;
+			}
+
+			case ExpressionSymbol::eValueSymbol:
+			{
+				ExpressionValue* val = static_cast<ExpressionValue*> (sym);
+
+				if (val->IsConstexpr())
+					Print ("\t- Constant expression value: %1\n", val->GetValue());
+				else
+				{
+					Print ("\t- Databuffer value:\n");
+					val->GetBuffer()->Dump();
+				}
+				break;
+			}
+
+			case ExpressionSymbol::eColonSymbol:
+			{
+				Print ("\t- Colon");
+				break;
+			}
+		}
+	}
+
+	exit (0);
+
+	/*
 	Verify();
 	mResult = Evaluate();
+	*/
 }
 
 // =============================================================================
@@ -98,24 +136,25 @@
 		ScriptVariable* globalvar;
 		mLexer->MustGetNext();
 
+		Print ("Token type: %1\n", mLexer->DescribeTokenType (mLexer->GetTokenType()));
+
 		if (mLexer->GetTokenType() == tkColon)
 			return new ExpressionColon;
 
 		// Check for operator
-		for (const OperatorInfo* op : gOperators)
-			if (mLexer->GetTokenType() == op->token)
-				return new ExpressionOperator (op - gOperators);
+		for (const OperatorInfo& op : gOperators)
+			if (mLexer->GetTokenType() == op.token)
+				return new ExpressionOperator ((EOperator) (&op - &gOperators[0]));
 
 		// Check sub-expression
 		if (mLexer->GetTokenType() == tkParenStart)
 		{
-			mLexer->MustGetNext();
 			Expression expr (mParser, mLexer, mType);
 			mLexer->MustGetNext (tkParenEnd);
 			return expr.GetResult();
 		}
 
-		op = new ExpressionValue;
+		op = new ExpressionValue (mType);
 
 		// Check function
 		if (CommandInfo* comm = FindCommandByName (GetTokenString()))
@@ -171,28 +210,36 @@
 		{
 			case EVoidType:
 			case EUnknownType:
+			{
 				Error ("unknown identifier `%1` (expected keyword, function or variable)", GetTokenString());
 				break;
+			}
 
 			case EBoolType:
+			{
 				if ((tt = mLexer->GetTokenType()) == tkTrue || tt == tkFalse)
 				{
 					op->SetValue (tt == tkTrue ? 1 : 0);
 					return op;
 				}
+			}
 			case EIntType:
-				if (!mLexer->GetTokenType() != tkNumber)
+			{
+				if (mLexer->GetTokenType() != tkNumber)
 					throw failed;
 
 				op->SetValue (GetTokenString().ToLong());
 				return op;
+			}
 
 			case EStringType:
-				if (!mLexer->GetTokenType() != tkString)
+			{
+				if (mLexer->GetTokenType() != tkString)
 					throw failed;
 
 				op->SetValue (GetStringTableIndex (GetTokenString()));
 				return op;
+			}
 		}
 
 		assert (false);
@@ -203,11 +250,39 @@
 		// We use a local enum here since catch(...) would catch Error() calls.
 		mLexer->SetPosition (pos);
 		delete op;
-		return false;
+		return null;
 	}
 
 	assert (false);
-	return false;
+	return null;
+}
+
+// =============================================================================
+//
+// The symbol parsing process only does token-based checking for operators. Thus
+// ALL minus operators are actually unary minuses simply because both have
+// tkMinus as their token and the unary minus is prior to the binary minus in
+// the operator table. Now that we have all symbols present, we can correct
+// cases like this.
+//
+void Expression::AdjustOperators()
+{
+	for (auto it = mSymbols.begin() + 1; it != mSymbols.end(); ++it)
+	{
+		if ((*it)->GetType() != ExpressionSymbol::eOperatorSymbol)
+			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->GetID() == opUnaryMinus && (*(it - 1))->GetType() == ExpressionSymbol::eValueSymbol)
+		{
+			Print ("Changing symbol operator #%1 from %2 to %3\n",
+				it - mSymbols.begin(), op->GetID(), opSubtraction);
+			op->SetID (opSubtraction);
+		}
+	}
 }
 
 // =============================================================================
@@ -233,19 +308,26 @@
 
 // =============================================================================
 //
-ExpressionOperator::ExpressionOperator (int id) :
-	mID (id),
-	mType (eOperator) {}
+ExpressionOperator::ExpressionOperator (EOperator id) :
+	ExpressionSymbol (eOperatorSymbol),
+	mID (id) {}
 
 // =============================================================================
 //
-ExpressionValue::ExpressionValue(EType valuetype) :
+ExpressionValue::ExpressionValue (EType valuetype) :
+	ExpressionSymbol (eValueSymbol),
 	mBuffer (null),
-	mType (eOperand),
 	mValueType (valuetype) {}
 
 // =============================================================================
 //
+ExpressionValue::~ExpressionValue()
+{
+	delete mBuffer;
+}
+
+// =============================================================================
+//
 void ExpressionValue::ConvertToBuffer()
 {
 	if (IsConstexpr() == false)
--- a/src/Expression.h	Mon Feb 03 20:12:44 2014 +0200
+++ b/src/Expression.h	Tue Feb 04 02:28:33 2014 +0200
@@ -8,23 +8,51 @@
 
 // =============================================================================
 //
+enum EOperator
+{
+	opNegateLogical,
+	opUnaryMinus,
+	opMultiplication,
+	opDivision,
+	opModulus,
+	opAddition,
+	opSubtraction,
+	opLeftShift,
+	opRightShift,
+	opCompareLesser,
+	opCompareGreater,
+	opCompareAtLeast,
+	opCompareAtMost,
+	opCompareEquals,
+	opCompareNotEquals,
+	opBitwiseAnd,
+	opBitwiseXOr,
+	opBitwiseOr,
+	opLogicalAnd,
+	opLogicalOr,
+	opTernary,
+};
+
+// =============================================================================
+//
 class Expression final
 {
 	public:
-		Expression (BotscriptParser* parser, EType reqtype, Lexer* lx);
+		Expression (BotscriptParser* parser, Lexer* lx, EType reqtype);
 		~Expression();
 		ExpressionValue*		GetResult();
 
 	private:
+		BotscriptParser*		mParser;
 		Lexer*					mLexer;
 		List<ExpressionSymbol*>	mSymbols;
 		EType					mType;
 		ExpressionValue*		mResult;
-		BotscriptParser*		mParser;
 
 		ExpressionValue*		Evaluate(); // Process the expression and yield a result
 		ExpressionSymbol*		ParseSymbol();
 		String					GetTokenString();
+		void					AdjustOperators();
 		void					Verify(); // Ensure the expr is valid
 };
 
@@ -35,11 +63,14 @@
 	public:
 		enum EExpressionSymbolType
 		{
-			eOperator,
-			eOperand,
-			eColon,
+			eOperatorSymbol,
+			eValueSymbol,
+			eColonSymbol,
 		};
 
+		ExpressionSymbol (EExpressionSymbolType type) :
+			mType (type) {}
+
 	PROPERTY (private,	EExpressionSymbolType,	Type,	NO_OPS,	STOCK_WRITE)
 };
 
@@ -47,22 +78,23 @@
 //
 class ExpressionOperator final : public ExpressionSymbol
 {
-	PROPERTY (public,	int,	ID,	NO_OPS,	STOCK_WRITE)
+	PROPERTY (public,	EOperator,	ID,	NO_OPS,	STOCK_WRITE)
 
 	public:
-		ExpressionOperator (int id);
+		ExpressionOperator (EOperator id);
 };
 
 // =============================================================================
 //
 class ExpressionValue final : public ExpressionSymbol
 {
-	PROPERTY (public,	int,			Value,		BOOL_OPS,	STOCK_WRITE)
+	PROPERTY (public,	int,			Value,		NUM_OPS,	STOCK_WRITE)
 	PROPERTY (public,	DataBuffer*,	Buffer,		NO_OPS,		STOCK_WRITE)
 	PROPERTY (public,	EType,			ValueType,	NO_OPS,		STOCK_WRITE)
 
 	public:
 		ExpressionValue (EType valuetype);
+		~ExpressionValue();
 
 		void ConvertToBuffer();
 
@@ -82,7 +114,7 @@
 {
 	public:
 		ExpressionColon() :
-			mType (eColon) {}
+			ExpressionSymbol (eColonSymbol) {}
 };
 
 #endif // BOTC_EXPRESSION_H
\ No newline at end of file
--- a/src/Parser.cc	Mon Feb 03 20:12:44 2014 +0200
+++ b/src/Parser.cc	Tue Feb 04 02:28:33 2014 +0200
@@ -393,7 +393,6 @@
 	mLexer->MustGetNext (tkParenStart);
 
 	// Read the expression and write it.
-	mLexer->MustGetNext();
 	DataBuffer* c = ParseExpression (EIntType);
 	buffer()->MergeAndDestroy (c);
 
@@ -459,7 +458,6 @@
 
 	// Condition
 	mLexer->MustGetNext (tkParenStart);
-	mLexer->MustGetNext();
 	DataBuffer* expr = ParseExpression (EIntType);
 	mLexer->MustGetNext (tkParenEnd);
 	mLexer->MustGetNext (tkBraceStart);
@@ -495,7 +493,6 @@
 	mLexer->MustGetNext (tkSemicolon);
 
 	// Condition
-	mLexer->MustGetNext();
 	DataBuffer* cond = ParseExpression (EIntType);
 
 	if (cond == null)
@@ -563,7 +560,6 @@
 	CheckNotToplevel();
 	PushScope();
 	mLexer->MustGetNext (tkParenStart);
-	mLexer->MustGetNext();
 	buffer()->MergeAndDestroy (ParseExpression (EIntType));
 	mLexer->MustGetNext (tkParenEnd);
 	mLexer->MustGetNext (tkBraceStart);
@@ -739,7 +735,6 @@
 			{
 				mLexer->MustGetNext (tkWhile);
 				mLexer->MustGetNext (tkParenStart);
-				mLexer->MustGetNext();
 				DataBuffer* expr = ParseExpression (EIntType);
 				mLexer->MustGetNext (tkParenEnd);
 				mLexer->MustGetNext (tkSemicolon);
@@ -1019,7 +1014,7 @@
 			Error ("too many arguments passed to %1\n\tusage is: %2",
 				comm->name, comm->GetSignature());
 
-		r->MergeAndDestroy (ParseExpression (comm->args[curarg].type));
+		r->MergeAndDestroy (ParseExpression (comm->args[curarg].type, true));
 		mLexer->MustGetNext();
 
 		if (curarg < comm->numargs - 1)
@@ -1061,80 +1056,6 @@
 }
 
 // ============================================================================
-// Is the given operator an assignment operator?
-//
-static bool IsAssignmentOperator (int oper)
-{
-	switch (oper)
-	{
-		case OPER_ASSIGNADD:
-		case OPER_ASSIGNSUB:
-		case OPER_ASSIGNMUL:
-		case OPER_ASSIGNDIV:
-		case OPER_ASSIGNMOD:
-		case OPER_ASSIGNLEFTSHIFT:
-		case OPER_ASSIGNRIGHTSHIFT:
-		case OPER_ASSIGN:
-			return true;
-	}
-
-	return false;
-}
-
-// ============================================================================
-// Finds an operator's corresponding dataheader
-//
-static word GetDataHeaderByOperator (ScriptVariable* var, int oper)
-{
-	if (IsAssignmentOperator (oper))
-	{
-		if (var == null)
-			Error ("operator %d requires left operand to be a variable\n", oper);
-
-		// TODO: At the moment, vars only are global
-		// OPER_ASSIGNLEFTSHIFT and OPER_ASSIGNRIGHTSHIFT do not
-		// have data headers, instead they are expanded out in
-		// the operator Parser
-		switch (oper)
-		{
-			case OPER_ASSIGNADD: return dhAddGlobalVar;
-			case OPER_ASSIGNSUB: return dhSubtractGlobalVar;
-			case OPER_ASSIGNMUL: return dhMultiplyGlobalVar;
-			case OPER_ASSIGNDIV: return dhDivideGlobalVar;
-			case OPER_ASSIGNMOD: return dhModGlobalVar;
-			case OPER_ASSIGN: return dhAssignGlobalVar;
-
-			default: Error ("bad assignment operator!\n");
-		}
-	}
-
-	switch (oper)
-	{
-		case OPER_ADD: return dhAdd;
-		case OPER_SUBTRACT: return dhSubtract;
-		case OPER_MULTIPLY: return dhMultiply;
-		case OPER_DIVIDE: return dhDivide;
-		case OPER_MODULUS: return dhModulus;
-		case OPER_EQUALS: return dhEquals;
-		case OPER_NOTEQUALS: return dhNotEquals;
-		case OPER_LESSTHAN: return dhLessThan;
-		case OPER_GREATERTHAN: return dhGreaterThan;
-		case OPER_LESSTHANEQUALS: return dhAtMost;
-		case OPER_GREATERTHANEQUALS: return dhAtLeast;
-		case OPER_LEFTSHIFT: return dhLeftShift;
-		case OPER_RIGHTSHIFT: return dhRightShift;
-		case OPER_OR: return dhOrLogical;
-		case OPER_AND: return dhAndLogical;
-		case OPER_BITWISEOR: return dhOrBitwise;
-		case OPER_BITWISEEOR: return dhEorBitwise;
-		case OPER_BITWISEAND: return dhAndBitwise;
-	}
-
-	Error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper);
-	return 0;
-}
-
-// ============================================================================
 //
 String BotscriptParser::ParseFloat()
 {
@@ -1155,6 +1076,71 @@
 }
 
 // ============================================================================
+//
+// Parses an assignment operator.
+//
+EAssignmentOperator BotscriptParser::ParseAssignmentOperator()
+{
+	const List<EToken> tokens =
+	{
+		tkAssign,
+		tkAddAssign,
+		tkSubAssign,
+		tkMultiplyAssign,
+		tkDivideAssign,
+		tkModulusAssign
+	};
+
+	mLexer->MustGetAnyOf (tokens);
+
+	switch (mLexer->GetTokenType())
+	{
+		case tkAssign:			return EAssign;
+		case tkAddAssign:		return EAssignAdd;
+		case tkSubAssign:		return EAssignSub;
+		case tkMultiplyAssign:	return EAssignMul;
+		case tkDivideAssign:	return EAssignDiv;
+		case tkModulusAssign:	return EAssignMod;
+		default: break;
+	}
+
+	assert (false);
+	return (EAssignmentOperator) 0;
+}
+
+// ============================================================================
+//
+EDataHeader BotscriptParser::GetAssigmentDataHeader (EAssignmentOperator op, ScriptVariable* var)
+{
+	if (var->IsGlobal())
+	{
+		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;
+		}
+	}
+
+	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;
+	}
+
+	assert (false);
+	return (EDataHeader) 0;
+}
+
+// ============================================================================
+//
 // 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.
@@ -1162,20 +1148,16 @@
 DataBuffer* BotscriptParser::ParseAssignment (ScriptVariable* var)
 {
 	// Get an operator
-	mLexer->MustGetNext();
-	int oper = ParseOperator();
-
-	if (IsAssignmentOperator (oper) == false)
-		Error ("expected assignment operator");
+	EAssignmentOperator oper = ParseAssignmentOperator();
 
 	if (mCurrentMode == ETopLevelMode)
 		Error ("can't alter variables at top level");
 
 	// Parse the right operand
-	mLexer->MustGetNext();
 	DataBuffer* retbuf = new DataBuffer;
 	DataBuffer* expr = ParseExpression (var->type);
 
+#if 0
 	// <<= and >>= do not have data headers. Solution: expand them.
 	// a <<= b -> a = a << b
 	// a >>= b -> a = a >> b
@@ -1190,11 +1172,14 @@
 	}
 	else
 	{
+#endif
 		retbuf->MergeAndDestroy (expr);
-		long dh = GetDataHeaderByOperator (var, oper);
+		EDataHeader dh = GetAssigmentDataHeader (oper, var);
 		retbuf->WriteDWord (dh);
 		retbuf->WriteDWord (var->index);
+#if 0
 	}
+#endif
 
 	return retbuf;
 }
@@ -1225,11 +1210,18 @@
 
 // ============================================================================
 //
-void BotscriptParser::ParseExpression (EType reqtype)
+DataBuffer* BotscriptParser::ParseExpression (EType reqtype, bool fromhere)
 {
-	Expression expr (this, reqtype, mLexer);
+	// hehe
+	if (fromhere == true)
+		mLexer->Skip (-1);
+
+	Expression expr (this, mLexer, reqtype);
 	expr.GetResult()->ConvertToBuffer();
-	buffer()->MergeAndDestroy (expr.GetResult()->GetBuffer());
+
+	// The buffer will be destroyed once the function ends so we need to
+	// clone it now.
+	return expr.GetResult()->GetBuffer()->Clone();
 }
 
 // ============================================================================
--- a/src/Parser.h	Mon Feb 03 20:12:44 2014 +0200
+++ b/src/Parser.h	Tue Feb 04 02:28:33 2014 +0200
@@ -57,50 +57,6 @@
 };
 
 // ============================================================================
-// Operators
-//
-enum EOperator
-{
-	OPER_ADD,
-	OPER_SUBTRACT,
-	OPER_MULTIPLY,
-	OPER_DIVIDE,
-	OPER_MODULUS,
-	OPER_ASSIGN,
-	OPER_ASSIGNADD,
-	OPER_ASSIGNSUB,
-	OPER_ASSIGNMUL,
-	OPER_ASSIGNDIV,
-	OPER_ASSIGNMOD, // -- 10
-	OPER_EQUALS,
-	OPER_NOTEQUALS,
-	OPER_LESSTHAN,
-	OPER_GREATERTHAN,
-	OPER_LESSTHANEQUALS,
-	OPER_GREATERTHANEQUALS,
-	OPER_LEFTSHIFT,
-	OPER_RIGHTSHIFT,
-	OPER_ASSIGNLEFTSHIFT,
-	OPER_ASSIGNRIGHTSHIFT, // -- 20
-	OPER_OR,
-	OPER_AND,
-	OPER_BITWISEOR,
-	OPER_BITWISEAND,
-	OPER_BITWISEEOR,
-	OPER_TERNARY,
-	OPER_STRLEN,
-};
-
-// ============================================================================
-//
-struct operatorInfo
-{
-	EOperator		opercode;
-	EDataHeader		dataheader;
-	EToken			token;
-};
-
-// ============================================================================
 // Mark types
 //
 enum eMarkType
@@ -124,6 +80,16 @@
 	eElseScope,
 };
 
+enum EAssignmentOperator
+{
+	EAssign,
+	EAssignAdd,
+	EAssignSub,
+	EAssignMul,
+	EAssignDiv,
+	EAssignMod,
+};
+
 // ============================================================================
 // Meta-data about scopes
 //
@@ -171,21 +137,21 @@
 		// METHODS
 		BotscriptParser();
 		~BotscriptParser();
-		ConstantInfo*	FindConstant (const String& tok);
-		void			ParseBotscript (String fileName);
-		DataBuffer*		ParseCommand (CommandInfo* comm);
-		DataBuffer*		ParseAssignment (ScriptVariable* var);
-		int				ParseOperator (bool peek = false);
-		String			ParseFloat();
-		void			PushScope();
-		DataBuffer*		ParseStatement();
-		void			AddSwitchCase (DataBuffer* b);
-		void			CheckToplevel();
-		void			CheckNotToplevel();
-		bool			TokenIs (EToken a);
-		String			GetTokenString();
-		String			DescribePosition() const;
-		void			WriteToFile (String outfile);
+		ConstantInfo*			FindConstant (const String& tok);
+		void					ParseBotscript (String fileName);
+		DataBuffer*				ParseCommand (CommandInfo* comm);
+		DataBuffer*				ParseAssignment (ScriptVariable* var);
+		EAssignmentOperator		ParseAssignmentOperator ();
+		String					ParseFloat();
+		void					PushScope();
+		DataBuffer*				ParseStatement();
+		void					AddSwitchCase (DataBuffer* b);
+		void					CheckToplevel();
+		void					CheckNotToplevel();
+		bool					TokenIs (EToken a);
+		String					GetTokenString();
+		String					DescribePosition() const;
+		void					WriteToFile (String outfile);
 
 		inline int GetNumEvents() const
 		{
@@ -258,7 +224,8 @@
 		void			ParseFuncdef();
 		void			writeMemberBuffers();
 		void			WriteStringTable();
-		void ParseExpression (EType reqtype);
+		DataBuffer*		ParseExpression (EType reqtype, bool fromhere = false);
+		EDataHeader		GetAssigmentDataHeader (EAssignmentOperator op, ScriptVariable* var);
 };
 
 #endif // BOTC_PARSER_H

mercurial