Added while loop support. However, script marks keep getting wrong position numbers..

Sat, 11 Aug 2012 19:35:47 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sat, 11 Aug 2012 19:35:47 +0300
changeset 41
47e686c96d8f
parent 40
9e4f785501db
child 42
5cd91fd1526c

Added while loop support. However, script marks keep getting wrong position numbers..

common.h file | annotate | diff | comparison | revisions
databuffer.h file | annotate | diff | comparison | revisions
main.cxx file | annotate | diff | comparison | revisions
objwriter.cxx file | annotate | diff | comparison | revisions
objwriter.h file | annotate | diff | comparison | revisions
parser.cxx file | annotate | diff | comparison | revisions
scriptreader.h file | annotate | diff | comparison | revisions
--- a/common.h	Mon Jul 30 11:34:57 2012 +0300
+++ b/common.h	Sat Aug 11 19:35:47 2012 +0300
@@ -118,6 +118,7 @@
 
 // Byte datatype
 typedef unsigned long int word;
+typedef unsigned char byte;
 
 // Keywords
 #define NUM_KEYWORDS 20
@@ -126,7 +127,7 @@
 #endif
 bool IsKeyword (str s);
 
-// Script mark -- also serves as reference type
+// Script mark and reference
 struct ScriptMark {
 	int type;
 	str name;
@@ -139,21 +140,23 @@
 };
 
 // ====================================================================
+// Generic union
+template <class T> union union_t {
+	T val;
+	byte b[sizeof (T)];
+	char c[sizeof (T)];
+	double d;
+	float f;
+	int i;
+	word w;
+};
+
+// ====================================================================
 // Finds a byte in the given value.
-template <class T> unsigned char GetByteIndex (T a, unsigned int b) {
-	if (b >= sizeof (T))
-		error ("CharByte: tried to get byte %u out of a %u-byte %s\n",
-			b, sizeof (T), typeid (T).name());
-	
-	unsigned long p1 = pow<unsigned long> (256, b);
-	unsigned long p2 = pow<unsigned long> (256, b+1);
-	unsigned long r = (a % p2) / p1;
-	
-	if (r > 256)
-		error ("DataBuffer::CharByte: result %lu too big!", r);
-	
-	unsigned char ur = static_cast<unsigned char> (r);
-	return ur;
+template <class T> inline unsigned char GetByteIndex (T a, unsigned int b) {
+	union_t<T> uni;
+	uni.val = a;
+	return uni.b[b];
 }
 
 #endif // __COMMON_H__
\ No newline at end of file
--- a/databuffer.h	Mon Jul 30 11:34:57 2012 +0300
+++ b/databuffer.h	Sat Aug 11 19:35:47 2012 +0300
@@ -188,6 +188,7 @@
 		m->type = type;
 		m->pos = writesize;
 		marks[u] = m;
+		printf ("add mark %u at %d\n", u, m->pos);
 		return u;
 	}
 	
@@ -233,9 +234,18 @@
 	void MoveMark (unsigned int mark) {
 		if (!marks[mark])
 			return;
+		printf ("move mark %u from %d to %d\n", mark, marks[mark]->pos, writesize);
 		marks[mark]->pos = writesize;
 	}
 	
