From 7fc84f364bcb2e37363d3e22300180ba92288811 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 22 Mar 2010 22:07:29 -0400 Subject: Support the ternary operator. --- dimension/common.nonterminals | 1 + dimension/common.rules | 42 ++++++++++++++++++++++++++++++++++++++- dimension/directives.nonterminals | 2 -- dimension/directives.rules | 38 ++--------------------------------- dimension/grammar.declarations | 2 +- dimension/grammar.epilogue | 1 + dimension/parse.c | 32 +++++++++++++++++++++++++++++ dimension/parse.h | 21 ++++++++++---------- 8 files changed, 89 insertions(+), 50 deletions(-) (limited to 'dimension') 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 ARITH_EXPR +%type CONDITIONAL %type MAX_LIST %type 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 RVALUE - -%type 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, -- cgit v1.2.3