diff --git a/src/config/toplevel.c b/src/config/toplevel.c index 2ad4b0a..c803f49 100644 --- a/src/config/toplevel.c +++ b/src/config/toplevel.c @@ -8,6 +8,7 @@ #include "module.h" #include "gui/bar.h" #include "gui/menu.h" +#include "vm/vm.h" gboolean config_action_conditions ( GScanner *scanner, action_t *action ) { @@ -358,7 +359,7 @@ GtkWidget *config_parse_toplevel ( GScanner *scanner, GtkWidget *container ) config_include(scanner, NULL); break; case G_TOKEN_DEFINE: - config_define(scanner); + parser_macro_add(scanner); break; case G_TOKEN_SET: config_set(scanner); diff --git a/src/vm/parser.c b/src/vm/parser.c index a1a8302..d0357f1 100644 --- a/src/vm/parser.c +++ b/src/vm/parser.c @@ -1,7 +1,9 @@ +#include "util/string.h" #include "vm/vm.h" static guint8 mark = EXPR_OP_MARK; +static GHashTable *macros; static gint parser_emit_jump ( GByteArray *code, guint8 op ) { @@ -163,6 +165,21 @@ static void parser_variable ( GScanner *scanner, GByteArray *code ) g_byte_array_append(code, data, sizeof(gpointer)+1); } +static gboolean parser_macro_handle ( GScanner *scanner, GByteArray *code ) +{ + GBytes *bytes; + gsize len; + gconstpointer data; + + if(!macros || + !(bytes = g_hash_table_lookup(macros, scanner->value.v_identifier)) ) + return FALSE; + + data = g_bytes_get_data(bytes, &len); + g_byte_array_append(code, data, len); + return TRUE; +} + static gboolean parser_identifier ( GScanner *scanner, GByteArray *code ) { if(!g_ascii_strcasecmp(scanner->value.v_identifier, "if")) @@ -175,7 +192,7 @@ static gboolean parser_identifier ( GScanner *scanner, GByteArray *code ) parser_emit_numeric(code, FALSE); else if(g_scanner_peek_next_token(scanner)=='(') return parser_function(scanner, code); - else + else if(!parser_macro_handle(scanner, code)) parser_variable(scanner, code); return TRUE; @@ -273,6 +290,38 @@ gboolean parser_expr_parse ( GScanner *scanner, GByteArray *code ) return parser_ops(scanner, code, 0); } +gboolean parser_macro_add ( GScanner *scanner ) +{ + GByteArray *code; + gchar *name; + + if(g_scanner_get_next_token(scanner) != G_TOKEN_IDENTIFIER) + return FALSE; + name = g_strdup(scanner->value.v_identifier); + if(g_scanner_get_next_token(scanner) != '=') + { + g_free(name); + return FALSE; + } + + code = g_byte_array_new(); + + if(!parser_expr_parse(scanner, code)) + { + g_byte_array_free(code, TRUE); + g_free(name); + return FALSE; + } + + if(!macros) + macros = g_hash_table_new_full( (GHashFunc)str_nhash, + (GEqualFunc)str_nequal, g_free, (GDestroyNotify)g_bytes_unref); + + g_hash_table_insert(macros, name, g_byte_array_free_to_bytes(code)); + + return TRUE; +} + static GScanner *parser_scanner_new ( void ) { GScanner *scanner; diff --git a/src/vm/vm.h b/src/vm/vm.h index ba33a70..89790d8 100644 --- a/src/vm/vm.h +++ b/src/vm/vm.h @@ -45,6 +45,7 @@ typedef struct { GByteArray *parser_expr_compile ( gchar *expr ); gboolean parser_expr_parse ( GScanner *scanner, GByteArray *code ); +gboolean parser_macro_add ( GScanner *scanner ); value_t vm_expr_eval ( expr_cache_t *expr ); gchar *expr_vm_result_to_string ( vm_t *vm ); gint expr_vm_get_func_params ( vm_t *vm, value_t *params[] );