summaryrefslogtreecommitdiffstats
path: root/o3d/compiler
diff options
context:
space:
mode:
authorgspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
committergspencer@google.com <gspencer@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2009-05-27 23:15:42 +0000
commit05b47f7a8c5451f858dc220df0e3a97542edace6 (patch)
treea2273d619f0625c9d44d40842845ccce2eac1045 /o3d/compiler
parent5cdc8bdb4c847cefe7f4542bd10c9880c2c557a0 (diff)
downloadchromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.zip
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.gz
chromium_src-05b47f7a8c5451f858dc220df0e3a97542edace6.tar.bz2
This is the O3D source tree's initial commit to the Chromium tree. It
is not built or referenced at all by the chrome build yet, and doesn't yet build in it's new home. We'll change that shortly. git-svn-id: svn://svn.chromium.org/chrome/trunk/src@17035 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'o3d/compiler')
-rw-r--r--o3d/compiler/antlr/build.scons69
-rw-r--r--o3d/compiler/hlsl/HLSL.g1020
-rw-r--r--o3d/compiler/puritan/build.scons57
-rw-r--r--o3d/compiler/puritan/exp_gen.cc934
-rw-r--r--o3d/compiler/puritan/exp_gen.h331
-rw-r--r--o3d/compiler/puritan/knobs.cc783
-rw-r--r--o3d/compiler/puritan/knobs.h268
-rw-r--r--o3d/compiler/puritan/main.cc129
-rw-r--r--o3d/compiler/puritan/puritan.cc1619
-rw-r--r--o3d/compiler/puritan/puritan.h259
-rw-r--r--o3d/compiler/puritan/puritan_assert.cc51
-rw-r--r--o3d/compiler/puritan/puritan_assert.h83
-rw-r--r--o3d/compiler/puritan/puritan_shared_ptr.h292
-rw-r--r--o3d/compiler/puritan/rand.cc150
-rw-r--r--o3d/compiler/puritan/rand.h73
-rw-r--r--o3d/compiler/puritan/structure_gen.cc328
-rw-r--r--o3d/compiler/puritan/structure_gen.h204
-rw-r--r--o3d/compiler/puritan/test_gen.cc50
-rw-r--r--o3d/compiler/puritan/test_gen.h47
-rw-r--r--o3d/compiler/technique/Technique.g3pl1126
-rw-r--r--o3d/compiler/technique/build.scons94
-rw-r--r--o3d/compiler/technique/technique_error.cc283
-rw-r--r--o3d/compiler/technique/technique_error.h60
-rw-r--r--o3d/compiler/technique/technique_parser.cc228
-rw-r--r--o3d/compiler/technique/technique_parser.h130
-rw-r--r--o3d/compiler/technique/technique_parser_test.cc414
-rw-r--r--o3d/compiler/technique/technique_structures.cc87
-rw-r--r--o3d/compiler/technique/technique_structures.h132
-rw-r--r--o3d/compiler/technique/test_data/HLSL_declarations.fx30
-rw-r--r--o3d/compiler/technique/test_data/fur.fx121
-rw-r--r--o3d/compiler/technique/test_data/lambert.fx38
-rw-r--r--o3d/compiler/technique/test_data/noshader.fx8
-rw-r--r--o3d/compiler/technique/test_data/notechnique.fx7
-rw-r--r--o3d/compiler/technique/test_data/sampler_test.fx54
-rw-r--r--o3d/compiler/technique/test_data/shadow_map.fx170
-rw-r--r--o3d/compiler/technique/test_data/simple.fx13
36 files changed, 9742 insertions, 0 deletions
diff --git a/o3d/compiler/antlr/build.scons b/o3d/compiler/antlr/build.scons
new file mode 100644
index 0000000..a6d7df5
--- /dev/null
+++ b/o3d/compiler/antlr/build.scons
@@ -0,0 +1,69 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+Import('env')
+
+env.Append(CPPPATH = env['RENDERER_INCLUDE_PATH'] + ['$ANTLRLIBC_DIR/include'])
+
+if env.Bit('windows'):
+ # force these files to be compiled as C
+ env.Append(CCFLAGS = ['/TC'])
+
+# Create the Antlr C Runtime library -------------------------------------------
+antlr_sources = [
+ 'antlr3baserecognizer',
+ 'antlr3basetree',
+ 'antlr3basetreeadaptor',
+ 'antlr3bitset',
+ 'antlr3collections',
+ 'antlr3commontoken',
+ 'antlr3commontree',
+ 'antlr3commontreeadaptor',
+ 'antlr3commontreenodestream',
+ 'antlr3convertutf',
+ 'antlr3cyclicdfa',
+ 'antlr3debughandlers',
+ 'antlr3encodings',
+ 'antlr3exception',
+ 'antlr3filestream',
+ 'antlr3inputstream',
+ 'antlr3intstream',
+ 'antlr3lexer',
+ 'antlr3parser',
+ 'antlr3rewritestreams',
+ 'antlr3string',
+ 'antlr3stringstream',
+ 'antlr3tokenstream',
+ 'antlr3treeparser',
+ 'antlr3ucs2inputstream',
+]
+antlr_objects = env.MakeObjects(antlr_sources, '$ANTLRLIBC_DIR/src', 'c')
+
+antlr_lib = env.ComponentLibrary('antlr3c', antlr_objects)
diff --git a/o3d/compiler/hlsl/HLSL.g b/o3d/compiler/hlsl/HLSL.g
new file mode 100644
index 0000000..7477b0d
--- /dev/null
+++ b/o3d/compiler/hlsl/HLSL.g
@@ -0,0 +1,1020 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+// This file contains the ANTLR grammar for parsing HLSL into an Abstract
+// Syntax Tree (AST).
+
+grammar HLSL;
+
+options {
+ language = Java;
+ }
+
+@header
+{
+}
+
+translation_unit
+ : ( global_declaration )* (technique)* EOF
+ ;
+
+global_declaration
+ : (function_storage_class? function_type_specifier ID LPAREN) => function_declaration
+ | sampler_declaration
+ | texture_declaration
+ | struct_definition
+ | typedef_definition
+ | var_declaration
+ ;
+
+// variables -------------------------------------------
+
+var_declaration
+ : var_storage_class*
+ var_type_modifier?
+ var_datatype id_declaration
+ semantic?
+ annotation_list?
+ ('=' initializer)?
+ var_packoffset?
+ var_register_bind?
+ SEMI
+ ;
+
+var_storage_class
+ : 'extern'
+ | 'nointerpolation'
+ | 'shared'
+ | 'static'
+ | 'uniform'
+ | 'volatile'
+ ;
+
+var_type_modifier
+ : ('const'|'row_major'|'column_major');
+
+var_datatype
+ : buffer_type_specifier
+ | scalar_type_or_string_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ ;
+
+var_packoffset
+ : 'packoffset' LPAREN register_name (DOT vector_subcomponent)? RPAREN
+ ;
+
+var_register_bind
+ : COLON register_name
+ ;
+
+id_declaration
+ : ID ( LBRACKET constant_expression RBRACKET )?
+ ;
+
+// function --------------------------------------------
+
+function_declaration
+ : function_storage_class?
+ function_type_specifier ID LPAREN argument_list RPAREN semantic?
+ function_body (SEMI)?
+ ;
+
+function_storage_class
+ : 'inline' // ignoring platform target
+ ;
+
+function_type_specifier
+ : scalar_type_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ | 'void'
+ ;
+
+semantic
+ : COLON semantic_specifier ;
+
+param_type_specifier
+ : scalar_type_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ | string_type_specifier
+ ;
+
+// typedef ---------------------------------------
+
+typedef_definition
+ : 'typedef'
+ ;
+
+// basic datatypes -------------------------------
+
+buffer_type_specifier
+ : ('buffer' '<' var_datatype '>' ID)
+ ;
+
+scalar_type_specifier
+ : 'bool'
+ | 'int'
+ | 'uint'
+ | 'half'
+ | 'float'
+ | 'double'
+ ;
+
+scalar_type_or_string_specifier
+ : scalar_type_specifier
+ | string_type_specifier
+ ;
+
+vector_type_specifier
+ : 'bool1'
+ | 'bool2'
+ | 'bool3'
+ | 'bool4'
+ | 'int1'
+ | 'int2'
+ | 'int3'
+ | 'int4'
+ | 'uint1'
+ | 'uint2'
+ | 'uint3'
+ | 'uint4'
+ | 'half1'
+ | 'half2'
+ | 'half3'
+ | 'half4'
+ | 'float1'
+ | 'float2'
+ | 'float3'
+ | 'float4'
+ | 'double1'
+ | 'double2'
+ | 'double3'
+ | 'double4'
+ | 'vector' '<' scalar_type_specifier ',' ('1'|'2'|'3'|'4') '>'
+ ;
+
+matrix_type_specifier
+ : 'float1x1'
+ | 'float1x2'
+ | 'float1x3'
+ | 'float1x4'
+ | 'float2x1'
+ | 'float2x2'
+ | 'float2x3'
+ | 'float2x4'
+ | 'float3x1'
+ | 'float3x2'
+ | 'float3x3'
+ | 'float3x4'
+ | 'float4x1'
+ | 'float4x2'
+ | 'float4x3'
+ | 'float4x4'
+ | 'matrix' '<' scalar_type_specifier ',' ('1'|'2'|'3'|'4') ',' ('1'|'2'|'3'|'4') '>'
+ ;
+
+string_type_specifier
+ : 'string'
+ ;
+
+// Sampler declarations ----------------------------
+
+sampler_declaration
+ : SAMPLER ID '=' sampler_type_specifier '{' sampler_state_declaration+ '}' SEMI
+ | SAMPLER ID SEMI // GLSL format
+ | sampler_type_specifier id_declaration '=' '{' sampler_state_declaration_simple ']' SEMI // DX10 style
+ ;
+
+sampler_state_declaration
+ : ( ('Texture'|'texture') '=' '<' ID '>' SEMI ) // DX9 must have one of these
+ | sampler_state_declaration_simple
+ ;
+
+sampler_state_declaration_simple
+ : ( sampler_state_specifier '=' initializer SEMI ) // DX10 style
+ ;
+
+sampler_type_specifier
+ : 'sampler' | 'Sampler'
+ | 'sampler1D' | 'Sampler1D' | 'sampler1d'
+ | 'sampler2D' | 'Sampler2D' | 'sampler2d'
+ | 'sampler3D' | 'Sampler3D' | 'sampler3d'
+ | 'samplerCUBE' | 'SamplerCUBE' | 'samplercube'
+ | 'sampler_state' | 'samplerstate' | 'SamplerState'
+ | 'SamplerComparisonState' | 'samplercomparisonstate' // DX10 only
+ ;
+
+sampler_state_specifier
+ : 'AddressU' | 'addressu'
+ | 'AddressV' | 'addressv'
+ | 'AddressW' | 'addressw'
+ | 'BorderColor' | 'bordercolor'
+ | 'ComparisonFilter' | 'comparisonfilter' // SamplerComparisonState only
+ | 'ComparisonFunc' | 'comparisonfunc' // SamplerComparisonState only
+ | 'MagFilter' | 'magfilter'
+ | 'MaxAnisotropy' | 'maxanisotropy'
+ | 'MinFilter' | 'minfilter'
+ | 'MipFilter' | 'mipfilter'
+ | 'MipMapLODBias' | 'MipMapLodBias' | 'mipmapLODbias' | 'mipmaplodbias'
+ ;
+
+ // texture declaration ----------------------------
+
+texture_declaration
+ : texture_type_specifier ID annotation_list? SEMI
+ | texture_type_specifier '<'
+ (scalar_type_specifier | vector_type_specifier ) '>' ID SEMI // GLSL syntax.
+ ;
+
+texture_type_specifier
+ : 'texture'
+ | 'texture1D' | 'Texture1D'
+ | 'texture2D' | 'Texture2D'
+ | 'texture3D' | 'Texture3D'
+ | 'textureCUBE' | 'TextureCUBE'
+ ;
+
+ // struct declaration -----------------------------
+
+struct_type_specifier
+ : ID
+ | ( STRUCT ( ID )? LCURLY ) => struct_definition
+ | STRUCT ID
+ ;
+
+annotation_list
+ : '<' (annotation)* '>';
+
+annotation
+ : scalar_type_or_string_specifier ID '=' constant_expression SEMI ;
+
+initializer
+ : constant_expression
+ | '{' constant_expression ( ',' constant_expression )* '}'
+ ;
+
+register_name
+ // registers for VS_3_0
+ : 'register' '(' input_register_name | output_register_name ')';
+
+input_register_name
+ : (('v'|'r'|'c'|'b'|'i'|'s'|'o') DECIMAL_LITERAL)
+ | ('a0'|'aL'|'p0')
+ ;
+
+output_register_name
+ : 'oD0'|'oD1'|'oFog'|'oPos'|'oPts'
+ | 'oT0'|'oT1'|'oT2'|'oT3'|'oT4'|'oT5'|'oT6'|'oT7'
+ ;
+
+pack_offset
+ : .+ ; // no idea what this field looks like.
+
+argument_list
+ : ( param_declaration ( COMMA param_declaration )* )?
+ ;
+
+param_declaration
+ : param_direction? param_variability? param_type_specifier id_declaration semantic?
+ | SAMPLER ID
+// | FUNCTION type_specifier ID
+ ;
+
+param_variability
+ : CONST
+ | UNIFORM
+ ;
+
+param_direction
+ : IN
+ | OUT
+ | INOUT
+ ;
+
+function_body
+ : LCURLY ( decl_or_statement )* RCURLY
+ ;
+
+decl_or_statement
+ // We copied the following sub-rule here to expedite the parsing time
+ // as this is a much more common case than the "Id init_declarator_list"
+ // case which would normally spend a lot of time in exception handling.
+ : (lvalue_expression assignment_operator ) => assignment_statement
+ | ( ( CONST )? vector_type_specifier ) => ( CONST )? vector_type_specifier init_declarator_list SEMI
+ | ( ( CONST )? scalar_type_specifier ) => ( CONST )? scalar_type_specifier init_declarator_list SEMI
+ | ( STRUCT ( ID )? LCURLY ) => struct_definition ( init_declarator_list )? SEMI
+ | STRUCT ID init_declarator_list SEMI
+ | ( ID init_declarator_list ) => ID init_declarator_list SEMI
+ | statement
+ ;
+
+init_declarator_list
+ : init_declarator ( COMMA init_declarator )* ;
+
+init_declarator
+ : declarator ( ASSIGN initializer )? ;
+
+declarator
+ : ID ( LBRACKET ( constant_expression )? RBRACKET )*;
+
+struct_definition
+ : STRUCT ( ID )? LCURLY struct_declaration_list RCURLY ID? SEMI;
+
+struct_declaration_list
+ // We currently don't support nested structs so the field type
+ // can only be either a scalar or a vector.
+ : ( struct_interpolation_modifier?
+ (scalar_type_specifier|vector_type_specifier) ID
+ (COLON semantic_specifier)? SEMI )+
+ ;
+
+struct_interpolation_modifier // DX10 only
+ : 'linear'
+ | 'centroid'
+ | 'nointerpolation'
+ | 'noperspective'
+ ;
+
+semantic_specifier
+ : ID ;
+
+statement
+ : ( lvalue_expression assignment_operator ) => assignment_statement
+ | ( lvalue_expression self_modify_operator ) => post_modify_statement
+ | pre_modify_statement
+ | expression_statement
+ | compound_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ | SEMI
+ ;
+
+assignment_statement
+ : lvalue_expression assignment_operator expression SEMI ;
+
+pre_modify_statement
+ : pre_modify_expression SEMI ;
+
+pre_modify_expression
+ : self_modify_operator lvalue_expression ;
+
+post_modify_statement
+ : post_modify_expression SEMI ;
+
+post_modify_expression
+ : lvalue_expression self_modify_operator ;
+
+self_modify_operator
+ : PLUSPLUS | MINUSMINUS ;
+
+expression_statement
+ : expression SEMI ;
+
+compound_statement
+ : LCURLY (
+ ( ID init_declarator_list) => ID init_declarator_list SEMI
+ | ( ( CONST )? vector_type_specifier ) => ( CONST )? vector_type_specifier init_declarator_list SEMI
+ | ( ( CONST )? scalar_type_specifier ) => ( CONST )? scalar_type_specifier init_declarator_list SEMI
+ | ( STRUCT ( ID )? LCURLY ) => struct_definition ( init_declarator_list )? SEMI
+ | STRUCT ID init_declarator_list SEMI
+ | statement
+ )*
+ RCURLY
+ ;
+
+selection_statement
+ : IF LPAREN expression RPAREN statement ( ELSE statement )?
+ ;
+
+iteration_statement
+ : WHILE LPAREN expression RPAREN statement
+ | FOR LPAREN assignment_statement
+ equality_expression SEMI modify_expression RPAREN statement
+ | DO statement WHILE LPAREN expression RPAREN SEMI
+ ;
+
+modify_expression
+ : (lvalue_expression assignment_operator ) =>
+ lvalue_expression assignment_operator expression
+ | pre_modify_expression
+ | post_modify_expression
+ ;
+
+jump_statement
+ : BREAK SEMI
+ | CONTINUE
+ | RETURN ( expression )? SEMI
+ | DISCARD
+ ;
+
+expression
+ : conditional_expression ;
+
+assignment_operator
+ : ASSIGN
+ | MUL_ASSIGN
+ | DIV_ASSIGN
+ | ADD_ASSIGN
+ | SUB_ASSIGN
+ | BITWISE_AND_ASSIGN
+ | BITWISE_OR_ASSIGN
+ | BITWISE_XOR_ASSIGN
+ | BITWISE_SHIFTL_ASSIGN
+ | BITWISE_SHIFTR_ASSIGN
+ ;
+
+constant_expression
+ : (ID) => variable_expression
+ | literal_value ;
+
+conditional_expression
+ : logical_or_expression ( QUESTION expression COLON conditional_expression )?
+ ;
+
+logical_or_expression
+ : exclusive_or_expression ( OR exclusive_or_expression )*
+ ;
+
+// We remove the NOT operator from the unary expression and stick it here
+// so that it has a lower precedence than relational operations.
+logical_and_expression
+ : ( NOT )? inclusive_or_expression ( AND ( NOT )? inclusive_or_expression )*
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression (BITWISE_OR exclusive_or_expression )*
+ ;
+
+exclusive_or_expression
+ : and_expression ( BITWISE_XOR and_expression )*
+ ;
+
+and_expression
+ : equality_expression ( BITWISE_AND equality_expression )*
+ ;
+
+equality_expression
+ : relational_expression ( (EQUAL|NOT_EQUAL) relational_expression )*
+ ;
+
+relational_expression
+ : shift_expression ( (LT|GT|LTE|GTE) shift_expression )*
+ ;
+
+shift_expression
+ : additive_expression ( (BITWISE_SHIFTL|BITWISE_SHIFTR) additive_expression )*
+ ;
+
+additive_expression
+ : multiplicative_expression ( (PLUS|MINUS) multiplicative_expression )*
+ ;
+
+multiplicative_expression
+ : cast_expression ( (MUL|DIV|MOD) cast_expression )*
+ ;
+
+cast_expression
+ : LBRACKET param_type_specifier RBRACKET cast_expression
+ | unary_expression
+ ;
+
+unary_expression
+ : (PLUS|MINUS) unary_expression
+ | postfix_expression
+ ;
+
+postfix_expression
+ : primary_expression ( postfix_suffix )? ;
+
+lvalue_expression
+ : variable_expression ( postfix_suffix )? ;
+
+postfix_suffix
+ // choosing between struct field access or vector swizzling is a semantic choice.
+ : ( DOT swizzle )
+ | ( DOT primary_expression )+ ;
+
+primary_expression
+// : constructor
+ : intrinsic_name LPAREN argument_expression_list RPAREN
+ | variable_or_call_expression
+ | literal_value
+ | LPAREN expression RPAREN
+ ;
+
+variable_expression
+ : ID ( LBRACKET expression RBRACKET )? ;
+
+// Combine variable expression and call expression here to get rid of the
+// syntactic predicate we used to use in the primary_expression rule. Using
+// predicates results in the parser spending a lot of time in exception
+// handling (when lookahead fails).
+variable_or_call_expression
+ : ID
+ (
+ ( ( LBRACKET expression RBRACKET )? )
+ |
+ ( LPAREN argument_expression_list RPAREN )
+ )
+ ;
+
+constructor
+ : vector_type_specifier LPAREN expression ( COMMA expression )* RPAREN ;
+
+argument_expression_list
+ : ( expression ( COMMA expression )* )? ;
+
+intrinsic_name
+ : ABS
+ | ACOS
+ | ALL
+ | ANY
+ | ASFLOAT
+ | ASIN
+ | ASINT
+ | ASUINT
+ | ATAN
+ | ATAN2
+ | CEIL
+ | CLAMP
+ | CLIP
+ | COS
+ | COSH
+ | CROSS
+ | DDX
+ | DDY
+ | DEGREES
+ | DETERMINANT
+ | DISTANCE
+ | DOT
+ | EXP
+ | EXP2
+ | FACEFORWARD
+ | FLOOR
+ | FMOD
+ | FRAC
+ | FREXP
+ | FWIDTH
+ | ISFINITE
+ | ISINF
+ | ISNAN
+ | LDEXP
+ | LENGTH
+ | LERP
+ | LIT
+ | LOG
+ | LOG10
+ | LOG2
+ | MAX
+ | MIN
+ | MODF
+ | MUL
+ | NOISE
+ | NORMALIZE
+ | POW
+ | RADIANS
+ | REFLECT
+ | REFRACT
+ | ROUND
+ | RSQRT
+ | SATURATE
+ | SIGN
+ | SIN
+ | SINCOS
+ | SINH
+ | SMOOTHSTEP
+ | SQRT
+ | STEP
+ | TAN
+ | TANH
+ | TEX1D
+ | TEX1DBIAS
+ | TEX1DGRAD
+ | TEX1DLOD
+ | TEX1DPROJ
+ | TEX2D
+ | TEX2DBIAS
+ | TEX2DGRAD
+ | TEX2DLOD
+ | TEX2DPROJ
+ | TEX3D
+ | TEX3DBIAS
+ | TEX3DGRAD
+ | TEX3DLOD
+ | TEX3DPROJ
+ | TEXCUBE
+ | TEXCUBEBIAS
+ | TEXCUBEGRAD
+ | TEXCUBELOD
+ | TEXCUBEPROJ
+ | TRANSPOSE
+ | TRUNC
+ ;
+
+int_literal
+ : DECIMAL_LITERAL
+ | OCT_LITERAL
+ | HEX_LITERAL
+ ;
+literal_value
+ : ('"') => string_literal
+ | int_literal
+ | float_literal
+ ;
+
+
+float_literal
+ : FLOAT_LITERAL
+ ;
+
+string_literal
+ : '"' STRING_LITERAL '"'
+ ;
+
+vector_subcomponent
+ : DOT ('x'|'y'|'z'|'w'|'r'|'g'|'b'|'a')
+ ;
+
+swizzle
+ : ( s += ('x'|'y'|'z'|'w') )+ { $s.size() <= 4 }?
+ | ( s += ('r'|'g'|'b'|'a') )+ { $s.size() <= 4 }?
+ ;
+
+// effects ---------------------------------------
+
+technique
+ : 'technique' ID? '{' (pass)+ '}' SEMI?
+ ;
+
+pass
+ : 'pass' (ID)? '{' (state_assignment)* '}' SEMI?
+ ;
+
+state_assignment
+ : a=ID '=' state_assignment_value SEMI
+ { System.out.println("Found stateassignment: " + $a.text); }
+ ;
+
+state_assignment_value
+ : 'compile' p=ID q=variable_or_call_expression
+ { System.out.println("Found compile: " + $p.text + " " + $q.text); }
+ | a=expression
+ { System.out.println("Found stateassignmentvalue: " + $a.text); }
+ | ('true' | 'false')
+ ;
+
+// -----------------------------------------------------------------------------
+
+NOT : '!' ;
+NOT_EQUAL : '!=' ;
+AND : '&&' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+MUL : '*' ;
+MUL_ASSIGN : '*=' ;
+PLUS : '+' ;
+PLUSPLUS : '++' ;
+ADD_ASSIGN : '+=' ;
+COMMA : ',' ;
+MINUS : '-' ;
+MINUSMINUS : '--' ;
+SUB_ASSIGN : '-=' ;
+DIV : '/' ;
+DIV_ASSIGN : '/=' ;
+MOD : '%';
+MOD_ASSIGN : '%=';
+COLON : ':' ;
+SEMI : ';' ;
+LT : '<' ;
+LTE : '<=' ;
+ASSIGN : '=' ;
+EQUAL : '==' ;
+GT : '>' ;
+GTE : '>=' ;
+QUESTION : '?' ;
+LBRACKET : '[' ;
+RBRACKET : ']' ;
+LCURLY : '{' ;
+OR : '||' ;
+RCURLY : '}' ;
+DOT : '.' ;
+BITWISE_NOT : '~';
+BITWISE_SHIFTL : '<<';
+BITWISE_SHIFTR : '>>';
+BITWISE_AND : '&';
+BITWISE_OR : '|';
+BITWISE_XOR : '^';
+BITWISE_SHIFTL_ASSIGN : '<<=';
+BITWISE_SHIFTR_ASSIGN : '>>=';
+BITWISE_AND_ASSIGN : '&=';
+BITWISE_OR_ASSIGN : '|=';
+BITWISE_XOR_ASSIGN : '^=';
+
+// keywords ----------------------------
+
+BREAK : 'break';
+BUFFER : 'buffer';
+CBUFFER : 'cbuffer';
+CONST : 'const';
+CONTINUE : 'continue';
+DISCARD : 'discard';
+DO : 'do';
+ELSE : 'else';
+EXTERN : 'extern';
+FALSE : 'false';
+FOR : 'for';
+IF : 'if';
+IN : 'in';
+INLINE : 'inline';
+INOUT : 'inout';
+MATRIX : 'matrix';
+NAMESPACE : 'namespace';
+NOINTERPOLATION : 'nointerpolation';
+OUT : 'out';
+RETURN : 'return';
+REGISTER : 'register';
+SHARED : 'shared';
+STATEBLOCK : 'stateblock';
+STATEBLOCK_STATE : 'stateblock_state';
+STATIC : 'static';
+STRING : 'string';
+STRUCT : 'struct';
+SWITCH : 'switch';
+TBUFFER : 'tbuffer';
+TEXTURE : 'texture';
+TEXTURE1D : 'texture1d';
+TEXTURE1DARRAY : 'texture1darray';
+TEXTURE2D : 'texture2d';
+TEXTURE2DARRAY : 'texture2darray';
+TEXTURE2DMS : 'texture2dms';
+TEXTURE2DMSARRAY : 'texture2dmsarray';
+TEXTURE3D : 'texture3d';
+TEXTURECUBE : 'texturecube';
+TEXTURECUBEARRAY : 'texturecubearray';
+TRUE : 'true';
+TYPEDEF : 'typedef';
+UNIFORM : 'uniform';
+VOID : 'void';
+VOLATILE : 'volatile';
+WHILE : 'while';
+
+// fx keywords ---------------------
+
+BLENDSTATE : 'blendstate';
+COMPILE : 'compile';
+DEPTHSTENCILSTATE : 'depthstencilstate';
+DEPTHSTENCILVIEW : 'depthstencilview';
+GEOMETRYSHADER : 'geometryshader';
+PASS : 'pass';
+PIXELSHADER : 'pixelshader';
+RASTERIZERSTATE : 'rasterizerstate';
+RENDERTARGETVIEW : 'rendertargetview';
+TECHNIQUE : 'technique';
+TECHNIQUE10 : 'technique10';
+VERTEXSHADER : 'vertexshader';
+
+
+// intrinsic functions --------------------
+ABS : 'abs';
+ACOS : 'acos';
+ALL : 'all';
+ANY : 'any';
+ASFLOAT : 'asfloat';
+ASIN : 'asin';
+ASINT : 'asint';
+ASUINT : 'asuint';
+ATAN : 'atan';
+ATAN2 : 'atan2';
+CEIL : 'ceil';
+CLAMP : 'clamp';
+CLIP : 'clip';
+COS : 'cos';
+COSH : 'cosh';
+CROSS : 'cross';
+DDX : 'ddx';
+DDY : 'ddy';
+DEGREES : 'degrees';
+DETERMINANT : 'determinant';
+DISTANCE : 'distance';
+DOT_PRODUCT : 'dot';
+EXP : 'exp';
+EXP2 : 'exp2';
+FACEFORWARD : 'faceforward';
+FLOOR : 'floor';
+FMOD : 'fmod';
+FRAC : 'frac';
+FREXP : 'frexp';
+FWIDTH : 'fwidth';
+ISFINITE : 'isfinite';
+ISINF : 'isinf';
+ISNAN : 'isnan';
+LDEXP : 'ldexp';
+LENGTH : 'length';
+LERP : 'lerp';
+LIT : 'lit';
+LOG : 'log';
+LOG10 : 'log10';
+LOG2 : 'log2';
+MAX : 'max';
+MIN : 'min';
+MODF : 'modf';
+MUL_FUNC : 'mul';
+NOISE : 'noise';
+NORMALIZE : 'normalize';
+POW : 'pow';
+RADIANS : 'radians';
+REFLECT : 'reflect';
+REFRACT : 'refract';
+ROUND : 'round';
+RSQRT : 'rsqrt';
+SATURATE : 'saturate';
+SIGN : 'sign';
+SIN : 'sin';
+SINCOS : 'sincos';
+SINH : 'sinh';
+SMOOTHSTEP : 'smoothstep';
+SQRT : 'sqrt';
+STEP : 'step';
+TAN : 'tan';
+TANH : 'tanh';
+TEX1D : 'tex1D';
+TEX1DBIAS : 'tex1Dbias';
+TEX1DGRAD : 'tex1Dgrad';
+TEX1DLOD : 'tex1Dlod';
+TEX1DPROJ : 'tex1Dproj';
+TEX2D : 'tex2D';
+TEX2DBIAS : 'tex2Dbias';
+TEX2DGRAD : 'tex2Dgrad';
+TEX2DLOD : 'tex2Dlod';
+TEX2DPROJ : 'tex2Dproj';
+TEX3D : 'tex3D';
+TEX3DBIAS : 'tex3Dbias';
+TEX3DGRAD : 'tex3Dgrad';
+TEX3DLOD : 'tex3Dlod';
+TEX3DPROJ : 'tex3Dproj';
+TEXCUBE : 'texCUBE';
+TEXCUBEBIAS : 'texCUBEbias';
+TEXCUBEGRAD : 'texCUBEgrad';
+TEXCUBELOD : 'texCUBElod';
+TEXCUBEPROJ : 'texCUBEproj';
+TRANSPOSE : 'transpose';
+TRUNC : 'trunc';
+
+
+
+// fundamental tokens ---------------------
+
+fragment HEXDIGIT
+ : ('0'..'9'|'a'..'f'|'A'..'F')
+ ;
+
+fragment UNICODE_ESCAPE
+ : '\\' 'u' HEXDIGIT HEXDIGIT HEXDIGIT HEXDIGIT
+ ;
+
+fragment OCTAL_ESCAPE
+ : '\\' ('0'..'3') ('0'..'7') ('0'..'7')
+ | '\\' ('0'..'7') ('0'..'7')
+ | '\\' ('0'..'7')
+ ;
+
+fragment ESCAPE_SEQUENCE
+ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
+ | UNICODE_ESCAPE
+ | OCTAL_ESCAPE
+ ;
+
+fragment EXPONENT : ('e'|'E') (PLUS | MINUS)? ('0'..'9')+ ;
+
+fragment FLOATSUFFIX : ('f'|'F'|'h'|'H') ;
+
+ID
+ : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
+ {
+ // check the length of the identifier before accepting it.
+ if (($ID.length() > 96)) {
+ RecognitionException();
+ }
+ }
+ ;
+
+DECIMAL_LITERAL
+ : ('1'..'9')('0'..'9')+
+ ;
+
+OCT_LITERAL
+ : ('0'..'3') ('0'..'7') ('0'..'7')
+ | ('0'..'7') ('0'..'7')
+ | ('0'..'7')
+ ;
+
+HEX_LITERAL
+ : '0x' HEXDIGIT+
+ ;
+
+CHARACTER_LITERAL
+ : '\'' ( ESCAPE_SEQUENCE | ~('\''|'\\') ) '\''
+ ;
+
+STRING_LITERAL
+ : ( ESCAPE_SEQUENCE | ~('\\'|'"') )*
+ ;
+
+FLOAT_LITERAL
+ : (PLUS | MINUS)? ('0'..'9')+ '.' ('0'..'9')* (EXPONENT)? (FLOATSUFFIX)?
+ | (PLUS | MINUS)? '.' ('0'..'9')+ (EXPONENT)? (FLOATSUFFIX)?
+ | (PLUS | MINUS)? ('0'..'9')+ (EXPONENT)? (FLOATSUFFIX)?
+ ;
+
+// skipped elements -----------------
+
+WHITESPACE
+ : ( ' ' | '\t' | '\f' | '\r' )
+ { $channel = HIDDEN; }
+ ;
+
+COMMENT
+ : '//' (~('\n'|'\r'))*
+ { $channel = HIDDEN; }
+ ;
+
+MULTILINE_COMMENT
+ : '/*' ( options {greedy=false;} : . )* '*/'
+ { $channel = HIDDEN; }
+ ;
+
+//RESERVED_WORDS
+// : 'auto'
+// | 'case'
+// | 'catch'
+// | 'char'
+// | 'class'
+// | 'const_cast'
+// | 'default'
+// | 'delete'
+// | 'dynamic_cast'
+// | 'enum'
+// | 'explicit'
+// | 'friend'
+// | 'goto'
+// | 'long'
+// | 'mutable'
+// | 'new'
+// | 'operator'
+// | 'private'
+// | 'protected'
+// | 'public'
+// | 'reinterpret_cast'
+// | 'short'
+// | 'signed'
+// | 'sizeof'
+// | 'snorm'
+// | 'static_cast'
+// | 'template'
+// | 'this'
+// | 'throw'
+// | 'try'
+// | 'typename'
+// | 'union'
+// | 'unorm'
+// | 'unsigned'
+// | 'using'
+// | 'varying'
+// | 'virtual'
+// { $channel = HIDDEN; }
+// ;
diff --git a/o3d/compiler/puritan/build.scons b/o3d/compiler/puritan/build.scons
new file mode 100644
index 0000000..7c59d0d
--- /dev/null
+++ b/o3d/compiler/puritan/build.scons
@@ -0,0 +1,57 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# Import the build environment that was decided in the project SConstruct.
+# This may be the Debug or Optimized environment
+Import('env')
+
+# Create a list of the files used to build the target library.
+inputs = [
+'exp_gen.cc',
+'knobs.cc',
+'puritan.cc',
+'puritan_assert.cc',
+'rand.cc',
+'structure_gen.cc',
+'test_gen.cc',
+'main.cc',
+]
+
+libraries = []
+
+# On Windows link with ADVAPI32 to get better RNG.
+if env.Bit('windows'):
+ libraries += ['advapi32.lib']
+
+# Create the puritan tool for generating random HLSL shaders
+puritan = env.Program('puritan', inputs, LIBS=libraries)
+puritan_install = env.Replicate('$ARTIFACTS_DIR', puritan)
+
+env.Alias('puritan', puritan_install)
diff --git a/o3d/compiler/puritan/exp_gen.cc b/o3d/compiler/puritan/exp_gen.cc
new file mode 100644
index 0000000..29c126b
--- /dev/null
+++ b/o3d/compiler/puritan/exp_gen.cc
@@ -0,0 +1,934 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <iostream>
+#include "puritan_assert.h"
+#include "exp_gen.h"
+#include "structure_gen.h"
+#include "knobs.h"
+
+namespace Salem
+{
+namespace Puritan
+{
+
+
+const char *f2tof_swizzle_names[] =
+{
+ "x", "y", 0
+};
+
+StrCoverage f2tof_swizzles ("F2tof Swizzles",
+ f2tof_swizzle_names);
+
+const char *f2tof2_swizzle_names[] =
+{
+ "xx", "yy", "xy", "yx", 0
+};
+
+StrCoverage f2tof2_swizzles ("F2tof2 Swizzles",
+ f2tof2_swizzle_names);
+
+const char *f4tof_swizzle_names[] =
+{
+ "x", "y", "z", "w", 0
+};
+
+StrCoverage f4tof_swizzles ("F4tof Swizzles",
+ f4tof_swizzle_names);
+
+const char *f4tof2_swizzle_names[] =
+{
+ "xx", "xy", "xw", "xz",
+ "yy", "yx", "yw", "yz",
+ "wx", "wy", "ww", "wz",
+ "zx", "zy", "zw", "zz",
+ 0
+};
+
+StrCoverage f4tof2_swizzles ("F4tof2 Swizzles",
+ f4tof2_swizzle_names);
+
+const char *f4tof4_swizzle_names[] =
+{
+ "x", "y", "z", "w", 0
+};
+
+StrCoverage f4tof4_swizzles ("f4tof4 Swizzles",
+ f4tof4_swizzle_names);
+
+//////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////
+// This code generates controlled random expressions for Puritan.
+
+// During generation, various knobs and random numbers determine the complexity
+// of the expression and push various operands into a list. Then the code
+// builds an expression tree removing things from the list until there's
+// nothing left.
+//
+
+//////////////////////////////////////////////////////////////////////
+
+// "frac" removed because it can cause discrepant CPU vs GPU results
+// - see ticket #3493
+const char *unfunc_names[] =
+{ "abs", /* "frac", */ "exp2", "log2",
+ "rcp", "rsqrt", "sqrt", "!", 0
+};
+
+StrCoverage unfuncs ("Unary functions", unfunc_names);
+
+const char *binfunc_names[] =
+{ "max", "min", "dot", 0 };
+
+StrCoverage binfuncs ("Binary functions", binfunc_names);
+
+const char *trifunc_names[] =
+{ "mad", "opcond", 0};
+
+StrCoverage trifuncs ("Trinary functions", trifunc_names);
+
+const char *unop_names[] =
+{ "-", 0 };
+
+StrCoverage unops ("Unops", unop_names);
+
+const char *binop_names[] =
+{ "*", "/", "+", "-", 0 };
+
+StrCoverage binops ("Binops", binop_names);
+
+// "eq", "ne" removed because these are very sensitive to precision errors
+// and could cause discrepant CPU vs GPU results
+const char *relop_names[] =
+{
+ "lt", "le", "gt", "ge",
+ /* "eq", "ne", */ "and", "or",
+ 0
+};
+
+StrCoverage relops ("Relops", relop_names);
+
+const char *special_names[] =
+{
+ "* 2.0", "* 4.0", "* 8.0",
+ "/ 2.0", "/ 4.0", "/ 8.0",
+ "1.0 -", "1.0-2.0*", 0
+};
+
+StrCoverage special ("Special", special_names);
+
+std::ostream & operator << (std::ostream & out,
+ const ENode & x)
+{
+ x->print (out);
+ return out;
+}
+
+void print_e (const ENode &x)
+{
+ std::cerr << x;
+}
+
+std::ostream & operator << (std::ostream & out,
+ const EList & x)
+{
+ bool need_comma = false;
+
+ for (EList::const_iterator i = x.begin (); i != x.end ();
+ i++)
+ {
+ if (need_comma)
+ {
+ out << ", ";
+ }
+ out << *i;
+ need_comma = true;
+ }
+ return out;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Generate expressions..
+
+// Remove one operand from the stack of expressions and convert it to the
+// prevailing type.
+
+ENode one_arg (exp_list * exp, Rand * rand, const Type & type, Gen *gen)
+{
+ PURITAN_ASSERT (!exp->empty (), "Ran out of expressions");
+ ENode arg = exp->back ();
+
+ exp->pop_back ();
+
+ return ENode (Exp::convert (arg, rand, type, gen));
+}
+
+// Create an expression tree returning with type RETURN_TYPE.
+ENode create_expression (Gen * gen, Type return_type, const Context & ctx)
+{
+ Rand *rand = &gen->rand;
+ static int depth;
+ Type type = return_type;
+ const Knobs & knobs = gen->knobs;
+ exp_list exp;
+
+ depth++;
+
+ // We create some things regardless of the complexity settings.
+ if (return_type == Float4 && knobs.float4_chance (rand))
+ {
+ // Make more args - call create_expression out of the arg list
+ // because otherwise the expression eval order will be undefined.
+ ENode a0 = (create_expression (gen, Float, ctx.deeper ()));
+ ENode a1 = (create_expression (gen, Float, ctx.deeper ()));
+ ENode a2 = (create_expression (gen, Float, ctx.deeper ()));
+ ENode a3 = (create_expression (gen, Float, ctx.deeper ()));
+
+ exp.push_back (ENode (new Float4Func (Float4, a0, a1, a2, a3)));
+ }
+
+ if (return_type == Float2 && knobs.float2_chance (rand))
+ {
+ ENode a0 = (create_expression (gen, Float, ctx.deeper ()));
+ ENode a1 = (create_expression (gen, Float, ctx.deeper ()));
+
+ exp.push_back (ENode (new BiIntrinsicFunc (Float2, "float2", a0, a1)));
+ }
+
+ if (ctx.callees && !ctx.callees->empty ())
+ {
+ FunctionSPtr target = ctx.callees->front ();
+ EList actuals;
+
+ ctx.callees->pop_front ();
+
+ for (DeclList::iterator ai = target->formals.begin ();
+ ai != target->formals.end ();
+ ai++)
+ {
+ switch (ai->scope.scope)
+ {
+ // input argument can be any expression
+ case Argument_IO:
+ case Argument_I:
+ {
+ ENode actual = create_expression (gen, ai->type, ctx.deeper ());
+ actuals.push_back (actual);
+ break;
+ }
+ case Argument_O:
+ {
+ ENode actual (new Variable
+ (gen->fetch_decl (ai->type,
+ ctx.deeper (),
+ Uninitialized,
+ Read)));
+
+ actuals.push_back (actual);
+ break;
+ }
+
+ default:
+ case Uniform:
+ case Static:
+ case StaticConstArrays:
+ case Sampler:
+ case NoScope:
+ {
+ PURITAN_ABORT ("Bad scope" << ai->scope.scope);
+ break;
+ }
+ }
+ }
+
+ exp.push_back
+ (ENode (new FCallTemplate (target->ret_type, target, actuals)));
+ }
+
+ if (ctx.samplers && !ctx.samplers->empty ())
+ {
+ // Have to get the arguments in range
+ // tex2D (id<n>, <exp> % id<n>_size)
+ unsigned sampler = ctx.samplers->front ();
+
+ ctx.samplers->pop_front ();
+ ENode lhs = create_expression (gen, Float4, ctx.deeper ());
+ ENode rhs (new SamplerSizeRef (sampler));
+ ENode mod (new BiIntrinsicFunc (Float4, "quick_mod", lhs, rhs));
+
+ exp.push_back (ENode (new SamplerRef (sampler, mod)));
+ }
+
+ // Build as many terms as we were asked for.
+ int l = gen->knobs.expression_depth (rand);
+
+ // Children functions get fewer nodes.
+ if (ctx.func)
+ {
+ l = l * 4 / 6 + 1;
+ }
+
+ for (int i = 0; i < l; i++)
+ {
+ if (knobs.type_change_chance (rand))
+ {
+ type = gen->random_type ();
+ }
+
+ if (knobs.array_use (rand))
+ {
+ Type t = knobs.array_constness (rand)
+ ? Float4ConstArray : Float4Array;
+
+ Decl decl = gen->gen_array_decl (t, ctx.deeper (), Read);
+ ENode v (new Variable (decl));
+ ENode idx;
+
+ if (knobs.array_index_const (rand) || ctx.loop.get() == NULL)
+ {
+ idx = ENode (new Constant (Float,
+ rand->range (0, array_size)));
+ }
+ else
+ {
+ idx = ENode (new Variable (ctx.loop->counter));
+ }
+
+ ENode id (new Index (v, idx));
+ exp.push_back (id);
+ }
+ else
+ {
+ if (knobs.uniform_chance (rand) && gen->n_uniforms)
+ {
+ size_t uni_idx = rand->srange (0, gen->n_uniforms);
+ std::vector <std::pair <Type, string> >::iterator uni
+ = gen->uniforms.begin () + uni_idx;
+ ENode e (new UniformRef (uni->first, uni->second));
+ exp.push_back (e);
+ }
+ else if (ctx.depth > 10 || knobs.constant_use (rand))
+ {
+ ENode e (new Constant (Float, gen->gen_fconstant ()));
+ exp.push_back (e);
+ }
+ else
+ {
+ Type t
+ = knobs.type_change_chance (rand)
+ ? gen->random_type () : type;
+
+ Decl decl = gen->fetch_decl (t,
+ ctx.deeper (),
+ Initialized,
+ Read);
+ ENode v (new Variable (decl));
+
+ exp.push_back (v);
+ }
+ }
+
+ // Stop making nodes if we've gone too far.
+ gen->exp_nodes++;
+ if (gen->exp_nodes >= knobs.exp_limit.uget ())
+ {
+ break;
+ }
+ }
+
+ // Now add enough operators to consume all but one of the terms, the final
+ // term is the result of the expression.
+
+ bool no_more_unarys = false;
+
+ while (exp.size () != 1)
+ {
+ if ((type == Float
+ && knobs.relop_chance (rand))
+ || (ctx.relop_p
+ && exp.size () < 3 && knobs.relop_cond_chance (rand)))
+ {
+ exp.push_back
+ (ENode (new Relop (relops.choose (rand),
+ one_arg (&exp, rand, Float, gen),
+ one_arg (&exp, rand, Float, gen))));
+
+ }
+ else if (knobs.special_chance (rand))
+ {
+ exp.push_back
+ (ENode (new SpecialPhrase (type,
+ special.choose (rand),
+ one_arg (&exp, rand, type, gen))));
+ }
+ else if (knobs.func_chance (rand))
+ {
+ if (exp.size () > 2 && knobs.trifunc_chance (rand))
+ {
+ string name = trifuncs.choose (rand);
+
+
+ // name of opcond function changes by type
+ if (name == "opcond")
+ {
+ switch (type.type)
+ {
+ case Float4:
+ name = "opcond4";
+ break;
+ case Float2:
+ name = "opcond2";
+ break;
+ case Float:
+ name = "opcond";
+ break;
+ case NoType:
+ case Int:
+ case Int4:
+ case SamplerFloat4:
+ case SamplerSize:
+ case Struct:
+ case Float4ConstArray:
+ case Float4Array:
+ default:
+ PURITAN_ABORT ("Illegal type for opcond" << type.type) ;
+ break;
+ }
+ }
+
+ exp.push_back
+ (ENode (new TriIntrinsicFunc (type,
+ name,
+ one_arg (&exp, rand, type, gen),
+ one_arg (&exp, rand, type, gen),
+ one_arg (&exp, rand, type, gen))));
+ }
+ else if (exp.size () > 1 && knobs.binfunc_chance (rand))
+ {
+ string f = binfuncs.choose (rand);
+ Type ret_type = f == "dot" ? Float : type;
+
+ ENode lhs = one_arg (&exp, rand, type, gen);
+ ENode rhs = one_arg (&exp, rand, type, gen);
+ exp.push_back
+ (ENode (new BiIntrinsicFunc (ret_type,
+ f,
+ lhs,
+ rhs)));
+ type = ret_type;
+ }
+ else
+ {
+ exp.push_back
+ (ENode (new UnIntrinsicFunc (type,
+ unfuncs.choose (rand),
+ one_arg (&exp, rand, type, gen))));
+ }
+ }
+ else if (!no_more_unarys && knobs.unary_chance (rand))
+ {
+ exp.push_back (ENode (new Unop (type,
+ unops.choose (rand),
+ one_arg (&exp, rand, type, gen))));
+ }
+ else if (knobs.swizzle_chance (rand))
+ {
+ exp.push_back (Exp::convert (one_arg (&exp, rand, type, gen), rand, type, gen));
+ }
+ else
+ {
+ exp.push_back
+ (ENode (new Binop (type, binops.choose (rand),
+ one_arg (&exp, rand, type, gen),
+ one_arg (&exp, rand, type, gen))));
+ }
+ }
+
+ return Exp::convert (exp.back (), rand, return_type, gen);
+
+}
+//////////////////////////////////////////////////////////////////////
+/// ENode Template, base class for all expression nodes.
+
+Exp::Exp (Type _type) :type (_type)
+{
+}
+
+Exp::~ Exp ()
+{
+}
+
+bool Exp::is_fconstant () const
+{
+ return false;
+}
+
+// Convert a tree from one type to another, return the new tree.
+ENode Exp::convert (ENode from, Rand * rand, Type to, Gen *gen)
+{
+ string pre;
+ string post;
+ unsigned n = 1;
+
+ if (from->type == to.type && !gen->knobs.copy_swizzle_chance (rand))
+ {
+ n = 0;
+ }
+ else if (from->type == Float && to.type == Float)
+ {
+
+ }
+ else if (from->type == Float2 && to.type == Float2)
+ {
+ post = f2tof2_swizzles.choose (rand);
+ }
+ else if (from->type == Float && to.type == Float2)
+ {
+ n = 1;
+ pre = "float2";
+ }
+ else if (from->type == Float && to.type == Float4)
+ {
+ n = 1;
+ pre = "float4";
+ }
+ else if (from->type == Float2 && to.type == Float)
+ {
+ post = f2tof_swizzles.choose (rand);
+ }
+ else if (from->type == Float2 && to.type == Float4)
+ {
+ // Can't spread out a float2
+ pre = "float4";
+ n = 2;
+ }
+ else if (from->type == Float4 && to.type == Float)
+ {
+ post = f4tof_swizzles.choose (rand);
+ }
+ else if (from->type == Float4 && to.type == Float2)
+ {
+ post = f4tof2_swizzles.choose (rand);
+ }
+ else if (from->type == Float4 && to.type == Float4)
+ {
+ for (unsigned i = 0; i < 4; i++)
+ post += f4tof4_swizzles.choose (rand);
+ }
+ else
+ {
+ PURITAN_ABORT ("Bad args in convert");
+ }
+
+ if (from->is_fconstant ())
+ {
+ n = 1;
+ }
+ return ENode (new Convert (to, from->type, pre, post, n, from));
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Boilerplate
+
+A0::A0 (Type ty) :Exp (ty)
+{
+}
+
+A1::A1 (Type ty, ENode _child) :Exp (ty), child (_child)
+{
+}
+
+A2::A2 (Type ty, ENode _lhs, ENode _rhs) :Exp (ty),
+ lhs (_lhs), rhs (_rhs)
+{
+}
+
+A3::A3 (Type ty, ENode _a0, ENode _a1,
+ ENode _a2) :Exp (ty), a0 (_a0), a1 (_a1),
+ a2 (_a2)
+{
+}
+
+A4::A4 (Type ty, ENode _a0, ENode _a1, ENode _a2,
+ ENode _a3) :Exp (ty), a0 (_a0), a1 (_a1),
+ a2 (_a2), a3 (_a3)
+{
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Unary operations
+
+Unop::Unop (Type ty, string _name, ENode _child)
+ :A1 (ty, _child), name (_name)
+{
+}
+
+void Unop::print (ostream & out) const
+{
+ out << " ( " << name << " " << child << ") ";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Function calls.
+
+FCallTemplate::FCallTemplate (TypeList ty,
+ FunctionSPtr _target,
+ EList _actuals)
+ :Exp (ty.front ()), target (_target), actuals (_actuals)
+{
+}
+
+void FCallTemplate::print (ostream & out) const
+{
+ out << "func" << target->idx << " (" << actuals << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Sampler references.
+
+SamplerRef::SamplerRef (unsigned _n, ENode _child)
+ :A1 (Float4, _child), n (_n)
+{
+}
+
+void SamplerRef::print (ostream & out) const
+{
+ out << "tex2D (in" << n << ", " << child << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Sampler references.
+
+SamplerSizeRef::SamplerSizeRef (unsigned _n)
+ :A0 (Float4), n (_n)
+{
+}
+
+void SamplerSizeRef::print (ostream & out) const
+{
+ out << "in" << n << "_size";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Uniform references.
+
+UniformRef::UniformRef (Type ty, string v)
+ :A0 (ty), name (v)
+{
+}
+
+void UniformRef::print (ostream & out) const
+{
+ out << name;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Constants.
+
+Constant::Constant (Type ty, string _val)
+ :A0 (ty), val (_val)
+{
+}
+
+void Constant::print (ostream & out) const
+{
+ out << val;
+}
+
+Constant::Constant (Type ty, unsigned _val)
+ :A0 (ty)
+{
+ ostringstream o;
+
+ o << _val;
+ val = (o.str ());
+}
+bool Constant::is_fconstant () const
+{
+ return true;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Variables.
+
+Variable::Variable (Decl _d)
+ :A0 (_d.type ()), decl (_d)
+{
+}
+
+void Variable::print (ostream & out) const
+{
+ out << " " << decl;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Indexes into arrays.
+
+Index::Index (ENode child, ENode idx)
+ :A2 (Float4, child, idx)
+{
+}
+
+void Index::print (ostream & out) const
+{
+ out << lhs << "[" << rhs << "]";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Constant array references.
+
+ConstArrayRef::ConstArrayRef (Decl _d)
+ :A0 (Float4), decl (_d)
+{
+}
+
+void ConstArrayRef::print (ostream & out) const
+{
+ out << " " << decl;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// lhs swizzles
+
+Swizzle::Swizzle (Type ty, string _name, ENode _child)
+ : A1 (ty, _child), name (_name)
+{
+
+}
+
+void Swizzle::print (ostream & out) const
+{
+ out << child << "." << name;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Variables on the LHS of an assignment.
+
+LHSVariable::LHSVariable (Decl _d, bool _swizzled)
+ :Exp (_d.type ()), decl (_d), swizzled (_swizzled)
+{
+}
+
+void LHSVariable::print (ostream & out) const
+{
+ out << " " << decl;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Special phrases.
+
+SpecialPhrase::SpecialPhrase (Type t, string _name, ENode _child)
+ :A1 (t, _child), name (_name)
+{
+}
+
+void SpecialPhrase::print (ostream & out) const
+{
+ if (name[0] == '1')
+ {
+ out << " " << name << child;
+ }
+ else
+ {
+ out << child << " " + name;
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Unary intrinsic
+
+UnIntrinsicFunc::UnIntrinsicFunc (Type ty, string _name,
+ ENode _child)
+ :A1 (ty, _child),
+ name (_name)
+{
+}
+
+void UnIntrinsicFunc::print (ostream & out) const
+{
+ if (name == "!")
+ {
+ out << "(!(" << child << "))";
+ }
+ else
+ {
+ out << " " << name << " (" << child << ")";
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Binary intrinsic
+
+BiIntrinsicFunc::BiIntrinsicFunc (Type ty, string _name,
+ ENode _lhs, ENode _rhs)
+ :A2 (ty, _lhs, _rhs), name (_name)
+{
+}
+
+void BiIntrinsicFunc::print (ostream & out) const
+{
+ out << " " << name << " (" << lhs << ", " << rhs << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Tri intrinsic
+
+TriIntrinsicFunc::TriIntrinsicFunc (Type ty,
+ string _name,
+ ENode _a1,
+ ENode _a2,
+ ENode _a3)
+ :A3 (ty, _a1, _a2, _a3), name (_name)
+{
+}
+
+void TriIntrinsicFunc::print (ostream & out) const
+{
+ out << name << "(" << a0 << ", " << a1 << ", " << a2 << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Float4
+
+Float4Func::Float4Func (Type ty, ENode _a1, ENode _a2,
+ ENode _a3, ENode _a4)
+ :A4 (ty, _a1, _a2, _a3, _a4)
+{
+}
+
+void Float4Func::print (ostream & out) const
+{
+ out << "float4 (" << a0 << ", " << a1 << ", " << a2 << ", " << a3
+ << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Convert
+
+Convert::Convert (Type to,
+ Type _from,
+ string _pre, string _post, unsigned _n,
+ ENode _child)
+ :A1 (to, _child), from (_from), pre (_pre), post (_post), n (_n)
+{
+}
+
+void Convert::print (ostream & out) const
+{
+ if (n == 0)
+ {
+ out << child;
+ }
+ else
+ {
+ out << pre << " (";
+ for (unsigned i = 0; i < n; i++)
+ {
+ if (i)
+ {
+ out << ", ";
+ }
+ out << child;
+ }
+ out << ")";
+ if (!post.empty ())
+ {
+ out << "." << post;
+ }
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Binop
+
+Binop::Binop (Type ty, string _name, ENode _lhs,
+ ENode _rhs)
+ :A2 (ty, _lhs, _rhs),
+ name (_name)
+{
+}
+
+void Binop::print (ostream & out) const
+{
+ out << lhs << " " << name << " " << rhs;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Relop
+
+Relop::Relop (string _name, ENode _lhs, ENode _rhs)
+ :A2 (Float, _lhs, _rhs),
+ name (_name)
+{
+}
+
+void Relop::print (ostream & out) const
+{
+ out << "op" << name << type.suffix_name() << "(" << lhs << ", " << rhs << ")";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// AssOp
+
+AssOp::AssOp (Type ty, string _name, ENode _lhs, ENode _rhs)
+ :A2 (ty, _lhs, _rhs),
+ name (_name)
+{
+}
+
+void AssOp::print (ostream & out) const
+{
+ out << lhs << " " << name << " " << rhs;
+}
+
+//////////////////////////////////////////////////////////////////////
+/// SelfModOp
+
+SelfModOp::SelfModOp (Type ty, string _name, ENode _child)
+ :A1 (ty, _child),
+ name (_name)
+{
+}
+
+void SelfModOp::print (ostream & out) const
+{
+ out << child << " " << name;
+}
+
+//////////////////////////////////////////////////////////////////////
+///
+
+//////////////////////////////////////////////////////////////////////
+
+}
+}
diff --git a/o3d/compiler/puritan/exp_gen.h b/o3d/compiler/puritan/exp_gen.h
new file mode 100644
index 0000000..9387d98
--- /dev/null
+++ b/o3d/compiler/puritan/exp_gen.h
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef PURITAN_EXPGEN_H
+#define PURITAN_EXPGEN_H
+#include "puritan.h"
+
+// Expression trees.
+namespace Salem
+{
+namespace Puritan
+{
+class Exp;
+class Gen;
+class Type;
+class Context;
+typedef ::shared_ptr<Exp> ENode;
+typedef std::vector <ENode> exp_list;
+// Make a tree.
+ENode create_expression (Gen *gen, Type return_type, const Context &ctx);
+
+// Print it out.
+std::ostream & operator<< (std::ostream &out, const ENode &x);
+
+class Exp
+{
+public:
+ Type type;
+ Exp (Type _type) ;
+ virtual ~Exp();
+
+ virtual void print (ostream &out) const = 0;
+ virtual bool is_fconstant() const;
+
+ static ENode convert (ENode from, Rand *rand, Type to, Gen *gen);
+};
+
+class A0 : public Exp
+{
+public:
+ A0 (Type ty);
+};
+
+class A1 : public Exp
+{
+public:
+ ENode child;
+ A1 (Type ty, ENode child);
+};
+
+class A2 : public Exp
+{
+public:
+ ENode lhs;
+ ENode rhs;
+ A2(Type ty,
+ ENode lhs,
+ ENode rhs);
+};
+
+class A3 : public Exp
+{
+public:
+ ENode a0;
+ ENode a1;
+ ENode a2;
+
+ A3(Type ty,
+ ENode a0,
+ ENode a1,
+ ENode a2);
+};
+
+class A4 : public Exp
+{
+public:
+ ENode a0;
+ ENode a1;
+ ENode a2;
+ ENode a3;
+
+ A4(Type ty,
+ ENode a0,
+ ENode a1,
+ ENode a2,
+ ENode a3);
+};
+
+class Unop : public A1
+{
+ string name;
+
+public:
+ Unop(Type ty, string _name, ENode child) ;
+ void print (ostream &out) const;
+};
+
+class FCallTemplate : public Exp
+{
+public:
+ FunctionSPtr target;
+ EList actuals;
+
+ FCallTemplate (TypeList ty, FunctionSPtr f, EList actuals);
+ void print (ostream &out) const;
+};
+
+class SamplerRef : public A1
+{
+ unsigned n;
+
+public:
+ SamplerRef (unsigned _n, ENode _child) ;
+ void print (ostream &out) const;
+};
+
+class SamplerSizeRef : public A0
+{
+ unsigned n;
+
+public:
+ SamplerSizeRef (unsigned _n);
+ void print (ostream &out) const;
+};
+
+class UniformRef : public A0
+{
+ string name;
+
+public:
+ UniformRef (Type ty, string v);
+ void print (ostream &out) const;
+};
+
+class Constant : public A0
+{
+ string val;
+public:
+ Constant (Type ty, string v);
+ Constant (Type ty, unsigned v);
+ bool is_fconstant() const;
+ void print (ostream &out) const;
+};
+
+class Variable : public A0
+{
+ Decl decl;
+
+public:
+ Variable (Decl _d) ;
+ void print (ostream &out) const;
+};
+
+
+class Index : public A2
+{
+public:
+ Index (ENode child, ENode index);
+ void print (ostream &out) const;
+
+};
+
+class ConstArrayRef : public A0
+{
+ Decl decl;
+public:
+ ConstArrayRef (Decl _d);
+ void print (ostream &out) const;
+};
+
+class LHSVariable : public Exp
+{
+ Decl decl;
+ bool swizzled;
+
+public:
+ LHSVariable (Decl _d, bool _swizzled) ;
+
+ void print (ostream &out) const;
+};
+
+class SpecialPhrase : public A1
+{
+ string name;
+
+public:
+ SpecialPhrase (Type , string name, ENode _child);
+
+ void print (ostream &out) const;
+};
+
+class UnIntrinsicFunc : public A1
+{
+ string name;
+
+public:
+ UnIntrinsicFunc(Type ty, string _name, ENode) ;
+
+ void print (ostream &out) const;
+};
+
+class BiIntrinsicFunc : public A2
+{
+ string name;
+
+public:
+ BiIntrinsicFunc(Type ty, string _name, ENode _lhs, ENode _rhs) ;
+
+ void print (ostream &out) const;
+};
+
+class TriIntrinsicFunc : public A3
+{
+ string name;
+public:
+ TriIntrinsicFunc(Type ty, string _name, ENode _a1, ENode _a2, ENode _a3);
+
+ void print (ostream &out) const;
+};
+
+class Float4Func : public A4
+{
+public:
+ Float4Func(Type ty, ENode _a1, ENode _a2, ENode _a3, ENode _a4);
+
+ void print (ostream &out) const;
+};
+
+class Convert : public A1
+{
+ Type from;
+ string pre;
+ string post;
+ unsigned n;
+
+public:
+ Convert (Type _to,
+ Type _from,
+ string pre,
+ string post,
+ unsigned n,
+ ENode _child);
+
+ void print (ostream &out) const;
+};
+
+
+class Swizzle : public A1
+{
+ string name;
+public:
+ Swizzle (Type ty, string _name, ENode _child) ;
+
+ void print (ostream &out) const;
+};
+
+class Binop : public A2
+{
+ string name;
+
+public:
+ Binop(Type ty, string _name, ENode _lhs, ENode _rhs) ;
+
+ void print (ostream &out) const;
+};
+
+class Relop : public A2
+{
+ string name;
+
+public:
+ Relop(string _name, ENode _lhs, ENode _rhs) ;
+ void print (ostream &out) const;
+};
+
+class AssOp : public A2
+{
+ string name;
+
+public:
+ AssOp(Type ty,
+ string _name,
+ ENode lhs,
+ ENode rhs);
+
+ void print (ostream &out) const;
+};
+
+class SelfModOp : public A1
+{
+ string name;
+
+public:
+ SelfModOp(Type ty, string _name, ENode lhs);
+ void print (ostream &out) const;
+};
+
+}
+}
+#endif
+
diff --git a/o3d/compiler/puritan/knobs.cc b/o3d/compiler/puritan/knobs.cc
new file mode 100644
index 0000000..d36a89e
--- /dev/null
+++ b/o3d/compiler/puritan/knobs.cc
@@ -0,0 +1,783 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "knobs.h"
+#include <sstream>
+#include <iomanip>
+#include <iostream>
+#include "rand.h"
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+// Knobs control the behavior of Puritan and keep track of what's happened.
+
+namespace Salem
+{
+namespace Puritan
+{
+static Knob *link;
+
+Knobs::Knobs (void)
+ :
+ top_level_statements
+("--top-level-statements",
+ "\t\tNumber of statements at the top level\n",
+ 1,
+ 3),
+
+ for_count
+ ("--for-count",
+ "\t\tNumber of for loops in code\n",
+ 0,
+ 2),
+
+ while_count
+ ("--while-count",
+ "\t\tNumber of while loops in code\n",
+ 0,
+ 2),
+
+ do_count
+ ("--do-count",
+ "\t\tNumber of do loops in code\n",
+ 0,
+ 1),
+
+ if_count
+ ("--if-count",
+ "\t\tNumber of ifs in code\n",
+ 0,
+ 5),
+
+ block_count
+ ("--block-count",
+ "\t\tNumber of blocks in code\n",
+ 0,
+ 3),
+
+ code_limit
+ ("--code-limit",
+ "\t\tMaximum number of code nodes\n",
+ 200),
+
+ exp_limit
+ ("--exp-limit",
+ "\t\tMaximum number of expression nodes\n",
+ 100),
+
+ exp_count
+ ("--exp-count",
+ "\t\tNumber of expressions in code\n",
+ 6,
+ 16),
+
+ func_count
+ ("--func-count",
+ "\t\tNumber of functions in code\n",
+ 1,
+ 9),
+
+ func_trim
+ ("--func-trim",
+ "\t\tSize factor to apply to callee functions\n",
+ 0.7),
+
+ arg_in_chance
+ ("--args-in-chance",
+ "\t\tChance argument may be just input\n",
+ 0.4),
+
+ arg_out_chance
+ ("--args-out-chance",
+ "\t\tAfter input, chance argument may be just output\n",
+ 0.4),
+
+ for_nesting
+ ("--for-nest",
+ "\t\tNumber of for loops inside for loops\n",
+ 0,
+ 9),
+
+ while_nesting
+ ("--while-nest",
+ "\t\tNumber of while loops inside while loops\n",
+ 0,
+ 4),
+
+ block_nesting
+ ("--block-nest",
+ "\t\tNumber of blocks inside blocks\n",
+ 0,
+ 1),
+
+ do_nesting
+ ("--do-nest",
+ "\t\tNumber of do loops inside do loops\n",
+ 0,
+ 4),
+
+ if_nesting
+ ("--if-nest",
+ "\t\tNumber of ifs inside ifs\n",
+ 0,
+ 9),
+
+ block_length
+ ("--block-length",
+ "\t\tNumber of statements in a block.\n",
+ 2,
+ 7),
+
+ expression_depth
+ ("--exp-depth",
+ "\t\tRange of expression complexity\n",
+ 1,
+ 7),
+
+ special_chance
+ ("--special-chance",
+ "\t\tProbability at each expression point of a special phrase.\n",
+ 0.2),
+
+ float4_chance
+ ("--float4-chance",
+ "\t\tProbability that an expression will have a float4 constructor.\n",
+ .03),
+
+ float4_struct_member_chance
+ ("--float4-struct-member-chance",
+ "\t\tProbability that an element of the output struct will be float4.\n",
+ .90),
+
+ float2_chance
+ ("--float2-chance",
+ "\t\tProbability that an expression will have a float2 constructor.\n",
+ 0.03),
+
+ func_chance
+ ("--func-chance",
+ "\t\tAfter special, probability of an intrinsic function.\n",
+ 0.1),
+
+ term_chance
+ ("--terminal-chance",
+ "\t\tAfter func, probability a terminal.\n",
+ 0.2),
+
+ unary_chance
+ ("--unary-chance",
+ "\t\tAfter terminal, probabaility of a unary op.\n",
+ 0.05),
+
+ swizzle_chance
+ ("--swizzle-chance",
+ "\t\tAfter unrary, chance that term will be a swizzle.\n",
+ 0.35),
+
+ fcall_chance
+ ("--fcall-chance",
+ "\t\tAfter swizzle, probability of a function call.\n",
+ 0.25),
+
+ copy_swizzle_chance
+ ("--copy-swizzle-chance",
+ "\t\tChance a simple non converting copy will be a swizzle.\n",
+ 0.3),
+
+ noinline_chance
+ ("--fnoinline-chance",
+ "\t\tProbability a function will be declared noinline.\n",
+ 0.25),
+
+ lhs_swizzle_chance
+ ("--lhs-swizzle-chance",
+ "\t\tProbabaility of a swizzle as an lval.\n",
+ 1.0),
+
+ assop_chance
+ ("--assop-chance",
+ "\t\tProbability of a fancy assignment operator as assignment.\n",
+ 0.1),
+
+ selfmod_chance
+ ("--selfmod-chance",
+ "\t\tProbability that an assignment will really be a selfmodify.\n",
+ 0.1),
+
+ trifunc_chance
+ ("--trifunc-chance",
+ "\t\tProbability of a trinary intrinsic.\n",
+ 0.2),
+
+ binfunc_chance
+ ("--binary-chance",
+ "\t\tAfter trinary, probabaility of a binary intrinsic instead of unary.\n",
+ 0.8),
+
+ relop_chance
+ ("--relop-chance",
+ "\t\tIf there's going to be a binop,"
+ "probability that it will be a relation.\n",
+ 0.1),
+
+ relop_cond_chance
+ ("--relop-cond-chance",
+ "\t\tNear the end of an expression in a test, "
+ "chance that the op will be a compare\n",
+ 0.9),
+
+ type_change_chance
+ ("--type-change-chance",
+ "\t\tProbability that the type of a subexpression will be different "
+ "to the expression.\n",
+ 0.01),
+
+ type_float4_chance
+ ("--type-float4-chance",
+ "\t\tProbability that a subexpression type will be float4.\n",
+ 0.9),
+
+ type_float2_chance
+ ("--type-float2-chance",
+ "\t\tAfter float4,"
+ "probability that a subexpression type will be float2 instead of float.\n",
+ 0.9),
+
+ sampler_count
+ ("--sampler-count",
+ "\t\tNumber of samplers used\n",
+ 0,
+ 9),
+
+ sampler_chance
+ ("--sampler-chance",
+ "\t\tProbability that an expression will use a sampler\n",
+ .4),
+
+ uniform_count
+ ("--uniform-count",
+ "\t\tNumber of unforms used\n",
+ 0,
+ 9),
+
+ uniform_chance
+ ("--unform-chance",
+ "\t\tProbability that an expression will use a uniform\n",
+ .4),
+
+ arg_count
+ ("--arg-count",
+ "\t\tNumber of arguments to functions\n",
+ 1,
+ 3),
+
+ static_initializer_depth
+ ("--static-initializer-depth",
+ "\t\tRange of static initializer expression complexity\n",
+ 1,
+ 2),
+
+ standalone
+ ("--standalone",
+ "\t\tIf the output should work outside the framework\n",
+ false),
+
+ seed
+ ("--seed",
+ "\t\tSeed for the random number generator\n",
+ 0),
+
+ variable_reuse
+ ("--variable-reuse",
+ "\t\tRatio of variables reused to created in expressions\n",
+ 0.90),
+
+ array_use
+ ("--array-use",
+ "\t\tRatio of array terms in terms in expressions\n",
+ 0.2),
+
+ array_reuse
+ ("--array-reuse",
+ "\t\tRatio of array terms reused to created in expressions\n",
+ 0.95),
+
+ array_constness
+ ("--array-constness",
+ "\t\tProportion of array refs which are references to const arrays\n",
+ 1.),
+
+ array_index_const
+ ("--array-index-const",
+ "\t\tProportion of array references which have a constant index\n",
+ 1.),
+
+ array_in_for_use
+ ("--array-in-for",
+ "\t\tProportion of array references which use a loop index, lhs only.\n",
+ 0.),
+
+ if_elses
+ ("--if-elses",
+ "\t\tProportion of ifs which have elses.\n",
+ 0.30),
+
+ loop_breaks
+ ("--loop-breaks",
+ "\t\tProportion of loops which have breaks.\n",
+ 0.80),
+
+ multiple_stmt
+ ("--multiple-stmt",
+ "\t\tRatio of single statements to blocks.\n",
+ 0.30),
+
+ constant_use
+ ("--constant-use",
+ "\t\tRatio of constants to variables in expressions.\n",
+ 0.30),
+
+ constant_small
+ ("--constant-small",
+ "\t\tChance a constant will be between 0 and 1.\n",
+ 0.90),
+
+// random_names
+// ("--random-names",
+// "\t\tShould names be random or easy on the eyes\n",
+// false),
+
+ int_variables
+ ("--int-variables",
+ "\t\tDeclare integer variables and use them in expressions\n",
+ false),
+
+ allow_two_negs
+ ("--allow-two-negs",
+ "\t\tAllow two negs in an expression\n",
+ false),
+ first (link)
+{
+ link = 0;
+}
+
+RangeKnob::RangeKnob (const char *_name,
+ const char *_help,
+ int _from, int _to)
+ :Knob (_name, _help),
+ from (_from), to (_to)
+{
+}
+
+IntKnob::IntKnob (const char *_name,
+ const char *_help,
+ int _val)
+ :Knob (_name, _help), val (_val)
+{
+}
+
+BoolKnob::BoolKnob (const char *_name,
+ const char *_help,
+ bool _x)
+ :Knob (_name, _help), val (_x)
+{
+}
+
+ProbKnob::ProbKnob (const char *_name,
+ const char *_help,
+ double _x)
+ :Knob (_name, _help), prob (_x)
+{
+}
+
+void RangeKnob::set (int a, int b)
+{
+ from = a;
+ to = b;
+}
+
+// link together the members so we can iterate simply through the struct
+// elements.
+
+
+Knob::~Knob ()
+{
+}
+
+Knob::Knob (const char *_name, const char *_help)
+ :prev (link),
+ name (_name), help (_help)
+{
+ link = this;
+}
+
+
+void RangeKnob::to_stream (std::ostream & out) const
+{
+ out << name << "=" << from;
+ if (from != to)
+ out << "," << to;
+}
+
+void IntKnob::to_stream (std::ostream & out) const
+{
+ out << name << "=" << val;
+}
+
+void BoolKnob::to_stream (std::ostream & out) const
+{
+ out << name << "=" << (val ? "t" : "f") ;
+}
+
+void BoolKnob::usage (std::ostream & out) const
+{
+ out << (name) << "=" << "[t|f] ";
+ out << (val ? "{t}" : "{f}") << "\n" << help;
+}
+
+void ProbKnob::usage (std::ostream & out) const
+{
+ char t[1000];
+ sprintf (t, "%s = <0.0 <= x <= 1.0> {%g}\n%s", name, prob, help);
+ out << t;
+}
+
+void IntKnob::usage (std::ostream & out) const
+{
+ out << (name) << "=" << "<int>";
+ out << " {" << val << "}\n" << help;
+}
+
+void RangeKnob::usage (std::ostream & out) const
+{
+ out << (name) << "=" << "<int>,<int>";
+ out << " {" << from;
+ if (from != to)
+ out << "," << to;
+ out << "}\n" << help;
+}
+
+bool BoolKnob::set_from_argument (const char *arg)
+{
+ if (arg[0] == 't' || arg[0] == '1')
+ {
+ val = true;
+ return true;
+ }
+ if (arg[0] == 'f' || arg[0] == '0')
+ {
+ val = false;
+ return true;
+ }
+ return false;
+}
+
+bool ProbKnob::set_from_argument (const char *arg)
+{
+ char *finish;
+ prob = strtod (arg, &finish);
+ return (arg != finish);
+}
+
+bool IntKnob::set_from_argument (const char *arg)
+{
+ char *finish;
+ val = strtol (arg, &finish, 0);
+ return (arg != finish);
+}
+
+int IntKnob::get () const
+{
+ return val;
+}
+
+unsigned IntKnob::uget () const
+{
+ return val;
+}
+
+bool RangeKnob::set_from_argument (const char *val)
+{
+ long int a, b;
+ char *next;
+ a = strtol (val, &next, 0);
+
+ if (next == val)
+ {
+ return false;
+ }
+
+ if (*next == 0)
+ {
+ from = a;
+ to = a;
+ return true;
+ }
+
+ if (*next != ',')
+ {
+ return false;
+ }
+
+ char *next_2;
+ next++;
+ b = strtol (next, &next_2, 0);
+ if (next_2 == next || *next_2 != 0)
+ return false;
+
+ from = a;
+ to = b;
+ return true;
+}
+
+bool Knobs::parse_argument (const char *arg)
+{
+ for (Knob * l = first; l; l = l->prev)
+ {
+ if (strncmp (l->name, arg, strlen (l->name)) == 0)
+ {
+ const char *val = strchr (arg, '=');
+ if (val)
+ return l->set_from_argument (val + 1);
+ }
+ }
+ return false;
+}
+
+std::ostream & operator << (std::ostream &out, const Knobs& x)
+{
+ unsigned j = 0;
+ for (Knob * l = x.first; l; l = l->prev)
+ {
+ std::ostringstream tmp;
+ l->to_stream (tmp);
+ out << std::setw(30) << tmp.str();
+ j++;
+ if (j == 3)
+ {
+ out << "\n";
+ j = 0;
+ }
+ }
+
+ return out;
+}
+
+std::string Knobs::usage ()
+{
+ std::ostringstream tmp;
+ Knobs dummy = Knobs ();
+
+ for (Knob * l = dummy.first; l; l = l->prev)
+ {
+ l->usage (tmp);
+ tmp << "\n";
+ }
+
+ return tmp.str ();
+}
+
+bool BoolKnob::operator () () const
+{
+ return val;
+}
+
+void BoolKnob::set (bool x)
+{
+ val = x;
+}
+
+bool ProbKnob::operator () (Rand * r) const
+{
+ double rnd = r->rnd_flt ();
+ return prob > rnd;
+}
+
+void ProbKnob::to_stream (std::ostream & out) const
+{
+ char t[1000];
+ sprintf (t, "%s=%g", name, prob);
+ out << t;
+}
+
+double ProbKnob::get () const
+{
+ return prob;
+}
+
+int RangeKnob::operator () (Rand * r) const
+{
+ return r->range (from, to);
+}
+
+unsigned RangeKnob::random_uint (Rand * r) const
+{
+ return r->range (from, to);
+}
+
+//////////////////////////////////////////////////////////////////////
+//
+// Coverage
+// Used for random selections and maintaining stats.
+
+// pointer to head of choice list, so we can look through choices later and
+// generate stats.
+Coverage * Coverage::head = 0;
+
+Coverage::Coverage (std::string _title)
+ :title (_title),
+ prev (head)
+{
+ head = this;
+}
+
+Coverage:: ~ Coverage ()
+{
+}
+
+void Coverage::increment (size_t idx)
+{
+ if (idx >= count.size ())
+ {
+ count.resize (idx + 1);
+
+ }
+ count[idx]++;
+}
+
+std::ostream &operator<<(std::ostream &out, const Coverage &thing)
+{
+ thing.output_worker (out);
+ return out;
+}
+
+StrCoverage:: StrCoverage (const char *_title,
+ const char **_selections):Coverage (_title)
+{
+ while (*_selections)
+ {
+ width = std::max (width, strlen (*_selections));
+ selections.push_back (*_selections);
+ count.push_back (0);
+ _selections++;
+ }
+// round to tab size
+ width = (width + 7) & -8;
+}
+
+std::string StrCoverage::choose (class Rand * r)
+{
+ size_t idx = r->srange (0, count.size ());
+ increment (idx);
+ return selections[idx];
+}
+
+void StrCoverage::output_worker (std::ostream & out) const
+{
+ unsigned items = 0;
+ out << title << "\n";
+ size_t online = 0;
+ for (unsigned i = 0; i < count.size (); i++)
+ {
+ out << " |";
+ out.fill (' ');
+ out.width (static_cast<int>(width));
+ out << selections[i];
+ out.fill (' ');
+ out.width (6);
+ out << count[i];
+ out.width (0);
+ online += width + 6;
+ items++;
+ if (items > 4 || online > 60)
+ {
+ out << " |\n";
+ items = 0;
+ online = 0;
+ }
+ }
+ if (online)
+ {
+ out << " |\n";
+ }
+ if (prev)
+ {
+ prev->output_worker (out);
+ }
+}
+
+IntCoverage::IntCoverage (const char *_title):Coverage (_title)
+{
+}
+
+void IntCoverage::output_worker (std::ostream & out) const
+{
+ unsigned items = 0;
+ out << title << "\n";
+
+ for (unsigned i = 0; i < count.size (); i++)
+ {
+ out << "|";
+ out << std::setw(4) << i ;
+
+ if (count[i])
+ {
+ out << std::setw(6) << count[i];
+ }
+ else
+ {
+ out << std::setw(6) << "****";
+ }
+ items++;
+ if (items > 4)
+ {
+ out << "\n";
+ items = 0;
+ }
+ }
+
+ if (items)
+ {
+ out << "\n";
+ }
+
+ if (prev)
+ {
+ prev->output_worker (out);
+ }
+}
+
+
+}
+}
diff --git a/o3d/compiler/puritan/knobs.h b/o3d/compiler/puritan/knobs.h
new file mode 100644
index 0000000..00fa692
--- /dev/null
+++ b/o3d/compiler/puritan/knobs.h
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef PURITAN_KNOBS_H
+#define PURITAN_KNOBS_H
+
+#include <string>
+#include <list>
+#include <vector>
+
+namespace Salem
+{
+namespace Puritan
+{
+
+class OutputInfo
+{
+public:
+ typedef enum
+ {
+ Float1,
+ Float2,
+ Float4
+ } ArgSize;
+
+ unsigned n_samplers;
+ std::list <std::pair <ArgSize, std::string> > uniforms;
+ std::list <ArgSize> returns;
+};
+
+class Knob
+{
+ class Knob *prev;
+ const char *name;
+ const char *help;
+
+ virtual bool set_from_argument (const char *val) = 0;
+ bool parse_argument (const char *val);
+ virtual void usage (std::ostream &out) const= 0;
+
+ friend class Knobs;
+ friend class IntKnob;
+ friend class RangeKnob;
+ friend class BoolKnob;
+ friend class ProbKnob;
+ friend std::ostream & operator << (std::ostream &out, const class Knobs& x);
+
+public:
+ Knob(const char *name, const char *desc);
+ virtual ~Knob();
+
+ virtual void to_stream (std::ostream &) const = 0;
+
+};
+
+class RangeKnob : public Knob
+{
+ int from;
+ int to;
+
+ bool set_from_argument (const char *val);
+ void usage (std::ostream &) const;
+
+public:
+ RangeKnob (const char *, const char *,int f, int t);
+
+ void set(int, int);
+ int operator () (class Rand *) const;
+ unsigned int random_uint (class Rand *) const ;
+ void to_stream (std::ostream &) const;
+
+};
+
+class IntKnob : public Knob
+{
+ int val;
+
+ bool set_from_argument (const char *val);
+ void usage (std::ostream &) const;
+
+public:
+ IntKnob (const char *, const char *,int);
+
+ int get() const;
+ unsigned uget() const;
+ void set(int x) { val = x;}
+ void to_stream (std::ostream &) const;
+
+};
+
+class BoolKnob : public Knob
+{
+ bool val;
+
+ bool set_from_argument (const char *val);
+ void usage (std::ostream &) const;
+public:
+ BoolKnob (const char *, const char *,bool f);
+ void to_stream (std::ostream &) const;
+ bool operator () () const;
+ void set(bool x);
+};
+
+class ProbKnob : public Knob
+{
+ double prob;
+
+ bool set_from_argument (const char *val);
+ void usage (std::ostream &) const;
+public:
+ ProbKnob (const char *, const char *,double d);
+ void set (double x) { prob = x; }
+ double get() const;
+ void to_stream (std::ostream &) const;
+ bool operator () (Rand *r) const ;
+};
+
+class Knobs
+{
+public:
+ RangeKnob top_level_statements;
+ RangeKnob for_count;
+ RangeKnob while_count;
+ RangeKnob do_count;
+ RangeKnob if_count;
+ RangeKnob block_count;
+ IntKnob code_limit;
+ IntKnob exp_limit;
+ RangeKnob exp_count;
+ RangeKnob func_count;
+ ProbKnob func_trim;
+ ProbKnob arg_in_chance;
+ ProbKnob arg_out_chance;
+ RangeKnob for_nesting;
+ RangeKnob while_nesting;
+ RangeKnob block_nesting;
+ RangeKnob do_nesting;
+ RangeKnob if_nesting;
+ RangeKnob block_length;
+ RangeKnob expression_depth;
+ ProbKnob special_chance;
+ ProbKnob float4_chance;
+ ProbKnob float4_struct_member_chance;
+ ProbKnob float2_chance;
+ ProbKnob func_chance;
+ ProbKnob term_chance;
+ ProbKnob unary_chance;
+ ProbKnob swizzle_chance;
+ ProbKnob fcall_chance;
+ ProbKnob copy_swizzle_chance;
+ ProbKnob noinline_chance;
+ ProbKnob lhs_swizzle_chance;
+ ProbKnob assop_chance;
+ ProbKnob selfmod_chance;
+ ProbKnob trifunc_chance;
+ ProbKnob binfunc_chance;
+ ProbKnob relop_chance;
+ ProbKnob relop_cond_chance;
+ ProbKnob type_change_chance;
+ ProbKnob type_float4_chance;
+ ProbKnob type_float2_chance;
+ RangeKnob sampler_count;
+ ProbKnob sampler_chance;
+ RangeKnob uniform_count;
+ ProbKnob uniform_chance;
+ RangeKnob arg_count;
+ RangeKnob static_initializer_depth;
+ BoolKnob standalone;
+ IntKnob seed;
+ ProbKnob variable_reuse;
+ ProbKnob array_use;
+ ProbKnob array_reuse;
+ ProbKnob array_constness;
+ ProbKnob array_index_const;
+ ProbKnob array_in_for_use;
+ ProbKnob if_elses;
+ ProbKnob loop_breaks;
+ ProbKnob multiple_stmt;
+ ProbKnob constant_use;
+ ProbKnob constant_small;
+ BoolKnob int_variables;
+ BoolKnob allow_two_negs;
+
+ Knob *first;
+ Knobs(void);
+ void to_stream (std::ostream &);
+ bool parse_argument (const char *arg);
+ static std::string usage ();
+};
+
+class Coverage
+{
+private:
+ // Next in chain
+
+ std::string title;
+ std::vector <int> count;
+ Coverage *prev;
+
+ friend class StrCoverage;
+ friend class IntCoverage;
+
+public:
+ static Coverage *head;
+ virtual void output_worker (std::ostream & out) const = 0;
+ Coverage (std::string _title) ;
+ virtual ~ Coverage () ;
+
+ void increment (size_t idx);
+};
+
+class StrCoverage:Coverage
+{
+private:
+ std::vector <std::string> selections;
+ size_t width;
+ void output_worker (std::ostream & out) const;
+
+public:
+ StrCoverage (const char *_title, const char **_selections);
+ std::string choose (class Rand * r);
+};
+
+class IntCoverage:public Coverage
+{
+private:
+ void output_worker (std::ostream & out) const;
+public:
+ IntCoverage (const char *_title);
+};
+
+
+std::ostream & operator << (std::ostream &out, const class Salem::Puritan::Coverage &x);
+std::ostream & operator << (std::ostream &out, const class Salem::Puritan::Knobs &x);
+}
+}
+
+#endif
diff --git a/o3d/compiler/puritan/main.cc b/o3d/compiler/puritan/main.cc
new file mode 100644
index 0000000..cc6570a
--- /dev/null
+++ b/o3d/compiler/puritan/main.cc
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+// This program demonstrates how to get test case information out of Puritan.
+
+#include <iostream>
+#include "test_gen.h"
+#include "knobs.h"
+
+static std::string name_of_size(Salem::Puritan::OutputInfo::ArgSize x) {
+ switch (x) {
+ case Salem::Puritan::OutputInfo::Float1:
+ return "float";
+ case Salem::Puritan::OutputInfo::Float2:
+ return "float2";
+ case Salem::Puritan::OutputInfo::Float4:
+ return "float4";
+ default:
+ break;
+ }
+ return "Impossible";
+}
+
+
+static std::string comma(bool * need_comma) {
+ if (*need_comma) {
+ return ", ";
+ } else {
+ *need_comma = true;
+ return "";
+ }
+}
+
+int main (int argc, char * const argv[]) {
+ int j = 0;
+ if (argc > 1) {
+ sscanf(argv[1], "%d", &j);
+ }
+
+ Salem::Puritan::Knobs options;
+
+ // Set up some options just the way we like
+ options.block_count.set(2, 3);
+ options.for_count.set(2, 3);
+ options.for_nesting.set(2, 3);
+ options.array_in_for_use.set(false);
+ options.seed.set(j);
+
+ Salem::Puritan::OutputInfo info;
+
+
+ // Build a test case
+ std::string test_case =
+ Salem::Puritan::generate(&info, options);
+
+ // Dump out the test information
+ std::cout << "(Seed " << options.seed.get() << "), "
+ << "(Samplers (";
+
+ bool need_comma = false;
+
+ for (unsigned i = 0; i < info.n_samplers; i++) {
+ std::cout << comma(&need_comma) << "in" << i;
+ }
+
+ std::cout << ")),"
+ << "(Uniforms (";
+
+ need_comma = false;
+
+ for (std::list <
+ std::pair <
+ Salem::Puritan::OutputInfo::ArgSize,
+ std::string > >::const_iterator
+ i = info.uniforms.begin();
+ i != info.uniforms.end();
+ i++) {
+ std::cout << comma(&need_comma)
+ << name_of_size(i->first)
+ << " "
+ << i->second;
+ }
+
+ std::cout << ")), "
+ << "(return struct {";
+
+ need_comma = false;
+ for (std::list <Salem::Puritan::OutputInfo::ArgSize>::const_iterator
+ i = info.returns.begin();
+ i != info.returns.end();
+ i++) {
+ std::cout << comma(&need_comma) << name_of_size(*i);
+ }
+
+ std::cout << "})\n";
+ std::cout << test_case;
+
+ return 1;
+}
diff --git a/o3d/compiler/puritan/puritan.cc b/o3d/compiler/puritan/puritan.cc
new file mode 100644
index 0000000..055b814
--- /dev/null
+++ b/o3d/compiler/puritan/puritan.cc
@@ -0,0 +1,1619 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include <sstream>
+#include <iterator>
+#include <iomanip>
+#include "puritan.h"
+#include "knobs.h"
+#include "structure_gen.h"
+#include "exp_gen.h"
+#include "puritan_assert.h"
+
+#ifdef _MSC_VER
+#define snprintf _snprintf
+#endif
+
+namespace Salem
+{
+namespace Puritan
+{
+// Counters for code coverage.
+IntCoverage cfor_count ("for loop count");
+IntCoverage cfor_nesting ("for loop nesting");
+IntCoverage cdo_count ("do loop count");
+IntCoverage cdo_nesting ("do loop nesting");
+IntCoverage cwhile_count ("while loop count");
+IntCoverage cwhile_nesting ("while loop nesting");
+IntCoverage cif_count ("if count");
+IntCoverage cif_nesting ("if nesting");
+IntCoverage cblock_count ("block count");
+IntCoverage cblock_nesting ("block nesting");
+IntCoverage cexp_count ("exp count");
+IntCoverage cfunc_count ("func count");
+IntCoverage csampler_count ("sampler count");
+IntCoverage cuniform_count ("unform count");
+
+const char *assop_names[] = { "*=", "/=", "+=", "-=", 0 };
+StrCoverage assops ("Assops", assop_names);
+
+const char *selfmodops_names[] = { "++", "--", 0 };
+StrCoverage selfmodops ("SelfModOps", selfmodops_names);
+
+const char *lhs_f4tof4_swizzle_names[] =
+{
+ "w", "z", "zw", "y",
+ "yw", "yz", "yzw", "x",
+ "xw", "xz", "xzw", "xy",
+ "xyw", "xyz", "xyzw",
+ 0
+};
+
+StrCoverage lhs_f4tof4_swizzles ("Lhs f4tof4 Swizzles",
+ lhs_f4tof4_swizzle_names);
+
+const char *lhs_f2tof2_swizzle_names[] =
+{
+ "xy", "x", "y",
+ 0
+};
+
+StrCoverage lhs_f2tof2_swizzles ("lhs_f2tof2_swizzles",
+ lhs_f2tof2_swizzle_names);
+
+
+
+
+// Build the control structurte for each function
+//
+// Each function starts off with an empty list of tokens describing what to
+// do. Knobs and random numbers insert things into the list in random places
+// to mark structure. Many things have two items in the list, for example, a
+// for will have For token and a Close token, marking the point that the for
+// scope is opened, and then closed. If something is inserted into the list
+// between the For and the Close, then it becomes nested inside the for when
+// the code is output. If the thing that is inserted is a pair and it has a
+// Close istelf and that straddles the Close of the for, then since the Closes
+// all look alike, it is still the same as being nested, except the scope of
+// the for then stretches out to the end of the new item.
+
+
+void Gen::create_control_structure ()
+{
+ // Divide the samplers among the functions, samples_per_func is a list of
+ // samplers used in each function.
+ std::vector <UList> samples_per_func;
+
+ for (unsigned fidx = 0; fidx < max_funcs; fidx++)
+ {
+ samples_per_func.push_back (UList ());
+ }
+
+ for (unsigned i = 0; i < n_samplers; i++)
+ {
+ for (unsigned j = 0; j < rand.urange (1,2); j++)
+ {
+ samples_per_func[rand.urange (0, max_funcs)].push_back (i);
+ }
+ }
+
+ for (unsigned fidx = 0; fidx < max_funcs; fidx++)
+ {
+ unsigned for_count
+ = coverage (fidx, knobs.for_count, &cfor_count);
+ unsigned for_nesting
+ = coverage (fidx, knobs.for_nesting, &cfor_nesting);
+ unsigned block_count
+ = coverage (fidx, knobs.block_count, &cblock_count);
+ unsigned block_nesting
+ = coverage (fidx, knobs.block_nesting, &cblock_nesting);
+ unsigned while_count
+ = coverage (fidx, knobs.while_count, &cwhile_count);
+ unsigned while_nesting
+ = coverage (fidx, knobs.while_nesting, &cwhile_nesting);
+ unsigned do_count
+ = coverage (fidx, knobs.do_count, &cdo_count);
+ unsigned do_nesting
+ = coverage (fidx, knobs.do_nesting, &cdo_nesting);
+ unsigned if_count
+ = coverage (fidx, knobs.if_count, &cif_count);
+ unsigned if_nesting
+ = coverage (fidx, knobs.if_nesting, &cif_nesting);
+ unsigned asn_count
+ = coverage (fidx, knobs.exp_count, &cexp_count);
+
+ std::vector <BlockSPtr> code_stack;
+ std::vector <ForSPtr> for_stack;
+
+ TokenVec tokens;
+
+ unsigned asn_tmp_count = asn_count;
+
+ while (code_nodes < knobs.code_limit.uget()
+ && (for_count || block_count || while_count
+ || do_count || if_count || asn_tmp_count))
+ {
+ code_nodes ++;
+ for_count = ins_stmts (&tokens,
+ for_count, for_nesting,
+ TokFor, 1, true);
+
+ block_count= ins_stmts (&tokens,
+ block_count, block_nesting,
+ TokBlock, 1, false);
+
+ while_count = ins_stmts (&tokens,
+ while_count, while_nesting,
+ TokWhile, 1, true);
+
+ do_count = ins_stmts (&tokens,
+ do_count, do_nesting,
+ TokDo, 1, true);
+
+ if_count = ins_stmts (&tokens,
+ if_count, if_nesting,
+ TokIf, 1, false);
+
+ if (knobs.selfmod_chance (&rand))
+ {
+ asn_tmp_count = ins_stmts (&tokens,
+ asn_tmp_count, 1,
+ TokSelfMod, 0, false);
+ }
+ else
+ {
+ asn_tmp_count = ins_stmts (&tokens,
+ asn_tmp_count, 1,
+ TokAssign, 0, false);
+ }
+
+ }
+
+
+ // The final statement is always a return, we stick it in an assignment
+ // slot
+
+ tokens.push_back (TokReturn);
+
+ asn_count ++;
+
+ // Spread the function calls and samplers over a number of assignments,
+ // so that there's always at least one of the right thing per function.
+ std::vector <UList> sampler_slots;
+ std::vector <FunctionList> caller_slots;
+
+ for (unsigned i = 0; i < asn_count; i++)
+ {
+ sampler_slots.push_back (UList ());
+ caller_slots.push_back (FunctionList ());
+ }
+
+ for (UList::const_iterator sampler = samples_per_func[fidx].begin ();
+ sampler != samples_per_func[fidx].end ();
+ sampler++)
+ {
+ for (unsigned j = 0; j < rand.urange (1,3); j++)
+ {
+ sampler_slots[rand.range (0, asn_count)].push_back (*sampler);
+ }
+ }
+
+ for (FunctionList::const_iterator
+ i = callees[fidx].begin ();
+ i != callees[fidx].end ();
+ i++)
+ {
+ for (unsigned j = 0; j < rand.urange (1,2); j++)
+ {
+ caller_slots[rand.range (0, asn_count)].push_back (*i);
+ }
+ }
+
+
+ ForSPtr last_for;
+
+ asn_count = 0;
+
+ FunctionSPtr cur = functions[fidx];
+
+ code_stack.push_back (cur);
+
+
+ for (TokenVec::iterator t = tokens.begin ();
+ t != tokens.end ();
+ t++)
+ {
+ Context ctx (cur->idx,
+ last_for,
+ &sampler_slots[asn_count],
+ &caller_slots[asn_count]);
+
+ switch (*t)
+ {
+ case TokBlock:
+ {
+ BlockSPtr c (new Block ());
+ code_stack.back ()->add_child (c);
+ code_stack.push_back (c);
+ for_stack.push_back (last_for);
+ break;
+ }
+ case TokFor:
+ {
+ Decl counter
+ = new_uninitialized_variable (Scope (Static, cur->idx),
+ Int);
+ // mark this variable such that its not assigned anywhere
+ counter.noWrites = true;
+ ForSPtr
+ f (new For (counter,
+ rand.range (0,10),
+ rand.range (11,20)));
+ last_for = f;
+ code_stack.back ()->add_child (f);
+ code_stack.push_back (f);
+ for_stack.push_back (f);
+ break;
+ }
+ case TokIf:
+ {
+ BlockSPtr
+ c (new IfTemplate (create_expression (this,
+ Float,
+ ctx.relop ()),
+ knobs.if_elses (&rand)));
+ code_stack.back ()->add_child (c);
+ code_stack.push_back (c);
+ for_stack.push_back (last_for);
+ break;
+ }
+ case TokWhile:
+ {
+ Decl counter
+ = new_uninitialized_variable (Scope (Static, cur->idx),
+ Float);
+ // mark this variable such that its not assigned anywhere
+ counter.noWrites = true;
+ BlockSPtr
+ c (new While (create_expression (this,
+ Float,
+ ctx.relop ()),
+ counter,
+ rand.range (1,10)));
+ code_stack.back ()->add_child (c);
+ code_stack.push_back (c);
+ for_stack.push_back (last_for);
+ break;
+ }
+ case TokDo:
+ {
+ Decl counter
+ = new_uninitialized_variable (Scope (Static, cur->idx),
+ Float);
+ // mark this variable such that its not assigned anywhere
+ counter.noWrites = true;
+ BlockSPtr
+ c (new Do (create_expression (this,
+ Float,
+ ctx.relop ()),
+ counter,
+ rand.range (1,10)));
+ code_stack.back ()->add_child (c);
+ code_stack.push_back (c);
+ for_stack.push_back (last_for);
+ break;
+ }
+ // End of any kind of block
+ case TokClose:
+ code_stack.pop_back ();
+ last_for = for_stack.back ();
+ for_stack.pop_back ();
+ break;
+ case TokSelfMod:
+ {
+ Type ty = random_type ();
+ Decl d = fetch_decl (ty, ctx, Initialized, ReadWrite);
+ ENode lhs = ENode
+ (new SelfModOp (ty, selfmodops.choose (&rand),
+ ENode (new LHSVariable (d, false))));
+ // We can use the assignment template for self mod, since it
+ // takes any expression.
+ code_stack.back ()->add_child
+ (CodeSPtr (new AssignmentTemplate (lhs)));
+ }
+ break;
+ case TokAssign:
+ {
+ ENode rhs;
+ ENode lhs;
+ Type type (NoType);
+ bool assop = knobs.assop_chance (&rand);
+ bool lhs_swizzle = true;
+ // Inside a for loop we may want to do array assignments.
+ if (ctx.loop.get()
+ && knobs.array_in_for_use (&rand)
+ && !knobs.array_constness (&rand))
+ {
+ Decl decl = gen_array_decl (Float4Array, ctx, Read);
+ rhs = create_expression (this, Float4, ctx);
+ lhs = ENode
+ (new Index (ENode (new LHSVariable (decl, false)),
+ ENode (new Constant (Float4, "4"))));
+ type = Float4;
+ }
+ else
+ {
+ type = random_type ();
+ rhs = create_expression (this, type, ctx);
+ // An assignment operator needs a preinitialized lhs.
+ Decl d = fetch_decl (type, ctx,
+ assop
+ ? Initialized
+ : Uninitialized,
+ assop
+ ? ReadWrite
+ : Write);
+ if (! d.initializer.get() )
+ lhs_swizzle = false;
+ lhs = ENode (new LHSVariable (d, false));
+ }
+
+
+ if (assop)
+ {
+ rhs = ENode (new AssOp (type, assops.choose (&rand),
+ lhs,
+ rhs));
+ }
+ else
+ {
+ if (lhs_swizzle)
+ {
+ if (type == Float4 && knobs.lhs_swizzle_chance (&rand))
+ {
+ lhs = ENode
+ (new Swizzle (type,
+ lhs_f4tof4_swizzles.choose (&rand),
+ lhs));
+ }
+ else if (type == Float2 && knobs.lhs_swizzle_chance (&rand))
+ {
+ lhs = ENode
+ (new Swizzle (type,
+ lhs_f2tof2_swizzles.choose (&rand),
+ lhs));
+ }
+ }
+ rhs = ENode (new AssOp (type, "=", lhs, rhs));
+ }
+
+ code_stack.back ()->add_child
+ (CodeSPtr (new AssignmentTemplate (rhs)));
+ asn_count ++;
+ }
+ break;
+
+ case TokReturn:
+ {
+ // Add the returns at the bottom, the main function returns a
+ // struct.
+
+ if (cur->idx == 0)
+ {
+ Decl decl = new_variable (Scope (Static, cur->idx),
+ cur->ret_type);
+ EList v;
+ for (TypeList::const_iterator i = cur->ret_type.begin ();
+ i != cur->ret_type.end ();
+ i++)
+ {
+ v.push_back (create_expression (this, *i, ctx));
+ }
+ code_stack.back ()->add_child
+ (CodeSPtr (new Return (v, decl)));
+ }
+ else
+ {
+ ENode rval1 = create_expression (this,
+ cur->ret_type.front (),
+ ctx);
+ code_stack.back ()->add_child
+ (CodeSPtr (new Return (rval1)));
+ }
+ }
+ break;
+
+ case TokBreak:
+ {
+ BreakSPtr
+ b (new Break
+ (create_expression (this, Float, ctx)));
+ code_stack.back ()->add_child (b);
+ }
+ break;
+ default:
+ PURITAN_ABORT("Illegal token " << static_cast<int>(*t));
+ break;
+ }
+ }
+ }
+}
+
+
+// Create the function template for each function and fill in the argument type
+// and return types.
+
+void Gen::create_call_structure ()
+{
+ for (unsigned i = 0; i < max_funcs; i++)
+ {
+ DeclList formals;
+ TypeList ret_type;
+
+ if (i == 0)
+ {
+ // first function is main, always returns a struct and takes just
+ // float2
+
+ unsigned nrets = rand.urange (1, 5);
+ for (unsigned j = 0; j < nrets; j++)
+ {
+ ret_type.push_back (knobs.float4_struct_member_chance (&rand)
+ ? Float4
+ : Float);
+
+ }
+
+ formals.push_back (
+ new_uninitialized_variable (Scope (Argument_I, i), Float2));
+ }
+ else
+ {
+ switch (rand.range (0,4))
+ {
+ case 0:
+ ret_type.push_back (Float);
+ break;
+ case 1:
+ ret_type.push_back (Float2);
+ break;
+ default:
+ ret_type.push_back (Float4);
+ break;
+ }
+
+ unsigned n = knobs.arg_count.random_uint (&rand);
+
+ for (unsigned j = 0; j < n; j++)
+ {
+ Context ctx (i, ForSPtr (), 0, 0);
+ scope_t arg =
+ knobs.arg_in_chance(&rand)
+ ? Argument_I : knobs.arg_out_chance (&rand)
+ ? Argument_O : Argument_IO;
+
+ formals.push_back (new_uninitialized_variable (Scope (arg, i),
+ random_type ()));
+ }
+ }
+ functions.push_back (FunctionSPtr
+ (new Function (this, i, ret_type,
+ formals,
+ knobs.standalone (),
+ knobs.noinline_chance(&rand))));
+ }
+ // Different call patterns, so far only one.
+ switch (int x = rand.range (0,0))
+ {
+ case 0:
+ // Each functions calls the one above, save the last
+ for (unsigned i = 0; i < max_funcs; i++)
+ {
+ FunctionList targets;
+ if (i != (max_funcs - 1))
+ {
+ targets.push_back (functions[i+1]);
+ }
+ callees.push_back (targets);
+ }
+ break;
+ case 1:
+ break;
+ default:
+ PURITAN_ABORT ("Unexpected case " << x);
+ }
+}
+
+// Add any samplers to the symbol table.
+void Gen::declare_samplers ()
+{
+ for (unsigned i = 0; i < n_samplers; i++)
+ {
+ new_uninitialized_variable (Scope (Sampler), SamplerFloat4, i);
+ new_uninitialized_variable (Scope (Uniform), SamplerSize, i);
+ }
+
+ for (unsigned i = 0; i < n_uniforms; i++)
+ {
+ Decl decl = new_uninitialized_variable (Scope (Uniform), Float4, i);
+ ostringstream decl_name;
+ decl_name << decl;
+ uniforms.push_back
+ (std::pair <Type, string> (Float4, decl_name.str()));
+ }
+}
+
+// Insert the statement tokens somewhere randomly.
+unsigned Gen::ins_stmts (TokenVec *vec,
+ unsigned count,
+ unsigned nest,
+ Token token,
+ unsigned ends,
+ bool break_p)
+{
+ nest = std::min (std::max(1U, nest), count);
+ size_t start_pos = 0;
+ size_t limit = vec->size();
+ size_t end_pos = limit;
+ for (unsigned j = 0; j < nest; j++)
+ {
+ start_pos = rand.srange (start_pos, end_pos);
+ end_pos = start_pos + 1 < end_pos
+ ? rand.srange (start_pos + 1, end_pos)
+ : end_pos;
+
+ PURITAN_ASSERT (start_pos <= end_pos, "Sanity check");
+
+ vec->insert (vec->begin () + start_pos, token);
+
+ start_pos ++;
+ end_pos++;
+
+ if (break_p && knobs.loop_breaks (&rand))
+ {
+ vec->insert (vec->begin () + start_pos, TokBreak);
+ start_pos ++;
+ end_pos++;
+ }
+
+ if (ends)
+ {
+ vec->insert (vec->begin () + start_pos, TokClose);
+ start_pos ++;
+ end_pos++;
+ }
+
+ }
+ return count - nest;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Class containing the scope of a name.
+Scope::Scope (scope_t x, unsigned i) : scope (x) , fnc_idx (i)
+{
+
+}
+
+bool Scope::visible_in (const Context &ctx,
+ Dir d) const
+{
+ switch (scope)
+ {
+ case Argument_IO:
+ return fnc_idx == ctx.func && (d == Read || d == Write);
+ case Argument_O:
+ return fnc_idx == ctx.func && (d == Write);
+ case Argument_I:
+ return fnc_idx == ctx.func && (d == Read || d == Write);
+ case StaticConstArrays:
+ case Sampler:
+ case Uniform:
+ return d == Read;
+ case Static:
+ return fnc_idx == ctx.func;
+ case NoScope:
+ default:
+ break;
+ }
+ PURITAN_ABORT ("Illegal scope " << scope);
+}
+
+string Scope::name () const
+{
+ switch (scope)
+ {
+ case Sampler:
+ return "sampler ";
+ case Uniform:
+ return "uniform ";
+ case Static:
+ case StaticConstArrays:
+ return "";
+ default:
+ case NoScope:
+ case Argument_I:
+ case Argument_O:
+ case Argument_IO:
+ PURITAN_ABORT ("Argument error " << scope);
+ }
+}
+
+string Scope::short_name () const
+{
+ switch (scope)
+ {
+ case Sampler:
+ return "in";
+ case Uniform:
+ return "u_";
+ case Static:
+ case StaticConstArrays:
+ return "s_";
+ case Argument_I:
+ return "ai_";
+ case Argument_O:
+ return "ao_";
+ case Argument_IO:
+ return "aio_";
+ default:
+ case NoScope:
+ PURITAN_ABORT ("Argument error " << scope);
+ }
+}
+
+bool Scope::eq (const Scope &other) const
+{
+ return scope == other.scope && fnc_idx == other.fnc_idx;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Generator
+// Main wrapper and support
+// Emit all the declarations at the given scope
+void
+Gen::output_declarations (ostream &out,
+ Scope s)
+{
+ DeclVec::const_iterator i = symtable.begin ();
+ while (i != symtable.end ())
+ {
+ const Decl & d = *i;
+ if (d.scope.eq (s))
+ {
+ if (d.type () == Float4Array)
+ {
+ out << "uniform float4 "
+ << d
+ << "[" << array_size << "];\n";
+ }
+ else if (d.type () == Float4ConstArray)
+ {
+ out << "const float4 "
+ << d
+ << "[" << array_size << "] = {\n";
+ for (unsigned i = 0; i < array_size * 4; i++)
+ {
+ if (i)
+ {
+ out << ",\n";
+ }
+
+ out << gen_fconstant ();
+ }
+ out << "};\n";
+ }
+ else
+ {
+ out << d.scope.name ();
+
+ if (d.scope.scope != Sampler)
+ {
+ out << " " << d.type;
+ }
+
+ out << " " << d;
+
+ if (d.initializer.get() )
+ {
+ out << " = " << d.initializer;
+ }
+ out << ";\n";
+ }
+ }
+ i++;
+ }
+}
+
+// Return a random type.
+Type Gen::random_type ()
+{
+ return (knobs.type_float4_chance (&rand))
+ ? Float4
+ : knobs.type_float2_chance (&rand)
+ ? Float2
+ : Float;
+}
+
+
+const char *id_char =
+"0123456789" "abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+const char *first_char =
+"abcdefghijklmnopqrstuvwxyz" "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+const char *digit = "012345678";
+
+char Gen::rchar (const char *what)
+{
+ return what[ (rand.srange (0, strlen (what)))];
+}
+
+
+// Make a random floating point constant.
+string Gen::gen_fconstant ()
+{
+ if (knobs.constant_small (&rand))
+ {
+ ostringstream out;
+ char b[100];
+ sprintf (b, "%g", 10.0 / rand.range (1, 10000));
+ out << b;
+ return out.str ();
+ }
+ else
+ {
+ string res;
+ unsigned len = rand.range (1, 30);
+ unsigned point = rand.range (0,len);
+
+ for (unsigned i = 0; i < len; i++)
+ {
+ res += rchar (digit);
+ if (i == point)
+ {
+ res += ".";
+ }
+ }
+ return res;
+ }
+}
+
+ostream & Gen::output_typedefs (ostream &out)
+{
+ FunctionSPtr main = functions.front ();
+
+ if (knobs.standalone())
+ {
+ out << "\n\nstruct PS_OUTPUT\n{\n";
+ unsigned k = 0;
+ for (TypeList::const_iterator i = main->ret_type.begin ();
+ i != main->ret_type.end ();
+ i++)
+ {
+ out << *i << " color" << k << " :" << "COLOR" << k << ";\n";
+ k++;
+ }
+ out << "};\n";
+ }
+#if 0
+ else
+ {
+ out << "#ifdef STANDALONE_DEFS\n"
+ << "#define D_IN(t,name) in t name\n"
+ << "#define D_OUT(t,name) out t name\n"
+ << "#define D_INOUT(t,name) inout t name\n"
+ << "#define D_VPOS : VPOS\n"
+ << "#define D_COLOR0 : COLOR0\n"
+ << "#define D_COLOR1 : COLOR1\n"
+ << "#define D_COLOR2 : COLOR2\n"
+ << "#define D_COLOR3 : COLOR3\n"
+ "\n\nstruct PS_OUTPUT\n{\n";
+
+ unsigned k = 0;
+
+ for (TypeList::const_iterator i = main->ret_type.begin ();
+ i != main->ret_type.end ();
+ i++)
+ {
+ out << *i << " color" << k << " " << "D_COLOR" << k << ";\n";
+ k++;
+ }
+ out << "};\n"
+ << "#endif\n"
+ << "#ifdef WRAPPED_DEFS\n"
+ << "#define D_IN(t,name) t name\n"
+ << "#define D_OUT(t,name) t&name\n"
+ << "#define D_INOUT(t,name) t&name\n"
+ << "etc etc\n"
+ << "#include \"something here\"\n"
+ << "#endif\n";
+ }
+#endif
+
+ return out;
+}
+
+// Create a new and unique name of the right type in the symbol table
+Decl Gen::new_variable (Scope scope,
+ Type type,
+ Kind k,
+ const Context &ctx)
+{
+ return k == Initialized
+ ? new_initialized_variable (scope, type, ctx)
+ : new_uninitialized_variable (scope, type);
+}
+
+Decl Gen::new_variable (Scope scope,
+ const TypeList & type)
+{
+ Decl newdecl = Decl (scope, Struct);
+ // We ignore the type, there's only one struct.
+ (void) type;
+ symtable.push_back (newdecl);
+ return newdecl;
+}
+
+Decl Gen::new_uninitialized_variable (Scope scope,
+ Type type,
+ unsigned idx)
+{
+ Decl newdecl = Decl (scope, type, idx);
+ symtable.push_back (newdecl);
+ return newdecl;
+}
+
+Decl Gen::new_uninitialized_variable (Scope scope,
+ Type type)
+{
+ Decl newdecl = Decl (scope, type);
+ symtable.push_back (newdecl);
+ return newdecl;
+}
+
+Decl Gen::new_initialized_variable (Scope scope,
+ Type type,
+ const Context &ctx)
+{
+ Decl newdecl = Decl (scope, type, create_expression (this, type, ctx));
+ symtable.push_back (newdecl);
+ return newdecl;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Contexts
+// A context is a structure which describes the conditions under something else
+// is being run. An expression can use the context to work out if it is in a
+// for loop or which function it's in.
+
+Context::Context (unsigned _owner,
+ ForSPtr _loop,
+ UList *_samplers,
+ FunctionList *_callees)
+
+ : func (_owner), loop (_loop) , depth (0), relop_p (false),
+ samplers (_samplers),
+ callees (_callees)
+{
+}
+
+Context Context::deeper () const
+{
+ Context res = *this;
+ res.depth++;
+ return res;
+}
+
+Context Context::relop () const
+{
+ Context res =deeper ();
+ res.relop_p = true;
+ return res;
+}
+
+Decl Gen::gen_array_decl (Type t,
+ const Context &ctx,
+ Dir d)
+{
+ if (knobs.array_reuse (&rand))
+ {
+ DeclVec::iterator i = existing_decl (t, ctx, d);
+ if (i != symtable.end ())
+ {
+ return *i;
+ }
+ }
+ return new_uninitialized_variable (Scope (Uniform), t);
+}
+
+Decl Gen::fetch_decl (Type t, const Context & ctx, Kind k, Dir dir)
+{
+ if (knobs.variable_reuse (&rand))
+ {
+ DeclVec::iterator i = existing_decl (t, ctx, dir);
+ if (i != symtable.end ())
+ {
+ return *i;
+ }
+ }
+ return new_variable (Scope (Static, ctx.func), t, k, ctx);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Simply reformat the output to make it look pretty.
+
+class Reformat
+{
+ string res;
+ string pending_line;
+ std::vector <unsigned> indent_stack;
+ unsigned last_indent;
+ bool pending_nl;
+ char prev_char;
+ char this_char;
+ bool had_open_p;
+ bool had_eq;
+ unsigned raw_line_length;
+ string tab ()
+ {
+ string t;
+ unsigned i;
+ for (i = 0; i < last_indent; i++)
+ {
+ t += " ";
+ }
+ return t;
+ }
+ void write (string x)
+ {
+ pending_line += x;
+ }
+ unsigned pos_on_line ()
+ {
+ return last_indent + pending_line.size ();
+ }
+ void flush_pending_line ()
+ {
+ if (!pending_line.empty ())
+ {
+ res += tab ();
+ res += pending_line;
+ res += "\n";
+ pending_line = "";
+ }
+ pending_nl = false;
+ had_open_p = false;
+ raw_line_length = 0;
+ last_indent = indent_stack.back ();
+ }
+ void tabout_and_writeln (string x)
+ {
+ tab ();
+ write (x);
+ write ("\n");
+ }
+public:
+ Reformat (string src) : res (""),
+ pending_line (""),
+ last_indent (0),
+ pending_nl (false),
+ prev_char (' '),
+ this_char (' '),
+ had_open_p (false),
+ had_eq (false),
+ raw_line_length (0)
+
+ {
+ indent_stack.push_back (0);
+ prev_char = '\n';
+ for (string::iterator p = src.begin (); p != src.end (); p++)
+ {
+ this_char = *p;
+
+ if (raw_line_length == 0)
+ {
+ raw_line_length = last_indent;
+ for (string::iterator q = p;
+ q != src.end () && *q != '\n';
+ q++)
+ {
+ raw_line_length++;
+ }
+ }
+
+ switch (this_char)
+ {
+ case '{':
+ flush_pending_line ();
+ pending_line = "{";
+ flush_pending_line ();
+ prev_char = this_char;
+ last_indent = indent_stack.back () + 2;
+ indent_stack.push_back (last_indent);
+ break;
+ // fall
+ case '(':
+ if (raw_line_length > 80 && pos_on_line () > 70)
+ {
+ flush_pending_line ();
+ }
+
+ if (pos_on_line () < 30)
+ {
+ indent_stack.push_back (pos_on_line ());
+ }
+ else
+ {
+ indent_stack.push_back (indent_stack.back ()+1);
+ }
+ pending_line += this_char;
+ prev_char = this_char;
+
+ break;
+
+ case '}':
+
+ flush_pending_line ();
+ indent_stack.pop_back ();
+ pending_line = "}";
+ last_indent = indent_stack.back ();
+ flush_pending_line ();
+
+
+ prev_char = '\n';
+ break;
+
+ case ')':
+ prev_char = this_char;
+ indent_stack.pop_back ();
+ pending_line += this_char;
+ break;
+ case '\n':
+ pending_nl = false;
+ flush_pending_line ();
+ prev_char = this_char;
+ break;
+ case ' ':
+ if (prev_char == ' '
+ || prev_char == '('
+ || prev_char == '\n'
+ || prev_char == '{')
+ {
+ break;
+ }
+ pending_line += this_char;
+ prev_char = this_char;
+ break;
+
+ case ';':
+ pending_line += this_char;
+ prev_char = this_char;
+ if (had_eq)
+ {
+ had_eq = false;
+ indent_stack.pop_back ();
+ }
+ break;
+
+ case '=':
+ pending_line += this_char;
+ prev_char = this_char;
+ if (!had_eq)
+ {
+ had_eq = true;
+ indent_stack.push_back (indent_stack.back () + 4);
+ }
+
+ break;
+
+ default:
+ // no need to break line if we know it will fit
+
+ if (raw_line_length > 80) {
+ if (prev_char == ' '
+ && (!isalpha (this_char))
+ && (!isdigit (this_char))
+ && pos_on_line () > 60)
+ {
+ flush_pending_line ();
+ }
+ else
+ if ( (prev_char == ' '
+ && pos_on_line () > 100)
+ || pending_nl)
+ {
+ flush_pending_line ();
+ }
+ }
+ if (prev_char == ';')
+ {
+ pending_line += ' ';
+ }
+
+ pending_line += this_char;
+ prev_char = this_char;
+ break;
+ }
+ }
+ flush_pending_line ();
+ }
+ string str ()
+ {
+ return res;
+ }
+};
+
+ostream &
+Gen::output_boiler_plate (ostream &out) const
+{
+ // isnan functions
+ out <<
+ "float isnan1 (float a)\n"
+ "{\n"
+ "return ((a<0) && (a>0));"
+ "}\n"
+ "float2 isnan2 (float2 a)\n"
+ "{\n"
+ "return ((a<0) && (a>0));"
+ "}\n"
+ "float4 isnan4 (float4 a)\n"
+ "{\n"
+ "return ((a<0) && (a>0));"
+ "}\n";
+
+ out <<
+ "float4 quick_mod (float4 a, float4 b)\n"
+ "{\n"
+ "float4 d = a / b;\n"
+ "float4 q = d - frac (d);\n"
+ "float4 r = a - q * b;\n"
+ "r -= frac(r);\n"
+ "return isnan4 (r) ? 0 : r;\n"
+ "}\n"
+ "float opcond(float x, float y, float z)\n"
+ "{\n"
+ "return x ? y : z;\n"
+ "}\n"
+ "float2 opcond2(float2 x, float2 y, float2 z)\n"
+ "{\n"
+ "return x ? y : z;\n"
+ "}\n"
+ "float4 opcond4(float4 x, float4 y, float4 z)\n"
+ "{\n"
+ "return x ? y : z;\n"
+ "}\n";
+
+ static char * floats[2][4] =
+ { { "float", "float2", "float4", 0},
+ {"1", "2", "4", 0} };
+ static char * ops[2][9] =
+ { {"lt", "le", "gt", "ge", "eq", "ne", "and", "or", 0},
+ {"<", "<=", ">", ">=", "==", "!=", "&&", "||", 0} };
+
+ for (unsigned i = 0; floats[0][i]; i++)
+ {
+ for (unsigned t = 0; ops[0][t]; t++)
+ {
+ out << floats[0][i] << " op" << ops[0][t] << floats[1][i]
+ << "(" << floats[0][i] << " a, " << floats[0][i] << " b) "
+ << "{ return isnan" << floats[1][i] << " (a) ? 0 : (isnan"
+ << floats[1][i] << " (b) ? 0 : (a" << ops[1][t] << "b));\n}";
+ }
+
+ }
+ return out;
+}
+
+std::ostream & operator << (std::ostream &out, const FunctionSPtr&x)
+{
+ x->output_code (out);
+ return out;
+}
+
+std::ostream & operator << (std::ostream &out,
+ const Program &functions)
+{
+ std::copy (functions.rbegin (),
+ functions.rend (),
+ std::ostream_iterator<FunctionSPtr> (out,"\n"));
+ return out;
+}
+
+std::ostream & operator << (std::ostream &out, gspair x)
+{
+ x.first->output_declarations (out, x.second);
+ return out;
+}
+
+static OutputInfo::ArgSize translate_type (Type t)
+{
+ switch (t.type)
+ {
+ case Float4:
+ return OutputInfo::Float4;
+ case Float2:
+ return OutputInfo::Float2;
+ case Float:
+ return OutputInfo::Float1;
+ case NoType:
+ case Int:
+ case Int4:
+ case SamplerFloat4:
+ case SamplerSize:
+ case Struct:
+ case Float4ConstArray:
+ case Float4Array:
+ default:
+ PURITAN_ABORT ("Unexpected type " << t.type);
+ break;
+ }
+}
+
+string Gen::generate (OutputInfo *output_info)
+{
+ ostringstream output_stream;
+ ostringstream comments;
+
+ // Reset the declaration counter so names start at 0 for each new file.
+ Decl::reset ();
+
+ declare_samplers ();
+ create_call_structure ();
+ create_control_structure ();
+
+ output_typedefs (output_stream);
+
+ output_stream << gspair (this, Scope (Sampler))
+ << gspair (this, Scope (Uniform))
+ << gspair (this, Scope (StaticConstArrays));
+
+ output_boiler_plate (output_stream);
+
+ output_stream << functions
+ << "/* cn=" << code_nodes << " en=" << exp_nodes << "*/\n";
+
+ comments << "/*\n" << knobs << "*/\n"
+ << "/*\n Coverage to this point\n"
+ << *Coverage::head
+ << "*/\n";
+
+ Reformat reformatted (output_stream.str ());
+
+
+ // Fill in the output description with what we've been up to.
+ if (output_info)
+ {
+ output_info->n_samplers = n_samplers;
+
+ PURITAN_ASSERT (output_info->uniforms.empty(),"Incorrect start state");
+ PURITAN_ASSERT (output_info->returns.empty(), "Incorrect start state");
+
+ FunctionSPtr func = functions[0];
+
+ for (TypeList::const_iterator i = func->ret_type.begin();
+ i != func->ret_type.end();
+ i++)
+ {
+ output_info->returns.push_front (translate_type (*i));
+ }
+
+ for (std::vector<std::pair <Type, string> >::const_iterator
+ i = uniforms.begin();
+ i != uniforms.end();
+ i++)
+ {
+ std::pair <OutputInfo::ArgSize, std::string>
+ x(translate_type (i->first), i->second);
+ output_info->uniforms.push_front (x);
+ }
+ }
+ return comments.str () + reformatted.str ();
+}
+
+Gen::Gen (Knobs & _config)
+ :
+ rand (_config.seed.get ()),
+ knobs (_config),
+ exp_nodes (0),
+ code_nodes (0),
+ max_funcs (coverage (knobs.func_count, &cfunc_count)),
+ n_samplers (coverage (knobs.sampler_count, &csampler_count)),
+ n_uniforms (coverage (knobs.uniform_count, &cuniform_count))
+{
+
+}
+
+
+// Return iterator pointing to an existing decl with the suggested type and
+// visible in the context. If it's an argument formal make sure that the
+// direction of intended action is ok.
+DeclVec::iterator Gen::existing_decl (Type t,
+ const Context &ctx,
+ Dir d)
+{
+ size_t length = symtable.size ();
+ size_t scan_from = rand.srange (0, length);
+
+ // Scan from the middle somewhere, and if that doesn't find
+ // anything, start again at the start.
+
+ DeclVec::iterator starts[2] =
+ { symtable.begin () + scan_from, symtable.begin()};
+ DeclVec::iterator ends[2] =
+ { symtable.end(), symtable.begin() + scan_from };
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ for (DeclVec::iterator res = starts[i];
+ res != ends[i];
+ res++)
+ {
+ // It's usable if we're writing, or it's initialized, or an
+ // incoming argument. Also, check if assignments it are allowed, if
+ // we are writing.
+ if (res->type == t
+ && res->scope.visible_in (ctx, d)
+ && (res->initializer.get()
+ || d == Write
+ || res->scope.scope == Argument_I
+ || res->scope.scope == Argument_IO)
+ && (!res->noWrites || d == Read))
+ {
+ return res;
+ }
+ }
+ }
+ return symtable.end ();
+}
+
+
+unsigned Decl::counter = 0;
+
+Decl::Decl () : scope (NoScope), type (NoType), idx (0), noWrites (false)
+{
+}
+
+Decl::Decl (bool) : scope (NoScope), type (NoType), idx (0), noWrites (false)
+{
+}
+
+Decl::Decl (Scope _scope,
+ Type _type)
+ : scope (_scope), type (_type), idx (++counter), noWrites (false)
+{
+}
+
+Decl::Decl (Scope _scope,
+ Type _type,
+ unsigned _idx)
+ : scope (_scope), type (_type), idx (_idx), noWrites (false)
+{
+}
+
+
+// Return a number according to the knob range, and increment the coverage
+// counter for it.
+int Gen::coverage (const RangeKnob &knob,
+ IntCoverage *marker)
+{
+ int r = knob (&rand);
+ marker->increment (r);
+ return r;
+}
+
+// As above, but the value is scaled so that minor functions get smaller
+// values.
+int Gen::coverage (unsigned fidx,
+ const RangeKnob &knob,
+ IntCoverage *marker)
+{
+ int r = knob (&rand);
+ if (fidx > 0)
+ {
+ r = (static_cast<int> ( (static_cast<double> (r))
+ * knobs.func_trim.get ()));
+ }
+ marker->increment (r);
+ return r;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Decl class
+// Knows the scope, type, name and initializer of every variable.
+
+Decl::Decl (Scope _scope,
+ Type _type,
+ ENode _init)
+ : scope (_scope),
+ type (_type),
+ initializer (_init),
+ idx (++counter)
+{
+}
+
+void Decl::reset ()
+{
+ Decl::counter = 0;
+}
+
+Scope::Scope (scope_t _scope) : scope (_scope), fnc_idx (0)
+{
+}
+
+std::ostream & operator << (std::ostream &out, const Decl&x)
+{
+ if (x.type == SamplerSize)
+ {
+ out << "in" << x.idx << "_size";
+ }
+ else
+ {
+ out << x.scope.short_name () << x.type.short_name () << x.idx;
+ }
+ return out;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Type
+
+Type::Type () : type (NoType) {}
+Type::Type (enum type _type) : type (_type) {}
+
+enum type Type::operator () () const
+{
+ return type;
+}
+
+bool Type::array_p ()
+{
+ return type == Float4ConstArray
+ || type == Float4Array;
+}
+
+
+std::ostream & operator << (std::ostream &out, Type x)
+{
+ const char *w;
+ switch (x.type)
+ {
+ case Int:
+ w= "int";
+ break;
+ case Int4:
+ w="int4";
+ break;
+ case Float:
+ w= "float";
+ break;
+ case Float2:
+ w= "float2";
+ break;
+ case Float4:
+ case SamplerSize:
+ w= "float4";
+ break;
+ case Float4ConstArray:
+ w ="floatc4x40";
+ break;
+ case Float4Array:
+ w = "floatv4x40";
+ break;
+ case Struct:
+ w = "struct PS_OUTPUT";
+ break;
+ default:
+ case NoType:
+ case SamplerFloat4:
+ PURITAN_ABORT ("Argument error" << x.type);
+ }
+ return (out << w);
+
+}
+
+string Type::short_name () const
+{
+ switch (type)
+ {
+ case Int:
+ return "i_";
+ case Int4:
+ return "i4_";
+ case Float:
+ return "f1_";
+ case Float2:
+ return "f2_";
+ case Float4:
+ return "f4_";
+ case Float4ConstArray:
+ return "carray_";
+ case Float4Array:
+ return "farray_";
+ case SamplerFloat4:
+ return "";
+ case Struct:
+ return "s_";
+ default:
+ case NoType:
+ case SamplerSize:
+ PURITAN_ABORT ("Argument error:" << type);
+ }
+}
+
+string Type::suffix_name () const
+{
+ switch (type)
+ {
+ case Int:
+ return "i";
+ case Int4:
+ return "i4";
+ case Float:
+ return "1";
+ case Float2:
+ return "2";
+ case Float4:
+ return "4";
+ case Float4ConstArray:
+ return "c";
+ case Float4Array:
+ return "f";
+ case SamplerFloat4:
+ return "";
+ case Struct:
+ return "s";
+ default:
+ case NoType:
+ case SamplerSize:
+ PURITAN_ABORT ("Argument error:" << type);
+ }
+}
+
+bool Type::operator != (Type x) const
+{
+ return x.type != type;
+}
+
+bool Type::operator == (Type x) const
+{
+ return x.type == type;
+}
+
+std::ostream & operator << (std::ostream &out, const TypeList &x)
+{
+ PURITAN_ASSERT (x.size () == 1, "Should never be called with a non unary list");
+ out << x.front ();
+ return out;
+}
+
+
+}
+}
+
diff --git a/o3d/compiler/puritan/puritan.h b/o3d/compiler/puritan/puritan.h
new file mode 100644
index 0000000..a9dc409
--- /dev/null
+++ b/o3d/compiler/puritan/puritan.h
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef PURITAN_PURITAN_H
+#define PURITAN_PURITAN_H
+
+#include <string>
+#include <sstream>
+#include <vector>
+#include <list>
+#include "puritan_assert.h"
+#include "rand.h"
+
+#include "puritan_shared_ptr.h"
+
+namespace Salem
+{
+namespace Puritan
+{
+
+class Decl;
+class Exp;
+class For;
+class Function;
+class Gen;
+class IntCoverage;
+class RangeKnob;
+class Scope;
+class Type;
+
+typedef ::shared_ptr<Exp> ENode;
+typedef ::shared_ptr<For> ForSPtr;
+typedef ::shared_ptr<Function> FunctionSPtr;
+typedef std::list <Decl> DeclList;
+typedef std::list <ENode> EList;
+typedef std::list <FunctionSPtr> FunctionList;
+typedef std::list <Type> TypeList;
+typedef std::list <unsigned> UList;
+typedef std::ostream ostream;
+typedef std::ostringstream ostringstream;
+typedef std::pair <Gen *, Scope> gspair;
+typedef std::string string;
+typedef std::vector <Decl> DeclVec;
+typedef std::vector <FunctionSPtr> Program;
+
+ostream & operator << (ostream &out, Type x);
+ostream & operator << (ostream &out, const Decl& x);
+ostream & operator << (ostream &out, const TypeList & x) ;
+ostream & operator << (ostream &out, gspair x);
+
+const unsigned int array_size = 3;
+
+enum type
+{
+ NoType,
+ Int, Int4,
+ Float, Float2, Float4,
+ SamplerFloat4,
+ SamplerSize,
+ Struct,
+ Float4ConstArray, Float4Array
+};
+
+class Type
+{
+public:
+ enum type type;
+ string name () const;
+ string short_name () const;
+ string suffix_name () const;
+ bool array_p ();
+ enum type operator () () const;
+ Type (enum type);
+ Type (); // default ctor for use with STL containers
+ bool operator == (Type) const;
+ bool operator != (Type) const;
+ unsigned struct_elements ();
+};
+
+typedef enum
+{
+ NoScope,
+ StaticConstArrays,
+ Sampler,
+ Uniform,
+ Static,
+ Argument_I,
+ Argument_O,
+ Argument_IO
+} scope_t;
+
+typedef enum
+{
+ Initialized,
+ Uninitialized
+} Kind;
+
+typedef enum
+{
+ Read,
+ Write,
+ ReadWrite
+} Dir;
+
+// Scope of a name.
+class Scope
+{
+public:
+ scope_t scope;
+ unsigned fnc_idx;
+
+ Scope (scope_t x) ;
+ Scope (scope_t x, unsigned fnc_idx) ;
+
+ bool eq (const Scope&other) const;
+ string name () const;
+ string short_name () const;
+ bool visible_in (const class Context & ctx, Dir d) const;
+};
+
+// Declarations - scope, type and name.
+class Decl
+{
+ static unsigned counter;
+
+public:
+ Scope scope;
+ Type type;
+ ENode initializer;
+
+ // use the creation index as the root of the name
+ unsigned idx;
+
+ // certain variables should be made unavailable for general assignments
+ // - for example, loop counters are modified by special
+ // increment/decrement statements and should not be modified elsewhere
+ bool noWrites;
+
+ Decl (Scope, Type type);
+ Decl (Scope, Type type, ENode init);
+ Decl (Scope, Type type, unsigned idx);
+ Decl (bool);
+ Decl (); // default ctor for use with STL containers
+ bool same ();
+ static void reset ();
+};
+
+// A context passes information about what we're doing down through the
+// recursive decent generator
+
+class Context
+{
+public:
+ unsigned func;
+ ForSPtr loop;
+ unsigned depth;
+ bool relop_p;
+
+ UList *samplers;
+ FunctionList *callees;
+
+ Context relop () const;
+ Context deeper () const;
+
+ Context (unsigned _owner,
+ ForSPtr _loop,
+ UList *samplers,
+ FunctionList *callees);
+};
+
+class Gen
+{
+private:
+ friend class Exp;
+ typedef enum { TokFor, TokWhile, TokDo, TokAssign,
+ TokSelfMod, TokReturn, TokIf, TokBlock,
+ TokClose, TokBreak } Token;
+ typedef std::vector <Token> TokenVec;
+ Rand rand;
+ class Knobs & knobs;
+ std::vector < std::pair < Type, std::string > > uniforms;
+ unsigned exp_nodes;
+ unsigned code_nodes;
+ unsigned max_funcs;
+ unsigned n_samplers;
+ unsigned n_uniforms;
+
+ Program functions;
+ std::vector <FunctionList> callees;
+ DeclVec symtable;
+
+ void create_control_structure ();
+ void create_call_structure ();
+ void declare_samplers ();
+
+
+ Decl gen_array_decl (Type t, const Context &ctx, Dir d);
+ Decl fetch_decl (Type t,const Context &ctx, Kind k, Dir d);
+ Decl new_variable (Scope scope, Type type, Kind k, const Context &c);
+ Decl new_variable (Scope scope, const TypeList & type);
+ Decl new_initialized_variable (Scope scope, Type type, const Context &c);
+ Decl new_uninitialized_variable (Scope s, Type c, unsigned idx);
+ Decl new_uninitialized_variable (Scope s, Type c);
+ DeclVec::iterator existing_decl (Type t, const Context &ctx, Dir d);
+
+ char rchar (const char *what);
+ ostream & output_boiler_plate (ostream &out) const;
+ int coverage (const RangeKnob &knob, IntCoverage *marker);
+ int coverage (unsigned fidx, const RangeKnob &knob, IntCoverage *marker) ;
+ unsigned ins_stmts (TokenVec *v, unsigned c,
+ unsigned n, Token t,
+ unsigned e, bool break_p);
+ void output_code (ostream &out, const Program &functions);
+ void output_declarations (ostream &out, Scope s);
+ ostream &output_typedefs (ostream &out);
+
+ string gen_fconstant ();
+ Type random_type ();
+
+ friend ostream & operator << (ostream &out, gspair x);
+ friend ENode create_expression (Gen *gen, Type rtype, const Context &ctx);
+public:
+ Gen (Knobs & _config);
+ string generate (class OutputInfo *output);
+};
+
+}
+}
+
+#endif
diff --git a/o3d/compiler/puritan/puritan_assert.cc b/o3d/compiler/puritan/puritan_assert.cc
new file mode 100644
index 0000000..0b648af
--- /dev/null
+++ b/o3d/compiler/puritan/puritan_assert.cc
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "puritan_assert.h"
+#include <iostream>
+#ifdef __GNUC__
+namespace Salem
+{
+namespace Puritan
+{
+#endif
+void puritan_assert_worker (const char *file, const char *func, unsigned line, const std::string &message)
+{
+ std::cerr << "Fatal error [" << file << ":" << func << ":" << line << "] " << message << "\n";
+ exit (1);
+}
+
+#ifdef __GNUC__
+}
+}
+#endif
+
diff --git a/o3d/compiler/puritan/puritan_assert.h b/o3d/compiler/puritan/puritan_assert.h
new file mode 100644
index 0000000..0e03e73
--- /dev/null
+++ b/o3d/compiler/puritan/puritan_assert.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef PURITAN_ASSERT_H
+#define PURITAN_ASSERT_H
+
+#include <string>
+#include <sstream>
+
+#ifndef __GNUC__
+
+// MSVC and GCC are different - MSVC needs assert worker to be at the top level
+// for boost to compile. GCC does not. I don't know which is correct
+
+__declspec (noreturn) void puritan_assert_worker (const char *,
+ const char *,
+ unsigned,
+ const std::string &);
+namespace Salem { namespace Puritan {
+#else
+namespace Salem { namespace Puritan {
+
+void puritan_assert_worker (const char *,
+ const char *,
+ unsigned,
+ const std::string &) __attribute__((noreturn));
+
+#endif
+
+
+#define PURITAN_ABORT(message) \
+do { \
+ std::ostringstream message_buf; \
+ message_buf << message; \
+ puritan_assert_worker (__FILE__, \
+ __FUNCTION__, \
+ __LINE__, \
+ message_buf.str()); \
+} while (0)
+
+#define PURITAN_ASSERT(check, message) \
+do { \
+ if (!(check)) \
+ { \
+ PURITAN_ABORT(message); \
+ } \
+} while (0)
+
+#undef assert
+#define assert(x) PURITAN_ASSERT(x,"")
+}
+}
+
+#endif
diff --git a/o3d/compiler/puritan/puritan_shared_ptr.h b/o3d/compiler/puritan/puritan_shared_ptr.h
new file mode 100644
index 0000000..ce1fa58
--- /dev/null
+++ b/o3d/compiler/puritan/puritan_shared_ptr.h
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// A simple reference counted pointer implementation. It is a subset
+// of the boost/tr1 shared_ptr class, which is expected to be part of
+// the next C++ standard. See section 20.6.6 [util.smartptr] of the
+// draft standard for a full description of the standard interface.
+//
+// The following standard features have been omitted from this implementation:
+// - no custom deallocators - uses delete
+// - no support for enable_shared_from_this
+// - no support for smart pointer casts
+// - no support for features that rely on variadic templates
+// - not exception-safe
+// - no overloaded comparison operators (e.g. operator<). They're
+// convenient, but they can be explicitly defined outside the class.
+//
+
+#ifndef UTIL_GTL_PURITAN_SHARED_PTR_H__
+#define UTIL_GTL_PURITAN_SHARED_PTR_H__
+
+#include <algorithm> // for swap
+
+template <typename T> class shared_ptr;
+template <typename T> class weak_ptr;
+
+// This class is an internal implementation detail for shared_ptr.
+//
+class SharedPtrControlBlock {
+ template <typename T> friend class shared_ptr;
+ template <typename T> friend class weak_ptr;
+ private:
+ SharedPtrControlBlock() : refcount_(1), weak_count_(1) { }
+ int refcount_;
+ int weak_count_;
+};
+
+template <typename T>
+class shared_ptr {
+ template <typename U> friend class weak_ptr;
+ public:
+ typedef T element_type;
+
+ explicit shared_ptr(T* ptr = NULL)
+ : ptr_(ptr),
+ control_block_(ptr != NULL ? new SharedPtrControlBlock : NULL) {
+ }
+
+ // Copy constructor: makes this object a copy of ptr
+ template <typename U>
+ shared_ptr(const shared_ptr<U>& ptr)
+ : ptr_(NULL),
+ control_block_(NULL) {
+ Initialize(ptr);
+ }
+ // Need non-templated version to prevent the compiler-generated default
+ shared_ptr(const shared_ptr<T>& ptr)
+ : ptr_(NULL),
+ control_block_(NULL) {
+ Initialize(ptr);
+ }
+
+ // Assignment operator. Replaces the existing shared_ptr with ptr.
+ template <typename U>
+ shared_ptr<T>& operator=(const shared_ptr<U>& ptr) {
+ if (ptr_ != ptr.ptr_) {
+ shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
+ swap(me);
+ }
+ return *this;
+ }
+
+ // Need non-templated version to prevent the compiler-generated default
+ shared_ptr<T>& operator=(const shared_ptr<T>& ptr) {
+ if (ptr_ != ptr.ptr_) {
+ shared_ptr<T> me(ptr); // will hold our previous state to be destroyed.
+ swap(me);
+ }
+ return *this;
+ }
+
+ ~shared_ptr() {
+ if (ptr_ != NULL) {
+ if (--control_block_->refcount_ == 0) {
+ delete ptr_;
+
+ // weak_count_ is defined as the number of weak_ptrs that observe
+ // ptr_, plus 1 if refcount_ is nonzero.
+ if (--control_block_->weak_count_ == 0) {
+ delete control_block_;
+ }
+ }
+ }
+ }
+
+ // Replaces underlying raw pointer with the one passed in. The reference
+ // count is set to one (or zero if the pointer is NULL) for the pointer
+ // being passed in and decremented for the one being replaced.
+ void reset(T* p = NULL) {
+ if (p != ptr_) {
+ shared_ptr<T> tmp(p);
+ tmp.swap(*this);
+ }
+ }
+
+ // Exchanges the contents of this with the contents of r. This function
+ // supports more efficient swapping since it eliminates the need for a
+ // temporary shared_ptr object.
+ void swap(shared_ptr<T>& r) {
+ std::swap(ptr_, r.ptr_);
+ std::swap(control_block_, r.control_block_);
+ }
+
+ // The following function is useful for gaining access to the underlying
+ // pointer when a shared_ptr remains in scope so the reference-count is
+ // known to be > 0 (e.g. for parameter passing).
+ T* get() const {
+ return ptr_;
+ }
+
+ T& operator*() const {
+ return *ptr_;
+ }
+
+ T* operator->() const {
+ return ptr_;
+ }
+
+ long use_count() const {
+ return control_block_ ? control_block_->refcount_ : 1;
+ }
+
+ bool unique() const {
+ return use_count() == 1;
+ }
+
+ private:
+ // If r is non-empty, initialize *this to share ownership with r,
+ // increasing the underlying reference count.
+ // If r is empty, *this remains empty.
+ // Requires: this is empty, namely this->ptr_ == NULL.
+ template <typename U>
+ void Initialize(const shared_ptr<U>& r) {
+ if (r.control_block_ != NULL) {
+ ++r.control_block_->refcount_;
+
+ ptr_ = r.ptr_;
+ control_block_ = r.control_block_;
+ }
+ }
+
+ T* ptr_;
+ SharedPtrControlBlock* control_block_;
+
+ template <typename U>
+ friend class shared_ptr;
+};
+
+// Matches the interface of std::swap as an aid to generic programming.
+template <typename T> void swap(shared_ptr<T>& r, shared_ptr<T>& s) {
+ r.swap(s);
+}
+
+// See comments at the top of the file for a description of why this
+// class exists, and the draft C++ standard (as of October 2007 the
+// latest draft is N2461) for the detailed specification.
+template <typename T>
+class weak_ptr {
+ template <typename U> friend class weak_ptr;
+ public:
+ typedef T element_type;
+
+ // Create an empty (i.e. already expired) weak_ptr.
+ weak_ptr() : ptr_(NULL), control_block_(NULL) { }
+
+ // Create a weak_ptr that observes the same object that ptr points
+ // to. Note that there is no race condition here: we know that the
+ // control block can't disappear while we're looking at it because
+ // it is owned by at least one shared_ptr, ptr.
+ template <typename U> weak_ptr(const shared_ptr<U>& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Copy a weak_ptr. The object it points to might disappear, but we
+ // don't care: we're only working with the control block, and it can't
+ // disappear while we're looking at because it's owned by at least one
+ // weak_ptr, ptr.
+ template <typename U> weak_ptr(const weak_ptr<U>& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Need non-templated version to prevent default copy constructor
+ weak_ptr(const weak_ptr& ptr) {
+ CopyFrom(ptr.ptr_, ptr.control_block_);
+ }
+
+ // Destroy the weak_ptr. If no shared_ptr owns the control block, and if
+ // we are the last weak_ptr to own it, then it can be deleted. Note that
+ // weak_count_ is defined as the number of weak_ptrs sharing this control
+ // block, plus 1 if there are any shared_ptrs. We therefore know that it's
+ // safe to delete the control block when weak_count_ reaches 0, without
+ // having to perform any additional tests.
+ ~weak_ptr() {
+ if (control_block_ != NULL &&
+ (--control_block_->weak_count_) == 0) {
+ delete control_block_;
+ }
+ }
+
+ weak_ptr& operator=(const weak_ptr& ptr) {
+ if (&ptr != this) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ }
+ return *this;
+ }
+ template <typename U> weak_ptr& operator=(const weak_ptr<U>& ptr) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ return *this;
+ }
+ template <typename U> weak_ptr& operator=(const shared_ptr<U>& ptr) {
+ weak_ptr tmp(ptr);
+ tmp.swap(*this);
+ return *this;
+ }
+
+ void swap(weak_ptr& ptr) {
+ ::swap(ptr_, ptr.ptr_);
+ ::swap(control_block_, ptr.control_block_);
+ }
+
+ void reset() {
+ weak_ptr tmp;
+ tmp.swap(*this);
+ }
+
+ // Return the number of shared_ptrs that own the object we are observing.
+ // Note that this number can be 0 (if this pointer has expired).
+ long use_count() const {
+ return control_block_ != NULL ? control_block_->refcount_ : 0;
+ }
+
+ bool expired() const { return use_count() == 0; }
+
+ private:
+ void CopyFrom(T* ptr, SharedPtrControlBlock* control_block) {
+ ptr_ = ptr;
+ control_block_ = control_block;
+ if (control_block_ != NULL)
+ ++control_block_->weak_count_;
+ }
+
+ private:
+ element_type* ptr_;
+ SharedPtrControlBlock* control_block_;
+};
+
+template <typename T> void swap(weak_ptr<T>& r, weak_ptr<T>& s) {
+ r.swap(s);
+}
+
+#endif // UTIL_GTL_PURITAN_SHARED_PTR_H__
diff --git a/o3d/compiler/puritan/rand.cc b/o3d/compiler/puritan/rand.cc
new file mode 100644
index 0000000..7a4775b
--- /dev/null
+++ b/o3d/compiler/puritan/rand.cc
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include <cstddef>
+#include <iostream>
+#include "rand.h"
+#include "puritan_assert.h"
+
+namespace Salem
+{
+namespace Puritan
+{
+static const unsigned a = 1103515245 ;
+static const unsigned b = 12345;
+
+// Convention:
+// If seed passed in is zero, this class will use the strong random number
+// generator from crypto API via CryptGenRandom()
+// Otherwise fallback to the linear-congruential generator.
+Rand::Rand (unsigned seed) : y (seed+1231)
+{
+ crypt_provider_ = NULL;
+ available_ = 0;
+ if (seed == 0)
+ InitializeProvider();
+}
+
+unsigned Rand::rnd_uint(void)
+{
+ unsigned result = 0;
+ // If there is no provider, use the LCG.
+ if (crypt_provider_ == NULL) {
+ y = (a * y + b);
+ result = y >> 4;
+ }
+#ifdef _WIN32
+ // The following code is used for improved random-number generation.
+ // TODO: Investigate use of openssl, which may do this on all
+ // platforms, but will still require platform-specific seeding.
+ else {
+ // Maintain a cache of random values by getting a large batch
+ // on each call, since calling CryptGenRandom() is expensive.
+ // Note: This code is not thread-safe, neither is the original LCG.
+ // Use InterlockedDecrement/CompareXchg etc. if that has to change.
+ long chosen_index = --available_;
+
+ if (chosen_index < 0) {
+ // We are out of values, time to replenish the cache.
+ ::CryptGenRandom(crypt_provider_, sizeof(cached_numbers_),
+ reinterpret_cast<BYTE*>(cached_numbers_));
+ available_ = kCacheSize;
+ chosen_index = --available_;
+ }
+
+ result = cached_numbers_[chosen_index];
+ }
+#endif
+
+ return result;
+}
+
+double Rand::rnd_flt()
+{
+ unsigned r = rnd_uint();
+ // We don't ask for the full range of random numbers because
+ // I see different rounding behavior on different machines at the limit.
+ unsigned mask = 0xffffff;
+ unsigned div = mask + 1;
+ double dr = r & mask;
+ double res = dr / div;
+ return res;
+}
+
+int Rand::range (int from, int to)
+{
+ PURITAN_ASSERT (from <= to, "Range is malformed");
+ if (from == to)
+ {
+ return from;
+ }
+ double x = (rnd_flt ()) * (to - from) + from;
+ int r = static_cast <int>(x);
+ return r;
+}
+
+unsigned Rand::urange (unsigned from, unsigned to)
+{
+ return range (from, to);
+}
+
+size_t Rand::srange (size_t from, size_t to)
+{
+ return range (static_cast <int>(from),
+ static_cast <int>(to));
+}
+
+// Return random string from list of strings.
+const char *Rand::from_list (const char **list)
+{
+ unsigned int i;
+ for (i = 0; list[i]; i++)
+ ;
+ unsigned rn = range (0, i);
+ return list[rn];
+}
+
+bool Rand::InitializeProvider() {
+#ifdef _WIN32
+ int result = ::CryptAcquireContext(& crypt_provider_, NULL, NULL,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT);
+ return (result != 0);
+#else
+ // If there is no cryptographic PRNG, this is a noop.
+ return true;
+#endif
+}
+
+}
+}
diff --git a/o3d/compiler/puritan/rand.h b/o3d/compiler/puritan/rand.h
new file mode 100644
index 0000000..d5804c0
--- /dev/null
+++ b/o3d/compiler/puritan/rand.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef PURITAN_RAND_H
+#define PURITAN_RAND_H
+
+// Use a strong RNG if available.
+// TODO: Investigate using openssl on all platforms.
+#ifdef _WIN32
+#include <windows.h>
+#include <wincrypt.h>
+#else
+typedef void* HCRYPTPROV;
+#endif
+
+
+namespace Salem
+{
+namespace Puritan
+{
+
+class Rand
+{
+public:
+ unsigned y;
+ unsigned rnd_uint(void) ;
+ Rand(unsigned seed);
+ double rnd_flt(void);
+ int range(int lo, int hi);
+ unsigned urange(unsigned lo, unsigned hi);
+ size_t srange(size_t lo, size_t hi);
+ const char *from_list (const char **);
+
+private:
+ bool InitializeProvider();
+
+ HCRYPTPROV crypt_provider_;
+ static const size_t kCacheSize = 0x1000;
+ unsigned int cached_numbers_[kCacheSize];
+ long available_;
+};
+}
+}
+#endif
diff --git a/o3d/compiler/puritan/structure_gen.cc b/o3d/compiler/puritan/structure_gen.cc
new file mode 100644
index 0000000..2be25c7
--- /dev/null
+++ b/o3d/compiler/puritan/structure_gen.cc
@@ -0,0 +1,328 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#include <sstream>
+#include "structure_gen.h"
+#include "exp_gen.h"
+namespace Salem
+{
+namespace Puritan
+{
+class Context;
+
+//////////////////////////////////////////////////////////////////////
+// Blocks
+
+void Block::print_code (ostream &out)
+{
+ print_code_kids (children, out);
+}
+
+void Block::add_child (CodeSPtr x)
+{
+ children.push_back (x);
+}
+
+//////////////////////////////////////////////////////////////////////
+// Functions
+
+Function::Function(Gen *_gen,
+ unsigned _idx,
+ TypeList _ret_type,
+ DeclList _formals,
+ bool _standalone,
+ bool _noinline)
+ : gen (_gen),
+ idx (_idx),
+ ret_type (_ret_type),
+ formals (_formals),
+ standalone (_standalone),
+ noinline (_noinline)
+{
+
+}
+
+void Function::output_code (ostream &out)
+{
+ // main always returns a struct
+ if (idx == 0)
+ {
+ if (standalone)
+ {
+ out << "struct ";
+ }
+
+ out << "PS_OUTPUT main (";
+ }
+ else
+ {
+ if (noinline)
+ {
+ out << "noinline ";
+
+ }
+ out << ret_type << " func" << idx << "(";
+ }
+ unsigned arg_idx = 0;
+
+ for (DeclList::iterator i = formals.begin();
+ i != formals.end();
+ i++, arg_idx++)
+ {
+ if (arg_idx != 0)
+ {
+ out << ", ";
+ }
+
+ out << (*i).type << " " << (*i);
+
+ if (standalone && idx == 0)
+ {
+ out << ":VPOS";
+ }
+ }
+
+ out << ")\n";
+
+
+ ostringstream code;
+
+ for (CodeVec::iterator x = children.begin();
+ x != children.end();
+ x++)
+ {
+ (*x)->print_code (code);
+ }
+
+ // emit the declarations at the top of the function and then the guts.
+ out << "{"
+ << gspair (gen, Scope(Static, idx))
+ << code.str()
+ << "}";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// For loops
+
+For::For(Decl _counter, int _from, int _to)
+ : from (_from), to (_to), counter (_counter)
+{
+
+}
+
+void For::print_code (ostream &out)
+{
+ out << "for (" << counter << " = " << from << ";"
+ << counter << " < " << to <<"; "
+ << counter << "++)\n";
+ print_code_kids (children, out);
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Breaks in loops
+
+Break::Break (ENode _cond)
+ : cond (_cond)
+{
+}
+
+void Break::print_code (ostream &out)
+{
+ out << "if (" << cond << ")\n{ break;}\n";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// While loops
+
+While::While(ENode _cond,
+ Decl _index,
+ unsigned _limit)
+ : cond(_cond),
+ counter (_index),
+ limit (_limit)
+{
+}
+
+void While::print_code (ostream &out)
+{
+ out << counter << " = " << limit << ";\n"
+ << "while (" << counter << "> 0 &&"
+ << cond << ")\n"
+ << "{" << "--" << counter << ";\n";
+
+ for (CodeVec::iterator x = children.begin();
+ x != children.end();
+ x++)
+ {
+ (*x)->print_code (out);
+ }
+
+ out << "}";
+}
+
+//////////////////////////////////////////////////////////////////////
+/// Do loops
+
+Do::Do(ENode _cond, Decl _counter, unsigned _limit)
+ : cond(_cond),
+ counter (_counter),
+ limit (_limit)
+{
+}
+
+void Do::print_code (ostream &out)
+{
+ out << counter << " = " << limit << ";\n"
+ << "do {";
+
+ for (CodeVec::iterator x = children.begin();
+ x != children.end();
+ x++)
+ {
+ (*x)->print_code (out);
+ }
+
+ out << "--" << counter << ";\n"
+ << "} while (" << counter << "> 0 &&"
+ << cond << ");\n";
+}
+
+//////////////////////////////////////////////////////////////////////
+// Ifs
+
+IfTemplate::IfTemplate(ENode _cond, bool _has_else)
+ : cond (_cond),
+ has_else (_has_else),
+ toggle (false)
+{
+}
+
+void IfTemplate::print_code (ostream &out)
+{
+ out << "if (" << cond << ")\n";
+
+ print_code_kids (children, out);
+ if (has_else)
+ {
+ out << "else\n";
+ print_code_kids (other_block, out);
+ }
+
+}
+
+void IfTemplate::add_child (CodeSPtr x)
+{
+ if (toggle && has_else)
+ {
+ other_block.push_back (x);
+ }
+ else
+ {
+ children.push_back (x);
+ }
+
+ toggle = ! toggle;
+}
+
+//////////////////////////////////////////////////////////////////////
+// Return
+
+Return::Return(EList _returns, Decl _name)
+ : returns (_returns),
+ name (_name)
+{
+}
+
+Return::Return(ENode _reta) : name(false)
+{
+ returns.push_back (_reta);
+}
+
+void Return::print_code (ostream &out)
+{
+ if (name.type != NoType)
+ {
+ const char *ext[] = {".color0", ".color1", ".color2", ".color3" };
+ unsigned k = 0;
+ for (EList::const_iterator i = returns.begin();
+ i != returns.end();
+ i++, k++)
+ {
+ out << name << ext[k] << " = " << *i << ";\n";
+ }
+ out << "return " << name << ";\n";
+ }
+ else
+ {
+ out << "return " << returns.front() << ";\n";
+ }
+}
+
+//////////////////////////////////////////////////////////////////////
+// Assignments
+
+AssignmentTemplate::AssignmentTemplate(ENode _terms)
+ : rp (_terms)
+{
+}
+
+void AssignmentTemplate::print_code (ostream &out)
+{
+ out << rp << ";\n";
+}
+
+
+//////////////////////////////////////////////////////////////////////
+// Skeleton base class for all above
+Code::Code()
+{
+}
+
+Code::~Code()
+{
+}
+
+void Code::print_code_kids (CodeVec &children, ostream &out)
+{
+ out << "{";
+ for (CodeVec::iterator x = children.begin();
+ x != children.end();
+ x++)
+ {
+ (*x)->print_code (out);
+ }
+ out << "}";
+}
+
+}
+}
diff --git a/o3d/compiler/puritan/structure_gen.h b/o3d/compiler/puritan/structure_gen.h
new file mode 100644
index 0000000..04f4820
--- /dev/null
+++ b/o3d/compiler/puritan/structure_gen.h
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+
+#ifndef PURITAN_STRUCTUREGEN_H
+#define PURITAN_STRUCTUREGEN_H
+
+#include "puritan.h"
+
+namespace Salem
+{
+namespace Puritan
+{
+typedef ::shared_ptr<class Block> BlockSPtr;
+typedef ::shared_ptr<class Break> BreakSPtr;
+typedef ::shared_ptr<class Code> CodeSPtr;
+typedef ::shared_ptr<class Exp> ENode;
+typedef ::shared_ptr<class For> ForSPtr;
+typedef ::shared_ptr<class Function> FunctionSPtr;
+typedef std::vector <CodeSPtr> CodeVec;
+typedef std::vector <FunctionSPtr> FunctionVec;
+
+
+class Code
+{
+ virtual void print_code (std::ostream &out) = 0;
+
+public:
+ Code ();
+ virtual ~Code();
+
+ void print_code_kids (CodeVec &children, std::ostream &out);
+
+ friend class Function;
+ friend class While;
+ friend class Do;
+};
+
+class Block:public Code
+{
+ void print_code (std::ostream &out);
+
+public:
+ CodeVec children;
+
+ void add_child (CodeSPtr x);
+};
+
+class Function:public Block
+{
+public:
+ class Gen *gen;
+ unsigned idx;
+ TypeList ret_type;
+ DeclList formals;
+ UList samplers;
+ FunctionSPtr calls;
+ std::string name;
+ bool standalone;
+ bool noinline;
+
+ Function(Gen *gen, unsigned _idx,
+ TypeList ret_type,
+ DeclList formals,
+ bool standalone,
+ bool noinline);
+
+ void new_decl (std::string name,
+ Scope scope,
+ FunctionSPtr func,
+ enum type type,
+ std::string init);
+
+ void output_code (std::ostream &out);
+};
+
+
+
+class For : public Block
+{
+
+ int from;
+ int to;
+
+ friend class Index;
+ friend class ConstArrayRef;
+public:
+
+ Decl counter;
+
+ static unsigned fidx;
+ For(Decl counter, int _from, int _to) ;
+
+ void print_code (std::ostream &out);
+};
+
+class Break: public Code
+{
+public:
+ ::shared_ptr<Exp> cond;
+
+ Break (ENode _cond) ;
+ void print_code (std::ostream &out);
+}
+;
+
+
+class While: public Block
+{
+ ENode cond;
+ Decl counter;
+ unsigned limit;
+public:
+ While(ENode _cond,
+ Decl i,
+ unsigned limit) ;
+
+ void print_code (std::ostream &out);
+};
+
+
+class Do: public Block
+{
+ ENode cond;
+ Decl counter;
+ unsigned limit;
+
+public:
+ Do(ENode _cond, Decl counter, unsigned limit) ;
+
+ void print_code (std::ostream &out);
+};
+
+class IfTemplate: public Block
+{
+ ENode cond;
+ bool has_else;
+ bool toggle;
+ CodeVec other_block;
+
+public:
+ IfTemplate(ENode _cond, bool has_else);
+
+ void print_code (std::ostream &out);
+ void add_child (CodeSPtr x);
+};
+
+
+
+class Return : public Code
+{
+public:
+ unsigned struct_elements;
+ EList returns;
+ Decl name;
+
+ Return(ENode _reta) ;
+ Return(EList _returns, Decl name) ;
+
+ void print_code (std::ostream &out);
+};
+
+
+class AssignmentTemplate : public Code
+{
+public:
+ ENode rp;
+ AssignmentTemplate(ENode _terms) ;
+ void print_code (std::ostream &out);
+};
+
+
+}
+}
+#endif
diff --git a/o3d/compiler/puritan/test_gen.cc b/o3d/compiler/puritan/test_gen.cc
new file mode 100644
index 0000000..85916a3
--- /dev/null
+++ b/o3d/compiler/puritan/test_gen.cc
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "puritan.h"
+#include "test_gen.h"
+#include <string>
+
+namespace Salem
+{
+namespace Puritan
+{
+string generate (class OutputInfo *output, Knobs & knobs)
+{
+ class Gen *gen;
+ gen = new Gen (knobs);
+ std::string res = gen->generate (output);
+ delete gen;
+ return res;
+}
+}
+}
diff --git a/o3d/compiler/puritan/test_gen.h b/o3d/compiler/puritan/test_gen.h
new file mode 100644
index 0000000..f5c2cf9
--- /dev/null
+++ b/o3d/compiler/puritan/test_gen.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef PURITAN_TESTGEN_H
+#define PURITAN_TESTGEN_H
+
+#include <string>
+#include "knobs.h"
+namespace Salem
+{
+namespace Puritan
+{
+std::string generate(class OutputInfo *info,
+ class Knobs &knobs);
+}
+}
+
+#endif
diff --git a/o3d/compiler/technique/Technique.g3pl b/o3d/compiler/technique/Technique.g3pl
new file mode 100644
index 0000000..9f71db1
--- /dev/null
+++ b/o3d/compiler/technique/Technique.g3pl
@@ -0,0 +1,1126 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Parse HLSL shaders and separate the shader code from the Technique block
+// parse the technique block into shader declarations and stateassignments
+// using a Parser and Lexer generated by Antlr3.0
+//
+// Compile from the command line using:
+//
+// $ set CLASSPATH=%CLASSPATH%;c:\bin\antlr\antlr-3.1.jar
+// $ java org.antlr.Tool Technique.g3pl
+// $ cl *.cc *.c /TP -I c:\bin\antlr\libantlr3c-3.1\include /c /nologo
+// $ link *.obj /LTCG /out:technique.exe c:\bin\antlr\antlr3c.lib \
+// /NODEFAULTLIB:libcmt.lib /nologo
+
+
+grammar Technique;
+
+options {
+ language = C;
+}
+
+@lexer::preincludes {
+#include <vector>
+#include "base/logging.h"
+#include "core/cross/types.h"
+
+#ifdef OS_WIN
+// These need to be defined here so that when antlr includes
+// winsock.h, it doesn't barf. For some reason these are undefined by
+// some header (and it appears to be a windows header).
+#define IN
+#define OUT
+#endif
+}
+
+@lexer::postinclude {
+ namespace o3d {
+ void TechniqueError(pANTLR3_BASE_RECOGNIZER recognizer,
+ pANTLR3_UINT8 * tokenNames);
+ }
+}
+
+@lexer::apifuncs
+{
+ // Install the custom error reporting function.
+ RECOGNIZER->displayRecognitionError = o3d::TechniqueError;
+}
+
+@lexer::members {
+ static int toInt(const pANTLR3_STRING string) {
+ return atoi(reinterpret_cast<const char*>(string->chars));
+ }
+ static o3d::String toStringL(const pANTLR3_STRING string) {
+ return o3d::String(reinterpret_cast<const char*>(string->chars));
+ }
+ // Removes escape sequences, as well as leading and trailing quotes.
+ static ANTLR3_STRING* unescape(const pANTLR3_STRING string) {
+ if (!string || !string->factory) return NULL;
+ ANTLR3_STRING* s = string->factory->newRaw(string->factory);
+ const char *f = reinterpret_cast<const char*>(string->chars);
+ if (!f) return s;
+ if (*f == '"') f++;
+ for (; *f; f++) {
+ if (*f == '\\') {
+ switch (*++f) {
+ case '\0': return s;
+ case 'b': s->addc(s, '\b'); break;
+ case 't': s->addc(s, '\t'); break;
+ case 'n': s->addc(s, '\n'); break;
+ case 'f': s->addc(s, '\f'); break;
+ case 'r': s->addc(s, '\r'); break;
+ default: s->addc(s, *f); break;
+ }
+ } else if (*f == '"') {
+ return s;
+ } else {
+ s->addc(s, *f);
+ }
+ }
+ return s;
+ }
+ static void setFilename(pANTLR3_BASE_RECOGNIZER rec,
+ const pANTLR3_STRING filename) {
+ if (filename) {
+ // We store the filename into the "custom" field in the lexer state,
+ // which gets copied into each token. If we use the fileName field
+ // in the stream itself, when the lexer runs ahead of the parser
+ // (which is often), the file name can be incorrect. By storing it
+ // in the token itself, the error code can retrieve the filename
+ // associated with that token.
+ rec->state->custom = unescape(filename);
+ }
+ }
+}
+
+@parser::preincludes {
+// NOTE: this header must be included before the "antlr.h" header
+// because on Windows it includes <windows.h> which will define <winsock.h>
+// before <winsock2.h>, causing a cascade of struct redefinition errors.
+#ifdef OS_WIN
+// NOTE: disable compiler warning about C function returning a
+// struct. This is caused by the Antlr generated functions being declared
+// extern "C" but being compiled and used as C++.
+#pragma warning( disable: 4190 )
+#endif
+#include <vector>
+#include "base/logging.h"
+#include "base/string_util.h"
+#include "core/cross/types.h"
+#include "compiler/technique/technique_structures.h"
+}
+
+@parser::includes {
+// NOTE: includes that occur after the "antlr3.h" header has been
+// declared which therefore can use the Antlr3 datatypes.
+}
+
+@parser::postinclude {
+ namespace o3d {
+ void TechniqueError(pANTLR3_BASE_RECOGNIZER recognizer,
+ pANTLR3_UINT8 * tokenNames);
+ void TechniqueSetErrorString(String* e);
+ }
+}
+
+@parser::apifuncs
+{
+ // Install the custom error reporting function.
+ RECOGNIZER->displayRecognitionError = o3d::TechniqueError;
+}
+
+@parser::members {
+ o3d::String *shader_string_;
+ o3d::TechniqueDeclarationList *technique_list_;
+ o3d::SamplerStateList *sampler_list_;
+ o3d::String *error_string_;
+ // NOTE: the reinterpret casts below are
+ // to cast from Antlr3's internal ANTLR_UINT8 strings to the UTF8
+ // char* that O3D uses.
+ o3d::String toString(const pANTLR3_STRING string) {
+ return o3d::String(reinterpret_cast<const char*>(string->chars));
+ }
+ void addString(const pANTLR3_STRING string) {
+ shader_string_->append(toString(string));
+ }
+ void addText(const pANTLR3_STRING string) {
+ if (string && string->chars) {
+ addString(string);
+ shader_string_->append("\n");
+ }
+ }
+ void sampler_state_assignment(const pANTLR3_STRING id,
+ const pANTLR3_STRING value) {
+ const char* idc = reinterpret_cast<const char *>(id->chars);
+ if (!base::strcasecmp(idc, "MinFilter")) {
+ sampler_list_->back().min_filter = toString(value);
+ } else if (!base::strcasecmp(idc, "MagFilter")) {
+ sampler_list_->back().mag_filter = toString(value);
+ } else if (!base::strcasecmp(idc, "MipFilter")) {
+ sampler_list_->back().mip_filter = toString(value);
+ } else if (!base::strcasecmp(idc, "AddressU")) {
+ sampler_list_->back().address_u = toString(value);
+ } else if (!base::strcasecmp(idc, "AddressV")) {
+ sampler_list_->back().address_v = toString(value);
+ } else if (!base::strcasecmp(idc, "AddressW")) {
+ sampler_list_->back().address_w = toString(value);
+ } else if (!base::strcasecmp(idc, "BorderColor")) {
+ sampler_list_->back().border_color = toString(value);
+ } else if (!base::strcasecmp(idc, "MaxAnisotropy")) {
+ sampler_list_->back().max_anisotropy = toString(value);
+ }
+ }
+}
+
+// rules -----------------------------------------------------------------------
+
+// This is the entry rule - zero or more global declarations followed by an
+// end-of-file token.
+translation_unit [o3d::TechniqueDeclarationList *technique_list,
+ o3d::SamplerStateList *sampler_list,
+ o3d::String *shader_string,
+ o3d::String *error_string]
+ returns [bool success]
+@init {
+ // On entry, reset the list of error strings.
+ technique_list_ = technique_list;
+ sampler_list_ = sampler_list;
+ shader_string_ = shader_string;
+ error_string_ = error_string;
+ o3d::TechniqueSetErrorString(error_string_);
+}
+@after {
+ // On exit, set the return value.
+ success = error_string_->length() == 0;
+ technique_list_ = NULL;
+ sampler_list_ = NULL;
+ shader_string_ = NULL;
+ error_string_ = NULL;
+ o3d::TechniqueSetErrorString(NULL);
+}
+ :
+ ( noise global_declaration )* EOF
+ ;
+
+noise
+ :
+ ( COMMENT | WHITESPACE | MULTILINE_COMMENT )* { addText($text); }
+ | LINE_DIRECTIVE
+ ;
+
+global_declaration
+ : (function_storage_class? function_type_specifier IDENTIFIER LPAREN) => function_declaration
+ { addText($text); }
+ | sampler_declaration
+ | texture_declaration
+ | struct_definition
+ { addText($text); }
+ | typedef_definition
+ { addText($text); }
+ | var_declaration
+ { addText($text); }
+ | technique_definition
+ ;
+
+// variables -------------------------------------------
+
+var_declaration
+ : var_storage_class*
+ var_type_modifier?
+ var_datatype id_declaration
+ semantic?
+ annotation_list?
+ ('=' initializer)?
+ var_packoffset?
+ var_register_bind?
+ SEMI
+ ;
+
+var_storage_class
+ : EXTERN
+ | NOINTERPOLATION
+ | SHARED
+ | STATIC
+ | UNIFORM
+ | VOLATILE
+ ;
+
+var_type_modifier
+ : T_CONST
+ | ROW_MAJOR
+ | COLUMN_MAJOR;
+
+var_datatype
+ : buffer_type_specifier
+ | scalar_type_or_string_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ ;
+
+var_packoffset
+ : 'packoffset' LPAREN register_name (DOT IDENTIFIER)? RPAREN
+ ;
+
+var_register_bind
+ : COLON register_name
+ ;
+
+id_declaration
+ : IDENTIFIER ( LBRACKET constant_expression RBRACKET )?
+ ;
+
+// function --------------------------------------------
+
+function_declaration
+ : function_storage_class?
+ function_type_specifier IDENTIFIER LPAREN argument_list RPAREN semantic?
+ function_body (SEMI)?
+ ;
+
+function_storage_class
+ : INLINE // ignoring platform target
+ ;
+
+function_type_specifier
+ : scalar_type_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ | T_VOID
+ ;
+
+semantic
+ : COLON semantic_specifier ;
+
+param_type_specifier
+ : scalar_type_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | struct_type_specifier
+ | string_type_specifier
+ | sampler_type_specifier
+ ;
+
+basic_type_specifier
+ : scalar_type_specifier
+ | vector_type_specifier
+ | matrix_type_specifier
+ | string_type_specifier
+ ;
+
+// typedef ---------------------------------------
+
+typedef_definition
+ : TYPEDEF
+ ;
+
+// basic datatypes -------------------------------
+
+buffer_type_specifier
+ : (BUFFER '<' var_datatype '>' IDENTIFIER)
+ ;
+
+// effects ---------------------------------------------------------------------
+
+technique_definition
+@declarations {
+ o3d::TechniqueDeclaration technique_decl;
+}
+@init {
+ // clear the technique declaration before use
+ technique_decl.clear();
+}
+ : TECHNIQUE IDENTIFIER
+ {
+ technique_decl.name = toString($IDENTIFIER.text);
+ }
+ annotation_list? '{' ( pass[technique_decl] )+ '}' SEMI?
+ {
+ technique_list_->push_back(technique_decl);
+ }
+
+ | TECHNIQUE
+ {
+ technique_decl.name = "";
+ }
+ annotation_list? '{' ( pass[technique_decl] )+ '}' SEMI?
+ {
+ technique_list_->push_back(technique_decl);
+ }
+ ;
+
+pass [o3d::TechniqueDeclaration& technique_decl]
+@declarations {
+ o3d::PassDeclaration pass_decl;
+}
+@after {
+ $technique_decl.pass.push_back(pass_decl);
+}
+ : PASS IDENTIFIER?
+ {
+ if ($IDENTIFIER != NULL && $IDENTIFIER.text->chars != NULL) {
+ pass_decl.name = toString($IDENTIFIER.text);
+ } else {
+ *error_string_ += "Bad pass identifier, line ";
+ *error_string_ += $PASS.line;
+ }
+ }
+ annotation_list? '{' ( state_assignment[pass_decl] )* '}' SEMI?
+ ;
+
+state_assignment [o3d::PassDeclaration& pass]
+ : (VERTEXSHADER) =>
+ x=VERTEXSHADER '=' 'compile' IDENTIFIER fn=variable_or_call_expression
+ {
+ $pass.vertex_shader_entry = $fn.identifier;
+ $pass.vertex_shader_profile = toString($IDENTIFIER.text);
+ $pass.vertex_shader_arguments = $fn.arglist;
+ }
+ SEMI
+ | (FRAGMENTSHADER) =>
+ x=FRAGMENTSHADER '=' 'compile' IDENTIFIER fn=variable_or_call_expression
+ {
+ $pass.fragment_shader_entry = $fn.identifier;
+ $pass.fragment_shader_profile = toString($IDENTIFIER.text);
+ $pass.fragment_shader_arguments = $fn.arglist;
+ }
+ SEMI
+ | IDENTIFIER '=' val=primary_expression
+ {
+ if ($IDENTIFIER.text->chars == NULL) {
+ *error_string_ += "Bad state assigment identifier, line ";
+ *error_string_ += $IDENTIFIER.line;
+
+ } else if ($val.text->chars == NULL) {
+ *error_string_ = "Bad state assigment value, line ";
+ *error_string_ += $IDENTIFIER.line;
+ } else {
+ o3d::StateAssignment state;
+ state.name = toString($IDENTIFIER.text);
+ state.value = toString($val.text);
+ $pass.state_assignment.push_back(state);
+ }
+ }
+ SEMI
+ ;
+
+// data types ------------------------------------------------------------------
+
+scalar_type_specifier
+ : 'bool'
+ | 'int'
+ | 'uint'
+ | 'half'
+ | FLOAT
+ | 'double'
+ ;
+
+scalar_type_or_string_specifier
+ : scalar_type_specifier
+ | string_type_specifier
+ ;
+
+vector_type_specifier
+ : 'bool1'
+ | 'bool2'
+ | 'bool3'
+ | 'bool4'
+ | 'int1'
+ | 'int2'
+ | 'int3'
+ | 'int4'
+ | 'uint1'
+ | 'uint2'
+ | 'uint3'
+ | 'uint4'
+ | 'half1'
+ | 'half2'
+ | 'half3'
+ | 'half4'
+ | 'float1'
+ | 'float2'
+ | 'float3'
+ | 'float4'
+ | 'double1'
+ | 'double2'
+ | 'double3'
+ | 'double4'
+ | VECTOR '<' scalar_type_specifier ',' DECIMAL_LITERAL '>'
+ ;
+
+matrix_type_specifier
+ : 'float1x1'
+ | 'float1x2'
+ | 'float1x3'
+ | 'float1x4'
+ | 'float2x1'
+ | 'float2x2'
+ | 'float2x3'
+ | 'float2x4'
+ | 'float3x1'
+ | 'float3x2'
+ | 'float3x3'
+ | 'float3x4'
+ | 'float4x1'
+ | 'float4x2'
+ | 'float4x3'
+ | 'float4x4'
+ | MATRIX '<' scalar_type_specifier ','
+ DECIMAL_LITERAL ',' DECIMAL_LITERAL '>'
+ ;
+
+string_type_specifier
+ : STRING
+ ;
+
+// Sampler declarations ----------------------------
+
+sampler_declaration
+ : sampler_type_specifier id_declaration
+ {
+ o3d::SamplerState s;
+ s.name = toString($id_declaration.text);
+ sampler_list_->push_back(s);
+ addString($sampler_type_specifier.text);
+ shader_string_->append(" ");
+ addString($id_declaration.text);
+ shader_string_->append(";\n");
+ }
+ ( '=' 'sampler_state' '{' sampler_state_declaration+ '}' )? SEMI
+ ;
+
+sampler_state_declaration
+ : TEXTURE '=' '<' IDENTIFIER '>' SEMI
+ { sampler_list_->back().texture = toString($IDENTIFIER.text); }
+ | TEXTURE '=' '(' IDENTIFIER ')' SEMI
+ { sampler_list_->back().texture = toString($IDENTIFIER.text); }
+ | IDENTIFIER '=' initializer SEMI
+ { sampler_state_assignment($IDENTIFIER.text, $initializer.text); }
+ ;
+
+sampler_type_specifier
+ : 'sampler'
+ | 'sampler1D'
+ | 'sampler2D'
+ | 'sampler3D'
+ | 'samplerCUBE'
+ | 'sampler_state'
+ | 'SamplerComparisonState' | 'samplercomparisonstate' // DX10 only
+ ;
+
+ // texture declaration ----------------------------
+
+texture_declaration
+ : texture_type_specifier IDENTIFIER semantic? annotation_list? SEMI
+ ;
+
+texture_type_specifier
+ : TEXTURE
+ | TEXTURE1D
+ | TEXTURE2D
+ | TEXTURE3D
+ | TEXTURECUBE
+ | TEXTURERECT
+ ;
+
+ // struct declaration -----------------------------
+
+struct_type_specifier
+ : IDENTIFIER
+ | ( STRUCT ( IDENTIFIER )? LCURLY ) => struct_definition
+ | STRUCT IDENTIFIER
+ ;
+
+annotation_list
+ : '<' annotation* '>'
+ ;
+
+annotation
+ : basic_type_specifier IDENTIFIER '=' initializer SEMI
+ ;
+
+initializer
+ : expression
+ | '{' expression ( ',' expression )* '}'
+ ;
+
+register_name
+ // registers for VS_3_0
+ : REGISTER '(' input_register_name | output_register_name ')';
+
+input_register_name
+ : IDENTIFIER DECIMAL_LITERAL
+ // IDENTIFIER must be v, r, c, b, i, s, o (check semantically)
+ | IDENTIFIER
+ // IDENTIFIER must be a0 aL p0 (check semantically)
+ ;
+
+output_register_name
+ : IDENTIFIER
+ // must be one of: 'oD0', 'oD1', 'oFog', 'oPos', 'oPts',
+ // 'oT0', 'oT1', 'oT2', 'oT3', 'oT4', 'oT5', 'oT6', 'oT7'
+ // (check semantically)
+ ;
+
+pack_offset
+ : .+ ; // no idea what this field looks like.
+
+argument_list
+ : ( param_declaration ( COMMA param_declaration )* )?
+ ;
+
+param_declaration
+ : param_direction? param_variability? param_type_specifier id_declaration semantic?
+// | FUNCTION type_specifier IDENTIFIER
+ ;
+
+param_variability
+ : T_CONST
+ | UNIFORM
+ ;
+
+param_direction
+ : T_IN
+ | T_OUT
+ | T_INOUT
+ ;
+
+function_body
+ : LCURLY ( decl_or_statement )* RCURLY
+ ;
+
+decl_or_statement
+ // We copied the following sub-rule here to expedite the parsing time
+ // as this is a much more common case than the "Id init_declarator_list"
+ // case which would normally spend a lot of time in exception handling.
+ : (lvalue_expression assignment_operator ) => assignment_statement
+ | ( ( T_CONST )? vector_type_specifier ) => ( T_CONST )? vector_type_specifier init_declarator_list SEMI
+ | ( ( T_CONST )? scalar_type_specifier ) => ( T_CONST )? scalar_type_specifier init_declarator_list SEMI
+ | ( ( T_CONST )? matrix_type_specifier ) => ( T_CONST )? matrix_type_specifier init_declarator_list SEMI
+ | ( STRUCT ( IDENTIFIER )? LCURLY ) => struct_definition ( init_declarator_list )? SEMI
+ | STRUCT IDENTIFIER init_declarator_list SEMI
+ | ( IDENTIFIER init_declarator_list ) => IDENTIFIER init_declarator_list SEMI
+ | statement
+ ;
+
+init_declarator_list
+ : init_declarator ( COMMA init_declarator )* ;
+
+init_declarator
+ : declarator ( ASSIGN expression )? ;
+
+declarator
+ : IDENTIFIER ( LBRACKET ( constant_expression )? RBRACKET )*
+ ;
+
+struct_definition
+ : STRUCT ( IDENTIFIER )? LCURLY struct_declaration_list RCURLY IDENTIFIER? SEMI
+ ;
+
+struct_declaration_list
+ // We currently don't support nested structs so the field type
+ // can only be either a scalar or a vector.
+ : ( struct_interpolation_modifier?
+ (scalar_type_specifier|vector_type_specifier) IDENTIFIER
+ (COLON semantic_specifier)? SEMI )+
+ ;
+
+struct_interpolation_modifier // DX10 only
+ : T_LINEAR
+ | CENTROID
+ | NOINTERPOLATION
+ | NOPERSPECTIVE
+ ;
+
+semantic_specifier
+ : IDENTIFIER
+ ;
+
+statement
+ : ( lvalue_expression assignment_operator ) => assignment_statement
+ | ( lvalue_expression self_modify_operator ) => post_modify_statement
+ | pre_modify_statement
+ | expression_statement
+ | compound_statement
+ | selection_statement
+ | iteration_statement
+ | jump_statement
+ | SEMI
+ ;
+
+assignment_statement
+ : lvalue_expression assignment_operator expression SEMI
+ ;
+
+pre_modify_statement
+ : pre_modify_expression SEMI ;
+
+pre_modify_expression
+ : self_modify_operator lvalue_expression ;
+
+post_modify_statement
+ : post_modify_expression SEMI ;
+
+post_modify_expression
+ : lvalue_expression self_modify_operator ;
+
+self_modify_operator
+ : PLUS_PLUS | MINUS_MINUS ;
+
+expression_statement
+ : expression SEMI ;
+
+compound_statement
+ : LCURLY (
+ ( IDENTIFIER init_declarator_list) => IDENTIFIER init_declarator_list SEMI
+ | ( ( T_CONST )? vector_type_specifier ) => ( T_CONST )? vector_type_specifier init_declarator_list SEMI
+ | ( ( T_CONST )? scalar_type_specifier ) => ( T_CONST )? scalar_type_specifier init_declarator_list SEMI
+ | ( STRUCT ( IDENTIFIER )? LCURLY ) => struct_definition ( init_declarator_list )? SEMI
+ | STRUCT IDENTIFIER init_declarator_list SEMI
+ | statement
+ )*
+ RCURLY
+ ;
+
+selection_statement
+ : IF LPAREN expression RPAREN statement ( ELSE statement )?
+ ;
+
+iteration_statement
+ : WHILE LPAREN expression RPAREN statement
+ | FOR LPAREN assignment_statement
+ equality_expression SEMI modify_expression RPAREN statement
+ | DO statement WHILE LPAREN expression RPAREN SEMI
+ ;
+
+modify_expression
+ : (lvalue_expression assignment_operator ) =>
+ lvalue_expression assignment_operator expression
+ | pre_modify_expression
+ | post_modify_expression
+ ;
+
+jump_statement
+ : BREAK SEMI
+ | CONTINUE
+ | RETURN ( expression )? SEMI
+ | DISCARD
+ ;
+
+expression
+ : conditional_expression
+ ;
+
+assignment_operator
+ : ASSIGN
+ | MUL_ASSIGN
+ | DIV_ASSIGN
+ | ADD_ASSIGN
+ | SUB_ASSIGN
+ | BITWISE_AND_ASSIGN
+ | BITWISE_OR_ASSIGN
+ | BITWISE_XOR_ASSIGN
+ | BITWISE_SHIFTL_ASSIGN
+ | BITWISE_SHIFTR_ASSIGN
+ ;
+
+constant_expression
+ : (IDENTIFIER) => variable_expression
+ | literal_value
+ ;
+
+conditional_expression
+ : logical_or_expression ( QUESTION expression COLON conditional_expression )?
+ ;
+
+logical_or_expression
+ : exclusive_or_expression ( OR exclusive_or_expression )*
+ ;
+
+// We remove the NOT operator from the unary expression and stick it here
+// so that it has a lower precedence than relational operations.
+logical_and_expression
+ : ( NOT )? inclusive_or_expression ( AND ( NOT )? inclusive_or_expression )*
+ ;
+
+inclusive_or_expression
+ : exclusive_or_expression (BITWISE_OR exclusive_or_expression )*
+ ;
+
+exclusive_or_expression
+ : and_expression ( BITWISE_XOR and_expression )*
+ ;
+
+and_expression
+ : equality_expression ( BITWISE_AND equality_expression )*
+ ;
+
+equality_expression
+ : relational_expression ( (EQUAL|NOT_EQUAL) relational_expression )*
+ ;
+
+relational_expression
+ : shift_expression ( (LESS|GREATER|LESSEQUAL|GREATEREQUAL) shift_expression )*
+ ;
+
+shift_expression
+ : additive_expression ( (BITWISE_SHIFTL|BITWISE_SHIFTR) additive_expression )*
+ ;
+
+additive_expression
+ : multiplicative_expression ( (PLUS|MINUS) multiplicative_expression )*
+ ;
+
+multiplicative_expression
+ : cast_expression ( (MUL|DIV|MOD) cast_expression )*
+ ;
+
+cast_expression
+ : LPAREN IDENTIFIER RPAREN postfix_expression
+ | LPAREN basic_type_specifier RPAREN postfix_expression
+ | unary_expression
+ ;
+
+unary_expression
+ : (PLUS|MINUS) unary_expression
+ | postfix_expression
+ ;
+
+postfix_expression
+ : primary_expression ( postfix_suffix )?
+ ;
+
+lvalue_expression
+ : variable_expression ( postfix_suffix )?
+ ;
+
+postfix_suffix
+ // choosing between struct field access or vector swizzling is a semantic choice.
+ : ( DOT primary_expression )+
+ ;
+
+primary_expression
+ : constructor
+ | variable_or_call_expression
+ | literal_value
+ | LPAREN expression RPAREN
+ ;
+
+variable_expression
+ : IDENTIFIER ( LBRACKET expression RBRACKET )?
+ ;
+
+// Combine variable expression and call expression here to get rid of the
+// syntactic predicate we used to use in the primary_expression rule. Using
+// predicates results in the parser spending a lot of time in exception
+// handling (when lookahead fails).
+variable_or_call_expression
+ returns [o3d::String identifier, o3d::String arglist]
+ : IDENTIFIER
+ (
+ ( ( LBRACKET expression RBRACKET )? )
+ {
+ $identifier = toString($IDENTIFIER.text);
+ $arglist = "";
+ }
+ |
+ ( LPAREN argument_expression_list RPAREN )
+ {
+ $identifier = toString($IDENTIFIER.text);
+ if ($argument_expression_list.text->chars) {
+ $arglist = toString($argument_expression_list.text);
+ } else {
+ $arglist = "";
+ }
+ }
+ )
+ ;
+
+constructor
+ : ( vector_type_specifier | matrix_type_specifier )
+ LPAREN expression ( COMMA expression )* RPAREN
+ ;
+
+argument_expression_list
+ : ( expression ( COMMA expression )* )?
+ ;
+
+int_literal
+ : DECIMAL_LITERAL
+// | OCT_LITERAL
+// | HEX_LITERAL
+ ;
+
+literal_value
+ : DECIMAL_LITERAL
+ | FLOAT_LITERAL
+ | STRING_LITERAL+
+ | ( T_FALSE | T_TRUE )
+ ;
+
+float_literal
+ : FLOAT_LITERAL
+ ;
+
+// lexical elements ------------------------------------------------------------
+
+NOT : '!' ;
+NOT_EQUAL : '!=' ;
+AND : '&&' ;
+LPAREN : '(' ;
+RPAREN : ')' ;
+MUL : '*' ;
+MUL_ASSIGN : '*=' ;
+PLUS : '+' ;
+PLUS_PLUS : '++' ;
+ADD_ASSIGN : '+=' ;
+COMMA : ',' ;
+MINUS : '-' ;
+MINUS_MINUS : '--' ;
+SUB_ASSIGN : '-=' ;
+DIV : '/' ;
+DIV_ASSIGN : '/=' ;
+MOD : '%';
+MOD_ASSIGN : '%=';
+COLON : ':' ;
+SEMI : ';' ;
+LESS : '<' ;
+LESSEQUAL : '<=' ;
+ASSIGN : '=' ;
+EQUAL : '==' ;
+GREATER : '>' ;
+GREATEREQUAL : '>=' ;
+QUESTION : '?' ;
+LBRACKET : '[' ;
+RBRACKET : ']' ;
+LCURLY : '{' ;
+OR : '||' ;
+RCURLY : '}' ;
+DOT : '.' ;
+BITWISE_NOT : '~';
+BITWISE_SHIFTL : '<<';
+BITWISE_SHIFTR : '>>';
+BITWISE_AND : '&';
+BITWISE_OR : '|';
+BITWISE_XOR : '^';
+BITWISE_SHIFTL_ASSIGN : '<<=';
+BITWISE_SHIFTR_ASSIGN : '>>=';
+BITWISE_AND_ASSIGN : '&=';
+BITWISE_OR_ASSIGN : '|=';
+BITWISE_XOR_ASSIGN : '^=';
+// keywords ----------------------------
+
+BREAK : 'break';
+BUFFER : 'buffer';
+COLUMN_MAJOR : 'column_major';
+CBUFFER : 'cbuffer';
+CENTROID : 'centroid';
+T_CONST : 'const';
+CONTINUE : 'continue';
+DISCARD : 'discard';
+DO : 'do';
+ELSE : 'else';
+EXTERN : 'extern';
+T_FALSE : 'false';
+FLOAT : (('f'|'F')('l'|'L')('o'|'O')('a'|'A')('t'|'T'));
+FOR : 'for';
+IF : 'if';
+T_IN : 'in';
+INLINE : 'inline';
+T_INOUT : 'inout';
+T_LINEAR : 'linear';
+MATRIX : ('m'|'M')('a'|'A')('t'|'T')('r'|'R')('i'|'I')('x'|'X');
+NAMESPACE : 'namespace';
+NOINTERPOLATION : 'nointerpolation';
+NOPERSPECTIVE : 'noperspective';
+T_OUT : 'out';
+RETURN : 'return';
+REGISTER : 'register';
+ROW_MAJOR : 'row_major';
+SHARED : 'shared';
+STATEBLOCK : 'stateblock';
+STATEBLOCK_STATE : 'stateblock_state';
+STATIC : 'static';
+STRING : ('s'|'S')('t'|'T')('r'|'R')('i'|'I')('n'|'N')('g'|'G');
+STRUCT : 'struct';
+SWITCH : 'switch';
+TBUFFER : 'tbuffer';
+TEXTURE :
+ ('t'|'T')('e'|'E')('x'|'X')('t'|'T')('u'|'U')('r'|'R')('e'|'E');
+TEXTURE1D : 'Texture1D';
+TEXTURE1DARRAY : 'Texture1DArray';
+TEXTURE2D : 'Texture2D';
+TEXTURE2DARRAY : 'Texture2DArray';
+TEXTURE2DMS : 'Texture2DMS';
+TEXTURE2DMSARRAY : 'Texture2DMSArray';
+TEXTURE3D : 'Texture3D';
+TEXTURECUBE : 'TextureCUBE';
+TEXTURECUBEARRAY : 'TextureCUBEArray';
+TEXTURERECT : 'TextureRECT';
+T_TRUE : 'true';
+TYPEDEF : 'typedef';
+UNIFORM : 'uniform';
+VECTOR : ('v'|'V')('e'|'E')('c'|'C')('t'|'T')('o'|'O')('r'|'R');
+T_VOID : 'void';
+VOLATILE : 'volatile';
+WHILE : 'while';
+
+// sampler state tokens
+
+PASS : ('p'|'P')('a'|'A')('s'|'S')('s'|'S');
+
+TECHNIQUE : ('t'|'T')('e'|'E')('c'|'C')('h'|'H')
+ ('n'|'N')('i'|'I')('q'|'Q')('u'|'U')('e'|'E')
+ ;
+
+VERTEXSHADER
+ : (('v'|'V')('e'|'E')('r'|'R')('t'|'T')('e'|'E')('x'|'X'))
+ ((('s'|'S')('h'|'H')('a'|'A')('d'|'D')('e'|'E')('r'|'R')) |
+ (('p'|'P')('r'|'R')('o'|'O')('g'|'G')('r'|'R')('a'|'A')('m'|'M')))
+ ;
+
+FRAGMENTSHADER
+ : (('f'|'F')('r'|'R')('a'|'A')('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T')
+ ('p'|'P')('r'|'R')('o'|'O')('g'|'G')('r'|'R')('a'|'A')('m'|'M'))
+ | (('p'|'P')('i'|'I')('x'|'X')('e'|'E')('l'|'L')
+ ('s'|'S')('h'|'H')('a'|'A')('d'|'D')('e'|'E')('r'|'R'))
+ ;
+
+RESERVED_WORDS
+ : (('a'|'A')('S'|'s')('m'|'M'))
+ | 'asm_fragment'
+ | 'auto'
+ | 'case'
+ | 'catch'
+ | 'char'
+ | 'class'
+ | 'const_cast'
+ | (('d'|'D')('e'|'E')('c'|'C')('l'|'L'))
+ | 'default'
+ | 'delete'
+ | (('d'|'D')('w'|'W')('o'|'O')('r'|'R')('d'|'D'))
+ | 'dynamic_cast'
+ | 'emit'
+ | 'enum'
+ | 'explicit'
+ | 'fixed'
+ | 'friend'
+ | 'get'
+ | 'goto'
+ | 'interface'
+ | 'long'
+ | 'mutable'
+ | 'new'
+ | 'operator'
+ | 'packed'
+ | (('p'|'P')('i'|'I')('x'|'X')('e'|'E')('l'|'L')
+ ('f'|'F')('r'|'R')('a'|'A')('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T'))
+ | 'private'
+ | 'protected'
+ | 'public'
+ | 'reinterpret_cast'
+ | 'short'
+ | 'signed'
+ | 'sizeof'
+ | 'snorm'
+ | 'static_cast'
+ | 'template'
+ | 'this'
+ | 'throw'
+ | 'try'
+ | 'typeid'
+ | 'typename'
+ | 'union'
+ | 'unorm'
+ | 'unsigned'
+ | 'using'
+ | (('v'|'V')('e'|'E')('r'|'R')('t'|'T')('e'|'E')('x'|'X')
+ ('f'|'F')('r'|'R')('a'|'A')
+ ('g'|'G')('m'|'M')('e'|'E')('n'|'N')('t'|'T'))
+ | 'virtual'
+ ;
+
+IDENTIFIER
+ : ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
+ ;
+
+DECIMAL_LITERAL
+ : ('0'..'9')+
+ ;
+
+fragment ESCAPE_SEQUENCE
+ : '\\' ('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\')
+ ;
+
+CHARACTER_LITERAL
+ : '\'' ( ESCAPE_SEQUENCE | ~('\''|'\\') ) '\''
+ ;
+
+STRING_LITERAL
+ : '"' ( ESCAPE_SEQUENCE | ~('\\'|'"') )* '"'
+ ;
+
+fragment EXPONENT : ('e'|'E') (PLUS | MINUS)? ('0'..'9')+ ;
+
+fragment FLOATSUFFIX : ('f'|'F'|'h'|'H') ;
+
+FLOAT_LITERAL
+ : ('0'..'9')+ '.' ('0'..'9')* (EXPONENT)? (FLOATSUFFIX)?
+ | '.' ('0'..'9')+ (EXPONENT)? (FLOATSUFFIX)?
+ ;
+
+// skipped elements ------------------------------------------------------------
+
+LINE_DIRECTIVE
+ : '#line' (' '|'\t')* line_num=DECIMAL_LITERAL '\r'? '\n'
+ { INPUT->setLine(INPUT, toInt($line_num.text)); $channel = HIDDEN; }
+ | '#line' (' '|'\t')* line_num=DECIMAL_LITERAL
+ (' '|'\t')* file=STRING_LITERAL '\r'? '\n'
+ { INPUT->setLine(INPUT, toInt($line_num.text)); $channel = HIDDEN;
+ setFilename(RECOGNIZER, $file.text); }
+ ;
+
+WHITESPACE
+ : (' '|'\r'|'\t'|'\u000C'|'\n') { $channel = HIDDEN; }
+ ;
+
+COMMENT
+ : '//' ~('\n'|'\r')* '\r'? '\n' { $channel = HIDDEN; }
+ ;
+
+MULTILINE_COMMENT
+ : '/*' ( options {greedy=false;} : . )* '*/' { $channel = HIDDEN; }
+ ;
+
+// -----------------------------------------------------------------------------
diff --git a/o3d/compiler/technique/build.scons b/o3d/compiler/technique/build.scons
new file mode 100644
index 0000000..384c2c4
--- /dev/null
+++ b/o3d/compiler/technique/build.scons
@@ -0,0 +1,94 @@
+# Copyright 2009, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+import os.path
+
+Import('env')
+
+env.Append(
+ CPPPATH = [
+ # Include path for generated headers.
+ env.Dir('$OBJ_ROOT/compiler/technique'),
+ # Include path for Antlr C runtime headers.
+ env.Dir('$ANTLRLIBC_DIR/include'),
+ ],
+ LIBPATH = [
+ env.Dir('$ANTLRLIBC_DIR/lib'),
+ ],
+ LIBS = [
+ 'antlr3c',
+ ],
+)
+
+# Define a builder for Antlr grammars.
+def TechniqueEmitter(target, source, env):
+ # TODO this path operation is horrible, please make '.base' work
+ base_name = os.path.splitext(source[0].abspath)[0]
+ generated_targets = [env.File(base_name + 'Lexer.c'),
+ env.File(base_name + 'Lexer.h'),
+ env.File(base_name + 'Parser.c'),
+ env.File(base_name + 'Parser.h'), ]
+ return generated_targets, source
+
+if env.Bit('windows'):
+ env.Append(
+ CCFLAGS=['/Wp64', '/TP'],
+ )
+else:
+ env.Append(
+ CCFLAGS = ['-x', 'c++'],
+ )
+
+# To enable ANTLRworks debugging, replace
+# org.antlr.Tool $SOURCE
+# below, with
+# org.antlr.Tool -debug $SOURCE
+
+env['BUILDERS']['Antlr'] = Builder(
+ action = ' '.join([
+ '$JAVA_EXE',
+ '-cp $ANTLR_DIR/antlr-3.1.1.jar',
+ 'org.antlr.Tool $SOURCE',
+ '-fo $TARGET.dir']),
+ emitter = TechniqueEmitter)
+
+# Generate the parser and lexer files
+antlr_output_files = env.Antlr( env.File('Technique.g3pl') )
+# filter out only the C files from the generated files.
+antlr_c_files = [f for f in antlr_output_files if f.suffix == '.c']
+
+# Compile the resulting C and C++ files as C++ to build a library
+inputs = [
+ antlr_c_files,
+ 'technique_error.cc',
+ 'technique_parser.cc',
+ 'technique_structures.cc',
+]
+env.ComponentLibrary('technique', inputs)
diff --git a/o3d/compiler/technique/technique_error.cc b/o3d/compiler/technique/technique_error.cc
new file mode 100644
index 0000000..7545ac5
--- /dev/null
+++ b/o3d/compiler/technique/technique_error.cc
@@ -0,0 +1,283 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Custom error reporting functon for the Technique parser, as described in
+// the Antlr3 documention for the C Runtime at
+// http://www.antlr.org/api/C/using.html
+//
+// NOTE: These error functions are only designed to work with 8-bit
+// token streams.
+
+#include "core/cross/types.h"
+#include "compiler/technique/technique_error.h"
+
+namespace o3d {
+String* error_string;
+
+void TechniqueSetErrorString(String* e) {
+ error_string = e;
+}
+
+void TechniqueError(pANTLR3_BASE_RECOGNIZER recognizer,
+ pANTLR3_UINT8 * tokenNames) {
+ // If the error string pointer has not been set, bail now.
+ if (!error_string) return;
+
+ pANTLR3_PARSER parser;
+ pANTLR3_STRING token_text;
+ pANTLR3_EXCEPTION exception;
+ pANTLR3_COMMON_TOKEN token;
+ pANTLR3_BASE_TREE theBaseTree;
+ pANTLR3_COMMON_TREE theCommonTree;
+
+ // Retrieve some info for easy reading.
+ exception = recognizer->state->exception;
+ token_text = NULL;
+
+ pANTLR3_COMMON_TOKEN exception_token =
+ static_cast<pANTLR3_COMMON_TOKEN>(exception->token);
+ if (exception_token && exception_token->custom) {
+ // The filename is retrieved from the "custom" field of the token, which
+ // was put there by the lexer. The lexer gets it from the #line directives
+ // in the pre-processed output.
+ pANTLR3_STRING filename =
+ static_cast<pANTLR3_STRING>(exception_token->custom);
+ *error_string += reinterpret_cast<char*>(filename->chars);
+ } else {
+ if (exception_token && exception_token->type == ANTLR3_TOKEN_EOF) {
+ *error_string += "End of input";
+ } else {
+ *error_string += "Unknown source";
+ }
+ }
+
+ // Next comes the line number
+ char buffer[10];
+ base::snprintf(buffer, sizeof(buffer), "%d", exception->line);
+ *error_string += "(";
+ *error_string += buffer;
+ *error_string += ")";
+
+ *error_string += ": Error: ";
+ *error_string += reinterpret_cast<char*>(exception->message);
+
+ // Find out what part of the system raised the error.
+ switch (recognizer->type) {
+ case ANTLR3_TYPE_PARSER: {
+ // This is a normal Parser error. Prepare the information we have
+ // available.
+ parser = (pANTLR3_PARSER)(recognizer->super);
+ token = (pANTLR3_COMMON_TOKEN)(exception->token);
+
+ *error_string += ", at offset ";
+ base::snprintf(buffer, sizeof(buffer), "%d",
+ exception->charPositionInLine);
+ *error_string += buffer;
+ if (token != NULL) {
+ if (token->type == ANTLR3_TOKEN_EOF) {
+ ANTLR3_FPRINTF(stderr, ", at <EOF>");
+ } else {
+ token_text = token->getText(token);
+ if (token_text != NULL) {
+ *error_string += " near \"";
+ *error_string += reinterpret_cast<const char*>(token_text->chars);
+ *error_string += "\"";
+ }
+ }
+ }
+ break;
+ }
+ case ANTLR3_TYPE_LEXER: {
+ *error_string += "lexer error.";
+ break;
+ }
+ case ANTLR3_TYPE_TREE_PARSER: {
+ // Tree parsers not supported. Exit.
+ DLOG(FATAL) << "Technique error should never see a Tree Parser.";
+ return;
+ }
+ default: {
+ // Parser type was not recognised. Exit.
+ DLOG(FATAL) << "Technique error called by an unknown Parser type.";
+ return;
+ }
+ }
+
+#if 0
+ // Although this function should generally be provided by the
+ // implementation, this one should be as helpful as possible for grammar
+ // developers and serve as an example of what you can do with each
+ // exception type. In general, when you make up your 'real' handler, you
+ // should debug the routine with all possible errors you expect which will
+ // then let you be as specific as possible about all circumstances.
+ //
+ // Note that in the general case, errors thrown by tree parsers indicate a
+ // problem with the output of the parser or with the tree grammar
+ // itself. The job of the parser is to produce a perfect (in traversal
+ // terms) syntactically correct tree, so errors at that stage should
+ // really be semantic errors that your own code determines and handles in
+ // whatever way is appropriate.
+ switch (exception->type) {
+ case ANTLR3_UNWANTED_TOKEN_EXCEPTION:
+ // Indicates that the recognizer was fed a token which seesm to be
+ // spurious input. We can detect this when the token that follows
+ // this unwanted token would normally be part of the syntactically
+ // correct stream. Then we can see that the token we are looking at
+ // is just something that should not be there and throw this exception.
+ if (tokenNames == NULL) {
+ ANTLR3_FPRINTF(stderr, " : Extraneous input...");
+ } else {
+ if (exception->expecting == ANTLR3_TOKEN_EOF) {
+ ANTLR3_FPRINTF(stderr, " : Extraneous input - expected <EOF>\n");
+ } else {
+ ANTLR3_FPRINTF(stderr,
+ " : Extraneous input - expected %s ...\n",
+ tokenNames[exception->expecting]);
+ }
+ }
+ break;
+ case ANTLR3_MISSING_TOKEN_EXCEPTION:
+ // Indicates that the recognizer detected that the token we just
+ // hit would be valid syntactically if preceeded by a particular
+ // token. Perhaps a missing ';' at line end or a missing ',' in an
+ // expression list, and such like.
+ if (tokenNames == NULL) {
+ ANTLR3_FPRINTF(stderr,
+ " : Missing token (%d)...\n",
+ exception->expecting);
+ } else {
+ if (exception->expecting == ANTLR3_TOKEN_EOF) {
+ ANTLR3_FPRINTF(stderr, " : Missing <EOF>\n");
+ } else {
+ ANTLR3_FPRINTF(stderr,
+ " : Missing %s \n",
+ tokenNames[exception->expecting]);
+ }
+ }
+ break;
+ case ANTLR3_RECOGNITION_EXCEPTION:
+ // Indicates that the recognizer received a token
+ // in the input that was not predicted. This is the basic exception type
+ // from which all others are derived. So we assume it was a syntax error.
+ // You may get this if there are not more tokens and more are needed
+ // to complete a parse for instance.
+ ANTLR3_FPRINTF(stderr, " : syntax error...\n");
+ break;
+ case ANTLR3_MISMATCHED_TOKEN_EXCEPTION:
+ // We were expecting to see one thing and got another. This is the
+ // most common error if we coudl not detect a missing or unwanted token.
+ // Here you can spend your efforts to
+ // derive more useful error messages based on the expected
+ // token set and the last token and so on. The error following
+ // bitmaps do a good job of reducing the set that we were looking
+ // for down to something small. Knowing what you are parsing may be
+ // able to allow you to be even more specific about an error.
+ if (tokenNames == NULL) {
+ ANTLR3_FPRINTF(stderr, " : syntax error...\n");
+ } else {
+ if (exception->expecting == ANTLR3_TOKEN_EOF) {
+ ANTLR3_FPRINTF(stderr, " : expected <EOF>\n");
+ } else {
+ ANTLR3_FPRINTF(stderr,
+ " : expected %s ...\n",
+ tokenNames[exception->expecting]);
+ }
+ }
+ break;
+ case ANTLR3_NO_VIABLE_ALT_EXCEPTION:
+ // We could not pick any alt decision from the input given
+ // so god knows what happened - however when you examine your grammar,
+ // you should. It means that at the point where the current token occurred
+ // that the DFA indicates nowhere to go from here.
+ ANTLR3_FPRINTF(stderr, " : cannot match to any predicted input...\n");
+ break;
+ case ANTLR3_MISMATCHED_SET_EXCEPTION: {
+ ANTLR3_UINT32 count;
+ ANTLR3_UINT32 bit;
+ ANTLR3_UINT32 size;
+ ANTLR3_UINT32 numbits;
+ pANTLR3_BITSET errBits;
+
+ // This means we were able to deal with one of a set of
+ // possible tokens at this point, but we did not see any
+ // member of that set.
+ ANTLR3_FPRINTF(stderr, " : unexpected input...\n expected one of : ");
+
+ // What tokens could we have accepted at this point in the
+ // parse?
+ count = 0;
+ errBits = antlr3BitsetLoad(exception->expectingSet);
+ numbits = errBits->numBits(errBits);
+ size = errBits->size(errBits);
+
+ if (size > 0) {
+ // However many tokens we could have dealt with here, it is usually
+ // not useful to print ALL of the set here. I arbitrarily chose 8
+ // here, but you should do whatever makes sense for you of course.
+ // No token number 0, so look for bit 1 and on.
+ for (bit = 1; bit < numbits && count < 8 && count < size; bit++) {
+ // TODO: This doesn't look right - should be asking if the bit is set!
+ if (tokenNames[bit]) {
+ ANTLR3_FPRINTF(stderr,
+ "%%s", count > 0 ? ", " : "",
+ tokenNames[bit]);
+ count++;
+ }
+ }
+ ANTLR3_FPRINTF(stderr, "\n");
+ } else {
+ ANTLR3_FPRINTF(stderr,
+ "Could not work out which set element was missing.\n");
+ }
+ break;
+ }
+ case ANTLR3_EARLY_EXIT_EXCEPTION:
+ // We entered a loop requiring a number of token sequences
+ // but found a token that ended that sequence earlier than
+ // we should have done.
+ ANTLR3_FPRINTF(stderr, " : missing elements...\n");
+ break;
+ default:
+ // We don't handle any other exceptions here, but you can
+ // if you wish. If we get an exception that hits this point
+ // then we are just going to report what we know about the
+ // token.
+ ANTLR3_FPRINTF(stderr, " : syntax not recognized...\n");
+ break;
+ }
+#endif // end #if 0
+
+ *error_string += "\n";
+
+ DLOG(INFO) << "parse error: " << error_string->c_str();
+}
+} // namespace o3d
diff --git a/o3d/compiler/technique/technique_error.h b/o3d/compiler/technique/technique_error.h
new file mode 100644
index 0000000..260856c
--- /dev/null
+++ b/o3d/compiler/technique/technique_error.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Custom error reporting functions for the Technique parser.
+//
+// NOTE: These error functions assume they are interacting with with
+// 8-bit token streams.
+
+#ifndef O3D_COMPILER_TECHNIQUE_TECHNIQUE_ERROR_H_
+#define O3D_COMPILER_TECHNIQUE_TECHNIQUE_ERROR_H_
+
+#include <build/build_config.h>
+#ifdef OS_WIN
+// NOTE: disable compiler warning about C function returning a
+// struct. This is caused by the Antlr generated functions being declared
+// extern "C" but being compiled and used as C++.
+#pragma warning(disable: 4190)
+#endif
+
+#include <vector>
+#include "TechniqueLexer.h"
+#include "TechniqueParser.h"
+
+namespace o3d {
+
+void TechniqueError(pANTLR3_BASE_RECOGNIZER recognizer,
+ pANTLR3_UINT8 * tokenNames);
+
+} // namespace o3d
+
+#endif // O3D_COMPILER_TECHNIQUE_TECHNIQUE_ERROR_H_
diff --git a/o3d/compiler/technique/technique_parser.cc b/o3d/compiler/technique/technique_parser.cc
new file mode 100644
index 0000000..01a29de
--- /dev/null
+++ b/o3d/compiler/technique/technique_parser.cc
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Driver function that sets up the Parser and Lexer for the "Technique"
+// grammar and executes the parsing process, returning the results as a
+// string and a Technique structure.
+//
+// Note that the "TechniqueParser.[c|h]" and "TechniqueLexer.[c|h]" files
+// are generated in standard C and compiled under C++, but the code
+// generator declares all functions as having "extern C" linkage. This may
+// lead to compiler warnings about returning "struct" type values from a
+// function - valid in C++, invalid under C.
+
+#include "base/logging.h"
+#include "compiler/technique/technique_parser.h"
+
+namespace o3d {
+
+// functions -------------------------------------------------------------------
+
+// Use the Technique grammar to parse a UTF8 text file from the filesystem.
+bool ParseFxFile(
+ const String& filename,
+ String *shader_string,
+ SamplerStateList *sampler_list,
+ TechniqueDeclarationList *technique_list,
+ String *error_string) {
+ // Create the input stream object from a file of UTF8 held in the filesystem.
+ // The antlr3 library requires a non-const pointer to the filename.
+ char* temp = const_cast<char*>(filename.c_str());
+ pANTLR3_INPUT_STREAM input_stream = antlr3AsciiFileStreamNew(
+ reinterpret_cast<pANTLR3_UINT8>(temp));
+ if (input_stream == NULL) {
+ DLOG(ERROR) << "Technique: Unable to open file" << filename
+ << "due to memory allocation failure.";
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Opened file \"" << filename << "\"";
+ }
+
+ // Create the language-specific Lexer.
+ pTechniqueLexer lexer = TechniqueLexerNew(input_stream);
+ if (lexer == NULL) {
+ DLOG(ERROR) << "Technique: Unable to create the lexer";
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created lexer.";
+ }
+
+ // Create token stream from the Lexer.
+ pANTLR3_COMMON_TOKEN_STREAM token_stream =
+ antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));
+ if (token_stream == NULL) {
+ DLOG(ERROR) << "Technique: failed to allocate token stream.";
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created token stream.";
+ }
+
+ // Force the token stream to turn off token filtering and pass all
+ // whitespace and comments through to the parser.
+ token_stream->discardOffChannel = ANTLR3_FALSE;
+
+ // Create the language Parser.
+ pTechniqueParser parser = TechniqueParserNew(token_stream);
+ if (parser == NULL) {
+ DLOG(ERROR) << "Technique: Out of memory trying to allocate parser";
+ token_stream->free(token_stream);
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created parser.";
+ }
+
+ // call the root parsing rule to parse the input stream.
+ DLOG(INFO) << "Technique: Parsing...";
+ shader_string->clear();
+ technique_list->clear();
+ sampler_list->clear();
+ bool return_value = parser->translation_unit(parser,
+ technique_list,
+ sampler_list,
+ shader_string,
+ error_string);
+ DLOG(INFO) << "Technique: Finished parsing.";
+
+ DLOG(INFO) << "Technique: Shader string = ";
+ DLOG(INFO) << *shader_string;
+
+ // Free created objects.
+ parser->free(parser);
+ token_stream->free(token_stream);
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+
+ // Finished
+ return return_value;
+}
+
+
+// Use the Technique grammar to parse an FX file from an in-memory,
+// zero-terminted UTF8 string buffer.
+bool ParseFxString(
+ const String& fx_string,
+ String *shader_string,
+ SamplerStateList *sampler_list,
+ TechniqueDeclarationList *technique_list,
+ String* error_string) {
+ // Create a token stream from a zero-terminated memory buffer of uint8.
+ ANTLR3_UINT32 fx_string_length =
+ static_cast<ANTLR3_UINT32>(fx_string.length());
+ if (fx_string_length == 0) {
+ DLOG(INFO) << "Technique: fx string has zero length. Skipping.";
+ return true;
+ }
+
+ // Create the input stream from the memory buffer.
+ // The antlr3 stream library requires a non-const pointer to the fx_string.
+ char* temp_fx_string = const_cast<char*>(fx_string.c_str());
+ pANTLR3_INPUT_STREAM input_stream =
+ antlr3NewAsciiStringInPlaceStream(
+ reinterpret_cast<pANTLR3_UINT8>(temp_fx_string),
+ fx_string_length,
+ NULL);
+ if (input_stream == NULL) {
+ DLOG(ERROR) << "Technique: Unable to create input stream from string.";
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created input stream from string.";
+ }
+
+ // Create the language-specific Lexer.
+ pTechniqueLexer lexer = TechniqueLexerNew(input_stream);
+ if (lexer == NULL) {
+ DLOG(ERROR) << "Technique: Unable to create the lexer";
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created lexer.";
+ }
+
+ // Create token stream from the Lexer.
+ pANTLR3_COMMON_TOKEN_STREAM token_stream =
+ antlr3CommonTokenStreamSourceNew(ANTLR3_SIZE_HINT, TOKENSOURCE(lexer));
+ if (token_stream == NULL) {
+ DLOG(ERROR) << "Technique: failed to allocate token stream.";
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created token stream.";
+ }
+
+ // Force the token stream to turn off token filtering and pass all
+ // whitespace and comments through to the parser.
+ token_stream->discardOffChannel = ANTLR3_FALSE;
+
+ // Create the language Parser.
+ pTechniqueParser parser = TechniqueParserNew(token_stream);
+ if (parser == NULL) {
+ DLOG(ERROR) << "Technique: Out of memory trying to allocate parser";
+ token_stream->free(token_stream);
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+ return false;
+ } else {
+ DLOG(INFO) << "Technique: Created parser.";
+ }
+
+ // call the root parsing rule to parse the input stream.
+ DLOG(INFO) << "Technique: Parsing...";
+ shader_string->clear();
+ technique_list->clear();
+ sampler_list->clear();
+ bool return_value = parser->translation_unit(parser,
+ technique_list,
+ sampler_list,
+ shader_string,
+ error_string);
+ DLOG(INFO) << "Technique: Finished parsing.";
+
+ DLOG(INFO) << "Technique: Shader string = ";
+ DLOG(INFO) << *shader_string;
+
+ // Free created objects.
+ parser->free(parser);
+ token_stream->free(token_stream);
+ lexer->free(lexer);
+ input_stream->close(input_stream);
+
+ // Completed
+ return return_value;
+}
+
+} // namespace o3d
diff --git a/o3d/compiler/technique/technique_parser.h b/o3d/compiler/technique/technique_parser.h
new file mode 100644
index 0000000..ef6e96e
--- /dev/null
+++ b/o3d/compiler/technique/technique_parser.h
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Parse an HLSL or Cg ".fx" file and break it into:
+// a) source code for the shader
+// b) structured information from a "technique{}" block, if one exists.
+//
+// Entry functions initialize the Parser and Lexer for the "Technique"
+// grammar and execute the parsing process, returning the results as a
+// string and a Technique object.
+//
+// Note that the two headers "TechniqueLexer.h" and "TechniqueParser.h" are
+// automatically generated using the Antlr compiler-generator from the
+// grammar file "Technique.g3pl"
+//
+// TODO: Note that this is a specialized grammar designed for this
+// purpose alone, and it does no sanity checking on the HLSL source
+// structure or identifiers itself. A more complete HLSL grammar and
+// analyser for this task can be found in the directory
+// "o3d/compiler/hlsl".
+
+#ifndef O3D_COMPILER_TECHNIQUE_TECHNIQUE_PARSER_H_
+#define O3D_COMPILER_TECHNIQUE_TECHNIQUE_PARSER_H_
+
+#include <build/build_config.h>
+#include <vector>
+#include "core/cross/types.h"
+#include "compiler/technique/technique_structures.h"
+#include "compiler/technique/technique_error.h"
+
+#ifdef OS_WIN
+// NOTE: disable compiler warning about C function returning a
+// struct caused by the Antlr generated functions being declared extern"C"
+// but being compiled and used as C++.
+#pragma warning(disable: 4190)
+#endif
+
+// As these headers are automatically generated, their full path has to be
+// passed via the build script as each build target will generate the
+// headers in a different location.
+#include "TechniqueLexer.h"
+#include "TechniqueParser.h"
+
+namespace o3d {
+
+// typedefs --------------------------------------------------------------------
+
+typedef std::vector<TechniqueDeclaration> TechniqueDeclarationList;
+
+
+// functions -------------------------------------------------------------------
+
+
+// Use the Technique grammar to parse a UTF8 text file from the filing system.
+// Inputs:
+// filename - a UTF8 filename to send to the filesystem.
+// shader_string - pointer to a String object that will be cleared.
+// sampler_list - pointer to a vector of SamplerState objects.
+// technique_list - pointer to a vector of TechniqueDeclaration objects.
+// error_string - pointer to a String object that will be cleared.
+// Returns:
+// shader_string - pointer to a String object containing the shader source.
+// sampler_list - pointer to a vector of SamplerState objects, each filled
+// in with fields parsed from the FX file.
+// technique_list - pointer to a vector of TechniqueDeclaration objects, each
+// filled with fields parsed from the FX file.
+// error_string - pointer to a String object containing parse errors,
+// if any.
+bool ParseFxFile(
+ const String &filename,
+ String *shader_string,
+ SamplerStateList *sampler_list,
+ TechniqueDeclarationList *technique_list,
+ String *error_string);
+
+
+// Use the Technique grammar to parse an in-memory string buffer.
+// Inputs:
+// fx_string - a zero-terminated UTF8 string of the .fx file source.
+// shader_string - pointer to a String object that will be cleared.
+// sampler_list - pointer to a vector of SamplerState objects.
+// technique_list - pointer to a vector of TechniqueDeclaration objects.
+// error_string - pointer to a String object that will be cleared.
+// Returns:
+// shader_string - pointer to a String object containing the shader source.
+// sampler_list - pointer to a vector of SamplerState objects, each filled
+// in with fields parsed from the FX file.
+// technique_list - pointer to a vector of TechniqueDeclaration objects, each
+// filled with fields parsed from the FX file.
+// error_string - pointer to a String object containing parse errors,
+// if any.
+bool ParseFxString(
+ const String &fx_string,
+ String *shader_string,
+ SamplerStateList *sampler_list,
+ TechniqueDeclarationList *technique_list,
+ String *error_string);
+
+} // namespace o3d
+
+#endif // O3D_COMPILER_TECHNIQUE_TECHNIQUE_PARSER_H_
diff --git a/o3d/compiler/technique/technique_parser_test.cc b/o3d/compiler/technique/technique_parser_test.cc
new file mode 100644
index 0000000..ea2ca0a
--- /dev/null
+++ b/o3d/compiler/technique/technique_parser_test.cc
@@ -0,0 +1,414 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+//
+// Test program to exercise the Technique Antlr grammar using both files and
+// in-memory string buffers.
+
+#include "tests/common/win/testing_common.h"
+#include "compiler/technique/technique_parser.h"
+
+namespace o3d {
+
+// classes ---------------------------------------------------------------------
+
+class TechniqueParserTest : public testing::Test {
+ protected:
+ virtual void SetUp();
+ virtual void TearDown();
+ private:
+};
+
+void TechniqueParserTest::SetUp() {
+}
+
+void TechniqueParserTest::TearDown() {
+}
+
+// globals ---------------------------------------------------------------------
+
+char simple_fx_source[] =
+"float4x4 worldViewProj : WORLDVIEWPROJECTION; \
+void vs(in float4 pos, out float4 opos) { \
+ opos = mul(pos, worldViewProj); \
+} \
+float4 fs(): COLOR { \
+ return float3(0.33f, 0.57f, 0.10f); \
+} \
+technique t1 { \
+ pass p0 { \
+ VertexShader = compile vs_2_0 vs(); \
+ PixelShader = compile ps_2_0 fs(); \
+ } \
+} \
+";
+
+char lambert_fx_source[] =
+"struct a2v { \
+ float4 pos : POSITION; \
+ float3 normal : NORMAL; \
+}; \
+ \
+struct v2f { \
+ float4 pos : POSITION; \
+ float3 n : TEXCOORD0; \
+ float3 l : TEXCOORD1; \
+}; \
+ \
+float4x4 worldViewProj : WorldViewProjection; \
+float4x4 world : World; \
+float4x4 worldIT : WorldInverseTranspose; \
+float3 lightWorldPos; \
+float4 lightColor; \
+ \
+v2f vsMain(a2v IN) { \
+ v2f OUT; \
+ OUT.pos = mul(IN.pos, worldViewProj); \
+ OUT.n = mul(float4(IN.normal,0), worldIT).xyz; \
+ OUT.l = lightWorldPos-mul(IN.pos, world).xyz; \
+ return OUT; \
+} \
+ \
+float4 fsMain(v2f IN): COLOR { \
+ float3 l=normalize(IN.l); \
+ float3 n=normalize(IN.n); \
+ float4 litR=lit(dot(n,l),0,0); \
+ return emissive+lightColor*(ambient+diffuse*litR.y); \
+} \
+ \
+technique { \
+ pass p0 { \
+ VertexShader = compile vs_2_0 vsMain(); \
+ PixelShader = compile ps_2_0 fsMain(); \
+ } \
+} \
+";
+
+// -----------------------------------------------------------------------------
+
+TEST_F(TechniqueParserTest, ParseSimpleFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/simple.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_LT(0, static_cast<int>(technique_list.size()));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ("t1", technique_list[0].name);
+ ASSERT_EQ(0, technique_list[0].annotation.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("p0", technique_list[0].pass[0].name);
+ ASSERT_EQ(0, technique_list[0].pass[0].annotation.size());
+ EXPECT_EQ("vs", technique_list[0].pass[0].vertex_shader_entry);
+ EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments);
+ EXPECT_EQ("fs", technique_list[0].pass[0].fragment_shader_entry);
+ EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments);
+ ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size());
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseSimpleFXFromString) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ EXPECT_TRUE(ParseFxString(simple_fx_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_LT(0, static_cast<int>(technique_list.size()));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ("t1", technique_list[0].name);
+ ASSERT_EQ(0, technique_list[0].annotation.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("p0", technique_list[0].pass[0].name);
+ ASSERT_EQ(0, technique_list[0].pass[0].annotation.size());
+ EXPECT_EQ("vs", technique_list[0].pass[0].vertex_shader_entry);
+ EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments);
+ EXPECT_EQ("fs", technique_list[0].pass[0].fragment_shader_entry);
+ EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments);
+ ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size());
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseLambertFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/lambert.fx";
+ EXPECT_TRUE(ParseFxFile(filepath.c_str(),
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_LT(0, static_cast<int>(technique_list.size()));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ("", technique_list[0].name);
+ ASSERT_EQ(0, technique_list[0].annotation.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("p0", technique_list[0].pass[0].name);
+ ASSERT_EQ(0, technique_list[0].pass[0].annotation.size());
+ EXPECT_EQ("vsMain", technique_list[0].pass[0].vertex_shader_entry);
+ EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments);
+ EXPECT_EQ("fsMain", technique_list[0].pass[0].fragment_shader_entry);
+ EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments);
+ ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size());
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseLambertFXFromString) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ EXPECT_TRUE(ParseFxString(lambert_fx_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_LT(0, static_cast<int>(technique_list.size()));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ("", technique_list[0].name);
+ ASSERT_EQ(0, technique_list[0].annotation.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("p0", technique_list[0].pass[0].name);
+ ASSERT_EQ(0, technique_list[0].pass[0].annotation.size());
+ EXPECT_EQ("vsMain", technique_list[0].pass[0].vertex_shader_entry);
+ EXPECT_EQ("vs_2_0", technique_list[0].pass[0].vertex_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments);
+ EXPECT_EQ("fsMain", technique_list[0].pass[0].fragment_shader_entry);
+ EXPECT_EQ("ps_2_0", technique_list[0].pass[0].fragment_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments);
+ ASSERT_EQ(0, technique_list[0].pass[0].state_assignment.size());
+ ASSERT_EQ(0, sampler_list.size());
+}
+
+
+
+// Test the longer shaders from files ------------------------------------------
+
+TEST_F(TechniqueParserTest, ParseNoShaderFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/noshader.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_LT(0, static_cast<int>(technique_list.size()));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ("t1", technique_list[0].name);
+ ASSERT_EQ(0, technique_list[0].annotation.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("p0", technique_list[0].pass[0].name);
+ ASSERT_EQ(0, technique_list[0].pass[0].annotation.size());
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_entry);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].vertex_shader_arguments);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_entry);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_profile);
+ EXPECT_EQ("", technique_list[0].pass[0].fragment_shader_arguments);
+ ASSERT_EQ(4, technique_list[0].pass[0].state_assignment.size());
+ EXPECT_EQ("ZEnable", technique_list[0].pass[0].state_assignment[0].name);
+ EXPECT_EQ("true", technique_list[0].pass[0].state_assignment[0].value);
+ EXPECT_EQ("ZWriteEnable", technique_list[0].pass[0].state_assignment[1].name);
+ EXPECT_EQ("true", technique_list[0].pass[0].state_assignment[1].value);
+ EXPECT_EQ("ZFunc", technique_list[0].pass[0].state_assignment[2].name);
+ EXPECT_EQ("LessEqual", technique_list[0].pass[0].state_assignment[2].value);
+ EXPECT_EQ("CullMode", technique_list[0].pass[0].state_assignment[3].name);
+ EXPECT_EQ("None", technique_list[0].pass[0].state_assignment[3].value);
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseNoTechniqueFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/notechnique.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(0, technique_list.size());
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseFurFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/fur.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ ASSERT_EQ(1, technique_list.size());
+ EXPECT_EQ(1, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseShadowMapFXFromFile) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/shadow_map.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ ASSERT_EQ(2, technique_list.size());
+ EXPECT_EQ(2, sampler_list.size());
+}
+
+
+
+// Tests of error cases --------------------------------------------------------
+
+TEST_F(TechniqueParserTest, ParseEmptyString) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String empty_fx_source = "";
+ EXPECT_TRUE(ParseFxString(empty_fx_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(0, technique_list.size());
+ EXPECT_EQ(String(""), shader_source);
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseInvalidString) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String invalid_fx_source = "$%^~ This is an invalid shader.";
+ EXPECT_FALSE(ParseFxString(invalid_fx_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(0, technique_list.size());
+ EXPECT_EQ(0, sampler_list.size());
+ // TODO: make sure the string was rejected as an invalid HLSL
+ // program and test the parser errors.
+}
+
+TEST_F(TechniqueParserTest, ParseInvalidFilename) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/invalid_filename.fx";
+ EXPECT_FALSE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(technique_list.size(), 0);
+ EXPECT_EQ(shader_source, String(""));
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseInvalidPassIdentifier) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String invalid_pass_identifier_source = "technique { pass pass { } };";
+ EXPECT_FALSE(ParseFxString(invalid_pass_identifier_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(1, technique_list.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("", technique_list[0].pass[0].name);
+ EXPECT_EQ(shader_source, String(""));
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseInvalidStateName) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ // NOTE: "FragmentShader" should read "FragmentProgram" or "PixelShader".
+ String invalid_pass_identifier_source =
+ "technique { pass { FragmentShader = compile ps_2_0 nothing(); } };";
+ EXPECT_FALSE(ParseFxString(invalid_pass_identifier_source,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(1, technique_list.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ EXPECT_EQ("", technique_list[0].pass[0].name);
+ EXPECT_EQ(shader_source, String(""));
+ EXPECT_EQ(0, sampler_list.size());
+}
+
+TEST_F(TechniqueParserTest, ParseSampler) {
+ String shader_source, error_string;
+ TechniqueDeclarationList technique_list;
+ SamplerStateList sampler_list;
+ String filepath = *g_program_path + "/unittest_data/sampler_test.fx";
+ EXPECT_TRUE(ParseFxFile(filepath,
+ &shader_source,
+ &sampler_list,
+ &technique_list,
+ &error_string));
+ EXPECT_EQ(1, technique_list.size());
+ ASSERT_EQ(1, technique_list[0].pass.size());
+ ASSERT_EQ(1, sampler_list.size());
+ EXPECT_EQ("Tex0", sampler_list[0].texture);
+ EXPECT_EQ("Linear", sampler_list[0].min_filter);
+ EXPECT_EQ("Point", sampler_list[0].mag_filter);
+ EXPECT_EQ("None", sampler_list[0].mip_filter);
+ EXPECT_EQ("Mirror", sampler_list[0].address_u);
+ EXPECT_EQ("Wrap", sampler_list[0].address_v);
+ EXPECT_EQ("Clamp", sampler_list[0].address_w);
+ EXPECT_EQ("16", sampler_list[0].max_anisotropy);
+ EXPECT_EQ("float4(1.0, 0.0, 0.0, 1.0)", sampler_list[0].border_color);
+}
+
+} // namespace o3d
diff --git a/o3d/compiler/technique/technique_structures.cc b/o3d/compiler/technique/technique_structures.cc
new file mode 100644
index 0000000..f32253d
--- /dev/null
+++ b/o3d/compiler/technique/technique_structures.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include <algorithm>
+#include "base/logging.h"
+#include "base/cross/std_functional.h"
+#include "compiler/technique/technique_structures.h"
+
+namespace o3d {
+
+void TechniqueDeclaration::clear() {
+ name.clear();
+ annotation.clear();
+ pass.clear();
+}
+
+void TechniqueDeclaration::dump() {
+ DLOG(INFO) << "Dump of Technique \"" << name << "\"";
+ DLOG(INFO) << "Technique Annotation count = " << annotation.size();
+ std::for_each(annotation.begin(),
+ annotation.end(),
+ std::mem_fun_ref(&Annotation::dump));
+ DLOG(INFO) << "Pass count = " << pass.size();
+ std::for_each(pass.begin(),
+ pass.end(),
+ std::mem_fun_ref(&PassDeclaration::dump));
+}
+
+void PassDeclaration::dump() {
+ DLOG(INFO) << "Pass \"" << name << "\"";
+ DLOG(INFO) << "Pass Annotation count = " << annotation.size();
+ std::for_each(annotation.begin(),
+ annotation.end(),
+ std::mem_fun_ref(&Annotation::dump));
+ DLOG(INFO) << "Vertex shader \"" << vertex_shader_entry << "\"";
+ DLOG(INFO) << "Vertex profile \"" << vertex_shader_profile << "\"";
+ DLOG(INFO) << "Vertex args \"" << vertex_shader_arguments << "\"";
+ DLOG(INFO) << "Fragment shader \"" << fragment_shader_entry << "\"";
+ DLOG(INFO) << "Fragment profile \"" << fragment_shader_profile << "\"";
+ DLOG(INFO) << "Fragment args \"" << fragment_shader_arguments << "\"";
+ DLOG(INFO) << "State Assignment count = " << state_assignment.size();
+ std::for_each(state_assignment.begin(),
+ state_assignment.end(),
+ std::mem_fun_ref(&StateAssignment::dump));
+}
+
+void StateAssignment::dump() {
+ DLOG(INFO) << "State assignment name \"" << name << "\"";
+ DLOG(INFO) << "State assignment value \"" << value << "\"";
+}
+
+void Annotation::dump() {
+ DLOG(INFO) << "Annotation name \"" << name << "\"";
+ DLOG(INFO) << "Annotation type \"" << type << "\"";
+ DLOG(INFO) << "Annotation value \"" << value << "\"";
+}
+
+} // namespace o3d
diff --git a/o3d/compiler/technique/technique_structures.h b/o3d/compiler/technique/technique_structures.h
new file mode 100644
index 0000000..ec7607a
--- /dev/null
+++ b/o3d/compiler/technique/technique_structures.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2009, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#ifndef O3D_COMPILER_TECHNIQUE_TECHNIQUE_STRUCTURES_H_
+#define O3D_COMPILER_TECHNIQUE_TECHNIQUE_STRUCTURES_H_
+
+#include <vector>
+#include "core/cross/types.h"
+
+namespace o3d {
+
+// typedefs --------------------------------------------------------------------
+
+class TechniqueDeclaration;
+class SamplerState;
+
+typedef std::vector<TechniqueDeclaration> TechniqueDeclarationList;
+typedef std::vector<SamplerState> SamplerStateList;
+
+// classes ---------------------------------------------------------------------
+
+// A set of simple data classes that hold the structured information
+// uncovered by the Technique parser. All values are public as providing
+// accessors for each member would be pretty pointless. If a field is
+// missing in the parsed FX file the matching field will either hold an
+// empty string or have zero entries in the container.
+//
+// TODO: if it proves necessary, interpret the "value" fields into
+// binary form as opposed to the current model of leaving them as strings.
+
+class Annotation {
+ public:
+ Annotation() {}
+ Annotation(String t, String n, String v) : type(t), name(n), value(v) {}
+ ~Annotation() {}
+ void dump();
+
+ String type;
+ String name;
+ String value;
+};
+
+class StateAssignment {
+ public:
+ StateAssignment() {}
+ StateAssignment(String n, String v) : name(n), value(v) {}
+ ~StateAssignment() {}
+ void dump();
+
+ String name;
+ String value;
+};
+
+class PassDeclaration {
+ public:
+ PassDeclaration() {}
+ explicit PassDeclaration(String n) : name(n) {}
+ ~PassDeclaration() {}
+ void dump();
+
+ String name;
+ std::vector<Annotation> annotation;
+ String vertex_shader_entry;
+ String vertex_shader_profile;
+ String vertex_shader_arguments;
+ String fragment_shader_entry;
+ String fragment_shader_profile;
+ String fragment_shader_arguments;
+ std::vector<StateAssignment> state_assignment;
+};
+
+class TechniqueDeclaration {
+ public:
+ TechniqueDeclaration() {}
+ ~TechniqueDeclaration() {}
+ void clear();
+ void dump();
+
+ String name;
+ std::vector<Annotation> annotation;
+ std::vector<PassDeclaration> pass;
+};
+
+class SamplerState {
+ public:
+ SamplerState() {}
+ ~SamplerState() {}
+
+ String name;
+ String texture;
+ String address_u;
+ String address_v;
+ String address_w;
+ String min_filter;
+ String mag_filter;
+ String mip_filter;
+ String border_color;
+ String max_anisotropy;
+};
+
+} // namespeace o3d
+
+#endif // O3D_COMPILER_TECHNIQUE_TECHNIQUE_STRUCTURES_H_
diff --git a/o3d/compiler/technique/test_data/HLSL_declarations.fx b/o3d/compiler/technique/test_data/HLSL_declarations.fx
new file mode 100644
index 0000000..55c927a
--- /dev/null
+++ b/o3d/compiler/technique/test_data/HLSL_declarations.fx
@@ -0,0 +1,30 @@
+// Variable declarations ----------------------------
+
+extern aa;
+nointerpolation ab;
+shared ac;
+static ad;
+uniform ae;
+volatile af;
+
+static uniform nointerpolation ag;
+shared extern const column_major ah;
+
+extern const ai;
+shared const aj;
+static const ak;
+uniform const al;
+
+static row_major float2x2 am;
+uniform column_major float3x2 an;
+
+
+
+// Geometry Shader ----------------
+
+Buffer<float4> g_Buffer;
+
+float4 geom_fn() {
+ float4 bufferdata = g_Buffer.Load(1);
+ return bufferdata;
+}
diff --git a/o3d/compiler/technique/test_data/fur.fx b/o3d/compiler/technique/test_data/fur.fx
new file mode 100644
index 0000000..6c326a6
--- /dev/null
+++ b/o3d/compiler/technique/test_data/fur.fx
@@ -0,0 +1,121 @@
+/*****************************************************************************/
+/* */
+/* File: fur.fx */
+/* */
+/*****************************************************************************/
+
+// fur.fx
+
+//---------------------------------------------------------------------------//
+
+int shellcount = 20;
+int shellnumber = 0;
+
+float FurScale = 0;
+float FurLength = 0;
+float UVScale = 0;
+
+
+texture FurTexture
+<
+ string TextureType = "2D";
+>;
+
+
+// transformations
+float4x4 worldViewProj : WORLDVIEWPROJ;
+
+//------------------------------------
+struct vertexInput {
+ float3 position : POSITION;
+ float3 normal : NORMAL;
+ //float4 color : COLOR0;
+ float4 texCoordDiffuse : TEXCOORD0;
+ float4 tex1 : TEXCOORD1;
+};
+
+struct vertexOutput {
+ float4 HPOS : POSITION;
+ //float4 color : COLOR;
+ float4 T0 : TEXCOORD0;
+ float3 normal : TEXCOORD1;
+
+};
+
+
+//------------------------------------
+vertexOutput VS_TransformAndTexture(vertexInput IN)
+{
+ vertexOutput OUT;
+
+ //float3 P = IN.position.xyz;
+ //float3 P = IN.position.xyz + (IN.normal * (FurDistance * (float)shellnumber));
+
+ //float3 P = IN.position.xyz + (IN.normal * FurScale * 10.0f) + (IN.normal*FurLength);
+ //float3 P = IN.position.xyz + (IN.normal * FurScale * 10.0f) + (IN.normal*FurLength);
+
+ float3 P = IN.position.xyz + (IN.normal * FurLength);
+
+ //OUT.T0 = IN.texCoordDiffuse * 2.0f;
+ //OUT.T0 = IN.tex1 * FurScale;
+ OUT.T0 = IN.texCoordDiffuse * UVScale;
+ //OUT.T0 = IN.tex1 / 3.0f;
+ OUT.HPOS = mul(float4(P, 1.0f), worldViewProj);
+ //OUT.color = IN.color;
+ OUT.normal = IN.normal;
+ return OUT;
+}
+
+
+//------------------------------------
+sampler TextureSampler = sampler_state
+{
+ texture = <FurTexture>;
+ AddressU = WRAP;
+ AddressV = WRAP;
+ AddressW = WRAP;
+ MIPFILTER = LINEAR;
+ MINFILTER = LINEAR;
+ MAGFILTER = LINEAR;
+};
+
+
+//-----------------------------------
+float4 PS_Textured( vertexOutput IN): COLOR
+{
+ float4 diffuseTexture = tex2D( TextureSampler, IN.T0 );
+ //float4 diffuseTexture2 = tex2D( TextureSampler2, IN.T0 );
+
+ //return (float4(furColor.xyz, FurStrength) * diffuseTexture);
+ return diffuseTexture;
+ //return float4(0.0f, 1.0f, 1.0f, 0.3f); //rrggbbaa
+}
+
+//-----------------------------------
+
+technique Fur
+{
+ pass Shell
+ <
+ string script="Draw=Geometry;";
+ >
+ {
+ VertexShader = compile vs_1_1 VS_TransformAndTexture();
+ PixelShader = compile ps_1_3 PS_Textured();
+ AlphaBlendEnable = true;
+ SrcBlend = srcalpha;
+ //DestBlend = one;
+ DestBlend = invsrcalpha;
+ //DestBlend = srccolor;
+ //DestBlend = invsrccolor;
+ //DestBlend = srcalpha;
+ //DestBlend = destalpha;
+ //DestBlend = invdestalpha;
+ //DestBlend = destcolor;
+ //DestBlend = invdestcolor;
+
+ //CullMode = None;
+ //CullMode = CCW;
+ }
+}
+
diff --git a/o3d/compiler/technique/test_data/lambert.fx b/o3d/compiler/technique/test_data/lambert.fx
new file mode 100644
index 0000000..b3f34b0
--- /dev/null
+++ b/o3d/compiler/technique/test_data/lambert.fx
@@ -0,0 +1,38 @@
+struct a2v {
+ float4 pos : POSITION;
+ float3 normal : NORMAL;
+};
+
+struct v2f {
+ float4 pos : POSITION;
+ float3 n : TEXCOORD0;
+ float3 l : TEXCOORD1;
+};
+
+float4x4 worldViewProj : WorldViewProjection;
+float4x4 world : World;
+float4x4 worldIT : WorldInverseTranspose;
+float3 lightWorldPos;
+float4 lightColor;
+
+v2f vsMain(a2v IN) {
+ v2f OUT;
+ OUT.pos = mul(IN.pos, worldViewProj);
+ OUT.n = mul(float4(IN.normal,0), worldIT).xyz;
+ OUT.l = lightWorldPos-mul(IN.pos, world).xyz;
+ return OUT;
+}
+
+float4 fsMain(v2f IN): COLOR {
+ float3 l=normalize(IN.l);
+ float3 n=normalize(IN.n);
+ float4 litR=lit(dot(n,l),0,0);
+ return emissive+lightColor*(ambient+diffuse*litR.y);
+}
+
+technique {
+ pass p0 {
+ VertexShader = compile vs_2_0 vsMain();
+ PixelShader = compile ps_2_0 fsMain();
+ }
+}
diff --git a/o3d/compiler/technique/test_data/noshader.fx b/o3d/compiler/technique/test_data/noshader.fx
new file mode 100644
index 0000000..13a4924
--- /dev/null
+++ b/o3d/compiler/technique/test_data/noshader.fx
@@ -0,0 +1,8 @@
+technique t1 {
+ pass p0 {
+ ZEnable = true;
+ ZWriteEnable = true;
+ ZFunc = LessEqual;
+ CullMode = None;
+ }
+}
diff --git a/o3d/compiler/technique/test_data/notechnique.fx b/o3d/compiler/technique/test_data/notechnique.fx
new file mode 100644
index 0000000..2201243
--- /dev/null
+++ b/o3d/compiler/technique/test_data/notechnique.fx
@@ -0,0 +1,7 @@
+float4x4 worldViewProj : WORLDVIEWPROJECTION;
+void vs(in float4 pos, out float4 opos) {
+ opos = mul(pos, worldViewProj);
+}
+float4 fs(): COLOR {
+ return float3(0.33f, 0.57f, 0.10f);
+}
diff --git a/o3d/compiler/technique/test_data/sampler_test.fx b/o3d/compiler/technique/test_data/sampler_test.fx
new file mode 100644
index 0000000..12bcc61
--- /dev/null
+++ b/o3d/compiler/technique/test_data/sampler_test.fx
@@ -0,0 +1,54 @@
+// texture
+texture Tex0 : DiffuseMap <
+ string name = "tiger.bmp";
+ string UIName = "Base Texture";
+ >;
+
+// transformations
+float4x4 worldViewProj : WORLDVIEWPROJECTION;
+
+struct VS_OUTPUT
+{
+ float4 position : POSITION;
+ float2 texcoord : TEXCOORD0;
+};
+
+VS_OUTPUT VS(VS_OUTPUT IN) {
+ VS_OUTPUT Out = (VS_OUTPUT)0;
+ Out.position = mul(IN.position, worldViewProj);
+ Out.texcoord = IN.texcoord;
+ return Out;
+}
+
+sampler Sampler = sampler_state
+{
+ Texture = (Tex0);
+ MinFilter = Linear;
+ MagFilter = Point;
+ MipFilter = None;
+ AddressU = Mirror;
+ AddressV = Wrap;
+ AddressW = Clamp;
+ MaxAnisotropy = 16;
+ BorderColor = float4(1.0, 0.0, 0.0, 1.0);
+};
+
+
+float4 PS(VS_OUTPUT IN) : COLOR
+{
+ float4 color = tex2D(Sampler, IN.texcoord);
+ return color ;
+}
+
+
+technique DefaultTechnique
+{
+ pass P0
+ {
+ // shaders
+ CullMode = None;
+ VertexShader = compile vs_2_0 VS();
+ PixelShader = compile ps_2_0 PS();
+ }
+}
+
diff --git a/o3d/compiler/technique/test_data/shadow_map.fx b/o3d/compiler/technique/test_data/shadow_map.fx
new file mode 100644
index 0000000..b4f1c88
--- /dev/null
+++ b/o3d/compiler/technique/test_data/shadow_map.fx
@@ -0,0 +1,170 @@
+// Shader from NVidia example documentation:
+// ftp://download.nvidia.com/developer/SDK/Individual_Samples/
+// MEDIA/docPix/docs/FX_Shadowing.pdf
+
+texture CTex : RENDERCOLORTARGET <
+ float2 Dimensions = {256,256};
+ string Format = "x8b8g8r8" ;
+ string UIWidget = "None";
+>;
+
+sampler CSamp = sampler_state {
+ texture = <CTex>;
+ AddressU = CLAMP; AddressV = CLAMP;
+ MipFilter = NONE;
+ MinFilter = LINEAR;
+ MagFilter = LINEAR;
+};
+
+texture DTex : RENDERDEPTHSTENCILTARGET <
+ float2 Dimensions = {256,256};
+ string format = "D24S8_SHADOWMAP";
+ string UIWidget = "None";
+>;
+
+sampler DSamp = sampler_state {
+ texture = <DTex>;
+ AddressU = CLAMP; AddressV = CLAMP;
+ MipFilter = NONE;
+ MinFilter = LINEAR;
+ MagFilter = LINEAR;
+};
+
+float Script : STANDARDSGLOBAL <
+ string UIWidget = "none";
+ string ScriptClass = "sceneorobject";
+ string ScriptOrder = "standard";
+ string ScriptOutput = "color";
+ string Script = "Tech=Technique?Shadowed:Unshadowed;";
+> = 0.8; // version #
+
+// The following global variables are values to be used
+// when clearing color and/or depth buffers
+float4 ClearColor <
+ string UIWidget = "color";
+ string UIName = "background";
+> = {0,0,0,0.0};
+
+float ClearDepth <
+ string UIWidget = "none";
+> = 1.0;
+
+float4 ShadowClearColor <
+ string UIWidget = "none";
+> = {1,1,1,0.0};
+
+void lightingCalc(ShadowingVertexOutput IN,
+ out float3 litContrib,
+ out float3 ambiContrib) {
+ float3 Nn = normalize(IN.WNormal);
+ float3 Vn = normalize(IN.WView);
+ Nn = faceforward(Nn,-Vn,Nn);
+ float falloff = 1.0 / dot(IN.LightVec,IN.LightVec);
+ float3 Ln = normalize(IN.LightVec);
+ float3 Hn = normalize(Vn + Ln);
+ float hdn = dot(Hn,Nn);
+ float ldn = dot(Ln,Nn);
+ float4 litVec = lit(ldn,hdn,SpecExpon);
+ ldn = litVec.y * SpotLightIntensity;
+ ambiContrib = SurfColor * AmbiLightColor;
+ float3 diffContrib = SurfColor*(Kd * ldn * SpotLightColor);
+ float3 specContrib = ((ldn * litVec.z * Ks) * SpotLightColor);
+ float3 result = diffContrib + specContrib;
+ float cone = tex2Dproj(SpotSamp,IN.LProj);
+ litContrib = ((cone*falloff) * result);
+}
+
+float4 useShadowPS(ShadowingVertexOutput IN) : COLOR {
+ float3 litPart, ambiPart;
+ lightingCalc(IN,litPart,ambiPart);
+ float4 shadowed = tex2Dproj(ShadDepthSampler,IN.LProj);
+ return float4((shadowed.x*litPart)+ambiPart,1);
+}
+
+float4 unshadowedPS(ShadowingVertexOutput IN) : COLOR {
+ float3 litPart, ambiPart;
+ lightingCalc(IN,litPart,ambiPart);
+}
+
+technique Unshadowed <
+ string Script = "Pass=NoShadow;";
+> {
+ pass NoShadow <
+ string Script =
+ "RenderColorTarget0=;"
+ "RenderDepthStencilTarget=;"
+ "RenderPort=;"
+ "ClearSetColor=ClearColor;"
+ "ClearSetDepth=ClearDepth;"
+ "ClearDepth=Color;"
+ "Clear=Depth;"
+ "Draw=geometry;";
+ > {
+ VertexShader = compile vs_2_0
+ shadowUseVS(WorldXf,
+ WorldITXf,
+ WorldViewProjXf,
+ ShadowViewProjXf,
+ ViewIXf,
+ ShadBiasXf,
+ SpotLightPos);
+ ZEnable = true;
+ ZWriteEnable = true;
+ ZFunc = LessEqual;
+ CullMode = None;
+ PixelShader = compile ps_2_a unshadowedPS();
+ }
+}
+
+technique Shadowed <
+ string Script = "Pass=MakeShadow;"
+ "Pass=UseShadow;";
+> {
+ pass MakeShadow <
+ string Script =
+ "RenderColorTarget0=ColorShadMap;"
+ "RenderDepthStencilTarget=ShadDepthTarget;"
+ "RenderPort=light0;"
+ "ClearSetColor=ShadowClearColor;"
+ "ClearSetDepth=ClearDepth;"
+ "Clear=Color;"
+ "Clear=Depth;"
+ "Draw=geometry;";
+ > {
+ VertexShader = compile vs_2_0
+ shadowGenVS(WorldXf,
+ WorldITXf,
+ ShadowViewProjXf);
+ ZEnable = true;
+ ZWriteEnable = true;
+ ZFunc = LessEqual;
+ CullMode = None;
+ // no pixel shader needed!
+ }
+
+ pass UseShadow <
+ string Script =
+ "RenderColorTarget0=;"
+ "RenderDepthStencilTarget=;"
+ " RenderPort=;"
+ "ClearSetColor=ClearColor;"
+ "ClearSetDepth=ClearDepth;"
+ "Clear=Color;"
+ "Clear=Depth;"
+ "Draw=geometry;";
+ > {
+ VertexShader = compile vs_2_0
+ shadowUseVS(WorldXf,
+ WorldITXf,
+ WorldViewProjXf,
+ ShadowViewProjXf,
+ ViewIXf,
+ ShadBiasXf,
+ SpotLightPos);
+ ZEnable = true;
+ ZWriteEnable = true;
+ ZFunc = LessEqual;
+ CullMode = None;
+ PixelShader = compile ps_2_a useShadowPS();
+ }
+}
diff --git a/o3d/compiler/technique/test_data/simple.fx b/o3d/compiler/technique/test_data/simple.fx
new file mode 100644
index 0000000..5c707429
--- /dev/null
+++ b/o3d/compiler/technique/test_data/simple.fx
@@ -0,0 +1,13 @@
+float4x4 worldViewProj : WORLDVIEWPROJECTION;
+void vs(in float4 pos, out float4 opos) {
+ opos = mul(pos, worldViewProj);
+}
+float4 fs(): COLOR {
+ return float3(0.33f, 0.57f, 0.10f);
+}
+technique t1 {
+ pass p0 {
+ VertexShader = compile vs_2_0 vs();
+ PixelShader = compile ps_2_0 fs();
+ }
+}