summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/common.nonterminals1
-rw-r--r--dimension/common.rules42
-rw-r--r--dimension/directives.nonterminals2
-rw-r--r--dimension/directives.rules38
-rw-r--r--dimension/grammar.declarations2
-rw-r--r--dimension/grammar.epilogue1
-rw-r--r--dimension/parse.c32
-rw-r--r--dimension/parse.h21
-rw-r--r--tests/dimension/arithexp.pov2
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 */