Initial commit. lol
authorIan Romanick <ian.d.romanick@intel.com>
Mon, 22 Feb 2010 21:19:34 +0000 (13:19 -0800)
committerIan Romanick <ian.d.romanick@intel.com>
Mon, 22 Feb 2010 21:19:34 +0000 (13:19 -0800)
26 files changed:
.dir-locals.el [new file with mode: 0644]
Makefile [new file with mode: 0644]
ast.h [new file with mode: 0644]
ast_to_hir.cc [new file with mode: 0644]
builtin_types.sh [new file with mode: 0755]
glsl_lexer.l [new file with mode: 0644]
glsl_parser.y [new file with mode: 0644]
glsl_parser_extras.cc [new file with mode: 0644]
glsl_parser_extras.h [new file with mode: 0644]
glsl_types.c [new file with mode: 0644]
glsl_types.h [new file with mode: 0644]
hash_table.c [new file with mode: 0644]
hash_table.h [new file with mode: 0644]
hir_field_selection.cc [new file with mode: 0644]
hir_function.c [new file with mode: 0644]
ir.cc [new file with mode: 0644]
ir.h [new file with mode: 0644]
main/imports.h [new file with mode: 0644]
main/simple_list.h [new file with mode: 0644]
symbol_table.c [new file with mode: 0644]
symbol_table.h [new file with mode: 0644]
tests/parameters-01.txt [new file with mode: 0644]
tests/parameters-02.txt [new file with mode: 0644]
tests/parameters-03.txt [new file with mode: 0644]
tests/swiz-01.glsl [new file with mode: 0644]
tests/swiz-02.glsl [new file with mode: 0644]

diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644 (file)
index 0000000..148e4ca
--- /dev/null
@@ -0,0 +1 @@
+((c-mode . ((c-basic-offset . 3))))
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2f2142e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,40 @@
+CSRCS = symbol_table.c hash_table.c glsl_types.c 
+CCSRCS = glsl_parser.tab.cc glsl_lexer.cc glsl_parser_extras.cc
+#      ast_to_hir.cc ir.cc hir_field_selection.cc
+OBJS = $(CSRCS:.c=.o)  $(CCSRCS:.cc=.o)
+
+CC = gcc
+CXX = g++
+WARN     = -Wall -Wextra -Wunsafe-loop-optimizations -Wstack-protector \
+       -Wunreachable-code
+CPPFLAGS = -D_FORTIFY_SOURCE=2 -D_GNU_SOURCE
+CFLAGS   = -O0 -ggdb3 -fstack-protector $(CPPFLAGS) $(WARN) -std=c89 -ansi -pedantic
+CXXFLAGS = -O0 -ggdb3 -fstack-protector $(CPPFLAGS) $(WARN)
+LDLAGS   = -ggdb3
+
+glsl: $(OBJS)
+       $(CXX) $(LDLAGS) $(OBJS) -o glsl
+
+glsl_parser.tab.cc glsl_parser.tab.h: glsl_parser.y
+       bison --report-file=glsl_parser.output -v -d \
+           --output=glsl_parser.tab.cc \
+           --name-prefix=_mesa_glsl_ $< && \
+       mv glsl_parser.tab.hh glsl_parser.tab.h
+
+glsl_lexer.cc: glsl_lexer.l
+       flex --outfile="glsl_lexer.cc" $<
+
+glsl_parser_tab.o: glsl_parser.tab.cc
+glsl_types.o: glsl_types.c glsl_types.h builtin_types.h
+glsl_lexer.o: glsl_lexer.cc glsl_parser.tab.h glsl_parser_extras.h ast.h
+glsl_parser.o:  glsl_parser_extras.h ast.h
+ast_to_hir.o: ast_to_hir.cc symbol_table.h glsl_parser_extras.h ast.h glsl_types.h ir.h
+
+builtin_types.h: builtin_types.sh
+       ./builtin_types.sh > builtin_types.h
+
+clean:
+       rm -f $(OBJS) glsl
+       rm -f glsl_lexer.cc glsl_parser.tab.{cc,h,hh} glsl_parser.output
+       rm -f builtin_types.h
+       rm -f *~
\ No newline at end of file
diff --git a/ast.h b/ast.h
new file mode 100644 (file)
index 0000000..591655d
--- /dev/null
+++ b/ast.h
@@ -0,0 +1,511 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef AST_H
+#define AST_H
+
+#include "main/simple_list.h"
+#include "glsl_parser_extras.h"
+
+struct ir_instruction;
+struct _mesa_glsl_parse_state;
+
+struct YYLTYPE;
+
+#define _mesa_ast_print(n) \
+   ((ast_node *) n)->print()
+
+#define _mesa_ast_to_hir(n, instr, s)                                  \
+   ((struct ast_node *) n)->vtbl->to_hir((struct ast_node *) n, instr, s)
+
+#define _mesa_ast_function_call_to_hir(n, p, s)                                \
+   ((struct ast_node *) n)->vtbl->function_call_to_hir(                        \
+                                       (struct ast_node *) n,          \
+                                       (struct ast_node *) p,          \
+                                       s)
+
+class ast_node : public simple_node {
+public:
+   virtual ~ast_node();
+   virtual void print(void) const;
+
+   /**
+    * Retrieve the source location of an AST node
+    *
+    * This function is primarily used to get the source position of an AST node
+    * into a form that can be passed to \c _mesa_glsl_error.
+    *
+    * \sa _mesa_glsl_error, ast_node::set_location
+    */
+   struct YYLTYPE get_location(void) const
+   {
+      struct YYLTYPE locp;
+
+      locp.source = this->location.source;
+      locp.first_line = this->location.line;
+      locp.first_column = this->location.column;
+      locp.last_line = locp.first_line;
+      locp.last_column = locp.first_column;
+
+      return locp;
+   }
+
+   /**
+    * Set the source location of an AST node from a parser location
+    *
+    * \sa ast_node::get_location
+    */
+   void set_location(const struct YYLTYPE *locp)
+   {
+      this->location.source = locp->source;
+      this->location.line = locp->first_line;
+      this->location.column = locp->first_column;
+   }
+
+
+   int  type;
+
+   struct {
+      unsigned source;
+      unsigned line;
+      unsigned column;
+   } location;
+
+protected:
+   ast_node(void);
+};
+
+
+enum ast_operators {
+   ast_assign,
+   ast_plus,        /**< Unary + operator. */
+   ast_neg,
+   ast_add,
+   ast_sub,
+   ast_mul,
+   ast_div,
+   ast_mod,
+   ast_lshift,
+   ast_rshift,
+   ast_less,
+   ast_greater,
+   ast_lequal,
+   ast_gequal,
+   ast_equal,
+   ast_nequal,
+   ast_bit_and,
+   ast_bit_xor,
+   ast_bit_or,
+   ast_bit_not,
+   ast_logic_and,
+   ast_logic_xor,
+   ast_logic_or,
+   ast_logic_not,
+
+   ast_mul_assign,
+   ast_div_assign,
+   ast_mod_assign,
+   ast_add_assign,
+   ast_sub_assign,
+   ast_ls_assign,
+   ast_rs_assign,
+   ast_and_assign,
+   ast_xor_assign,
+   ast_or_assign,
+
+   ast_conditional,
+
+   ast_pre_inc,
+   ast_pre_dec,
+   ast_post_inc,
+   ast_post_dec,
+   ast_field_selection,
+   ast_array_index,
+
+   ast_function_call,
+
+   ast_identifier,
+   ast_int_constant,
+   ast_uint_constant,
+   ast_float_constant,
+   ast_bool_constant,
+
+   ast_sequence
+};
+
+class ast_expression : public ast_node {
+public:
+   ast_expression(int oper, ast_expression *,
+                 ast_expression *, ast_expression *);
+
+   virtual void print(void) const;
+
+   enum ast_operators oper;
+
+   ast_expression *subexpressions[3];
+
+   union {
+      char *identifier;
+      int int_constant;
+      float float_constant;
+      unsigned uint_constant;
+      int bool_constant;
+   } primary_expression;
+
+
+   /**
+    * List of expressions for an \c ast_sequence.
+    */
+   struct simple_node expressions;
+};
+
+/**
+ * Number of possible operators for an ast_expression
+ *
+ * This is done as a define instead of as an additional value in the enum so
+ * that the compiler won't generate spurious messages like "warning:
+ * enumeration value ‘ast_num_operators’ not handled in switch"
+ */
+#define AST_NUM_OPERATORS (ast_sequence + 1)
+
+
+class ast_compound_statement : public ast_node {
+public:
+   ast_compound_statement(int new_scope, ast_node *statements);
+   virtual void print(void) const;
+
+   int new_scope;
+   struct simple_node statements;
+};
+
+class ast_declaration : public ast_node {
+public:
+   ast_declaration(char *identifier, int is_array, ast_expression *array_size,
+                  ast_expression *initializer);
+   virtual void print(void) const;
+
+   char *identifier;
+   
+   int is_array;
+   ast_expression *array_size;
+
+   ast_expression *initializer;
+};
+
+
+enum {
+   ast_precision_high = 0, /**< Default precision. */
+   ast_precision_medium,
+   ast_precision_low
+};
+
+struct ast_type_qualifier {
+   unsigned invariant:1;
+   unsigned constant:1;
+   unsigned attribute:1;
+   unsigned varying:1;
+   unsigned in:1;
+   unsigned out:1;
+   unsigned centroid:1;
+   unsigned uniform:1;
+   unsigned smooth:1;
+   unsigned flat:1;
+   unsigned noperspective:1;
+};
+
+class ast_struct_specifier : public ast_node {
+public:
+   ast_struct_specifier(char *identifier, ast_node *declarator_list);
+   virtual void print(void) const;
+
+   char *name;
+   struct simple_node declarations;
+};
+
+
+enum ast_types {
+   ast_void,
+   ast_float,
+   ast_int,
+   ast_uint,
+   ast_bool,
+   ast_vec2,
+   ast_vec3,
+   ast_vec4,
+   ast_bvec2,
+   ast_bvec3,
+   ast_bvec4,
+   ast_ivec2,
+   ast_ivec3,
+   ast_ivec4,
+   ast_uvec2,
+   ast_uvec3,
+   ast_uvec4,
+   ast_mat2,
+   ast_mat2x3,
+   ast_mat2x4,
+   ast_mat3x2,
+   ast_mat3,
+   ast_mat3x4,
+   ast_mat4x2,
+   ast_mat4x3,
+   ast_mat4,
+   ast_sampler1d,
+   ast_sampler2d,
+   ast_sampler3d,
+   ast_samplercube,
+   ast_sampler1dshadow,
+   ast_sampler2dshadow,
+   ast_samplercubeshadow,
+   ast_sampler1darray,
+   ast_sampler2darray,
+   ast_sampler1darrayshadow,
+   ast_sampler2darrayshadow,
+   ast_isampler1d,
+   ast_isampler2d,
+   ast_isampler3d,
+   ast_isamplercube,
+   ast_isampler1darray,
+   ast_isampler2darray,
+   ast_usampler1d,
+   ast_usampler2d,
+   ast_usampler3d,
+   ast_usamplercube,
+   ast_usampler1darray,
+   ast_usampler2darray,
+
+   ast_struct,
+   ast_type_name
+};
+
+
+class ast_type_specifier : public ast_node {
+public:
+   ast_type_specifier(int specifier);
+
+   virtual void print(void) const;
+
+   enum ast_types type_specifier;
+
+   char *type_name;
+   ast_struct_specifier *structure;
+
+   int is_array;
+   ast_expression *array_size;
+
+   unsigned precision:2;
+};
+
+
+class ast_fully_specified_type : public ast_node {
+public:
+   virtual void print(void) const;
+
+   ast_type_qualifier qualifier;
+   ast_type_specifier *specifier;
+};
+
+
+class ast_declarator_list : public ast_node {
+public:
+   ast_declarator_list(ast_fully_specified_type *);
+   virtual void print(void) const;
+
+   ast_fully_specified_type *type;
+   struct simple_node declarations;
+
+   /**
+    * Special flag for vertex shader "invariant" declarations.
+    *
+    * Vertex shaders can contain "invariant" variable redeclarations that do
+    * not include a type.  For example, "invariant gl_Position;".  This flag
+    * is used to note these cases when no type is specified.
+    */
+   int invariant;
+};
+
+
+class ast_parameter_declarator : public ast_node {
+public:
+   virtual void print(void) const;
+
+   ast_fully_specified_type *type;
+   char *identifier;
+   int is_array;
+   ast_expression *array_size;
+};
+
+
+class ast_function : public ast_node {
+public:
+   ast_function(void);
+
+   virtual void print(void) const;
+
+   ast_fully_specified_type *return_type;
+   char *identifier;
+
+   struct simple_node parameters;
+};
+
+
+class ast_declaration_statement : public ast_node {
+public:
+   ast_declaration_statement(void);
+
+   enum {
+      ast_function,
+      ast_declaration,
+      ast_precision
+   } mode;
+
+   union {
+      class ast_function *function;
+      ast_declarator_list *declarator;
+      ast_type_specifier *type;
+      ast_node *node;
+   } declaration;
+};
+
+
+class ast_expression_statement : public ast_node {
+public:
+   ast_expression_statement(ast_expression *);
+   virtual void print(void) const;
+
+   ast_expression *expression;
+};
+
+
+class ast_case_label : public ast_node {
+public:
+
+   /**
+    * An expression of NULL means 'default'.
+    */
+   ast_expression *expression;
+};
+
+class ast_selection_statement : public ast_node {
+public:
+   ast_selection_statement(ast_expression *condition,
+                          ast_node *then_statement,
+                          ast_node *else_statement);
+   virtual void print(void) const;
+
+   ast_expression *condition;
+   ast_node *then_statement;
+   ast_node *else_statement;
+};
+
+
+class ast_switch_statement : public ast_node {
+public:
+   ast_expression *expression;
+   struct simple_node statements;
+};
+
+class ast_iteration_statement : public ast_node {
+public:
+   ast_iteration_statement(int mode, ast_node *init, ast_node *condition,
+                          ast_expression *rest_expression, ast_node *body);
+
+   virtual void print(void) const;
+
+   enum ast_iteration_modes {
+      ast_for,
+      ast_while,
+      ast_do_while
+   } mode;
+   
+
+   ast_node *init_statement;
+   ast_node *condition;
+   ast_expression *rest_expression;
+
+   ast_node *body;
+};
+
+
+class ast_jump_statement : public ast_node {
+public:
+   ast_jump_statement(int mode, ast_expression *return_value);
+   virtual void print(void) const;
+
+   enum ast_jump_modes {
+      ast_continue,
+      ast_break,
+      ast_return,
+      ast_discard
+   } mode;
+
+   ast_expression *opt_return_value;
+};
+
+
+class ast_function_definition : public ast_node {
+public:
+   virtual void print(void) const;
+
+   ast_function *prototype;
+   ast_compound_statement *body;
+};
+
+
+extern struct ir_instruction *
+ast_expression_to_hir(const ast_node *ast,
+                     struct simple_node *instructions,
+                     struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+ast_expression_statement_to_hir(const struct ast_node *ast,
+                               struct simple_node *instructions,
+                               struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+ast_compound_statement_to_hir(const struct ast_node *ast,
+                             struct simple_node *instructions,
+                             struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+ast_function_definition_to_hir(const struct ast_node *ast,
+                              struct simple_node *instructions,
+                              struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+ast_declarator_list_to_hir(const struct ast_node *ast,
+                          struct simple_node *instructions,
+                          struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+ast_parameter_declarator_to_hir(const struct ast_node *ast,
+                               struct simple_node *instructions,
+                               struct _mesa_glsl_parse_state *state);
+
+extern struct ir_instruction *
+_mesa_ast_field_selection_to_hir(const struct ast_expression *expr,
+                                struct simple_node *instructions,
+                                struct _mesa_glsl_parse_state *state);
+
+#endif /* AST_H */
diff --git a/ast_to_hir.cc b/ast_to_hir.cc
new file mode 100644 (file)
index 0000000..8474a46
--- /dev/null
@@ -0,0 +1,1172 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file ast_to_hir.c
+ * Convert abstract syntax to to high-level intermediate reprensentation (HIR).
+ *
+ * During the conversion to HIR, the majority of the symantic checking is
+ * preformed on the program.  This includes:
+ *
+ *    * Symbol table management
+ *    * Type checking
+ *    * Function binding
+ *
+ * The majority of this work could be done during parsing, and the parser could
+ * probably generate HIR directly.  However, this results in frequent changes
+ * to the parser code.  Since we do not assume that every system this complier
+ * is built on will have Flex and Bison installed, we have to store the code
+ * generated by these tools in our version control system.  In other parts of
+ * the system we've seen problems where a parser was changed but the generated
+ * code was not committed, merge conflicts where created because two developers
+ * had slightly different versions of Bison installed, etc.
+ *
+ * I have also noticed that running Bison generated parsers in GDB is very
+ * irritating.  When you get a segfault on '$$ = $1->foo', you can't very
+ * well 'print $1' in GDB.
+ *
+ * As a result, my preference is to put as little C code as possible in the
+ * parser (and lexer) sources.
+ */
+#include <stdio.h>
+#include "main/imports.h"
+#include "symbol_table.h"
+#include "glsl_parser_extras.h"
+#include "ast.h"
+#include "glsl_types.h"
+#include "ir.h"
+
+void
+_mesa_generate_hir_from_ast(struct _mesa_glsl_parse_state *state)
+{
+   struct simple_node *ptr;
+
+   foreach (ptr, & state->translation_unit) {
+      if (1) {
+      }
+   }
+}
+
+
+static const struct glsl_type *
+arithmetic_result_type(const struct glsl_type *type_a,
+                      const struct glsl_type *type_b,
+                      bool multiply,
+                      struct _mesa_glsl_parse_state *state)
+{
+   /* From GLSL 1.50 spec, page 56:
+    *
+    *    "The arithmetic binary operators add (+), subtract (-),
+    *    multiply (*), and divide (/) operate on integer and
+    *    floating-point scalars, vectors, and matrices."
+    */
+   if (! is_numeric_base_type(type_a->base_type)
+       || ! is_numeric_base_type(type_b->base_type)) {
+      return glsl_error_type;
+   }
+
+
+   /*    "If one operand is floating-point based and the other is
+    *    not, then the conversions from Section 4.1.10 "Implicit
+    *    Conversions" are applied to the non-floating-point-based operand."
+    *
+    * This conversion was added in GLSL 1.20.  If the compilation mode is
+    * GLSL 1.10, the conversion is skipped.
+    */
+   if (state->language_version >= 120) {
+      if ((type_a->base_type == GLSL_TYPE_FLOAT)
+         && (type_b->base_type != GLSL_TYPE_FLOAT)) {
+      } else if ((type_a->base_type != GLSL_TYPE_FLOAT)
+                && (type_b->base_type == GLSL_TYPE_FLOAT)) {
+      }
+   }
+      
+   /*    "If the operands are integer types, they must both be signed or
+    *    both be unsigned."
+    *
+    * From this rule and the preceeding conversion it can be inferred that
+    * both types must be GLSL_TYPE_FLOAT, or GLSL_TYPE_UINT, or GLSL_TYPE_INT.
+    * The is_numeric_base_type check above already filtered out the case
+    * where either type is not one of these, so now the base types need only
+    * be tested for equality.
+    */
+   if (type_a->base_type != type_b->base_type) {
+      return glsl_error_type;
+   }
+
+   /*    "All arithmetic binary operators result in the same fundamental type
+    *    (signed integer, unsigned integer, or floating-point) as the
+    *    operands they operate on, after operand type conversion. After
+    *    conversion, the following cases are valid
+    *
+    *    * The two operands are scalars. In this case the operation is
+    *      applied, resulting in a scalar."
+    */
+   if (is_glsl_type_scalar(type_a) && is_glsl_type_scalar(type_b))
+      return type_a;
+
+   /*   "* One operand is a scalar, and the other is a vector or matrix.
+    *      In this case, the scalar operation is applied independently to each
+    *      component of the vector or matrix, resulting in the same size
+    *      vector or matrix."
+    */
+   if (is_glsl_type_scalar(type_a)) {
+      if (!is_glsl_type_scalar(type_b))
+        return type_b;
+   } else if (is_glsl_type_scalar(type_b)) {
+      return type_a;
+   }
+
+   /* All of the combinations of <scalar, scalar>, <vector, scalar>,
+    * <scalar, vector>, <scalar, matrix>, and <matrix, scalar> have been
+    * handled.
+    */
+   assert(type_a->vector_elements > 1);
+   assert(type_b->vector_elements > 1);
+
+   /*   "* The two operands are vectors of the same size. In this case, the
+    *      operation is done component-wise resulting in the same size
+    *      vector."
+    */
+   if (is_glsl_type_vector(type_a) && is_glsl_type_vector(type_b)) {
+      if (type_a->vector_elements == type_b->vector_elements)
+        return type_a;
+      else
+        return glsl_error_type;
+   }
+
+   /* All of the combinations of <scalar, scalar>, <vector, scalar>,
+    * <scalar, vector>, <scalar, matrix>, <matrix, scalar>, and
+    * <vector, vector> have been handled.  At least one of the operands must
+    * be matrix.  Further, since there are no integer matrix types, the base
+    * type of both operands must be float.
+    */
+   assert((type_a->matrix_rows > 1) || (type_b->matrix_rows > 1));
+   assert(type_a->base_type == GLSL_TYPE_FLOAT);
+   assert(type_b->base_type == GLSL_TYPE_FLOAT);
+
+   /*   "* The operator is add (+), subtract (-), or divide (/), and the
+    *      operands are matrices with the same number of rows and the same
+    *      number of columns. In this case, the operation is done component-
+    *      wise resulting in the same size matrix."
+    *    * The operator is multiply (*), where both operands are matrices or
+    *      one operand is a vector and the other a matrix. A right vector
+    *      operand is treated as a column vector and a left vector operand as a
+    *      row vector. In all these cases, it is required that the number of
+    *      columns of the left operand is equal to the number of rows of the
+    *      right operand. Then, the multiply (*) operation does a linear
+    *      algebraic multiply, yielding an object that has the same number of
+    *      rows as the left operand and the same number of columns as the right
+    *      operand. Section 5.10 "Vector and Matrix Operations" explains in
+    *      more detail how vectors and matrices are operated on."
+    */
+   if (! multiply) {
+      if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b)
+         && (type_a->vector_elements == type_b->vector_elements)
+         && (type_a->matrix_rows == type_b->matrix_rows))
+        return type_a;
+      else
+        return glsl_error_type;
+   } else {
+      if (is_glsl_type_matrix(type_a) && is_glsl_type_matrix(type_b)) {
+        if (type_a->vector_elements == type_b->matrix_rows) {
+           char type_name[7];
+           const struct glsl_type *t;
+
+           type_name[0] = 'm';
+           type_name[1] = 'a';
+           type_name[2] = 't';
+
+           if (type_a->matrix_rows == type_b->vector_elements) {
+              type_name[3] = '0' + type_a->matrix_rows;
+              type_name[4] = '\0';
+           } else {
+              type_name[3] = '0' + type_a->matrix_rows;
+              type_name[4] = 'x';
+              type_name[5] = '0' + type_b->vector_elements;
+              type_name[6] = '\0';
+           }
+
+           t = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
+           return (t != NULL) ? t : glsl_error_type;
+        }
+      } else if (is_glsl_type_matrix(type_a)) {
+        /* A is a matrix and B is a column vector.  Columns of A must match
+         * rows of B.
+         */
+        if (type_a->vector_elements == type_b->vector_elements)
+           return type_b;
+      } else {
+        assert(is_glsl_type_matrix(type_b));
+
+        /* A is a row vector and B is a matrix.  Columns of A must match
+         * rows of B.
+         */
+        if (type_a->vector_elements == type_b->matrix_rows)
+           return type_a;
+      }
+   }
+
+
+   /*    "All other cases are illegal."
+    */
+   return glsl_error_type;
+}
+
+
+static const struct glsl_type *
+unary_arithmetic_result_type(const struct glsl_type *type)
+{
+   /* From GLSL 1.50 spec, page 57:
+    *
+    *    "The arithmetic unary operators negate (-), post- and pre-increment
+    *     and decrement (-- and ++) operate on integer or floating-point
+    *     values (including vectors and matrices). All unary operators work
+    *     component-wise on their operands. These result with the same type
+    *     they operated on."
+    */
+   if (!is_numeric_base_type(type->base_type))
+      return glsl_error_type;
+
+   return type;
+}
+
+
+static const struct glsl_type *
+modulus_result_type(const struct glsl_type *type_a,
+                   const struct glsl_type *type_b)
+{
+   /* From GLSL 1.50 spec, page 56:
+    *    "The operator modulus (%) operates on signed or unsigned integers or
+    *    integer vectors. The operand types must both be signed or both be
+    *    unsigned."
+    */
+   if (! is_integer_base_type(type_a->base_type)
+       || ! is_integer_base_type(type_b->base_type)
+       || (type_a->base_type != type_b->base_type)) {
+      return glsl_error_type;
+   }
+
+   /*    "The operands cannot be vectors of differing size. If one operand is
+    *    a scalar and the other vector, then the scalar is applied component-
+    *    wise to the vector, resulting in the same type as the vector. If both
+    *    are vectors of the same size, the result is computed component-wise."
+    */
+   if (is_glsl_type_vector(type_a)) {
+      if (!is_glsl_type_vector(type_b)
+         || (type_a->vector_elements == type_b->vector_elements))
+        return type_a;
+   } else
+      return type_b;
+
+   /*    "The operator modulus (%) is not defined for any other data types
+    *    (non-integer types)."
+    */
+   return glsl_error_type;
+}
+
+
+static const struct glsl_type *
+relational_result_type(const struct glsl_type *type_a,
+                      const struct glsl_type *type_b,
+                      struct _mesa_glsl_parse_state *state)
+{
+   /* From GLSL 1.50 spec, page 56:
+    *    "The relational operators greater than (>), less than (<), greater
+    *    than or equal (>=), and less than or equal (<=) operate only on
+    *    scalar integer and scalar floating-point expressions."
+    */
+   if (! is_numeric_base_type(type_a->base_type)
+       || ! is_numeric_base_type(type_b->base_type)
+       || ! is_glsl_type_scalar(type_a) 
+       || ! is_glsl_type_scalar(type_b))
+      return glsl_error_type;
+
+   /*    "Either the operands' types must match, or the conversions from
+    *    Section 4.1.10 "Implicit Conversions" will be applied to the integer
+    *    operand, after which the types must match."
+    *
+    * This conversion was added in GLSL 1.20.  If the compilation mode is
+    * GLSL 1.10, the conversion is skipped.
+    */
+   if (state->language_version >= 120) {
+      if ((type_a->base_type == GLSL_TYPE_FLOAT)
+         && (type_b->base_type != GLSL_TYPE_FLOAT)) {
+        /* FINISHME: Generate the implicit type conversion. */
+      } else if ((type_a->base_type != GLSL_TYPE_FLOAT)
+                && (type_b->base_type == GLSL_TYPE_FLOAT)) {
+        /* FINISHME: Generate the implicit type conversion. */
+      }
+   }
+
+   if (type_a->base_type != type_b->base_type)
+      return glsl_error_type;
+
+   /*    "The result is scalar Boolean."
+    */
+   return glsl_bool_type;
+}
+
+
+struct ir_instruction *
+ast_expression_to_hir(const struct ast_node *ast,
+                     struct simple_node *instructions,
+                     struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_expression *expr =
+      (struct ast_expression *) ast;
+   static const int operations[AST_NUM_OPERATORS] = {
+      -1,               /* ast_assign doesn't convert to ir_expression. */
+      -1,               /* ast_plus doesn't convert to ir_expression. */
+      ir_unop_neg,
+      ir_binop_add,
+      ir_binop_sub,
+      ir_binop_mul,
+      ir_binop_div,
+      ir_binop_mod,
+      ir_binop_lshift,
+      ir_binop_rshift,
+      ir_binop_less,
+      ir_binop_greater,
+      ir_binop_lequal,
+      ir_binop_gequal,
+      ir_binop_equal,
+      ir_binop_nequal,
+      ir_binop_bit_and,
+      ir_binop_bit_xor,
+      ir_binop_bit_or,
+      ir_unop_bit_not,
+      ir_binop_logic_and,
+      ir_binop_logic_xor,
+      ir_binop_logic_or,
+      ir_unop_logic_not,
+
+      /* Note: The following block of expression types actually convert
+       * to multiple IR instructions.
+       */
+      ir_binop_mul,     /* ast_mul_assign */
+      ir_binop_div,     /* ast_div_assign */
+      ir_binop_mod,     /* ast_mod_assign */
+      ir_binop_add,     /* ast_add_assign */
+      ir_binop_sub,     /* ast_sub_assign */
+      ir_binop_lshift,  /* ast_ls_assign */
+      ir_binop_rshift,  /* ast_rs_assign */
+      ir_binop_bit_and, /* ast_and_assign */
+      ir_binop_bit_xor, /* ast_xor_assign */
+      ir_binop_bit_or,  /* ast_or_assign */
+
+      -1,               /* ast_conditional doesn't convert to ir_expression. */
+      -1,               /* ast_pre_inc doesn't convert to ir_expression. */
+      -1,               /* ast_pre_dec doesn't convert to ir_expression. */
+      -1,               /* ast_post_inc doesn't convert to ir_expression. */
+      -1,               /* ast_post_dec doesn't convert to ir_expression. */
+      -1,               /* ast_field_selection doesn't conv to ir_expression. */
+      -1,               /* ast_array_index doesn't convert to ir_expression. */
+      -1,               /* ast_function_call doesn't conv to ir_expression. */
+      -1,               /* ast_identifier doesn't convert to ir_expression. */
+      -1,               /* ast_int_constant doesn't convert to ir_expression. */
+      -1,               /* ast_uint_constant doesn't conv to ir_expression. */
+      -1,               /* ast_float_constant doesn't conv to ir_expression. */
+      -1,               /* ast_bool_constant doesn't conv to ir_expression. */
+      -1,               /* ast_sequence doesn't convert to ir_expression. */
+   };
+   struct ir_instruction *result = NULL;
+   struct ir_instruction *op[2];
+   struct simple_node op_list;
+   const struct glsl_type *type = glsl_error_type;
+   bool error_emitted = false;
+   YYLTYPE loc;
+
+   loc = ast->get_location();
+   make_empty_list(& op_list);
+
+   switch (expr->oper) {
+   case ast_assign:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+      op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+
+      error_emitted = ((op[0]->type == glsl_error_type)
+                      || (op[1]->type == glsl_error_type));
+
+      type = op[0]->type;
+      if (!error_emitted) {
+        YYLTYPE loc;
+
+        /* FINISHME: This does not handle 'foo.bar.a.b.c[5].d = 5' */
+        loc = expr->subexpressions[0]->get_location();
+        if (op[0]->mode != ir_op_dereference) {
+           _mesa_glsl_error(& loc, state, "invalid lvalue in assignment");
+           error_emitted = true;
+
+           type = glsl_error_type;
+        } else {
+           const struct ir_dereference *const ref =
+              (struct ir_dereference *) op[0];
+           const struct ir_variable *const var =
+              (struct ir_variable *) ref->var;
+
+           if ((var != NULL)
+               && (var->mode == ir_op_var_decl)
+               && (var->read_only)) {
+              _mesa_glsl_error(& loc, state, "cannot assign to read-only "
+                               "variable `%s'", var->name);
+              error_emitted = true;
+
+              type = glsl_error_type;
+           }
+        }
+      }
+
+      /* FINISHME: Check that the LHS and RHS have matching types. */
+      /* FINISHME: For GLSL 1.10, check that the types are not arrays. */
+
+      result = new ir_assignment(op[0], op[1], NULL);
+      break;
+
+   case ast_plus:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+
+      error_emitted = (op[0]->type == glsl_error_type);
+      if (type == glsl_error_type)
+        op[0]->type = type;
+
+      result = op[0];
+      break;
+
+   case ast_neg:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+
+      type = unary_arithmetic_result_type(op[0]->type);
+
+      error_emitted = (op[0]->type == glsl_error_type);
+
+      result = new ir_expression(operations[expr->oper], type,
+                                op[0], NULL);
+      break;
+
+   case ast_add:
+   case ast_sub:
+   case ast_mul:
+   case ast_div:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+      op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+
+      type = arithmetic_result_type(op[0]->type, op[1]->type,
+                                   (expr->operr == ast_mul),
+                                   state);
+
+      result = new ir_expression(operations[expr->oper], type,
+                                op[0], op[1]);
+      break;
+
+   case ast_mod:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+      op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+
+      error_emitted = ((op[0]->type == glsl_error_type)
+                      || (op[1]->type == glsl_error_type));
+
+      type = modulus_result_type(op[0]->type, op[1]->type);
+
+      assert(operations[expr->oper] == ir_binop_mod);
+
+      result = new ir_expression(operations[expr->oper], type,
+                                op[0], op[1]);
+      break;
+
+   case ast_lshift:
+   case ast_rshift:
+      /* FINISHME: Implement bit-shift operators. */
+      break;
+
+   case ast_less:
+   case ast_greater:
+   case ast_lequal:
+   case ast_gequal:
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+      op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+
+      error_emitted = ((op[0]->type == glsl_error_type)
+                      || (op[1]->type == glsl_error_type));
+
+      type = relational_result_type(op[0]->type, op[1]->type, state);
+
+      /* The relational operators must either generate an error or result
+       * in a scalar boolean.  See page 57 of the GLSL 1.50 spec.
+       */
+      assert((type == glsl_error_type)
+            || ((type->base_type == GLSL_TYPE_BOOL)
+                && is_glsl_type_scalar(type)));
+
+      result = new ir_expression(operations[expr->oper], type,
+                                op[0], op[1]);
+      break;
+
+   case ast_nequal:
+   case ast_equal:
+      /* FINISHME: Implement equality operators. */
+      break;
+
+   case ast_bit_and:
+   case ast_bit_xor:
+   case ast_bit_or:
+   case ast_bit_not:
+      /* FINISHME: Implement bit-wise operators. */
+      break;
+
+   case ast_logic_and:
+   case ast_logic_xor:
+   case ast_logic_or:
+   case ast_logic_not:
+      /* FINISHME: Implement logical operators. */
+      break;
+
+   case ast_mul_assign:
+   case ast_div_assign:
+   case ast_add_assign:
+   case ast_sub_assign: {
+      struct ir_instruction *temp_rhs;
+
+      op[0] = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+      op[1] = _mesa_ast_to_hir(expr->subexpressions[1], instructions, state);
+
+      error_emitted = ((op[0]->type == glsl_error_type)
+                      || (op[1]->type == glsl_error_type));
+
+      type = arithmetic_result_type(op[0]->type, op[1]->type,
+                                   (expr->oper == ast_mul_assign),
+                                   state);
+
+      temp_rhs = new ir_expression(operations[expr->oper], type,
+                                  op[0], op[1]);
+
+      /* FINISHME: Check that the LHS is assignable. */
+
+      /* We still have to test that the LHS and RHS have matching type.  For
+       * example, the following GLSL code should generate a type error:
+       *
+       *    mat4 m; vec4 v; m *= v;
+       *
+       * The type of (m*v) is a vec4, but the type of m is a mat4.
+       *
+       * FINISHME: Is multiplication between a matrix and a vector the only
+       * FINISHME: case that resuls in mismatched types?
+       */
+      /* FINISHME: Check that the LHS and RHS have matching types. */
+
+      /* GLSL 1.10 does not allow array assignment.  However, we don't have to
+       * explicitly test for this because none of the binary expression
+       * operators allow array operands either.
+       */
+
+      /* FINISHME: This is wrong.  The operation should assign to a new
+       * FINISHME: temporary.  This assignment should then be added to the
+       * FINISHME: instruction list.  Another assignment to the real
+       * FINISHME: destination should be generated.  The temporary should then
+       * FINISHME: be returned as the r-value.
+       */
+      result = new ir_assignment(op[0], temp_rhs, NULL);
+      break;
+   }
+
+   case ast_mod_assign:
+
+   case ast_ls_assign:
+   case ast_rs_assign:
+
+   case ast_and_assign:
+   case ast_xor_assign:
+   case ast_or_assign:
+
+   case ast_conditional:
+
+   case ast_pre_inc:
+   case ast_pre_dec:
+
+   case ast_post_inc:
+   case ast_post_dec:
+      break;
+
+   case ast_field_selection:
+      result = _mesa_ast_field_selection_to_hir(expr, instructions, state);
+      type = result->type;
+      break;
+
+   case ast_array_index:
+      break;
+
+   case ast_function_call:
+      /* There are three sorts of function calls.
+       *
+       * 1. contstructors - The first subexpression is an ast_type_specifier.
+       * 2. methods - Only the .length() method of array types.
+       * 3. functions - Calls to regular old functions.
+       *
+       * Method calls are actually detected when the ast_field_selection
+       * expression is handled.
+       */
+      result = _mesa_ast_function_call_to_hir(expr->subexpressions[0],
+                                             expr->subexpressions[1],
+                                             state);
+      type = result->type;
+      break;
+
+   case ast_identifier: {
+      /* ast_identifier can appear several places in a full abstract syntax
+       * tree.  This particular use must be at location specified in the grammar
+       * as 'variable_identifier'.
+       */
+      struct ir_variable *var =
+        _mesa_symbol_table_find_symbol(state->symbols, 0,
+                                       expr->primary_expression.identifier);
+
+      result = new ir_dereference(var);
+
+      if (var != NULL) {
+        type = result->type;
+      } else {
+        _mesa_glsl_error(& loc, NULL, "`%s' undeclared",
+                         expr->primary_expression.identifier);
+
+        error_emitted = true;
+      }
+      break;
+   }
+
+   case ast_int_constant:
+      type = glsl_int_type;
+      result = new ir_constant(type, & expr->primary_expression);
+      break;
+
+   case ast_uint_constant:
+      type = glsl_uint_type;
+      result = new ir_constant(type, & expr->primary_expression);
+      break;
+
+   case ast_float_constant:
+      type = glsl_float_type;
+      result = new ir_constant(type, & expr->primary_expression);
+      break;
+
+   case ast_bool_constant:
+      type = glsl_bool_type;
+      result = new ir_constant(type, & expr->primary_expression);
+      break;
+
+   case ast_sequence: {
+      struct simple_node *ptr;
+
+      /* It should not be possible to generate a sequence in the AST without
+       * any expressions in it.
+       */
+      assert(!is_empty_list(&expr->expressions));
+
+      /* The r-value of a sequence is the last expression in the sequence.  If
+       * the other expressions in the sequence do not have side-effects (and
+       * therefore add instructions to the instruction list), they get dropped
+       * on the floor.
+       */
+      foreach (ptr, &expr->expressions)
+        result = _mesa_ast_to_hir(ptr, instructions, state);
+
+      type = result->type;
+
+      /* Any errors should have already been emitted in the loop above.
+       */
+      error_emitted = true;
+      break;
+   }
+   }
+
+   if (is_error_type(type) && !error_emitted)
+      _mesa_glsl_error(& loc, NULL, "type mismatch");
+
+   return result;
+}
+
+
+struct ir_instruction *
+ast_expression_statement_to_hir(const struct ast_node *ast,
+                               struct simple_node *instructions,
+                               struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_expression_statement *stmt =
+      (struct ast_expression_statement *) ast;
+
+   /* It is possible to have expression statements that don't have an
+    * expression.  This is the solitary semicolon:
+    *
+    * for (i = 0; i < 5; i++)
+    *     ;
+    *
+    * In this case the expression will be NULL.  Test for NULL and don't do
+    * anything in that case.
+    */
+   if (stmt->expression != NULL)
+      _mesa_ast_to_hir(stmt->expression, instructions, state);
+
+   /* Statements do not have r-values.
+    */
+   return NULL;
+}
+
+
+struct ir_instruction *
+ast_compound_statement_to_hir(const struct ast_node *ast,
+                             struct simple_node *instructions,
+                             struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_compound_statement *stmt =
+      (struct ast_compound_statement *) ast;
+   struct simple_node *ptr;
+
+
+   if (stmt->new_scope)
+      _mesa_symbol_table_push_scope(state->symbols);
+
+   foreach (ptr, &stmt->statements)
+      _mesa_ast_to_hir(ptr, instructions, state);
+
+   if (stmt->new_scope)
+      _mesa_symbol_table_pop_scope(state->symbols);
+
+   /* Compound statements do not have r-values.
+    */
+   return NULL;
+}
+
+
+static const struct glsl_type *
+type_specifier_to_glsl_type(const struct ast_type_specifier *spec,
+                           const char **name,
+                           struct _mesa_glsl_parse_state *state)
+{
+   static const char *const type_names[] = {
+      "void",
+      "float",
+      "int",
+      "uint",
+      "bool",
+      "vec2",
+      "vec3",
+      "vec4",
+      "bvec2",
+      "bvec3",
+      "bvec4",
+      "ivec2",
+      "ivec3",
+      "ivec4",
+      "uvec2",
+      "uvec3",
+      "uvec4",
+      "mat2",
+      "mat2x3",
+      "mat2x4",
+      "mat3x2",
+      "mat3",
+      "mat3x4",
+      "mat4x2",
+      "mat4x3",
+      "mat4",
+      "sampler1D",
+      "sampler2D",
+      "sampler3D",
+      "samplerCube",
+      "sampler1DShadow",
+      "sampler2DShadow",
+      "samplerCubeShadow",
+      "sampler1DArray",
+      "sampler2DArray",
+      "sampler1DArrayShadow",
+      "sampler2DArrayShadow",
+      "isampler1D",
+      "isampler2D",
+      "isampler3D",
+      "isamplerCube",
+      "isampler1DArray",
+      "isampler2DArray",
+      "usampler1D",
+      "usampler2D",
+      "usampler3D",
+      "usamplerCube",
+      "usampler1DArray",
+      "usampler2DArray",
+
+      NULL, /* ast_struct */
+      NULL  /* ast_type_name */
+   };
+   struct glsl_type *type;
+   const char *type_name = NULL;
+
+   if (spec->type_specifier == ast_struct) {
+      /* FINISHME: Handle annonymous structures. */
+      type = NULL;
+   } else {
+      type_name = (spec->type_specifier == ast_type_name)
+        ? spec->type_name : type_names[spec->type_specifier];
+
+      type = _mesa_symbol_table_find_symbol(state->symbols, 0, type_name);
+      *name = type_name;
+
+      /* FINISHME: Handle array declarations.  Note that this requires complete
+       * FINSIHME: handling of constant expressions.
+       */
+   }
+
+   return type;
+}
+
+
+static void
+apply_type_qualifier_to_variable(const struct ast_type_qualifier *qual,
+                                struct ir_variable *var,
+                                struct _mesa_glsl_parse_state *state)
+{
+   if (qual->invariant)
+      var->invariant = 1;
+
+   /* FINISHME: Mark 'in' variables at global scope as read-only. */
+   if (qual->constant || qual->attribute || qual->uniform
+       || (qual->varying && (state->target == fragment_shader)))
+      var->read_only = 1;
+
+   if (qual->centroid)
+      var->centroid = 1;
+
+   if (qual->in && qual->out)
+      var->mode = ir_var_inout;
+   else if (qual->attribute || qual->in
+           || (qual->varying && (state->target == fragment_shader)))
+      var->mode = ir_var_in;
+   else if (qual->out)
+      var->mode = ir_var_out;
+   else if (qual->uniform)
+      var->mode = ir_var_uniform;
+   else
+      var->mode = ir_var_auto;
+
+   if (qual->flat)
+      var->interpolation = ir_var_flat;
+   else if (qual->noperspective)
+      var->interpolation = ir_var_noperspective;
+   else
+      var->interpolation = ir_var_smooth;
+}
+
+
+struct ir_instruction *
+ast_declarator_list_to_hir(const struct ast_node *ast,
+                          struct simple_node *instructions,
+                          struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_declarator_list *dlist = (struct ast_declarator_list *) ast;
+   struct simple_node *ptr;
+   const struct glsl_type *decl_type;
+   const char *type_name = NULL;
+
+
+   /* FINISHME: Handle vertex shader "invariant" declarations that do not
+    * FINISHME: include a type.  These re-declare built-in variables to be
+    * FINISHME: invariant.
+    */
+
+   decl_type = type_specifier_to_glsl_type(dlist->type->specifier,
+                                          & type_name, state);
+
+   foreach (ptr, &dlist->declarations) {
+      struct ast_declaration *const decl = (struct ast_declaration * )ptr;
+      const struct glsl_type *var_type;
+      struct ir_variable *var;
+
+
+      /* FINISHME: Emit a warning if a variable declaration shadows a
+       * FINISHME: declaration at a higher scope.
+       */
+
+      if (decl_type == NULL) {
+        YYLTYPE loc;
+
+        loc = ast->get_location();
+        if (type_name != NULL) {
+           _mesa_glsl_error(& loc, state,
+                            "invalid type `%s' in declaration of `%s'",
+                            type_name, decl->identifier);
+        } else {
+           _mesa_glsl_error(& loc, state,
+                            "invalid type in declaration of `%s'",
+                            decl->identifier);
+        }
+        continue;
+      }
+
+      if (decl->is_array) {
+        /* FINISHME: Handle array declarations.  Note that this requires
+         * FINISHME: complete handling of constant expressions.
+         */
+
+        /* FINISHME: Reject delcarations of multidimensional arrays. */
+      } else {
+        var_type = decl_type;
+      }
+
+      var = new ir_variable(var_type, decl->identifier);
+
+      /* FINSIHME: Variables that are attribute, uniform, varying, in, or
+       * FINISHME: out varibles must be declared either at global scope or
+       * FINISHME: in a parameter list (in and out only).
+       */
+
+      apply_type_qualifier_to_variable(& dlist->type->qualifier, var, state);
+
+      /* Attempt to add the variable to the symbol table.  If this fails, it
+       * means the variable has already been declared at this scope.
+       */
+      if (_mesa_symbol_table_add_symbol(state->symbols, 0, decl->identifier,
+                                       var) != 0) {
+        YYLTYPE loc = ast->get_location();
+
+        _mesa_glsl_error(& loc, state, "`%s' redeclared",
+                         decl->identifier);
+        continue;
+      }
+
+      insert_at_tail(instructions, (struct simple_node *) var);
+
+      /* FINISHME: Process the declaration initializer. */
+   }
+
+   /* Variable declarations do not have r-values.
+    */
+   return NULL;
+}
+
+
+struct ir_instruction *
+ast_parameter_declarator_to_hir(const struct ast_node *ast,
+                               struct simple_node *instructions,
+                               struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_parameter_declarator *decl =
+      (struct ast_parameter_declarator *) ast;
+   struct ir_variable *var;
+   const struct glsl_type *type;
+   const char *name = NULL;
+
+
+   type = type_specifier_to_glsl_type(decl->type->specifier, & name, state);
+
+   if (type == NULL) {
+      YYLTYPE loc = ast->get_location();
+      if (name != NULL) {
+        _mesa_glsl_error(& loc, state,
+                         "invalid type `%s' in declaration of `%s'",
+                         name, decl->identifier);
+      } else {
+        _mesa_glsl_error(& loc, state,
+                         "invalid type in declaration of `%s'",
+                         decl->identifier);
+      }
+
+      type = glsl_error_type;
+   }
+
+   var = new ir_variable(type, decl->identifier);
+
+   /* FINISHME: Handle array declarations.  Note that this requires
+    * FINISHME: complete handling of constant expressions.
+    */
+
+   apply_type_qualifier_to_variable(& decl->type->qualifier, var, state);
+
+   insert_at_tail(instructions, var);
+
+   /* Parameter declarations do not have r-values.
+    */
+   return NULL;
+}
+
+
+static void
+ast_function_parameters_to_hir(struct simple_node *ast_parameters,
+                              struct simple_node *ir_parameters,
+                              struct _mesa_glsl_parse_state *state)
+{
+   struct simple_node *ptr;
+
+   foreach (ptr, ast_parameters) {
+      _mesa_ast_to_hir(ptr, ir_parameters, state);
+   }
+}
+
+
+static bool
+parameter_lists_match(struct simple_node *list_a, struct simple_node *list_b)
+{
+   struct simple_node *node_a;
+   struct simple_node *node_b;
+
+   node_b = first_elem(list_b);
+   foreach (node_a, list_a) {
+      /* If all of the parameters from the other parameter list have been
+       * exhausted, the lists have different length and, by definition,
+       * do not match.
+       */
+      if (at_end(list_b, node_b))
+        return false;
+
+      /* If the types of the parameters do not match, the parameters lists
+       * are different.
+       */
+      /* FINISHME */
+
+
+      node_b = next_elem(node_b);
+   }
+
+   return true;
+}
+
+
+struct ir_instruction *
+ast_function_definition_to_hir(const struct ast_node *ast,
+                              struct simple_node *instructions,
+                              struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_function_definition *func =
+      (struct ast_function_definition *) ast;
+   struct ir_label *label;
+   struct simple_node *ptr;
+   struct simple_node *tmp;
+   struct ir_function_signature *signature = NULL;
+   struct ir_function *f = NULL;
+   struct simple_node parameters;
+
+
+   /* Convert the list of function parameters to HIR now so that they can be
+    * used below to compare this function's signature with previously seen
+    * signatures for functions with the same name.
+    */
+   make_empty_list(& parameters);
+   ast_function_parameters_to_hir(& func->prototype->parameters, & parameters,
+                                 state);
+
+
+   /* Verify that this function's signature either doesn't match a previously
+    * seen signature for a function with the same name, or, if a match is found,
+    * that the previously seen signature does not have an associated definition.
+    */
+   f = _mesa_symbol_table_find_symbol(state->symbols, 0,
+                                     func->prototype->identifier);
+   if (f != NULL) {
+      foreach (ptr, & f->signatures) {
+        signature = (struct ir_function_signature *) ptr;
+
+        /* Compare the parameter list of the function being defined to the
+         * existing function.  If the parameter lists match, then the return
+         * type must also match and the existing function must not have a
+         * definition.
+         */
+        if (parameter_lists_match(& parameters, & signature->parameters)) {
+           /* FINISHME: Compare return types. */
+
+           if (signature->definition != NULL) {
+              YYLTYPE loc = ast->get_location();
+
+              _mesa_glsl_error(& loc, state, "function `%s' redefined",
+                               func->prototype->identifier);
+              signature = NULL;
+              break;
+           }
+        }
+
+        signature = NULL;
+      }
+
+   } else {
+      f = new ir_function();
+      f->name = func->prototype->identifier;
+
+      _mesa_symbol_table_add_symbol(state->symbols, 0, f->name, f);
+   }
+
+
+   /* Finish storing the information about this new function in its signature.
+    */
+   if (signature == NULL) {
+      signature = new ir_function_signature();
+      insert_at_tail(& f->signatures, (struct simple_node *) signature);
+   } else {
+      /* Destroy all of the previous parameter information.  The previous
+       * parameter information comes from the function prototype, and it can
+       * either include invalid parameter names or may not have names at all.
+       */
+      foreach_s(ptr, tmp, & signature->parameters) {
+        assert(((struct ir_instruction *)ptr)->mode == ir_op_var_decl);
+
+        remove_from_list(ptr);
+        free(ptr);
+      }
+   }
+
+
+   ast_function_parameters_to_hir(& func->prototype->parameters,
+                                 & signature->parameters,
+                                 state);
+   /* FINISHME: Set signature->return_type */
+
+   label = new ir_label(func->prototype->identifier);
+   if (signature->definition == NULL) {
+      signature->definition = label;
+   }
+   insert_at_tail(instructions, label);
+
+   /* Add the function parameters to the symbol table.  During this step the
+    * parameter declarations are also moved from the temporary "parameters" list
+    * to the instruction list.  There are other more efficient ways to do this,
+    * but they involve ugly linked-list gymnastics.
+    */
+   _mesa_symbol_table_push_scope(state->symbols);
+   foreach_s(ptr, tmp, & parameters) {
+      struct ir_variable *const var = (struct ir_variable *) ptr;
+
+      assert(var->mode == ir_op_var_decl);
+
+      remove_from_list(ptr);
+      insert_at_tail(instructions, ptr);
+
+      _mesa_symbol_table_add_symbol(state->symbols, 0, var->name, var);
+   }
+
+   /* Convert the body of the function to HIR, and append the resulting
+    * instructions to the list that currently consists of the function label
+    * and the function parameters.
+    */
+   _mesa_ast_to_hir(func->body, instructions, state);
+
+   _mesa_symbol_table_pop_scope(state->symbols);
+
+
+   /* Function definitions do not have r-values.
+    */
+   return NULL;
+}
diff --git a/builtin_types.sh b/builtin_types.sh
new file mode 100755 (executable)
index 0000000..19dcbaf
--- /dev/null
@@ -0,0 +1,328 @@
+#!/bin/sh
+#
+# Copyright © 2009 Intel Corporation
+#
+# Permission is hereby granted, free of charge, to any person obtaining a
+# copy of this software and associated documentation files (the "Software"),
+# to deal in the Software without restriction, including without limitation
+# the rights to use, copy, modify, merge, publish, distribute, sublicense,
+# and/or sell copies of the Software, and to permit persons to whom the
+# Software is furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice (including the next
+# paragraph) shall be included in all copies or substantial portions of the
+# Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+# DEALINGS IN THE SOFTWARE.
+
+# gen_integral_type <name> <base_type> <vector elements> <matrix rows>
+function gen_integral_type
+{
+    printf '   { %17s, 0, 0, 0, 0, %u, %u, "%s", 0, {NULL} },\n' $2 $3 $4 $1
+    index=$((index + 1))
+}
+
+# gen_struct_type <name>
+function gen_struct_type
+{
+    elements=$(printf "%s_fields" $1)
+    printf '   {\n      GLSL_TYPE_STRUCT, 0, 0, 0, 0, 0, 0, "%s",\n      Elements(%s),\n      {(void *) %s}\n   },\n' \
+       $1 $elements $elements
+}
+
+# gen_sampler_type <name> <dimensions> <shadow> <array> <type>
+function gen_sampler_type
+{
+    name=$(printf "sampler%s" $1)
+
+    if [ $4 -eq 1 ]; then
+       name=$(printf "%sArray" $name)
+    fi
+
+    if [ $3 -eq 1 ]; then
+       name=$(printf "%sShadow" $name)
+    fi
+
+    if [ $5 == GLSL_TYPE_INT ]; then
+       name=$(printf "i%s" $name)
+    elif [ $5 == GLSL_TYPE_UINT ]; then
+       name=$(printf "u%s" $name)
+    fi
+
+    printf '   { GLSL_TYPE_SAMPLER, %21s, %u, %u, %15s, 0, 0,\n     "%s", 0, {NULL} },\n' \
+       $2 $3 $4 $5 $name
+}
+
+function gen_header
+{
+    if [ x$1 == x ]; then
+       name="builtin_types"
+    else
+       name="builtin_${1}_types"
+    fi
+
+    printf "\nstatic const struct glsl_type %s[] = {\n" $name
+}
+
+function gen_footer
+{
+    printf "};\n"
+}
+
+function gen_struct_field_header
+{
+    printf "\nstatic const struct glsl_struct_field %s_fields[] = {\n" $1
+}
+
+function gen_struct_field_footer
+{
+    printf "};\n"
+}
+
+function gen_struct_field
+{
+    printf '   { & %s[%2u], "%s" },\n' $1 $2 "$3"
+}
+
+cat <<EOF
+/* THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT! See builtin_types.sh. */
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef Elements
+#define Elements(x) (sizeof(x)/sizeof(*(x)))
+#endif
+
+static const struct glsl_type error_type = {
+   GLSL_TYPE_ERROR, 0, 0, 0, 0, 0, 0, "", 0, {NULL}
+};
+
+const struct glsl_type *const glsl_error_type = & error_type;
+
+EOF
+
+echo '/** \name Core built-in types'
+echo ' *'
+echo ' * These types exist in all versions of GLSL.'
+echo ' */'
+echo '/*@{*/'
+gen_header "core"
+
+index=0;
+bool_index=$index
+gen_integral_type "bool" "GLSL_TYPE_BOOL" 0 0
+for i in 2 3 4; do
+    gen_integral_type "bvec$i" "GLSL_TYPE_BOOL" $i 0
+done
+
+int_index=$index
+gen_integral_type "int" "GLSL_TYPE_INT" 0 0
+for i in 2 3 4; do
+    gen_integral_type "ivec$i" "GLSL_TYPE_INT" $i 0
+done
+
+float_index=$index
+gen_integral_type "float" "GLSL_TYPE_FLOAT" 0 0
+for i in 2 3 4; do
+    gen_integral_type "vec$i" "GLSL_TYPE_FLOAT" $i 0
+done
+
+for i in 2 3 4; do
+    gen_integral_type "mat$i" "GLSL_TYPE_FLOAT" $i $i
+done
+
+for i in "1D" "2D"; do
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 0 "GLSL_TYPE_FLOAT"
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 1 0 "GLSL_TYPE_FLOAT"
+done
+
+gen_sampler_type "3D"     "GLSL_SAMPLER_DIM_3D"   0 0 "GLSL_TYPE_FLOAT"
+gen_sampler_type "Cube"   "GLSL_SAMPLER_DIM_CUBE" 0 0 "GLSL_TYPE_FLOAT"
+gen_sampler_type "2DRect" "GLSL_SAMPLER_DIM_RECT" 0 0 "GLSL_TYPE_FLOAT"
+gen_sampler_type "2DRect" "GLSL_SAMPLER_DIM_RECT" 1 0 "GLSL_TYPE_FLOAT"
+
+gen_footer
+
+echo
+echo 'const struct glsl_type *const glsl_bool_type  = & builtin_core_types['$bool_index'];'
+echo 'const struct glsl_type *const glsl_int_type   = & builtin_core_types['$int_index'];'
+echo 'const struct glsl_type *const glsl_float_type = & builtin_core_types['$float_index'];'
+echo '/*@}*/'
+
+echo
+echo '/** \name GLSL structures that have not been deprecated.'
+echo ' */'
+echo '/*@{*/'
+gen_struct_field_header gl_DepthRangeParameters
+gen_struct_field builtin_core_types 8 "near"
+gen_struct_field builtin_core_types 8 "far"
+gen_struct_field builtin_core_types 8 "diff"
+gen_struct_field_footer
+
+gen_header "structure"
+gen_struct_type gl_DepthRangeParameters
+gen_footer
+echo '/*@}*/'
+
+echo
+echo '/** \name GLSL 1.00 / 1.10 structures that are deprecated in GLSL 1.30'
+echo ' */'
+echo '/*@{*/'
+gen_struct_field_header gl_PointParameters
+gen_struct_field builtin_core_types 8 "size"
+gen_struct_field builtin_core_types 8 "sizeMin"
+gen_struct_field builtin_core_types 8 "sizeMax"
+gen_struct_field builtin_core_types 8 "fadeThresholdSize"
+gen_struct_field builtin_core_types 8 "distanceConstantAttenuation"
+gen_struct_field builtin_core_types 8 "distanceLinearAttenuation"
+gen_struct_field builtin_core_types 8 "distanceQuadraticAttenuation"
+gen_struct_field_footer
+
+gen_struct_field_header gl_MaterialParameters
+gen_struct_field builtin_core_types 11 "emission"
+gen_struct_field builtin_core_types 11 "ambient"
+gen_struct_field builtin_core_types 11 "diffuse"
+gen_struct_field builtin_core_types 11 "specular"
+gen_struct_field builtin_core_types 8  "shininess"
+gen_struct_field_footer
+
+gen_struct_field_header gl_LightSourceParameters
+gen_struct_field builtin_core_types 11 "ambient"
+gen_struct_field builtin_core_types 11 "diffuse"
+gen_struct_field builtin_core_types 11 "specular"
+gen_struct_field builtin_core_types 11 "position"
+gen_struct_field builtin_core_types 11 "halfVector"
+gen_struct_field builtin_core_types 10 "spotDirection"
+gen_struct_field builtin_core_types 8  "spotExponent"
+gen_struct_field builtin_core_types 8  "spotCutoff"
+gen_struct_field builtin_core_types 8  "spotCosCutoff"
+gen_struct_field builtin_core_types 8  "constantAttenuation"
+gen_struct_field builtin_core_types 8  "linearAttenuation"
+gen_struct_field builtin_core_types 8  "quadraticAttenuation"
+gen_struct_field_footer
+
+gen_struct_field_header gl_LightModelParameters
+gen_struct_field builtin_core_types 11 "ambient"
+gen_struct_field_footer
+
+gen_struct_field_header gl_LightModelProducts
+gen_struct_field builtin_core_types 11 "sceneColor"
+gen_struct_field_footer
+
+gen_struct_field_header gl_LightProducts
+gen_struct_field builtin_core_types 11 "ambient"
+gen_struct_field builtin_core_types 11 "diffuse"
+gen_struct_field builtin_core_types 11 "specular"
+gen_struct_field_footer
+
+gen_struct_field_header gl_FogParameters
+gen_struct_field builtin_core_types 11 "color"
+gen_struct_field builtin_core_types 8  "density"
+gen_struct_field builtin_core_types 8  "start"
+gen_struct_field builtin_core_types 8  "end"
+gen_struct_field builtin_core_types 8  "scalre"
+gen_struct_field_footer
+
+gen_header "110_deprecated_structure"
+gen_struct_type gl_PointParameters
+gen_struct_type gl_MaterialParameters
+gen_struct_type gl_LightSourceParameters
+gen_struct_type gl_LightModelParameters
+gen_struct_type gl_LightModelProducts
+gen_struct_type gl_LightProducts
+gen_struct_type gl_FogParameters
+gen_footer
+echo '/*@}*/'
+
+
+echo
+echo '/** \name Types added in GLSL 1.20'
+echo ' */'
+echo '/*@{*/'
+gen_header "120"
+for i in 2 3 4; do
+    for j in 2 3 4; do
+       if [ $i -ne $j ]; then
+           gen_integral_type "mat${i}x${j}" "GLSL_TYPE_FLOAT" $i $j
+       fi
+    done
+done
+gen_footer
+echo '/*@}*/'
+
+echo
+echo '/** \name Types added in GLSL 1.30'
+echo ' */'
+echo '/*@{*/'
+gen_header "130"
+index=0;
+uint_index=$index
+gen_integral_type "uint" "GLSL_TYPE_UINT" 0 0
+for i in 2 3 4; do
+    gen_integral_type "uvec$i" "GLSL_TYPE_UINT" $i 0
+done
+
+echo
+echo "   /* 1D and 2D texture arrays */"
+for i in "1D" "2D"; do
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 1 "GLSL_TYPE_FLOAT"
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 1 "GLSL_TYPE_INT"
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 1 "GLSL_TYPE_UINT"
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 1 1 "GLSL_TYPE_FLOAT"
+done
+
+echo
+echo "   /* cube shadow samplers */"
+gen_sampler_type "Cube"   "GLSL_SAMPLER_DIM_CUBE" 1 0 "GLSL_TYPE_FLOAT"
+
+echo
+echo "   /* signed and unsigned integer samplers */"
+for i in "1D" "2D" "3D"; do
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 0 "GLSL_TYPE_INT"
+    gen_sampler_type $i "GLSL_SAMPLER_DIM_$i" 0 0 "GLSL_TYPE_UINT"
+done
+
+gen_sampler_type "Cube"   "GLSL_SAMPLER_DIM_CUBE" 0 0 "GLSL_TYPE_INT"
+gen_sampler_type "Cube"   "GLSL_SAMPLER_DIM_CUBE" 0 0 "GLSL_TYPE_UINT"
+
+gen_footer
+echo ''
+echo 'const struct glsl_type *const glsl_uint_type   = & builtin_130_types['$uint_index'];'
+echo '/*@}*/'
+
+echo
+echo '/** \name Sampler types added by GL_EXT_texture_buffer_object'
+echo ' */'
+echo '/*@{*/'
+gen_header "EXT_texture_buffer_object"
+gen_sampler_type "Buffer" "GLSL_SAMPLER_DIM_BUF" 0 0 "GLSL_TYPE_FLOAT"
+gen_sampler_type "Buffer" "GLSL_SAMPLER_DIM_BUF" 0 0 "GLSL_TYPE_INT"
+gen_sampler_type "Buffer" "GLSL_SAMPLER_DIM_BUF" 0 0 "GLSL_TYPE_UINT"
+gen_footer
+echo '/*@}*/'
diff --git a/glsl_lexer.l b/glsl_lexer.l
new file mode 100644 (file)
index 0000000..201d461
--- /dev/null
@@ -0,0 +1,273 @@
+%{
+/*
+ * Copyright © 2008, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include "ast.h"
+#include "glsl_parser_extras.h"
+#include "glsl_parser.tab.h"
+#include "symbol_table.h"
+
+#define YY_USER_ACTION                                         \
+   do {                                                                \
+      yylloc->source = 0;                                      \
+      yylloc->first_column = yycolumn + 1;                     \
+      yylloc->first_line = yylineno + 1;                       \
+      yycolumn += yyleng;                                      \
+   } while(0);
+
+%}
+
+%option bison-bridge bison-locations reentrant noyywrap
+%option never-interactive
+%option prefix="_mesa_glsl_"
+%option extra-type="struct _mesa_glsl_parse_state *"
+%option stack
+
+%x PP COMMENT
+
+%%
+
+"/*"                   { yy_push_state(COMMENT, yyscanner); }
+<COMMENT>[^*\n]*
+<COMMENT>[^*\n]*\n     { yylineno++; yycolumn = 0; }
+<COMMENT>"*"+[^*/\n]*
+<COMMENT>"*"+[^*/\n]*\n { yylineno++; yycolumn = 0; }
+<COMMENT>"*"+"/"        { yy_pop_state(yyscanner); }
+
+\/\/.*\n               { yylineno++; yycolumn = 0; }
+[ \r\t]+               ;
+
+    /* Preprocessor tokens. */ 
+^[ \t]*#[ \t]*$                        ;
+^[ \t]*#[ \t]*version          { BEGIN PP; return VERSION; }
+^[ \t]*#[ \t]*extension                { BEGIN PP; return EXTENSION; }
+^[ \t]*#[ \t]*line             { BEGIN PP; return LINE; }
+^[ \t]*#[ \t]*pragma           { BEGIN PP; return PRAGMA; }
+<PP>:                          return COLON;
+<PP>[_a-zA-Z][_a-zA-Z0-9]*     {
+                                  yylval->identifier = strdup(yytext);
+                                  return IDENTIFIER;
+                               }
+<PP>[1-9][0-9]*                        {
+                                   yylval->n = strtol(yytext, NULL, 10);
+                                   return INTCONSTANT;
+                               }
+<PP>\n                         { BEGIN 0; yylineno++; yycolumn = 0; return EOL; }
+
+\n             { yylineno++; yycolumn = 0; }
+
+attribute      return ATTRIBUTE;
+const          return CONST;
+bool           return BOOL;
+float          return FLOAT;
+int            return INT;
+
+break          return BREAK;
+continue       return CONTINUE;
+do             return DO;
+while          return WHILE;
+else           return ELSE;
+for            return FOR;
+if             return IF;
+discard                return DISCARD;
+return         return RETURN;
+
+bvec2          return BVEC2;
+bvec3          return BVEC3;
+bvec4          return BVEC4;
+ivec2          return IVEC2;
+ivec3          return IVEC3;
+ivec4          return IVEC4;
+vec2           return VEC2;
+vec3           return VEC3;
+vec4           return VEC4;
+mat2           return MAT2;
+mat3           return MAT3;
+mat4           return MAT4;
+mat2x2         return MAT2X2;
+mat2x3         return MAT2X3;
+mat2x4         return MAT2X4;
+mat3x2         return MAT3X2;
+mat3x3         return MAT3X3;
+mat3x4         return MAT3X4;
+mat4x2         return MAT4X2;
+mat4x3         return MAT4X3;
+mat4x4         return MAT4X4;
+
+in             return IN;
+out            return OUT;
+inout          return INOUT;
+uniform                return UNIFORM;
+varying                return VARYING;
+centroid       return CENTROID;
+invariant      return INVARIANT;
+
+sampler1D      return SAMPLER1D;
+sampler2D      return SAMPLER2D;
+sampler3D      return SAMPLER3D;
+samplerCube    return SAMPLERCUBE;
+sampler1DShadow        return SAMPLER1DSHADOW;
+sampler2DShadow        return SAMPLER2DSHADOW;
+
+struct         return STRUCT;
+void           return VOID;
+
+\+\+           return INC_OP;
+--             return DEC_OP;
+\<=            return LE_OP;
+>=             return GE_OP;
+==             return EQ_OP;
+!=             return NE_OP;
+&&             return AND_OP;
+\|\|           return OR_OP;
+"^^"           return XOR_OP;
+
+\*=            return MUL_ASSIGN;
+\/=            return DIV_ASSIGN;
+\+=            return ADD_ASSIGN;
+\%=            return MOD_ASSIGN;
+\<\<=          return LEFT_ASSIGN;
+>>=            return RIGHT_ASSIGN;
+&=             return AND_ASSIGN;
+^=             return XOR_ASSIGN;
+\|=            return OR_ASSIGN;
+-=             return SUB_ASSIGN;
+
+[1-9][0-9]*            {
+                           yylval->n = strtol(yytext, NULL, 10);
+                           return INTCONSTANT;
+                       }
+0[xX][0-9a-fA-F]+      {
+                           yylval->n = strtol(yytext + 2, NULL, 16);
+                           return INTCONSTANT;
+                       }
+0[0-7]*                        {
+                           yylval->n = strtol(yytext + 2, NULL, 8);
+                           return INTCONSTANT;
+                       }
+
+[0-9]+\.[0-9]+([eE][+-]?[0-9]+)?[fF]?  {
+                           yylval->real = strtod(yytext, NULL);
+                           return FLOATCONSTANT;
+                       }
+\.[0-9]+([eE][+-]?[0-9]+)?[fF]?                {
+                           yylval->real = strtod(yytext, NULL);
+                           return FLOATCONSTANT;
+                       }
+[0-9]+\.([eE][+-]?[0-9]+)?[fF]?                {
+                           yylval->real = strtod(yytext, NULL);
+                           return FLOATCONSTANT;
+                       }
+[0-9]+[eE][+-]?[0-9]+[fF]?             {
+                           yylval->real = strtod(yytext, NULL);
+                           return FLOATCONSTANT;
+                       }
+
+true                   {
+                           yylval->n = 1;
+                           return BOOLCONSTANT;
+                       }
+false                  {
+                           yylval->n = 0;
+                           return BOOLCONSTANT;
+                       }
+
+
+    /* Reserved words in GLSL 1.10. */
+asm            return ASM;
+class          return CLASS;
+union          return UNION;
+enum           return ENUM;
+typedef                return TYPEDEF;
+template       return TEMPLATE;
+this           return THIS;
+packed         return PACKED;
+goto           return GOTO;
+switch         return SWITCH;
+default                return DEFAULT;
+inline         return INLINE;
+noinline       return NOINLINE;
+volatile       return VOLATILE;
+public         return PUBLIC;
+static         return STATIC;
+extern         return EXTERN;
+external       return EXTERNAL;
+interface      return INTERFACE;
+long           return LONG;
+short          return SHORT;
+double         return DOUBLE;
+half           return HALF;
+fixed          return FIXED;
+unsigned       return UNSIGNED;
+input          return INPUT;
+output         return OUTPUT;
+hvec2          return HVEC2;
+hvec3          return HVEC3;
+hvec4          return HVEC4;
+dvec2          return DVEC2;
+dvec3          return DVEC3;
+dvec4          return DVEC4;
+fvec2          return FVEC2;
+fvec3          return FVEC3;
+fvec4          return FVEC4;
+sampler2DRect          return SAMPLER2DRECT;
+sampler3DRect          return SAMPLER3DRECT;
+sampler2DRectShadow    return SAMPLER2DRECTSHADOW;
+sizeof         return SIZEOF;
+cast           return CAST;
+namespace      return NAMESPACE;
+using          return USING;
+
+    /* Additional reserved words in GLSL 1.20. */
+lowp           return LOWP;
+mediump                return MEDIUMP;
+highp          return HIGHP;
+precision      return PRECISION;
+
+[_a-zA-Z][_a-zA-Z0-9]* {
+                           yylval->identifier = strdup(yytext);
+
+                           if (_mesa_symbol_table_find_symbol(yyextra->symbols,
+                                                              0,
+                                                              yylval->identifier))
+                              return TYPE_NAME;
+                           else
+                              return IDENTIFIER;
+                       }
+
+.                      { return yytext[0]; }
+
+%%
+
+void
+_mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state,
+                     const char *string, size_t len)
+{
+   yylex_init_extra(state, & state->scanner);
+   yy_scan_bytes(string, len, state->scanner);
+}
+
+void
+_mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state)
+{
+   yylex_destroy(state->scanner);
+}
diff --git a/glsl_parser.y b/glsl_parser.y
new file mode 100644 (file)
index 0000000..f9bfb0b
--- /dev/null
@@ -0,0 +1,1228 @@
+%{
+/*
+ * Copyright © 2008, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+    
+#include "ast.h"
+#include "glsl_parser_extras.h"
+#include "symbol_table.h"
+#include "glsl_types.h"
+
+#define YYLEX_PARAM state->scanner
+
+%}
+
+%pure-parser
+%locations
+%error-verbose
+
+%lex-param   {void *scanner}
+%parse-param {struct _mesa_glsl_parse_state *state}
+
+%union {
+   int n;
+   float real;
+   char *identifier;
+
+   union {
+      struct ast_type_qualifier q;
+      unsigned i;
+   } type_qualifier;
+
+   struct ast_node *node;
+   struct ast_type_specifier *type_specifier;
+   struct ast_fully_specified_type *fully_specified_type;
+   struct ast_function *function;
+   struct ast_parameter_declarator *parameter_declarator;
+   struct ast_function_definition *function_definition;
+   struct ast_compound_statement *compound_statement;
+   struct ast_expression *expression;
+   struct ast_declarator_list *declarator_list;
+   struct ast_struct_specifier *struct_specifier;
+   struct ast_declaration *declaration;
+
+   struct {
+      struct ast_node *cond;
+      struct ast_expression *rest;
+   } for_rest_statement;
+}
+
+%token ATTRIBUTE CONST BOOL FLOAT INT UINT
+%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN SWITCH CASE DEFAULT
+%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 UVEC2 UVEC3 UVEC4 VEC2 VEC3 VEC4
+%token MAT2 MAT3 MAT4 CENTROID IN OUT INOUT UNIFORM VARYING
+%token NOPERSPECTIVE FLAT SMOOTH
+%token MAT2X2 MAT2X3 MAT2X4
+%token MAT3X2 MAT3X3 MAT3X4
+%token MAT4X2 MAT4X3 MAT4X4
+%token SAMPLER1D SAMPLER2D SAMPLER3D SAMPLERCUBE SAMPLER1DSHADOW SAMPLER2DSHADOW
+%token SAMPLERCUBESHADOW SAMPLER1DARRAY SAMPLER2DARRAY SAMPLER1DARRAYSHADOW
+%token SAMPLER2DARRAYSHADOW ISAMPLER1D ISAMPLER2D ISAMPLER3D ISAMPLERCUBE
+%token ISAMPLER1DARRAY ISAMPLER2DARRAY USAMPLER1D USAMPLER2D USAMPLER3D
+%token USAMPLERCUBE USAMPLER1DARRAY USAMPLER2DARRAY
+%token STRUCT VOID WHILE
+%token <identifier> IDENTIFIER TYPE_NAME
+%token <real> FLOATCONSTANT
+%token <n> INTCONSTANT UINTCONSTANT BOOLCONSTANT
+%token <identifier> FIELD_SELECTION
+%token LEFT_OP RIGHT_OP
+%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP
+%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN
+%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN
+%token SUB_ASSIGN
+%token INVARIANT
+%token HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION
+
+%token VERSION EXTENSION LINE PRAGMA COLON EOL INTERFACE OUTPUT
+
+   /* Reserved words that are not actually used in the grammar.
+    */
+%token ASM CLASS UNION ENUM TYPEDEF TEMPLATE THIS PACKED GOTO
+%token INLINE NOINLINE VOLATILE PUBLIC STATIC EXTERN EXTERNAL
+%token LONG SHORT DOUBLE HALF FIXED UNSIGNED INPUT OUPTUT
+%token HVEC2 HVEC3 HVEC4 DVEC2 DVEC3 DVEC4 FVEC2 FVEC3 FVEC4
+%token SAMPLER2DRECT SAMPLER3DRECT SAMPLER2DRECTSHADOW
+%token SIZEOF CAST NAMESPACE USING LOWP MEDIUMP HIGHP
+
+%type <identifier> variable_identifier
+%type <node> statement
+%type <node> statement_list
+%type <node> simple_statement
+%type <node> statement_matched
+%type <node> statement_unmatched
+%type <n> precision_qualifier
+%type <type_qualifier> type_qualifier
+%type <type_qualifier> storage_qualifier
+%type <type_qualifier> interpolation_qualifier
+%type <type_specifier> type_specifier
+%type <type_specifier> type_specifier_no_prec
+%type <type_specifier> type_specifier_nonarray
+%type <n> basic_type_specifier_nonarray
+%type <fully_specified_type> fully_specified_type
+%type <function> function_prototype
+%type <function> function_header
+%type <function> function_header_with_parameters
+%type <function> function_declarator
+%type <parameter_declarator> parameter_declarator
+%type <parameter_declarator> parameter_declaration
+%type <type_qualifier> parameter_qualifier
+%type <type_qualifier> parameter_type_qualifier
+%type <type_specifier> parameter_type_specifier
+%type <function_definition> function_definition
+%type <compound_statement> compound_statement_no_new_scope
+%type <compound_statement> compound_statement
+%type <node> statement_no_new_scope
+%type <node> expression_statement
+%type <expression> expression
+%type <expression> primary_expression
+%type <expression> assignment_expression
+%type <expression> conditional_expression
+%type <expression> logical_or_expression
+%type <expression> logical_xor_expression
+%type <expression> logical_and_expression
+%type <expression> inclusive_or_expression
+%type <expression> exclusive_or_expression
+%type <expression> and_expression
+%type <expression> equality_expression
+%type <expression> relational_expression
+%type <expression> shift_expression
+%type <expression> additive_expression
+%type <expression> multiplicative_expression
+%type <expression> unary_expression
+%type <expression> constant_expression
+%type <expression> integer_expression
+%type <expression> postfix_expression
+%type <expression> function_call_header_with_parameters
+%type <expression> function_call_header_no_parameters
+%type <expression> function_call_header
+%type <expression> function_call_generic
+%type <expression> function_call_or_method
+%type <expression> function_call
+%type <n> assignment_operator
+%type <n> unary_operator
+%type <node> function_identifier
+%type <node> external_declaration
+%type <declarator_list> init_declarator_list
+%type <declarator_list> single_declaration
+%type <expression> initializer
+%type <node> declaration
+%type <node> declaration_statement
+%type <node> jump_statement
+%type <struct_specifier> struct_specifier
+%type <node> struct_declaration_list
+%type <declarator_list> struct_declaration
+%type <declaration> struct_declarator
+%type <declaration> struct_declarator_list
+%type <node> selection_statement_matched
+%type <node> selection_statement_unmatched
+%type <node> iteration_statement
+%type <node> condition
+%type <node> conditionopt
+%type <node> for_init_statement
+%type <for_rest_statement> for_rest_statement
+%%
+
+translation_unit: 
+       version_statement
+       {
+          _mesa_glsl_initialize_types(state);
+       }
+       external_declaration_list
+       |
+       {
+          state->language_version = 110;
+          _mesa_glsl_initialize_types(state);
+       }
+       external_declaration_list
+       ;
+
+version_statement:
+       VERSION INTCONSTANT EOL
+       {
+          switch ($2) {
+          case 110:
+          case 120:
+          case 130:
+             /* FINISHME: Check against implementation support versions. */
+             state->language_version = $2;
+             break;
+          default:
+             _mesa_glsl_error(& @2, state, "Shading language version"
+                              "%u is not supported\n", $2);
+             break;
+          }
+       }
+       ;
+
+external_declaration_list:
+       external_declaration
+       {
+          insert_at_tail(& state->translation_unit,
+                         (struct simple_node *) $1);
+       }
+       | external_declaration_list external_declaration
+       {
+          insert_at_tail(& state->translation_unit,
+                         (struct simple_node *) $2);
+       }
+       ;
+
+variable_identifier:
+       IDENTIFIER
+       ;
+
+primary_expression:
+       variable_identifier
+       {
+          $$ = new ast_expression(ast_identifier, NULL, NULL, NULL);
+          $$->primary_expression.identifier = $1;
+       }
+       | INTCONSTANT
+       {
+          $$ = new ast_expression(ast_int_constant, NULL, NULL, NULL);
+          $$->primary_expression.int_constant = $1;
+       }
+       | UINTCONSTANT
+       {
+          $$ = new ast_expression(ast_uint_constant, NULL, NULL, NULL);
+          $$->primary_expression.uint_constant = $1;
+       }
+       | FLOATCONSTANT
+       {
+          $$ = new ast_expression(ast_float_constant, NULL, NULL, NULL);
+          $$->primary_expression.float_constant = $1;
+       }
+       | BOOLCONSTANT
+       {
+          $$ = new ast_expression(ast_bool_constant, NULL, NULL, NULL);
+          $$->primary_expression.bool_constant = $1;
+       }
+       | '(' expression ')'
+       {
+          $$ = $2;
+       }
+       ;
+
+postfix_expression:
+       primary_expression
+       | postfix_expression '[' integer_expression ']'
+       {
+          $$ = new ast_expression(ast_array_index, $1, $3, NULL);
+       }
+       | function_call
+       {
+          $$ = $1;
+       }
+       | postfix_expression '.' IDENTIFIER
+       {
+          $$ = new ast_expression(ast_field_selection, $1, NULL, NULL);
+          $$->primary_expression.identifier = $3;
+       }
+       | postfix_expression INC_OP
+       {
+          $$ = new ast_expression(ast_post_inc, $1, NULL, NULL);
+       }
+       | postfix_expression DEC_OP
+       {
+          $$ = new ast_expression(ast_post_dec, $1, NULL, NULL);
+       }
+       ;
+
+integer_expression:
+       expression
+       ;
+
+function_call:
+       function_call_or_method
+       ;
+
+function_call_or_method:
+       function_call_generic
+       | postfix_expression '.' function_call_generic
+       {
+          $$ = new ast_expression(ast_field_selection, $1, $3, NULL);
+       }
+       ;
+
+function_call_generic:
+       function_call_header_with_parameters ')'
+       | function_call_header_no_parameters ')'
+       ;
+
+function_call_header_no_parameters:
+       function_call_header VOID
+       | function_call_header
+       ;
+
+function_call_header_with_parameters:
+       function_call_header assignment_expression
+       {
+          $$ = $1;
+          $$->subexpressions[1] = $2;
+       }
+       | function_call_header_with_parameters ',' assignment_expression
+       {
+          $$ = $1;
+          insert_at_tail((struct simple_node *) $$->subexpressions[1],
+                         (struct simple_node *) $3);
+       }
+       ;
+
+       // Grammar Note: Constructors look like functions, but lexical 
+       // analysis recognized most of them as keywords. They are now
+       // recognized through "type_specifier".
+function_call_header:
+       function_identifier '('
+       {
+          $$ = new ast_expression(ast_function_call,
+                                  (struct ast_expression *) $1,
+                                  NULL, NULL);
+       }
+       ;
+
+function_identifier:
+       type_specifier
+       {
+          $$ = (struct ast_node *) $1;
+       }
+       | IDENTIFIER
+       {
+          ast_expression *expr =
+             new ast_expression(ast_identifier, NULL, NULL, NULL);
+          expr->primary_expression.identifier = $1;
+
+          $$ = (struct ast_node *) expr;
+       }
+       | FIELD_SELECTION
+       {
+          ast_expression *expr =
+             new ast_expression(ast_identifier, NULL, NULL, NULL);
+          expr->primary_expression.identifier = $1;
+
+          $$ = (struct ast_node *) expr;
+       }
+       ;
+
+       // Grammar Note: No traditional style type casts.
+unary_expression:
+       postfix_expression
+       | INC_OP unary_expression
+       {
+          $$ = new ast_expression(ast_pre_inc, $2, NULL, NULL);
+       }
+       | DEC_OP unary_expression
+       {
+          $$ = new ast_expression(ast_pre_dec, $2, NULL, NULL);
+       }
+       | unary_operator unary_expression
+       {
+          $$ = new ast_expression($1, $2, NULL, NULL);
+       }
+       ;
+
+       // Grammar Note: No '*' or '&' unary ops. Pointers are not supported.
+unary_operator:
+       '+'     { $$ = ast_plus; }
+       | '-'   { $$ = ast_neg; }
+       | '!'   { $$ = ast_logic_not; }
+       | '~'   { $$ = ast_bit_not; }
+       ;
+
+multiplicative_expression:
+       unary_expression
+       | multiplicative_expression '*' unary_expression
+       {
+          $$ = new ast_expression(ast_mul, $1, $3, NULL);
+       }
+       | multiplicative_expression '/' unary_expression
+       {
+          $$ = new ast_expression(ast_div, $1, $3, NULL);
+       }
+       | multiplicative_expression '%' unary_expression
+       {
+          $$ = new ast_expression(ast_mod, $1, $3, NULL);
+       }
+       ;
+
+additive_expression:
+       multiplicative_expression
+       | additive_expression '+' multiplicative_expression
+       {
+          $$ = new ast_expression(ast_add, $1, $3, NULL);
+       }
+       | additive_expression '-' multiplicative_expression
+       {
+          $$ = new ast_expression(ast_sub, $1, $3, NULL);
+       }
+       ;
+
+shift_expression:
+       additive_expression
+       | shift_expression LEFT_OP additive_expression
+       {
+          $$ = new ast_expression(ast_lshift, $1, $3, NULL);
+       }
+       | shift_expression RIGHT_OP additive_expression
+       {
+          $$ = new ast_expression(ast_rshift, $1, $3, NULL);
+       }
+       ;
+
+relational_expression:
+       shift_expression
+       | relational_expression '<' shift_expression
+       {
+          $$ = new ast_expression(ast_less, $1, $3, NULL);
+       }
+       | relational_expression '>' shift_expression
+       {
+          $$ = new ast_expression(ast_greater, $1, $3, NULL);
+       }
+       | relational_expression LE_OP shift_expression
+       {
+          $$ = new ast_expression(ast_lequal, $1, $3, NULL);
+       }
+       | relational_expression GE_OP shift_expression
+       {
+          $$ = new ast_expression(ast_gequal, $1, $3, NULL);
+       }
+       ;
+
+equality_expression:
+       relational_expression
+       | equality_expression EQ_OP relational_expression
+       {
+          $$ = new ast_expression(ast_equal, $1, $3, NULL);
+       }
+       | equality_expression NE_OP relational_expression
+       {
+          $$ = new ast_expression(ast_nequal, $1, $3, NULL);
+       }
+       ;
+
+and_expression:
+       equality_expression
+       | and_expression '&' equality_expression
+       {
+          $$ = new ast_expression(ast_bit_or, $1, $3, NULL);
+       }
+       ;
+
+exclusive_or_expression:
+       and_expression
+       | exclusive_or_expression '^' and_expression
+       {
+          $$ = new ast_expression(ast_bit_xor, $1, $3, NULL);
+       }
+       ;
+
+inclusive_or_expression:
+       exclusive_or_expression
+       | inclusive_or_expression '|' exclusive_or_expression
+       {
+          $$ = new ast_expression(ast_bit_or, $1, $3, NULL);
+       }
+       ;
+
+logical_and_expression:
+       inclusive_or_expression
+       | logical_and_expression AND_OP inclusive_or_expression
+       {
+          $$ = new ast_expression(ast_logic_and, $1, $3, NULL);
+       }
+       ;
+
+logical_xor_expression:
+       logical_and_expression
+       | logical_xor_expression XOR_OP logical_and_expression
+       {
+          $$ = new ast_expression(ast_logic_xor, $1, $3, NULL);
+       }
+       ;
+
+logical_or_expression:
+       logical_xor_expression
+       | logical_or_expression OR_OP logical_xor_expression
+       {
+          $$ = new ast_expression(ast_logic_or, $1, $3, NULL);
+       }
+       ;
+
+conditional_expression:
+       logical_or_expression
+       | logical_or_expression '?' expression ':' assignment_expression
+       {
+          $$ = new ast_expression(ast_conditional, $1, $3, $5);
+       }
+       ;
+
+assignment_expression:
+       conditional_expression
+       | unary_expression assignment_operator assignment_expression
+       {
+          $$ = new ast_expression($2, $1, $3, NULL);
+       }
+       ;
+
+assignment_operator:
+       '='             { $$ = ast_assign; }
+       | MUL_ASSIGN    { $$ = ast_mul_assign; }
+       | DIV_ASSIGN    { $$ = ast_div_assign; }
+       | MOD_ASSIGN    { $$ = ast_mod_assign; }
+       | ADD_ASSIGN    { $$ = ast_add_assign; }
+       | SUB_ASSIGN    { $$ = ast_sub_assign; }
+       | LEFT_ASSIGN   { $$ = ast_ls_assign; }
+       | RIGHT_ASSIGN  { $$ = ast_rs_assign; }
+       | AND_ASSIGN    { $$ = ast_and_assign; }
+       | XOR_ASSIGN    { $$ = ast_xor_assign; }
+       | OR_ASSIGN     { $$ = ast_or_assign; }
+       ;
+
+expression:
+       assignment_expression
+       {
+          $$ = $1;
+       }
+       | expression ',' assignment_expression
+       {
+          if ($1->oper != ast_sequence) {
+             $$ = new ast_expression(ast_sequence, NULL, NULL, NULL);
+             insert_at_tail(& $$->expressions, $1);
+          } else {
+             $$ = $1;
+          }
+
+          insert_at_tail(& $$->expressions, $3);
+       }
+       ;
+
+constant_expression:
+       conditional_expression
+       ;
+
+declaration:
+       function_prototype ';'
+       {
+          $$ = $1;
+       }
+       | init_declarator_list ';'
+       {
+          $$ = $1;
+       }
+       | PRECISION precision_qualifier type_specifier_no_prec ';'
+       {
+          $$ = NULL; /* FINISHME */
+       }
+       ;
+
+function_prototype:
+       function_declarator ')'
+       ;
+
+function_declarator:
+       function_header
+       | function_header_with_parameters
+       ;
+
+function_header_with_parameters:
+       function_header parameter_declaration
+       {
+          $$ = $1;
+          insert_at_head(& $$->parameters,
+                         (struct simple_node *) $2);
+       }
+       | function_header_with_parameters ',' parameter_declaration
+       {
+          $$ = $1;
+          insert_at_head(& $$->parameters,
+                         (struct simple_node *) $3);
+       }
+       ;
+
+function_header:
+       fully_specified_type IDENTIFIER '('
+       {
+          $$ = new ast_function();
+          $$->return_type = $1;
+          $$->identifier = $2;
+       }
+       ;
+
+parameter_declarator:
+       type_specifier IDENTIFIER
+       {
+          $$ = new ast_parameter_declarator();
+          $$->type = new ast_fully_specified_type();
+          $$->type->specifier = $1;
+          $$->identifier = $2;
+       }
+       | type_specifier IDENTIFIER '[' constant_expression ']'
+       {
+          $$ = new ast_parameter_declarator();
+          $$->type = new ast_fully_specified_type();
+          $$->type->specifier = $1;
+          $$->identifier = $2;
+          $$->is_array = true;
+          $$->array_size = $4;
+       }
+       ;
+
+parameter_declaration:
+       parameter_type_qualifier parameter_qualifier parameter_declarator
+       {
+          $1.i |= $2.i;
+
+          $$ = $3;
+          $$->type->qualifier = $1.q;
+       }
+       | parameter_qualifier parameter_declarator
+       {
+          $$ = $2;
+          $$->type->qualifier = $1.q;
+       }
+       | parameter_type_qualifier parameter_qualifier parameter_type_specifier
+       {
+          $1.i |= $2.i;
+
+          $$ = new ast_parameter_declarator();
+          $$->type = new ast_fully_specified_type();
+          $$->type->qualifier = $1.q;
+          $$->type->specifier = $3;
+       }
+       | parameter_qualifier parameter_type_specifier
+       {
+          $$ = new ast_parameter_declarator();
+          $$->type = new ast_fully_specified_type();
+          $$->type->qualifier = $1.q;
+          $$->type->specifier = $2;
+       }
+       ;
+
+parameter_qualifier:
+       /* empty */     { $$.i = 0; }
+       | IN            { $$.i = 0; $$.q.in = 1; }
+       | OUT           { $$.i = 0; $$.q.out = 1; }
+       | INOUT         { $$.i = 0; $$.q.in = 1; $$.q.out = 1; }
+       ;
+
+parameter_type_specifier:
+       type_specifier
+       ;
+
+init_declarator_list:
+       single_declaration
+       | init_declarator_list ',' IDENTIFIER
+       {
+          ast_declaration *decl = new ast_declaration($3, false, NULL, NULL);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | init_declarator_list ',' IDENTIFIER '[' ']'
+       {
+          ast_declaration *decl = new ast_declaration($3, true, NULL, NULL);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | init_declarator_list ',' IDENTIFIER '[' constant_expression ']'
+       {
+          ast_declaration *decl = new ast_declaration($3, true, $5, NULL);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | init_declarator_list ',' IDENTIFIER '[' ']' '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($3, true, NULL, $7);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | init_declarator_list ',' IDENTIFIER '[' constant_expression ']' '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($3, true, $5, $8);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | init_declarator_list ',' IDENTIFIER '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($3, false, NULL, $5);
+
+          $$ = $1;
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       ;
+
+       // Grammar Note: No 'enum', or 'typedef'.
+single_declaration:
+       fully_specified_type
+       {
+          $$ = new ast_declarator_list($1);
+       }
+       | fully_specified_type IDENTIFIER
+       {
+          ast_declaration *decl = new ast_declaration($2, false, NULL, NULL);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | fully_specified_type IDENTIFIER '[' ']'
+       {
+          ast_declaration *decl = new ast_declaration($2, true, NULL, NULL);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | fully_specified_type IDENTIFIER '[' constant_expression ']'
+       {
+          ast_declaration *decl = new ast_declaration($2, true, $4, NULL);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | fully_specified_type IDENTIFIER '[' ']' '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($2, true, NULL, $6);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | fully_specified_type IDENTIFIER '[' constant_expression ']' '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($2, true, $4, $7);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | fully_specified_type IDENTIFIER '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($2, false, NULL, $4);
+
+          $$ = new ast_declarator_list($1);
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       | INVARIANT IDENTIFIER // Vertex only.
+       {
+          ast_declaration *decl = new ast_declaration($2, false, NULL, NULL);
+
+          $$ = new ast_declarator_list(NULL);
+          $$->invariant = true;
+
+          insert_at_tail(& $$->declarations,
+                         (struct simple_node *) decl);
+       }
+       ;
+
+fully_specified_type:
+       type_specifier
+       {
+          $$ = new ast_fully_specified_type();
+          $$->specifier = $1;
+       }
+       | type_qualifier type_specifier
+       {
+          $$ = new ast_fully_specified_type();
+          $$->qualifier = $1.q;
+          $$->specifier = $2;
+       }
+       ;
+
+interpolation_qualifier:
+       SMOOTH          { $$.i = 0; $$.q.smooth = 1; }
+       | FLAT          { $$.i = 0; $$.q.flat = 1; }
+       | NOPERSPECTIVE { $$.i = 0; $$.q.noperspective = 1; }
+       ;
+
+parameter_type_qualifier:
+       CONST           { $$.i = 0; $$.q.constant = 1; }
+       ;
+
+type_qualifier:
+       storage_qualifier
+       | interpolation_qualifier type_qualifier
+       {
+          $$.i = $1.i | $2.i;
+       }
+       | INVARIANT type_qualifier
+       {
+          $$ = $2;
+          $$.q.invariant = 1;
+       }
+       ;
+
+storage_qualifier:
+       CONST                   { $$.i = 0; $$.q.constant = 1; }
+       | ATTRIBUTE             { $$.i = 0; $$.q.attribute = 1; }
+       | VARYING               { $$.i = 0; $$.q.varying = 1; }
+       | CENTROID VARYING      { $$.i = 0; $$.q.centroid = 1; $$.q.varying = 1; }
+       | IN                    { $$.i = 0; $$.q.in = 1; }
+       | OUT                   { $$.i = 0; $$.q.out = 1; }
+       | CENTROID IN           { $$.i = 0; $$.q.centroid = 1; $$.q.in = 1; }
+       | CENTROID OUT          { $$.i = 0; $$.q.centroid = 1; $$.q.out = 1; }
+       | UNIFORM               { $$.i = 0; $$.q.uniform = 1; }
+       ;
+
+type_specifier:
+       type_specifier_no_prec
+       | precision_qualifier type_specifier_no_prec
+       {
+          $$ = $2;
+          $$->precision = $1;
+       }
+       ;
+
+type_specifier_no_prec:
+       type_specifier_nonarray
+       | type_specifier_nonarray '[' ']'
+       {
+          $$ = $1;
+          $$->is_array = true;
+          $$->array_size = NULL;
+       }
+       | type_specifier_nonarray '[' constant_expression ']'
+       {
+          $$ = $1;
+          $$->is_array = true;
+          $$->array_size = $3;
+       }
+       ;
+
+type_specifier_nonarray:
+       basic_type_specifier_nonarray
+       {
+          $$ = new ast_type_specifier($1);
+       }
+       | struct_specifier
+       {
+          $$ = new ast_type_specifier(ast_struct);
+          $$->structure = $1;
+       }
+       | TYPE_NAME
+       {
+          $$ = new ast_type_specifier(ast_type_name);
+          $$->type_name = $1;
+       }
+       ;
+
+basic_type_specifier_nonarray:
+       VOID                    { $$ = ast_void; }
+       | FLOAT                 { $$ = ast_float; }
+       | INT                   { $$ = ast_int; }
+       | UINT                  { $$ = ast_uint; }
+       | BOOL                  { $$ = ast_bool; }
+       | VEC2                  { $$ = ast_vec2; }
+       | VEC3                  { $$ = ast_vec3; }
+       | VEC4                  { $$ = ast_vec4; }
+       | BVEC2                 { $$ = ast_bvec2; }
+       | BVEC3                 { $$ = ast_bvec3; }
+       | BVEC4                 { $$ = ast_bvec4; }
+       | IVEC2                 { $$ = ast_ivec2; }
+       | IVEC3                 { $$ = ast_ivec3; }
+       | IVEC4                 { $$ = ast_ivec4; }
+       | UVEC2                 { $$ = ast_uvec2; }
+       | UVEC3                 { $$ = ast_uvec3; }
+       | UVEC4                 { $$ = ast_uvec4; }
+       | MAT2                  { $$ = ast_mat2; }
+       | MAT3                  { $$ = ast_mat3; }
+       | MAT4                  { $$ = ast_mat4; }
+       | MAT2X2                { $$ = ast_mat2; }
+       | MAT2X3                { $$ = ast_mat2x3; }
+       | MAT2X4                { $$ = ast_mat2x4; }
+       | MAT3X2                { $$ = ast_mat3x2; }
+       | MAT3X3                { $$ = ast_mat3; }
+       | MAT3X4                { $$ = ast_mat3x4; }
+       | MAT4X2                { $$ = ast_mat4x2; }
+       | MAT4X3                { $$ = ast_mat4x3; }
+       | MAT4X4                { $$ = ast_mat4; }
+       | SAMPLER1D             { $$ = ast_sampler1d; }
+       | SAMPLER2D             { $$ = ast_sampler2d; }
+       | SAMPLER3D             { $$ = ast_sampler3d; }
+       | SAMPLERCUBE           { $$ = ast_samplercube; }
+       | SAMPLER1DSHADOW       { $$ = ast_sampler1dshadow; }
+       | SAMPLER2DSHADOW       { $$ = ast_sampler2dshadow; }
+       | SAMPLERCUBESHADOW     { $$ = ast_samplercubeshadow; }
+       | SAMPLER1DARRAY        { $$ = ast_sampler1darray; }
+       | SAMPLER2DARRAY        { $$ = ast_sampler2darray; }
+       | SAMPLER1DARRAYSHADOW  { $$ = ast_sampler1darrayshadow; }
+       | SAMPLER2DARRAYSHADOW  { $$ = ast_sampler2darrayshadow; }
+       | ISAMPLER1D            { $$ = ast_isampler1d; }
+       | ISAMPLER2D            { $$ = ast_isampler2d; }
+       | ISAMPLER3D            { $$ = ast_isampler3d; }
+       | ISAMPLERCUBE          { $$ = ast_isamplercube; }
+       | ISAMPLER1DARRAY       { $$ = ast_isampler1darray; }
+       | ISAMPLER2DARRAY       { $$ = ast_isampler2darray; }
+       | USAMPLER1D            { $$ = ast_usampler1d; }
+       | USAMPLER2D            { $$ = ast_usampler2d; }
+       | USAMPLER3D            { $$ = ast_usampler3d; }
+       | USAMPLERCUBE          { $$ = ast_usamplercube; }
+       | USAMPLER1DARRAY       { $$ = ast_usampler1darray; }
+       | USAMPLER2DARRAY       { $$ = ast_usampler2darray; }
+       ;
+
+precision_qualifier:
+       HIGH_PRECISION          { $$ = ast_precision_high; }
+       | MEDIUM_PRECISION      { $$ = ast_precision_medium; }
+       | LOW_PRECISION         { $$ = ast_precision_low; }
+       ;
+
+struct_specifier:
+       STRUCT IDENTIFIER '{' struct_declaration_list '}'
+       {
+          $$ = new ast_struct_specifier($2, $4);
+
+          _mesa_symbol_table_add_symbol(state->symbols, 0, $2, $$);
+       }
+       | STRUCT '{' struct_declaration_list '}'
+       {
+          $$ = new ast_struct_specifier(NULL, $3);
+       }
+       ;
+
+struct_declaration_list:
+       struct_declaration
+       {
+          $$ = (struct ast_node *) $1;
+       }
+       | struct_declaration_list struct_declaration
+       {
+          $$ = (struct ast_node *) $1;
+          insert_at_tail((struct simple_node *) $$,
+                         (struct simple_node *) $2);
+       }
+       ;
+
+struct_declaration:
+       type_specifier struct_declarator_list ';'
+       {
+          ast_fully_specified_type *type = new ast_fully_specified_type();
+
+          type->specifier = $1;
+          $$ = new ast_declarator_list(type);
+
+          insert_at_tail((struct simple_node *) $2,
+                         & $$->declarations);
+       }
+       ;
+
+struct_declarator_list:
+       struct_declarator
+       | struct_declarator_list ',' struct_declarator
+       {
+          $$ = $1;
+          insert_at_tail((struct simple_node *) $$,
+                         (struct simple_node *) $3);
+       }
+       ;
+
+struct_declarator:
+       IDENTIFIER
+       {
+          $$ = new ast_declaration($1, false, NULL, NULL);
+       }
+       | IDENTIFIER '[' constant_expression ']'
+       {
+          $$ = new ast_declaration($1, true, $3, NULL);
+       }
+       ;
+
+initializer:
+       assignment_expression
+       ;
+
+declaration_statement:
+       declaration
+       ;
+
+       // Grammar Note: labeled statements for SWITCH only; 'goto' is not
+       // supported.
+statement:
+       statement_matched
+       | statement_unmatched
+       ;
+
+statement_matched:
+       compound_statement      { $$ = (struct ast_node *) $1; }
+       | simple_statement
+       ;
+
+statement_unmatched:
+       selection_statement_unmatched
+       ;
+
+simple_statement:
+       declaration_statement
+       | expression_statement
+       | selection_statement_matched
+       | switch_statement              { $$ = NULL; }
+       | case_label                    { $$ = NULL; }
+       | iteration_statement
+       | jump_statement
+       ;
+
+compound_statement:
+       '{' '}'
+       {
+          $$ = new ast_compound_statement(true, NULL);
+       }
+       | '{' statement_list '}'
+       {
+          $$ = new ast_compound_statement(true, $2);
+       }
+       ;
+
+statement_no_new_scope:
+       compound_statement_no_new_scope { $$ = (struct ast_node *) $1; }
+       | simple_statement
+       ;
+
+compound_statement_no_new_scope:
+       '{' '}'
+       {
+          $$ = new ast_compound_statement(false, NULL);
+       }
+       | '{' statement_list '}'
+       {
+          $$ = new ast_compound_statement(false, $2);
+       }
+       ;
+
+statement_list:
+       statement
+       {
+          if ($1 == NULL) {
+             _mesa_glsl_error(& @1, state, "<nil> statement\n");
+             assert($1 != NULL);
+          }
+
+          $$ = $1;
+          make_empty_list((struct simple_node *) $$);
+       }
+       | statement_list statement
+       {
+          if ($2 == NULL) {
+             _mesa_glsl_error(& @2, state, "<nil> statement\n");
+             assert($2 != NULL);
+          }
+          $$ = $1;
+          insert_at_tail((struct simple_node *) $$,
+                         (struct simple_node *) $2);
+       }
+       ;
+
+expression_statement:
+       ';'
+       {
+          $$ = new ast_expression_statement(NULL);
+       }
+       | expression ';'
+       {
+          $$ = new ast_expression_statement($1);
+       }
+       ;
+
+selection_statement_matched:
+       IF '(' expression ')' statement_matched ELSE statement_matched
+       {
+          $$ = new ast_selection_statement($3, $5, $7);
+       }
+       ;
+
+selection_statement_unmatched:
+       IF '(' expression ')' statement_matched
+       {
+          $$ = new ast_selection_statement($3, $5, NULL);
+       }
+       | IF '(' expression ')' statement_unmatched
+       {
+          $$ = new ast_selection_statement($3, $5, NULL);
+       }
+       | IF '(' expression ')' statement_matched ELSE statement_unmatched
+       {
+          $$ = new ast_selection_statement($3, $5, $7);
+       }
+       ;
+
+condition:
+       expression
+       {
+          $$ = (struct ast_node *) $1;
+       }
+       | fully_specified_type IDENTIFIER '=' initializer
+       {
+          ast_declaration *decl = new ast_declaration($2, false, NULL, $4);
+          ast_declarator_list *declarator = new ast_declarator_list($1);
+
+          insert_at_tail(& declarator->declarations,
+                         (struct simple_node *) decl);
+
+          $$ = declarator;
+       }
+       ;
+
+switch_statement:
+       SWITCH '(' expression ')' compound_statement
+       ;
+
+case_label:
+       CASE expression ':'
+       | DEFAULT ':'
+       ;
+
+iteration_statement:
+       WHILE '(' condition ')' statement_no_new_scope
+       {
+          $$ = new ast_iteration_statement(ast_iteration_statement::ast_while,
+                                           NULL, $3, NULL, $5);
+       }
+       | DO statement WHILE '(' expression ')' ';'
+       {
+          $$ = new ast_iteration_statement(ast_iteration_statement::ast_do_while,
+                                           NULL, $5, NULL, $2);
+       }
+       | FOR '(' for_init_statement for_rest_statement ')' statement_no_new_scope
+       {
+          $$ = new ast_iteration_statement(ast_iteration_statement::ast_for,
+                                           $3, $4.cond, $4.rest, $6);
+       }
+       ;
+
+for_init_statement:
+       expression_statement
+       | declaration_statement
+       ;
+
+conditionopt:
+       condition
+       | /* empty */
+       {
+          $$ = NULL;
+       }
+       ;
+
+for_rest_statement:
+       conditionopt ';'
+       {
+          $$.cond = $1;
+          $$.rest = NULL;
+       }
+       | conditionopt ';' expression
+       {
+          $$.cond = $1;
+          $$.rest = $3;
+       }
+       ;
+
+       // Grammar Note: No 'goto'. Gotos are not supported.
+jump_statement:
+       CONTINUE ';' 
+       {
+          $$ = new ast_jump_statement(ast_jump_statement::ast_continue, NULL);
+       }
+       | BREAK ';'
+       {
+          $$ = new ast_jump_statement(ast_jump_statement::ast_break, NULL);
+       }
+       | RETURN ';'
+       {
+          $$ = new ast_jump_statement(ast_jump_statement::ast_return, NULL);
+       }
+       | RETURN expression ';'
+       {
+          $$ = new ast_jump_statement(ast_jump_statement::ast_return, $2);
+       }
+       | DISCARD ';' // Fragment shader only.
+       {
+          $$ = new ast_jump_statement(ast_jump_statement::ast_discard, NULL);
+       }
+       ;
+
+external_declaration:
+       function_definition     { $$ = $1; }
+       | declaration           { $$ = $1; }
+       ;
+
+function_definition:
+       function_prototype compound_statement_no_new_scope
+       {
+          $$ = new ast_function_definition();
+          $$->prototype = $1;
+          $$->body = $2;
+       }
+       ;
diff --git a/glsl_parser_extras.cc b/glsl_parser_extras.cc
new file mode 100644 (file)
index 0000000..679b600
--- /dev/null
@@ -0,0 +1,771 @@
+/*
+ * Copyright © 2008, 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+    
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include "ast.h"
+#include "glsl_parser_extras.h"
+#include "glsl_parser.tab.h"
+#include "symbol_table.h"
+
+void
+_mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...)
+{
+   char buf[1024];
+   int len;
+   va_list ap;
+
+   (void) state;
+   len = snprintf(buf, sizeof(buf), "%u:%u(%u): error: ",
+                 locp->source, locp->first_line, locp->first_column);
+
+   va_start(ap, fmt);
+   vsnprintf(buf + len, sizeof(buf) - len, fmt, ap);
+   va_end(ap);
+
+   printf("%s\n", buf);
+}
+
+
+ast_node::~ast_node()
+{
+   /* empty */
+}
+
+
+void
+_mesa_ast_type_qualifier_print(const struct ast_type_qualifier *q)
+{
+   if (q->constant)
+      printf("const ");
+
+   if (q->invariant)
+      printf("invariant ");
+
+   if (q->attribute)
+      printf("attribute ");
+
+   if (q->varying)
+      printf("varying ");
+
+   if (q->in && q->out) 
+      printf("inout ");
+   else {
+      if (q->in)
+        printf("in ");
+
+      if (q->out)
+        printf("out ");
+   }
+
+   if (q->centroid)
+      printf("centroid ");
+   if (q->uniform)
+      printf("uniform ");
+   if (q->smooth)
+      printf("smooth ");
+   if (q->flat)
+      printf("flat ");
+   if (q->noperspective)
+      printf("noperspective ");
+}
+
+
+void
+ast_node::print(void) const
+{
+   printf("node_%d ", type);
+}
+
+
+ast_node::ast_node(void)
+{
+//   make_empty_list(& ast->node);
+}
+
+void
+ast_type_specifier::print(void) const
+{
+   switch (type_specifier) {
+   case ast_void: printf("void "); break;
+   case ast_float: printf("float "); break;
+   case ast_int: printf("int "); break;
+   case ast_uint: printf("uint "); break;
+   case ast_bool: printf("bool "); break;
+   case ast_vec2: printf("vec2 "); break;
+   case ast_vec3: printf("vec3 "); break;
+   case ast_vec4: printf("vec4 "); break;
+   case ast_bvec2: printf("bvec2 "); break;
+   case ast_bvec3: printf("bvec3 "); break;
+   case ast_bvec4: printf("bvec4 "); break;
+   case ast_ivec2: printf("ivec2 "); break;
+   case ast_ivec3: printf("ivec3 "); break;
+   case ast_ivec4: printf("ivec4 "); break;
+   case ast_uvec2: printf("uvec2 "); break;
+   case ast_uvec3: printf("uvec3 "); break;
+   case ast_uvec4: printf("uvec4 "); break;
+   case ast_mat2: printf("mat2 "); break;
+   case ast_mat2x3: printf("mat2x3 "); break;
+   case ast_mat2x4: printf("mat2x4 "); break;
+   case ast_mat3x2: printf("mat3x2 "); break;
+   case ast_mat3: printf("mat3 "); break;
+   case ast_mat3x4: printf("mat3x4 "); break;
+   case ast_mat4x2: printf("mat4x2 "); break;
+   case ast_mat4x3: printf("mat4x3 "); break;
+   case ast_mat4: printf("mat4 "); break;
+   case ast_sampler1d: printf("sampler1d "); break;
+   case ast_sampler2d: printf("sampler2d "); break;
+   case ast_sampler3d: printf("sampler3d "); break;
+   case ast_samplercube: printf("samplercube "); break;
+   case ast_sampler1dshadow: printf("sampler1dshadow "); break;
+   case ast_sampler2dshadow: printf("sampler2dshadow "); break;
+   case ast_samplercubeshadow: printf("samplercubeshadow "); break;
+   case ast_sampler1darray: printf("sampler1darray "); break;
+   case ast_sampler2darray: printf("sampler2darray "); break;
+   case ast_sampler1darrayshadow: printf("sampler1darrayshadow "); break;
+   case ast_sampler2darrayshadow: printf("sampler2darrayshadow "); break;
+   case ast_isampler1d: printf("isampler1d "); break;
+   case ast_isampler2d: printf("isampler2d "); break;
+   case ast_isampler3d: printf("isampler3d "); break;
+   case ast_isamplercube: printf("isamplercube "); break;
+   case ast_isampler1darray: printf("isampler1darray "); break;
+   case ast_isampler2darray: printf("isampler2darray "); break;
+   case ast_usampler1d: printf("usampler1d "); break;
+   case ast_usampler2d: printf("usampler2d "); break;
+   case ast_usampler3d: printf("usampler3d "); break;
+   case ast_usamplercube: printf("usamplercube "); break;
+   case ast_usampler1darray: printf("usampler1darray "); break;
+   case ast_usampler2darray: printf("usampler2darray "); break;
+
+   case ast_struct:
+      structure->print();
+      break;
+
+   case ast_type_name: printf("%s ", type_name); break;
+   }
+
+   if (is_array) {
+      printf("[ ");
+
+      if (array_size) {
+        array_size->print();
+      }
+
+      printf("] ");
+   }
+}
+
+static void
+ast_opt_array_size_print(bool is_array, const ast_expression *array_size)
+{
+   if (is_array) {
+      printf("[ ");
+
+      if (array_size)
+        array_size->print();
+
+      printf("] ");
+   }
+}
+
+
+ast_type_specifier::ast_type_specifier(int specifier)
+{
+   type_specifier = ast_types(specifier);
+}
+
+
+void
+ast_compound_statement::print(void) const
+{
+   const struct simple_node *ptr;
+
+   printf("{\n");
+   
+   foreach(ptr, & statements) {
+      _mesa_ast_print(ptr);
+   }
+
+   printf("}\n");
+}
+
+
+ast_compound_statement::ast_compound_statement(int new_scope,
+                                              ast_node *statements)
+{
+   this->new_scope = new_scope;
+   make_empty_list(& this->statements);
+
+   if (statements != NULL) {
+      /* This seems odd, but it works.  The simple_list is,
+       * basically, a circular list.  insert_at_tail adds
+       * the specified node to the list before the current
+       * head.
+       */
+      insert_at_tail((struct simple_node *) statements,
+                    & this->statements);
+   }
+}
+
+
+void
+ast_expression::print(void) const
+{
+   static const char *const operators[] = {
+      "=",
+      "+",
+      "-",
+      "+",
+      "-",
+      "*",
+      "/",
+      "%",
+      "<<",
+      ">>",
+      "<",
+      ">",
+      "<=",
+      ">=",
+      "==",
+      "!=",
+      "&",
+      "^",
+      "|",
+      "~",
+      "&&",
+      "^^",
+      "!",
+
+      "*=",
+      "/=",
+      "%=",
+      "+=",
+      "-=",
+      "<<=",
+      ">>=",
+      "&=",
+      "^=",
+      "|=",
+
+      "?:",
+      "++",
+      "--",
+      "++",
+      "--",
+      ".",
+   };
+
+
+   switch (oper) {
+   case ast_assign:
+   case ast_add:
+   case ast_sub:
+   case ast_mul:
+   case ast_div:
+   case ast_mod:
+   case ast_lshift:
+   case ast_rshift:
+   case ast_less:
+   case ast_greater:
+   case ast_lequal:
+   case ast_gequal:
+   case ast_equal:
+   case ast_nequal:
+   case ast_bit_and:
+   case ast_bit_xor:
+   case ast_bit_or:
+   case ast_logic_and:
+   case ast_logic_xor:
+   case ast_logic_or:
+   case ast_mul_assign:
+   case ast_div_assign:
+   case ast_mod_assign:
+   case ast_add_assign:
+   case ast_sub_assign:
+   case ast_ls_assign:
+   case ast_rs_assign:
+   case ast_and_assign:
+   case ast_xor_assign:
+   case ast_or_assign:
+      subexpressions[0]->print();
+      printf("%s ", operators[oper]);
+      subexpressions[1]->print();
+      break;
+
+   case ast_field_selection:
+      subexpressions[0]->print();
+      printf(". %s ", primary_expression.identifier);
+      break;
+
+   case ast_plus:
+   case ast_neg:
+   case ast_bit_not:
+   case ast_logic_not:
+   case ast_pre_inc:
+   case ast_pre_dec:
+      printf("%s ", operators[oper]);
+      subexpressions[0]->print();
+      break;
+
+   case ast_post_inc:
+   case ast_post_dec:
+      subexpressions[0]->print();
+      printf("%s ", operators[oper]);
+      break;
+
+   case ast_conditional:
+      subexpressions[0]->print();
+      printf("? ");
+      subexpressions[1]->print();
+      printf(": ");
+      subexpressions[1]->print();
+      break;
+
+   case ast_array_index:
+      subexpressions[0]->print();
+      printf("[ ");
+      subexpressions[1]->print();
+      printf("] ");
+      break;
+
+   case ast_function_call: {
+      ast_expression *parameters = subexpressions[1];
+
+      subexpressions[0]->print();
+      printf("( ");
+
+      if (parameters != NULL) {
+        struct simple_node *ptr;
+
+        parameters->print();
+        foreach (ptr, (struct simple_node *) parameters) {
+           printf(", ");
+           _mesa_ast_print(ptr);
+        }
+      }
+
+      printf(") ");
+      break;
+   }
+
+   case ast_identifier:
+      printf("%s ", primary_expression.identifier);
+      break;
+
+   case ast_int_constant:
+      printf("%d ", primary_expression.int_constant);
+      break;
+
+   case ast_uint_constant:
+      printf("%u ", primary_expression.uint_constant);
+      break;
+
+   case ast_float_constant:
+      printf("%f ", primary_expression.float_constant);
+      break;
+
+   case ast_bool_constant:
+      printf("%s ",
+            primary_expression.bool_constant
+            ? "true" : "false");
+      break;
+
+   case ast_sequence: {
+      struct simple_node *ptr;
+      struct simple_node *const head = first_elem(& expressions);
+      
+      printf("( ");
+      foreach (ptr, & expressions) {
+        if (ptr != head)
+           printf(", ");
+
+        _mesa_ast_print(ptr);
+      }
+      printf(") ");
+      break;
+   }
+   }
+}
+
+ast_expression::ast_expression(int oper,
+                              ast_expression *ex0,
+                              ast_expression *ex1,
+                              ast_expression *ex2)
+{
+   this->oper = ast_operators(oper);
+   this->subexpressions[0] = ex0;
+   this->subexpressions[1] = ex1;
+   this->subexpressions[2] = ex2;
+   make_empty_list(& expressions);
+}
+
+
+void
+ast_expression_statement::print(void) const
+{
+   if (expression)
+      expression->print();
+
+   printf("; ");
+}
+
+
+ast_expression_statement::ast_expression_statement(ast_expression *ex) :
+   expression(ex)
+{
+   /* empty */
+}
+
+
+void
+ast_function::print(void) const
+{
+   struct simple_node *ptr;
+
+   return_type->print();
+   printf(" %s (", identifier);
+
+   foreach(ptr, & parameters) {
+      _mesa_ast_print(ptr);
+   }
+
+   printf(")");
+}
+
+
+ast_function::ast_function(void)
+{
+   make_empty_list(& parameters);
+}
+
+
+void
+ast_fully_specified_type::print(void) const
+{
+   _mesa_ast_type_qualifier_print(& qualifier);
+   specifier->print();
+}
+
+
+void
+ast_parameter_declarator::print(void) const
+{
+   type->print();
+   if (identifier)
+      printf("%s ", identifier);
+   ast_opt_array_size_print(is_array, array_size);
+}
+
+
+void
+ast_function_definition::print(void) const
+{
+   prototype->print();
+   body->print();
+}
+
+
+void
+ast_declaration::print(void) const
+{
+   printf("%s ", identifier);
+   ast_opt_array_size_print(is_array, array_size);
+
+   if (initializer) {
+      printf("= ");
+      initializer->print();
+   }
+}
+
+
+ast_declaration::ast_declaration(char *identifier, int is_array,
+                                ast_expression *array_size,
+                                ast_expression *initializer)
+{
+   this->identifier = identifier;
+   this->is_array = is_array;
+   this->array_size = array_size;
+   this->initializer = initializer;
+}
+
+
+void
+ast_declarator_list::print(void) const
+{
+   struct simple_node *head;
+   struct simple_node *ptr;
+
+   assert(type || invariant);
+
+   if (type)
+      type->print();
+   else
+      printf("invariant ");
+
+   head = first_elem(& declarations);
+   foreach (ptr, & declarations) {
+      if (ptr != head)
+        printf(", ");
+
+      _mesa_ast_print(ptr);
+   }
+
+   printf("; ");
+}
+
+
+ast_declarator_list::ast_declarator_list(ast_fully_specified_type *type)
+{
+   this->type = type;
+   make_empty_list(& this->declarations);
+}
+
+void
+ast_jump_statement::print(void) const
+{
+   switch (mode) {
+   case ast_continue:
+      printf("continue; ");
+      break;
+   case ast_break:
+      printf("break; ");
+      break;
+   case ast_return:
+      printf("return ");
+      if (opt_return_value)
+        opt_return_value->print();
+
+      printf("; ");
+      break;
+   case ast_discard:
+      printf("discard; ");
+      break;
+   }
+}
+
+
+ast_jump_statement::ast_jump_statement(int mode, ast_expression *return_value)
+{
+   this->mode = ast_jump_modes(mode);
+
+   if (mode == ast_return)
+      opt_return_value = return_value;
+}
+
+
+void
+ast_selection_statement::print(void) const
+{
+   printf("if ( ");
+   condition->print();
+   printf(") ");
+
+   then_statement->print();
+
+   if (else_statement) {
+      printf("else ");
+      else_statement->print();
+   }
+   
+}
+
+
+ast_selection_statement::ast_selection_statement(ast_expression *condition,
+                                                ast_node *then_statement,
+                                                ast_node *else_statement)
+{
+   this->condition = condition;
+   this->then_statement = then_statement;
+   this->else_statement = else_statement;
+}
+
+
+void
+ast_iteration_statement::print(void) const
+{
+   switch (mode) {
+   case ast_for:
+      printf("for( ");
+      if (init_statement)
+        init_statement->print();
+      printf("; ");
+
+      if (condition)
+        condition->print();
+      printf("; ");
+
+      if (rest_expression)
+        rest_expression->print();
+      printf(") ");
+
+      body->print();
+      break;
+
+   case ast_while:
+      printf("while ( ");
+      if (condition)
+        condition->print();
+      printf(") ");
+      body->print();
+      break;
+
+   case ast_do_while:
+      printf("do ");
+      body->print();
+      printf("while ( ");
+      if (condition)
+        condition->print();
+      printf("); ");
+      break;
+   }
+}
+
+
+ast_iteration_statement::ast_iteration_statement(int mode,
+                                                ast_node *init,
+                                                ast_node *condition,
+                                                ast_expression *rest_expression,
+                                                ast_node *body)
+{
+   this->mode = ast_iteration_modes(mode);
+   this->init_statement = init;
+   this->condition = condition;
+   this->rest_expression = rest_expression;
+   this->body = body;
+}
+
+
+void
+ast_struct_specifier::print(void) const
+{
+   struct simple_node *ptr;
+
+   printf("struct %s { ", name);
+   foreach (ptr, & declarations) {
+      _mesa_ast_print(ptr);
+   }
+   printf("} ");
+}
+
+
+ast_struct_specifier::ast_struct_specifier(char *identifier,
+                                          ast_node *declarator_list)
+{
+   name = identifier;
+
+   /* This seems odd, but it works.  The simple_list is,
+    * basically, a circular list.  insert_at_tail adds
+    * the specified node to the list before the current
+    * head.
+    */
+   insert_at_tail((struct simple_node *) declarator_list,
+                 & declarations);
+}
+
+
+static char *
+load_text_file(const char *file_name, size_t *size)
+{
+       char *text = NULL;
+       struct stat st;
+       ssize_t total_read = 0;
+       int fd = open(file_name, O_RDONLY);
+
+       *size = 0;
+       if (fd < 0) {
+               return NULL;
+       }
+
+       if (fstat(fd, & st) == 0) {
+          text = (char *) malloc(st.st_size + 1);
+               if (text != NULL) {
+                       do {
+                               ssize_t bytes = read(fd, text + total_read,
+                                                    st.st_size - total_read);
+                               if (bytes < 0) {
+                                       free(text);
+                                       text = NULL;
+                                       break;
+                               }
+
+                               if (bytes == 0) {
+                                       break;
+                               }
+
+                               total_read += bytes;
+                       } while (total_read < st.st_size);
+
+                       text[total_read] = '\0';
+                       *size = total_read;
+               }
+       }
+
+       close(fd);
+
+       return text;
+}
+
+
+int
+main(int argc, char **argv)
+{
+   struct _mesa_glsl_parse_state state;
+   char *shader;
+   size_t shader_len;
+   struct simple_node *ptr;
+   struct simple_node instructions;
+
+   (void) argc;
+   shader = load_text_file(argv[1], & shader_len);
+
+   state.scanner = NULL;
+   make_empty_list(& state.translation_unit);
+   state.symbols = _mesa_symbol_table_ctor();
+
+   _mesa_glsl_lexer_ctor(& state, shader, shader_len);
+   _mesa_glsl_parse(& state);
+   _mesa_glsl_lexer_dtor(& state);
+
+   foreach (ptr, & state.translation_unit) {
+      _mesa_ast_print(ptr);
+   }
+
+#if 0
+   make_empty_list(& instructions);
+   foreach (ptr, & state.translation_unit) {
+      _mesa_ast_to_hir(ptr, &instructions, &state);
+   }
+#endif
+
+   _mesa_symbol_table_dtor(state.symbols);
+
+   return 0;
+}
diff --git a/glsl_parser_extras.h b/glsl_parser_extras.h
new file mode 100644 (file)
index 0000000..932c12d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef GLSL_PARSER_EXTRAS_H
+#define GLSL_PARSER_EXTRAS_H
+
+#include "main/simple_list.h"
+
+enum _mesa_glsl_parser_targets {
+   vertex_shader,
+   geometry_shader,
+   fragment_shader
+};
+
+struct _mesa_glsl_parse_state {
+   void *scanner;
+   struct simple_node translation_unit;
+   struct _mesa_symbol_table *symbols;
+
+   unsigned language_version;
+   enum _mesa_glsl_parser_targets target;
+};
+
+typedef struct YYLTYPE {
+   int first_line;
+   int first_column;
+   int last_line;
+   int last_column;
+   unsigned source;
+} YYLTYPE;
+# define YYLTYPE_IS_DECLARED 1
+# define YYLTYPE_IS_TRIVIAL 1
+
+extern void _mesa_glsl_error(YYLTYPE *locp, void *state, const char *fmt, ...);
+
+extern void _mesa_glsl_lexer_ctor(struct _mesa_glsl_parse_state *state,
+                                 const char *string, size_t len);
+
+extern void _mesa_glsl_lexer_dtor(struct _mesa_glsl_parse_state *state);
+
+union YYSTYPE;
+extern int _mesa_glsl_lex(union YYSTYPE *yylval, YYLTYPE *yylloc, 
+                         void *scanner);
+
+extern int _mesa_glsl_parse(struct _mesa_glsl_parse_state *);
+
+#endif /* GLSL_PARSER_EXTRAS_H */
diff --git a/glsl_types.c b/glsl_types.c
new file mode 100644 (file)
index 0000000..8973218
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include "symbol_table.h"
+#include "glsl_parser_extras.h"
+#include "glsl_types.h"
+#include "builtin_types.h"
+
+
+struct glsl_type *
+_mesa_glsl_array_type_ctor(struct glsl_type *base, unsigned length,
+                          const char *name)
+{
+   struct glsl_type *type = calloc(1, sizeof(*type));
+
+   type->base_type = GLSL_TYPE_ARRAY;
+   type->name = name;
+   type->length = length;
+   type->fields.array = base;
+
+   return type;
+}
+
+
+static void
+add_types_to_symbol_table(struct _mesa_symbol_table *symtab,
+                         const struct glsl_type *types,
+                         unsigned num_types)
+{
+   unsigned i;
+
+   for (i = 0; i < num_types; i++) {
+      _mesa_symbol_table_add_symbol(symtab, 0, types[i].name,
+                                   (void *) & types[i]);
+   }
+}
+
+
+static void
+generate_110_types(struct _mesa_symbol_table *symtab)
+{
+   add_types_to_symbol_table(symtab, builtin_core_types,
+                            Elements(builtin_core_types));
+   add_types_to_symbol_table(symtab, builtin_structure_types,
+                            Elements(builtin_structure_types));
+   add_types_to_symbol_table(symtab, builtin_110_deprecated_structure_types,
+                            Elements(builtin_110_deprecated_structure_types));
+}
+
+
+static void
+generate_120_types(struct _mesa_symbol_table *symtab)
+{
+   generate_110_types(symtab);
+
+   add_types_to_symbol_table(symtab, builtin_120_types,
+                            Elements(builtin_120_types));
+}
+
+
+static void
+generate_130_types(struct _mesa_symbol_table *symtab)
+{
+   generate_120_types(symtab);
+
+   add_types_to_symbol_table(symtab, builtin_130_types,
+                            Elements(builtin_130_types));
+}
+
+
+void
+_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state)
+{
+   switch (state->language_version) {
+   case 110:
+      generate_110_types(state->symbols);
+      break;
+   case 120:
+      generate_120_types(state->symbols);
+      break;
+   case 130:
+      generate_130_types(state->symbols);
+      break;
+   default:
+      /* error */
+      break;
+   }
+}
+
+
+const struct glsl_type *
+_mesa_glsl_get_vector_type(unsigned base_type, unsigned vector_length)
+{
+   switch (base_type) {
+   case GLSL_TYPE_UINT:
+      switch (vector_length) {
+      case 1:
+      case 2:
+      case 3:
+      case 4:
+        return glsl_uint_type + (vector_length - 1);
+      default:
+        return glsl_error_type;
+      }
+   case GLSL_TYPE_INT:
+      switch (vector_length) {
+      case 1:
+      case 2:
+      case 3:
+      case 4:
+        return glsl_int_type + (vector_length - 1);
+      default:
+        return glsl_error_type;
+      }
+   case GLSL_TYPE_FLOAT:
+      switch (vector_length) {
+      case 1:
+      case 2:
+      case 3:
+      case 4:
+        return glsl_float_type + (vector_length - 1);
+      default:
+        return glsl_error_type;
+      }
+   case GLSL_TYPE_BOOL:
+      switch (vector_length) {
+      case 1:
+      case 2:
+      case 3:
+      case 4:
+        return glsl_bool_type + (vector_length - 1);
+      default:
+        return glsl_error_type;
+      }
+   default:
+      return glsl_error_type;
+   }
+}
diff --git a/glsl_types.h b/glsl_types.h
new file mode 100644 (file)
index 0000000..c69da95
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ * Copyright © 2009 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#pragma once
+#ifndef GLSL_TYPES_H
+#define GLSL_TYPES_H
+
+#define GLSL_TYPE_UINT          0
+#define GLSL_TYPE_INT           1
+#define GLSL_TYPE_FLOAT         2
+#define GLSL_TYPE_BOOL          3
+#define GLSL_TYPE_SAMPLER       4
+#define GLSL_TYPE_STRUCT        5
+#define GLSL_TYPE_ARRAY         6
+#define GLSL_TYPE_FUNCTION      7
+#define GLSL_TYPE_VOID          8
+#define GLSL_TYPE_ERROR         9
+
+#define is_numeric_base_type(b) \
+   (((b) >= GLSL_TYPE_UINT) && ((b) <= GLSL_TYPE_FLOAT))
+
+#define is_integer_base_type(b) \
+   (((b) == GLSL_TYPE_UINT) || ((b) == GLSL_TYPE_INT))
+
+#define is_error_type(t) ((t)->base_type == GLSL_TYPE_ERROR)
+
+#define GLSL_SAMPLER_DIM_1D     0
+#define GLSL_SAMPLER_DIM_2D     1
+#define GLSL_SAMPLER_DIM_3D     2
+#define GLSL_SAMPLER_DIM_CUBE   3
+#define GLSL_SAMPLER_DIM_RECT   4
+#define GLSL_SAMPLER_DIM_BUF    5
+
+
+struct glsl_type {
+   unsigned base_type:4;
+
+   unsigned sampler_dimensionality:3;
+   unsigned sampler_shadow:1;
+   unsigned sampler_array:1;
+   unsigned sampler_type:2;    /**< Type of data returned using this sampler.
+                               * only \c GLSL_TYPE_FLOAT, \c GLSL_TYPE_INT,
+                               * and \c GLSL_TYPE_UINT are valid.
+                               */
+
+   unsigned vector_elements:3; /**< 0, 2, 3, or 4 vector elements. */
+   unsigned matrix_rows:3;     /**< 0, 2, 3, or 4 matrix rows. */
+
+   /**
+    * Name of the data type
+    *
+    * This may be \c NULL for anonymous structures, for arrays, or for
+    * function types.
+    */
+   const char *name;
+
+   /**
+    * For \c GLSL_TYPE_ARRAY, this is the length of the array.  For
+    * \c GLSL_TYPE_STRUCT, it is the number of elements in the structure and
+    * the number of values pointed to by \c fields.structure (below).
+    *
+    * For \c GLSL_TYPE_FUNCTION, it is the number of parameters to the
+    * function.  The return value from a function is implicitly the first
+    * parameter.  The types of the parameters are stored in
+    * \c fields.parameters (below).
+    */
+   unsigned length;
+
+   /**
+    * Subtype of composite data types.
+    */
+   union {
+      const struct glsl_type *array;            /**< Type of array elements. */
+      const struct glsl_type *parameters;       /**< Parameters to function. */
+      const struct glsl_struct_field *structure;/**< List of struct fields. */
+   } fields;
+};
+
+#define is_glsl_type_scalar(t)                 \
+   (((t)->vector_elements == 0)                        \
+    && ((t)->base_type >= GLSL_TYPE_UINT)      \
+    && ((t)->base_type <= GLSL_TYPE_BOOL))
+
+#define is_glsl_type_vector(t)                 \
+   (((t)->vector_elements > 0)                 \
+    && ((t)->matrix_rows == 0)                 \
+    && ((t)->base_type >= GLSL_TYPE_UINT)      \
+    && ((t)->base_type <= GLSL_TYPE_BOOL))
+
+#define is_glsl_type_matrix(t)                 \
+   (((t)->matrix_rows > 0)                     \
+    && ((t)->base_type == GLSL_TYPE_FLOAT)) /* GLSL only has float matrices. */
+
+struct glsl_struct_field {
+   const struct glsl_type *type;
+   const char *name;
+};
+
+struct _mesa_glsl_parse_state;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void
+_mesa_glsl_initialize_types(struct _mesa_glsl_parse_state *state);
+
+extern const struct glsl_type *
+_mesa_glsl_get_vector_type(unsigned base_type, unsigned vector_length);
+
+extern const struct glsl_type *const glsl_error_type;
+extern const struct glsl_type *const glsl_int_type;
+extern const struct glsl_type *const glsl_uint_type;
+extern const struct glsl_type *const glsl_float_type;
+extern const struct glsl_type *const glsl_bool_type;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* GLSL_TYPES_H */
diff --git a/hash_table.c b/hash_table.c
new file mode 100644 (file)
index 0000000..e89a256
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file hash_table.c
+ * \brief Implementation of a generic, opaque hash table data type.
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+
+#include "main/imports.h"
+#include "main/simple_list.h"
+#include "hash_table.h"
+
+struct node {
+   struct node *next;
+   struct node *prev;
+};
+
+struct hash_table {
+    hash_func_t    hash;
+    hash_compare_func_t  compare;
+
+    unsigned num_buckets;
+    struct node buckets[1];
+};
+
+
+struct hash_node {
+    struct node link;
+    const void *key;
+    void *data;
+};
+
+
+struct hash_table *
+hash_table_ctor(unsigned num_buckets, hash_func_t hash,
+                hash_compare_func_t compare)
+{
+    struct hash_table *ht;
+    unsigned i;
+
+
+    if (num_buckets < 16) {
+        num_buckets = 16;
+    }
+
+    ht = _mesa_malloc(sizeof(*ht) + ((num_buckets - 1) 
+                                    * sizeof(ht->buckets[0])));
+    if (ht != NULL) {
+        ht->hash = hash;
+        ht->compare = compare;
+        ht->num_buckets = num_buckets;
+
+        for (i = 0; i < num_buckets; i++) {
+            make_empty_list(& ht->buckets[i]);
+        }
+    }
+
+    return ht;
+}
+
+
+void
+hash_table_dtor(struct hash_table *ht)
+{
+   hash_table_clear(ht);
+   _mesa_free(ht);
+}
+
+
+void
+hash_table_clear(struct hash_table *ht)
+{
+   struct node *node;
+   struct node *temp;
+   unsigned i;
+
+
+   for (i = 0; i < ht->num_buckets; i++) {
+      foreach_s(node, temp, & ht->buckets[i]) {
+        remove_from_list(node);
+        _mesa_free(node);
+      }
+
+      assert(is_empty_list(& ht->buckets[i]));
+   }
+}
+
+
+void *
+hash_table_find(struct hash_table *ht, const void *key)
+{
+    const unsigned hash_value = (*ht->hash)(key);
+    const unsigned bucket = hash_value % ht->num_buckets;
+    struct node *node;
+
+    foreach(node, & ht->buckets[bucket]) {
+       struct hash_node *hn = (struct hash_node *) node;
+
+       if ((*ht->compare)(hn->key, key) == 0) {
+         return hn->data;
+       }
+    }
+
+    return NULL;
+}
+
+
+void
+hash_table_insert(struct hash_table *ht, void *data, const void *key)
+{
+    const unsigned hash_value = (*ht->hash)(key);
+    const unsigned bucket = hash_value % ht->num_buckets;
+    struct hash_node *node;
+
+    node = _mesa_calloc(sizeof(*node));
+
+    node->data = data;
+    node->key = key;
+
+    insert_at_head(& ht->buckets[bucket], & node->link);
+}
+
+
+unsigned
+hash_table_string_hash(const void *key)
+{
+    const char *str = (const char *) key;
+    unsigned hash = 5381;
+
+
+    while (*str != '\0') {
+        hash = (hash * 33) + *str;
+        str++;
+    }
+
+    return hash;
+}
diff --git a/hash_table.h b/hash_table.h
new file mode 100644 (file)
index 0000000..7b302f5
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * \file hash_table.h
+ * \brief Implementation of a generic, opaque hash table data type.
+ *
+ * \author Ian Romanick <ian.d.romanick@intel.com>
+ */
+
+#ifndef HASH_TABLE_H
+#define HASH_TABLE_H
+
+#include <string.h>
+
+struct hash_table;
+
+typedef unsigned (*hash_func_t)(const void *key);
+typedef int (*hash_compare_func_t)(const void *key1, const void *key2);
+
+/**
+ * Hash table constructor
+ *
+ * Creates a hash table with the specified number of buckets.  The supplied
+ * \c hash and \c compare routines are used when adding elements to the table
+ * and when searching for elements in the table.
+ *
+ * \param num_buckets  Number of buckets (bins) in the hash table.
+ * \param hash         Function used to compute hash value of input keys.
+ * \param compare      Function used to compare keys.
+ */
+extern struct hash_table *hash_table_ctor(unsigned num_buckets,
+    hash_func_t hash, hash_compare_func_t compare);
+
+
+/**
+ * Release all memory associated with a hash table
+ *
+ * \warning
+ * This function cannot release memory occupied either by keys or data.
+ */
+extern void hash_table_dtor(struct hash_table *ht);
+
+
+/**
+ * Flush all entries from a hash table
+ *
+ * \param ht  Table to be cleared of its entries.
+ */
+extern void hash_table_clear(struct hash_table *ht);
+
+
+/**
+ * Search a hash table for a specific element
+ *
+ * \param ht   Table to be searched
+ * \param key  Key of the desired element
+ *
+ * \return
+ * The \c data value supplied to \c hash_table_insert when the element with
+ * the matching key was added.  If no matching key exists in the table,
+ * \c NULL is returned.
+ */
+extern void *hash_table_find(struct hash_table *ht, const void *key);
+
+
+/**
+ * Add an element to a hash table
+ */
+extern void hash_table_insert(struct hash_table *ht, void *data,
+    const void *key);
+
+
+/**
+ * Compute hash value of a string
+ *
+ * Computes the hash value of a string using the DJB2 algorithm developed by
+ * Professor Daniel J. Bernstein.  It was published on comp.lang.c once upon
+ * a time.  I was unable to find the original posting in the archives.
+ *
+ * \param key  Pointer to a NUL terminated string to be hashed.
+ *
+ * \sa hash_table_string_compare
+ */
+extern unsigned hash_table_string_hash(const void *key);
+
+
+/**
+ * Compare two strings used as keys
+ *
+ * This is just a macro wrapper around \c strcmp.
+ *
+ * \sa hash_table_string_hash
+ */
+#define hash_table_string_compare ((hash_compare_func_t) strcmp)
+
+#endif /* HASH_TABLE_H */
diff --git a/hir_field_selection.cc b/hir_field_selection.cc
new file mode 100644 (file)
index 0000000..295cbaf
--- /dev/null
@@ -0,0 +1,187 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <stdio.h>
+#include "main/imports.h"
+#include "symbol_table.h"
+#include "glsl_parser_extras.h"
+#include "ast.h"
+#include "glsl_types.h"
+#include "ir.h"
+
+#define X 1
+#define R 5
+#define S 9
+#define I 13
+
+static bool
+generate_swizzle(const char *str, struct ir_swizzle_mask *swiz,
+                unsigned vector_length)
+{
+   /* For each possible swizzle character, this table encodes the value in
+    * \c idx_map that represents the 0th element of the vector.  For invalid
+    * swizzle characters (e.g., 'k'), a special value is used that will allow
+    * detection of errors.
+    */
+   unsigned char base_idx[26] = {
+   /* a  b  c  d  e  f  g  h  i  j  k  l  m */
+      R, R, I, I, I, I, R, I, I, I, I, I, I,
+   /* n  o  p  q  r  s  t  u  v  w  x  y  z */
+      I, I, S, S, R, S, S, I, I, X, X, X, X
+   };
+
+   /* Each valid swizzle character has an entry in the previous table.  This
+    * table encodes the base index encoded in the previous table plus the actual
+    * index of the swizzle character.  When processing swizzles, the first
+    * character in the string is indexed in the previous table.  Each character
+    * in the string is indexed in this table, and the value found there has the
+    * value form the first table subtracted.  The result must be on the range
+    * [0,3].
+    *
+    * For example, the string "wzyx" will get X from the first table.  Each of
+    * the charcaters will get X+3, X+2, X+1, and X+0 from this table.  After
+    * subtraction, the swizzle values are { 3, 2, 1, 0 }.
+    *
+    * The string "wzrg" will get X from the first table.  Each of the characters
+    * will get X+3, X+2, R+0, and R+1 from this table.  After subtraction, the
+    * swizzle values are { 3, 2, 4, 5 }.  Since 4 and 5 are outside the range
+    * [0,3], the error is detected.
+    */
+   unsigned char idx_map[26] = {
+   /* a    b    c    d    e    f    g    h    i    j    k    l    m */
+      R+3, R+2, 0,   0,   0,   0,   R+1, 0,   0,   0,   0,   0,   0,
+   /* n    o    p    q    r    s    t    u    v    w    x    y    z */
+      0,   0,   S+2, S+3, R+0, S+0, S+1, 0,   0,   X+3, X+0, X+1, X+2
+   };
+
+   int swiz_idx[4] = { 0, 0, 0, 0 };
+   unsigned base;
+   unsigned dup_mask = 0;
+   unsigned seen_mask = 0;
+   unsigned i;
+
+
+   /* Validate the first character in the swizzle string and look up the base
+    * index value as described above.
+    */
+   if ((str[0] < 'a') || (str[0] > 'z'))
+      return FALSE;
+
+   base = base_idx[str[0] - 'a'];
+
+
+   for (i = 0; (i < 4) && (str[i] != '\0'); i++) {
+      unsigned bit;
+
+      /* Validate the next character, and, as described above, convert it to a
+       * swizzle index.
+       */
+      if ((str[i] < 'a') || (str[i] > 'z'))
+        return FALSE;
+
+      swiz_idx[i] = idx_map[str[0] - 'a'] - base;
+      if ((swiz_idx[i] < 0) || (swiz_idx[i] >= (int) vector_length))
+        return FALSE;
+
+
+      /* Track a bit-mask of the swizzle index values that have been seen.  If
+       * a value is seen more than once, set the "duplicate" flag.
+       */
+      bit = (1U << swiz_idx[i]);
+      dup_mask |= seen_mask & bit;
+      seen_mask |= bit;
+   }
+
+   if (str[i] != '\0')
+        return FALSE;
+
+   swiz->x = swiz_idx[0];
+   swiz->y = swiz_idx[1];
+   swiz->z = swiz_idx[2];
+   swiz->w = swiz_idx[3];
+   swiz->num_components = i;
+   swiz->has_duplicates = (dup_mask != 0);
+
+   return TRUE;
+}
+
+
+struct ir_instruction *
+_mesa_ast_field_selection_to_hir(const ast_expression *expr,
+                                simple_node *instructions,
+                                struct _mesa_glsl_parse_state *state)
+{
+   ir_instruction *op;
+   ir_dereference *deref;
+   YYLTYPE loc;
+
+
+   op = _mesa_ast_to_hir(expr->subexpressions[0], instructions, state);
+   deref = new ir_dereference(op);
+
+   /* Initially assume that the resulting type of the field selection is an
+    * error.  This make the error paths below a bit easier to follow.
+    */
+   deref->type = glsl_error_type;
+
+   /* If processing the thing being dereferenced generated an error, bail out
+    * now.  Doing so prevents spurious error messages from being logged below.
+    */
+   if (is_error_type(op->type))
+      return (struct ir_instruction *) deref;
+
+   /* There are two kinds of field selection.  There is the selection of a
+    * specific field from a structure, and there is the selection of a
+    * swizzle / mask from a vector.  Which is which is determined entirely
+    * by the base type of the thing to which the field selection operator is
+    * being applied.
+    */
+   _mesa_ast_get_location(expr, & loc);
+   if (is_glsl_type_vector(op->type)) {
+      if (generate_swizzle(expr->primary_expression.identifier, 
+                          & deref->selector.swizzle,
+                          op->type->vector_elements)) {
+        /* Based on the number of elements in the swizzle and the base type
+         * (i.e., float, int, unsigned, or bool) of the vector being swizzled,
+         * generate the type of the resulting value.
+         */
+        deref->type =
+           _mesa_glsl_get_vector_type(op->type->base_type,
+                                      deref->selector.swizzle.num_components);
+      } else {
+        /* FINISHME: Logging of error messages should be moved into
+         * FINISHME: generate_swizzle.  This allows the generation of more
+         * FINISHME: specific error messages.
+         */
+        _mesa_glsl_error(& loc, state, "Invalid swizzle / mask `%s'",
+                         expr->primary_expression.identifier);
+      }
+   } else if (op->type->base_type == GLSL_TYPE_STRUCT) {
+      /* FINISHME: Handle field selection from structures. */
+   } else {
+      _mesa_glsl_error(& loc, state, "Cannot access field `%s' of "
+                      "non-structure / non-vector.",
+                      expr->primary_expression.identifier);
+   }
+
+   return (struct ir_instruction *) deref;
+}
diff --git a/hir_function.c b/hir_function.c
new file mode 100644 (file)
index 0000000..eac2b59
--- /dev/null
@@ -0,0 +1,41 @@
+struct ir_instruction *
+_mesa_ast_constructor_to_hir(const struct ast_node *n,
+                            const struct ast_node *parameters,
+                            struct _mesa_glsl_parse_state *state)
+{
+   const struct ast_type_specifier *type = (struct ast_type_specifier *) n;
+
+
+   /* There are effectively three kinds of constructors.  Each has its own set
+    * of rules.
+    *
+    * * Built-in scalar, vector, and matrix types:  For each of these the only
+    *   matching requirement is that the number of values supplied is
+    *   sufficient to initialize all of the fields of the type.
+    * * Array types: The number of initializers must match the size of the
+    *   array, if a size is specified.  Each of the initializers must
+    *   exactly match the base type of the array.
+    * * Structure types: These initializers must exactly match the fields of
+    *   the structure in order.  This is the most restrictive type.
+    *
+    * In all cases the built-in promotions from integer to floating-point types
+    * are applied.
+    */
+
+   if (type->is_array) {
+      /* FINISHME */
+   } else if ((type->type_specifier == ast_struct)
+             || (type->type_specifier == ast_type_name)) {
+      /* FINISHME */
+   } else {
+      const struct glsl_type *ctor_type;
+
+      /* Look-up the type, by name, in the symbol table.
+       */
+
+
+      /* Generate a series of assignments of constructor parameters to fields
+       * of the object being initialized.
+       */
+   }
+}
diff --git a/ir.cc b/ir.cc
new file mode 100644 (file)
index 0000000..7bd7854
--- /dev/null
+++ b/ir.cc
@@ -0,0 +1,116 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <string.h>
+#include "main/imports.h"
+#include "main/simple_list.h"
+#include "ir.h"
+#include "glsl_types.h"
+
+ir_instruction::ir_instruction(int mode)
+{
+   this->mode = mode;
+   make_empty_list(this);
+}
+
+
+ir_assignment::ir_assignment(ir_instruction *lhs, ir_instruction *rhs,
+                            ir_expression *condition)
+   : ir_instruction(ir_op_assign)
+{
+   this->lhs = (ir_dereference *) lhs;
+   this->rhs = rhs;
+   this->condition = condition;
+}
+
+
+ir_expression::ir_expression(int op, const struct glsl_type *type,
+                            ir_instruction *op0, ir_instruction *op1)
+   : ir_instruction(ir_op_expression)
+{
+   this->type = type;
+   this->operation = ir_expression_operation(op);
+   this->operands[0] = op0;
+   this->operands[1] = op1;
+}
+
+
+ir_label::ir_label(const char *label)
+   : ir_instruction(ir_op_label), label(label)
+{
+   /* empty */
+}
+
+
+ir_constant::ir_constant(const struct glsl_type *type, const void *data)
+   : ir_instruction(ir_op_constant)
+{
+   const unsigned elements = 
+      ((type->vector_elements == 0) ? 1 : type->vector_elements)
+      * ((type->matrix_rows == 0) ? 1 : type->matrix_rows);
+   unsigned size = 0;
+
+   this->type = type;
+   switch (type->base_type) {
+   case GLSL_TYPE_UINT:  size = sizeof(this->value.u[0]); break;
+   case GLSL_TYPE_INT:   size = sizeof(this->value.i[0]); break;
+   case GLSL_TYPE_FLOAT: size = sizeof(this->value.f[0]); break;
+   case GLSL_TYPE_BOOL:  size = sizeof(this->value.b[0]); break;
+   default:
+      /* FINISHME: What to do?  Exceptions are not the answer.
+       */
+      break;
+   }
+
+   memcpy(& this->value, data, size * elements);
+}
+
+
+ir_dereference::ir_dereference(ir_instruction *var)
+   : ir_instruction(ir_op_dereference)
+{
+   this->mode = ir_reference_variable;
+   this->var = var;
+   this->type = (var != NULL) ? var->type : glsl_error_type;
+}
+
+
+ir_variable::ir_variable(const struct glsl_type *type, const char *name)
+   : ir_instruction(ir_op_var_decl)
+{
+   this->type = type;
+   this->name = name;
+}
+
+
+ir_function_signature::ir_function_signature(void)
+   : ir_instruction(ir_op_func_sig)
+{
+   make_empty_list(& parameters);
+}
+
+
+ir_function::ir_function(void)
+   : ir_instruction(ir_op_func)
+{
+   make_empty_list(& signatures);
+}
diff --git a/ir.h b/ir.h
new file mode 100644 (file)
index 0000000..304f1dc
--- /dev/null
+++ b/ir.h
@@ -0,0 +1,302 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+struct ir_program {
+   void *bong_hits;
+};
+
+
+enum ir_opcodes {
+   ir_op_var_decl,
+   ir_op_assign,
+   ir_op_expression,
+   ir_op_dereference,
+   ir_op_jump,
+   ir_op_label,
+   ir_op_constant,
+   ir_op_func_sig,
+   ir_op_func
+};
+
+/**
+ * Base class of all IR instructions
+ */
+class ir_instruction : public simple_node {
+public:
+   unsigned mode;
+   const struct glsl_type *type;
+
+protected:
+   ir_instruction(int mode);
+
+private:
+   /**
+    * Dummy constructor to catch bad constructors in derived classes.
+    *
+    * Every derived must use the constructor that sets the instructions
+    * mode.  Having the \c void constructor private prevents derived classes
+    * from accidentally doing the wrong thing.
+    */
+   ir_instruction(void);
+};
+
+
+enum ir_variable_mode {
+   ir_var_auto = 0,
+   ir_var_uniform,
+   ir_var_in,
+   ir_var_out,
+   ir_var_inout
+};
+
+enum ir_varaible_interpolation {
+   ir_var_smooth = 0,
+   ir_var_flat,
+   ir_var_noperspective
+};
+
+class ir_variable : public ir_instruction {
+public:
+   ir_variable(const struct glsl_type *, const char *);
+
+   const char *name;
+
+   unsigned read_only:1;
+   unsigned centroid:1;
+   unsigned invariant:1;
+
+   unsigned mode:3;
+   unsigned interpolation:2;
+};
+
+
+class ir_label : public ir_instruction {
+public:
+   ir_label(const char *label);
+
+   const char *label;
+};
+
+
+/*@{*/
+class ir_function_signature : public ir_instruction {
+public:
+   ir_function_signature(void);
+
+   /**
+    * Function return type.
+    *
+    * \note This discards the optional precision qualifier.
+    */
+   const struct glsl_type *return_type;
+
+   /**
+    * List of function parameters stored as ir_variable objects.
+    */
+   struct simple_node parameters;
+
+   /**
+    * Pointer to the label that begins the function definition.
+    */
+   ir_label *definition;
+};
+
+
+/**
+ * Header for tracking functions in the symbol table
+ */
+class ir_function : public ir_instruction {
+public:
+   ir_function(void);
+
+   /**
+    * Name of the function.
+    */
+   const char *name;
+
+   struct simple_node signatures;
+};
+/*@}*/
+
+class ir_expression;
+class ir_dereference;
+
+class ir_assignment : public ir_instruction {
+public:
+   ir_assignment(ir_instruction *lhs, ir_instruction *rhs,
+                ir_expression *condition);
+
+   /**
+    * Left-hand side of the assignment.
+    */
+   ir_dereference *lhs;
+
+   /**
+    * Value being assigned
+    *
+    * This should be either \c ir_op_expression or \c ir_op_deference.
+    */
+   ir_instruction *rhs;
+
+   /**
+    * Optional condition for the assignment.
+    */
+   ir_expression *condition;
+};
+
+
+enum ir_expression_operation {
+   ir_unop_bit_not,
+   ir_unop_logic_not,
+   ir_unop_neg,
+   ir_unop_abs,
+   ir_unop_rcp,
+   ir_unop_rsq,
+   ir_unop_exp,
+   ir_unop_log,
+   ir_unop_f2i,      /**< Float-to-integer conversion. */
+   ir_unop_i2f,      /**< Integer-to-float conversion. */
+
+   /**
+    * \name Unary floating-point rounding operations.
+    */
+   /*@{*/
+   ir_unop_trunc,
+   ir_unop_ceil,
+   ir_unop_floor,
+   /*@}*/
+
+   ir_binop_add,
+   ir_binop_sub,
+   ir_binop_mul,
+   ir_binop_div,
+   ir_binop_mod,
+
+   /**
+    * \name Binary comparison operators
+    */
+   /*@{*/
+   ir_binop_less,
+   ir_binop_greater,
+   ir_binop_lequal,
+   ir_binop_gequal,
+   ir_binop_equal,
+   ir_binop_nequal,
+   /*@}*/
+
+   /**
+    * \name Bit-wise binary operations.
+    */
+   /*@{*/
+   ir_binop_lshift,
+   ir_binop_rshift,
+   ir_binop_bit_and,
+   ir_binop_bit_xor,
+   ir_binop_bit_or,
+   /*@}*/
+
+   ir_binop_logic_and,
+   ir_binop_logic_xor,
+   ir_binop_logic_or,
+   ir_binop_logic_not,
+
+   ir_binop_dot,
+   ir_binop_min,
+   ir_binop_max,
+
+   ir_binop_pow
+};
+
+class ir_expression : public ir_instruction {
+public:
+   ir_expression(int op, const struct glsl_type *type,
+                ir_instruction *, ir_instruction *);
+
+   ir_expression_operation operation;
+   ir_instruction *operands[2];
+};
+
+
+struct ir_swizzle_mask {
+   unsigned x:2;
+   unsigned y:2;
+   unsigned z:2;
+   unsigned w:2;
+
+   /**
+    * Number of components in the swizzle.
+    */
+   unsigned num_components:2;
+
+   /**
+    * Does the swizzle contain duplicate components?
+    *
+    * L-value swizzles cannot contain duplicate components.
+    */
+   unsigned has_duplicates:1;
+};
+
+class ir_dereference : public ir_instruction {
+public:
+   ir_dereference(struct ir_instruction *);
+
+   enum {
+      ir_reference_variable,
+      ir_reference_array,
+      ir_reference_record
+   } mode;
+
+   /**
+    * Object being dereferenced.
+    *
+    * Must be either an \c ir_variable or an \c ir_deference.
+    */
+   ir_instruction *var;
+
+   union {
+      ir_expression *array_index;
+      const char *field;
+      struct ir_swizzle_mask swizzle;
+   } selector;
+};
+
+
+class ir_constant : public ir_instruction {
+public:
+   ir_constant(const struct glsl_type *type, const void *data);
+
+   /**
+    * Value of the constant.
+    *
+    * The field used to back the values supplied by the constant is determined
+    * by the type associated with the \c ir_instruction.  Constants may be
+    * scalars, vectors, or matrices.
+    */
+   union {
+      unsigned u[16];
+      int i[16];
+      float f[16];
+      bool b[16];
+   } value;
+};
+
diff --git a/main/imports.h b/main/imports.h
new file mode 100644 (file)
index 0000000..d219734
--- /dev/null
@@ -0,0 +1,6 @@
+#include <assert.h>
+#include <stdlib.h>
+
+#define _mesa_malloc(x)   malloc(x)
+#define _mesa_free(x)     free(x)
+#define _mesa_calloc(x)   calloc(1,x)
diff --git a/main/simple_list.h b/main/simple_list.h
new file mode 100644 (file)
index 0000000..5ef39e1
--- /dev/null
@@ -0,0 +1,235 @@
+/**
+ * \file simple_list.h
+ * Simple macros for type-safe, intrusive lists.
+ *
+ *  Intended to work with a list sentinal which is created as an empty
+ *  list.  Insert & delete are O(1).
+ *  
+ * \author
+ *  (C) 1997, Keith Whitwell
+ */
+
+/*
+ * Mesa 3-D graphics library
+ * Version:  3.5
+ *
+ * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+#ifndef _SIMPLE_LIST_H
+#define _SIMPLE_LIST_H
+
+struct simple_node {
+   struct simple_node *next;
+   struct simple_node *prev;
+};
+
+/**
+ * Remove an element from list.
+ *
+ * \param elem element to remove.
+ */
+#define remove_from_list(elem)                 \
+do {                                           \
+   (elem)->next->prev = (elem)->prev;          \
+   (elem)->prev->next = (elem)->next;          \
+} while (0)
+
+/**
+ * Insert an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_head(list, elem)             \
+do {                                           \
+   (elem)->prev = list;                                \
+   (elem)->next = (list)->next;                        \
+   (list)->next->prev = elem;                  \
+   (list)->next = elem;                                \
+} while(0)
+
+/**
+ * Insert an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to insert.
+ */
+#define insert_at_tail(list, elem)             \
+do {                                           \
+   (elem)->next = list;                                \
+   (elem)->prev = (list)->prev;                        \
+   (list)->prev->next = elem;                  \
+   (list)->prev = elem;                                \
+} while(0)
+
+/**
+ * Move an element to the list head.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_head(list, elem)               \
+do {                                           \
+   remove_from_list(elem);                     \
+   insert_at_head(list, elem);                 \
+} while (0)
+
+/**
+ * Move an element to the list tail.
+ *
+ * \param list list.
+ * \param elem element to move.
+ */
+#define move_to_tail(list, elem)               \
+do {                                           \
+   remove_from_list(elem);                     \
+   insert_at_tail(list, elem);                 \
+} while (0)
+
+/**
+ * Consatinate a cyclic list to a list
+ *
+ * Appends the sequence of nodes starting with \c tail to the list \c head.
+ * A "cyclic list" is a list that does not have a sentinal node.  This means
+ * that the data pointed to by \c tail is an actual node, not a dataless
+ * sentinal.  Note that if \c tail constist of a single node, this macro
+ * behaves identically to \c insert_at_tail
+ *
+ * \param head Head of the list to be appended to.  This may or may not
+ *             be a cyclic list.
+ * \param tail Head of the cyclic list to be appended to \c head.
+ * \param temp Temporary \c simple_list used by the macro
+ *
+ * \sa insert_at_tail
+ */
+#define concat_list_and_cycle(head, tail, temp)        \
+do {                                           \
+   (head)->prev->next = (tail);                        \
+   (tail)->prev->next = (head);                        \
+   (temp) = (head)->prev;                      \
+   (head)->prev = (tail)->prev;                        \
+   (tail)->prev = (temp);                      \
+} while (0)
+
+#define concat_list(head, next_list)           \
+do {                                           \
+   (next_list)->next->prev = (head)->prev;     \
+   (next_list)->prev->next = (head);           \
+   (head)->prev->next = (next_list)->next;     \
+   (head)->prev = (next_list)->prev;           \
+} while (0)
+
+/**
+ * Make a empty list empty.
+ *
+ * \param sentinal list (sentinal element).
+ */
+#define make_empty_list(sentinal)              \
+do {                                           \
+   (sentinal)->next = sentinal;                        \
+   (sentinal)->prev = sentinal;                        \
+} while (0)
+
+/**
+ * Get list first element.
+ *
+ * \param list list.
+ *
+ * \return pointer to first element.
+ */
+#define first_elem(list)       ((list)->next)
+
+/**
+ * Get list last element.
+ *
+ * \param list list.
+ *
+ * \return pointer to last element.
+ */
+#define last_elem(list)        ((list)->prev)
+
+/**
+ * Get next element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to next element.
+ */
+#define next_elem(elem)        ((elem)->next)
+
+/**
+ * Get previous element.
+ *
+ * \param elem element.
+ *
+ * \return pointer to previous element.
+ */
+#define prev_elem(elem)        ((elem)->prev)
+
+/**
+ * Test whether element is at end of the list.
+ * 
+ * \param list list.
+ * \param elem element.
+ * 
+ * \return non-zero if element is at end of list, or zero otherwise.
+ */
+#define at_end(list, elem)     ((elem) == (list))
+
+/**
+ * Test if a list is empty.
+ * 
+ * \param list list.
+ * 
+ * \return non-zero if list empty, or zero otherwise.
+ */
+#define is_empty_list(list)    ((list)->next == (list))
+
+/**
+ * Walk through the elements of a list.
+ *
+ * \param ptr pointer to the current element.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach(ptr, list)     \
+        for( ptr=(list)->next ;  ptr!=list ;  ptr=(ptr)->next )
+
+/**
+ * Walk through the elements of a list.
+ *
+ * Same as #foreach but lets you unlink the current value during a list
+ * traversal.  Useful for freeing a list, element by element.
+ * 
+ * \param ptr pointer to the current element.
+ * \param t temporary pointer.
+ * \param list list.
+ *
+ * \note It should be followed by a { } block or a single statement, as in a \c
+ * for loop.
+ */
+#define foreach_s(ptr, t, list)   \
+        for(ptr=(list)->next,t=(ptr)->next; list != ptr; ptr=t, t=(t)->next)
+
+#endif
diff --git a/symbol_table.c b/symbol_table.c
new file mode 100644 (file)
index 0000000..4e043d1
--- /dev/null
@@ -0,0 +1,377 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include "main/imports.h"
+#include "symbol_table.h"
+#include "hash_table.h"
+
+struct symbol {
+    /**
+     * Link to the next symbol in the table with the same name
+     *
+     * The linked list of symbols with the same name is ordered by scope
+     * from inner-most to outer-most.
+     */
+    struct symbol *next_with_same_name;
+
+
+    /**
+     * Link to the next symbol in the table with the same scope
+     *
+     * The linked list of symbols with the same scope is unordered.  Symbols
+     * in this list my have unique names.
+     */
+    struct symbol *next_with_same_scope;
+
+
+    /**
+     * Header information for the list of symbols with the same name.
+     */
+    struct symbol_header *hdr;
+
+
+    /**
+     * Name space of the symbol
+     *
+     * Name space are arbitrary user assigned integers.  No two symbols can
+     * exist in the same name space at the same scope level.
+     */
+    int name_space;
+
+    
+    /**
+     * Arbitrary user supplied data.
+     */
+    void *data;
+
+   /** Scope depth where this symbol was defined. */
+   unsigned depth;
+};
+
+
+/**
+ */
+struct symbol_header {
+    /** Linkage in list of all headers in a given symbol table. */
+    struct symbol_header *next;
+
+    /** Symbol name. */
+    const char *name;
+
+    /** Linked list of symbols with the same name. */
+    struct symbol *symbols;
+};
+
+
+/**
+ * Element of the scope stack.
+ */
+struct scope_level {
+    /** Link to next (inner) scope level. */
+    struct scope_level *next;
+    
+    /** Linked list of symbols with the same scope. */
+    struct symbol *symbols;
+};
+
+
+/**
+ *
+ */
+struct _mesa_symbol_table {
+    /** Hash table containing all symbols in the symbol table. */
+    struct hash_table *ht;
+
+    /** Top of scope stack. */
+    struct scope_level *current_scope;
+
+    /** List of all symbol headers in the table. */
+    struct symbol_header *hdr;
+
+   /** Current scope depth. */
+   unsigned depth;
+};
+
+
+struct _mesa_symbol_table_iterator {
+    /**
+     * Name space of symbols returned by this iterator.
+     */
+    int name_space;
+
+
+    /**
+     * Currently iterated symbol
+     *
+     * The next call to \c _mesa_symbol_table_iterator_get will return this
+     * value.  It will also update this value to the value that should be
+     * returned by the next call.
+     */
+    struct symbol *curr;
+};
+
+
+static void
+check_symbol_table(struct _mesa_symbol_table *table)
+{
+#if 1
+    struct scope_level *scope;
+
+    for (scope = table->current_scope; scope != NULL; scope = scope->next) {
+        struct symbol *sym;
+
+        for (sym = scope->symbols
+             ; sym != NULL
+             ; sym = sym->next_with_same_name) {
+            const struct symbol_header *const hdr = sym->hdr;
+            struct symbol *sym2;
+
+            for (sym2 = hdr->symbols
+                 ; sym2 != NULL
+                 ; sym2 = sym2->next_with_same_name) {
+                assert(sym2->hdr == hdr);
+            }
+        }
+    }
+#endif
+}
+
+void
+_mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table)
+{
+    struct scope_level *const scope = table->current_scope;
+    struct symbol *sym = scope->symbols;
+
+    table->current_scope = scope->next;
+    table->depth--;
+
+    free(scope);
+
+    while (sym != NULL) {
+        struct symbol *const next = sym->next_with_same_scope;
+        struct symbol_header *const hdr = sym->hdr;
+
+        assert(hdr->symbols == sym);
+
+        hdr->symbols = sym->next_with_same_name;
+
+        free(sym);
+
+        sym = next;
+    }
+
+    check_symbol_table(table);
+}
+
+
+void
+_mesa_symbol_table_push_scope(struct _mesa_symbol_table *table)
+{
+    struct scope_level *const scope = calloc(1, sizeof(*scope));
+    
+    scope->next = table->current_scope;
+    table->current_scope = scope;
+    table->depth++;
+}
+
+
+static struct symbol_header *
+find_symbol(struct _mesa_symbol_table *table, const char *name)
+{
+    return (struct symbol_header *) hash_table_find(table->ht, name);
+}
+
+
+struct _mesa_symbol_table_iterator *
+_mesa_symbol_table_iterator_ctor(struct _mesa_symbol_table *table,
+                                 int name_space, const char *name)
+{
+    struct _mesa_symbol_table_iterator *iter = calloc(1, sizeof(*iter));
+    struct symbol_header *const hdr = find_symbol(table, name);
+    
+    iter->name_space = name_space;
+
+    if (hdr != NULL) {
+        struct symbol *sym;
+
+        for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
+            assert(sym->hdr == hdr);
+
+            if ((name_space == -1) || (sym->name_space == name_space)) {
+                iter->curr = sym;
+                break;
+            }
+        }
+    }
+
+    return iter;
+}
+
+
+void
+_mesa_symbol_table_iterator_dtor(struct _mesa_symbol_table_iterator *iter)
+{
+    free(iter);
+}
+
+
+void *
+_mesa_symbol_table_iterator_get(struct _mesa_symbol_table_iterator *iter)
+{
+    return (iter->curr == NULL) ? NULL : iter->curr->data;
+}
+
+
+int
+_mesa_symbol_table_iterator_next(struct _mesa_symbol_table_iterator *iter)
+{
+    struct symbol_header *hdr;
+
+    if (iter->curr == NULL) {
+        return 0;
+    }
+
+    hdr = iter->curr->hdr;
+    iter->curr = iter->curr->next_with_same_name;
+
+    while (iter->curr != NULL) {
+        assert(iter->curr->hdr == hdr);
+
+        if ((iter->name_space == -1)
+            || (iter->curr->name_space == iter->name_space)) {
+            return 1;
+        }
+
+        iter->curr = iter->curr->next_with_same_name;
+    }
+
+    return 0;
+}
+
+
+void *
+_mesa_symbol_table_find_symbol(struct _mesa_symbol_table *table,
+                               int name_space, const char *name)
+{
+    struct symbol_header *const hdr = find_symbol(table, name);
+
+    if (hdr != NULL) {
+        struct symbol *sym;
+
+
+        for (sym = hdr->symbols; sym != NULL; sym = sym->next_with_same_name) {
+            assert(sym->hdr == hdr);
+
+            if ((name_space == -1) || (sym->name_space == name_space)) {
+                return sym->data;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+
+int
+_mesa_symbol_table_add_symbol(struct _mesa_symbol_table *table,
+                              int name_space, const char *name,
+                              void *declaration)
+{
+    struct symbol_header *hdr;
+    struct symbol *sym;
+
+    check_symbol_table(table);
+
+    hdr = find_symbol(table, name);
+
+    check_symbol_table(table);
+
+    if (hdr == NULL) {
+        hdr = calloc(1, sizeof(*hdr));
+        hdr->name = name;
+
+        hash_table_insert(table->ht, hdr, name);
+       hdr->next = table->hdr;
+       table->hdr = hdr;
+    }
+
+    check_symbol_table(table);
+
+    /* If the symbol already exists at this scope, it cannot be added to the
+     * table.
+     */
+    if (hdr->symbols && (hdr->symbols->depth == table->depth))
+       return -1;
+
+    sym = calloc(1, sizeof(*sym));
+    sym->next_with_same_name = hdr->symbols;
+    sym->next_with_same_scope = table->current_scope->symbols;
+    sym->hdr = hdr;
+    sym->name_space = name_space;
+    sym->data = declaration;
+    sym->depth = table->depth;
+
+    assert(sym->hdr == hdr);
+
+    hdr->symbols = sym;
+    table->current_scope->symbols = sym;
+
+    check_symbol_table(table);
+    return 0;
+}
+
+
+struct _mesa_symbol_table *
+_mesa_symbol_table_ctor(void)
+{
+    struct _mesa_symbol_table *table = calloc(1, sizeof(*table));
+
+    if (table != NULL) {
+       table->ht = hash_table_ctor(32, hash_table_string_hash,
+                                  hash_table_string_compare);
+
+       _mesa_symbol_table_push_scope(table);
+    }
+
+    return table;
+}
+
+
+void
+_mesa_symbol_table_dtor(struct _mesa_symbol_table *table)
+{
+   struct symbol_header *hdr;
+   struct symbol_header *next;
+
+   while (table->current_scope != NULL) {
+      _mesa_symbol_table_pop_scope(table);
+   }
+
+   for (hdr = table->hdr; hdr != NULL; hdr = next) {
+       next = hdr->next;
+       _mesa_free(hdr);
+   }
+
+   hash_table_dtor(table->ht);
+   free(table);
+}
diff --git a/symbol_table.h b/symbol_table.h
new file mode 100644 (file)
index 0000000..d3f65e3
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2008 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#ifndef MESA_SYMBOL_TABLE_H
+#define MESA_SYMBOL_TABLE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct _mesa_symbol_table;
+struct _mesa_symbol_table_iterator;
+
+extern void _mesa_symbol_table_push_scope(struct _mesa_symbol_table *table);
+
+extern void _mesa_symbol_table_pop_scope(struct _mesa_symbol_table *table);
+
+extern int _mesa_symbol_table_add_symbol(struct _mesa_symbol_table *symtab,
+    int name_space, const char *name, void *declaration);
+
+extern void *_mesa_symbol_table_find_symbol(
+    struct _mesa_symbol_table *symtab, int name_space, const char *name);
+
+extern struct _mesa_symbol_table *_mesa_symbol_table_ctor(void);
+
+extern void _mesa_symbol_table_dtor(struct _mesa_symbol_table *);
+
+extern struct _mesa_symbol_table_iterator *_mesa_symbol_table_iterator_ctor(
+    struct _mesa_symbol_table *table, int name_space, const char *name);
+
+extern void _mesa_symbol_table_iterator_dtor(
+    struct _mesa_symbol_table_iterator *);
+
+extern void *_mesa_symbol_table_iterator_get(
+    struct _mesa_symbol_table_iterator *iter);
+
+extern int _mesa_symbol_table_iterator_next(
+    struct _mesa_symbol_table_iterator *iter);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MESA_SYMBOL_TABLE_H */
diff --git a/tests/parameters-01.txt b/tests/parameters-01.txt
new file mode 100644 (file)
index 0000000..f0beb6c
--- /dev/null
@@ -0,0 +1,9 @@
+void a()
+{
+       ;       
+}
+
+void a()
+{
+       ;       
+}
diff --git a/tests/parameters-02.txt b/tests/parameters-02.txt
new file mode 100644 (file)
index 0000000..58f44e5
--- /dev/null
@@ -0,0 +1,9 @@
+void a()
+{
+       ;       
+}
+
+void a(float x)
+{
+       ;       
+}
diff --git a/tests/parameters-03.txt b/tests/parameters-03.txt
new file mode 100644 (file)
index 0000000..7ec30f8
--- /dev/null
@@ -0,0 +1,9 @@
+/* FAIL - x is redeclared in the function body at the same scope as the
+ *        parameter
+ */
+void a(float x, float y)
+{
+       float x;
+
+       x = y;
+}
diff --git a/tests/swiz-01.glsl b/tests/swiz-01.glsl
new file mode 100644 (file)
index 0000000..a72af37
--- /dev/null
@@ -0,0 +1,10 @@
+#version 120
+
+void main()
+{
+       float a;
+       vec4 b;
+
+       b.x = 6.0;
+       a = b.x;
+}
diff --git a/tests/swiz-02.glsl b/tests/swiz-02.glsl
new file mode 100644 (file)
index 0000000..5e2acd1
--- /dev/null
@@ -0,0 +1,10 @@
+#version 120
+
+void main()
+{
+       float a;
+       vec4 b;
+
+       b.x = 6.0;
+       a = b.xy;
+}