Added support for else-statements

Sat, 25 Aug 2012 03:40:36 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sat, 25 Aug 2012 03:40:36 +0300
changeset 56
384c5605bda9
parent 55
173956c1ac27
child 57
96f60ca748a0

Added support for else-statements

main.cxx file | annotate | diff | comparison | revisions
parser.cxx file | annotate | diff | comparison | revisions
scriptreader.h file | annotate | diff | comparison | revisions
--- a/main.cxx	Sat Aug 25 03:04:14 2012 +0300
+++ b/main.cxx	Sat Aug 25 03:40:36 2012 +0300
@@ -61,6 +61,7 @@
 	"case",
 	"default",
 	"do",
+	"else",
 	"event",
 	"for",
 	"goto",
@@ -76,7 +77,6 @@
 	// These ones aren't implemented yet but I plan to do so, thus they are
 	// reserved. Also serves as a to-do list of sorts for me. >:F
 	"continue",
-	"else",
 	"enum", // Would enum actually be useful? I think so.
 	"func", // Would function support need external support from zandronum?
 	"return",
--- a/parser.cxx	Sat Aug 25 03:04:14 2012 +0300
+++ b/parser.cxx	Sat Aug 25 03:40:36 2012 +0300
@@ -57,6 +57,8 @@
 #define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
 	ParserError ("%s-statements may not be defined at top level!", token.chars());
 
+#define SCOPE(n) blockstack[g_BlockStackCursor - n]
+
 int g_NumStates = 0;
 int g_NumEvents = 0;
 int g_CurMode = MODE_TOPLEVEL;
@@ -71,6 +73,10 @@
 // and writes the data to the object file via ObjWriter - which also takes care
 // of necessary buffering so stuff is written in the correct order.
 void ScriptReader::ParseBotScript (ObjWriter* w) {
+	// Zero the entire block stack first
+	for (int i = 0; i < MAX_STRUCTSTACK; i++)
+		memset (&blockstack[i], 0, sizeof (BlockInformation));
+	
 	while (Next()) {
 		// ============================================================
 		if (!token.compare ("state")) {
@@ -207,8 +213,6 @@
 			MustNext ("(");
 			
 			// Read the expression and write it.
-			// TODO: This should be storing it into a variable first, so
-			// that else statements would be possible!
 			MustNext ();
 			DataBuffer* c = ParseExpression (TYPE_INT);
 			w->WriteBuffer (c);
@@ -226,8 +230,34 @@
 			w->AddReference (marknum);
 			
 			// Store it in the block stack
-			blockstack[g_BlockStackCursor].mark1 = marknum;
-			blockstack[g_BlockStackCursor].type = BLOCKTYPE_IF;
+			SCOPE(0).mark1 = marknum;
+			SCOPE(0).type = BLOCKTYPE_IF;
+			continue;
+		}
+		
+		if (!token.compare ("else")) {
+			MUST_NOT_TOPLEVEL
+			MustNext ("{");
+			
+			// Don't use PushBlockStack as that will reset the scope.
+			g_BlockStackCursor++;
+			if (g_BlockStackCursor >= MAX_STRUCTSTACK)
+				ParserError ("too deep scope");
+			
+			if (SCOPE(0).type != BLOCKTYPE_IF)
+				ParserError ("else without preceding if");
+			
+			// Write down to jump to the end of the else statement
+			// Otherwise we have fall-throughs
+			SCOPE(0).mark2 = w->AddMark ("");
+			
+			// Instruction to jump to the end after if block is complete
+			w->Write (DH_GOTO);
+			w->AddReference (SCOPE(0).mark2);
+			
+			// Move the ifnot mark here and set type to else
+			w->MoveMark (SCOPE(0).mark1);
+			SCOPE(0).type = BLOCKTYPE_ELSE;
 			continue;
 		}
 		
@@ -259,9 +289,9 @@
 			w->AddReference (mark2);
 			
 			// Store the needed stuff
-			blockstack[g_BlockStackCursor].mark1 = mark1;
-			blockstack[g_BlockStackCursor].mark2 = mark2;
-			blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE;
+			SCOPE(0).mark1 = mark1;
+			SCOPE(0).mark2 = mark2;
+			SCOPE(0).type = BLOCKTYPE_WHILE;
 			continue;
 		}
 		
@@ -301,10 +331,10 @@
 			w->AddReference (mark2);
 			
 			// Store the marks and incrementor
-			blockstack[g_BlockStackCursor].mark1 = mark1;
-			blockstack[g_BlockStackCursor].mark2 = mark2;
-			blockstack[g_BlockStackCursor].buffer1 = incr;
-			blockstack[g_BlockStackCursor].type = BLOCKTYPE_FOR;
+			SCOPE(0).mark1 = mark1;
+			SCOPE(0).mark2 = mark2;
+			SCOPE(0).buffer1 = incr;
+			SCOPE(0).type = BLOCKTYPE_FOR;
 			continue;
 		}
 		
