summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKenneth Graunke <kenneth@whitecape.org>2010-06-23 12:31:09 -0700
committerIan Romanick <ian.d.romanick@intel.com>2010-06-23 14:14:57 -0700
commitbc1097d151677ace501a1f78c11e40ed5b80fdc6 (patch)
treeee48dcb3b3ede939c203c223e738b6baa50ced05
parent186e2634bfb8f624f3721673964e29428269cd47 (diff)
glcpp: Support line continuations within preprocessor directives.
Fixes CorrectPreprocess5.frag.
-rw-r--r--glcpp/pp.c79
1 files changed, 79 insertions, 0 deletions
diff --git a/glcpp/pp.c b/glcpp/pp.c
index 5455518..a25b7b7 100644
--- a/glcpp/pp.c
+++ b/glcpp/pp.c
@@ -21,6 +21,8 @@
* DEALINGS IN THE SOFTWARE.
*/
+#include <assert.h>
+#include <ctype.h>
#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);