/** * Skip through the text to a matching "#endif" or "#else" or * "#elif*def". We do this when we are skipping code due to a failed * "#if*def" test. */ static char * skip_to_else_end(char * start) { char * scan = start; char * res; for (;;) { scan = next_directive(scan); switch (find_directive(scan)) { case DIR_ELSE: /* * We found an "else" directive for an "ifdef"/"ifndef" * that we were skipping over. Start processing the text. * Let the @code{DIR_ENDIF} advance the scanning pointer. */ ifdef_lvl++; /* FALLTHROUGH */ case DIR_ENDIF: { /* * We reached the end of the "ifdef"/"ifndef" (or transitioned to * process-the-text mode via "else"). Start processing the text. */ char * pz = strchr(scan, NL); if (pz != NULL) res = pz+1; else res = scan + strlen(scan); goto leave_func; } case DIR_IF: skip_if_block = true; scan = skip_to_endif(scan); skip_if_block = false; break; case DIR_IFDEF: case DIR_IFNDEF: scan = skip_to_endif(scan); break; default: /* * We either don't know what it is or we do not care. */ break; } /* switch (find_directive(scan)) */ } leave_func: cctx->scx_line += count_lines(start, res); return res; }
/** * This must follow an @code{#if}, @code{#ifdef} or @code{#ifndef}. * If it follows the @code{#if}, then it will be ignored. Otherwise, * it will change the processing state to the reverse of what it was. */ char * doDir_else(directive_enum_t id, char const * arg, char * scan_next) { if (--ifdef_lvl < 0) return bad_dirv_ctx(id, arg, scan_next); return skip_to_endif(scan_next); }
/** * @code{#if} expressions are not analyzed. @strong{Everything} from here * to the matching @code{#endif} is skipped. */ char * doDir_if(directive_enum_t id, char const * arg, char * scan_next) { skip_if_block = true; scan_next = skip_to_endif(scan_next); skip_if_block = false; (void)arg; (void)id; return scan_next; }
static void if_handle(state_t* state, match_t* match, bool* reprocess) { list_t* result = ppparam_get(state); struct expr* expr = NULL; uint16_t value; bstring output; bool stopped_at_else; // Ensure the parameter format is correct. if (list_size(result) == 1 && ((parameter_t*)list_get_at(result, 0))->type == EXPRESSION) { // Get the expression. expr = ((parameter_t*)list_get_at(result, 0))->expr; replace_state = state; value = expr_evaluate(expr, &if_define_replace, &dhalt_expression_exit_handler); replace_state = NULL; if (value) { output = skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) skip_to_endif(state, false, &stopped_at_else); } else { bassigncstr(output, ""); skip_to_endif(state, true, &stopped_at_else); if (stopped_at_else) { output = skip_to_endif(state, false, &stopped_at_else); } } // print the output to the pre processor input ppimpl_printf(state, "%s", output->data); } else dhalt(ERR_PP_ASM_IF_PARAMETERS_INCORRECT, ppimpl_get_location(state)); ppparam_free(result); }
/** * Skip through the text to a matching "#endif". We do this when we * have processed the allowable text (found an "#else" after * accepting the preceding text) or when encountering a "#if*def" * while skipping a block of text due to a failed test. */ static char * skip_to_endif(char * start) { bool skipping_if = skip_if_block; char * scan = start; char * dirv_end; for (;;) { scan = next_directive(scan); switch (find_directive(scan)) { case DIR_ENDIF: { /* * We found the endif we are interested in */ char * pz = strchr(scan, NL); if (pz != NULL) dirv_end = pz+1; else dirv_end = scan + strlen(scan); goto leave_func; } case DIR_ELIF: if (! skip_if_block) AG_ABEND(ELIF_CONTEXT_MSG); break; case DIR_IF: skip_if_block = true; /* FALLTHROUGH */ case DIR_IFDEF: case DIR_IFNDEF: /* * We found a nested conditional, so skip to endif nested, too. */ scan = skip_to_endif(scan); skip_if_block = skipping_if; break; default: /* * We do not care what we found */ break; /* ignore it */ } /* switch (find_directive(scan)) */ } leave_func: cctx->scx_line += count_lines(start, dirv_end); return dirv_end; }