summaryrefslogtreecommitdiffstats
path: root/dimension
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-02-02 12:03:26 -0500
committerTavian Barnes <tavianator@gmail.com>2010-02-02 12:03:26 -0500
commit3da1fe6d2fb07f3f361482d8056e36636dcec3f5 (patch)
tree54ee1eaf680f7a97820f4a150f7d9679f3345d8b /dimension
parentc1f6c955de83cf35fb34cc1fcf9a276bf6dbd7c8 (diff)
downloaddimension-3da1fe6d2fb07f3f361482d8056e36636dcec3f5.tar.xz
Implement #if.
Diffstat (limited to 'dimension')
-rw-r--r--dimension/common.terminals9
-rw-r--r--dimension/directives.declarations2
-rw-r--r--dimension/directives.nonterminals2
-rw-r--r--dimension/directives.rules51
-rw-r--r--dimension/grammar.epilogue9
-rw-r--r--dimension/lexer.l3
-rw-r--r--dimension/parse.c192
-rw-r--r--dimension/parse.h11
-rw-r--r--dimension/tokenize.c161
9 files changed, 414 insertions, 26 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;
}