mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 14:20:59 +00:00
Cleaned up the GIB parser and GIB_Execute() a lot. Made aliases work in
GIB. Added some breakpoint GIB builtins for debugging script/intepreter interactions. Made carne work properly again (local variables don't disappear in interactive mode)
This commit is contained in:
parent
1201f615ee
commit
c9fbb334f1
9 changed files with 226 additions and 178 deletions
|
@ -39,8 +39,8 @@ char GIB_Parse_Match_Index (const char *str, unsigned int *i);
|
|||
char GIB_Parse_Match_Paren (const char *str, unsigned int *i);
|
||||
char GIB_Parse_Match_Var (const char *str, unsigned int *i);
|
||||
|
||||
gib_tree_t *GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags);
|
||||
gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_flags_t flags, gib_tree_t **embedded);
|
||||
gib_tree_t *GIB_Parse_Lines (const char *program, unsigned int pofs);
|
||||
gib_tree_t *GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t **embedded);
|
||||
|
||||
extern qboolean gib_parse_error;
|
||||
const char *GIB_Parse_ErrorMsg (void);
|
||||
|
|
|
@ -33,16 +33,14 @@
|
|||
#define __GIB_TREE_H
|
||||
|
||||
#define TREE_NORMAL 0 // Normal node
|
||||
// Flags for tokens
|
||||
#define TREE_CONCAT 1 // Concatenate to previous
|
||||
#define TREE_P_EMBED 2 // Embedded stuff needs to be processed
|
||||
#define TREE_SPLIT 4 // Token is the name of an array that should be split
|
||||
// Flags for arguments
|
||||
#define TREE_A_CONCAT 1 // Concatenate to previous
|
||||
#define TREE_A_EMBED 2 // Embedded stuff needs to be processed
|
||||
#define TREE_A_EXPAND 4 // Token needs to be expanded
|
||||
// Flags for lines
|
||||
#define TREE_COND 1 // Conditional jump (if or while command)
|
||||
#define TREE_NOT 2 // Invert condition
|
||||
#define TREE_END 4 // Node ends a loop or conditional
|
||||
#define TREE_FORNEXT 8 // For loop is starting again
|
||||
#define TREE_EMBED 16 // Embedded command (expect return value)
|
||||
#define TREE_L_NOT 1 // Invert condition
|
||||
#define TREE_L_FORNEXT 4 // For loop is starting again
|
||||
#define TREE_L_EMBED 8 // Embedded command (expect return value)
|
||||
|
||||
typedef char gib_tree_flags_t;
|
||||
|
||||
|
@ -51,10 +49,20 @@ typedef struct gib_tree_s {
|
|||
char delim;
|
||||
unsigned int start, end, refs;
|
||||
gib_tree_flags_t flags;
|
||||
enum gib_tree_type_e {
|
||||
TREE_T_CMD, // A command
|
||||
TREE_T_COND, // Conditional jump
|
||||
TREE_T_ASSIGN, // Assignment
|
||||
TREE_T_JUMP, // Jump
|
||||
TREE_T_JUMPPLUS, // Jump, go to next instruction
|
||||
TREE_T_ARG, // Argument (not a line)
|
||||
TREE_T_FORNEXT, // Fetch next arg in for loop
|
||||
TREE_T_META // Info node
|
||||
} type;
|
||||
struct gib_tree_s *children, *next, *jump;
|
||||
} gib_tree_t;
|
||||
|
||||
gib_tree_t *GIB_Tree_New (gib_tree_flags_t flags);
|
||||
gib_tree_t *GIB_Tree_New (enum gib_tree_type_e type);
|
||||
void GIB_Tree_Free_Recursive (gib_tree_t *tree);
|
||||
void GIB_Tree_Ref (gib_tree_t **tp);
|
||||
void GIB_Tree_Unref (gib_tree_t **tp);
|
||||
|
|
|
@ -48,6 +48,7 @@ const char rcsid[] = "$Id$";
|
|||
#include "QF/gib_tree.h"
|
||||
#include "QF/gib_vars.h"
|
||||
#include "QF/gib_execute.h"
|
||||
#include "QF/idparse.h"
|
||||
|
||||
void
|
||||
GIB_Buffer_Construct (struct cbuf_s *cbuf)
|
||||
|
@ -101,7 +102,7 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf)
|
|||
free (g->script);
|
||||
}
|
||||
g->script = 0;
|
||||
g->program = 0;
|
||||
g->program = g->ip = 0;
|
||||
g->stack.p = 0;
|
||||
g->waitret = g->done = false;
|
||||
|
||||
|
@ -130,12 +131,30 @@ GIB_Buffer_Add (cbuf_t * cbuf, const char *str)
|
|||
gib_buffer_data_t *g = GIB_DATA (cbuf);
|
||||
gib_tree_t **save, *cur;
|
||||
|
||||
if (g->program) {
|
||||
// AddText should only be used to populate a buffer before
|
||||
// executing it and shouldn't happen to a running GIB buffer,
|
||||
// but if it does, try to find somewhere else to put the text.
|
||||
if (g->ip) {
|
||||
for (;cbuf; cbuf = cbuf->up)
|
||||
if (cbuf->interpreter == &id_interp) {
|
||||
Cbuf_AddText (cbuf, str);
|
||||
return;
|
||||
}
|
||||
Sys_Printf (
|
||||
"-------------\n"
|
||||
"|GIB Warning|\n"
|
||||
"-------------\n"
|
||||
"Text added to running GIB buffer discarded.\n"
|
||||
"Text: %s\n",
|
||||
str
|
||||
);
|
||||
return;
|
||||
} else if (g->program) {
|
||||
for (cur = g->program; cur->next; cur = cur->next);
|
||||
save = &cur->next;
|
||||
} else
|
||||
save = &g->program;
|
||||
if (!(*save = GIB_Parse_Lines (str, 0, TREE_NORMAL)))
|
||||
if (!(*save = GIB_Parse_Lines (str, 0)))
|
||||
Sys_Printf (
|
||||
"-----------------\n"
|
||||
"|GIB Parse Error|\n"
|
||||
|
@ -153,11 +172,18 @@ GIB_Buffer_Insert (cbuf_t * cbuf, const char *str)
|
|||
gib_buffer_data_t *g = GIB_DATA (cbuf);
|
||||
gib_tree_t *lines, *cur;
|
||||
|
||||
if ((lines = GIB_Parse_Lines (str, 0, TREE_NORMAL))) {
|
||||
// No GIB builtin should ever insert text into a running
|
||||
// GIB buffer, so create an idparse buffer to handle the
|
||||
// legacy console code.
|
||||
if (g->ip) {
|
||||
cbuf_t *new = Cbuf_New (&id_interp);
|
||||
new->up = cbuf;
|
||||
cbuf->down = new;
|
||||
cbuf->state = CBUF_STATE_STACK;
|
||||
Cbuf_InsertText (new, str);
|
||||
return;
|
||||
} else if ((lines = GIB_Parse_Lines (str, 0))) {
|
||||
for (cur = lines; cur; cur = cur->next);
|
||||
// if (g->ip) { // This buffer is already running!
|
||||
|
||||
GIB_Tree_Unref (&g->program);
|
||||
cur->next = g->program;
|
||||
g->program = lines;
|
||||
} else
|
||||
|
|
|
@ -164,7 +164,7 @@ GIB_Function_f (void)
|
|||
// Is the function program already tokenized?
|
||||
if (GIB_Argm (2)->delim != '{') {
|
||||
// Parse on the fly
|
||||
if (!(program = GIB_Parse_Lines (GIB_Argv (2), 0, TREE_NORMAL))) {
|
||||
if (!(program = GIB_Parse_Lines (GIB_Argv (2), 0))) {
|
||||
// Error!
|
||||
GIB_Error ("parse", "Parse error while defining function '%s'.",
|
||||
GIB_Argv (1));
|
||||
|
@ -304,10 +304,6 @@ GIB_For_f (void)
|
|||
dstring_t *dstr;
|
||||
unsigned int i;
|
||||
|
||||
if (GIB_Argc () < 5) {
|
||||
GIB_DATA (cbuf_active)->ip = GIB_DATA (cbuf_active)->ip->jump;
|
||||
return;
|
||||
}
|
||||
GIB_Buffer_Push_Sstack (cbuf_active);
|
||||
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
|
||||
dstring_clearstr (dstr);
|
||||
|
@ -316,43 +312,6 @@ GIB_For_f (void)
|
|||
dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
|
||||
dstring_appendstr (dstr, GIB_Argv (i));
|
||||
}
|
||||
GIB_Execute_For_Next (cbuf_active);
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_Break_f (void)
|
||||
{
|
||||
if (!GIB_DATA (cbuf_active)->ip->jump) {
|
||||
GIB_Error ("loop", "Break command attempted outside of a loop.");
|
||||
return;
|
||||
}
|
||||
if (!GIB_DATA (cbuf_active)->ip->jump->flags & TREE_COND) // In a for
|
||||
// loop?
|
||||
GIB_Buffer_Pop_Sstack (cbuf_active); // Kill it
|
||||
GIB_DATA (cbuf_active)->ip = GIB_DATA (cbuf_active)->ip->jump->jump;
|
||||
}
|
||||
|
||||
static gib_tree_t gib_cont = {
|
||||
"",
|
||||
' ',
|
||||
0, 0, 0, 0,
|
||||
TREE_NORMAL
|
||||
};
|
||||
|
||||
static void
|
||||
GIB_Continue_f (void)
|
||||
{
|
||||
if (!GIB_DATA (cbuf_active)->ip->jump) {
|
||||
GIB_Error ("loop", "Continue command attempted outside of a loop.");
|
||||
return;
|
||||
}
|
||||
if (GIB_DATA (cbuf_active)->ip->jump->flags & TREE_COND) {
|
||||
gib_cont.next = GIB_DATA (cbuf_active)->ip->jump;
|
||||
GIB_DATA (cbuf_active)->ip = &gib_cont;
|
||||
} else {
|
||||
GIB_Execute_For_Next (cbuf_active);
|
||||
GIB_DATA (cbuf_active)->ip = GIB_DATA (cbuf_active)->ip->jump;
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this is a standard console command, not a GIB builtin
|
||||
|
@ -910,6 +869,26 @@ GIB_Print_f (void)
|
|||
Sys_Printf ("%s", GIB_Argv (1));
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_bp1_f (void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_bp2_f (void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_bp3_f (void)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
GIB_bp4_f (void)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
GIB_Builtin_Init (qboolean sandbox)
|
||||
{
|
||||
|
@ -929,8 +908,6 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("domain::clear", GIB_Domain_Clear_f);
|
||||
GIB_Builtin_Add ("return", GIB_Return_f);
|
||||
GIB_Builtin_Add ("for", GIB_For_f);
|
||||
GIB_Builtin_Add ("break", GIB_Break_f);
|
||||
GIB_Builtin_Add ("continue", GIB_Continue_f);
|
||||
GIB_Builtin_Add ("length", GIB_Length_f);
|
||||
GIB_Builtin_Add ("equal", GIB_Equal_f);
|
||||
GIB_Builtin_Add ("count", GIB_Count_f);
|
||||
|
@ -952,4 +929,8 @@ GIB_Builtin_Init (qboolean sandbox)
|
|||
GIB_Builtin_Add ("file::delete", GIB_File_Delete_f);
|
||||
GIB_Builtin_Add ("range", GIB_Range_f);
|
||||
GIB_Builtin_Add ("print", GIB_Print_f);
|
||||
GIB_Builtin_Add ("bp1", GIB_bp1_f);
|
||||
GIB_Builtin_Add ("bp2", GIB_bp2_f);
|
||||
GIB_Builtin_Add ("bp3", GIB_bp3_f);
|
||||
GIB_Builtin_Add ("bp4", GIB_bp4_f);
|
||||
}
|
||||
|
|
|
@ -144,15 +144,15 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
|
|||
args->argc = 0;
|
||||
|
||||
for (cur = line->children; cur; cur = cur->next) {
|
||||
if (cur->flags & TREE_CONCAT) {
|
||||
if (cur->flags & TREE_A_CONCAT) {
|
||||
pos = args->argv[args->argc - 1]->size - 1;
|
||||
if (cur->flags & TREE_P_EMBED) {
|
||||
if (cur->flags & TREE_A_EMBED) {
|
||||
GIB_Process_Embedded (cur, cbuf->args);
|
||||
} else
|
||||
dstring_appendstr (args->argv[args->argc - 1], cur->str);
|
||||
} else {
|
||||
pos = 0;
|
||||
if (cur->flags & TREE_P_EMBED) {
|
||||
if (cur->flags & TREE_A_EMBED) {
|
||||
Cbuf_ArgsAdd (args, "");
|
||||
GIB_Process_Embedded (cur, cbuf->args);
|
||||
} else
|
||||
|
@ -162,7 +162,7 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
|
|||
if (cur->delim == '('
|
||||
&& GIB_Process_Math (args->argv[args->argc - 1], pos))
|
||||
return -1;
|
||||
if (cur->flags & TREE_SPLIT)
|
||||
if (cur->flags & TREE_A_EXPAND)
|
||||
GIB_Execute_Split_Var (cbuf);
|
||||
}
|
||||
return 0;
|
||||
|
@ -177,7 +177,7 @@ GIB_Execute_For_Next (cbuf_t * cbuf)
|
|||
GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1;
|
||||
if (array->size == 1) {
|
||||
GIB_Buffer_Pop_Sstack (cbuf);
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
array->size--;
|
||||
var =
|
||||
|
@ -186,7 +186,7 @@ GIB_Execute_For_Next (cbuf_t * cbuf)
|
|||
&index, true);
|
||||
dstring_clearstr (var->array[index].value);
|
||||
dstring_appendstr (var->array[index].value, array->dstrs[array->size]->str);
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -195,63 +195,73 @@ GIB_Execute (cbuf_t * cbuf)
|
|||
gib_buffer_data_t *g = GIB_DATA (cbuf);
|
||||
gib_builtin_t *b;
|
||||
gib_function_t *f;
|
||||
double cond;
|
||||
unsigned int index;
|
||||
gib_var_t *var;
|
||||
|
||||
if (!g->program)
|
||||
return;
|
||||
if (!g->ip)
|
||||
g->ip = g->program;
|
||||
while (!g->done) {
|
||||
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
|
||||
return;
|
||||
if (g->ip->flags & TREE_COND) {
|
||||
cond = g->ip->flags & TREE_NOT ?
|
||||
atof (cbuf->args->argv[1]->str) :
|
||||
!atof (cbuf->args->argv[1]->str);
|
||||
if (cond)
|
||||
g->ip = g->ip ? g->ip->next : g->program;
|
||||
while (g->ip) {
|
||||
switch (g->ip->type) {
|
||||
case TREE_T_JUMP:
|
||||
g->ip = g->ip->jump;
|
||||
} else if (g->ip->flags & TREE_FORNEXT) {
|
||||
if (GIB_Execute_For_Next (cbuf))
|
||||
g->ip = g->ip->jump;
|
||||
} else if (g->ip->flags & TREE_END) {
|
||||
g->ip = g->ip->jump;
|
||||
if (g->ip->flags & TREE_COND)
|
||||
continue;
|
||||
} else if (cbuf->args->argc) {
|
||||
if (g->ip->flags & TREE_EMBED) {
|
||||
// Get ready for return values
|
||||
g->waitret = true;
|
||||
GIB_Buffer_Push_Sstack (cbuf);
|
||||
} else
|
||||
g->waitret = false;
|
||||
if (cbuf->args->argc >= 2 && !strcmp (cbuf->args->argv[1]->str, "=")
|
||||
&& ((gib_tree_t *) cbuf->args->argm[1])->delim == ' ') {
|
||||
unsigned int index;
|
||||
gib_var_t *var =
|
||||
GIB_Var_Get_Complex (&g->locals, &g->globals,
|
||||
cbuf->args->argv[0]->str, &index,
|
||||
true);
|
||||
GIB_Var_Assign (var, index, cbuf->args->argv + 2,
|
||||
cbuf->args->argc - 2);
|
||||
} else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) {
|
||||
b->func ();
|
||||
} else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
|
||||
cbuf_t *new = Cbuf_PushStack (&gib_interp);
|
||||
|
||||
GIB_Function_Execute (new, f, cbuf->args->argv,
|
||||
cbuf->args->argc);
|
||||
} else {
|
||||
GIB_Execute_Generate_Composite (cbuf);
|
||||
if (Cmd_Command (cbuf->args))
|
||||
GIB_Error ("command",
|
||||
"No builtin, function, or console command named '%s' was found.",
|
||||
cbuf->args->argv[0]->str);
|
||||
}
|
||||
case TREE_T_JUMPPLUS:
|
||||
g->ip = g->ip->jump->next;
|
||||
continue;
|
||||
case TREE_T_FORNEXT:
|
||||
if (GIB_Execute_For_Next (cbuf))
|
||||
g->ip = g->ip->jump->next;
|
||||
else
|
||||
g->ip = g->ip->next;
|
||||
continue;
|
||||
case TREE_T_COND:
|
||||
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
|
||||
return;
|
||||
if (g->ip->flags & TREE_L_NOT ? atof (cbuf->args->argv[1]->str) : !atof (cbuf->args->argv[1]->str))
|
||||
g->ip = g->ip->jump->next;
|
||||
else
|
||||
g->ip = g->ip->next;
|
||||
continue;
|
||||
case TREE_T_ASSIGN:
|
||||
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
|
||||
return;
|
||||
var = GIB_Var_Get_Complex (&g->locals, &g->globals, cbuf->args->argv[0]->str, &index, true);
|
||||
GIB_Var_Assign (var, index, cbuf->args->argv + 2, cbuf->args->argc - 2);
|
||||
g->ip = g->ip->next;
|
||||
continue;
|
||||
case TREE_T_CMD:
|
||||
if (GIB_Execute_Prepare_Line (cbuf, g->ip))
|
||||
return;
|
||||
else if (cbuf->args->argc) {
|
||||
if (g->ip->flags & TREE_L_EMBED) {
|
||||
// Get ready for return values
|
||||
g->waitret = true;
|
||||
GIB_Buffer_Push_Sstack (cbuf);
|
||||
} else
|
||||
g->waitret = false;
|
||||
if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str)))
|
||||
b->func ();
|
||||
else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) {
|
||||
cbuf_t *new = Cbuf_PushStack (&gib_interp);
|
||||
GIB_Function_Execute (new, f, cbuf->args->argv, cbuf->args->argc);
|
||||
} else {
|
||||
GIB_Execute_Generate_Composite (cbuf);
|
||||
if (Cmd_Command (cbuf->args))
|
||||
GIB_Error (
|
||||
"command",
|
||||
"No builtin, function, or console command named '%s' was found.",
|
||||
cbuf->args->argv[0]->str
|
||||
);
|
||||
}
|
||||
if (cbuf->state)
|
||||
return;
|
||||
g->ip = g->ip->next;
|
||||
}
|
||||
continue;
|
||||
default:
|
||||
GIB_Error ("QUAKEFORGE-BUG-PLEASE-REPORT", "Unknown instruction type; tastes like chicken.");
|
||||
return;
|
||||
}
|
||||
if (!(g->ip = g->ip->next)) // No more commands
|
||||
g->done = true;
|
||||
if (cbuf->state) // Let the stack walker figure out what
|
||||
// to do
|
||||
return;
|
||||
}
|
||||
g->ip = g->program = 0;
|
||||
g->script = 0;
|
||||
}
|
||||
|
|
|
@ -218,8 +218,7 @@ GIB_Parse_ErrorPos (void)
|
|||
// FIXME: Concatenation in stupid circumstances should generate errors
|
||||
|
||||
static gib_tree_t *
|
||||
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
|
||||
gib_tree_flags_t flags, gib_tree_t ** embedded)
|
||||
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_tree_t ** embedded)
|
||||
{
|
||||
char c, delim, *str;
|
||||
unsigned int tstart, start;
|
||||
|
@ -284,33 +283,29 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
|
|||
}
|
||||
}
|
||||
c = 0;
|
||||
cur = *node = GIB_Tree_New (flags);
|
||||
cur = *node = GIB_Tree_New (TREE_T_ARG);
|
||||
cur->start = start + pofs;
|
||||
cur->end = *i + pofs;
|
||||
cur->delim = delim;
|
||||
str = calloc (*i - tstart + 1, sizeof (char));
|
||||
memcpy (str, program + tstart, *i - tstart);
|
||||
|
||||
// Don't bother parsing further if we are concatenating, as the
|
||||
// resulting
|
||||
// string would differ from the parsed program.
|
||||
if (cur->delim == '{' && !cat) {
|
||||
if (cur->delim == '{') {
|
||||
// Try to parse sub-program
|
||||
if (!(new = GIB_Parse_Lines (str, tstart + pofs, flags)))
|
||||
if (!(new = GIB_Parse_Lines (str, tstart + pofs)))
|
||||
goto ERROR;
|
||||
cur->children = new;
|
||||
// Check for embedded commands/variables
|
||||
} else if (cur->delim == ' ' || cur->delim == '(') {
|
||||
if (!
|
||||
(cur->children =
|
||||
GIB_Parse_Embedded (str, tstart + pofs, flags, &new))) {
|
||||
GIB_Parse_Embedded (str, tstart + pofs, &new))) {
|
||||
// There could be no embedded elements, so check for a real
|
||||
// error
|
||||
if (gib_parse_error)
|
||||
goto ERROR;
|
||||
} else {
|
||||
// Link/set flags
|
||||
cur->flags |= TREE_P_EMBED;
|
||||
cur->flags |= TREE_A_EMBED;
|
||||
// Add any embedded commands to top of chain
|
||||
if (new) {
|
||||
for (tmp = new; tmp->next; tmp = tmp->next);
|
||||
|
@ -321,7 +316,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
|
|||
// Check for array splitting
|
||||
// Concatenating this onto something else is non-sensical
|
||||
if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%') && !cat) {
|
||||
cur->flags |= TREE_SPLIT;
|
||||
cur->flags |= TREE_A_EXPAND;
|
||||
}
|
||||
// We can handle escape characters now
|
||||
} else if (cur->delim == '\"')
|
||||
|
@ -329,7 +324,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
|
|||
cur->str = str;
|
||||
|
||||
if (cat) {
|
||||
cur->flags |= TREE_CONCAT;
|
||||
cur->flags |= TREE_A_CONCAT;
|
||||
cat = false;
|
||||
}
|
||||
// Nothing left to parse?
|
||||
|
@ -355,7 +350,6 @@ static gib_tree_t *
|
|||
GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
||||
{
|
||||
gib_tree_t *p, *start = line;
|
||||
unsigned int flags = line->flags;
|
||||
|
||||
while (!strcmp (line->children->str, "if")
|
||||
|| !strcmp (line->children->str, "ifnot")) {
|
||||
|
@ -370,16 +364,16 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
("First program block in 'if' statement not enclosed in braces or invalid.",
|
||||
line->start);
|
||||
return line;
|
||||
} else if (line->flags & TREE_EMBED) {
|
||||
} else if (line->flags & TREE_L_EMBED) {
|
||||
GIB_Parse_Error
|
||||
("'if' statements may not be used in embedded commands.",
|
||||
line->start);
|
||||
return line;
|
||||
}
|
||||
// Set conditional flag
|
||||
line->flags |= TREE_COND;
|
||||
// Set as conditional
|
||||
line->type = TREE_T_COND;
|
||||
if (line->children->str[2])
|
||||
line->flags |= TREE_NOT;
|
||||
line->flags |= TREE_L_NOT;
|
||||
// Save our spot
|
||||
p = line;
|
||||
// Move subprogram inline
|
||||
|
@ -388,11 +382,6 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
// Find end of subprogram
|
||||
while (line->next)
|
||||
line = line->next;
|
||||
line->next = GIB_Tree_New (flags | TREE_END);
|
||||
line = line->next;
|
||||
// Mark jump point
|
||||
p->jump = line;
|
||||
line->flags |= TREE_END; // Last instruction of subprogram
|
||||
// Handle "else"
|
||||
if (p->children->next->next->next
|
||||
&& !strcmp (p->children->next->next->next->str, "else")) {
|
||||
|
@ -403,6 +392,12 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
line->start);
|
||||
return line;
|
||||
}
|
||||
// On 'true' first block must jump past this
|
||||
// We will figure out jump target later
|
||||
line->next = GIB_Tree_New (TREE_T_JUMPPLUS);
|
||||
line = line->next;
|
||||
// Jump to else block on 'false'
|
||||
p->jump = line;
|
||||
// Is "else" followed by a subprogram?
|
||||
if (p->children->next->next->next->next->delim == '{') {
|
||||
// Move subprogram inline
|
||||
|
@ -412,18 +407,20 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
line = line->next;
|
||||
} else {
|
||||
// Push rest of tokens into a new line
|
||||
line->next = GIB_Tree_New (flags);
|
||||
line->next = GIB_Tree_New (TREE_T_CMD);
|
||||
line->next->children = p->children->next->next->next->next;
|
||||
p->children->next->next->next->next = 0;
|
||||
line = line->next;
|
||||
}
|
||||
} else
|
||||
break; // Don't touch if statements in the sub
|
||||
// program
|
||||
} else {
|
||||
// Jump past block on 'false'
|
||||
p->jump = line;
|
||||
break; // Don't touch if statements in the sub program
|
||||
}
|
||||
}
|
||||
// Now we know our exit point, set it on all our ending instructions
|
||||
// Now we know exit point from if-else if chain, set our jumps
|
||||
while (start) {
|
||||
if (start->flags & TREE_END && !start->jump)
|
||||
if (start->type == TREE_T_JUMPPLUS && !start->jump)
|
||||
start->jump = line;
|
||||
start = start->next;
|
||||
}
|
||||
|
@ -443,28 +440,39 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
("Program block in 'while' statement not enclosed in braces or invalid.",
|
||||
line->start);
|
||||
return line;
|
||||
} else if (line->flags & TREE_EMBED) {
|
||||
} else if (line->flags & TREE_L_EMBED) {
|
||||
GIB_Parse_Error
|
||||
("'while' statements may not be used in embedded commands.",
|
||||
line->start);
|
||||
return line;
|
||||
}
|
||||
// Set conditional flag
|
||||
line->flags |= TREE_COND;
|
||||
line->type = TREE_T_COND;
|
||||
// Save our spot
|
||||
p = line;
|
||||
// Move subprogram inline
|
||||
line->next = line->children->next->next->children;
|
||||
line->children->next->next->children = 0;
|
||||
// Find end of subprogram, set jump point back to top of loop as we go
|
||||
// Find end of subprogram
|
||||
for (; line->next; line = line->next)
|
||||
if (!line->jump)
|
||||
line->jump = p;
|
||||
line->next = GIB_Tree_New (flags | TREE_END);
|
||||
if (!line->jump && line->children) {
|
||||
if (!strcmp (line->children->str, "continue")) {
|
||||
line->type = TREE_T_JUMP;
|
||||
line->jump = p;
|
||||
} else if (!strcmp (line->children->str, "break"))
|
||||
line->type = TREE_T_JUMPPLUS;
|
||||
}
|
||||
line->next = GIB_Tree_New (TREE_T_JUMP);
|
||||
line->next->jump = p;
|
||||
line = line->next;
|
||||
// Mark jump point out of loop
|
||||
p->jump = line;
|
||||
// Set jumps out of loop for "break" commands;
|
||||
while (p) {
|
||||
if (p->type == TREE_T_JUMPPLUS && !p->jump)
|
||||
p->jump = line;
|
||||
p = p->next;
|
||||
}
|
||||
} else if (!strcmp (line->children->str, "for")) {
|
||||
gib_tree_t *tmp;
|
||||
|
||||
|
@ -486,25 +494,40 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
|
|||
line->start);
|
||||
return line;
|
||||
}
|
||||
// Add instruction to fetch next argument (this is the true loop start)
|
||||
line->next = GIB_Tree_New (TREE_T_FORNEXT);
|
||||
line = line->next;
|
||||
p = line;
|
||||
// Move subprogram inline
|
||||
line->next = tmp->children;
|
||||
tmp->children = 0;
|
||||
// Find end of subprogram, set jump point back to top of loop as we go
|
||||
// Find end of subprogram
|
||||
for (; line->next; line = line->next)
|
||||
if (!line->jump)
|
||||
line->jump = p;
|
||||
line->next = GIB_Tree_New (flags | TREE_FORNEXT);
|
||||
if (!line->jump && line->children) {
|
||||
if (!strcmp (line->children->str, "continue")) {
|
||||
line->type = TREE_T_JUMP;
|
||||
line->jump = p;
|
||||
} else if (!strcmp (line->children->str, "break"))
|
||||
line->type = TREE_T_JUMPPLUS;
|
||||
}
|
||||
line->next = GIB_Tree_New (TREE_T_JUMP);
|
||||
line->next->jump = p;
|
||||
line = line->next;
|
||||
// Mark jump point out of loop
|
||||
p->jump = line;
|
||||
}
|
||||
// Mark jump point out of loop for break command
|
||||
while (p) {
|
||||
if (p->type == TREE_T_JUMPPLUS && !p->jump)
|
||||
p->jump = line;
|
||||
p = p->next;
|
||||
}
|
||||
} else if (line->children->next && line->children->next->delim == ' ' && !strcmp (line->children->next->str, "="))
|
||||
line->type = TREE_T_ASSIGN;
|
||||
return line;
|
||||
}
|
||||
|
||||
gib_tree_t *
|
||||
GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags)
|
||||
GIB_Parse_Lines (const char *program, unsigned int pofs)
|
||||
{
|
||||
unsigned int i = 0, lstart;
|
||||
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs;
|
||||
|
@ -517,9 +540,9 @@ GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags)
|
|||
break;
|
||||
lstart = i;
|
||||
// If we parse something useful...
|
||||
if ((tokens = GIB_Parse_Tokens (program, &i, pofs, flags, &embs))) {
|
||||
if ((tokens = GIB_Parse_Tokens (program, &i, pofs, &embs))) {
|
||||
// Link it in
|
||||
cur = GIB_Tree_New (flags);
|
||||
cur = GIB_Tree_New (TREE_T_CMD);
|
||||
cur->delim = '\n';
|
||||
str = calloc (i - lstart + 1, sizeof (char));
|
||||
memcpy (str, program + lstart, i - lstart);
|
||||
|
@ -549,8 +572,7 @@ GIB_Parse_Lines (const char *program, unsigned int pofs, gib_tree_flags_t flags)
|
|||
}
|
||||
|
||||
gib_tree_t *
|
||||
GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
||||
gib_tree_flags_t flags, gib_tree_t ** embedded)
|
||||
GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedded)
|
||||
{
|
||||
unsigned int i, n, t;
|
||||
char c, d, *str;
|
||||
|
@ -575,7 +597,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
|||
}
|
||||
end = i + 1;
|
||||
// Construct the actual line to be executed
|
||||
cur = GIB_Tree_New (flags | TREE_EMBED);
|
||||
cur = GIB_Tree_New (TREE_T_CMD);
|
||||
cur->flags |= TREE_L_EMBED;
|
||||
cur->delim = '`';
|
||||
str = calloc (i - n + 1, sizeof (char));
|
||||
memcpy (str, program + n, i - n);
|
||||
|
@ -586,7 +609,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
|||
t = 0;
|
||||
if (!
|
||||
(tokens =
|
||||
GIB_Parse_Tokens (cur->str, &t, start + pofs, flags, &emb)))
|
||||
GIB_Parse_Tokens (cur->str, &t, start + pofs, &emb)))
|
||||
goto ERROR;
|
||||
cur->children = tokens;
|
||||
GIB_Parse_Semantic_Preprocess (cur)->next = *embedded;
|
||||
|
@ -602,7 +625,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
|||
*embedded = cur;
|
||||
// Create a representative child node for GIB_Process_Embedded to
|
||||
// use
|
||||
cur = GIB_Tree_New (flags | TREE_EMBED);
|
||||
cur = GIB_Tree_New (TREE_T_META);
|
||||
cur->delim = '`';
|
||||
// Save start/end indices
|
||||
cur->start = start;
|
||||
|
@ -624,7 +647,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
|||
goto ERROR;
|
||||
end += i;
|
||||
|
||||
cur = GIB_Tree_New (flags | TREE_EMBED);
|
||||
cur = GIB_Tree_New (TREE_T_META);
|
||||
cur->delim = d;
|
||||
str = calloc (i - n + 1, sizeof (char));
|
||||
memcpy (str, program + n, i - n);
|
||||
|
@ -632,7 +655,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
|
|||
// Can we use the name as is, or must processing be done at
|
||||
// runtime?
|
||||
if (strchr (str, '$') || strchr (str, '#'))
|
||||
cur->flags |= TREE_P_EMBED;
|
||||
cur->flags |= TREE_A_EMBED;
|
||||
// Save start/end indices
|
||||
cur->start = start;
|
||||
cur->end = end;
|
||||
|
|
|
@ -101,7 +101,7 @@ GIB_Process_Embedded (gib_tree_t * node, cbuf_args_t * args)
|
|||
dstring_appendstr (args->argv[args->argc - 1],
|
||||
retvals->dstrs[0]->str);
|
||||
GIB_Buffer_Pop_Sstack (cbuf_active);
|
||||
} else if (cur->flags & TREE_P_EMBED) {
|
||||
} else if (cur->flags & TREE_A_EMBED) {
|
||||
n = args->argv[args->argc - 1]->size - 1;
|
||||
dstring_appendstr (args->argv[args->argc - 1], cur->str);
|
||||
var = GIB_Var_Get_Very_Complex (&GIB_DATA (cbuf_active)->locals,
|
||||
|
|
|
@ -43,11 +43,11 @@ const char rcsid[] = "$Id$";
|
|||
#include "QF/gib_tree.h"
|
||||
|
||||
gib_tree_t *
|
||||
GIB_Tree_New (gib_tree_flags_t flags)
|
||||
GIB_Tree_New (enum gib_tree_type_e type)
|
||||
{
|
||||
gib_tree_t *new = calloc (1, sizeof (gib_tree_t));
|
||||
|
||||
new->flags = flags;
|
||||
new->type = type;
|
||||
// All nodes are created for a reason, so start with 1 ref
|
||||
new->refs = 1;
|
||||
return new;
|
||||
|
|
|
@ -197,12 +197,12 @@ Cbuf_Execute_Stack (cbuf_t *cbuf)
|
|||
sp->state = CBUF_STATE_JUNK;
|
||||
sp = sp->up;
|
||||
}
|
||||
|
||||
if (cbuf->down) {
|
||||
Cbuf_DeleteStack (cbuf->down);
|
||||
cbuf->down = 0;
|
||||
}
|
||||
Cbuf_Reset (cbuf);
|
||||
if (sp) // This should be null if we exited normally
|
||||
Cbuf_Reset (cbuf);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Loading…
Reference in a new issue