glsl/glcpp: Fix glcpp to catch garbage after #if 1 ... #else
[mesa.git] / src / glsl / glcpp / glcpp-parse.y
index 6f15e85a1221279f5a4d4f4f5f9c64c49fba8680..82e310270d6324b5dff100926c50f733a9d51429 100644 (file)
@@ -85,7 +85,6 @@ _token_create_ival (void *ctx, int type, int ival);
 static token_list_t *
 _token_list_create (void *ctx);
 
-/* Note: This function calls ralloc_steal on token. */
 static void
 _token_list_append (token_list_t *list, token_t *token);
 
@@ -106,9 +105,15 @@ _parser_active_list_pop (glcpp_parser_t *parser);
 static int
 _parser_active_list_contains (glcpp_parser_t *parser, const char *identifier);
 
+/* Expand list, and begin lexing from the result (after first
+ * prefixing a token of type 'head_token_type').
+ */
 static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list);
+_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser,
+                                  int head_token_type,
+                                  token_list_t *list);
 
+/* Perform macro expansion in-place on the given list. */
 static void
 _glcpp_parser_expand_token_list (glcpp_parser_t *parser,
                                 token_list_t *list);
@@ -128,7 +133,9 @@ _glcpp_parser_skip_stack_change_if (glcpp_parser_t *parser, YYLTYPE *loc,
 static void
 _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc);
 
-#define yylex glcpp_parser_lex
+static void
+_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version,
+                                         const char *ident, bool explicitly_set);
 
 static int
 glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser);
@@ -157,10 +164,10 @@ add_builtin_define(glcpp_parser_t *parser, const char *name, int value);
 %lex-param {glcpp_parser_t *parser}
 
 %expect 0
-%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE_FUNC HASH_DEFINE_OBJ HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING NEWLINE OTHER PLACEHOLDER SPACE
+%token COMMA_FINAL DEFINED ELIF_EXPANDED HASH HASH_DEFINE FUNC_IDENTIFIER OBJ_IDENTIFIER HASH_ELIF HASH_ELSE HASH_ENDIF HASH_IF HASH_IFDEF HASH_IFNDEF HASH_LINE HASH_UNDEF HASH_VERSION IDENTIFIER IF_EXPANDED INTEGER INTEGER_STRING LINE_EXPANDED NEWLINE OTHER PLACEHOLDER SPACE
 %token PASTE
 %type <ival> expression INTEGER operator SPACE integer_constant
-%type <str> IDENTIFIER INTEGER_STRING OTHER
+%type <str> IDENTIFIER FUNC_IDENTIFIER OBJ_IDENTIFIER INTEGER_STRING OTHER
 %type <string_list> identifier_list
 %type <token> preprocessing_token conditional_token
 %type <token_list> pp_tokens replacement_list text_line conditional_tokens
@@ -185,11 +192,22 @@ input:
 
 line:
        control_line {
-               ralloc_strcat (&parser->output, "\n");
+               ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
+       }
+|      HASH_LINE {
+               glcpp_parser_resolve_implicit_version(parser);
+       } pp_tokens NEWLINE {
+
+               if (parser->skip_stack == NULL ||
+                   parser->skip_stack->type == SKIP_NO_SKIP)
+               {
+                       _glcpp_parser_expand_and_lex_from (parser,
+                                                          LINE_EXPANDED, $3);
+               }
        }
 |      text_line {
                _glcpp_parser_print_expanded_token_list (parser, $1);
-               ralloc_strcat (&parser->output, "\n");
+               ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length, "\n");
                ralloc_free ($1);
        }
 |      expanded_line
@@ -203,27 +221,61 @@ expanded_line:
 |      ELIF_EXPANDED expression NEWLINE {
                _glcpp_parser_skip_stack_change_if (parser, & @1, "elif", $2);
        }
+|      LINE_EXPANDED integer_constant NEWLINE {
+               parser->has_new_line_number = 1;
+               parser->new_line_number = $2;
+               ralloc_asprintf_rewrite_tail (&parser->output,
+                                             &parser->output_length,
+                                             "#line %" PRIiMAX "\n",
+                                             $2);
+       }
+|      LINE_EXPANDED integer_constant integer_constant NEWLINE {
+               parser->has_new_line_number = 1;
+               parser->new_line_number = $2;
+               parser->has_new_source_number = 1;
+               parser->new_source_number = $3;
+               ralloc_asprintf_rewrite_tail (&parser->output,
+                                             &parser->output_length,
+                                             "#line %" PRIiMAX " %" PRIiMAX "\n",
+                                             $2, $3);
+       }
 ;
 
