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 *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

View file

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

View file

@ -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);

View file

@ -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,6 +1427,9 @@ 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);
@ -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;
@ -1893,11 +1901,21 @@ 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"))
@ -1905,6 +1923,11 @@ Cmd_If_f (void)
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");

View file

@ -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,12 +63,33 @@ 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;
@ -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)
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);
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[n].func;
new->op.func = optable[fi].func;
new->generic.prev = cur;
new->generic.next = 0;
cur->generic.next = new;
cur = new;
break;
}
}
if (!(optable[n].func)) {
} 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;
@ -183,6 +211,7 @@ void EXP_SimplifyTokens (token *chain)
}
}
}
}
}
void EXP_RemoveToken (token *tok)
@ -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");
}

View file

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