diff options
-rw-r--r-- | dimension/common.nonterminals | 1 | ||||
-rw-r--r-- | dimension/common.rules | 42 | ||||
-rw-r--r-- | dimension/directives.nonterminals | 2 | ||||
-rw-r--r-- | dimension/directives.rules | 38 | ||||
-rw-r--r-- | dimension/grammar.declarations | 2 | ||||
-rw-r--r-- | dimension/grammar.epilogue | 1 | ||||
-rw-r--r-- | dimension/parse.c | 32 | ||||
-rw-r--r-- | dimension/parse.h | 21 | ||||
-rw-r--r-- | tests/dimension/arithexp.pov | 2 |
9 files changed, 90 insertions, 51 deletions
diff --git a/dimension/common.nonterminals b/dimension/common.nonterminals index 2008290..164440a 100644 --- a/dimension/common.nonterminals +++ b/dimension/common.nonterminals @@ -73,6 +73,7 @@ /* Generalized arithmetic expressions */ %type <astnode> ARITH_EXPR +%type <astnode> CONDITIONAL %type <astnode> MAX_LIST %type <astnode> MIN_LIST diff --git a/dimension/common.rules b/dimension/common.rules index 02f2010..81719c5 100644 --- a/dimension/common.rules +++ b/dimension/common.rules @@ -395,7 +395,10 @@ ARITH_EXPR: FLOAT_LITERAL | ARITH_EXPR "." "transmit" { $$ = dmnsn_new_astnode1(DMNSN_AST_DOT_TRANSMIT, @$, $1); } - | "(" ARITH_EXPR ")" { $$ = $2; } + | "(" 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); } @@ -530,6 +533,43 @@ MIN_LIST: ARITH_EXPR "," ARITH_EXPR { } ; +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 { diff --git a/dimension/directives.nonterminals b/dimension/directives.nonterminals index 5738bcd..6f858af 100644 --- a/dimension/directives.nonterminals +++ b/dimension/directives.nonterminals @@ -20,5 +20,3 @@ *************************************************************************/ %type <astnode> RVALUE - -%type <astnode> CONDITIONAL diff --git a/dimension/directives.rules b/dimension/directives.rules index a01ab9a..b995c78 100644 --- a/dimension/directives.rules +++ b/dimension/directives.rules @@ -70,6 +70,7 @@ LANGUAGE_DIRECTIVE: "#include" STRING { dmnsn_delete_astnode($2); YYERROR; } +; RVALUE: ARITH_EXPR ";" %dprec 2 { $$ = dmnsn_eval($1, symtable); @@ -88,39 +89,4 @@ RVALUE: ARITH_EXPR ";" %dprec 2 { | INTERIOR | CAMERA | TRANSFORMATION - -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 ")" { - $$ = $2; - } - | "!" CONDITIONAL { - $$ = dmnsn_new_astnode1(DMNSN_AST_NOT, @$, $2); - } +; diff --git a/dimension/grammar.declarations b/dimension/grammar.declarations index 363554e..3eae498 100644 --- a/dimension/grammar.declarations +++ b/dimension/grammar.declarations @@ -23,7 +23,7 @@ %name-prefix "dmnsn_yy" -%expect 7 +%expect 8 %parse-param {const char *filename} %parse-param {void *yyscanner} diff --git a/dimension/grammar.epilogue b/dimension/grammar.epilogue index 881ec98..6b93dc3 100644 --- a/dimension/grammar.epilogue +++ b/dimension/grammar.epilogue @@ -178,6 +178,7 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type) dmnsn_astnode_map(DMNSN_AST_AND, "&" ); dmnsn_astnode_map(DMNSN_AST_OR, "|" ); dmnsn_astnode_map(DMNSN_AST_NOT, "!" ); + dmnsn_astnode_map(DMNSN_AST_TERNARY, "?:"); dmnsn_astnode_map(DMNSN_AST_ABS, "abs" ); dmnsn_astnode_map(DMNSN_AST_ACOS, "acos" ); diff --git a/dimension/parse.c b/dimension/parse.c index 0f94f6c..52479ad 100644 --- a/dimension/parse.c +++ b/dimension/parse.c @@ -1413,6 +1413,35 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) return ret; } +static dmnsn_astnode +dmnsn_eval_ternary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +{ + dmnsn_astnode test, iftrue, iffalse, ret; + dmnsn_array_get(astnode.children, 0, &test); + dmnsn_array_get(astnode.children, 1, &iftrue); + dmnsn_array_get(astnode.children, 2, &iffalse); + test = dmnsn_eval_scalar(test, symtable); + + switch(astnode.type) { + case DMNSN_AST_TERNARY: + dmnsn_assert(test.type == DMNSN_AST_INTEGER, + "Conditional expression evaluated to non-integer."); + ret = dmnsn_eval(*(long *)test.ptr ? iftrue : iffalse, symtable); + break; + + default: + dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col, + "invalid ternary operator '%s'", + dmnsn_astnode_string(astnode.type)); + ret = dmnsn_copy_astnode(astnode); + ret.type = DMNSN_AST_NONE; + break; + } + + dmnsn_delete_astnode(test); + return ret; +} + dmnsn_astnode dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { @@ -1513,6 +1542,9 @@ dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) case DMNSN_AST_VDOT: return dmnsn_eval_binary(astnode, symtable); + case DMNSN_AST_TERNARY: + return dmnsn_eval_ternary(astnode, symtable); + default: dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col, "expected arithmetic expression; found %s", diff --git a/dimension/parse.h b/dimension/parse.h index 09931d1..ef5bb17 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -90,6 +90,17 @@ typedef enum { DMNSN_AST_DOT_T, DMNSN_AST_DOT_TRANSMIT, + DMNSN_AST_EQUAL, + DMNSN_AST_NOT_EQUAL, + DMNSN_AST_LESS, + DMNSN_AST_LESS_EQUAL, + DMNSN_AST_GREATER, + DMNSN_AST_GREATER_EQUAL, + DMNSN_AST_AND, + DMNSN_AST_OR, + DMNSN_AST_NOT, + DMNSN_AST_TERNARY, + DMNSN_AST_ABS, DMNSN_AST_ACOS, DMNSN_AST_ACOSH, @@ -133,16 +144,6 @@ typedef enum { DMNSN_AST_Z, DMNSN_AST_T, - DMNSN_AST_EQUAL, - DMNSN_AST_NOT_EQUAL, - DMNSN_AST_LESS, - DMNSN_AST_LESS_EQUAL, - DMNSN_AST_GREATER, - DMNSN_AST_GREATER_EQUAL, - DMNSN_AST_AND, - DMNSN_AST_OR, - DMNSN_AST_NOT, - DMNSN_AST_IDENTIFIER, DMNSN_AST_STRING, diff --git a/tests/dimension/arithexp.pov b/tests/dimension/arithexp.pov index 30281e5..863c254 100644 --- a/tests/dimension/arithexp.pov +++ b/tests/dimension/arithexp.pov @@ -21,7 +21,7 @@ sphere { 2*<<2.0 - 1.0, 3.0, 4.0>.x, (1.0 + 2)*2 - 5, 1.0 + 2*2 - 4> - -<0, 0, 1>, - exp(1) - 1*2 + exp(1) - (0 >= 1 ? 0 : 1*2) } /* Float functions */ |