[gtk+/wip/otte/shader: 70/176] gskslpreprocessor: Implement #ifdef, #else and #endif



commit 47a845a1c0b2db05cda779c49cb99b947ee4f455
Author: Benjamin Otte <otte redhat com>
Date:   Sun Oct 1 02:03:44 2017 +0200

    gskslpreprocessor: Implement #ifdef, #else and #endif

 gsk/gskslpreprocessor.c |  229 ++++++++++++++++++++++++++++++++++++++++++-----
 1 files changed, 208 insertions(+), 21 deletions(-)
---
diff --git a/gsk/gskslpreprocessor.c b/gsk/gskslpreprocessor.c
index 8368750..11f39df 100644
--- a/gsk/gskslpreprocessor.c
+++ b/gsk/gskslpreprocessor.c
@@ -40,8 +40,18 @@ struct _GskSlPreprocessor
   GArray *tokens;
   GHashTable *defines;
   gboolean fatal_error;
+  GSList *conditionals;
 };
 
+typedef enum {
+  /* ignore this part, the last conditional check didn't match */
+  GSK_COND_IGNORE = (1 << 0),
+  /* we're inside the else block, so no more elif */
+  GSK_COND_ELSE = (1 << 1),
+  /* we've had a match in one of the previous blocks (or this one matches) */
+  GSK_COND_MATCH = (1 << 2)
+} GskConditional;
+
 /* API */
 
 static void
@@ -104,6 +114,7 @@ gsk_sl_preprocessor_unref (GskSlPreprocessor *preproc)
   if (preproc->ref_count > 0)
     return;
 
+  g_slist_free (preproc->conditionals);
   g_hash_table_destroy (preproc->defines);
   gsk_sl_tokenizer_unref (preproc->tokenizer);
   g_object_unref (preproc->compiler);
@@ -118,6 +129,43 @@ gsk_sl_preprocessor_has_fatal_error (GskSlPreprocessor *preproc)
   return preproc->fatal_error;
 }
 
