Sat, 11 Aug 2012 19:35:47 +0300
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