void destroy_itemset( struct itemset * this_itemset ) { int i; char * key; struct list * key_list = new_list(); list_keys_in_hash( this_itemset->items, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { key = listlookup( key_list, i ); struct item * data = hashlookup( this_itemset->items, key )->data; free( data ); } destroy_key_list( key_list ); destroy_hash( this_itemset->items ); key_list = new_list(); list_keys_in_hash( this_itemset->ready_for, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { key = listlookup( key_list, i ); struct list * ready_items = hashlookup( this_itemset->ready_for, key )->data; destroy_list( ready_items ); } destroy_key_list( key_list ); destroy_hash( this_itemset->ready_for ); destroy_list( this_itemset->complete ); free( this_itemset ); return; }
char * print_hash_key_set( struct hash * current ) { struct list * var_list = new_list(); list_keys_in_hash( current, var_list, "" ); int var_list_len = 0; int i = var_list->next_index; while ( i-- ) { var_list_len += strlen(listlookup( var_list, i )); } int brace_len = BRACE_LEN; int comma_len = COMMA_LEN; char * key_set_str = malloc( ( var_list->next_index * comma_len + var_list_len + 2 * brace_len + 1 ) * sizeof(char) ); *key_set_str = '\0'; sprintf( key_set_str, "{" ); i = var_list->next_index; while ( i-- ) { strcat( key_set_str, listlookup( var_list, i )); if ( i ) { strcat( key_set_str, "," ); } } strcat( key_set_str, "}" ); destroy_key_list(var_list); return key_set_str; }
void list_keys_in_hash( struct hash * current, struct list * result, char * prefix ) { int siglen = strlen(current->sigstr); int prefixlen = strlen(prefix); char * path = malloc( ( prefixlen + siglen + 2 ) * sizeof(char) ); // Extra child char. strcpy( path, prefix ); strcat( path, current->sigstr ); path[ prefixlen + siglen + 1 ] = path[ prefixlen + siglen ] = '\0'; char * chars_in_child = chars_in( current->child, 0, 0 ); char child_char = '\0'; struct hash * child_hash = NULL; int i = current->num_children; while ( i-- ) { // Recurse through all children. child_char = chars_in_child[i]; if ( child_char == '\0' ) { // No keys to recurse through. continue; } path[ prefixlen + siglen ] = child_char; // Get the path prefix for this child. child_hash = charhashlookup( current->child, child_char )->data; list_keys_in_hash( child_hash, result, path ); } // Decide if the path to this node needs to be included in the list of keys. if ( current->data ) { path[ prefixlen + siglen ] = '\0'; append_to_list( result, (void *) path ); } else { free(path); } free(chars_in_child); return; }
void fill_FIRST() { FIRST = new_hash(); int i; int j; char * symbol; char * lhs; char * left_corner; struct list * key_list = new_list(); list_keys_in_hash( IS_TERMINAL, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { symbol = listlookup( key_list, i ); struct hash * symbol_firsts = new_hash(); if ( ( (int *) hashlookup( IS_TERMINAL, symbol )->data ) == &TRUE ) { // Terminals self-derive. add_to_hash( symbol_firsts, symbol, (void *) (long int) 1 ); } add_to_hash( FIRST, symbol, (void *) symbol_firsts ); } destroy_key_list( key_list ); int change = 1; while ( change ) { change = 0; for ( i = 0; i < NUM_PRODUCTIONS; i++ ) { struct list * production = GRAMMAR[i].production; lhs = listlookup( production, 0 ); left_corner = listlookup( production, 1 ); key_list = new_list(); list_keys_in_hash( hashlookup( FIRST, left_corner )->data, key_list, "" ); for ( j = 0; j < key_list->next_index; j++ ) { // Go through all the firsts of left_corner. symbol = listlookup( key_list, j ); struct hash * lhs_firsts = hashlookup( FIRST, lhs )->data; struct hash * looked_up = hashlookup( lhs_firsts, symbol ); if ( ! looked_up ) { add_to_hash( lhs_firsts, symbol, (void *) &TRUE ); // Add them to firsts of lhs. change = 1; } } destroy_key_list( key_list ); } } }
void fill_FOLLOW() { FOLLOW = new_hash(); char * symbol; char * next_symbol; char * lhs; int i; int j; struct list * production; int change; struct hash * symbol_followers; struct list * key_list = new_list(); list_keys_in_hash( IS_TERMINAL, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { symbol = listlookup( key_list, i ); if ( ( (int *) hashlookup( IS_TERMINAL, symbol )->data ) == &FALSE ) { symbol_followers = new_hash(); add_to_hash( FOLLOW, symbol, (void *) symbol_followers ); } } destroy_key_list( key_list ); change = 1; while ( change ) { change = 0; for ( i = 0; i < NUM_PRODUCTIONS; i++ ) { production = GRAMMAR[i].production; lhs = listlookup( production, 0 ); for ( j = 1; j < production->next_index; j++ ) { // Loop RHS symbols. symbol = listlookup( production, j ); if ( ( (int *) hashlookup( IS_TERMINAL, symbol )->data ) == &TRUE ) { // No FOLLOW for terminals. continue; } symbol_followers = hashlookup( FOLLOW, symbol )->data; if ( j + 1 < production->next_index ) { // There is an adjacent symbol. next_symbol = listlookup( production, j + 1 ); struct hash * next_symbol_firsts = hashlookup( FIRST, next_symbol )->data; // Everything in FIRST{next_symbol} should be in FOLLOW{symbol}. change = expand_hash( symbol_followers, next_symbol_firsts ) || change; continue; } else { // Last symbol in production is nonterminal. struct hash * lhs_followers = hashlookup( FOLLOW, lhs )->data; // Everything in FOLLOW{lhs} should be in FOLLOW{symbol}. change = expand_hash( symbol_followers, lhs_followers ) || change; continue; } } } } }
struct hash * copy_shallow_hash( struct hash * original ) { struct hash * copy = new_hash(); struct list * key_list = new_list(); list_keys_in_hash( original, key_list, "" ); char * key = NULL; int i = key_list->next_index; while ( i-- ) { key = listlookup( key_list, i ); add_to_hash( copy, key, hashlookup( original, key ) ); } destroy_key_list( key_list ); return copy; }
int main() { struct hash * frequency_hash = new_hash(); char char_string[2] = { ' ', '\0' }; int number_of_characters = 0; int i; char c; while ( ( c = getchar() ) != EOF ) { if ( c == '\n' ) { continue; } char_string[0] = c; struct hash * looked_up = hashlookup( frequency_hash, char_string ); struct index_frequency * data; if ( !looked_up ) { data = malloc( sizeof( struct index_frequency ) ); data->index = number_of_characters; data->frequency = 0; looked_up = add_to_hash( frequency_hash, char_string, (void *) data ); } data = looked_up->data; int frequency = data->frequency; data->frequency = frequency + 1; number_of_characters++; } struct list * key_list = new_list(); list_keys_in_hash( frequency_hash, key_list, "" ); int min_index = number_of_characters + 1; char * min_key = ""; int min_frequency = number_of_characters + 1; for ( i = 0; i < key_list->next_index; i++ ) { char * key = listlookup( key_list, i ); struct index_frequency * data; data = hashlookup( frequency_hash, key )->data; if ( data->frequency < min_frequency ) { min_index = data->index; min_frequency = data->frequency; min_key = key; } else if ( data->frequency == min_frequency ) { if ( data->index < min_index ) { min_index = data->index; min_key = key; } } } printf( "The first non-repeated character is: \n%s\n", min_key ); }
void fill_TRIE( struct hash * token_types ) { int i; char * path; char * accepting_type; TRIE = new_trie_node(); struct list * key_list = new_list(); list_keys_in_hash( token_types, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { path = listlookup( key_list, i ); accepting_type = hashlookup( token_types, path )->data; add_to_trie( TRIE, path, accepting_type ); } destroy_key_list( key_list ); return; }
int expand_hash( struct hash * target, struct hash * source ) { int i; char * symbol; void * value; int change = 0; struct list * key_list = new_list(); list_keys_in_hash( source, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { symbol = listlookup( key_list, i ); struct hash * looked_up = hashlookup( target, symbol ); if ( ! looked_up ) { value = hashlookup( source, symbol )->data; add_to_hash( target, symbol, value ); // Use the same value or pointer. change = 1; } } return change; }
void install_complete_transitions( int i, struct itemset * current_itemset, struct parser_generator * self ) { struct list * table = self->TABLE; struct list * complete_items = current_itemset->complete; char * lhs; struct item * complete_item; struct list * complete_production; int j; int k; struct hash * table_row = listlookup( self->TABLE, i ); for ( j = 0; j < complete_items->next_index; j++ ) { complete_item = listlookup( complete_items, j ); int prod_num = complete_item->prod_num; complete_production = GRAMMAR[prod_num].production; lhs = listlookup( complete_production, 0 ); // Loop all terminals which can follow this lhs. struct list * key_list = new_list(); list_keys_in_hash( hashlookup( FOLLOW, lhs )->data, key_list, "" ); for ( k = 0; k < key_list->next_index; k++ ) { struct list * trans_list; char * follower = listlookup( key_list, k ); // Add a reduce transition on each follower token. struct hash * looked_up = hashlookup( table_row, follower ); if ( ! looked_up ) { trans_list = new_list(); add_to_hash( table_row, follower, (void *) trans_list ); } else { trans_list = looked_up->data; } struct transition * reduce_transition = new_transition(); reduce_transition->action = "reduce"; reduce_transition->arg = prod_num; append_to_list( trans_list, reduce_transition ); } destroy_key_list( key_list ); } }
void install_incomplete_transitions( int i, struct itemset * current_itemset, struct parser_generator * self ) { struct list * itemsets = self->itemsets; struct hash * itemsets_by_key = self->itemsets_by_key; struct hash * ready_for = current_itemset->ready_for; // Prepare to loop through the keys of current_itemset->ready_for. struct list * key_list = new_list(); list_keys_in_hash( ready_for, key_list, "" ); int j; int k; for ( j = 0; j < key_list->next_index; j++ ) { // Loop ready-for symbols. char * symbol = listlookup( key_list, j ); struct list * ready_for_symbol = hashlookup( ready_for, symbol )->data; struct itemset * proposed_itemset = new_itemset(); for ( k = 0; k < ready_for_symbol->next_index; k++ ) { // Loop symbol items. struct item * ready_item = listlookup( ready_for_symbol, k ); struct item * proposed_item = new_item(); proposed_item->prod_num = ready_item->prod_num; proposed_item->dot = ready_item->dot + 1; char * proposed_item_key = create_item_key( proposed_item ); add_to_hash( proposed_itemset->items, proposed_item_key, (void *) proposed_item ); free( proposed_item_key ); // It's now in the hash. } // End symbol items loop. char * proposed_itemset_key = create_closure_key( proposed_itemset ); struct hash * looked_up = hashlookup( itemsets_by_key, proposed_itemset_key ); if ( ! looked_up ) { append_to_list( itemsets, (void *) proposed_itemset ); int state_num = itemsets->next_index - 1; looked_up = add_to_hash( itemsets_by_key, proposed_itemset_key, (void *) (long int) state_num ); } else { destroy_itemset( proposed_itemset ); } int destination = (long int) looked_up->data; install_incomplete_transition( i, symbol, destination, self ); } // End ready-for symbols loop. return; }
char * create_closure_key( struct itemset * current_itemset ) { struct item * current_item; struct hash * looked_up; struct list * production; int p; int d; int i; // Push all the items in the itemset onto the unchecked stack. struct list * unchecked = new_list(); struct hash * current_items = current_itemset->items; struct list * key_list = new_list(); list_keys_in_hash( current_items, key_list, "" ); for ( i = 0; i < key_list->next_index; i++ ) { char * key = listlookup( key_list, i ); append_to_list( unchecked, (void *) hashlookup( current_items, key )->data ); } destroy_key_list( key_list ); // Now process unchecked items, possibly adding more along the way. while ( unchecked->next_index ) { current_item = pop_from_list( unchecked ); p = current_item->prod_num; d = current_item->dot; production = GRAMMAR[p].production; if ( d == production->next_index - 1 ) { // This item is complete. append_to_list( current_itemset->complete, (void *) current_item ); continue; // Nothing more to do here. } // Otherwise, this item is incomplete, // so record it in the appropriate ready_for slot for this itemset. char * predicted = listlookup( production, d + 1 ); struct list * items_ready_for = NULL; struct hash * looked_up = hashlookup( current_itemset->ready_for, predicted ); if ( ! looked_up ) { items_ready_for = new_list(); add_to_hash( current_itemset->ready_for, predicted, (void *) items_ready_for ); } else { items_ready_for = looked_up->data; } append_to_list( items_ready_for, (void *) current_item ); // If the predicted symbol is terminal, this item is done processing. if ( ( (int *) hashlookup( IS_TERMINAL, predicted )->data ) == &TRUE ) { continue; // Can't expand terminals. } // Otherwise, the predicted symbol is nonterminal, // so expand the itemset using all applicable productions. struct list * predicted_productions = hashlookup( PRODUCTIONS_FOR, predicted )->data; for ( i = 0; i < predicted_productions->next_index; i++ ) { int predicted_p = (long int) listlookup( predicted_productions, i ); struct item * predicted_item = new_item(); predicted_item->prod_num = predicted_p; char * predicted_key = create_item_key( predicted_item ); if ( looked_up = hashlookup( current_items, predicted_key ) ) { // Item unneeded. free( predicted_item ); free( predicted_key ); continue; } // Otherwise, add the new item to the itemset, and to the unchecked stack. add_to_hash( current_items, predicted_key, (void *) predicted_item ); free( predicted_key ); append_to_list( unchecked, (void *) predicted_item ); } } // Now that the itemset has been filled out, create and return its identifying string. key_list = new_list(); list_keys_in_hash( current_items, key_list, "" ); char * closure_key = join_key_list( key_list, "_" ); destroy_key_list( key_list ); return closure_key; }