Appendix A: Scene File Grammar

This appendix contains the formal syntax of the mental images .mi scene description format. The grammar is in yacc format; yacc is a Unix compiler generator. Nonterminals that begin with T_ are typed values:

T_SYMBOL
is an unquoted string consisting of zero or more is an unquoted string consisting of zero or more letters, numbers, and underscores and does not begin with a number.

T_INTEGER
is a nonempty sequence of numerical digits. is a nonempty sequence of numerical digits.

T_FLOAT
is a nonempty sequence of digits, followed by a is a nonempty sequence of digits, followed by a period, followed by a nonempty sequence of digits.

T_STRING
is a sequence of arbitrary printable characters is a sequence of arbitrary printable characters enclosed in double quotes. Nonprintables such as newlines are not allowed. Backslash and double quote characters that should be part of the string must be prefixed with a backslash.

T_BYTE_STRING
is a sequence of hexadecimal bytes, each is a sequence of hexadecimal bytes, each consisting of two characters in the range 0..9 or a..f. Line breaks are allowed between bytes. Other characters are not allowed.

T_VECTOR
is a backquote followed by 12 bytes followed by is a backquote followed by 12 bytes followed by a backquote. The 12 bytes are the binary image of three floats, not swapped.

This appendix is intended to aid translator writers, and to describe the relationship between the .mi scene description language and the API available to geometry shader writers. Note that the grammars used by mental ray 1.9 and mental ray 2.0 are arranged in a slightly different way, but functionally the 2.0 grammar is a fully compatible superset of the 1.9 grammar with added features such as instancing. Obsolete language features are not listed.

= pcrr at 7.0pt -2pt

=|=0 \=12 |obeylines|gdef|doverbatim#1#1|endgroup

