diff options
Diffstat (limited to 'src/compiler/glsl/glcpp')
298 files changed, 6284 insertions, 0 deletions
diff --git a/src/compiler/glsl/glcpp/.gitignore b/src/compiler/glsl/glcpp/.gitignore new file mode 100644 index 0000000000..24a7119caa --- /dev/null +++ b/src/compiler/glsl/glcpp/.gitignore @@ -0,0 +1,6 @@ +glcpp +glcpp-lex.c +glcpp-parse.output +glcpp-parse.c +glcpp-parse.h +tests/*.out diff --git a/src/compiler/glsl/glcpp/README b/src/compiler/glsl/glcpp/README new file mode 100644 index 0000000000..0637935e28 --- /dev/null +++ b/src/compiler/glsl/glcpp/README @@ -0,0 +1,30 @@ +glcpp -- GLSL "C" preprocessor + +This is a simple preprocessor designed to provide the preprocessing +needs of the GLSL language. The requirements for this preprocessor are +specified in the GLSL 1.30 specification availble from: + +http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.30.10.pdf + +This specification is not precise on some semantics, (for example, +#define and #if), defining these merely "as is standard for C++ +preprocessors". To fill in these details, I've been using a draft of +the C99 standard as available from: + +http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf + +Any downstream compiler accepting output from glcpp should be prepared +to encounter and deal with the following preprocessor macros: + + #line + #pragma + #extension + +All other macros will be handled according to the GLSL specification +and will not appear in the output. + +Known limitations +----------------- +A file that ends with a function-like macro name as the last +non-whitespace token will result in a parse error, (where it should be +passed through as is).
\ No newline at end of file diff --git a/src/compiler/glsl/glcpp/glcpp-lex.l b/src/compiler/glsl/glcpp/glcpp-lex.l new file mode 100644 index 0000000000..fa9aa50691 --- /dev/null +++ b/src/compiler/glsl/glcpp/glcpp-lex.l @@ -0,0 +1,577 @@ +%{ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +#include "glcpp.h" +#include "glcpp-parse.h" + +/* Flex annoyingly generates some functions without making them + * static. Let's declare them here. */ +int glcpp_get_column (yyscan_t yyscanner); +void glcpp_set_column (int column_no , yyscan_t yyscanner); + +#ifdef _MSC_VER +#define YY_NO_UNISTD_H +#endif + +#define YY_NO_INPUT + +#define YY_USER_ACTION \ + do { \ + if (parser->has_new_line_number) \ + yylineno = parser->new_line_number; \ + if (parser->has_new_source_number) \ + yylloc->source = parser->new_source_number; \ + yylloc->first_column = yycolumn + 1; \ + yylloc->first_line = yylloc->last_line = yylineno; \ + yycolumn += yyleng; \ + yylloc->last_column = yycolumn + 1; \ + parser->has_new_line_number = 0; \ + parser->has_new_source_number = 0; \ + } while(0); + +#define YY_USER_INIT \ + do { \ + yylineno = 1; \ + yycolumn = 0; \ + yylloc->source = 0; \ + } while(0) + +/* It's ugly to have macros that have return statements inside of + * them, but flex-based lexer generation is all built around the + * return statement. + * + * To mitigate the ugliness, we defer as much of the logic as possible + * to an actual function, not a macro (see + * glcpplex_update_state_per_token) and we make the word RETURN + * prominent in all of the macros which may return. + * + * The most-commonly-used macro is RETURN_TOKEN which will perform all + * necessary state updates based on the provided token,, then + * conditionally return the token. It will not return a token if the + * parser is currently skipping tokens, (such as within #if + * 0...#else). + * + * The RETURN_TOKEN_NEVER_SKIP macro is a lower-level variant that + * makes the token returning unconditional. This is needed for things + * like #if and the tokens of its condition, (since these must be + * evaluated by the parser even when otherwise skipping). + * + * Finally, RETURN_STRING_TOKEN is a simple convenience wrapper on top + * of RETURN_TOKEN that performs a string copy of yytext before the + * return. + */ +#define RETURN_TOKEN_NEVER_SKIP(token) \ + do { \ + if (glcpp_lex_update_state_per_token (parser, token)) \ + return token; \ + } while (0) + +#define RETURN_TOKEN(token) \ + do { \ + if (! parser->skipping) { \ + RETURN_TOKEN_NEVER_SKIP(token); \ + } \ + } while(0) + +#define RETURN_STRING_TOKEN(token) \ + do { \ + if (! parser->skipping) { \ + yylval->str = ralloc_strdup (yyextra, yytext); \ + RETURN_TOKEN_NEVER_SKIP (token); \ + } \ + } while(0) + + +/* Update all state necessary for each token being returned. + * + * Here we'll be tracking newlines and spaces so that the lexer can + * alter its behavior as necessary, (for example, '#' has special + * significance if it is the first non-whitespace, non-comment token + * in a line, but does not otherwise). + * + * NOTE: If this function returns FALSE, then no token should be + * returned at all. This is used to suprress duplicate SPACE tokens. + */ +static int +glcpp_lex_update_state_per_token (glcpp_parser_t *parser, int token) +{ + /* After the first non-space token in a line, we won't + * allow any '#' to introduce a directive. */ + if (token == NEWLINE) { + parser->first_non_space_token_this_line = 1; + } else if (token != SPACE) { + parser->first_non_space_token_this_line = 0; + } + + /* Track newlines just to know whether a newline needs + * to be inserted if end-of-file comes early. */ + if (token == NEWLINE) { + parser->last_token_was_newline = 1; + } else { + parser->last_token_was_newline = 0; + } + + /* Track spaces to avoid emitting multiple SPACE + * tokens in a row. */ + if (token == SPACE) { + if (! parser->last_token_was_space) { + parser->last_token_was_space = 1; + return 1; + } else { + parser->last_token_was_space = 1; + return 0; + } + } else { + parser->last_token_was_space = 0; + return 1; + } +} + + +%} + +%option bison-bridge bison-locations reentrant noyywrap +%option extra-type="glcpp_parser_t *" +%option prefix="glcpp_" +%option stack +%option never-interactive +%option warn nodefault + + /* Note: When adding any start conditions to this list, you must also + * update the "Internal compiler error" catch-all rule near the end of + * this file. */ + +%x COMMENT DEFINE DONE HASH NEWLINE_CATCHUP UNREACHABLE + +SPACE [[:space:]] +NONSPACE [^[:space:]] +HSPACE [ \t] +HASH # +NEWLINE (\r\n|\n\r|\r|\n) +IDENTIFIER [_a-zA-Z][_a-zA-Z0-9]* +PP_NUMBER [.]?[0-9]([._a-zA-Z0-9]|[eEpP][-+])* +PUNCTUATION [][(){}.&*~!/%<>^|;,=+-] + +/* The OTHER class is simply a catch-all for things that the CPP +parser just doesn't care about. Since flex regular expressions that +match longer strings take priority over those matching shorter +strings, we have to be careful to avoid OTHER matching and hiding +something that CPP does care about. So we simply exclude all +characters that appear in any other expressions. */ + +OTHER [^][_#[:space:]#a-zA-Z0-9(){}.&*~!/%<>^|;,=+-] + +DIGITS [0-9][0-9]* +DECIMAL_INTEGER [1-9][0-9]*[uU]? +OCTAL_INTEGER 0[0-7]*[uU]? +HEXADECIMAL_INTEGER 0[xX][0-9a-fA-F]+[uU]? + +%% + + glcpp_parser_t *parser = yyextra; + + /* When we lex a multi-line comment, we replace it (as + * specified) with a single space. But if the comment spanned + * multiple lines, then subsequent parsing stages will not + * count correct line numbers. To avoid this problem we keep + * track of all newlines that were commented out by a + * multi-line comment, and we emit a NEWLINE token for each at + * the next legal opportunity, (which is when the lexer would + * be emitting a NEWLINE token anyway). + */ + if (YY_START == NEWLINE_CATCHUP) { + if (parser->commented_newlines) + parser->commented_newlines--; + if (parser->commented_newlines == 0) + BEGIN INITIAL; + RETURN_TOKEN_NEVER_SKIP (NEWLINE); + } + + /* Set up the parser->skipping bit here before doing any lexing. + * + * This bit controls whether tokens are skipped, (as implemented by + * RETURN_TOKEN), such as between "#if 0" and "#endif". + * + * The parser maintains a skip_stack indicating whether we should be + * skipping, (and nested levels of #if/#ifdef/#ifndef/#endif) will + * push and pop items from the stack. + * + * Here are the rules for determining whether we are skipping: + * + * 1. If the skip stack is NULL, we are outside of all #if blocks + * and we are not skipping. + * + * 2. If the skip stack is non-NULL, the type of the top node in + * the stack determines whether to skip. A type of + * SKIP_NO_SKIP is used for blocks wheere we are emitting + * tokens, (such as between #if 1 and #endif, or after the + * #else of an #if 0, etc.). + * + * 3. The lexing_directive bit overrides the skip stack. This bit + * is set when we are actively lexing the expression for a + * pre-processor condition, (such as #if, #elif, or #else). In + * this case, even if otherwise skipping, we need to emit the + * tokens for this condition so that the parser can evaluate + * the expression. (For, #else, there's no expression, but we + * emit tokens so the parser can generate a nice error message + * if there are any tokens here). + */ + if (parser->skip_stack && + parser->skip_stack->type != SKIP_NO_SKIP && + ! parser->lexing_directive) + { + parser->skipping = 1; + } else { + parser->skipping = 0; + } + + /* Single-line comments */ +<INITIAL,DEFINE,HASH>"//"[^\r\n]* { +} + + /* Multi-line comments */ +<INITIAL,DEFINE,HASH>"/*" { yy_push_state(COMMENT, yyscanner); } +<COMMENT>[^*\r\n]* +<COMMENT>[^*\r\n]*{NEWLINE} { yylineno++; yycolumn = 0; parser->commented_newlines++; } +<COMMENT>"*"+[^*/\r\n]* +<COMMENT>"*"+[^*/\r\n]*{NEWLINE} { yylineno++; yycolumn = 0; parser->commented_newlines++; } +<COMMENT>"*"+"/" { + yy_pop_state(yyscanner); + /* In the <HASH> start condition, we don't want any SPACE token. */ + if (yyextra->space_tokens && YY_START != HASH) + RETURN_TOKEN (SPACE); +} + +{HASH} { + + /* If the '#' is the first non-whitespace, non-comment token on this + * line, then it introduces a directive, switch to the <HASH> start + * condition. + * + * Otherwise, this is just punctuation, so return the HASH_TOKEN + * token. */ + if (parser->first_non_space_token_this_line) { + BEGIN HASH; + } + + RETURN_TOKEN_NEVER_SKIP (HASH_TOKEN); +} + +<HASH>version{HSPACE}+ { + BEGIN INITIAL; + yyextra->space_tokens = 0; + RETURN_STRING_TOKEN (VERSION_TOKEN); +} + + /* Swallow empty #pragma directives, (to avoid confusing the + * downstream compiler). + * + * Note: We use a simple regular expression for the lookahead + * here. Specifically, we cannot use the complete {NEWLINE} expression + * since it uses alternation and we've found that there's a flex bug + * where using alternation in the lookahead portion of a pattern + * triggers a buffer overrun. */ +<HASH>pragma{HSPACE}*/[\r\n] { + BEGIN INITIAL; +} + + /* glcpp doesn't handle #extension, #version, or #pragma directives. + * Simply pass them through to the main compiler's lexer/parser. */ +<HASH>(extension|pragma)[^\r\n]* { + BEGIN INITIAL; + RETURN_STRING_TOKEN (PRAGMA); +} + +<HASH>line{HSPACE}+ { + BEGIN INITIAL; + RETURN_TOKEN (LINE); +} + +<HASH>{NEWLINE} { + BEGIN INITIAL; + RETURN_TOKEN_NEVER_SKIP (NEWLINE); +} + + /* For the pre-processor directives, we return these tokens + * even when we are otherwise skipping. */ +<HASH>ifdef { + BEGIN INITIAL; + yyextra->lexing_directive = 1; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (IFDEF); +} + +<HASH>ifndef { + BEGIN INITIAL; + yyextra->lexing_directive = 1; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (IFNDEF); +} + +<HASH>if/[^_a-zA-Z0-9] { + BEGIN INITIAL; + yyextra->lexing_directive = 1; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (IF); +} + +<HASH>elif/[^_a-zA-Z0-9] { + BEGIN INITIAL; + yyextra->lexing_directive = 1; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (ELIF); +} + +<HASH>else { + BEGIN INITIAL; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (ELSE); +} + +<HASH>endif { + BEGIN INITIAL; + yyextra->space_tokens = 0; + RETURN_TOKEN_NEVER_SKIP (ENDIF); +} + +<HASH>error[^\r\n]* { + BEGIN INITIAL; + RETURN_STRING_TOKEN (ERROR_TOKEN); +} + + /* After we see a "#define" we enter the <DEFINE> start state + * for the lexer. Within <DEFINE> we are looking for the first + * identifier and specifically checking whether the identifier + * is followed by a '(' or not, (to lex either a + * FUNC_IDENTIFIER or an OBJ_IDENITIFIER token). + * + * While in the <DEFINE> state we also need to explicitly + * handle a few other things that may appear before the + * identifier: + * + * * Comments, (handled above with the main support for + * comments). + * + * * Whitespace (simply ignored) + * + * * Anything else, (not an identifier, not a comment, + * and not whitespace). This will generate an error. + */ +<HASH>define{HSPACE}* { + if (! parser->skipping) { + BEGIN DEFINE; + yyextra->space_tokens = 0; + RETURN_TOKEN (DEFINE_TOKEN); + } +} + +<HASH>undef { + BEGIN INITIAL; + yyextra->space_tokens = 0; + RETURN_TOKEN (UNDEF); +} + +<HASH>{HSPACE}+ { + /* Nothing to do here. Importantly, don't leave the <HASH> + * start condition, since it's legal to have space between the + * '#' and the directive.. */ +} + + /* This will catch any non-directive garbage after a HASH */ +<HASH>{NONSPACE} { + BEGIN INITIAL; + RETURN_TOKEN (GARBAGE); +} + + /* An identifier immediately followed by '(' */ +<DEFINE>{IDENTIFIER}/"(" { + BEGIN INITIAL; + RETURN_STRING_TOKEN (FUNC_IDENTIFIER); +} + + /* An identifier not immediately followed by '(' */ +<DEFINE>{IDENTIFIER} { + BEGIN INITIAL; + RETURN_STRING_TOKEN (OBJ_IDENTIFIER); +} + + /* Whitespace */ +<DEFINE>{HSPACE}+ { + /* Just ignore it. Nothing to do here. */ +} + + /* '/' not followed by '*', so not a comment. This is an error. */ +<DEFINE>[/][^*]{NONSPACE}* { + BEGIN INITIAL; + glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext); + RETURN_STRING_TOKEN (INTEGER_STRING); +} + + /* A character that can't start an identifier, comment, or + * space. This is an error. */ +<DEFINE>[^_a-zA-Z/[:space:]]{NONSPACE}* { + BEGIN INITIAL; + glcpp_error(yylloc, yyextra, "#define followed by a non-identifier: %s", yytext); + RETURN_STRING_TOKEN (INTEGER_STRING); +} + +{DECIMAL_INTEGER} { + RETURN_STRING_TOKEN (INTEGER_STRING); +} + +{OCTAL_INTEGER} { + RETURN_STRING_TOKEN (INTEGER_STRING); +} + +{HEXADECIMAL_INTEGER} { + RETURN_STRING_TOKEN (INTEGER_STRING); +} + +"<<" { + RETURN_TOKEN (LEFT_SHIFT); +} + +">>" { + RETURN_TOKEN (RIGHT_SHIFT); +} + +"<=" { + RETURN_TOKEN (LESS_OR_EQUAL); +} + +">=" { + RETURN_TOKEN (GREATER_OR_EQUAL); +} + +"==" { + RETURN_TOKEN (EQUAL); +} + +"!=" { + RETURN_TOKEN (NOT_EQUAL); +} + +"&&" { + RETURN_TOKEN (AND); +} + +"||" { + RETURN_TOKEN (OR); +} + +"++" { + RETURN_TOKEN (PLUS_PLUS); +} + +"--" { + RETURN_TOKEN (MINUS_MINUS); +} + +"##" { + if (! parser->skipping) { + if (parser->is_gles) + glcpp_error(yylloc, yyextra, "Token pasting (##) is illegal in GLES"); + RETURN_TOKEN (PASTE); + } +} + +"defined" { + RETURN_TOKEN (DEFINED); +} + +{IDENTIFIER} { + RETURN_STRING_TOKEN (IDENTIFIER); +} + +{PP_NUMBER} { + RETURN_STRING_TOKEN (OTHER); +} + +{PUNCTUATION} { + RETURN_TOKEN (yytext[0]); +} + +{OTHER}+ { + RETURN_STRING_TOKEN (OTHER); +} + +{HSPACE} { + if (yyextra->space_tokens) { + RETURN_TOKEN (SPACE); + } +} + + /* We preserve all newlines, even between #if 0..#endif, so no + skipping.. */ +<*>{NEWLINE} { + if (parser->commented_newlines) { + BEGIN NEWLINE_CATCHUP; + } else { + BEGIN INITIAL; + } + yyextra->space_tokens = 1; + yyextra->lexing_directive = 0; + yylineno++; + yycolumn = 0; + RETURN_TOKEN_NEVER_SKIP (NEWLINE); +} + +<INITIAL,COMMENT,DEFINE,HASH><<EOF>> { + if (YY_START == COMMENT) + glcpp_error(yylloc, yyextra, "Unterminated comment"); + BEGIN DONE; /* Don't keep matching this rule forever. */ + yyextra->lexing_directive = 0; + if (! parser->last_token_was_newline) + RETURN_TOKEN (NEWLINE); +} + + /* This is a catch-all to avoid the annoying default flex action which + * matches any character and prints it. If any input ever matches this + * rule, then we have made a mistake above and need to fix one or more + * of the preceding patterns to match that input. */ + +<*>. { + glcpp_error(yylloc, yyextra, "Internal compiler error: Unexpected character: %s", yytext); + + /* We don't actually use the UNREACHABLE start condition. We + only have this block here so that we can pretend to call some + generated functions, (to avoid "defined but not used" + warnings. */ + if (YY_START == UNREACHABLE) { + unput('.'); + yy_top_state(yyextra); + } +} + +%% + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader) +{ + yy_scan_string(shader, parser->scanner); +} diff --git a/src/compiler/glsl/glcpp/glcpp-parse.y b/src/compiler/glsl/glcpp/glcpp-parse.y new file mode 100644 index 0000000000..ef1a6575aa --- /dev/null +++ b/src/compiler/glsl/glcpp/glcpp-parse.y @@ -0,0 +1,2557 @@ +%{ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <inttypes.h> + +#include "glcpp.h" +#include "main/core.h" /* for struct gl_extensions */ +#include "main/mtypes.h" /* for gl_api enum */ + +static void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error); + +static void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + token_list_t *replacements); + +static void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *macro, + string_list_t *parameters, + token_list_t *replacements); + +static string_list_t * +_string_list_create (void *ctx); + +static void +_string_list_append_item (string_list_t *list, const char *str); + +static int +_string_list_contains (string_list_t *list, const char *member, int *index); + +static const char * +_string_list_has_duplicate (string_list_t *list); + +static int +_string_list_length (string_list_t *list); + +static int +_string_list_equal (string_list_t *a, string_list_t *b); + +static argument_list_t * +_argument_list_create (void *ctx); + +static void +_argument_list_append (argument_list_t *list, token_list_t *argument); + +static int +_argument_list_length (argument_list_t *list); + +static token_list_t * +_argument_list_member_at (argument_list_t *list, int index); + +/* Note: This function ralloc_steal()s the str pointer. */ +static token_t * +_token_create_str (void *ctx, int type, char *str); + +static token_t * +_token_create_ival (void *ctx, int type, int ival); + +static token_list_t * +_token_list_create (void *ctx); + +static void +_token_list_append (token_list_t *list, token_t *token); + +static void +_token_list_append_list (token_list_t *list, token_list_t *tail); + +static int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b); + +static void +_parser_active_list_push (glcpp_parser_t *parser, + const char *identifier, + token_node_t *marker); + +static void +_parser_active_list_pop (glcpp_parser_t *parser); + +static int +_parser_active_list_contains (glcpp_parser_t *parser, const char *identifier); + +typedef enum { + EXPANSION_MODE_IGNORE_DEFINED, + EXPANSION_MODE_EVALUATE_DEFINED +} expansion_mode_t; + +/* Expand list, and begin lexing from the result (after first + * prefixing a token of type 'head_token_type'). + */ +static void +_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser, + int head_token_type, + token_list_t *list, + expansion_mode_t mode); + +/* Perform macro expansion in-place on the given list. */ +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list, + expansion_mode_t mode); + +static void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list); + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition); + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition); + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc); + +static void +_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version, + const char *ident, bool explicitly_set); + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser); + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list); + +static void +add_builtin_define(glcpp_parser_t *parser, const char *name, int value); + +%} + +%pure-parser +%error-verbose + +%locations +%initial-action { + @$.first_line = 1; + @$.first_column = 1; + @$.last_line = 1; + @$.last_column = 1; + @$.source = 0; +} + +%parse-param {glcpp_parser_t *parser} +%lex-param {glcpp_parser_t *parser} + +%expect 0 + + /* We use HASH_TOKEN, DEFINE_TOKEN and VERSION_TOKEN (as opposed to + * HASH, DEFINE, and VERSION) to avoid conflicts with other symbols, + * (such as the <HASH> and <DEFINE> start conditions in the lexer). */ +%token DEFINED ELIF_EXPANDED HASH_TOKEN DEFINE_TOKEN FUNC_IDENTIFIER OBJ_IDENTIFIER ELIF ELSE ENDIF ERROR_TOKEN IF IFDEF IFNDEF LINE PRAGMA UNDEF VERSION_TOKEN GARBAGE IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE PLUS_PLUS MINUS_MINUS +%token PASTE +%type <ival> INTEGER operator SPACE integer_constant +%type <expression_value> expression +%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA +%type <string_list> identifier_list +%type <token> preprocessing_token +%type <token_list> pp_tokens replacement_list text_line +%left OR +%left AND +%left '|' +%left '^' +%left '&' +%left EQUAL NOT_EQUAL +%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL +%left LEFT_SHIFT RIGHT_SHIFT +%left '+' '-' +%left '*' '/' '%' +%right UNARY + +%debug + +%% + +input: + /* empty */ +| input line +; + +line: + control_line +| SPACE control_line +| text_line { + _glcpp_parser_print_expanded_token_list (parser, $1); + ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n"); + ralloc_free ($1); + } +| expanded_line +; + +expanded_line: + IF_EXPANDED expression NEWLINE { + if (parser->is_gles && $2.undefined_macro) + glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro); + _glcpp_parser_skip_stack_push_if (parser, & @1, $2.value); + } +| ELIF_EXPANDED expression NEWLINE { + if (parser->is_gles && $2.undefined_macro) + glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro); + _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2.value); + } +| LINE_EXPANDED integer_constant NEWLINE { + parser->has_new_line_number = 1; + parser->new_line_number = $2; + ralloc_asprintf_rewrite_tail (&parser->output, + &parser->output_length, + "#line %" PRIiMAX "\n", + $2); + } +| LINE_EXPANDED integer_constant integer_constant NEWLINE { + parser->has_new_line_number = 1; + parser->new_line_number = $2; + parser->has_new_source_number = 1; + parser->new_source_number = $3; + ralloc_asprintf_rewrite_tail (&parser->output, + &parser->output_length, + "#line %" PRIiMAX " %" PRIiMAX "\n", + $2, $3); + } +; + +define: + OBJ_IDENTIFIER replacement_list NEWLINE { + _define_object_macro (parser, & @1, $1, $2); + } +| FUNC_IDENTIFIER '(' ')' replacement_list NEWLINE { + _define_function_macro (parser, & @1, $1, NULL, $4); + } +| FUNC_IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE { + _define_function_macro (parser, & @1, $1, $3, $5); + } +; + +control_line: + control_line_success { + ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n"); + } +| control_line_error +| HASH_TOKEN LINE { + glcpp_parser_resolve_implicit_version(parser); + } pp_tokens NEWLINE { + + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + _glcpp_parser_expand_and_lex_from (parser, + LINE_EXPANDED, $4, + EXPANSION_MODE_IGNORE_DEFINED); + } + } +; + +control_line_success: + HASH_TOKEN DEFINE_TOKEN { + glcpp_parser_resolve_implicit_version(parser); + } define +| HASH_TOKEN UNDEF { + glcpp_parser_resolve_implicit_version(parser); + } IDENTIFIER NEWLINE { + macro_t *macro; + if (strcmp("__LINE__", $4) == 0 + || strcmp("__FILE__", $4) == 0 + || strcmp("__VERSION__", $4) == 0 + || strncmp("GL_", $4, 3) == 0) + glcpp_error(& @1, parser, "Built-in (pre-defined)" + " macro names cannot be undefined."); + + macro = hash_table_find (parser->defines, $4); + if (macro) { + hash_table_remove (parser->defines, $4); + ralloc_free (macro); + } + ralloc_free ($4); + } +| HASH_TOKEN IF { + glcpp_parser_resolve_implicit_version(parser); + } pp_tokens NEWLINE { + /* Be careful to only evaluate the 'if' expression if + * we are not skipping. When we are skipping, we + * simply push a new 0-valued 'if' onto the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + _glcpp_parser_expand_and_lex_from (parser, + IF_EXPANDED, $4, + EXPANSION_MODE_EVALUATE_DEFINED); + } + else + { + _glcpp_parser_skip_stack_push_if (parser, & @1, 0); + parser->skip_stack->type = SKIP_TO_ENDIF; + } + } +| HASH_TOKEN IF NEWLINE { + /* #if without an expression is only an error if we + * are not skipping */ + if (parser->skip_stack == NULL || + parser->skip_stack->type == SKIP_NO_SKIP) + { + glcpp_error(& @1, parser, "#if with no expression"); + } + _glcpp_parser_skip_stack_push_if (parser, & @1, 0); + } +| HASH_TOKEN IFDEF { + glcpp_parser_resolve_implicit_version(parser); + } IDENTIFIER junk NEWLINE { + macro_t *macro = hash_table_find (parser->defines, $4); + ralloc_free ($4); + _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL); + } +| HASH_TOKEN IFNDEF { + glcpp_parser_resolve_implicit_version(parser); + } IDENTIFIER junk NEWLINE { + macro_t *macro = hash_table_find (parser->defines, $4); + ralloc_free ($4); + _glcpp_parser_skip_stack_push_if (parser, & @3, macro == NULL); + } +| HASH_TOKEN ELIF pp_tokens NEWLINE { + /* Be careful to only evaluate the 'elif' expression + * if we are not skipping. When we are skipping, we + * simply change to a 0-valued 'elif' on the skip + * stack. + * + * This avoids generating diagnostics for invalid + * expressions that are being skipped. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + _glcpp_parser_expand_and_lex_from (parser, + ELIF_EXPANDED, $3, + EXPANSION_MODE_EVALUATE_DEFINED); + } + else if (parser->skip_stack && + parser->skip_stack->has_else) + { + glcpp_error(& @1, parser, "#elif after #else"); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & @1, + "elif", 0); + } + } +| HASH_TOKEN ELIF NEWLINE { + /* #elif without an expression is an error unless we + * are skipping. */ + if (parser->skip_stack && + parser->skip_stack->type == SKIP_TO_ELSE) + { + glcpp_error(& @1, parser, "#elif with no expression"); + } + else if (parser->skip_stack && + parser->skip_stack->has_else) + { + glcpp_error(& @1, parser, "#elif after #else"); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & @1, + "elif", 0); + glcpp_warning(& @1, parser, "ignoring illegal #elif without expression"); + } + } +| HASH_TOKEN ELSE { parser->lexing_directive = 1; } NEWLINE { + if (parser->skip_stack && + parser->skip_stack->has_else) + { + glcpp_error(& @1, parser, "multiple #else"); + } + else + { + _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1); + if (parser->skip_stack) + parser->skip_stack->has_else = true; + } + } +| HASH_TOKEN ENDIF { + _glcpp_parser_skip_stack_pop (parser, & @1); + } NEWLINE +| HASH_TOKEN VERSION_TOKEN integer_constant NEWLINE { + if (parser->version_resolved) { + glcpp_error(& @1, parser, "#version must appear on the first line"); + } + _glcpp_parser_handle_version_declaration(parser, $3, NULL, true); + } +| HASH_TOKEN VERSION_TOKEN integer_constant IDENTIFIER NEWLINE { + if (parser->version_resolved) { + glcpp_error(& @1, parser, "#version must appear on the first line"); + } + _glcpp_parser_handle_version_declaration(parser, $3, $4, true); + } +| HASH_TOKEN NEWLINE { + glcpp_parser_resolve_implicit_version(parser); + } +| HASH_TOKEN PRAGMA NEWLINE { + ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "#%s", $2); + } +; + +control_line_error: + HASH_TOKEN ERROR_TOKEN NEWLINE { + glcpp_error(& @1, parser, "#%s", $2); + } +| HASH_TOKEN DEFINE_TOKEN NEWLINE { + glcpp_error (& @1, parser, "#define without macro name"); + } +| HASH_TOKEN GARBAGE pp_tokens NEWLINE { + glcpp_error (& @1, parser, "Illegal non-directive after #"); + } +; + +integer_constant: + INTEGER_STRING { + if (strlen ($1) >= 3 && strncmp ($1, "0x", 2) == 0) { + $$ = strtoll ($1 + 2, NULL, 16); + } else if ($1[0] == '0') { + $$ = strtoll ($1, NULL, 8); + } else { + $$ = strtoll ($1, NULL, 10); + } + } +| INTEGER { + $$ = $1; + } + +expression: + integer_constant { + $$.value = $1; + $$.undefined_macro = NULL; + } +| IDENTIFIER { + $$.value = 0; + if (parser->is_gles) + $$.undefined_macro = ralloc_strdup (parser, $1); + else + $$.undefined_macro = NULL; + } +| expression OR expression { + $$.value = $1.value || $3.value; + + /* Short-circuit: Only flag undefined from right side + * if left side evaluates to false. + */ + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else if (! $1.value) + $$.undefined_macro = $3.undefined_macro; + } +| expression AND expression { + $$.value = $1.value && $3.value; + + /* Short-circuit: Only flag undefined from right-side + * if left side evaluates to true. + */ + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else if ($1.value) + $$.undefined_macro = $3.undefined_macro; + } +| expression '|' expression { + $$.value = $1.value | $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '^' expression { + $$.value = $1.value ^ $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '&' expression { + $$.value = $1.value & $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression NOT_EQUAL expression { + $$.value = $1.value != $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression EQUAL expression { + $$.value = $1.value == $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression GREATER_OR_EQUAL expression { + $$.value = $1.value >= $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression LESS_OR_EQUAL expression { + $$.value = $1.value <= $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '>' expression { + $$.value = $1.value > $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '<' expression { + $$.value = $1.value < $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression RIGHT_SHIFT expression { + $$.value = $1.value >> $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression LEFT_SHIFT expression { + $$.value = $1.value << $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '-' expression { + $$.value = $1.value - $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '+' expression { + $$.value = $1.value + $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '%' expression { + if ($3.value == 0) { + yyerror (& @1, parser, + "zero modulus in preprocessor directive"); + } else { + $$.value = $1.value % $3.value; + } + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '/' expression { + if ($3.value == 0) { + yyerror (& @1, parser, + "division by 0 in preprocessor directive"); + } else { + $$.value = $1.value / $3.value; + } + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| expression '*' expression { + $$.value = $1.value * $3.value; + if ($1.undefined_macro) + $$.undefined_macro = $1.undefined_macro; + else + $$.undefined_macro = $3.undefined_macro; + } +| '!' expression %prec UNARY { + $$.value = ! $2.value; + $$.undefined_macro = $2.undefined_macro; + } +| '~' expression %prec UNARY { + $$.value = ~ $2.value; + $$.undefined_macro = $2.undefined_macro; + } +| '-' expression %prec UNARY { + $$.value = - $2.value; + $$.undefined_macro = $2.undefined_macro; + } +| '+' expression %prec UNARY { + $$.value = + $2.value; + $$.undefined_macro = $2.undefined_macro; + } +| '(' expression ')' { + $$ = $2; + } +; + +identifier_list: + IDENTIFIER { + $$ = _string_list_create (parser); + _string_list_append_item ($$, $1); + ralloc_steal ($$, $1); + } +| identifier_list ',' IDENTIFIER { + $$ = $1; + _string_list_append_item ($$, $3); + ralloc_steal ($$, $3); + } +; + +text_line: + NEWLINE { $$ = NULL; } +| pp_tokens NEWLINE +; + +replacement_list: + /* empty */ { $$ = NULL; } +| pp_tokens +; + +junk: + /* empty */ +| pp_tokens { + glcpp_error(&@1, parser, "extra tokens at end of directive"); + } +; + +pp_tokens: + preprocessing_token { + parser->space_tokens = 1; + $$ = _token_list_create (parser); + _token_list_append ($$, $1); + } +| pp_tokens preprocessing_token { + $$ = $1; + _token_list_append ($$, $2); + } +; + +preprocessing_token: + IDENTIFIER { + $$ = _token_create_str (parser, IDENTIFIER, $1); + $$->location = yylloc; + } +| INTEGER_STRING { + $$ = _token_create_str (parser, INTEGER_STRING, $1); + $$->location = yylloc; + } +| operator { + $$ = _token_create_ival (parser, $1, $1); + $$->location = yylloc; + } +| DEFINED { + $$ = _token_create_ival (parser, DEFINED, DEFINED); + $$->location = yylloc; + } +| OTHER { + $$ = _token_create_str (parser, OTHER, $1); + $$->location = yylloc; + } +| SPACE { + $$ = _token_create_ival (parser, SPACE, SPACE); + $$->location = yylloc; + } +; + +operator: + '[' { $$ = '['; } +| ']' { $$ = ']'; } +| '(' { $$ = '('; } +| ')' { $$ = ')'; } +| '{' { $$ = '{'; } +| '}' { $$ = '}'; } +| '.' { $$ = '.'; } +| '&' { $$ = '&'; } +| '*' { $$ = '*'; } +| '+' { $$ = '+'; } +| '-' { $$ = '-'; } +| '~' { $$ = '~'; } +| '!' { $$ = '!'; } +| '/' { $$ = '/'; } +| '%' { $$ = '%'; } +| LEFT_SHIFT { $$ = LEFT_SHIFT; } +| RIGHT_SHIFT { $$ = RIGHT_SHIFT; } +| '<' { $$ = '<'; } +| '>' { $$ = '>'; } +| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; } +| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; } +| EQUAL { $$ = EQUAL; } +| NOT_EQUAL { $$ = NOT_EQUAL; } +| '^' { $$ = '^'; } +| '|' { $$ = '|'; } +| AND { $$ = AND; } +| OR { $$ = OR; } +| ';' { $$ = ';'; } +| ',' { $$ = ','; } +| '=' { $$ = '='; } +| PASTE { $$ = PASTE; } +| PLUS_PLUS { $$ = PLUS_PLUS; } +| MINUS_MINUS { $$ = MINUS_MINUS; } +; + +%% + +string_list_t * +_string_list_create (void *ctx) +{ + string_list_t *list; + + list = ralloc (ctx, string_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_string_list_append_item (string_list_t *list, const char *str) +{ + string_node_t *node; + + node = ralloc (list, string_node_t); + node->str = ralloc_strdup (node, str); + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_string_list_contains (string_list_t *list, const char *member, int *index) +{ + string_node_t *node; + int i; + + if (list == NULL) + return 0; + + for (i = 0, node = list->head; node; i++, node = node->next) { + if (strcmp (node->str, member) == 0) { + if (index) + *index = i; + return 1; + } + } + + return 0; +} + +/* Return duplicate string in list (if any), NULL otherwise. */ +const char * +_string_list_has_duplicate (string_list_t *list) +{ + string_node_t *node, *dup; + + if (list == NULL) + return NULL; + + for (node = list->head; node; node = node->next) { + for (dup = node->next; dup; dup = dup->next) { + if (strcmp (node->str, dup->str) == 0) + return node->str; + } + } + + return NULL; +} + +int +_string_list_length (string_list_t *list) +{ + int length = 0; + string_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +int +_string_list_equal (string_list_t *a, string_list_t *b) +{ + string_node_t *node_a, *node_b; + + if (a == NULL && b == NULL) + return 1; + + if (a == NULL || b == NULL) + return 0; + + for (node_a = a->head, node_b = b->head; + node_a && node_b; + node_a = node_a->next, node_b = node_b->next) + { + if (strcmp (node_a->str, node_b->str)) + return 0; + } + + /* Catch the case of lists being different lengths, (which + * would cause the loop above to terminate after the shorter + * list). */ + return node_a == node_b; +} + +argument_list_t * +_argument_list_create (void *ctx) +{ + argument_list_t *list; + + list = ralloc (ctx, argument_list_t); + list->head = NULL; + list->tail = NULL; + + return list; +} + +void +_argument_list_append (argument_list_t *list, token_list_t *argument) +{ + argument_node_t *node; + + node = ralloc (list, argument_node_t); + node->argument = argument; + + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; +} + +int +_argument_list_length (argument_list_t *list) +{ + int length = 0; + argument_node_t *node; + + if (list == NULL) + return 0; + + for (node = list->head; node; node = node->next) + length++; + + return length; +} + +token_list_t * +_argument_list_member_at (argument_list_t *list, int index) +{ + argument_node_t *node; + int i; + + if (list == NULL) + return NULL; + + node = list->head; + for (i = 0; i < index; i++) { + node = node->next; + if (node == NULL) + break; + } + + if (node) + return node->argument; + + return NULL; +} + +/* Note: This function ralloc_steal()s the str pointer. */ +token_t * +_token_create_str (void *ctx, int type, char *str) +{ + token_t *token; + + token = ralloc (ctx, token_t); + token->type = type; + token->value.str = str; + + ralloc_steal (token, str); + + return token; +} + +token_t * +_token_create_ival (void *ctx, int type, int ival) +{ + token_t *token; + + token = ralloc (ctx, token_t); + token->type = type; + token->value.ival = ival; + + return token; +} + +token_list_t * +_token_list_create (void *ctx) +{ + token_list_t *list; + + list = ralloc (ctx, token_list_t); + list->head = NULL; + list->tail = NULL; + list->non_space_tail = NULL; + + return list; +} + +void +_token_list_append (token_list_t *list, token_t *token) +{ + token_node_t *node; + + node = ralloc (list, token_node_t); + node->token = token; + node->next = NULL; + + if (list->head == NULL) { + list->head = node; + } else { + list->tail->next = node; + } + + list->tail = node; + if (token->type != SPACE) + list->non_space_tail = node; +} + +void +_token_list_append_list (token_list_t *list, token_list_t *tail) +{ + if (tail == NULL || tail->head == NULL) + return; + + if (list->head == NULL) { + list->head = tail->head; + } else { + list->tail->next = tail->head; + } + + list->tail = tail->tail; + list->non_space_tail = tail->non_space_tail; +} + +static token_list_t * +_token_list_copy (void *ctx, token_list_t *other) +{ + token_list_t *copy; + token_node_t *node; + + if (other == NULL) + return NULL; + + copy = _token_list_create (ctx); + for (node = other->head; node; node = node->next) { + token_t *new_token = ralloc (copy, token_t); + *new_token = *node->token; + _token_list_append (copy, new_token); + } + + return copy; +} + +static void +_token_list_trim_trailing_space (token_list_t *list) +{ + token_node_t *tail, *next; + + if (list->non_space_tail) { + tail = list->non_space_tail->next; + list->non_space_tail->next = NULL; + list->tail = list->non_space_tail; + + while (tail) { + next = tail->next; + ralloc_free (tail); + tail = next; + } + } +} + +static int +_token_list_is_empty_ignoring_space (token_list_t *l) +{ + token_node_t *n; + + if (l == NULL) + return 1; + + n = l->head; + while (n != NULL && n->token->type == SPACE) + n = n->next; + + return n == NULL; +} + +int +_token_list_equal_ignoring_space (token_list_t *a, token_list_t *b) +{ + token_node_t *node_a, *node_b; + + if (a == NULL || b == NULL) { + int a_empty = _token_list_is_empty_ignoring_space(a); + int b_empty = _token_list_is_empty_ignoring_space(b); + return a_empty == b_empty; + } + + node_a = a->head; + node_b = b->head; + + while (1) + { + if (node_a == NULL && node_b == NULL) + break; + + if (node_a == NULL || node_b == NULL) + return 0; + /* Make sure whitespace appears in the same places in both. + * It need not be exactly the same amount of whitespace, + * though. + */ + if (node_a->token->type == SPACE + && node_b->token->type == SPACE) { + while (node_a && node_a->token->type == SPACE) + node_a = node_a->next; + while (node_b && node_b->token->type == SPACE) + node_b = node_b->next; + continue; + } + + if (node_a->token->type != node_b->token->type) + return 0; + + switch (node_a->token->type) { + case INTEGER: + if (node_a->token->value.ival != + node_b->token->value.ival) + { + return 0; + } + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + if (strcmp (node_a->token->value.str, + node_b->token->value.str)) + { + return 0; + } + break; + } + + node_a = node_a->next; + node_b = node_b->next; + } + + return 1; +} + +static void +_token_print (char **out, size_t *len, token_t *token) +{ + if (token->type < 256) { + ralloc_asprintf_rewrite_tail (out, len, "%c", token->type); + return; + } + + switch (token->type) { + case INTEGER: + ralloc_asprintf_rewrite_tail (out, len, "%" PRIiMAX, token->value.ival); + break; + case IDENTIFIER: + case INTEGER_STRING: + case OTHER: + ralloc_asprintf_rewrite_tail (out, len, "%s", token->value.str); + break; + case SPACE: + ralloc_asprintf_rewrite_tail (out, len, " "); + break; + case LEFT_SHIFT: + ralloc_asprintf_rewrite_tail (out, len, "<<"); + break; + case RIGHT_SHIFT: + ralloc_asprintf_rewrite_tail (out, len, ">>"); + break; + case LESS_OR_EQUAL: + ralloc_asprintf_rewrite_tail (out, len, "<="); + break; + case GREATER_OR_EQUAL: + ralloc_asprintf_rewrite_tail (out, len, ">="); + break; + case EQUAL: + ralloc_asprintf_rewrite_tail (out, len, "=="); + break; + case NOT_EQUAL: + ralloc_asprintf_rewrite_tail (out, len, "!="); + break; + case AND: + ralloc_asprintf_rewrite_tail (out, len, "&&"); + break; + case OR: + ralloc_asprintf_rewrite_tail (out, len, "||"); + break; + case PASTE: + ralloc_asprintf_rewrite_tail (out, len, "##"); + break; + case PLUS_PLUS: + ralloc_asprintf_rewrite_tail (out, len, "++"); + break; + case MINUS_MINUS: + ralloc_asprintf_rewrite_tail (out, len, "--"); + break; + case DEFINED: + ralloc_asprintf_rewrite_tail (out, len, "defined"); + break; + case PLACEHOLDER: + /* Nothing to print. */ + break; + default: + assert(!"Error: Don't know how to print token."); + + break; + } +} + +/* Return a new token (ralloc()ed off of 'token') formed by pasting + * 'token' and 'other'. Note that this function may return 'token' or + * 'other' directly rather than allocating anything new. + * + * Caution: Only very cursory error-checking is performed to see if + * the final result is a valid single token. */ +static token_t * +_token_paste (glcpp_parser_t *parser, token_t *token, token_t *other) +{ + token_t *combined = NULL; + + /* Pasting a placeholder onto anything makes no change. */ + if (other->type == PLACEHOLDER) + return token; + + /* When 'token' is a placeholder, just return 'other'. */ + if (token->type == PLACEHOLDER) + return other; + + /* A very few single-character punctuators can be combined + * with another to form a multi-character punctuator. */ + switch (token->type) { + case '<': + if (other->type == '<') + combined = _token_create_ival (token, LEFT_SHIFT, LEFT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, LESS_OR_EQUAL, LESS_OR_EQUAL); + break; + case '>': + if (other->type == '>') + combined = _token_create_ival (token, RIGHT_SHIFT, RIGHT_SHIFT); + else if (other->type == '=') + combined = _token_create_ival (token, GREATER_OR_EQUAL, GREATER_OR_EQUAL); + break; + case '=': + if (other->type == '=') + combined = _token_create_ival (token, EQUAL, EQUAL); + break; + case '!': + if (other->type == '=') + combined = _token_create_ival (token, NOT_EQUAL, NOT_EQUAL); + break; + case '&': + if (other->type == '&') + combined = _token_create_ival (token, AND, AND); + break; + case '|': + if (other->type == '|') + combined = _token_create_ival (token, OR, OR); + break; + } + + if (combined != NULL) { + /* Inherit the location from the first token */ + combined->location = token->location; + return combined; + } + + /* Two string-valued (or integer) tokens can usually just be + * mashed together. (We also handle a string followed by an + * integer here as well.) + * + * There are some exceptions here. Notably, if the first token + * is an integer (or a string representing an integer), then + * the second token must also be an integer or must be a + * string representing an integer that begins with a digit. + */ + if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING || token->type == INTEGER) && + (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING || other->type == INTEGER)) + { + char *str; + int combined_type; + + /* Check that pasting onto an integer doesn't create a + * non-integer, (that is, only digits can be + * pasted. */ + if (token->type == INTEGER_STRING || token->type == INTEGER) + { + switch (other->type) { + case INTEGER_STRING: + if (other->value.str[0] < '0' || + other->value.str[0] > '9') + goto FAIL; + break; + case INTEGER: + if (other->value.ival < 0) + goto FAIL; + break; + default: + goto FAIL; + } + } + + if (token->type == INTEGER) + str = ralloc_asprintf (token, "%" PRIiMAX, + token->value.ival); + else + str = ralloc_strdup (token, token->value.str); + + + if (other->type == INTEGER) + ralloc_asprintf_append (&str, "%" PRIiMAX, + other->value.ival); + else + ralloc_strcat (&str, other->value.str); + + /* New token is same type as original token, unless we + * started with an integer, in which case we will be + * creating an integer-string. */ + combined_type = token->type; + if (combined_type == INTEGER) + combined_type = INTEGER_STRING; + + combined = _token_create_str (token, combined_type, str); + combined->location = token->location; + return combined; + } + + FAIL: + glcpp_error (&token->location, parser, ""); + ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "Pasting \""); + _token_print (&parser->info_log, &parser->info_log_length, token); + ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" and \""); + _token_print (&parser->info_log, &parser->info_log_length, other); + ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" does not give a valid preprocessing token.\n"); + + return token; +} + +static void +_token_list_print (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + if (list == NULL) + return; + + for (node = list->head; node; node = node->next) + _token_print (&parser->output, &parser->output_length, node->token); +} + +void +yyerror (YYLTYPE *locp, glcpp_parser_t *parser, const char *error) +{ + glcpp_error(locp, parser, "%s", error); +} + +static void add_builtin_define(glcpp_parser_t *parser, + const char *name, int value) +{ + token_t *tok; + token_list_t *list; + + tok = _token_create_ival (parser, INTEGER, value); + + list = _token_list_create(parser); + _token_list_append(list, tok); + _define_object_macro(parser, NULL, name, list); +} + +glcpp_parser_t * +glcpp_parser_create (const struct gl_extensions *extensions, gl_api api) +{ + glcpp_parser_t *parser; + + parser = ralloc (NULL, glcpp_parser_t); + + glcpp_lex_init_extra (parser, &parser->scanner); + parser->defines = hash_table_ctor (32, hash_table_string_hash, + hash_table_string_compare); + parser->active = NULL; + parser->lexing_directive = 0; + parser->space_tokens = 1; + parser->last_token_was_newline = 0; + parser->last_token_was_space = 0; + parser->first_non_space_token_this_line = 1; + parser->newline_as_space = 0; + parser->in_control_line = 0; + parser->paren_count = 0; + parser->commented_newlines = 0; + + parser->skip_stack = NULL; + parser->skipping = 0; + + parser->lex_from_list = NULL; + parser->lex_from_node = NULL; + + parser->output = ralloc_strdup(parser, ""); + parser->output_length = 0; + parser->info_log = ralloc_strdup(parser, ""); + parser->info_log_length = 0; + parser->error = 0; + + parser->extensions = extensions; + parser->api = api; + parser->version_resolved = false; + + parser->has_new_line_number = 0; + parser->new_line_number = 1; + parser->has_new_source_number = 0; + parser->new_source_number = 0; + + return parser; +} + +void +glcpp_parser_destroy (glcpp_parser_t *parser) +{ + glcpp_lex_destroy (parser->scanner); + hash_table_dtor (parser->defines); + ralloc_free (parser); +} + +typedef enum function_status +{ + FUNCTION_STATUS_SUCCESS, + FUNCTION_NOT_A_FUNCTION, + FUNCTION_UNBALANCED_PARENTHESES +} function_status_t; + +/* Find a set of function-like macro arguments by looking for a + * balanced set of parentheses. + * + * When called, 'node' should be the opening-parenthesis token, (or + * perhaps preceeding SPACE tokens). Upon successful return *last will + * be the last consumed node, (corresponding to the closing right + * parenthesis). + * + * Return values: + * + * FUNCTION_STATUS_SUCCESS: + * + * Successfully parsed a set of function arguments. + * + * FUNCTION_NOT_A_FUNCTION: + * + * Macro name not followed by a '('. This is not an error, but + * simply that the macro name should be treated as a non-macro. + * + * FUNCTION_UNBALANCED_PARENTHESES + * + * Macro name is not followed by a balanced set of parentheses. + */ +static function_status_t +_arguments_parse (argument_list_t *arguments, + token_node_t *node, + token_node_t **last) +{ + token_list_t *argument; + int paren_count; + + node = node->next; + + /* Ignore whitespace before first parenthesis. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL || node->token->type != '(') + return FUNCTION_NOT_A_FUNCTION; + + node = node->next; + + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + + for (paren_count = 1; node; node = node->next) { + if (node->token->type == '(') + { + paren_count++; + } + else if (node->token->type == ')') + { + paren_count--; + if (paren_count == 0) + break; + } + + if (node->token->type == ',' && + paren_count == 1) + { + _token_list_trim_trailing_space (argument); + argument = _token_list_create (arguments); + _argument_list_append (arguments, argument); + } + else { + if (argument->head == NULL) { + /* Don't treat initial whitespace as + * part of the argument. */ + if (node->token->type == SPACE) + continue; + } + _token_list_append (argument, node->token); + } + } + + if (paren_count) + return FUNCTION_UNBALANCED_PARENTHESES; + + *last = node; + + return FUNCTION_STATUS_SUCCESS; +} + +static token_list_t * +_token_list_create_with_one_ival (void *ctx, int type, int ival) +{ + token_list_t *list; + token_t *node; + + list = _token_list_create (ctx); + node = _token_create_ival (list, type, ival); + _token_list_append (list, node); + + return list; +} + +static token_list_t * +_token_list_create_with_one_space (void *ctx) +{ + return _token_list_create_with_one_ival (ctx, SPACE, SPACE); +} + +static token_list_t * +_token_list_create_with_one_integer (void *ctx, int ival) +{ + return _token_list_create_with_one_ival (ctx, INTEGER, ival); +} + +/* Evaluate a DEFINED token node (based on subsequent tokens in the list). + * + * Note: This function must only be called when "node" is a DEFINED token, + * (and will abort with an assertion failure otherwise). + * + * If "node" is followed, (ignoring any SPACE tokens), by an IDENTIFIER token + * (optionally preceded and followed by '(' and ')' tokens) then the following + * occurs: + * + * If the identifier is a defined macro, this function returns 1. + * + * If the identifier is not a defined macro, this function returns 0. + * + * In either case, *last will be updated to the last node in the list + * consumed by the evaluation, (either the token of the identifier or the + * token of the closing parenthesis). + * + * In all other cases, (such as "node is the final node of the list", or + * "missing closing parenthesis", etc.), this function generates a + * preprocessor error, returns -1 and *last will not be set. + */ +static int +_glcpp_parser_evaluate_defined (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last) +{ + token_node_t *argument, *defined = node; + + assert (node->token->type == DEFINED); + + node = node->next; + + /* Ignore whitespace after DEFINED token. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL) + goto FAIL; + + if (node->token->type == IDENTIFIER || node->token->type == OTHER) { + argument = node; + } else if (node->token->type == '(') { + node = node->next; + + /* Ignore whitespace after '(' token. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL || (node->token->type != IDENTIFIER && + node->token->type != OTHER)) + { + goto FAIL; + } + + argument = node; + + node = node->next; + + /* Ignore whitespace after identifier, before ')' token. */ + while (node && node->token->type == SPACE) + node = node->next; + + if (node == NULL || node->token->type != ')') + goto FAIL; + } else { + goto FAIL; + } + + *last = node; + + return hash_table_find (parser->defines, + argument->token->value.str) ? 1 : 0; + +FAIL: + glcpp_error (&defined->token->location, parser, + "\"defined\" not followed by an identifier"); + return -1; +} + +/* Evaluate all DEFINED nodes in a given list, modifying the list in place. + */ +static void +_glcpp_parser_evaluate_defined_in_list (glcpp_parser_t *parser, + token_list_t *list) +{ + token_node_t *node, *node_prev, *replacement, *last = NULL; + int value; + + if (list == NULL) + return; + + node_prev = NULL; + node = list->head; + + while (node) { + + if (node->token->type != DEFINED) + goto NEXT; + + value = _glcpp_parser_evaluate_defined (parser, node, &last); + if (value == -1) + goto NEXT; + + replacement = ralloc (list, token_node_t); + replacement->token = _token_create_ival (list, INTEGER, value); + + /* Splice replacement node into list, replacing from "node" + * through "last". */ + if (node_prev) + node_prev->next = replacement; + else + list->head = replacement; + replacement->next = last->next; + if (last == list->tail) + list->tail = replacement; + + node = replacement; + + NEXT: + node_prev = node; + node = node->next; + } +} + +/* Perform macro expansion on 'list', placing the resulting tokens + * into a new list which is initialized with a first token of type + * 'head_token_type'. Then begin lexing from the resulting list, + * (return to the current lexing source when this list is exhausted). + * + * See the documentation of _glcpp_parser_expand_token_list for a description + * of the "mode" parameter. + */ +static void +_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser, + int head_token_type, + token_list_t *list, + expansion_mode_t mode) +{ + token_list_t *expanded; + token_t *token; + + expanded = _token_list_create (parser); + token = _token_create_ival (parser, head_token_type, head_token_type); + _token_list_append (expanded, token); + _glcpp_parser_expand_token_list (parser, list, mode); + _token_list_append_list (expanded, list); + glcpp_parser_lex_from (parser, expanded); +} + +static void +_glcpp_parser_apply_pastes (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + node = list->head; + while (node) + { + token_node_t *next_non_space; + + /* Look ahead for a PASTE token, skipping space. */ + next_non_space = node->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) + break; + + if (next_non_space->token->type != PASTE) { + node = next_non_space; + continue; + } + + /* Now find the next non-space token after the PASTE. */ + next_non_space = next_non_space->next; + while (next_non_space && next_non_space->token->type == SPACE) + next_non_space = next_non_space->next; + + if (next_non_space == NULL) { + yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n"); + return; + } + + node->token = _token_paste (parser, node->token, next_non_space->token); + node->next = next_non_space->next; + if (next_non_space == list->tail) + list->tail = node; + } + + list->non_space_tail = list->tail; +} + +/* This is a helper function that's essentially part of the + * implementation of _glcpp_parser_expand_node. It shouldn't be called + * except for by that function. + * + * Returns NULL if node is a simple token with no expansion, (that is, + * although 'node' corresponds to an identifier defined as a + * function-like macro, it is not followed with a parenthesized + * argument list). + * + * Compute the complete expansion of node (which is a function-like + * macro) and subsequent nodes which are arguments. + * + * Returns the token list that results from the expansion and sets + * *last to the last node in the list that was consumed by the + * expansion. Specifically, *last will be set as follows: as the + * token of the closing right parenthesis. + * + * See the documentation of _glcpp_parser_expand_token_list for a description + * of the "mode" parameter. + */ +static token_list_t * +_glcpp_parser_expand_function (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last, + expansion_mode_t mode) +{ + macro_t *macro; + const char *identifier; + argument_list_t *arguments; + function_status_t status; + token_list_t *substituted; + int parameter_index; + + identifier = node->token->value.str; + + macro = hash_table_find (parser->defines, identifier); + + assert (macro->is_function); + + arguments = _argument_list_create (parser); + status = _arguments_parse (arguments, node, last); + + switch (status) { + case FUNCTION_STATUS_SUCCESS: + break; + case FUNCTION_NOT_A_FUNCTION: + return NULL; + case FUNCTION_UNBALANCED_PARENTHESES: + glcpp_error (&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier); + return NULL; + } + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) { + ralloc_free (arguments); + return _token_list_create_with_one_space (parser); + } + + if (! ((_argument_list_length (arguments) == + _string_list_length (macro->parameters)) || + (_string_list_length (macro->parameters) == 0 && + _argument_list_length (arguments) == 1 && + arguments->head->argument->head == NULL))) + { + glcpp_error (&node->token->location, parser, + "Error: macro %s invoked with %d arguments (expected %d)\n", + identifier, + _argument_list_length (arguments), + _string_list_length (macro->parameters)); + return NULL; + } + + /* Perform argument substitution on the replacement list. */ + substituted = _token_list_create (arguments); + + for (node = macro->replacements->head; node; node = node->next) + { + if (node->token->type == IDENTIFIER && + _string_list_contains (macro->parameters, + node->token->value.str, + ¶meter_index)) + { + token_list_t *argument; + argument = _argument_list_member_at (arguments, + parameter_index); + /* Before substituting, we expand the argument + * tokens, or append a placeholder token for + * an empty argument. */ + if (argument->head) { + token_list_t *expanded_argument; + expanded_argument = _token_list_copy (parser, + argument); + _glcpp_parser_expand_token_list (parser, + expanded_argument, + mode); + _token_list_append_list (substituted, + expanded_argument); + } else { + token_t *new_token; + + new_token = _token_create_ival (substituted, + PLACEHOLDER, + PLACEHOLDER); + _token_list_append (substituted, new_token); + } + } else { + _token_list_append (substituted, node->token); + } + } + + /* After argument substitution, and before further expansion + * below, implement token pasting. */ + + _token_list_trim_trailing_space (substituted); + + _glcpp_parser_apply_pastes (parser, substituted); + + return substituted; +} + +/* Compute the complete expansion of node, (and subsequent nodes after + * 'node' in the case that 'node' is a function-like macro and + * subsequent nodes are arguments). + * + * Returns NULL if node is a simple token with no expansion. + * + * Otherwise, returns the token list that results from the expansion + * and sets *last to the last node in the list that was consumed by + * the expansion. Specifically, *last will be set as follows: + * + * As 'node' in the case of object-like macro expansion. + * + * As the token of the closing right parenthesis in the case of + * function-like macro expansion. + * + * See the documentation of _glcpp_parser_expand_token_list for a description + * of the "mode" parameter. + */ +static token_list_t * +_glcpp_parser_expand_node (glcpp_parser_t *parser, + token_node_t *node, + token_node_t **last, + expansion_mode_t mode) +{ + token_t *token = node->token; + const char *identifier; + macro_t *macro; + + /* We only expand identifiers */ + if (token->type != IDENTIFIER) { + return NULL; + } + + *last = node; + identifier = token->value.str; + + /* Special handling for __LINE__ and __FILE__, (not through + * the hash table). */ + if (strcmp(identifier, "__LINE__") == 0) + return _token_list_create_with_one_integer (parser, node->token->location.first_line); + + if (strcmp(identifier, "__FILE__") == 0) + return _token_list_create_with_one_integer (parser, node->token->location.source); + + /* Look up this identifier in the hash table. */ + macro = hash_table_find (parser->defines, identifier); + + /* Not a macro, so no expansion needed. */ + if (macro == NULL) + return NULL; + + /* Finally, don't expand this macro if we're already actively + * expanding it, (to avoid infinite recursion). */ + if (_parser_active_list_contains (parser, identifier)) { + /* We change the token type here from IDENTIFIER to + * OTHER to prevent any future expansion of this + * unexpanded token. */ + char *str; + token_list_t *expansion; + token_t *final; + + str = ralloc_strdup (parser, token->value.str); + final = _token_create_str (parser, OTHER, str); + expansion = _token_list_create (parser); + _token_list_append (expansion, final); + return expansion; + } + + if (! macro->is_function) + { + token_list_t *replacement; + + /* Replace a macro defined as empty with a SPACE token. */ + if (macro->replacements == NULL) + return _token_list_create_with_one_space (parser); + + replacement = _token_list_copy (parser, macro->replacements); + _glcpp_parser_apply_pastes (parser, replacement); + return replacement; + } + + return _glcpp_parser_expand_function (parser, node, last, mode); +} + +/* Push a new identifier onto the parser's active list. + * + * Here, 'marker' is the token node that appears in the list after the + * expansion of 'identifier'. That is, when the list iterator begins + * examining 'marker', then it is time to pop this node from the + * active stack. + */ +static void +_parser_active_list_push (glcpp_parser_t *parser, + const char *identifier, + token_node_t *marker) +{ + active_list_t *node; + + node = ralloc (parser->active, active_list_t); + node->identifier = ralloc_strdup (node, identifier); + node->marker = marker; + node->next = parser->active; + + parser->active = node; +} + +static void +_parser_active_list_pop (glcpp_parser_t *parser) +{ + active_list_t *node = parser->active; + + if (node == NULL) { + parser->active = NULL; + return; + } + + node = parser->active->next; + ralloc_free (parser->active); + + parser->active = node; +} + +static int +_parser_active_list_contains (glcpp_parser_t *parser, const char *identifier) +{ + active_list_t *node; + + if (parser->active == NULL) + return 0; + + for (node = parser->active; node; node = node->next) + if (strcmp (node->identifier, identifier) == 0) + return 1; + + return 0; +} + +/* Walk over the token list replacing nodes with their expansion. + * Whenever nodes are expanded the walking will walk over the new + * nodes, continuing to expand as necessary. The results are placed in + * 'list' itself. + * + * The "mode" argument controls the handling of any DEFINED tokens that + * result from expansion as follows: + * + * EXPANSION_MODE_IGNORE_DEFINED: Any resulting DEFINED tokens will be + * left in the final list, unevaluated. This is the correct mode + * for expanding any list in any context other than a + * preprocessor conditional, (#if or #elif). + * + * EXPANSION_MODE_EVALUATE_DEFINED: Any resulting DEFINED tokens will be + * evaluated to 0 or 1 tokens depending on whether the following + * token is the name of a defined macro. If the DEFINED token is + * not followed by an (optionally parenthesized) identifier, then + * an error will be generated. This the correct mode for + * expanding any list in the context of a preprocessor + * conditional, (#if or #elif). + */ +static void +_glcpp_parser_expand_token_list (glcpp_parser_t *parser, + token_list_t *list, + expansion_mode_t mode) +{ + token_node_t *node_prev; + token_node_t *node, *last = NULL; + token_list_t *expansion; + active_list_t *active_initial = parser->active; + + if (list == NULL) + return; + + _token_list_trim_trailing_space (list); + + node_prev = NULL; + node = list->head; + + if (mode == EXPANSION_MODE_EVALUATE_DEFINED) + _glcpp_parser_evaluate_defined_in_list (parser, list); + + while (node) { + + while (parser->active && parser->active->marker == node) + _parser_active_list_pop (parser); + + expansion = _glcpp_parser_expand_node (parser, node, &last, mode); + if (expansion) { + token_node_t *n; + + if (mode == EXPANSION_MODE_EVALUATE_DEFINED) { + _glcpp_parser_evaluate_defined_in_list (parser, + expansion); + } + + for (n = node; n != last->next; n = n->next) + while (parser->active && + parser->active->marker == n) + { + _parser_active_list_pop (parser); + } + + _parser_active_list_push (parser, + node->token->value.str, + last->next); + + /* Splice expansion into list, supporting a + * simple deletion if the expansion is + * empty. */ + if (expansion->head) { + if (node_prev) + node_prev->next = expansion->head; + else + list->head = expansion->head; + expansion->tail->next = last->next; + if (last == list->tail) + list->tail = expansion->tail; + } else { + if (node_prev) + node_prev->next = last->next; + else + list->head = last->next; + if (last == list->tail) + list->tail = NULL; + } + } else { + node_prev = node; + } + node = node_prev ? node_prev->next : list->head; + } + + /* Remove any lingering effects of this invocation on the + * active list. That is, pop until the list looks like it did + * at the beginning of this function. */ + while (parser->active && parser->active != active_initial) + _parser_active_list_pop (parser); + + list->non_space_tail = list->tail; +} + +void +_glcpp_parser_print_expanded_token_list (glcpp_parser_t *parser, + token_list_t *list) +{ + if (list == NULL) + return; + + _glcpp_parser_expand_token_list (parser, list, EXPANSION_MODE_IGNORE_DEFINED); + + _token_list_trim_trailing_space (list); + + _token_list_print (parser, list); +} + +static void +_check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc, + const char *identifier) +{ + /* Section 3.3 (Preprocessor) of the GLSL 1.30 spec (and later) and + * the GLSL ES spec (all versions) say: + * + * "All macro names containing two consecutive underscores ( __ ) + * are reserved for future use as predefined macro names. All + * macro names prefixed with "GL_" ("GL" followed by a single + * underscore) are also reserved." + * + * The intention is that names containing __ are reserved for internal + * use by the implementation, and names prefixed with GL_ are reserved + * for use by Khronos. Since every extension adds a name prefixed + * with GL_ (i.e., the name of the extension), that should be an + * error. Names simply containing __ are dangerous to use, but should + * be allowed. + * + * A future version of the GLSL specification will clarify this. + */ + if (strstr(identifier, "__")) { + glcpp_warning(loc, parser, + "Macro names containing \"__\" are reserved " + "for use by the implementation.\n"); + } + if (strncmp(identifier, "GL_", 3) == 0) { + glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n"); + } +} + +static int +_macro_equal (macro_t *a, macro_t *b) +{ + if (a->is_function != b->is_function) + return 0; + + if (a->is_function) { + if (! _string_list_equal (a->parameters, b->parameters)) + return 0; + } + + return _token_list_equal_ignoring_space (a->replacements, + b->replacements); +} + +void +_define_object_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + token_list_t *replacements) +{ + macro_t *macro, *previous; + + /* We define pre-defined macros before we've started parsing the + * actual file. So if there's no location defined yet, that's what + * were doing and we don't want to generate an error for using the + * reserved names. */ + if (loc != NULL) + _check_for_reserved_macro_name(parser, loc, identifier); + + macro = ralloc (parser, macro_t); + + macro->is_function = 0; + macro->parameters = NULL; + macro->identifier = ralloc_strdup (macro, identifier); + macro->replacements = replacements; + ralloc_steal (macro, replacements); + + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + ralloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +void +_define_function_macro (glcpp_parser_t *parser, + YYLTYPE *loc, + const char *identifier, + string_list_t *parameters, + token_list_t *replacements) +{ + macro_t *macro, *previous; + const char *dup; + + _check_for_reserved_macro_name(parser, loc, identifier); + + /* Check for any duplicate parameter names. */ + if ((dup = _string_list_has_duplicate (parameters)) != NULL) { + glcpp_error (loc, parser, "Duplicate macro parameter \"%s\"", + dup); + } + + macro = ralloc (parser, macro_t); + ralloc_steal (macro, parameters); + ralloc_steal (macro, replacements); + + macro->is_function = 1; + macro->parameters = parameters; + macro->identifier = ralloc_strdup (macro, identifier); + macro->replacements = replacements; + previous = hash_table_find (parser->defines, identifier); + if (previous) { + if (_macro_equal (macro, previous)) { + ralloc_free (macro); + return; + } + glcpp_error (loc, parser, "Redefinition of macro %s\n", + identifier); + } + + hash_table_insert (parser->defines, macro, identifier); +} + +static int +glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser) +{ + token_node_t *node; + int ret; + + if (parser->lex_from_list == NULL) { + ret = glcpp_lex (yylval, yylloc, parser->scanner); + + /* XXX: This ugly block of code exists for the sole + * purpose of converting a NEWLINE token into a SPACE + * token, but only in the case where we have seen a + * function-like macro name, but have not yet seen its + * closing parenthesis. + * + * There's perhaps a more compact way to do this with + * mid-rule actions in the grammar. + * + * I'm definitely not pleased with the complexity of + * this code here. + */ + if (parser->newline_as_space) + { + if (ret == '(') { + parser->paren_count++; + } else if (ret == ')') { + parser->paren_count--; + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } else if (ret == NEWLINE) { + ret = SPACE; + } else if (ret != SPACE) { + if (parser->paren_count == 0) + parser->newline_as_space = 0; + } + } + else if (parser->in_control_line) + { + if (ret == NEWLINE) + parser->in_control_line = 0; + } + else if (ret == DEFINE_TOKEN || + ret == UNDEF || ret == IF || + ret == IFDEF || ret == IFNDEF || + ret == ELIF || ret == ELSE || + ret == ENDIF || ret == HASH_TOKEN) + { + parser->in_control_line = 1; + } + else if (ret == IDENTIFIER) + { + macro_t *macro; + macro = hash_table_find (parser->defines, + yylval->str); + if (macro && macro->is_function) { + parser->newline_as_space = 1; + parser->paren_count = 0; + } + } + + return ret; + } + + node = parser->lex_from_node; + + if (node == NULL) { + ralloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + return NEWLINE; + } + + *yylval = node->token->value; + ret = node->token->type; + + parser->lex_from_node = node->next; + + return ret; +} + +static void +glcpp_parser_lex_from (glcpp_parser_t *parser, token_list_t *list) +{ + token_node_t *node; + + assert (parser->lex_from_list == NULL); + + /* Copy list, eliminating any space tokens. */ + parser->lex_from_list = _token_list_create (parser); + + for (node = list->head; node; node = node->next) { + if (node->token->type == SPACE) + continue; + _token_list_append (parser->lex_from_list, node->token); + } + + ralloc_free (list); + + parser->lex_from_node = parser->lex_from_list->head; + + /* It's possible the list consisted of nothing but whitespace. */ + if (parser->lex_from_node == NULL) { + ralloc_free (parser->lex_from_list); + parser->lex_from_list = NULL; + } +} + +static void +_glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc, + int condition) +{ + skip_type_t current = SKIP_NO_SKIP; + skip_node_t *node; + + if (parser->skip_stack) + current = parser->skip_stack->type; + + node = ralloc (parser, skip_node_t); + node->loc = *loc; + + if (current == SKIP_NO_SKIP) { + if (condition) + node->type = SKIP_NO_SKIP; + else + node->type = SKIP_TO_ELSE; + } else { + node->type = SKIP_TO_ENDIF; + } + + node->has_else = false; + node->next = parser->skip_stack; + parser->skip_stack = node; +} + +static void +_glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc, + const char *type, int condition) +{ + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "#%s without #if\n", type); + return; + } + + if (parser->skip_stack->type == SKIP_TO_ELSE) { + if (condition) + parser->skip_stack->type = SKIP_NO_SKIP; + } else { + parser->skip_stack->type = SKIP_TO_ENDIF; + } +} + +static void +_glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc) +{ + skip_node_t *node; + + if (parser->skip_stack == NULL) { + glcpp_error (loc, parser, "#endif without #if\n"); + return; + } + + node = parser->skip_stack; + parser->skip_stack = node->next; + ralloc_free (node); +} + +static void +_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version, + const char *es_identifier, + bool explicitly_set) +{ + const struct gl_extensions *extensions = parser->extensions; + + if (parser->version_resolved) + return; + + parser->version_resolved = true; + + add_builtin_define (parser, "__VERSION__", version); + + parser->is_gles = (version == 100) || + (es_identifier && + (strcmp(es_identifier, "es") == 0)); + + /* Add pre-defined macros. */ + if (parser->is_gles) { + add_builtin_define(parser, "GL_ES", 1); + add_builtin_define(parser, "GL_EXT_separate_shader_objects", 1); + add_builtin_define(parser, "GL_EXT_draw_buffers", 1); + + if (extensions != NULL) { + if (extensions->OES_EGL_image_external) + add_builtin_define(parser, "GL_OES_EGL_image_external", 1); + if (extensions->OES_standard_derivatives) + add_builtin_define(parser, "GL_OES_standard_derivatives", 1); + if (extensions->ARB_texture_multisample) + add_builtin_define(parser, "GL_OES_texture_storage_multisample_2d_array", 1); + if (extensions->ARB_blend_func_extended) + add_builtin_define(parser, "GL_EXT_blend_func_extended", 1); + } + } else { + add_builtin_define(parser, "GL_ARB_draw_buffers", 1); + add_builtin_define(parser, "GL_ARB_enhanced_layouts", 1); + add_builtin_define(parser, "GL_ARB_separate_shader_objects", 1); + add_builtin_define(parser, "GL_ARB_texture_rectangle", 1); + add_builtin_define(parser, "GL_AMD_shader_trinary_minmax", 1); + + + if (extensions != NULL) { + if (extensions->EXT_texture_array) + add_builtin_define(parser, "GL_EXT_texture_array", 1); + + if (extensions->ARB_arrays_of_arrays) + add_builtin_define(parser, "GL_ARB_arrays_of_arrays", 1); + + if (extensions->ARB_fragment_coord_conventions) + add_builtin_define(parser, "GL_ARB_fragment_coord_conventions", + 1); + + if (extensions->ARB_fragment_layer_viewport) + add_builtin_define(parser, "GL_ARB_fragment_layer_viewport", 1); + + if (extensions->ARB_explicit_attrib_location) + add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1); + + if (extensions->ARB_explicit_uniform_location) + add_builtin_define(parser, "GL_ARB_explicit_uniform_location", 1); + + if (extensions->ARB_shader_texture_lod) + add_builtin_define(parser, "GL_ARB_shader_texture_lod", 1); + + if (extensions->ARB_draw_instanced) + add_builtin_define(parser, "GL_ARB_draw_instanced", 1); + + if (extensions->ARB_conservative_depth) { + add_builtin_define(parser, "GL_AMD_conservative_depth", 1); + add_builtin_define(parser, "GL_ARB_conservative_depth", 1); + } + + if (extensions->ARB_shader_bit_encoding) + add_builtin_define(parser, "GL_ARB_shader_bit_encoding", 1); + + if (extensions->ARB_shader_clock) + add_builtin_define(parser, "GL_ARB_shader_clock", 1); + + if (extensions->ARB_uniform_buffer_object) + add_builtin_define(parser, "GL_ARB_uniform_buffer_object", 1); + + if (extensions->ARB_texture_cube_map_array) + add_builtin_define(parser, "GL_ARB_texture_cube_map_array", 1); + + if (extensions->ARB_shading_language_packing) + add_builtin_define(parser, "GL_ARB_shading_language_packing", 1); + + if (extensions->ARB_texture_multisample) + add_builtin_define(parser, "GL_ARB_texture_multisample", 1); + + if (extensions->ARB_texture_query_levels) + add_builtin_define(parser, "GL_ARB_texture_query_levels", 1); + + if (extensions->ARB_texture_query_lod) + add_builtin_define(parser, "GL_ARB_texture_query_lod", 1); + + if (extensions->ARB_gpu_shader5) + add_builtin_define(parser, "GL_ARB_gpu_shader5", 1); + + if (extensions->ARB_gpu_shader_fp64) + add_builtin_define(parser, "GL_ARB_gpu_shader_fp64", 1); + + if (extensions->ARB_vertex_attrib_64bit) + add_builtin_define(parser, "GL_ARB_vertex_attrib_64bit", 1); + + if (extensions->AMD_vertex_shader_layer) + add_builtin_define(parser, "GL_AMD_vertex_shader_layer", 1); + + if (extensions->AMD_vertex_shader_viewport_index) + add_builtin_define(parser, "GL_AMD_vertex_shader_viewport_index", 1); + + if (extensions->ARB_shading_language_420pack) + add_builtin_define(parser, "GL_ARB_shading_language_420pack", 1); + + if (extensions->ARB_sample_shading) + add_builtin_define(parser, "GL_ARB_sample_shading", 1); + + if (extensions->ARB_texture_gather) + add_builtin_define(parser, "GL_ARB_texture_gather", 1); + + if (extensions->ARB_shader_atomic_counters) + add_builtin_define(parser, "GL_ARB_shader_atomic_counters", 1); + + if (extensions->ARB_viewport_array) + add_builtin_define(parser, "GL_ARB_viewport_array", 1); + + if (extensions->ARB_compute_shader) + add_builtin_define(parser, "GL_ARB_compute_shader", 1); + + if (extensions->ARB_shader_image_load_store) + add_builtin_define(parser, "GL_ARB_shader_image_load_store", 1); + + if (extensions->ARB_shader_image_size) + add_builtin_define(parser, "GL_ARB_shader_image_size", 1); + + if (extensions->ARB_shader_texture_image_samples) + add_builtin_define(parser, "GL_ARB_shader_texture_image_samples", 1); + + if (extensions->ARB_derivative_control) + add_builtin_define(parser, "GL_ARB_derivative_control", 1); + + if (extensions->ARB_shader_precision) + add_builtin_define(parser, "GL_ARB_shader_precision", 1); + + if (extensions->ARB_shader_storage_buffer_object) + add_builtin_define(parser, "GL_ARB_shader_storage_buffer_object", 1); + + if (extensions->ARB_tessellation_shader) + add_builtin_define(parser, "GL_ARB_tessellation_shader", 1); + + if (extensions->ARB_shader_subroutine) + add_builtin_define(parser, "GL_ARB_shader_subroutine", 1); + + if (extensions->ARB_shader_draw_parameters) + add_builtin_define(parser, "GL_ARB_shader_draw_parameters", 1); + } + } + + if (extensions != NULL) { + if (extensions->EXT_shader_integer_mix) + add_builtin_define(parser, "GL_EXT_shader_integer_mix", 1); + + if (extensions->EXT_shader_samples_identical) + add_builtin_define(parser, "GL_EXT_shader_samples_identical", 1); + } + + if (version >= 150) + add_builtin_define(parser, "GL_core_profile", 1); + + /* Currently, all ES2/ES3 implementations support highp in the + * fragment shader, so we always define this macro in ES2/ES3. + * If we ever get a driver that doesn't support highp, we'll + * need to add a flag to the gl_context and check that here. + */ + if (version >= 130 || parser->is_gles) + add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1); + + if (explicitly_set) { + ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, + "#version %" PRIiMAX "%s%s", version, + es_identifier ? " " : "", + es_identifier ? es_identifier : ""); + } +} + +/* GLSL version if no version is explicitly specified. */ +#define IMPLICIT_GLSL_VERSION 110 + +/* GLSL ES version if no version is explicitly specified. */ +#define IMPLICIT_GLSL_ES_VERSION 100 + +void +glcpp_parser_resolve_implicit_version(glcpp_parser_t *parser) +{ + int language_version = parser->api == API_OPENGLES2 ? + IMPLICIT_GLSL_ES_VERSION : + IMPLICIT_GLSL_VERSION; + + _glcpp_parser_handle_version_declaration(parser, language_version, + NULL, false); +} diff --git a/src/compiler/glsl/glcpp/glcpp.c b/src/compiler/glsl/glcpp/glcpp.c new file mode 100644 index 0000000000..c62f4efec9 --- /dev/null +++ b/src/compiler/glsl/glcpp/glcpp.c @@ -0,0 +1,182 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <getopt.h> + +#include "glcpp.h" +#include "main/mtypes.h" +#include "main/shaderobj.h" +#include "util/strtod.h" + +extern int glcpp_parser_debug; + +void +_mesa_reference_shader(struct gl_context *ctx, struct gl_shader **ptr, + struct gl_shader *sh) +{ + (void) ctx; + *ptr = sh; +} + +/* Read from fp until EOF and return a string of everything read. + */ +static char * +load_text_fp (void *ctx, FILE *fp) +{ +#define CHUNK 4096 + char *text = NULL; + size_t text_size = 0; + size_t total_read = 0; + size_t bytes; + + while (1) { + if (total_read + CHUNK + 1 > text_size) { + text_size = text_size ? text_size * 2 : CHUNK + 1; + text = reralloc_size (ctx, text, text_size); + if (text == NULL) { + fprintf (stderr, "Out of memory\n"); + return NULL; + } + } + bytes = fread (text + total_read, 1, CHUNK, fp); + total_read += bytes; + + if (bytes < CHUNK) { + break; + } + } + + text[total_read] = '\0'; + + return text; +} + +static char * +load_text_file(void *ctx, const char *filename) +{ + char *text; + FILE *fp; + + if (filename == NULL || strcmp (filename, "-") == 0) + return load_text_fp (ctx, stdin); + + fp = fopen (filename, "r"); + if (fp == NULL) { + fprintf (stderr, "Failed to open file %s: %s\n", + filename, strerror (errno)); + return NULL; + } + + text = load_text_fp (ctx, fp); + + fclose(fp); + + return text; +} + +/* Initialize only those things that glcpp cares about. + */ +static void +init_fake_gl_context (struct gl_context *gl_ctx) +{ + gl_ctx->API = API_OPENGL_COMPAT; + gl_ctx->Const.DisableGLSLLineContinuations = false; +} + +static void +usage (void) +{ + fprintf (stderr, + "Usage: glcpp [OPTIONS] [--] [<filename>]\n" + "\n" + "Pre-process the given filename (stdin if no filename given).\n" + "The following options are supported:\n" + " --disable-line-continuations Do not interpret lines ending with a\n" + " backslash ('\\') as a line continuation.\n"); +} + +enum { + DISABLE_LINE_CONTINUATIONS_OPT = CHAR_MAX + 1 +}; + +static const struct option +long_options[] = { + {"disable-line-continuations", no_argument, 0, DISABLE_LINE_CONTINUATIONS_OPT }, + {"debug", no_argument, 0, 'd'}, + {0, 0, 0, 0 } +}; + +int +main (int argc, char *argv[]) +{ + char *filename = NULL; + void *ctx = ralloc(NULL, void*); + char *info_log = ralloc_strdup(ctx, ""); + const char *shader; + int ret; + struct gl_context gl_ctx; + int c; + + init_fake_gl_context (&gl_ctx); + + while ((c = getopt_long(argc, argv, "d", long_options, NULL)) != -1) { + switch (c) { + case DISABLE_LINE_CONTINUATIONS_OPT: + gl_ctx.Const.DisableGLSLLineContinuations = true; + break; + case 'd': + glcpp_parser_debug = 1; + break; + default: + usage (); + exit (1); + } + } + + if (optind + 1 < argc) { + printf ("Unexpected argument: %s\n", argv[optind+1]); + usage (); + exit (1); + } + if (optind < argc) { + filename = argv[optind]; + } + + shader = load_text_file (ctx, filename); + if (shader == NULL) + return 1; + + _mesa_locale_init(); + + ret = glcpp_preprocess(ctx, &shader, &info_log, NULL, &gl_ctx); + + printf("%s", shader); + fprintf(stderr, "%s", info_log); + + ralloc_free(ctx); + + return ret; +} diff --git a/src/compiler/glsl/glcpp/glcpp.h b/src/compiler/glsl/glcpp/glcpp.h new file mode 100644 index 0000000000..70aa14b6ec --- /dev/null +++ b/src/compiler/glsl/glcpp/glcpp.h @@ -0,0 +1,251 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#ifndef GLCPP_H +#define GLCPP_H + +#include <stdint.h> +#include <stdbool.h> + +#include "main/mtypes.h" + +#include "util/ralloc.h" + +#include "program/hash_table.h" + +#define yyscan_t void* + +/* Some data types used for parser values. */ + +typedef struct expression_value { + intmax_t value; + char *undefined_macro; +} expression_value_t; + + +typedef struct string_node { + const char *str; + struct string_node *next; +} string_node_t; + +typedef struct string_list { + string_node_t *head; + string_node_t *tail; +} string_list_t; + +typedef struct token token_t; +typedef struct token_list token_list_t; + +typedef union YYSTYPE +{ + intmax_t ival; + expression_value_t expression_value; + char *str; + string_list_t *string_list; + token_t *token; + token_list_t *token_list; +} YYSTYPE; + +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 + +typedef struct YYLTYPE { + int first_line; + int first_column; + int last_line; + int last_column; + unsigned source; +} YYLTYPE; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 + +# define YYLLOC_DEFAULT(Current, Rhs, N) \ +do { \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC(Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC(Rhs, 0).last_column; \ + } \ + (Current).source = 0; \ +} while (0) + +struct token { + int type; + YYSTYPE value; + YYLTYPE location; +}; + +typedef struct token_node { + token_t *token; + struct token_node *next; +} token_node_t; + +struct token_list { + token_node_t *head; + token_node_t *tail; + token_node_t *non_space_tail; +}; + +typedef struct argument_node { + token_list_t *argument; + struct argument_node *next; +} argument_node_t; + +typedef struct argument_list { + argument_node_t *head; + argument_node_t *tail; +} argument_list_t; + +typedef struct glcpp_parser glcpp_parser_t; + +typedef enum { + TOKEN_CLASS_IDENTIFIER, + TOKEN_CLASS_IDENTIFIER_FINALIZED, + TOKEN_CLASS_FUNC_MACRO, + TOKEN_CLASS_OBJ_MACRO +} token_class_t; + +token_class_t +glcpp_parser_classify_token (glcpp_parser_t *parser, + const char *identifier, + int *parameter_index); + +typedef struct { + int is_function; + string_list_t *parameters; + const char *identifier; + token_list_t *replacements; +} macro_t; + +typedef struct expansion_node { + macro_t *macro; + token_node_t *replacements; + struct expansion_node *next; +} expansion_node_t; + +typedef enum skip_type { + SKIP_NO_SKIP, + SKIP_TO_ELSE, + SKIP_TO_ENDIF +} skip_type_t; + +typedef struct skip_node { + skip_type_t type; + bool has_else; + YYLTYPE loc; /* location of the initial #if/#elif/... */ + struct skip_node *next; +} skip_node_t; + +typedef struct active_list { + const char *identifier; + token_node_t *marker; + struct active_list *next; +} active_list_t; + +struct glcpp_parser { + yyscan_t scanner; + struct hash_table *defines; + active_list_t *active; + int lexing_directive; + int space_tokens; + int last_token_was_newline; + int last_token_was_space; + int first_non_space_token_this_line; + int newline_as_space; + int in_control_line; + int paren_count; + int commented_newlines; + skip_node_t *skip_stack; + int skipping; + token_list_t *lex_from_list; + token_node_t *lex_from_node; + char *output; + char *info_log; + size_t output_length; + size_t info_log_length; + int error; + const struct gl_extensions *extensions; + gl_api api; + bool version_resolved; + bool has_new_line_number; + int new_line_number; + bool has_new_source_number; + int new_source_number; + bool is_gles; +}; + +struct gl_extensions; + +glcpp_parser_t * +glcpp_parser_create (const struct gl_extensions *extensions, gl_api api); + +int +glcpp_parser_parse (glcpp_parser_t *parser); + +void +glcpp_parser_destroy (glcpp_parser_t *parser); + +void +glcpp_parser_resolve_implicit_version(glcpp_parser_t *parser); + +int +glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions, struct gl_context *g_ctx); + +/* Functions for writing to the info log */ + +void +glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...); + +void +glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...); + +/* Generated by glcpp-lex.l to glcpp-lex.c */ + +int +glcpp_lex_init_extra (glcpp_parser_t *parser, yyscan_t* scanner); + +void +glcpp_lex_set_source_string(glcpp_parser_t *parser, const char *shader); + +int +glcpp_lex (YYSTYPE *lvalp, YYLTYPE *llocp, yyscan_t scanner); + +int +glcpp_lex_destroy (yyscan_t scanner); + +/* Generated by glcpp-parse.y to glcpp-parse.c */ + +int +yyparse (glcpp_parser_t *parser); + +#endif diff --git a/src/compiler/glsl/glcpp/pp.c b/src/compiler/glsl/glcpp/pp.c new file mode 100644 index 0000000000..160c6662ff --- /dev/null +++ b/src/compiler/glsl/glcpp/pp.c @@ -0,0 +1,241 @@ +/* + * Copyright © 2010 Intel Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include "glcpp.h" + +void +glcpp_error (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) +{ + va_list ap; + + parser->error = 1; + ralloc_asprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, + "%u:%u(%u): " + "preprocessor error: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + ralloc_vasprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, + fmt, ap); + va_end(ap); + ralloc_asprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, "\n"); +} + +void +glcpp_warning (YYLTYPE *locp, glcpp_parser_t *parser, const char *fmt, ...) +{ + va_list ap; + + ralloc_asprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, + "%u:%u(%u): " + "preprocessor warning: ", + locp->source, + locp->first_line, + locp->first_column); + va_start(ap, fmt); + ralloc_vasprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, + fmt, ap); + va_end(ap); + ralloc_asprintf_rewrite_tail(&parser->info_log, + &parser->info_log_length, "\n"); +} + +/* Given str, (that's expected to start with a newline terminator of some + * sort), return a pointer to the first character in str after the newline. + * + * A newline terminator can be any of the following sequences: + * + * "\r\n" + * "\n\r" + * "\n" + * "\r" + * + * And the longest such sequence will be skipped. + */ +static const char * +skip_newline (const char *str) +{ + const char *ret = str; + + if (ret == NULL) + return ret; + + if (*ret == '\0') + return ret; + + if (*ret == '\r') { + ret++; + if (*ret && *ret == '\n') + ret++; + } else if (*ret == '\n') { + ret++; + if (*ret && *ret == '\r') + ret++; + } + + return ret; +} + +/* Remove any line continuation characters in the shader, (whether in + * preprocessing directives or in GLSL code). + */ +static char * +remove_line_continuations(glcpp_parser_t *ctx, const char *shader) +{ + char *clean = ralloc_strdup(ctx, ""); + const char *backslash, *newline, *search_start; + const char *cr, *lf; + char newline_separator[3]; + int collapsed_newlines = 0; + + search_start = shader; + + /* Determine what flavor of newlines this shader is using. GLSL + * provides for 4 different possible ways to separate lines, (using + * one or two characters): + * + * "\n" (line-feed, like Linux, Unix, and new Mac OS) + * "\r" (carriage-return, like old Mac files) + * "\r\n" (carriage-return + line-feed, like DOS files) + * "\n\r" (line-feed + carriage-return, like nothing, really) + * + * This code explicitly supports a shader that uses a mixture of + * newline terminators and will properly handle line continuation + * backslashes followed by any of the above. + * + * But, since we must also insert additional newlines in the output + * (for any collapsed lines) we attempt to maintain consistency by + * examining the first encountered newline terminator, and using the + * same terminator for any newlines we insert. + */ + cr = strchr(search_start, '\r'); + lf = strchr(search_start, '\n'); + + newline_separator[0] = '\n'; + newline_separator[1] = '\0'; + newline_separator[2] = '\0'; + + if (cr == NULL) { + /* Nothing to do. */ + } else if (lf == NULL) { + newline_separator[0] = '\r'; + } else if (lf == cr + 1) { + newline_separator[0] = '\r'; + newline_separator[1] = '\n'; + } else if (cr == lf + 1) { + newline_separator[0] = '\n'; + newline_separator[1] = '\r'; + } + + while (true) { + backslash = strchr(search_start, '\\'); + + /* If we have previously collapsed any line-continuations, + * then we want to insert additional newlines at the next + * occurrence of a newline character to avoid changing any + * line numbers. + */ + if (collapsed_newlines) { + cr = strchr (search_start, '\r'); + lf = strchr (search_start, '\n'); + if (cr && lf) + newline = cr < lf ? cr : lf; + else if (cr) + newline = cr; + else + newline = lf; + if (newline && + (backslash == NULL || newline < backslash)) + { + ralloc_strncat(&clean, shader, + newline - shader + 1); + while (collapsed_newlines) { + ralloc_strcat(&clean, newline_separator); + collapsed_newlines--; + } + shader = skip_newline (newline); + search_start = shader; + } + } + + search_start = backslash + 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] == '\r' || backslash[1] == '\n') + { + collapsed_newlines++; + ralloc_strncat(&clean, shader, backslash - shader); + shader = skip_newline (backslash + 1); + search_start = shader; + } + } + + ralloc_strcat(&clean, shader); + + return clean; +} + +int +glcpp_preprocess(void *ralloc_ctx, const char **shader, char **info_log, + const struct gl_extensions *extensions, struct gl_context *gl_ctx) +{ + int errors; + glcpp_parser_t *parser = glcpp_parser_create (extensions, gl_ctx->API); + + if (! gl_ctx->Const.DisableGLSLLineContinuations) + *shader = remove_line_continuations(parser, *shader); + + glcpp_lex_set_source_string (parser, *shader); + + glcpp_parser_parse (parser); + + if (parser->skip_stack) + glcpp_error (&parser->skip_stack->loc, parser, "Unterminated #if\n"); + + glcpp_parser_resolve_implicit_version(parser); + + ralloc_strcat(info_log, parser->info_log); + + ralloc_steal(ralloc_ctx, parser->output); + *shader = parser->output; + + errors = parser->error; + glcpp_parser_destroy (parser); + return errors; +} diff --git a/src/compiler/glsl/glcpp/tests/.gitignore b/src/compiler/glsl/glcpp/tests/.gitignore new file mode 100644 index 0000000000..3802c850a3 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/.gitignore @@ -0,0 +1,4 @@ +subtest-cr/ +subtest-lf/ +subtest-cr-lf/ +subtest-lf-cr/ diff --git a/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c new file mode 100644 index 0000000000..1f2320e6fc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c @@ -0,0 +1 @@ + this is four tokens with spaces diff --git a/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected new file mode 100644 index 0000000000..00791910ed --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/000-content-with-spaces.c.expected @@ -0,0 +1 @@ + this is four tokens with spaces diff --git a/src/compiler/glsl/glcpp/tests/001-define.c b/src/compiler/glsl/glcpp/tests/001-define.c new file mode 100644 index 0000000000..cbf2fee0e7 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/001-define.c @@ -0,0 +1,2 @@ +#define foo 1 +foo diff --git a/src/compiler/glsl/glcpp/tests/001-define.c.expected b/src/compiler/glsl/glcpp/tests/001-define.c.expected new file mode 100644 index 0000000000..a464d9da74 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/001-define.c.expected @@ -0,0 +1,2 @@ + +1 diff --git a/src/compiler/glsl/glcpp/tests/002-define-chain.c b/src/compiler/glsl/glcpp/tests/002-define-chain.c new file mode 100644 index 0000000000..87d75c6875 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/002-define-chain.c @@ -0,0 +1,3 @@ +#define foo 1 +#define bar foo +bar diff --git a/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected b/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected new file mode 100644 index 0000000000..c6c9ee38a9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/002-define-chain.c.expected @@ -0,0 +1,3 @@ + + +1 diff --git a/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c new file mode 100644 index 0000000000..a18b724eca --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c @@ -0,0 +1,3 @@ +#define bar foo +#define foo 1 +bar diff --git a/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected new file mode 100644 index 0000000000..c6c9ee38a9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/003-define-chain-reverse.c.expected @@ -0,0 +1,3 @@ + + +1 diff --git a/src/compiler/glsl/glcpp/tests/004-define-recursive.c b/src/compiler/glsl/glcpp/tests/004-define-recursive.c new file mode 100644 index 0000000000..2ac56ea3dc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/004-define-recursive.c @@ -0,0 +1,6 @@ +#define foo bar +#define bar baz +#define baz foo +foo +bar +baz diff --git a/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected b/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected new file mode 100644 index 0000000000..2d07687f8c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/004-define-recursive.c.expected @@ -0,0 +1,6 @@ + + + +foo +bar +baz diff --git a/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c new file mode 100644 index 0000000000..f5521df968 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c @@ -0,0 +1,3 @@ +#define foo 1 +#define bar a foo +bar diff --git a/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected new file mode 100644 index 0000000000..892975c268 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/005-define-composite-chain.c.expected @@ -0,0 +1,3 @@ + + +a 1 diff --git a/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c new file mode 100644 index 0000000000..4bb91a1221 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c @@ -0,0 +1,3 @@ +#define bar a foo +#define foo 1 +bar diff --git a/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected new file mode 100644 index 0000000000..892975c268 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/006-define-composite-chain-reverse.c.expected @@ -0,0 +1,3 @@ + + +a 1 diff --git a/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c new file mode 100644 index 0000000000..5784565bdf --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c @@ -0,0 +1,6 @@ +#define foo a bar +#define bar b baz +#define baz c foo +foo +bar +baz diff --git a/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected new file mode 100644 index 0000000000..0b0b477d9d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/007-define-composite-recursive.c.expected @@ -0,0 +1,6 @@ + + + +a b c foo +b c a bar +c a b baz diff --git a/src/compiler/glsl/glcpp/tests/008-define-empty.c b/src/compiler/glsl/glcpp/tests/008-define-empty.c new file mode 100644 index 0000000000..b1bd17ec21 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/008-define-empty.c @@ -0,0 +1,2 @@ +#define foo +foo diff --git a/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected b/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected new file mode 100644 index 0000000000..d148bc8e80 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/008-define-empty.c.expected @@ -0,0 +1,2 @@ + + diff --git a/src/compiler/glsl/glcpp/tests/009-undef.c b/src/compiler/glsl/glcpp/tests/009-undef.c new file mode 100644 index 0000000000..3fc1fb4424 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/009-undef.c @@ -0,0 +1,4 @@ +#define foo 1 +foo +#undef foo +foo diff --git a/src/compiler/glsl/glcpp/tests/009-undef.c.expected b/src/compiler/glsl/glcpp/tests/009-undef.c.expected new file mode 100644 index 0000000000..9c0b35a451 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/009-undef.c.expected @@ -0,0 +1,4 @@ + +1 + +foo diff --git a/src/compiler/glsl/glcpp/tests/010-undef-re-define.c b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c new file mode 100644 index 0000000000..32ff73798b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c @@ -0,0 +1,6 @@ +#define foo 1 +foo +#undef foo +foo +#define foo 2 +foo diff --git a/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected new file mode 100644 index 0000000000..5970f49028 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/010-undef-re-define.c.expected @@ -0,0 +1,6 @@ + +1 + +foo + +2 diff --git a/src/compiler/glsl/glcpp/tests/011-define-func-empty.c b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c new file mode 100644 index 0000000000..d9ce13c228 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c @@ -0,0 +1,2 @@ +#define foo() +foo() diff --git a/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected new file mode 100644 index 0000000000..d148bc8e80 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/011-define-func-empty.c.expected @@ -0,0 +1,2 @@ + + diff --git a/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c new file mode 100644 index 0000000000..c2bb730b11 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c @@ -0,0 +1,2 @@ +#define foo() bar +foo() diff --git a/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected new file mode 100644 index 0000000000..9f075f2600 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/012-define-func-no-args.c.expected @@ -0,0 +1,2 @@ + +bar diff --git a/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c new file mode 100644 index 0000000000..f78fb8b118 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c @@ -0,0 +1,2 @@ +#define foo(x) 1 +foo(bar) diff --git a/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected new file mode 100644 index 0000000000..a464d9da74 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/013-define-func-1-arg-unused.c.expected @@ -0,0 +1,2 @@ + +1 diff --git a/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c new file mode 100644 index 0000000000..11feb2624b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c @@ -0,0 +1,2 @@ +#define foo(x,y) 1 +foo(bar,baz) diff --git a/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected new file mode 100644 index 0000000000..a464d9da74 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/014-define-func-2-arg-unused.c.expected @@ -0,0 +1,2 @@ + +1 diff --git a/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c new file mode 100644 index 0000000000..558da9c617 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c @@ -0,0 +1,4 @@ +#define foo ()1 +foo() +#define bar ()2 +bar() diff --git a/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected new file mode 100644 index 0000000000..a70321a4c5 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/015-define-object-with-parens.c.expected @@ -0,0 +1,4 @@ + +()1() + +()2() diff --git a/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c new file mode 100644 index 0000000000..a2e2404c7c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c @@ -0,0 +1,2 @@ +#define foo(x) ((x)+1) +foo(bar) diff --git a/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected new file mode 100644 index 0000000000..6bfe04f738 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/016-define-func-1-arg.c.expected @@ -0,0 +1,2 @@ + +((bar)+1) diff --git a/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c new file mode 100644 index 0000000000..c725383527 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c @@ -0,0 +1,2 @@ +#define foo(x,y) ((x)*(y)) +foo(bar,baz) diff --git a/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected new file mode 100644 index 0000000000..f7a2b8c26c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/017-define-func-2-args.c.expected @@ -0,0 +1,2 @@ + +((bar)*(baz)) diff --git a/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c new file mode 100644 index 0000000000..668130b8f9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c @@ -0,0 +1,3 @@ +#define x 0 +#define foo(x) x +foo(1) diff --git a/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected new file mode 100644 index 0000000000..c6c9ee38a9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/018-define-func-macro-as-parameter.c.expected @@ -0,0 +1,3 @@ + + +1 diff --git a/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c new file mode 100644 index 0000000000..c4e62b2550 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c @@ -0,0 +1,2 @@ +#define foo(x) (x) +foo(this is more than one word) diff --git a/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected new file mode 100644 index 0000000000..1e89b8cfd0 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/019-define-func-1-arg-multi.c.expected @@ -0,0 +1,2 @@ + +(this is more than one word) diff --git a/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c new file mode 100644 index 0000000000..3049ad1546 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c @@ -0,0 +1,2 @@ +#define foo(x,y) x,two fish,red fish,y +foo(one fish, blue fish) diff --git a/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected new file mode 100644 index 0000000000..19f59f5ecb --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/020-define-func-2-arg-multi.c.expected @@ -0,0 +1,2 @@ + +one fish,two fish,red fish,blue fish diff --git a/src/compiler/glsl/glcpp/tests/021-define-func-compose.c b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c new file mode 100644 index 0000000000..21ddd0e65f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c @@ -0,0 +1,3 @@ +#define bar(x) (1+(x)) +#define foo(y) (2*(y)) +foo(bar(3)) diff --git a/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected new file mode 100644 index 0000000000..87f51f0bac --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/021-define-func-compose.c.expected @@ -0,0 +1,3 @@ + + +(2*((1+(3)))) diff --git a/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c new file mode 100644 index 0000000000..c20d73a4a2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c @@ -0,0 +1,2 @@ +#define foo(x) (x) +foo(argument(including parens)for the win) diff --git a/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected new file mode 100644 index 0000000000..1dfc6698bb --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/022-define-func-arg-with-parens.c.expected @@ -0,0 +1,2 @@ + +(argument(including parens)for the win) diff --git a/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c new file mode 100644 index 0000000000..7ebfed6516 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c @@ -0,0 +1,8 @@ +#define noargs() 1 +# define onearg(foo) foo + # define twoargs( x , y ) x y + # define threeargs( a , b , c ) a b c +noargs ( ) +onearg ( 2 ) +twoargs ( 3 , 4 ) +threeargs ( 5 , 6 , 7 ) diff --git a/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected new file mode 100644 index 0000000000..9c58275d0f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/023-define-extra-whitespace.c.expected @@ -0,0 +1,8 @@ + + + + +1 +2 +3 4 +5 6 7 diff --git a/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c new file mode 100644 index 0000000000..e788adce30 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c @@ -0,0 +1,3 @@ +#define foo foo +#define bar foo +bar diff --git a/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected new file mode 100644 index 0000000000..15600af546 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/024-define-chain-to-self-recursion.c.expected @@ -0,0 +1,3 @@ + + +foo diff --git a/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c new file mode 100644 index 0000000000..b433671d1b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo bar diff --git a/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected new file mode 100644 index 0000000000..4a59f0520e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/025-func-macro-as-non-macro.c.expected @@ -0,0 +1,2 @@ + +foo bar diff --git a/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c new file mode 100644 index 0000000000..0d83740530 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c @@ -0,0 +1,6 @@ +#define foo(a) bar + +foo +( +1 +) diff --git a/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected new file mode 100644 index 0000000000..5e3c70f2cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/026-define-func-extra-newlines.c.expected @@ -0,0 +1,3 @@ + + +bar diff --git a/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c new file mode 100644 index 0000000000..5ccb52caba --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c @@ -0,0 +1,3 @@ +#define failure() success +#define foo failure() +foo diff --git a/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected new file mode 100644 index 0000000000..94c15f9505 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/027-define-chain-obj-to-func.c.expected @@ -0,0 +1,3 @@ + + +success diff --git a/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c new file mode 100644 index 0000000000..44962a7187 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c @@ -0,0 +1,3 @@ +#define success() failure +#define foo success +foo diff --git a/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected new file mode 100644 index 0000000000..94c15f9505 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/028-define-chain-obj-to-non-func.c.expected @@ -0,0 +1,3 @@ + + +success diff --git a/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c new file mode 100644 index 0000000000..261f7d28fc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c @@ -0,0 +1,3 @@ +#define bar(failure) failure +#define foo bar(success) +foo diff --git a/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected new file mode 100644 index 0000000000..94c15f9505 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/029-define-chain-obj-to-func-with-args.c.expected @@ -0,0 +1,3 @@ + + +success diff --git a/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c new file mode 100644 index 0000000000..e56fbefd62 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c @@ -0,0 +1,4 @@ +#define baz(failure) failure +#define bar(failure) failure +#define foo bar(baz(success)) +foo diff --git a/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected new file mode 100644 index 0000000000..bed826e783 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/030-define-chain-obj-to-func-compose.c.expected @@ -0,0 +1,4 @@ + + + +success diff --git a/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c new file mode 100644 index 0000000000..3f4c8744df --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c @@ -0,0 +1,4 @@ +#define baz(failure) failure +#define bar(failure) failure +#define foo() bar(baz(success)) +foo() diff --git a/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected new file mode 100644 index 0000000000..bed826e783 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/031-define-chain-func-to-func-compose.c.expected @@ -0,0 +1,4 @@ + + + +success diff --git a/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c new file mode 100644 index 0000000000..b3ac70f499 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c @@ -0,0 +1,2 @@ +#define foo(a) foo(2*(a)) +foo(3) diff --git a/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected new file mode 100644 index 0000000000..983f941740 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/032-define-func-self-recurse.c.expected @@ -0,0 +1,2 @@ + +foo(2*(3)) diff --git a/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c new file mode 100644 index 0000000000..f65e48286c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c @@ -0,0 +1,2 @@ +#define foo(a) foo(2*(a)) +foo(foo(3)) diff --git a/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected new file mode 100644 index 0000000000..0818362364 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/033-define-func-self-compose.c.expected @@ -0,0 +1,2 @@ + +foo(2*(foo(2*(3)))) diff --git a/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c new file mode 100644 index 0000000000..209a5f7e07 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo(foo) diff --git a/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected new file mode 100644 index 0000000000..3f808fe665 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/034-define-func-self-compose-non-func.c.expected @@ -0,0 +1,2 @@ + +foo diff --git a/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c new file mode 100644 index 0000000000..c307fbe830 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c @@ -0,0 +1,2 @@ +#define foo(bar) bar +foo(1+foo) diff --git a/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected new file mode 100644 index 0000000000..09dfdd64e9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/035-define-func-self-compose-non-func-multi-token-argument.c.expected @@ -0,0 +1,2 @@ + +1+foo diff --git a/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c new file mode 100644 index 0000000000..b21ff33673 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c @@ -0,0 +1,3 @@ +#define bar success +#define foo(x) x +foo(more bar) diff --git a/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected new file mode 100644 index 0000000000..580ed9599c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/036-define-func-non-macro-multi-token-argument.c.expected @@ -0,0 +1,3 @@ + + +more success diff --git a/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c new file mode 100644 index 0000000000..b3a2f37f1b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c @@ -0,0 +1,3 @@ +#define expand(x) expand(x once) +#define foo(x) x +foo(expand(just)) diff --git a/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected new file mode 100644 index 0000000000..e804d7e4f9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/037-finalize-unexpanded-macro.c.expected @@ -0,0 +1,3 @@ + + +expand(just once) diff --git a/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c new file mode 100644 index 0000000000..1407c7d6e3 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c @@ -0,0 +1,2 @@ +#define foo(x) success +foo(argument (with,embedded , commas) -- tricky) diff --git a/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected new file mode 100644 index 0000000000..6544adb3a2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/038-func-arg-with-commas.c.expected @@ -0,0 +1,2 @@ + +success diff --git a/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c new file mode 100644 index 0000000000..a7c053bb40 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c @@ -0,0 +1,24 @@ +/* This works. */ +#define foo(a) (a) +#define bar two,words +foo(bar) + +/* So does this. */ +#define foo2(a,b) (a separate b) +#define foo2_wrap(a) foo2(a) +foo2_wrap(bar) + +/* But this generates an error. */ +#define foo_wrap(a) foo(a) +foo_wrap(bar) + +/* Adding parentheses to foo_wrap fixes it. */ +#define foo_wrap_parens(a) foo((a)) +foo_wrap_parens(bar) + +/* As does adding parentheses to bar */ +#define bar_parens (two,words) +foo_wrap(bar_parens) +foo_wrap_parens(bar_parens) + + diff --git a/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected new file mode 100644 index 0000000000..4cc795338b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/039-func-arg-obj-macro-with-comma.c.expected @@ -0,0 +1,26 @@ +0:12(21): preprocessor error: Error: macro foo invoked with 2 arguments (expected 1) + + + + +(two,words) + + + + +(two separate words) + + + +foo(two,words) + + + +((two,words)) + + + +((two,words)) +(((two,words))) + + diff --git a/src/compiler/glsl/glcpp/tests/040-token-pasting.c b/src/compiler/glsl/glcpp/tests/040-token-pasting.c new file mode 100644 index 0000000000..caab3ba736 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/040-token-pasting.c @@ -0,0 +1,2 @@ +#define paste(a,b) a ## b +paste(one , token) diff --git a/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected b/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected new file mode 100644 index 0000000000..48e836ec3f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/040-token-pasting.c.expected @@ -0,0 +1,2 @@ + +onetoken diff --git a/src/compiler/glsl/glcpp/tests/041-if-0.c b/src/compiler/glsl/glcpp/tests/041-if-0.c new file mode 100644 index 0000000000..2cab677d3e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/041-if-0.c @@ -0,0 +1,5 @@ +success_1 +#if 0 +failure +#endif +success_2 diff --git a/src/compiler/glsl/glcpp/tests/041-if-0.c.expected b/src/compiler/glsl/glcpp/tests/041-if-0.c.expected new file mode 100644 index 0000000000..8b506b32d5 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/041-if-0.c.expected @@ -0,0 +1,5 @@ +success_1 + + + +success_2 diff --git a/src/compiler/glsl/glcpp/tests/042-if-1.c b/src/compiler/glsl/glcpp/tests/042-if-1.c new file mode 100644 index 0000000000..874a25cf41 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/042-if-1.c @@ -0,0 +1,5 @@ +success_1 +#if 1 +success_2 +#endif +success_3 diff --git a/src/compiler/glsl/glcpp/tests/042-if-1.c.expected b/src/compiler/glsl/glcpp/tests/042-if-1.c.expected new file mode 100644 index 0000000000..a6ae9465a9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/042-if-1.c.expected @@ -0,0 +1,5 @@ +success_1 + +success_2 + +success_3 diff --git a/src/compiler/glsl/glcpp/tests/043-if-0-else.c b/src/compiler/glsl/glcpp/tests/043-if-0-else.c new file mode 100644 index 0000000000..323351f9db --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/043-if-0-else.c @@ -0,0 +1,7 @@ +success_1 +#if 0 +failure +#else +success_2 +#endif +success_3 diff --git a/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected b/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected new file mode 100644 index 0000000000..3d7e6be96c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/043-if-0-else.c.expected @@ -0,0 +1,7 @@ +success_1 + + + +success_2 + +success_3 diff --git a/src/compiler/glsl/glcpp/tests/044-if-1-else.c b/src/compiler/glsl/glcpp/tests/044-if-1-else.c new file mode 100644 index 0000000000..28dfc25c6f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/044-if-1-else.c @@ -0,0 +1,7 @@ +success_1 +#if 1 +success_2 +#else +failure +#endif +success_3 diff --git a/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected b/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected new file mode 100644 index 0000000000..4a31e1cfa9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/044-if-1-else.c.expected @@ -0,0 +1,7 @@ +success_1 + +success_2 + + + +success_3 diff --git a/src/compiler/glsl/glcpp/tests/045-if-0-elif.c b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c new file mode 100644 index 0000000000..e50f686d46 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#elif 0 +failure_2 +#elif 1 +success_3 +#elif 1 +failure_3 +#endif +success_4 diff --git a/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected new file mode 100644 index 0000000000..a9bb1588e4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/045-if-0-elif.c.expected @@ -0,0 +1,11 @@ +success_1 + + + + + +success_3 + + + +success_4 diff --git a/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c new file mode 100644 index 0000000000..130515a01e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c @@ -0,0 +1,11 @@ +success_1 +#if 1 +success_2 +#elif 0 +failure_1 +#elif 1 +failure_2 +#elif 0 +failure_3 +#endif +success_3 diff --git a/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected new file mode 100644 index 0000000000..a4995713ca --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/046-if-1-elsif.c.expected @@ -0,0 +1,11 @@ +success_1 + +success_2 + + + + + + + +success_3 diff --git a/src/compiler/glsl/glcpp/tests/047-if-elif-else.c b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c new file mode 100644 index 0000000000..e8f0838a9e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#elif 0 +failure_2 +#elif 0 +failure_3 +#else +success_2 +#endif +success_3 diff --git a/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected new file mode 100644 index 0000000000..54d3086119 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/047-if-elif-else.c.expected @@ -0,0 +1,11 @@ +success_1 + + + + + + + +success_2 + +success_3 diff --git a/src/compiler/glsl/glcpp/tests/048-if-nested.c b/src/compiler/glsl/glcpp/tests/048-if-nested.c new file mode 100644 index 0000000000..fc4679c3be --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/048-if-nested.c @@ -0,0 +1,11 @@ +success_1 +#if 0 +failure_1 +#if 1 +failure_2 +#else +failure_3 +#endif +failure_4 +#endif +success_2 diff --git a/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected b/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected new file mode 100644 index 0000000000..8beb9c32c3 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/048-if-nested.c.expected @@ -0,0 +1,11 @@ +success_1 + + + + + + + + + +success_2 diff --git a/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c new file mode 100644 index 0000000000..833ea03882 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c @@ -0,0 +1,5 @@ +#if 1 + 2 * 3 + - (25 % 17 - + 1) +failure with operator precedence +#else +success +#endif diff --git a/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected new file mode 100644 index 0000000000..729bdd15f8 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/049-if-expression-precedence.c.expected @@ -0,0 +1,5 @@ + + + +success + diff --git a/src/compiler/glsl/glcpp/tests/050-if-defined.c b/src/compiler/glsl/glcpp/tests/050-if-defined.c new file mode 100644 index 0000000000..34f0f95140 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/050-if-defined.c @@ -0,0 +1,17 @@ +#if defined foo +failure_1 +#else +success_1 +#endif +#define foo +#if defined foo +success_2 +#else +failure_2 +#endif +#undef foo +#if defined foo +failure_3 +#else +success_3 +#endif diff --git a/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected b/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected new file mode 100644 index 0000000000..737eb8d940 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/050-if-defined.c.expected @@ -0,0 +1,17 @@ + + + +success_1 + + + +success_2 + + + + + + + +success_3 + diff --git a/src/compiler/glsl/glcpp/tests/051-if-relational.c b/src/compiler/glsl/glcpp/tests/051-if-relational.c new file mode 100644 index 0000000000..c3db488e0d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/051-if-relational.c @@ -0,0 +1,35 @@ +#if 3 < 2 +failure_1 +#else +success_1 +#endif + +#if 3 >= 2 +success_2 +#else +failure_2 +#endif + +#if 2 + 3 <= 5 +success_3 +#else +failure_3 +#endif + +#if 3 - 2 == 1 +success_3 +#else +failure_3 +#endif + +#if 1 > 3 +failure_4 +#else +success_4 +#endif + +#if 1 != 5 +success_5 +#else +failure_5 +#endif diff --git a/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected b/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected new file mode 100644 index 0000000000..652fefdd43 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/051-if-relational.c.expected @@ -0,0 +1,35 @@ + + + +success_1 + + + +success_2 + + + + + +success_3 + + + + + +success_3 + + + + + + + +success_4 + + + +success_5 + + + diff --git a/src/compiler/glsl/glcpp/tests/052-if-bitwise.c b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c new file mode 100644 index 0000000000..2d8e45eb61 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c @@ -0,0 +1,20 @@ +#if (0xaaaaaaaa | 0x55555555) != 4294967295 +failure_1 +#else +success_1 +#endif +#if (0x12345678 ^ 0xfdecba98) == 4023971040 +success_2 +#else +failure_2 +#endif +#if (~ 0xdeadbeef) != -3735928560 +failure_3 +#else +success_3 +#endif +#if (0667 & 0733) == 403 +success_4 +#else +failure_4 +#endif diff --git a/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected new file mode 100644 index 0000000000..44e52b206e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/052-if-bitwise.c.expected @@ -0,0 +1,20 @@ + + + +success_1 + + +success_2 + + + + + + +success_3 + + +success_4 + + + diff --git a/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c new file mode 100644 index 0000000000..d24c54a88d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c @@ -0,0 +1,15 @@ +#if (15 / 2) != 7 +failure_1 +#else +success_1 +#endif +#if (1 << 12) == 4096 +success_2 +#else +failure_2 +#endif +#if (31762 >> 8) != 124 +failure_3 +#else +success_3 +#endif diff --git a/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected new file mode 100644 index 0000000000..7e78e0454e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/053-if-divide-and-shift.c.expected @@ -0,0 +1,15 @@ + + + +success_1 + + +success_2 + + + + + + +success_3 + diff --git a/src/compiler/glsl/glcpp/tests/054-if-with-macros.c b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c new file mode 100644 index 0000000000..3da79a0d96 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c @@ -0,0 +1,34 @@ +#define one 1 +#define two 2 +#define three 3 +#define five 5 +#if five < two +failure_1 +#else +success_1 +#endif +#if three >= two +success_2 +#else +failure_2 +#endif +#if two + three <= five +success_3 +#else +failure_3 +#endif +#if five - two == three +success_4 +#else +failure_4 +#endif +#if one > three +failure_5 +#else +success_5 +#endif +#if one != five +success_6 +#else +failure_6 +#endif diff --git a/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected new file mode 100644 index 0000000000..70f737c90a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/054-if-with-macros.c.expected @@ -0,0 +1,34 @@ + + + + + + + +success_1 + + +success_2 + + + + +success_3 + + + + +success_4 + + + + + + +success_5 + + +success_6 + + + diff --git a/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c new file mode 100644 index 0000000000..00f2c2346d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c @@ -0,0 +1,3 @@ +#define failure() success +#define foo failure +foo() diff --git a/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected new file mode 100644 index 0000000000..94c15f9505 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/055-define-chain-obj-to-func-parens-in-text.c.expected @@ -0,0 +1,3 @@ + + +success diff --git a/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c new file mode 100644 index 0000000000..58701d1f25 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c @@ -0,0 +1,4 @@ +#define bar with,embedded,commas +#define function(x) success +#define foo function +foo(bar) diff --git a/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected new file mode 100644 index 0000000000..bed826e783 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/056-macro-argument-with-comma.c.expected @@ -0,0 +1,4 @@ + + + +success diff --git a/src/compiler/glsl/glcpp/tests/057-empty-arguments.c b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c new file mode 100644 index 0000000000..6140232865 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c @@ -0,0 +1,6 @@ +#define zero() success +zero() +#define one(x) success +one() +#define two(x,y) success +two(,) diff --git a/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected new file mode 100644 index 0000000000..7d97e15e29 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/057-empty-arguments.c.expected @@ -0,0 +1,6 @@ + +success + +success + +success diff --git a/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c new file mode 100644 index 0000000000..8ac260c76b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c @@ -0,0 +1,5 @@ +#define paste(x,y) x ## y +paste(a,b) +paste(a,) +paste(,b) +paste(,) diff --git a/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected new file mode 100644 index 0000000000..e0967a1b95 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/058-token-pasting-empty-arguments.c.expected @@ -0,0 +1,5 @@ + +ab +a +b + diff --git a/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c new file mode 100644 index 0000000000..37b895a423 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c @@ -0,0 +1,4 @@ +#define paste(x,y) x ## y +paste(1,2) +paste(1,000) +paste(identifier,2) diff --git a/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected new file mode 100644 index 0000000000..f1288aa7cb --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/059-token-pasting-integer.c.expected @@ -0,0 +1,4 @@ + +12 +1000 +identifier2 diff --git a/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c new file mode 100644 index 0000000000..ed80ea879c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c @@ -0,0 +1,3 @@ +#define double(a) a*2 +#define foo double( +foo 5) diff --git a/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected new file mode 100644 index 0000000000..3e5501aa6e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/060-left-paren-in-macro-right-paren-in-text.c.expected @@ -0,0 +1,3 @@ + + +5*2 diff --git a/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c new file mode 100644 index 0000000000..6dbfd1f62d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c @@ -0,0 +1,5 @@ +#define foo(x) success +#define bar foo +#define baz bar +#define joe baz +joe (failure) diff --git a/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected new file mode 100644 index 0000000000..15eb64b97f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/061-define-chain-obj-to-func-multi.c.expected @@ -0,0 +1,5 @@ + + + + +success diff --git a/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c new file mode 100644 index 0000000000..d9e439bb89 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c @@ -0,0 +1,5 @@ +#define foo(a,b) +#if 0 +foo(bar) +foo( +#endif diff --git a/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected new file mode 100644 index 0000000000..3f2ff2d6cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/062-if-0-skips-garbage.c.expected @@ -0,0 +1,5 @@ + + + + + diff --git a/src/compiler/glsl/glcpp/tests/063-comments.c b/src/compiler/glsl/glcpp/tests/063-comments.c new file mode 100644 index 0000000000..e641d2f0f9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/063-comments.c @@ -0,0 +1,20 @@ +/* this is a comment */ +// so is this +// */ +f = g/**//h; +/*//*/l(); +m = n//**/o ++ p; +/* this +comment spans +multiple lines and +contains *** stars +and slashes / *** / +and other stuff. +****/ +more code here +/* Test that /* nested + comments */ +are not treated like comments. +/*/ this is a comment */ +/*/*/ diff --git a/src/compiler/glsl/glcpp/tests/063-comments.c.expected b/src/compiler/glsl/glcpp/tests/063-comments.c.expected new file mode 100644 index 0000000000..f6e10ce037 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/063-comments.c.expected @@ -0,0 +1,20 @@ + + + +f = g /h; + l(); +m = n ++ p; + + + + + + + +more code here + + +are not treated like comments. + + diff --git a/src/compiler/glsl/glcpp/tests/064-version.c b/src/compiler/glsl/glcpp/tests/064-version.c new file mode 100644 index 0000000000..21326481b8 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/064-version.c @@ -0,0 +1,2 @@ +#version 130 +#define FOO diff --git a/src/compiler/glsl/glcpp/tests/064-version.c.expected b/src/compiler/glsl/glcpp/tests/064-version.c.expected new file mode 100644 index 0000000000..4036b1ee37 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/064-version.c.expected @@ -0,0 +1,2 @@ +#version 130 + diff --git a/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c new file mode 100644 index 0000000000..48aa0f8c3e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c @@ -0,0 +1,17 @@ +#if defined(foo) +failure_1 +#else +success_1 +#endif +#define foo +#if defined ( foo ) +success_2 +#else +failure_2 +#endif +#undef foo +#if defined (foo) +failure_3 +#else +success_3 +#endif diff --git a/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected new file mode 100644 index 0000000000..737eb8d940 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/065-if-defined-parens.c.expected @@ -0,0 +1,17 @@ + + + +success_1 + + + +success_2 + + + + + + + +success_3 + diff --git a/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c new file mode 100644 index 0000000000..3b0b47349d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c @@ -0,0 +1,3 @@ +#if(1) +success +#endif diff --git a/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected new file mode 100644 index 0000000000..5a28fb3b66 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/066-if-nospace-expression.c.expected @@ -0,0 +1,3 @@ + +success + diff --git a/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c new file mode 100644 index 0000000000..f46cce4e60 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c @@ -0,0 +1,40 @@ +#define D1 +#define D2 + +#define result success + +#ifdef U1 +#ifdef U2 +#undef result +#define result failure +#endif +#endif +result + +#ifndef D1 +#ifndef D2 +#undef result +#define result failure +#endif +#endif +result + +#undef result +#define result failure +#ifdef D1 +#ifdef D2 +#undef result +#define result success +#endif +#endif +result + +#undef result +#define result failure +#ifndef U1 +#ifndef U2 +#undef result +#define result success +#endif +#endif +result diff --git a/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected new file mode 100644 index 0000000000..9a5ed2eb2d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/067-nested-ifdef-ifndef.c.expected @@ -0,0 +1,40 @@ + + + + + + + + + + + +success + + + + + + + +success + + + + + + + + + +success + + + + + + + + + +success diff --git a/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c new file mode 100644 index 0000000000..699ac5144e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c @@ -0,0 +1,11 @@ +#define empty +<empty< +<empty= +>empty> +>empty= +=empty= +!empty= +&empty& +|empty| ++empty+ +-empty- diff --git a/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected new file mode 100644 index 0000000000..27582cda5e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/068-accidental-pasting.c.expected @@ -0,0 +1,11 @@ + +< < +< = +> > +> = += = +! = +& & +| | ++ + +- - diff --git a/src/compiler/glsl/glcpp/tests/069-repeated-argument.c b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c new file mode 100644 index 0000000000..2b46ead294 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c @@ -0,0 +1,2 @@ +#define double(x) x x +double(1) diff --git a/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected new file mode 100644 index 0000000000..8b4b095e48 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/069-repeated-argument.c.expected @@ -0,0 +1,2 @@ + +1 1 diff --git a/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c new file mode 100644 index 0000000000..d15a4840b0 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c @@ -0,0 +1,5 @@ +#if UNDEFINED_MACRO +Failure +#else +Success +#endif diff --git a/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected new file mode 100644 index 0000000000..44b93a434f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/070-undefined-macro-in-expression.c.expected @@ -0,0 +1,5 @@ + + + +Success + diff --git a/src/compiler/glsl/glcpp/tests/071-punctuator.c b/src/compiler/glsl/glcpp/tests/071-punctuator.c new file mode 100644 index 0000000000..959d682598 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/071-punctuator.c @@ -0,0 +1 @@ +a = b diff --git a/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected b/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected new file mode 100644 index 0000000000..959d682598 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/071-punctuator.c.expected @@ -0,0 +1 @@ +a = b diff --git a/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c new file mode 100644 index 0000000000..e421e9d5e2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c @@ -0,0 +1,2 @@ +#define paste(x) success_ ## x +paste(1) paste(2) paste(3) diff --git a/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected new file mode 100644 index 0000000000..7b80af7e46 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/072-token-pasting-same-line.c.expected @@ -0,0 +1,2 @@ + +success_1 success_2 success_3 diff --git a/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c new file mode 100644 index 0000000000..61a48097ca --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c @@ -0,0 +1,4 @@ +#ifdef UNDEF +#if UNDEF > 1 +#endif +#endif diff --git a/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected new file mode 100644 index 0000000000..fd40910d9e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/073-if-in-ifdef.c.expected @@ -0,0 +1,4 @@ + + + + diff --git a/src/compiler/glsl/glcpp/tests/074-elif-undef.c b/src/compiler/glsl/glcpp/tests/074-elif-undef.c new file mode 100644 index 0000000000..67aac8977e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/074-elif-undef.c @@ -0,0 +1,3 @@ +#ifndef UNDEF +#elif UNDEF < 0 +#endif diff --git a/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected b/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected new file mode 100644 index 0000000000..b28b04f643 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/074-elif-undef.c.expected @@ -0,0 +1,3 @@ + + + diff --git a/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c new file mode 100644 index 0000000000..264bc4f10e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c @@ -0,0 +1,4 @@ +#ifndef UNDEF +#elif UNDEF < 0 +#elif UNDEF == 3 +#endif diff --git a/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected new file mode 100644 index 0000000000..fd40910d9e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/075-elif-elif-undef.c.expected @@ -0,0 +1,4 @@ + + + + diff --git a/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c new file mode 100644 index 0000000000..ebd550ed00 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c @@ -0,0 +1,5 @@ +#ifdef UNDEF +#if UNDEF == 4 +#elif UNDEF == 5 +#endif +#endif diff --git a/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected new file mode 100644 index 0000000000..3f2ff2d6cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/076-elif-undef-nested.c.expected @@ -0,0 +1,5 @@ + + + + + diff --git a/src/compiler/glsl/glcpp/tests/077-else-without-if.c b/src/compiler/glsl/glcpp/tests/077-else-without-if.c new file mode 100644 index 0000000000..81f00bfe27 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/077-else-without-if.c @@ -0,0 +1 @@ +#else diff --git a/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected b/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected new file mode 100644 index 0000000000..69f3404703 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/077-else-without-if.c.expected @@ -0,0 +1,3 @@ +0:1(1): preprocessor error: #else without #if + + diff --git a/src/compiler/glsl/glcpp/tests/078-elif-without-if.c b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c new file mode 100644 index 0000000000..60466b3890 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c @@ -0,0 +1 @@ +#elif defined FOO diff --git a/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected new file mode 100644 index 0000000000..b8e40ecc09 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/078-elif-without-if.c.expected @@ -0,0 +1,3 @@ +0:1(1): preprocessor error: #elif without #if + + diff --git a/src/compiler/glsl/glcpp/tests/079-endif-without-if.c b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c new file mode 100644 index 0000000000..69331c3ca9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c @@ -0,0 +1 @@ +#endif diff --git a/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected new file mode 100644 index 0000000000..7ae579dd25 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/079-endif-without-if.c.expected @@ -0,0 +1,3 @@ +0:1(1): preprocessor error: #endif without #if + + diff --git a/src/compiler/glsl/glcpp/tests/080-if-without-expression.c b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c new file mode 100644 index 0000000000..a27ba36a36 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c @@ -0,0 +1,4 @@ +/* Error message for unskipped #if with no expression. */ +#if +#endif + diff --git a/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected new file mode 100644 index 0000000000..2e4cd7323c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/080-if-without-expression.c.expected @@ -0,0 +1,5 @@ +0:2(1): preprocessor error: #if with no expression + + + + diff --git a/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c new file mode 100644 index 0000000000..79c78663dd --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c @@ -0,0 +1,3 @@ +#if 0 +#elif +#endif diff --git a/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected new file mode 100644 index 0000000000..b607b84906 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/081-elif-without-expression.c.expected @@ -0,0 +1,4 @@ +0:2(1): preprocessor error: #elif with no expression + + + diff --git a/src/compiler/glsl/glcpp/tests/082-invalid-paste.c b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c new file mode 100644 index 0000000000..8b84d50c3a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c @@ -0,0 +1,7 @@ +#define PASTE(x,y) x ## y +PASTE(<,>) +PASTE(0,abc) +PASTE(1,=) +PASTE(2,@) +PASTE(3,-4) +PASTE(4,+5.2) diff --git a/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected new file mode 100644 index 0000000000..b48a2d6d29 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/082-invalid-paste.c.expected @@ -0,0 +1,19 @@ +0:2(7): preprocessor error: +Pasting "<" and ">" does not give a valid preprocessing token. +0:3(7): preprocessor error: +Pasting "0" and "abc" does not give a valid preprocessing token. +0:4(7): preprocessor error: +Pasting "1" and "=" does not give a valid preprocessing token. +0:5(7): preprocessor error: +Pasting "2" and "@" does not give a valid preprocessing token. +0:6(7): preprocessor error: +Pasting "3" and "-" does not give a valid preprocessing token. +0:7(7): preprocessor error: +Pasting "4" and "+" does not give a valid preprocessing token. + +< +0 +1 +2 +34 +45.2 diff --git a/src/compiler/glsl/glcpp/tests/083-unterminated-if.c b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c new file mode 100644 index 0000000000..9180635092 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c @@ -0,0 +1,2 @@ +#if 1 + diff --git a/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected new file mode 100644 index 0000000000..4659ab6fe6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/083-unterminated-if.c.expected @@ -0,0 +1,4 @@ +0:1(6): preprocessor error: Unterminated #if + + + diff --git a/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c new file mode 100644 index 0000000000..0789ba5e52 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c @@ -0,0 +1,2 @@ +#define FUNC(x) (2*(x)) +FUNC(23 diff --git a/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected new file mode 100644 index 0000000000..af49a37369 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/084-unbalanced-parentheses.c.expected @@ -0,0 +1,2 @@ +0:2(8): preprocessor error: syntax error, unexpected $end + diff --git a/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c new file mode 100644 index 0000000000..91bea60061 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c @@ -0,0 +1,5 @@ +#define MULT(x,y) ((x)*(y)) +MULT() +MULT(1) +MULT(1,2,3) + diff --git a/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected new file mode 100644 index 0000000000..d23845bfd4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/085-incorrect-argument-count.c.expected @@ -0,0 +1,11 @@ +0:2(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2) + +0:3(1): preprocessor error: Error: macro MULT invoked with 1 arguments (expected 2) + +0:4(1): preprocessor error: Error: macro MULT invoked with 3 arguments (expected 2) + + +MULT() +MULT(1) +MULT(1,2,3) + diff --git a/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c new file mode 100644 index 0000000000..a6b7201f95 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c @@ -0,0 +1,3 @@ +#define __BAD reserved +#define GL_ALSO_BAD() also reserved +#define THIS__TOO__IS__BAD reserved diff --git a/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected new file mode 100644 index 0000000000..38b089daec --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/086-reserved-macro-names.c.expected @@ -0,0 +1,9 @@ +0:1(9): preprocessor warning: Macro names containing "__" are reserved for use by the implementation. + +0:2(9): preprocessor error: Macro names starting with "GL_" are reserved. + +0:3(9): preprocessor warning: Macro names containing "__" are reserved for use by the implementation. + + + + diff --git a/src/compiler/glsl/glcpp/tests/087-if-comments.c b/src/compiler/glsl/glcpp/tests/087-if-comments.c new file mode 100644 index 0000000000..ce8dc43057 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/087-if-comments.c @@ -0,0 +1,5 @@ +#if (1 == 0) // dangerous comment +fail +#else +win +#endif diff --git a/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected b/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected new file mode 100644 index 0000000000..2783a9c14d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/087-if-comments.c.expected @@ -0,0 +1,5 @@ + + + +win + diff --git a/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c new file mode 100644 index 0000000000..422c654641 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c @@ -0,0 +1,5 @@ +#define abc 123 +#define abc 123 + +#define foo(x) ( x ) + 23 +#define foo(x) ( x ) + 23 diff --git a/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected new file mode 100644 index 0000000000..3f2ff2d6cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/088-redefine-macro-legitimate.c.expected @@ -0,0 +1,5 @@ + + + + + diff --git a/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c new file mode 100644 index 0000000000..b3d1391e16 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c @@ -0,0 +1,17 @@ +#define x y +#define x z + +#define abc 123 +#define abc() 123 + +#define foo() bar +#define foo(x) bar + +#define bar() baz +#define bar baz + +#define biff(a,b) a+b +#define biff(a,b,c) a+b + +#define oper(a,b) a+b +#define oper(a,b) a*b diff --git a/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected new file mode 100644 index 0000000000..a945161497 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/089-redefine-macro-error.c.expected @@ -0,0 +1,29 @@ +0:2(9): preprocessor error: Redefinition of macro x + +0:5(9): preprocessor error: Redefinition of macro abc + +0:8(9): preprocessor error: Redefinition of macro foo + +0:11(9): preprocessor error: Redefinition of macro bar + +0:14(9): preprocessor error: Redefinition of macro biff + +0:17(9): preprocessor error: Redefinition of macro oper + + + + + + + + + + + + + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/090-hash-error.c b/src/compiler/glsl/glcpp/tests/090-hash-error.c new file mode 100644 index 0000000000..d19bb7faed --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/090-hash-error.c @@ -0,0 +1 @@ +#error human error diff --git a/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected b/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected new file mode 100644 index 0000000000..876a6ea9cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/090-hash-error.c.expected @@ -0,0 +1 @@ +0:1(1): preprocessor error: #error human error diff --git a/src/compiler/glsl/glcpp/tests/091-hash-line.c b/src/compiler/glsl/glcpp/tests/091-hash-line.c new file mode 100644 index 0000000000..26d70382a8 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/091-hash-line.c @@ -0,0 +1,14 @@ +#line 0 +#error line 0 error +#line 25 +#error line 25 error +#line 0 1 +#error source 1, line 0 error +#line 30 2 +#error source 2, line 30 error +#line 45 2 /* A line with a comment */ +#define NINETY 90 +#define TWO 2 +#line NINETY TWO /* A #line line with macro expansion */ +#define FUNCTION_LIKE_MACRO(source, line) source line +#line FUNCTION_LIKE_MACRO(180,2) diff --git a/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected new file mode 100644 index 0000000000..ac9ab252f1 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/091-hash-line.c.expected @@ -0,0 +1,14 @@ +0:0(1): preprocessor error: #error line 0 error +0:25(1): preprocessor error: #error line 25 error +1:0(1): preprocessor error: #error source 1, line 0 error +2:30(1): preprocessor error: #error source 2, line 30 error +#line 0 +#line 25 +#line 0 1 +#line 30 2 +#line 45 2 + + +#line 90 2 + +#line 180 2 diff --git a/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c new file mode 100644 index 0000000000..3c161a5c50 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c @@ -0,0 +1,5 @@ +#define A +#define A 1 + +#define B 1 +#define B diff --git a/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected new file mode 100644 index 0000000000..698294d91f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/092-redefine-macro-error-2.c.expected @@ -0,0 +1,9 @@ +0:2(9): preprocessor error: Redefinition of macro A + +0:5(9): preprocessor error: Redefinition of macro B + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c new file mode 100644 index 0000000000..bf65d4f527 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c @@ -0,0 +1,2 @@ +#if (1 / 0) +#endif diff --git a/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected new file mode 100644 index 0000000000..a858870b79 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/093-divide-by-zero.c.expected @@ -0,0 +1,3 @@ +0:1(12): preprocessor error: division by 0 in preprocessor directive + + diff --git a/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c new file mode 100644 index 0000000000..04497b1791 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c @@ -0,0 +1,13 @@ +/* glcpp is generating a division-by-zero error for this case. It's + * easy to argue that it should be short-circuiting the evaluation and + * not generating the diagnostic (which happens to be what gcc does). + * But it doesn't seem like we should force this behavior on our + * pre-processor, (and, as always, the GLSL specification of the + * pre-processor is too vague on this point). + * + * If a short-circuit evaluation optimization does get added to the + * pre-processor then it would legitimate to update the expected file + * for this test. +*/ +#if 1 || (1 / 0) +#endif diff --git a/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected new file mode 100644 index 0000000000..570952b245 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/094-divide-by-zero-short-circuit.c.expected @@ -0,0 +1,14 @@ +0:12(17): preprocessor error: division by 0 in preprocessor directive + + + + + + + + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/095-recursive-define.c b/src/compiler/glsl/glcpp/tests/095-recursive-define.c new file mode 100644 index 0000000000..801d90ce2e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/095-recursive-define.c @@ -0,0 +1,3 @@ +#define A(a, b) B(a, b) +#define C A(0, C) +C diff --git a/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected b/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected new file mode 100644 index 0000000000..493ab091be --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/095-recursive-define.c.expected @@ -0,0 +1,3 @@ + + +B(0, C) diff --git a/src/compiler/glsl/glcpp/tests/096-paste-twice.c b/src/compiler/glsl/glcpp/tests/096-paste-twice.c new file mode 100644 index 0000000000..8da756fcba --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/096-paste-twice.c @@ -0,0 +1,3 @@ +#define paste_twice(a,b,c) a ## b ## c +paste_twice(just, one, token) + diff --git a/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected b/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected new file mode 100644 index 0000000000..96c57d2a6e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/096-paste-twice.c.expected @@ -0,0 +1,3 @@ + +justonetoken + diff --git a/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c new file mode 100644 index 0000000000..0f46835c29 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c @@ -0,0 +1,3 @@ +#define PASTE_MACRO one ## token +PASTE_MACRO + diff --git a/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected new file mode 100644 index 0000000000..36f6699253 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/097-paste-with-non-function-macro.c.expected @@ -0,0 +1,3 @@ + +onetoken + diff --git a/src/compiler/glsl/glcpp/tests/098-elif-undefined.c b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c new file mode 100644 index 0000000000..1f520d4d43 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c @@ -0,0 +1,7 @@ +#if 0 +Not this +#elif UNDEFINED_MACRO +Nor this +#else +Yes, this. +#endif diff --git a/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected new file mode 100644 index 0000000000..c6ef689ce4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/098-elif-undefined.c.expected @@ -0,0 +1,7 @@ + + + + + +Yes, this. + diff --git a/src/compiler/glsl/glcpp/tests/099-c99-example.c b/src/compiler/glsl/glcpp/tests/099-c99-example.c new file mode 100644 index 0000000000..d1976b1f26 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/099-c99-example.c @@ -0,0 +1,17 @@ +#define x 3 +#define f(a) f(x * (a)) +#undef x +#define x 2 +#define g f +#define z z[0] +#define h g(~ +#define m(a) a(w) +#define w 0,1 +#define t(a) a +#define p() int +#define q(x) x +#define r(x,y) x ## y +f(y+1) + f(f(z)) % t(t(g)(0) + t)(1); +g(x +(3,4)-w) | h 5) & m + (f)^m(m); +p() i[q()] = { q(1), r(2,3), r(4,), r(,5), r(,)}; diff --git a/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected b/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected new file mode 100644 index 0000000000..352bbff48f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/099-c99-example.c.expected @@ -0,0 +1,16 @@ + + + + + + + + + + + + + +f(2 * (y+1)) + f(2 * (f(2 * (z[0])))) % f(2 * (0)) + t(1); +f(2 * (2 +(3,4)-0,1)) | f(2 * (~ 5)) & f(2 * (0,1))^m(0,1); +int i[] = { 1, 23, 4, 5, }; diff --git a/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c new file mode 100644 index 0000000000..31dbb9a9ed --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c @@ -0,0 +1,7 @@ +#define one 1 +#define two 2 + +switch (1) { + case one + two: + break; +} diff --git a/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected new file mode 100644 index 0000000000..09f1f417bd --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/100-macro-with-colon.c.expected @@ -0,0 +1,7 @@ + + + +switch (1) { + case 1 + 2: + break; +} diff --git a/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c new file mode 100644 index 0000000000..e1693805b6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c @@ -0,0 +1,16 @@ +#define object 1 +#define function(x) 1 + +#if object +once +#endif +#if object +twice +#endif + +#if function(0) +once +#endif +#if function(0) +once again +#endif diff --git a/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected new file mode 100644 index 0000000000..1e0b30696c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/101-macros-used-twice.c.expected @@ -0,0 +1,16 @@ + + + + +once + + +twice + + + +once + + +once again + diff --git a/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c new file mode 100644 index 0000000000..301779eb94 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c @@ -0,0 +1,2 @@ +#if 0 +#endif garbage diff --git a/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected new file mode 100644 index 0000000000..d9f3bdc946 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/102-garbage-after-endif.c.expected @@ -0,0 +1,2 @@ +0:2(8): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE + diff --git a/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c new file mode 100644 index 0000000000..c460feadf5 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c @@ -0,0 +1,3 @@ +#if 0 +#else garbage +#endif diff --git a/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected new file mode 100644 index 0000000000..b053b39977 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/103-garbage-after-else-0.c.expected @@ -0,0 +1,4 @@ +0:2(7): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE +0:1(6): preprocessor error: Unterminated #if + + diff --git a/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c new file mode 100644 index 0000000000..3fbeec48e4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c @@ -0,0 +1,2 @@ +#line 2 +int foo(); diff --git a/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected new file mode 100644 index 0000000000..3fbeec48e4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/104-hash-line-followed-by-code.c.expected @@ -0,0 +1,2 @@ +#line 2 +int foo(); diff --git a/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c new file mode 100644 index 0000000000..da156c6a59 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c @@ -0,0 +1,5 @@ +#define X(x) x +#line X( \ + 1 \ + ) +#line 2 diff --git a/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected new file mode 100644 index 0000000000..814cef1b8c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/105-multiline-hash-line.c.expected @@ -0,0 +1,5 @@ + +#line 1 + + +#line 2 diff --git a/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c new file mode 100644 index 0000000000..929e93e782 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c @@ -0,0 +1,6 @@ +#define X(x) x +#if X( \ + 1 \ + ) +int foo(); +#endif diff --git a/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected new file mode 100644 index 0000000000..1c0cbc970f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/106-multiline-hash-if.c.expected @@ -0,0 +1,6 @@ + + + + +int foo(); + diff --git a/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c new file mode 100644 index 0000000000..8c1c67a4d6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c @@ -0,0 +1,7 @@ +#define X(x) x +#if 0 +#elif X( \ + 1 \ + ) +int foo(); +#endif diff --git a/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected new file mode 100644 index 0000000000..b0601d7ee4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/107-multiline-hash-elif.c.expected @@ -0,0 +1,7 @@ + + + + + +int foo(); + diff --git a/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c new file mode 100644 index 0000000000..0ce36f2eb1 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c @@ -0,0 +1 @@ +#version110 diff --git a/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected new file mode 100644 index 0000000000..4f4243f947 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/108-no-space-after-hash-version.c.expected @@ -0,0 +1 @@ +0:1(1): preprocessor error: Illegal non-directive after # diff --git a/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c new file mode 100644 index 0000000000..f52966a8e8 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c @@ -0,0 +1 @@ +#line2 diff --git a/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected new file mode 100644 index 0000000000..4f4243f947 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/109-no-space-after-hash-line.c.expected @@ -0,0 +1 @@ +0:1(1): preprocessor error: Illegal non-directive after # diff --git a/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c new file mode 100644 index 0000000000..6d7d0f38d9 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c @@ -0,0 +1,3 @@ +#if 1 +#elif110 +#endif diff --git a/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected new file mode 100644 index 0000000000..4d93de41dd --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/110-no-space-digits-after-hash-elif.c.expected @@ -0,0 +1,3 @@ +0:2(1): preprocessor error: Illegal non-directive after # + + diff --git a/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c new file mode 100644 index 0000000000..b3413371ec --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c @@ -0,0 +1,19 @@ +#if(1) +success +#endif + +#if+1 +success +#endif + +#if-1 +success +#endif + +#if!1 +success +#endif + +#if~1 +success +#endif diff --git a/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected new file mode 100644 index 0000000000..5c005c393a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/111-no-space-operator-after-hash-if.c.expected @@ -0,0 +1,19 @@ + +success + + + +success + + + +success + + + + + + + +success + diff --git a/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c new file mode 100644 index 0000000000..e8221bc49c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c @@ -0,0 +1,24 @@ +#if 0 +#elif(1) +success +#endif + +#if 0 +#elif+1 +success +#endif + +#if 0 +#elif-1 +success +#endif + +#if 0 +#elif!1 +success +#endif + +#if 0 +#elif~1 +success +#endif diff --git a/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected new file mode 100644 index 0000000000..86b37036b6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/112-no-space-operator-after-hash-elif.c.expected @@ -0,0 +1,24 @@ + + +success + + + + +success + + + + +success + + + + + + + + + +success + diff --git a/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c new file mode 100644 index 0000000000..369c487926 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c @@ -0,0 +1,7 @@ +1. Number of dalmations: __LINE__ __FILE__ __LINE__ +2. Nominal visual acuity: __LINE__ __FILE__ / __LINE__ __FILE__ +3. Battle of Thermopylae, as film: __LINE__ __FILE__ __FILE__ +4. HTTP code for "Not Found": __LINE__ __FILE__ __LINE__ +5. Hexadecimal for 20560: __LINE__ __FILE__ __LINE__ __FILE__ +6: Zip code for Nortonville, KS: __LINE__ __LINE__ __FILE__ __LINE__ __FILE__ +7. James Bond, as a number: __FILE__ __FILE__ __LINE__ diff --git a/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected new file mode 100644 index 0000000000..55bc788ffd --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/113-line-and-file-macros.c.expected @@ -0,0 +1,7 @@ +1. Number of dalmations: 1 0 1 +2. Nominal visual acuity: 2 0 / 2 0 +3. Battle of Thermopylae, as film: 3 0 0 +4. HTTP code for "Not Found": 4 0 4 +5. Hexadecimal for 20560: 5 0 5 0 +6: Zip code for Nortonville, KS: 6 6 0 6 0 +7. James Bond, as a number: 0 0 7 diff --git a/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c new file mode 100644 index 0000000000..d80d9c7ef4 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c @@ -0,0 +1,7 @@ +#define PASTE3(a,b,c) a ## b ## c +#define PASTE4(a,b,c,d) a ## b ## c ## d +#define PASTE5(a,b,c,d,e) a ## b ## c ## d ## e +4. HTTP code for "Not Found": PASTE3(__LINE__, __FILE__ , __LINE__) +5. Hexadecimal for 20560: PASTE4(__LINE__, __FILE__, __LINE__, __FILE__) +6: Zip code for Nortonville, KS: PASTE5(__LINE__, __LINE__, __FILE__, __LINE__, __FILE__) +7. James Bond, as a number: PASTE3(__FILE__, __FILE__, __LINE__) diff --git a/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected new file mode 100644 index 0000000000..aa9711034a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/114-paste-integer-tokens.c.expected @@ -0,0 +1,7 @@ + + + +4. HTTP code for "Not Found": 404 +5. Hexadecimal for 20560: 5050 +6: Zip code for Nortonville, KS: 66060 +7. James Bond, as a number: 007 diff --git a/src/compiler/glsl/glcpp/tests/115-line-continuations.c b/src/compiler/glsl/glcpp/tests/115-line-continuations.c new file mode 100644 index 0000000000..105590d85e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/115-line-continuations.c @@ -0,0 +1,9 @@ +// This comment continues to the next line, hiding the define \ +#define CONTINUATION_UNSUPPORTED + +#ifdef CONTINUATION_UNSUPPORTED +failure +#else +success +#endif + diff --git a/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected b/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected new file mode 100644 index 0000000000..428b5e822c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/115-line-continuations.c.expected @@ -0,0 +1,9 @@ + + + + + + +success + + diff --git a/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c new file mode 100644 index 0000000000..83d5ddf681 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c @@ -0,0 +1,13 @@ +// glcpp-args: --disable-line-continuations + +// This comments ends with a backslash \\ +#define NO_CONTINUATION + +#ifdef NO_CONTINUATION +success +#else +failure +#endif + + + diff --git a/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected new file mode 100644 index 0000000000..5ca78928a6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/116-disable-line-continuations.c.expected @@ -0,0 +1,13 @@ + + + + + + +success + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c new file mode 100644 index 0000000000..6a6f282988 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c @@ -0,0 +1,12 @@ +/* This test case is the minimal case to replicate the bug reported here: + * + * https://bugs.freedesktop.org/show_bug.cgi?id=65112 + * + * To trigger the bug, there must be a line-continuation sequence + * (backslash newline), then an additional newline character, and + * finally another backslash that is not part of a line-continuation + * sequence. + */ +\ + +/* \ */ diff --git a/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected new file mode 100644 index 0000000000..8aaa04d28e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/117-line-continuation-and-non-continuation-backslash.c.expected @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c new file mode 100644 index 0000000000..53e80394ab --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c @@ -0,0 +1,4 @@ +#define FOO first/* +*/second + +FOO diff --git a/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected new file mode 100644 index 0000000000..1fa8135cb1 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/118-comment-becomes-space.c.expected @@ -0,0 +1,4 @@ + + + +first second diff --git a/src/compiler/glsl/glcpp/tests/119-elif-after-else.c b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c new file mode 100644 index 0000000000..9b9e9233bc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c @@ -0,0 +1,6 @@ +#if 0 +#else +int foo; +#elif 0 +int bar; +#endif diff --git a/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected new file mode 100644 index 0000000000..636956799c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/119-elif-after-else.c.expected @@ -0,0 +1,7 @@ +0:4(1): preprocessor error: #elif after #else + + +int foo; + +int bar; + diff --git a/src/compiler/glsl/glcpp/tests/120-undef-builtin.c b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c new file mode 100644 index 0000000000..49e7696613 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c @@ -0,0 +1,3 @@ +#undef __LINE__ +#undef __FILE__ +#undef __VERSION__ diff --git a/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected new file mode 100644 index 0000000000..3b736df378 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/120-undef-builtin.c.expected @@ -0,0 +1,6 @@ +0:1(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined. +0:2(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined. +0:3(1): preprocessor error: Built-in (pre-defined) macro names cannot be undefined. + + + diff --git a/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c new file mode 100644 index 0000000000..67ebe73e5c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c @@ -0,0 +1,2 @@ +/* + */ // diff --git a/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected new file mode 100644 index 0000000000..8cb7cb9891 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/121-comment-bug-72686.c.expected @@ -0,0 +1,2 @@ + + diff --git a/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c new file mode 100644 index 0000000000..ae7ea09f67 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c @@ -0,0 +1,16 @@ +/* Original definitions. */ +#define TWO ( 1+1 ) +#define FOUR (2 + 2) +#define SIX (3 + 3) + +/* Redefinitions with whitespace in same places, but different amounts, (so no + * error). */ +#define TWO ( 1+1 ) +#define FOUR (2 + 2) +#define SIX (3/*comment is whitespace*/+ /* collapsed */ /* to */ /* one */ /* space */ 3) + +/* Redefinitions with whitespace in different places. Each of these should + * trigger an error. */ +#define TWO (1 + 1) +#define FOUR ( 2+2 ) +#define SIX (/*not*/3 + 3/*expected*/) diff --git a/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected new file mode 100644 index 0000000000..602bdef94c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/122-redefine-whitespace.c.expected @@ -0,0 +1,22 @@ +0:14(9): preprocessor error: Redefinition of macro TWO + +0:15(9): preprocessor error: Redefinition of macro FOUR + +0:16(9): preprocessor error: Redefinition of macro SIX + + + + + + + + + + + + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c new file mode 100644 index 0000000000..0b341a381f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c @@ -0,0 +1,3 @@ +#if 1 +#else garbage +#endif diff --git a/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected new file mode 100644 index 0000000000..b053b39977 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/123-garbage-after-else-1.c.expected @@ -0,0 +1,4 @@ +0:2(7): preprocessor error: syntax error, unexpected IDENTIFIER, expecting NEWLINE +0:1(6): preprocessor error: Unterminated #if + + diff --git a/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c new file mode 100644 index 0000000000..947ba1885e --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c @@ -0,0 +1,37 @@ +#define e THIS_SHOULD_NOT_BE_EXPANDED +#define E NOR_THIS +#define p NOT_THIS_EITHER +#define P AND_SURELY_NOT_THIS +#define OK CRAZY_BUT_TRUE_THIS_NEITHER + +/* This one is actually meant to be expanded */ +#define MUST_EXPAND GO + +/* The following are "preprocessing numbers" and should not trigger macro + * expansion. */ +1e +1OK + +/* These are also "preprocessing numbers", so no expansion */ +123e+OK +.23E+OK +1.3e-OK +12.E-OK +123p+OK +.23P+OK +1.3p-OK +12.P-OK +123..OK +.23.OK.OK + +/* Importantly, just before the MUST_EXPAND in each of these, the preceding + * "preprocessing number" ends and we have an actual expression. So the + * MUST_EXPAND macro must be expanded (who would have though?) in each case. */ +123ef+MUST_EXPAND +.23E3-MUST_EXPAND +1.3e--MUST_EXPAND +12.E-&MUST_EXPAND +123p+OK+MUST_EXPAND +.23P+OK;MUST_EXPAND +1.3p-OK-MUST_EXPAND +12.P-OK&MUST_EXPAND diff --git a/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected new file mode 100644 index 0000000000..6ec588862d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/124-preprocessing-numbers.c.expected @@ -0,0 +1,37 @@ + + + + + + + + + + + +1e +1OK + + +123e+OK +.23E+OK +1.3e-OK +12.E-OK +123p+OK +.23P+OK +1.3p-OK +12.P-OK +123..OK +.23.OK.OK + + + + +123ef+GO +.23E3-GO +1.3e--GO +12.E-&GO +123p+OK+GO +.23P+OK;GO +1.3p-OK-GO +12.P-OK&GO diff --git a/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c new file mode 100644 index 0000000000..4ee29f6d93 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c @@ -0,0 +1,27 @@ +/* For GLSL in OpenGL ES, an undefined macro appearing in an #if or #elif + * expression, (other than as an argument to defined) is an error. + * + * Except in the case of a short-circuiting && or || operator, where the + * specification explicitly mandates that there be no error. + */ +#version 300 es + +/* These yield errors */ +#if NOT_DEFINED +#endif + +#if 0 +#elif ALSO_NOT_DEFINED +#endif + +/* But these yield no errors */ +#if 1 || STILL_NOT_DEFINED +Success +#endif + +#if 0 +#elif 0 && WILL_ANYONE_DEFINE_ANYTHING +#else +More success +#endif + diff --git a/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected new file mode 100644 index 0000000000..616aa912e2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/125-es-short-circuit-undefined.c.expected @@ -0,0 +1,29 @@ +0:10(16): preprocessor error: undefined macro NOT_DEFINED in expression (illegal in GLES) +0:14(23): preprocessor error: undefined macro ALSO_NOT_DEFINED in expression (illegal in GLES) + + + + + + +#version 300 es + + + + + + + + + + + +Success + + + + + +More success + + diff --git a/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c new file mode 100644 index 0000000000..4c0d29000a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c @@ -0,0 +1,5 @@ +#ifdef MACRO garbage +#endif + +#ifndef MORE garbage +#endif diff --git a/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected new file mode 100644 index 0000000000..82a06f8a3b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/126-garbage-after-directive.c.expected @@ -0,0 +1,7 @@ +0:1(14): preprocessor error: extra tokens at end of directive +0:4(14): preprocessor error: extra tokens at end of directive + + + + + diff --git a/src/compiler/glsl/glcpp/tests/127-pragma-empty.c b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c new file mode 100644 index 0000000000..0f9b0b3d38 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c @@ -0,0 +1,3 @@ +/* It seems an odd (and particularly useless) thing to have an empty pragma, + * but we probably shouldn't trigger an error in this case. */ +#pragma diff --git a/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected new file mode 100644 index 0000000000..92371a07c3 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/127-pragma-empty.c.expected @@ -0,0 +1,3 @@ + + + diff --git a/src/compiler/glsl/glcpp/tests/128-space-before-hash.c b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c new file mode 100644 index 0000000000..fba9596baf --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c @@ -0,0 +1,21 @@ + /* Any directive can be preceded by a space. */ + #version 300 + #pragma Testing spaces before hash + # + #line 3 + #define FOO + #ifdef FOO + yes + #endif + #if 0 + #elif defined FOO + yes again + #endif + #if 0 + #else + for the third time, yes! + #endif + #undef FOO + #ifndef FOO + yes, of course + #endif diff --git a/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected new file mode 100644 index 0000000000..9babb6fb07 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/128-space-before-hash.c.expected @@ -0,0 +1,21 @@ + +#version 300 +#pragma Testing spaces before hash + +#line 3 + + + yes + + + + yes again + + + + for the third time, yes! + + + + yes, of course + diff --git a/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c new file mode 100644 index 0000000000..a229179f18 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c @@ -0,0 +1 @@ +#define 123 456 diff --git a/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected new file mode 100644 index 0000000000..fd0b41347f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/129-define-non-identifier.c.expected @@ -0,0 +1,2 @@ +0:1(9): preprocessor error: #define followed by a non-identifier: 123 +0:1(9): preprocessor error: syntax error, unexpected INTEGER_STRING, expecting FUNC_IDENTIFIER or OBJ_IDENTIFIER diff --git a/src/compiler/glsl/glcpp/tests/130-define-comment.c b/src/compiler/glsl/glcpp/tests/130-define-comment.c new file mode 100644 index 0000000000..33312362cc --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/130-define-comment.c @@ -0,0 +1,2 @@ +#define /*...*/ FUNC( /*...*/ x /*...*/ ) /*...*/ FOO( /*...*/ x /*...*/ ) +FUNC(bar) diff --git a/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected b/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected new file mode 100644 index 0000000000..d789e29d5a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/130-define-comment.c.expected @@ -0,0 +1,2 @@ + +FOO( bar ) diff --git a/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c new file mode 100644 index 0000000000..240292dad0 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c @@ -0,0 +1 @@ +this file ends with no newline
\ No newline at end of file diff --git a/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected new file mode 100644 index 0000000000..5780030632 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/131-eof-without-newline.c.expected @@ -0,0 +1 @@ +this file ends with no newline diff --git a/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c new file mode 100644 index 0000000000..6795e35ea0 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c @@ -0,0 +1 @@ +#define
\ No newline at end of file diff --git a/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected new file mode 100644 index 0000000000..341e5e2aa6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/132-eof-without-newline-define.c.expected @@ -0,0 +1 @@ +0:1(1): preprocessor error: #define without macro name diff --git a/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c new file mode 100644 index 0000000000..56ec5f722c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c @@ -0,0 +1 @@ +This file ends with no newline within a comment /*
\ No newline at end of file diff --git a/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected new file mode 100644 index 0000000000..d186f48761 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/133-eof-without-newline-comment.c.expected @@ -0,0 +1,2 @@ +0:1(51): preprocessor error: Unterminated comment +This file ends with no newline within a comment diff --git a/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c new file mode 100644 index 0000000000..3015f0e886 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c @@ -0,0 +1,22 @@ +/*...*/ # /*...*/ version 300 + /*...*/#/*...*/ extension whatever + /*..*/ # /*..*/ pragma ignored +/**/ # /**/ line 4 + /*...*/# /*...*/ ifdef NOT_DEFINED + /*...*/# /*...*/ else + /*..*/ #/*..*/ endif + /*...*/# /*...*/ ifndef ALSO_NOT_DEFINED + /*...*/# /*...*/ else + /*..*/ #/*..*/ endif +/*...*/ # /*...*/ if 0 + /*...*/#/*...*/ elif 1 + /*..*/ # /*..*/ else + /**/ # /**/ endif + /*...*/# /*...*/ define FOO bar + /*..*/ #/*..*/ define FUNC() baz + /*..*/ # /*..*/ define FUNC2(a,b) b a +FOO +FUNC() +FUNC2(x,y) + + diff --git a/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected new file mode 100644 index 0000000000..760c960cb6 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/134-hash-comment-directive.c.expected @@ -0,0 +1,22 @@ +#version 300 +#extension whatever +#pragma ignored +#line 4 + + + + + + + + + + + + + +bar +baz +y x + + diff --git a/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c new file mode 100644 index 0000000000..fd96bd64c7 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c @@ -0,0 +1,2 @@ +#define FOO(a,a) which a? +#define BAR(x,y,z,x) so very x diff --git a/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected new file mode 100644 index 0000000000..bc1a334ed2 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/135-duplicate-parameter.c.expected @@ -0,0 +1,4 @@ +0:1(9): preprocessor error: Duplicate macro parameter "a" +0:2(9): preprocessor error: Duplicate macro parameter "x" + + diff --git a/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c new file mode 100644 index 0000000000..167d3c8a3c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c @@ -0,0 +1,8 @@ +/* The body can include C expressions with ++ and -- */ +a = x++; +b = ++x; +c = x--; +d = --x; +/* But these are not legal in preprocessor expressions. */ +#if x++ > 4 +#endif diff --git a/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected new file mode 100644 index 0000000000..137921b169 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/136-plus-plus-and-minus-minus.c.expected @@ -0,0 +1,8 @@ +0:7(12): preprocessor error: syntax error, unexpected PLUS_PLUS + +a = x++; +b = ++x; +c = x--; +d = --x; + + diff --git a/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c new file mode 100644 index 0000000000..c8cd47fb57 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c @@ -0,0 +1,4 @@ +#define FIELD(x) foo.x +#define FIELD_OF(s, x) s.x +FIELD(bar) +FIELD_OF(foo, bar) diff --git a/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected new file mode 100644 index 0000000000..f9f5be13e0 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/137-expand-macro-after-period.c.expected @@ -0,0 +1,4 @@ + + +foo.bar +foo.bar diff --git a/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c new file mode 100644 index 0000000000..38967dc57d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c @@ -0,0 +1,7 @@ +#if 0 +/* + * This multi-line comment needs to be 3 lines to test what's intended. + */ +#else +SUCCESS +#endif diff --git a/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected new file mode 100644 index 0000000000..0d6ef4d9ad --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/138-multi-line-comment-in-if-0.c.expected @@ -0,0 +1,7 @@ + + + + + +SUCCESS + diff --git a/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c new file mode 100644 index 0000000000..30e128db4c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c @@ -0,0 +1,5 @@ +#define +#define +#define /*...*/ +#define //... +Errors expected because no macro name is ever given! diff --git a/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected new file mode 100644 index 0000000000..42b02d1a8a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/139-define-without-macro-name.c.expected @@ -0,0 +1,5 @@ +0:1(1): preprocessor error: #define without macro name +0:2(1): preprocessor error: #define without macro name +0:3(1): preprocessor error: #define without macro name +0:4(1): preprocessor error: #define without macro name +Errors expected because no macro name is ever given! diff --git a/src/compiler/glsl/glcpp/tests/140-null-directive.c b/src/compiler/glsl/glcpp/tests/140-null-directive.c new file mode 100644 index 0000000000..1dcb26ef8b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/140-null-directive.c @@ -0,0 +1,9 @@ +/* GLSL accepts a null directive. Let's test that in several variations: */ +# + # +/*....*/#/*....*/ + /*..*/ # /*..*/ +#//... + # //... +/*....*/#/**///.. + /*..*/ # /**/ // diff --git a/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected b/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected new file mode 100644 index 0000000000..fa103f60e8 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/140-null-directive.c.expected @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c new file mode 100644 index 0000000000..a93f3ce35f --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c @@ -0,0 +1,6 @@ +Line 1 /* Test for a bug where #pragma was throwing off the __LINE__ count. */ +Line __LINE__ /* Line 2 */ +#pragma Line 3 +Line __LINE__ /* Line 4 */ +#pragma Line 5 +Line __LINE__ /* Line 6 */ diff --git a/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected new file mode 100644 index 0000000000..330731dc80 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/141-pragma-and-__LINE__.c.expected @@ -0,0 +1,6 @@ +Line 1 +Line 2 +#pragma Line 3 +Line 4 +#pragma Line 5 +Line 6 diff --git a/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c new file mode 100644 index 0000000000..b60c04232a --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c @@ -0,0 +1,94 @@ +/* Macro using defined with a hard-coded identifier (no parentheses) */ +#define is_foo_defined defined /*...*/ foo +#undef foo +#if is_foo_defined +failure +#else +success +#endif +#define foo +#if is_foo_defined +success +#else +failure +#endif + +/* Macro using defined with a hard-coded identifier within parentheses */ +#define is_foo_defined_parens defined /*...*/ ( /*...*/ foo /*...*/ ) // +#define foo +#if is_foo_defined_parens +success +#else +failure +#endif +#undef foo +#if is_foo_defined_parens +failure +#else +success +#endif + +/* Macro using defined with an argument identifier (no parentheses) */ +#define is_defined(arg) defined /*...*/ arg +#define foo bar +#undef bar +#if is_defined(foo) +failure +#else +success +#endif +#define bar bar +#if is_defined(foo) +success +#else +failure +#endif + +/* Macro using defined with an argument identifier within parentheses */ +#define is_defined_parens(arg) defined /*...*/ ( /*...*/ arg /*...*/ ) // +#define foo bar +#define bar bar +#if is_defined_parens(foo) +success +#else +failure +#endif +#undef bar +#if is_defined_parens(foo) +failure +#else +success +#endif + +/* Multiple levels of macro resulting in defined */ +#define X defined A && Y +#define Y defined B && Z +#define Z defined C +#define A +#define B +#define C +#if X +success +#else +failure +#endif +#undef A +#if X +failure +#else +success +#endif +#define A +#undef B +#if X +failure +#else +success +#endif +#define B +#undef C +#if X +failure +#else +success +#endif diff --git a/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected new file mode 100644 index 0000000000..4eca90bc3d --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/142-defined-within-macro.c.expected @@ -0,0 +1,94 @@ + + + + + + +success + + + +success + + + + + + + + +success + + + + + + + +success + + + + + + + + + +success + + + +success + + + + + + + + + +success + + + + + + + +success + + + + + + + + + + +success + + + + + + + +success + + + + + + +success + + + + + + +success + diff --git a/src/compiler/glsl/glcpp/tests/143-multiple-else.c b/src/compiler/glsl/glcpp/tests/143-multiple-else.c new file mode 100644 index 0000000000..62ad49cf7b --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/143-multiple-else.c @@ -0,0 +1,6 @@ +#if 0 +#else +int foo; +#else +int bar; +#endif diff --git a/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected b/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected new file mode 100644 index 0000000000..00b3328c83 --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/143-multiple-else.c.expected @@ -0,0 +1,7 @@ +0:4(1): preprocessor error: multiple #else + + +int foo; + +int bar; + diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test b/src/compiler/glsl/glcpp/tests/glcpp-test new file mode 100755 index 0000000000..3945ee4f6c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/glcpp-test @@ -0,0 +1,110 @@ +#!/bin/sh + +if [ ! -z "$srcdir" ]; then + testdir=$srcdir/glsl/glcpp/tests + outdir=`pwd`/glsl/glcpp/tests + glcpp=`pwd`/glsl/glcpp/glcpp +else + testdir=. + outdir=. + glcpp=../glcpp +fi + +trap 'rm $test.valgrind-errors; exit 1' INT QUIT + +usage () +{ + cat <<EOF +Usage: glcpp [options...] + +Run the test suite for mesa's GLSL pre-processor. + +Valid options include: + + --testdir=<DIR> Use tests in the given <DIR> (default is ".") + --valgrind Run the test suite a second time under valgrind +EOF +} + +test_specific_args () +{ + test="$1" + + tr "\r" "\n" < "$test" | grep 'glcpp-args:' | sed -e 's,^.*glcpp-args: *,,' +} + +# Parse command-line options +for option; do + case "${option}" in + "--help") + usage + exit 0 + ;; + "--valgrind") + do_valgrind=yes + ;; + "--testdir="*) + testdir="${option#--testdir=}" + outdir="${outdir}/${option#--testdir=}" + ;; + *) + echo "Unrecognized option: $option" >&2 + echo >&2 + usage + exit 1 + ;; + esac +done + +total=0 +pass=0 +clean=0 + +mkdir -p $outdir + +echo "====== Testing for correctness ======" +for test in $testdir/*.c; do + out=$outdir/${test##*/}.out + + printf "Testing $test... > $out ($test.expected) " + $glcpp $(test_specific_args $test) < $test > $out 2>&1 + total=$((total+1)) + if cmp $test.expected $out >/dev/null 2>&1; then + echo "PASS" + pass=$((pass+1)) + else + echo "FAIL" + diff -u $test.expected $out + fi +done + +echo "" +echo "$pass/$total tests returned correct results" +echo "" + +if [ "$do_valgrind" = "yes" ]; then + echo "====== Testing for valgrind cleanliness ======" + for test in $testdir/*.c; do + printf "Testing $test with valgrind..." + valgrind --error-exitcode=31 --log-file=$test.valgrind-errors $glcpp $(test_specific_args $test) < $test >/dev/null 2>&1 + if [ "$?" = "31" ]; then + echo "ERRORS" + cat $test.valgrind-errors + else + echo "CLEAN" + clean=$((clean+1)) + rm $test.valgrind-errors + fi + done + + echo "" + echo "$pass/$total tests returned correct results" + echo "$clean/$total tests are valgrind-clean" +fi + +if [ "$pass" = "$total" ] && [ "$do_valgrind" != "yes" ] || [ "$pass" = "$total" ]; then + exit 0 +else + exit 1 +fi + diff --git a/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf new file mode 100755 index 0000000000..c75370f48c --- /dev/null +++ b/src/compiler/glsl/glcpp/tests/glcpp-test-cr-lf @@ -0,0 +1,141 @@ +#!/bin/sh + +# The build system runs this test from a different working directory, and may +# be in a build directory entirely separate from the source. So if the +# "srcdir" variable is set, we must use it to locate the test files and the +# glcpp-test script. + +if [ ! -z "$srcdir" ]; then + testdir="$srcdir/glsl/glcpp/tests" + glcpp_test="$srcdir/glsl/glcpp/tests/glcpp-test" +else + testdir=. + glcpp_test=./glcpp-test +fi + +total=0 +pass=0 + +# This supports a pipe that doesn't destroy the exit status of first command +# +# http://unix.stackexchange.com/questions/14270/get-exit-status-of-process-thats-piped-to-another +stdintoexitstatus() { + read exitstatus + return $exitstatus +} + +run_test () +{ + cmd="$1" + + total=$((total+1)) + + if [ "$VERBOSE" = "yes" ]; then + if $cmd; then + echo "PASS" + pass=$((pass+1)) + else + echo "FAIL" + fi + else + # This is "$cmd | tail -2" but with the exit status of "$cmd" not "tail -2" + if (((($cmd; echo $? >&3) | tail -2 | head -1 >&4) 3>&1) | stdintoexitstatus) 4>&1; then + echo "PASS" + pass=$((pass+1)) + else + echo "FAIL" + fi + fi +} + +usage () +{ + cat <<EOF +Usage: glcpp-cr-lf [options...] + +Run the entire glcpp-test suite several times, each time with each source +file transformed to use a non-standard line-termination character. Each +entire run with a different line-termination character is considered a +single test. + +Valid options include: + + -v|--verbose Print all output from the various sub-tests +EOF +} + +# Parse command-line options +for option; do + case "${option}" in + -v|--verbose) + VERBOSE=yes; + ;; + *) + echo "Unrecognized option: $option" >&2 + echo >&2 + usage + exit 1 + ;; + esac +done + +# All tests depend on the .out files being present. So first do a +# normal run of the test suite, (silently) just to create the .out +# files as a side effect. +rm -rf ./subtest-lf +mkdir subtest-lf +for file in "$testdir"/*.c; do + base=$(basename "$file") + cp "$file" subtest-lf +done + +${glcpp_test} --testdir=subtest-lf >/dev/null 2>&1 + +echo "===== Testing with \\\\r line terminators (old Mac format) =====" + +# Prepare test files with '\r' instead of '\n' +rm -rf ./subtest-cr +mkdir subtest-cr +for file in "$testdir"/*.c; do + base=$(basename "$file") + tr "\n" "\r" < "$file" > subtest-cr/"$base" + cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr/"$base".expected +done + +run_test "${glcpp_test} --testdir=subtest-cr" + +echo "===== Testing with \\\\r\\\\n line terminators (DOS format) =====" + +# Prepare test files with '\r\n' instead of '\n' +rm -rf ./subtest-cr-lf +mkdir subtest-cr-lf +for file in "$testdir"/*.c; do + base=$(basename "$file") + sed -e 's/$/
/' < "$file" > subtest-cr-lf/"$base" + cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-cr-lf/"$base".expected +done + +run_test "${glcpp_test} --testdir=subtest-cr-lf" + +echo "===== Testing with \\\\n\\\\r (bizarre, but allowed by GLSL spec.) =====" + +# Prepare test files with '\n\r' instead of '\n' +rm -rf ./subtest-lf-cr +mkdir subtest-lf-cr +for file in "$testdir"/*.c; do + base=$(basename "$file") + sed -e 's/$/
/' < "$file" | tr "\n\r" "\r\n" > subtest-lf-cr/"$base" + cp `pwd`/glsl/glcpp/tests/subtest-lf/"$base".out subtest-lf-cr/"$base".expected +done + +run_test "${glcpp_test} --testdir=subtest-lf-cr" + +echo "" +echo "$pass/$total tests returned correct results" +echo "" + +if [ "$pass" = "$total" ]; then + exit 0 +else + exit 1 +fi |