+static void
+gsk_sl_preprocessor_push_conditional (GskSlPreprocessor *preproc,
+                                      GskConditional     cond)
+{
+  preproc->conditionals = g_slist_prepend (preproc->conditionals, GUINT_TO_POINTER (cond));
+}
+
+static GskConditional
+gsk_sl_preprocessor_pop_conditional (GskSlPreprocessor *preproc)
+{
+  GskConditional cond = GPOINTER_TO_UINT (preproc->conditionals->data);
+
+  preproc->conditionals = g_slist_remove (preproc->conditionals, preproc->conditionals->data);
+
+  return cond;
+}
+
+static gboolean
+gsk_sl_preprocessor_has_conditional (GskSlPreprocessor *preproc)
+{
+  return preproc->conditionals != NULL;
+}
+
+static gboolean
+gsk_sl_preprocessor_in_ignored_conditional (GskSlPreprocessor *preproc)
+{
+  GSList *l;
+
+  for (l = preproc->conditionals; l; l = l->next)
+    {
+      if (GPOINTER_TO_UINT (l->data) & GSK_COND_IGNORE)
+        return TRUE;
+    }
+
+  return FALSE;
+}
+
 static gboolean
 gsk_sl_preprocessor_next_token (GskSlPreprocessor *preproc,
                                 GskSlPpToken      *pp,
@@ -144,6 +192,12 @@ gsk_sl_preprocessor_append_token (GskSlPreprocessor *preproc,
                                   GskSlPpToken      *pp,
                                   GSList            *used_defines)
 {
+  if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
+    {
+      gsk_sl_preprocessor_clear_token (pp);
+      return;
+    }
+
   if (gsk_sl_token_is (&pp->token, GSK_SL_TOKEN_IDENTIFIER))
     {
       GskSlDefine *define;
@@ -194,7 +248,158 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
 
   if (gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
     {
-      if (g_str_equal (pp.token.str, "define"))
+      if (g_str_equal (pp.token.str, "else"))
+        {
+          if (gsk_sl_preprocessor_has_conditional (preproc))
+            {
+              GskConditional cond = gsk_sl_preprocessor_pop_conditional (preproc);
+
+              if (cond & GSK_COND_ELSE)
+                {
+                  gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#else after #else.");
+                  cond |= GSK_COND_IGNORE;
+                }
+              else if (cond & GSK_COND_MATCH)
+                cond |= GSK_COND_IGNORE;
+              else
+                cond &= ~GSK_COND_IGNORE;
+
+              cond |= GSK_COND_ELSE | GSK_COND_MATCH;
+
+              gsk_sl_preprocessor_push_conditional (preproc, cond);
+            }
+          else
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#else without #if.");
+            }
+          gsk_sl_preprocessor_clear_token (&pp);
+
+          if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after 
#else.");
+              gsk_sl_preprocessor_clear_token (&pp);
+            }
+          else
+            {
+              gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+            }
+          return;
+        }
+#if 0
+      else if (g_str_equal (pp.token.str, "elif"))
+        {
+        }
+#endif
+      else if (g_str_equal (pp.token.str, "endif"))
+        {
+          if (gsk_sl_preprocessor_has_conditional (preproc))
+            {
+              gsk_sl_preprocessor_pop_conditional (preproc);
+            }
+          else
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "#endif without #if.");
+            }
+          gsk_sl_preprocessor_clear_token (&pp);
+
+          if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline after 
#endif.");
+              gsk_sl_preprocessor_clear_token (&pp);
+            }
+          else
+            {
+              gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+            }
+          return;
+        }
+#if 0
+      else if (g_str_equal (pp.token.str, "if"))
+        {
+        }
+#endif
+      else if (g_str_equal (pp.token.str, "ifdef"))
+        {
+          gsk_sl_preprocessor_clear_token (&pp);
+          if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No variable after 
#ifdef.");
+              gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+              return;
+            }
+          if (!gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected identifier 
after #ifdef.");
+              gsk_sl_preprocessor_clear_token (&pp);
+            }
+          else
+            {
+              if (g_hash_table_lookup (preproc->defines, pp.token.str))
+                {
+                  gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_MATCH);
+                }
+              else
+                {
+                  gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_IGNORE);
+                }
+              
+              if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+                {
+                  gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline 
after #ifdef.");
+                  gsk_sl_preprocessor_clear_token (&pp);
+                }
+              else
+                {
+                  gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+                }
+              return;
+            }
+        }
+      else if (g_str_equal (pp.token.str, "ifndef"))
+        {
+          gsk_sl_preprocessor_clear_token (&pp);
+          if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "No variable after 
#ifndef.");
+              gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+              return;
+            }
+          if (!gsk_sl_token_is (&pp.token, GSK_SL_TOKEN_IDENTIFIER))
+            {
+              gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected identifier 
after #ifndef.");
+              gsk_sl_preprocessor_clear_token (&pp);
+            }
+          else
+            {
+              if (g_hash_table_lookup (preproc->defines, pp.token.str))
+                {
+                  gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_IGNORE);
+                }
+              else
+                {
+                  gsk_sl_preprocessor_push_conditional (preproc, GSK_COND_MATCH);
+                }
+              
+              if (!gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
+                {
+                  gsk_sl_preprocessor_error_full (preproc, PREPROCESSOR, &pp.location, "Expected newline 
after #ifndef.");
+                  gsk_sl_preprocessor_clear_token (&pp);
+                }
+              else
+                {
+                  gsk_sl_preprocessor_handle_token (preproc, &pp, was_newline);
+                }
+              return;
+            }
+        }
+      else if (gsk_sl_preprocessor_in_ignored_conditional (preproc))
+        {
+          /* All checks above are for preprocessor directives that are checked even in
+           * ignored parts of code */
+          gsk_sl_preprocessor_clear_token (&pp);
+          /* Everything below has no effect in ignored parts of the code */
+        }
+      else if (g_str_equal (pp.token.str, "define"))
         {
           gsk_sl_preprocessor_clear_token (&pp);
           if (gsk_sl_preprocessor_next_token (preproc, &pp, &was_newline))
@@ -229,13 +434,10 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
             }
         }
 #if 0
-      else if (g_str_equal (pp.token.str, "else"))
-        {
-        }
-      else if (g_str_equal (pp.token.str, "elif"))
+      else if (g_str_equal (pp.token.str, "line"))
         {
         }
-      else if (g_str_equal (pp.token.str, "endif"))
+      else if (g_str_equal (pp.token.str, "pragma"))
         {
         }
       else if (g_str_equal (pp.token.str, "error"))
@@ -244,21 +446,6 @@ gsk_sl_preprocessor_handle_preprocessor_directive (GskSlPreprocessor *preproc)
       else if (g_str_equal (pp.token.str, "extension"))
         {
         }
-      else if (g_str_equal (pp.token.str, "if"))
-        {
-        }
-      else if (g_str_equal (pp.token.str, "ifdef"))
-        {
-        }
-      else if (g_str_equal (pp.token.str, "ifndef"))
-        {
-        }
-      else if (g_str_equal (pp.token.str, "line"))
-        {
-        }
-      else if (g_str_equal (pp.token.str, "pragma"))
-        {
-        }
 #endif
       else if (g_str_equal (pp.token.str, "undef"))
         {


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]