glcpp: Rewrite line-continuation support to act globally.
authorCarl Worth <cworth@cworth.org>
Thu, 29 Nov 2012 22:49:46 +0000 (14:49 -0800)
committerCarl Worth <cworth@cworth.org>
Fri, 11 Jan 2013 21:55:41 +0000 (13:55 -0800)
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 <kenneth@whitecape.org>
src/glsl/glcpp/pp.c

index 3f336488ccbe72d563d84dcf928c4e38dc23dded..789f7f94191db40bccf16da0236604aea19cee73 100644 (file)
@@ -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;
 }