summaryrefslogtreecommitdiffstats
path: root/o3d/compiler
diff options
context:
space:
mode:
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();
+ }
+}