-control_line:
-       HASH_DEFINE_OBJ IDENTIFIER replacement_list NEWLINE {
-               _define_object_macro (parser, & @2, $2, $3);
+define:
+       OBJ_IDENTIFIER replacement_list NEWLINE {
+               _define_object_macro (parser, & @1, $1, $2);
        }
-|      HASH_DEFINE_FUNC IDENTIFIER '(' ')' replacement_list NEWLINE {
-               _define_function_macro (parser, & @2, $2, NULL, $5);
+|      FUNC_IDENTIFIER '(' ')' replacement_list NEWLINE {
+               _define_function_macro (parser, & @1, $1, NULL, $4);
        }
-|      HASH_DEFINE_FUNC IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
-               _define_function_macro (parser, & @2, $2, $4, $6);
+|      FUNC_IDENTIFIER '(' identifier_list ')' replacement_list NEWLINE {
+               _define_function_macro (parser, & @1, $1, $3, $5);
        }
-|      HASH_UNDEF IDENTIFIER NEWLINE {
-               macro_t *macro = hash_table_find (parser->defines, $2);
+;
+
+control_line:
+       HASH_DEFINE {
+               glcpp_parser_resolve_implicit_version(parser);
+       } define
+|      HASH_UNDEF {
+               glcpp_parser_resolve_implicit_version(parser);
+       } IDENTIFIER NEWLINE {
+               if (strcmp("__LINE__", $3) == 0
+                   || strcmp("__FILE__", $3) == 0
+                   || strcmp("__VERSION__", $3) == 0)
+                       glcpp_error(& @1, parser, "Built-in (pre-defined)"
+                                   " macro names can not be undefined.");
+
+               macro_t *macro = hash_table_find (parser->defines, $3);
                if (macro) {
-                       hash_table_remove (parser->defines, $2);
+                       hash_table_remove (parser->defines, $3);
                        ralloc_free (macro);
                }
-               ralloc_free ($2);
+               ralloc_free ($3);
        }
-|      HASH_IF conditional_tokens NEWLINE {
+|      HASH_IF {
+               glcpp_parser_resolve_implicit_version(parser);
+       } conditional_tokens NEWLINE {
                /* Be careful to only evaluate the 'if' expression if
                 * we are not skipping. When we are skipping, we
                 * simply push a new 0-valued 'if' onto the skip
@@ -234,7 +286,8 @@ control_line:
                if (parser->skip_stack == NULL ||
                    parser->skip_stack->type == SKIP_NO_SKIP)
                {
-                       _glcpp_parser_expand_if (parser, IF_EXPANDED, $2);
+                       _glcpp_parser_expand_and_lex_from (parser,
+                                                          IF_EXPANDED, $3);
                }       
                else
                {
@@ -252,15 +305,19 @@ control_line:
                }       
                _glcpp_parser_skip_stack_push_if (parser, & @1, 0);
        }
-|      HASH_IFDEF IDENTIFIER junk NEWLINE {
-               macro_t *macro = hash_table_find (parser->defines, $2);
-               ralloc_free ($2);
+|      HASH_IFDEF {
+               glcpp_parser_resolve_implicit_version(parser);
+       } IDENTIFIER junk NEWLINE {
+               macro_t *macro = hash_table_find (parser->defines, $3);
+               ralloc_free ($3);
                _glcpp_parser_skip_stack_push_if (parser, & @1, macro != NULL);
        }
-|      HASH_IFNDEF IDENTIFIER junk NEWLINE {
-               macro_t *macro = hash_table_find (parser->defines, $2);
-               ralloc_free ($2);
-               _glcpp_parser_skip_stack_push_if (parser, & @1, macro == NULL);
+|      HASH_IFNDEF {
+               glcpp_parser_resolve_implicit_version(parser);
+       } IDENTIFIER junk NEWLINE {
+               macro_t *macro = hash_table_find (parser->defines, $3);
+               ralloc_free ($3);
+               _glcpp_parser_skip_stack_push_if (parser, & @2, macro == NULL);
        }
 |      HASH_ELIF conditional_tokens NEWLINE {
                /* Be careful to only evaluate the 'elif' expression
@@ -273,7 +330,13 @@ control_line:
                if (parser->skip_stack &&
                    parser->skip_stack->type == SKIP_TO_ELSE)
                {
-                       _glcpp_parser_expand_if (parser, ELIF_EXPANDED, $2);
+                       _glcpp_parser_expand_and_lex_from (parser,
+                                                          ELIF_EXPANDED, $2);
+               }
+               else if (parser->skip_stack &&
+                   parser->skip_stack->has_else)
+               {
+                       glcpp_error(& @1, parser, "#elif after #else");
                }
                else
                {
@@ -289,6 +352,11 @@ control_line:
                {
                        glcpp_error(& @1, parser, "#elif with no expression");
                }
+               else if (parser->skip_stack &&
+                   parser->skip_stack->has_else)
+               {
+                       glcpp_error(& @1, parser, "#elif after #else");
+               }
                else
                {
                        _glcpp_parser_skip_stack_change_if (parser, & @1,
@@ -296,34 +364,37 @@ control_line:
                        glcpp_warning(& @1, parser, "ignoring illegal #elif without expression");
                }
        }
-|      HASH_ELSE NEWLINE {
-               _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+|      HASH_ELSE { parser->lexing_directive = 1; } NEWLINE {
+               if (parser->skip_stack &&
+                   parser->skip_stack->has_else)
+               {
+                       glcpp_error(& @1, parser, "multiple #else");
+               }
+               else
+               {
+                       _glcpp_parser_skip_stack_change_if (parser, & @1, "else", 1);
+                       if (parser->skip_stack)
+                               parser->skip_stack->has_else = true;
+               }
        }
-|      HASH_ENDIF NEWLINE {
+|      HASH_ENDIF {
                _glcpp_parser_skip_stack_pop (parser, & @1);
-       }
+       } NEWLINE
 |      HASH_VERSION integer_constant NEWLINE {
-               macro_t *macro = hash_table_find (parser->defines, "__VERSION__");
-               if (macro) {
-                       hash_table_remove (parser->defines, "__VERSION__");
-                       ralloc_free (macro);
+               if (parser->version_resolved) {
+                       glcpp_error(& @1, parser, "#version must appear on the first line");
                }
-               add_builtin_define (parser, "__VERSION__", $2);
-
-               if ($2 == 100)
-                       add_builtin_define (parser, "GL_ES", 1);
-
-               /* Currently, all ES2 implementations support highp in the
-                * fragment shader, so we always define this macro in ES2.
-                * If we ever get a driver that doesn't support highp, we'll
-                * need to add a flag to the gl_context and check that here.
-                */
-               if ($2 >= 130 || $2 == 100)
-                       add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
-
-               ralloc_asprintf_append (&parser->output, "#version %" PRIiMAX, $2);
+               _glcpp_parser_handle_version_declaration(parser, $2, NULL, true);
+       }
+|      HASH_VERSION integer_constant IDENTIFIER NEWLINE {
+               if (parser->version_resolved) {
+                       glcpp_error(& @1, parser, "#version must appear on the first line");
+               }
+               _glcpp_parser_handle_version_declaration(parser, $2, $3, true);
+       }
+|      HASH NEWLINE {
+               glcpp_parser_resolve_implicit_version(parser);
        }
-|      HASH NEWLINE
 ;
 
 integer_constant:
@@ -342,6 +413,11 @@ integer_constant:
 
 expression:
        integer_constant
+|      IDENTIFIER {
+               if (parser->is_gles)
+                       glcpp_error(& @1, parser, "undefined macro %s in expression (illegal in GLES)", $1);
+               $$ = 0;
+       }
 |      expression OR expression {
                $$ = $1 || $3;
        }
@@ -763,8 +839,6 @@ _token_list_append (token_list_t *list, token_t *token)
        node->token = token;
        node->next = NULL;
 
-       ralloc_steal (list, token);
-
        if (list->head == NULL) {
                list->head = node;
        } else {
@@ -865,14 +939,16 @@ _token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
 
                if (node_a == NULL || node_b == NULL)
                        return 0;
-
-               if (node_a->token->type == SPACE) {
-                       node_a = node_a->next;
-                       continue;
-               }
-
-               if (node_b->token->type == SPACE) {
-                       node_b = node_b->next;
+               /* Make sure whitespace appears in the same places in both.
+                * It need not be exactly the same amount of whitespace,
+                * though.
+                */
+               if (node_a->token->type == SPACE
+                   && node_b->token->type == SPACE) {
+                       while (node_a->token->type == SPACE)
+                               node_a = node_a->next;
+                       while (node_b->token->type == SPACE)
+                               node_b = node_b->next;
                        continue;
                }
 
@@ -906,54 +982,54 @@ _token_list_equal_ignoring_space (token_list_t *a, token_list_t *b)
 }
 
 static void
-_token_print (char **out, token_t *token)
+_token_print (char **out, size_t *len, token_t *token)
 {
        if (token->type < 256) {
-               ralloc_asprintf_append (out, "%c", token->type);
+               ralloc_asprintf_rewrite_tail (out, len, "%c", token->type);
                return;
        }
 
        switch (token->type) {
        case INTEGER:
-               ralloc_asprintf_append (out, "%" PRIiMAX, token->value.ival);
+               ralloc_asprintf_rewrite_tail (out, len, "%" PRIiMAX, token->value.ival);
                break;
        case IDENTIFIER:
        case INTEGER_STRING:
        case OTHER:
-               ralloc_strcat (out, token->value.str);
+               ralloc_asprintf_rewrite_tail (out, len, "%s", token->value.str);
                break;
        case SPACE:
-               ralloc_strcat (out, " ");
+               ralloc_asprintf_rewrite_tail (out, len, " ");
                break;
        case LEFT_SHIFT:
-               ralloc_strcat (out, "<<");
+               ralloc_asprintf_rewrite_tail (out, len, "<<");
                break;
        case RIGHT_SHIFT:
-               ralloc_strcat (out, ">>");
+               ralloc_asprintf_rewrite_tail (out, len, ">>");
                break;
        case LESS_OR_EQUAL:
-               ralloc_strcat (out, "<=");
+               ralloc_asprintf_rewrite_tail (out, len, "<=");
                break;
        case GREATER_OR_EQUAL:
-               ralloc_strcat (out, ">=");
+               ralloc_asprintf_rewrite_tail (out, len, ">=");
                break;
        case EQUAL:
-               ralloc_strcat (out, "==");
+               ralloc_asprintf_rewrite_tail (out, len, "==");
                break;
        case NOT_EQUAL:
-               ralloc_strcat (out, "!=");
+               ralloc_asprintf_rewrite_tail (out, len, "!=");
                break;
        case AND:
-               ralloc_strcat (out, "&&");
+               ralloc_asprintf_rewrite_tail (out, len, "&&");
                break;
        case OR:
-               ralloc_strcat (out, "||");
+               ralloc_asprintf_rewrite_tail (out, len, "||");
                break;
        case PASTE:
-               ralloc_strcat (out, "##");
+               ralloc_asprintf_rewrite_tail (out, len, "##");
                break;
        case COMMA_FINAL:
-               ralloc_strcat (out, ",");
+               ralloc_asprintf_rewrite_tail (out, len, ",");
                break;
        case PLACEHOLDER:
                /* Nothing to print. */
@@ -1022,32 +1098,73 @@ _token_paste (glcpp_parser_t *parser, token_t *token, token_t *other)
                return combined;
        }
 
-       /* Two string-valued tokens can usually just be mashed
-        * together.
+       /* Two string-valued (or integer) tokens can usually just be
+        * mashed together. (We also handle a string followed by an
+        * integer here as well.)
         *
-        * XXX: This isn't actually legitimate. Several things here
-        * should result in a diagnostic since the result cannot be a
-        * valid, single pre-processing token. For example, pasting
-        * "123" and "abc" is not legal, but we don't catch that
-        * here. */
-       if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING) &&
-           (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING))
+        * There are some exceptions here. Notably, if the first token
+        * is an integer (or a string representing an integer), then
+        * the second token must also be an integer or must be a
+        * string representing an integer that begins with a digit.
+        */
+       if ((token->type == IDENTIFIER || token->type == OTHER || token->type == INTEGER_STRING || token->type == INTEGER) &&
+           (other->type == IDENTIFIER || other->type == OTHER || other->type == INTEGER_STRING || other->type == INTEGER))
        {
                char *str;
+               int combined_type;
 
-               str = ralloc_asprintf (token, "%s%s", token->value.str,
-                                      other->value.str);
-               combined = _token_create_str (token, token->type, str);
+               /* Check that pasting onto an integer doesn't create a
+                * non-integer, (that is, only digits can be
+                * pasted. */
+               if (token->type == INTEGER_STRING || token->type == INTEGER)
+               {
+                       switch (other->type) {
+                       case INTEGER_STRING:
+                               if (other->value.str[0] < '0' ||
+                                   other->value.str[0] > '9')
+                                       goto FAIL;
+                               break;
+                       case INTEGER:
+                               if (other->value.ival < 0)
+                                       goto FAIL;
+                               break;
+                       default:
+                               goto FAIL;
+                       }
+               }
+
+               if (token->type == INTEGER)
+                       str = ralloc_asprintf (token, "%" PRIiMAX,
+                                              token->value.ival);
+               else
+                       str = ralloc_strdup (token, token->value.str);
+                                              
+
+               if (other->type == INTEGER)
+                       ralloc_asprintf_append (&str, "%" PRIiMAX,
+                                               other->value.ival);
+               else
+                       ralloc_strcat (&str, other->value.str);
+
+               /* New token is same type as original token, unless we
+                * started with an integer, in which case we will be
+                * creating an integer-string. */
+               combined_type = token->type;
+               if (combined_type == INTEGER)
+                       combined_type = INTEGER_STRING;
+
+               combined = _token_create_str (token, combined_type, str);
                combined->location = token->location;
                return combined;
        }
 
+    FAIL:
        glcpp_error (&token->location, parser, "");
-       ralloc_strcat (&parser->info_log, "Pasting \"");
-       _token_print (&parser->info_log, token);
-       ralloc_strcat (&parser->info_log, "\" and \"");
-       _token_print (&parser->info_log, other);
-       ralloc_strcat (&parser->info_log, "\" does not give a valid preprocessing token.\n");
+       ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "Pasting \"");
+       _token_print (&parser->info_log, &parser->info_log_length, token);
+       ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" and \"");
+       _token_print (&parser->info_log, &parser->info_log_length, other);
+       ralloc_asprintf_rewrite_tail (&parser->info_log, &parser->info_log_length, "\" does not give a valid preprocessing token.\n");
 
        return token;
 }
@@ -1061,7 +1178,7 @@ _token_list_print (glcpp_parser_t *parser, token_list_t *list)
                return;
 
        for (node = list->head; node; node = node->next)
-               _token_print (&parser->output, node->token);
+               _token_print (&parser->output, &parser->output_length, node->token);
 }
 
 void
