+ return false;
+ }
+
+ return true;
+}
+
+static pp_conditional_t *push_conditional(void)
+{
+ pp_conditional_t *conditional
+ = obstack_alloc(&pp_obstack, sizeof(*conditional));
+ memset(conditional, 0, sizeof(*conditional));
+
+ conditional->parent = conditional_stack;
+ conditional_stack = conditional;
+
+ return conditional;
+}
+
+static void pop_conditional(void)
+{
+ assert(conditional_stack != NULL);
+ conditional_stack = conditional_stack->parent;
+}
+
+static void check_unclosed_conditionals(void)
+{
+ while (conditional_stack != NULL) {
+ pp_conditional_t *conditional = conditional_stack;
+
+ if (conditional->in_else) {
+ errorf(&conditional->source_position, "unterminated #else");
+ } else {
+ errorf(&conditional->source_position, "unterminated condition");
+ }
+ pop_conditional();
+ }
+}
+
+static void parse_ifdef_ifndef_directive(void)
+{
+ bool is_ifndef = (pp_token.type == TP_ifndef);
+ bool condition;
+ next_preprocessing_token();
+
+ if (skip_mode) {
+ eat_pp_directive();
+ pp_conditional_t *conditional = push_conditional();
+ conditional->source_position = pp_token.source_position;
+ conditional->skip = true;
+ return;
+ }
+
+ 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(&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;