if(n)def implementation
authorMatthias Braun <matze@braunis.de>
Mon, 3 Nov 2008 16:25:11 +0000 (16:25 +0000)
committerMatthias Braun <matze@braunis.de>
Mon, 3 Nov 2008 16:25:11 +0000 (16:25 +0000)
[r23414]

main.c
preprocessor.c
preproctest/doubleif.c [new file with mode: 0644]
preproctest/header.h [new file with mode: 0644]
preproctest/ifdef.c [new file with mode: 0644]
preproctest/incifdef.c [new file with mode: 0644]
token.c

diff --git a/main.c b/main.c
index 7c5a982..2466581 100644 (file)
--- a/main.c
+++ b/main.c
 #endif
 
 /** The current c mode/dialect. */
-lang_features_t c_mode;
+lang_features_t c_mode = _C89 | _ANSI | _C99 | _GNUC;
 
 /** The 'machine size', 16, 32 or 64 bit, 32bit is the default. */
 unsigned int machine_size = 32;
index 012d90b..f47b28b 100644 (file)
@@ -31,6 +31,15 @@ struct pp_definition_t {
        token_t           *replacement_list;
 };
 
+typedef struct pp_conditional_t pp_conditional_t;
+struct pp_conditional_t {
+       source_position_t  source_position;
+       bool               condition;
+       bool               in_else;
+       bool               skip; /**< conditional in skip mode (then+else gets skipped) */
+       pp_conditional_t  *parent;
+};
+
 typedef struct pp_input_t pp_input_t;
 struct pp_input_t {
        FILE              *file;
@@ -50,16 +59,19 @@ static pp_input_t     *input_stack;
 static unsigned        n_inputs;
 static struct obstack  input_obstack;
 
+static pp_conditional_t *conditional_stack;
+
 token_t                   pp_token;
 static bool               resolve_escape_sequences = false;
 static bool               do_print_spaces          = true;
+static bool               do_expansions;
+static bool               skip_mode;
 static FILE              *out;
 static struct obstack     pp_obstack;
 static unsigned           counted_newlines;
 static unsigned           counted_spaces;
 static const char        *printed_input_name = NULL;
 static pp_definition_t   *current_expansion  = NULL;
-static bool               do_expansions;
 
 static inline void next_char(void);
 static void next_preprocessing_token(void);
@@ -1180,6 +1192,9 @@ static void print_spaces(void)
 
 static void emit_pp_token(void)
 {
+       if (skip_mode)
+               return;
+
        if (pp_token.type != '\n') {
                print_spaces();
                input.had_non_space = true;
@@ -1492,30 +1507,193 @@ static void parse_include_directive(void)
        }
 }
 
+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.v.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;
+               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(&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();
+}
+
 static void parse_preprocessing_directive(void)
 {
        do_print_spaces = false;
        do_expansions   = false;
        eat_pp('#');
 
-       switch(pp_token.type) {
-       case TP_define:
-               parse_define_directive();
-               break;
-       case TP_undef:
-               parse_undef_directive();
-               break;
-       case TP_include:
-               parse_include_directive();
-               /* no need to parse ending '\n' */
-               do_print_spaces = true;
-               do_expansions   = true;
-               return;
-       default:
-               errorf(&pp_token.source_position,
-                      "invalid preprocessing directive #%T", &pp_token);
-               eat_pp_directive();
-               break;
+       if (skip_mode) {
+               switch(pp_token.type) {
+               case TP_ifdef:
+               case TP_ifndef:
+                       parse_ifdef_ifndef_directive();
+                       break;
+               case TP_else:
+                       parse_else_directive();
+                       break;
+               case TP_endif:
+                       parse_endif_directive();
+                       break;
+               default:
+                       eat_pp_directive();
+                       break;
+               }
+       } else {
+               switch(pp_token.type) {
+               case TP_define:
+                       parse_define_directive();
+                       break;
+               case TP_undef:
+                       parse_undef_directive();
+                       break;
+               case TP_ifdef:
+               case TP_ifndef:
+                       parse_ifdef_ifndef_directive();
+                       break;
+               case TP_else:
+                       parse_else_directive();
+                       break;
+               case TP_endif:
+                       parse_endif_directive();
+                       break;
+               case TP_include:
+                       parse_include_directive();
+                       /* no need to parse ending '\n' */
+                       do_print_spaces = true;
+                       do_expansions   = true;
+                       return;
+               default:
+                       errorf(&pp_token.source_position,
+                                  "invalid preprocessing directive #%T", &pp_token);
+                       eat_pp_directive();
+                       break;
+               }
        }
 
        do_print_spaces = true;
@@ -1571,6 +1749,7 @@ int pptest_main(int argc, char **argv)
        }
 end_of_main_loop:
 
+       check_unclosed_conditionals();
        close_input();
 
        obstack_free(&input_obstack, NULL);
diff --git a/preproctest/doubleif.c b/preproctest/doubleif.c
new file mode 100644 (file)
index 0000000..e511c56
--- /dev/null
@@ -0,0 +1,21 @@
+#define DEFINED
+
+#ifndef NOT_DEFINE
+       #ifdef DEFINED
+               ok1
+       #else
+               bad
+       #endif
+#else
+       bad
+#endif
+
+#ifndef HEADER_H
+#define HEADER_H
+bla
+#ifndef HEADER_H
+#define HEADER_H
+#include "not_here.h"
+nbla
+#endif
+#endif
diff --git a/preproctest/header.h b/preproctest/header.h
new file mode 100644 (file)
index 0000000..b779b43
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef HEADER_H
+#define HEADER_H
+
+#include "preproctest/header.h"
+
+int in_the_header;
+
+#endif
diff --git a/preproctest/ifdef.c b/preproctest/ifdef.c
new file mode 100644 (file)
index 0000000..9a47ae6
--- /dev/null
@@ -0,0 +1,68 @@
+before
+#ifdef NOTDEFINED
+inside
+#endif
+after
+
+before
+#ifdef NOTDEFINED
+inside
+#else
+else
+#endif
+after
+
+before
+#ifndef NOTDEFINED
+inside
+#endif
+after
+
+before
+#ifndef NOTDEFINED
+inside
+#else
+else
+#endif
+after
+
+#define JO1    1
+#define JO2
+
+#ifdef JO1
+jo1 defined
+#else
+#endif
+
+#ifdef JO2
+jo2 defined
+#endif
+
+#ifndef JO1
+jo1 not defined
+#else
+#endif
+
+#ifndef JO2
+jo2 not defined
+#endif
+
+#undef JO2
+
+#ifdef JO1
+jo1 defined
+#else
+#endif
+
+#ifdef JO2
+jo2 defined
+#endif
+
+#ifndef JO1
+jo1 not defined
+#else
+#endif
+
+#ifndef JO2
+jo2 not defined
+#endif
diff --git a/preproctest/incifdef.c b/preproctest/incifdef.c
new file mode 100644 (file)
index 0000000..b4d99b8
--- /dev/null
@@ -0,0 +1,2 @@
+#include "preproctest/header.h"
+#include "preproctest/header.h"
diff --git a/token.c b/token.c
index 946f510..ad4dc0d 100644 (file)
--- a/token.c
+++ b/token.c
@@ -67,11 +67,13 @@ void init_tokens(void)
 #undef T
 
 #define T(mode,x,str,val)                                          \
-       assert(TP_##x >= 0 && TP_##x < TP_LAST_TOKEN);                 \
-       symbol                   = symbol_table_insert(str);           \
-       symbol->pp_ID            = TP_##x;                             \
-       if (pp_token_symbols[TP_##x] == NULL)                          \
-               pp_token_symbols[TP_##x] = symbol;
+       if (c_mode & (mode)) {                                         \
+               assert(TP_##x >= 0 && TP_##x < TP_LAST_TOKEN);             \
+               symbol                   = symbol_table_insert(str);       \
+               symbol->pp_ID            = TP_##x;                         \
+               if (pp_token_symbols[TP_##x] == NULL)                      \
+                       pp_token_symbols[TP_##x] = symbol;                     \
+       }
 
 #define TS(x,str,val)                                              \
        assert(TP_##x >= 0 && TP_##x < T_LAST_TOKEN);                  \
@@ -157,10 +159,10 @@ void print_pp_token_type(FILE *f, preprocessor_token_type_t token_type)
 
        const symbol_t *symbol = pp_token_symbols[token_type];
        if(symbol != NULL) {
-               fprintf(f, "'%s'", symbol->string);
+               fprintf(f, "%s", symbol->string);
        } else {
                if(token_type >= 0 && token_type < 256) {
-                       fprintf(f, "'%c'", token_type);
+                       fprintf(f, "%c", token_type);
                        return;
                }
                fputs("unknown token", f);