2012-07-15
Variables can now be assigned values, unfortunately not at top level.
main.cxx | file | annotate | diff | comparison | revisions | |
parser.cxx | file | annotate | diff | comparison | revisions | |
variables.cxx | file | annotate | diff | comparison | revisions | |
variables.h | file | annotate | diff | comparison | revisions |
--- a/main.cxx Sun Jul 15 00:32:26 2012 +0300 +++ b/main.cxx Sun Jul 15 03:24:46 2012 +0300 @@ -106,7 +106,7 @@ printf ("%u global variable%s\n", globalcount, PLURAL (globalcount)); printf ("%d state%s written\n", g_NumStates, PLURAL (g_NumStates)); printf ("%d event%s written\n", g_NumEvents, PLURAL (g_NumEvents)); - printf ("-- %u bytes written to %s\n", w->numWrittenBytes, argv[2]); + printf ("-- %u byte%s written to %s\n", w->numWrittenBytes, PLURAL (w->numWrittenBytes), argv[2]); // Clear out the junk delete r;
--- a/parser.cxx Sun Jul 15 00:32:26 2012 +0300 +++ b/parser.cxx Sun Jul 15 03:24:46 2012 +0300 @@ -74,7 +74,10 @@ fclose (newfile); ScriptReader* newreader = new ScriptReader (token.chars()); newreader->BeginParse (w); - } else if (!token.icompare ("state")) { + continue; + } + + if (!token.icompare ("state")) { MUST_TOPLEVEL MustString (); @@ -107,7 +110,10 @@ g_NumStates++; g_CurState = token; gotMainLoop = false; - } else if (!token.icompare ("event")) { + continue; + } + + if (!token.icompare ("event")) { MUST_TOPLEVEL // Event definition @@ -124,45 +130,51 @@ w->Write (DH_EVENT); w->Write<long> (e->number); g_NumEvents++; - } else if (!token.icompare ("mainloop")) { + continue; + } + + if (!token.icompare ("mainloop")) { MUST_TOPLEVEL MustNext ("{"); g_CurMode = MODE_MAINLOOP; w->Write (DH_MAINLOOP); gotMainLoop = true; - } else if (!token.icompare ("onenter") || !token.icompare ("onexit")) { + continue; + } + + if (!token.icompare ("onenter") || !token.icompare ("onexit")) { MUST_TOPLEVEL bool onenter = !token.compare ("onenter"); MustNext ("{"); g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT; w->Write (onenter ? DH_ONENTER : DH_ONEXIT); - } else if (!token.compare ("int") || !token.compare ("bool")) { + continue; + } + + if (!token.compare ("var")) { // For now, only globals are supported if (g_CurMode != MODE_TOPLEVEL || g_CurState.len()) ParserError ("variables must only be global for now"); - // Variable definition - int type = !token.compare ("int") ? RETURNVAL_INT: RETURNVAL_BOOLEAN; + MustNext (); - MustNext (); + // Var name must not be a number + if (token.isnumber()) + ParserError ("variable name must not be a number"); + str varname = token; - ScriptVar* var = DeclareGlobalVariable (this, varname, type); + ScriptVar* var = DeclareGlobalVariable (this, varname); if (!var) ParserError ("declaring %s variable %s failed", g_CurState.len() ? "state" : "global", varname.chars()); - // Assign it, if desired - if (!PeekNext().compare ("=")) { - MustNext ("="); - MustValue (type); - - var->value = token; - } - MustNext (";"); - } else if (!token.compare ("}")) { + continue; + } + + if (!token.compare ("}")) { // Closing brace int dataheader = (g_CurMode == MODE_EVENT) ? DH_ENDEVENT : (g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP : @@ -177,14 +189,68 @@ g_CurMode = MODE_TOPLEVEL; MustNext (";"); - } else { - // Check if it's a command. - CommandDef* comm = GetCommandByName (token); - if (comm) - ParseCommand (comm, w); - else - ParserError ("unknown keyword `%s`", token.chars()); + continue; } + // Check global variables + ScriptVar* g = FindGlobalVariable (token); + if (g) { + // Not in top level, unfortunately.. + if (g_CurMode == MODE_TOPLEVEL) + ParserError ("can't alter variables at top level"); + + // Only addition for now.. + MustNext (); + + // Build operator string. Only '=' is one + // character, others are two. + str oper = token; + if (token.compare ("=") != 0) { + MustNext (); + oper += token; + } + + // Unary operators + if (!oper.compare ("++")) { + w->Write<long> (DH_INCGLOBALVAR); + w->Write<long> (g->index); + } else if (!oper.compare ("--")) { + w->Write<long> (DH_DECGLOBALVAR); + w->Write<long> (g->index); + } + + // And only with numbers for now too. + // TODO: make a proper expression parser! + MustNumber(); + + int val = atoi (token.chars()); + w->Write<long> (DH_PUSHNUMBER); + w->Write<long> (val); + + int dataheader = !oper.compare("=") ? DH_ASSIGNGLOBALVAR : + !oper.compare("+=") ? DH_ADDGLOBALVAR : + !oper.compare("-=") ? DH_SUBGLOBALVAR : + !oper.compare("*=") ? DH_MULGLOBALVAR : + !oper.compare("/=") ? DH_DIVGLOBALVAR : + !oper.compare("%=") ? DH_MODGLOBALVAR : -1; + + if (dataheader == -1) + ParserError ("bad operator `%s`!", oper.chars()); + + w->Write<long> (dataheader); + w->Write<long> (g->index); + + MustNext (";"); + continue; + } + + // Check if it's a command. + CommandDef* comm = GetCommandByName (token); + if (comm) { + ParseCommand (comm, w); + continue; + } + + ParserError ("unknown keyword `%s`", token.chars()); } if (g_CurMode != MODE_TOPLEVEL) @@ -229,31 +295,40 @@ break; } - /* - if (!Next ()) + if (!PeekNext().len()) ParserError ("unexpected end-of-file, unterminated command"); // If we get a ")" now, the user probably gave too few parameters - if (!token.compare (")")) + if (!PeekNext().compare (")")) ParserError ("unexpected `)`, did you pass too few parameters? (need %d)", comm->numargs); - */ - switch (comm->argtypes[curarg]) { - case RETURNVAL_INT: - MustNumber(); - w->Write<long> (DH_PUSHNUMBER); - w->Write<long> (atoi (token.chars ())); - break; - case RETURNVAL_BOOLEAN: - MustBool(); - w->Write<long> (DH_PUSHNUMBER); - w->Write<long> (BoolValue ()); - break; - case RETURNVAL_STRING: - MustString(); - w->Write<long> (DH_PUSHSTRINGINDEX); - w->Write<long> (PushToStringTable (token.chars())); - break; + // Argument may be using a variable + ScriptVar* g = FindGlobalVariable (PeekNext ()); + if (g && comm->argtypes[curarg] != RETURNVAL_STRING) { + // Advance cursor past the var name + Next(); + + w->Write<long> (DH_PUSHGLOBALVAR); + w->Write<long> (g->index); + } else { + // Check for raw value + switch (comm->argtypes[curarg]) { + case RETURNVAL_INT: + MustNumber(); + w->Write<long> (DH_PUSHNUMBER); + w->Write<long> (atoi (token.chars ())); + break; + case RETURNVAL_BOOLEAN: + MustBool(); + w->Write<long> (DH_PUSHNUMBER); + w->Write<long> (BoolValue ()); + break; + case RETURNVAL_STRING: + MustString(); + w->Write<long> (DH_PUSHSTRINGINDEX); + w->Write<long> (PushToStringTable (token.chars())); + break; + } } if (curarg < comm->numargs - 1) {
--- a/variables.cxx Sun Jul 15 00:32:26 2012 +0300 +++ b/variables.cxx Sun Jul 15 03:24:46 2012 +0300 @@ -61,11 +61,7 @@ // Tries to declare a new global-scope variable. Returns pointer // to new global variable, NULL if declaration failed. -ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name, int type) { - // Apparently the Zandronum engine does not support string variables.. - if (type == RETURNVAL_VOID || type == RETURNVAL_STRING) - return NULL; - +ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name) { // Find a NULL pointer to a global variable ScriptVar* g; unsigned int u = 0; @@ -85,10 +81,8 @@ g->index = u; g->name = name; g->statename = ""; - g->type = type; g->next = NULL; - g->value = (type == RETURNVAL_BOOLEAN) ? "false" : - (type == RETURNVAL_INT) ? "0" : ""; + g->value = 0; g_GlobalVariables[u] = g; return g; @@ -101,17 +95,21 @@ }*/ // Find a global variable by name -/* ScriptVar* FindScriptVariable (str name) { - ScriptVar* g; - ITERATE_SCRIPT_VARS (g) +ScriptVar* FindGlobalVariable (str name) { + unsigned int u = 0; + ITERATE_GLOBAL_VARS (u) { + ScriptVar* g = g_GlobalVariables[u]; + if (!g) + return NULL; + if (!g->name.compare (name)) return g; + } return NULL; -}*/ +} unsigned int CountGlobalVars () { - ScriptVar* var; unsigned int count = 0; unsigned int u = 0; ITERATE_GLOBAL_VARS (u) {
--- a/variables.h Sun Jul 15 00:32:26 2012 +0300 +++ b/variables.h Sun Jul 15 03:24:46 2012 +0300 @@ -44,10 +44,9 @@ #include "scriptreader.h" struct ScriptVar { - int type; str name; str statename; - str value; + int value; unsigned int index; ScriptVar* next; }; @@ -62,8 +61,9 @@ #define ITERATE_SCRIPT_VARS(g) \ for (g = g_ScriptVariable; g != NULL; g = g->next) -ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name, int type); +ScriptVar* DeclareGlobalVariable (ScriptReader* r, str name); unsigned int CountGlobalVars (); void InitVariables (); +ScriptVar* FindGlobalVariable (str name); #endif // __VARIABLES_H__ \ No newline at end of file