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.

Reviewed-by: Kenneth Graunke <kenneth@whitecape.org>
This commit is contained in:
Carl Worth
2012-11-29 14:49:46 -08:00
parent 60a11e295b
commit 962a1c07b4

View File

@@ -70,82 +70,59 @@ glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...)
&parser->info_log_length, "\n"); &parser->info_log_length, "\n");
} }
/* Searches backwards for '^ *#' from a given starting point. */ /* Remove any line continuation characters in the shader, (whether in
static int * preprocessing directives or in GLSL code).
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 * static char *
remove_line_continuations(glcpp_parser_t *ctx, const char *shader) remove_line_continuations(glcpp_parser_t *ctx, const char *shader)
{ {
int in_continued_line = 0;
int extra_newlines = 0;
char *clean = ralloc_strdup(ctx, ""); char *clean = ralloc_strdup(ctx, "");
const char *search_start = shader; const char *backslash, *newline;
const char *newline; int collapsed_newlines = 0;
while ((newline = strchr(search_start, '\n')) != NULL) {
const char *backslash = NULL;
/* # of characters preceding the newline. */ while (true) {
int n = newline - shader; backslash = strchr(shader, '\\');
/* Find the preceding '\', if it exists */ /* If we have previously collapsed any line-continuations,
if (n >= 1 && newline[-1] == '\\') * then we want to insert additional newlines at the next
backslash = newline - 1; * occurrence of a newline character to avoid changing any
else if (n >= 2 && newline[-1] == '\r' && newline[-2] == '\\') * line numbers.
backslash = newline - 2; */
if (collapsed_newlines) {
/* Double backslashes don't count (the backslash is escaped) */ newline = strchr(shader, '\n');
if (backslash != NULL && backslash[-1] == '\\') { if (newline &&
backslash = NULL; (backslash == NULL || newline < backslash))
} {
ralloc_strncat(&clean, shader,
if (backslash != NULL) { newline - shader + 1);
/* We found a line continuation, but do we care? */ while (collapsed_newlines--)
if (!in_continued_line) { ralloc_strcat(&clean, "\n");
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);
shader = newline + 1; shader = newline + 1;
extra_newlines++;
} }
} 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;
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;
}
} }
ralloc_strcat(&clean, shader); ralloc_strcat(&clean, shader);
return clean; return clean;
} }