diff options
author | Tavian Barnes <tavianator@gmail.com> | 2010-02-02 12:03:26 -0500 |
---|---|---|
committer | Tavian Barnes <tavianator@gmail.com> | 2010-02-02 12:03:26 -0500 |
commit | 3da1fe6d2fb07f3f361482d8056e36636dcec3f5 (patch) | |
tree | 54ee1eaf680f7a97820f4a150f7d9679f3345d8b | |
parent | c1f6c955de83cf35fb34cc1fcf9a276bf6dbd7c8 (diff) | |
download | dimension-3da1fe6d2fb07f3f361482d8056e36636dcec3f5.tar.xz |
Implement #if.
-rw-r--r-- | dimension/common.terminals | 9 | ||||
-rw-r--r-- | dimension/directives.declarations | 2 | ||||
-rw-r--r-- | dimension/directives.nonterminals | 2 | ||||
-rw-r--r-- | dimension/directives.rules | 51 | ||||
-rw-r--r-- | dimension/grammar.epilogue | 9 | ||||
-rw-r--r-- | dimension/lexer.l | 3 | ||||
-rw-r--r-- | dimension/parse.c | 192 | ||||
-rw-r--r-- | dimension/parse.h | 11 | ||||
-rw-r--r-- | dimension/tokenize.c | 161 | ||||
-rw-r--r-- | tests/dimension/directives.pov | 14 | ||||
-rwxr-xr-x | tests/dimension/directives.sh | 14 |
11 files changed, 432 insertions, 36 deletions
diff --git a/dimension/common.terminals b/dimension/common.terminals index 37d3c16..ae5ebdf 100644 --- a/dimension/common.terminals +++ b/dimension/common.terminals @@ -47,6 +47,9 @@ %token DMNSN_T_NOT_EQUAL "!=" /* Operators */ +%left "|" +%left "&" +%left "=" "!=" "<" "<=" ">" ">=" %left "+" "-" %left "*" "/" %left "." @@ -491,12 +494,12 @@ %token DMNSN_T_DEBUG %token DMNSN_T_DECLARE "#declare" %token DMNSN_T_DEFAULT -%token DMNSN_T_ELSE -%token DMNSN_T_END +%token DMNSN_T_ELSE "#else" +%token DMNSN_T_END "#end" %token DMNSN_T_ERROR %token DMNSN_T_FCLOSE %token DMNSN_T_FOPEN -%token DMNSN_T_IF +%token DMNSN_T_IF "#if" %token DMNSN_T_IFDEF %token DMNSN_T_IFNDEF %token DMNSN_T_INCLUDE "#include" diff --git a/dimension/directives.declarations b/dimension/directives.declarations index 0543b3d..3c4da86 100644 --- a/dimension/directives.declarations +++ b/dimension/directives.declarations @@ -19,7 +19,7 @@ %name-prefix "dmnsn_ld_yy" -%expect 9 +%expect 10 %parse-param {const char *filename} %parse-param {void *yyscanner} diff --git a/dimension/directives.nonterminals b/dimension/directives.nonterminals index ac23a0a..702ea47 100644 --- a/dimension/directives.nonterminals +++ b/dimension/directives.nonterminals @@ -18,3 +18,5 @@ *************************************************************************/ %type <astnode> RVALUE + +%type <astnode> CONDITIONAL diff --git a/dimension/directives.rules b/dimension/directives.rules index 916039b..db47bb9 100644 --- a/dimension/directives.rules +++ b/dimension/directives.rules @@ -16,6 +16,18 @@ LANGUAGE_DIRECTIVE: "#declare" "identifier" "=" RVALUE { dmnsn_undef_symbol(symtable, $2); free($2); } + | "#if" "(" CONDITIONAL ")" { + dmnsn_astnode cond = dmnsn_eval($3, symtable); + dmnsn_delete_astnode($3); + + if (cond.type == DMNSN_AST_NONE) { + dmnsn_delete_astnode(cond); + YYERROR; + } + + dmnsn_local_symbol(symtable, "__cond__", cond); + dmnsn_delete_astnode(cond); + } RVALUE: ARITH_EXPR ";" %dprec 2 { $$ = dmnsn_eval($1, symtable); @@ -33,3 +45,42 @@ RVALUE: ARITH_EXPR ";" %dprec 2 { | FINISH | CAMERA | TRANSFORMATION + +CONDITIONAL: ARITH_EXPR { + /* Force the expression to be evaluated logically */ + dmnsn_astnode zero = dmnsn_new_astnode(DMNSN_AST_INTEGER, @$); + zero.ptr = malloc(sizeof(long)); + if (!zero.ptr) + dmnsn_error(DMNSN_SEVERITY_HIGH, + "Failed to allocate room for integer."); + *(long *)zero.ptr = 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; + } diff --git a/dimension/grammar.epilogue b/dimension/grammar.epilogue index b62165e..c9e16f3 100644 --- a/dimension/grammar.epilogue +++ b/dimension/grammar.epilogue @@ -128,6 +128,15 @@ dmnsn_astnode_string(dmnsn_astnode_type astnode_type) dmnsn_astnode_map(DMNSN_AST_MUL, "*"); dmnsn_astnode_map(DMNSN_AST_DIV, "/"); + dmnsn_astnode_map(DMNSN_AST_EQUAL, "=" ); + dmnsn_astnode_map(DMNSN_AST_NOT_EQUAL, "!="); + dmnsn_astnode_map(DMNSN_AST_LESS, "<" ); + dmnsn_astnode_map(DMNSN_AST_LESS_EQUAL, "<="); + dmnsn_astnode_map(DMNSN_AST_GREATER, ">" ); + dmnsn_astnode_map(DMNSN_AST_GREATER_EQUAL, ">="); + dmnsn_astnode_map(DMNSN_AST_AND, "&" ); + dmnsn_astnode_map(DMNSN_AST_OR, "|" ); + dmnsn_astnode_map(DMNSN_AST_NEGATE, "-"); dmnsn_astnode_map(DMNSN_AST_DOT_X, ".x"); dmnsn_astnode_map(DMNSN_AST_DOT_Y, ".y"); diff --git a/dimension/lexer.l b/dimension/lexer.l index 9510bcf..cd02da1 100644 --- a/dimension/lexer.l +++ b/dimension/lexer.l @@ -208,6 +208,9 @@ unsigned long wchar; (?# Directives) "#declare" RETURN_TOKEN(DMNSN_T_DECLARE); +"#else" RETURN_TOKEN(DMNSN_T_ELSE); +"#end" RETURN_TOKEN(DMNSN_T_END); +"#if" RETURN_TOKEN(DMNSN_T_IF); "#include" RETURN_TOKEN(DMNSN_T_INCLUDE); "#local" RETURN_TOKEN(DMNSN_T_LOCAL); "#undef" RETURN_TOKEN(DMNSN_T_UNDEF); diff --git a/dimension/parse.c b/dimension/parse.c index 9357ef3..6ff5628 100644 --- a/dimension/parse.c +++ b/dimension/parse.c @@ -268,6 +268,7 @@ dmnsn_copy_astnode(dmnsn_astnode astnode) return copy; } +/* 5-element vectors */ #define DMNSN_VECTOR_NELEM 5 static dmnsn_astnode @@ -455,32 +456,189 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) lhs = dmnsn_eval(lhs, symtable); rhs = dmnsn_eval(rhs, symtable); - dmnsn_astnode ret = dmnsn_copy_astnode(astnode); + dmnsn_astnode ret; if (lhs.type == DMNSN_AST_NONE || rhs.type == DMNSN_AST_NONE) { + ret = dmnsn_copy_astnode(astnode); 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); - } + switch (astnode.type) { + case DMNSN_AST_EQUAL: + { + dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); + + dmnsn_astnode l, r; + dmnsn_array_get(lhs.children, 0, &l); + dmnsn_array_get(rhs.children, 0, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(rewrite.children, &l); + dmnsn_array_push(rewrite.children, &r); + + for (i = 1; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_astnode temp = dmnsn_copy_astnode(astnode); + dmnsn_array_get(lhs.children, i, &l); + dmnsn_array_get(rhs.children, i, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(temp.children, &l); + dmnsn_array_push(temp.children, &r); + + dmnsn_astnode next = dmnsn_copy_astnode(astnode); + next.type = DMNSN_AST_AND; + dmnsn_array_push(next.children, &rewrite); + dmnsn_array_push(next.children, &temp); + rewrite = next; + } + + ret = dmnsn_eval_binary(rewrite, symtable); + dmnsn_delete_astnode(rewrite); + break; + } + + case DMNSN_AST_NOT_EQUAL: + { + dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); + + dmnsn_astnode l, r; + dmnsn_array_get(lhs.children, 0, &l); + dmnsn_array_get(rhs.children, 0, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(rewrite.children, &l); + dmnsn_array_push(rewrite.children, &r); + + for (i = 1; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_astnode temp = dmnsn_copy_astnode(astnode); + dmnsn_array_get(lhs.children, i, &l); + dmnsn_array_get(rhs.children, i, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(temp.children, &l); + dmnsn_array_push(temp.children, &r); + + dmnsn_astnode next = dmnsn_copy_astnode(astnode); + next.type = DMNSN_AST_OR; + dmnsn_array_push(next.children, &rewrite); + dmnsn_array_push(next.children, &temp); + rewrite = next; + } - dmnsn_delete_array(op.children); - op.children = NULL; - dmnsn_delete_astnode(op); + ret = dmnsn_eval_binary(rewrite, symtable); + dmnsn_delete_astnode(rewrite); + break; + } + + case DMNSN_AST_AND: + { + dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); + rewrite.type = DMNSN_AST_OR; + + dmnsn_astnode l, r; + dmnsn_array_get(lhs.children, 0, &l); + dmnsn_array_get(rhs.children, 0, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(rewrite.children, &l); + dmnsn_array_push(rewrite.children, &r); + + for (i = 1; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_astnode temp = dmnsn_copy_astnode(astnode); + temp.type = DMNSN_AST_OR; + dmnsn_array_get(lhs.children, i, &l); + dmnsn_array_get(rhs.children, i, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(temp.children, &l); + dmnsn_array_push(temp.children, &r); + + dmnsn_astnode next = dmnsn_copy_astnode(astnode); + next.type = DMNSN_AST_AND; + dmnsn_array_push(next.children, &rewrite); + dmnsn_array_push(next.children, &temp); + rewrite = next; + } + + ret = dmnsn_eval_binary(rewrite, symtable); + dmnsn_delete_astnode(rewrite); + break; + } + + case DMNSN_AST_OR: + { + dmnsn_astnode rewrite = dmnsn_copy_astnode(astnode); + rewrite.type = DMNSN_AST_OR; + + dmnsn_astnode l, r; + dmnsn_array_get(lhs.children, 0, &l); + dmnsn_array_get(rhs.children, 0, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(rewrite.children, &l); + dmnsn_array_push(rewrite.children, &r); + + for (i = 1; i < DMNSN_VECTOR_NELEM; ++i) { + dmnsn_astnode temp = dmnsn_copy_astnode(astnode); + temp.type = DMNSN_AST_OR; + dmnsn_array_get(lhs.children, i, &l); + dmnsn_array_get(rhs.children, i, &r); + ++*l.refcount; + ++*r.refcount; + dmnsn_array_push(temp.children, &l); + dmnsn_array_push(temp.children, &r); + + dmnsn_astnode next = dmnsn_copy_astnode(astnode); + next.type = DMNSN_AST_OR; + dmnsn_array_push(next.children, &rewrite); + dmnsn_array_push(next.children, &temp); + rewrite = next; + } + + ret = dmnsn_eval_binary(rewrite, symtable); + dmnsn_delete_astnode(rewrite); + break; + } + + case DMNSN_AST_LESS: + case DMNSN_AST_LESS_EQUAL: + case DMNSN_AST_GREATER: + case DMNSN_AST_GREATER_EQUAL: + dmnsn_diagnostic(astnode.filename, astnode.line, astnode.col, + "invalid comparison operator '%s' between vectors", + dmnsn_astnode_string(astnode.type)); + ret = dmnsn_copy_astnode(astnode); + ret.type = DMNSN_AST_NONE; + break; + + default: + { + ret = dmnsn_copy_astnode(astnode); + 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)); + dmnsn_astnode temp = dmnsn_eval_binary(op, symtable); + dmnsn_array_set(ret.children, i, &temp); + } + + dmnsn_delete_array(op.children); + op.children = NULL; + dmnsn_delete_astnode(op); + break; + } + } } else if (lhs.type == DMNSN_AST_INTEGER && rhs.type == DMNSN_AST_INTEGER && astnode.type != DMNSN_AST_DIV) { + ret = dmnsn_copy_astnode(astnode); + long l, r; l = *(long *)lhs.ptr; r = *(long *)rhs.ptr; @@ -532,6 +690,8 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) ret.type = DMNSN_AST_INTEGER; ret.ptr = res; } else { + ret = dmnsn_copy_astnode(astnode); + double l = 0.0, r = 0.0; if (lhs.type == DMNSN_AST_INTEGER) { @@ -543,7 +703,8 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) "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)); + dmnsn_astnode_string(DMNSN_AST_VECTOR), + dmnsn_astnode_string(lhs.type)); ret.type = DMNSN_AST_NONE; dmnsn_delete_astnode(lhs); dmnsn_delete_astnode(rhs); @@ -559,7 +720,8 @@ dmnsn_eval_binary(dmnsn_astnode astnode, dmnsn_symbol_table *symtable) "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)); + dmnsn_astnode_string(DMNSN_AST_VECTOR), + dmnsn_astnode_string(rhs.type)); ret.type = DMNSN_AST_NONE; dmnsn_delete_astnode(lhs); dmnsn_delete_astnode(rhs); diff --git a/dimension/parse.h b/dimension/parse.h index bbc52e7..28997af 100644 --- a/dimension/parse.h +++ b/dimension/parse.h @@ -83,11 +83,20 @@ 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_COLOR, DMNSN_AST_IDENTIFIER, - DMNSN_AST_STRING, + DMNSN_AST_STRING } dmnsn_astnode_type; /* Abstract syntax tree node (a dmnsn_array* of these is an AST) */ diff --git a/dimension/tokenize.c b/dimension/tokenize.c index 5fce280..8e696ed 100644 --- a/dimension/tokenize.c +++ b/dimension/tokenize.c @@ -20,6 +20,7 @@ #include "tokenize.h" #include "directives.h" #include "utility.h" +#include <stdbool.h> typedef struct dmnsn_buffered_token { int type; @@ -39,7 +40,7 @@ typedef struct dmnsn_token_buffer { } dmnsn_token_buffer; static dmnsn_token_buffer * -dmnsn_new_token_buffer(int type) +dmnsn_new_token_buffer(int type, dmnsn_token_buffer *prev) { dmnsn_token_buffer *tbuffer = malloc(sizeof(dmnsn_token_buffer)); if (!tbuffer) { @@ -49,7 +50,7 @@ dmnsn_new_token_buffer(int type) tbuffer->type = type; tbuffer->buffered = dmnsn_new_array(sizeof(dmnsn_buffered_token)); tbuffer->i = 0; - tbuffer->prev = NULL; + tbuffer->prev = prev; return tbuffer; } @@ -73,8 +74,8 @@ dmnsn_declaration_buffer(int token, dmnsn_token_buffer *prev, const char *filename, dmnsn_symbol_table *symtable, void *yyscanner) { - dmnsn_token_buffer *tbuffer = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM); - tbuffer->prev = prev; + dmnsn_token_buffer *tbuffer + = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM, prev); /* Buffer the current token */ dmnsn_buffered_token buffered = { @@ -133,8 +134,8 @@ dmnsn_undef_buffer(int token, dmnsn_token_buffer *prev, const char *filename, dmnsn_symbol_table *symtable, void *yyscanner) { - dmnsn_token_buffer *tbuffer = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM); - tbuffer->prev = prev; + dmnsn_token_buffer *tbuffer + = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM, prev); /* Buffer the current token */ dmnsn_buffered_token buffered = { @@ -168,6 +169,140 @@ dmnsn_undef_buffer(int token, dmnsn_token_buffer *prev, return tbuffer; } +static dmnsn_token_buffer * +dmnsn_if_buffer(int token, dmnsn_token_buffer *prev, + dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, + const char *filename, dmnsn_symbol_table *symtable, + void *yyscanner) +{ + dmnsn_token_buffer *cond_buffer + = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM, prev); + + /* Buffer the current token */ + dmnsn_buffered_token buffered = { + .type = token, + .lval = *lvalp, + .lloc = *llocp + }; + dmnsn_array_push(cond_buffer->buffered, &buffered); + + /* Grab all the tokens belonging to the #if (...) */ + int parenlevel = -1; + while (1) { + /* Recursive call - permit other directives inside the condition */ + buffered.type = dmnsn_yylex(&buffered.lval, &buffered.lloc, + filename, symtable, yyscanner); + + if (buffered.type == DMNSN_T_EOF) { + dmnsn_diagnostic(filename, buffered.lloc.first_line, + buffered.lloc.first_column, + "syntax error, unexpected end-of-file"); + dmnsn_delete_token_buffer(cond_buffer); + return NULL; + } else if (buffered.type == DMNSN_T_LEX_ERROR) { + dmnsn_delete_token_buffer(cond_buffer); + return NULL; + } + + dmnsn_array_push(cond_buffer->buffered, &buffered); + + if (buffered.type == DMNSN_T_LPAREN) { + if (parenlevel < 0) + parenlevel = 1; + else + ++parenlevel; + } else if (buffered.type == DMNSN_T_RPAREN) { + --parenlevel; + if (parenlevel == 0) { + break; + } + } + } + + /* Fake EOF */ + buffered.type = DMNSN_T_EOF; + dmnsn_array_push(cond_buffer->buffered, &buffered); + + dmnsn_yyset_extra(cond_buffer, yyscanner); + if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) { + dmnsn_yyset_extra(cond_buffer->prev, yyscanner); + dmnsn_delete_token_buffer(cond_buffer); + return NULL; + } + + dmnsn_yyset_extra(cond_buffer->prev, yyscanner); + dmnsn_delete_token_buffer(cond_buffer); + + dmnsn_token_buffer *tbuffer= dmnsn_new_token_buffer(DMNSN_T_IF, prev); + + dmnsn_astnode *cnode = dmnsn_find_symbol(symtable, "__cond__"); + if (!cnode) { + dmnsn_error(DMNSN_SEVERITY_HIGH, "__cond__ unset."); + } + + bool cond = false; + if (cnode->type == DMNSN_AST_INTEGER) { + cond = (*(long *)cnode->ptr) ? true : false; + } else if (cnode->type == DMNSN_AST_FLOAT) { + cond = (*(double *)cnode->ptr) ? true : false; + } else { + dmnsn_error(DMNSN_SEVERITY_HIGH, "__cond__ has wrong type."); + } + + dmnsn_undef_symbol(symtable, "__cond__"); + + int nesting = 1; + while (1) { + /* Non-recursive call */ + buffered.type = dmnsn_yylex_impl(&buffered.lval, &buffered.lloc, + filename, yyscanner); + + if (buffered.type == DMNSN_T_EOF) { + dmnsn_diagnostic(filename, buffered.lloc.first_line, + buffered.lloc.first_column, + "syntax error, unexpected end-of-file"); + dmnsn_delete_token_buffer(tbuffer); + return NULL; + } else if (buffered.type == DMNSN_T_LEX_ERROR) { + dmnsn_delete_token_buffer(tbuffer); + return NULL; + } + + switch (buffered.type) { + case DMNSN_T_IF: + case DMNSN_T_IFDEF: + case DMNSN_T_IFNDEF: + case DMNSN_T_MACRO: + case DMNSN_T_SWITCH: + case DMNSN_T_WHILE: + ++nesting; + break; + + case DMNSN_T_END: + --nesting; + break; + + default: + break; + } + + if (nesting == 0) { + break; + } else if (nesting == 1 && buffered.type == DMNSN_T_ELSE) { + cond = !cond; + continue; + } + + if (cond) { + dmnsn_array_push(tbuffer->buffered, &buffered); + } else { + free(buffered.lval.value); + } + } + + return tbuffer; +} + int dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, const char *filename, dmnsn_symbol_table *symtable, void *yyscanner) @@ -260,6 +395,20 @@ dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp, break; } + case DMNSN_T_IF: + { + dmnsn_token_buffer *tb = dmnsn_if_buffer( + token, tbuffer, lvalp, llocp, filename, symtable, yyscanner + ); + if (!tb) { + return DMNSN_T_LEX_ERROR; + } + + dmnsn_yyset_extra(tb, yyscanner); + tbuffer = tb; + continue; + } + default: return token; } diff --git a/tests/dimension/directives.pov b/tests/dimension/directives.pov index 95ad88a..1bb712d 100644 --- a/tests/dimension/directives.pov +++ b/tests/dimension/directives.pov @@ -26,9 +26,13 @@ #declare Unused = -1; #undef Unused -sphere { - Center, R - pigment { - color Color green 1 +#if (#if (1 = 1) 0 #end = 0 & 0) + Illegal +#else + sphere { + Center, R + pigment { + color Color green 1 + } } -} +#end diff --git a/tests/dimension/directives.sh b/tests/dimension/directives.sh index b2c9e9e..955ea15 100755 --- a/tests/dimension/directives.sh +++ b/tests/dimension/directives.sh @@ -26,12 +26,16 @@ directives_exp="$(echo -n \ #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") green (integer "1") + #if \( #if \( (integer "1") = (integer "1") \) (integer "0") #end = (integer "0") & (integer "0") \) + (identifier "Illegal") + #else + sphere { + (identifier "Center") , (identifier "R") + pigment { + color (identifier "Color") green (integer "1") + } } - })' \ + #end)' \ | tr '\n' ' ' | sed -r 's/[[:space:]]+/ /g') $(echo -n \ '((sphere |