%{
%union {
        miBoolean        boolean;
        char            *symbol;
        char            *string;
        struct          {
                int      len;
                miUchar *bytes;
        }                byte_string;
        int              integer;
        double           floating;
        miMatrix         matrix;
        miVector         vector;
        miGeoVector      geovector;
        miTransform     *transform;
        miParameter     *para_type;
        miDlist         *dlist;
        miTag            tag;
}

%token <symbol>         T_SYMBOL
%token <integer>        T_INTEGER
%token <floating>       T_FLOAT
%token <string>         T_STRING
%token <byte_string>    T_BYTE_STRING
%token <vector>         T_VECTOR

%token ACCELERATION ACCURACY ADAPTIVE ALL ANGLE APERTURE APPLY APPROXIMATE
%token ARRAY ASPECT
%token BACK BASIS BEZIER BLUE BOOLEAN BOTH BOX BSP BSPLINE BUMP
%token CALL CAMERA CARDINAL CAUSTIC CLASSIFICATION CLIP CODE COLOR COMPLEXITY
%token CONE CONNECT CONSTANT CONTOUR CONTRAST CP CURVATURE CURVE
%token D DEBUG_ DECLARE DELETE_ DEPTH DERIVATIVE DESATURATE DIRECTION DISC
%token DISPLACE DISTANCE DITHER
%token ECHO EMITTER END ENVIRONMENT EVEN ENERGY EXPONENT
%token FACE FALSE_ FAN FIELD FILE_ FILTER FOCAL FRAME FRONT
%token GAMMA GAUSS GEOMETRY GLOBILLUM GREEN GRID GROUP
%token HIDE HOLE
%token IMP IMPLICIT INCREMENTAL INFINITY_ INHERITANCE INSTANCE INSTGROUP
%token INTEGER INTERFACE
%token JITTER
%token LENGTH LENS LIGHT LINK LOCAL
%token M MAPSTO MATERIAL MATRIX MAX MEMORY MERGE MESH MI MIN MIXED MOTION
%token N NOCONTOUR NULL_
%token OBJECT ODD OFF ON OPAQUE_ OPTIONS ORIGIN OUTPUT
%token P PARAMETRIC PHENOMENON PHOTON PHOTONMAP PHOTONS PHOTONVOL PREMULTIPLY
%token PRIORITY
%token QUALITY
%token RATIONAL RAY RAYCL RECTANGLE RECURSIVE
%token REBUILD
%token RED RENDER RESOLUTION ROOT
%token SAMPLES SCALAR SCANLINE SEGMENTS SET SHADOW SHADOWMAP SHUTTER SIZE
%token SOFTNESS SORT SPACE SPATIAL SPDL SPECIAL SPHERE SPREAD STORE STRING
%token STRIP STRUCT SUBDIVISION SHADER SMART SURFACE SYSTEM
%token T TAG TAGGED TASK TAYLOR TEXTURE TIME TRACE TRANSFORM TREE TRIANGLE TRIM
%token TRUE_
%token U V VALUE VECTOR VERBOSE VERSION VIEW VISIBLE VOLUME
%token W WHITE WIDTH WINDOW WORLD

%type <floating>                floating
%type <boolean>                 boolean
%type <string>                  symbol
%type <string>                  opt_symbol
%type <matrix>                  transform
%type <matrix>                  obj_transform
%type <integer>                 tex_flags
%type <integer>                 tex_flag
%type <integer>                 tex_type
%type <integer>                 simple_type
%type <string>                  inst_item
%type <tag>                     inst_func
%type <tag>                     inst_params
%type <integer>                 filter_type
%type <tag>                     function
%type <tag>                     function_list
%type <tag>                     tex_func_list
%type <tag>                     phen_root
%type <string>                  mtl_or_label
%type <para_type>               shret_type
%type <para_type>               shret_type_nosh
%type <para_type>               shret_decl_seq
%type <para_type>               shret_decl
%type <para_type>               parm_decl_list
%type <para_type>               parm_decl_seq
%type <para_type>               parm_decl
%type <boolean>                 rational
%type <dlist>                   basis_matrix
%type <floating>                merge_option
%type <vector>                  vector
%type <geovector>               geovector
%type <dlist>                   para_list
%type <boolean>                 opt_volume_flag
%type <boolean>                 opt_vector_flag
%type <boolean>                 opt_incremental
%type <integer>                 apply
%type <integer>                 apply_list

%%

start           :
                        { functag = 0;
                          mi_api_incremental(is_incremental = miFALSE); }
                  command_list
                |
                ;


/*-----------------------------------------------------------------------------
 * primitive types
 *---------------------------------------------------------------------------*/

boolean         : ON
                        { $$ = miTRUE; }
                | OFF
                        { $$ = miFALSE; }
                | TRUE_
                        { $$ = miTRUE; }
                | FALSE_
                        { $$ = miFALSE; }
                ;

floating        : T_FLOAT       { $$ = $1; }
                | T_INTEGER     { $$ = $1; }
                ;

vector          : floating floating floating
                        { $$.x = $1; $$.y = $2; $$.z = $3; }
                | T_VECTOR
                        { $$ = $1; }
                ;

geovector       : floating floating floating
                        { $$.x = $1; $$.y = $2; $$.z = $3; }
                | T_VECTOR
                        { $$.z = $1.z; $$.y = $1.y; $$.x = $1.x; }
                ;

transform       : TRANSFORM     floating floating floating floating
                                floating floating floating floating
                                floating floating floating floating
                                floating floating floating floating
                        { $$[0] = $2;  $$[1] = $3;  $$[2] = $4;  $$[3] = $5;
                          $$[4] = $6;  $$[5] = $7;  $$[6] = $8;  $$[7] = $9;
                          $$[8] = $10; $$[9] = $11; $$[10]= $12; $$[11]= $13;
                          $$[12]= $14; $$[13]= $15; $$[14]= $16; $$[15]= $17; }
                ;

symbol          : T_SYMBOL
                        { $$ = $1; }
                | T_STRING
                        { $$ = $1; }
                ;

opt_symbol      :
                        { $$ = 0; }
                | symbol
                        { $$ = $1; }
                ;


/*-----------------------------------------------------------------------------
 * top-level commands
 *---------------------------------------------------------------------------*/

command_list    :       { mi_api_incremental(is_incremental = miFALSE); }
                  command
                | command_list
                        { mi_api_incremental(is_incremental = miFALSE); }
                  command
                ;

command         : frame
                | debug
                | set
                | call
                | version
                | incr_command
                | INCREMENTAL
                        { mi_api_incremental(is_incremental = miTRUE); }
                  incr_command
                | DELETE_ symbol
                        { mi_api_delete($2); }
                | RENDER symbol symbol symbol
                        { mi_api_render($2, $3, $4,
                                         mi_mem_strdup(ctx->inheritance_func));
                          if (mi_get_subverbosity(miM_MI) & miMSG_PHASE)
                                mi_progress("resume mi scene file parsing");
                          yyreturn MIYYRENDER;
                        }
                | VERBOSE boolean
                        { if (!ctx->mi_force_verbose)
                                mi_set_verbosity($2? miERR_ALL & ~miERR_DEBUG
                                                               & ~miERR_VDEBUG
                                                   : miERR_FATAL|miERR_ERROR);}
                | VERBOSE T_INTEGER
                        { if (!ctx->mi_force_verbose)
                                mi_set_verbosity((1 << $2) - 1); }
                | ECHO T_STRING
                        { mi_info("%s", $2);
                          mi_mem_release($2); }
                | SYSTEM T_STRING
                        { if ((system ($2) >> 8) & 0xff)
                          mi_api_warning("system \"%s\" failed", $2);
                          mi_mem_release($2); }
                | MEMORY T_INTEGER
                        { mi_api_warning("memory view parameter ignored"); }
                | CODE T_STRING
                        { mi_link_file_add($2, miTRUE, miFALSE, miFALSE); }
                | CODE
                        { mi_api_code_verbatim_begin(); }
                  code_bytes_list
                        { mi_api_code_verbatim_end(); }
                | LINK T_STRING
                        { mi_link_file_add($2, miFALSE, miFALSE, miFALSE); }
                | DECLARE function_decl
                | DECLARE phenomenon_decl
                | REGISTRY symbol
                        { mi_api_registry_begin($2); }
                  reg_body END REGISTRY
                        { mi_api_registry_end(); }
                ;

reg_body        :
                | reg_item reg_body
                ;

reg_item        : VALUE symbol
                        { mi_api_registry_add(mi_mem_strdup("value"), $2); }
                | LINK symbol
                        { mi_api_registry_add(mi_mem_strdup("link"), $2); }
                | CODE symbol
                        { mi_api_registry_add(mi_mem_strdup("code"), $2); }
                | MI symbol
                        { mi_api_registry_add(mi_mem_strdup("mi"), $2); }
                | SPDL symbol
                        { mi_api_registry_add(mi_mem_strdup("spdl"), $2); }
                | ECHO symbol
                        { mi_api_registry_add(mi_mem_strdup("echo"), $2); }
                | SYSTEM symbol
                        { mi_api_registry_add(mi_mem_strdup("system"), $2); }
                | symbol symbol
                        { mi_api_registry_add($1, $2); }
                ;

incr_command    : options
                | camera
                | texture
                | material
                | light
                | instance
                | instgroup
                | object
                | SHADER symbol function_list
                        { mi_api_shader_add($2, $3); }
                ;

code_bytes_list : T_BYTE_STRING
                        { mi_api_code_byte_copy($1.len, $1.bytes); }
                | code_bytes_list T_BYTE_STRING
                        { mi_api_code_byte_copy($2.len, $2.bytes); }
                ;

set             : SET symbol
                        { mi_api_variable_set($2, 0); }
                | SET symbol symbol
                        { mi_api_variable_set($2, $3); }
                ;

call            : CALL function_list
                        { mi_api_shader_call($2, 0, 0); }
                | CALL function_list ',' symbol symbol
                        { mi_api_shader_call($2, $4, $5); }
                ;

debug           : DEBUG_ symbol opt_symbol
                        { mi_api_debug($2,$3); }
                ;

version         : VERSION T_STRING
                        { mi_api_version_check($2, 0);
                          ctx->mi_did_check_version = miTRUE; }
                | MIN VERSION T_STRING
                        { mi_api_version_check($3, 0);
                          ctx->mi_did_check_version = miTRUE; }
                | MAX VERSION T_STRING
                        { mi_api_version_check($3, 1);
                          ctx->mi_did_check_version = miTRUE; }
                ;


/*-----------------------------------------------------------------------------
 * options
 *---------------------------------------------------------------------------*/

options         : OPTIONS symbol
                        { options = mi_api_options_begin($2); }
                  option_list END OPTIONS
                        { mi_api_options_end(); }
                ;

option_list     :
                | option_list option_item
                ;

option_item     : optview_item
                | ACCELERATION RAYCL
                        { options->acceleration = 'c'; }
                | ACCELERATION BSP
                        { options->acceleration = 'b'; }
                | ACCELERATION GRID
                        { options->acceleration = 'g'; }
                | SAMPLES T_INTEGER
                        { options->min_samples = $2-2;
                          options->max_samples = $2; }
                | SAMPLES T_INTEGER T_INTEGER
                        { options->min_samples = $2;
                          options->max_samples = $3; }
                ;

optview_item    : SHADOW OFF
                        { options->shadow = 0; }
                | SHADOW ON
                        { options->shadow = 1; }
                | SHADOW SORT
                        { options->shadow = 'l'; }
                | SHADOW SEGMENTS
                        { options->shadow = 's'; }
                | TRACE boolean
                        { options->trace = $2; }
                | SCANLINE boolean
                        { options->scanline = $2; }
                | LENS boolean
                        { options->no_lens = !$2; }
                | VOLUME boolean
                        { options->no_volume = !$2; }
                | GEOMETRY boolean
                        { options->no_geometry = !$2; }
                | DISPLACE boolean
                        { options->no_displace = !$2; }
                | OUTPUT boolean
                        { options->no_output = !$2; }
                | MERGE boolean
                        { options->no_merge = !$2; }
                | FILTER filter_type floating
                        { options->filter        = $2;
                          options->filter_size_x =
                          options->filter_size_y = $3; }
                | FILTER filter_type floating floating
                        { options->filter        = $2;
                          options->filter_size_x = $3;
                          options->filter_size_y = $4; }
                | FACE FRONT
                        { options->face = 'f'; }
                | FACE BACK
                        { options->face = 'b'; }
                | FACE BOTH
                        { options->face = 'a'; }
                | FIELD OFF
                        { options->field = 0; }
                | FIELD EVEN
                        { options->field = 'e'; }
                | FIELD ODD
                        { options->field = 'o'; }
                | PHOTON TRACE DEPTH T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $4;
                          options->photon_trace_depth      = $4 + $4; }
                | PHOTON TRACE DEPTH T_INTEGER T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $5;
                          options->photon_trace_depth      = $4 + $5; }
                | PHOTON TRACE DEPTH T_INTEGER T_INTEGER T_INTEGER
                        { options->photon_reflection_depth = $4;
                          options->photon_refraction_depth = $5;
                          options->photon_trace_depth      = $6; }
                | TRACE DEPTH T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $3;
                          options->trace_depth      = $3 + $3; }
                | TRACE DEPTH T_INTEGER T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $4;
                          options->trace_depth      = $3 + $4; }
                | TRACE DEPTH T_INTEGER T_INTEGER T_INTEGER
                        { options->reflection_depth = $3;
                          options->refraction_depth = $4;
                          options->trace_depth      = $5; }
                | CONTRAST floating floating floating
                        { options->contrast.r = $2;
                          options->contrast.g = $3;
                          options->contrast.b = $4;
                          options->contrast.a = ($2 + $3 + $4)/3; }
                | CONTRAST floating floating floating floating
                        { options->contrast.r = $2;
                          options->contrast.g = $3;
                          options->contrast.b = $4;
                          options->contrast.a = $5; }
                | TIME CONTRAST floating floating floating
                        { options->time_contrast.r = $3;
                          options->time_contrast.g = $4;
                          options->time_contrast.b = $5;
                          options->time_contrast.a = ($3 + $4 + $5)/3; }
                | TIME CONTRAST floating floating floating floating
                        { options->time_contrast.r = $3;
                          options->time_contrast.g = $4;
                          options->time_contrast.b = $5;
                          options->time_contrast.a = $6; }
                | CONTOUR STORE function
                        { options->contour_store = $3; }
                | CONTOUR CONTRAST function
                        { options->contour_contrast = $3; }
                | JITTER floating
                        { options->jitter = $2; }
                | SHUTTER floating
                        { options->shutter = $2;
                          options->motion  = options->shutter > 0; }
                | TASK SIZE T_INTEGER
                        { options->task_size = $3; }
                | RAYCL SUBDIVISION T_INTEGER T_INTEGER
                        { options->subdivision    = $3;
                          options->subdivision_2d = $4; }
                | RAYCL MEMORY T_INTEGER
                        { options->subdivision_memory = $3; }
                | BSP SIZE T_INTEGER
                        { options->space_max_size = $3; }
                | BSP DEPTH T_INTEGER
                        { options->space_max_depth = $3; }
                | GRID SIZE floating
                        { options->grid_size = $3; }
                | DESATURATE boolean
                        { mi_img_mode($2, (miBoolean)-1, (miBoolean)-1, -1.0);}
                | DITHER boolean
                        { mi_img_mode((miBoolean)-1, $2, (miBoolean)-1, -1.0);}
                | PREMULTIPLY boolean
                        { mi_img_mode((miBoolean)-1, (miBoolean)-1, $2, -1.0);}
                | GAMMA floating
                        { mi_img_mode((miBoolean)-1, (miBoolean)-1,
                                                         (miBoolean)-1, $2); }
                | OBJECT SPACE
                        { options->render_space = 'o'; }
                | CAMERA SPACE
                        { options->render_space = 'c'; }
                | MIXED SPACE
                        { options->render_space = 'm'; }
                | INHERITANCE symbol
                        { if (ctx->inheritance_func)
                                mi_mem_release(ctx->inheritance_func);
                          ctx->inheritance_func = $2; }
                | SHADOWMAP MOTION boolean
                        { options->shadow_map_motion = $3; }
                | SHADOWMAP REBUILD boolean
                        { options->recompute_shadow_maps = (($3)?'y':'n'); }
                | SHADOWMAP boolean
                        { options->use_shadow_maps = $2; }
                | CAUSTIC boolean
                        { options->caustic = $2; }
                | CAUSTIC ACCURACY T_INTEGER
                        { options->caustic_accuracy = $3; }
                | CAUSTIC ACCURACY T_INTEGER floating
                        { options->caustic_accuracy = $3;
                          options->caustic_radius = $4; }
                | CAUSTIC FILTER c_filter_type
                        { options->caustic_filter = $3;
                          options->caustic_filter_const = 1.1; }
                | CAUSTIC FILTER c_filter_type floating
                        { options->caustic_filter = $3;
                          options->caustic_filter_const = $4; }
                | GLOBILLUM boolean
                        { options->globillum = $2; }
                | GLOBILLUM ACCURACY T_INTEGER
                        { options->global_accuracy = $3; }
                | GLOBILLUM ACCURACY T_INTEGER floating
                        { options->global_accuracy = $3;
                          options->global_radius = $4; }
                | PHOTONVOL ACCURACY T_INTEGER
                        { options->photonvol_accuracy = $3; }
                | PHOTONVOL ACCURACY T_INTEGER floating
                        { options->photonvol_accuracy = $3;
                          options->photonvol_radius = $4; }
                | PHOTONMAP FILE_ T_STRING
                        { mi_scene_delete(options->photonmap_file);
                          strcpy((char *)mi_scene_create(
                                        &options->photonmap_file,
                                        miSCENE_STRING, strlen($3)+1), $3);
                          mi_db_unpin(options->photonmap_file);
                          mi_mem_release($3); }
                | PHOTONMAP REBUILD boolean
                        { options->photonmap_rebuild = $3; }
                | APPROXIMATE opt_displace
                ;