@@ -314,8 +344,8 @@
 			MUST_NOT_TOPLEVEL
 			PushBlockStack ();
 			MustNext ("{");
-			blockstack[g_BlockStackCursor].mark1 = w->AddMark ("");
-			blockstack[g_BlockStackCursor].type = BLOCKTYPE_DO;
+			SCOPE(0).mark1 = w->AddMark ("");
+			SCOPE(0).type = BLOCKTYPE_DO;
 			continue;
 		}
 		
@@ -342,17 +372,16 @@
 			w->WriteBuffer (ParseExpression (TYPE_INT));
 			MustNext (")");
 			MustNext ("{");
-			blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH;
-			blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark
-			blockstack[g_BlockStackCursor].buffer1 = NULL; // default header
+			SCOPE(0).type = BLOCKTYPE_SWITCH;
+			SCOPE(0).mark1 = w->AddMark (""); // end mark
+			SCOPE(0).buffer1 = NULL; // default header
 			continue;
 		}
 		
 		// ============================================================
 		if (!token.compare ("case")) {
 			// case is only allowed inside switch
-			BlockInformation* info = &blockstack[g_BlockStackCursor];
-			if (info->type != BLOCKTYPE_SWITCH)
+			if (SCOPE(0).type != BLOCKTYPE_SWITCH)
 				ParserError ("case label outside switch");
 			
 			// Get the literal (Zandronum does not support expressions here)
@@ -361,7 +390,7 @@
 			MustNext (":");
 			
 			for (int i = 0; i < MAX_CASE; i++)
-				if (info->casenumbers[i] == num)
+				if (SCOPE(0).casenumbers[i] == num)
 					ParserError ("multiple case %d labels in one switch", num);
 			
 			// Write down the expression and case-go-to. This builds
@@ -376,16 +405,15 @@
 			w->Write<word> (DH_CASEGOTO);
 			w->Write<word> (num);
 			AddSwitchCase (w, NULL);
-			info->casenumbers[info->casecursor] = num;
+			SCOPE(0).casenumbers[SCOPE(0).casecursor] = num;
 			continue;
 		}
 		
 		if (!token.compare ("default")) {
-			BlockInformation* info = &blockstack[g_BlockStackCursor];
-			if (info->type != BLOCKTYPE_SWITCH)
+			if (SCOPE(0).type != BLOCKTYPE_SWITCH)
 				ParserError ("default label outside switch");
 			
-			if (info->buffer1)
+			if (SCOPE(0).buffer1)
 				ParserError ("multiple default labels in one switch");
 			
 			MustNext (":");
@@ -398,7 +426,7 @@
 			// to pop it with DH_DROP manually if we end up in
 			// a default.
 			DataBuffer* b = new DataBuffer;
-			info->buffer1 = b;
+			SCOPE(0).buffer1 = b;
 			b->Write<word> (DH_DROP);
 			b->Write<word> (DH_GOTO);
 			AddSwitchCase (w, b);
@@ -411,20 +439,18 @@
 			if (!g_BlockStackCursor)
 				ParserError ("unexpected `break`");
 			
-			BlockInformation* info = &blockstack[g_BlockStackCursor];
-			
 			w->Write<word> (DH_GOTO);
 			
 			// switch and if use mark1 for the closing point,
 			// for and while use mark2.
-			switch (info->type) {
+			switch (SCOPE(0).type) {
 			case BLOCKTYPE_IF:
 			case BLOCKTYPE_SWITCH:
-				w->AddReference (info->mark1);
+				w->AddReference (SCOPE(0).mark1);
 				break;
 			case BLOCKTYPE_FOR:
 			case BLOCKTYPE_WHILE:
-				w->AddReference (info->mark2);
+				w->AddReference (SCOPE(0).mark2);
 				break;
 			default:
 				ParserError ("unexpected `break`");
@@ -458,23 +484,27 @@
 			
 			// If we're in the block stack, we're descending down from it now
 			if (g_BlockStackCursor > 0) {
-				BlockInformation* info = &blockstack[g_BlockStackCursor];
-				switch (info->type) {
+				switch (SCOPE(0).type) {
 				case BLOCKTYPE_IF:
 					// Adjust the closing mark.
-					w->MoveMark (info->mark1);
+					w->MoveMark (SCOPE(0).mark1);
+					break;
+				case BLOCKTYPE_ELSE:
+					// else instead uses mark1 for itself (so if expression
+					// fails, jump to else), mark2 means end of else
+					w->MoveMark (SCOPE(0).mark2);
 					break;
 				case BLOCKTYPE_FOR:
 					// Write the incrementor at the end of the loop block
-					w->WriteBuffer (info->buffer1);
+					w->WriteBuffer (SCOPE(0).buffer1);
 					// fall-thru
 				case BLOCKTYPE_WHILE:
 					// Write down the instruction to go back to the start of the loop
 					w->Write (DH_GOTO);
-					w->AddReference (info->mark1);
+					w->AddReference (SCOPE(0).mark1);
 					
 					// Move the closing mark here since we're at the end of the while loop
-					w->MoveMark (info->mark2);
+					w->MoveMark (SCOPE(0).mark2);
 					break;
 				case BLOCKTYPE_DO: { 
 					MustNext ("while");
@@ -487,41 +517,40 @@
 					// If the condition runs true, go back to the start.
 					w->WriteBuffer (expr);
 					w->Write<long> (DH_IFGOTO);
-					w->AddReference (info->mark1);
+					w->AddReference (SCOPE(0).mark1);
 					break;
 				}
 				case BLOCKTYPE_SWITCH: {
 					// Switch closes. Move down to the record buffer of
 					// the lower block.
-					BlockInformation* previnfo = &blockstack[g_BlockStackCursor - 1];
-					if (previnfo->casecursor != -1)
-						w->SwitchBuffer = previnfo->casebuffers[previnfo->casecursor];
+					if (SCOPE(1).casecursor != -1)
+						w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor];
 					else
 						w->SwitchBuffer = NULL;
 					
 					// If there was a default in the switch, write its header down now.
 					// If not, write instruction to jump to the end of switch after
 					// the headers (thus won't fall-through if no case matched)
-					if (info->buffer1)
-						w->WriteBuffer (info->buffer1);
+					if (SCOPE(0).buffer1)
+						w->WriteBuffer (SCOPE(0).buffer1);
 					else {
 						w->Write<word> (DH_DROP);
 						w->Write<word> (DH_GOTO);
-						w->AddReference (info->mark1);
+						w->AddReference (SCOPE(0).mark1);
 					}
 					
 					// Go through all of the buffers we
 					// recorded down and write them.
 					for (unsigned int u = 0; u < MAX_CASE; u++) {
-						if (!info->casebuffers[u])
+						if (!SCOPE(0).casebuffers[u])
 							continue;
 						
-						w->MoveMark (info->casemarks[u]);
-						w->WriteBuffer (info->casebuffers[u]);
+						w->MoveMark (SCOPE(0).casemarks[u]);
+						w->WriteBuffer (SCOPE(0).casebuffers[u]);
 					}
 					
 					// Move the closing mark here
-					w->MoveMark (info->mark1);
+					w->MoveMark (SCOPE(0).mark1);
 				}
 				}
 				
@@ -713,8 +742,8 @@
 		MustNext ();
 		DataBuffer* rb = ParseExprValue (reqtype);
 		
-		// Ternary operator requires - naturally - a third operator
 		if (oper == OPER_TERNARY) {
+			// Ternary operator requires - naturally - a third operand.
 			MustNext (":");
 			MustNext ();
 			DataBuffer* tb = ParseExprValue (reqtype);
@@ -952,7 +981,10 @@
 
 void ScriptReader::PushBlockStack () {
 	g_BlockStackCursor++;
-	BlockInformation* info = &blockstack[g_BlockStackCursor];
+	if (g_BlockStackCursor >= MAX_STRUCTSTACK)
+		ParserError ("too deep scope");
+	
+	BlockInformation* info = &SCOPE(0);
 	info->type = 0;
 	info->mark1 = 0;
 	info->mark2 = 0;
@@ -978,7 +1010,7 @@
 }
 
 void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
-	BlockInformation* info = &blockstack[g_BlockStackCursor];
+	BlockInformation* info = &SCOPE(0);
 	
 	info->casecursor++;
 	if (info->casecursor >= MAX_CASE)
--- a/scriptreader.h	Sat Aug 25 03:04:14 2012 +0300
+++ b/scriptreader.h	Sat Aug 25 03:40:36 2012 +0300
@@ -194,11 +194,13 @@
 
 // Block types
 enum {
+	BLOCKTYPE_UNSET = 0,
 	BLOCKTYPE_IF,
 	BLOCKTYPE_WHILE,
 	BLOCKTYPE_FOR,
 	BLOCKTYPE_DO,
 	BLOCKTYPE_SWITCH,
+	BLOCKTYPE_ELSE,
 };
 
 #endif // __SCRIPTREADER_H__
\ No newline at end of file

mercurial