From d8c0f50c117dc83eb32bcf1f96c04268408d9a75 Mon Sep 17 00:00:00 2001 From: Brian Koropoff Date: Fri, 11 Apr 2003 02:57:11 +0000 Subject: [PATCH] The ultimate GIB bugfix commit, including reworked semantic processing, a fix for arguments passed to a GIB function run via rcon, and various other fixes. --- include/QF/Makefile.am | 14 +- include/QF/gib_function.h | 6 +- include/QF/gib_parse.h | 3 +- include/QF/gib_tree.h | 6 +- libs/gib/Makefile.am | 3 +- libs/gib/gib_builtin.c | 22 ++- libs/gib/gib_execute.c | 88 ++++++---- libs/gib/gib_function.c | 39 ++++- libs/gib/gib_parse.c | 353 ++++++++------------------------------ libs/gib/gib_process.c | 2 +- libs/gib/gib_thread.c | 2 +- tools/carne/main.c | 2 +- 12 files changed, 200 insertions(+), 340 deletions(-) diff --git a/include/QF/Makefile.am b/include/QF/Makefile.am index e8dd5fb58..e4720057e 100644 --- a/include/QF/Makefile.am +++ b/include/QF/Makefile.am @@ -4,10 +4,10 @@ includedir = $(prefix)/include/QF include_HEADERS = bspfile.h cbuf.h cdaudio.h checksum.h clip_hull.h cmd.h \ console.h crc.h csqc.h cvar.h dstring.h draw.h gib_buffer.h \ gib_builtin.h gib_execute.h gib_function.h gib_init.h gib_parse.h \ - gib_process.h gib_regex.h gib_thread.h gib_tree.h gib_vars.h hash.h hl.h \ - idparse.h in_event.h info.h input.h joystick.h keys.h link.h locs.h \ - mathlib.h mdfour.h model.h modelgen.h msg.h pak.h pakfile.h pcx.h \ - plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h qdefs.h qendian.h \ - qfplist.h qtypes.h quakefs.h quakeio.h render.h riff.h screen.h sizebuf.h \ - skin.h sound.h spritegn.h sys.h teamplay.h texture.h tga.h uint32.h va.h \ - ver_check.h vid.h wad.h zone.h + gib_process.h gib_regex.h gib_semantics.h gib_thread.h gib_tree.h \ + gib_vars.h hash.h hl.h idparse.h in_event.h info.h input.h joystick.h \ + keys.h link.h locs.h mathlib.h mdfour.h model.h modelgen.h msg.h pak.h \ + pakfile.h pcx.h plugin.h pr_comp.h pr_debug.h pr_obj.h progs.h qargs.h \ + qdefs.h qendian.h qfplist.h qtypes.h quakefs.h quakeio.h render.h riff.h \ + screen.h sizebuf.h skin.h sound.h spritegn.h sys.h teamplay.h texture.h \ + tga.h uint32.h va.h ver_check.h vid.h wad.h zone.h diff --git a/include/QF/gib_function.h b/include/QF/gib_function.h index d3131e542..c1018c4eb 100644 --- a/include/QF/gib_function.h +++ b/include/QF/gib_function.h @@ -48,7 +48,9 @@ typedef struct gib_function_s { void GIB_Function_Define (const char *name, const char *text, gib_tree_t *program, gib_script_t *script, hashtab_t *globals); gib_function_t *GIB_Function_Find (const char *name); -void GIB_Function_Prepare_Args (cbuf_t *cbuf, dstring_t **args, unsigned int argc); -void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc); +void GIB_Function_Prepare_Args (cbuf_t *cbuf, const char **args, unsigned int argc); +void GIB_Function_Prepare_Args_D (cbuf_t *cbuf, dstring_t **args, unsigned int argc); +void GIB_Function_Execute (cbuf_t *cbuf, gib_function_t *func, const char **args, unsigned int argc); +void GIB_Function_Execute_D (cbuf_t *cbuf, gib_function_t *func, dstring_t **args, unsigned int argc); #endif diff --git a/include/QF/gib_parse.h b/include/QF/gib_parse.h index e66226d28..d96cdd828 100644 --- a/include/QF/gib_parse.h +++ b/include/QF/gib_parse.h @@ -40,8 +40,9 @@ 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_t *GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t **embedded); +gib_tree_t *GIB_Parse_Embedded (gib_tree_t *token); extern qboolean gib_parse_error; +void GIB_Parse_Error (const char *msg, unsigned int pos); const char *GIB_Parse_ErrorMsg (void); unsigned int GIB_Parse_ErrorPos (void); diff --git a/include/QF/gib_tree.h b/include/QF/gib_tree.h index b596b448e..904fd03fb 100644 --- a/include/QF/gib_tree.h +++ b/include/QF/gib_tree.h @@ -54,10 +54,10 @@ typedef struct gib_tree_s { 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 + TREE_T_META, // Info node + TREE_T_NOP // Do nothing (label, etc) } type; struct gib_tree_s *children, *next, *jump; } gib_tree_t; @@ -66,5 +66,5 @@ 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); - + #endif /* __GIB_TREE_H */ diff --git a/libs/gib/Makefile.am b/libs/gib/Makefile.am index f4bfa2511..84baf9342 100644 --- a/libs/gib/Makefile.am +++ b/libs/gib/Makefile.am @@ -7,4 +7,5 @@ lib_LTLIBRARIES= libQFgib.la libQFgib_la_LDFLAGS= -version-info 1:0:0 libQFgib_la_SOURCES= \ gib_buffer.c gib_builtin.c gib_execute.c gib_function.c gib_parse.c gib_process.c \ - gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c ops.c exp.c regex.c + gib_regex.c gib_thread.c gib_vars.c gib_init.c gib_tree.c gib_semantics.c ops.c \ + exp.c regex.c diff --git a/libs/gib/gib_builtin.c b/libs/gib/gib_builtin.c index b0917baaf..42550c720 100644 --- a/libs/gib/gib_builtin.c +++ b/libs/gib/gib_builtin.c @@ -208,6 +208,9 @@ GIB_Local_f (void) if (GIB_Argc () >= 3) GIB_Var_Assign (var, index, cbuf_active->args->argv + 3, GIB_Argc () - 3); + if (GIB_CanReturn ()) + for (i = 3; i < GIB_Argc(); i++) + GIB_Return (GIB_Argv(i)); } else for (i = 1; i < GIB_Argc(); i++) var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->locals, &zero, GIB_Argv (i), &index, true); @@ -229,6 +232,9 @@ GIB_Global_f (void) if (GIB_Argc () >= 3) GIB_Var_Assign (var, index, cbuf_active->args->argv + 3, GIB_Argc () - 3); + if (GIB_CanReturn ()) + for (i = 3; i < GIB_Argc(); i++) + GIB_Return (GIB_Argv(i)); } else for (i = 1; i < GIB_Argc(); i++) var = GIB_Var_Get_Complex (&GIB_DATA (cbuf_active)->globals, &zero, GIB_Argv (i), &index, true); @@ -321,19 +327,21 @@ static void GIB_Runexported_f (void) { gib_function_t *f; + const char **args; if (!(f = GIB_Function_Find (Cmd_Argv (0)))) Sys_Printf ("Error: No function found for exported command \"%s\".\n" "This is most likely a bug, please report it to" "The QuakeForge developers.", Cmd_Argv (0)); else { - cbuf_t *sub = Cbuf_New (&gib_interp); + cbuf_t *sub = Cbuf_PushStack (&gib_interp); + unsigned int i; - GIB_Function_Execute (sub, f, cbuf_active->args->argv, - cbuf_active->args->argc); - cbuf_active->down = sub; - sub->up = cbuf_active; - cbuf_active->state = CBUF_STATE_STACK; + args = malloc (sizeof (char *) * Cmd_Argc()); + for (i = 0; i < Cmd_Argc(); i++) + args[i] = Cmd_Argv(i); + GIB_Function_Execute (sub, f, args, Cmd_Argc()); + free (args); } } @@ -586,7 +594,7 @@ GIB_Thread_Create_f (void) else { gib_thread_t *thread = GIB_Thread_New (); - GIB_Function_Execute (thread->cbuf, f, cbuf_active->args->argv + 1, + GIB_Function_Execute_D (thread->cbuf, f, cbuf_active->args->argv + 1, cbuf_active->args->argc - 1); GIB_Thread_Add (thread); if (GIB_CanReturn ()) diff --git a/libs/gib/gib_execute.c b/libs/gib/gib_execute.c index 435ad467c..99a876104 100644 --- a/libs/gib/gib_execute.c +++ b/libs/gib/gib_execute.c @@ -58,8 +58,7 @@ GIB_Execute_Generate_Composite (struct cbuf_s *cbuf) for (i = 0; i < args->argc; i++) { // ->str could be moved by realloc when a dstring is resized // so save the offset instead of the pointer - args->args[i] = - (const char *) strlen (GIB_DATA (cbuf)->arg_composite->str); + args->args[i] = (const char *) strlen (GIB_DATA (cbuf)->arg_composite->str); dstring_appendstr (GIB_DATA (cbuf)->arg_composite, args->argv[i]->str); dstring_appendstr (GIB_DATA (cbuf)->arg_composite, " "); } @@ -71,8 +70,7 @@ GIB_Execute_Generate_Composite (struct cbuf_s *cbuf) for (i = 0; i < args->argc; i++) // now that arg_composite is done we can add the pointer to the stored // offsets and get valid pointers. This *should* be portable. - args->args[i] += - (unsigned long int) GIB_DATA (cbuf)->arg_composite->str; + args->args[i] += (unsigned long int) GIB_DATA (cbuf)->arg_composite->str; } static void @@ -101,9 +99,11 @@ GIB_Execute_Split_Var (cbuf_t * cbuf) break; } cbuf->args->argc--; - if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, - &GIB_DATA (cbuf)->globals, str, &i, false))) - return; + if (!(var = GIB_Var_Get_Complex ( + &GIB_DATA (cbuf)->locals, + &GIB_DATA (cbuf)->globals, + str, &i, false))) + return; if (end < 0) end += var->size; else if (end > var->size) @@ -123,17 +123,19 @@ GIB_Execute_Split_Var (cbuf_t * cbuf) } } else { gib_var_t **vlist, **v; - + cbuf->args->argc--; - if (!(var = GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, - &GIB_DATA (cbuf)->globals, str, &i, false))) - return; + if (!(var = GIB_Var_Get_Complex ( + &GIB_DATA (cbuf)->locals, + &GIB_DATA (cbuf)->globals, + str, &i, false))) + return; if (!var->array[i].leaves) return; vlist = (gib_var_t **) Hash_GetList (var->array[i].leaves); for (v = vlist; *v; v++) Cbuf_ArgsAdd (cbuf->args, (*v)->key); - } + } } static int @@ -175,17 +177,17 @@ GIB_Execute_For_Next (cbuf_t * cbuf) { unsigned int index; gib_var_t *var; - struct gib_dsarray_s *array = - GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1; + struct gib_dsarray_s *array = GIB_DATA (cbuf)->stack.values + GIB_DATA (cbuf)->stack.p - 1; if (array->size == 1) { GIB_Buffer_Pop_Sstack (cbuf); return -1; } array->size--; - var = - GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, - &GIB_DATA (cbuf)->globals, array->dstrs[0]->str, - &index, true); + var = GIB_Var_Get_Complex ( + &GIB_DATA (cbuf)->locals, + &GIB_DATA (cbuf)->globals, array->dstrs[0]->str, + &index, true + ); dstring_clearstr (var->array[index].value); dstring_appendstr (var->array[index].value, array->dstrs[array->size]->str); return 0; @@ -199,40 +201,53 @@ GIB_Execute (cbuf_t * cbuf) gib_function_t *f; unsigned int index; gib_var_t *var; + unsigned int i; if (!g->program) return; g->ip = g->ip ? g->ip->next : g->program; while (g->ip) { switch (g->ip->type) { - case TREE_T_JUMP: + case TREE_T_NOP: // Move to next instruction + g->ip = g->ip->next; + continue; + case TREE_T_JUMP: // Absolute jump g->ip = g->ip->jump; continue; - case TREE_T_JUMPPLUS: - g->ip = g->ip->jump->next; - continue; - case TREE_T_FORNEXT: + case TREE_T_FORNEXT: // Fetch next value in a for loop if (GIB_Execute_For_Next (cbuf)) g->ip = g->ip->jump->next; else g->ip = g->ip->next; continue; - case TREE_T_COND: + case TREE_T_COND: // Conditional jump, move to next instruction 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; + 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: + case TREE_T_ASSIGN: // Assignment 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); + 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); + if (g->ip->flags & TREE_L_EMBED) { + GIB_Buffer_Push_Sstack (cbuf); + g->waitret = true; + for (i = 2; i < cbuf->args->argc; i++) + GIB_Return (cbuf->args->argv[i]->str); + } else + g->waitret = false; g->ip = g->ip->next; continue; - case TREE_T_CMD: + case TREE_T_CMD: // Normal command if (GIB_Execute_Prepare_Line (cbuf, g->ip)) return; if (g->ip->flags & TREE_L_EMBED) { @@ -246,13 +261,17 @@ GIB_Execute (cbuf_t * cbuf) 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); + GIB_Function_Execute_D ( + 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.", + "No builtin, function, or console command " + "named '%s' was found.", cbuf->args->argv[0]->str ); } @@ -261,8 +280,11 @@ GIB_Execute (cbuf_t * cbuf) } g->ip = g->ip->next; continue; - default: - GIB_Error ("QUAKEFORGE-BUG-PLEASE-REPORT", "Unknown instruction type; tastes like chicken."); + default: // We should never get here + GIB_Error ( + "QUAKEFORGE-BUG-PLEASE-REPORT", + "Unknown instruction type; tastes like chicken." + ); return; } } diff --git a/libs/gib/gib_function.c b/libs/gib/gib_function.c index 76e2e0931..b6a9ed027 100644 --- a/libs/gib/gib_function.c +++ b/libs/gib/gib_function.c @@ -149,7 +149,29 @@ GIB_Function_Find (const char *name) } void -GIB_Function_Prepare_Args (cbuf_t * cbuf, dstring_t ** args, unsigned int argc) +GIB_Function_Prepare_Args (cbuf_t * cbuf, const char **args, unsigned int argc) +{ + static hashtab_t *zero = 0; + unsigned int i; + gib_var_t *var; + static char argss[] = "args"; + + var = + GIB_Var_Get_Complex (&GIB_DATA (cbuf)->locals, &zero, argss, &i, true); + var->array = realloc (var->array, sizeof (struct gib_varray_s) * argc); + memset (var->array + 1, 0, (argc - 1) * sizeof (struct gib_varray_s)); + var->size = argc; + for (i = 0; i < argc; i++) { + if (var->array[i].value) + dstring_clearstr (var->array[i].value); + else + var->array[i].value = dstring_newstr (); + dstring_appendstr (var->array[i].value, args[i]); + } +} + +void +GIB_Function_Prepare_Args_D (cbuf_t * cbuf, dstring_t **args, unsigned int argc) { static hashtab_t *zero = 0; unsigned int i; @@ -178,7 +200,7 @@ GIB_Function_Prepare_Args (cbuf_t * cbuf, dstring_t ** args, unsigned int argc) */ void -GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args, +GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, const char ** args, unsigned int argc) { GIB_Tree_Ref (&func->program); @@ -189,3 +211,16 @@ GIB_Function_Execute (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args, GIB_DATA (cbuf)->globals = func->globals; GIB_Function_Prepare_Args (cbuf, args, argc); } + +void +GIB_Function_Execute_D (cbuf_t * cbuf, gib_function_t * func, dstring_t ** args, + unsigned int argc) +{ + GIB_Tree_Ref (&func->program); + if (func->script) + func->script->refs++; + GIB_Buffer_Set_Program (cbuf, func->program); + GIB_DATA (cbuf)->script = func->script; + GIB_DATA (cbuf)->globals = func->globals; + GIB_Function_Prepare_Args_D (cbuf, args, argc); +} diff --git a/libs/gib/gib_parse.c b/libs/gib/gib_parse.c index 0d59ad777..5651b89fc 100644 --- a/libs/gib/gib_parse.c +++ b/libs/gib/gib_parse.c @@ -50,6 +50,7 @@ const char rcsid[] = "$Id$"; #include "QF/gib_function.h" #include "QF/gib_vars.h" #include "QF/gib_parse.h" +#include "QF/gib_semantics.h" /* @@ -78,7 +79,7 @@ GIB_Escaped (const char *str, int i) matching character is found, calling themselves and their neighbors recursively to handle sections of string that they are uninterested in. - + FIXME: Make sure everything is calling everything else it might need to. Make appropriate functions intolerant of newlines. */ @@ -195,7 +196,7 @@ qboolean gib_parse_error; unsigned int gib_parse_error_pos; const char *gib_parse_error_msg; -static void +void GIB_Parse_Error (const char *msg, unsigned int pos) { gib_parse_error = true; @@ -215,14 +216,12 @@ GIB_Parse_ErrorPos (void) return gib_parse_error_pos; } -// 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_t ** embedded) +GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs) { char c = 0, delim, *str; unsigned int tstart, start; - gib_tree_t *nodes = 0, *cur, *new, *embs = 0, *tmp; + gib_tree_t *nodes = 0, *cur, *new; gib_tree_t **node = &nodes; enum {CAT_NORMAL = 0, CAT_DISALLOW, CAT_CONCAT} cat = CAT_DISALLOW; const char *catestr = "Comma found before first argument, nothing to concatenate to."; @@ -314,25 +313,6 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t cur->children = new; // Check for embedded commands/variables } else if (cur->delim == ' ' || cur->delim == '(') { - if (! - (cur->children = - 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_A_EMBED; - // Add any embedded commands to top of chain - if (new) { - for (tmp = new; tmp->next; tmp = tmp->next); - tmp->next = embs; - embs = new; - } - } - // Check for array splitting - // Concatenating this onto something else is non-sensical if (cur->delim == ' ' && (str[0] == '@' || str[0] == '%')) { if (cat == CAT_CONCAT) { GIB_Parse_Error ("Variable expansions may not be concatenated with other arguments.", start + pofs); @@ -342,10 +322,9 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t cat = CAT_DISALLOW; cur->flags |= TREE_A_EXPAND; } - // We can handle escape characters now + // We can handle escape characters now } else if (cur->delim == '\"') GIB_Process_Escapes (str); - if (cat == CAT_CONCAT) cur->flags |= TREE_A_CONCAT; // Nothing left to parse? @@ -357,217 +336,20 @@ GIB_Parse_Tokens (const char *program, unsigned int *i, unsigned int pofs, gib_t node = &cur->next; } DONE: - *embedded = embs; return nodes; ERROR: if (c) GIB_Parse_Error (va ("Could not find match for '%c'.", c), *i + pofs); if (nodes) GIB_Tree_Unref (&nodes); - if (embs) - GIB_Tree_Unref (&embs); return 0; } -static gib_tree_t * -GIB_Parse_Semantic_Preprocess (gib_tree_t * line) -{ - gib_tree_t *p, *start = line; - - // If second token is concatenated, than the first can't possibly mean anything - if (line->children->next && line->children->next->flags & TREE_A_CONCAT) - return line; - while (!strcmp (line->children->str, "if") - || !strcmp (line->children->str, "ifnot")) { - // Sanity checking - if (!line->children->next || !line->children->next->next) { - GIB_Parse_Error ("Not enough arguments to 'if' statement.", - line->start); - return line; - } else if (!line->children->next->next->children - || line->children->next->next->delim != '{') { - GIB_Parse_Error - ("First program block in 'if' statement not enclosed in braces or invalid.", - line->start); - return line; - } else if (line->flags & TREE_L_EMBED) { - GIB_Parse_Error - ("'if' statements may not be used in embedded commands.", - line->start); - return line; - } - // Set as conditional - line->type = TREE_T_COND; - if (line->children->str[2]) - line->flags |= TREE_L_NOT; - // 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 - while (line->next) - line = line->next; - // Handle "else" - if (p->children->next->next->next - && !strcmp (p->children->next->next->next->str, "else")) { - // Sanity checking - if (!p->children->next->next->next->next) { - GIB_Parse_Error - ("'if' statement contains 'else' but no secondary program block or command.", - 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 - line->next = p->children->next->next->next->next->children; - p->children->next->next->next->next->children = 0; - while (line->next) - line = line->next; - } else { - // Push rest of tokens into a new line - 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 { - // Jump past block on 'false' - p->jump = line; - break; // Don't touch if statements in the sub program - } - } - // Now we know exit point from if-else if chain, set our jumps - while (start) { - if (start->type == TREE_T_JUMPPLUS && !start->jump) - start->jump = line; - start = start->next; - } - // Nothing expanded from a line remains, exit now - if (!line->children) - return line; - // If we have a while loop, handle that - if (!strcmp (line->children->str, "while")) { - // Sanity checks - if (!line->children->next || !line->children->next->next) { - GIB_Parse_Error ("Not enough arguments to 'while' statement.", - line->start); - return line; - } else if (!line->children->next->next->children - || line->children->next->next->delim != '{') { - GIB_Parse_Error - ("Program block in 'while' statement not enclosed in braces or invalid.", - line->start); - return line; - } 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->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 - for (; line->next; line = line->next) - 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; - - // Sanity checks - if (!line->children->next || !line->children->next->next - || strcmp (line->children->next->next->str, "in") - || !line->children->next->next->next - || !line->children->next->next->next->next) { - GIB_Parse_Error ("Malformed 'for' statement.", line->start); - return line; - } else if (line->flags & TREE_L_EMBED) { - GIB_Parse_Error ("'for' statements may not be used in embedded commands.", line->start); - return line; - } - // Find last token in line (contains program block) - for (tmp = line->children->next->next->next->next; tmp->next; - tmp = tmp->next); - // More sanity - if (tmp->delim != '{' || !tmp->children) { - GIB_Parse_Error - ("Program block in 'for' statement not enclosed in braces or invalid.", - 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 - for (; line->next; line = line->next) - 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->flags & TREE_A_CONCAT) && - line->children->next->delim == ' ' && - !strcmp (line->children->next->str, "=") - ) { - if (line->flags & TREE_L_EMBED) - GIB_Parse_Error ("Assignment may not be used as an embedded command.", line->start); - line->type = TREE_T_ASSIGN; - } - return line; -} - gib_tree_t * GIB_Parse_Lines (const char *program, unsigned int pofs) { unsigned int i = 0, lstart; - gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *embs; + gib_tree_t *lines = 0, *cur, *tokens, **line = &lines, *temp; char *str; while (1) { @@ -577,26 +359,26 @@ GIB_Parse_Lines (const char *program, unsigned int pofs) break; lstart = i; // If we parse something useful... - if ((tokens = GIB_Parse_Tokens (program, &i, pofs, &embs))) { - // Link it in - cur = GIB_Tree_New (TREE_T_CMD); - cur->delim = '\n'; - str = calloc (i - lstart + 1, sizeof (char)); + if ((tokens = GIB_Parse_Tokens (program, &i, pofs))) { + str = calloc (i - lstart + 1, sizeof(char)); memcpy (str, program + lstart, i - lstart); - cur->str = str; - cur->start = lstart + pofs; - cur->end = i + pofs; - cur->children = tokens; - // Line contains embedded commands? - if (embs) { - // Add them to chain before actual line - *line = embs; - for (; embs->next; embs = embs->next); - embs->next = cur; - } else - *line = cur; - // Do preprocessing - line = &(GIB_Parse_Semantic_Preprocess (cur))->next; + + // All settings for the line must be passed here + cur = GIB_Semantic_Tokens_To_Lines ( + tokens, str, 0, + lstart+pofs, + i+pofs + ); + if (gib_parse_error) { + free (str); + goto ERROR; + } + // Find last line + for (temp = cur; temp->next; temp = temp->next); + + // Link it to lines we already have + *line = cur; + line = &temp->next; } if (gib_parse_error) goto ERROR; @@ -609,16 +391,16 @@ 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) +GIB_Parse_Embedded (gib_tree_t *token) { - unsigned int i, n, t; + unsigned int i, n, t, start, end; char c, d, *str; - gib_tree_t *lines = 0, **line = &lines, *cur, *tokens, *emb, *tmp, **embfirst; - unsigned int start, end; + const char *program = token->str; + gib_tree_t *lines = 0, *cur, *tokens, **metanext, *temp; gib_parse_error = false; - embfirst = embedded; - *embedded = 0; + + metanext = &token->children; for (i = 0; program[i]; i++) { if (program[i] == '`' || (program[i] == '$' && program[i + 1] == '(')) { @@ -634,45 +416,56 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd goto ERROR; } end = i + 1; + // Construct the actual line to be executed - 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); - cur->str = str; - cur->start = start + pofs; - cur->end = end + pofs; + + // Reset error condition c = 0; + // Location to begin parsing from t = 0; - if (!(tokens = GIB_Parse_Tokens (cur->str, &t, start + pofs, &emb))) { - GIB_Tree_Unref (&cur); + + // Extract embedded command into a new string + str = calloc (end - start + 1, sizeof(char)); + memcpy (str, program + n, i - n); + + // Attempt to parse tokens from it + tokens = GIB_Parse_Tokens (str, &t, start + token->start); + if (!tokens) { + free (str); goto ERROR; } - cur->children = tokens; - GIB_Parse_Semantic_Preprocess (cur)->next = *embedded; + + // All settings for the line must be passed here + cur = GIB_Semantic_Tokens_To_Lines ( + tokens, str, TREE_L_EMBED, + start + token->start, + end + token->start + ); if (gib_parse_error) { - GIB_Tree_Unref (&cur); + free (str); goto ERROR; } - // Did this have embedded commands of it's own? - if (emb) { - // Link them in first - for (tmp = emb; tmp->next; tmp = tmp->next); - tmp->next = cur; - *embedded = emb; - } else - *embedded = cur; - // Create a representative child node for GIB_Process_Embedded to - // use + // Find last line + for (temp = cur; temp->next; temp = temp->next); + + // Link it to lines we already have + // (new lines are added to the start) + temp->next = lines; + lines = cur; + + // Create a representative child node for + // GIB_Process_Embedded to use cur = GIB_Tree_New (TREE_T_META); cur->delim = '`'; + // Save start/end indices cur->start = start; cur->end = end; - *line = cur; - line = &cur->next; - // Check for variable substitution + + // Link it to end of children list for token we are processing + *metanext = cur; + metanext = &cur->next; + // Check for variable substitution } else if (program[i] == '$' || program[i] == '#') { // Extract variable name start = i; @@ -699,8 +492,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd // Save start/end indices cur->start = start; cur->end = end; - *line = cur; - line = &cur->next; + *metanext = cur; + metanext = &cur->next; // Don't skip anything important if (program[n - 1] != '{') i--; @@ -709,10 +502,8 @@ GIB_Parse_Embedded (const char *program, unsigned int pofs, gib_tree_t ** embedd return lines; ERROR: if (c) - GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + pofs); + GIB_Parse_Error (va ("Could not find match for '%c'.", c), i + token->start); if (lines) GIB_Tree_Unref (&lines); - if (*embfirst) - GIB_Tree_Unref (embfirst); return 0; } diff --git a/libs/gib/gib_process.c b/libs/gib/gib_process.c index 3a9c8031a..af714c9b8 100644 --- a/libs/gib/gib_process.c +++ b/libs/gib/gib_process.c @@ -95,7 +95,7 @@ GIB_Process_Embedded (gib_tree_t * node, cbuf_args_t * args) Cbuf_ArgsAdd (args, retvals->dstrs[j]->str); args->argm[args->argc - 1] = node; } - if (str[prev] || retvals->size) // Still more stuff left? + if (str[prev] && retvals->size) // Still more stuff left? Cbuf_ArgsAdd (args, ""); } else dstring_appendstr (args->argv[args->argc - 1], diff --git a/libs/gib/gib_thread.c b/libs/gib/gib_thread.c index 478560860..f842f16b4 100644 --- a/libs/gib/gib_thread.c +++ b/libs/gib/gib_thread.c @@ -186,7 +186,7 @@ GIB_Event_Callback (gib_event_t * event, unsigned int argc, ...) va_end (ap); - GIB_Function_Execute (thread->cbuf, f, args->argv, args->argc); + GIB_Function_Execute_D (thread->cbuf, f, args->argv, args->argc); GIB_Thread_Add (thread); Cbuf_ArgsDelete (args); } diff --git a/tools/carne/main.c b/tools/carne/main.c index ca5c09e63..019277cb7 100644 --- a/tools/carne/main.c +++ b/tools/carne/main.c @@ -73,7 +73,7 @@ Carne_Execute_Script (const char *path, cbuf_args_t *args) goto ERROR; } - GIB_Function_Prepare_Args (mbuf, args->argv, args->argc); + GIB_Function_Prepare_Args_D (mbuf, args->argv, args->argc); // Main loop while (1) {