+	// Adjusts a mark to the current position
+	void OffsetMark (unsigned int mark, size_t offset) {
+		if (!marks[mark])
+			return;
+		printf ("move mark %u from %d to %d\n", mark, marks[mark]->pos, marks[mark]->pos+offset);
+		marks[mark]->pos += offset;
+	}
+	
 	// Dump the buffer (for debugging purposes)
 	void Dump() {
 		for (unsigned int x = 0; x < writesize; x++)
--- a/main.cxx	Mon Jul 30 11:34:57 2012 +0300
+++ b/main.cxx	Sat Aug 11 19:35:47 2012 +0300
@@ -108,7 +108,7 @@
 	printf ("%s\n%s\n", header.chars(), headerline.chars());
 	
 	if (argc < 2) {
-		fprintf (stderr, "usage: %s <infile> [outfile]\n", argv[0]);
+		fprintf (stderr, "usage: %s <infile> [outfile] # compiles botscript\n", argv[0]);
 		fprintf (stderr, "       %s -l                 # lists commands\n", argv[0]);
 		exit (1);
 	}
--- a/objwriter.cxx	Mon Jul 30 11:34:57 2012 +0300
+++ b/objwriter.cxx	Sat Aug 11 19:35:47 2012 +0300
@@ -120,28 +120,34 @@
 	if (sizeof (unsigned char) != 1)
 		error ("size of unsigned char isn't 1, but %d!\n", sizeof (unsigned char));
 	
+	unsigned int refpos = 0;
 	for (unsigned int x = 0; x < MainBuffer->writesize; x++) {
 		// Check if this position is a reference
 		for (unsigned int r = 0; r < MAX_MARKS; r++) {
 			if (MainBuffer->refs[r] && MainBuffer->refs[r]->pos == x) {
-				// All marks need their positions bumped up as the bytecode will gain
-				// 4 more bytes with the written reference. Other references do not
-				// need their positions bumped because they check against mainbuffer
-				// position (x), not written ones.
-				for (unsigned int s = 0; s < MAX_MARKS; s++)
-					if (MainBuffer->marks[s])
-						MainBuffer->marks[s]->pos += sizeof (word);
-				
 				word ref = static_cast<word> (MainBuffer->marks[MainBuffer->refs[r]->num]->pos);
+				printf ("insert reference to mark %d (%ld) refpos = %d\n", MainBuffer->refs[r]->num, ref, refpos);
 				WriteDataToFile<word> (ref);
 				
 				// This reference is now used up - no need to keep it anymore.
 				delete MainBuffer->refs[r];
 				MainBuffer->refs[r] = NULL;
+				
+				// All marks still ahead need their positions bumped up as the bytecode
+				// will gain 4 more bytes with the written reference. Other references
+				// do not need their positions bumped because they check against mainbuffer
+				// position (x), not written ones.
+				for (unsigned int s = 0; s < MAX_MARKS; s++)
+					if (MainBuffer->marks[s] && MainBuffer->marks[s]->pos > refpos) {
+						printf ("mark %u bumped\n", s);
+						MainBuffer->marks[s]->pos += sizeof (word);
+					}
+				refpos += sizeof (word);
 			}
 		}
 		
 		WriteDataToFile<unsigned char> (*(MainBuffer->buffer+x));
+		refpos++;
 	}
 	
 	printf ("-- %u byte%s written to %s\n", numWrittenBytes, PLURAL (numWrittenBytes), filepath.chars());
@@ -185,4 +191,8 @@
 // Deletes a mark
 void ObjWriter::DeleteMark (unsigned int mark) {
 	GetCurrentBuffer()->DeleteMark (mark);
+}
+
+void ObjWriter::OffsetMark (unsigned int mark, int offset) {
+	GetCurrentBuffer()->OffsetMark (mark, offset);
 }
\ No newline at end of file
--- a/objwriter.h	Mon Jul 30 11:34:57 2012 +0300
+++ b/objwriter.h	Sat Aug 11 19:35:47 2012 +0300
@@ -77,6 +77,7 @@
 	unsigned int FindMark (int type, str name);
 	unsigned int AddReference (unsigned int mark);
 	void MoveMark (unsigned int mark);
+	void OffsetMark (unsigned int mark, int offset);
 	void DeleteMark (unsigned int mark);
 	
 	template <class T> void Write (T stuff) {
--- 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
--- a/scriptreader.h	Mon Jul 30 11:34:57 2012 +0300
+++ b/scriptreader.h	Sat Aug 11 19:35:47 2012 +0300
@@ -51,6 +51,17 @@
 
 class ScriptVar;
 
+// ============================================================================
+// Meta-data about blocks
+struct BlockInformation {
+	unsigned int mark1;
+	unsigned int mark2;
+	unsigned int type;
+};
+
+// ============================================================================
+// The script reader reads the script, parses it and tells the object writer
+// the bytecode it needs to write to file.
 class ScriptReader {
 public:
 	// ====================================================================
@@ -62,7 +73,7 @@
 	unsigned int pos[MAX_FILESTACK];
 	unsigned int curline[MAX_FILESTACK];
 	unsigned int curchar[MAX_FILESTACK];
-	unsigned int blockstack[MAX_STRUCTSTACK];
+	BlockInformation blockstack[MAX_STRUCTSTACK];
 	long savedpos[MAX_FILESTACK]; // filepointer cursor position
 	str token;
 	int commentmode;
@@ -99,7 +110,7 @@
 	DataBuffer* ParseAssignment (ScriptVar* var);
 	int ParseOperator (bool peek = false);
 	DataBuffer* ParseExprValue (int reqtype);
-	void AddBlockMark (ObjWriter* w, word dataheader);
+	void PushBlockStack ();
 	
 	// preprocessor.cxx:
 	void PreprocessDirectives ();
@@ -151,4 +162,10 @@
 	MARKTYPE_INTERNAL, // internal structures
 };
 
+// Block types
+enum {
+	BLOCKTYPE_IF,
+	BLOCKTYPE_WHILE
+};
+
 #endif // __SCRIPTREADER_H__
\ No newline at end of file

mercurial