Variables can now be assigned values, unfortunately not at top level.

2012-07-15

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 15 Jul 2012 03:24:46 +0300 (2012-07-15)
changeset 24
7dcc8419dbdb
parent 23
ba351235688e
child 25
2a600af97c6b

Variables can now be assigned values, unfortunately not at top level.

main.cxx file | annotate | diff | comparison | revisions
parser.cxx file | annotate | diff | comparison | revisions
variables.cxx file | annotate | diff | comparison | revisions
variables.h file | annotate | diff | comparison | revisions
--- a/main.cxx	Sun Jul 15 00:32:26 2012 +0300
+++ b/main.cxx	Sun Jul 15 03:24:46 2012 +0300
@@ -106,7 +106,7 @@
 	printf ("%u global variable%s\n", globalcount, PLURAL (globalcount));
 	printf ("%d state%s written\n", g_NumStates, PLURAL (g_NumStates));
 	printf ("%d event%s written\n", g_NumEvents, PLURAL (g_NumEvents));
-	printf ("-- %u bytes written to %s\n", w->numWrittenBytes, argv[2]);
+	printf ("-- %u byte%s written to %s\n", w->numWrittenBytes, PLURAL (w->numWrittenBytes), argv[2]);
 	
 	// Clear out the junk
 	delete r;
--- a/parser.cxx	Sun Jul 15 00:32:26 2012 +0300
+++ b/parser.cxx	Sun Jul 15 03:24:46 2012 +0300
@@ -74,7 +74,10 @@
 			fclose (newfile);
 			ScriptReader* newreader = new ScriptReader (token.chars());
 			newreader->BeginParse (w);