filter_type     : BOX
                        { $$ = 'b'; }
                | TRIANGLE
                        { $$ = 't'; }
                | GAUSS
                        { $$ = 'g'; }
                ;

c_filter_type   : BOX
                        { $$ = 'b'; }
                | CONE
                        { $$ = 'c'; }
                | GAUSS
                        { $$ = 'g'; }
                ;

opt_displace    :       { miAPPROX_DEFAULT(approx); }
                  s_approx_tech ALL
                        { memcpy(&options->approx, &approx, sizeof(miApprox));}
                |       { miAPPROX_DEFAULT(approx); }
                  DISPLACE s_approx_tech ALL
                        { memcpy(&options->approx_displace, &approx,
                                                           sizeof(miApprox)); }
                ;


/*-----------------------------------------------------------------------------
 * camera
 *---------------------------------------------------------------------------*/

camera          : CAMERA symbol
                        { camera = mi_api_camera_begin($2);
                          have_l = have_o = have_v = have_e = 0; }
                  camera_list END CAMERA
                        { mi_api_camera_end(); }
                ;

camera_list     :
                | camera_list camera_item
                ;

camera_item     : camview_item
                | frame_number
                | FIELD T_INTEGER
                        { camera->frame_field = $2; }
                ;

camview_item    : OUTPUT
                        { mi_api_function_delete(&camera->output); }
                | OUTPUT T_STRING T_STRING
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_file_def(0, 0, $2, $3)); }
                | OUTPUT T_STRING T_STRING T_STRING
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          mi_api_output_type_identify(&tbm, &ibm, $2);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_file_def(tbm, ibm, $3, $4));}
                | OUTPUT T_STRING function
                        { if (!have_o++)
                                mi_api_function_delete(&camera->output);
                          mi_api_output_type_identify(&tbm, &ibm, $2);
                          camera->output = mi_api_function_append(
                                camera->output,
                                mi_api_output_function_def(tbm, ibm, $3)); }
                | VOLUME
                        { mi_api_function_delete(&camera->volume); }
                | VOLUME function_list
                        { if (!have_v++)
                                mi_api_function_delete(&camera->volume);
                          camera->volume = mi_api_function_append(
                                                camera->volume, $2); }
                | ENVIRONMENT
                        { mi_api_function_delete(&camera->environment); }
                | ENVIRONMENT function_list
                        { if (!have_e++)
                                mi_api_function_delete(&camera->environment);
                          camera->environment = mi_api_function_append(
                                                camera->environment, $2); }
                | LENS
                        { mi_api_function_delete(&camera->lens); }
                | LENS function_list
                        { if (!have_l++)
                                mi_api_function_delete(&camera->lens);
                          camera->lens = mi_api_function_append(
                                                camera->lens, $2); }
                | FOCAL floating
                        { camera->focal = $2;
                          camera->orthographic = miFALSE; }
                | FOCAL INFINITY_
                        { camera->orthographic = miTRUE; }
                | APERTURE floating
                        { camera->aperture = $2; }
                | ASPECT floating
                        { camera->aspect = $2; }
                | RESOLUTION T_INTEGER T_INTEGER
                        { camera->x_resolution = $2;
                          camera->y_resolution = $3; }
                | WINDOW T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                        { camera->window.xl = $2;
                          camera->window.yl = $3;
                          camera->window.xh = $4;
                          camera->window.yh = $5; }
                | CLIP floating floating
                        { camera->clip.min = $2;
                          camera->clip.max = $3; }
                ;

frame_number    : FRAME T_INTEGER
                        { camera->frame       = $2;
                          camera->frame_time  = 0;
                          camera->frame_field = 0; }
                | FRAME T_INTEGER floating
                        { camera->frame       = $2;
                          camera->frame_time  = 0;
                          camera->frame_field = $3; }
                ;


/*-----------------------------------------------------------------------------
 * instance
 *---------------------------------------------------------------------------*/

instance        : INSTANCE symbol
                        { curr_inst = mi_api_instance_begin($2);
                          if (!curr_inst) curr_inst = &dummy_inst; }
                  inst_item inst_func
                  inst_flags
                  inst_params
                        { mi_api_instance_end($4,$5,$7); }
                  END INSTANCE
                ;

inst_item       :
                        { $$ = 0; }
                | symbol
                        { $$ = $1; }
                ;

