summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dimension/grammar.y269
-rw-r--r--dimension/lexer.l4
-rw-r--r--dimension/parse.c395
-rw-r--r--dimension/parse.h11
-rw-r--r--tests/dimension/directives.pov14
-rwxr-xr-xtests/dimension/directives.sh29
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