[Piglit] [PATCH 1/8] shader_runner: Rework script parser utils.
Francisco Jerez
currojerez at riseup.net
Tue Oct 18 23:17:39 UTC 2016
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.
---
tests/shaders/parser_utils.c | 66 ++++++++++++++++++++++++++++++++++-
tests/shaders/parser_utils.h | 83 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 147 insertions(+), 2 deletions(-)
diff --git a/tests/shaders/parser_utils.c b/tests/shaders/parser_utils.c
index e534a4c..470144e 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 538fa6b..8b766bc 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
--
2.9.0
More information about the Piglit
mailing list