inst_func       :
                        { $$ = miNULLTAG; }
                | GEOMETRY function_list
                        { $$ = $2; }
                ;

inst_flags      :
                | inst_flag inst_flags
                ;

inst_flag       : VISIBLE boolean
                        { curr_inst->visible = $2 ? 2 : 1; }
                | SHADOW boolean
                        { curr_inst->shadow = $2 ? 2 : 1; }
                | TRACE boolean
                        { curr_inst->trace = $2 ? 2 : 1; }
                | CAUSTIC
                        { curr_inst->caustic = 3; }
                | CAUSTIC T_INTEGER
                        { curr_inst->caustic = $2; }
                | HIDE boolean
                        { curr_inst->off = $2; }
                | TRANSFORM
                        { curr_inst->tf.function = miNULLTAG;
                          mi_matrix_ident(curr_inst->tf.global_to_local); }
                | TRANSFORM function
                        { curr_inst->tf.function = $2;
                          mi_matrix_ident(curr_inst->tf.global_to_local); }
                | transform
                        { curr_inst->tf.function = miNULLTAG;
                          mi_matrix_copy(
                                curr_inst->tf.global_to_local, $1);
                          if (!mi_matrix_invert(curr_inst->tf.local_to_global,
                                               curr_inst->tf.global_to_local)){
                                mi_api_warning("singular matrix, using "
                                                                "identity");
                                mi_matrix_ident(curr_inst->tf.global_to_local);
                                mi_matrix_ident(curr_inst->tf.local_to_global);
                        }}
                | MOTION OFF
                        { mi_matrix_null(curr_inst->motion_transform);
                          curr_inst->gen_motion = miGM_OFF; }
                | MOTION TRANSFORM
                        { mi_matrix_null(curr_inst->motion_transform);
                          curr_inst->gen_motion = miGM_INHERIT; }
                | MOTION transform
                        { mi_matrix_copy(curr_inst->motion_transform,$2);
                          curr_inst->gen_motion = miGM_TRANSFORM; }
                | MATERIAL
                        { curr_inst->material = miNULLTAG;
                          curr_inst->mtl_array_size = 0; }
                  inst_mtl
                ;

inst_params     :
                        { $$ = (miTag)-1; }
                | '(' ')'
                        { $$ = miNULLTAG; }
                | '('
                        { if (!ctx->inheritance_func)
                                mi_api_error(
                                        "no inheritance function in options");
                          else {
                                mi_api_function_call(mi_mem_strdup(
                                        ctx->inheritance_func));
                          }
                        }
                  parameter_seq instparamstail
                        { $$ = mi_api_function_call_end(0); }
                ;

instparamstail  : ')'
                | ',' ')'
                ;

inst_mtl        :
                | symbol
                        { curr_inst->material = mi_api_material_lookup($1); }
                | '['
                        { taglist = mi_api_dlist_create(miDLIST_TAG); }
                  inst_mtl_array ']'
                        { curr_inst->mtl_array_size = taglist->nb;
                          curr_inst->material = mi_api_taglist(taglist);
                          mi_api_dlist_delete(taglist); }
                ;

inst_mtl_array  : symbol
                        { mi_api_dlist_add(taglist,
                                        (void *)mi_api_material_lookup($1)); }
                  inst_mtl_next
                ;

inst_mtl_next   :
                | ','
                | ',' inst_mtl_array
                ;


/*-----------------------------------------------------------------------------
 * instgroup
 *---------------------------------------------------------------------------*/

instgroup       : INSTGROUP symbol
                        { mi_api_instgroup_begin($2); }
                  grouplist END INSTGROUP
                        { mi_api_instgroup_end(); }
                ;

grouplist       :
                | symbol
                        { mi_api_instgroup_additem($1); }
                  grouplist
                ;


/*****************************************************************************
 *************************    either    **************************************
 *****************************************************************************/

/*-----------------------------------------------------------------------------
 * function declaration
 *---------------------------------------------------------------------------*/

function_decl   : shret_type_nosh T_STRING parm_decl_list
                        { mi_api_function_declare($1, $2, $3); }
                | SHADER shret_type T_STRING parm_decl_list
                        { tag = mi_api_function_declare($2, $3, $4);
                          curr_decl = !tag ? &dummy_decl :
                                        (miFunction_decl *)mi_scene_edit(tag);}
                  declare_req_seq END DECLARE
                        { if (tag) mi_scene_edit_end(tag); }
                ;

shret_type      : shret_type_nosh
                        { $$ = $1; }
                | SHADER
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, 0, 0); }
                ;

shret_type_nosh :
                        { $$ = mi_api_parameter_decl(miTYPE_COLOR, 0, 0); }
                | simple_type
                        { $$ = mi_api_parameter_decl($1, 0, 0); }
                | STRUCT '{' shret_decl_seq '}'
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_STRUCT, 0, 0);
                          mi_api_parameter_child(parm, $3);
                          $$ = parm; }
                ;

shret_decl_seq  : shret_decl_seq ',' shret_decl
                        { $$ = mi_api_parameter_append($1, $3); }
                | shret_decl
                        { $$ = $1; }
                ;

shret_decl      : simple_type symbol
                        { $$ = mi_api_parameter_decl($1, $2, 0); }
                | SHADER symbol
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, $2, 0); }
                ;

parm_decl_list  : '(' parm_decl_seq ')'
                        { $$ = $2; }
                | '(' parm_decl_seq ',' ')'
                        { $$ = $2; }
                | '(' ')'
                        { $$ = 0; }
                ;

parm_decl_seq   : parm_decl_seq ',' parm_decl
                        { $$ = mi_api_parameter_append($1, $3); }
                | parm_decl
                        { $$ = $1; }
                ;

parm_decl       : simple_type symbol
                        { $$ = mi_api_parameter_decl($1, $2, 0); }
                | SHADER symbol
                        { $$ = mi_api_parameter_decl(miTYPE_SHADER, $2, 0); }
                | STRUCT symbol '{' parm_decl_seq '}'
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_STRUCT, $2, 0);
                          mi_api_parameter_child(parm, $4);
                          $$ = parm; }
                | ARRAY parm_decl
                        { miParameter *parm =
                                mi_api_parameter_decl(miTYPE_ARRAY, 0, 0);
                          mi_api_parameter_child(parm, $2);
                          $$ = parm; }
                ;

simple_type     : BOOLEAN
                        { $$ = miTYPE_BOOLEAN; }
                | INTEGER
                        { $$ = miTYPE_INTEGER; }
                | SCALAR
                        { $$ = miTYPE_SCALAR; }
                | STRING
                        { $$ = miTYPE_STRING; }
                | COLOR
                        { $$ = miTYPE_COLOR; }
                | VECTOR
                        { $$ = miTYPE_VECTOR; }
                | TRANSFORM
                        { $$ = miTYPE_TRANSFORM; }
                | SCALAR TEXTURE
                        { $$ = miTYPE_SCALAR_TEX; }
                | VECTOR TEXTURE
                        { $$ = miTYPE_VECTOR_TEX; }
                | COLOR TEXTURE
                        { $$ = miTYPE_COLOR_TEX; }
                | LIGHT
                        { $$ = miTYPE_LIGHT; }
                | MATERIAL
                        { $$ = miTYPE_MATERIAL; }
                | GEOMETRY
                        { $$ = miTYPE_GEOMETRY; }
                ;

declare_req_seq :
                | declare_req declare_req_seq
                ;

