Keywords: main

Next: Bibliography Up: No Title Previous: 6.9 Convert Scenes to

# 7. 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 letters, numbers, and underscores and does not begin with a number.

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

- `T_FLOAT` 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 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 consisting of two characters in the range `0`..`9` or `a`..`f`. Line breaks are allowed between bytes. Other characters are not allowed. The maximum length is 1024 bytes (2048 characters); for more bytes use multiple strings.

- `T_VECTOR` is a backquote followed by 12 bytes followed by a backquote. The 12 bytes are the binary image of three floats in big-endian order.

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. This is the complete mental ray 3.1 grammar. The 3.0 grammar is a strict subset of the 3.1 grammar; it lacks certain features marked with 3.1 in the main text but is otherwise identical. Similarly, the 2.x grammar is a strict subset of the 3.0 grammar, with a few exceptions described in the Porting chapter.

    %start start

    %union {
            miBoolean        boolean;
            char            *symbol;
            char            *string;
            struct          {
                    int      len;
                    miUchar *bytes;
            }                byte_string;
            int              integer;
            double           floating;
            float            floatoctet[8];
            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 ALPHA ANGLE ANY APERTURE APPLY
    %token APPROXIMATE ARRAY ASPECT AUTOVOLUME
    %token BACK BASIS BEZIER BLUE BOOLEAN BOTH BOX BSP BSPLINE BUFFER BUMP
    %token CALL CAMERA CARDINAL CAUSTIC CHILD CLASSIFICATION CLIP CODE COLOR
    %token CONE CONIC CONNECT CONSTANT CONTOUR CONTRAST CONTROL CORNER CP
    %token CREASE CURVATURE CURVE CUSP CYLINDER COLORCLIP
    %token D DART DATA DEBUG_ DECLARE DEGREE DELAUNAY DELETE_ DENSITY DEPTH
    %token DERIVATIVE DESATURATE DETAIL DIAGNOSTIC DIRECTION DISC DISPLACE
    %token DISTANCE DITHER
    %token ECHO EMITTER END ENVIRONMENT EVEN ENERGY EULUMDAT EXPONENT
    %token FACE FALSE_ FAN FASTLOOKUP FIELD FILE_ FILTER FINALGATHER FINE FLAGS
    %token FOCAL FORMAT FRAME FRONT
    %token GAMMA GAUSS GEOMETRY GLOBILLUM GRADING GREEN GRID GROUP GUI
    %token HAIR HERMITE HIDE HOLE
    %token IES IMP IMPLICIT INCREMENTAL INFINITY_ INHERITANCE INSTANCE INSTGROUP
    %token INTEGER INTERFACE_ IRRADIANCE
    %token JITTER
    %token LANCZOS LENGTH LENS LEVEL LIGHT LIGHTMAP LIGHTPROFILE LINK LOCAL
    %token LUMINANCE
    %token M MAPSTO MATERIAL MATRIX MAX_ MEMORY MERGE MI MIN_ MITCHELL MIXED MOTION
    %token N NOCONTOUR NORMAL NULL_ NTSC
    %token OBJECT ODD OFF OFFSET ON OPAQUE_ OPENGL OPTIONS ORIGIN OUTPUT OVERRIDE
    %token P PARALLEL_ PARAMETRIC PASS PHENOMENON PHOTON PHOTONMAP PHOTONS
    %token PHOTONVOL PREMULTIPLY PREP PRIORITY PRIVATE
    %token QUALITY
    %token RADIUS RATIONAL RAY RAYCL RAW READ REBUILD RECTANGLE RECURSIVE RED
    %token REGISTRY REGULAR
    %token RENDER RESOLUTION RGB_ ROOT
    %token SAMPLELOCK SAMPLES SCALAR SCANLINE SEGMENTS SELECT SESSION SET SHADOW
    %token SHADOWMAP SHARP SHUTTER SIZE SOFTNESS SORT SPACE SPATIAL SPDL SPECIAL
    %token SPHERE SPREAD STEPS STORE STRING STRIP STRUCT SUBDIVISION SHADER SURFACE
    %token SYSTEM
    %token T TAG TAGGED TASK TAYLOR TEXTURE TIME TRACE TRANSFORM TRAVERSAL TREE
    %token TRIANGLE TRIM TRUE_
    %token U USER V VALUE VECTOR VERBOSE VERSION VERTEX VIEW VISIBLE VOLUME
    %token W WEIGHT WHITE WIDTH WINDOW WORLD WRITABLE WRITE

    %type <floating> floating
    %type <boolean> boolean
    %type <string> symbol
    %type <string> opt_symbol
    %type <matrix> 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 <tag> function
    %type <tag> function_list
    %type <tag> tex_func_list
    %type <tag> phen_root
    %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 <vector> vector
    %type <integer> apply
    %type <integer> apply_list
    %type <tag> opt_function_list
    %type <string> opt_string
    %type <integer> colorclip_mode
    %type <geovector> geovector
    %type <string> mtl_or_label
    %type <boolean> rational
    %type <dlist> basis_matrix
    %type <floating> merge_option
    %type <dlist> para_list
    %type <boolean> opt_volume_flag
    %type <boolean> opt_vector_flag
    %type <boolean> opt_incremental
    %type <floatoctet> out_parms
    %type <integer> filter_type
    %type <integer> c_filter_type
    %type <integer> pass_samples
    %type <dlist> string_list

    %%

    start :
                            { functag = 0;
                              mi_api_incremental(is_incremental = miFALSE);
                              mi_api_private(session_depth = 0);
                              my_timer = mi_timing(0, 0); }
                      command_list
                            { mi_timing(my_timer, 0); }
                    |
                    ;

    /*-----------------------------------------------------------------------------
     * 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; }
                    ;

    opt_string :
                            { $$ = 0; }
                    | T_STRING
                            { $$ = $1; }
                    ;

    colorclip_mode : RGB_
                            { $$ = miIMG_COLORCLIP_RGB; }
                    |  ALPHA
                            { $$ = miIMG_COLORCLIP_ALPHA; }
                    |  RAW
                            { $$ = miIMG_COLORCLIP_RAW; }
                    ;

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

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

    command : set
                    | frame
                    | debug
                    | call
                    | version
                    | incr_command
                    | PRIVATE
                            { mi_api_private(session_depth = 255); }
                      incr_command
                    | SESSION DEPTH T_INTEGER
                            { mi_api_private(session_depth = $3); }
                      incr_command
                    | INCREMENTAL
                            { mi_api_incremental(is_incremental = miTRUE);
                              mi_api_private(session_depth = 0); }
                      incr_command
                    | DELETE_ symbol
                            { mi_api_delete($2); }
                    | RENDER symbol symbol symbol
                            { mi_timing(my_timer, "mi scene file parsing");
                              mi_timing(my_timer, 0);
                              mi_api_render($2, $3, $4,
                                             mi_mem_strdup(ctx->inheritance_func));
                              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);
                              mi_mem_release($2); }
                    | 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);
                              mi_mem_release($2); }
                    | DECLARE function_decl
                    | DECLARE phenomenon_decl
                    | DECLARE data_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 : light
                    | instance
                    | options
                    | camera
                    | object
                    | texture
                    | profile_data
                    | material
                    | instgroup
                    | userdata
                    | gui
                    | 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); }
                    | MIN_ VERSION T_STRING
                            { mi_api_version_check($3, 0); }
                    | MAX_ VERSION T_STRING
                            { mi_api_version_check($3, 1); }
                    ;

    /*****************************************************************************
     *************************    mi1 compatibility    ***************************
     *****************************************************************************/

    /*-----------------------------------------------------------------------------
     * frame
     *---------------------------------------------------------------------------*/

    frame :
                            { mi_api_frame_begin(&camera, &options); }
                      frame_number
                      initial_frame_cmd_list
                      view
                      frame_command_list
                      END FRAME
                            { mi_timing(my_timer, "mi scene file parsing");
                              mi_timing(my_timer, 0);
                              mi_api_frame_end();
                              yyreturn MIYYENDFRAME; }
                    ;

    initial_frame_cmd_list
                    :
                    | initial_frame_cmd_list initial_frame_cmd
                    ;

    initial_frame_cmd
                    : texture
                    | light
                    | material
                    ;

    frame_command_list
                    :
                    | frame_command_list frame_command
                    ;

    frame_command
                    : texture
                    | light
                    | material
                    | object
                    | call
                    | debug
                    | version
                    | gui
                    ;

    /*-----------------------------------------------------------------------------
     * view
     *---------------------------------------------------------------------------*/

    view : VIEW
                              { have_l = have_o = have_v = have_e = 0; }
                      view_list
                      END VIEW
                    ;

    view_list :
                    | view_list view_item
                    ;

    view_item : camview_item
                    | optview_item
                    | MIN_ SAMPLES T_INTEGER
                            { options->min_samples = $3; }
                    | MAX_ SAMPLES T_INTEGER
                            { options->max_samples = $3; }
                    | SAMPLES T_INTEGER
                            { mi_api_warning(
                                    "\"samples\" view parameter ignored"); }
                    | RECURSIVE boolean
                            { if (!$2)
                                    mi_api_warning("\"recursive off\" ignored"); }
                    | ADAPTIVE boolean
                            { mi_api_warning("\"adaptive\" statement ignored"); }
                    | ACCELERATION RAY CLASSIFICATION
                            { options->acceleration = 'b';
                              mi_api_warning(
                                    "ray classification is obsolete, using BSP"); }
                    | ACCELERATION SPATIAL SUBDIVISION
                            { options->acceleration = 'b'; }
                    | ACCELERATION GRID
                            { options->acceleration = 'g'; }
                    | SUBDIVISION MEMORY T_INTEGER
                            { mi_api_warning("ray classification is obsolete, "
                              "statement \"subdivision memory %d\" ignored", $3); }
                    | SUBDIVISION T_INTEGER T_INTEGER
                            { mi_api_warning("ray classification is obsolete, "
                              "statement \"subdivision %d %d\" ignored", $2, $3); }
                    | MAX_ SIZE T_INTEGER
                            { options->space_max_size = $3; }
                    | MAX_ DEPTH T_INTEGER
                            { options->space_max_depth = $3; }
                    | SHADOW SORT boolean
                            { if ($3) options->shadow = 'l'; }
                    | SHADOW SEGMENTS boolean
                            { if ($3) options->shadow = 's'; }
                    | transform
                            { mi_api_view_transform($1); }
                    | RED floating floating
                    | GREEN floating floating
                    | BLUE floating floating
                    | WHITE floating floating
                    ;

    /*****************************************************************************
     *************************    new mi2 features    ****************************
     *****************************************************************************/

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

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

    option_list :
                    | option_list option_item
                    ;

    option_item : optview_item
                    |       { curr_datatag = &options->userdata; }
                      data
                    | ACCELERATION RAYCL
                            { options->acceleration = 'b';
                              mi_api_warning(
                                    "ray classification is obsolete, using BSP"); }
                    | ACCELERATION BSP
                            { options->acceleration = 'b'; }
                    | ACCELERATION GRID
                            { options->acceleration = 'g'; }
                    | MOTION STEPS T_INTEGER
                            { options->n_motion_vectors = $3;}
                    | DIAGNOSTIC SAMPLES boolean
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_SAMPLES,$3);}
                    | DIAGNOSTIC PHOTON OFF
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_PHOTON, miFALSE);}
                    | DIAGNOSTIC PHOTON DENSITY floating
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_PHOTON, miFALSE);
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_PHOTON_D, miTRUE);
                              options->diag_photon_density = $4;}
                    | DIAGNOSTIC PHOTON IRRADIANCE floating
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_PHOTON, miFALSE);
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_PHOTON_I, miTRUE);
                              options->diag_photon_density = $4;}
                    | DIAGNOSTIC GRID OFF
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID, miFALSE);}
                    | DIAGNOSTIC GRID OBJECT floating
                            { options->diag_grid_size = $4;
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID, miFALSE);
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID_O, $4 != 0.0);}
                    | DIAGNOSTIC GRID WORLD floating
                            { options->diag_grid_size = $4;
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID, miFALSE);
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID_W, $4 != 0.0);}
                    | DIAGNOSTIC GRID CAMERA floating
                            { options->diag_grid_size = $4;
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID, miFALSE);
                              miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_GRID_C, $4 != 0.0);}
                    | DIAGNOSTIC BSP OFF
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_BSP, miFALSE); }
                    | DIAGNOSTIC BSP DEPTH
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_BSP_D, miTRUE); }
                    | DIAGNOSTIC BSP SIZE
                            { miBIT_SWITCH(options->diagnostic_mode,
                                    miSCENE_DIAG_BSP_L, miTRUE); }
                    | 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; }
                    | SAMPLES T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                            { options->min_samples = $2;
                              options->max_samples = $3;
                              options->def_min_samples = $4;
                              options->def_max_samples = $5; }
                    | SHADOW SORT
                            { options->shadow = 'l'; }
                    | SHADOW SEGMENTS
                            { options->shadow = 's'; }
                    ;

    optview_item : SHADOW OFF
                            { options->shadow = 0; }
                    | SHADOW ON
                            { options->shadow = 1; }
                    | TRACE boolean
                            { options->trace = $2; }
                    | SCANLINE boolean
                            { options->scanline = $2; }
                    | SCANLINE OPENGL
                            { options->scanline = 'o'; }
                    | 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; }
                    | HAIR boolean
                            { options->no_hair = !$2; }
                    | PASS boolean
                            { options->no_pass = !$2; }
                    | AUTOVOLUME boolean
                            { options->autovolume = $2; }
                    | FILTER filter_type
                            { options->filter        = $2;
                              options->filter_size_x =
                              options->filter_size_y = 0.0; }
                    | 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'; }
                    | SAMPLELOCK boolean
                            { options->samplelock = $2; }
                    | 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; }
                    | SHUTTER floating floating
                            { options->shutter_delay = $2;
                              options->shutter       = $3;
                              options->motion        = options->shutter > 0; }
                    | TASK SIZE T_INTEGER
                            { options->task_size = $3; }
                    | RAYCL SUBDIVISION T_INTEGER T_INTEGER
                            { mi_api_warning("ray classification is obsolete, "
                              "statement \"raycl subdivision %d %d\" ignored",
                                                                    $3, $4); }
                    | RAYCL MEMORY T_INTEGER
                            { mi_api_warning("ray classification is obsolete, "
                              "statement \"raycl memory %d\" ignored", $3); }
                    | BSP SIZE T_INTEGER
                            { options->space_max_size = $3; }
                    | BSP DEPTH T_INTEGER
                            { options->space_max_depth = $3; }
                    | BSP MEMORY T_INTEGER
                            { options->space_max_mem = $3; }
                    | BSP SHADOW boolean
                            { options->space_shadow_separate = $3; }
                    | GRID SIZE T_INTEGER
                            { options->grid_max_size = $3; }
                    | GRID SIZE T_FLOAT
                            { options->grid_res[0] =
                              options->grid_res[1] =
                              options->grid_res[2] = $3;
                              mi_api_warning("obsolete grid size statement, "
                                    "use grid resolution instead"); }
                    | GRID RESOLUTION T_INTEGER
                            { options->grid_res[0] =
                              options->grid_res[1] =
                              options->grid_res[2] = $3; }
                    | GRID RESOLUTION T_INTEGER T_INTEGER T_INTEGER
                            { options->grid_res[0] = $3;
                              options->grid_res[1] = $4;
                              options->grid_res[2] = $5; }
                    | GRID DEPTH T_INTEGER
                            { options->grid_max_depth = $3; }
                    | DESATURATE boolean
                            { options->desaturate = $2; }
                    | DITHER boolean
                            { options->dither = $2; }
                    | PREMULTIPLY boolean
                            { options->nopremult = !$2; }
                    | COLORCLIP colorclip_mode
                            { options->colorclip = $2; }
                    | GAMMA floating
                            { options->gamma = $2; }
                    | OBJECT SPACE
                            { options->render_space = 'o'; }
                    | CAMERA SPACE
                            { options->render_space = 'c'; }
                    | MIXED SPACE
                            { options->render_space = 'm'; }
                    | WORLD SPACE
                            { mi_api_warning(
                                    "world space statement ignored"); } /*<<<*/
                    | INHERITANCE symbol
                            { options->inh_is_traversal = miFALSE;
                              if (ctx->inheritance_func)
                                    mi_mem_release(ctx->inheritance_func);
                              ctx->inheritance_func = $2;
                              if (!(options->inh_funcdecl = mi_api_decl_lookup(
                                                               mi_mem_strdup($2))))
                                    mi_api_nerror(176, "undeclared inheritance "
                                                              "shader \"%s\"", $2);
                            }
                    | TRAVERSAL symbol
                            { options->inh_is_traversal = miTRUE;
                              if (ctx->inheritance_func)
                                    mi_mem_release(ctx->inheritance_func);
                              ctx->inheritance_func = $2;
                              if (!(options->inh_funcdecl = mi_api_decl_lookup(
                                                               mi_mem_strdup($2))))
                                    mi_api_nerror(176, "undeclared traversal "
                                                              "shader \"%s\"", $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; }
                    | SHADOWMAP OPENGL
                            { options->use_shadow_maps = 'o'; }
                    | CAUSTIC boolean
                            { options->caustic = $2; }
                    | CAUSTIC T_INTEGER
                            { options->caustic_flag = $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 T_INTEGER
                            { options->globillum_flag = $2; }
                    | GLOBILLUM ACCURACY T_INTEGER
                            { options->globillum_accuracy = $3; }
                    | GLOBILLUM ACCURACY T_INTEGER floating
                            { options->globillum_accuracy = $3;
                              options->globillum_radius = $4; }
                    | FINALGATHER boolean
                            { options->finalgather = $2; }
                    | FINALGATHER FASTLOOKUP
                            { options->finalgather = 'f'; }
                    | FINALGATHER ACCURACY T_INTEGER
                            { options->finalgather_view      = miFALSE;
                              options->finalgather_rays      = $3; }
                    | FINALGATHER ACCURACY T_INTEGER floating
                            { options->finalgather_view      = miFALSE;
                              options->finalgather_rays      = $3;
                              options->finalgather_maxradius = $4;
                              options->finalgather_minradius = 0.0; }
                    | FINALGATHER ACCURACY T_INTEGER floating floating
                            { options->finalgather_view      = miFALSE;
                              options->finalgather_rays      = $3;
                              options->finalgather_maxradius = $4;
                              options->finalgather_minradius = $5; }
                    | FINALGATHER ACCURACY VIEW T_INTEGER
                            { options->finalgather_view      = miTRUE;
                              options->finalgather_rays      = $4; }
                    | FINALGATHER ACCURACY VIEW T_INTEGER floating
                            { options->finalgather_view      = miTRUE;
                              options->finalgather_rays      = $4;
                              options->finalgather_maxradius = $5;
                              options->finalgather_minradius = 0.0; }
                    | FINALGATHER ACCURACY VIEW T_INTEGER floating floating
                            { options->finalgather_view      = miTRUE;
                              options->finalgather_rays      = $4;
                              options->finalgather_maxradius = $5;
                              options->finalgather_minradius = $6; }

                    | FINALGATHER FILE_
                            { mi_scene_delete(options->finalgather_file);
                              options->finalgather_file = 0; }
                    | FINALGATHER FILE_ T_STRING
                            { mi_scene_delete(options->finalgather_file);
                              strcpy((char *)mi_scene_create(
                                            &options->finalgather_file,
                                            miSCENE_STRING, strlen($3)+1), $3);
                              mi_db_unpin(options->finalgather_file);
                              mi_mem_release($3); }
                    | FINALGATHER REBUILD boolean
                            { options->finalgather_rebuild = $3; }
                    | PHOTONVOL ACCURACY T_INTEGER
                            { options->photonvol_accuracy = $3; }
                    | PHOTONVOL ACCURACY T_INTEGER floating
                            { options->photonvol_accuracy = $3;
                              options->photonvol_radius = $4; }
                    | PHOTONMAP FILE_
                            { mi_scene_delete(options->photonmap_file);
                              options->photonmap_file = 0; }
                    | 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
                    | FRAME BUFFER T_INTEGER opt_symbol
                            { mi_api_framebuffer(options, $3, $4); }
                    | LUMINANCE WEIGHT NTSC
                            { options->luminance_weight.r = 0.299;
                              options->luminance_weight.g = 0.587;
                              options->luminance_weight.b = 0.114;
                              options->luminance_weight.a = 0.0; }
                    | LUMINANCE WEIGHT floating floating floating
                            { options->luminance_weight.r = $3;
                              options->luminance_weight.g = $4;
                              options->luminance_weight.b = $5;
                              options->luminance_weight.a = 0; }
                    ;

    filter_type : BOX
                            { $$ = 'b'; }
                    | TRIANGLE
                            { $$ = 't'; }
                    | GAUSS
                            { $$ = 'g'; }
                    | MITCHELL
                            { $$ = 'm'; }
                    | LANCZOS
                            { $$ = 'l'; }
                    ;

    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 = have_p = 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 out_parms T_STRING
                            { miTag ftag;
                              if (!have_o++)
                                    mi_api_function_delete(&camera->output);
                              camera->output = mi_api_function_append(
                                    camera->output,
                                    ftag = mi_api_output_file_def(0, 0, $2, $4));
                              mi_api_output_file_parameter(ftag, 0, &$3[0]);
                              mi_api_output_file_parameter(ftag, 1, &$3[1]); }
                    | 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 T_STRING out_parms T_STRING
                            { miTag ftag;
                              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,
                                    ftag = mi_api_output_file_def(tbm, ibm,$3,$5));
                              mi_api_output_file_parameter(ftag, 0, &$4[0]);
                              mi_api_output_file_parameter(ftag, 1, &$4[1]); }
                    | 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)); }
                    | PASS NULL_
                            { mi_api_function_delete(&camera->pass); }
                    | PASS pass_samples opt_string WRITE T_STRING
                            { if (!have_p++)
                                    mi_api_function_delete(&camera->pass);
                              mi_api_output_type_identify(&tbm, &ibm, $3);
                              camera->pass = mi_api_function_append(camera->pass,
                                    mi_api_pass_save_def(0, 0, $2, $5)); }
                    | PASS PREP pass_samples opt_string
                      READ T_STRING WRITE T_STRING function_list
                            { if (!have_p++)
                                    mi_api_function_delete(&camera->pass);
                              mi_api_output_type_identify(&tbm, &ibm, $4);
                              camera->pass = mi_api_function_append(camera->pass,
                                    mi_api_pass_prep_def(tbm, ibm, $3, $6,$8,$9));}
                    | PASS MERGE pass_samples opt_string
                      READ string_list opt_function_list
                            { if (!have_p++)
                                    mi_api_function_delete(&camera->pass);
                              mi_api_output_type_identify(&tbm, &ibm, $4);
                              camera->pass = mi_api_function_append(camera->pass,
                                    mi_api_pass_merge_def(tbm, ibm, $3, $6,0,$7));}
                    | PASS MERGE pass_samples opt_string
                      READ string_list WRITE T_STRING opt_function_list
                            { if (!have_p++)
                                    mi_api_function_delete(&camera->pass);
                              mi_api_output_type_identify(&tbm, &ibm, $4);
                              camera->pass = mi_api_function_append(camera->pass,
                                    mi_api_pass_merge_def(tbm,ibm, $3, $6,$8,$9));}
                    | PASS DELETE_ T_STRING
                            { if (!have_p++)
                                    mi_api_function_delete(&camera->pass);
                              camera->pass = mi_api_function_append(camera->pass,
                                    mi_api_pass_delete_def($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->focal = 1;
                              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; }
                    | OFFSET floating floating
                            { camera->x_offset = $2;
                              camera->y_offset = $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; }
                    |       { curr_datatag = &camera->userdata; }
                      data
                    ;

    out_parms : QUALITY T_INTEGER
                            { $$[0] = (float)$2; }
                    | EVEN
                            { $$[1] = 1.0; }
                    | ODD
                            { $$[1] = 2.0; }
                    ;

    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  = $3;
                              camera->frame_field = 0; }
                    ;

    pass_samples :
                            { $$ = ~0; }
                    | SAMPLES T_INTEGER
                            { $$ = $2; }
                    ;

    string_list :
                            { $$ = stringlist
                                 = mi_api_dlist_create(miDLIST_POINTER); }
                      '[' strings ']'
                    ;

    strings : T_STRING
                            { mi_api_dlist_add(stringlist, $1); }
                    | T_STRING ','
                            { mi_api_dlist_add(stringlist, $1); }
                      strings
                    ;

    /*-----------------------------------------------------------------------------
     * 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; }
                    | SELECT boolean
                            { curr_inst->select  = $2 ? 2 : 1; }
                    | CAUSTIC
                            { curr_inst->caustic &= 0x30;
                              curr_inst->caustic |= 0x03; }
                    | CAUSTIC boolean
                            { curr_inst->caustic &= 0x0f;
                              curr_inst->caustic |= $2 ? 0x20 : 0x10; }
                    | CAUSTIC T_INTEGER
                            { curr_inst->caustic &= 0x30;
                              curr_inst->caustic |= ($2 & 0x0f); }
                    | GLOBILLUM
                            { curr_inst->globillum &= 0x30;
                              curr_inst->globillum |= 0x03; }
                    | GLOBILLUM boolean
                            { curr_inst->globillum &= 0x0f;
                              curr_inst->globillum |= $2 ? 0x20 : 0x10; }
                    | GLOBILLUM T_INTEGER
                            { curr_inst->globillum &= 0x30;
                              curr_inst->globillum |= ($2 & 0x0f); }
                    | 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;
                              curr_inst->mtl_override   = miFALSE; }
                      inst_mtl
                    | TAG T_INTEGER
                            { curr_inst->label = $2; }
                    |       { curr_datatag = &curr_inst->userdata; }
                      data
                    ;

    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 comma_rparen
                            { $$ = mi_api_function_call_end(0); }
                    ;

    comma_rparen : ')'
                    | ',' ')'
                    ;

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

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

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

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

    instgroup : INSTGROUP symbol
                            { curr_group = mi_api_instgroup_begin($2);
                              mi_api_instgroup_clear(); }
                      group_flags
                      group_list END INSTGROUP
                            { mi_api_instgroup_end(); }
                    ;

    group_flags :
                    | group_flag group_flags
                    ;

    group_flag : MERGE floating
                            { curr_group->merge = $2;
                              curr_group->merge_group = $2 >= miMERGE_MIN; }
                    | TAG T_INTEGER
                            { curr_group->label = $2; }
                    |       { curr_datatag = &curr_group->userdata; }
                      data
                    ;

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

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

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

    function_decl : shret_type_nosh T_STRING parm_decl_list
                            { mi_api_funcdecl_begin($1, $2, $3);
                              mi_api_funcdecl_end(); }
                    | SHADER shret_type T_STRING parm_decl_list
                            { if (!(curr_decl = mi_api_funcdecl_begin($2, $3, $4)))
                                    curr_decl = &dummy_decl; }
                      declare_req_seq END DECLARE
                            { mi_api_funcdecl_end(); }
                    ;

    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); }
                    | DATA symbol
                            { $$ = mi_api_parameter_decl(miTYPE_DATA,   $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); }
                    | DATA symbol
                            { $$ = mi_api_parameter_decl(miTYPE_DATA,   $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; }
                    | LIGHTPROFILE
                            { $$ = miTYPE_LIGHTPROFILE; }
                    | 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"); }
                    | PARALLEL_
                            { curr_decl->phen.parallel = miTRUE; }
                    | VOLUME LEVEL T_INTEGER
                            { curr_decl->phen.volume_level = $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;          }
                    | LIGHTMAP              { $$ = miAPPLY_LIGHTMAP;        }
                    | PHOTONVOL             { $$ = miAPPLY_PHOTONVOL;       }
                    ;

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

    opt_function_list:
                            { $$ = 0; }
                    | function_list
                            { $$ = $1; }
                    ;

    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);
                              mi_api_private(session_depth); }
                    ;

    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(); }
                    | '[' ']'
                            { mi_api_parameter_push(miTRUE);
                              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
                    ;

    /*-----------------------------------------------------------------------------
     * user data
     *---------------------------------------------------------------------------*/

    userdata : DATA symbol data_label T_INTEGER
                            { curr_data = mi_api_data_begin($2, 0,
                                                            (void *)(miIntptr)$4);
                              curr_data->label = label; }
                      '[' data_bytes_list ']'
                            { mi_api_data_end(); }
                    | DATA symbol data_label symbol
                            { curr_data = mi_api_data_begin($2, 1,
                                                            (void *)(miIntptr)$4);
                              curr_data->label = label;
                              mi_api_data_end(); }
                    | DATA symbol data_label symbol '('
                            { mi_api_function_call($4); }
                      parameter_seq comma_rparen
                            { tag = mi_api_function_call_end(0);
                              curr_data = mi_api_data_begin($2, 2,
                                                            (void *)(miIntptr)tag);
                              curr_data->label = label;
                              mi_api_data_end(); }
                    ;

    data_label :
                            { label = 0; }
                    | TAG T_INTEGER
                            { label = $2; }

    data_bytes_list :
                    | data_bytes_list T_BYTE_STRING
                            { mi_api_data_byte_copy($2.len, $2.bytes); }
                    ;

    data_decl : DATA T_STRING parm_decl_list
                            { if (curr_decl = mi_api_funcdecl_begin(0, $2, $3))
                                    curr_decl->type = miFUNCTION_DATA; }
                      data_decl_req END DECLARE
                            { if (curr_decl) mi_api_funcdecl_end(); }
                    ;

    data_decl_req :
                    | gui
                    | VERSION T_INTEGER
                            { if (curr_decl) curr_decl->version = $2; }
                    | APPLY apply_list
                            { if (curr_decl) curr_decl->apply = $2; }
                    ;

    data : DATA symbol
                            { *curr_datatag = mi_api_data_append(*curr_datatag,
                                                    mi_api_data_lookup($2)); }
                    | DATA NULL_
                            { *curr_datatag = 0; }
                    ;

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

    phenomenon_decl : PHENOMENON shret_type T_STRING parm_decl_list
                            { curr_decl = mi_api_phen_begin($2, $3, $4);
                              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);
                              mi_api_texture_set_filter(pyramid_filter); }
                      tex_data
                            { if (pyramid_filter > 0. && functag &&
                                  (mi_db_type(functag) != miSCENE_IMAGE)) {
                                    mi_api_nwarning(42, "cannot filter shaders");
                              }
                              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; }
                    | WRITABLE
                            { $$ = 4; }
                    ;

    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
                            { functag = mi_api_texture_array_def_end(); }
                    | '[' T_INTEGER T_INTEGER T_INTEGER ']'
                            { mi_api_texture_array_def_begin($2, $3, $4); }
                      tex_bytes_list
                            { functag = mi_api_texture_array_def_end(); }
                    | tex_func_list
                            { functag = mi_api_texture_function_def($1); }
                    | T_STRING
                            { functag = mi_api_texture_file_def($1); }
                    | T_STRING '[' T_INTEGER T_INTEGER ']'
                            { mi_api_texture_file_size($3, $4, 1, 0);
                              functag = mi_api_texture_file_def($1); }
                    | T_STRING '[' T_INTEGER T_INTEGER T_INTEGER ']'
                            { mi_api_texture_file_size($3, $4, $5, 0);
                              functag = mi_api_texture_file_def($1); }
                    ;

    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 profiles
     *---------------------------------------------------------------------------*/

    profile_data : LIGHTPROFILE symbol
                            { lprof = mi_api_lightprofile_begin($2); }
                      lprof_ops
                      END LIGHTPROFILE
                            { mi_api_lightprofile_end(); }
                    ;

    lprof_ops : lprof_ops lprof_op
                    |
                    ;

    lprof_op : FORMAT IES
                            { lprof->format = miLP_STD_IES; }
                    | FORMAT EULUMDAT
                            { lprof->format = miLP_STD_EULUMDAT; }
                    | FLAGS T_INTEGER
                            { lprof->flags = $2; }
                    | FILE_ T_STRING
                            { char* fn = mi_scene_create(&lprof->filename,
                                            miSCENE_STRING, strlen($2)+1);
                              strcpy(fn, $2);
                              mi_scene_edit_end(lprof->filename); }
                    | HERMITE T_INTEGER
                            { lprof->base    = miLP_BASIS_HERMITE;
                              lprof->quality = $2; }
                    | RESOLUTION T_INTEGER T_INTEGER
                            { lprof->n_horz_angles = $2;
                              lprof->n_vert_angles = $3; }
                    ;

    /*-----------------------------------------------------------------------------
     * 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_store_photons = $3;
                              curr_light->caustic_emit_photons = 0; }
                    | CAUSTIC PHOTONS T_INTEGER T_INTEGER
                            { curr_light->caustic_store_photons = $3;
                              curr_light->caustic_emit_photons = $4; }
                    | GLOBILLUM PHOTONS T_INTEGER
                            { curr_light->global_store_photons = $3;
                              curr_light->global_emit_photons = 0; }
                    | GLOBILLUM PHOTONS T_INTEGER T_INTEGER
                            { curr_light->global_store_photons = $3;
                              curr_light->global_emit_photons = $4; }
                    | RECTANGLE vector vector light_samples
                            { curr_light->area = miLIGHT_RECTANGLE;
                              curr_light->primitive.rectangle.edge_u = $2;
                              curr_light->primitive.rectangle.edge_v = $3; }
                    | DISC vector floating light_samples
                            { curr_light->area = miLIGHT_DISC;
                              curr_light->primitive.disc.normal      = $2;
                              curr_light->primitive.disc.radius      = $3; }
                    | SPHERE floating light_samples
                            { curr_light->area = miLIGHT_SPHERE;
                              curr_light->primitive.sphere.radius    = $2; }
                    | CYLINDER vector floating light_samples
                            { curr_light->area = miLIGHT_CYLINDER;
                              curr_light->primitive.cylinder.axis    = $2;
                              curr_light->primitive.cylinder.radius  = $3; }
                    | OBJECT symbol light_samples
                            { curr_light->area = miLIGHT_OBJECT;
                              curr_light->primitive.object.object =
                                    mi_api_name_lookup($2); }
                    | USER light_samples
                            { curr_light->area = miLIGHT_USER; }
                    | RECTANGLE
                            { curr_light->area = miLIGHT_NONE; }
                    | DISC
                            { curr_light->area = miLIGHT_NONE; }
                    | SPHERE
                            { curr_light->area = miLIGHT_NONE; }
                    | CYLINDER
                            { curr_light->area = miLIGHT_NONE; }
                    | 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; }
                    | VISIBLE boolean
                            { curr_light->visible = $2; }
                    | TAG T_INTEGER
                            { curr_light->label = $2; }
                    |       { curr_datatag = &curr_light->userdata; }
                      data
                    ;

    light_samples :
                    | T_INTEGER
                            { curr_light->samples_u     = $1;
                              curr_light->samples_v     = 1;  }
                    | T_INTEGER T_INTEGER
                            { curr_light->samples_u     = $1;
                              curr_light->samples_v     = $2; }
                    | T_INTEGER T_INTEGER T_INTEGER
                            { curr_light->samples_u     = $1;
                              curr_light->samples_v     = $2;
                              curr_light->low_level     = $3; }
                    | T_INTEGER T_INTEGER T_INTEGER T_INTEGER T_INTEGER
                            { curr_light->samples_u     = $1;
                              curr_light->samples_v     = $2;
                              curr_light->low_level     = $3;
                              curr_light->low_samples_u = $4;
                              curr_light->low_samples_v = $5; }
                    ;

    /*-----------------------------------------------------------------------------
     * 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 = have_lm = 0; }
                      mtl_flags
                      mtl_shader
                      mtl_args
                      END MATERIAL
                            { mi_api_material_end(); }
                    ;

    mtl_shader :
                    |
                      function_list
                            { curr_mtl->shader = $1; }
                    ;

    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; }
                    | LIGHTMAP
                            { mi_api_function_delete(&curr_mtl->lightmap); }
                    | LIGHTMAP function_list
                            { if (!have_lm++)
                                    mi_api_function_delete(&curr_mtl->lightmap);
                              curr_mtl->lightmap = $2; }
                    ;

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

    object : OBJECT opt_symbol
                            { curr_obj = mi_api_object_begin($2); }
                      obj_flags
                      object_body
                      END OBJECT
                            { mi_api_object_end(); }
                    ;

    obj_flags :
                    | obj_flag obj_flags
                    ;

    obj_flag : VISIBLE
                            { curr_obj->visible = miTRUE; }
                    | VISIBLE boolean
                            { curr_obj->visible = $2; }
                    | SHADOW
                            { curr_obj->shadow  = miTRUE; }
                    | SHADOW boolean
                            { curr_obj->shadow  = $2; }
                    | TRACE
                            { curr_obj->trace   = miTRUE; }
                    | TRACE boolean
                            { curr_obj->trace   = $2; }
                    | SELECT
                            { curr_obj->select  = miTRUE; }
                    | SELECT boolean
                            { curr_obj->select  = $2; }
                    | TAGGED
                            { curr_obj->mtl_is_label = miTRUE; }
                    | TAGGED boolean
                            { curr_obj->mtl_is_label = $2; }
                    | CAUSTIC
                            { curr_obj->caustic |= 3; }
                    | CAUSTIC boolean
                            { curr_obj->caustic &= 0x03;
                              if (!$2)
                                      curr_obj->caustic |= 0x10; }
                    | CAUSTIC T_INTEGER
                            { curr_obj->caustic &= 0x10;
                              curr_obj->caustic |= ($2 & 0x03); }
                    | GLOBILLUM
                            { curr_obj->globillum |= 3; }
                    | GLOBILLUM boolean
                            { curr_obj->globillum &= 0x03;
                              if (!$2)
                                      curr_obj->globillum |= 0x10; }
                    | GLOBILLUM T_INTEGER
                            { curr_obj->globillum &= 0x10;
                              curr_obj->globillum |= ($2 & 0x03); }
                    | TAG T_INTEGER
                            { curr_obj->label = $2; }
                    |       { curr_datatag = &curr_obj->userdata; }
                      data
                    | transform
                            { mi_api_object_matrix($1); }
                    | MAX_ DISPLACE floating
                            { curr_obj->maxdisplace = $3; }
                    | BOX vector vector
                            { curr_obj->bbox_min = $2;
                              curr_obj->bbox_max = $3; }
                    | BOX
                            { curr_obj->bbox_min = nullvec;
                              curr_obj->bbox_max = nullvec; }
                    | MOTION BOX vector vector
                            { curr_obj->bbox_min_m = $3;
                              curr_obj->bbox_max_m = $4; }
                    | MOTION BOX
                            { curr_obj->bbox_min_m = nullvec;
                              curr_obj->bbox_max_m = nullvec; }
                    | SAMPLES T_INTEGER
                            { curr_obj->min_samples = $2-2;
                              curr_obj->max_samples = $2;}
                    | SAMPLES T_INTEGER T_INTEGER
                            { curr_obj->min_samples = $2;
                              curr_obj->max_samples = $3;}
                    ;

    object_body : bases_and_groups
                    | FILE_ T_STRING
                            { mi_api_object_file($2); }
                    | hair_object
                    ;

    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); }
                    | 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, 3, 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($3);
                              mi_mem_release($2); }
                      vector_list
                      vertex_list
                      geometry_list
                      END GROUP
                            { mi_api_object_group_end(); }
                    ;

    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_list
                      u_vector_list
                      vertex_flag
                    ;

    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_list :
                    | m_vector_list M T_INTEGER
                            { mi_api_vertex_motion_add($3); }
                    ;

    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); }
                    ;

    vertex_flag :
                    | CUSP
                            { mi_api_vertex_flags_add(miAPI_V_CUSP, 0, 1.f); }
                    | CUSP LEVEL T_INTEGER
                            { mi_api_vertex_flags_add(miAPI_V_CUSP, $3, 1.f); }
                    | CONIC
                            { mi_api_vertex_flags_add(miAPI_V_CONIC, 0, 1.f); }
                    | CONIC LEVEL T_INTEGER
                            { mi_api_vertex_flags_add(miAPI_V_CONIC, $3, 1.f); }
                    | CORNER
                            { mi_api_vertex_flags_add(miAPI_V_CORNER, 0, 1.f); }
                    | CORNER LEVEL T_INTEGER
                            { mi_api_vertex_flags_add(miAPI_V_CORNER, $3, 1.f); }
                    | DART
                            { mi_api_vertex_flags_add(miAPI_V_DART, 0, 0.f); }
                    ;

    geometry_list :
                    | geometry_list geometry
                    ;

    geometry : polygon
                    | curve
                    | spacecurve
                    | surface
                    | subdivsurf
                    | connection
                    | approximation
            /*      | implicit_patch        */
                    ;

    /* polygons */

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

    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; }
                    ;

    /* curves and space curves */

    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); }
                    ;

    spacecurve : SPACE CURVE symbol
                            { mi_api_spacecurve_begin($3); }
                      spcurve_list
                            { mi_api_spacecurve_end(); }
                    ;

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

    /* free-form surfaces */

    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(); }
                    ;

    mtl_or_label : symbol
                            { $$ = $1; }
                    | T_INTEGER
                            { $$ = (char *)(miIntptr)$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);}
                    ;

    /* subdivision surfaces */

    subdivsurf : SUBDIVISION SURFACE symbol
                            { mi_api_subdivsurf_begin($3); }
                      sds_base_faces
                      derivatives
                      END SUBDIVISION SURFACE
                            { mi_api_subdivsurf_end(); }
                    ;

    derivatives :
                    | derivative derivatives
                    ;

    derivative : DERIVATIVE T_INTEGER
                            { mi_api_subdivsurf_derivative($2, 0); }
                    | DERIVATIVE T_INTEGER SPACE T_INTEGER
                            { mi_api_subdivsurf_derivative($2, $4); }
                    ;

    sds_base_faces :
                    | sds_base_face sds_base_faces
                    ;

    sds_base_face : P opt_symbol sds_indices
                            { mi_api_subdivsurf_baseface();
                              mi_api_subdivsurf_mtl(-1, $2); }
                      base_data
                    ;

    base_data :
                    | base_spec base_data
                    ;

    base_spec : '{'
                            { mi_api_subdivsurf_push();
                              mi_api_subdivsurf_subdivide(-1); }
                      hira_data '}'
                            { mi_api_subdivsurf_pop(); }
                    | CREASE T_INTEGER sds_creaseflags
                            { mi_api_subdivsurf_crease(-1, $2); }
                    | TRIM T_INTEGER
                            { mi_api_subdivsurf_trim(-1, $2); }
                    ;

    hira_data :
                    | hira_spec hira_data
                    ;

    hira_spec : MATERIAL T_INTEGER symbol
                            { mi_api_subdivsurf_mtl($2, $3); }
                    | MATERIAL T_INTEGER T_INTEGER
                            { mi_api_subdivsurf_mtl_tag($2, $3); }
                    | DETAIL T_INTEGER sds_indices
                            { mi_api_subdivsurf_detail($2); }
                    | CREASE T_INTEGER T_INTEGER sds_creaseflags
                            { mi_api_subdivsurf_crease($2, $3); }
                    | TRIM T_INTEGER T_INTEGER
                            { mi_api_subdivsurf_trim($2, $3); }
                    | CHILD T_INTEGER '{'
                            { mi_api_subdivsurf_push();
                              mi_api_subdivsurf_subdivide($2); }
                      hira_data '}'
                            { mi_api_subdivsurf_pop(); }
                    ;

    sds_indices :
                    | T_INTEGER
                            { mi_api_subdivsurf_index($1); }
                      sds_indices
                    ;

    sds_creaseflags :
                    | floating
                            { mi_api_subdivsurf_crease_edge($1); }
                      sds_creaseflags
                    ;

    /* hairs */

    hair_object : HAIR
                            { hair = mi_api_hair_begin(); }
                      hair_options
                      SCALAR '[' T_INTEGER ']'
                            { hair_index   = 0;
                              hair_scalars = mi_api_hair_scalars_begin($6); }
                      hair_scalars
                            { mi_api_hair_scalars_end(hair_index); }
                      HAIR '[' T_INTEGER ']'
                            { mi_api_hair_hairs_begin($13); }
                      hair_hairs
                            { mi_api_hair_hairs_end();
                              mi_api_hair_end(); }
                      END HAIR

    hair_options : hair_option hair_options
                    |
                    ;

    hair_option : MATERIAL symbol
                            { hair->material = mi_api_material_lookup($2); }
                    | RADIUS floating
                            { hair->radius = $2; }
                    | APPROXIMATE T_INTEGER
                            { hair->approx = $2; }
                    | DEGREE T_INTEGER
                            { hair->degree = $2; }
                    | MAX_ SIZE T_INTEGER
                            { hair->space_max_size  = $3; }
                    | MAX_ DEPTH T_INTEGER
                            { hair->space_max_depth = $3; }
                    | HAIR N
                            { mi_api_hair_info(0, 'n', 3); }
                    | HAIR M T_INTEGER
                            { mi_api_hair_info(0, 'm', 3*$3); }
                    | HAIR T T_INTEGER
                            { mi_api_hair_info(0, 't', $3); }
                    | HAIR RADIUS
                            { mi_api_hair_info(0, 'r', 1); }
                    | HAIR U T_INTEGER
                            { mi_api_hair_info(0, 'u', $3); }
                    | VERTEX N
                            { mi_api_hair_info(1, 'n', 3); }
                    | VERTEX M T_INTEGER
                            { mi_api_hair_info(1, 'm', 3*$3); }
                    | VERTEX T T_INTEGER
                            { mi_api_hair_info(1, 't', $3); }
                    | VERTEX RADIUS
                            { mi_api_hair_info(1, 'r', 1); }
                    | VERTEX U T_INTEGER
                            { mi_api_hair_info(1, 'u', $3); }
                    ;

    hair_scalars :
                    | hair_scalars floating
                            { if (hair_index < hair->no_scalars)
                                    hair_scalars[hair_index] = $2;
                              hair_index++; }
                    ;

    hair_hairs :
                    | hair_hairs T_INTEGER
                            { mi_api_hair_hairs_add($2); }
                    ;

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

    approximation : { miAPPROX_DEFAULT(approx); }
                      approx_body
                    ;

    approx_body : APPROXIMATE SURFACE s_approx_tech s_approx_names
                    | APPROXIMATE SUBDIVISION SURFACE
                                           c_approx_tech sds_approx_names
                    | APPROXIMATE DISPLACE s_approx_tech d_approx_names
                    | APPROXIMATE CURVE    c_approx_tech c_approx_names
                    | APPROXIMATE SPACE CURVE
                                           c_approx_tech spc_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;
                              approx.max            = miHUGE_INT;
                              if (approx.style == miAPPROX_STYLE_FINE)
                                    approx.subdiv[miMAX] = 7; }
                    | s_approx_params T_INTEGER T_INTEGER
                            { approx.subdiv[miMIN]  = $2;
                              approx.subdiv[miMAX]  = $3;
                              approx.max            = miHUGE_INT; }
                    | s_approx_params MAX_ T_INTEGER
                            { approx.subdiv[miMIN]  = 0;
                              approx.subdiv[miMAX]  = 5;
                              approx.max            = $3;
                              if (approx.style == miAPPROX_STYLE_FINE)
                                    approx.subdiv[miMAX] = 7; }
                    | s_approx_params T_INTEGER T_INTEGER MAX_ T_INTEGER
                            { approx.subdiv[miMIN]  = $2;
                              approx.subdiv[miMAX]  = $3;
                              approx.max            = $5; }
                    | s_approx_params SAMPLES T_INTEGER
                            { approx.subdiv[miMIN]  = 0;
                              approx.subdiv[miMAX]  = 5;
                              approx.max            = $3;
                              if (approx.style == miAPPROX_STYLE_FINE)
                                    approx.subdiv[miMAX] = 7; }
                    | s_approx_params T_INTEGER T_INTEGER SAMPLES T_INTEGER
                            { approx.subdiv[miMIN]  = $2;
                              approx.subdiv[miMAX]  = $3;
                              approx.max            = $5; }
                    ;

    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; }
                    | ANY
                            { approx.any            = miTRUE; }
                    | TREE
                            { approx.style          = miAPPROX_STYLE_TREE; }
                    | GRID
                            { approx.style          = miAPPROX_STYLE_GRID; }
                    | DELAUNAY
                            { approx.style          = miAPPROX_STYLE_DELAUNAY; }
                    | CONTOUR
                            { approx.style          = miAPPROX_STYLE_CONTOUR; }
                    | CONTOUR NORMAL
                            { approx.style          = miAPPROX_STYLE_CONTOUR_NORM;}
                    | FINE
                            { approx.style          = miAPPROX_STYLE_FINE; }
                    | SHARP floating
                            { approx.sharp          = $2<0? 0: $2>1? 255: $2*255.;}
                    | 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; }
                    | GRADING floating
                            { approx.grading                = $2; }
                    ;

    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); }
                    ;

    sds_approx_names: symbol
                            { mi_api_subdivsurf_approx($1, &approx); }
                    | sds_approx_names symbol
                            { mi_api_subdivsurf_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); }
                    ;

    spc_approx_names: symbol
                            { mi_api_spacecurve_approx($1, &approx); }
                    | c_approx_names symbol
                            { mi_api_spacecurve_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); }
                    ;

    /*-----------------------------------------------------------------------------
     * user-interface commands
     *---------------------------------------------------------------------------*/

    gui : GUI opt_symbol
                            { mi_api_gui_begin($2); }
                      '(' gui_attr_list ')' '{' gui_controls '}'
                            { mi_api_gui_end(); }
                    | GUI opt_symbol
                            { mi_api_gui_begin($2); }
                      '{' gui_controls '}'
                            { mi_api_gui_end(); }
                    ;

    gui_elems :
                    | gui_elem gui_elems
                    ;

    gui_elem : '(' gui_attr_list ')'
                    | '{'
                            { mi_api_gui_push(); }
                      gui_controls '}'
                            { mi_api_gui_pop(); }
                    ;

    gui_controls :
                    | gui_control gui_controls
                    ;

    gui_control : CONTROL symbol opt_symbol
                            { mi_api_gui_control_begin($3?$2:0, $3?$3:$2); }
                      gui_elems
                            { mi_api_gui_control_end(); }
                    ;

    gui_attr_list :
                    | ','
                    | gui_attr
                    | gui_attr ',' gui_attr_list
                    ;

    gui_attr : symbol
                            { mi_api_gui_attr($1, miNTYPES, 0); }
                    | symbol boolean
                            { mi_api_gui_attr($1, miTYPE_BOOLEAN, 1, $2); }
                    | symbol floating
                            { mi_api_gui_attr($1, miTYPE_SCALAR, 1, $2); }
                    | symbol floating floating
                            { mi_api_gui_attr($1, miTYPE_SCALAR, 2, $2, $3); }
                    | symbol floating floating floating
                            { mi_api_gui_attr($1, miTYPE_SCALAR, 3, $2, $3, $4); }
                    | symbol floating floating floating floating
                            { mi_api_gui_attr($1, miTYPE_SCALAR, 4, $2,$3,$4,$5); }
                    | symbol symbol
                            { mi_api_gui_attr($1, miTYPE_STRING, 1, $2); }
                    ;
    %%

Next: Bibliography Up: No Title Previous: 6.9 Convert Scenes to