summaryrefslogtreecommitdiffstats
path: root/src/glsl/pp/sl_pp_macro.c
diff options
context:
space:
mode:
authorMichal Krol <[email protected]>2009-06-22 09:05:29 +0200
committerMichal Krol <[email protected]>2009-09-07 10:11:47 +0200
commit6a11d4150cfcdd646c17f8b365b5481c2c583208 (patch)
tree9037f4dc93262d269ba126788a0d5691bb10b4cd /src/glsl/pp/sl_pp_macro.c
parent5e8e3cddae9b2797cfa525c643c701debe2f4c04 (diff)
glsl: Implement macro expansion.
Diffstat (limited to 'src/glsl/pp/sl_pp_macro.c')
-rw-r--r--src/glsl/pp/sl_pp_macro.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/src/glsl/pp/sl_pp_macro.c b/src/glsl/pp/sl_pp_macro.c
index eed09783040..82591b9d77d 100644
--- a/src/glsl/pp/sl_pp_macro.c
+++ b/src/glsl/pp/sl_pp_macro.c
@@ -27,8 +27,18 @@
#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++;
+ }
+ }
+}