declare_req     : gui
                | SCANLINE OFF
                        { curr_decl->phen.scanline = 1; }
                | SCANLINE ON
                        { curr_decl->phen.scanline = 2; }
                | TRACE OFF
                        { curr_decl->phen.trace = 1; }
                | TRACE ON
                        { curr_decl->phen.trace = 2; }
                | SHADOW OFF
                        { curr_decl->phen.shadow = 1; }
                | SHADOW ON
                        { curr_decl->phen.shadow = 2; }
                | SHADOW SORT
                        { curr_decl->phen.shadow = 'l'; }
                | SHADOW SEGMENTS
                        { curr_decl->phen.shadow = 's'; }
                | FACE FRONT
                        { curr_decl->phen.face = 'f'; }
                | FACE BACK
                        { curr_decl->phen.face = 'b'; }
                | FACE BOTH
                        { curr_decl->phen.face = 'a'; }
                | TEXTURE T_INTEGER
                        { curr_decl->phen.mintextures = $2; }
                | BUMP T_INTEGER
                        { curr_decl->phen.minbumps = $2; }
                | DERIVATIVE
                        { curr_decl->phen.deriv1 =
                          curr_decl->phen.deriv2 = 0; }
                | DERIVATIVE T_INTEGER
                        { if ($2 == 1)
                                curr_decl->phen.deriv1 = miTRUE;
                          else if ($2 == 2)
                                curr_decl->phen.deriv2 = miTRUE;
                          else
                                mi_api_error("derivative not 1 or 2"); }
                | DERIVATIVE T_INTEGER T_INTEGER
                        { if ($2 == 1 || $3 == 1)
                                curr_decl->phen.deriv1 = miTRUE;
                          else if ($2 == 2 || $3 == 2)
                                curr_decl->phen.deriv2 = miTRUE;
                          if ($2 != 1 && $2 != 2 || $3 != 1 && $3 != 2)
                                mi_api_error("derivative not 1 or 2"); }
                | OBJECT SPACE
                        { curr_decl->phen.render_space = 'o'; }
                | CAMERA SPACE
                        { curr_decl->phen.render_space = 'c'; }
                | MIXED SPACE
                        { curr_decl->phen.render_space = 'm'; }
                | WORLD SPACE
                        { mi_api_warning("world space statement ignored"); }
                | SMART VOLUME boolean
                        { curr_decl->phen.smart_volume = $3; }
                | VERSION T_INTEGER
                        { curr_decl->version = $2; }
                | APPLY apply_list
                        { curr_decl->apply = $2; }
                ;

apply_list      : apply                 { $$ = $1; }
                | apply ',' apply_list  { $$ = $1 | $3; }
                ;

apply           : LENS                  { $$ = miAPPLY_LENS;            }
                | MATERIAL              { $$ = miAPPLY_MATERIAL;        }
                | LIGHT                 { $$ = miAPPLY_LIGHT;           }
                | SHADOW                { $$ = miAPPLY_SHADOW;          }
                | ENVIRONMENT           { $$ = miAPPLY_ENVIRONMENT;     }
                | VOLUME                { $$ = miAPPLY_VOLUME;          }
                | TEXTURE               { $$ = miAPPLY_TEXTURE;         }
                | PHOTON                { $$ = miAPPLY_PHOTON;          }
                | GEOMETRY              { $$ = miAPPLY_GEOMETRY;        }
                | DISPLACE              { $$ = miAPPLY_DISPLACE;        }
                | EMITTER               { $$ = miAPPLY_PHOTON_EMITTER;  }
                | OUTPUT                { $$ = miAPPLY_OUTPUT;          }
                ;


/*-----------------------------------------------------------------------------
 * function instance
 *---------------------------------------------------------------------------*/

function_list   :
                        { funclist = miNULLTAG; }
                  func_list
                        { $$ = funclist; }
                ;

func_list       : function
                        { funclist = $1; }
                | func_list function
                        { funclist = mi_api_function_append(funclist, $2); }
                ;

function        : T_STRING
                        { mi_api_function_call($1); }
                  parameter_list
                        { $$ = mi_api_function_call_end(functag); functag = 0;}
                | '=' symbol
                        { $$ = mi_api_function_assign($2); }
                | '=' opt_incremental SHADER symbol function
                        { mi_api_shader_add($4, $5); $$ = $5;
                          mi_api_incremental(is_incremental); }
                ;

opt_incremental :
                        { mi_api_incremental(miFALSE); }
                | INCREMENTAL
                        { mi_api_incremental(miTRUE); }
                ;

parameter_list  : '(' ')'
                | '(' parameter_seq ')'
                | '(' parameter_seq ',' ')'
                ;

parameter_seq   : parameter
                | parameter_seq ',' parameter
                ;

parameter       : symbol
                        { mi_api_parameter_name($1); }
                  value_list
                ;

value_list      : value
                | value_list value
                ;

value           : NULL_
                | boolean
                        { int value = $1;
                          mi_api_parameter_value(miTYPE_BOOLEAN, &value,0,0); }
                | T_INTEGER
                        { int value = $1;
                          mi_api_parameter_value(miTYPE_INTEGER, &value,0,0); }
                | T_FLOAT
                        { float value = $1;
                          mi_api_parameter_value(miTYPE_SCALAR,  &value,0,0); }
                | symbol
                        { mi_api_parameter_value(miTYPE_STRING,  $1, 0, 0); }
                | '=' symbol
                        { mi_api_parameter_shader($2); }
                | '=' INTERFACE symbol
                        { mi_api_parameter_interface($3); }
                | '{'
                        { mi_api_parameter_push(miFALSE); }
                  parameter_seq '}'
                        { mi_api_parameter_pop(); }
                | '['
                        { mi_api_parameter_push(miTRUE); }
                  array_value_seq ']'
                        { mi_api_parameter_pop(); }
                | '[' ']'
                ;

array_value_seq :       { mi_api_new_array_element(); }
                  value_list
                  array_value_cont
                ;

array_value_cont:
                | ','
                        { mi_api_new_array_element(); }
                  value_list array_value_cont
                ;


/*-----------------------------------------------------------------------------
 * phenomenon declaration
 *---------------------------------------------------------------------------*/

phenomenon_decl : PHENOMENON shret_type T_STRING
                        { mi_api_phen_begin($3); }
                  parm_decl_list
                        { curr_decl = mi_api_phen_parameter_end($2, $5);
                          if (!curr_decl) curr_decl = &dummy_decl; }
                  phen_body_list
                  END DECLARE
                        { mi_api_phen_end(); }
                ;

phen_body_list  :
                | phen_body phen_body_list
                ;

phen_body       : SHADER symbol function_list
                        { mi_api_shader_add($2, $3); }
                | material
                | light
                | instance
                | declare_req
                | ROOT phen_root
                        { if (curr_decl->phen.root)
                                mi_api_error("multiple roots not allowed");
                          else
                                curr_decl->phen.root = $2; }
                | OUTPUT T_STRING T_STRING
                        { curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_file_def(0, 0, $2, $3)); }
                | OUTPUT T_STRING T_STRING T_STRING
                        { mi_api_output_type_identify(&tbm, &ibm, $2);
                          curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_file_def(tbm, ibm, $3, $4));}
                | OUTPUT T_STRING function
                        { mi_api_output_type_identify(&tbm, &ibm, $2);
                          curr_decl->phen.output = mi_api_function_append(
                                curr_decl->phen.output,
                                mi_api_output_function_def(tbm, ibm, $3)); }
                | LENS function_list
                        { curr_decl->phen.lens = mi_api_function_append(
                                                curr_decl->phen.lens, $2); }
                | VOLUME function_list
                        { curr_decl->phen.volume = mi_api_function_append(
                                                curr_decl->phen.volume, $2); }
                | ENVIRONMENT function_list
                        { curr_decl->phen.environment = mi_api_function_append(
                                           curr_decl->phen.environment, $2); }
                | GEOMETRY function_list
                        { curr_decl->phen.geometry = mi_api_function_append(
                                                curr_decl->phen.geometry, $2);}
                | CONTOUR STORE function
                        { curr_decl->phen.contour_store = $3; }
                | CONTOUR CONTRAST function
                        { curr_decl->phen.contour_contrast = $3; }
                | OUTPUT PRIORITY T_INTEGER
                        { curr_decl->phen.output_seqnr = $3; }
                | LENS PRIORITY T_INTEGER
                        { curr_decl->phen.lens_seqnr = $3; }
                | VOLUME PRIORITY T_INTEGER
                        { curr_decl->phen.volume_seqnr = $3; }
                ;

