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:
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user