@@ -1084,10 +1201,9 @@ static void add_builtin_define(glcpp_parser_t *parser,
 }
 
 glcpp_parser_t *
-glcpp_parser_create (const struct gl_extensions *extensions, int api)
+glcpp_parser_create (const struct gl_extensions *extensions, gl_api api)
 {
        glcpp_parser_t *parser;
-       int language_version;
 
        parser = ralloc (NULL, glcpp_parser_t);
 
@@ -1095,11 +1211,12 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
        parser->defines = hash_table_ctor (32, hash_table_string_hash,
                                           hash_table_string_compare);
        parser->active = NULL;
-       parser->lexing_if = 0;
+       parser->lexing_directive = 0;
        parser->space_tokens = 1;
        parser->newline_as_space = 0;
        parser->in_control_line = 0;
        parser->paren_count = 0;
+        parser->commented_newlines = 0;
 
        parser->skip_stack = NULL;
 
@@ -1107,43 +1224,23 @@ glcpp_parser_create (const struct gl_extensions *extensions, int api)
        parser->lex_from_node = NULL;
 
        parser->output = ralloc_strdup(parser, "");
+       parser->output_length = 0;
        parser->info_log = ralloc_strdup(parser, "");
+       parser->info_log_length = 0;
        parser->error = 0;
 
-       /* Add pre-defined macros. */
-       add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
-       add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
+        parser->extensions = extensions;
+        parser->api = api;
+        parser->version_resolved = false;
 
-       if (api == API_OPENGLES2)
-               add_builtin_define(parser, "GL_ES", 1);
-
-       if (extensions != NULL) {
-          if (extensions->EXT_texture_array) {
-             add_builtin_define(parser, "GL_EXT_texture_array", 1);
-          }
-
-          if (extensions->ARB_fragment_coord_conventions)
-             add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
-                                1);
-
-          if (extensions->ARB_explicit_attrib_location)
-             add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
-          if (extensions->AMD_conservative_depth)
-             add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
-       }
-
-       language_version = 110;
-       add_builtin_define(parser, "__VERSION__", language_version);
+       parser->has_new_line_number = 0;
+       parser->new_line_number = 1;
+       parser->has_new_source_number = 0;
+       parser->new_source_number = 0;
 
        return parser;
 }
 
