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:
Brian Koropoff 2003-02-25 06:52:27 +00:00
parent 1201f615ee
commit c9fbb334f1
9 changed files with 226 additions and 178 deletions

View file

@ -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_Paren (const char *str, unsigned int *i);
char GIB_Parse_Match_Var (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_Lines (const char *program, unsigned int pofs);
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_Embedded (const char *program, unsigned int pofs, gib_tree_t **embedded);
extern qboolean gib_parse_error; extern qboolean gib_parse_error;
const char *GIB_Parse_ErrorMsg (void); const char *GIB_Parse_ErrorMsg (void);

View file

@ -33,16 +33,14 @@
#define __GIB_TREE_H #define __GIB_TREE_H
#define TREE_NORMAL 0 // Normal node #define TREE_NORMAL 0 // Normal node
// Flags for tokens // Flags for arguments
#define TREE_CONCAT 1 // Concatenate to previous #define TREE_A_CONCAT 1 // Concatenate to previous
#define TREE_P_EMBED 2 // Embedded stuff needs to be processed #define TREE_A_EMBED 2 // Embedded stuff needs to be processed
#define TREE_SPLIT 4 // Token is the name of an array that should be split #define TREE_A_EXPAND 4 // Token needs to be expanded
// Flags for lines // Flags for lines
#define TREE_COND 1 // Conditional jump (if or while command) #define TREE_L_NOT 1 // Invert condition
#define TREE_NOT 2 // Invert condition #define TREE_L_FORNEXT 4 // For loop is starting again
#define TREE_END 4 // Node ends a loop or conditional #define TREE_L_EMBED 8 // Embedded command (expect return value)
#define TREE_FORNEXT 8 // For loop is starting again
#define TREE_EMBED 16 // Embedded command (expect return value)
typedef char gib_tree_flags_t; typedef char gib_tree_flags_t;
@ -51,10 +49,20 @@ typedef struct gib_tree_s {
char delim; char delim;
unsigned int start, end, refs; unsigned int start, end, refs;
gib_tree_flags_t flags; 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; struct gib_tree_s *children, *next, *jump;
} gib_tree_t; } 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_Free_Recursive (gib_tree_t *tree);
void GIB_Tree_Ref (gib_tree_t **tp); void GIB_Tree_Ref (gib_tree_t **tp);
void GIB_Tree_Unref (gib_tree_t **tp); void GIB_Tree_Unref (gib_tree_t **tp);

View file

@ -48,6 +48,7 @@ const char rcsid[] = "$Id$";
#include "QF/gib_tree.h" #include "QF/gib_tree.h"
#include "QF/gib_vars.h" #include "QF/gib_vars.h"
#include "QF/gib_execute.h" #include "QF/gib_execute.h"
#include "QF/idparse.h"
void void
GIB_Buffer_Construct (struct cbuf_s *cbuf) GIB_Buffer_Construct (struct cbuf_s *cbuf)
@ -101,7 +102,7 @@ GIB_Buffer_Reset (struct cbuf_s *cbuf)
free (g->script); free (g->script);
} }
g->script = 0; g->script = 0;
g->program = 0; g->program = g->ip = 0;
g->stack.p = 0; g->stack.p = 0;
g->waitret = g->done = false; 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_buffer_data_t *g = GIB_DATA (cbuf);
gib_tree_t **save, *cur; 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); for (cur = g->program; cur->next; cur = cur->next);
save = &cur->next; save = &cur->next;
} else } else
save = &g->program; save = &g->program;
if (!(*save = GIB_Parse_Lines (str, 0, TREE_NORMAL))) if (!(*save = GIB_Parse_Lines (str, 0)))
Sys_Printf ( Sys_Printf (
"-----------------\n" "-----------------\n"
"|GIB Parse Error|\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_buffer_data_t *g = GIB_DATA (cbuf);
gib_tree_t *lines, *cur; 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); for (cur = lines; cur; cur = cur->next);
// if (g->ip) { // This buffer is already running!
GIB_Tree_Unref (&g->program);
cur->next = g->program; cur->next = g->program;
g->program = lines; g->program = lines;
} else } else

View file

