From 4e86ccc2533abbc60ae0480ed1329e2be99a4008 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 17 Mar 2018 17:39:44 -0700 Subject: [PATCH] Use new table features to improve searching for operators. --- include/table.h | 13 ++++++++++++- src/parser.c | 35 +++++++++++++++++++++++++-------- src/table.c | 52 ++++++++++++++++++++++++++++++++++++------------- 3 files changed, 77 insertions(+), 23 deletions(-) diff --git a/include/table.h b/include/table.h index b309bba..7a7fb58 100644 --- a/include/table.h +++ b/include/table.h @@ -61,6 +61,16 @@ typedef struct libab_table_entry_s libab_table_entry; * @param table the table to initialize. */ void libab_table_init(libab_table* table); +/** + * Searches for the given string in the table, comparing + * values to a given reference as an extra filtering step. + * @param table the table to search. + * @param string the string to search for. + * @param data the data to compare against potential values. + * @param compare the comparison function to use. + * @return the table entry, or NULL if an entry was not found. + */ +libab_table_entry* libab_table_search_filter(libab_table* table, const char* string, void* data, compare_func compare); /** * Searches for the given string in the table. * @param table the table to search. @@ -73,9 +83,10 @@ libab_table_entry* libab_table_search(libab_table* table, const char* string); * if it is an operator. * @param table the table to search. * @param string the string to search for. + * @param type the type of operator to search for (infix, prefix, postfix) * @return the found operator, or NULL if it was not found. */ -libab_operator* libab_table_search_operator(libab_table* table, const char* string); +libab_operator* libab_table_search_operator(libab_table* table, const char* string, int type); /** * Searches for the given string in the table, returning a value only * if it is a function. diff --git a/src/parser.c b/src/parser.c index d7fcf70..75bb0b6 100644 --- a/src/parser.c +++ b/src/parser.c @@ -30,6 +30,14 @@ struct operator_data { }\ } while(0); +void _parser_extract_token_buffer(struct parser_state* state, char* buffer, + size_t length, libab_lexer_match* match) { + size_t token_size = match->to - match->from; + size_t buffer_length = (token_size < (length - 1)) ? token_size : (length - 1); + strncpy(buffer, state->string + match->from, buffer_length); + buffer[buffer_length] = '\0'; +} + int _parser_foreach_free_tree(void* data, va_list args) { libab_tree_free(data); free(data); @@ -778,14 +786,11 @@ int _parser_can_atom_follow(enum parser_expression_type type) { return !(type == EXPR_CLOSE_PARENTH || type == EXPR_OP_POSTFIX || type == EXPR_ATOM); } -void _parser_find_operator(struct parser_state* state, libab_lexer_match* match, struct operator_data* data) { +void _parser_find_operator_infix(struct parser_state* state, libab_lexer_match* match, struct operator_data* data) { char op_buffer[8]; - size_t token_size = match->to - match->from; - size_t buffer_length = (token_size < 7) ? token_size : 7; - strncpy(op_buffer, state->string + match->from, buffer_length); - op_buffer[buffer_length] = '\0'; + _parser_extract_token_buffer(state, op_buffer, 8, match); if(match->type != TOKEN_OP_RESERVED) { - libab_operator* operator = libab_table_search_operator(state->base_table, op_buffer); + libab_operator* operator = libab_table_search_operator(state->base_table, op_buffer, TOKEN_OP_INFIX); data->associativity = operator->associativity; data->precedence = operator->precedence; } else { @@ -847,6 +852,20 @@ libab_result _parser_expression_tree(struct parser_state* state, ll* source, lib return result; } +int _parser_match_is_infix_op(struct parser_state* state, libab_lexer_match* match) { + int is_infix = 0; + if(match->type == TOKEN_OP_INFIX || match->type == TOKEN_OP_RESERVED) { + is_infix = 1; + } else { + libab_operator* operator; + char op_buffer[8]; + _parser_extract_token_buffer(state, op_buffer, 8, match); + operator = libab_table_search_operator(state->base_table, op_buffer, TOKEN_OP_INFIX); + if(operator) is_infix = 1; + } + return is_infix; +} + libab_result _parse_expression(struct parser_state* state, libab_tree** store_into) { libab_result result = LIBAB_SUCCESS; struct operator_data operator; @@ -893,12 +912,12 @@ libab_result _parse_expression(struct parser_state* state, libab_tree** store_in _parser_state_step(state); new_type = EXPR_OP_POSTFIX; } else if(new_token->type == TOKEN_OP_INFIX || new_token->type == TOKEN_OP_RESERVED) { - _parser_find_operator(state, new_token, &operator); + _parser_find_operator_infix(state, new_token, &operator); _parser_state_step(state); while(result == LIBAB_SUCCESS && op_stack.tail && _parser_match_is_op(op_stack.tail->data)) { - _parser_find_operator(state, op_stack.tail->data, &other_operator); + _parser_find_operator_infix(state, op_stack.tail->data, &other_operator); if(((libab_lexer_match*)op_stack.tail->data)->type == TOKEN_OP_PREFIX || (operator.associativity == -1 && diff --git a/src/table.c b/src/table.c index ef54631..c81812d 100644 --- a/src/table.c +++ b/src/table.c @@ -1,12 +1,21 @@ #include "table.h" #include #include "util.h" +#include "lexer.h" void libab_table_init(libab_table* table) { ht_init(&table->table); table->parent = NULL; } -libab_table_entry* table_search(libab_table* table, const char* string) { +libab_table_entry* libab_table_search_filter(libab_table* table, const char* string, void* data, compare_func compare) { + void* to_return = NULL; + do { + to_return = ht_get_filter(&table->table, string, data, compare); + table = table->parent; + } while(table && to_return == NULL); + return to_return; +} +libab_table_entry* libab_table_search(libab_table* table, const char* string) { void* to_return = NULL; do { to_return = ht_get(&table->table, string); @@ -14,21 +23,36 @@ libab_table_entry* table_search(libab_table* table, const char* string) { } while(table && to_return == NULL); return to_return; } -libab_operator* libab_table_search_operator(libab_table* table, const char* string) { - libab_table_entry* entry = table_search(table, string); - libab_operator* to_return = NULL; - if(entry && entry->variant == ENTRY_OP) { - to_return = &entry->data_u.op; - } - return to_return; + +#define OP_TYPE_COMPARATOR(NAME, TYPE) int NAME(const void* left, const void* right) {\ + const libab_table_entry* entry = right;\ + return entry->variant == ENTRY_OP && entry->data_u.op.type == TYPE;\ } -libab_function* libab_table_search_function(libab_table* table, const char* string) { - libab_table_entry* entry = table_search(table, string); - libab_function* to_return = NULL; - if(entry && entry->variant == ENTRY_FUN) { - to_return = &entry->data_u.function; + +OP_TYPE_COMPARATOR(_table_compare_prefix, TOKEN_OP_PREFIX) +OP_TYPE_COMPARATOR(_table_compare_infix, TOKEN_OP_INFIX) +OP_TYPE_COMPARATOR(_table_compare_postfix, TOKEN_OP_POSTFIX) + +libab_operator* libab_table_search_operator(libab_table* table, const char* string, int type) { + libab_table_entry* entry = NULL; + if(type == TOKEN_OP_PREFIX) { + entry = libab_table_search_filter(table, string, NULL, _table_compare_prefix); + } else if(type == TOKEN_OP_INFIX) { + entry = libab_table_search_filter(table, string, NULL, _table_compare_infix); + } else if(type == TOKEN_OP_POSTFIX) { + entry = libab_table_search_filter(table, string, NULL, _table_compare_postfix); } - return to_return; + return entry ? &entry->data_u.op : NULL; +} + +int _table_compare_function(const void* left, const void* right) { + const libab_table_entry* entry = right; + return entry->variant == ENTRY_FUN; +} + +libab_function* libab_table_search_function(libab_table* table, const char* string) { + libab_table_entry* entry = libab_table_search_filter(table, string, NULL, _table_compare_function); + return entry ? &entry->data_u.function : NULL; } libab_result libab_table_put(libab_table* table, const char* string, libab_table_entry* entry) { return libab_convert_ds_result(ht_put(&table->table, string, entry));