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.
This commit is contained in:
Brian Koropoff 2002-04-24 22:33:04 +00:00
parent e4975cd675
commit bf323c3f0a
6 changed files with 115 additions and 53 deletions

View file

@ -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 *looptext; // If a looping buffer, the text we are looping on
struct dstring_s *retval; // Return value struct dstring_s *retval; // Return value
unsigned int *args; // Array of positions of each token in composite line 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 struct hashtab_s *locals; // Local variables
// Flags // Flags

View file

@ -59,6 +59,7 @@ typedef struct optable_s
{ {
char *str; char *str;
opfunc func; opfunc func;
unsigned int operands;
} optable_t; } optable_t;
extern exp_error_t EXP_ERROR; extern exp_error_t EXP_ERROR;

View file

@ -22,6 +22,7 @@
#ifndef __ops_h #ifndef __ops_h
#define __ops_h #define __ops_h
float OP_Not (float op1, float op2);
float OP_Add (float op1, float op2); float OP_Add (float op1, float op2);
float OP_Sub (float op1, float op2); float OP_Sub (float op1, float op2);
float OP_Mult (float op1, float op2); float OP_Mult (float op1, float op2);

View file

@ -854,6 +854,13 @@ Cmd_Args (int start)
return cmd_activebuffer->line->str + cmd_activebuffer->args[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 int
Cmd_EndDoubleQuote (const char *str) Cmd_EndDoubleQuote (const char *str)
@ -1371,7 +1378,7 @@ Cmd_Process (void)
cmd_activebuffer->args[arg] += adj; cmd_activebuffer->args[arg] += adj;
adj += (str->size - 1) - (org->size - 1); adj += (str->size - 1) - (org->size - 1);
dstring_replace (cmd_activebuffer->line, str->str, str->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; return 0;
} }
@ -1387,6 +1394,8 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
dstring_clearstr (cmd_activebuffer->realline); dstring_clearstr (cmd_activebuffer->realline);
dstring_appendstr (cmd_activebuffer->realline, text); 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 /* Turn off tags at the beginning of a command. This causes tags to
continue past token boundaries. */ continue past token boundaries. */
@ -1394,7 +1403,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
tag_special = 0; tag_special = 0;
if (text[0] == '|') if (text[0] == '|')
str++; str++;
dstring_clearstr (cmd_activebuffer->line);
while (strlen (str + i)) { while (strlen (str + i)) {
if (!legacy && cmd_argc == 1) { // See if command wants unprocessed tokens 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); 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++; i++;
space++; space++;
} }
if (space)
dstring_appendsubstr (cmd_activebuffer->line, str + i - space, space);
len = Cmd_GetToken (str + i, legacy); len = Cmd_GetToken (str + i, legacy);
if (len < 0) { if (len < 0) {
Cmd_Error ("Parse error: Unmatched quotes, braces, or " Cmd_Error ("Parse error: Unmatched quotes, braces, or "
@ -1421,6 +1427,9 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
cmd_activebuffer->argv = realloc (cmd_activebuffer->argv, cmd_activebuffer->argv = realloc (cmd_activebuffer->argv,
sizeof (cmd_token_t *) * cmd_argc); sizeof (cmd_token_t *) * cmd_argc);
SYS_CHECKMEM (cmd_activebuffer->argv); 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, cmd_activebuffer->args = realloc (cmd_activebuffer->args,
sizeof (int) * cmd_argc); sizeof (int) * cmd_argc);
@ -1434,6 +1443,7 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
/* Remove surrounding quotes or double quotes or braces */ /* Remove surrounding quotes or double quotes or braces */
quotes = 0; quotes = 0;
braces = 0; braces = 0;
cmd_activebuffer->argsu[cmd_argc - 1] = i;
cmd_activebuffer->args[cmd_argc - 1] = i; cmd_activebuffer->args[cmd_argc - 1] = i;
cmd_activebuffer->argv[cmd_argc - 1]->delim = ' '; cmd_activebuffer->argv[cmd_argc - 1]->delim = ' ';
if ((!legacy && str[i] == '\'' && str[i + len] == '\'') if ((!legacy && str[i] == '\'' && str[i + len] == '\'')
@ -1443,8 +1453,6 @@ Cmd_TokenizeString (const char *text, qboolean legacy)
len -= 1; len -= 1;
quotes = 1; quotes = 1;
} }
dstring_appendsubstr (cmd_activebuffer->line,
str + i - quotes, len + quotes * 2);
if (str[i] == '{' && str[i + len] == '}') { if (str[i] == '{' && str[i + len] == '}') {
i++; i++;
len -= 1; len -= 1;
@ -1893,11 +1901,21 @@ Cmd_If_f (void)
{ {
long int num; long int num;
if (Cmd_Argc () < 3) { if ((Cmd_Argc () !=3 && !(Cmd_Argc () >= 5)) || (Cmd_Argc () > 5 && strcmp(Cmd_Argv(3),"else"))) {
Sys_Printf ("Usage: if {condition} {commands}\n"); Sys_Printf ("Usage: if {condition} {commands} else {commands}\n");
return; 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); num = strtol (Cmd_Argv(1), 0, 10);
if (!strcmp(Cmd_Argv(0), "ifnot")) if (!strcmp(Cmd_Argv(0), "ifnot"))
@ -1905,6 +1923,11 @@ Cmd_If_f (void)
if (num) if (num)
Cbuf_InsertText (Cmd_Argv (2)); 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; return;
} }
@ -2116,6 +2139,7 @@ Cmd_Init (void)
"variable"); "variable");
Cmd_AddCommand ("if", Cmd_If_f, "Conditionally execute a set of commands."); 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 ("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_AddCommand ("while", Cmd_While_f, "Execute a set of commands while a condition is true.");
Cmd_SetPure ("while"); Cmd_SetPure ("while");

View file

@ -32,19 +32,22 @@ exp_error_t EXP_ERROR;
optable_t optable[] = optable_t optable[] =
{ {
{"**", OP_Exp}, {"!", OP_Not, 1},
{"/", OP_Div}, {"**", OP_Exp, 2},
{"*", OP_Mult}, {"/", OP_Div, 2},
{"+", OP_Add}, {"*", OP_Mult, 2},
{"-", OP_Sub}, {"+", OP_Add, 2},
{"==", OP_Eq}, {"-", OP_Sub, 2},
{"!=", OP_Neq}, {"==", OP_Eq, 2},
{">=", OP_GreaterThanEqual}, {"!=", OP_Neq, 2},
{">", OP_GreaterThan}, {">=", OP_GreaterThanEqual, 2},
{"<=", OP_LessThanEqual}, {">", OP_GreaterThan, 2},
{"<", OP_LessThan}, {"<=", OP_LessThanEqual, 2},
{"||", OP_Or}, {"<", OP_LessThan, 2},
{"&&", OP_And}, {"||", OP_Or, 2},
{"or", OP_Or, 2},
{"&&", OP_And, 2},
{"and", OP_And, 2},
{"", 0} {"", 0}
}; };
@ -60,12 +63,33 @@ token *EXP_NewToken (void)
return new; 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) token *EXP_ParseString (char *str)
{ {
char buf[256]; char buf[256];
token *chain, *new, *cur; token *chain, *new, *cur;
int i,n,m; int i,m,fi;
cur = chain = EXP_NewToken(); cur = chain = EXP_NewToken();
chain->generic.type = TOKEN_OPAREN; chain->generic.type = TOKEN_OPAREN;
@ -75,8 +99,10 @@ token *EXP_ParseString (char *str)
for (i = 0; i < strlen(str); i++) for (i = 0; i < strlen(str); i++)
{ {
m = 0; m = 0;
while(str[i] == ' ') while(isspace((byte)str[i]))
i++; i++;
if (!str[i])
break;
if (isdigit((byte)str[i]) || str[i] == '.') if (isdigit((byte)str[i]) || str[i] == '.')
{ {
while ((isdigit((byte)str[i]) || str[i] == '.') && i < strlen(str) && m < 256) while ((isdigit((byte)str[i]) || str[i] == '.') && i < strlen(str) && m < 256)
@ -111,27 +137,23 @@ token *EXP_ParseString (char *str)
} }
else else
{ {
while(!(isdigit((byte)str[i])) && str[i] != '.' && str[i] != '(' && str[i] != ')' && m < 256) while(!(isdigit((byte)str[i])) && !isspace((byte)str[i]) && str[i] != '.' && str[i] != '(' && str[i] != ')' && m < 256) {
buf[m++] = str[i++]; buf[m++] = str[i++];
}
buf[m] = 0; buf[m] = 0;
if (m) if (m)
{ {
for (n = 0; optable[n].func; n++) fi = EXP_FindIndexByStr (buf);
{ if (fi != -1) {
if (!(strncmp(optable[n].str, buf, strlen(optable[n].str)))) i -= (m - strlen(optable[fi].str) + 1);
{ new = EXP_NewToken();
i -= (m - strlen(optable[n].str) + 1); new->generic.type = TOKEN_OP;
new = EXP_NewToken(); new->op.func = optable[fi].func;
new->generic.type = TOKEN_OP; new->generic.prev = cur;
new->op.func = optable[n].func; new->generic.next = 0;
new->generic.prev = cur; cur->generic.next = new;
new->generic.next = 0; cur = new;
cur->generic.next = new; } else {
cur = new;
break;
}
}
if (!(optable[n].func)) {
EXP_DestroyTokens (chain); EXP_DestroyTokens (chain);
return 0; 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) 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.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 (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); cur->generic.prev->num.value = optable[i].func(cur->generic.prev->num.value, cur->generic.next->num.value);
temp = cur; temp = cur;
@ -181,6 +209,7 @@ void EXP_SimplifyTokens (token *chain)
EXP_RemoveToken(temp->generic.next); EXP_RemoveToken(temp->generic.next);
EXP_RemoveToken(temp); EXP_RemoveToken(temp);
} }
}
} }
} }
} }
@ -273,7 +302,7 @@ exp_error_t EXP_Validate (token *chain)
new->op.func = OP_Mult; new->op.func = OP_Mult;
EXP_InsertTokenAfter (cur, new); EXP_InsertTokenAfter (cur, new);
} }
else else if (optable[EXP_FindIndexByFunc(cur->generic.next->op.func)].operands == 2)
return EXP_E_SYNTAX; /* Operator misuse */ return EXP_E_SYNTAX; /* Operator misuse */
} }
else if (cur->generic.type == TOKEN_OP && cur->generic.next->generic.type == TOKEN_CPAREN) 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: case TOKEN_GENERIC:
break; break;
} }
printf("\n");
} }

View file

@ -21,6 +21,11 @@
#include <math.h> #include <math.h>
float OP_Not (float op1, float op2)
{
return !op1;
}
float OP_Add (float op1, float op2) float OP_Add (float op1, float op2)
{ {
return op1 + op2; return op1 + op2;