From bc1097d151677ace501a1f78c11e40ed5b80fdc6 Mon Sep 17 00:00:00 2001 From: Kenneth Graunke Date: Wed, 23 Jun 2010 12:31:09 -0700 Subject: glcpp: Support line continuations within preprocessor directives. Fixes CorrectPreprocess5.frag. --- glcpp/pp.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/glcpp/pp.c b/glcpp/pp.c index 5455518c7c7..a25b7b72a6b 100644 --- a/glcpp/pp.c +++ b/glcpp/pp.c @@ -21,6 +21,8 @@ * DEALINGS IN THE SOFTWARE. */ +#include +#include #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); -- cgit v1.2.3