parser.cxx

changeset 48
976c57f153b3
parent 47
d84d82213137
child 49
8e2f7a031410
--- a/parser.cxx	Sun Aug 12 04:45:27 2012 +0300
+++ b/parser.cxx	Mon Aug 13 19:04:29 2012 +0300
@@ -201,6 +201,8 @@
 			MustNext ();
 			
 			// Find the mark this goto statement points to
+			// TODO: This should define the mark instead of bombing
+			// out if the mark isn't found!
 			unsigned int m = w->FindMark (token);
 			if (m == MAX_MARKS)
 				ParserError ("unknown label `%s`!", token.chars());
@@ -221,7 +223,9 @@
 			// Condition
 			MustNext ("(");
 			
-			// Read the expression and write it. Store it to memory too for else statements.
+			// 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);
@@ -334,6 +338,99 @@
 		}
 		
 		// ============================================================
+		// Switch
+		if (!token.icompare ("switch")) {
+			/* This goes a bit tricky. switch is structured in the
+			 * bytecode followingly:
+			 * (expression)
+			 * case a: goto casemark1
+			 * case b: goto casemark2
+			 * case c: goto casemark3
+			 * goto mark1 // jump to end if no matches
+			 * casemark1: ...
+			 * casemark2: ...
+			 * casemark3: ...
+			 * mark1: // end mark
+			 */
+			
+			MUST_NOT_TOPLEVEL
+			PushBlockStack ();
+			MustNext ("(");
+			MustNext ();
+			w->WriteBuffer (ParseExpression (TYPE_INT));
+			MustNext (")");
+			MustNext ("{");
+			blockstack[g_BlockStackCursor].type = BLOCKTYPE_SWITCH;
+			blockstack[g_BlockStackCursor].mark1 = w->AddMark (""); // end mark
+			continue;
+		}
+		
+		// ============================================================
+		if (!token.icompare ("case")) {
+			// case is only allowed inside switch
+			if (g_BlockStackCursor <= 0 || blockstack[g_BlockStackCursor].type != BLOCKTYPE_SWITCH)
+				ParserError ("`case` outside switch");
+			
+			BlockInformation* info = &blockstack[g_BlockStackCursor];
+			info->casecursor++;
+			if (info->casecursor >= MAX_CASE)
+				ParserError ("too many `case` statements in one switch");
+			
+			// Get the literal (Zandronum does not support expressions here)
+			MustNumber ();
+			int num = atoi (token.chars ());
+			
+			MustNext (":");
+			
+			// Init a mark for the case buffer
+			int m = w->AddMark ("");
+			info->casemarks[info->casecursor] = m;
+			
+			// Write down the expression and case-go-to. This builds
+			// the case tree. The closing event will write the actual
+			// blocks and move the marks appropriately.
+			info->casebuffers[info->casecursor] = w->RecordBuffer = NULL;
+			w->Write<word> (DH_CASEGOTO);
+			w->Write<word> (num);
+			w->AddReference (m);
+			
+			// Init a buffer for the case block, tell the object
+			// writer to record all written data to it.
+			info->casebuffers[info->casecursor] = w->RecordBuffer = new DataBuffer;
+			continue;
+		}
+		
+		// ============================================================
+		// Break statement.
+		if (!token.icompare ("break")) {
+			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) {
+			case BLOCKTYPE_IF:
+			case BLOCKTYPE_SWITCH:
+				w->AddReference (info->mark1);
+				break;
+			case BLOCKTYPE_FOR:
+			case BLOCKTYPE_WHILE:
+				w->AddReference (info->mark2);
+				break;
+			default:
+				ParserError ("unexpected `break`");
+				break;
+			}
+			
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
 		if (!token.compare ("}")) {
 			// Closing brace
 			
@@ -357,7 +454,7 @@
 					// Move the closing mark here since we're at the end of the while loop
 					w->MoveMark (info->mark2);
 					break;
-				case BLOCKTYPE_DO:
+				case BLOCKTYPE_DO: { 
 					MustNext ("while");
 					MustNext ("(");
 					MustNext ();
@@ -372,6 +469,30 @@
 					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->RecordBuffer = previnfo->casebuffers[previnfo->casecursor];
+					else
+						w->RecordBuffer = NULL;
+					
+					// 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])
+							continue;
+						
+						w->MoveMark (info->casemarks[u]);
+						w->WriteBuffer (info->casebuffers[u]);
+					}
+					
+					// Move the closing mark here
+					w->MoveMark (info->mark1);
+				}
+				}
+				
 				// Descend down the stack
 				g_BlockStackCursor--;
 				continue;
@@ -693,6 +814,11 @@
 	info->mark1 = 0;
 	info->mark2 = 0;
 	info->buffer1 = NULL;
+	info->casecursor = -1;
+	for (int i = 0; i < MAX_CASE; i++) {
+		info->casemarks[i] = MAX_MARKS;
+		info->casebuffers[i] = NULL;
+	}
 }
 
 DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {

mercurial