phen_root       : MATERIAL symbol
                        { if (*curr_decl->declaration != 'm') {
                                mi_api_error("not a material phenomenon");
                                $$ = 0;
                          } else
                                $$ = mi_api_material_lookup($2); }
                | LIGHT symbol
                        { if (*curr_decl->declaration != 'l') {
                                mi_api_error("not a light phenomenon");
                                $$ = 0;
                          } else
                                $$ = mi_api_light_lookup($2); }
                | function_list
                        { $$ = 0;
                          if (*curr_decl->declaration == 'm')
                                mi_api_error("must use ``root material''");
                          else if (*curr_decl->declaration == 'l')
                                mi_api_error("must use ``root light''");
                          else
                                $$ = mi_api_function_append(
                                                curr_decl->phen.root, $1); }
                ;


/*-----------------------------------------------------------------------------
 * texture
 *---------------------------------------------------------------------------*/

texture         :       { pyramid_filter = 0.; }
                  tex_flags tex_type TEXTURE symbol
                        { functag = mi_api_texture_begin($5,$3,$2); }
                  tex_data
                        { functag = 0; }
                ;

tex_flags       :
                        { $$ = 0; }
                | tex_flag tex_flags
                        { $$ = $1 | $2; }
                ;

tex_flag        : LOCAL
                        { $$ = 1; }
                | FILTER
                        { pyramid_filter = 1.; $$ = 2; }
                | FILTER floating
                        { pyramid_filter = $2;
                          $$ = (pyramid_filter > 0.) ? 2 : 0; }
                ;

tex_type        : COLOR
                        { $$ = 0; }
                | SCALAR
                        { $$ = 1; }
                | VECTOR
                        { $$ = 2; }
                ;

tex_data        : '[' T_INTEGER T_INTEGER ']'
                        { mi_api_texture_array_def_begin($2,$3,1); }
                  tex_bytes_list
                        { mi_api_texture_array_def_end(); }
                | '[' T_INTEGER T_INTEGER T_INTEGER ']'
                        { mi_api_texture_array_def_begin($2,$3,$4); }
                  tex_bytes_list
                        { mi_api_texture_array_def_end(); }
                | tex_func_list
                        { mi_api_texture_function_def($1); }
                | T_STRING
                        { miTag itag = mi_api_texture_file_def($1);
                          if (pyramid_filter > 0. && itag) {
                                miImg_image *img = (miImg_image*)
                                                   mi_scene_edit(itag);
                                mi_img_pyramid_set_filter(img, pyramid_filter);
                                mi_scene_edit_end(itag); }}
                ;


tex_func_list   : function
                        { $$ = $1; }
                | function tex_func_list
                        { $$ = mi_api_function_append($1, $2); }
                ;
tex_bytes_list  :
                | tex_bytes_list T_BYTE_STRING
                        { mi_api_texture_byte_copy($2.len,$2.bytes); }
                ;


/*-----------------------------------------------------------------------------
 * light
 *---------------------------------------------------------------------------*/

light           : LIGHT symbol
                        { curr_light = mi_api_light_begin($2);
                          light_map = 0; }
                  light_ops
                  END LIGHT
                        { switch(light_map & 6) {
                            case 2: curr_light->type = miLIGHT_ORIGIN;   break;
                            case 4: curr_light->type = miLIGHT_DIRECTION;break;
                            case 6: curr_light->type = miLIGHT_SPOT;     break;
                          }
                          mi_api_light_end(); }
                ;

light_ops       :
                | light_op light_ops
                ;

light_op        : function
                        { if (!(light_map & 1))
                                mi_api_function_delete(&curr_light->shader);
                          light_map |= 1;
                          curr_light->shader = mi_api_function_append(
                                                curr_light->shader, $1); }
                | EMITTER function
                        { if (!(light_map & 8))
                                mi_api_function_delete(&curr_light->emitter);
                          light_map |= 8;
                          curr_light->emitter = mi_api_function_append(
                                                curr_light->emitter, $2); }
                | SHADOWMAP
                        { curr_light->use_shadow_maps = miTRUE; }
                | SHADOWMAP boolean
                        { curr_light->use_shadow_maps = $2; }
                | ORIGIN vector
                        { curr_light->origin = $2;
                          light_map |= 2; }
                | DIRECTION vector
                        { curr_light->direction = $2;
                          mi_vector_normalize(&curr_light->direction);
                          light_map |= 4; }
                | ENERGY floating floating floating
                        { curr_light->energy.r = $2;
                          curr_light->energy.g = $3;
                          curr_light->energy.b = $4; }
                | EXPONENT floating
                        { curr_light->exponent = $2; }
                | CAUSTIC PHOTONS T_INTEGER
                        { curr_light->caustic_photons = $3; }
                | GLOBILLUM PHOTONS T_INTEGER
                        { curr_light->global_photons = $3; }
                | RECTANGLE vector vector
                        { curr_light->area = miLIGHT_RECTANGLE;
                          curr_light->primitive.rectangle.edge_u = $2;
                          curr_light->primitive.rectangle.edge_v = $3; }
                | RECTANGLE vector vector T_INTEGER T_INTEGER
                        { curr_light->area = miLIGHT_RECTANGLE;
                          curr_light->primitive.rectangle.edge_u = $2;
                          curr_light->primitive.rectangle.edge_v = $3;
                          curr_light->samples_u                  = $4;
                          curr_light->samples_v                  = $5; }
                | DISC vector floating
                        { curr_light->area = miLIGHT_DISC;
                          curr_light->primitive.disc.normal      = $2;
                          curr_light->primitive.disc.radius      = $3; }
                | DISC vector floating T_INTEGER T_INTEGER
                        { curr_light->area = miLIGHT_DISC;
                          curr_light->primitive.disc.normal      = $2;
                          curr_light->primitive.disc.radius      = $3;
                          curr_light->samples_u                  = $4;
                          curr_light->samples_v                  = $5; }
                | SPHERE floating
                        { curr_light->area = miLIGHT_SPHERE;
                          curr_light->primitive.sphere.radius    = $2; }
                | SPHERE floating T_INTEGER T_INTEGER
                        { curr_light->area = miLIGHT_SPHERE;
                          curr_light->primitive.sphere.radius    = $2;
                          curr_light->samples_u                  = $3;
                          curr_light->samples_v                  = $4; }
                | SPREAD floating
                        { curr_light->spread = $2; }
                | SHADOWMAP RESOLUTION T_INTEGER
                        { curr_light->shadowmap_resolution = $3; }
                | SHADOWMAP SOFTNESS floating
                        { curr_light->shadowmap_softness = $3; }
                | SHADOWMAP SAMPLES T_INTEGER
                        { curr_light->shadowmap_samples = $3; }
                | SHADOWMAP FILE_ T_STRING
                        { mi_scene_delete(curr_light->shadowmap_file);
                          strcpy((char *)mi_scene_create(
                                        &curr_light->shadowmap_file,
                                        miSCENE_STRING, strlen($3)+1), $3);
                          mi_db_unpin(curr_light->shadowmap_file);
                          mi_mem_release($3); }
                | VISIBLE
                        { curr_light->visible = miTRUE; }
                ;


/*-----------------------------------------------------------------------------
 * material
 *---------------------------------------------------------------------------*/

material        : MATERIAL symbol
                        { curr_mtl = mi_api_material_begin($2);
                          have_d = have_s = have_v =
                          have_e = have_c = have_p = have_pv = 0; }
                  mtl_flags
                  function_list
                        { curr_mtl->shader = $5; }
                  mtl_args
                  END MATERIAL
                        { mi_api_material_end(); }
                ;

mtl_flags       :
                | mtl_flag mtl_flags
                ;

mtl_flag        : NOCONTOUR
                        { mi_api_warning(
                                "obsolete \"nocontour\" flag ignored"); }
                | OPAQUE_
                        { curr_mtl->opaque = miTRUE; }
                ;

mtl_args        :
                | mtl_arg mtl_args
                ;

