glsl: Implement macro expansion.
authorMichal Krol <michal@vmware.com>
Mon, 22 Jun 2009 07:05:29 +0000 (09:05 +0200)
committerMichal Krol <michal@vmware.com>
Mon, 7 Sep 2009 08:11:47 +0000 (10:11 +0200)
src/glsl/pp/sl_pp_define.c
src/glsl/pp/sl_pp_macro.c
src/glsl/pp/sl_pp_macro.h
src/glsl/pp/sl_pp_process.c
src/glsl/pp/sl_pp_process.h

index 5ce0f0551b8d4efb7760bcabd86a7e11e96c2965..39d14350641acfe45dc3166b530c8984c96ca908 100644 (file)
@@ -48,6 +48,8 @@ _parse_formal_args(const struct sl_pp_token_info *input,
 {
    struct sl_pp_macro_formal_arg **arg;
 
+   macro->num_args = 0;
+
    skip_whitespace(input, first, last);
    if (*first < last) {
       if (input[*first].token == SL_PP_RPAREN) {
@@ -78,6 +80,8 @@ _parse_formal_args(const struct sl_pp_token_info *input,
       (**arg).next = NULL;
       arg = &(**arg).next;
 
+      macro->num_args++;
+
       skip_whitespace(input, first, last);
       if (*first < last) {
          if (input[*first].token == SL_PP_COMMA) {
@@ -104,7 +108,12 @@ sl_pp_process_define(struct sl_pp_context *context,
                      unsigned int last,
                      struct sl_pp_macro *macro)
 {
+   unsigned int i;
+   unsigned int body_len;
+   unsigned int j;
+
    macro->name = -1;
+   macro->num_args = -1;
    macro->arg = NULL;
    macro->body = NULL;
    macro->next = NULL;
@@ -131,26 +140,25 @@ sl_pp_process_define(struct sl_pp_context *context,
       }
    }
 
-   /* Trim whitespace from the left side. */
-   skip_whitespace(input, &first, last);
+   /* Calculate body size, trim out whitespace, make room for EOF. */
+   body_len = 1;
+   for (i = first; i < last; i++) {
+      if (input[i].token != SL_PP_WHITESPACE) {
+         body_len++;
+      }
+   }
 
-   /* Trom whitespace from the right side. */
-   while (first < last && input[last - 1].token == SL_PP_WHITESPACE) {
-      last--;
+   macro->body = malloc(sizeof(struct sl_pp_token_info) * body_len);
+   if (!macro->body) {
+      return -1;
    }
 
-   /* All that is left between first and last is the macro definition. */
-   macro->body_len = last - first;
-   if (macro->body_len) {
-      macro->body = malloc(sizeof(struct sl_pp_token_info) * macro->body_len);
-      if (!macro->body) {
-         return -1;
+   for (j = 0, i = first; i < last; i++) {
+      if (input[i].token != SL_PP_WHITESPACE) {
+         macro->body[j++] = input[i];
       }
-
-      memcpy(macro->body,
-             &input[first],
-             sizeof(struct sl_pp_token_info) * macro->body_len);
    }
+   macro->body[j++].token = SL_PP_EOF;
 
    return 0;
 }
index eed097830404d6a14a510a8192a0330c1808eac3..82591b9d77d16b569b2527caad3af15ca3ec66c8 100644 (file)
 
 #include <stdlib.h>
 #include "sl_pp_macro.h"
+#include "sl_pp_process.h"
 
 
+static void
+skip_whitespace(const struct sl_pp_token_info *input,
+                unsigned int *pi)
+{
+   while (input[*pi].token == SL_PP_WHITESPACE) {
+      (*pi)++;
+   }
+}
+
 void
 sl_pp_macro_free(struct sl_pp_macro *macro)
 {
@@ -49,3 +59,197 @@ sl_pp_macro_free(struct sl_pp_macro *macro)
       macro = next_macro;
    }
 }
+
+int
+sl_pp_macro_expand(struct sl_pp_context *context,
+                   const struct sl_pp_token_info *input,
+                   unsigned int *pi,
+                   struct sl_pp_macro *local,
+                   struct sl_pp_process_state *state)
+{
+   int macro_name;
+   struct sl_pp_macro *macro = NULL;
+   struct sl_pp_macro *actual_arg = NULL;
+   unsigned int j;
+
+   if (input[*pi].token != SL_PP_IDENTIFIER) {
+      return -1;
+   }
+
+   macro_name = input[*pi].data.identifier;
+
+   if (local) {
+      for (macro = local; macro; macro = macro->next) {
+         if (macro->name == macro_name) {
+            break;
+         }
+      }
+   }
+
+   if (!macro) {
+      for (macro = context->macro; macro; macro = macro->next) {
+         if (macro->name == macro_name) {
+            break;
+         }
+      }
+   }
+
+   if (!macro) {
+      if (sl_pp_process_out(state, &input[*pi])) {
+         return -1;
+      }
+      (*pi)++;
+      return 0;
+   }
+
+   (*pi)++;
+
+   if (macro->num_args >= 0) {
+      skip_whitespace(input, pi);
+      if (input[*pi].token != SL_PP_LPAREN) {
+         return -1;
+      }
+      (*pi)++;
+      skip_whitespace(input, pi);
+   }
+
+   if (macro->num_args > 0) {
+      struct sl_pp_macro_formal_arg *formal_arg = macro->arg;
+      struct sl_pp_macro **pmacro = &actual_arg;
+
+      for (j = 0; j < (unsigned int)macro->num_args; j++) {
+         unsigned int body_len;
+         unsigned int i;
+         int done = 0;
+         unsigned int paren_nesting = 0;
+         unsigned int k;
+
+         *pmacro = malloc(sizeof(struct sl_pp_macro));
+         if (!*pmacro) {
+            return -1;
+         }
+
+         (**pmacro).name = formal_arg->name;
+         (**pmacro).num_args = -1;
+         (**pmacro).arg = NULL;
+         (**pmacro).body = NULL;
+         (**pmacro).next = NULL;
+
+         body_len = 1;
+         for (i = *pi; !done; i++) {
+            switch (input[i].token) {
+            case SL_PP_WHITESPACE:
+               break;
+
+            case SL_PP_COMMA:
+               if (!paren_nesting) {
+                  if (j < (unsigned int)macro->num_args - 1) {
+                     done = 1;
+                  } else {
+                     return -1;
+                  }
+               } else {
+                  body_len++;
+               }
+               break;
+
+            case SL_PP_LPAREN:
+               paren_nesting++;
+               body_len++;
+               break;
+
+            case SL_PP_RPAREN:
+               if (!paren_nesting) {
+                  if (j == (unsigned int)macro->num_args - 1) {
+                     done = 1;
+                  } else {
+                     return -1;
+                  }
+               } else {
+                  paren_nesting--;
+                  body_len++;
+               }
+               break;
+
+            case SL_PP_EOF:
+               return -1;
+
+            default:
+               body_len++;
+            }
+         }
+
+         (**pmacro).body = malloc(sizeof(struct sl_pp_token_info) * body_len);
+         if (!(**pmacro).body) {
+            return -1;
+         }
+
+         for (done = 0, k = 0, i = *pi; !done; i++) {
+            switch (input[i].token) {
+            case SL_PP_WHITESPACE:
+               break;
+
+            case SL_PP_COMMA:
+               if (!paren_nesting && j < (unsigned int)macro->num_args - 1) {
+                  done = 1;
+               } else {
+                  (**pmacro).body[k++] = input[i];
+               }
+               break;
+
+            case SL_PP_LPAREN:
+               paren_nesting++;
+               (**pmacro).body[k++] = input[i];
+               break;
+
+            case SL_PP_RPAREN:
+               if (!paren_nesting && j == (unsigned int)macro->num_args - 1) {
+                  done = 1;
+               } else {
+                  paren_nesting--;
+                  (**pmacro).body[k++] = input[i];
+               }
+               break;
+
+            default:
+               (**pmacro).body[k++] = input[i];
+            }
+         }
+
+         (**pmacro).body[k++].token = SL_PP_EOF;
+         (*pi) = i;
+
+         formal_arg = formal_arg->next;
+         pmacro = &(**pmacro).next;
+      }
+   }
+
+   /* Right paren for non-empty argument list has already been eaten. */
+   if (macro->num_args == 0) {
+      skip_whitespace(input, pi);
+      if (input[*pi].token != SL_PP_RPAREN) {
+         return -1;
+      }
+      (*pi)++;
+   }
+
+   for (j = 0;;) {
+      switch (macro->body[j].token) {
+      case SL_PP_IDENTIFIER:
+         if (sl_pp_macro_expand(context, macro->body, &j, actual_arg, state)) {
+            return -1;
+         }
+         break;
+
+      case SL_PP_EOF:
+         sl_pp_macro_free(actual_arg);
+         return 0;
+
+      default:
+         if (sl_pp_process_out(state, &macro->body[j])) {
+            return -1;
+         }
+         j++;
+      }
+   }
+}
index 4ebbff55906291acdd53deae5408b0b43831e24b..eeb338eec458cc09075f4c9dd669a07438ed72b2 100644 (file)
@@ -38,13 +38,20 @@ struct sl_pp_macro_formal_arg {
 
 struct sl_pp_macro {
    int name;
+   int num_args;
    struct sl_pp_macro_formal_arg *arg;
    struct sl_pp_token_info *body;
-   unsigned int body_len;
    struct sl_pp_macro *next;
 };
 
 void
 sl_pp_macro_free(struct sl_pp_macro *macro);
 
+int
+sl_pp_macro_expand(struct sl_pp_context *context,
+                   const struct sl_pp_token_info *input,
+                   unsigned int *pi,
+                   struct sl_pp_macro *local,
+                   struct sl_pp_process_state *state);
+
 #endif /* SL_PP_MACRO_H */
index 2a375df71a47385d85357cbefffa078cd5bcd007..e930966604cd1c38c0c2c1e97807a3315bf70476 100644 (file)
@@ -39,16 +39,16 @@ skip_whitespace(const struct sl_pp_token_info *input,
 }
 
 
-struct process_state {
+struct sl_pp_process_state {
    struct sl_pp_token_info *out;
    unsigned int out_len;
    unsigned int out_max;
 };
 
 
-static int
-out_token(struct process_state *state,
-          const struct sl_pp_token_info *token)
+int
+sl_pp_process_out(struct sl_pp_process_state *state,
+                  const struct sl_pp_token_info *token)
 {
    if (state->out_len >= state->out_max) {
       unsigned int new_max = state->out_max;
@@ -72,7 +72,6 @@ out_token(struct process_state *state,
    return 0;
 }
 
-
 int
 sl_pp_process(struct sl_pp_context *context,
               const struct sl_pp_token_info *input,
@@ -81,7 +80,7 @@ sl_pp_process(struct sl_pp_context *context,
    unsigned int i = 0;
    int found_eof = 0;
    struct sl_pp_macro **macro;
-   struct process_state state;
+   struct sl_pp_process_state state;
 
    macro = &context->macro;
    memset(&state, 0, sizeof(state));
@@ -110,7 +109,7 @@ sl_pp_process(struct sl_pp_context *context,
                   switch (input[i].token) {
                   case SL_PP_NEWLINE:
                      /* Preserve newline just for the sake of line numbering. */
-                     if (out_token(&state, &input[i])) {
+                     if (sl_pp_process_out(&state, &input[i])) {
                         return -1;
                      }
                      i++;
@@ -118,7 +117,7 @@ sl_pp_process(struct sl_pp_context *context,
                      break;
 
                   case SL_PP_EOF:
-                     if (out_token(&state, &input[i])) {
+                     if (sl_pp_process_out(&state, &input[i])) {
                         return -1;
                      }
                      i++;
@@ -152,7 +151,7 @@ sl_pp_process(struct sl_pp_context *context,
 
          case SL_PP_NEWLINE:
             /* Empty directive. */
-            if (out_token(&state, &input[i])) {
+            if (sl_pp_process_out(&state, &input[i])) {
                return -1;
             }
             i++;
@@ -160,7 +159,7 @@ sl_pp_process(struct sl_pp_context *context,
 
          case SL_PP_EOF:
             /* Empty directive. */
-            if (out_token(&state, &input[i])) {
+            if (sl_pp_process_out(&state, &input[i])) {
                return -1;
             }
             i++;
@@ -182,7 +181,7 @@ sl_pp_process(struct sl_pp_context *context,
 
             case SL_PP_NEWLINE:
                /* Preserve newline just for the sake of line numbering. */
-               if (out_token(&state, &input[i])) {
+               if (sl_pp_process_out(&state, &input[i])) {
                   return -1;
                }
                i++;
@@ -190,7 +189,7 @@ sl_pp_process(struct sl_pp_context *context,
                break;
 
             case SL_PP_EOF:
-               if (out_token(&state, &input[i])) {
+               if (sl_pp_process_out(&state, &input[i])) {
                   return -1;
                }
                i++;
@@ -198,8 +197,14 @@ sl_pp_process(struct sl_pp_context *context,
                found_eol = 1;
                break;
 
+            case SL_PP_IDENTIFIER:
+               if (sl_pp_macro_expand(context, input, &i, NULL, &state)) {
+                  return -1;
+               }
+               break;
+
             default:
-               if (out_token(&state, &input[i])) {
+               if (sl_pp_process_out(&state, &input[i])) {
                   return -1;
                }
                i++;
index f7df9a2850a9278bc7eb7f3a6dc2d79ceea84a8e..37cdc4c9a781f15e6d447351638f75ea3ff7763b 100644 (file)
@@ -33,6 +33,8 @@
 #include "sl_pp_token.h"
 
 
+struct sl_pp_process_state;
+
 int
 sl_pp_process(struct sl_pp_context *context,
               const struct sl_pp_token_info *input,
@@ -45,4 +47,8 @@ sl_pp_process_define(struct sl_pp_context *context,
                      unsigned int last,
                      struct sl_pp_macro *macro);
 
+int
+sl_pp_process_out(struct sl_pp_process_state *state,
+                  const struct sl_pp_token_info *token);
+
 #endif /* SL_PP_PROCESS_H */