-		} else if (!token.icompare ("state")) {
+			continue;
+		}
+		
+		if (!token.icompare ("state")) {
 			MUST_TOPLEVEL
 			
 			MustString ();
@@ -107,7 +110,10 @@
 			g_NumStates++;
 			g_CurState = token;
 			gotMainLoop = false;
-		} else if (!token.icompare ("event")) {
+			continue;
+		}
+		
+		if (!token.icompare ("event")) {
 			MUST_TOPLEVEL
 			
 			// Event definition
@@ -124,45 +130,51 @@
 			w->Write (DH_EVENT);
 			w->Write<long> (e->number);
 			g_NumEvents++;
-		} else if (!token.icompare ("mainloop")) {
+			continue;
+		}
+		
+		if (!token.icompare ("mainloop")) {
 			MUST_TOPLEVEL
 			MustNext ("{");
 			g_CurMode = MODE_MAINLOOP;
 			w->Write (DH_MAINLOOP);
 			gotMainLoop = true;
-		} else if (!token.icompare ("onenter") || !token.icompare ("onexit")) {
+			continue;
+		}
+		
+		if (!token.icompare ("onenter") || !token.icompare ("onexit")) {
 			MUST_TOPLEVEL
 			bool onenter = !token.compare ("onenter");
 			
 			MustNext ("{");
 			g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT;
 			w->Write (onenter ? DH_ONENTER : DH_ONEXIT);
-		} else if (!token.compare ("int") || !token.compare ("bool")) {
+			continue;
+		}
+		
+		if (!token.compare ("var")) {
 			// For now, only globals are supported
 			if (g_CurMode != MODE_TOPLEVEL || g_CurState.len())
 				ParserError ("variables must only be global for now");
 			
-			// Variable definition
-			int type = !token.compare ("int") ? RETURNVAL_INT: RETURNVAL_BOOLEAN;
+			MustNext ();
 			
-			MustNext ();
+			// Var name must not be a number
+			if (token.isnumber())
+				ParserError ("variable name must not be a number");
+			
 			str varname = token;
-			ScriptVar* var = DeclareGlobalVariable (this, varname, type);
+			ScriptVar* var = DeclareGlobalVariable (this, varname);
 			
 			if (!var)
 				ParserError ("declaring %s variable %s failed",
 					g_CurState.len() ? "state" : "global", varname.chars());
 			
-			// Assign it, if desired
-			if (!PeekNext().compare ("=")) {
-				MustNext ("=");
-				MustValue (type);
-				
-				var->value = token;
-			}
-			
 			MustNext (";");
-		} else if (!token.compare ("}")) {
+			continue;
+		}
+		
+		if (!token.compare ("}")) {
 			// Closing brace
 			int dataheader =	(g_CurMode == MODE_EVENT) ? DH_ENDEVENT :
 						(g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP :
@@ -177,14 +189,68 @@
 			g_CurMode = MODE_TOPLEVEL;
 			
 			MustNext (";");
-		} else {
-			// Check if it's a command.
-			CommandDef* comm = GetCommandByName (token);
-			if (comm)
-				ParseCommand (comm, w);
-			else
-				ParserError ("unknown keyword `%s`", token.chars());
+			continue;
 		}
+		// Check global variables
+		ScriptVar* g = FindGlobalVariable (token);
+		if (g) {
+			// Not in top level, unfortunately..
+			if (g_CurMode == MODE_TOPLEVEL)
+				ParserError ("can't alter variables at top level");
+			
+			// Only addition for now..
+			MustNext ();
+			
+			// Build operator string. Only '=' is one
+			// character, others are two.
+			str oper = token;
+			if (token.compare ("=") != 0) {
+				MustNext ();
+				oper += token;
+			}
+			
+			// Unary operators
+			if (!oper.compare ("++")) {
+				w->Write<long> (DH_INCGLOBALVAR);
+				w->Write<long> (g->index);
+			} else if (!oper.compare ("--")) {
+				w->Write<long> (DH_DECGLOBALVAR);
+				w->Write<long> (g->index);
+			}
+			
+			// And only with numbers for now too.
+			// TODO: make a proper expression parser!
+			MustNumber();
+			
+			int val = atoi (token.chars());
+			w->Write<long> (DH_PUSHNUMBER);
+			w->Write<long> (val);
+			
+			int dataheader =	!oper.compare("=") ? DH_ASSIGNGLOBALVAR :
+						!oper.compare("+=") ? DH_ADDGLOBALVAR :
+						!oper.compare("-=") ? DH_SUBGLOBALVAR :
+						!oper.compare("*=") ? DH_MULGLOBALVAR :
+						!oper.compare("/=") ? DH_DIVGLOBALVAR :
+						!oper.compare("%=") ? DH_MODGLOBALVAR : -1;
+			
+			if (dataheader == -1)
+				ParserError ("bad operator `%s`!", oper.chars());
+			
+			w->Write<long> (dataheader);
+			w->Write<long> (g->index);
+			
+			MustNext (";");
+			continue;
+		}
+		
+		// Check if it's a command.
+		CommandDef* comm = GetCommandByName (token);
+		if (comm) { 
+			ParseCommand (comm, w);
+			continue;
+		}
+		
+		ParserError ("unknown keyword `%s`", token.chars());
 	}
 	
 	if (g_CurMode != MODE_TOPLEVEL)
@@ -229,31 +295,40 @@
 			break;
 		}
 		
-		/*
-		if (!Next ())
+		if (!PeekNext().len())
 			ParserError ("unexpected end-of-file, unterminated command");
 		
 		// If we get a ")" now, the user probably gave too few parameters
-		if (!token.compare (")"))
+		if (!PeekNext().compare (")"))
 			ParserError ("unexpected `)`, did you pass too few parameters? (need %d)", comm->numargs);
-		*/
 		
