/************************************************************************* * Copyright (C) 2009 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 . * *************************************************************************/ %{ #include "parse.h" #include "tokenize.h" #include "utility.h" #include #include #define YYSTYPE dmnsn_parse_item #define YYLTYPE dmnsn_parse_location int dmnsn_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, const char *filename, void *yyscanner); void dmnsn_yylex_init(void **scannerp); void dmnsn_yyset_in(FILE *file, void *scanner); void dmnsn_yylex_destroy(void *scanner); #define YYLLOC_DEFAULT(Current, Rhs, N) \ do { \ if (N) { \ (Current).first_filename = YYRHSLOC(Rhs, 1).first_filename; \ (Current).first_line = YYRHSLOC(Rhs, 1).first_line; \ (Current).first_column = YYRHSLOC(Rhs, 1).first_column; \ (Current).last_filename = YYRHSLOC(Rhs, N).last_filename; \ (Current).last_line = YYRHSLOC(Rhs, N).last_line; \ (Current).last_column = YYRHSLOC(Rhs, N).last_column; \ } else { \ (Current).first_filename = (Current).last_filename = \ YYRHSLOC(Rhs, 0).last_filename; \ (Current).first_line = (Current).last_line = \ YYRHSLOC(Rhs, 0).last_line; \ (Current).first_column = (Current).last_column = \ YYRHSLOC(Rhs, 0).last_column; \ } \ } while (0) /* Create a new astnode, populating filename, line, and col */ static dmnsn_astnode dmnsn_new_astnode(dmnsn_astnode_type type, YYLTYPE lloc) { dmnsn_astnode astnode = { .type = type, .children = dmnsn_new_array(sizeof(dmnsn_astnode)), .ptr = NULL, .refcount = malloc(sizeof(unsigned int)), .filename = lloc.first_filename, .line = lloc.first_line, .col = lloc.first_column }; if (!astnode.refcount) { dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate reference count."); } *astnode.refcount = 1; return astnode; } /* Semi-shallow copy */ static dmnsn_astnode dmnsn_copy_astnode(dmnsn_astnode astnode) { dmnsn_astnode copy = { .type = astnode.type, .children = dmnsn_new_array(sizeof(dmnsn_astnode)), .ptr = NULL, .refcount = malloc(sizeof(unsigned int)), .filename = astnode.filename, .line = astnode.line, .col = astnode.col }; if (!copy.refcount) { dmnsn_error(DMNSN_SEVERITY_HIGH, "Couldn't allocate reference count."); } *copy.refcount = 1; unsigned int i; for (i = 0; i < dmnsn_array_size(astnode.children); ++i) { dmnsn_astnode n; dmnsn_array_get(astnode.children, i, &n); ++*n.refcount; dmnsn_array_push(copy.children, &n); } switch (astnode.type) { case DMNSN_AST_INTEGER: copy.ptr = malloc(sizeof(long)); memcpy(copy.ptr, astnode.ptr, sizeof(long)); break; case DMNSN_AST_FLOAT: copy.ptr = malloc(sizeof(double)); memcpy(copy.ptr, astnode.ptr, sizeof(double)); break; case DMNSN_AST_STRING: copy.ptr = strdup(astnode.ptr); break; default: break; } return copy; } static dmnsn_astnode dmnsn_new_astnode1(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1) { dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc); dmnsn_array_push(astnode.children, &n1); return astnode; } static dmnsn_astnode dmnsn_new_astnode2(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1, dmnsn_astnode n2) { dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc); dmnsn_array_push(astnode.children, &n1); dmnsn_array_push(astnode.children, &n2); return astnode; } static dmnsn_astnode dmnsn_new_astnode3(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3) { dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc); dmnsn_array_push(astnode.children, &n1); dmnsn_array_push(astnode.children, &n2); dmnsn_array_push(astnode.children, &n3); return astnode; } static dmnsn_astnode dmnsn_new_astnode4(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3, dmnsn_astnode n4) { dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc); dmnsn_array_push(astnode.children, &n1); dmnsn_array_push(astnode.children, &n2); dmnsn_array_push(astnode.children, &n3); dmnsn_array_push(astnode.children, &n4); return astnode; } static dmnsn_astnode dmnsn_new_astnode5(dmnsn_astnode_type type, YYLTYPE lloc, dmnsn_astnode n1, dmnsn_astnode n2, dmnsn_astnode n3, dmnsn_astnode n4, dmnsn_astnode n5) { dmnsn_astnode astnode = dmnsn_new_astnode(type, lloc); dmnsn_array_push(astnode.children, &n1); dmnsn_array_push(astnode.children, &n2); dmnsn_array_push(astnode.children, &n3); dmnsn_array_push(astnode.children, &n4); dmnsn_array_push(astnode.children, &n5); return astnode; } void yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, dmnsn_astree *astree, dmnsn_symbol_table *symtable, const char *str) { dmnsn_diagnostic(locp->first_filename, locp->first_line, locp->first_column, "%s", str); } %} %define api.pure %locations %error-verbose %token-table %name-prefix "dmnsn_yy" %expect 18 %parse-param {const char *filename} %parse-param {void *yyscanner} %parse-param {dmnsn_astree *astree} %parse-param {dmnsn_symbol_table *symtable} %lex-param {const char *filename} %lex-param {void *yyscanner} %token END 0 "end-of-file" /* Punctuation */ %token DMNSN_T_LBRACE "{" %token DMNSN_T_RBRACE "}" %token DMNSN_T_LPAREN "(" %token DMNSN_T_RPAREN ")" %token DMNSN_T_LBRACKET "[" %token DMNSN_T_RBRACKET "]" %token DMNSN_T_PLUS "+" %token DMNSN_T_MINUS "-" %token DMNSN_T_STAR "*" %token DMNSN_T_SLASH "/" %token DMNSN_T_COMMA "," %token DMNSN_T_SEMICOLON ";" %token DMNSN_T_QUESTION "?" %token DMNSN_T_COLON ":" %token DMNSN_T_AND "&" %token DMNSN_T_DOT "." %token DMNSN_T_PIPE "|" %token DMNSN_T_LESS "<" %token DMNSN_T_GREATER ">" %token DMNSN_T_BANG "!" %token DMNSN_T_EQUALS "=" %token DMNSN_T_LESS_EQUAL "<=" %token DMNSN_T_GREATER_EQUAL ">=" %token DMNSN_T_NOT_EQUAL "!=" /* Operators */ %left "+" "-" %left "*" "/" %left "." %left DMNSN_T_NEGATE /* Numeric values */ %token DMNSN_T_INTEGER "integer" %token DMNSN_T_FLOAT "float" /* Keywords */ %token DMNSN_T_AA_LEVEL %token DMNSN_T_AA_THRESHOLD %token DMNSN_T_ABS %token DMNSN_T_ABSORPTION %token DMNSN_T_ACCURACY %token DMNSN_T_ACOS %token DMNSN_T_ACOSH %token DMNSN_T_ADAPTIVE %token DMNSN_T_ADC_BAILOUT %token DMNSN_T_AGATE %token DMNSN_T_AGATE_TURB %token DMNSN_T_ALL %token DMNSN_T_ALL_INTERSECTIONS %token DMNSN_T_ALPHA %token DMNSN_T_ALTITUDE %token DMNSN_T_ALWAYS_SAMPLE %token DMNSN_T_AMBIENT %token DMNSN_T_AMBIENT_LIGHT %token DMNSN_T_ANGLE "angle" %token DMNSN_T_APERTURE %token DMNSN_T_APPEND %token DMNSN_T_ARC_ANGLE %token DMNSN_T_AREA_LIGHT %token DMNSN_T_ARRAY %token DMNSN_T_ASC %token DMNSN_T_ASCII %token DMNSN_T_ASIN %token DMNSN_T_ASINH %token DMNSN_T_ASSUMED_GAMMA %token DMNSN_T_ATAN %token DMNSN_T_ATAN2 %token DMNSN_T_ATANH %token DMNSN_T_AUTOSTOP %token DMNSN_T_AVERAGE %token DMNSN_T_B_SPLINE %token DMNSN_T_BACKGROUND "background" %token DMNSN_T_BEZIER_SPLINE %token DMNSN_T_BICUBIC_PATCH %token DMNSN_T_BLACK_HOLE %token DMNSN_T_BLOB %token DMNSN_T_BLUE "blue" %token DMNSN_T_BLUR_SAMPLES %token DMNSN_T_BOUNDED_BY %token DMNSN_T_BOX "box" %token DMNSN_T_BOXED %token DMNSN_T_BOZO %token DMNSN_T_BRICK %token DMNSN_T_BRICK_SIZE %token DMNSN_T_BRIGHTNESS %token DMNSN_T_BRILLIANCE %token DMNSN_T_BUMP_MAP %token DMNSN_T_BUMP_SIZE %token DMNSN_T_BUMPS %token DMNSN_T_CAMERA "camera" %token DMNSN_T_CAUSTICS %token DMNSN_T_CEIL %token DMNSN_T_CELLS %token DMNSN_T_CHARSET %token DMNSN_T_CHECKER %token DMNSN_T_CHR %token DMNSN_T_CIRCULAR %token DMNSN_T_CLIPPED_BY %token DMNSN_T_CLOCK %token DMNSN_T_CLOCK_DELTA %token DMNSN_T_CLOCK_ON %token DMNSN_T_COLLECT %token DMNSN_T_COLOR "color" %token DMNSN_T_COLOR_MAP %token DMNSN_T_COMPONENT %token DMNSN_T_COMPOSITE %token DMNSN_T_CONCAT %token DMNSN_T_CONE %token DMNSN_T_CONFIDENCE %token DMNSN_T_CONIC_SWEEP %token DMNSN_T_CONSERVE_ENERGY %token DMNSN_T_CONTAINED_BY %token DMNSN_T_CONTROL0 %token DMNSN_T_CONTROL1 %token DMNSN_T_COORDS %token DMNSN_T_COS %token DMNSN_T_COSH %token DMNSN_T_COUNT %token DMNSN_T_CRACKLE %token DMNSN_T_CRAND %token DMNSN_T_CUBE %token DMNSN_T_CUBIC %token DMNSN_T_CUBIC_SPLINE %token DMNSN_T_CUBIC_WAVE %token DMNSN_T_CUTAWAY_TEXTURES %token DMNSN_T_CYLINDER %token DMNSN_T_CYLINDRICAL %token DMNSN_T_DEFINED %token DMNSN_T_DEGREES %token DMNSN_T_DENSITY %token DMNSN_T_DENSITY_FILE %token DMNSN_T_DENSITY_MAP %token DMNSN_T_DENTS %token DMNSN_T_DF3 %token DMNSN_T_DIFFERENCE %token DMNSN_T_DIFFUSE %token DMNSN_T_DIMENSION_SIZE %token DMNSN_T_DIMENSIONS %token DMNSN_T_DIRECTION "direction" %token DMNSN_T_DISC %token DMNSN_T_DISPERSION %token DMNSN_T_DISPERSION_SAMPLES %token DMNSN_T_DIST_EXP %token DMNSN_T_DISTANCE %token DMNSN_T_DIV %token DMNSN_T_DOUBLE_ILLUMINATE %token DMNSN_T_ECCENTRICITY %token DMNSN_T_EMISSION %token DMNSN_T_ERROR_BOUND %token DMNSN_T_EVALUATE %token DMNSN_T_EXP %token DMNSN_T_EXPAND_THRESHOLDS %token DMNSN_T_EXPONENT %token DMNSN_T_EXTERIOR %token DMNSN_T_EXTINCTION %token DMNSN_T_FACE_INDICES %token DMNSN_T_FACETS %token DMNSN_T_FADE_COLOR %token DMNSN_T_FADE_DISTANCE %token DMNSN_T_FADE_POWER %token DMNSN_T_FALLOFF %token DMNSN_T_FALLOFF_ANGLE %token DMNSN_T_FALSE %token DMNSN_T_FILE_EXISTS %token DMNSN_T_FILTER "filter" %token DMNSN_T_FINAL_CLOCK %token DMNSN_T_FINAL_FRAME %token DMNSN_T_FINISH %token DMNSN_T_FISHEYE %token DMNSN_T_FLATNESS %token DMNSN_T_FLIP %token DMNSN_T_FLOOR %token DMNSN_T_FOCAL_POINT %token DMNSN_T_FOG %token DMNSN_T_FOG_ALT %token DMNSN_T_FOG_OFFSET %token DMNSN_T_FOG_TYPE %token DMNSN_T_FORM %token DMNSN_T_FRAME_NUMBER %token DMNSN_T_FREQUENCY %token DMNSN_T_FRESNEL %token DMNSN_T_FUNCTION %token DMNSN_T_GATHER %token DMNSN_T_GIF %token DMNSN_T_GLOBAL_LIGHTS %token DMNSN_T_GLOBAL_SETTINGS %token DMNSN_T_GRADIENT %token DMNSN_T_GRANITE %token DMNSN_T_GRAY "gray" %token DMNSN_T_GRAY_THRESHOLD %token DMNSN_T_GREEN "green" %token DMNSN_T_HEIGHT_FIELD %token DMNSN_T_HEXAGON %token DMNSN_T_HF_GRAY_16 %token DMNSN_T_HIERARCHY %token DMNSN_T_HYPERCOMPLEX %token DMNSN_T_HOLLOW %token DMNSN_T_IFF %token DMNSN_T_IMAGE_HEIGHT %token DMNSN_T_IMAGE_MAP %token DMNSN_T_IMAGE_PATTERN %token DMNSN_T_IMAGE_WIDTH %token DMNSN_T_INITIAL_CLOCK %token DMNSN_T_INITIAL_FRAME %token DMNSN_T_INSIDE %token DMNSN_T_INSIDE_VECTOR %token DMNSN_T_INT %token DMNSN_T_INTERIOR %token DMNSN_T_INTERIOR_TEXTURE %token DMNSN_T_INTERNAL %token DMNSN_T_INTERPOLATE %token DMNSN_T_INTERSECTION %token DMNSN_T_INTERVALS %token DMNSN_T_INVERSE %token DMNSN_T_IOR %token DMNSN_T_IRID %token DMNSN_T_IRID_WAVELENGTH %token DMNSN_T_ISOSURFACE %token DMNSN_T_JITTER %token DMNSN_T_JPEG %token DMNSN_T_JULIA %token DMNSN_T_JULIA_FRACTAL %token DMNSN_T_LAMBDA %token DMNSN_T_LATHE %token DMNSN_T_LEOPARD %token DMNSN_T_LIGHT_GROUP %token DMNSN_T_LIGHT_SOURCE "light_source" %token DMNSN_T_LINEAR_SPLINE %token DMNSN_T_LINEAR_SWEEP %token DMNSN_T_LN %token DMNSN_T_LOAD_FILE %token DMNSN_T_LOCATION "location" %token DMNSN_T_LOG %token DMNSN_T_LOOK_AT "look_at" %token DMNSN_T_LOOKS_LIKE %token DMNSN_T_LOW_ERROR_FACTOR %token DMNSN_T_MAGNET %token DMNSN_T_MAJOR_RADIUS %token DMNSN_T_MANDEL %token DMNSN_T_MAP_TYPE %token DMNSN_T_MARBLE %token DMNSN_T_MATERIAL %token DMNSN_T_MATERIAL_MAP %token DMNSN_T_MATRIX %token DMNSN_T_MAX %token DMNSN_T_MAX_EXTENT %token DMNSN_T_MAX_GRADIENT %token DMNSN_T_MAX_INTERSECTIONS %token DMNSN_T_MAX_ITERATION %token DMNSN_T_MAX_SAMPLE %token DMNSN_T_MAX_TRACE %token DMNSN_T_MAX_TRACE_LEVEL %token DMNSN_T_MEDIA %token DMNSN_T_MEDIA_ATTENUATION %token DMNSN_T_MEDIA_INTERACTION %token DMNSN_T_MERGE %token DMNSN_T_MESH %token DMNSN_T_MESH2 %token DMNSN_T_METALLIC %token DMNSN_T_METHOD %token DMNSN_T_METRIC %token DMNSN_T_MIN %token DMNSN_T_MIN_EXTENT %token DMNSN_T_MINIMUM_REUSE %token DMNSN_T_MOD %token DMNSN_T_MORTAR %token DMNSN_T_NATURAL_SPLINE %token DMNSN_T_NEAREST_COUNT %token DMNSN_T_NO %token DMNSN_T_NO_BUMP_SCALE %token DMNSN_T_NO_IMAGE %token DMNSN_T_NO_REFLECTION %token DMNSN_T_NO_SHADOW %token DMNSN_T_NOISE_GENERATOR %token DMNSN_T_NORMAL %token DMNSN_T_NORMAL_INDICES %token DMNSN_T_NORMAL_MAP %token DMNSN_T_NORMAL_VECTORS %token DMNSN_T_NUMBER_OF_WAVES %token DMNSN_T_OBJECT %token DMNSN_T_OCTAVES %token DMNSN_T_OFF %token DMNSN_T_OFFSET %token DMNSN_T_OMEGA %token DMNSN_T_OMNIMAX %token DMNSN_T_ON %token DMNSN_T_ONCE %token DMNSN_T_ONION %token DMNSN_T_OPEN %token DMNSN_T_ORIENT %token DMNSN_T_ORIENTATION %token DMNSN_T_ORTHOGRAPHIC %token DMNSN_T_PANORAMIC %token DMNSN_T_PARALLEL %token DMNSN_T_PARAMETRIC %token DMNSN_T_PASS_THROUGH %token DMNSN_T_PATTERN %token DMNSN_T_PERSPECTIVE "perspective" %token DMNSN_T_PGM %token DMNSN_T_PHASE %token DMNSN_T_PHONG %token DMNSN_T_PHONG_SIZE %token DMNSN_T_PHOTONS %token DMNSN_T_PI %token DMNSN_T_PIGMENT "pigment" %token DMNSN_T_PIGMENT_MAP %token DMNSN_T_PIGMENT_PATTERN %token DMNSN_T_PLANAR %token DMNSN_T_PLANE %token DMNSN_T_PNG %token DMNSN_T_POINT_AT %token DMNSN_T_POLY %token DMNSN_T_POLY_WAVE %token DMNSN_T_POLYGON %token DMNSN_T_POT %token DMNSN_T_POW %token DMNSN_T_PPM %token DMNSN_T_PRECISION %token DMNSN_T_PRECOMPUTE %token DMNSN_T_PRETRACE_END %token DMNSN_T_PRETRACE_START %token DMNSN_T_PRISM %token DMNSN_T_PROD %token DMNSN_T_PROJECTED_THROUGH %token DMNSN_T_PWR %token DMNSN_T_QUADRATIC_SPLINE %token DMNSN_T_QUADRIC %token DMNSN_T_QUARTIC %token DMNSN_T_QUATERNION %token DMNSN_T_QUICK_COLOR %token DMNSN_T_QUILTED %token DMNSN_T_RADIAL %token DMNSN_T_RADIANS %token DMNSN_T_RADIOSITY %token DMNSN_T_RADIUS %token DMNSN_T_RAINBOW %token DMNSN_T_RAMP_WAVE %token DMNSN_T_RAND %token DMNSN_T_RATIO %token DMNSN_T_RECIPROCAL %token DMNSN_T_RECURSION_LIMIT %token DMNSN_T_RED "red" %token DMNSN_T_REFLECTION %token DMNSN_T_REFLECTION_EXPONENT %token DMNSN_T_REFRACTION %token DMNSN_T_REPEAT %token DMNSN_T_RGB "rgb" %token DMNSN_T_RGBF "rgbf" %token DMNSN_T_RGBFT "rgbft" %token DMNSN_T_RGBT "rgbt" %token DMNSN_T_RIGHT "right" %token DMNSN_T_RIPPLES %token DMNSN_T_ROTATE "rotate" %token DMNSN_T_ROUGHNESS %token DMNSN_T_SAMPLES %token DMNSN_T_SAVE_FILE %token DMNSN_T_SCALE "scale" %token DMNSN_T_SCALLOP_WAVE %token DMNSN_T_SCATTERING %token DMNSN_T_SEED %token DMNSN_T_SELECT %token DMNSN_T_SHADOWLESS %token DMNSN_T_SIN %token DMNSN_T_SINE_WAVE %token DMNSN_T_SINH %token DMNSN_T_SIZE %token DMNSN_T_SKY "sky" %token DMNSN_T_SKY_SPHERE %token DMNSN_T_SLICE %token DMNSN_T_SLOPE %token DMNSN_T_SLOPE_MAP %token DMNSN_T_SMOOTH %token DMNSN_T_SMOOTH_TRIANGLE %token DMNSN_T_SOLID %token DMNSN_T_SOR %token DMNSN_T_SPACING %token DMNSN_T_SPECULAR %token DMNSN_T_SPHERE "sphere" %token DMNSN_T_SPHERE_SWEEP %token DMNSN_T_SPHERICAL %token DMNSN_T_SPIRAL1 %token DMNSN_T_SPIRAL2 %token DMNSN_T_SPLINE %token DMNSN_T_SPLIT_UNION %token DMNSN_T_SPOTLIGHT %token DMNSN_T_SPOTTED %token DMNSN_T_SQR %token DMNSN_T_SQRT %token DMNSN_T_STR %token DMNSN_T_STRCMP %token DMNSN_T_STRENGTH %token DMNSN_T_STRLEN %token DMNSN_T_STRLWR %token DMNSN_T_STRUPR %token DMNSN_T_STURM %token DMNSN_T_SUBSTR %token DMNSN_T_SUM %token DMNSN_T_SUPERELLIPSOID %token DMNSN_T_SYS %token DMNSN_T_T "t" %token DMNSN_T_TAN %token DMNSN_T_TANH %token DMNSN_T_TARGET %token DMNSN_T_TEXT %token DMNSN_T_TEXTURE %token DMNSN_T_TEXTURE_LIST %token DMNSN_T_TEXTURE_MAP %token DMNSN_T_TGA %token DMNSN_T_THICKNESS %token DMNSN_T_THRESHOLD %token DMNSN_T_TIFF %token DMNSN_T_TIGHTNESS %token DMNSN_T_TILE2 %token DMNSN_T_TILES %token DMNSN_T_TOLERANCE %token DMNSN_T_TOROIDAL %token DMNSN_T_TORUS %token DMNSN_T_TRACE %token DMNSN_T_TRANSFORM %token DMNSN_T_TRANSLATE "translate" %token DMNSN_T_TRANSMIT "transmit" %token DMNSN_T_TRIANGLE %token DMNSN_T_TRIANGLE_WAVE %token DMNSN_T_TRUE %token DMNSN_T_TTF %token DMNSN_T_TURB_DEPTH %token DMNSN_T_TURBULENCE %token DMNSN_T_TYPE %token DMNSN_T_U "u" %token DMNSN_T_U_STEPS %token DMNSN_T_ULTRA_WIDE_ANGLE %token DMNSN_T_UNION %token DMNSN_T_UP "up" %token DMNSN_T_USE_ALPHA %token DMNSN_T_USE_COLOR %token DMNSN_T_USE_INDEX %token DMNSN_T_UTF8 %token DMNSN_T_UV_INDICES %token DMNSN_T_UV_MAPPING %token DMNSN_T_UV_VECTORS %token DMNSN_T_V "v" %token DMNSN_T_V_STEPS %token DMNSN_T_VAL %token DMNSN_T_VARIANCE %token DMNSN_T_VAXIS_ROTATE %token DMNSN_T_VCROSS %token DMNSN_T_VDOT %token DMNSN_T_VERTEX_VECTORS %token DMNSN_T_VLENGTH %token DMNSN_T_VNORMALIZE %token DMNSN_T_VROTATE %token DMNSN_T_VSTR %token DMNSN_T_VTURBULENCE %token DMNSN_T_WARP %token DMNSN_T_WATER_LEVEL %token DMNSN_T_WAVES %token DMNSN_T_WIDTH %token DMNSN_T_WOOD %token DMNSN_T_WRINKLES %token DMNSN_T_X "x" %token DMNSN_T_Y "y" %token DMNSN_T_YES %token DMNSN_T_Z "z" /* Directives (#declare etc.) */ %token DMNSN_T_BREAK %token DMNSN_T_CASE %token DMNSN_T_DEBUG %token DMNSN_T_DECLARE "#declare" %token DMNSN_T_DEFAULT %token DMNSN_T_ELSE %token DMNSN_T_END %token DMNSN_T_ERROR %token DMNSN_T_FCLOSE %token DMNSN_T_FOPEN %token DMNSN_T_IF %token DMNSN_T_IFDEF %token DMNSN_T_IFNDEF %token DMNSN_T_INCLUDE "#include" %token DMNSN_T_LOCAL "#local" %token DMNSN_T_MACRO %token DMNSN_T_RANGE %token DMNSN_T_READ %token DMNSN_T_RENDER %token DMNSN_T_STATISTICS %token DMNSN_T_SWITCH %token DMNSN_T_UNDEF "#undef" %token DMNSN_T_VERSION %token DMNSN_T_WARNING %token DMNSN_T_WHILE %token DMNSN_T_WRITE /* Identifiers */ %token DMNSN_T_IDENTIFIER "identifier" /* Strings */ %token DMNSN_T_STRING "string" /* Top-level items */ %type SCENE_ITEM /* Language directives */ %type RVALUE %type IDENTIFIER /* Transformations */ %type TRANSFORMATION /* The camera */ %type CAMERA %type CAMERA_ITEMS %type CAMERA_ITEM %type CAMERA_TYPE %type CAMERA_VECTOR %type CAMERA_MODIFIER /* Atmospheric effects */ %type ATMOSPHERIC_EFFECT %type BACKGROUND /* Objects */ %type OBJECT %type FINITE_SOLID_OBJECT %type BOX %type LIGHT_SOURCE %type SPHERE /* Object modifiers */ %type OBJECT_MODIFIERS %type OBJECT_MODIFIER /* Textures */ %type TEXTURE %type TEXTURE_ITEMS /* Pigments */ %type PIGMENT %type PIGMENT_TYPE /* Floats */ %type FLOAT %type FLOAT_LITERAL /* Vectors */ %type VECTOR %type VECTOR_LITERAL /* Generalized arithmetic expressions */ %type ARITH_EXPR /* Colors */ %type COLOR %type COLOR_BODY %type COLOR_VECTOR %type COLOR_KEYWORD_GROUP %type COLOR_KEYWORD_GROUP_INIT %destructor { free($$); } %destructor { dmnsn_delete_astnode($$); } %% /* Start symbol */ SCENE: /* empty */ | SCENE LANGUAGE_DIRECTIVE | SCENE SCENE_ITEM { dmnsn_array_push(astree, &$2); } ; /* Language directives */ LANGUAGE_DIRECTIVE: DECLARATION ; DECLARATION: "#declare" "identifier" "=" RVALUE { dmnsn_declare_symbol(symtable, $2, $4); free($2); dmnsn_delete_astnode($4); } | "#local" "identifier" "=" RVALUE { dmnsn_local_symbol(symtable, $2, $4); free($2); dmnsn_delete_astnode($4); } | "#undef" "identifier" { dmnsn_undef_symbol(symtable, $2); free($2); } ; RVALUE: ARITH_EXPR ";" { $$ = dmnsn_eval($1, symtable); dmnsn_delete_astnode($1); if ($$.type == DMNSN_AST_NONE) { dmnsn_delete_astnode($$); YYERROR; } } | COLOR ";" ; IDENTIFIER: "identifier" { $$ = dmnsn_new_astnode(DMNSN_AST_IDENTIFIER, @$); $$.ptr = $1; } ; /* Top-level scene item */ SCENE_ITEM: ATMOSPHERIC_EFFECT | CAMERA | OBJECT ; /* 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 ; /* Atmospheric effects */ ATMOSPHERIC_EFFECT: BACKGROUND ; BACKGROUND: "background" "{" COLOR "}" { $$ = dmnsn_new_astnode1(DMNSN_AST_BACKGROUND, @$, $3); } ; /* Objects */ OBJECT: FINITE_SOLID_OBJECT | LIGHT_SOURCE ; FINITE_SOLID_OBJECT: BOX | SPHERE ; BOX: "box" "{" VECTOR "," VECTOR OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_BOX, @$, $3, $5, $6); } ; LIGHT_SOURCE: "light_source" "{" VECTOR "," COLOR "}" { $$ = dmnsn_new_astnode2(DMNSN_AST_LIGHT_SOURCE, @$, $3, $5); } ; SPHERE: "sphere" "{" VECTOR "," FLOAT OBJECT_MODIFIERS "}" { $$ = dmnsn_new_astnode3(DMNSN_AST_SPHERE, @$, $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 { $$ = dmnsn_new_astnode1(DMNSN_AST_TEXTURE, @$, $1); } ; /* Textures */ TEXTURE: "texture" "{" TEXTURE_ITEMS "}" { $$ = $3; } ; TEXTURE_ITEMS: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_TEXTURE, @$); } | TEXTURE_ITEMS PIGMENT { $$ = $1; dmnsn_array_push($$.children, &$2); } ; /* Pigments */ PIGMENT: "pigment" "{" PIGMENT_TYPE "}" { $$ = dmnsn_new_astnode1(DMNSN_AST_PIGMENT, @$, $3); } ; PIGMENT_TYPE: /* empty */ { $$ = dmnsn_new_astnode(DMNSN_AST_NONE, @$); } | COLOR ; /* Floats */ FLOAT: ARITH_EXPR { $$ = dmnsn_eval_scalar($1, symtable); dmnsn_delete_astnode($1); if ($$.type == DMNSN_AST_NONE) { dmnsn_delete_astnode($$); YYERROR; } } ; FLOAT_LITERAL: "integer" { $$ = dmnsn_new_astnode(DMNSN_AST_INTEGER, @$); $$.ptr = malloc(sizeof(long)); if (!$$.ptr) dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for integer."); *(long *)$$.ptr = strtol($1, NULL, 0); free($1); } | "float" { $$ = dmnsn_new_astnode(DMNSN_AST_FLOAT, @$); $$.ptr = malloc(sizeof(double)); if (!$$.ptr) dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for float."); *(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 ")" { $$ = $2; } | IDENTIFIER ; /* Colors */ COLOR: COLOR_BODY { $$ = $1; $$.type = DMNSN_AST_COLOR; } | "color" COLOR_BODY { $$ = $2; $$.type = DMNSN_AST_COLOR; } ; COLOR_BODY: COLOR_VECTOR | COLOR_KEYWORD_GROUP ; COLOR_VECTOR: "rgb" VECTOR { $$ = $2; } | "rgbf" VECTOR { $$ = $2; } | "rgbt" VECTOR { /* Swap the transmit and filter components */ $$ = $2; 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; } ; 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_astnode(DMNSN_AST_INTEGER, @$); zero.ptr = malloc(sizeof(long)); if (!zero.ptr) dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for integer."); *(long *)zero.ptr = 0; $$ = dmnsn_eval_vector(zero, symtable); dmnsn_delete_astnode(zero); } ; COLOR_KEYWORD_ITEM: ARITH_EXPR { if ($1.type == DMNSN_AST_IDENTIFIER) { dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, $1.ptr); if (!symbol) { dmnsn_diagnostic(@1.first_filename, @1.first_line, @1.first_column, "unbound identifier '%s'", $1); dmnsn_delete_astnode($1); YYERROR; } else if (symbol->type != DMNSN_AST_VECTOR && symbol->type != DMNSN_AST_COLOR) { dmnsn_astnode eval = dmnsn_eval_vector(*symbol, symtable); if (eval.type == DMNSN_AST_NONE) { dmnsn_diagnostic(@1.first_filename, @1.first_line, @1.first_column, "expected color; found '%s'", dmnsn_astnode_string(symbol->type)); dmnsn_delete_astnode($1); YYERROR; } $0 = dmnsn_copy_astnode(eval); dmnsn_delete_astnode(eval); } else { $0 = dmnsn_copy_astnode(*symbol); } } else { dmnsn_astnode eval = dmnsn_eval_vector($1, symtable); $0 = dmnsn_copy_astnode(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); } ; %% dmnsn_astree * dmnsn_parse(FILE *file, dmnsn_symbol_table *symtable) { const char *filename; dmnsn_astnode *fnode = dmnsn_find_symbol(symtable, "__file__"); if (fnode && fnode->type == DMNSN_AST_STRING) { filename = fnode->ptr; } else { filename = "<>"; dmnsn_declare_symbol(symtable, "__file__", dmnsn_new_ast_string(filename)); } void *scanner; dmnsn_astree *astree = dmnsn_new_array(sizeof(dmnsn_astnode)); dmnsn_yylex_init(&scanner); dmnsn_yyset_in(file, scanner); if (yyparse(filename, scanner, astree, symtable) != 0) { dmnsn_delete_astree(astree); astree = NULL; } dmnsn_yylex_destroy(scanner); return astree; } const char * dmnsn_token_string(dmnsn_token_type token_type) { #define TOKEN_SIZE 255 static char token[TOKEN_SIZE + 1]; unsigned int i = YYTRANSLATE(token_type); if (i > YYNTOKENS) { fprintf(stderr, "Warning: unrecognised token %d.\n", (int)token_type); return "unrecognized-token"; } /* Trim the quotation marks */ if (strlen(yytname[i]) - 1 >= TOKEN_SIZE) { fprintf(stderr, "Warning: name of token %d too long.\n", (int)token_type); return "unrepresentable-token"; } strcpy(token, yytname[i] + 1); token[strlen(token) - 1] = '\0'; return token; #undef TOKEN_SIZE } const char * dmnsn_astnode_string(dmnsn_astnode_type astnode_type) { switch (astnode_type) { /* Macro to shorten this switch */ #define dmnsn_astnode_map(type, str) \ case type: \ return str; dmnsn_astnode_map(DMNSN_AST_NONE, "none"); dmnsn_astnode_map(DMNSN_AST_ROTATION, "rotate"); dmnsn_astnode_map(DMNSN_AST_SCALE, "scale"); dmnsn_astnode_map(DMNSN_AST_TRANSLATION, "translate"); dmnsn_astnode_map(DMNSN_AST_CAMERA, "camera"); dmnsn_astnode_map(DMNSN_AST_PERSPECTIVE, "perspective"); dmnsn_astnode_map(DMNSN_AST_LOCATION, "location"); dmnsn_astnode_map(DMNSN_AST_RIGHT, "right"); dmnsn_astnode_map(DMNSN_AST_UP, "up"); dmnsn_astnode_map(DMNSN_AST_SKY, "sky"); dmnsn_astnode_map(DMNSN_AST_ANGLE, "angle"); dmnsn_astnode_map(DMNSN_AST_LOOK_AT, "look_at"); dmnsn_astnode_map(DMNSN_AST_DIRECTION, "direction"); dmnsn_astnode_map(DMNSN_AST_BACKGROUND, "background"); dmnsn_astnode_map(DMNSN_AST_BOX, "box"); dmnsn_astnode_map(DMNSN_AST_SPHERE, "sphere"); dmnsn_astnode_map(DMNSN_AST_LIGHT_SOURCE, "light_source"); dmnsn_astnode_map(DMNSN_AST_OBJECT_MODIFIERS, "object-modifiers"); dmnsn_astnode_map(DMNSN_AST_TEXTURE, "texture"); dmnsn_astnode_map(DMNSN_AST_PIGMENT, "pigment"); dmnsn_astnode_map(DMNSN_AST_FLOAT, "float"); dmnsn_astnode_map(DMNSN_AST_INTEGER, "integer"); dmnsn_astnode_map(DMNSN_AST_VECTOR, "vector"); dmnsn_astnode_map(DMNSN_AST_ADD, "+"); dmnsn_astnode_map(DMNSN_AST_SUB, "-"); dmnsn_astnode_map(DMNSN_AST_MUL, "*"); dmnsn_astnode_map(DMNSN_AST_DIV, "/"); dmnsn_astnode_map(DMNSN_AST_NEGATE, "-"); dmnsn_astnode_map(DMNSN_AST_DOT_X, ".x"); dmnsn_astnode_map(DMNSN_AST_DOT_Y, ".y"); dmnsn_astnode_map(DMNSN_AST_DOT_Z, ".z"); dmnsn_astnode_map(DMNSN_AST_DOT_T, ".t"); dmnsn_astnode_map(DMNSN_AST_DOT_TRANSMIT, ".transmit"); dmnsn_astnode_map(DMNSN_AST_COLOR, "color"); dmnsn_astnode_map(DMNSN_AST_IDENTIFIER, "identifier"); dmnsn_astnode_map(DMNSN_AST_STRING, "string"); default: fprintf(stderr, "Warning: unrecognised astnode type %d.\n", (int)astnode_type); return "unrecognized-astnode"; } }