-int
-glcpp_parser_parse (glcpp_parser_t *parser)
-{
-       return yyparse (parser);
-}
-
 void
 glcpp_parser_destroy (glcpp_parser_t *parser)
 {
@@ -1243,32 +1340,93 @@ _arguments_parse (argument_list_t *arguments,
 }
 
 static token_list_t *
-_token_list_create_with_one_space (void *ctx)
+_token_list_create_with_one_ival (void *ctx, int type, int ival)
 {
        token_list_t *list;
-       token_t *space;
+       token_t *node;
 
        list = _token_list_create (ctx);
-       space = _token_create_ival (list, SPACE, SPACE);
-       _token_list_append (list, space);
+       node = _token_create_ival (list, type, ival);
+       _token_list_append (list, node);
 
        return list;
 }
 
+static token_list_t *
+_token_list_create_with_one_space (void *ctx)
+{
+       return _token_list_create_with_one_ival (ctx, SPACE, SPACE);
+}
+
+static token_list_t *
+_token_list_create_with_one_integer (void *ctx, int ival)
+{
+       return _token_list_create_with_one_ival (ctx, INTEGER, ival);
+}
+
+/* Perform macro expansion on 'list', placing the resulting tokens
+ * into a new list which is initialized with a first token of type
+ * 'head_token_type'. Then begin lexing from the resulting list,
+ * (return to the current lexing source when this list is exhausted).
+ */
 static void
-_glcpp_parser_expand_if (glcpp_parser_t *parser, int type, token_list_t *list)
+_glcpp_parser_expand_and_lex_from (glcpp_parser_t *parser,
+                                  int head_token_type,
+                                  token_list_t *list)
 {
        token_list_t *expanded;
        token_t *token;
 
        expanded = _token_list_create (parser);
-       token = _token_create_ival (parser, type, type);
+       token = _token_create_ival (parser, head_token_type, head_token_type);
        _token_list_append (expanded, token);
        _glcpp_parser_expand_token_list (parser, list);
        _token_list_append_list (expanded, list);
        glcpp_parser_lex_from (parser, expanded);
 }
 
+static void
+_glcpp_parser_apply_pastes (glcpp_parser_t *parser, token_list_t *list)
+{
+       token_node_t *node;
+
+       node = list->head;
+       while (node)
+       {
+               token_node_t *next_non_space;
+
+               /* Look ahead for a PASTE token, skipping space. */
+               next_non_space = node->next;
+               while (next_non_space && next_non_space->token->type == SPACE)
+                       next_non_space = next_non_space->next;
+
+               if (next_non_space == NULL)
+                       break;
+
+               if (next_non_space->token->type != PASTE) {
+                       node = next_non_space;
+                       continue;
+               }
+
+               /* Now find the next non-space token after the PASTE. */
+               next_non_space = next_non_space->next;
+               while (next_non_space && next_non_space->token->type == SPACE)
+                       next_non_space = next_non_space->next;
+
+               if (next_non_space == NULL) {
+                       yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
+                       return;
+               }
+
+               node->token = _token_paste (parser, node->token, next_non_space->token);
+               node->next = next_non_space->next;
+               if (next_non_space == list->tail)
+                       list->tail = node;
+       }
+
+       list->non_space_tail = list->tail;
+}
+
 /* This is a helper function that's essentially part of the
  * implementation of _glcpp_parser_expand_node. It shouldn't be called
  * except for by that function.
@@ -1380,43 +1538,7 @@ _glcpp_parser_expand_function (glcpp_parser_t *parser,
 
        _token_list_trim_trailing_space (substituted);
 
-       node = substituted->head;
-       while (node)
-       {
-               token_node_t *next_non_space;
-
-               /* Look ahead for a PASTE token, skipping space. */
-               next_non_space = node->next;
-               while (next_non_space && next_non_space->token->type == SPACE)
-                       next_non_space = next_non_space->next;
-
-               if (next_non_space == NULL)
-                       break;
-
-               if (next_non_space->token->type != PASTE) {
-                       node = next_non_space;
-                       continue;
-               }
-
-               /* Now find the next non-space token after the PASTE. */
-               next_non_space = next_non_space->next;
-               while (next_non_space && next_non_space->token->type == SPACE)
-                       next_non_space = next_non_space->next;
-
-               if (next_non_space == NULL) {
-                       yyerror (&node->token->location, parser, "'##' cannot appear at either end of a macro expansion\n");
-                       return NULL;
-               }
-
-               node->token = _token_paste (parser, node->token, next_non_space->token);
-               node->next = next_non_space->next;
-               if (next_non_space == substituted->tail)
-                       substituted->tail = node;
-
-               node = node->next;
-       }
-
-       substituted->non_space_tail = substituted->tail;
+       _glcpp_parser_apply_pastes (parser, substituted);
 
        return substituted;
 }
