#line 2 "common.rules" /************************************************************************* * Copyright (C) 2010 Tavian Barnes * * * * This file is part of Dimension. * * * * Dimension is free software; you can redistribute it and/or modify it * * under the terms of the GNU General Public License as published by the * * Free Software Foundation; either version 3 of the License, or (at * * your option) any later version. * * * * Dimension is distributed in the hope that it will be useful, but * * WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * *************************************************************************/ /* Fundamental language elements */ IDENTIFIER: "identifier" { $$ = dmnsn_new_astleaf(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup($1); dmnsn_free($1); } ; STRING: "string" { $$ = dmnsn_new_astleaf(DMNSN_AST_STRING, @$); $$.ptr = $1; } ; /* Transformations */ TRANSFORMATION: "rotate" VECTOR { dmnsn_astnode rotation = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2); $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, rotation); } | "scale" VECTOR { dmnsn_astnode scale = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2); $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, scale); } | "translate" VECTOR { dmnsn_astnode translation = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2); $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, translation); } | "matrix" "<" FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT "," FLOAT ">" { dmnsn_astnode matrix = dmnsn_new_astnode(DMNSN_AST_MATRIX, @$); dmnsn_array_push(matrix.children, &$3); dmnsn_array_push(matrix.children, &$5); dmnsn_array_push(matrix.children, &$7); dmnsn_array_push(matrix.children, &$9); dmnsn_array_push(matrix.children, &$11); dmnsn_array_push(matrix.children, &$13); dmnsn_array_push(matrix.children, &$15); dmnsn_array_push(matrix.children, &$17); dmnsn_array_push(matrix.children, &$19); dmnsn_array_push(matrix.children, &$21); dmnsn_array_push(matrix.children, &$23); dmnsn_array_push(matrix.children, &$25); $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, matrix); } | "transform" IDENTIFIER { dmnsn_astnode *trans = dmnsn_find_symbol(symtable, $2.ptr); if (!trans) { dmnsn_diagnostic(@2, "unbound identifier '%s'", (const char *)$2.ptr); dmnsn_delete_astnode($2); YYERROR; } if (trans->type != DMNSN_AST_TRANSFORMATION) { dmnsn_diagnostic( @2, "identifier '%s' is a %s; expected a %s", (const char *)$2.ptr, dmnsn_astnode_string(trans->type), dmnsn_astnode_string(DMNSN_AST_TRANSFORMATION) ); dmnsn_delete_astnode($2); YYERROR; } $$ = dmnsn_new_astnode(DMNSN_AST_TRANSFORMATION, @$); dmnsn_copy_children($$, *trans); dmnsn_delete_astnode($2); } | "transform" "{" TRANSFORMATION_ITEMS "}" { $$ = $3; } ; TRANSFORMATION_ITEMS: TRANSFORMATION_ITEM { $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSFORMATION, @$, $1); } | TRANSFORMATION_ITEMS TRANSFORMATION_ITEM { $$ = $1; dmnsn_array_push($$.children, &$2); } ; TRANSFORMATION_ITEM: IDENTIFIER { dmnsn_astnode *trans = dmnsn_find_symbol(symtable, $1.ptr); if (!trans) { dmnsn_diagnostic(@1, "unbound identifier '%s'", (const char *)$1.ptr); dmnsn_delete_astnode($1); YYERROR; } if (trans->type != DMNSN_AST_TRANSFORMATION) { dmnsn_diagnostic( @1, "identifier '%s' is a %s; expected a %s", (const char *)$1.ptr, dmnsn_astnode_string(trans->type), dmnsn_astnode_string(DMNSN_AST_TRANSFORMATION) ); dmnsn_delete_astnode($1); YYERROR; } dmnsn_array_get(trans->children, 0, &$$); ++*$$.refcount; dmnsn_delete_astnode($1); } | TRANSFORMATION { dmnsn_array_get($1.children, 0, &$$); ++*$$.refcount; dmnsn_delete_astnode($1); } | "inverse" { $$ = dmnsn_new_astleaf(DMNSN_AST_INVERSE, @$); } ; /* Cameras */ CAMERA: "camera" "{" CAMERA_ITEMS "}" { $$ = $3; } ; CAMERA_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_CAMERA, @$); } | CAMERA_ITEMS CAMERA_ITEM { $$ = $1; dmnsn_array_push($$.children, &$2); } ; CAMERA_ITEM: CAMERA_TYPE | CAMERA_VECTOR | CAMERA_MODIFIER ; CAMERA_TYPE: "perspective" { $$ = dmnsn_new_astleaf(DMNSN_AST_PERSPECTIVE, @$); } ; CAMERA_VECTOR: "location" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_LOCATION, @$, $2); } | "right" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_RIGHT, @$, $2); } | "up" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_UP, @$, $2); } | "sky" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_SKY, @$, $2); } | "direction" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_DIRECTION, @$, $2); } ; CAMERA_MODIFIER: "angle" FLOAT { $$ = dmnsn_new_astnode1(DMNSN_AST_ANGLE, @$, $2); } | "look_at" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_LOOK_AT, @$, $2); } | TRANSFORMATION ; /* Objects */ OBJECT: FINITE_SOLID_OBJECT | INFINITE_SOLID_OBJECT | CSG_OBJECT | LIGHT_SOURCE | "object" "{" IDENTIFIER OBJECT_MODIFIERS "}" { dmnsn_astnode *object = dmnsn_find_symbol(symtable, $3.ptr); if (!object) { dmnsn_diagnostic(@3, "unbound identifier '%s'", (const char *)$3.ptr); dmnsn_delete_astnode($3); dmnsn_delete_astnode($4); YYERROR; } if (object->type == DMNSN_AST_OBJECT) { dmnsn_delete_astnode($3); $$ = dmnsn_new_astnode(object->type, @$); dmnsn_copy_children($$, *object); dmnsn_astnode *modifiers, orig_modifiers; modifiers = dmnsn_array_at($$.children, 1); dmnsn_array_get(object->children, dmnsn_array_size(object->children) - 1, &orig_modifiers); dmnsn_delete_astnode(*modifiers); *modifiers = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, @4); dmnsn_copy_children(*modifiers, orig_modifiers); DMNSN_ARRAY_FOREACH (dmnsn_astnode *, astnode, $4.children) { ++*astnode->refcount; dmnsn_array_push(modifiers->children, astnode); } dmnsn_delete_astnode($4); } else { dmnsn_diagnostic(@3, "identifier '%s' is a %s; expected an %s", (const char *)$3.ptr, dmnsn_astnode_string(object->type), dmnsn_astnode_string(DMNSN_AST_OBJECT)); dmnsn_delete_astnode($3); dmnsn_delete_astnode($4); YYERROR; } } | "object" "{" OBJECT OBJECT_MODIFIERS "}" { $$ = $3; dmnsn_astnode modifiers; dmnsn_array_get($$.children, dmnsn_array_size($$.children) - 1, &modifiers); DMNSN_ARRAY_FOREACH (dmnsn_astnode *, astnode, $4.children) { ++*astnode->refcount; dmnsn_array_push(modifiers.children, astnode); } dmnsn_delete_astnode($4); } ; FINITE_SOLID_OBJECT: BOX | CONE | CYLINDER | SPHERE | TORUS ; BOX: "box" "{" VECTOR "," VECTOR OBJECT_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode2(DMNSN_AST_BOX, @$, $3, $5); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $6); } ; CONE: "cone" "{" VECTOR "," FLOAT "," VECTOR "," FLOAT MAYBE_OPEN OBJECT_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode5(DMNSN_AST_CONE, @$, $3, $5, $7, $9, $10); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $11); } ; CYLINDER: "cylinder" "{" VECTOR "," VECTOR "," FLOAT MAYBE_OPEN OBJECT_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode4(DMNSN_AST_CYLINDER, @$, $3, $5, $7, $8); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $9); } ; MAYBE_OPEN: /* empty */ { $$ = dmnsn_new_ast_integer(false); } | "open" { $$ = dmnsn_new_ast_integer(true); } ; SPHERE: "sphere" "{" VECTOR "," FLOAT OBJECT_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode2(DMNSN_AST_SPHERE, @$, $3, $5); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $6); } ; TORUS: "torus" "{" FLOAT "," FLOAT TORUS_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode2(DMNSN_AST_TORUS, @$, $3, $5); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $6); } ; TORUS_MODIFIERS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, @$); } | TORUS_MODIFIERS OBJECT_MODIFIER { $$ = $1; dmnsn_array_push($$.children, &$2); } | TORUS_MODIFIERS "sturm" { dmnsn_diagnostic(@2, "WARNING: Dimension does not use 'sturm';" " ignored."); dmnsn_astnode on = dmnsn_new_ast_integer(true); dmnsn_astnode sturm = dmnsn_new_astnode1(DMNSN_AST_STURM, @2, on); $$ = $1; dmnsn_array_push($$.children, &sturm); } | TORUS_MODIFIERS "sturm" INT { dmnsn_diagnostic(@2, "WARNING: Dimension does not use 'sturm';" " ignored."); dmnsn_astnode sturm = dmnsn_new_astnode1(DMNSN_AST_STURM, @2, $3); $$ = $1; dmnsn_array_push($$.children, &sturm); } ; INFINITE_SOLID_OBJECT: PLANE ; PLANE: "plane" "{" VECTOR "," FLOAT OBJECT_MODIFIERS "}" { dmnsn_astnode object = dmnsn_new_astnode2(DMNSN_AST_PLANE, @$, $3, $5); $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, object, $6); } ; CSG_OBJECT: UNION | INTERSECTION | DIFFERENCE | MERGE ; UNION: "union" "{" OBJECTS OBJECT_MODIFIERS "}" { dmnsn_astnode csg_union = $3; csg_union.type = DMNSN_AST_UNION; $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, csg_union, $4); } ; INTERSECTION: "intersection" "{" OBJECTS OBJECT_MODIFIERS "}" { dmnsn_astnode intersection = $3; intersection.type = DMNSN_AST_INTERSECTION; $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, intersection, $4); } ; DIFFERENCE: "difference" "{" OBJECTS OBJECT_MODIFIERS "}" { dmnsn_astnode difference = $3; difference.type = DMNSN_AST_DIFFERENCE; $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, difference, $4); } ; MERGE: "merge" "{" OBJECTS OBJECT_MODIFIERS "}" { dmnsn_astnode merge = $3; merge.type = DMNSN_AST_MERGE; $$ = dmnsn_new_astnode2(DMNSN_AST_OBJECT, @$, merge, $4); } ; OBJECTS: OBJECT { $$ = dmnsn_new_astnode1(DMNSN_AST_ARRAY, @$, $1); } | OBJECTS OBJECT { $$ = $1; dmnsn_array_push($$.children, &$2); } ; LIGHT_SOURCE: "light_source" "{" VECTOR "," COLOR OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5, $6); } ; /* Object modifiers */ OBJECT_MODIFIERS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_OBJECT_MODIFIERS, @$); } | OBJECT_MODIFIERS OBJECT_MODIFIER { $$ = $1; dmnsn_array_push($$.children, &$2); } ; OBJECT_MODIFIER: TRANSFORMATION | TEXTURE | PIGMENT | FINISH | INTERIOR ; /* Patterns */ BLOCK_PATTERN_TYPE: "checker" { dmnsn_astnode p = dmnsn_new_astleaf(DMNSN_AST_CHECKER, @$); $$ = dmnsn_new_astnode1(DMNSN_AST_PATTERN, @$, p); } ; CONTINUOUS_PATTERN_TYPE: "gradient" VECTOR { dmnsn_astnode p = dmnsn_new_astnode1(DMNSN_AST_GRADIENT, @$, $2); $$ = dmnsn_new_astnode1(DMNSN_AST_PATTERN, @$, p); } ; PATTERN_TYPE: BLOCK_PATTERN_TYPE | CONTINUOUS_PATTERN_TYPE ; /* Textures */ TEXTURE: "texture" "{" TEXTURE_ITEMS "}" { $$ = $3; } ; TEXTURE_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_TEXTURE, @$); } | TEXTURE_ITEMS PIGMENT { $$ = $1; dmnsn_array_push($$.children, &$2); } | TEXTURE_ITEMS FINISH { $$ = $1; dmnsn_array_push($$.children, &$2); } | TEXTURE_ITEMS TRANSFORMATION { $$ = $1; dmnsn_array_push($$.children, &$2); } ; /* Pigments */ PIGMENT: "pigment" "{" PIGMENT_BODY "}" { $$ = $3; } ; PIGMENT_BODY: PIGMENT_TYPE PIGMENT_MODIFIERS { $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT, @$, $1, $2); } | "checker" COLOR_LIST2 PIGMENT_MODIFIERS { dmnsn_astnode checker = dmnsn_new_astleaf(DMNSN_AST_CHECKER, @1); dmnsn_astnode pattern = dmnsn_new_astnode1(DMNSN_AST_PATTERN, @1, checker); dmnsn_array_push($3.children, &$2); $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT, @$, pattern, $3); } | "checker" PIGMENT_LIST2 PIGMENT_MODIFIERS { dmnsn_astnode checker = dmnsn_new_astleaf(DMNSN_AST_CHECKER, @1); dmnsn_astnode pattern = dmnsn_new_astnode1(DMNSN_AST_PATTERN, @1, checker); dmnsn_array_push($3.children, &$2); $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT, @$, pattern, $3); } ; PIGMENT_TYPE: COLOR | CONTINUOUS_PATTERN_TYPE | "image_map" "{" BITMAP_TYPE STRING "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_IMAGE_MAP, @$, $3, $4); } | "image_map" "{" STRING "}" { dmnsn_astnode type = dmnsn_new_astleaf(DMNSN_AST_PNG, @$); $$ = dmnsn_new_astnode2(DMNSN_AST_IMAGE_MAP, @$, type, $3); } ; BITMAP_TYPE: "png" { $$ = dmnsn_new_astleaf(DMNSN_AST_PNG, @$); } ; PIGMENT_MODIFIERS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_PIGMENT_MODIFIERS, @$); } | PIGMENT_MODIFIERS TRANSFORMATION { $$ = $1; dmnsn_array_push($$.children, &$2); } | PIGMENT_MODIFIERS COLOR_MAP { $$ = $1; dmnsn_array_push($$.children, &$2); } | PIGMENT_MODIFIERS PIGMENT_MAP { $$ = $1; dmnsn_array_push($$.children, &$2); } | PIGMENT_MODIFIERS "quick_color" COLOR { dmnsn_astnode quick_color = dmnsn_new_astnode1(DMNSN_AST_QUICK_COLOR, @2, $3); $$ = $1; dmnsn_array_push($$.children, &quick_color); } ; COLOR_LIST2: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_COLOR_LIST, @$); } | COLOR { $$ = dmnsn_new_astnode1(DMNSN_AST_COLOR_LIST, @$, $1); } | COLOR "," COLOR { $$ = dmnsn_new_astnode2(DMNSN_AST_COLOR_LIST, @$, $1, $3); } ; COLOR_MAP: "color_map" "{" COLOR_MAP_ENTRIES "}" { $$ = $3; } ; COLOR_MAP_ENTRIES: COLOR_MAP_ENTRY { $$ = dmnsn_new_astnode1(DMNSN_AST_COLOR_MAP, @$, $1); } | COLOR_MAP_ENTRIES COLOR_MAP_ENTRY { $$ = $1; dmnsn_array_push($$.children, &$2); } ; COLOR_MAP_ENTRY: "[" FLOAT "color" COLOR_BODY "]" { $$ = dmnsn_new_astnode2(DMNSN_AST_COLOR_MAP_ENTRY, @$, $2, $4); } ; PIGMENT_LIST2: PIGMENT { $$ = dmnsn_new_astnode1(DMNSN_AST_PIGMENT_LIST, @$, $1); } | PIGMENT PIGMENT { $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT_LIST, @$, $1, $2); } | PIGMENT "," PIGMENT { $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT_LIST, @$, $1, $3); } ; PIGMENT_MAP: "pigment_map" "{" PIGMENT_MAP_ENTRIES "}" { $$ = $3; } ; PIGMENT_MAP_ENTRIES: PIGMENT_MAP_ENTRY { $$ = dmnsn_new_astnode1(DMNSN_AST_PIGMENT_MAP, @$, $1); } | PIGMENT_MAP_ENTRIES PIGMENT_MAP_ENTRY { $$ = $1; dmnsn_array_push($$.children, &$2); } ; PIGMENT_MAP_ENTRY: "[" FLOAT PIGMENT_BODY "]" { $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT_MAP_ENTRY, @$, $2, $3); } ; /* Finishes */ FINISH: "finish" "{" FINISH_ITEMS "}" { $$ = $3; } ; FINISH_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_FINISH, @$); } | FINISH_ITEMS "ambient" COLOR { dmnsn_astnode ambient = dmnsn_new_astnode1(DMNSN_AST_AMBIENT, @2, $3); $$ = $1; dmnsn_array_push($$.children, &ambient); } | FINISH_ITEMS "diffuse" FLOAT { dmnsn_astnode diffuse = dmnsn_new_astnode1(DMNSN_AST_DIFFUSE, @2, $3); $$ = $1; dmnsn_array_push($$.children, &diffuse); } | FINISH_ITEMS "phong" FLOAT { dmnsn_astnode phong = dmnsn_new_astnode1(DMNSN_AST_PHONG, @2, $3); $$ = $1; dmnsn_array_push($$.children, &phong); } | FINISH_ITEMS "phong_size" FLOAT { dmnsn_astnode phong_size = dmnsn_new_astnode1(DMNSN_AST_PHONG_SIZE, @2, $3); $$ = $1; dmnsn_array_push($$.children, &phong_size); } | FINISH_ITEMS REFLECTION { $$ = $1; dmnsn_array_push($$.children, &$2); } ; REFLECTION: "reflection" "{" COLOR REFLECTION_ITEMS "}" { ++*$3.refcount; $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $3, $4); } | "reflection" "{" COLOR "," COLOR REFLECTION_ITEMS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_REFLECTION, @$, $3, $5, $6); } ; REFLECTION_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_REFLECTION_ITEMS, @$); } | REFLECTION_ITEMS "falloff" FLOAT { dmnsn_astnode falloff = dmnsn_new_astnode1(DMNSN_AST_FALLOFF, @2, $3); $$ = $1; dmnsn_array_push($$.children, &falloff); } ; /* Interiors */ INTERIOR: "interior" "{" INTERIOR_ITEMS "}" { $$ = $3; } ; INTERIOR_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_INTERIOR, @$); } | INTERIOR_ITEMS "ior" FLOAT { dmnsn_astnode diffuse = dmnsn_new_astnode1(DMNSN_AST_IOR, @2, $3); $$ = $1; dmnsn_array_push($$.children, &diffuse); } ; /* Floats */ FLOAT: ARITH_EXPR { $$ = dmnsn_eval_scalar($1, symtable); dmnsn_delete_astnode($1); if ($$.type == DMNSN_AST_NONE) { dmnsn_delete_astnode($$); YYERROR; } } ; INT: FLOAT { $$ = $1; if ($$.type == DMNSN_AST_FLOAT) { dmnsn_diagnostic(@$, "WARNING: float rounded to integer"); } } ; FLOAT_LITERAL: "integer" { dmnsn_astnode string = dmnsn_new_astleaf(DMNSN_AST_STRING, @$); string.ptr = $1; $$ = dmnsn_new_astnode1(DMNSN_AST_VAL, @$, string); } | "float" { dmnsn_astnode string = dmnsn_new_astleaf(DMNSN_AST_STRING, @$); string.ptr = $1; $$ = dmnsn_new_astnode1(DMNSN_AST_VAL, @$, string); } ; /* Vectors */ VECTOR: ARITH_EXPR { $$ = dmnsn_eval_vector($1, symtable); dmnsn_delete_astnode($1); if ($$.type == DMNSN_AST_NONE) { dmnsn_delete_astnode($$); YYERROR; } } ; VECTOR_LITERAL: "<" ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode2(DMNSN_AST_VECTOR, @$, $2, $4); } | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode3(DMNSN_AST_VECTOR, @$, $2, $4, $6); } | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode4(DMNSN_AST_VECTOR, @$, $2, $4, $6, $8); } | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode5(DMNSN_AST_VECTOR, @$, $2, $4, $6, $8, $10); } ; /* Generalized arithmetic expressions */ ARITH_EXPR: FLOAT_LITERAL | VECTOR_LITERAL | ARITH_EXPR "+" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_ADD, @$, $1, $3); } | ARITH_EXPR "-" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_SUB, @$, $1, $3); } | ARITH_EXPR "*" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3); } | ARITH_EXPR "/" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_DIV, @$, $1, $3); } | "+" ARITH_EXPR %prec DMNSN_T_NEGATE { $$ = $2; } | "-" ARITH_EXPR %prec DMNSN_T_NEGATE { $$ = dmnsn_new_astnode1(DMNSN_AST_NEGATE, @$, $2); } | ARITH_EXPR "." "x" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1); } | ARITH_EXPR "." "u" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1); } | ARITH_EXPR "." "red" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_X, @$, $1); } | ARITH_EXPR "." "y" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1); } | ARITH_EXPR "." "v" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1); } | ARITH_EXPR "." "green" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Y, @$, $1); } | ARITH_EXPR "." "z" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1); } | ARITH_EXPR "." "blue" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_Z, @$, $1); } | ARITH_EXPR "." "t" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1); } | ARITH_EXPR "." "filter" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_T, @$, $1); } | ARITH_EXPR "." "transmit" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_TRANSMIT, @$, $1); } | "(" ARITH_EXPR ")" %dprec 2 { $$ = $2; } | "(" CONDITIONAL "?" ARITH_EXPR ":" ARITH_EXPR ")" { $$ = dmnsn_new_astnode3(DMNSN_AST_TERNARY, @$, $2, $4, $6); } | "abs" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ABS, @$, $3); } | "acos" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ACOS, @$, $3); } | "acosh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ACOSH, @$, $3); } | "asc" "(" STRING ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ASC, @$, $3); } | "asin" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ASIN, @$, $3); } | "asinh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ASINH, @$, $3); } | "atan" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ATAN, @$, $3); } | "atan2" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_ATAN2, @$, $3, $5); } | "atanh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_ATANH, @$, $3); } | "ceil" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_CEIL, @$, $3); } | "cos" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_COS, @$, $3); } | "cosh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_COSH, @$, $3); } | "degrees" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_DEGREES, @$, $3); } | "div" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_INT_DIV, @$, $3, $5); } | "exp" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_EXP, @$, $3); } | "floor" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_FLOOR, @$, $3); } | "int" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_INT, @$, $3); } | "ln" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_LN, @$, $3); } | "log" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_LOG, @$, $3); } | "max" "(" MAX_LIST ")" { $$ = $3; } | "min" "(" MIN_LIST ")" { $$ = $3; } | "mod" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_MOD, @$, $3, $5); } | "pow" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_POW, @$, $3, $5); } | "radians" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_RADIANS, @$, $3); } | "sin" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_SIN, @$, $3); } | "sinh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_SINH, @$, $3); } | "sqrt" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_SQRT, @$, $3); } | "strcmp" "(" STRING "," STRING ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_STRCMP, @$, $3, $5); } | "strlen" "(" STRING ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_STRLEN, @$, $3); } | "tan" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_TAN, @$, $3); } | "tanh" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_TANH, @$, $3); } | "val" "(" STRING ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_VAL, @$, $3); } | "vaxis_rotate" "(" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ")" { dmnsn_astnode axis = dmnsn_new_astnode1(DMNSN_AST_VNORMALIZE, @$, $5); axis = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $7, axis); $$ = dmnsn_new_astnode2(DMNSN_AST_VAXIS_ROTATE, @$, $3, axis); } | "vcross" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_VCROSS, @$, $3, $5); } | "vdot" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_VDOT, @$, $3, $5); } | "vlength" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_VLENGTH, @$, $3); } | "vnormalize" "(" ARITH_EXPR ")" { $$ = dmnsn_new_astnode1(DMNSN_AST_VNORMALIZE, @$, $3); } | "vrotate" "(" ARITH_EXPR "," ARITH_EXPR ")" { $$ = dmnsn_new_astnode2(DMNSN_AST_VROTATE, @$, $3, $5); } | "image_height" { $$ = dmnsn_new_astleaf(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup("image_height"); } | "image_width" { $$ = dmnsn_new_astleaf(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup("image_width"); } | "pi" { $$ = dmnsn_new_astleaf(DMNSN_AST_PI, @$); } | "true" { $$ = dmnsn_new_astleaf(DMNSN_AST_TRUE, @$); } | "on" { $$ = dmnsn_new_astleaf(DMNSN_AST_TRUE, @$); } | "yes" { $$ = dmnsn_new_astleaf(DMNSN_AST_TRUE, @$); } | "false" { $$ = dmnsn_new_astleaf(DMNSN_AST_FALSE, @$); } | "off" { $$ = dmnsn_new_astleaf(DMNSN_AST_FALSE, @$); } | "no" { $$ = dmnsn_new_astleaf(DMNSN_AST_FALSE, @$); } | "x" { $$ = dmnsn_new_astleaf(DMNSN_AST_X, @$); } | "u" { $$ = dmnsn_new_astleaf(DMNSN_AST_X, @$); } | "y" { $$ = dmnsn_new_astleaf(DMNSN_AST_Y, @$); } | "v" { $$ = dmnsn_new_astleaf(DMNSN_AST_Y, @$); } | "z" { $$ = dmnsn_new_astleaf(DMNSN_AST_Z, @$); } | "t" { $$ = dmnsn_new_astleaf(DMNSN_AST_T, @$); } | IDENTIFIER ; MAX_LIST: ARITH_EXPR "," ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_MAX, @$, $1, $3); } | MAX_LIST "," ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_MAX, @$, $1, $3); } ; MIN_LIST: ARITH_EXPR "," ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_MIN, @$, $1, $3); } | MIN_LIST "," ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_MIN, @$, $1, $3); } ; CONDITIONAL: ARITH_EXPR { /* Force the expression to be evaluated logically */ dmnsn_astnode zero = dmnsn_new_ast_integer(0); $$ = dmnsn_new_astnode2(DMNSN_AST_OR, @$, zero, $1); } | ARITH_EXPR "=" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_EQUAL, @$, $1, $3); } | ARITH_EXPR "!=" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_NOT_EQUAL, @$, $1, $3); } | ARITH_EXPR "<" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_LESS, @$, $1, $3); } | ARITH_EXPR "<=" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_LESS_EQUAL, @$, $1, $3); } | ARITH_EXPR ">" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_GREATER, @$, $1, $3); } | ARITH_EXPR ">=" ARITH_EXPR { $$ = dmnsn_new_astnode2(DMNSN_AST_GREATER_EQUAL, @$, $1, $3); } | CONDITIONAL "&" CONDITIONAL { $$ = dmnsn_new_astnode2(DMNSN_AST_AND, @$, $1, $3); } | CONDITIONAL "|" CONDITIONAL { $$ = dmnsn_new_astnode2(DMNSN_AST_OR, @$, $1, $3); } | "(" CONDITIONAL ")" %dprec 1 { $$ = $2; } | "!" CONDITIONAL { $$ = dmnsn_new_astnode1(DMNSN_AST_NOT, @$, $2); } ; /* Colors */ COLOR: COLOR_BODY { $$ = $1; } | "color" COLOR_BODY { $$ = $2; } ; COLOR_BODY: COLOR_VECTOR %dprec 1 | COLOR_KEYWORD_GROUP %dprec 2 ; COLOR_VECTOR: "rgb" VECTOR { dmnsn_astnode f, t; dmnsn_array_get($2.children, 3, &f); dmnsn_array_get($2.children, 4, &t); dmnsn_delete_astnode(f); dmnsn_delete_astnode(t); dmnsn_array_resize($2.children, 3); $$ = dmnsn_eval_vector($2, symtable); dmnsn_delete_astnode($2); } | "rgbf" VECTOR { dmnsn_astnode t; dmnsn_array_get($2.children, 4, &t); dmnsn_delete_astnode(t); dmnsn_array_resize($2.children, 4); $$ = dmnsn_eval_vector($2, symtable); dmnsn_delete_astnode($2); } | "rgbt" VECTOR { /* Chop off the fifth component */ dmnsn_astnode t; dmnsn_array_get($2.children, 4, &t); dmnsn_delete_astnode(t); dmnsn_array_resize($2.children, 4); $$ = dmnsn_eval_vector($2, symtable); dmnsn_delete_astnode($2); /* Swap the transmit and filter components */ dmnsn_astnode temp; dmnsn_array_get($$.children, 4, &temp); dmnsn_array_set($$.children, 4, dmnsn_array_at($$.children, 3)); dmnsn_array_set($$.children, 3, &temp); } | "rgbft" VECTOR { $$ = $2; } | VECTOR ; COLOR_KEYWORD_GROUP: COLOR_KEYWORD_GROUP_INIT COLOR_KEYWORD_ITEM | COLOR_KEYWORD_GROUP COLOR_KEYWORD_ITEM ; COLOR_KEYWORD_GROUP_INIT: /* empty */ { dmnsn_astnode zero = dmnsn_new_ast_integer(0); $$ = dmnsn_eval_vector(zero, symtable); dmnsn_delete_astnode(zero); } ; COLOR_KEYWORD_ITEM: IDENTIFIER { dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, $1.ptr); if (!symbol) { dmnsn_diagnostic(@1, "unbound identifier '%s'", (const char *)$1.ptr); dmnsn_delete_astnode($1); YYERROR; } else { dmnsn_astnode eval = dmnsn_eval_vector(*symbol, symtable); if (eval.type == DMNSN_AST_NONE) { dmnsn_delete_astnode($1); YYERROR; } dmnsn_copy_children($0, eval); dmnsn_delete_astnode(eval); } dmnsn_delete_astnode($1); } | "red" FLOAT { dmnsn_astnode old; dmnsn_array_get($0.children, 0, &old); dmnsn_array_set($0.children, 0, &$2); dmnsn_delete_astnode(old); } | "green" FLOAT { dmnsn_astnode old; dmnsn_array_get($0.children, 1, &old); dmnsn_array_set($0.children, 1, &$2); dmnsn_delete_astnode(old); } | "blue" FLOAT { dmnsn_astnode old; dmnsn_array_get($0.children, 2, &old); dmnsn_array_set($0.children, 2, &$2); dmnsn_delete_astnode(old); } | "filter" FLOAT { dmnsn_astnode old; dmnsn_array_get($0.children, 3, &old); dmnsn_array_set($0.children, 3, &$2); dmnsn_delete_astnode(old); } | "transmit" FLOAT { dmnsn_astnode old; dmnsn_array_get($0.children, 4, &old); dmnsn_array_set($0.children, 4, &$2); dmnsn_delete_astnode(old); } ;