@ -164,7 +164,7 @@ GIB_Function_f (void)
// Is the function program already tokenized? // Is the function program already tokenized?
if (GIB_Argm (2)->delim != '{') { if (GIB_Argm (2)->delim != '{') {
// Parse on the fly // 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! // Error!
GIB_Error ("parse", "Parse error while defining function '%s'.", GIB_Error ("parse", "Parse error while defining function '%s'.",
GIB_Argv (1)); GIB_Argv (1));
@ -304,10 +304,6 @@ GIB_For_f (void)
dstring_t *dstr; dstring_t *dstr;
unsigned int i; 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); GIB_Buffer_Push_Sstack (cbuf_active);
dstr = GIB_Buffer_Dsarray_Get (cbuf_active); dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
dstring_clearstr (dstr); dstring_clearstr (dstr);
@ -316,43 +312,6 @@ GIB_For_f (void)
dstr = GIB_Buffer_Dsarray_Get (cbuf_active); dstr = GIB_Buffer_Dsarray_Get (cbuf_active);
dstring_appendstr (dstr, GIB_Argv (i)); 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 // 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)); 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 void
GIB_Builtin_Init (qboolean sandbox) 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 ("domain::clear", GIB_Domain_Clear_f);
GIB_Builtin_Add ("return", GIB_Return_f); GIB_Builtin_Add ("return", GIB_Return_f);
GIB_Builtin_Add ("for", GIB_For_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 ("length", GIB_Length_f);
GIB_Builtin_Add ("equal", GIB_Equal_f); GIB_Builtin_Add ("equal", GIB_Equal_f);
GIB_Builtin_Add ("count", GIB_Count_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 ("file::delete", GIB_File_Delete_f);
GIB_Builtin_Add ("range", GIB_Range_f); GIB_Builtin_Add ("range", GIB_Range_f);
GIB_Builtin_Add ("print", GIB_Print_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);
} }

View file

@ -144,15 +144,15 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
args->argc = 0; args->argc = 0;
for (cur = line->children; cur; cur = cur->next) { 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; 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); GIB_Process_Embedded (cur, cbuf->args);
} else } else
dstring_appendstr (args->argv[args->argc - 1], cur->str); dstring_appendstr (args->argv[args->argc - 1], cur->str);
} else { } else {
pos = 0; pos = 0;
if (cur->flags & TREE_P_EMBED) { if (cur->flags & TREE_A_EMBED) {
Cbuf_ArgsAdd (args, ""); Cbuf_ArgsAdd (args, "");
GIB_Process_Embedded (cur, cbuf->args); GIB_Process_Embedded (cur, cbuf->args);
} else } else
@ -162,7 +162,7 @@ GIB_Execute_Prepare_Line (cbuf_t * cbuf, gib_tree_t * line)
if (cur->delim == '(' if (cur->delim == '('
&& GIB_Process_Math (args->argv[args->argc - 1], pos)) && GIB_Process_Math (args->argv[args->argc - 1], pos))
return -1; return -1;
if (cur->flags & TREE_SPLIT) if (cur->flags & TREE_A_EXPAND)
GIB_Execute_Split_Var (cbuf); GIB_Execute_Split_Var (cbuf);
} }
return 0; return 0;
@ -177,7 +177,7 @@ GIB_Execute_For_Next (cbuf_t * cbuf)
GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1; GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1;
if (array->size == 1) { if (array->size == 1) {
GIB_Buffer_Pop_Sstack (cbuf); GIB_Buffer_Pop_Sstack (cbuf);
return 0; return -1;
} }
array->size--; array->size--;
var = var =
@ -186,7 +186,7 @@ GIB_Execute_For_Next (cbuf_t * cbuf)
&index, true); &index, true);
dstring_clearstr (var->array[index].value); dstring_clearstr (var->array[index].value);
dstring_appendstr (var->array[index].value, array->dstrs[array->size]->str); dstring_appendstr (var->array[index].value, array->dstrs[array->size]->str);
return 1; return 0;
} }
void void
@ -195,63 +195,73 @@ GIB_Execute (cbuf_t * cbuf)
gib_buffer_data_t *g = GIB_DATA (cbuf); gib_buffer_data_t *g = GIB_DATA (cbuf);
gib_builtin_t *b; gib_builtin_t *b;
gib_function_t *f; gib_function_t *f;
double cond; unsigned int index;
gib_var_t *var;
if (!g->program) g->ip = g->ip ? g->ip->next : g->program;
return; while (g->ip) {
if (!g->ip) switch (g->ip->type) {
g->ip = g->program; case TREE_T_JUMP:
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->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; continue;
} else if (cbuf->args->argc) { case TREE_T_JUMPPLUS:
if (g->ip->flags & TREE_EMBED) { g->ip = g->ip->jump->next;
// Get ready for return values continue;
g->waitret = true; case TREE_T_FORNEXT:
GIB_Buffer_Push_Sstack (cbuf); if (GIB_Execute_For_Next (cbuf))
} else g->ip = g->ip->jump->next;
g->waitret = false; else
if (cbuf->args->argc >= 2 && !strcmp (cbuf->args->argv[1]->str, "=") g->ip = g->ip->next;
&& ((gib_tree_t *) cbuf->args->argm[1])->delim == ' ') { continue;
unsigned int index; case TREE_T_COND:
gib_var_t *var = if (GIB_Execute_Prepare_Line (cbuf, g->ip))
GIB_Var_Get_Complex (&g->locals, &g->globals, return;
cbuf->args->argv[0]->str, &index, if (g->ip->flags & TREE_L_NOT ? atof (cbuf->args->argv[1]->str) : !atof (cbuf->args->argv[1]->str))
true); g->ip = g->ip->jump->next;
GIB_Var_Assign (var, index, cbuf->args->argv + 2, else
cbuf->args->argc - 2); g->ip = g->ip->next;
} else if ((b = GIB_Builtin_Find (cbuf->args->argv[0]->str))) { continue;
b->func (); case TREE_T_ASSIGN:
} else if ((f = GIB_Function_Find (cbuf->args->argv[0]->str))) { if (GIB_Execute_Prepare_Line (cbuf, g->ip))
cbuf_t *new = Cbuf_PushStack (&gib_interp); return;
var = GIB_Var_Get_Complex (&g->locals, &g->globals, cbuf->args->argv[0]->str, &index, true);
GIB_Function_Execute (new, f, cbuf->args->argv, GIB_Var_Assign (var, index, cbuf->args->argv + 2, cbuf->args->argc - 2);
cbuf->args->argc); g->ip = g->ip->next;
} else { continue;
GIB_Execute_Generate_Composite (cbuf); case TREE_T_CMD:
if (Cmd_Command (cbuf->args)) if (GIB_Execute_Prepare_Line (cbuf, g->ip))
GIB_Error ("command", return;
"No builtin, function, or console command named '%s' was found.", else if (cbuf->args->argc) {
cbuf->args->argv[0]->str); 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;
} }

View file

@ -218,8 +218,7 @@ GIB_Parse_ErrorPos (void)
// FIXME: Concatenation in stupid circumstances should generate errors // FIXME: Concatenation in stupid circumstances should generate errors
static gib_tree_t * static gib_tree_t *
GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_tree_t ** embedded)
gib_tree_flags_t flags, gib_tree_t ** embedded)
{ {
char c, delim, *str; char c, delim, *str;
unsigned int tstart, start; unsigned int tstart, start;
@ -284,33 +283,29 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
} }
} }
c = 0; c = 0;
cur = *node = GIB_Tree_New (flags); cur = *node = GIB_Tree_New (TREE_T_ARG);
cur->start = start + pofs; cur->start = start + pofs;
cur->end = *i + pofs; cur->end = *i + pofs;
cur->delim = delim; cur->delim = delim;
str = calloc (*i - tstart + 1, sizeof (char)); str = calloc (*i - tstart + 1, sizeof (char));
memcpy (str, program + tstart, *i - tstart); memcpy (str, program + tstart, *i - tstart);
if (cur->delim == '{') {
// Don't bother parsing further if we are concatenating, as the
// resulting
// string would differ from the parsed program.
if (cur->delim == '{' && !cat) {
// Try to parse sub-program // Try to parse sub-program
if (!(new = GIB_Parse_Lines (str, tstart + pofs, flags))) if (!(new = GIB_Parse_Lines (str, tstart + pofs)))
goto ERROR; goto ERROR;
cur->children = new; cur->children = new;
// Check for embedded commands/variables // Check for embedded commands/variables
} else if (cur->delim == ' ' || cur->delim == '(') { } else if (cur->delim == ' ' || cur->delim == '(') {
if (! if (!
(cur->children = (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 // There could be no embedded elements, so check for a real
// error // error
if (gib_parse_error) if (gib_parse_error)
goto ERROR; goto ERROR;
} else { } else {
// Link/set flags // Link/set flags
cur->flags |= TREE_P_EMBED; cur->flags |= TREE_A_EMBED;
// Add any embedded commands to top of chain // Add any embedded commands to top of chain
if (new) { if (new) {
for (tmp = new; tmp->next; tmp = tmp->next); 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 // Check for array splitting
// Concatenating this onto something else is non-sensical // Concatenating this onto something else is non-sensical
if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%') && !cat) { if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%') && !cat) {
cur->flags |= TREE_SPLIT; cur->flags |= TREE_A_EXPAND;
} }
// We can handle escape characters now // We can handle escape characters now
} else if (cur->delim == '\"') } else if (cur->delim == '\"')
@ -329,7 +324,7 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs,
cur->str = str; cur->str = str;
if (cat) { if (cat) {
cur->flags |= TREE_CONCAT; cur->flags |= TREE_A_CONCAT;
cat = false; cat = false;
} }
// Nothing left to parse? // Nothing left to parse?
@ -355,7 +350,6 @@ static gib_tree_t *
GIB_Parse_Semantic_Preprocess (gib_tree_t * line) GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
{ {
gib_tree_t *p, *start = line; gib_tree_t *p, *start = line;
unsigned int flags = line->flags;
while (!strcmp (line->children->str, "if") while (!strcmp (line->children->str, "if")
|| !strcmp (line->children->str, "ifnot")) { || !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.", ("First program block in 'if' statement not enclosed in braces or invalid.",
line->start); line->start);
return line; return line;
} else if (line->flags & TREE_EMBED) { } else if (line->flags & TREE_L_EMBED) {
GIB_Parse_Error GIB_Parse_Error
("'if' statements may not be used in embedded commands.", ("'if' statements may not be used in embedded commands.",
line->start); line->start);
return line; return line;
} }
// Set conditional flag // Set as conditional
line->flags |= TREE_COND; line->type = TREE_T_COND;
if (line->children->str[2]) if (line->children->str[2])
line->flags |= TREE_NOT; line->flags |= TREE_L_NOT;
// Save our spot // Save our spot
p = line; p = line;
// Move subprogram inline // Move subprogram inline
@ -388,11 +382,6 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
// Find end of subprogram // Find end of subprogram
while (line->next) while (line->next)
line = 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" // Handle "else"
if (p->children->next->next->next if (p->children->next->next->next
&& !strcmp (p->children->next->next->next->str, "else")) { && !strcmp (p->children->next->next->next->str, "else")) {
@ -403,6 +392,12 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
line->start); line->start);
return line; 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? // Is "else" followed by a subprogram?
if (p->children->next->next->next->next->delim == '{') { if (p->children->next->next->next->next->delim == '{') {
// Move subprogram inline // Move subprogram inline
@ -412,18 +407,20 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
line = line->next; line = line->next;
} else { } else {
// Push rest of tokens into a new line // 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; line->next->children = p->children->next->next->next->next;
p->children->next->next->next->next = 0; p->children->next->next->next->next = 0;
line = line->next; line = line->next;
} }
} else } else {
break; // Don't touch if statements in the sub // Jump past block on 'false'
// program 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) { while (start) {
if (start->flags & TREE_END && !start->jump) if (start->type == TREE_T_JUMPPLUS && !start->jump)
start->jump = line; start->jump = line;
start = start->next; 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.", ("Program block in 'while' statement not enclosed in braces or invalid.",
line->start); line->start);
return line; return line;
} else if (line->flags & TREE_EMBED) { } else if (line->flags & TREE_L_EMBED) {
GIB_Parse_Error GIB_Parse_Error
("'while' statements may not be used in embedded commands.", ("'while' statements may not be used in embedded commands.",
line->start); line->start);
return line; return line;
} }
// Set conditional flag // Set conditional flag
line->flags |= TREE_COND; line->type = TREE_T_COND;
// Save our spot // Save our spot
p = line; p = line;
// Move subprogram inline // Move subprogram inline
line->next = line->children->next->next->children; line->next = line->children->next->next->children;
line->children->next->next->children = 0; 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) for (; line->next; line = line->next)
if (!line->jump) if (!line->jump && line->children) {
line->jump = p; if (!strcmp (line->children->str, "continue")) {
line->next = GIB_Tree_New (flags | TREE_END); 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->next->jump = p;
line = line->next; line = line->next;
// Mark jump point out of loop // Mark jump point out of loop
p->jump = line; 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")) { } else if (!strcmp (line->children->str, "for")) {
gib_tree_t *tmp; gib_tree_t *tmp;
@ -486,25 +494,40 @@ GIB_Parse_Semantic_Preprocess (gib_tree_t * line)
line->start); line->start);
return line; 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; p = line;
// Move subprogram inline // Move subprogram inline
line->next = tmp->children; line->next = tmp->children;
tmp->children = 0; 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) for (; line->next; line = line->next)
if (!line->jump) if (!line->jump && line->children) {
line->jump = p; if (!strcmp (line->children->str, "continue")) {
line->next = GIB_Tree_New (flags | TREE_FORNEXT); 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->next->jump = p;
line = line->next; line = line->next;
// Mark jump point out of loop // Mark jump point out of loop
p->jump = line; 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; return line;
} }
gib_tree_t * 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; unsigned int i = 0, lstart;
gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs; 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; break;
lstart = i; lstart = i;
// If we parse something useful... // 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 // Link it in
cur = GIB_Tree_New (flags); cur = GIB_Tree_New (TREE_T_CMD);
cur->delim = '\n'; cur->delim = '\n';
str = calloc (i - lstart + 1, sizeof (char)); str = calloc (i - lstart + 1, sizeof (char));
memcpy (str, program + lstart, i - lstart); 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_tree_t *
GIB_Parse_Embedded (const char *program, unsigned int pofs, GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedded)
gib_tree_flags_t flags, gib_tree_t ** embedded)
{ {
unsigned int i, n, t; unsigned int i, n, t;
char c, d, *str; char c, d, *str;
@ -575,7 +597,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
} }
end = i + 1; end = i + 1;
// Construct the actual line to be executed // 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 = '`'; cur->delim = '`';
str = calloc (i - n + 1, sizeof (char)); str = calloc (i - n + 1, sizeof (char));
memcpy (str, program + n, i - n); memcpy (str, program + n, i - n);
@ -586,7 +609,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
t = 0; t = 0;
if (! if (!
(tokens = (tokens =
GIB_Parse_Tokens (cur->str, &t, start + pofs, flags, &emb))) GIB_Parse_Tokens (cur->str, &t, start + pofs, &emb)))
goto ERROR; goto ERROR;
cur->children = tokens; cur->children = tokens;
GIB_Parse_Semantic_Preprocess (cur)->next = *embedded; GIB_Parse_Semantic_Preprocess (cur)->next = *embedded;
@ -602,7 +625,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
*embedded = cur; *embedded = cur;
// Create a representative child node for GIB_Process_Embedded to // Create a representative child node for GIB_Process_Embedded to
// use // use
cur = GIB_Tree_New (flags | TREE_EMBED); cur = GIB_Tree_New (TREE_T_META);
cur->delim = '`'; cur->delim = '`';
// Save start/end indices // Save start/end indices
cur->start = start; cur->start = start;
@ -624,7 +647,7 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs,
goto ERROR; goto ERROR;
end += i; end += i;
cur = GIB_Tree_New (flags | TREE_EMBED); cur = GIB_Tree_New (TREE_T_META);
cur->delim = d; cur->delim = d;
str = calloc (i - n + 1, sizeof (char)); str = calloc (i - n + 1, sizeof (char));
memcpy (str, program + n, i - n); 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 // Can we use the name as is, or must processing be done at
// runtime? // runtime?
if (strchr (str, '$') || strchr (str, '#')) if (strchr (str, '$') || strchr (str, '#'))
cur->flags |= TREE_P_EMBED; cur->flags |= TREE_A_EMBED;
// Save start/end indices // Save start/end indices
cur->start = start; cur->start = start;
cur->end = end; cur->end = end;

