101e04c3fSmrg%{ 201e04c3fSmrg/* 301e04c3fSmrg * Copyright © 2010 Intel Corporation 401e04c3fSmrg * 501e04c3fSmrg * Permission is hereby granted, free of charge, to any person obtaining a 601e04c3fSmrg * copy of this software and associated documentation files (the "Software"), 701e04c3fSmrg * to deal in the Software without restriction, including without limitation 801e04c3fSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 901e04c3fSmrg * and/or sell copies of the Software, and to permit persons to whom the 1001e04c3fSmrg * Software is furnished to do so, subject to the following conditions: 1101e04c3fSmrg * 1201e04c3fSmrg * The above copyright notice and this permission notice (including the next 1301e04c3fSmrg * paragraph) shall be included in all copies or substantial portions of the 1401e04c3fSmrg * Software. 1501e04c3fSmrg * 1601e04c3fSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 1701e04c3fSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 1801e04c3fSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 1901e04c3fSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 2001e04c3fSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 2101e04c3fSmrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2201e04c3fSmrg * DEALINGS IN THE SOFTWARE. 2301e04c3fSmrg */ 2401e04c3fSmrg 2501e04c3fSmrg#include <stdio.h> 2601e04c3fSmrg#include <stdlib.h> 2701e04c3fSmrg#include <string.h> 2801e04c3fSmrg#include <assert.h> 2901e04c3fSmrg#include <inttypes.h> 3001e04c3fSmrg 3101e04c3fSmrg#include "glcpp.h" 3201e04c3fSmrg#include "main/mtypes.h" 337ec681f3Smrg#include "util/strndup.h" 347ec681f3Smrg 357ec681f3Smrgconst char * 367ec681f3Smrg_mesa_lookup_shader_include(struct gl_context *ctx, char *path, 377ec681f3Smrg bool error_check); 387ec681f3Smrg 397ec681f3Smrgsize_t 407ec681f3Smrg_mesa_get_shader_include_cursor(struct gl_shared_state *shared); 417ec681f3Smrg 427ec681f3Smrgvoid 437ec681f3Smrg_mesa_set_shader_include_cursor(struct gl_shared_state *shared, size_t cursor); 4401e04c3fSmrg 4501e04c3fSmrgstatic void 4601e04c3fSmrgyyerror(YYLTYPE *locp, glcpp_parser_t *parser, const char *error); 4701e04c3fSmrg 4801e04c3fSmrgstatic void 4901e04c3fSmrg_define_object_macro(glcpp_parser_t *parser, 5001e04c3fSmrg YYLTYPE *loc, 5101e04c3fSmrg const char *macro, 5201e04c3fSmrg token_list_t *replacements); 5301e04c3fSmrg 5401e04c3fSmrgstatic void 5501e04c3fSmrg_define_function_macro(glcpp_parser_t *parser, 5601e04c3fSmrg YYLTYPE *loc, 5701e04c3fSmrg const char *macro, 5801e04c3fSmrg string_list_t *parameters, 5901e04c3fSmrg token_list_t *replacements); 6001e04c3fSmrg 6101e04c3fSmrgstatic string_list_t * 6201e04c3fSmrg_string_list_create(glcpp_parser_t *parser); 6301e04c3fSmrg 6401e04c3fSmrgstatic void 6501e04c3fSmrg_string_list_append_item(glcpp_parser_t *parser, string_list_t *list, 6601e04c3fSmrg const char *str); 6701e04c3fSmrg 6801e04c3fSmrgstatic int 6901e04c3fSmrg_string_list_contains(string_list_t *list, const char *member, int *index); 7001e04c3fSmrg 7101e04c3fSmrgstatic const char * 7201e04c3fSmrg_string_list_has_duplicate(string_list_t *list); 7301e04c3fSmrg 7401e04c3fSmrgstatic int 7501e04c3fSmrg_string_list_length(string_list_t *list); 7601e04c3fSmrg 7701e04c3fSmrgstatic int 7801e04c3fSmrg_string_list_equal(string_list_t *a, string_list_t *b); 7901e04c3fSmrg 8001e04c3fSmrgstatic argument_list_t * 8101e04c3fSmrg_argument_list_create(glcpp_parser_t *parser); 8201e04c3fSmrg 8301e04c3fSmrgstatic void 8401e04c3fSmrg_argument_list_append(glcpp_parser_t *parser, argument_list_t *list, 8501e04c3fSmrg token_list_t *argument); 8601e04c3fSmrg 8701e04c3fSmrgstatic int 8801e04c3fSmrg_argument_list_length(argument_list_t *list); 8901e04c3fSmrg 9001e04c3fSmrgstatic token_list_t * 9101e04c3fSmrg_argument_list_member_at(argument_list_t *list, int index); 9201e04c3fSmrg 9301e04c3fSmrgstatic token_t * 9401e04c3fSmrg_token_create_str(glcpp_parser_t *parser, int type, char *str); 9501e04c3fSmrg 9601e04c3fSmrgstatic token_t * 9701e04c3fSmrg_token_create_ival(glcpp_parser_t *parser, int type, int ival); 9801e04c3fSmrg 9901e04c3fSmrgstatic token_list_t * 10001e04c3fSmrg_token_list_create(glcpp_parser_t *parser); 10101e04c3fSmrg 10201e04c3fSmrgstatic void 10301e04c3fSmrg_token_list_append(glcpp_parser_t *parser, token_list_t *list, token_t *token); 10401e04c3fSmrg 10501e04c3fSmrgstatic void 10601e04c3fSmrg_token_list_append_list(token_list_t *list, token_list_t *tail); 10701e04c3fSmrg 10801e04c3fSmrgstatic int 10901e04c3fSmrg_token_list_equal_ignoring_space(token_list_t *a, token_list_t *b); 11001e04c3fSmrg 11101e04c3fSmrgstatic void 11201e04c3fSmrg_parser_active_list_push(glcpp_parser_t *parser, const char *identifier, 11301e04c3fSmrg token_node_t *marker); 11401e04c3fSmrg 11501e04c3fSmrgstatic void 11601e04c3fSmrg_parser_active_list_pop(glcpp_parser_t *parser); 11701e04c3fSmrg 11801e04c3fSmrgstatic int 11901e04c3fSmrg_parser_active_list_contains(glcpp_parser_t *parser, const char *identifier); 12001e04c3fSmrg 12101e04c3fSmrgtypedef enum { 12201e04c3fSmrg EXPANSION_MODE_IGNORE_DEFINED, 12301e04c3fSmrg EXPANSION_MODE_EVALUATE_DEFINED 12401e04c3fSmrg} expansion_mode_t; 12501e04c3fSmrg 12601e04c3fSmrg/* Expand list, and begin lexing from the result (after first 12701e04c3fSmrg * prefixing a token of type 'head_token_type'). 12801e04c3fSmrg */ 12901e04c3fSmrgstatic void 13001e04c3fSmrg_glcpp_parser_expand_and_lex_from(glcpp_parser_t *parser, int head_token_type, 13101e04c3fSmrg token_list_t *list, expansion_mode_t mode); 13201e04c3fSmrg 13301e04c3fSmrg/* Perform macro expansion in-place on the given list. */ 13401e04c3fSmrgstatic void 13501e04c3fSmrg_glcpp_parser_expand_token_list(glcpp_parser_t *parser, token_list_t *list, 13601e04c3fSmrg expansion_mode_t mode); 13701e04c3fSmrg 13801e04c3fSmrgstatic void 13901e04c3fSmrg_glcpp_parser_print_expanded_token_list(glcpp_parser_t *parser, 14001e04c3fSmrg token_list_t *list); 14101e04c3fSmrg 14201e04c3fSmrgstatic void 14301e04c3fSmrg_glcpp_parser_skip_stack_push_if(glcpp_parser_t *parser, YYLTYPE *loc, 14401e04c3fSmrg int condition); 14501e04c3fSmrg 14601e04c3fSmrgstatic void 14701e04c3fSmrg_glcpp_parser_skip_stack_change_if(glcpp_parser_t *parser, YYLTYPE *loc, 14801e04c3fSmrg const char *type, int condition); 14901e04c3fSmrg 15001e04c3fSmrgstatic void 15101e04c3fSmrg_glcpp_parser_skip_stack_pop(glcpp_parser_t *parser, YYLTYPE *loc); 15201e04c3fSmrg 15301e04c3fSmrgstatic void 15401e04c3fSmrg_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version, 15501e04c3fSmrg const char *ident, bool explicitly_set); 15601e04c3fSmrg 15701e04c3fSmrgstatic int 15801e04c3fSmrgglcpp_parser_lex(YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser); 15901e04c3fSmrg 16001e04c3fSmrgstatic void 16101e04c3fSmrgglcpp_parser_lex_from(glcpp_parser_t *parser, token_list_t *list); 16201e04c3fSmrg 1637ec681f3Smrgstruct define_include { 1647ec681f3Smrg glcpp_parser_t *parser; 1657ec681f3Smrg YYLTYPE *loc; 1667ec681f3Smrg}; 1677ec681f3Smrg 1687ec681f3Smrgstatic void 1697ec681f3Smrgglcpp_parser_copy_defines(const void *key, void *data, void *closure); 1707ec681f3Smrg 17101e04c3fSmrgstatic void 17201e04c3fSmrgadd_builtin_define(glcpp_parser_t *parser, const char *name, int value); 17301e04c3fSmrg 17401e04c3fSmrg%} 17501e04c3fSmrg 17601e04c3fSmrg%pure-parser 17701e04c3fSmrg%error-verbose 17801e04c3fSmrg 17901e04c3fSmrg%locations 18001e04c3fSmrg%initial-action { 18101e04c3fSmrg @$.first_line = 1; 18201e04c3fSmrg @$.first_column = 1; 18301e04c3fSmrg @$.last_line = 1; 18401e04c3fSmrg @$.last_column = 1; 18501e04c3fSmrg @$.source = 0; 18601e04c3fSmrg} 18701e04c3fSmrg 18801e04c3fSmrg%parse-param {glcpp_parser_t *parser} 18901e04c3fSmrg%lex-param {glcpp_parser_t *parser} 19001e04c3fSmrg 19101e04c3fSmrg%expect 0 19201e04c3fSmrg 19301e04c3fSmrg /* We use HASH_TOKEN, DEFINE_TOKEN and VERSION_TOKEN (as opposed to 19401e04c3fSmrg * HASH, DEFINE, and VERSION) to avoid conflicts with other symbols, 19501e04c3fSmrg * (such as the <HASH> and <DEFINE> start conditions in the lexer). */ 1967ec681f3Smrg%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 PATH INCLUDE 19701e04c3fSmrg%token PASTE 19801e04c3fSmrg%type <ival> INTEGER operator SPACE integer_constant version_constant 19901e04c3fSmrg%type <expression_value> expression 2007ec681f3Smrg%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER ERROR_TOKEN PRAGMA PATH INCLUDE 20101e04c3fSmrg%type <string_list> identifier_list 20201e04c3fSmrg%type <token> preprocessing_token 20301e04c3fSmrg%type <token_list> pp_tokens replacement_list text_line 20401e04c3fSmrg%left OR 20501e04c3fSmrg%left AND 20601e04c3fSmrg%left '|' 20701e04c3fSmrg%left '^' 20801e04c3fSmrg%left '&' 20901e04c3fSmrg%left EQUAL NOT_EQUAL 21001e04c3fSmrg%left '<' '>' LESS_OR_EQUAL GREATER_OR_EQUAL 21101e04c3fSmrg%left LEFT_SHIFT RIGHT_SHIFT 21201e04c3fSmrg%left '+' '-' 21301e04c3fSmrg%left '*' '/' '%' 21401e04c3fSmrg%right UNARY 21501e04c3fSmrg 21601e04c3fSmrg%debug 21701e04c3fSmrg 21801e04c3fSmrg%% 21901e04c3fSmrg 22001e04c3fSmrginput: 22101e04c3fSmrg /* empty */ 22201e04c3fSmrg| input line 22301e04c3fSmrg; 22401e04c3fSmrg 22501e04c3fSmrgline: 22601e04c3fSmrg control_line 22701e04c3fSmrg| SPACE control_line 22801e04c3fSmrg| text_line { 22901e04c3fSmrg _glcpp_parser_print_expanded_token_list (parser, $1); 23001e04c3fSmrg _mesa_string_buffer_append_char(parser->output, '\n'); 23101e04c3fSmrg } 23201e04c3fSmrg| expanded_line 23301e04c3fSmrg; 23401e04c3fSmrg 23501e04c3fSmrgexpanded_line: 23601e04c3fSmrg IF_EXPANDED expression NEWLINE { 23701e04c3fSmrg if (parser->is_gles && $2.undefined_macro) 23801e04c3fSmrg glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro); 23901e04c3fSmrg _glcpp_parser_skip_stack_push_if (parser, & @1, $2.value); 24001e04c3fSmrg } 24101e04c3fSmrg| ELIF_EXPANDED expression NEWLINE { 24201e04c3fSmrg if (parser->is_gles && $2.undefined_macro) 24301e04c3fSmrg glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $2.undefined_macro); 24401e04c3fSmrg _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2.value); 24501e04c3fSmrg } 24601e04c3fSmrg| LINE_EXPANDED integer_constant NEWLINE { 24701e04c3fSmrg parser->has_new_line_number = 1; 24801e04c3fSmrg parser->new_line_number = $2; 24901e04c3fSmrg _mesa_string_buffer_printf(parser->output, "#line %" PRIiMAX "\n", $2); 25001e04c3fSmrg } 25101e04c3fSmrg| LINE_EXPANDED integer_constant integer_constant NEWLINE { 25201e04c3fSmrg parser->has_new_line_number = 1; 25301e04c3fSmrg parser->new_line_number = $2; 25401e04c3fSmrg parser->has_new_source_number = 1; 25501e04c3fSmrg parser->new_source_number = $3; 25601e04c3fSmrg _mesa_string_buffer_printf(parser->output, 25701e04c3fSmrg "#line %" PRIiMAX " %" PRIiMAX "\n", 25801e04c3fSmrg $2, $3); 25901e04c3fSmrg } 2607ec681f3Smrg| LINE_EXPANDED integer_constant PATH NEWLINE { 2617ec681f3Smrg parser->has_new_line_number = 1; 2627ec681f3Smrg parser->new_line_number = $2; 2637ec681f3Smrg _mesa_string_buffer_printf(parser->output, 2647ec681f3Smrg "#line %" PRIiMAX " %s\n", 2657ec681f3Smrg $2, $3); 2667ec681f3Smrg } 26701e04c3fSmrg; 26801e04c3fSmrg 26901e04c3fSmrgdefine: 27001e04c3fSmrg OBJ_IDENTIFIER replacement_list NEWLINE { 27101e04c3fSmrg _define_object_macro (parser, & @1, $1, $2); 27201e04c3fSmrg } 27301e04c3fSmrg| FUNC_IDENTIFIER '(' ')' replacement_list NEWLINE { 27401e04c3fSmrg _define_function_macro (parser, & @1, $1, NULL, $4); 27501e04c3fSmrg } 27601e04c3fSmrg| FUNC_IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE { 27701e04c3fSmrg _define_function_macro (parser, & @1, $1, $3, $5); 27801e04c3fSmrg } 27901e04c3fSmrg; 28001e04c3fSmrg 28101e04c3fSmrgcontrol_line: 28201e04c3fSmrg control_line_success { 28301e04c3fSmrg _mesa_string_buffer_append_char(parser->output, '\n'); 28401e04c3fSmrg } 28501e04c3fSmrg| control_line_error 28601e04c3fSmrg| HASH_TOKEN LINE pp_tokens NEWLINE { 28701e04c3fSmrg 28801e04c3fSmrg if (parser->skip_stack == NULL || 28901e04c3fSmrg parser->skip_stack->type == SKIP_NO_SKIP) 29001e04c3fSmrg { 29101e04c3fSmrg _glcpp_parser_expand_and_lex_from (parser, 29201e04c3fSmrg LINE_EXPANDED, $3, 29301e04c3fSmrg EXPANSION_MODE_IGNORE_DEFINED); 29401e04c3fSmrg } 29501e04c3fSmrg } 29601e04c3fSmrg; 29701e04c3fSmrg 29801e04c3fSmrgcontrol_line_success: 29901e04c3fSmrg HASH_TOKEN DEFINE_TOKEN define 30001e04c3fSmrg| HASH_TOKEN UNDEF IDENTIFIER NEWLINE { 30101e04c3fSmrg struct hash_entry *entry; 30201e04c3fSmrg 30301e04c3fSmrg /* Section 3.4 (Preprocessor) of the GLSL ES 3.00 spec says: 30401e04c3fSmrg * 30501e04c3fSmrg * It is an error to undefine or to redefine a built-in 30601e04c3fSmrg * (pre-defined) macro name. 30701e04c3fSmrg * 30801e04c3fSmrg * The GLSL ES 1.00 spec does not contain this text, but 30901e04c3fSmrg * dEQP's preprocess test in GLES2 checks for it. 31001e04c3fSmrg * 31101e04c3fSmrg * Section 3.3 (Preprocessor) revision 7, of the GLSL 4.50 31201e04c3fSmrg * spec says: 31301e04c3fSmrg * 31401e04c3fSmrg * By convention, all macro names containing two consecutive 31501e04c3fSmrg * underscores ( __ ) are reserved for use by underlying 31601e04c3fSmrg * software layers. Defining or undefining such a name 31701e04c3fSmrg * in a shader does not itself result in an error, but may 31801e04c3fSmrg * result in unintended behaviors that stem from having 31901e04c3fSmrg * multiple definitions of the same name. All macro names 32001e04c3fSmrg * prefixed with "GL_" (...) are also reseved, and defining 32101e04c3fSmrg * such a name results in a compile-time error. 32201e04c3fSmrg * 32301e04c3fSmrg * The code below implements the same checks as GLSLang. 32401e04c3fSmrg */ 32501e04c3fSmrg if (strncmp("GL_", $3, 3) == 0) 32601e04c3fSmrg glcpp_error(& @1, parser, "Built-in (pre-defined)" 32701e04c3fSmrg " names beginning with GL_ cannot be undefined."); 32801e04c3fSmrg else if (strstr($3, "__") != NULL) { 32901e04c3fSmrg if (parser->is_gles 33001e04c3fSmrg && parser->version >= 300 33101e04c3fSmrg && (strcmp("__LINE__", $3) == 0 33201e04c3fSmrg || strcmp("__FILE__", $3) == 0 33301e04c3fSmrg || strcmp("__VERSION__", $3) == 0)) { 33401e04c3fSmrg glcpp_error(& @1, parser, "Built-in (pre-defined)" 33501e04c3fSmrg " names cannot be undefined."); 33601e04c3fSmrg } else if (parser->is_gles && parser->version <= 300) { 33701e04c3fSmrg glcpp_error(& @1, parser, 33801e04c3fSmrg " names containing consecutive underscores" 33901e04c3fSmrg " are reserved."); 34001e04c3fSmrg } else { 34101e04c3fSmrg glcpp_warning(& @1, parser, 34201e04c3fSmrg " names containing consecutive underscores" 34301e04c3fSmrg " are reserved."); 34401e04c3fSmrg } 34501e04c3fSmrg } 34601e04c3fSmrg 34701e04c3fSmrg entry = _mesa_hash_table_search (parser->defines, $3); 34801e04c3fSmrg if (entry) { 34901e04c3fSmrg _mesa_hash_table_remove (parser->defines, entry); 35001e04c3fSmrg } 35101e04c3fSmrg } 3527ec681f3Smrg| HASH_TOKEN INCLUDE NEWLINE { 3537ec681f3Smrg size_t include_cursor = _mesa_get_shader_include_cursor(parser->gl_ctx->Shared); 3547ec681f3Smrg 3557ec681f3Smrg /* Remove leading and trailing "" or <> */ 3567ec681f3Smrg char *start = strchr($2, '"'); 3577ec681f3Smrg if (!start) { 3587ec681f3Smrg _mesa_set_shader_include_cursor(parser->gl_ctx->Shared, 0); 3597ec681f3Smrg start = strchr($2, '<'); 3607ec681f3Smrg } 3617ec681f3Smrg char *path = strndup(start + 1, strlen(start + 1) - 1); 3627ec681f3Smrg 3637ec681f3Smrg const char *shader = 3647ec681f3Smrg _mesa_lookup_shader_include(parser->gl_ctx, path, false); 3657ec681f3Smrg free(path); 3667ec681f3Smrg 3677ec681f3Smrg if (!shader) 3687ec681f3Smrg glcpp_error(&@1, parser, "%s not found", $2); 3697ec681f3Smrg else { 3707ec681f3Smrg /* Create a temporary parser with the same settings */ 3717ec681f3Smrg glcpp_parser_t *tmp_parser = 3727ec681f3Smrg glcpp_parser_create(parser->gl_ctx, parser->extensions, parser->state); 3737ec681f3Smrg tmp_parser->version_set = true; 3747ec681f3Smrg tmp_parser->version = parser->version; 3757ec681f3Smrg 3767ec681f3Smrg /* Set the shader source and run the lexer */ 3777ec681f3Smrg glcpp_lex_set_source_string(tmp_parser, shader); 3787ec681f3Smrg 3797ec681f3Smrg /* Copy any existing define macros to the temporary 3807ec681f3Smrg * shade include parser. 3817ec681f3Smrg */ 3827ec681f3Smrg struct define_include di; 3837ec681f3Smrg di.parser = tmp_parser; 3847ec681f3Smrg di.loc = &@1; 3857ec681f3Smrg 3867ec681f3Smrg hash_table_call_foreach(parser->defines, 3877ec681f3Smrg glcpp_parser_copy_defines, 3887ec681f3Smrg &di); 3897ec681f3Smrg 3907ec681f3Smrg /* Print out '#include' to the glsl parser. We do this 3917ec681f3Smrg * so that it can do the error checking require to 3927ec681f3Smrg * make sure the ARB_shading_language_include 3937ec681f3Smrg * extension is enabled. 3947ec681f3Smrg */ 3957ec681f3Smrg _mesa_string_buffer_printf(parser->output, "#include\n"); 3967ec681f3Smrg 3977ec681f3Smrg /* Parse the include string before adding to the 3987ec681f3Smrg * preprocessor output. 3997ec681f3Smrg */ 4007ec681f3Smrg glcpp_parser_parse(tmp_parser); 4017ec681f3Smrg _mesa_string_buffer_printf(parser->info_log, "%s", 4027ec681f3Smrg tmp_parser->info_log->buf); 4037ec681f3Smrg _mesa_string_buffer_printf(parser->output, "%s", 4047ec681f3Smrg tmp_parser->output->buf); 4057ec681f3Smrg 4067ec681f3Smrg /* Copy any new define macros to the parent parser 4077ec681f3Smrg * and steal the memory of our temp parser so we don't 4087ec681f3Smrg * free these new defines before they are no longer 4097ec681f3Smrg * needed. 4107ec681f3Smrg */ 4117ec681f3Smrg di.parser = parser; 4127ec681f3Smrg di.loc = &@1; 4137ec681f3Smrg ralloc_steal(parser, tmp_parser); 4147ec681f3Smrg 4157ec681f3Smrg hash_table_call_foreach(tmp_parser->defines, 4167ec681f3Smrg glcpp_parser_copy_defines, 4177ec681f3Smrg &di); 4187ec681f3Smrg 4197ec681f3Smrg /* Destroy tmp parser memory we no longer need */ 4207ec681f3Smrg glcpp_lex_destroy(tmp_parser->scanner); 4217ec681f3Smrg _mesa_hash_table_destroy(tmp_parser->defines, NULL); 4227ec681f3Smrg } 4237ec681f3Smrg 4247ec681f3Smrg _mesa_set_shader_include_cursor(parser->gl_ctx->Shared, include_cursor); 4257ec681f3Smrg } 42601e04c3fSmrg| HASH_TOKEN IF pp_tokens NEWLINE { 42701e04c3fSmrg /* Be careful to only evaluate the 'if' expression if 42801e04c3fSmrg * we are not skipping. When we are skipping, we 42901e04c3fSmrg * simply push a new 0-valued 'if' onto the skip 43001e04c3fSmrg * stack. 43101e04c3fSmrg * 43201e04c3fSmrg * This avoids generating diagnostics for invalid 43301e04c3fSmrg * expressions that are being skipped. */ 43401e04c3fSmrg if (parser->skip_stack == NULL || 43501e04c3fSmrg parser->skip_stack->type == SKIP_NO_SKIP) 43601e04c3fSmrg { 43701e04c3fSmrg _glcpp_parser_expand_and_lex_from (parser, 43801e04c3fSmrg IF_EXPANDED, $3, 43901e04c3fSmrg EXPANSION_MODE_EVALUATE_DEFINED); 44001e04c3fSmrg } 44101e04c3fSmrg else 44201e04c3fSmrg { 44301e04c3fSmrg _glcpp_parser_skip_stack_push_if (parser, & @1, 0); 44401e04c3fSmrg parser->skip_stack->type = SKIP_TO_ENDIF; 44501e04c3fSmrg } 44601e04c3fSmrg } 44701e04c3fSmrg| HASH_TOKEN IF NEWLINE { 44801e04c3fSmrg /* #if without an expression is only an error if we 44901e04c3fSmrg * are not skipping */ 45001e04c3fSmrg if (parser->skip_stack == NULL || 45101e04c3fSmrg parser->skip_stack->type == SKIP_NO_SKIP) 45201e04c3fSmrg { 45301e04c3fSmrg glcpp_error(& @1, parser, "#if with no expression"); 45401e04c3fSmrg } 45501e04c3fSmrg _glcpp_parser_skip_stack_push_if (parser, & @1, 0); 45601e04c3fSmrg } 45701e04c3fSmrg| HASH_TOKEN IFDEF IDENTIFIER junk NEWLINE { 45801e04c3fSmrg struct hash_entry *entry = 45901e04c3fSmrg _mesa_hash_table_search(parser->defines, $3); 46001e04c3fSmrg macro_t *macro = entry ? entry->data : NULL; 46101e04c3fSmrg _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL); 46201e04c3fSmrg } 46301e04c3fSmrg| HASH_TOKEN IFNDEF IDENTIFIER junk NEWLINE { 46401e04c3fSmrg struct hash_entry *entry = 46501e04c3fSmrg _mesa_hash_table_search(parser->defines, $3); 46601e04c3fSmrg macro_t *macro = entry ? entry->data : NULL; 46701e04c3fSmrg _glcpp_parser_skip_stack_push_if (parser, & @3, macro == NULL); 46801e04c3fSmrg } 46901e04c3fSmrg| HASH_TOKEN ELIF pp_tokens NEWLINE { 47001e04c3fSmrg /* Be careful to only evaluate the 'elif' expression 47101e04c3fSmrg * if we are not skipping. When we are skipping, we 47201e04c3fSmrg * simply change to a 0-valued 'elif' on the skip 47301e04c3fSmrg * stack. 47401e04c3fSmrg * 47501e04c3fSmrg * This avoids generating diagnostics for invalid 47601e04c3fSmrg * expressions that are being skipped. */ 47701e04c3fSmrg if (parser->skip_stack && 47801e04c3fSmrg parser->skip_stack->type == SKIP_TO_ELSE) 47901e04c3fSmrg { 48001e04c3fSmrg _glcpp_parser_expand_and_lex_from (parser, 48101e04c3fSmrg ELIF_EXPANDED, $3, 48201e04c3fSmrg EXPANSION_MODE_EVALUATE_DEFINED); 48301e04c3fSmrg } 48401e04c3fSmrg else if (parser->skip_stack && 48501e04c3fSmrg parser->skip_stack->has_else) 48601e04c3fSmrg { 48701e04c3fSmrg glcpp_error(& @1, parser, "#elif after #else"); 48801e04c3fSmrg } 48901e04c3fSmrg else 49001e04c3fSmrg { 49101e04c3fSmrg _glcpp_parser_skip_stack_change_if (parser, & @1, 49201e04c3fSmrg "elif", 0); 49301e04c3fSmrg } 49401e04c3fSmrg } 49501e04c3fSmrg| HASH_TOKEN ELIF NEWLINE { 49601e04c3fSmrg /* #elif without an expression is an error unless we 49701e04c3fSmrg * are skipping. */ 49801e04c3fSmrg if (parser->skip_stack && 49901e04c3fSmrg parser->skip_stack->type == SKIP_TO_ELSE) 50001e04c3fSmrg { 50101e04c3fSmrg glcpp_error(& @1, parser, "#elif with no expression"); 50201e04c3fSmrg } 50301e04c3fSmrg else if (parser->skip_stack && 50401e04c3fSmrg parser->skip_stack->has_else) 50501e04c3fSmrg { 50601e04c3fSmrg glcpp_error(& @1, parser, "#elif after #else"); 50701e04c3fSmrg } 50801e04c3fSmrg else 50901e04c3fSmrg { 51001e04c3fSmrg _glcpp_parser_skip_stack_change_if (parser, & @1, 51101e04c3fSmrg "elif", 0); 51201e04c3fSmrg glcpp_warning(& @1, parser, "ignoring illegal #elif without expression"); 51301e04c3fSmrg } 51401e04c3fSmrg } 51501e04c3fSmrg| HASH_TOKEN ELSE { parser->lexing_directive = 1; } NEWLINE { 51601e04c3fSmrg if (parser->skip_stack && 51701e04c3fSmrg parser->skip_stack->has_else) 51801e04c3fSmrg { 51901e04c3fSmrg glcpp_error(& @1, parser, "multiple #else"); 52001e04c3fSmrg } 52101e04c3fSmrg else 52201e04c3fSmrg { 52301e04c3fSmrg _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1); 52401e04c3fSmrg if (parser->skip_stack) 52501e04c3fSmrg parser->skip_stack->has_else = true; 52601e04c3fSmrg } 52701e04c3fSmrg } 52801e04c3fSmrg| HASH_TOKEN ENDIF { 52901e04c3fSmrg _glcpp_parser_skip_stack_pop (parser, & @1); 53001e04c3fSmrg } NEWLINE 53101e04c3fSmrg| HASH_TOKEN VERSION_TOKEN version_constant NEWLINE { 53201e04c3fSmrg if (parser->version_set) { 53301e04c3fSmrg glcpp_error(& @1, parser, "#version must appear on the first line"); 53401e04c3fSmrg } 53501e04c3fSmrg _glcpp_parser_handle_version_declaration(parser, $3, NULL, true); 53601e04c3fSmrg } 53701e04c3fSmrg| HASH_TOKEN VERSION_TOKEN version_constant IDENTIFIER NEWLINE { 53801e04c3fSmrg if (parser->version_set) { 53901e04c3fSmrg glcpp_error(& @1, parser, "#version must appear on the first line"); 54001e04c3fSmrg } 54101e04c3fSmrg _glcpp_parser_handle_version_declaration(parser, $3, $4, true); 54201e04c3fSmrg } 54301e04c3fSmrg| HASH_TOKEN NEWLINE { 54401e04c3fSmrg glcpp_parser_resolve_implicit_version(parser); 54501e04c3fSmrg } 54601e04c3fSmrg| HASH_TOKEN PRAGMA NEWLINE { 54701e04c3fSmrg _mesa_string_buffer_printf(parser->output, "#%s", $2); 54801e04c3fSmrg } 54901e04c3fSmrg; 55001e04c3fSmrg 55101e04c3fSmrgcontrol_line_error: 55201e04c3fSmrg HASH_TOKEN ERROR_TOKEN NEWLINE { 55301e04c3fSmrg glcpp_error(& @1, parser, "#%s", $2); 55401e04c3fSmrg } 55501e04c3fSmrg| HASH_TOKEN DEFINE_TOKEN NEWLINE { 55601e04c3fSmrg glcpp_error (& @1, parser, "#define without macro name"); 55701e04c3fSmrg } 55801e04c3fSmrg| HASH_TOKEN GARBAGE pp_tokens NEWLINE { 55901e04c3fSmrg glcpp_error (& @1, parser, "Illegal non-directive after #"); 56001e04c3fSmrg } 56101e04c3fSmrg; 56201e04c3fSmrg 56301e04c3fSmrginteger_constant: 56401e04c3fSmrg INTEGER_STRING { 56501e04c3fSmrg /* let strtoll detect the base */ 56601e04c3fSmrg $$ = strtoll ($1, NULL, 0); 56701e04c3fSmrg } 56801e04c3fSmrg| INTEGER { 56901e04c3fSmrg $$ = $1; 57001e04c3fSmrg } 57101e04c3fSmrg 57201e04c3fSmrgversion_constant: 57301e04c3fSmrg INTEGER_STRING { 57401e04c3fSmrg /* Both octal and hexadecimal constants begin with 0. */ 57501e04c3fSmrg if ($1[0] == '0' && $1[1] != '\0') { 57601e04c3fSmrg glcpp_error(&@1, parser, "invalid #version \"%s\" (not a decimal constant)", $1); 57701e04c3fSmrg $$ = 0; 57801e04c3fSmrg } else { 57901e04c3fSmrg $$ = strtoll($1, NULL, 10); 58001e04c3fSmrg } 58101e04c3fSmrg } 58201e04c3fSmrg 58301e04c3fSmrgexpression: 58401e04c3fSmrg integer_constant { 58501e04c3fSmrg $$.value = $1; 58601e04c3fSmrg $$.undefined_macro = NULL; 58701e04c3fSmrg } 58801e04c3fSmrg| IDENTIFIER { 58901e04c3fSmrg $$.value = 0; 59001e04c3fSmrg if (parser->is_gles) 59101e04c3fSmrg $$.undefined_macro = linear_strdup(parser->linalloc, $1); 59201e04c3fSmrg else 59301e04c3fSmrg $$.undefined_macro = NULL; 59401e04c3fSmrg } 59501e04c3fSmrg| expression OR expression { 59601e04c3fSmrg $$.value = $1.value || $3.value; 59701e04c3fSmrg 59801e04c3fSmrg /* Short-circuit: Only flag undefined from right side 59901e04c3fSmrg * if left side evaluates to false. 60001e04c3fSmrg */ 60101e04c3fSmrg if ($1.undefined_macro) 60201e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 60301e04c3fSmrg else if (! $1.value) 60401e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 60501e04c3fSmrg } 60601e04c3fSmrg| expression AND expression { 60701e04c3fSmrg $$.value = $1.value && $3.value; 60801e04c3fSmrg 60901e04c3fSmrg /* Short-circuit: Only flag undefined from right-side 61001e04c3fSmrg * if left side evaluates to true. 61101e04c3fSmrg */ 61201e04c3fSmrg if ($1.undefined_macro) 61301e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 61401e04c3fSmrg else if ($1.value) 61501e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 61601e04c3fSmrg } 61701e04c3fSmrg| expression '|' expression { 61801e04c3fSmrg $$.value = $1.value | $3.value; 61901e04c3fSmrg if ($1.undefined_macro) 62001e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 62101e04c3fSmrg else 62201e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 62301e04c3fSmrg } 62401e04c3fSmrg| expression '^' expression { 62501e04c3fSmrg $$.value = $1.value ^ $3.value; 62601e04c3fSmrg if ($1.undefined_macro) 62701e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 62801e04c3fSmrg else 62901e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 63001e04c3fSmrg } 63101e04c3fSmrg| expression '&' expression { 63201e04c3fSmrg $$.value = $1.value & $3.value; 63301e04c3fSmrg if ($1.undefined_macro) 63401e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 63501e04c3fSmrg else 63601e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 63701e04c3fSmrg } 63801e04c3fSmrg| expression NOT_EQUAL expression { 63901e04c3fSmrg $$.value = $1.value != $3.value; 64001e04c3fSmrg if ($1.undefined_macro) 64101e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 64201e04c3fSmrg else 64301e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 64401e04c3fSmrg } 64501e04c3fSmrg| expression EQUAL expression { 64601e04c3fSmrg $$.value = $1.value == $3.value; 64701e04c3fSmrg if ($1.undefined_macro) 64801e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 64901e04c3fSmrg else 65001e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 65101e04c3fSmrg } 65201e04c3fSmrg| expression GREATER_OR_EQUAL expression { 65301e04c3fSmrg $$.value = $1.value >= $3.value; 65401e04c3fSmrg if ($1.undefined_macro) 65501e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 65601e04c3fSmrg else 65701e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 65801e04c3fSmrg } 65901e04c3fSmrg| expression LESS_OR_EQUAL expression { 66001e04c3fSmrg $$.value = $1.value <= $3.value; 66101e04c3fSmrg if ($1.undefined_macro) 66201e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 66301e04c3fSmrg else 66401e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 66501e04c3fSmrg } 66601e04c3fSmrg| expression '>' expression { 66701e04c3fSmrg $$.value = $1.value > $3.value; 66801e04c3fSmrg if ($1.undefined_macro) 66901e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 67001e04c3fSmrg else 67101e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 67201e04c3fSmrg } 67301e04c3fSmrg| expression '<' expression { 67401e04c3fSmrg $$.value = $1.value < $3.value; 67501e04c3fSmrg if ($1.undefined_macro) 67601e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 67701e04c3fSmrg else 67801e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 67901e04c3fSmrg } 68001e04c3fSmrg| expression RIGHT_SHIFT expression { 68101e04c3fSmrg $$.value = $1.value >> $3.value; 68201e04c3fSmrg if ($1.undefined_macro) 68301e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 68401e04c3fSmrg else 68501e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 68601e04c3fSmrg } 68701e04c3fSmrg| expression LEFT_SHIFT expression { 68801e04c3fSmrg $$.value = $1.value << $3.value; 68901e04c3fSmrg if ($1.undefined_macro) 69001e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 69101e04c3fSmrg else 69201e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 69301e04c3fSmrg } 69401e04c3fSmrg| expression '-' expression { 69501e04c3fSmrg $$.value = $1.value - $3.value; 69601e04c3fSmrg if ($1.undefined_macro) 69701e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 69801e04c3fSmrg else 69901e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 70001e04c3fSmrg } 70101e04c3fSmrg| expression '+' expression { 70201e04c3fSmrg $$.value = $1.value + $3.value; 70301e04c3fSmrg if ($1.undefined_macro) 70401e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 70501e04c3fSmrg else 70601e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 70701e04c3fSmrg } 70801e04c3fSmrg| expression '%' expression { 70901e04c3fSmrg if ($3.value == 0) { 71001e04c3fSmrg yyerror (& @1, parser, 71101e04c3fSmrg "zero modulus in preprocessor directive"); 71201e04c3fSmrg } else { 71301e04c3fSmrg $$.value = $1.value % $3.value; 71401e04c3fSmrg } 71501e04c3fSmrg if ($1.undefined_macro) 71601e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 71701e04c3fSmrg else 71801e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 71901e04c3fSmrg } 72001e04c3fSmrg| expression '/' expression { 72101e04c3fSmrg if ($3.value == 0) { 72201e04c3fSmrg yyerror (& @1, parser, 72301e04c3fSmrg "division by 0 in preprocessor directive"); 72401e04c3fSmrg } else { 72501e04c3fSmrg $$.value = $1.value / $3.value; 72601e04c3fSmrg } 72701e04c3fSmrg if ($1.undefined_macro) 72801e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 72901e04c3fSmrg else 73001e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 73101e04c3fSmrg } 73201e04c3fSmrg| expression '*' expression { 73301e04c3fSmrg $$.value = $1.value * $3.value; 73401e04c3fSmrg if ($1.undefined_macro) 73501e04c3fSmrg $$.undefined_macro = $1.undefined_macro; 73601e04c3fSmrg else 73701e04c3fSmrg $$.undefined_macro = $3.undefined_macro; 73801e04c3fSmrg } 73901e04c3fSmrg| '!' expression %prec UNARY { 74001e04c3fSmrg $$.value = ! $2.value; 74101e04c3fSmrg $$.undefined_macro = $2.undefined_macro; 74201e04c3fSmrg } 74301e04c3fSmrg| '~' expression %prec UNARY { 74401e04c3fSmrg $$.value = ~ $2.value; 74501e04c3fSmrg $$.undefined_macro = $2.undefined_macro; 74601e04c3fSmrg } 74701e04c3fSmrg| '-' expression %prec UNARY { 74801e04c3fSmrg $$.value = - $2.value; 74901e04c3fSmrg $$.undefined_macro = $2.undefined_macro; 75001e04c3fSmrg } 75101e04c3fSmrg| '+' expression %prec UNARY { 75201e04c3fSmrg $$.value = + $2.value; 75301e04c3fSmrg $$.undefined_macro = $2.undefined_macro; 75401e04c3fSmrg } 75501e04c3fSmrg| '(' expression ')' { 75601e04c3fSmrg $$ = $2; 75701e04c3fSmrg } 75801e04c3fSmrg; 75901e04c3fSmrg 76001e04c3fSmrgidentifier_list: 76101e04c3fSmrg IDENTIFIER { 76201e04c3fSmrg $$ = _string_list_create (parser); 76301e04c3fSmrg _string_list_append_item (parser, $$, $1); 76401e04c3fSmrg } 76501e04c3fSmrg| identifier_list ',' IDENTIFIER { 76601e04c3fSmrg $$ = $1; 76701e04c3fSmrg _string_list_append_item (parser, $$, $3); 76801e04c3fSmrg } 76901e04c3fSmrg; 77001e04c3fSmrg 77101e04c3fSmrgtext_line: 77201e04c3fSmrg NEWLINE { $$ = NULL; } 77301e04c3fSmrg| pp_tokens NEWLINE 77401e04c3fSmrg; 77501e04c3fSmrg 77601e04c3fSmrgreplacement_list: 77701e04c3fSmrg /* empty */ { $$ = NULL; } 77801e04c3fSmrg| pp_tokens 77901e04c3fSmrg; 78001e04c3fSmrg 78101e04c3fSmrgjunk: 78201e04c3fSmrg /* empty */ 78301e04c3fSmrg| pp_tokens { 7847ec681f3Smrg if (parser->gl_ctx->Const.AllowExtraPPTokens) 7857ec681f3Smrg glcpp_warning(&@1, parser, "extra tokens at end of directive"); 7867ec681f3Smrg else 7877ec681f3Smrg glcpp_error(&@1, parser, "extra tokens at end of directive"); 78801e04c3fSmrg } 78901e04c3fSmrg; 79001e04c3fSmrg 79101e04c3fSmrgpp_tokens: 79201e04c3fSmrg preprocessing_token { 79301e04c3fSmrg parser->space_tokens = 1; 79401e04c3fSmrg $$ = _token_list_create (parser); 79501e04c3fSmrg _token_list_append (parser, $$, $1); 79601e04c3fSmrg } 79701e04c3fSmrg| pp_tokens preprocessing_token { 79801e04c3fSmrg $$ = $1; 79901e04c3fSmrg _token_list_append (parser, $$, $2); 80001e04c3fSmrg } 80101e04c3fSmrg; 80201e04c3fSmrg 80301e04c3fSmrgpreprocessing_token: 80401e04c3fSmrg IDENTIFIER { 80501e04c3fSmrg $$ = _token_create_str (parser, IDENTIFIER, $1); 80601e04c3fSmrg $$->location = yylloc; 80701e04c3fSmrg } 80801e04c3fSmrg| INTEGER_STRING { 80901e04c3fSmrg $$ = _token_create_str (parser, INTEGER_STRING, $1); 81001e04c3fSmrg $$->location = yylloc; 81101e04c3fSmrg } 8127ec681f3Smrg| PATH { 8137ec681f3Smrg $$ = _token_create_str (parser, PATH, $1); 8147ec681f3Smrg $$->location = yylloc; 8157ec681f3Smrg } 81601e04c3fSmrg| operator { 81701e04c3fSmrg $$ = _token_create_ival (parser, $1, $1); 81801e04c3fSmrg $$->location = yylloc; 81901e04c3fSmrg } 82001e04c3fSmrg| DEFINED { 82101e04c3fSmrg $$ = _token_create_ival (parser, DEFINED, DEFINED); 82201e04c3fSmrg $$->location = yylloc; 82301e04c3fSmrg } 82401e04c3fSmrg| OTHER { 82501e04c3fSmrg $$ = _token_create_str (parser, OTHER, $1); 82601e04c3fSmrg $$->location = yylloc; 82701e04c3fSmrg } 82801e04c3fSmrg| SPACE { 82901e04c3fSmrg $$ = _token_create_ival (parser, SPACE, SPACE); 83001e04c3fSmrg $$->location = yylloc; 83101e04c3fSmrg } 83201e04c3fSmrg; 83301e04c3fSmrg 83401e04c3fSmrgoperator: 83501e04c3fSmrg '[' { $$ = '['; } 83601e04c3fSmrg| ']' { $$ = ']'; } 83701e04c3fSmrg| '(' { $$ = '('; } 83801e04c3fSmrg| ')' { $$ = ')'; } 83901e04c3fSmrg| '{' { $$ = '{'; } 84001e04c3fSmrg| '}' { $$ = '}'; } 84101e04c3fSmrg| '.' { $$ = '.'; } 84201e04c3fSmrg| '&' { $$ = '&'; } 84301e04c3fSmrg| '*' { $$ = '*'; } 84401e04c3fSmrg| '+' { $$ = '+'; } 84501e04c3fSmrg| '-' { $$ = '-'; } 84601e04c3fSmrg| '~' { $$ = '~'; } 84701e04c3fSmrg| '!' { $$ = '!'; } 84801e04c3fSmrg| '/' { $$ = '/'; } 84901e04c3fSmrg| '%' { $$ = '%'; } 85001e04c3fSmrg| LEFT_SHIFT { $$ = LEFT_SHIFT; } 85101e04c3fSmrg| RIGHT_SHIFT { $$ = RIGHT_SHIFT; } 85201e04c3fSmrg| '<' { $$ = '<'; } 85301e04c3fSmrg| '>' { $$ = '>'; } 85401e04c3fSmrg| LESS_OR_EQUAL { $$ = LESS_OR_EQUAL; } 85501e04c3fSmrg| GREATER_OR_EQUAL { $$ = GREATER_OR_EQUAL; } 85601e04c3fSmrg| EQUAL { $$ = EQUAL; } 85701e04c3fSmrg| NOT_EQUAL { $$ = NOT_EQUAL; } 85801e04c3fSmrg| '^' { $$ = '^'; } 85901e04c3fSmrg| '|' { $$ = '|'; } 86001e04c3fSmrg| AND { $$ = AND; } 86101e04c3fSmrg| OR { $$ = OR; } 86201e04c3fSmrg| ';' { $$ = ';'; } 86301e04c3fSmrg| ',' { $$ = ','; } 86401e04c3fSmrg| '=' { $$ = '='; } 86501e04c3fSmrg| PASTE { $$ = PASTE; } 86601e04c3fSmrg| PLUS_PLUS { $$ = PLUS_PLUS; } 86701e04c3fSmrg| MINUS_MINUS { $$ = MINUS_MINUS; } 86801e04c3fSmrg; 86901e04c3fSmrg 87001e04c3fSmrg%% 87101e04c3fSmrg 87201e04c3fSmrgstring_list_t * 87301e04c3fSmrg_string_list_create(glcpp_parser_t *parser) 87401e04c3fSmrg{ 87501e04c3fSmrg string_list_t *list; 87601e04c3fSmrg 87701e04c3fSmrg list = linear_alloc_child(parser->linalloc, sizeof(string_list_t)); 87801e04c3fSmrg list->head = NULL; 87901e04c3fSmrg list->tail = NULL; 88001e04c3fSmrg 88101e04c3fSmrg return list; 88201e04c3fSmrg} 88301e04c3fSmrg 88401e04c3fSmrgvoid 88501e04c3fSmrg_string_list_append_item(glcpp_parser_t *parser, string_list_t *list, 88601e04c3fSmrg const char *str) 88701e04c3fSmrg{ 88801e04c3fSmrg string_node_t *node; 88901e04c3fSmrg 89001e04c3fSmrg node = linear_alloc_child(parser->linalloc, sizeof(string_node_t)); 89101e04c3fSmrg node->str = linear_strdup(parser->linalloc, str); 89201e04c3fSmrg 89301e04c3fSmrg node->next = NULL; 89401e04c3fSmrg 89501e04c3fSmrg if (list->head == NULL) { 89601e04c3fSmrg list->head = node; 89701e04c3fSmrg } else { 89801e04c3fSmrg list->tail->next = node; 89901e04c3fSmrg } 90001e04c3fSmrg 90101e04c3fSmrg list->tail = node; 90201e04c3fSmrg} 90301e04c3fSmrg 90401e04c3fSmrgint 90501e04c3fSmrg_string_list_contains(string_list_t *list, const char *member, int *index) 90601e04c3fSmrg{ 90701e04c3fSmrg string_node_t *node; 90801e04c3fSmrg int i; 90901e04c3fSmrg 91001e04c3fSmrg if (list == NULL) 91101e04c3fSmrg return 0; 91201e04c3fSmrg 91301e04c3fSmrg for (i = 0, node = list->head; node; i++, node = node->next) { 91401e04c3fSmrg if (strcmp (node->str, member) == 0) { 91501e04c3fSmrg if (index) 91601e04c3fSmrg *index = i; 91701e04c3fSmrg return 1; 91801e04c3fSmrg } 91901e04c3fSmrg } 92001e04c3fSmrg 92101e04c3fSmrg return 0; 92201e04c3fSmrg} 92301e04c3fSmrg 92401e04c3fSmrg/* Return duplicate string in list (if any), NULL otherwise. */ 92501e04c3fSmrgconst char * 92601e04c3fSmrg_string_list_has_duplicate(string_list_t *list) 92701e04c3fSmrg{ 92801e04c3fSmrg string_node_t *node, *dup; 92901e04c3fSmrg 93001e04c3fSmrg if (list == NULL) 93101e04c3fSmrg return NULL; 93201e04c3fSmrg 93301e04c3fSmrg for (node = list->head; node; node = node->next) { 93401e04c3fSmrg for (dup = node->next; dup; dup = dup->next) { 93501e04c3fSmrg if (strcmp (node->str, dup->str) == 0) 93601e04c3fSmrg return node->str; 93701e04c3fSmrg } 93801e04c3fSmrg } 93901e04c3fSmrg 94001e04c3fSmrg return NULL; 94101e04c3fSmrg} 94201e04c3fSmrg 94301e04c3fSmrgint 94401e04c3fSmrg_string_list_length(string_list_t *list) 94501e04c3fSmrg{ 94601e04c3fSmrg int length = 0; 94701e04c3fSmrg string_node_t *node; 94801e04c3fSmrg 94901e04c3fSmrg if (list == NULL) 95001e04c3fSmrg return 0; 95101e04c3fSmrg 95201e04c3fSmrg for (node = list->head; node; node = node->next) 95301e04c3fSmrg length++; 95401e04c3fSmrg 95501e04c3fSmrg return length; 95601e04c3fSmrg} 95701e04c3fSmrg 95801e04c3fSmrgint 95901e04c3fSmrg_string_list_equal(string_list_t *a, string_list_t *b) 96001e04c3fSmrg{ 96101e04c3fSmrg string_node_t *node_a, *node_b; 96201e04c3fSmrg 96301e04c3fSmrg if (a == NULL && b == NULL) 96401e04c3fSmrg return 1; 96501e04c3fSmrg 96601e04c3fSmrg if (a == NULL || b == NULL) 96701e04c3fSmrg return 0; 96801e04c3fSmrg 96901e04c3fSmrg for (node_a = a->head, node_b = b->head; 97001e04c3fSmrg node_a && node_b; 97101e04c3fSmrg node_a = node_a->next, node_b = node_b->next) 97201e04c3fSmrg { 97301e04c3fSmrg if (strcmp (node_a->str, node_b->str)) 97401e04c3fSmrg return 0; 97501e04c3fSmrg } 97601e04c3fSmrg 97701e04c3fSmrg /* Catch the case of lists being different lengths, (which 97801e04c3fSmrg * would cause the loop above to terminate after the shorter 97901e04c3fSmrg * list). */ 98001e04c3fSmrg return node_a == node_b; 98101e04c3fSmrg} 98201e04c3fSmrg 98301e04c3fSmrgargument_list_t * 98401e04c3fSmrg_argument_list_create(glcpp_parser_t *parser) 98501e04c3fSmrg{ 98601e04c3fSmrg argument_list_t *list; 98701e04c3fSmrg 98801e04c3fSmrg list = linear_alloc_child(parser->linalloc, sizeof(argument_list_t)); 98901e04c3fSmrg list->head = NULL; 99001e04c3fSmrg list->tail = NULL; 99101e04c3fSmrg 99201e04c3fSmrg return list; 99301e04c3fSmrg} 99401e04c3fSmrg 99501e04c3fSmrgvoid 99601e04c3fSmrg_argument_list_append(glcpp_parser_t *parser, 99701e04c3fSmrg argument_list_t *list, token_list_t *argument) 99801e04c3fSmrg{ 99901e04c3fSmrg argument_node_t *node; 100001e04c3fSmrg 100101e04c3fSmrg node = linear_alloc_child(parser->linalloc, sizeof(argument_node_t)); 100201e04c3fSmrg node->argument = argument; 100301e04c3fSmrg 100401e04c3fSmrg node->next = NULL; 100501e04c3fSmrg 100601e04c3fSmrg if (list->head == NULL) { 100701e04c3fSmrg list->head = node; 100801e04c3fSmrg } else { 100901e04c3fSmrg list->tail->next = node; 101001e04c3fSmrg } 101101e04c3fSmrg 101201e04c3fSmrg list->tail = node; 101301e04c3fSmrg} 101401e04c3fSmrg 101501e04c3fSmrgint 101601e04c3fSmrg_argument_list_length(argument_list_t *list) 101701e04c3fSmrg{ 101801e04c3fSmrg int length = 0; 101901e04c3fSmrg argument_node_t *node; 102001e04c3fSmrg 102101e04c3fSmrg if (list == NULL) 102201e04c3fSmrg return 0; 102301e04c3fSmrg 102401e04c3fSmrg for (node = list->head; node; node = node->next) 102501e04c3fSmrg length++; 102601e04c3fSmrg 102701e04c3fSmrg return length; 102801e04c3fSmrg} 102901e04c3fSmrg 103001e04c3fSmrgtoken_list_t * 103101e04c3fSmrg_argument_list_member_at(argument_list_t *list, int index) 103201e04c3fSmrg{ 103301e04c3fSmrg argument_node_t *node; 103401e04c3fSmrg int i; 103501e04c3fSmrg 103601e04c3fSmrg if (list == NULL) 103701e04c3fSmrg return NULL; 103801e04c3fSmrg 103901e04c3fSmrg node = list->head; 104001e04c3fSmrg for (i = 0; i < index; i++) { 104101e04c3fSmrg node = node->next; 104201e04c3fSmrg if (node == NULL) 104301e04c3fSmrg break; 104401e04c3fSmrg } 104501e04c3fSmrg 104601e04c3fSmrg if (node) 104701e04c3fSmrg return node->argument; 104801e04c3fSmrg 104901e04c3fSmrg return NULL; 105001e04c3fSmrg} 105101e04c3fSmrg 105201e04c3fSmrgtoken_t * 105301e04c3fSmrg_token_create_str(glcpp_parser_t *parser, int type, char *str) 105401e04c3fSmrg{ 105501e04c3fSmrg token_t *token; 105601e04c3fSmrg 105701e04c3fSmrg token = linear_alloc_child(parser->linalloc, sizeof(token_t)); 105801e04c3fSmrg token->type = type; 105901e04c3fSmrg token->value.str = str; 10607ec681f3Smrg token->expanding = false; 106101e04c3fSmrg 106201e04c3fSmrg return token; 106301e04c3fSmrg} 106401e04c3fSmrg 106501e04c3fSmrgtoken_t * 106601e04c3fSmrg_token_create_ival(glcpp_parser_t *parser, int type, int ival) 106701e04c3fSmrg{ 106801e04c3fSmrg token_t *token; 106901e04c3fSmrg 107001e04c3fSmrg token = linear_alloc_child(parser->linalloc, sizeof(token_t)); 107101e04c3fSmrg token->type = type; 107201e04c3fSmrg token->value.ival = ival; 10737ec681f3Smrg token->expanding = false; 107401e04c3fSmrg 107501e04c3fSmrg return token; 107601e04c3fSmrg} 107701e04c3fSmrg 107801e04c3fSmrgtoken_list_t * 107901e04c3fSmrg_token_list_create(glcpp_parser_t *parser) 108001e04c3fSmrg{ 108101e04c3fSmrg token_list_t *list; 108201e04c3fSmrg 108301e04c3fSmrg list = linear_alloc_child(parser->linalloc, sizeof(token_list_t)); 108401e04c3fSmrg list->head = NULL; 108501e04c3fSmrg list->tail = NULL; 108601e04c3fSmrg list->non_space_tail = NULL; 108701e04c3fSmrg 108801e04c3fSmrg return list; 108901e04c3fSmrg} 109001e04c3fSmrg 109101e04c3fSmrgvoid 109201e04c3fSmrg_token_list_append(glcpp_parser_t *parser, token_list_t *list, token_t *token) 109301e04c3fSmrg{ 109401e04c3fSmrg token_node_t *node; 109501e04c3fSmrg 109601e04c3fSmrg node = linear_alloc_child(parser->linalloc, sizeof(token_node_t)); 109701e04c3fSmrg node->token = token; 109801e04c3fSmrg node->next = NULL; 109901e04c3fSmrg 110001e04c3fSmrg if (list->head == NULL) { 110101e04c3fSmrg list->head = node; 110201e04c3fSmrg } else { 110301e04c3fSmrg list->tail->next = node; 110401e04c3fSmrg } 110501e04c3fSmrg 110601e04c3fSmrg list->tail = node; 110701e04c3fSmrg if (token->type != SPACE) 110801e04c3fSmrg list->non_space_tail = node; 110901e04c3fSmrg} 111001e04c3fSmrg 111101e04c3fSmrgvoid 111201e04c3fSmrg_token_list_append_list(token_list_t *list, token_list_t *tail) 111301e04c3fSmrg{ 111401e04c3fSmrg if (tail == NULL || tail->head == NULL) 111501e04c3fSmrg return; 111601e04c3fSmrg 111701e04c3fSmrg if (list->head == NULL) { 111801e04c3fSmrg list->head = tail->head; 111901e04c3fSmrg } else { 112001e04c3fSmrg list->tail->next = tail->head; 112101e04c3fSmrg } 112201e04c3fSmrg 112301e04c3fSmrg list->tail = tail->tail; 112401e04c3fSmrg list->non_space_tail = tail->non_space_tail; 112501e04c3fSmrg} 112601e04c3fSmrg 112701e04c3fSmrgstatic token_list_t * 112801e04c3fSmrg_token_list_copy(glcpp_parser_t *parser, token_list_t *other) 112901e04c3fSmrg{ 113001e04c3fSmrg token_list_t *copy; 113101e04c3fSmrg token_node_t *node; 113201e04c3fSmrg 113301e04c3fSmrg if (other == NULL) 113401e04c3fSmrg return NULL; 113501e04c3fSmrg 113601e04c3fSmrg copy = _token_list_create (parser); 113701e04c3fSmrg for (node = other->head; node; node = node->next) { 113801e04c3fSmrg token_t *new_token = linear_alloc_child(parser->linalloc, sizeof(token_t)); 113901e04c3fSmrg *new_token = *node->token; 114001e04c3fSmrg _token_list_append (parser, copy, new_token); 114101e04c3fSmrg } 114201e04c3fSmrg 114301e04c3fSmrg return copy; 114401e04c3fSmrg} 114501e04c3fSmrg 114601e04c3fSmrgstatic void 114701e04c3fSmrg_token_list_trim_trailing_space(token_list_t *list) 114801e04c3fSmrg{ 114901e04c3fSmrg if (list->non_space_tail) { 115001e04c3fSmrg list->non_space_tail->next = NULL; 115101e04c3fSmrg list->tail = list->non_space_tail; 115201e04c3fSmrg } 115301e04c3fSmrg} 115401e04c3fSmrg 115501e04c3fSmrgstatic int 115601e04c3fSmrg_token_list_is_empty_ignoring_space(token_list_t *l) 115701e04c3fSmrg{ 115801e04c3fSmrg token_node_t *n; 115901e04c3fSmrg 116001e04c3fSmrg if (l == NULL) 116101e04c3fSmrg return 1; 116201e04c3fSmrg 116301e04c3fSmrg n = l->head; 116401e04c3fSmrg while (n != NULL && n->token->type == SPACE) 116501e04c3fSmrg n = n->next; 116601e04c3fSmrg 116701e04c3fSmrg return n == NULL; 116801e04c3fSmrg} 116901e04c3fSmrg 117001e04c3fSmrgint 117101e04c3fSmrg_token_list_equal_ignoring_space(token_list_t *a, token_list_t *b) 117201e04c3fSmrg{ 117301e04c3fSmrg token_node_t *node_a, *node_b; 117401e04c3fSmrg 117501e04c3fSmrg if (a == NULL || b == NULL) { 117601e04c3fSmrg int a_empty = _token_list_is_empty_ignoring_space(a); 117701e04c3fSmrg int b_empty = _token_list_is_empty_ignoring_space(b); 117801e04c3fSmrg return a_empty == b_empty; 117901e04c3fSmrg } 118001e04c3fSmrg 118101e04c3fSmrg node_a = a->head; 118201e04c3fSmrg node_b = b->head; 118301e04c3fSmrg 118401e04c3fSmrg while (1) 118501e04c3fSmrg { 118601e04c3fSmrg if (node_a == NULL && node_b == NULL) 118701e04c3fSmrg break; 118801e04c3fSmrg 118901e04c3fSmrg /* Ignore trailing whitespace */ 119001e04c3fSmrg if (node_a == NULL && node_b->token->type == SPACE) { 119101e04c3fSmrg while (node_b && node_b->token->type == SPACE) 119201e04c3fSmrg node_b = node_b->next; 119301e04c3fSmrg } 119401e04c3fSmrg 11957ec681f3Smrg if (node_a == NULL && node_b == NULL) 11967ec681f3Smrg break; 11977ec681f3Smrg 119801e04c3fSmrg if (node_b == NULL && node_a->token->type == SPACE) { 119901e04c3fSmrg while (node_a && node_a->token->type == SPACE) 120001e04c3fSmrg node_a = node_a->next; 120101e04c3fSmrg } 120201e04c3fSmrg 120301e04c3fSmrg if (node_a == NULL && node_b == NULL) 120401e04c3fSmrg break; 120501e04c3fSmrg 120601e04c3fSmrg if (node_a == NULL || node_b == NULL) 120701e04c3fSmrg return 0; 120801e04c3fSmrg /* Make sure whitespace appears in the same places in both. 120901e04c3fSmrg * It need not be exactly the same amount of whitespace, 121001e04c3fSmrg * though. 121101e04c3fSmrg */ 121201e04c3fSmrg if (node_a->token->type == SPACE && node_b->token->type == SPACE) { 121301e04c3fSmrg while (node_a && node_a->token->type == SPACE) 121401e04c3fSmrg node_a = node_a->next; 121501e04c3fSmrg while (node_b && node_b->token->type == SPACE) 121601e04c3fSmrg node_b = node_b->next; 121701e04c3fSmrg continue; 121801e04c3fSmrg } 121901e04c3fSmrg 122001e04c3fSmrg if (node_a->token->type != node_b->token->type) 122101e04c3fSmrg return 0; 122201e04c3fSmrg 122301e04c3fSmrg switch (node_a->token->type) { 122401e04c3fSmrg case INTEGER: 122501e04c3fSmrg if (node_a->token->value.ival != node_b->token->value.ival) { 122601e04c3fSmrg return 0; 122701e04c3fSmrg } 122801e04c3fSmrg break; 122901e04c3fSmrg case IDENTIFIER: 123001e04c3fSmrg case INTEGER_STRING: 123101e04c3fSmrg case OTHER: 123201e04c3fSmrg if (strcmp(node_a->token->value.str, node_b->token->value.str)) { 123301e04c3fSmrg return 0; 123401e04c3fSmrg } 123501e04c3fSmrg break; 123601e04c3fSmrg } 123701e04c3fSmrg 123801e04c3fSmrg node_a = node_a->next; 123901e04c3fSmrg node_b = node_b->next; 124001e04c3fSmrg } 124101e04c3fSmrg 124201e04c3fSmrg return 1; 124301e04c3fSmrg} 124401e04c3fSmrg 124501e04c3fSmrgstatic void 124601e04c3fSmrg_token_print(struct _mesa_string_buffer *out, token_t *token) 124701e04c3fSmrg{ 124801e04c3fSmrg if (token->type < 256) { 124901e04c3fSmrg _mesa_string_buffer_append_char(out, token->type); 125001e04c3fSmrg return; 125101e04c3fSmrg } 125201e04c3fSmrg 125301e04c3fSmrg switch (token->type) { 125401e04c3fSmrg case INTEGER: 125501e04c3fSmrg _mesa_string_buffer_printf(out, "%" PRIiMAX, token->value.ival); 125601e04c3fSmrg break; 125701e04c3fSmrg case IDENTIFIER: 125801e04c3fSmrg case INTEGER_STRING: 12597ec681f3Smrg case PATH: 126001e04c3fSmrg case OTHER: 126101e04c3fSmrg _mesa_string_buffer_append(out, token->value.str); 126201e04c3fSmrg break; 126301e04c3fSmrg case SPACE: 126401e04c3fSmrg _mesa_string_buffer_append_char(out, ' '); 126501e04c3fSmrg break; 126601e04c3fSmrg case LEFT_SHIFT: 126701e04c3fSmrg _mesa_string_buffer_append(out, "<<"); 126801e04c3fSmrg break; 126901e04c3fSmrg case RIGHT_SHIFT: 127001e04c3fSmrg _mesa_string_buffer_append(out, ">>"); 127101e04c3fSmrg break; 127201e04c3fSmrg case LESS_OR_EQUAL: 127301e04c3fSmrg _mesa_string_buffer_append(out, "<="); 127401e04c3fSmrg break; 127501e04c3fSmrg case GREATER_OR_EQUAL: 127601e04c3fSmrg _mesa_string_buffer_append(out, ">="); 127701e04c3fSmrg break; 127801e04c3fSmrg case EQUAL: 127901e04c3fSmrg _mesa_string_buffer_append(out, "=="); 128001e04c3fSmrg break; 128101e04c3fSmrg case NOT_EQUAL: 128201e04c3fSmrg _mesa_string_buffer_append(out, "!="); 128301e04c3fSmrg break; 128401e04c3fSmrg case AND: 128501e04c3fSmrg _mesa_string_buffer_append(out, "&&"); 128601e04c3fSmrg break; 128701e04c3fSmrg case OR: 128801e04c3fSmrg _mesa_string_buffer_append(out, "||"); 128901e04c3fSmrg break; 129001e04c3fSmrg case PASTE: 129101e04c3fSmrg _mesa_string_buffer_append(out, "##"); 129201e04c3fSmrg break; 129301e04c3fSmrg case PLUS_PLUS: 129401e04c3fSmrg _mesa_string_buffer_append(out, "++"); 129501e04c3fSmrg break; 129601e04c3fSmrg case MINUS_MINUS: 129701e04c3fSmrg _mesa_string_buffer_append(out, "--"); 129801e04c3fSmrg break; 129901e04c3fSmrg case DEFINED: 130001e04c3fSmrg _mesa_string_buffer_append(out, "defined"); 130101e04c3fSmrg break; 130201e04c3fSmrg case PLACEHOLDER: 130301e04c3fSmrg /* Nothing to print. */ 130401e04c3fSmrg break; 130501e04c3fSmrg default: 130601e04c3fSmrg assert(!"Error: Don't know how to print token."); 130701e04c3fSmrg 130801e04c3fSmrg break; 130901e04c3fSmrg } 131001e04c3fSmrg} 131101e04c3fSmrg 131201e04c3fSmrg/* Return a new token formed by pasting 'token' and 'other'. Note that this 131301e04c3fSmrg * function may return 'token' or 'other' directly rather than allocating 131401e04c3fSmrg * anything new. 131501e04c3fSmrg * 131601e04c3fSmrg * Caution: Only very cursory error-checking is performed to see if 131701e04c3fSmrg * the final result is a valid single token. */ 131801e04c3fSmrgstatic token_t * 131901e04c3fSmrg_token_paste(glcpp_parser_t *parser, token_t *token, token_t *other) 132001e04c3fSmrg{ 132101e04c3fSmrg token_t *combined = NULL; 132201e04c3fSmrg 132301e04c3fSmrg /* Pasting a placeholder onto anything makes no change. */ 132401e04c3fSmrg if (other->type == PLACEHOLDER) 132501e04c3fSmrg return token; 132601e04c3fSmrg 132701e04c3fSmrg /* When 'token' is a placeholder, just return 'other'. */ 132801e04c3fSmrg if (token->type == PLACEHOLDER) 132901e04c3fSmrg return other; 133001e04c3fSmrg 133101e04c3fSmrg /* A very few single-character punctuators can be combined 133201e04c3fSmrg * with another to form a multi-character punctuator. */ 133301e04c3fSmrg switch (token->type) { 133401e04c3fSmrg case '<': 133501e04c3fSmrg if (other->type == '<') 133601e04c3fSmrg combined = _token_create_ival (parser, LEFT_SHIFT, LEFT_SHIFT); 133701e04c3fSmrg else if (other->type == '=') 133801e04c3fSmrg combined = _token_create_ival (parser, LESS_OR_EQUAL, LESS_OR_EQUAL); 133901e04c3fSmrg break; 134001e04c3fSmrg case '>': 134101e04c3fSmrg if (other->type == '>') 134201e04c3fSmrg combined = _token_create_ival (parser, RIGHT_SHIFT, RIGHT_SHIFT); 134301e04c3fSmrg else if (other->type == '=') 134401e04c3fSmrg combined = _token_create_ival (parser, GREATER_OR_EQUAL, GREATER_OR_EQUAL); 134501e04c3fSmrg break; 134601e04c3fSmrg case '=': 134701e04c3fSmrg if (other->type == '=') 134801e04c3fSmrg combined = _token_create_ival (parser, EQUAL, EQUAL); 134901e04c3fSmrg break; 135001e04c3fSmrg case '!': 135101e04c3fSmrg if (other->type == '=') 135201e04c3fSmrg combined = _token_create_ival (parser, NOT_EQUAL, NOT_EQUAL); 135301e04c3fSmrg break; 135401e04c3fSmrg case '&': 135501e04c3fSmrg if (other->type == '&') 135601e04c3fSmrg combined = _token_create_ival (parser, AND, AND); 135701e04c3fSmrg break; 135801e04c3fSmrg case '|': 135901e04c3fSmrg if (other->type == '|') 136001e04c3fSmrg combined = _token_create_ival (parser, OR, OR); 136101e04c3fSmrg break; 136201e04c3fSmrg } 136301e04c3fSmrg 136401e04c3fSmrg if (combined != NULL) { 136501e04c3fSmrg /* Inherit the location from the first token */ 136601e04c3fSmrg combined->location = token->location; 136701e04c3fSmrg return combined; 136801e04c3fSmrg } 136901e04c3fSmrg 137001e04c3fSmrg /* Two string-valued (or integer) tokens can usually just be 137101e04c3fSmrg * mashed together. (We also handle a string followed by an 137201e04c3fSmrg * integer here as well.) 137301e04c3fSmrg * 137401e04c3fSmrg * There are some exceptions here. Notably, if the first token 137501e04c3fSmrg * is an integer (or a string representing an integer), then 137601e04c3fSmrg * the second token must also be an integer or must be a 137701e04c3fSmrg * string representing an integer that begins with a digit. 137801e04c3fSmrg */ 137901e04c3fSmrg if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING || token->type == INTEGER) && 138001e04c3fSmrg (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING || other->type == INTEGER)) 138101e04c3fSmrg { 138201e04c3fSmrg char *str; 138301e04c3fSmrg int combined_type; 138401e04c3fSmrg 138501e04c3fSmrg /* Check that pasting onto an integer doesn't create a 138601e04c3fSmrg * non-integer, (that is, only digits can be 138701e04c3fSmrg * pasted. */ 138801e04c3fSmrg if (token->type == INTEGER_STRING || token->type == INTEGER) { 138901e04c3fSmrg switch (other->type) { 139001e04c3fSmrg case INTEGER_STRING: 139101e04c3fSmrg if (other->value.str[0] < '0' || other->value.str[0] > '9') 139201e04c3fSmrg goto FAIL; 139301e04c3fSmrg break; 139401e04c3fSmrg case INTEGER: 139501e04c3fSmrg if (other->value.ival < 0) 139601e04c3fSmrg goto FAIL; 139701e04c3fSmrg break; 139801e04c3fSmrg default: 139901e04c3fSmrg goto FAIL; 140001e04c3fSmrg } 140101e04c3fSmrg } 140201e04c3fSmrg 140301e04c3fSmrg if (token->type == INTEGER) 140401e04c3fSmrg str = linear_asprintf(parser->linalloc, "%" PRIiMAX, token->value.ival); 140501e04c3fSmrg else 140601e04c3fSmrg str = linear_strdup(parser->linalloc, token->value.str); 140701e04c3fSmrg 140801e04c3fSmrg if (other->type == INTEGER) 140901e04c3fSmrg linear_asprintf_append(parser->linalloc, &str, "%" PRIiMAX, other->value.ival); 141001e04c3fSmrg else 141101e04c3fSmrg linear_strcat(parser->linalloc, &str, other->value.str); 141201e04c3fSmrg 141301e04c3fSmrg /* New token is same type as original token, unless we 141401e04c3fSmrg * started with an integer, in which case we will be 141501e04c3fSmrg * creating an integer-string. */ 141601e04c3fSmrg combined_type = token->type; 141701e04c3fSmrg if (combined_type == INTEGER) 141801e04c3fSmrg combined_type = INTEGER_STRING; 141901e04c3fSmrg 142001e04c3fSmrg combined = _token_create_str (parser, combined_type, str); 142101e04c3fSmrg combined->location = token->location; 142201e04c3fSmrg return combined; 142301e04c3fSmrg } 142401e04c3fSmrg 142501e04c3fSmrg FAIL: 142601e04c3fSmrg glcpp_error (&token->location, parser, ""); 142701e04c3fSmrg _mesa_string_buffer_append(parser->info_log, "Pasting \""); 142801e04c3fSmrg _token_print(parser->info_log, token); 142901e04c3fSmrg _mesa_string_buffer_append(parser->info_log, "\" and \""); 143001e04c3fSmrg _token_print(parser->info_log, other); 143101e04c3fSmrg _mesa_string_buffer_append(parser->info_log, "\" does not give a valid preprocessing token.\n"); 143201e04c3fSmrg 143301e04c3fSmrg return token; 143401e04c3fSmrg} 143501e04c3fSmrg 143601e04c3fSmrgstatic void 143701e04c3fSmrg_token_list_print(glcpp_parser_t *parser, token_list_t *list) 143801e04c3fSmrg{ 143901e04c3fSmrg token_node_t *node; 144001e04c3fSmrg 144101e04c3fSmrg if (list == NULL) 144201e04c3fSmrg return; 144301e04c3fSmrg 144401e04c3fSmrg for (node = list->head; node; node = node->next) 144501e04c3fSmrg _token_print(parser->output, node->token); 144601e04c3fSmrg} 144701e04c3fSmrg 144801e04c3fSmrgvoid 144901e04c3fSmrgyyerror(YYLTYPE *locp, glcpp_parser_t *parser, const char *error) 145001e04c3fSmrg{ 145101e04c3fSmrg glcpp_error(locp, parser, "%s", error); 145201e04c3fSmrg} 145301e04c3fSmrg 145401e04c3fSmrgstatic void 145501e04c3fSmrgadd_builtin_define(glcpp_parser_t *parser, const char *name, int value) 145601e04c3fSmrg{ 145701e04c3fSmrg token_t *tok; 145801e04c3fSmrg token_list_t *list; 145901e04c3fSmrg 146001e04c3fSmrg tok = _token_create_ival (parser, INTEGER, value); 146101e04c3fSmrg 146201e04c3fSmrg list = _token_list_create(parser); 146301e04c3fSmrg _token_list_append(parser, list, tok); 146401e04c3fSmrg _define_object_macro(parser, NULL, name, list); 146501e04c3fSmrg} 146601e04c3fSmrg 146701e04c3fSmrg/* Initial output buffer size, 4096 minus ralloc() overhead. It was selected 146801e04c3fSmrg * to minimize total amount of allocated memory during shader-db run. 146901e04c3fSmrg */ 147001e04c3fSmrg#define INITIAL_PP_OUTPUT_BUF_SIZE 4048 147101e04c3fSmrg 147201e04c3fSmrgglcpp_parser_t * 14737ec681f3Smrgglcpp_parser_create(struct gl_context *gl_ctx, 14747ec681f3Smrg glcpp_extension_iterator extensions, void *state) 147501e04c3fSmrg{ 147601e04c3fSmrg glcpp_parser_t *parser; 147701e04c3fSmrg 147801e04c3fSmrg parser = ralloc (NULL, glcpp_parser_t); 147901e04c3fSmrg 148001e04c3fSmrg glcpp_lex_init_extra (parser, &parser->scanner); 14817ec681f3Smrg parser->defines = _mesa_hash_table_create(NULL, _mesa_hash_string, 148201e04c3fSmrg _mesa_key_string_equal); 148301e04c3fSmrg parser->linalloc = linear_alloc_parent(parser, 0); 148401e04c3fSmrg parser->active = NULL; 148501e04c3fSmrg parser->lexing_directive = 0; 148601e04c3fSmrg parser->lexing_version_directive = 0; 148701e04c3fSmrg parser->space_tokens = 1; 148801e04c3fSmrg parser->last_token_was_newline = 0; 148901e04c3fSmrg parser->last_token_was_space = 0; 149001e04c3fSmrg parser->first_non_space_token_this_line = 1; 149101e04c3fSmrg parser->newline_as_space = 0; 149201e04c3fSmrg parser->in_control_line = 0; 149301e04c3fSmrg parser->paren_count = 0; 149401e04c3fSmrg parser->commented_newlines = 0; 149501e04c3fSmrg 149601e04c3fSmrg parser->skip_stack = NULL; 149701e04c3fSmrg parser->skipping = 0; 149801e04c3fSmrg 149901e04c3fSmrg parser->lex_from_list = NULL; 150001e04c3fSmrg parser->lex_from_node = NULL; 150101e04c3fSmrg 150201e04c3fSmrg parser->output = _mesa_string_buffer_create(parser, 150301e04c3fSmrg INITIAL_PP_OUTPUT_BUF_SIZE); 150401e04c3fSmrg parser->info_log = _mesa_string_buffer_create(parser, 150501e04c3fSmrg INITIAL_PP_OUTPUT_BUF_SIZE); 150601e04c3fSmrg parser->error = 0; 150701e04c3fSmrg 15087ec681f3Smrg parser->gl_ctx = gl_ctx; 150901e04c3fSmrg parser->extensions = extensions; 15107ec681f3Smrg parser->extension_list = &gl_ctx->Extensions; 151101e04c3fSmrg parser->state = state; 15127ec681f3Smrg parser->api = gl_ctx->API; 151301e04c3fSmrg parser->version = 0; 151401e04c3fSmrg parser->version_set = false; 151501e04c3fSmrg 151601e04c3fSmrg parser->has_new_line_number = 0; 151701e04c3fSmrg parser->new_line_number = 1; 151801e04c3fSmrg parser->has_new_source_number = 0; 151901e04c3fSmrg parser->new_source_number = 0; 152001e04c3fSmrg 152101e04c3fSmrg parser->is_gles = false; 152201e04c3fSmrg 152301e04c3fSmrg return parser; 152401e04c3fSmrg} 152501e04c3fSmrg 152601e04c3fSmrgvoid 152701e04c3fSmrgglcpp_parser_destroy(glcpp_parser_t *parser) 152801e04c3fSmrg{ 152901e04c3fSmrg glcpp_lex_destroy (parser->scanner); 153001e04c3fSmrg _mesa_hash_table_destroy(parser->defines, NULL); 153101e04c3fSmrg ralloc_free (parser); 153201e04c3fSmrg} 153301e04c3fSmrg 153401e04c3fSmrgtypedef enum function_status 153501e04c3fSmrg{ 153601e04c3fSmrg FUNCTION_STATUS_SUCCESS, 153701e04c3fSmrg FUNCTION_NOT_A_FUNCTION, 153801e04c3fSmrg FUNCTION_UNBALANCED_PARENTHESES 153901e04c3fSmrg} function_status_t; 154001e04c3fSmrg 154101e04c3fSmrg/* Find a set of function-like macro arguments by looking for a 154201e04c3fSmrg * balanced set of parentheses. 154301e04c3fSmrg * 154401e04c3fSmrg * When called, 'node' should be the opening-parenthesis token, (or 154501e04c3fSmrg * perhaps preceeding SPACE tokens). Upon successful return *last will 154601e04c3fSmrg * be the last consumed node, (corresponding to the closing right 154701e04c3fSmrg * parenthesis). 154801e04c3fSmrg * 154901e04c3fSmrg * Return values: 155001e04c3fSmrg * 155101e04c3fSmrg * FUNCTION_STATUS_SUCCESS: 155201e04c3fSmrg * 155301e04c3fSmrg * Successfully parsed a set of function arguments. 155401e04c3fSmrg * 155501e04c3fSmrg * FUNCTION_NOT_A_FUNCTION: 155601e04c3fSmrg * 155701e04c3fSmrg * Macro name not followed by a '('. This is not an error, but 155801e04c3fSmrg * simply that the macro name should be treated as a non-macro. 155901e04c3fSmrg * 156001e04c3fSmrg * FUNCTION_UNBALANCED_PARENTHESES 156101e04c3fSmrg * 156201e04c3fSmrg * Macro name is not followed by a balanced set of parentheses. 156301e04c3fSmrg */ 156401e04c3fSmrgstatic function_status_t 156501e04c3fSmrg_arguments_parse(glcpp_parser_t *parser, 156601e04c3fSmrg argument_list_t *arguments, token_node_t *node, 156701e04c3fSmrg token_node_t **last) 156801e04c3fSmrg{ 156901e04c3fSmrg token_list_t *argument; 157001e04c3fSmrg int paren_count; 157101e04c3fSmrg 157201e04c3fSmrg node = node->next; 157301e04c3fSmrg 157401e04c3fSmrg /* Ignore whitespace before first parenthesis. */ 157501e04c3fSmrg while (node && node->token->type == SPACE) 157601e04c3fSmrg node = node->next; 157701e04c3fSmrg 157801e04c3fSmrg if (node == NULL || node->token->type != '(') 157901e04c3fSmrg return FUNCTION_NOT_A_FUNCTION; 158001e04c3fSmrg 158101e04c3fSmrg node = node->next; 158201e04c3fSmrg 158301e04c3fSmrg argument = _token_list_create (parser); 158401e04c3fSmrg _argument_list_append (parser, arguments, argument); 158501e04c3fSmrg 158601e04c3fSmrg for (paren_count = 1; node; node = node->next) { 158701e04c3fSmrg if (node->token->type == '(') { 158801e04c3fSmrg paren_count++; 158901e04c3fSmrg } else if (node->token->type == ')') { 159001e04c3fSmrg paren_count--; 159101e04c3fSmrg if (paren_count == 0) 159201e04c3fSmrg break; 159301e04c3fSmrg } 159401e04c3fSmrg 159501e04c3fSmrg if (node->token->type == ',' && paren_count == 1) { 159601e04c3fSmrg _token_list_trim_trailing_space (argument); 159701e04c3fSmrg argument = _token_list_create (parser); 159801e04c3fSmrg _argument_list_append (parser, arguments, argument); 159901e04c3fSmrg } else { 160001e04c3fSmrg if (argument->head == NULL) { 160101e04c3fSmrg /* Don't treat initial whitespace as part of the argument. */ 160201e04c3fSmrg if (node->token->type == SPACE) 160301e04c3fSmrg continue; 160401e04c3fSmrg } 160501e04c3fSmrg _token_list_append(parser, argument, node->token); 160601e04c3fSmrg } 160701e04c3fSmrg } 160801e04c3fSmrg 160901e04c3fSmrg if (paren_count) 161001e04c3fSmrg return FUNCTION_UNBALANCED_PARENTHESES; 161101e04c3fSmrg 161201e04c3fSmrg *last = node; 161301e04c3fSmrg 161401e04c3fSmrg return FUNCTION_STATUS_SUCCESS; 161501e04c3fSmrg} 161601e04c3fSmrg 161701e04c3fSmrgstatic token_list_t * 161801e04c3fSmrg_token_list_create_with_one_ival(glcpp_parser_t *parser, int type, int ival) 161901e04c3fSmrg{ 162001e04c3fSmrg token_list_t *list; 162101e04c3fSmrg token_t *node; 162201e04c3fSmrg 162301e04c3fSmrg list = _token_list_create(parser); 162401e04c3fSmrg node = _token_create_ival(parser, type, ival); 162501e04c3fSmrg _token_list_append(parser, list, node); 162601e04c3fSmrg 162701e04c3fSmrg return list; 162801e04c3fSmrg} 162901e04c3fSmrg 163001e04c3fSmrgstatic token_list_t * 163101e04c3fSmrg_token_list_create_with_one_space(glcpp_parser_t *parser) 163201e04c3fSmrg{ 163301e04c3fSmrg return _token_list_create_with_one_ival(parser, SPACE, SPACE); 163401e04c3fSmrg} 163501e04c3fSmrg 163601e04c3fSmrgstatic token_list_t * 163701e04c3fSmrg_token_list_create_with_one_integer(glcpp_parser_t *parser, int ival) 163801e04c3fSmrg{ 163901e04c3fSmrg return _token_list_create_with_one_ival(parser, INTEGER, ival); 164001e04c3fSmrg} 164101e04c3fSmrg 164201e04c3fSmrg/* Evaluate a DEFINED token node (based on subsequent tokens in the list). 164301e04c3fSmrg * 164401e04c3fSmrg * Note: This function must only be called when "node" is a DEFINED token, 164501e04c3fSmrg * (and will abort with an assertion failure otherwise). 164601e04c3fSmrg * 164701e04c3fSmrg * If "node" is followed, (ignoring any SPACE tokens), by an IDENTIFIER token 164801e04c3fSmrg * (optionally preceded and followed by '(' and ')' tokens) then the following 164901e04c3fSmrg * occurs: 165001e04c3fSmrg * 165101e04c3fSmrg * If the identifier is a defined macro, this function returns 1. 165201e04c3fSmrg * 165301e04c3fSmrg * If the identifier is not a defined macro, this function returns 0. 165401e04c3fSmrg * 165501e04c3fSmrg * In either case, *last will be updated to the last node in the list 165601e04c3fSmrg * consumed by the evaluation, (either the token of the identifier or the 165701e04c3fSmrg * token of the closing parenthesis). 165801e04c3fSmrg * 165901e04c3fSmrg * In all other cases, (such as "node is the final node of the list", or 166001e04c3fSmrg * "missing closing parenthesis", etc.), this function generates a 166101e04c3fSmrg * preprocessor error, returns -1 and *last will not be set. 166201e04c3fSmrg */ 166301e04c3fSmrgstatic int 166401e04c3fSmrg_glcpp_parser_evaluate_defined(glcpp_parser_t *parser, token_node_t *node, 166501e04c3fSmrg token_node_t **last) 166601e04c3fSmrg{ 166701e04c3fSmrg token_node_t *argument, *defined = node; 166801e04c3fSmrg 166901e04c3fSmrg assert(node->token->type == DEFINED); 167001e04c3fSmrg 167101e04c3fSmrg node = node->next; 167201e04c3fSmrg 167301e04c3fSmrg /* Ignore whitespace after DEFINED token. */ 167401e04c3fSmrg while (node && node->token->type == SPACE) 167501e04c3fSmrg node = node->next; 167601e04c3fSmrg 167701e04c3fSmrg if (node == NULL) 167801e04c3fSmrg goto FAIL; 167901e04c3fSmrg 168001e04c3fSmrg if (node->token->type == IDENTIFIER || node->token->type == OTHER) { 168101e04c3fSmrg argument = node; 168201e04c3fSmrg } else if (node->token->type == '(') { 168301e04c3fSmrg node = node->next; 168401e04c3fSmrg 168501e04c3fSmrg /* Ignore whitespace after '(' token. */ 168601e04c3fSmrg while (node && node->token->type == SPACE) 168701e04c3fSmrg node = node->next; 168801e04c3fSmrg 168901e04c3fSmrg if (node == NULL || (node->token->type != IDENTIFIER && 169001e04c3fSmrg node->token->type != OTHER)) { 169101e04c3fSmrg goto FAIL; 169201e04c3fSmrg } 169301e04c3fSmrg 169401e04c3fSmrg argument = node; 169501e04c3fSmrg 169601e04c3fSmrg node = node->next; 169701e04c3fSmrg 169801e04c3fSmrg /* Ignore whitespace after identifier, before ')' token. */ 169901e04c3fSmrg while (node && node->token->type == SPACE) 170001e04c3fSmrg node = node->next; 170101e04c3fSmrg 170201e04c3fSmrg if (node == NULL || node->token->type != ')') 170301e04c3fSmrg goto FAIL; 170401e04c3fSmrg } else { 170501e04c3fSmrg goto FAIL; 170601e04c3fSmrg } 170701e04c3fSmrg 170801e04c3fSmrg *last = node; 170901e04c3fSmrg 171001e04c3fSmrg return _mesa_hash_table_search(parser->defines, 171101e04c3fSmrg argument->token->value.str) ? 1 : 0; 171201e04c3fSmrg 171301e04c3fSmrgFAIL: 171401e04c3fSmrg glcpp_error (&defined->token->location, parser, 171501e04c3fSmrg "\"defined\" not followed by an identifier"); 171601e04c3fSmrg return -1; 171701e04c3fSmrg} 171801e04c3fSmrg 171901e04c3fSmrg/* Evaluate all DEFINED nodes in a given list, modifying the list in place. 172001e04c3fSmrg */ 172101e04c3fSmrgstatic void 172201e04c3fSmrg_glcpp_parser_evaluate_defined_in_list(glcpp_parser_t *parser, 172301e04c3fSmrg token_list_t *list) 172401e04c3fSmrg{ 172501e04c3fSmrg token_node_t *node, *node_prev, *replacement, *last = NULL; 172601e04c3fSmrg int value; 172701e04c3fSmrg 172801e04c3fSmrg if (list == NULL) 172901e04c3fSmrg return; 173001e04c3fSmrg 173101e04c3fSmrg node_prev = NULL; 173201e04c3fSmrg node = list->head; 173301e04c3fSmrg 173401e04c3fSmrg while (node) { 173501e04c3fSmrg 173601e04c3fSmrg if (node->token->type != DEFINED) 173701e04c3fSmrg goto NEXT; 173801e04c3fSmrg 173901e04c3fSmrg value = _glcpp_parser_evaluate_defined (parser, node, &last); 174001e04c3fSmrg if (value == -1) 174101e04c3fSmrg goto NEXT; 174201e04c3fSmrg 174301e04c3fSmrg replacement = linear_alloc_child(parser->linalloc, sizeof(token_node_t)); 174401e04c3fSmrg replacement->token = _token_create_ival (parser, INTEGER, value); 174501e04c3fSmrg 174601e04c3fSmrg /* Splice replacement node into list, replacing from "node" 174701e04c3fSmrg * through "last". */ 174801e04c3fSmrg if (node_prev) 174901e04c3fSmrg node_prev->next = replacement; 175001e04c3fSmrg else 175101e04c3fSmrg list->head = replacement; 175201e04c3fSmrg replacement->next = last->next; 175301e04c3fSmrg if (last == list->tail) 175401e04c3fSmrg list->tail = replacement; 175501e04c3fSmrg 175601e04c3fSmrg node = replacement; 175701e04c3fSmrg 175801e04c3fSmrg NEXT: 175901e04c3fSmrg node_prev = node; 176001e04c3fSmrg node = node->next; 176101e04c3fSmrg } 176201e04c3fSmrg} 176301e04c3fSmrg 176401e04c3fSmrg/* Perform macro expansion on 'list', placing the resulting tokens 176501e04c3fSmrg * into a new list which is initialized with a first token of type 176601e04c3fSmrg * 'head_token_type'. Then begin lexing from the resulting list, 176701e04c3fSmrg * (return to the current lexing source when this list is exhausted). 176801e04c3fSmrg * 176901e04c3fSmrg * See the documentation of _glcpp_parser_expand_token_list for a description 177001e04c3fSmrg * of the "mode" parameter. 177101e04c3fSmrg */ 177201e04c3fSmrgstatic void 177301e04c3fSmrg_glcpp_parser_expand_and_lex_from(glcpp_parser_t *parser, int head_token_type, 177401e04c3fSmrg token_list_t *list, expansion_mode_t mode) 177501e04c3fSmrg{ 177601e04c3fSmrg token_list_t *expanded; 177701e04c3fSmrg token_t *token; 177801e04c3fSmrg 177901e04c3fSmrg expanded = _token_list_create (parser); 178001e04c3fSmrg token = _token_create_ival (parser, head_token_type, head_token_type); 178101e04c3fSmrg _token_list_append (parser, expanded, token); 178201e04c3fSmrg _glcpp_parser_expand_token_list (parser, list, mode); 178301e04c3fSmrg _token_list_append_list (expanded, list); 178401e04c3fSmrg glcpp_parser_lex_from (parser, expanded); 178501e04c3fSmrg} 178601e04c3fSmrg 178701e04c3fSmrgstatic void 178801e04c3fSmrg_glcpp_parser_apply_pastes(glcpp_parser_t *parser, token_list_t *list) 178901e04c3fSmrg{ 179001e04c3fSmrg token_node_t *node; 179101e04c3fSmrg 179201e04c3fSmrg node = list->head; 179301e04c3fSmrg while (node) { 179401e04c3fSmrg token_node_t *next_non_space; 179501e04c3fSmrg 179601e04c3fSmrg /* Look ahead for a PASTE token, skipping space. */ 179701e04c3fSmrg next_non_space = node->next; 179801e04c3fSmrg while (next_non_space && next_non_space->token->type == SPACE) 179901e04c3fSmrg next_non_space = next_non_space->next; 180001e04c3fSmrg 180101e04c3fSmrg if (next_non_space == NULL) 180201e04c3fSmrg break; 180301e04c3fSmrg 180401e04c3fSmrg if (next_non_space->token->type != PASTE) { 180501e04c3fSmrg node = next_non_space; 180601e04c3fSmrg continue; 180701e04c3fSmrg } 180801e04c3fSmrg 180901e04c3fSmrg /* Now find the next non-space token after the PASTE. */ 181001e04c3fSmrg next_non_space = next_non_space->next; 181101e04c3fSmrg while (next_non_space && next_non_space->token->type == SPACE) 181201e04c3fSmrg next_non_space = next_non_space->next; 181301e04c3fSmrg 181401e04c3fSmrg if (next_non_space == NULL) { 181501e04c3fSmrg yyerror(&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n"); 181601e04c3fSmrg return; 181701e04c3fSmrg } 181801e04c3fSmrg 181901e04c3fSmrg node->token = _token_paste(parser, node->token, next_non_space->token); 182001e04c3fSmrg node->next = next_non_space->next; 182101e04c3fSmrg if (next_non_space == list->tail) 182201e04c3fSmrg list->tail = node; 182301e04c3fSmrg } 182401e04c3fSmrg 182501e04c3fSmrg list->non_space_tail = list->tail; 182601e04c3fSmrg} 182701e04c3fSmrg 182801e04c3fSmrg/* This is a helper function that's essentially part of the 182901e04c3fSmrg * implementation of _glcpp_parser_expand_node. It shouldn't be called 183001e04c3fSmrg * except for by that function. 183101e04c3fSmrg * 183201e04c3fSmrg * Returns NULL if node is a simple token with no expansion, (that is, 183301e04c3fSmrg * although 'node' corresponds to an identifier defined as a 183401e04c3fSmrg * function-like macro, it is not followed with a parenthesized 183501e04c3fSmrg * argument list). 183601e04c3fSmrg * 183701e04c3fSmrg * Compute the complete expansion of node (which is a function-like 183801e04c3fSmrg * macro) and subsequent nodes which are arguments. 183901e04c3fSmrg * 184001e04c3fSmrg * Returns the token list that results from the expansion and sets 184101e04c3fSmrg * *last to the last node in the list that was consumed by the 184201e04c3fSmrg * expansion. Specifically, *last will be set as follows: as the 184301e04c3fSmrg * token of the closing right parenthesis. 184401e04c3fSmrg * 184501e04c3fSmrg * See the documentation of _glcpp_parser_expand_token_list for a description 184601e04c3fSmrg * of the "mode" parameter. 184701e04c3fSmrg */ 184801e04c3fSmrgstatic token_list_t * 184901e04c3fSmrg_glcpp_parser_expand_function(glcpp_parser_t *parser, token_node_t *node, 185001e04c3fSmrg token_node_t **last, expansion_mode_t mode) 185101e04c3fSmrg{ 185201e04c3fSmrg struct hash_entry *entry; 185301e04c3fSmrg macro_t *macro; 185401e04c3fSmrg const char *identifier; 185501e04c3fSmrg argument_list_t *arguments; 185601e04c3fSmrg function_status_t status; 185701e04c3fSmrg token_list_t *substituted; 185801e04c3fSmrg int parameter_index; 185901e04c3fSmrg 186001e04c3fSmrg identifier = node->token->value.str; 186101e04c3fSmrg 186201e04c3fSmrg entry = _mesa_hash_table_search(parser->defines, identifier); 186301e04c3fSmrg macro = entry ? entry->data : NULL; 186401e04c3fSmrg 186501e04c3fSmrg assert(macro->is_function); 186601e04c3fSmrg 186701e04c3fSmrg arguments = _argument_list_create(parser); 186801e04c3fSmrg status = _arguments_parse(parser, arguments, node, last); 186901e04c3fSmrg 187001e04c3fSmrg switch (status) { 187101e04c3fSmrg case FUNCTION_STATUS_SUCCESS: 187201e04c3fSmrg break; 187301e04c3fSmrg case FUNCTION_NOT_A_FUNCTION: 187401e04c3fSmrg return NULL; 187501e04c3fSmrg case FUNCTION_UNBALANCED_PARENTHESES: 187601e04c3fSmrg glcpp_error(&node->token->location, parser, "Macro %s call has unbalanced parentheses\n", identifier); 187701e04c3fSmrg return NULL; 187801e04c3fSmrg } 187901e04c3fSmrg 188001e04c3fSmrg /* Replace a macro defined as empty with a SPACE token. */ 188101e04c3fSmrg if (macro->replacements == NULL) { 188201e04c3fSmrg return _token_list_create_with_one_space(parser); 188301e04c3fSmrg } 188401e04c3fSmrg 188501e04c3fSmrg if (!((_argument_list_length (arguments) == 188601e04c3fSmrg _string_list_length (macro->parameters)) || 188701e04c3fSmrg (_string_list_length (macro->parameters) == 0 && 188801e04c3fSmrg _argument_list_length (arguments) == 1 && 188901e04c3fSmrg arguments->head->argument->head == NULL))) { 189001e04c3fSmrg glcpp_error(&node->token->location, parser, 189101e04c3fSmrg "Error: macro %s invoked with %d arguments (expected %d)\n", 189201e04c3fSmrg identifier, _argument_list_length (arguments), 189301e04c3fSmrg _string_list_length(macro->parameters)); 189401e04c3fSmrg return NULL; 189501e04c3fSmrg } 189601e04c3fSmrg 189701e04c3fSmrg /* Perform argument substitution on the replacement list. */ 189801e04c3fSmrg substituted = _token_list_create(parser); 189901e04c3fSmrg 190001e04c3fSmrg for (node = macro->replacements->head; node; node = node->next) { 190101e04c3fSmrg if (node->token->type == IDENTIFIER && 190201e04c3fSmrg _string_list_contains(macro->parameters, node->token->value.str, 190301e04c3fSmrg ¶meter_index)) { 190401e04c3fSmrg token_list_t *argument; 190501e04c3fSmrg argument = _argument_list_member_at(arguments, parameter_index); 190601e04c3fSmrg /* Before substituting, we expand the argument tokens, or append a 190701e04c3fSmrg * placeholder token for an empty argument. */ 190801e04c3fSmrg if (argument->head) { 190901e04c3fSmrg token_list_t *expanded_argument; 191001e04c3fSmrg expanded_argument = _token_list_copy(parser, argument); 191101e04c3fSmrg _glcpp_parser_expand_token_list(parser, expanded_argument, mode); 191201e04c3fSmrg _token_list_append_list(substituted, expanded_argument); 191301e04c3fSmrg } else { 191401e04c3fSmrg token_t *new_token; 191501e04c3fSmrg 191601e04c3fSmrg new_token = _token_create_ival(parser, PLACEHOLDER, 191701e04c3fSmrg PLACEHOLDER); 191801e04c3fSmrg _token_list_append(parser, substituted, new_token); 191901e04c3fSmrg } 192001e04c3fSmrg } else { 192101e04c3fSmrg _token_list_append(parser, substituted, node->token); 192201e04c3fSmrg } 192301e04c3fSmrg } 192401e04c3fSmrg 192501e04c3fSmrg /* After argument substitution, and before further expansion 192601e04c3fSmrg * below, implement token pasting. */ 192701e04c3fSmrg 192801e04c3fSmrg _token_list_trim_trailing_space(substituted); 192901e04c3fSmrg 193001e04c3fSmrg _glcpp_parser_apply_pastes(parser, substituted); 193101e04c3fSmrg 193201e04c3fSmrg return substituted; 193301e04c3fSmrg} 193401e04c3fSmrg 193501e04c3fSmrg/* Compute the complete expansion of node, (and subsequent nodes after 193601e04c3fSmrg * 'node' in the case that 'node' is a function-like macro and 193701e04c3fSmrg * subsequent nodes are arguments). 193801e04c3fSmrg * 193901e04c3fSmrg * Returns NULL if node is a simple token with no expansion. 194001e04c3fSmrg * 194101e04c3fSmrg * Otherwise, returns the token list that results from the expansion 194201e04c3fSmrg * and sets *last to the last node in the list that was consumed by 194301e04c3fSmrg * the expansion. Specifically, *last will be set as follows: 194401e04c3fSmrg * 194501e04c3fSmrg * As 'node' in the case of object-like macro expansion. 194601e04c3fSmrg * 194701e04c3fSmrg * As the token of the closing right parenthesis in the case of 194801e04c3fSmrg * function-like macro expansion. 194901e04c3fSmrg * 195001e04c3fSmrg * See the documentation of _glcpp_parser_expand_token_list for a description 195101e04c3fSmrg * of the "mode" parameter. 195201e04c3fSmrg */ 195301e04c3fSmrgstatic token_list_t * 195401e04c3fSmrg_glcpp_parser_expand_node(glcpp_parser_t *parser, token_node_t *node, 19557ec681f3Smrg token_node_t **last, expansion_mode_t mode, 19567ec681f3Smrg int line) 195701e04c3fSmrg{ 195801e04c3fSmrg token_t *token = node->token; 195901e04c3fSmrg const char *identifier; 196001e04c3fSmrg struct hash_entry *entry; 196101e04c3fSmrg macro_t *macro; 196201e04c3fSmrg 19637ec681f3Smrg /* If token is already being expanded return to avoid an infinite loop */ 19647ec681f3Smrg if (token->expanding) 19657ec681f3Smrg return NULL; 19667ec681f3Smrg 196701e04c3fSmrg /* We only expand identifiers */ 196801e04c3fSmrg if (token->type != IDENTIFIER) { 196901e04c3fSmrg return NULL; 197001e04c3fSmrg } 197101e04c3fSmrg 197201e04c3fSmrg *last = node; 197301e04c3fSmrg identifier = token->value.str; 197401e04c3fSmrg 197501e04c3fSmrg /* Special handling for __LINE__ and __FILE__, (not through 197601e04c3fSmrg * the hash table). */ 197701e04c3fSmrg if (*identifier == '_') { 197801e04c3fSmrg if (strcmp(identifier, "__LINE__") == 0) 19797ec681f3Smrg return _token_list_create_with_one_integer(parser, line); 198001e04c3fSmrg 198101e04c3fSmrg if (strcmp(identifier, "__FILE__") == 0) 198201e04c3fSmrg return _token_list_create_with_one_integer(parser, 198301e04c3fSmrg node->token->location.source); 198401e04c3fSmrg } 198501e04c3fSmrg 198601e04c3fSmrg /* Look up this identifier in the hash table. */ 198701e04c3fSmrg entry = _mesa_hash_table_search(parser->defines, identifier); 198801e04c3fSmrg macro = entry ? entry->data : NULL; 198901e04c3fSmrg 199001e04c3fSmrg /* Not a macro, so no expansion needed. */ 199101e04c3fSmrg if (macro == NULL) 199201e04c3fSmrg return NULL; 199301e04c3fSmrg 199401e04c3fSmrg /* Finally, don't expand this macro if we're already actively 199501e04c3fSmrg * expanding it, (to avoid infinite recursion). */ 199601e04c3fSmrg if (_parser_active_list_contains (parser, identifier)) { 19977ec681f3Smrg /* We change the `expanding` bool to true to prevent any 199801e04c3fSmrg * future expansion of this unexpanded token. */ 199901e04c3fSmrg char *str; 200001e04c3fSmrg token_list_t *expansion; 200101e04c3fSmrg token_t *final; 200201e04c3fSmrg 200301e04c3fSmrg str = linear_strdup(parser->linalloc, token->value.str); 20047ec681f3Smrg final = _token_create_str(parser, token->type, str); 20057ec681f3Smrg final->expanding = true; 200601e04c3fSmrg expansion = _token_list_create(parser); 200701e04c3fSmrg _token_list_append(parser, expansion, final); 200801e04c3fSmrg return expansion; 200901e04c3fSmrg } 201001e04c3fSmrg 201101e04c3fSmrg if (! macro->is_function) { 201201e04c3fSmrg token_list_t *replacement; 201301e04c3fSmrg 201401e04c3fSmrg /* Replace a macro defined as empty with a SPACE token. */ 201501e04c3fSmrg if (macro->replacements == NULL) 201601e04c3fSmrg return _token_list_create_with_one_space(parser); 201701e04c3fSmrg 201801e04c3fSmrg replacement = _token_list_copy(parser, macro->replacements); 201901e04c3fSmrg _glcpp_parser_apply_pastes(parser, replacement); 202001e04c3fSmrg return replacement; 202101e04c3fSmrg } 202201e04c3fSmrg 202301e04c3fSmrg return _glcpp_parser_expand_function(parser, node, last, mode); 202401e04c3fSmrg} 202501e04c3fSmrg 202601e04c3fSmrg/* Push a new identifier onto the parser's active list. 202701e04c3fSmrg * 202801e04c3fSmrg * Here, 'marker' is the token node that appears in the list after the 202901e04c3fSmrg * expansion of 'identifier'. That is, when the list iterator begins 203001e04c3fSmrg * examining 'marker', then it is time to pop this node from the 203101e04c3fSmrg * active stack. 203201e04c3fSmrg */ 203301e04c3fSmrgstatic void 203401e04c3fSmrg_parser_active_list_push(glcpp_parser_t *parser, const char *identifier, 203501e04c3fSmrg token_node_t *marker) 203601e04c3fSmrg{ 203701e04c3fSmrg active_list_t *node; 203801e04c3fSmrg 203901e04c3fSmrg node = linear_alloc_child(parser->linalloc, sizeof(active_list_t)); 204001e04c3fSmrg node->identifier = linear_strdup(parser->linalloc, identifier); 204101e04c3fSmrg node->marker = marker; 204201e04c3fSmrg node->next = parser->active; 204301e04c3fSmrg 204401e04c3fSmrg parser->active = node; 204501e04c3fSmrg} 204601e04c3fSmrg 204701e04c3fSmrgstatic void 204801e04c3fSmrg_parser_active_list_pop(glcpp_parser_t *parser) 204901e04c3fSmrg{ 205001e04c3fSmrg active_list_t *node = parser->active; 205101e04c3fSmrg 205201e04c3fSmrg if (node == NULL) { 205301e04c3fSmrg parser->active = NULL; 205401e04c3fSmrg return; 205501e04c3fSmrg } 205601e04c3fSmrg 205701e04c3fSmrg node = parser->active->next; 205801e04c3fSmrg parser->active = node; 205901e04c3fSmrg} 206001e04c3fSmrg 206101e04c3fSmrgstatic int 206201e04c3fSmrg_parser_active_list_contains(glcpp_parser_t *parser, const char *identifier) 206301e04c3fSmrg{ 206401e04c3fSmrg active_list_t *node; 206501e04c3fSmrg 206601e04c3fSmrg if (parser->active == NULL) 206701e04c3fSmrg return 0; 206801e04c3fSmrg 206901e04c3fSmrg for (node = parser->active; node; node = node->next) 207001e04c3fSmrg if (strcmp(node->identifier, identifier) == 0) 207101e04c3fSmrg return 1; 207201e04c3fSmrg 207301e04c3fSmrg return 0; 207401e04c3fSmrg} 207501e04c3fSmrg 207601e04c3fSmrg/* Walk over the token list replacing nodes with their expansion. 207701e04c3fSmrg * Whenever nodes are expanded the walking will walk over the new 207801e04c3fSmrg * nodes, continuing to expand as necessary. The results are placed in 207901e04c3fSmrg * 'list' itself. 208001e04c3fSmrg * 208101e04c3fSmrg * The "mode" argument controls the handling of any DEFINED tokens that 208201e04c3fSmrg * result from expansion as follows: 208301e04c3fSmrg * 208401e04c3fSmrg * EXPANSION_MODE_IGNORE_DEFINED: Any resulting DEFINED tokens will be 208501e04c3fSmrg * left in the final list, unevaluated. This is the correct mode 208601e04c3fSmrg * for expanding any list in any context other than a 208701e04c3fSmrg * preprocessor conditional, (#if or #elif). 208801e04c3fSmrg * 208901e04c3fSmrg * EXPANSION_MODE_EVALUATE_DEFINED: Any resulting DEFINED tokens will be 209001e04c3fSmrg * evaluated to 0 or 1 tokens depending on whether the following 209101e04c3fSmrg * token is the name of a defined macro. If the DEFINED token is 209201e04c3fSmrg * not followed by an (optionally parenthesized) identifier, then 209301e04c3fSmrg * an error will be generated. This the correct mode for 209401e04c3fSmrg * expanding any list in the context of a preprocessor 209501e04c3fSmrg * conditional, (#if or #elif). 209601e04c3fSmrg */ 209701e04c3fSmrgstatic void 209801e04c3fSmrg_glcpp_parser_expand_token_list(glcpp_parser_t *parser, token_list_t *list, 209901e04c3fSmrg expansion_mode_t mode) 210001e04c3fSmrg{ 210101e04c3fSmrg token_node_t *node_prev; 210201e04c3fSmrg token_node_t *node, *last = NULL; 210301e04c3fSmrg token_list_t *expansion; 210401e04c3fSmrg active_list_t *active_initial = parser->active; 21057ec681f3Smrg int line; 210601e04c3fSmrg 210701e04c3fSmrg if (list == NULL) 210801e04c3fSmrg return; 210901e04c3fSmrg 211001e04c3fSmrg _token_list_trim_trailing_space (list); 211101e04c3fSmrg 21127ec681f3Smrg line = list->tail->token->location.last_line; 21137ec681f3Smrg 211401e04c3fSmrg node_prev = NULL; 211501e04c3fSmrg node = list->head; 211601e04c3fSmrg 211701e04c3fSmrg if (mode == EXPANSION_MODE_EVALUATE_DEFINED) 211801e04c3fSmrg _glcpp_parser_evaluate_defined_in_list (parser, list); 211901e04c3fSmrg 212001e04c3fSmrg while (node) { 212101e04c3fSmrg 212201e04c3fSmrg while (parser->active && parser->active->marker == node) 212301e04c3fSmrg _parser_active_list_pop (parser); 212401e04c3fSmrg 21257ec681f3Smrg expansion = _glcpp_parser_expand_node (parser, node, &last, mode, line); 212601e04c3fSmrg if (expansion) { 212701e04c3fSmrg token_node_t *n; 212801e04c3fSmrg 212901e04c3fSmrg if (mode == EXPANSION_MODE_EVALUATE_DEFINED) { 213001e04c3fSmrg _glcpp_parser_evaluate_defined_in_list (parser, expansion); 213101e04c3fSmrg } 213201e04c3fSmrg 213301e04c3fSmrg for (n = node; n != last->next; n = n->next) 213401e04c3fSmrg while (parser->active && parser->active->marker == n) { 213501e04c3fSmrg _parser_active_list_pop (parser); 213601e04c3fSmrg } 213701e04c3fSmrg 213801e04c3fSmrg _parser_active_list_push(parser, node->token->value.str, last->next); 213901e04c3fSmrg 214001e04c3fSmrg /* Splice expansion into list, supporting a simple deletion if the 214101e04c3fSmrg * expansion is empty. 214201e04c3fSmrg */ 214301e04c3fSmrg if (expansion->head) { 214401e04c3fSmrg if (node_prev) 214501e04c3fSmrg node_prev->next = expansion->head; 214601e04c3fSmrg else 214701e04c3fSmrg list->head = expansion->head; 214801e04c3fSmrg expansion->tail->next = last->next; 214901e04c3fSmrg if (last == list->tail) 215001e04c3fSmrg list->tail = expansion->tail; 215101e04c3fSmrg } else { 215201e04c3fSmrg if (node_prev) 215301e04c3fSmrg node_prev->next = last->next; 215401e04c3fSmrg else 215501e04c3fSmrg list->head = last->next; 215601e04c3fSmrg if (last == list->tail) 215701e04c3fSmrg list->tail = NULL; 215801e04c3fSmrg } 215901e04c3fSmrg } else { 216001e04c3fSmrg node_prev = node; 216101e04c3fSmrg } 216201e04c3fSmrg node = node_prev ? node_prev->next : list->head; 216301e04c3fSmrg } 216401e04c3fSmrg 216501e04c3fSmrg /* Remove any lingering effects of this invocation on the 216601e04c3fSmrg * active list. That is, pop until the list looks like it did 216701e04c3fSmrg * at the beginning of this function. */ 216801e04c3fSmrg while (parser->active && parser->active != active_initial) 216901e04c3fSmrg _parser_active_list_pop (parser); 217001e04c3fSmrg 217101e04c3fSmrg list->non_space_tail = list->tail; 217201e04c3fSmrg} 217301e04c3fSmrg 217401e04c3fSmrgvoid 217501e04c3fSmrg_glcpp_parser_print_expanded_token_list(glcpp_parser_t *parser, 217601e04c3fSmrg token_list_t *list) 217701e04c3fSmrg{ 217801e04c3fSmrg if (list == NULL) 217901e04c3fSmrg return; 218001e04c3fSmrg 218101e04c3fSmrg _glcpp_parser_expand_token_list (parser, list, EXPANSION_MODE_IGNORE_DEFINED); 218201e04c3fSmrg 218301e04c3fSmrg _token_list_trim_trailing_space (list); 218401e04c3fSmrg 218501e04c3fSmrg _token_list_print (parser, list); 218601e04c3fSmrg} 218701e04c3fSmrg 218801e04c3fSmrgstatic void 218901e04c3fSmrg_check_for_reserved_macro_name(glcpp_parser_t *parser, YYLTYPE *loc, 219001e04c3fSmrg const char *identifier) 219101e04c3fSmrg{ 219201e04c3fSmrg /* Section 3.3 (Preprocessor) of the GLSL 1.30 spec (and later) and 219301e04c3fSmrg * the GLSL ES spec (all versions) say: 219401e04c3fSmrg * 219501e04c3fSmrg * "All macro names containing two consecutive underscores ( __ ) 219601e04c3fSmrg * are reserved for future use as predefined macro names. All 219701e04c3fSmrg * macro names prefixed with "GL_" ("GL" followed by a single 219801e04c3fSmrg * underscore) are also reserved." 219901e04c3fSmrg * 220001e04c3fSmrg * The intention is that names containing __ are reserved for internal 220101e04c3fSmrg * use by the implementation, and names prefixed with GL_ are reserved 220201e04c3fSmrg * for use by Khronos. Since every extension adds a name prefixed 220301e04c3fSmrg * with GL_ (i.e., the name of the extension), that should be an 220401e04c3fSmrg * error. Names simply containing __ are dangerous to use, but should 220501e04c3fSmrg * be allowed. 220601e04c3fSmrg * 220701e04c3fSmrg * A future version of the GLSL specification will clarify this. 220801e04c3fSmrg */ 220901e04c3fSmrg if (strstr(identifier, "__")) { 221001e04c3fSmrg glcpp_warning(loc, parser, "Macro names containing \"__\" are reserved " 221101e04c3fSmrg "for use by the implementation.\n"); 221201e04c3fSmrg } 221301e04c3fSmrg if (strncmp(identifier, "GL_", 3) == 0) { 221401e04c3fSmrg glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n"); 221501e04c3fSmrg } 221601e04c3fSmrg if (strcmp(identifier, "defined") == 0) { 221701e04c3fSmrg glcpp_error (loc, parser, "\"defined\" cannot be used as a macro name"); 221801e04c3fSmrg } 221901e04c3fSmrg} 222001e04c3fSmrg 222101e04c3fSmrgstatic int 222201e04c3fSmrg_macro_equal(macro_t *a, macro_t *b) 222301e04c3fSmrg{ 222401e04c3fSmrg if (a->is_function != b->is_function) 222501e04c3fSmrg return 0; 222601e04c3fSmrg 222701e04c3fSmrg if (a->is_function) { 222801e04c3fSmrg if (! _string_list_equal (a->parameters, b->parameters)) 222901e04c3fSmrg return 0; 223001e04c3fSmrg } 223101e04c3fSmrg 223201e04c3fSmrg return _token_list_equal_ignoring_space(a->replacements, b->replacements); 223301e04c3fSmrg} 223401e04c3fSmrg 223501e04c3fSmrgvoid 223601e04c3fSmrg_define_object_macro(glcpp_parser_t *parser, YYLTYPE *loc, 223701e04c3fSmrg const char *identifier, token_list_t *replacements) 223801e04c3fSmrg{ 223901e04c3fSmrg macro_t *macro, *previous; 224001e04c3fSmrg struct hash_entry *entry; 224101e04c3fSmrg 224201e04c3fSmrg /* We define pre-defined macros before we've started parsing the actual 224301e04c3fSmrg * file. So if there's no location defined yet, that's what were doing and 224401e04c3fSmrg * we don't want to generate an error for using the reserved names. */ 224501e04c3fSmrg if (loc != NULL) 224601e04c3fSmrg _check_for_reserved_macro_name(parser, loc, identifier); 224701e04c3fSmrg 224801e04c3fSmrg macro = linear_alloc_child(parser->linalloc, sizeof(macro_t)); 224901e04c3fSmrg 225001e04c3fSmrg macro->is_function = 0; 225101e04c3fSmrg macro->parameters = NULL; 225201e04c3fSmrg macro->identifier = linear_strdup(parser->linalloc, identifier); 225301e04c3fSmrg macro->replacements = replacements; 225401e04c3fSmrg 225501e04c3fSmrg entry = _mesa_hash_table_search(parser->defines, identifier); 225601e04c3fSmrg previous = entry ? entry->data : NULL; 225701e04c3fSmrg if (previous) { 225801e04c3fSmrg if (_macro_equal (macro, previous)) { 225901e04c3fSmrg return; 226001e04c3fSmrg } 226101e04c3fSmrg glcpp_error (loc, parser, "Redefinition of macro %s\n", identifier); 226201e04c3fSmrg } 226301e04c3fSmrg 226401e04c3fSmrg _mesa_hash_table_insert (parser->defines, identifier, macro); 226501e04c3fSmrg} 226601e04c3fSmrg 226701e04c3fSmrgvoid 226801e04c3fSmrg_define_function_macro(glcpp_parser_t *parser, YYLTYPE *loc, 226901e04c3fSmrg const char *identifier, string_list_t *parameters, 227001e04c3fSmrg token_list_t *replacements) 227101e04c3fSmrg{ 227201e04c3fSmrg macro_t *macro, *previous; 227301e04c3fSmrg struct hash_entry *entry; 227401e04c3fSmrg const char *dup; 227501e04c3fSmrg 227601e04c3fSmrg _check_for_reserved_macro_name(parser, loc, identifier); 227701e04c3fSmrg 227801e04c3fSmrg /* Check for any duplicate parameter names. */ 227901e04c3fSmrg if ((dup = _string_list_has_duplicate (parameters)) != NULL) { 228001e04c3fSmrg glcpp_error (loc, parser, "Duplicate macro parameter \"%s\"", dup); 228101e04c3fSmrg } 228201e04c3fSmrg 228301e04c3fSmrg macro = linear_alloc_child(parser->linalloc, sizeof(macro_t)); 228401e04c3fSmrg 228501e04c3fSmrg macro->is_function = 1; 228601e04c3fSmrg macro->parameters = parameters; 228701e04c3fSmrg macro->identifier = linear_strdup(parser->linalloc, identifier); 228801e04c3fSmrg macro->replacements = replacements; 228901e04c3fSmrg 229001e04c3fSmrg entry = _mesa_hash_table_search(parser->defines, identifier); 229101e04c3fSmrg previous = entry ? entry->data : NULL; 229201e04c3fSmrg if (previous) { 229301e04c3fSmrg if (_macro_equal (macro, previous)) { 229401e04c3fSmrg return; 229501e04c3fSmrg } 229601e04c3fSmrg glcpp_error (loc, parser, "Redefinition of macro %s\n", identifier); 229701e04c3fSmrg } 229801e04c3fSmrg 229901e04c3fSmrg _mesa_hash_table_insert(parser->defines, identifier, macro); 230001e04c3fSmrg} 230101e04c3fSmrg 230201e04c3fSmrgstatic int 230301e04c3fSmrgglcpp_parser_lex(YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser) 230401e04c3fSmrg{ 230501e04c3fSmrg token_node_t *node; 230601e04c3fSmrg int ret; 230701e04c3fSmrg 230801e04c3fSmrg if (parser->lex_from_list == NULL) { 230901e04c3fSmrg ret = glcpp_lex(yylval, yylloc, parser->scanner); 231001e04c3fSmrg 231101e04c3fSmrg /* XXX: This ugly block of code exists for the sole 231201e04c3fSmrg * purpose of converting a NEWLINE token into a SPACE 231301e04c3fSmrg * token, but only in the case where we have seen a 231401e04c3fSmrg * function-like macro name, but have not yet seen its 231501e04c3fSmrg * closing parenthesis. 231601e04c3fSmrg * 231701e04c3fSmrg * There's perhaps a more compact way to do this with 231801e04c3fSmrg * mid-rule actions in the grammar. 231901e04c3fSmrg * 232001e04c3fSmrg * I'm definitely not pleased with the complexity of 232101e04c3fSmrg * this code here. 232201e04c3fSmrg */ 232301e04c3fSmrg if (parser->newline_as_space) { 232401e04c3fSmrg if (ret == '(') { 232501e04c3fSmrg parser->paren_count++; 232601e04c3fSmrg } else if (ret == ')') { 232701e04c3fSmrg parser->paren_count--; 232801e04c3fSmrg if (parser->paren_count == 0) 232901e04c3fSmrg parser->newline_as_space = 0; 233001e04c3fSmrg } else if (ret == NEWLINE) { 233101e04c3fSmrg ret = SPACE; 233201e04c3fSmrg } else if (ret != SPACE) { 233301e04c3fSmrg if (parser->paren_count == 0) 233401e04c3fSmrg parser->newline_as_space = 0; 233501e04c3fSmrg } 233601e04c3fSmrg } else if (parser->in_control_line) { 233701e04c3fSmrg if (ret == NEWLINE) 233801e04c3fSmrg parser->in_control_line = 0; 233901e04c3fSmrg } 234001e04c3fSmrg else if (ret == DEFINE_TOKEN || ret == UNDEF || ret == IF || 234101e04c3fSmrg ret == IFDEF || ret == IFNDEF || ret == ELIF || ret == ELSE || 234201e04c3fSmrg ret == ENDIF || ret == HASH_TOKEN) { 234301e04c3fSmrg parser->in_control_line = 1; 234401e04c3fSmrg } else if (ret == IDENTIFIER) { 234501e04c3fSmrg struct hash_entry *entry = _mesa_hash_table_search(parser->defines, 234601e04c3fSmrg yylval->str); 234701e04c3fSmrg macro_t *macro = entry ? entry->data : NULL; 234801e04c3fSmrg if (macro && macro->is_function) { 234901e04c3fSmrg parser->newline_as_space = 1; 235001e04c3fSmrg parser->paren_count = 0; 235101e04c3fSmrg } 235201e04c3fSmrg } 235301e04c3fSmrg 235401e04c3fSmrg return ret; 235501e04c3fSmrg } 235601e04c3fSmrg 235701e04c3fSmrg node = parser->lex_from_node; 235801e04c3fSmrg 235901e04c3fSmrg if (node == NULL) { 236001e04c3fSmrg parser->lex_from_list = NULL; 236101e04c3fSmrg return NEWLINE; 236201e04c3fSmrg } 236301e04c3fSmrg 236401e04c3fSmrg *yylval = node->token->value; 236501e04c3fSmrg ret = node->token->type; 236601e04c3fSmrg 236701e04c3fSmrg parser->lex_from_node = node->next; 236801e04c3fSmrg 236901e04c3fSmrg return ret; 237001e04c3fSmrg} 237101e04c3fSmrg 237201e04c3fSmrgstatic void 237301e04c3fSmrgglcpp_parser_lex_from(glcpp_parser_t *parser, token_list_t *list) 237401e04c3fSmrg{ 237501e04c3fSmrg token_node_t *node; 237601e04c3fSmrg 237701e04c3fSmrg assert (parser->lex_from_list == NULL); 237801e04c3fSmrg 237901e04c3fSmrg /* Copy list, eliminating any space tokens. */ 238001e04c3fSmrg parser->lex_from_list = _token_list_create (parser); 238101e04c3fSmrg 238201e04c3fSmrg for (node = list->head; node; node = node->next) { 238301e04c3fSmrg if (node->token->type == SPACE) 238401e04c3fSmrg continue; 238501e04c3fSmrg _token_list_append (parser, parser->lex_from_list, node->token); 238601e04c3fSmrg } 238701e04c3fSmrg 238801e04c3fSmrg parser->lex_from_node = parser->lex_from_list->head; 238901e04c3fSmrg 239001e04c3fSmrg /* It's possible the list consisted of nothing but whitespace. */ 239101e04c3fSmrg if (parser->lex_from_node == NULL) { 239201e04c3fSmrg parser->lex_from_list = NULL; 239301e04c3fSmrg } 239401e04c3fSmrg} 239501e04c3fSmrg 239601e04c3fSmrgstatic void 239701e04c3fSmrg_glcpp_parser_skip_stack_push_if(glcpp_parser_t *parser, YYLTYPE *loc, 239801e04c3fSmrg int condition) 239901e04c3fSmrg{ 240001e04c3fSmrg skip_type_t current = SKIP_NO_SKIP; 240101e04c3fSmrg skip_node_t *node; 240201e04c3fSmrg 240301e04c3fSmrg if (parser->skip_stack) 240401e04c3fSmrg current = parser->skip_stack->type; 240501e04c3fSmrg 240601e04c3fSmrg node = linear_alloc_child(parser->linalloc, sizeof(skip_node_t)); 240701e04c3fSmrg node->loc = *loc; 240801e04c3fSmrg 240901e04c3fSmrg if (current == SKIP_NO_SKIP) { 241001e04c3fSmrg if (condition) 241101e04c3fSmrg node->type = SKIP_NO_SKIP; 241201e04c3fSmrg else 241301e04c3fSmrg node->type = SKIP_TO_ELSE; 241401e04c3fSmrg } else { 241501e04c3fSmrg node->type = SKIP_TO_ENDIF; 241601e04c3fSmrg } 241701e04c3fSmrg 241801e04c3fSmrg node->has_else = false; 241901e04c3fSmrg node->next = parser->skip_stack; 242001e04c3fSmrg parser->skip_stack = node; 242101e04c3fSmrg} 242201e04c3fSmrg 242301e04c3fSmrgstatic void 242401e04c3fSmrg_glcpp_parser_skip_stack_change_if(glcpp_parser_t *parser, YYLTYPE *loc, 242501e04c3fSmrg const char *type, int condition) 242601e04c3fSmrg{ 242701e04c3fSmrg if (parser->skip_stack == NULL) { 242801e04c3fSmrg glcpp_error (loc, parser, "#%s without #if\n", type); 242901e04c3fSmrg return; 243001e04c3fSmrg } 243101e04c3fSmrg 243201e04c3fSmrg if (parser->skip_stack->type == SKIP_TO_ELSE) { 243301e04c3fSmrg if (condition) 243401e04c3fSmrg parser->skip_stack->type = SKIP_NO_SKIP; 243501e04c3fSmrg } else { 243601e04c3fSmrg parser->skip_stack->type = SKIP_TO_ENDIF; 243701e04c3fSmrg } 243801e04c3fSmrg} 243901e04c3fSmrg 244001e04c3fSmrgstatic void 244101e04c3fSmrg_glcpp_parser_skip_stack_pop(glcpp_parser_t *parser, YYLTYPE *loc) 244201e04c3fSmrg{ 244301e04c3fSmrg skip_node_t *node; 244401e04c3fSmrg 244501e04c3fSmrg if (parser->skip_stack == NULL) { 244601e04c3fSmrg glcpp_error (loc, parser, "#endif without #if\n"); 244701e04c3fSmrg return; 244801e04c3fSmrg } 244901e04c3fSmrg 245001e04c3fSmrg node = parser->skip_stack; 245101e04c3fSmrg parser->skip_stack = node->next; 245201e04c3fSmrg} 245301e04c3fSmrg 245401e04c3fSmrgstatic void 245501e04c3fSmrg_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version, 245601e04c3fSmrg const char *identifier, 245701e04c3fSmrg bool explicitly_set) 245801e04c3fSmrg{ 245901e04c3fSmrg if (parser->version_set) 246001e04c3fSmrg return; 246101e04c3fSmrg 246201e04c3fSmrg parser->version = version; 246301e04c3fSmrg parser->version_set = true; 246401e04c3fSmrg 246501e04c3fSmrg add_builtin_define (parser, "__VERSION__", version); 246601e04c3fSmrg 246701e04c3fSmrg parser->is_gles = (version == 100) || 246801e04c3fSmrg (identifier && (strcmp(identifier, "es") == 0)); 246901e04c3fSmrg bool is_compat = version >= 150 && identifier && 247001e04c3fSmrg strcmp(identifier, "compatibility") == 0; 247101e04c3fSmrg 247201e04c3fSmrg /* Add pre-defined macros. */ 247301e04c3fSmrg if (parser->is_gles) 247401e04c3fSmrg add_builtin_define(parser, "GL_ES", 1); 247501e04c3fSmrg else if (is_compat) 247601e04c3fSmrg add_builtin_define(parser, "GL_compatibility_profile", 1); 247701e04c3fSmrg else if (version >= 150) 247801e04c3fSmrg add_builtin_define(parser, "GL_core_profile", 1); 247901e04c3fSmrg 248001e04c3fSmrg /* Currently, all ES2/ES3 implementations support highp in the 248101e04c3fSmrg * fragment shader, so we always define this macro in ES2/ES3. 248201e04c3fSmrg * If we ever get a driver that doesn't support highp, we'll 248301e04c3fSmrg * need to add a flag to the gl_context and check that here. 248401e04c3fSmrg */ 248501e04c3fSmrg if (version >= 130 || parser->is_gles) 248601e04c3fSmrg add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1); 248701e04c3fSmrg 248801e04c3fSmrg /* Add all the extension macros available in this context */ 248901e04c3fSmrg if (parser->extensions) 249001e04c3fSmrg parser->extensions(parser->state, add_builtin_define, parser, 249101e04c3fSmrg version, parser->is_gles); 249201e04c3fSmrg 249301e04c3fSmrg if (parser->extension_list) { 249401e04c3fSmrg /* If MESA_shader_integer_functions is supported, then the building 249501e04c3fSmrg * blocks required for the 64x64 => 64 multiply exist. Add defines for 249601e04c3fSmrg * those functions so that they can be tested. 249701e04c3fSmrg */ 249801e04c3fSmrg if (parser->extension_list->MESA_shader_integer_functions) { 249901e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_sign64", 1); 250001e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_umul64", 1); 250101e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_udiv64", 1); 250201e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_umod64", 1); 250301e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_idiv64", 1); 250401e04c3fSmrg add_builtin_define(parser, "__have_builtin_builtin_imod64", 1); 250501e04c3fSmrg } 250601e04c3fSmrg } 250701e04c3fSmrg 250801e04c3fSmrg if (explicitly_set) { 250901e04c3fSmrg _mesa_string_buffer_printf(parser->output, 251001e04c3fSmrg "#version %" PRIiMAX "%s%s", version, 251101e04c3fSmrg identifier ? " " : "", 251201e04c3fSmrg identifier ? identifier : ""); 251301e04c3fSmrg } 251401e04c3fSmrg} 251501e04c3fSmrg 251601e04c3fSmrg/* GLSL version if no version is explicitly specified. */ 251701e04c3fSmrg#define IMPLICIT_GLSL_VERSION 110 251801e04c3fSmrg 251901e04c3fSmrg/* GLSL ES version if no version is explicitly specified. */ 252001e04c3fSmrg#define IMPLICIT_GLSL_ES_VERSION 100 252101e04c3fSmrg 252201e04c3fSmrgvoid 252301e04c3fSmrgglcpp_parser_resolve_implicit_version(glcpp_parser_t *parser) 252401e04c3fSmrg{ 252501e04c3fSmrg int language_version = parser->api == API_OPENGLES2 ? 252601e04c3fSmrg IMPLICIT_GLSL_ES_VERSION : IMPLICIT_GLSL_VERSION; 252701e04c3fSmrg 252801e04c3fSmrg _glcpp_parser_handle_version_declaration(parser, language_version, 252901e04c3fSmrg NULL, false); 253001e04c3fSmrg} 25317ec681f3Smrg 25327ec681f3Smrgstatic void 25337ec681f3Smrgglcpp_parser_copy_defines(const void *key, void *data, void *closure) 25347ec681f3Smrg{ 25357ec681f3Smrg struct define_include *di = (struct define_include *) closure; 25367ec681f3Smrg macro_t *macro = (macro_t *) data; 25377ec681f3Smrg 25387ec681f3Smrg /* If we hit an error on a previous pass, just return */ 25397ec681f3Smrg if (di->parser->error) 25407ec681f3Smrg return; 25417ec681f3Smrg 25427ec681f3Smrg const char *identifier = macro->identifier; 25437ec681f3Smrg struct hash_entry *entry = _mesa_hash_table_search(di->parser->defines, 25447ec681f3Smrg identifier); 25457ec681f3Smrg 25467ec681f3Smrg macro_t *previous = entry ? entry->data : NULL; 25477ec681f3Smrg if (previous) { 25487ec681f3Smrg if (_macro_equal(macro, previous)) { 25497ec681f3Smrg return; 25507ec681f3Smrg } 25517ec681f3Smrg glcpp_error(di->loc, di->parser, "Redefinition of macro %s\n", 25527ec681f3Smrg identifier); 25537ec681f3Smrg } 25547ec681f3Smrg 25557ec681f3Smrg _mesa_hash_table_insert(di->parser->defines, identifier, macro); 25567ec681f3Smrg} 2557