ParseNode* new_node(void *malloc_pool, ObItemType type, int num) { ParseNode* node = (ParseNode*)parse_malloc(sizeof(ParseNode), malloc_pool); if (node != NULL) { memset(node, 0 , sizeof(ParseNode)); node->type_ = type; node->num_child_ = num; if(num > 0) { int64_t alloc_size = sizeof(ParseNode*) * num ; //node->children_ = (ParseNode**)malloc(alloc_size); node->children_ = (ParseNode**)parse_malloc(alloc_size, malloc_pool); if (node->children_ != NULL) { memset(node->children_, 0, alloc_size); } else { parse_free(node); node = NULL; } } else { node->children_ = 0; } } return node; }
void parse_file( OBJECT * f, FRAME * frame ) { /* Suspend scan of current file and push this new file in the stream. */ yyfparse( f ); /* Now parse each block of rules and execute it. Execute it outside of the * parser so that recursive calls to yyrun() work (no recursive yyparse's). */ for ( ; ; ) { PARSE * p; FUNCTION * func; /* Filled by yyparse() calling parse_save(). */ yypsave = 0; /* If parse error or empty parse, outta here. */ if ( yyparse() || !( p = yypsave ) ) break; /* Run the parse tree. */ func = function_compile( p ); parse_free( p ); list_free( function_run( func, frame, stack_global() ) ); function_free( func ); } yyfdone(); }
void destroy_token_list(token_list_t *list) { int i; for(i=0; i< list->max_tokens; i++) { if (TK[i] != 0) parse_free(TK[i]); } }
void destroy_tree(ParseNode* root) { int i; if(root == 0) return; for(i = 0; i < root->num_child_; ++i) { destroy_tree(root->children_[i]); } if(root->str_value_ != NULL) { parse_free((char*)root->str_value_); } if(root->num_child_) { parse_free(root->children_); } parse_free(root); }
void parse_free( PARSE * p ) { if ( --p->refs ) return; if ( p->string ) object_free( p->string ); if ( p->string1 ) object_free( p->string1 ); if ( p->left ) parse_free( p->left ); if ( p->right ) parse_free( p->right ); if ( p->third ) parse_free( p->third ); if ( p->rulename ) object_free( p->rulename ); if ( p->file ) object_free( p->file ); BJAM_FREE( (char *)p ); }
void mbox_free (mbox_t *mbox) { register thrdqueue_t *q = mbox->mail_queue; /* Join with thread */ pthread_join(mbox->parser_th, NULL); thq_delete(q, (void (*)(void *))mbox_mail_free); parse_free(&mbox->parse); dstrbuf_free(mbox->aux.multiline); free(mbox); }
void parse_free( PARSE *p ) { if( --p->refs ) return; if( p->string ) freestr( p->string ); if( p->string1 ) freestr( p->string1 ); if( p->left ) parse_free( p->left ); if( p->right ) parse_free( p->right ); if( p->third ) parse_free( p->third ); #ifdef OPT_IMPROVED_MEMUSE_EXT mempool_free(parse_pool, p); #else free( (char *)p ); #endif }
/* * set_rule_body() - set the argument list and procedure of the given rule */ static void set_rule_body( RULE* rule, argument_list* args, PARSE* procedure ) { if ( args ) args_refer( args ); if ( rule->arguments ) args_free( rule->arguments ); rule->arguments = args; if ( procedure ) parse_refer( procedure ); if ( rule->procedure ) parse_free( rule->procedure ); rule->procedure = procedure; }
void rule_free( RULE* r ) { freestr( r->name ); r->name = ""; parse_free( r->procedure ); r->procedure = 0; if ( r->arguments ) args_free( r->arguments ); r->arguments = 0; if ( r->actions ) actions_free( r->actions ); r->actions = 0; }
LIST * compile_setcomp( PARSE *parse, LOL *args, int *jmp ) { RULE *rule = bindrule( parse->string ); LIST *params = 0; PARSE *p; /* Build param list */ for( p = parse->left; p; p = p->left ) params = list_append( params, p->string, 1 ); if( DEBUG_COMPILE ) { debug_compile( 0, "rule" ); printf( "%s ", parse->string ); list_print( params ); printf( "\n" ); } /* Free old one, if present */ if( rule->procedure ) parse_free( rule->procedure ); if( rule->params ) list_free( rule->params ); rule->procedure = parse->right; rule->params = params; /* we now own this parse tree */ /* don't let parse_free() release it */ parse_refer( parse->right ); return L0; }
/** * Simplify the command and call one of the sub parser functions * * @param cmd Raw command string. This parameter is mutated. This * parameter cannot be NULL. * @param cmd_len Length in bytes of the command string. * @return Program status. */ static status_t parse_command(char* cmd, int cmd_len) { assert(cmd != NULL); int ws_cursor = 0; if (cmd[0] == '\0' || cmd[0] == '\n' || cmd[0] == '\r') return SUCCESS; // remove whitespace from command for (int i = 0; i < cmd_len; ++i) { switch (cmd[i]) { case ' ': case '\n': case '\r': case '\t': break; default: cmd[ws_cursor++] = cmd[i]; } } status_t status; // We have 2 commands: alloc and free. if (strstr(cmd, "alloc") != NULL) status = parse_alloc(cmd); else if (strstr(cmd, "free") != NULL) status = parse_free(cmd); else return parse_error(cmd); if (status != SUCCESS) return status; // Output free blocks buddy_dump(); return SUCCESS; }
void parse_lines( const char *s, char** lines ) { /* Suspend scan of current file */ /* and push this new file in the stream */ yyfparselines(s, lines); /* Now parse each block of rules and execute it. */ /* Execute it outside of the parser so that recursive */ /* calls to yyrun() work (no recursive yyparse's). */ for(;;) { LOL l; PARSE *p; int jmp = 0; /* JMP_NONE */ /* $(<) and $(>) empty in outer scope. */ lol_init( &l ); /* Filled by yyparse() calling parse_save() */ yypsave = 0; /* If parse error or empty parse, outta here */ if( yyparse() || !( p = yypsave ) ) break; /* Run the parse tree. */ list_free( (*(p->func))( p, &l, &jmp ) ); parse_free( p ); } }
int vmmaction(struct parse_result *res) { struct sockaddr_un sun; struct imsg imsg; int done = 0; int n; int ret, action; if (ctl_sock == -1) { if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0)) == -1) err(1, "socket"); bzero(&sun, sizeof(sun)); sun.sun_family = AF_UNIX; strlcpy(sun.sun_path, socket_name, sizeof(sun.sun_path)); if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) err(1, "connect: %s", socket_name); if ((ibuf = malloc(sizeof(struct imsgbuf))) == NULL) err(1, "malloc"); imsg_init(ibuf, ctl_sock); } switch (res->action) { case CMD_START: /* XXX validation should be done in start_vm() */ if (res->size < 1) errx(1, "specified memory size too small"); if (res->path == NULL) errx(1, "no kernel specified"); if (res->ndisks > VMM_MAX_DISKS_PER_VM) errx(1, "too many disks"); else if (res->ndisks == 0) warnx("starting without disks"); if (res->nifs == -1) res->nifs = 0; if (res->nifs == 0) warnx("starting without network interfaces"); ret = start_vm(res->name, res->size, res->nifs, res->ndisks, res->disks, res->path); if (ret) { errno = ret; err(1, "start VM operation failed"); } break; case CMD_STOP: terminate_vm(res->id, res->name); break; case CMD_STATUS: get_info_vm(res->id, res->name, 0); break; case CMD_CONSOLE: get_info_vm(res->id, res->name, 1); break; case CMD_RELOAD: imsg_compose(ibuf, IMSG_VMDOP_RELOAD, 0, 0, -1, res->path, res->path == NULL ? 0 : strlen(res->path) + 1); done = 1; break; case CMD_LOAD: imsg_compose(ibuf, IMSG_VMDOP_LOAD, 0, 0, -1, res->path, res->path == NULL ? 0 : strlen(res->path) + 1); done = 1; break; case CMD_CREATE: case NONE: break; } action = res->action; parse_free(res); while (ibuf->w.queued) if (msgbuf_write(&ibuf->w) <= 0 && errno != EAGAIN) err(1, "write error"); while (!done) { if ((n = imsg_read(ibuf)) == -1 && errno != EAGAIN) errx(1, "imsg_read error"); if (n == 0) errx(1, "pipe closed"); while (!done) { if ((n = imsg_get(ibuf, &imsg)) == -1) errx(1, "imsg_get error"); if (n == 0) break; if (imsg.hdr.type == IMSG_CTL_FAIL) { if (IMSG_DATA_SIZE(&imsg) == sizeof(ret)) { memcpy(&ret, imsg.data, sizeof(ret)); errno = ret; warn("command failed"); } else { warnx("command failed"); } done = 1; break; } ret = 0; switch (action) { case CMD_START: done = start_vm_complete(&imsg, &ret, tty_autoconnect); break; case CMD_STOP: done = terminate_vm_complete(&imsg, &ret); break; case CMD_CONSOLE: case CMD_STATUS: done = add_info(&imsg, &ret); break; default: done = 1; break; } imsg_free(&imsg); } } return (0); }
LIST * evaluate_rule( char * rulename, FRAME * frame ) { LIST * result = L0; RULE * rule; profile_frame prof[1]; module_t * prev_module = frame->module; LIST * l; { LOL arg_context_, * arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if ( rule->python_function ) { /* The below messing with modules is due to the way modules are * implemented in Jam. Suppose we are in module M1 now. The global * variable map actually holds 'M1' variables, and M1->variables hold * global variables. * * If we call Python right away, Python calls back Jam and then Jam * does 'module M1 { }' then Jam will try to swap the current global * variables with M1->variables. The result will be that global * variables map will hold global variables, and any variable settings * we do will go to the global module, not M1. * * By restoring basic state, where the global variable map holds global * variable, we make sure any future 'module M1' entry will work OK. */ LIST * result; module_t * m = python_module(); frame->module = m; exit_module( prev_module ); enter_module( m ); result = call_python_function( rule, frame ); exit_module( m ); enter_module ( prev_module ); return result; } #endif /* Drop the rule name. */ l = list_pop_front( l ); /* Tack the rest of the expansion onto the front of the first argument. */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute. */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp( rulename, rule->procedure->rulename ) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof( buf ) - 1 ); strncat( buf, rule->name, sizeof( buf ) - 1 ); debug_compile( 1, buf, frame ); } else { debug_compile( 1, rulename, frame ); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* Propagate current module to nested rule invocations. */ frame->module = rule->module; /* Swap variables. */ exit_module( prev_module ); enter_module( rule->module ); } /* Record current rule name in frame. */ if ( rule->procedure ) { frame->rulename = rulename; /* And enter record profile info. */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>). */ if ( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit( 1 ); } /* If this rule will be executed for updating the targets then construct the * action for make(). */ if ( rule->actions ) { TARGETS * t; ACTION * action; /* The action is associated with this instance of this rule. */ action = (ACTION *)BJAM_MALLOC( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* If we have a group of targets all being built using the same action * then we must not allow any of them to be used as sources unless they * had all already been built in the first place or their joined action * has had a chance to finish its work and build all of them anew. * * Without this it might be possible, in case of a multi-process build, * for their action, triggered by buiding one of the targets, to still * be running when another target in the group reports as done in order * to avoid triggering the same action again and gets used prematurely. * * As a quick-fix to achieve this effect we make all the targets list * each other as 'included targets'. More precisely, we mark the first * listed target as including all the other targets in the list and vice * versa. This makes anyone depending on any of those targets implicitly * depend on all of them, thus making sure none of those targets can be * used as sources until all of them have been built. Note that direct * dependencies could not have been used due to the 'circular * dependency' issue. * * TODO: Although the current implementation solves the problem of one * of the targets getting used before its action completes its work it * also forces the action to run whenever any of the targets in the * group is not up to date even though some of them might not actually * be used by the targets being built. We should see how we can * correctly recognize such cases and use that to avoid running the * action if possible and not rebuild targets not actually depending on * targets that are not up to date. * * TODO: Using the 'include' feature might have side-effects due to * interaction with the actual 'inclusion scanning' system. This should * be checked. */ if ( action->targets ) { TARGET * t0 = action->targets->target; for ( t = action->targets->next; t; t = t->next ) { target_include( t->target, t0 ); target_include( t0, t->target ); } } /* Append this action to the actions of each target. */ for ( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule. * parse_refer()/parse_free() call pair added to ensure rule not freed * during use. */ if ( rule->procedure ) { SETTINGS * local_args = collect_arguments( rule, frame ); PARSE * parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if ( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result ) { #ifdef OPT_EXPAND_RULE_NAMES_EXT RULE *rule; char *expanded; char *c; int i; BUFFER buff; buffer_init( &buff ); if( (i = var_string( rulename, &buff, 0, args, ' ' )) < 0 ) { printf( "Failed to expand rule %s -- expansion too long\n", rulename ); exit( EXITBAD ); } expanded = buffer_ptr( &buff ); while ( expanded[0] == ' ' ) expanded++; while ( (c = strrchr(expanded, ' ')) ) *c = '\0'; if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); if ( strcmp(rulename, expanded) ) printf( "-> %s ", expanded ); lol_print( args ); printf( "\n" ); } rule = bindrule( expanded ); #else RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } #endif #ifdef OPT_LOAD_MISSING_RULE_EXT if( !rule->actions && !rule->procedure ) { if( ruleexists( "FindMissingRule" ) ) { LOL lol; LIST *args = list_append( L0, expanded, 0 ); LIST *result; lol_init( &lol ); lol_add( &lol, args ); result = evaluate_rule( "FindMissingRule", &lol, L0 ); lol_free( &lol ); if( list_first( result ) ) { rule = bindrule( list_value( list_first( result ) ) ); } list_free( result ); } } #endif /* OPT_LOAD_MISSING_RULE_EXT */ /* Check traditional targets $(<) and sources $(>) */ #ifdef OPT_IMPROVED_WARNINGS_EXT if( !rule->actions && !rule->procedure && !globs.silence ) printf( "warning: unknown rule %s %s\n", rule->name, file_and_line()); #else if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); #endif /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; #ifdef OPT_BUILTIN_NEEDS_EXT action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ), 0 ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ), 0 ); action->autosettings = targetlist( (TARGETS *)0, lol_get( args, 2 ), 0 ); #else action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); #endif #ifdef OPT_USE_CHECKSUMS_EXT action->extratargets = targetlist( (TARGETS *)0, lol_get( args, 3 ), 0 ); #endif /* OPT_USE_CHECKSUMS_EXT */ #ifdef OPT_CLEAN_GLOBS_EXT { TARGETS* targets; for ( targets = action->targets; targets; targets = targets->next ) { if ( !( targets->target->flags & T_FLAG_NOTFILE ) ) add_used_target_to_hash( targets->target ); } } #endif /* OPT_CLEAN_GLOBS_EXT */ /* Append this action to the actions of each target */ #ifdef OPT_MULTIPASS_EXT action->pass = actionpass; for( t = action->targets; t; t = t->next ) { t->target->progress = T_MAKE_INIT; t->target->actions = actionlist( t->target->actions, action ); } #else for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); #endif } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; int jmp = JMP_NONE; LISTITEM *l; int i; /* build parameters as local vars */ for( l = list_first(rule->params), i = 0; l; l = list_next(l), i++ ) s = addsettings( s, 0, list_value(l), list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_appendList( result, (*parse->func)( parse, args, &jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); #ifdef OPT_EXPAND_RULE_NAMES_EXT buffer_free( &buff ); #endif return result; }
LIST * evaluate_rule( const char *rulename, LOL *args, LIST *result, int *jmp ) { RULE *rule = bindrule( rulename ); if( DEBUG_COMPILE ) { debug_compile( 1, rulename ); lol_print( args ); printf( "\n" ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) printf( "warning: unknown rule %s\n", rule->name ); /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ if( rule->procedure ) { PARSE *parse = rule->procedure; SETTINGS *s = 0; LIST *l; int i; # ifdef OPT_RULE_PROFILING_EXT struct timeval startTime, endTime; if ( DEBUG_PROFILE_RULES ) gettimeofday(&startTime, 0); # endif /* build parameters as local vars */ for( l = rule->params, i = 0; l; l = l->next, i++ ) s = addsettings( s, 0, l->string, list_copy( L0, lol_get( args, i ) ) ); /* Run rule. */ /* Bring in local params. */ /* refer/free to ensure rule not freed during use. */ parse_refer( parse ); pushsettings( s ); result = list_append( result, (*parse->func)( parse, args, jmp ) ); popsettings( s ); freesettings( s ); parse_free( parse ); # ifdef OPT_RULE_PROFILING_EXT if ( DEBUG_PROFILE_RULES ) { gettimeofday(&endTime, 0); rule->invocations++; rule->invocation_time += (endTime.tv_sec - startTime.tv_sec) * (int64_t)1000000 + (endTime.tv_usec - startTime.tv_usec); } # endif } if( DEBUG_COMPILE ) debug_compile( -1, 0 ); return result; }
/** * @brief Run command described by string stored in buffer * * @param buffer command to be executed * * @return true on success */ static void * run_command(void * p) { UNUSED(p); char ** cmd = NULL; int ret; int i = 0; struct parse_list_t cmd_list; struct parse_litem_t * it; pthread_mutex_lock(&buffer_mutex_exec); pthread_cond_wait(&buffer_cond_exec, &buffer_mutex_exec); while (! g_exit) { parse_list_init(&cmd_list); if (! parse_command(&cmd_list, buffer)) { print_error(ERR_PARSE_FAILED); goto signalize; } if (cmd_list.length == 1 && ! strcmp(cmd_list.head->token, CMD_EXIT)) { g_exit = true; goto signalize; } //write(1, MSG_COMMAND, strlen(MSG_COMMAND)); if (cmd_list.length == 0) { goto signalize; // nothing to do } cmd = (char **) malloc((cmd_list.length + 1) * sizeof(char *)); if (! cmd) { parse_free(&cmd_list); goto signalize; } for (it = cmd_list.head, i = 0; it; it = it->next, ++i) { //printf("cmd[%d] == %s\n", i, it->token); cmd[i] = it->token; } cmd[cmd_list.length] = (char *) 0; ret = vfork(); if (ret < 0) { perror("fork failed"); } else if (ret == 0) { // child // open input if (cmd_list.input) { ret = open(cmd_list.input, O_RDONLY); if (ret < 0) { perror(cmd_list.input); exit(EXIT_FAILURE); } if (dup2(ret, STDIN_FILENO) < 0) { perror("dup2 STDIN_FILENO"); exit(EXIT_FAILURE); } } else if (cmd_list.background) { close(STDIN_FILENO); } // open output if (cmd_list.output) { ret = open(cmd_list.output, O_WRONLY | O_CREAT | O_TRUNC, 0666); if (ret < 0) { perror(cmd_list.output); exit(EXIT_FAILURE); } if (dup2(ret, STDOUT_FILENO) < 0) { perror("dup2 STDOUT_FILENO"); exit(EXIT_FAILURE); } } /* * Restore signal handlers */ signal_handler_restore(); if (cmd_list.background) { pidlist_insert(&pidlist, getpid()); fprintf(stderr, "\r>>> child %d is running in background\n", getpid()); } else { // run in foreground, unblock SIGINT sigint_unblock(); } // run it! :-* ret = execvp(cmd_list.head->token, cmd); if (ret < 0) { perror(cmd_list.head->token); exit(EXIT_FAILURE); } } else { // parent if (! cmd_list.background) waitpid(ret, NULL, 0); } signalize: if (cmd) { free(cmd); cmd = NULL; } parse_free(&cmd_list); buffer[0] = '\0'; // mark buffer as empty pthread_cond_signal(&buffer_cond_read); if (! g_exit) // wait only if no exit signaled pthread_cond_wait(&buffer_cond_exec, &buffer_mutex_exec); } // g_exit pthread_mutex_unlock(&buffer_mutex_exec); return NULL; }
LIST * evaluate_rule( char *rulename, FRAME *frame ) { LIST *result = L0; RULE *rule; profile_frame prof[1]; module_t *prev_module = frame->module; LIST *l; { LOL arg_context_, *arg_context = &arg_context_; if ( !frame->prev ) lol_init(arg_context); else arg_context = frame->prev->args; l = var_expand( L0, rulename, rulename+strlen(rulename), arg_context, 0 ); } if ( !l ) { backtrace_line( frame->prev ); printf( "warning: rulename %s expands to empty string\n", rulename ); backtrace( frame->prev ); return result; } rulename = l->string; rule = bindrule( l->string, frame->module ); #ifdef HAVE_PYTHON if (rule->python_function) { return call_python_function(rule, frame); } #endif /* drop the rule name */ l = list_pop_front( l ); /* tack the rest of the expansion onto the front of the first argument */ frame->args->list[0] = list_append( l, lol_get( frame->args, 0 ) ); if ( DEBUG_COMPILE ) { /* Try hard to indicate in which module the rule is going to execute */ if ( rule->module != frame->module && rule->procedure != 0 && strcmp(rulename, rule->procedure->rulename) ) { char buf[256] = ""; strncat( buf, rule->module->name, sizeof(buf) - 1 ); strncat( buf, rule->name, sizeof(buf) - 1 ); debug_compile( 1, buf, frame); } else { debug_compile( 1, rulename, frame); } lol_print( frame->args ); printf( "\n" ); } if ( rule->procedure && rule->module != prev_module ) { /* propagate current module to nested rule invocations */ frame->module = rule->module; /* swap variables */ exit_module( prev_module ); enter_module( rule->module ); } /* record current rule name in frame */ if ( rule->procedure ) { frame->rulename = rulename; /* and enter record profile info */ if ( DEBUG_PROFILE ) profile_enter( rule->procedure->rulename, prof ); } /* Check traditional targets $(<) and sources $(>) */ if( !rule->actions && !rule->procedure ) { backtrace_line( frame->prev ); printf( "rule %s unknown in module %s\n", rule->name, frame->module->name ); backtrace( frame->prev ); exit(1); } /* If this rule will be executed for updating the targets */ /* then construct the action for make(). */ if( rule->actions ) { TARGETS *t; ACTION *action; /* The action is associated with this instance of this rule */ action = (ACTION *)malloc( sizeof( ACTION ) ); memset( (char *)action, '\0', sizeof( *action ) ); action->rule = rule; action->targets = targetlist( (TARGETS *)0, lol_get( frame->args, 0 ) ); action->sources = targetlist( (TARGETS *)0, lol_get( frame->args, 1 ) ); /* Append this action to the actions of each target */ for( t = action->targets; t; t = t->next ) t->target->actions = actionlist( t->target->actions, action ); } /* Now recursively compile any parse tree associated with this rule */ /* refer/free to ensure rule not freed during use */ if( rule->procedure ) { SETTINGS *local_args = collect_arguments( rule, frame ); PARSE *parse = rule->procedure; parse_refer( parse ); pushsettings( local_args ); result = parse_evaluate( parse, frame ); popsettings( local_args ); freesettings( local_args ); parse_free( parse ); } if ( frame->module != prev_module ) { exit_module( frame->module ); enter_module( prev_module ); } if ( DEBUG_PROFILE && rule->procedure ) profile_exit( prof ); if( DEBUG_COMPILE ) debug_compile( -1, 0, frame); return result; }