@@ -1458,8 +1580,18 @@ _glcpp_parser_expand_node (glcpp_parser_t *parser,
                return NULL;
        }
 
-       /* Look up this identifier in the hash table. */
+       *last = node;
        identifier = token->value.str;
+
+       /* Special handling for __LINE__ and __FILE__, (not through
+        * the hash table). */
+       if (strcmp(identifier, "__LINE__") == 0)
+               return _token_list_create_with_one_integer (parser, node->token->location.first_line);
+
+       if (strcmp(identifier, "__FILE__") == 0)
+               return _token_list_create_with_one_integer (parser, node->token->location.source);
+
+       /* Look up this identifier in the hash table. */
        macro = hash_table_find (parser->defines, identifier);
 
        /* Not a macro, so no expansion needed. */
@@ -1480,19 +1612,20 @@ _glcpp_parser_expand_node (glcpp_parser_t *parser,
                final = _token_create_str (parser, OTHER, str);
                expansion = _token_list_create (parser);
                _token_list_append (expansion, final);
-               *last = node;
                return expansion;
        }
 
        if (! macro->is_function)
        {
-               *last = node;
+               token_list_t *replacement;
 
                /* Replace a macro defined as empty with a SPACE token. */
                if (macro->replacements == NULL)
                        return _token_list_create_with_one_space (parser);
 
-               return _token_list_copy (parser, macro->replacements);
+               replacement = _token_list_copy (parser, macro->replacements);
+               _glcpp_parser_apply_pastes (parser, replacement);
+               return replacement;
        }
 
        return _glcpp_parser_expand_function (parser, node, last);