-		switch (comm->argtypes[curarg]) {
-		case RETURNVAL_INT:
-			MustNumber();
-			w->Write<long> (DH_PUSHNUMBER);
-			w->Write<long> (atoi (token.chars ()));
-			break;
-		case RETURNVAL_BOOLEAN:
-			MustBool();
-			w->Write<long> (DH_PUSHNUMBER);
-			w->Write<long> (BoolValue ());
-			break;
-		case RETURNVAL_STRING:
-			MustString();
-			w->Write<long> (DH_PUSHSTRINGINDEX);
-			w->Write<long> (PushToStringTable (token.chars()));
-			break;
+		// Argument may be using a variable
+		ScriptVar* g = FindGlobalVariable (PeekNext ());
+		if (g && comm->argtypes[curarg] != RETURNVAL_STRING) {
+			// Advance cursor past the var name
+			Next();
+			
+			w->Write<long> (DH_PUSHGLOBALVAR);
+			w->Write<long> (g->index);
+		} else {
+			// Check for raw value
+			switch (comm->argtypes[curarg]) {
+			case RETURNVAL_INT:
+				MustNumber();
+				w->Write<long> (DH_PUSHNUMBER);
+				w->Write<long> (atoi (token.chars ()));
+				break;
+			case RETURNVAL_BOOLEAN:
+				MustBool();
+				w->Write<long> (DH_PUSHNUMBER);
+				w->Write<long> (BoolValue ());
+				break;
+			case RETURNVAL_STRING:
+				MustString();
+				w->Write<long> (DH_PUSHSTRINGINDEX);
+				w->Write<long> (PushToStringTable (token.chars()));
+				break;
+			}
 		}
 		
 		if (curarg < comm->numargs - 1) {
--- a/variables.cxx	Sun Jul 15 00:32:26 2012 +0300
+++ b/variables.cxx	Sun Jul 15 03:24:46 2012 +0300
@@ -61,11 +61,7 @@
 
 // Tries to declare a new global-scope variable. Returns pointer
 // to new global variable, NULL if declaration failed.
-ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name, int type) {
-	// Apparently the Zandronum engine does not support string variables..
-	if (type == RETURNVAL_VOID || type == RETURNVAL_STRING)
-		return NULL;
-	
+ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name) {
 	// Find a NULL pointer to a global variable
 	ScriptVar* g;
 	unsigned int u = 0;
@@ -85,10 +81,8 @@
 	g->index = u;
 	g->name = name;
 	g->statename = "";
-	g->type = type;
 	g->next = NULL;
-	g->value =	(type == RETURNVAL_BOOLEAN) ? "false" :
-			(type == RETURNVAL_INT) ? "0" : "";
+	g->value = 0;
 	
 	g_GlobalVariables[u] = g;
 	return g;
@@ -101,17 +95,21 @@
 }*/
 
 // Find a global variable by name
-/* ScriptVar* FindScriptVariable (str name) {
-	ScriptVar* g;
-	ITERATE_SCRIPT_VARS (g)
+ScriptVar* FindGlobalVariable (str name) {
+	unsigned int u = 0;
+	ITERATE_GLOBAL_VARS (u) {
+		ScriptVar* g = g_GlobalVariables[u];
+		if (!g)
+			return NULL;
+		
 		if (!g->name.compare (name))
 			return g;
+	}
 	
 	return NULL;
-}*/
+}
 
 unsigned int CountGlobalVars () {
-	ScriptVar* var;
 	unsigned int count = 0;
 	unsigned int u = 0;
 	ITERATE_GLOBAL_VARS (u) {
--- a/variables.h	Sun Jul 15 00:32:26 2012 +0300
+++ b/variables.h	Sun Jul 15 03:24:46 2012 +0300
@@ -44,10 +44,9 @@
 #include "scriptreader.h"
 
 struct ScriptVar {
-	int type;
 	str name;
 	str statename;
-	str value;
+	int value;
 	unsigned int index;
 	ScriptVar* next;
 };
@@ -62,8 +61,9 @@
 #define ITERATE_SCRIPT_VARS(g) \
 	for (g = g_ScriptVariable; g != NULL; g = g->next)
 
-ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name, int type);
+ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name);
 unsigned int CountGlobalVars ();
 void InitVariables ();
+ScriptVar* FindGlobalVariable (str name);
 
 #endif // __VARIABLES_H__
\ No newline at end of file

mercurial