Sun, 12 Aug 2012 01:52:42 +0300
FINALLY, marks and references work smoothly without hacks. if and while work properly.
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 |
--- a/common.h Sat Aug 11 19:35:47 2012 +0300 +++ b/common.h Sun Aug 12 01:52:42 2012 +0300 @@ -43,7 +43,8 @@ #include <stdio.h> #include <stdarg.h> -#include <typeinfo> +#include <typeinfo> +#include <stdint.h> #include "bots.h" #include "str.h" @@ -117,15 +118,17 @@ } // Byte datatype -typedef unsigned long int word; -typedef unsigned char byte; +// typedef unsigned long int word; +typedef int32_t word; +typedef uint8_t byte; // Keywords -#define NUM_KEYWORDS 20 #ifndef __MAIN_CXX__ extern const char** g_Keywords; #endif + bool IsKeyword (str s); +unsigned int NumKeywords (); // Script mark and reference struct ScriptMark {
--- a/databuffer.h Sat Aug 11 19:35:47 2012 +0300 +++ b/databuffer.h Sun Aug 12 01:52:42 2012 +0300 @@ -97,37 +97,36 @@ // ==================================================================== // Write stuff to the buffer - template<class T> void Write(T stuff) { - if (sizeof (char) != 1) { - error ("DataBuffer: sizeof(char) must be 1!\n"); - } - - // Out of space, must resize - if (writesize + sizeof(T) >= allocsize) { - // First, store the old buffer temporarily + template<class T> void Write (T stuff) { + if (writesize + sizeof (T) >= allocsize) { + // We don't have enough space in the buffer to write + // the stuff - thus resize. First, store the old + // buffer temporarily: char* copy = new char[allocsize]; memcpy (copy, buffer, allocsize); - // Remake the buffer with the new size. - // Have a bit of leeway so we don't have to - // resize immediately again. + // Remake the buffer with the new size. Have enough space + // for the stuff we're going to write, as well as a bit + // of leeway so we don't have to resize immediately again. size_t newsize = allocsize + sizeof (T) + 128; delete buffer; buffer = new unsigned char[newsize]; allocsize = newsize; - // Now, copy the new stuff over. + // Now, copy the stuff back. memcpy (buffer, copy, allocsize); - - // Nuke the copy now as it's no longer needed delete copy; } - // Write the new stuff one byte at a time + // Buffer is now guaranteed to have enough space. + // Write the stuff one byte at a time. + union_t<T> uni; + uni.val = stuff; for (unsigned int x = 0; x < sizeof (T); x++) { - if (writesize >= allocsize) + if (writesize >= allocsize) // should NEVER happen because resizing is done above error ("DataBuffer: written size exceeds allocated size!\n"); - buffer[writesize] = GetByteIndex<T> (stuff, x); + + buffer[writesize] = uni.b[x]; writesize++; } } @@ -169,7 +168,7 @@ } // ==================================================================== - // Adds a mark to the buffer. A mark is a reference to a particular + // Adds a mark to the buffer. A mark is a "pointer" to a particular // position in the bytecode. The actual permanent position cannot // be predicted in any way or form, thus these things will be used // to "mark" a position like that for future use. @@ -188,10 +187,13 @@ m->type = type; m->pos = writesize; marks[u] = m; - printf ("add mark %u at %d\n", u, m->pos); return u; } + // ==================================================================== + // A ref is another "mark" that references a mark. When the bytecode + // is written to file, they are changed into their marks' current + // positions. Marks themselves are never written to files, only refs are unsigned int AddMarkReference (unsigned int marknum) { unsigned int u; for (u = 0; u < MAX_MARKS; u++) @@ -204,11 +206,15 @@ // NOTE: Do not check if the mark actually exists here since a // reference may come in the code earlier than the actual mark // and the new mark number can be predicted. + // 11/8/12: eh? The mark is always created first. ScriptMarkReference* r = new ScriptMarkReference; r->num = marknum; r->pos = writesize; refs[u] = r; + // Write a dummy placeholder for the reference + Write<word> (1234); + return u; } @@ -231,18 +237,15 @@ } // Adjusts a mark to the current position - void MoveMark (unsigned int mark) { + void MoveMark (unsigned int mark, int offset = -1) { 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; }
--- a/main.cxx Sat Aug 11 19:35:47 2012 +0300 +++ b/main.cxx Sun Aug 12 01:52:42 2012 +0300 @@ -56,7 +56,7 @@ #include "bots.h" #include "botcommands.h" -const char* g_Keywords[NUM_KEYWORDS] = { +const char* g_Keywords[] = { "state", "event", "mainloop", @@ -65,6 +65,7 @@ "var", "goto", "if", + "while", // These ones aren't implemented yet but I plan to do so, thus they are // reserved. Also serves as a to-do list of sorts for me. >:F @@ -79,7 +80,6 @@ "func", // Would function support need external support from zandronum? "return", "switch", - "while" }; int main (int argc, char** argv) { @@ -116,7 +116,7 @@ // A word should always be exactly 4 bytes. The above list command // doesn't need it, but the rest of the program does. if (sizeof (word) != 4) - error ("%s expects a word (unsigned long int) to be 4 bytes in size, is %d\n", + error ("%s expects a word (uint32_t) to be 4 bytes in size, is %d\n", APPNAME, sizeof (word)); str outfile; @@ -218,8 +218,12 @@ // ============================================================================ // Is the given argument a reserved keyword? bool IsKeyword (str s) { - for (unsigned int u = 0; u < NUM_KEYWORDS; u++) + for (unsigned int u = 0; u < NumKeywords (); u++) if (!s.icompare (g_Keywords[u])) return true; return false; +} + +unsigned int NumKeywords () { + return sizeof (g_Keywords) / sizeof (const char*); } \ No newline at end of file
--- a/objwriter.cxx Sat Aug 11 19:35:47 2012 +0300 +++ b/objwriter.cxx Sun Aug 12 01:52:42 2012 +0300 @@ -120,35 +120,22 @@ 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) { - 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); - } + // First, resolve references + for (unsigned int u = 0; u < MAX_MARKS; u++) { + ScriptMarkReference* ref = MainBuffer->refs[u]; + if (!ref) + continue; + + for (unsigned int v = 0; v < sizeof (word); v++) { + union_t<word> uni; + uni.val = static_cast<word> (MainBuffer->marks[ref->num]->pos); + memset (MainBuffer->buffer + ref->pos + v, uni.b[v], 1); } - + } + + // Then, dump the main buffer to the file + for (unsigned int x = 0; x < MainBuffer->writesize; x++) WriteDataToFile<unsigned char> (*(MainBuffer->buffer+x)); - refpos++; - } printf ("-- %u byte%s written to %s\n", numWrittenBytes, PLURAL (numWrittenBytes), filepath.chars()); fclose (fp);
--- a/objwriter.h Sat Aug 11 19:35:47 2012 +0300 +++ b/objwriter.h Sun Aug 12 01:52:42 2012 +0300 @@ -86,14 +86,17 @@ return; } - // Cannot use default arguments in function templates.. - void Write (word stuff) {Write<word> (stuff);} + // Default to word + void Write (word stuff) { + Write<word> (stuff); + } template <class T> void WriteDataToFile (T stuff) { // One byte at a time for (unsigned int x = 0; x < sizeof (T); x++) { - unsigned char c = GetByteIndex<T> (stuff, x); - fwrite (&c, 1, 1, fp); + union_t<T> uni; + uni.val = stuff; + fwrite (&uni.b[x], 1, 1, fp); numWrittenBytes++; } }
--- a/parser.cxx Sat Aug 11 19:35:47 2012 +0300 +++ b/parser.cxx Sun Aug 12 01:52:42 2012 +0300 @@ -238,7 +238,6 @@ // While if (!token.compare ("while")) { - printf ("begin while loop\n"); MUST_NOT_TOPLEVEL PushBlockStack (); @@ -279,22 +278,16 @@ 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 @@ -624,9 +617,9 @@ } void ScriptReader::PushBlockStack () { + g_BlockStackCursor++; BlockInformation* info = &blockstack[g_BlockStackCursor]; info->type = 0; info->mark1 = 0; info->mark2 = 0; - g_BlockStackCursor++; } \ No newline at end of file