diff options
author | Kenneth Graunke <kenneth@whitecape.org> | 2010-06-23 12:31:09 -0700 |
---|---|---|
committer | Ian Romanick <ian.d.romanick@intel.com> | 2010-06-23 14:14:57 -0700 |
commit | bc1097d151677ace501a1f78c11e40ed5b80fdc6 (patch) | |
tree | ee48dcb3b3ede939c203c223e738b6baa50ced05 | |
parent | 186e2634bfb8f624f3721673964e29428269cd47 (diff) |
glcpp: Support line continuations within preprocessor directives.
Fixes CorrectPreprocess5.frag.
-rw-r--r-- | glcpp/pp.c | 79 |
1 files changed, 79 insertions, 0 deletions
@@ -21,6 +21,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include <assert.h> +#include <ctype.h> #include "glcpp.h" void @@ -56,11 +58,88 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) parser->info_log = talloc_strdup_append(parser->info_log, "\n"); } +/* Searches backwards for '^ *#' from a given starting point. */ +static int +in_directive(const char *shader, const char *ptr) +{ + assert(ptr >= shader); + + /* Search backwards for '#'. If we find a \n first, it doesn't count */ + for (; ptr >= shader && *ptr != '#'; ptr--) { + if (*ptr == '\n') + return 0; + } + if (ptr >= shader) { + /* Found '#'...look for spaces preceded by a newline */ + for (ptr--; ptr >= shader && isblank(*ptr); ptr--); + // FIXME: I don't think the '\n' case can happen + if (ptr < shader || *ptr == '\n') + return 1; + } + return 0; +} + +/* Remove any line continuation characters in preprocessing directives. + * However, ignore any in GLSL code, as "There is no line continuation + * character" (1.30 page 9) in GLSL. + */ +static char * +remove_line_continuations(glcpp_parser_t *ctx, const char *shader) +{ + int in_continued_line = 0; + int extra_newlines = 0; + char *clean = talloc_strdup(ctx, ""); + const char *search_start = shader; + const char *newline; + while ((newline = strchr(search_start, '\n')) != NULL) { + const char *backslash = NULL; + /* Find the preceding '\', if it exists */ + if (newline[-1] == '\\') { + backslash = newline - 1; + } else if (newline[-1] == '\r' && newline[-2] == '\\') { + backslash = newline - 2; + } + /* Double backslashes don't count (the backslash is escaped) */ + if (backslash != NULL && backslash[-1] == '\\') { + backslash = NULL; + } + + if (backslash != NULL) { + /* We found a line continuation, but do we care? */ + if (!in_continued_line) { + if (in_directive(shader, backslash)) { + in_continued_line = 1; + extra_newlines = 0; + } + } + if (in_continued_line) { + /* Copy everything before the \ */ + clean = talloc_strndup_append(clean, shader, backslash - shader); + shader = newline + 1; + extra_newlines++; + } + } else if (in_continued_line) { + /* Copy everything up to and including the \n */ + clean = talloc_strndup_append(clean, shader, newline - shader + 1); + shader = newline + 1; + /* Output extra newlines to make line numbers match */ + for (; extra_newlines > 0; extra_newlines--) + clean = talloc_strdup_append(clean, "\n"); + in_continued_line = 0; + } + search_start = newline + 1; + } + clean = talloc_strdup_append(clean, shader); + return clean; +} + extern int preprocess(void *talloc_ctx, const char **shader, char **info_log) { int errors; glcpp_parser_t *parser = glcpp_parser_create (); + *shader = remove_line_continuations(parser, *shader); + glcpp_lex_set_source_string (parser, *shader); glcpp_parser_parse (parser); |