parser.cxx

changeset 36
a8838b5f1213
parent 35
3d3f6ed40171
child 37
c349dca807f9
--- a/parser.cxx	Sat Jul 28 17:57:37 2012 +0300
+++ b/parser.cxx	Sun Jul 29 04:02:07 2012 +0300
@@ -62,9 +62,12 @@
 bool g_GotMainLoop = false;
 
 // ============================================================================
-// Main parser
+// Main parser code. Begins read of the script file, checks the syntax of it
+// 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::BeginParse (ObjWriter* w) {
 	while (Next()) {
+		printf ("BeginParse: token: `%s`\n", token.chars());
 		if (!token.icompare ("state")) {
 			MUST_TOPLEVEL
 			
@@ -114,7 +117,7 @@
 			g_CurMode = MODE_EVENT;
 			
 			w->Write (DH_EVENT);
-			w->Write<byte> (e->number);
+			w->Write<word> (e->number);
 			g_NumEvents++;
 			continue;
 		}
@@ -164,6 +167,7 @@
 		}
 		
 		if (!token.compare ("}")) {
+			printf ("parse closing brace\n");
 			// Closing brace
 			int dataheader =	(g_CurMode == MODE_EVENT) ? DH_ENDEVENT :
 						(g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP :
@@ -174,8 +178,8 @@
 				ParserError ("unexpected `}`");
 			
 			// Data header must be written before mode is changed because
-			// onenter and mainloop go into buffers, and we want the closing
-			// data headers into said buffers too.
+			// onenter and mainloop go into special buffers, and we want
+			// the closing data headers into said buffers too.
 			w->Write (dataheader);
 			g_CurMode = MODE_TOPLEVEL;
 			
@@ -184,12 +188,23 @@
 			continue;
 		}
 		
+		// If it's a variable, expect assignment.
+		if (ScriptVar* var = FindGlobalVariable (token)) {
+			DataBuffer* b = ParseAssignment (var);
+			printf ("current token after assignment: `%s`\n", token.chars());
+			MustNext (";");
+			w->WriteBuffer (b);
+			delete b;
+			continue;
+		}
+		
 		// If it's not a keyword, parse it as an expression.
+		printf ("token length: %d, first char: %c [%d]\n", token.len(), token.chars()[0], token.chars()[0]);
 		DataBuffer* b = ParseExpression (TYPE_VOID);
 		w->WriteBuffer (b);
 		delete b;
-		printf ("expression done!\n");
-		MustThis (";");
+		printf ("expression done! current token is %s\n", token.chars());
+		MustNext (";");
 	}
 	
 	if (g_CurMode != MODE_TOPLEVEL)
@@ -207,18 +222,22 @@
 }
 
 // ============================================================================
-// Parses a given command
+// Parses a command call
 DataBuffer* ScriptReader::ParseCommand (CommandDef* comm) {
 	DataBuffer* r = new DataBuffer(64);
-	// If this was defined at top-level, we stop right at square one!
 	if (g_CurMode == MODE_TOPLEVEL)
-		ParserError ("no commands allowed at top level!");
+		ParserError ("command call at top level");
 	
+	printf ("\n\n\n=====================================\nBEGIN PARSING COMMAND\n");
 	printf ("token: %s\n", token.chars());
 	MustNext ("(");
+	MustNext ();
 	
 	int curarg = 0;
 	while (1) {
+		printf ("at argument %d\n", curarg);
+		printf ("next token: %s\n", token.chars());
+		
 		if (!token.compare (")")) {
 			printf ("closing command with token `%s`\n", token.chars());
 			if (curarg < comm->numargs - 1)
@@ -226,28 +245,26 @@
 			break;
 			curarg++;
 		}
-		printf ("prev token: %s\n", token.chars());
-		MustNext ();
-		printf ("next token: %s\n", token.chars());
-		
-		// jump back to start
-		if (!token.compare (")"))
-			continue;
 		
 		if (curarg >= comm->maxargs)
 			ParserError ("too many arguments passed to %s\n", comm->name.chars());
 		
 		r->Merge (ParseExpression (comm->argtypes[curarg]));
+		MustNext ();
+		printf ("after expression, token is `%s`\n", token.chars());
 		
 		if (curarg < comm->numargs - 1) {
 			MustThis (",");
+			MustNext ();
 		} else if (curarg < comm->maxargs - 1) {
 			// Can continue, but can terminate as well.
 			if (!token.compare (")")) {
 				curarg++;
 				break;
-			} else
+			} else {
 				MustThis (",");
+				MustNext ();
+			}
 		}
 		
 		curarg++;
@@ -255,19 +272,21 @@
 	
 	// If the script skipped any optional arguments, fill in defaults.
 	while (curarg < comm->maxargs) {
-		r->Write<byte> (DH_PUSHNUMBER);
-		r->Write<byte> (comm->defvals[curarg]);
+		r->Write<word> (DH_PUSHNUMBER);
+		r->Write<word> (comm->defvals[curarg]);
 		curarg++;
 	}
 	
-	r->Write<byte> (DH_COMMAND);
-	r->Write<byte> (comm->number);
-	r->Write<byte> (comm->maxargs);
+	r->Write<word> (DH_COMMAND);
+	r->Write<word> (comm->number);
+	r->Write<word> (comm->maxargs);
 	
 	printf ("command complete\n");
 	return r;
 }
 
