summaryrefslogtreecommitdiffstats
path: root/dimension/tokenize.c
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@gmail.com>2010-03-23 17:35:53 -0400
committerTavian Barnes <tavianator@gmail.com>2010-03-23 17:48:37 -0400
commite51389d68ef2e152054d987d7a99930bce180954 (patch)
tree78a59584f7e640e0d077a5d887305e3b5fdba060 /dimension/tokenize.c
parent1d441aea4446484342f93fbf315f7f70de8adaf7 (diff)
downloaddimension-e51389d68ef2e152054d987d7a99930bce180954.tar.xz
Implement macro support.
Diffstat (limited to 'dimension/tokenize.c')
-rw-r--r--dimension/tokenize.c180
1 files changed, 178 insertions, 2 deletions
diff --git a/dimension/tokenize.c b/dimension/tokenize.c
index 2bead0b..fb50cd6 100644
--- a/dimension/tokenize.c
+++ b/dimension/tokenize.c
@@ -62,8 +62,9 @@ dmnsn_new_token_buffer(int type, dmnsn_token_buffer *prev, const char *filename)
}
static void
-dmnsn_delete_token_buffer(dmnsn_token_buffer *tbuffer)
+dmnsn_delete_token_buffer(void *ptr)
{
+ dmnsn_token_buffer *tbuffer = ptr;
if (tbuffer) {
unsigned int i;
for (i = 0; i < dmnsn_array_size(tbuffer->buffered); ++i) {
@@ -636,6 +637,148 @@ dmnsn_stream_buffer(int token, dmnsn_token_buffer *prev,
return tbuffer;
}
+static bool
+dmnsn_declare_macro(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 *decl_buffer
+ = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM, prev, filename);
+
+ /* Buffer the current token */
+ dmnsn_buffered_token buffered = {
+ .type = token,
+ .lval = *lvalp,
+ .lloc = *llocp
+ };
+ dmnsn_array_push(decl_buffer->buffered, &buffered);
+
+ /* Grab all the tokens belonging to the #macro ID (...) */
+ if (dmnsn_buffer_balanced(decl_buffer, true, DMNSN_T_LPAREN, DMNSN_T_RPAREN,
+ filename, symtable, yyscanner)
+ != 0)
+ {
+ dmnsn_delete_token_buffer(decl_buffer);
+ return false;
+ }
+
+ /* Fake EOF */
+ buffered.type = DMNSN_T_EOF;
+ buffered.lval.value = NULL;
+ dmnsn_array_push(decl_buffer->buffered, &buffered);
+
+ dmnsn_yyset_extra(decl_buffer, yyscanner);
+ if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) {
+ dmnsn_yyset_extra(decl_buffer->prev, yyscanner);
+ dmnsn_delete_token_buffer(decl_buffer);
+ return false;
+ }
+
+ dmnsn_yyset_extra(decl_buffer->prev, yyscanner);
+ dmnsn_delete_token_buffer(decl_buffer);
+
+ dmnsn_token_buffer *tbuffer = dmnsn_new_token_buffer(token, NULL, filename);
+
+ dmnsn_astnode *mname = dmnsn_find_symbol(symtable, "__macro__");
+ dmnsn_assert(mname, "__macro__ unset.");
+ dmnsn_assert(mname->type == DMNSN_AST_STRING, "__macro__ has wrong type.");
+ dmnsn_astnode *mnode = dmnsn_find_symbol(symtable, mname->ptr);
+ dmnsn_assert(mnode, "#macro unset.");
+ dmnsn_assert(mnode->type == DMNSN_AST_MACRO, "#macro has wrong type.");
+ dmnsn_undef_symbol(symtable, "__macro__");
+
+ int nesting = 1;
+ while (1) {
+ /* Non-recursive call */
+ buffered.type = dmnsn_yylex_wrapper(&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(tbuffer);
+ return false;
+ }
+
+ 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;
+
+ dmnsn_array_push(tbuffer->buffered, &buffered);
+ }
+
+ mnode->ptr = tbuffer;
+ mnode->free_fn = &dmnsn_delete_token_buffer;
+ return true;
+}
+
+static dmnsn_token_buffer *
+dmnsn_macro_buffer(int token, dmnsn_astnode *mnode, dmnsn_token_buffer *prev,
+ dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
+ const char *filename, dmnsn_symbol_table *symtable,
+ void *yyscanner)
+{
+ dmnsn_token_buffer *invoke_buffer
+ = dmnsn_new_token_buffer(DMNSN_T_LEX_VERBATIM, prev, filename);
+
+ /* Buffer the current token */
+ dmnsn_buffered_token buffered = {
+ .type = token,
+ .lval = *lvalp,
+ .lloc = *llocp
+ };
+ dmnsn_array_push(invoke_buffer->buffered, &buffered);
+
+ /* Grab all the tokens belonging to the #macro ID (...) */
+ if (dmnsn_buffer_balanced(invoke_buffer, true, DMNSN_T_LPAREN, DMNSN_T_RPAREN,
+ filename, symtable, yyscanner)
+ != 0)
+ {
+ dmnsn_delete_token_buffer(invoke_buffer);
+ return NULL;
+ }
+
+ /* Fake EOF */
+ buffered.type = DMNSN_T_EOF;
+ buffered.lval.value = NULL;
+ dmnsn_array_push(invoke_buffer->buffered, &buffered);
+
+ dmnsn_yyset_extra(invoke_buffer, yyscanner);
+ dmnsn_push_scope(symtable);
+ if (dmnsn_ld_yyparse(filename, yyscanner, symtable) != 0) {
+ dmnsn_yyset_extra(invoke_buffer->prev, yyscanner);
+ dmnsn_delete_token_buffer(invoke_buffer);
+ return NULL;
+ }
+
+ dmnsn_yyset_extra(invoke_buffer->prev, yyscanner);
+ dmnsn_delete_token_buffer(invoke_buffer);
+
+ dmnsn_token_buffer *tbuffer = mnode->ptr;
+ tbuffer->i = 0;
+ tbuffer->prev = prev;
+ return tbuffer;
+}
+
int dmnsn_yylex_impl(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
const char *filename, void *yyscanner);
@@ -660,7 +803,11 @@ dmnsn_yylex_wrapper(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
}
dmnsn_yyset_extra(tbuffer->prev, yyscanner);
- dmnsn_delete_token_buffer(tbuffer);
+ if (tbuffer->type == DMNSN_T_MACRO) {
+ dmnsn_pop_scope(symtable);
+ } else {
+ dmnsn_delete_token_buffer(tbuffer);
+ }
tbuffer = dmnsn_yyget_extra(yyscanner);
}
}
@@ -862,6 +1009,35 @@ dmnsn_yylex(dmnsn_parse_item *lvalp, dmnsn_parse_location *llocp,
break;
}
+ case DMNSN_T_MACRO:
+ {
+ bool status = dmnsn_declare_macro(
+ token, tbuffer, lvalp, llocp, filename, symtable, yyscanner
+ );
+ if (!status) {
+ return DMNSN_T_LEX_ERROR;
+ }
+ break;
+ }
+
+ case DMNSN_T_IDENTIFIER:
+ {
+ dmnsn_astnode *symbol = dmnsn_find_symbol(symtable, lvalp->value);
+ if (symbol && symbol->type == DMNSN_AST_MACRO) {
+ dmnsn_token_buffer *tb = dmnsn_macro_buffer(
+ token, symbol, tbuffer, lvalp, llocp, filename, symtable, yyscanner
+ );
+ if (!tb) {
+ return DMNSN_T_LEX_ERROR;
+ }
+
+ dmnsn_yyset_extra(tb, yyscanner);
+ break;
+ } else {
+ return token;
+ }
+ }
+
default:
return token;
}