@@ -1645,11 +1778,27 @@ static void
 _check_for_reserved_macro_name (glcpp_parser_t *parser, YYLTYPE *loc,
                                const char *identifier)
 {
-       /* According to the GLSL specification, macro names starting with "__"
-        * or "GL_" are reserved for future use.  So, don't allow them.
+       /* Section 3.3 (Preprocessor) of the GLSL 1.30 spec (and later) and
+        * the GLSL ES spec (all versions) say:
+        *
+        *     "All macro names containing two consecutive underscores ( __ )
+        *     are reserved for future use as predefined macro names. All
+        *     macro names prefixed with "GL_" ("GL" followed by a single
+        *     underscore) are also reserved."
+        *
+        * The intention is that names containing __ are reserved for internal
+        * use by the implementation, and names prefixed with GL_ are reserved
+        * for use by Khronos.  Since every extension adds a name prefixed
+        * with GL_ (i.e., the name of the extension), that should be an
+        * error.  Names simply containing __ are dangerous to use, but should
+        * be allowed.
+        *
+        * A future version of the GLSL specification will clarify this.
         */
-       if (strncmp(identifier, "__", 2) == 0) {
-               glcpp_error (loc, parser, "Macro names starting with \"__\" are reserved.\n");
+       if (strstr(identifier, "__")) {
+               glcpp_warning(loc, parser,
+                             "Macro names containing \"__\" are reserved "
+                             "for use by the implementation.\n");
        }
        if (strncmp(identifier, "GL_", 3) == 0) {
                glcpp_error (loc, parser, "Macro names starting with \"GL_\" are reserved.\n");
@@ -1776,7 +1925,7 @@ glcpp_parser_lex (YYSTYPE *yylval, YYLTYPE *yylloc, glcpp_parser_t *parser)
                        if (ret == NEWLINE)
                                parser->in_control_line = 0;
                }
-               else if (ret == HASH_DEFINE_OBJ || ret == HASH_DEFINE_FUNC ||
+               else if (ret == HASH_DEFINE ||
                           ret == HASH_UNDEF || ret == HASH_IF ||
                           ret == HASH_IFDEF || ret == HASH_IFNDEF ||
                           ret == HASH_ELIF || ret == HASH_ELSE ||
@@ -1863,6 +2012,7 @@ _glcpp_parser_skip_stack_push_if (glcpp_parser_t *parser, YYLTYPE *loc,
                node->type = SKIP_TO_ENDIF;
        }
 
+       node->has_else = false;
        node->next = parser->skip_stack;
        parser->skip_stack = node;
 }
@@ -1898,3 +2048,162 @@ _glcpp_parser_skip_stack_pop (glcpp_parser_t *parser, YYLTYPE *loc)
        parser->skip_stack = node->next;
        ralloc_free (node);
 }
+
+static void
+_glcpp_parser_handle_version_declaration(glcpp_parser_t *parser, intmax_t version,
+                                         const char *es_identifier,
+                                         bool explicitly_set)
+{
+       const struct gl_extensions *extensions = parser->extensions;
+
+       if (parser->version_resolved)
+               return;
+
+       parser->version_resolved = true;
+
+       add_builtin_define (parser, "__VERSION__", version);
+
+       parser->is_gles = (version == 100) ||
+                          (es_identifier &&
+                           (strcmp(es_identifier, "es") == 0));
+
+       /* Add pre-defined macros. */
+       if (parser->is_gles) {
+          add_builtin_define(parser, "GL_ES", 1);
+           add_builtin_define(parser, "GL_EXT_separate_shader_objects", 1);
+
+          if (extensions != NULL) {
+             if (extensions->OES_EGL_image_external)
+                add_builtin_define(parser, "GL_OES_EGL_image_external", 1);
+          }
+       } else {
+          add_builtin_define(parser, "GL_ARB_draw_buffers", 1);
+           add_builtin_define(parser, "GL_ARB_separate_shader_objects", 1);
+          add_builtin_define(parser, "GL_ARB_texture_rectangle", 1);
+           add_builtin_define(parser, "GL_AMD_shader_trinary_minmax", 1);
+
+
+          if (extensions != NULL) {
+             if (extensions->EXT_texture_array)
+                add_builtin_define(parser, "GL_EXT_texture_array", 1);
+
+             if (extensions->ARB_arrays_of_arrays)
+                 add_builtin_define(parser, "GL_ARB_arrays_of_arrays", 1);
+
+             if (extensions->ARB_fragment_coord_conventions)
+                add_builtin_define(parser, "GL_ARB_fragment_coord_conventions",
+                                   1);
+
+              if (extensions->ARB_fragment_layer_viewport)
+                 add_builtin_define(parser, "GL_ARB_fragment_layer_viewport", 1);
+
+             if (extensions->ARB_explicit_attrib_location)
+                add_builtin_define(parser, "GL_ARB_explicit_attrib_location", 1);
+
+             if (extensions->ARB_explicit_uniform_location)
+                add_builtin_define(parser, "GL_ARB_explicit_uniform_location", 1);
+
+             if (extensions->ARB_shader_texture_lod)
+                add_builtin_define(parser, "GL_ARB_shader_texture_lod", 1);
+
+             if (extensions->ARB_draw_instanced)
+                add_builtin_define(parser, "GL_ARB_draw_instanced", 1);
+
+             if (extensions->ARB_conservative_depth) {
+                add_builtin_define(parser, "GL_AMD_conservative_depth", 1);
+                add_builtin_define(parser, "GL_ARB_conservative_depth", 1);
+             }
+
+             if (extensions->ARB_shader_bit_encoding)
+                add_builtin_define(parser, "GL_ARB_shader_bit_encoding", 1);
+
+             if (extensions->ARB_uniform_buffer_object)
+                add_builtin_define(parser, "GL_ARB_uniform_buffer_object", 1);
+
+             if (extensions->ARB_texture_cube_map_array)
+                add_builtin_define(parser, "GL_ARB_texture_cube_map_array", 1);
+
+             if (extensions->ARB_shading_language_packing)
+                add_builtin_define(parser, "GL_ARB_shading_language_packing", 1);
+
+             if (extensions->ARB_texture_multisample)
+                add_builtin_define(parser, "GL_ARB_texture_multisample", 1);
+
+             if (extensions->ARB_texture_query_levels)
+                add_builtin_define(parser, "GL_ARB_texture_query_levels", 1);
+
+             if (extensions->ARB_texture_query_lod)
+                add_builtin_define(parser, "GL_ARB_texture_query_lod", 1);
+
+             if (extensions->ARB_gpu_shader5)
+                add_builtin_define(parser, "GL_ARB_gpu_shader5", 1);
+
+             if (extensions->AMD_vertex_shader_layer)
+                add_builtin_define(parser, "GL_AMD_vertex_shader_layer", 1);
+
+             if (extensions->AMD_vertex_shader_viewport_index)
+                add_builtin_define(parser, "GL_AMD_vertex_shader_viewport_index", 1);
+
+             if (extensions->ARB_shading_language_420pack)
+                add_builtin_define(parser, "GL_ARB_shading_language_420pack", 1);
+
+             if (extensions->ARB_sample_shading)
+                add_builtin_define(parser, "GL_ARB_sample_shading", 1);
+
+             if (extensions->ARB_texture_gather)
+                add_builtin_define(parser, "GL_ARB_texture_gather", 1);
+
+             if (extensions->ARB_shader_atomic_counters)
+                add_builtin_define(parser, "GL_ARB_shader_atomic_counters", 1);
+
+             if (extensions->ARB_viewport_array)
+                add_builtin_define(parser, "GL_ARB_viewport_array", 1);
+
+              if (extensions->ARB_compute_shader)
+                 add_builtin_define(parser, "GL_ARB_compute_shader", 1);
+
+             if (extensions->ARB_shader_image_load_store)
+                add_builtin_define(parser, "GL_ARB_shader_image_load_store", 1);
+          }
+       }
+
+       if (extensions != NULL) {
+          if (extensions->EXT_shader_integer_mix)
+             add_builtin_define(parser, "GL_EXT_shader_integer_mix", 1);
+       }
+
+       if (version >= 150)
+               add_builtin_define(parser, "GL_core_profile", 1);
+
+       /* Currently, all ES2/ES3 implementations support highp in the
+        * fragment shader, so we always define this macro in ES2/ES3.
+        * If we ever get a driver that doesn't support highp, we'll
+        * need to add a flag to the gl_context and check that here.
+        */
+       if (version >= 130 || parser->is_gles)
+               add_builtin_define (parser, "GL_FRAGMENT_PRECISION_HIGH", 1);
+
+       if (explicitly_set) {
+          ralloc_asprintf_rewrite_tail (&parser->output, &parser->output_length,
+                                        "#version %" PRIiMAX "%s%s", version,
+                                        es_identifier ? " " : "",
+                                        es_identifier ? es_identifier : "");
+       }
+}
+
+/* GLSL version if no version is explicitly specified. */
+#define IMPLICIT_GLSL_VERSION 110
+
+/* GLSL ES version if no version is explicitly specified. */
+#define IMPLICIT_GLSL_ES_VERSION 100
+
+void
+glcpp_parser_resolve_implicit_version(glcpp_parser_t *parser)
+{
+       int language_version = parser->api == API_OPENGLES2 ?
+                              IMPLICIT_GLSL_ES_VERSION :
+                              IMPLICIT_GLSL_VERSION;
+
+       _glcpp_parser_handle_version_declaration(parser, language_version,
+                                                NULL, false);
+}