From 2483039aca78078f21a57e8e950a0bc0181fbd3d Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 29 Nov 2012 14:49:46 -0800 Subject: [PATCH] glcpp: Rewrite line-continuation support to act globally. Previously, we were only supporting line-continuation backslash characters within lines of pre-processor directives, (as per the specification). With OpenGL 4.2 and GLES3, line continuations are now supported anywhere within a shader. While changing this, also fix a bug where the preprocessor was ignoring line continuation characters when a line ended in multiple backslash characters. The new code is also more efficient than the old. Previously, we would perform a ralloc copy at each newline. We now perform copies only at each occurrence of a line-continuation. This commit fixes the line-continuation.vert test in piglit. Reviewed-by: Kenneth Graunke --- src/glsl/glcpp/pp.c | 115 +++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 66 deletions(-) diff --git a/src/glsl/glcpp/pp.c b/src/glsl/glcpp/pp.c index 3f336488ccb..789f7f94191 100644 --- a/src/glsl/glcpp/pp.c +++ b/src/glsl/glcpp/pp.c @@ -70,82 +70,65 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) &parser->info_log_length, "\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. +/* Remove any line continuation characters in the shader, (whether in + * preprocessing directives or in GLSL code). */ static char * remove_line_continuations(glcpp_parser_t *ctx, const char *shader) { - int in_continued_line = 0; - int extra_newlines = 0; char *clean = ralloc_strdup(ctx, ""); - const char *search_start = shader; - const char *newline; - while ((newline = strchr(search_start, '\n')) != NULL) { - const char *backslash = NULL; - - /* # of characters preceding the newline. */ - int n = newline - shader; - - /* Find the preceding '\', if it exists */ - if (n >= 1 && newline[-1] == '\\') - backslash = newline - 1; - else if (n >= 2 && 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 \ */ - ralloc_strncat(&clean, shader, backslash - shader); + const char *backslash, *newline, *search_start; + int collapsed_newlines = 0; + + search_start = shader; + + while (true) { + backslash = strchr(search_start, '\\'); + + /* If we have previously collapsed any line-continuations, + * then we want to insert additional newlines at the next + * occurrence of a newline character to avoid changing any + * line numbers. + */ + if (collapsed_newlines) { + newline = strchr(search_start, '\n'); + if (newline && + (backslash == NULL || newline < backslash)) + { + ralloc_strncat(&clean, shader, + newline - shader + 1); + while (collapsed_newlines--) + ralloc_strcat(&clean, "\n"); shader = newline + 1; - extra_newlines++; + search_start = shader; } - } else if (in_continued_line) { - /* Copy everything up to and including the \n */ - ralloc_strncat(&clean, shader, newline - shader + 1); - shader = newline + 1; - /* Output extra newlines to make line numbers match */ - for (; extra_newlines > 0; extra_newlines--) - ralloc_strcat(&clean, "\n"); - in_continued_line = 0; } - search_start = newline + 1; + + search_start = backslash + 1; + + if (backslash == NULL) + break; + + /* At each line continuation, (backslash followed by a + * newline), copy all preceding text to the output, then + * advance the shader pointer to the character after the + * newline. + */ + if (backslash[1] == '\n' || + (backslash[1] == '\r' && backslash[2] == '\n')) + { + collapsed_newlines++; + ralloc_strncat(&clean, shader, backslash - shader); + if (backslash[1] == '\n') + shader = backslash + 2; + else + shader = backslash + 3; + search_start = shader; + } } + ralloc_strcat(&clean, shader); + return clean; } -- 2.30.2