diff options
author | Francisco Jerez <currojerez@riseup.net> | 2016-07-14 18:01:37 -0700 |
---|---|---|
committer | Francisco Jerez <currojerez@riseup.net> | 2016-11-07 14:07:03 -0800 |
commit | 27bb3fda64e1cbb1028cfa91b7b5ff186df2ce9e (patch) | |
tree | 8d1dd3f1eca227363942e17b63d9ba0d73c0e7b4 | |
parent | f66765d4c5f088fc63d6626a3d8209ffe44e5684 (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.c | 66 | ||||
-rw-r--r-- | 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 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 |