%{ /* expr.y * by Will Wagner * last updated 20 Sep 1997, 13:48:07 wwagner * * This file contains a parser for the POVRay expression language, since * the recursive-descent parser that currently exists is really hard * to understand. This should be simpler, though YACC may not be * available for all platforms which POVRay supports. * * This is a modification of the initial grammar which should make * POVRay's expression language infinitely more flexible. Either a * vector or a float is acceptable in all places (except where strings * are expected; don't be stupid), and the conversion is done * implicitly. A vector's first element is used as a float, and a * float is element-extended to a vector. * * Examples: * <1, 2, 3> is floatified to 1 * 1 is vectorized to <1, 1, 1> * * Not-the-right-size vectors might pose a bit of a challenge, * i.e. using UV vectors where XYZ vectors are expected, etc. The * too-small vector should probably be zero-padded to the proper size. * Inconsistent rules like this are just asking for trouble. However, * if the STL vector class just issues a 0 for a non-existent cell, * things would probably be close to fine. * * Changes * 27 Jul 1997 * - Created the file. * * 04 Aug 1997 * - Added precedence directives and moved the member rule * (vexpr.[tuvxyz]) up near the top of the grammar - NO CONFLICTS * WHATSOEVER! I'm the man. * * 11 Aug 1997 * - Minor changes. * * 06 Sep 1997 * - Began repairing the pointerness of the vectors, and making * sure there are no leaks. * * 07 Sep 1997 * - Completed repairing the pointerness of the vectors; added a * vector-of-vector (and vector-of-string) killing function to * simplify the parsing actions. * * Things to do * - Decide what to do about the too-small vector problem. It's * either zero-pad everything (which doesn't preserve the * semantics of the earlier float-vector conversion), or * element-extend everything (which doesn't preserve the semantics * of a vector). * * - Look into adding color stuff into this grammar. It shouldn't * be terribly hard. Also consider how arrays would be added. * * - Finish writing the rand, seed, str, substr, vaxis_rotate, * and vrotate actions. * */ #include #include #include #include #include #include #include #include #include "vector.h" #include "lexer.h" #include "parse.h" #include "registry.h" int addlen(int, char *); char upcase(char); char lowcase(char); void kill_vector_vector(vector *> *); void kill_string_vector(vector *); %} %union { int ival; char *sval; vector *vsval; pov_vector *vval; vector *> *vvval; void *noval; } %type member_decl %type pov_string_expr, pov_string_func_decl, pov_string_literal %type pov_string_func_args, pov_string_literal_list %type pov_logical_expr, pov_rel_expr, pov_add_expr, pov_mul_expr %type pov_unary_expr, pov_paren_expr, pov_func_decl, pov_literal %type pov_float_literal %type pov_func_args, pov_literal_list %type pov_expr %token ABS_TOKEN, ACOSH_TOKEN, ACOS_TOKEN, AMPERSAND_TOKEN, ASC_TOKEN, %token ASINH_TOKEN, ASIN_TOKEN, ATAN2_TOKEN, ATANH_TOKEN, ATAN_TOKEN, %token AT_TOKEN, BACK_QUOTE_TOKEN, BACK_SLASH_TOKEN, BAR_TOKEN, BLUE_TOKEN, %token CEIL_TOKEN, CHR_TOKEN, CLOCK_TOKEN, COLON_TOKEN, COMMA_TOKEN, %token CONCAT_TOKEN, COSH_TOKEN, COS_TOKEN, DASH_TOKEN, DEGREES_TOKEN, %token DIV_TOKEN, DOLLAR_TOKEN, DOUBLE_QUOTE_TOKEN, END_OF_FILE_TOKEN, %token EQUALS_TOKEN, EXCLAMATION_TOKEN, EXP_TOKEN, FALSE_TOKEN, %token FILE_EXISTS_TOKEN, FILTER_TOKEN, FLOAT_ID_TOKEN, FLOAT_TOKEN, %token FLOOR_TOKEN, GREEN_TOKEN, HASH_TOKEN, HAT_TOKEN, INT_TOKEN, %token LEFT_ANGLE_TOKEN, LEFT_CURLY_TOKEN, LEFT_PAREN_TOKEN, %token LEFT_SQUARE_TOKEN, LOG_TOKEN, MAX_TOKEN, MIN_TOKEN, MOD_TOKEN, %token NO_TOKEN, OFF_TOKEN, ON_TOKEN, PERCENT_TOKEN, PERIOD_TOKEN, PI_TOKEN, %token PLUS_TOKEN, POW_TOKEN, QUESTION_TOKEN, RADIANS_TOKEN, RAND_TOKEN, %token RED_TOKEN, REL_GE_TOKEN, REL_LE_TOKEN, REL_NE_TOKEN, %token RIGHT_ANGLE_TOKEN, RIGHT_CURLY_TOKEN, RIGHT_PAREN_TOKEN, %token RIGHT_SQUARE_TOKEN, SEED_TOKEN, SEMICOLON_TOKEN, SINGLE_QUOTE_TOKEN, %token SINH_TOKEN, SIN_TOKEN, SLASH_TOKEN, SQRT_TOKEN, STAR_TOKEN, %token STRCMP_TOKEN, STRING_ID_TOKEN, STRING_LITERAL_TOKEN, STRLEN_TOKEN, %token STRLWR_TOKEN, STRUPR_TOKEN, STR_TOKEN, SUBSTR_TOKEN, TANH_TOKEN, %token TAN_TOKEN, TILDE_TOKEN, TRANSMIT_TOKEN, TRUE_TOKEN, T_TOKEN, U_TOKEN, %token VAL_TOKEN, VAXIS_ROTATE_TOKEN, VCROSS_TOKEN, VDOT_TOKEN, %token VECTOR_ID_TOKEN, VERSION_TOKEN, VLENGTH_TOKEN, VNORMALIZE_TOKEN, %token VROTATE_TOKEN, V_TOKEN, X_TOKEN, YES_TOKEN, Y_TOKEN, Z_TOKEN %token LAST_TOKEN %left LOGICAL_OR, LOGICAL_AND %left LESS_THAN, LESS_OR_EQUAL, EQUAL_TO, NOT_EQUAL, GREATER_OR_EQUAL, GREATER_THAN %left ADDITION, SUBTRACTION %left MULTIPLICATION, DIVISION %left LOGICAL_NOT, UNARY_PLUS, UNARY_MINUS %right MEMBER_OF %start pov_expr %% pov_expr: pov_logical_expr { $$ = (void *)$1; } | pov_string_expr { $$ = (void *)$1; } ; pov_logical_expr: pov_logical_expr BAR_TOKEN pov_rel_expr %prec LOGICAL_OR { (*$1)[0] = (*$1)[0] || (*$3)[0]; delete $3; $$ = $1; } | pov_logical_expr AMPERSAND_TOKEN pov_rel_expr %prec LOGICAL_AND { (*$1)[0] = (*$1)[0] && (*$3)[0]; delete $3; $$ = $1; } | pov_logical_expr PERIOD_TOKEN member_decl %prec MEMBER_OF { $$ = new pov_vector(1, (*$1)[$3]); delete $1; } | pov_rel_expr { $$ = $1; } ; pov_rel_expr: pov_rel_expr LEFT_ANGLE_TOKEN pov_add_expr %prec LESS_THAN { (*$1)[0] = *$1 < *$3; delete $3; $$ = $1; } | pov_rel_expr REL_LE_TOKEN pov_add_expr %prec LESS_OR_EQUAL { (*$1)[0] = *$1 <= *$3; delete $3; $$ = $1; } | pov_rel_expr EQUALS_TOKEN pov_add_expr %prec EQUAL_TO { (*$1)[0] = *$1 == *$3; delete $3; $$ = $1; } | pov_rel_expr REL_NE_TOKEN pov_add_expr %prec NOT_EQUAL { (*$1)[0] = *$1 != *$3; delete $3; $$ = $1; } | pov_rel_expr REL_GE_TOKEN pov_add_expr %prec GREATER_OR_EQUAL { (*$1)[0] = *$1 >= *$3; delete $3; $$ = $1; } | pov_rel_expr RIGHT_ANGLE_TOKEN pov_add_expr %prec GREATER_THAN { (*$1)[0] = *$1 > *$3; delete $3; $$ = $1; } | pov_add_expr { $$ = $1; } ; pov_add_expr: pov_add_expr PLUS_TOKEN pov_mul_expr %prec ADDITION { *$1 += *$3; $$ = $1; } | pov_add_expr DASH_TOKEN pov_mul_expr %prec SUBTRACTION { *$1 -= *$3; $$ = $1; } | pov_mul_expr { $$ = $1; } ; pov_mul_expr: pov_mul_expr STAR_TOKEN pov_unary_expr %prec MULTIPLICATION { *$1 *= *$3; $$ = $1; } | pov_mul_expr SLASH_TOKEN pov_unary_expr %prec DIVISION { *$1 /= *$3; $$ = $1; } | pov_unary_expr { $$ = $1; } ; pov_unary_expr: EXCLAMATION_TOKEN pov_paren_expr %prec LOGICAL_NOT { pov_vector& v = *$2; for (int i = 0; i < (int)v.size(); ++i) v[i] = !v[i]; $$ = $2; } | PLUS_TOKEN pov_paren_expr %prec UNARY_PLUS { $$ = $2; } | DASH_TOKEN pov_paren_expr %prec UNARY_MINUS { pov_vector& v = *$2; for (int i = 0; i < (int)v.size(); ++i) v[i] = -(v[i]); $$ = $2; } | pov_paren_expr { $$ = $1; } ; pov_paren_expr: LEFT_PAREN_TOKEN pov_logical_expr RIGHT_PAREN_TOKEN { $$ = $2; } | pov_func_decl { $$ = $1; } | pov_literal { $$ = $1; } ; pov_func_decl: ABS_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = fabs(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ACOS_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = acos(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ACOSH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = acosh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ASC_TOKEN pov_string_func_args { $$ = new pov_vector (1, (double)(*$2)[0][0]); kill_string_vector($2); } | ASIN_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = asin(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ASINH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = asinh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ATAN_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = atan(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ATANH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = atanh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | ATAN2_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); pov_vector& w = *((*$2)[1]); for (int i = 0; i < (int)v.size(); ++i) v[i] = atan2(v[i], w[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | CEIL_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = ceil(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | COS_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = cos(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | COSH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = cosh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | DEGREES_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] /= M_PI / 180.0; $$ = new pov_vector(v); kill_vector_vector($2); } | DIV_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); pov_vector& w = *((*$2)[1]); for (int i = 0; i < (int)v.size(); ++i) v[i] = (double)((int)(v[i]) / (int)(w[i])); $$ = new pov_vector(v); kill_vector_vector($2); } | EXP_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = exp(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | FILE_EXISTS_TOKEN pov_string_func_args { struct stat buf; $$ = new pov_vector (1, (double)!stat((*$2)[0], &buf)); kill_string_vector($2); } | FLOOR_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = floor(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | INT_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = (double)((int)(v[i])); $$ = new pov_vector(v); kill_vector_vector($2); } | LOG_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = log(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | MAX_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 1; i < (int)v.size(); ++i) if (*((*$2)[i]) > v) v = *((*$2)[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | MIN_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 1; i < (int)v.size(); ++i) if (*((*$2)[i]) < v) v = *((*$2)[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | MOD_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); pov_vector& w = *((*$2)[1]); for (int i = 0; i < (int)v.size(); ++i) v[i] = fmod(v[i], w[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | POW_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); pov_vector& w = *((*$2)[1]); for (int i = 1; i < (int)v.size(); ++i) v[i] = pow(v[i], w[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | RADIANS_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] *= M_PI / 180.0; $$ = new pov_vector(v); kill_vector_vector($2); } | RAND_TOKEN pov_string_func_args { $$ = new pov_vector(1, 0.0); } | SEED_TOKEN pov_func_args { $$ = new pov_vector(1, 0.0); } | SIN_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = sin(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | SINH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = sinh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | SQRT_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = sqrt(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | STRCMP_TOKEN pov_string_func_args { $$ = new pov_vector (1, (double)strcmp((*$2)[0], (*$2)[1])); kill_string_vector($2); } | STRLEN_TOKEN pov_string_func_args { $$ = new pov_vector (1, (double)strlen((*$2)[0])); kill_string_vector($2); } | TAN_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = tan(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | TANH_TOKEN pov_func_args { pov_vector& v = *((*$2)[0]); for (int i = 0; i < (int)v.size(); ++i) v[i] = tanh(v[i]); $$ = new pov_vector(v); kill_vector_vector($2); } | VAL_TOKEN pov_string_func_args { $$ = new pov_vector (1, atof((*$2)[0])); kill_string_vector($2); } | VAXIS_ROTATE_TOKEN pov_func_args { kill_vector_vector($2); } | VCROSS_TOKEN pov_func_args { $$ = new pov_vector ((*((*$2)[0])).Cross(*((*$2)[1]))); kill_vector_vector($2); } | VDOT_TOKEN pov_func_args { $$ = new pov_vector (1, (*((*$2)[0])).Dot(*((*$2)[1]))); kill_vector_vector($2); } | VLENGTH_TOKEN pov_func_args { $$ = new pov_vector (1, (*((*$2)[0])).Length()); kill_vector_vector($2); } | VNORMALIZE_TOKEN pov_func_args { $$ = new pov_vector ((*((*$2)[0])).Normalized()); kill_vector_vector($2); } | VROTATE_TOKEN pov_func_args { kill_vector_vector($2); } ; member_decl: T_TOKEN { $$ = 3; } | U_TOKEN { $$ = 0; } | V_TOKEN { $$ = 1; } | X_TOKEN { $$ = 0; } | Y_TOKEN { $$ = 1; } | Z_TOKEN { $$ = 2; } | RED_TOKEN { $$ = 0; } | GREEN_TOKEN { $$ = 1; } | BLUE_TOKEN { $$ = 2; } | FILTER_TOKEN { $$ = 3; } | TRANSMIT_TOKEN { $$ = 4; } ; pov_func_args: LEFT_PAREN_TOKEN pov_literal_list RIGHT_PAREN_TOKEN { $$ = $2; } ; pov_literal_list: pov_literal_list COMMA_TOKEN pov_literal { $$ = $1; $$->push_back($3); } | pov_literal { $$ = new vector *>(1, $1); } ; pov_literal: LEFT_ANGLE_TOKEN pov_literal_list RIGHT_ANGLE_TOKEN { $$ = new pov_vector(1, (*(*$2)[0])[0]); for (int i = 1; i < (int)(*$2).size(); ++i) $$->push_back((*(*$2)[i])[0]); kill_vector_vector($2); } | VECTOR_ID_TOKEN { $$ = new pov_vector (*(registry.sym().Means (tok.GetTokenString()))); } | T_TOKEN { $$ = new pov_vector(4, 0.0); (*$$)[3] = 1.0; } | U_TOKEN { $$ = new pov_vector(2, 0.0); (*$$)[0] = 1.0; } | V_TOKEN { $$ = new pov_vector(2, 0.0); (*$$)[1] = 1.0; } | X_TOKEN { $$ = new pov_vector(3, 0.0); (*$$)[0] = 1.0; } | Y_TOKEN { $$ = new pov_vector(3, 0.0); (*$$)[1] = 1.0; } | Z_TOKEN { $$ = new pov_vector(3, 0.0); (*$$)[2] = 1.0; } | pov_float_literal { $$ = $1; } ; pov_float_literal: FLOAT_TOKEN { $$ = new pov_vector (1, tok.GetTokenFloat()); } | FLOAT_ID_TOKEN { $$ = new pov_vector (1, registry.sym().Means (tok.GetTokenString())); } | PI_TOKEN { $$ = new pov_vector(1, M_PI); } | CLOCK_TOKEN { $$ = new pov_vector (1, registry.clock()); } | VERSION_TOKEN { $$ = new pov_vector (1, registry.version()); } | TRUE_TOKEN { $$ = new pov_vector(1, 1.0); } | YES_TOKEN { $$ = new pov_vector(1, 1.0); } | ON_TOKEN { $$ = new pov_vector(1, 1.0); } | FALSE_TOKEN { $$ = new pov_vector(1, 0.0); } | NO_TOKEN { $$ = new pov_vector(1, 0.0); } | OFF_TOKEN { $$ = new pov_vector(1, 0.0); } ; pov_string_expr: pov_string_func_decl { $$ = $1; } | pov_string_literal { $$ = $1; } ; pov_string_func_decl: CHR_TOKEN pov_func_args { $$ = new char[2]; $$[0] = (char)((*(*$2)[0])[0]); $$[1] = '\0'; kill_vector_vector($2); } | CONCAT_TOKEN pov_string_func_args { int len = accumulate((*$2).begin(), (*$2).end(), 1, addlen()); $$ = new char[len]('\0'); for_each((*$2).begin(), (*$2).end(), bind1st(strcat(), $$)); kill_string_vector($2); } | STR_TOKEN pov_func_args { kill_vector_vector($2); } | STRLWR_TOKEN pov_string_func_args { $$ = new char[strlen((*$2)[0]) + 1]; strcpy($$, (*$2)[0]); for_each($$.begin(), $$.end(), lowcase()); kill_string_vector($2); } | SUBSTR_TOKEN { } | STRUPR_TOKEN pov_string_func_args { $$ = new char[strlen((*$2)[0]) + 1]; strcpy($$, (*$2)[0]); for_each($$.begin(), $$.end(), upcase()); kill_string_vector($2); } ; pov_string_func_args: LEFT_PAREN_TOKEN pov_string_literal_list RIGHT_PAREN_TOKEN { $$ = $2; } ; pov_string_literal_list: pov_string_literal_list COMMA_TOKEN pov_string_literal { $$ = $1->push_back($3); } | pov_string_literal { $$ == new vector(1, $1); } ; pov_string_literal: STRING_LITERAL_TOKEN { char *s = tok.GetTokenString(); $$ = new char[strlen(s) + 1]; strcpy($$, s); } | STRING_ID_TOKEN { char *s = registry.sym().Means (tok.GetTokenString()); $$ = new char[strlen(s) + 1]; strcpy($$, s); } ; %% int yyerror(char *s) { throw ParserError(s, yylineno); } int addlen(int init, char *str) { return init + (int)strlen(str); } char upcase(char c) { return toupper(c); } char lowcase(char c) { return tolower(c); } void kill_vector_vector(vector *> *v) { while (v->rbegin() != v->rend()) { delete (*(v->rbegin())); pop_back(*v); } delete v; } void kill_string_vector(vector *v) { while (v->rbegin() != v->rend()) { delete[] (*(v->rbegin())); pop_back(*v); } delete v; }