+// ============================================================================
+// Is the given operator an assignment operator?
 static bool IsAssignmentOperator (int oper) {
 	switch (oper) {
 	case OPER_ASSIGNADD:
@@ -282,6 +301,7 @@
 }
 
 // ============================================================================
+// Finds an operator's corresponding dataheader
 static long DataHeaderByOperator (ScriptVar* var, int oper) {
 	if (IsAssignmentOperator (oper)) {
 		if (!var)
@@ -312,7 +332,7 @@
 }
 
 // ============================================================================
-// Parses an expression
+// Parses an expression, potentially recursively
 DataBuffer* ScriptReader::ParseExpression (int reqtype) {
 	printf ("begin parsing expression. this token is `%s`, next token is `%s`\n",
 		token.chars(), PeekNext().chars());
@@ -320,20 +340,18 @@
 	
 	DataBuffer* lb = NULL;
 	
+	// If it's a variable, note it down - we need to do special checks with it later.
 	ScriptVar* var = FindGlobalVariable (token);
-	if (var) {
-		MustNext ();
-		if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction
-			ParserError ("can't alter variables at top level");
-		reqtype = TYPE_INT;
-	} else
-		lb = ParseExprValue (reqtype);
+	
+	lb = ParseExprValue (reqtype);
 	printf ("done\n");
 	
 	// Get an operator
 	printf ("parse operator at token %s\n", token.chars());
-	int oper = ParseOperator ();
+	int oper = ParseOperator (true);
+	printf ("operator parsed: token is now %s\n", token.chars());
 	printf ("got %d\n", oper);
+	
 	// No operator found - stop here.
 	if (oper == -1) {
 		retbuf->Merge (lb);
@@ -341,30 +359,37 @@
 		return retbuf;
 	}
 	
+	// We peeked the operator, move forward now
+	MustNext();
+	
+	// Can't be an assignement operator, those belong in assignments.
+	if (IsAssignmentOperator (oper))
+		ParserError ("assignment operator inside expressions");
+	
 	// Parse the right operand,
 	printf ("parse right operand\n");
 	MustNext ();
 	DataBuffer* rb = ParseExprValue (reqtype);
 	printf ("done\n");
 	
+	retbuf->Merge (rb);
 	retbuf->Merge (lb);
-	retbuf->Merge (rb);
 	
 	long dh = DataHeaderByOperator (var, oper);
-	retbuf->Write<byte> (dh);
-	
-	if (IsAssignmentOperator (oper))
-		retbuf->Write<byte> (var->index);
+	retbuf->Write<word> (dh);
 	
 	printf ("expression complete\n");
 	return retbuf;
 }
 
 // ============================================================================
-// Parsess an operator from tokens and returns an identifier.
-int ScriptReader::ParseOperator () {
+// Parses an operator string. Returns the operator number code.
+int ScriptReader::ParseOperator (bool peek) {
 	str oper;
-	oper += PeekNext ();
+	if (peek)
+		oper += PeekNext ();
+	else
+		oper += token;
 	
 	// Check one-char operators
 	int o =	!oper.compare ("=") ? OPER_ASSIGN :
@@ -376,13 +401,11 @@
 		-1;
 	
 	if (o != -1) {
-		MustNext ();
 		return o;
 	}
 	
 	// Two-char operators
-	MustNext ();
-	oper += PeekNext (1);
+	oper += PeekNext (peek ? 1 : 0);
 	
 	o =	!oper.compare ("+=") ? OPER_ASSIGNADD :
 		!oper.compare ("-=") ? OPER_ASSIGNSUB :
@@ -391,10 +414,8 @@
 		!oper.compare ("%=") ? OPER_ASSIGNMOD :
 		-1;
 	
-	if (o != -1) {
+	if (o != -1)
 		MustNext ();
-		MustNext ();
-	}
 	
 	return o;
 }
@@ -423,12 +444,12 @@
 		// Command
 		if (reqtype && comm->returnvalue != reqtype)
 			ParserError ("%s returns an incompatible data type", comm->name.chars());
-		return ParseCommand (comm);
+		b = ParseCommand (comm);
 	} else if ((g = FindGlobalVariable (token)) && reqtype != TYPE_STRING) {
 		printf ("value is a global var\n");
 		// Global variable
-		b->Write<byte> (DH_PUSHGLOBALVAR);
-		b->Write<byte> (g->index);
+		b->Write<word> (DH_PUSHGLOBALVAR);
+		b->Write<word> (g->index);
 	} else {
 		printf ("value is a literal\n");
 		// If nothing else, check for literal
@@ -437,22 +458,15 @@
 			ParserError ("bad syntax");
 			break;
 		case TYPE_INT: {
-			printf ("value is an integer literal\n");
-			/* if (!token.isnumber ())
-				ParserError ("expected an integer, got `%s`", token.chars());
-			*/
 			MustNumber (true);
-			printf ("literal is `%s` = %d\n", token.chars(), atoi (token.chars()));
 			
 			// All values are written unsigned - thus we need to write the value's
 			// absolute value, followed by an unary minus if it was negative.
-			b->Write<byte> (DH_PUSHNUMBER);
+			b->Write<word> (DH_PUSHNUMBER);
 			long v = atoi (token.chars ());
-			b->Write<byte> (static_cast<byte> (abs (v)));
-			if (v < 0) {
-				printf ("%ld is negative, write abs value %d and unary minus\n", v, abs(v));
-				b->Write<byte> (DH_UNARYMINUS);
-			}
+			b->Write<word> (static_cast<word> (abs (v)));
+			if (v < 0)
+				b->Write<word> (DH_UNARYMINUS);
 			break;
 		}
 		case TYPE_STRING:
@@ -461,11 +475,45 @@
 			// table and returns it index if it doesn't find it there.
 			printf ("value is a string literal\n");
 			MustString (true);
-			b->Write<byte> (DH_PUSHSTRINGINDEX);
-			b->Write<byte> (PushToStringTable (token.chars()));
+			b->Write<word> (DH_PUSHSTRINGINDEX);
+			b->Write<word> (PushToStringTable (token.chars()));
 			break;
 		}
 	}
+	printf ("value parsed: current token is `%s`\n", token.chars());
 	
 	return b;
+}
+
+// ============================================================================
+// 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.
+DataBuffer* ScriptReader::ParseAssignment (ScriptVar* var) {
+	printf ("ASSIGNMENT: this token is `%s`, next token is `%s`\n",
+		token.chars(), PeekNext().chars());
+	
+	// Get an operator
+	printf ("parse assignment operator at token %s\n", token.chars());
+	
+	MustNext ();
+	int oper = ParseOperator ();
+	if (!IsAssignmentOperator (oper))
+		ParserError ("expected assignment operator");
+	printf ("got %d\n", oper);
+	
+	if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction
+		ParserError ("can't alter variables at top level");
+	
+	// Parse the right operand,
+	printf ("parse right operand\n");
+	MustNext ();
+	DataBuffer* retbuf = ParseExprValue (TYPE_INT);
+	
+	long dh = DataHeaderByOperator (var, oper);
+	retbuf->Write<word> (dh);
+	retbuf->Write<word> (var->index);
+	
+	printf ("assignment complete\n");
+	return retbuf;
 }
\ No newline at end of file

mercurial