From bf323c3f0af6f904501baf1e856a9c0a68227063 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Wed, 24 Apr 2002 22:33:04 +0000 Subject: [PATCH] Cleaned up Cmd_Args. It is no longer uselessly built up in Cmd_TokenizeString since I realized the code was just pulling it apart and putting it back together. Added Cmd_Argsu to access the unprocessed command. Added support for else following if in such a way that if/else if/else structures work. Added support for unary operators in EXP and added the ! (not) operator. The ifnot command will be kept for variety. --- include/QF/cmd.h | 1 + include/QF/exp.h | 1 + include/QF/ops.h | 1 + libs/util/cmd.c | 52 +++++++++++++++++------ libs/util/exp.c | 108 ++++++++++++++++++++++++++++++----------------- libs/util/ops.c | 5 +++ 6 files changed, 115 insertions(+), 53 deletions(-) diff --git a/include/QF/cmd.h b/include/QF/cmd.h index a37b785e6..e3921d5e4 100644 --- a/include/QF/cmd.h +++ b/include/QF/cmd.h @@ -58,6 +58,7 @@ typedef struct cmd_buffer_s { struct dstring_s *looptext; // If a looping buffer, the text we are looping on struct dstring_s *retval; // Return value unsigned int *args; // Array of positions of each token in composite line + unsigned int *argsu; // Array of positions of each token in original line struct hashtab_s *locals; // Local variables // Flags diff --git a/include/QF/exp.h b/include/QF/exp.h index ff6fee377..260730050 100644 --- a/include/QF/exp.h +++ b/include/QF/exp.h @@ -59,6 +59,7 @@ typedef struct optable_s { char *str; opfunc func; + unsigned int operands; } optable_t; extern exp_error_t EXP_ERROR; diff --git a/include/QF/ops.h b/include/QF/ops.h index 87e407b48..2b3cfef44 100644 --- a/include/QF/ops.h +++ b/include/QF/ops.h @@ -22,6 +22,7 @@ #ifndef __ops_h #define __ops_h +float OP_Not (float op1, float op2); float OP_Add (float op1, float op2); float OP_Sub (float op1, float op2); float OP_Mult (float op1, float op2); diff --git a/libs/util/cmd.c b/libs/util/cmd.c index 9eeaa3ef2..0b2188220 100644 --- a/libs/util/cmd.c +++ b/libs/util/cmd.c @@ -854,6 +854,13 @@ Cmd_Args (int start) return cmd_activebuffer->line->str + cmd_activebuffer->args[start]; } +const char * +Cmd_Argsu (int start) +{ + if (start >= cmd_activebuffer->argc) + return ""; + return cmd_activebuffer->realline->str + cmd_activebuffer->argsu[start]; +} int Cmd_EndDoubleQuote (const char *str) @@ -1371,7 +1378,7 @@ Cmd_Process (void) cmd_activebuffer->args[arg] += adj; adj += (str->size - 1) - (org->size - 1); dstring_replace (cmd_activebuffer->line, str->str, str->size - 1, - cmd_activebuffer->args[arg] + quotes, org->size - 1); + cmd_activebuffer->args[arg] + quotes + (cmd_activebuffer->argv[arg]->delim == '{'), org->size - 1); } return 0; } @@ -1387,6 +1394,8 @@ Cmd_TokenizeString (const char *text, qboolean legacy) dstring_clearstr (cmd_activebuffer->realline); dstring_appendstr (cmd_activebuffer->realline, text); + dstring_clearstr (cmd_activebuffer->line); + dstring_appendstr (cmd_activebuffer->line, text); /* Turn off tags at the beginning of a command. This causes tags to continue past token boundaries. */ @@ -1394,7 +1403,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy) tag_special = 0; if (text[0] == '|') str++; - dstring_clearstr (cmd_activebuffer->line); while (strlen (str + i)) { if (!legacy && cmd_argc == 1) { // See if command wants unprocessed tokens cmd = (cmd_function_t *) Hash_Find (cmd_hash, cmd_activebuffer->argv[0]->original->str); @@ -1406,8 +1414,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy) i++; space++; } - if (space) - dstring_appendsubstr (cmd_activebuffer->line, str + i - space, space); len = Cmd_GetToken (str + i, legacy); if (len < 0) { Cmd_Error ("Parse error: Unmatched quotes, braces, or " @@ -1421,7 +1427,10 @@ Cmd_TokenizeString (const char *text, qboolean legacy) cmd_activebuffer->argv = realloc (cmd_activebuffer->argv, sizeof (cmd_token_t *) * cmd_argc); SYS_CHECKMEM (cmd_activebuffer->argv); - + cmd_activebuffer->argsu = realloc (cmd_activebuffer->argsu, + sizeof (int) * cmd_argc); + SYS_CHECKMEM (cmd_activebuffer->argsu); + cmd_activebuffer->args = realloc (cmd_activebuffer->args, sizeof (int) * cmd_argc); SYS_CHECKMEM (cmd_activebuffer->args); @@ -1434,6 +1443,7 @@ Cmd_TokenizeString (const char *text, qboolean legacy) /* Remove surrounding quotes or double quotes or braces */ quotes = 0; braces = 0; + cmd_activebuffer->argsu[cmd_argc - 1] = i; cmd_activebuffer->args[cmd_argc - 1] = i; cmd_activebuffer->argv[cmd_argc - 1]->delim = ' '; if ((!legacy && str[i] == '\'' && str[i + len] == '\'') @@ -1443,8 +1453,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy) len -= 1; quotes = 1; } - dstring_appendsubstr (cmd_activebuffer->line, - str + i - quotes, len + quotes * 2); if (str[i] == '{' && str[i + len] == '}') { i++; len -= 1; @@ -1456,9 +1464,9 @@ Cmd_TokenizeString (const char *text, qboolean legacy) if (!legacy && !braces && process && text[0] != '|') cmd_activebuffer->argv[cmd_argc-1]->state = cmd_process; else - cmd_activebuffer->argv[cmd_argc-1]->state = cmd_original; + cmd_activebuffer->argv[cmd_argc-1]->state = cmd_original; cmd_activebuffer->argv[cmd_argc-1]->pos = 0; - cmd_activebuffer->argv[cmd_argc-1]->space = space; + cmd_activebuffer->argv[cmd_argc-1]->space = space; i += len + quotes + braces; /* If we ended on a quote or brace, skip it */ } @@ -1893,18 +1901,33 @@ Cmd_If_f (void) { long int num; - if (Cmd_Argc () < 3) { - Sys_Printf ("Usage: if {condition} {commands}\n"); + if ((Cmd_Argc () !=3 && !(Cmd_Argc () >= 5)) || (Cmd_Argc () > 5 && strcmp(Cmd_Argv(3),"else"))) { + Sys_Printf ("Usage: if {condition} {commands} else {commands}\n"); return; } - + + /* HACK HACK HACK + If is set as a pure command, but it needs the first argument + to be evaluated. Normally this would mean Cmd_Args is out + of sync, but since if uses Cmd_Argsu (4) and no other commands + will need these tokens, it is safe. + */ + if (Cmd_ProcessToken (cmd_activebuffer->argv[1]) < 0) + return; + cmd_activebuffer->argv[1]->state = cmd_done; + num = strtol (Cmd_Argv(1), 0, 10); - + if (!strcmp(Cmd_Argv(0), "ifnot")) num = !num; - + if (num) Cbuf_InsertText (Cmd_Argv (2)); + if (!num && Cmd_Argc() == 5) + Cbuf_InsertText (Cmd_Argv (4)); + if (!num && Cmd_Argc() > 5) { + Cbuf_InsertText (Cmd_Argsu (4)); + } return; } @@ -2116,6 +2139,7 @@ Cmd_Init (void) "variable"); Cmd_AddCommand ("if", Cmd_If_f, "Conditionally execute a set of commands."); + Cmd_SetPure ("if"); Cmd_AddCommand ("ifnot", Cmd_If_f, "Conditionally execute a set of commands if the condition is false."); Cmd_AddCommand ("while", Cmd_While_f, "Execute a set of commands while a condition is true."); Cmd_SetPure ("while"); diff --git a/libs/util/exp.c b/libs/util/exp.c index 6f8abdc8e..4d5378275 100644 --- a/libs/util/exp.c +++ b/libs/util/exp.c @@ -32,19 +32,22 @@ exp_error_t EXP_ERROR; optable_t optable[] = { - {"**", OP_Exp}, - {"/", OP_Div}, - {"*", OP_Mult}, - {"+", OP_Add}, - {"-", OP_Sub}, - {"==", OP_Eq}, - {"!=", OP_Neq}, - {">=", OP_GreaterThanEqual}, - {">", OP_GreaterThan}, - {"<=", OP_LessThanEqual}, - {"<", OP_LessThan}, - {"||", OP_Or}, - {"&&", OP_And}, + {"!", OP_Not, 1}, + {"**", OP_Exp, 2}, + {"/", OP_Div, 2}, + {"*", OP_Mult, 2}, + {"+", OP_Add, 2}, + {"-", OP_Sub, 2}, + {"==", OP_Eq, 2}, + {"!=", OP_Neq, 2}, + {">=", OP_GreaterThanEqual, 2}, + {">", OP_GreaterThan, 2}, + {"<=", OP_LessThanEqual, 2}, + {"<", OP_LessThan, 2}, + {"||", OP_Or, 2}, + {"or", OP_Or, 2}, + {"&&", OP_And, 2}, + {"and", OP_And, 2}, {"", 0} }; @@ -60,13 +63,34 @@ token *EXP_NewToken (void) return new; } +int EXP_FindIndexByFunc (opfunc func) +{ + int i; + for (i = 0; optable[i].func; i++) + if (func == optable[i].func) + return i; + return -1; +} + +int EXP_FindIndexByStr (const char *str) +{ + int i, len, fi; + + for (i = 0, len = 0, fi = -1; optable[i].func; i++) + if (!strncmp(str, optable[i].str, strlen(optable[i].str)) && strlen(optable[i].str) > len) { + len = strlen(optable[i].str); + fi = i; + } + return fi; +} + token *EXP_ParseString (char *str) { char buf[256]; - + token *chain, *new, *cur; - int i,n,m; - + int i,m,fi; + cur = chain = EXP_NewToken(); chain->generic.type = TOKEN_OPAREN; chain->generic.prev = 0; @@ -75,8 +99,10 @@ token *EXP_ParseString (char *str) for (i = 0; i < strlen(str); i++) { m = 0; - while(str[i] == ' ') + while(isspace((byte)str[i])) i++; + if (!str[i]) + break; if (isdigit((byte)str[i]) || str[i] == '.') { while ((isdigit((byte)str[i]) || str[i] == '.') && i < strlen(str) && m < 256) @@ -111,27 +137,23 @@ token *EXP_ParseString (char *str) } else { - while(!(isdigit((byte)str[i])) && str[i] != '.' && str[i] != '(' && str[i] != ')' && m < 256) - buf[m++] = str[i++]; + while(!(isdigit((byte)str[i])) && !isspace((byte)str[i]) && str[i] != '.' && str[i] != '(' && str[i] != ')' && m < 256) { + buf[m++] = str[i++]; + } buf[m] = 0; if (m) { - for (n = 0; optable[n].func; n++) - { - if (!(strncmp(optable[n].str, buf, strlen(optable[n].str)))) - { - i -= (m - strlen(optable[n].str) + 1); - new = EXP_NewToken(); - new->generic.type = TOKEN_OP; - new->op.func = optable[n].func; - new->generic.prev = cur; - new->generic.next = 0; - cur->generic.next = new; - cur = new; - break; - } - } - if (!(optable[n].func)) { + fi = EXP_FindIndexByStr (buf); + if (fi != -1) { + i -= (m - strlen(optable[fi].str) + 1); + new = EXP_NewToken(); + new->generic.type = TOKEN_OP; + new->op.func = optable[fi].func; + new->generic.prev = cur; + new->generic.next = 0; + cur->generic.next = new; + cur = new; + } else { EXP_DestroyTokens (chain); return 0; } @@ -172,8 +194,14 @@ void EXP_SimplifyTokens (token *chain) { for (cur = chain->generic.next; cur->generic.type != TOKEN_CPAREN; cur = cur->generic.next) { - if (cur->generic.type == TOKEN_OP && cur->op.func == optable[i].func && cur->generic.next) - if (cur->generic.prev->generic.type == TOKEN_NUM && cur->generic.next->generic.type == TOKEN_NUM) + if (cur->generic.type == TOKEN_OP && cur->op.func == optable[i].func && cur->generic.next) { + if (optable[i].operands == 1 && cur->generic.next->generic.type == TOKEN_NUM) { + cur->generic.next->num.value = optable[i].func(cur->generic.next->num.value, 0); + temp = cur; + cur = cur->generic.next; + EXP_RemoveToken(temp); + } + else if (cur->generic.prev->generic.type == TOKEN_NUM && cur->generic.next->generic.type == TOKEN_NUM) { cur->generic.prev->num.value = optable[i].func(cur->generic.prev->num.value, cur->generic.next->num.value); temp = cur; @@ -181,6 +209,7 @@ void EXP_SimplifyTokens (token *chain) EXP_RemoveToken(temp->generic.next); EXP_RemoveToken(temp); } + } } } } @@ -243,7 +272,7 @@ exp_error_t EXP_Validate (token *chain) { token *cur, *new; int paren = 0; - + for (cur = chain; cur->generic.next; cur = cur->generic.next) { if (cur->generic.type == TOKEN_OPAREN) @@ -273,7 +302,7 @@ exp_error_t EXP_Validate (token *chain) new->op.func = OP_Mult; EXP_InsertTokenAfter (cur, new); } - else + else if (optable[EXP_FindIndexByFunc(cur->generic.next->op.func)].operands == 2) return EXP_E_SYNTAX; /* Operator misuse */ } else if (cur->generic.type == TOKEN_OP && cur->generic.next->generic.type == TOKEN_CPAREN) @@ -312,4 +341,5 @@ void EXP_PrintTokens (token *chain) case TOKEN_GENERIC: break; } + printf("\n"); } diff --git a/libs/util/ops.c b/libs/util/ops.c index e7951b28d..9279f6e4f 100644 --- a/libs/util/ops.c +++ b/libs/util/ops.c @@ -21,6 +21,11 @@ #include +float OP_Not (float op1, float op2) +{ + return !op1; +} + float OP_Add (float op1, float op2) { return op1 + op2;