mtl_arg         : DISPLACE
                        { mi_api_function_delete(&curr_mtl->displace); }
                | DISPLACE function_list
                        { if (!have_d++)
                                mi_api_function_delete(&curr_mtl->displace);
                          curr_mtl->displace = $2; }
                | SHADOW
                        { mi_api_function_delete(&curr_mtl->shadow); }
                | SHADOW function_list
                        { if (!have_s++)
                                mi_api_function_delete(&curr_mtl->shadow);
                          curr_mtl->shadow = $2; }
                | VOLUME
                        { mi_api_function_delete(&curr_mtl->volume); }
                | VOLUME function_list
                        { if (!have_v++)
                                mi_api_function_delete(&curr_mtl->volume);
                          curr_mtl->volume = $2; }
                | ENVIRONMENT
                        { mi_api_function_delete(&curr_mtl->environment); }
                | ENVIRONMENT function_list
                        { if (!have_e++)
                                mi_api_function_delete(&curr_mtl->environment);
                          curr_mtl->environment = $2; }
                | CONTOUR
                        { mi_api_function_delete(&curr_mtl->contour); }
                | CONTOUR function_list
                        { if (!have_c++)
                                mi_api_function_delete(&curr_mtl->contour);
                          curr_mtl->contour = $2; }
                | PHOTON
                        { mi_api_function_delete(&curr_mtl->photon); }
                | PHOTON function_list
                        { if (!have_p++)
                                mi_api_function_delete(&curr_mtl->photon);
                          curr_mtl->photon = $2; }
                | PHOTONVOL
                        { mi_api_function_delete(&curr_mtl->photonvol); }
                | PHOTONVOL function_list
                        { if (!have_pv++)
                              mi_api_function_delete(&curr_mtl->photonvol);
                          curr_mtl->photonvol = $2; }
                ;


/*-----------------------------------------------------------------------------
 * object
 *---------------------------------------------------------------------------*/

object          : OBJECT opt_symbol
                        { visible=shadow=trace=mtl_is_label=miFALSE;
                          caustic=label=0; }
                  obj_flags
                  obj_transform
                        { mi_api_object_begin($2,visible,shadow,trace,caustic,
                                label, is_obj_transf ? $5 : 0, mtl_is_label);
                          mi_api_basis_list_clear(); }
                  bases_and_groups
                  END OBJECT
                        { mi_api_object_end();
                          mi_api_basis_list_clear(); }
                ;

obj_flags       :
                | obj_flag obj_flags
                ;

obj_flag        : VISIBLE
                        { visible = miTRUE; }
                | SHADOW
                        { shadow = miTRUE; }
                | TRACE
                        { trace = miTRUE; }
                | TAGGED
                        { mtl_is_label = miTRUE; }
                | CAUSTIC
                        { caustic = 3; }
                | CAUSTIC T_INTEGER
                        { caustic = $2; }
                | TAG T_INTEGER
                        { label = $2; }
                ;

obj_transform   :
                        { is_obj_transf = miFALSE; }
                | transform
                        { is_obj_transf = miTRUE;
                          (void)memcpy($$, $1, sizeof(miMatrix)); }
                ;

bases_and_groups:
                | basis bases_and_groups
                | group bases_and_groups
                ;

basis           : BASIS symbol rational MATRIX T_INTEGER T_INTEGER basis_matrix
                        { mi_api_basis_add($2, $3, miBASIS_MATRIX, $5, $6, $7);
                          mi_api_dlist_delete($7); }
                | BASIS symbol rational BEZIER T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_BEZIER, $5, 0, 0); }
                | BASIS symbol rational TAYLOR T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_TAYLOR, $5, 0, 0); }
                | BASIS symbol rational BSPLINE T_INTEGER
                        { mi_api_basis_add($2, $3, miBASIS_BSPLINE, $5, 0, 0);}
                | BASIS symbol rational CARDINAL
                        { mi_api_basis_add($2, $3, miBASIS_CARDINAL, 0, 0, 0);}
                ;

rational        :
                        { $$ = miFALSE; }
                | RATIONAL
                        { $$ = miTRUE; }
                ;

basis_matrix    :       { $$ = mi_api_dlist_create(miDLIST_GEOSCALAR); }
                | basis_matrix floating
                        { miGeoScalar s=$2; mi_api_dlist_add($1, &s); $$=$1; }
                ;

group           : GROUP opt_symbol merge_option
                        { mi_api_object_group_begin($2, $3);
                          are_polys = are_surfs = miFALSE; }
                  vector_list
                  vertex_list
                  geometry_list
                  END GROUP
                        { mi_api_object_group_end(are_polys, are_surfs); }
                ;

merge_option    :
                        { $$ = 0.0; }
                | MERGE floating
                        { $$ = $2; }
                ;

vector_list     :
                | vector_list geovector
                        { mi_api_geovector_xyz_add(&$2); }
                ;

vertex_list     :
                | vertex_list vertex
                ;

vertex          : V T_INTEGER
                        { mi_api_vertex_add($2); }
                  n_vector
                  d_vector
                  t_vector_list
                  m_vector
                  u_vector_list
                ;

n_vector        :
                | N T_INTEGER
                        { mi_api_vertex_normal_add($2); }
                ;

d_vector        :
                | D T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv_add($2, $3); }
                | D T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv2_add($2, $3, $4); }
                | D T_INTEGER T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_deriv_add($2, $3);
                          mi_api_vertex_deriv2_add($4, $5, $6); }
                ;

m_vector        :
                | M T_INTEGER
                        { mi_api_vertex_motion_add($2); }
                ;

t_vector_list   :
                | t_vector_list T T_INTEGER
                        { mi_api_vertex_tex_add($3, -1, -1); }
                | t_vector_list T T_INTEGER T_INTEGER T_INTEGER
                        { mi_api_vertex_tex_add($3, $4, $5); }
                ;

u_vector_list   :
                | u_vector_list U T_INTEGER
                        { mi_api_vertex_user_add($3); }
                ;

geometry_list   :
                | geometry_list geometry
                ;

geometry        : polygon
                | curve
                | surface
                | connection
                | approximation
                ;

polygon         : CP opt_symbol
                        { mi_api_poly_begin(1, $2); }
                  poly_indices
                        { mi_api_poly_end(); are_polys = miTRUE; }
                | P opt_symbol
                        { mi_api_poly_begin(0, $2); }
                  poly_indices
                        { mi_api_poly_end(); are_polys = miTRUE; }
                | STRIP opt_symbol
                        { mi_api_poly_begin(2, $2); }
                  strip_indices
                        { mi_api_poly_end(); are_polys = miTRUE; }
                | FAN opt_symbol
                        { mi_api_poly_begin(3, $2); }
                  strip_indices
                        { mi_api_poly_end(); are_polys = miTRUE; }
                ;

poly_indices    :
                | T_INTEGER
                        { mi_api_poly_index_add($1); }
                  poly_indices
                | HOLE
                        { mi_api_poly_hole_add(); }
                  poly_indices
                ;

strip_indices   :
                | T_INTEGER
                        { mi_api_poly_index_add($1); }
                  strip_indices
                ;

h_vertex_ref_seq: h_vertex_ref
                | h_vertex_ref_seq h_vertex_ref
                ;

h_vertex_ref    : T_INTEGER
                        { mi_api_vertex_ref_add($1, (double)1.0); }
                | T_INTEGER T_FLOAT
                        { mi_api_vertex_ref_add($1, $2); }
                | T_INTEGER W floating
                        { mi_api_vertex_ref_add($1, $3); }
                ;


para_list       : T_FLOAT
                        { miDlist *dlp =mi_api_dlist_create(miDLIST_GEOSCALAR);
                          miGeoScalar s = $1;   /* $1 is a double */
                          mi_api_dlist_add(dlp, &s);
                          $$ = dlp; }
                | para_list T_FLOAT
                        { miGeoScalar s = $2;   /* $2 is a double */
                          mi_api_dlist_add($1, &s);
                          $$ = $1; }
                ;

curve           : CURVE symbol rational symbol
                        { mi_api_curve_begin($2,$4,$3); }
                  para_list h_vertex_ref_seq curve_spec
                        { mi_api_curve_end($6); }
                ;

curve_spec      :
                | SPECIAL curve_special_list
                ;

curve_special_list
                : curve_special
                | curve_special_list curve_special
                ;

