Added support for __FILE__ and __LINE__ to the preprocessor.
authorRyan C. Gordon <icculus@icculus.org>
Tue, 02 Mar 2010 10:04:35 -0800
changeset 875 dc28354d576e
parent 874 24cf91180d22
child 876 e005b1f38952
Added support for __FILE__ and __LINE__ to the preprocessor.
mojoshader_preprocessor.c
--- a/mojoshader_preprocessor.c	Fri Feb 26 02:37:01 2010 -0500
+++ b/mojoshader_preprocessor.c	Tue Mar 02 10:04:35 2010 -0800
@@ -44,6 +44,8 @@
     char failstr[256];
     int recursion_count;
     int asm_comments;
+    int file_macro_special;
+    int line_macro_special;
     Conditional *conditional_pool;
     IncludeState *include_stack;
     IncludeState *include_pool;
@@ -434,7 +436,8 @@
     {
         if (strcmp(bucket->identifier, sym) == 0)
         {
-            failf(ctx, "'%s' already defined", sym);
+            failf(ctx, "'%s' already defined", sym); // !!! FIXME: warning?
+            // !!! FIXME: gcc reports the location of previous #define here.
             return 0;
         } // if
         bucket = bucket->next;
@@ -669,6 +672,8 @@
     ctx->open_callback = open_callback;
     ctx->close_callback = close_callback;
     ctx->asm_comments = asm_comments;
+    ctx->file_macro_special = 1;
+    ctx->line_macro_special = 1;
     ctx->filename_cache = stringcache_create(m, f, d);
     if (ctx->filename_cache == 0)
     {
@@ -991,6 +996,20 @@
         return;
     } // if
 
+    // Don't treat these symbols as special anymore if they get (re)#defined.
+    if (strcmp(sym, "__FILE__") == 0)
+    {
+        if (ctx->file_macro_special)
+            failf(ctx, "'%s' already defined", sym); // !!! FIXME: warning?
+        ctx->file_macro_special = 0;
+    } // if
+    else if (strcmp(sym, "__LINE__") == 0)
+    {
+        if (ctx->line_macro_special)
+            failf(ctx, "'%s' already defined", sym); // !!! FIXME: warning?
+        ctx->line_macro_special = 0;
+    } // else if
+
     // #define a(b) is different than #define a (b)    :(
     state->report_whitespace = 1;
     lexer(state);
@@ -1180,6 +1199,19 @@
         return;
     } // if
 
+    if (strcmp(sym, "__FILE__") == 0)
+    {
+        if ((ctx->file_macro_special) && (find_define(ctx, sym) == NULL))
+            failf(ctx, "undefining \"%s\"", sym);  // !!! FIXME: should be warning.
+        ctx->file_macro_special = 0;
+    } // if
+    else if (strcmp(sym, "__LINE__") == 0)
+    {
+        if ((ctx->line_macro_special) && (find_define(ctx, sym) == NULL))
+            failf(ctx, "undefining \"%s\"", sym);  // !!! FIXME: should be warning.
+        ctx->line_macro_special = 0;
+    } // if
+
     remove_define(ctx, sym);
 } // handle_pp_undef
 
@@ -1260,6 +1292,46 @@
 
     Define *params = NULL;
 
+    if ( (ctx->file_macro_special) && (strcmp(sym, "__FILE__") == 0) )
+    {
+        const char *fname = state->filename;
+        const unsigned int line = state->line;
+        const size_t len = strlen(fname) + 2;
+        char *str = (char *) Malloc(ctx, len);
+        if (!str)
+            return 0;
+        str[0] = '\"';
+        memcpy(str + 1, fname, len - 2);
+        str[len - 1] = '\"';
+        if (!push_source(ctx,fname,str,len,line,close_define_include,NULL,1))
+        {
+            assert(ctx->out_of_memory);
+            Free(ctx, str);
+            return 0;
+        } // if
+        return 1;
+    } // if
+
+    else if ( (ctx->line_macro_special) && (strcmp(sym, "__LINE__") == 0) )
+    {
+        const char *fname = state->filename;
+        const unsigned int line = state->line;
+        const size_t bufsize = 32;
+        char *str = (char *) Malloc(ctx, bufsize);
+        if (!str)
+            return 0;
+
+        const size_t len = snprintf(str, bufsize, "%u", line);
+        assert(len < bufsize);
+        if (!push_source(ctx,fname,str,len,line,close_define_include,NULL,1))
+        {
+            assert(ctx->out_of_memory);
+            Free(ctx, str);
+            return 0;
+        } // if
+        return 1;
+    } // else
+
     // IncludeState defines (macro args) take precedence over Context defines.
     const Define *def = find_macro_arg(state);
     if (def == NULL)