+
+ if (pp_token.type != TP_IDENTIFIER) {
+ errorf(&pp_token.source_position,
+ "expected identifier after #%s, got '%t'",
+ is_ifndef ? "ifndef" : "ifdef", &pp_token);
+ eat_pp_directive();
+
+ /* just take the true case in the hope to avoid further errors */
+ condition = true;
+ } else {
+ symbol_t *symbol = pp_token.symbol;
+ pp_definition_t *pp_definition = symbol->pp_definition;
+ next_preprocessing_token();
+
+ if (pp_token.type != '\n') {
+ errorf(&pp_token.source_position,
+ "extra tokens at end of #%s",
+ is_ifndef ? "ifndef" : "ifdef");
+ eat_pp_directive();
+ }
+
+ /* evaluate wether we are in true or false case */
+ condition = is_ifndef ? pp_definition == NULL : pp_definition != NULL;
+ }
+
+ pp_conditional_t *conditional = push_conditional();
+ conditional->source_position = pp_token.source_position;
+ conditional->condition = condition;
+
+ if (!condition) {
+ skip_mode = true;
+ }
+}
+
+static void parse_else_directive(void)
+{
+ eat_pp(TP_else);
+
+ if (pp_token.type != '\n') {
+ if (!skip_mode) {
+ warningf(WARN_OTHER, &pp_token.source_position, "extra tokens at end of #else");
+ }
+ eat_pp_directive();
+ }
+
+ pp_conditional_t *conditional = conditional_stack;
+ if (conditional == NULL) {
+ errorf(&pp_token.source_position, "#else without prior #if");
+ return;
+ }
+
+ if (conditional->in_else) {
+ errorf(&pp_token.source_position,
+ "#else after #else (condition started %P)",
+ conditional->source_position);
+ skip_mode = true;
+ return;
+ }
+
+ conditional->in_else = true;
+ if (!conditional->skip) {
+ skip_mode = conditional->condition;
+ }
+ conditional->source_position = pp_token.source_position;
+}
+
+static void parse_endif_directive(void)
+{
+ eat_pp(TP_endif);
+
+ if (pp_token.type != '\n') {
+ if (!skip_mode) {
+ warningf(WARN_OTHER, &pp_token.source_position, "extra tokens at end of #endif");
+ }
+ eat_pp_directive();
+ }
+
+ pp_conditional_t *conditional = conditional_stack;
+ if (conditional == NULL) {
+ errorf(&pp_token.source_position, "#endif without prior #if");
+ return;
+ }
+
+ if (!conditional->skip) {
+ skip_mode = false;
+ }
+ pop_conditional();