parser.cxx

changeset 41
47e686c96d8f
parent 40
9e4f785501db
child 42
5cd91fd1526c
--- a/parser.cxx	Mon Jul 30 11:34:57 2012 +0300
+++ b/parser.cxx	Sat Aug 11 19:35:47 2012 +0300
@@ -54,7 +54,7 @@
 #define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
 	ParserError ("%s-statements may only be defined at top level!", token.chars());
 
-#define MUST_NOT_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
+#define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
 	ParserError ("%s-statements may not be defined at top level!", token.chars());
 
 int g_NumStates = 0;
@@ -172,6 +172,8 @@
 		
 		// Label
 		if (!PeekNext().compare (":")) {
+			MUST_NOT_TOPLEVEL
+			
 			if (IsKeyword (token))
 				ParserError ("label name `%s` conflicts with keyword\n", token.chars());
 			if (FindCommand (token))
@@ -186,6 +188,8 @@
 		
 		// Goto
 		if (!token.icompare ("goto")) {
+			MUST_NOT_TOPLEVEL
+			
 			// Get the name of the label
 			MustNext ();
 			
@@ -203,6 +207,9 @@
 		
 		// If
 		if (!token.icompare ("if")) {
+			MUST_NOT_TOPLEVEL
+			PushBlockStack ();
+			
 			// Condition
 			MustNext ("(");
 			
@@ -214,9 +221,53 @@
 			MustNext (")");
 			MustNext ("{");
 			
+			// Add a mark - to here temporarily - and add a reference to it.
+			// Upon a closing brace, the mark will be adjusted.
+			unsigned int marknum = w->AddMark (MARKTYPE_IF, "");
+			
 			// Use DH_IFNOTGOTO - if the expression is not true, we goto the mark
 			// we just defined - and this mark will be at the end of the block.
-			AddBlockMark (w, DH_IFNOTGOTO);
+			w->Write<word> (DH_IFNOTGOTO);
+			w->AddReference (marknum);
+			
+			// Store it in the block stack
+			blockstack[g_BlockStackCursor].mark1 = marknum;
+			blockstack[g_BlockStackCursor].type = BLOCKTYPE_IF;
+			continue;
+		}
+		
+		// While
+		if (!token.compare ("while")) {
+			printf ("begin while loop\n");
+			MUST_NOT_TOPLEVEL
+			PushBlockStack ();
+			
+			// While loops need two marks - one at the start of the loop and one at the
+			// end. The condition is checked at the very start of the loop, if it fails,
+			// we use goto to skip to the end of the loop. At the end, we loop back to
+			// the beginning with a go-to statement.
+			unsigned int mark1 = w->AddMark (MARKTYPE_INTERNAL, ""); // start
+			unsigned int mark2 = w->AddMark (MARKTYPE_INTERNAL, ""); // end
+			
+			// Condition
+			MustNext ("(");
+			MustNext ();
+			DataBuffer* expr = ParseExpression (TYPE_INT);
+			MustNext (")");
+			
+			MustNext ("{");
+			
+			// Write condition
+			w->WriteBuffer (expr);
+			
+			// Instruction to go to the end if it fails
+			w->Write<word> (DH_IFNOTGOTO);
+			w->AddReference (mark2);
+			
+			// Store the needed stuff
+			blockstack[g_BlockStackCursor].mark1 = mark1;
+			blockstack[g_BlockStackCursor].mark2 = mark2;
+			blockstack[g_BlockStackCursor].type = BLOCKTYPE_WHILE;
 			continue;
 		}
 		
@@ -225,11 +276,28 @@
 			
 			// If we're in the block stack, we're descending down from it now
 			if (g_BlockStackCursor > 0) {
-				// Adjust its closing mark so that it's here.
-				unsigned int marknum = blockstack[g_BlockStackCursor];
-				if (marknum != MAX_MARKS)
-					w->MoveMark (marknum);
-				w->AddMark (MARKTYPE_INTERNAL, "");
+				BlockInformation* info = &blockstack[g_BlockStackCursor];
+				switch (info->type) {
+				case BLOCKTYPE_IF:
+					printf ("end if\n");
+					// Adjust the closing mark.
+					w->MoveMark (info->mark1);
+					break;
+				case BLOCKTYPE_WHILE:
+					printf ("end while loop\n");
+					
+					// Write down the instruction to go back to the start of the loop
+					w->Write (DH_GOTO);
+					w->AddReference (info->mark1);
+					
+					// Move the closing mark here since we're at the end of the while loop
+					w->MoveMark (info->mark2);
+					
+					// Offset it by 4 since the parser doesn't like having marks directly afte refs
+					w->OffsetMark (info->mark2, sizeof (word)*2);
+				}
+				
+				// Descend down the stack
 				g_BlockStackCursor--;
 				continue;
 			}
@@ -555,16 +623,10 @@
 	return retbuf;
 }
 
-void ScriptReader::AddBlockMark (ObjWriter* w, word dataheader) {
-	// Add a mark - to here temporarily - and add a reference to it.
-	// Upon a closing brace, the mark will be adjusted.
-	unsigned int marknum = w->AddMark (MARKTYPE_IF, "");
-	
-	// Write the header and store reference to the mark
-	w->Write<word> (dataheader);
-	w->AddReference (marknum);
-	
-	// Store it in the block stack
+void ScriptReader::PushBlockStack () {
+	BlockInformation* info = &blockstack[g_BlockStackCursor];
+	info->type = 0;
+	info->mark1 = 0;
+	info->mark2 = 0;
 	g_BlockStackCursor++;
-	blockstack[g_BlockStackCursor] = marknum;
 }
\ No newline at end of file

mercurial