diff options
-rw-r--r-- | dimension/grammar.y | 269 | ||||
-rw-r--r-- | dimension/lexer.l | 4 | ||||
-rw-r--r-- | dimension/parse.c | 395 | ||||
-rw-r--r-- | dimension/parse.h | 11 | ||||
-rw-r--r-- | tests/dimension/directives.pov | 14 | ||||
-rwxr-xr-x | tests/dimension/directives.sh | 29 |
6 files changed, 433 insertions, 289 deletions
diff --git a/dimension/grammar.y b/dimension/grammar.y index e52d668..00bc9cb 100644 --- a/dimension/grammar.y +++ b/dimension/grammar.y @@ -147,7 +147,7 @@ yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, %name-prefix "dmnsn_yy" -%expect 0 +%expect 1 %parse-param {const char *filename} %parse-param {void *yyscanner} @@ -638,14 +638,14 @@ yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, %token DMNSN_T_IFDEF %token DMNSN_T_IFNDEF %token DMNSN_T_INCLUDE "#include" -%token DMNSN_T_LOCAL +%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 +%token DMNSN_T_UNDEF "#undef" %token DMNSN_T_VERSION %token DMNSN_T_WARNING %token DMNSN_T_WHILE @@ -660,6 +660,10 @@ yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, /* Top-level items */ %type <astnode> SCENE_ITEM +/* Language directives */ +%type <astnode> RVALUE +%type <astnode> IDENTIFIER + /* Transformations */ %type <astnode> TRANSFORMATION @@ -696,14 +700,15 @@ yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, /* Floats */ %type <astnode> FLOAT -%type <astnode> FLOAT_EXPR %type <astnode> FLOAT_LITERAL /* Vectors */ %type <astnode> VECTOR -%type <astnode> VECTOR_EXPR %type <astnode> VECTOR_LITERAL +/* Generalized arithmetic expressions */ +%type <astnode> ARITH_EXPR + /* Colors */ %type <astnode> COLOR %type <astnode> COLOR_BODY @@ -711,18 +716,60 @@ yyerror(YYLTYPE *locp, const char *filename, void *yyscanner, %type <astnode> COLOR_KEYWORD_GROUP %type <astnode> COLOR_KEYWORD_GROUP_INIT +%destructor { free($$); } <value> %destructor { dmnsn_delete_astnode($$); } <astnode> %% /* Start symbol */ -SCENE: /* empty */ { } +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 @@ -758,14 +805,17 @@ CAMERA_ITEMS: /* empty */ { $$ = $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); @@ -782,6 +832,7 @@ CAMERA_VECTOR: "location" VECTOR { | "direction" VECTOR { $$ = dmnsn_new_astnode1(DMNSN_AST_DIRECTION, @$, $2); } +; CAMERA_MODIFIER: "angle" FLOAT { $$ = dmnsn_new_astnode1(DMNSN_AST_ANGLE, @$, $2); @@ -790,6 +841,7 @@ CAMERA_MODIFIER: "angle" FLOAT { $$ = dmnsn_new_astnode1(DMNSN_AST_LOOK_AT, @$, $2); } | TRANSFORMATION +; /* Atmospheric effects */ @@ -890,91 +942,15 @@ PIGMENT_TYPE: /* empty */ { /* Floats */ -FLOAT: FLOAT_EXPR { +FLOAT: ARITH_EXPR { $$ = dmnsn_eval_scalar($1, symtable); dmnsn_delete_astnode($1); - } -; - -FLOAT_EXPR: FLOAT_LITERAL - | FLOAT_EXPR "+" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_ADD, @$, $1, $3); - } - | FLOAT_EXPR "-" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_SUB, @$, $1, $3); - } - | FLOAT_EXPR "*" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3); - } - | FLOAT_EXPR "/" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_DIV, @$, $1, $3); - } - | "+" FLOAT_EXPR %prec DMNSN_T_NEGATE { $$ = $2; } - | "-" FLOAT_EXPR %prec DMNSN_T_NEGATE { - $$ = dmnsn_new_astnode1(DMNSN_AST_NEGATE, @$, $2); - } - - | VECTOR_EXPR "." "x" { - dmnsn_array_get($1.children, 0, &$$); - dmnsn_array_remove($1.children, 0); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "u" { - dmnsn_array_get($1.children, 0, &$$); - dmnsn_array_remove($1.children, 0); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "red" { - dmnsn_array_get($1.children, 0, &$$); - dmnsn_array_remove($1.children, 0); - dmnsn_delete_astnode($1); - } - - | VECTOR_EXPR "." "y" { - dmnsn_array_get($1.children, 1, &$$); - dmnsn_array_remove($1.children, 1); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "v" { - dmnsn_array_get($1.children, 1, &$$); - dmnsn_array_remove($1.children, 1); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "green" { - dmnsn_array_get($1.children, 1, &$$); - dmnsn_array_remove($1.children, 1); - dmnsn_delete_astnode($1); - } - - | VECTOR_EXPR "." "z" { - dmnsn_array_get($1.children, 2, &$$); - dmnsn_array_remove($1.children, 2); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "blue" { - dmnsn_array_get($1.children, 2, &$$); - dmnsn_array_remove($1.children, 2); - dmnsn_delete_astnode($1); - } - - | VECTOR_EXPR "." "t" { - dmnsn_array_get($1.children, 3, &$$); - dmnsn_array_remove($1.children, 3); - dmnsn_delete_astnode($1); - } - | VECTOR_EXPR "." "filter" { - dmnsn_array_get($1.children, 3, &$$); - dmnsn_array_remove($1.children, 3); - dmnsn_delete_astnode($1); - } - - | VECTOR_EXPR "." "transmit" { - dmnsn_array_get($1.children, 4, &$$); - dmnsn_array_remove($1.children, 4); - dmnsn_delete_astnode($1); - } - | "(" FLOAT_EXPR ")" { $$ = $2; } + if ($$.type == DMNSN_AST_NONE) { + dmnsn_delete_astnode($$); + YYERROR; + } + } ; FLOAT_LITERAL: "integer" { @@ -1001,56 +977,93 @@ FLOAT_LITERAL: "integer" { /* Vectors */ -VECTOR: VECTOR_EXPR { +VECTOR: ARITH_EXPR { $$ = dmnsn_eval_vector($1, symtable); dmnsn_delete_astnode($1); - } - | FLOAT_EXPR { - $$ = dmnsn_eval_vector($1, symtable); - dmnsn_delete_astnode($1); - } -; -VECTOR_EXPR: VECTOR_LITERAL - | VECTOR_EXPR "+" VECTOR_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_ADD, @$, $1, $3); - } - | VECTOR_EXPR "-" VECTOR_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_SUB, @$, $1, $3); - } - | VECTOR_EXPR "*" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3); - } - | FLOAT_EXPR "*" VECTOR_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_MUL, @$, $1, $3); - } - | VECTOR_EXPR "/" FLOAT_EXPR { - $$ = dmnsn_new_astnode2(DMNSN_AST_DIV, @$, $1, $3); - } - | "+" VECTOR_EXPR %prec DMNSN_T_NEGATE { $$ = $2; } - | "-" VECTOR_EXPR %prec DMNSN_T_NEGATE { - $$ = dmnsn_new_astnode1(DMNSN_AST_NEGATE, @$, $2); - } - | "(" VECTOR_EXPR ")" { $$ = $2; } + if ($$.type == DMNSN_AST_NONE) { + dmnsn_delete_astnode($$); + YYERROR; + } + } ; -VECTOR_LITERAL: "<" FLOAT_EXPR "," FLOAT_EXPR ">" { +VECTOR_LITERAL: "<" ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode2(DMNSN_AST_VECTOR, @$, $2, $4); } - | "<" FLOAT_EXPR "," FLOAT_EXPR "," FLOAT_EXPR ">" { + | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR ">" { $$ = dmnsn_new_astnode3(DMNSN_AST_VECTOR, @$, $2, $4, $6); } - | "<" FLOAT_EXPR "," FLOAT_EXPR "," FLOAT_EXPR "," - FLOAT_EXPR ">" { + | "<" ARITH_EXPR "," ARITH_EXPR "," ARITH_EXPR "," + ARITH_EXPR ">" { $$ = dmnsn_new_astnode4(DMNSN_AST_VECTOR, @$, $2, $4, $6, $8); } - | "<" FLOAT_EXPR "," FLOAT_EXPR "," FLOAT_EXPR "," - FLOAT_EXPR "," FLOAT_EXPR ">" { + | "<" 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 | "color" COLOR_BODY { $$ = $2; } ; @@ -1145,7 +1158,7 @@ dmnsn_parse(FILE *file, dmnsn_symbol_table *symtable) if (yyparse(filename, scanner, astree, symtable) != 0) { dmnsn_delete_astree(astree); - return NULL; + astree = NULL; } dmnsn_yylex_destroy(scanner); @@ -1219,12 +1232,20 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type) dmnsn_astnode_map(DMNSN_AST_VECTOR, "vector"); - dmnsn_astnode_map(DMNSN_AST_NEGATE, "-"); 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_IDENTIFIER, "identifier"); + dmnsn_astnode_map(DMNSN_AST_STRING, "string"); default: diff --git a/dimension/lexer.l b/dimension/lexer.l index 54d2040..691467b 100644 --- a/dimension/lexer.l +++ b/dimension/lexer.l @@ -194,8 +194,10 @@ unsigned long wchar; "z" RETURN_TOKEN(DMNSN_T_Z); (?# Directives) -"#include" RETURN_TOKEN(DMNSN_T_INCLUDE); "#declare" RETURN_TOKEN(DMNSN_T_DECLARE); +"#include" RETURN_TOKEN(DMNSN_T_INCLUDE); +"#local" RETURN_TOKEN(DMNSN_T_LOCAL); +"#undef" RETURN_TOKEN(DMNSN_T_UNDEF); (?# Identifiers) [[:alpha:]][[:alnum:]_]* RETURN_VALUE_TOKEN(DMNSN_T_IDENTIFIER); diff --git a/dimension/parse.c b/dimension/parse.c index 1916941..320277c 100644 --- a/dimension/parse.c +++ b/dimension/parse.c @@ -18,6 +18,7 @@ *************************************************************************/ #include "parse.h" +#include "utility.h" static dmnsn_astnode dmnsn_new_astnode(dmnsn_astnode_type type) @@ -89,11 +90,10 @@ dmnsn_delete_astnode(dmnsn_astnode astnode) void dmnsn_delete_astree(dmnsn_astree *astree) { - unsigned int i; - dmnsn_astnode node; - if (astree) { + unsigned int i; for (i = 0; i < dmnsn_array_size(astree); ++i) { + dmnsn_astnode node; dmnsn_array_get(astree, i, &node); dmnsn_delete_astnode(node); } @@ -218,7 +218,8 @@ dmnsn_undef_symbol(dmnsn_symbol_table *symtable, const char *id) dmnsn_array_size(scope) - j - 1); if (strcmp(id, symbol->id) == 0) { - dmnsn_array_remove(scope, j); + dmnsn_delete_symbol(*symbol); + dmnsn_array_remove(scope, dmnsn_array_size(scope) - j - 1); return; } } @@ -267,20 +268,128 @@ dmnsn_copy_astnode(dmnsn_astnode astnode) return copy; } +#define DMNSN_VECTOR_NELEM 5 + +static dmnsn_astnode +dmnsn_vector_promote(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +{ + dmnsn_astnode promoted = dmnsn_copy_astnode(astnode); + + if (astnode.type == DMNSN_AST_VECTOR) { + dmnsn_astnode component; + unsigned int i; + for (i = 0; i < dmnsn_array_size(astnode.children); ++i) { + dmnsn_array_get(astnode.children, i, &component); + component = dmnsn_eval_scalar(component, symtable); + + if (component.type == DMNSN_AST_NONE) { + dmnsn_delete_astnode(promoted); + return component; + } else { + dmnsn_array_push(promoted.children, &component); + } + } + + while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { + component = dmnsn_copy_astnode(component); + component.type = DMNSN_AST_INTEGER; + + long *val = malloc(sizeof(long)); + *val = 0; + + component.ptr = val; + dmnsn_array_push(promoted.children, &component); + } + } else { + dmnsn_astnode component = dmnsn_eval_scalar(astnode, symtable); + + if (component.type == DMNSN_AST_NONE) { + promoted.type = DMNSN_AST_NONE; + } else { + promoted.type = DMNSN_AST_VECTOR; + while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { + dmnsn_array_push(promoted.children, &component); + ++*component.refcount; + } + } + + dmnsn_delete_astnode(component); + } + + return promoted; +} + static dmnsn_astnode -dmnsn_eval_scalar_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +dmnsn_eval_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { - dmnsn_astnode ret = dmnsn_copy_astnode(astnode), rhs; + unsigned int i; + + dmnsn_astnode rhs; dmnsn_array_get(astnode.children, 0, &rhs); - rhs = dmnsn_eval_scalar(rhs, symtable); + rhs = dmnsn_eval(rhs, symtable); + + dmnsn_astnode ret = dmnsn_copy_astnode(astnode); + + if (rhs.type == DMNSN_AST_NONE) { + ret.type = DMNSN_AST_NONE; + } else if (rhs.type == DMNSN_AST_VECTOR) { + switch (astnode.type) { + case DMNSN_AST_DOT_X: + dmnsn_array_get(rhs.children, 0, &ret); + ++*ret.refcount; + break; + + case DMNSN_AST_DOT_Y: + dmnsn_array_get(rhs.children, 1, &ret); + ++*ret.refcount; + break; + + case DMNSN_AST_DOT_Z: + dmnsn_array_get(rhs.children, 2, &ret); + ++*ret.refcount; + break; - if (rhs.type == DMNSN_AST_INTEGER) { + case DMNSN_AST_DOT_T: + dmnsn_array_get(rhs.children, 3, &ret); + ++*ret.refcount; + break; + + case DMNSN_AST_DOT_TRANSMIT: + dmnsn_array_get(rhs.children, 4, &ret); + ++*ret.refcount; + break; + + default: + { + ret.type = DMNSN_AST_VECTOR; + + dmnsn_astnode op = dmnsn_copy_astnode(astnode); + for (i = 0; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 0)); + dmnsn_astnode temp = dmnsn_eval_unary(op, symtable); + dmnsn_array_set(ret.children, i, &temp); + } + + dmnsn_delete_array(op.children); + op.children = NULL; + dmnsn_delete_astnode(op); + break; + } + } + } else if (rhs.type == DMNSN_AST_INTEGER) { long n = *(long *)rhs.ptr; long *res = malloc(sizeof(long)); if (!res) dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for integer."); switch(astnode.type) { + case DMNSN_AST_DOT_X: + case DMNSN_AST_DOT_Y: + case DMNSN_AST_DOT_Z: + case DMNSN_AST_DOT_T: + case DMNSN_AST_DOT_TRANSMIT: + *res = n; + case DMNSN_AST_NEGATE: *res = -n; break; @@ -299,6 +408,13 @@ dmnsn_eval_scalar_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for float."); switch(astnode.type) { + case DMNSN_AST_DOT_X: + case DMNSN_AST_DOT_Y: + case DMNSN_AST_DOT_Z: + case DMNSN_AST_DOT_T: + case DMNSN_AST_DOT_TRANSMIT: + *res = n; + case DMNSN_AST_NEGATE: *res = -n; break; @@ -311,8 +427,12 @@ dmnsn_eval_scalar_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) ret.type = DMNSN_AST_FLOAT; ret.ptr = res; } else { - dmnsn_error(DMNSN_SEVERITY_HIGH, - "Invalid right hand side to unary operator."); + dmnsn_diagnostic(rhs.filename, rhs.line, rhs.col, + "expected %s, %s, or %s; found %s", + dmnsn_astnode_string(DMNSN_AST_INTEGER), + dmnsn_astnode_string(DMNSN_AST_FLOAT), + dmnsn_astnode_string(DMNSN_AST_VECTOR)); + ret.type = DMNSN_AST_NONE; } dmnsn_delete_astnode(rhs); @@ -320,16 +440,42 @@ dmnsn_eval_scalar_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) } static dmnsn_astnode -dmnsn_eval_scalar_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { - dmnsn_astnode ret = dmnsn_copy_astnode(astnode), lhs, rhs; + unsigned int i; + + dmnsn_astnode lhs, rhs; dmnsn_array_get(astnode.children, 0, &lhs); dmnsn_array_get(astnode.children, 1, &rhs); - lhs = dmnsn_eval_scalar(lhs, symtable); - rhs = dmnsn_eval_scalar(rhs, symtable); + lhs = dmnsn_eval(lhs, symtable); + rhs = dmnsn_eval(rhs, symtable); + + dmnsn_astnode ret = dmnsn_copy_astnode(astnode); + + if (lhs.type == DMNSN_AST_NONE || rhs.type == DMNSN_AST_NONE) { + ret.type = DMNSN_AST_NONE; + } else if (lhs.type == DMNSN_AST_VECTOR || rhs.type == DMNSN_AST_VECTOR) { + ret.type = DMNSN_AST_VECTOR; + + dmnsn_astnode oldlhs = lhs, oldrhs = rhs; + lhs = dmnsn_vector_promote(lhs, symtable); + rhs = dmnsn_vector_promote(rhs, symtable); + dmnsn_delete_astnode(oldlhs); + dmnsn_delete_astnode(oldrhs); + + dmnsn_astnode op = dmnsn_copy_astnode(astnode); + for (i = 0; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_array_get(lhs.children, i, dmnsn_array_at(op.children, 0)); + dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 1)); + dmnsn_astnode temp = dmnsn_eval_binary(op, symtable); + dmnsn_array_set(ret.children, i, &temp); + } - if (lhs.type == DMNSN_AST_INTEGER && rhs.type == DMNSN_AST_INTEGER - && astnode.type != DMNSN_AST_DIV) { + dmnsn_delete_array(op.children); + op.children = NULL; + dmnsn_delete_astnode(op); + } else if (lhs.type == DMNSN_AST_INTEGER && rhs.type == DMNSN_AST_INTEGER + && astnode.type != DMNSN_AST_DIV) { long l, r; l = *(long *)lhs.ptr; r = *(long *)rhs.ptr; @@ -359,21 +505,37 @@ dmnsn_eval_scalar_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) } else { double l = 0.0, r = 0.0; - if (lhs.type == DMNSN_AST_INTEGER) + if (lhs.type == DMNSN_AST_INTEGER) { l = *(long *)lhs.ptr; - else if (lhs.type == DMNSN_AST_FLOAT) + } else if (lhs.type == DMNSN_AST_FLOAT) { l = *(double *)lhs.ptr; - else - dmnsn_error(DMNSN_SEVERITY_HIGH, - "Invalid left hand side to binary operator."); + } else { + dmnsn_diagnostic(lhs.filename, lhs.line, lhs.col, + "expected %s, %s, or %s; found %s", + dmnsn_astnode_string(DMNSN_AST_INTEGER), + dmnsn_astnode_string(DMNSN_AST_FLOAT), + dmnsn_astnode_string(DMNSN_AST_VECTOR)); + ret.type = DMNSN_AST_NONE; + dmnsn_delete_astnode(lhs); + dmnsn_delete_astnode(rhs); + return ret; + } - if (rhs.type == DMNSN_AST_INTEGER) + if (rhs.type == DMNSN_AST_INTEGER) { r = *(long *)rhs.ptr; - else if (rhs.type == DMNSN_AST_FLOAT) + } else if (rhs.type == DMNSN_AST_FLOAT) { r = *(double *)rhs.ptr; - else - dmnsn_error(DMNSN_SEVERITY_HIGH, - "Invalid right hand side to binary operator."); + } else { + dmnsn_diagnostic(rhs.filename, rhs.line, rhs.col, + "expected %s, %s, or %s; found %s", + dmnsn_astnode_string(DMNSN_AST_INTEGER), + dmnsn_astnode_string(DMNSN_AST_FLOAT), + dmnsn_astnode_string(DMNSN_AST_VECTOR)); + ret.type = DMNSN_AST_NONE; + dmnsn_delete_astnode(lhs); + dmnsn_delete_astnode(rhs); + return ret; + } double *res = malloc(sizeof(double)); if (!res) @@ -401,170 +563,89 @@ dmnsn_eval_scalar_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) ret.type = DMNSN_AST_FLOAT; ret.ptr = res; } - + dmnsn_delete_astnode(lhs); dmnsn_delete_astnode(rhs); return ret; } dmnsn_astnode -dmnsn_eval_scalar(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { - dmnsn_astnode ret; - switch (astnode.type) { + case DMNSN_AST_NONE: case DMNSN_AST_INTEGER: - ret = dmnsn_copy_astnode(astnode); - ret.ptr = malloc(sizeof(long)); - if (!ret.ptr) - dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for integer."); - - memcpy(ret.ptr, astnode.ptr, sizeof(long)); - return ret; - case DMNSN_AST_FLOAT: - ret = dmnsn_copy_astnode(astnode); - ret.ptr = malloc(sizeof(double)); - if (!ret.ptr) - dmnsn_error(DMNSN_SEVERITY_HIGH, "Failed to allocate room for float."); + ++*astnode.refcount; + return astnode; - memcpy(ret.ptr, astnode.ptr, sizeof(double)); - return ret; + case DMNSN_AST_VECTOR: + return dmnsn_vector_promote(astnode, symtable); + + case DMNSN_AST_IDENTIFIER: + { + dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, astnode.ptr); + if (symbol) { + return dmnsn_eval(*symbol, symtable); + } else { + dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col, + "unbound identifier '%s'", astnode.ptr); + dmnsn_astnode error = dmnsn_new_astnode(DMNSN_AST_NONE); + ++*error.refcount; + return error; + } + } + case DMNSN_AST_DOT_X: + case DMNSN_AST_DOT_Y: + case DMNSN_AST_DOT_Z: + case DMNSN_AST_DOT_T: + case DMNSN_AST_DOT_TRANSMIT: case DMNSN_AST_NEGATE: - return dmnsn_eval_scalar_unary(astnode, symtable); + return dmnsn_eval_unary(astnode, symtable); case DMNSN_AST_ADD: case DMNSN_AST_SUB: case DMNSN_AST_MUL: case DMNSN_AST_DIV: - return dmnsn_eval_scalar_binary(astnode, symtable); + return dmnsn_eval_binary(astnode, symtable); default: - dmnsn_error(DMNSN_SEVERITY_HIGH, - "Given non-arithmetic-expression to evaluate."); - return astnode; /* Silence warning */ - } -} - -#define DMNSN_VECTOR_NELEM 5 - -static dmnsn_astnode -dmnsn_vector_promote(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - dmnsn_astnode promoted = dmnsn_copy_astnode(astnode), component; - promoted.type = DMNSN_AST_VECTOR; - - if (astnode.type == DMNSN_AST_VECTOR) { - unsigned int i; - for (i = 0; i < dmnsn_array_size(astnode.children); ++i) { - dmnsn_array_get(astnode.children, i, &component); - component = dmnsn_eval_scalar(component, symtable); - dmnsn_array_push(promoted.children, &component); - } - - while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { - component = dmnsn_copy_astnode(component); - component.type = DMNSN_AST_INTEGER; - - long *val = malloc(sizeof(long)); - *val = 0; - - component.ptr = val; - dmnsn_array_push(promoted.children, &component); - } - } else { - component = dmnsn_eval_scalar(astnode, symtable); - dmnsn_array_push(promoted.children, &component); - - while (dmnsn_array_size(promoted.children) < DMNSN_VECTOR_NELEM) { - component = dmnsn_eval_scalar(component, symtable); - dmnsn_array_push(promoted.children, &component); - } - } - - return promoted; -} - -static dmnsn_astnode -dmnsn_eval_vector_unary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) -{ - unsigned int i; - - dmnsn_astnode rhs; - dmnsn_array_get(astnode.children, 0, &rhs); - rhs = dmnsn_eval_vector(rhs, symtable); - - dmnsn_astnode ret = dmnsn_copy_astnode(astnode), temp; - ret.type = DMNSN_AST_VECTOR; - - dmnsn_astnode op = dmnsn_copy_astnode(astnode); - for (i = 0; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 0)); - temp = dmnsn_eval_scalar_unary(op, symtable); - dmnsn_array_set(ret.children, i, &temp); + dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col, + "expected arithmetic expression; found %s", + dmnsn_astnode_string(astnode.type)); + dmnsn_astnode error = dmnsn_new_astnode(DMNSN_AST_NONE); + ++*error.refcount; + return error; } - dmnsn_delete_array(op.children); - op.children = NULL; - dmnsn_delete_astnode(op); - dmnsn_delete_astnode(rhs); - return ret; + return astnode; } -static dmnsn_astnode -dmnsn_eval_vector_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) +dmnsn_astnode +dmnsn_eval_scalar(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { - unsigned int i; - - dmnsn_astnode lhs, rhs; - dmnsn_array_get(astnode.children, 0, &lhs); - dmnsn_array_get(astnode.children, 1, &rhs); - lhs = dmnsn_eval_vector(lhs, symtable); - rhs = dmnsn_eval_vector(rhs, symtable); - - dmnsn_astnode ret = dmnsn_copy_astnode(astnode), temp; - ret.type = DMNSN_AST_VECTOR; - - dmnsn_astnode op = dmnsn_copy_astnode(astnode); - for (i = 0; i < DMNSN_VECTOR_NELEM; ++i) { - dmnsn_array_get(lhs.children, i, dmnsn_array_at(op.children, 0)); - dmnsn_array_get(rhs.children, i, dmnsn_array_at(op.children, 1)); - temp = dmnsn_eval_scalar_binary(op, symtable); - dmnsn_array_set(ret.children, i, &temp); + dmnsn_astnode ret = dmnsn_eval(astnode, symtable); + if (ret.type == DMNSN_AST_VECTOR) { + dmnsn_diagnostic(ret.filename, ret.line, ret.col, + "expected %s or %s; found %s", + dmnsn_astnode_string(DMNSN_AST_INTEGER), + dmnsn_astnode_string(DMNSN_AST_FLOAT), + dmnsn_astnode_string(ret.type)); + dmnsn_delete_astnode(ret); + ret = dmnsn_new_astnode(DMNSN_AST_NONE); } - - dmnsn_delete_array(op.children); - op.children = NULL; - dmnsn_delete_astnode(op); - dmnsn_delete_astnode(lhs); - dmnsn_delete_astnode(rhs); return ret; } dmnsn_astnode dmnsn_eval_vector(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) { - switch (astnode.type) { - case DMNSN_AST_INTEGER: - case DMNSN_AST_FLOAT: - case DMNSN_AST_VECTOR: - return dmnsn_vector_promote(astnode, symtable); + dmnsn_astnode eval = dmnsn_eval(astnode, symtable); + dmnsn_astnode ret = dmnsn_vector_promote(eval, symtable); - case DMNSN_AST_NEGATE: - return dmnsn_eval_vector_unary(astnode, symtable); - - case DMNSN_AST_ADD: - case DMNSN_AST_SUB: - case DMNSN_AST_MUL: - case DMNSN_AST_DIV: - return dmnsn_eval_vector_binary(astnode, symtable); - - default: - dmnsn_error(DMNSN_SEVERITY_HIGH, - "Given non-arithmetic-expression to evaluate."); - return astnode; /* Silence warning */ - } + dmnsn_delete_astnode(eval); + return ret; } static void diff --git a/dimension/parse.h b/dimension/parse.h index 6f5b981..e4772e1 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -60,12 +60,20 @@ typedef enum { DMNSN_AST_VECTOR, - DMNSN_AST_NEGATE, DMNSN_AST_ADD, DMNSN_AST_SUB, DMNSN_AST_MUL, DMNSN_AST_DIV, + DMNSN_AST_NEGATE, + DMNSN_AST_DOT_X, + DMNSN_AST_DOT_Y, + DMNSN_AST_DOT_Z, + DMNSN_AST_DOT_T, + DMNSN_AST_DOT_TRANSMIT, + + DMNSN_AST_IDENTIFIER, + DMNSN_AST_STRING, } dmnsn_astnode_type; @@ -124,6 +132,7 @@ void dmnsn_undef_symbol(dmnsn_symbol_table *symtable, const char *id); dmnsn_astnode *dmnsn_find_symbol(dmnsn_symbol_table *symtable, const char *id); /* Evaluate an arithmetic expression */ +dmnsn_astnode dmnsn_eval(dmnsn_astnode astnode, dmnsn_symbol_table *symtable); dmnsn_astnode dmnsn_eval_scalar(dmnsn_astnode astnode, dmnsn_symbol_table *symtable); dmnsn_astnode dmnsn_eval_vector(dmnsn_astnode astnode, diff --git a/tests/dimension/directives.pov b/tests/dimension/directives.pov index 6907450..6b0e72c 100644 --- a/tests/dimension/directives.pov +++ b/tests/dimension/directives.pov @@ -19,6 +19,16 @@ // Test the language directives -#include "punctuation.pov" +#declare Center = 0; +#declare R = 1; +#local Color = rgb <1, 0, 1>; -#declare id +#declare Unused = -1; +#undef Unused + +sphere { + Center, R + pigment { + color Color + } +} diff --git a/tests/dimension/directives.sh b/tests/dimension/directives.sh index 75c2452..c64cbd8 100755 --- a/tests/dimension/directives.sh +++ b/tests/dimension/directives.sh @@ -19,11 +19,32 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # ######################################################################### -directives=$(${top_builddir}/dimension/dimension --tokenize ${srcdir}/directives.pov) -directives_exp='(#include (string "punctuation.pov") #declare (identifier "id"))'; +directives=$(${top_builddir}/dimension/dimension --tokenize --parse ${srcdir}/directives.pov) +directives_exp="$(echo -n \ +'(#declare (identifier "Center") = (integer "0") ; + #declare (identifier "R") = (integer "1") ; + #local (identifier "Color") = rgb < (integer "1") , (integer "0") , (integer "1") > ; + #declare (identifier "Unused") = - (integer "1") ; + #undef (identifier "Unused") + sphere { + (identifier "Center") , (identifier "R") + pigment { + color (identifier "Color") + } + })' \ +| tr '\n' ' ' | sed -r 's/[[:space:]]+/ /g') +$(echo -n \ +'((sphere + (vector (integer 0) (integer 0) (integer 0) (integer 0) (integer 0)) + (integer 1) + (object-modifiers + (texture + (pigment (vector (integer 1) (integer 0) (integer 1) + (integer 0) (integer 0)))))))' \ +| tr '\n' ' ' | sed -r 's/[[:space:]]+/ /g')" if [ "$directives" != "$directives_exp" ]; then - echo "directives.pov tokenized as \"$directives\"" >&2 - echo " -- expected \"$directives_exp\"" >&2 + echo "directives.pov parsed as \"$directives\"" >&2 + echo " -- expected \"$directives_exp\"" >&2 exit 1 fi |