#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" { const char *id = $1; dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, id); while (symbol && symbol->type == DMNSN_AST_IDENTIFIER) { id = symbol->ptr; symbol = dmnsn_find_symbol(symtable, id); } $$ = dmnsn_new_astnode(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup(id); free($1); } ; STRING: "string" { $$ = dmnsn_new_astnode(DMNSN_AST_STRING, @$); $$.ptr = $1; } ; /* Transformations */ TRANSFORMATION: "rotate" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_ROTATION, @$, $2); } | "scale" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_SCALE, @$, $2); } | "translate" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_TRANSLATION, @$, $2); } ; /* 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_astnode(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; } switch (object->type) { case DMNSN_AST_BOX: case DMNSN_AST_DIFFERENCE: case DMNSN_AST_INTERSECTION: case DMNSN_AST_LIGHT_SOURCE: case DMNSN_AST_MERGE: case DMNSN_AST_PLANE: case DMNSN_AST_SPHERE: case DMNSN_AST_UNION: { dmnsn_delete_astnode($3); $$ = dmnsn_new_astnode(object->type, @$); dmnsn_copy_children($$, *object); dmnsn_astnode *modifiers, orig_modifiers; modifiers = dmnsn_array_at($$.children, dmnsn_array_size($$.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); unsigned int i; for (i = 0; i < dmnsn_array_size($4.children); ++i) { dmnsn_astnode astnode; dmnsn_array_get($4.children, i, &astnode); ++*astnode.refcount; dmnsn_array_push(modifiers->children, &astnode); } dmnsn_delete_astnode($4); break; } default: dmnsn_diagnostic(@3, "identifier '%s' is a %s; expected an object type", (const char *)$3.ptr, dmnsn_astnode_string(object->type)); dmnsn_delete_astnode($3); dmnsn_delete_astnode($4); YYERROR; break; } } | "object" "{" OBJECT OBJECT_MODIFIERS "}" { $$ = $3; dmnsn_astnode modifiers; dmnsn_array_get($$.children, dmnsn_array_size($$.children) - 1, &modifiers); unsigned int i; for (i = 0; i < dmnsn_array_size($4.children); ++i) { dmnsn_astnode astnode; dmnsn_array_get($4.children, i, &astnode); ++*astnode.refcount; dmnsn_array_push(modifiers.children, &astnode); } dmnsn_delete_astnode($4); } ; FINITE_SOLID_OBJECT: BOX | SPHERE ; BOX: "box" "{" VECTOR "," VECTOR OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_BOX, @$, $3, $5, $6); } ; SPHERE: "sphere" "{" VECTOR "," FLOAT OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_SPHERE, @$, $3, $5, $6); } ; INFINITE_SOLID_OBJECT: PLANE ; PLANE: "plane" "{" VECTOR "," FLOAT OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_PLANE, @$, $3, $5, $6); } ; CSG_OBJECT: UNION | INTERSECTION | DIFFERENCE | MERGE ; UNION: "union" "{" OBJECTS OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_UNION, @$, $3, $4); } ; INTERSECTION: "intersection" "{" OBJECTS OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_INTERSECTION, @$, $3, $4); } ; DIFFERENCE: "difference" "{" OBJECTS OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_DIFFERENCE, @$, $3, $4); } ; MERGE: "merge" "{" OBJECTS OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_MERGE, @$, $3, $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 ; /* 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_TYPE PIGMENT_MODIFIERS "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_PIGMENT, @$, $3, $4); } ; PIGMENT_TYPE: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_NONE, @$); } | COLOR | "image_map" "{" BITMAP_TYPE STRING "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_IMAGE_MAP, @$, $3, $4); } | "image_map" "{" STRING "}" { dmnsn_astnode type = dmnsn_new_astnode(DMNSN_AST_PNG, @$); $$ = dmnsn_new_astnode2(DMNSN_AST_IMAGE_MAP, @$, type, $3); } ; BITMAP_TYPE: "png" { $$ = dmnsn_new_astnode(DMNSN_AST_PNG, @$); } ; PIGMENT_MODIFIERS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_PIGMENT_MODIFIERS, @$); } | PIGMENT_MODIFIERS TRANSFORMATION { $$ = $1; dmnsn_array_push($$.children, &$2); } ; /* 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_new_astnode(DMNSN_AST_INTEGER, @$); $$.ptr = dmnsn_malloc(sizeof(long)); *(long *)$$.ptr = strtol($1, NULL, 0); free($1); } | "float" { $$ = dmnsn_new_astnode(DMNSN_AST_FLOAT, @$); $$.ptr = dmnsn_malloc(sizeof(double)); *(double *)$$.ptr = strtod($1, NULL); free($1); } ; /* 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_astnode(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup("image_height"); } | "image_width" { $$ = dmnsn_new_astnode(DMNSN_AST_IDENTIFIER, @$); $$.ptr = dmnsn_strdup("image_width"); } | "pi" { $$ = dmnsn_new_astnode(DMNSN_AST_PI, @$); } | "true" { $$ = dmnsn_new_astnode(DMNSN_AST_TRUE, @$); } | "on" { $$ = dmnsn_new_astnode(DMNSN_AST_TRUE, @$); } | "yes" { $$ = dmnsn_new_astnode(DMNSN_AST_TRUE, @$); } | "false" { $$ = dmnsn_new_astnode(DMNSN_AST_FALSE, @$); } | "off" { $$ = dmnsn_new_astnode(DMNSN_AST_FALSE, @$); } | "no" { $$ = dmnsn_new_astnode(DMNSN_AST_FALSE, @$); } | "x" { $$ = dmnsn_new_astnode(DMNSN_AST_X, @$); } | "u" { $$ = dmnsn_new_astnode(DMNSN_AST_X, @$); } | "y" { $$ = dmnsn_new_astnode(DMNSN_AST_Y, @$); } | "v" { $$ = dmnsn_new_astnode(DMNSN_AST_Y, @$); } | "z" { $$ = dmnsn_new_astnode(DMNSN_AST_Z, @$); } | "t" { $$ = dmnsn_new_astnode(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); } ;