Mon, 30 Jul 2012 03:38:02 +0300
Added if() support
commands.cxx | 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.cxx | file | annotate | diff | comparison | revisions | |
scriptreader.h | file | annotate | diff | comparison | revisions | |
stringtable.cxx | file | annotate | diff | comparison | revisions |
--- a/commands.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/commands.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -122,9 +122,10 @@ if (curarg >= comm->numargs) { r->MustNext ("="); switch (type) { - case RETURNVAL_INT: r->MustNumber(); break; + case RETURNVAL_INT: + case RETURNVAL_BOOLEAN: + r->MustNumber(); break; case RETURNVAL_STRING: r->MustString(); break; - case RETURNVAL_BOOLEAN: r->MustBool(); break; } comm->defvals[curarg] = r->token;
--- a/databuffer.h Sun Jul 29 16:55:32 2012 +0300 +++ b/databuffer.h Mon Jul 30 03:38:02 2012 +0300 @@ -222,6 +222,13 @@ } } } + + // Adjusts a mark to the current position + void MoveMark (unsigned int mark) { + if (!marks[mark]) + return; + marks[mark]->pos = writesize - sizeof (word); + } }; #endif // __DATABUFFER_H__ \ No newline at end of file
--- a/main.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/main.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -64,6 +64,7 @@ "onexit", "var", "goto", + "if", // 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 @@ -76,7 +77,6 @@ "enum", // Would enum actually be useful? I think so. "for", "func", // Would function support need external support from zandronum? - "if", "return", "switch", "while" @@ -169,17 +169,17 @@ // Parse done, print statistics and write to file unsigned int globalcount = CountGlobalVars (); - printf ("%u/%u global variable%s\n", globalcount, MAX_SCRIPT_VARIABLES, PLURAL (globalcount)); + printf ("%u / %u global variable%s\n", globalcount, MAX_SCRIPT_VARIABLES, PLURAL (globalcount)); printf ("%d state%s written\n", g_NumStates, PLURAL (g_NumStates)); printf ("%d event%s written\n", g_NumEvents, PLURAL (g_NumEvents)); w->WriteToFile (); // Clear out the junk - printf ("clear r\n"); delete r; - printf ("clear w\n"); delete w; - printf ("done!\n"); + + // Done! + exit (0); } // ============================================================================
--- a/objwriter.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/objwriter.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -59,16 +59,6 @@ filepath = path; } -ObjWriter::~ObjWriter () { - delete MainBuffer; - delete OnEnterBuffer; - - // This crashes for some reason o_O - // Should make no difference anyway, since ObjWriter - // is only deleted at the end of the program anyway - // delete MainLoopBuffer; -} - void ObjWriter::WriteString (char* s) { Write<long> (strlen (s)); for (unsigned int u = 0; u < strlen (s); u++) @@ -123,7 +113,7 @@ WriteString (g_StringTable[a]); } - printf ("%u string%s written\n", stringcount, PLURAL (stringcount)); + printf ("%u / %u string%s written\n", stringcount, MAX_LIST_STRINGS, PLURAL (stringcount)); } // Write main buffer to file @@ -139,7 +129,19 @@ 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 position %ld at script pos %u\n", + ref, x); WriteDataToFile<word> (ref); + + // This reference is now used up + delete MainBuffer->refs[r]; + MainBuffer->refs[r] = NULL; + + // All other references need their positions bumped up as the + // bytecode gained 4 more bytes with the written reference + for (unsigned int s = 0; s < MAX_MARKS; s++) + if (MainBuffer->refs[s]) + MainBuffer->refs[s]->pos += sizeof (word); } } @@ -177,4 +179,9 @@ return u; } return MAX_MARKS; +} + +// Moves a mark to the current position +void ObjWriter::MoveMark (unsigned int mark) { + GetCurrentBuffer()->MoveMark (mark); } \ No newline at end of file
--- a/objwriter.h Sun Jul 29 16:55:32 2012 +0300 +++ b/objwriter.h Mon Jul 30 03:38:02 2012 +0300 @@ -64,7 +64,6 @@ // ==================================================================== // METHODS ObjWriter (str path); - ~ObjWriter (); void WriteString (char* s); void WriteString (const char* s); void WriteString (str s); @@ -77,6 +76,7 @@ unsigned int AddMark (int type, str name); unsigned int FindMark (int type, str name); unsigned int AddReference (unsigned int mark); + void MoveMark (unsigned int mark); template <class T> void Write (T stuff) { DataBuffer* buffer = GetCurrentBuffer ();
--- a/parser.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/parser.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -63,14 +63,14 @@ str g_CurState = ""; bool g_stateSpawnDefined = false; bool g_GotMainLoop = false; -int g_StructStack = 0; +unsigned int g_BlockStackCursor = 0; // ============================================================================ // 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) { - g_StructStack = 0; + g_BlockStackCursor = 0; while (Next()) { printf ("BeginParse: token: `%s`\n", token.chars()); if (!token.icompare ("state")) { @@ -202,15 +202,53 @@ continue; } + // If + if (!token.icompare ("if")) { + // Condition + MustNext ("("); + + // Read the expression and write it. + MustNext (); + DataBuffer* c = ParseExpression (TYPE_INT); + w->WriteBuffer (c); + delete c; + + 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. + w->Write<word> (DH_IFNOTGOTO); + w->AddReference (marknum); + + // Store it in the block stack + blockstack[g_BlockStackCursor] = marknum; + g_BlockStackCursor++; + continue; + } + if (!token.compare ("}")) { - // If this was done inside the struct stack (i.e. - // inside "if" for instance), it does not end the mode. - if (g_StructStack > 0) { - g_StructStack--; + // Closing brace + + // 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) { + // printf ("\tblock %d stack mark moved from %d ", + g_BlockStackCursor, w->GetCurrentBuffer()->marks[marknum]->pos); + w->MoveMark (marknum); + // printf ("to %d\n", w->GetCurrentBuffer()->marks[marknum]->pos); + } + + g_BlockStackCursor--; continue; } - // Closing brace int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : (g_CurMode == MODE_ONENTER) ? DH_ENDONENTER : @@ -367,6 +405,12 @@ case OPER_MULTIPLY: return DH_MULTIPLY; case OPER_DIVIDE: return DH_DIVIDE; case OPER_MODULUS: return DH_MODULUS; + case OPER_EQUALS: return DH_EQUALS; + case OPER_NOTEQUALS: return DH_NOTEQUALS; + case OPER_LESSTHAN: return DH_LESSTHAN; + case OPER_GREATERTHAN: return DH_GREATERTHAN; + case OPER_LESSTHANEQUALS: return DH_LESSTHANEQUALS; + case OPER_GREATERTHANEQUALS: return DH_GREATERTHANEQUALS; } error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper); @@ -431,7 +475,12 @@ oper += token; // Check one-char operators - int o = !oper.compare ("=") ? OPER_ASSIGN : + bool equalsnext = !PeekNext (peek ? 1 : 0).compare ("="); + printf ("operator one-char: %s\nequals is%s next (`%s`)\n", oper.chars(), + (equalsnext) ? "" : " not", PeekNext (peek ? 1 : 0).chars()); + int o = (!oper.compare ("=") && !equalsnext) ? OPER_ASSIGN : + (!oper.compare (">") && !equalsnext) ? OPER_GREATERTHAN : + (!oper.compare ("<") && !equalsnext) ? OPER_LESSTHAN : !oper.compare ("+") ? OPER_ADD : !oper.compare ("-") ? OPER_SUBTRACT : !oper.compare ("*") ? OPER_MULTIPLY : @@ -446,11 +495,17 @@ // Two-char operators oper += PeekNext (peek ? 1 : 0); + printf ("operator two-char: %s\n", oper.chars()); + o = !oper.compare ("+=") ? OPER_ASSIGNADD : !oper.compare ("-=") ? OPER_ASSIGNSUB : !oper.compare ("*=") ? OPER_ASSIGNMUL : !oper.compare ("/=") ? OPER_ASSIGNDIV : !oper.compare ("%=") ? OPER_ASSIGNMOD : + !oper.compare ("==") ? OPER_EQUALS : + !oper.compare ("!=") ? OPER_NOTEQUALS : + !oper.compare (">=") ? OPER_GREATERTHANEQUALS : + !oper.compare ("<=") ? OPER_LESSTHANEQUALS : -1; if (o != -1) @@ -502,6 +557,7 @@ // 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<word> (DH_PUSHNUMBER); + long v = atoi (token.chars ()); b->Write<word> (static_cast<word> (abs (v))); if (v < 0)
--- a/scriptreader.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/scriptreader.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -45,6 +45,7 @@ #include "common.h" #include "scriptreader.h" +// ============================================================================ ScriptReader::ScriptReader (str path) { token = ""; prevtoken = ""; @@ -58,6 +59,7 @@ commentmode = 0; } +// ============================================================================ ScriptReader::~ScriptReader () { // If comment mode is 2 by the time the file ended, the // comment was left unterminated. 1 is no problem, since @@ -73,6 +75,7 @@ } } +// ============================================================================ // Opens a file and pushes its pointer to stack void ScriptReader::OpenFile (str path) { if (fc+1 >= MAX_FILESTACK) @@ -100,9 +103,11 @@ atnewline = 0; } +// ============================================================================ +// Closes the current file void ScriptReader::CloseFile (unsigned int u) { if (u >= MAX_FILESTACK) - u = fc; + u = fc; if (!fp[u]) return; @@ -115,6 +120,7 @@ fseek (fp[fc], savedpos[fc], SEEK_SET); } +// ============================================================================ char ScriptReader::ReadChar () { if (feof (fp[fc])) return 0; @@ -141,6 +147,8 @@ return c[0]; } +// ============================================================================ +// Peeks the next character char ScriptReader::PeekChar (int offset) { // Store current position long curpos = ftell (fp[fc]); @@ -162,6 +170,7 @@ return c[0]; } +// ============================================================================ // Read a token from the file buffer. Returns true if token was found, false if not. bool ScriptReader::Next (bool peek) { prevpos = ftell (fp[fc]); @@ -252,15 +261,7 @@ return true; } -void ScriptReader::Prev () { - if (!prevpos) - error ("ScriptReader::Prev: cannot go back twice!\n"); - - fseek (fp[fc], prevpos, SEEK_SET); - prevpos = 0; - token = prevtoken; -} - +// ============================================================================ // Returns the next token without advancing the cursor. str ScriptReader::PeekNext (int offset) { // Store current information @@ -283,6 +284,7 @@ return tmp; } +// ============================================================================ void ScriptReader::Seek (unsigned int n, int origin) { switch (origin) { case SEEK_SET: @@ -300,6 +302,7 @@ Next(); } +// ============================================================================ void ScriptReader::MustNext (const char* c) { if (!Next()) { if (strlen (c)) @@ -312,22 +315,26 @@ MustThis (c); } +// ============================================================================ void ScriptReader::MustThis (const char* c) { if (token.compare (c) != 0) ParserError ("expected `%s`, got `%s` instead", c, token.chars()); } +// ============================================================================ void ScriptReader::ParserError (const char* message, ...) { PERFORM_FORMAT (message, outmessage); ParserMessage ("\nError: ", outmessage); exit (1); } +// ============================================================================ void ScriptReader::ParserWarning (const char* message, ...) { PERFORM_FORMAT (message, outmessage); ParserMessage ("Warning: ", outmessage); } +// ============================================================================ void ScriptReader::ParserMessage (const char* header, char* message) { if (fc >= 0 && fc < MAX_FILESTACK) fprintf (stderr, "%sIn file %s, at line %u, col %u: %s\n", @@ -336,6 +343,7 @@ fprintf (stderr, "%s%s\n", header, message); } +// ============================================================================ // if gotquote == 1, the current token already holds the quotation mark. void ScriptReader::MustString (bool gotquote) { if (gotquote) @@ -360,6 +368,7 @@ token = string; } +// ============================================================================ void ScriptReader::MustNumber (bool fromthis) { str num; if (!fromthis) @@ -374,33 +383,14 @@ num += token; } - // Result must be a number. - if (!num.isnumber()) - ParserError ("expected a number, got `%s`", num.chars()); - - // Save the number into the token. - token = num; -} - -void ScriptReader::MustBool () { - MustNext(); - if (!token.compare ("0") || !token.compare ("1") || - !token.compare ("true") || !token.compare ("false") || - !token.compare ("yes") || !token.compare ("no")) { - return; - } - - ParserError ("expected a boolean value, got `%s`", token.chars()); -} - -bool ScriptReader::BoolValue () { - return (!token.compare ("1") || !token.compare ("true") || !token.compare ("yes")); -} - -void ScriptReader::MustValue (int type) { - switch (type) { - case RETURNVAL_INT: MustNumber (); break; - case RETURNVAL_STRING: MustString (); break; - case RETURNVAL_BOOLEAN: MustBool (); break; + // "true" and "false" are valid numbers + if (!token.icompare ("true")) + token = "1"; + else if (!token.icompare ("false")) + token = "0"; + else { + if (!num.isnumber()) + ParserError ("expected a number, got `%s`", num.chars()); + token = num; } } \ No newline at end of file
--- a/scriptreader.h Sun Jul 29 16:55:32 2012 +0300 +++ b/scriptreader.h Mon Jul 30 03:38:02 2012 +0300 @@ -47,6 +47,7 @@ #include "commands.h" #define MAX_FILESTACK 8 +#define MAX_STRUCTSTACK 32 class ScriptVar; @@ -61,6 +62,7 @@ unsigned int pos[MAX_FILESTACK]; unsigned int curline[MAX_FILESTACK]; unsigned int curchar[MAX_FILESTACK]; + unsigned int blockstack[MAX_STRUCTSTACK]; long savedpos[MAX_FILESTACK]; // filepointer cursor position str token; int commentmode; @@ -85,7 +87,6 @@ void MustString (bool gotquote = false); void MustNumber (bool fromthis = false); void MustBool (); - void MustValue (int type); bool BoolValue (); void ParserError (const char* message, ...); @@ -133,7 +134,13 @@ OPER_ASSIGNSUB, OPER_ASSIGNMUL, OPER_ASSIGNDIV, - OPER_ASSIGNMOD + OPER_ASSIGNMOD, // -- 10 + OPER_EQUALS, + OPER_NOTEQUALS, + OPER_LESSTHAN, + OPER_GREATERTHAN, + OPER_LESSTHANEQUALS, + OPER_GREATERTHANEQUALS, }; // Mark types
--- a/stringtable.cxx Sun Jul 29 16:55:32 2012 +0300 +++ b/stringtable.cxx Mon Jul 30 03:38:02 2012 +0300 @@ -58,6 +58,10 @@ // ============================================================================ // Potentially adds a string to the table and returns the index of it. unsigned int PushToStringTable (char* s) { + // Must not be too long. + if (strlen (s) >= MAX_STRING_LENGTH) + error ("string `%s` too long (%d characters max)\n", s, strlen (s)); + // Find a free slot in the table. unsigned int a; for (a = 0; a < MAX_LIST_STRINGS; a++) { @@ -72,7 +76,7 @@ // no free slots! if (a == MAX_LIST_STRINGS) - error ("too many strings defined!"); + error ("too many strings defined!\n"); // Determine the length size_t l1 = strlen (s);