curve_special   : T_INTEGER
                        { mi_api_curve_specpnt($1, -1); }
                | T_INTEGER MAPSTO T_INTEGER
                        { mi_api_curve_specpnt($1, $3); }
                ;


surface         : SURFACE symbol mtl_or_label
                        { mi_api_surface_begin($2, $3); }
                  rational symbol floating floating para_list
                        { mi_api_surface_params(miU, $6, $7, $8, $9, $5); }
                  rational symbol floating floating para_list
                        { mi_api_surface_params(miV, $12, $13, $14, $15, $11);}
                  h_vertex_ref_seq
                  tex_surf_list
                  surf_spec_list
                        { mi_api_surface_end(); are_surfs = miTRUE; }
                ;

mtl_or_label    : symbol
                        { $$ = $1; }
                | T_INTEGER
                        { $$ = (char *)$1; }
                ;

tex_surf_list   :
                | tex_surf_list tex_surf
                ;

tex_surf        : opt_volume_flag opt_vector_flag TEXTURE
                  rational symbol para_list
                  rational symbol para_list
                        { mi_api_surface_texture_begin(
                                        $1, $2, $5, $6, $4, $8, $9, $7); }
                  h_vertex_ref_seq

                | DERIVATIVE
                        { mi_api_surface_derivative(1); }
                | DERIVATIVE T_INTEGER
                        { mi_api_surface_derivative($2); }
                | DERIVATIVE T_INTEGER T_INTEGER
                        { mi_api_surface_derivative($2);
                          mi_api_surface_derivative($3); }
                ;

opt_volume_flag :
                        { $$ = miFALSE; }
                | VOLUME
                        { $$ = miTRUE; }
                ;

opt_vector_flag :
                        { $$ = miFALSE; }
                | VECTOR
                        { $$ = miTRUE; }
                ;


surf_spec_list  :
                | surf_spec_list surf_spec
                ;

surf_spec       : TRIM trim_spec_list
                | HOLE hole_spec_list
                | SPECIAL
                        { newloop = miTRUE; }
                  special_spec_list
                ;

trim_spec_list  : symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(miTRUE, miCURVE_TRIM,$1,&r);}
                | trim_spec_list symbol floating floating
                        { miGeoRange r;
                          r.min = $3;
                          r.max = $4;
                          mi_api_surface_curveseg(miFALSE,miCURVE_TRIM,$2,&r);}
                ;

hole_spec_list  : symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(miTRUE,miCURVE_HOLE,$1,&r); }
                | hole_spec_list symbol floating floating
                        { miGeoRange r;
                          r.min = $3;
                          r.max = $4;
                          mi_api_surface_curveseg(miFALSE,miCURVE_HOLE,$2,&r);}
                ;

special_spec_list
                : special_spec
                | special_spec_list special_spec
                ;

special_spec    : T_INTEGER
                        { mi_api_surface_specpnt($1, -1); }
                | T_INTEGER MAPSTO T_INTEGER
                        { mi_api_surface_specpnt($1, $3); }
                | symbol floating floating
                        { miGeoRange r;
                          r.min = $2;
                          r.max = $3;
                          mi_api_surface_curveseg(newloop,
                                                  miCURVE_SPECIAL, $1, &r);
                          newloop = miFALSE; }
                ;

connection      : CONNECT
                  symbol symbol floating floating
                  symbol symbol floating floating
                        { miGeoRange c1, c2;
                          c1.min = $4;
                          c1.max = $5;
                          c2.min = $8;
                          c2.max = $9;
                          mi_api_object_group_connection($2,$3,&c1,$6,$7,&c2);}
                ;


/*-----------------------------------------------------------------------------
 * approximations (in objects and options)
 *---------------------------------------------------------------------------*/

approximation   :       { miAPPROX_DEFAULT(approx); }
                  approx_body
                ;

approx_body     : APPROXIMATE SURFACE  s_approx_tech s_approx_names
                | APPROXIMATE DISPLACE s_approx_tech d_approx_names
                | APPROXIMATE CURVE    c_approx_tech c_approx_names
                | APPROXIMATE TRIM     c_approx_tech t_approx_names
                | APPROXIMATE          s_approx_tech
                        { mi_api_poly_approx(&approx); }
                ;

s_approx_tech   : s_approx_params
                        { approx.subdiv[miMIN]  = 0;
                          approx.subdiv[miMAX]  = 5; }
                | s_approx_params T_INTEGER T_INTEGER
                        { approx.subdiv[miMIN]  = $2;
                          approx.subdiv[miMAX]  = $3; }
                ;

c_approx_tech   : c_approx_params
                        { approx.subdiv[miMIN]  = 0;
                          approx.subdiv[miMAX]  = 5; }
                | c_approx_params T_INTEGER T_INTEGER
                        { approx.subdiv[miMIN]  = $2;
                          approx.subdiv[miMAX]  = $3; }
                ;

s_approx_params : s_approx_param
                | s_approx_param s_approx_params
                ;

c_approx_params : c_approx_param
                | c_approx_param c_approx_params
                ;

s_approx_param  : x_approx_param
                | PARAMETRIC floating floating
                        { approx.method                 = miAPPROX_PARAMETRIC;
                          approx.cnst[miCNST_UPARAM]    = $2;
                          approx.cnst[miCNST_VPARAM]    = $3; }
                | REGULAR PARAMETRIC floating floating
                        { approx.method                 = miAPPROX_REGULAR;
                          approx.cnst[miCNST_UPARAM]    = $3;
                          approx.cnst[miCNST_VPARAM]    = $4; }
                | IMPLICIT
                        { approx.method                 = miAPPROX_ALGEBRAIC; }
                ;

c_approx_param  : x_approx_param
                | PARAMETRIC floating
                        { approx.method                 = miAPPROX_PARAMETRIC;
                          approx.cnst[miCNST_UPARAM]    = $2;
                          approx.cnst[miCNST_VPARAM]    = 1.0; }
                | REGULAR PARAMETRIC floating
                        { approx.method                 = miAPPROX_REGULAR;
                          approx.cnst[miCNST_UPARAM]    = $3;
                          approx.cnst[miCNST_VPARAM]    = 1.0; }
                ;

x_approx_param  : VIEW
                        { approx.view_dep               = miTRUE; }
                | TREE
                        { approx.style                  = miAPPROX_STYLE_TREE;}
                | GRID
                        { approx.style                  = miAPPROX_STYLE_GRID;}
                | MESH
                        { approx.style                  = miAPPROX_STYLE_MESH;}
                | LENGTH floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_LENGTH]    = $2; }
                | DISTANCE floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_DISTANCE]  = $2; }
                | ANGLE floating
                        { approx.method                 = miAPPROX_LDA;
                          approx.cnst[miCNST_ANGLE]     = $2; }
                | SPATIAL approx_view floating
                        { approx.method                 = miAPPROX_SPATIAL;
                          approx.cnst[miCNST_LENGTH]    = $3; }
                | CURVATURE approx_view floating floating
                        { approx.method                 = miAPPROX_CURVATURE;
                          approx.cnst[miCNST_DISTANCE]  = $3;
                          approx.cnst[miCNST_ANGLE]     = $4; }
                ;

approx_view     :
                | VIEW
                        { approx.view_dep               = miTRUE; }
                ;

s_approx_names  : symbol
                        { mi_api_surface_approx($1, &approx); }
                | s_approx_names symbol
                        { mi_api_surface_approx($2, &approx); }
                ;

d_approx_names  : symbol
                        { mi_api_surface_approx_displace($1, &approx); }
                | s_approx_names symbol
                        { mi_api_surface_approx_displace($2, &approx); }
                ;

c_approx_names  : symbol
                        { mi_api_curve_approx($1, &approx); }
                | c_approx_names symbol
                        { mi_api_curve_approx($2, &approx); }
                ;

t_approx_names  : symbol
                        { mi_api_surface_approx_trim($1, &approx); }
                | t_approx_names symbol
                        { mi_api_surface_approx_trim($2, &approx); }
                ;
%%

= pcrr at 12.0pt


Table of Contents