summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2016-07-14 18:01:37 -0700
committerFrancisco Jerez <currojerez@riseup.net>2016-11-07 14:07:03 -0800
commit27bb3fda64e1cbb1028cfa91b7b5ff186df2ce9e (patch)
tree8d1dd3f1eca227363942e17b63d9ba0d73c0e7b4
parentf66765d4c5f088fc63d6626a3d8209ffe44e5684 (diff)
shader_runner: Rework script parser utils.
This introduces a collection of text parsing primitives meant to replace the current helper functions from parser_utils.h and other manual string manipulation done in shader_runner.c. The design principles are: - Make things easier for the caller to handle failure. Some of the current parser code doesn't handle failure at all (e.g. the whole get_* helpers), which will cause the script to misbehave silently in presence of a syntax error. Other parser functions (e.g. lookup_enum_string or process_comparison) kill the piglit test with failure status when the input cannot be parsed, which prevents the caller from handling parse errors gracefully in cases where failure is expected (e.g. because a symbol has multiple alternative production rules). All parser primitives introduced here return a boolean result that represents whether the symbol could be parsed from the input string. The REQUIRE() macro is provided to encourage printing informative diagnostic messages in error conditions. - Allow composition of parser primitives to form more complex parsers with similar high-level behavior. Chained parsers can be represented easily using the '&&' operator. E.g.: | return parse_str(line, "foo", &rest) && | parse_bar(rest, &bar, &rest); will parse "foo" followed by a 'bar' value and leave 'rest' pointing at the following text to allow subsequent composition [the parser utils currently in use would require hard-coding the character length of the first symbol, which is error-prone and can get hairy if the length of the symbol is not known beforehand]. Look-ahead can be achieved by passing NULL as last argument which will simply check whether the symbol can be parsed without updating the current parse location. E.g. to check whether a symbol starts with 'GL_' and then parse it as a GL enum: | return parse_str(line, "GL_", NULL) && | parse_enum_gl(line, &e, &rest); - Allow parsing of slightly more complex grammars where a single non-terminal symbol can have multiple alternative production rules. Selection of one of the alternatives can be represented succinctly by combining multiple parsers with the '||' operator (the result will be left-biased in presence of ambiguity due to the short-circuit rule of C boolean operators). E.g. to parse a string of the form '<name-string> <pname-enum> <type-enum or integer>' you can do something along the lines of: | return parse_word_copy(line, name, sizeof(name), &rest) && | parse_enum_tab(all_pnames, rest, &pname, &rest) && | (parse_enum_tab(all_types, rest, &expected, &rest) || | parse_int(rest, &expected, &rest)); See the doxygen documentation below for more details.
-rw-r--r--tests/shaders/parser_utils.c66
-rw-r--r--tests/shaders/parser_utils.h83
2 files changed, 147 insertions, 2 deletions
diff --git a/tests/shaders/parser_utils.c b/tests/shaders/parser_utils.c
index e534a4c44..470144e16 100644
--- a/tests/shaders/parser_utils.c
+++ b/tests/shaders/parser_utils.c
@@ -1,5 +1,5 @@
/*
- * Copyright © 2010 Intel Corporation
+ * Copyright © 2010-2016 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -24,6 +24,70 @@
#include <ctype.h>
#include "parser_utils.h"
+bool
+parse_whitespace(const char *s, const char **rest)
+{
+ const char *end = s;
+ for (; *end && *end != '\n' && isspace(*end); end++);
+
+ if (rest)
+ *rest = end;
+
+ return end != s;
+}
+
+bool
+parse_str(const char *s, const char *lit, const char **rest)
+{
+ const char *t;
+ parse_whitespace(s, &t);
+ const bool ret = strncmp(t, lit, strlen(lit)) == 0;
+
+ if (rest)
+ *rest = (ret ? t + strlen(lit) : s);
+
+ return ret;
+}
+
+bool
+parse_word(const char *s, const char **t, const char **rest)
+{
+ parse_whitespace(s, t);
+
+ const char *end = *t;
+ for (; *end && !isspace(*end); end++);
+
+ if (rest)
+ *rest = (*t != end ? end : s);
+
+ return *t != end;
+}
+
+bool
+parse_word_copy(const char *s, char *t, unsigned n, const char **rest)
+{
+ const char *start, *end;
+ const bool ret = parse_word(s, &start, &end) && end - start < n;
+
+ if (ret) {
+ memcpy(t, start, end - start);
+ t[end - start] = 0;
+ }
+ if (rest)
+ *rest = (ret ? end : s);
+
+ return ret;
+}
+
+bool
+parse_enum_gl(const char *s, GLenum *e, const char **rest)
+{
+ char name[512];
+ const bool ret = parse_word_copy(s, name, sizeof(name), rest);
+ *e = (ret ? piglit_get_gl_enum_from_name(name) : GL_NONE);
+ return ret;
+}
+
/**
* Skip over whitespace upto the end of line
*/
diff --git a/tests/shaders/parser_utils.h b/tests/shaders/parser_utils.h
index 538fa6b66..8b766bc3a 100644
--- a/tests/shaders/parser_utils.h
+++ b/tests/shaders/parser_utils.h
@@ -1,5 +1,5 @@
/*
- * Copyright © 2010 Intel Corporation
+ * Copyright © 2010-2016 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@@ -21,9 +21,90 @@
* DEALINGS IN THE SOFTWARE.
*/
+/**
+ * \file parser_utils.h
+ *
+ * These are a bunch of plain-text parsing utilities, most of them
+ * have the form:
+ * boolean-like parse_foo(input-string, output-foo, output-string)
+ *
+ * If the input is a well-formed string representation of a "foo"
+ * value, as many characters will be read from the string as they are
+ * needed to initialize the "foo" object returned via the first output
+ * argument, and the boolean return value will evaluate to true. If
+ * the output string argument is not NULL, a pointer one past the last
+ * character consumed to parse a "foo" value will be returned to the
+ * caller so that the rest of the document can be processed (e.g. by
+ * passing the output string as input string of another parse
+ * function).
+ *
+ * If the input cannot be parsed as a "foo" object, the boolean return
+ * value will evaluate to false and the input string will be returned
+ * as output string as-is (which mimicks the behavior of the C
+ * standard library strto* functions). The "foo" output argument will
+ * be left in an undefined state in that case.
+ */
+#ifndef PIGLIT_PARSER_UTILS_H
+#define PIGLIT_PARSER_UTILS_H
+
#include <stdbool.h>
+#include "piglit-util-gl.h"
+
+/**
+ * Parse one or more whitespace characters (other than newline) from
+ * the input string.
+ */
+bool
+parse_whitespace(const char *s, const char **rest);
+
+/**
+ * Parse an exact match of string \p lit, optionally preceded by
+ * whitespace.
+ */
+bool
+parse_str(const char *s, const char *lit, const char **rest);
+
+/**
+ * Parse a single non-empty whitespace-separated token. On success \p
+ * t and \p rest will respectively point at the first and one past the
+ * last character of the result.
+ */
+bool
+parse_word(const char *s, const char **t, const char **rest);
+
+/**
+ * Like parse_word(), but the result is copied into the fixed-size
+ * buffer pointed to by \p t and null-terminated.
+ *
+ * The parse is considered to fail if the size of the result
+ * (including the terminating null character) would have exceded the
+ * number of characters allocated for it in the buffer as given by the
+ * \p n argument.
+ */
+bool
+parse_word_copy(const char *s, char *t, unsigned n, const char **rest);
+
+/**
+ * Parse a GL_* symbolic constant.
+ */
+bool
+parse_enum_gl(const char *s, GLenum *e, const char **rest);
const char *eat_whitespace(const char *src);
const char *eat_text(const char *src);
bool string_match(const char *string, const char *line);
const char *strcpy_to_space(char *dst, const char *src);
+
+/**
+ * Abort the Piglit test with failure status if the boolean expression
+ * (typically the result of a chain of parse function calls) evaluates
+ * to false.
+ */
+#define REQUIRE(b, ...) do { \
+ if (!(b)) { \
+ fprintf(stderr, __VA_ARGS__); \
+ piglit_report_result(PIGLIT_FAIL); \
+ } \
+ } while (0)
+
+#endif