View file

@ -101,7 +101,7 @@ GIB_Process_Embedded (gib_tree_t * node, cbuf_args_t * args)
dstring_appendstr (args->argv[args->argc - 1], dstring_appendstr (args->argv[args->argc - 1],
retvals->dstrs[0]->str); retvals->dstrs[0]->str);
GIB_Buffer_Pop_Sstack (cbuf_active); 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; n = args->argv[args->argc - 1]->size - 1;
dstring_appendstr (args->argv[args->argc - 1], cur->str); dstring_appendstr (args->argv[args->argc - 1], cur->str);
var = GIB_Var_Get_Very_Complex (&GIB_DATA (cbuf_active)->locals, var = GIB_Var_Get_Very_Complex (&GIB_DATA (cbuf_active)->locals,

View file

@ -43,11 +43,11 @@ const char rcsid[] = "$Id$";
#include "QF/gib_tree.h" #include "QF/gib_tree.h"
gib_tree_t * 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)); 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 // All nodes are created for a reason, so start with 1 ref
new->refs = 1; new->refs = 1;
return new; return new;

View file

@ -197,12 +197,12 @@ Cbuf_Execute_Stack (cbuf_t *cbuf)
sp->state = CBUF_STATE_JUNK; sp->state = CBUF_STATE_JUNK;
sp = sp->up; sp = sp->up;
} }
if (cbuf->down) { if (cbuf->down) {
Cbuf_DeleteStack (cbuf->down); Cbuf_DeleteStack (cbuf->down);
cbuf->down = 0; cbuf->down = 0;
} }
Cbuf_Reset (cbuf); if (sp) // This should be null if we exited normally
Cbuf_Reset (cbuf);
} }
void void