home *** CD-ROM | disk | FTP | other *** search
- /* $Id: remsp.c,v 1.2 1999/11/04 14:02:23 shields Exp $ */
- /*
- This software is subject to the terms of the IBM Jikes Compiler
- License Agreement available at the following URL:
- http://www.ibm.com/research/jikes.
- Copyright (C) 1983, 1999, International Business Machines Corporation
- and others. All Rights Reserved.
- You must accept the terms of that agreement to use this software.
- */
- static char hostfile[] = __FILE__;
-
- #include "common.h"
- #include "reduce.h"
- #include "header.h"
-
- #define IS_SP_RHS(symbol) (sp_rules[symbol] != NIL)
- #define IS_SP_RULE(rule_no) (rule_list[rule_no] != OMEGA)
-
- static int max_sp_state;
-
- static struct action_element
- {
- struct action_element *next;
- short symbol,
- action;
- } **new_action;
- static struct action_element *action_element_pool = NULL;
-
- static struct update_action_element
- {
- struct update_action_element *next;
- short symbol,
- action,
- state;
- } **update_action;
-
- static struct sp_state_element
- {
- struct sp_state_element *next,
- *link;
- struct action_element *action_root;
- struct node *rule_root,
- *complete_items;
- short state_number,
- rule_count,
- action_count;
- } **sp_table;
- static struct sp_state_element *sp_state_root;
-
- static short *sp_rules,
- *stack,
- *index_of,
- *next_rule,
- *rule_list,
-
- **sp_action;
-
- static BOOLEAN *is_conflict_symbol;
-
- static SET_PTR look_ahead;
-
- static int top,
- symbol_root,
- rule_root;
-
- /**********************************************************************/
- /* ALLOCATE_ACTION_ELEMENT: */
- /**********************************************************************/
- /* This function first tries to recycle an action_element node from a */
- /* free list. If the list is empty a new node is allocated from */
- /* temporary storage. */
- /**********************************************************************/
- static struct action_element* allocate_action_element(void)
- {
- struct action_element *p;
-
- p = action_element_pool;
- if (p != NULL)
- action_element_pool = p -> next;
- else
- {
- p = (struct action_element *)
- talloc(sizeof(struct action_element));
- if (p == (struct action_element *) NULL)
- nospace(__FILE__, __LINE__);
- }
-
- return p;
- }
-
-
- /**********************************************************************/
- /* FREE_ACTION_ELEMENTS: */
- /**********************************************************************/
- /* This routine returns a list of action_element structures to the */
- /* free list. */
- /**********************************************************************/
- static void free_action_elements(struct action_element *head,
- struct action_element *tail)
- {
- tail -> next = action_element_pool;
- action_element_pool = head;
-
- return;
- }
-
-
- /**********************************************************************/
- /* COMPUTE_SP_MAP: */
- /**********************************************************************/
- /* Compute_sp_map is an instantiation of the digraph algorithm. It */
- /* is invoked repeatedly by remove_single_productions to: */
- /* */
- /* 1) Partially order the right-hand side of all the single */
- /* productions (SP) into a list [A1, A2, A3, ..., An] */
- /* such that if Ai -> Aj then i < j. */
- /* */
- /* 2) As a side effect, it uses the ordering above to order all */
- /* the SP rules. */
- /* */
- /**********************************************************************/
- static void compute_sp_map(int symbol)
- {
- int indx;
- int i,
- lhs_symbol,
- rule_no;
-
- stack[++top] = symbol;
- indx = top;
- index_of[symbol] = indx;
-
- /**********************************************************************/
- /* In this instantiation of the digraph algorithm, two symbols (A, B) */
- /* are related if A -> B is a SP and A is the right-hand side of */
- /* some other SP rule. */
- /**********************************************************************/
- for (rule_no = sp_rules[symbol];
- rule_no != NIL; rule_no = next_rule[rule_no])
- {
- lhs_symbol = rules[rule_no].lhs;
- if (IS_SP_RHS(lhs_symbol))
- {
- if (index_of[lhs_symbol] == OMEGA)
- compute_sp_map(lhs_symbol);
-
- index_of[symbol] = MIN(index_of[symbol],
- index_of[lhs_symbol]);
- }
- }
-
- /**********************************************************************/
- /* If the index of symbol is the same index it started with then */
- /* symbol if the root of a SCC... */
- /**********************************************************************/
- if (index_of[symbol] == indx)
- {
- /**************************************************************/
- /* If symbol is on top of the stack then it is the only */
- /* symbol in its SCC (thus it is not part of a cycle). */
- /* Note that since remove_single_productions is only invoked */
- /* when the input grammar is conflict-free, the graph of */
- /* the single productions will never contain any cycle. */
- /* Thus, this test will always succeed and all single */
- /* productions associated with the symbol being processed */
- /* are added to the list of SP rules here... */
- /**************************************************************/
- if (stack[top] == symbol)
- {
- for (rule_no = sp_rules[symbol];
- rule_no != NIL; rule_no = next_rule[rule_no])
- {
- if (rule_root == NIL)
- rule_list[rule_no] = rule_no;
- else
- {
- rule_list[rule_no] = rule_list[rule_root];
- rule_list[rule_root] = rule_no;
- }
- rule_root = rule_no;
- }
- }
-
- /**************************************************************/
- /* As all SCC contains exactly one symbol (as explained above)*/
- /* this loop will always execute exactly once. */
- /**************************************************************/
- do
- {
- i = stack[top--];
- index_of[i] = INFINITY;
- } while(i != symbol);
- }
-
- return;
- }
-
-
- /**********************************************************************/
- /* COMPUTE_SP_ACTION: */
- /**********************************************************************/
- /* When the parser enters STATE_NO and it is processing SYMBOL, its */
- /* next move is ACTION. Given these 3 parameters, compute_sp_action */
- /* computes the set of reduce actions that may be executed after */
- /* SYMBOL is shifted in STATE_NO. */
- /* */
- /* NOTE that this algorithm works only for the LALR(1) case. When the */
- /* transition on SYMBOL is a lookahead-shift, indicating that the */
- /* parser requires extra lookahead on a particular symbol, the set of */
- /* reduce actions for that symbol is calculated as the empty set. */
- /**********************************************************************/
- static void compute_sp_action(short state_no, short symbol, short action)
- {
- struct goto_header_type go_to;
-
- struct node *item_ptr;
- int item_no,
- rule_no,
- lhs_symbol,
- i,
- k;
-
- BOOLEAN end_node;
-
- struct node *p;
-
- go_to = statset[state_no].go_to;
-
- if (sp_action[symbol] == NULL)
- sp_action[symbol] = Allocate_short_array(num_terminals + 1);
-
- for ALL_TERMINALS(i) /* initialize sp_action to the empty map */
- sp_action[symbol][i] = OMEGA;
-
- /**********************************************************************/
- /* Note that before this routine is invoked, the global vector */
- /* index_of identifies the index of each symbol in the goto map of */
- /* state_no. */
- /**********************************************************************/
- if (is_conflict_symbol[symbol]) /* do nothing */
- ;
- else if (action > 0) /* transition action (shift or goto) */
- {
- for (item_ptr = statset[action].complete_items;
- item_ptr != NULL; item_ptr = item_ptr -> next)
- {
- item_no = item_ptr -> value;
- rule_no = item_table[item_no].rule_number;
- lhs_symbol = rules[rule_no].lhs;
- if (RHS_SIZE(rule_no) == 1 && lhs_symbol != accept_image)
- {
- if (slr_bit)
- {
- ASSIGN_SET(look_ahead, 0, follow, lhs_symbol);
- }
- else
- {
- i = index_of[lhs_symbol];
- k = GOTO_LAPTR(go_to, i);
- if (la_index[k] == OMEGA)
- {
- int stack_top = 0;
- la_traverse(state_no, i, &stack_top);
- }
- ASSIGN_SET(look_ahead, 0, la_set, k);
- }
- RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */
-
- for ALL_TERMINALS(i)
- {
- if (IS_ELEMENT(look_ahead, i))
- sp_action[symbol][i] = rule_no;
- }
- }
- }
-
- /**************************************************************/
- /* Remove all lookahead symbols on which conflicts were */
- /* detected from consideration. */
- /**************************************************************/
- for (end_node = ((p = conflict_symbols[action]) == NULL);
- ! end_node; end_node = (p == conflict_symbols[action]))
- {
- p = p -> next;
- sp_action[symbol][p -> value] = OMEGA;
- }
- }
- else /* read-reduce action */
- {
- rule_no = -action;
- if (RHS_SIZE(rule_no) == 1)
- {
- lhs_symbol = rules[rule_no].lhs;
-
- if (slr_bit)
- {
- ASSIGN_SET(look_ahead, 0, follow, lhs_symbol);
- }
- else
- {
- i = index_of[lhs_symbol];
- k = GOTO_LAPTR(go_to, i);
- if (la_index[k] == OMEGA)
- {
- int stack_top = 0;
- la_traverse(state_no, i, &stack_top);
- }
- ASSIGN_SET(look_ahead, 0, la_set, k);
- }
- RESET_BIT(look_ahead, empty); /* empty not valid look-ahead */
-
- for ALL_TERMINALS(i)
- {
- if (IS_ELEMENT(look_ahead, i))
- sp_action[symbol][i] = rule_no;
- }
- }
- }
-
- return;
- }
-
-
- /**********************************************************************/
- /* SP_DEFAULT_ACTION: */
- /**********************************************************************/
- /* Sp_default_action takes as parameter a state, state_no and a rule, */
- /* rule_no that may be reduce when the parser enters state_no. */
- /* Sp_default_action tries to determine the highest rule that may be */
- /* reached via a sequence of SP reductions. */
- /**********************************************************************/
- static short sp_default_action(short state_no, short rule_no)
- {
- struct reduce_header_type red;
- struct goto_header_type go_to;
-
- int lhs_symbol,
- action,
- i;
-
- go_to = statset[state_no].go_to;
-
- /**********************************************************************/
- /* While the rule we have at hand is a single production, ... */
- /**********************************************************************/
- while (IS_SP_RULE(rule_no))
- {
- lhs_symbol = rules[rule_no].lhs;
- for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++)
- ;
-
- action = GOTO_ACTION(go_to, i);
- if (action < 0) /* goto-reduce action? */
- {
- action = -action;
- if (RHS_SIZE(action) != 1)
- break;
-
- rule_no = action;
- }
- else
- {
- int best_rule = OMEGA;
-
- /**************************************************************/
- /* Enter the state action and look for preferably a SP rule */
- /* or some rule with right-hand size 1. */
- /**************************************************************/
- red = reduce[action];
- for (i = 1; i <= red.size; i++)
- {
- action = REDUCE_RULE_NO(red, i);
- if (IS_SP_RULE(action))
- {
- best_rule = action;
- break;
- }
- if (RHS_SIZE(action) == 1)
- best_rule = action;
- }
- if (best_rule == OMEGA)
- break;
-
- rule_no = best_rule;
- }
- }
-
- return rule_no;
- }
-
- /**********************************************************************/
- /* SP_NT_ACTION: */
- /**********************************************************************/
- /* This routine takes as parameter a state, state_no, a nonterminal, */
- /* lhs_symbol (that is the right-hand side of a SP or a rule with */
- /* right-hand size 1, but not identified as a SP) on which there is */
- /* a transition in state_no and a lookahead symbol la_symbol that may */
- /* be processed after taking the transition. It returns the reduce */
- /* action that follows the transition if an action on la_symbol is */
- /* found, otherwise it returns the most suitable default action. */
- /**********************************************************************/
- static short sp_nt_action(short state_no, short lhs_symbol, short la_symbol)
- {
- struct reduce_header_type red;
- struct goto_header_type go_to;
-
- int action,
- rule_no,
- i;
-
- go_to = statset[state_no].go_to;
- for (i = 1; GOTO_SYMBOL(go_to, i) != lhs_symbol; i++)
- ;
-
- action = GOTO_ACTION(go_to, i);
- if (action < 0)
- action = -action;
- else
- {
- red = reduce[action];
- action = OMEGA;
- for (i = 1; i <= red.size; i++)
- {
- rule_no = REDUCE_RULE_NO(red, i);
- if (REDUCE_SYMBOL(red, i) == la_symbol)
- {
- action = rule_no;
- break;
- }
- else if (action == OMEGA && IS_SP_RULE(rule_no))
- action = rule_no;
- }
- }
-
- return action;
- }
-
-
- /**********************************************************************/
- /* GREATEST_COMMON_ANCESTOR: */
- /**********************************************************************/
- /* Let BASE_RULE be a rule A -> X. The item [A -> .X] is in STATE1 */
- /* and STATE2. After shifting on X (in STATE1 and STATE2), if the */
- /* lookahead is LA_SYMBOL then BASE_RULE is reduced. In STATE1, a */
- /* sequence of single-production reductions is executed ending with */
- /* a reduction of RULE1. In STATE2, a sequence of single-productions */
- /* is also executed ending with RULE2. */
- /* The goal of this function is to find the greatest ancestor of */
- /* BASE_RULE that is also a descendant of both RULE1 and RULE2. */
- /**********************************************************************/
- static short greatest_common_ancestor(short base_rule, short la_symbol,
- short state1, short rule1,
- short state2, short rule2)
- {
- int lhs_symbol,
- act1,
- act2,
- rule_no;
-
- act1 = base_rule;
- act2 = base_rule;
- while (act1 == act2)
- {
- rule_no = act1;
- if (act1 == rule1 || act2 == rule2)
- break;
-
- lhs_symbol = rules[rule_no].lhs;
-
- act1 = sp_nt_action(state1, lhs_symbol, la_symbol);
- act2 = sp_nt_action(state2, lhs_symbol, la_symbol);
- }
-
- return rule_no;
- }
-
-
- /**********************************************************************/
- /* COMPUTE_UPDATE_ACTION: */
- /**********************************************************************/
- /* In SOURCE_STATE there is a transition on SYMBOL into STATE_NO. */
- /* SYMBOL is the right-hand side of a SP rule and the global map */
- /* sp_action[SYMBOL] yields a set of update reduce actions that may */
- /* follow the transition on SYMBOL into STATE_NO. */
- /**********************************************************************/
- static void compute_update_actions(short source_state,
- short state_no, short symbol)
- {
- int i,
- rule_no;
-
- struct reduce_header_type red;
- struct update_action_element *p;
-
- red = reduce[state_no];
-
- for (i = 1; i <= red.size; i++)
- {
- if (IS_SP_RULE(REDUCE_RULE_NO(red, i)))
- {
- rule_no = sp_action[symbol][REDUCE_SYMBOL(red, i)];
- if (rule_no == OMEGA)
- rule_no = sp_default_action(source_state,
- REDUCE_RULE_NO(red, i));
-
- /**************************************************************/
- /* Lookup the update map to see if a previous update was made */
- /* in STATE_NO on SYMBOL... */
- /**************************************************************/
- for (p = update_action[state_no]; p != NULL; p = p -> next)
- {
- if (p -> symbol == REDUCE_SYMBOL(red, i))
- break;
- }
-
- /**************************************************************/
- /* If no previous update action was defined on STATE_NO and */
- /* SYMBOL, simply add it. Otherwise, chose as the greatest */
- /* common ancestor of the initial reduce action and the two */
- /* contending updates as the update action. */
- /**************************************************************/
- if (p == NULL)
- {
- p = (struct update_action_element *)
- talloc(sizeof(struct update_action_element));
- if (p == (struct update_action_element *) NULL)
- nospace(__FILE__, __LINE__);
- p -> next = update_action[state_no];
- update_action[state_no] = p;
-
- p -> symbol = REDUCE_SYMBOL(red, i);
- p -> action = rule_no;
- p -> state = source_state;
- }
- else if ((rule_no != p -> action) &&
- (p -> action != REDUCE_RULE_NO(red, i)))
- {
- p -> action = greatest_common_ancestor(REDUCE_RULE_NO(red, i),
- REDUCE_SYMBOL(red, i),
- source_state, rule_no,
- p -> state,
- p -> action);
- }
- }
- }
-
- return;
- }
-
-
- /**********************************************************************/
- /* SP_STATE_MAP: */
- /**********************************************************************/
- /* Sp_state_map is invoked to create a new state using the reduce map */
- /* sp_symbol[SYMBOL]. The new state will be entered via a transition */
- /* on SYMBOL which is the right-hand side of the SP rule of which */
- /* ITEM_NO is the final item. */
- /* */
- /* RULE_HEAD is the root of a list of rules in the global vector */
- /* next_rule. This list of rules identifies the range of the reduce */
- /* map sp_symbol[SYMBOL]. The value SP_RULE_COUNT is the number of */
- /* rules in the list. The value SP_ACTION_COUNT is the number of */
- /* actions in the map sp_symbol[SYMBOL]. */
- /**********************************************************************/
- static short sp_state_map(int rule_head, short item_no,
- short sp_rule_count,
- short sp_action_count, short symbol)
- {
- struct sp_state_element *state;
- struct node *p;
-
- int rule_no,
- i;
-
- BOOLEAN no_overwrite;
-
- unsigned long hash_address;
-
- /******************************************************************/
- /* These new SP states are defined by their reduce maps. Hash the */
- /* reduce map based on the set of rules in its range - simply add */
- /* them up and reduce modulo STATE_TABLE_SIZE. */
- /******************************************************************/
- hash_address = 0;
- for (rule_no = rule_head;
- rule_no != NIL; rule_no = next_rule[rule_no])
- hash_address += rule_no;
-
- hash_address %= STATE_TABLE_SIZE;
-
- /******************************************************************/
- /* Search the hash table for a compatible state. Two states S1 */
- /* and S2 are compatible if */
- /* 1) the set of rules in their reduce map is identical. */
- /* 2) for each terminal symbol t, either */
- /* reduce[S1][t] == reduce[S2][t] or */
- /* reduce[S1][t] == OMEGA or */
- /* reduce[S2][t] == OMEGA */
- /* */
- /******************************************************************/
- for (state = sp_table[hash_address];
- state != NULL; state = state -> link)
- {
- if (state -> rule_count == sp_rule_count) /* same # of rules? */
- {
- for (p = state -> rule_root; p != NULL; p = p -> next)
- {
- if (next_rule[p -> value] == OMEGA) /* not in list? */
- break;
- }
-
- /******************************************************************/
- /* If the set of rules are identical, we proceed to compare the */
- /* actions for compatibility. The idea is to make sure that all */
- /* actions in the hash table do not clash in the actions in the */
- /* map sp_action[SYMBOL]. */
- /******************************************************************/
- if (p == NULL) /* all the rules match? */
- {
- struct action_element *actionp,
- *action_tail;
-
- for (actionp = state -> action_root;
- actionp != NULL; actionp = actionp -> next)
- {
- if (sp_action[symbol][actionp -> symbol] != OMEGA &&
- sp_action[symbol][actionp -> symbol] !=
- actionp -> action)
- break;
- }
-
- /**************************************************************/
- /* If the two states are compatible merge them into the map */
- /* sp_action[SYMBOL]. (Note that this effectively destroys */
- /* the original map.) Also, keep track of whether or not an */
- /* actual merging action was necessary with the boolean */
- /* variable no_overwrite. */
- /**************************************************************/
- if (actionp == NULL) /* compatible states */
- {
- no_overwrite = TRUE;
- for (actionp = state -> action_root;
- actionp != NULL;
- action_tail = actionp, actionp = actionp -> next)
- {
- if (sp_action[symbol][actionp -> symbol] == OMEGA)
- {
- sp_action[symbol][actionp -> symbol] =
- actionp -> action;
- no_overwrite = FALSE;
- }
- }
-
- /**********************************************************/
- /* If the item was not previously associated with this */
- /* state, add it. */
- /**********************************************************/
- for (p = state -> complete_items;
- p != NULL; p = p -> next)
- {
- if (p -> value == item_no)
- break;
- }
- if (p == NULL)
- {
- p = Allocate_node();
- p -> value = item_no;
- p -> next = state -> complete_items;
- state -> complete_items = p;
- }
-
- /**********************************************************/
- /* If the two maps are identical (there was no merging), */
- /* return the state number otherwise, free the old map */
- /* and break out of the search loop. */
- /**********************************************************/
- if (no_overwrite &&
- state -> action_count == sp_action_count)
- return state -> state_number;
-
- free_action_elements(state -> action_root, action_tail);
-
- break; /* for (state = sp_table[hash_address]; ... */
- }
- }
- }
- }
-
- /******************************************************************/
- /* If we did not find a compatible state, construct a new one. */
- /* Add it to the list of state and add it to the hash table. */
- /******************************************************************/
- if (state == NULL)
- {
- state = (struct sp_state_element *)
- talloc(sizeof(struct sp_state_element));
- if (state == NULL)
- nospace(__FILE__, __LINE__);
-
- state -> next = sp_state_root;
- sp_state_root = state;
-
- state -> link = sp_table[hash_address];
- sp_table[hash_address] = state;
-
- max_sp_state++;
- state -> state_number = max_sp_state;
- state -> rule_count = sp_rule_count;
-
- p = Allocate_node();
- p -> value = item_no;
- p -> next = NULL;
- state -> complete_items = p;
-
- state -> rule_root = NULL;
- for (rule_no = rule_head;
- rule_no != NIL; rule_no = next_rule[rule_no])
- {
- p = Allocate_node();
- p -> value = rule_no;
- p -> next = state -> rule_root;
- state -> rule_root = p;
- }
- }
-
- /******************************************************************/
- /* If the state is new or had its reduce map merged with another */
- /* map, we update the reduce map here. */
- /******************************************************************/
- state -> action_count = sp_action_count;
- state -> action_root = NULL;
- for ALL_TERMINALS(i)
- {
- struct action_element *actionp;
-
- if (sp_action[symbol][i] != OMEGA)
- {
- actionp = allocate_action_element();
- actionp -> symbol = i;
- actionp -> action = sp_action[symbol][i];
-
- actionp -> next = state -> action_root;
- state -> action_root = actionp;
- }
- }
-
- return state -> state_number;
- }
-
-
- /*****************************************************************************/
- /* REMOVE_SINGLE_PRODUCTIONS: */
- /*****************************************************************************/
- /* This program is invoked to remove as many single production actions as */
- /* possible for a conflict-free automaton. */
- /*****************************************************************************/
- void remove_single_productions(void)
- {
- struct goto_header_type go_to;
- struct shift_header_type sh;
- struct reduce_header_type red;
-
- struct sp_state_element *state;
- struct node *p,
- *rule_tail;
-
- int rule_head,
- sp_rule_count,
- sp_action_count,
- rule_no,
- state_no,
- symbol,
- lhs_symbol,
- action,
- item_no,
- i,
- j;
-
- BOOLEAN end_node;
-
- short *symbol_list,
- *shift_transition,
- *rule_count;
-
- short shift_table[SHIFT_TABLE_SIZE];
-
- struct new_shift_element
- {
- short link,
- shift_number;
- } *new_shift;
-
- /******************************************************************/
- /* Set up a a pool of temporary space. */
- /******************************************************************/
- reset_temporary_space();
-
- /******************************************************************/
- /* Allocate all other necessary temporary objects. */
- /******************************************************************/
- sp_rules = Allocate_short_array(num_symbols + 1);
- stack = Allocate_short_array(num_symbols + 1);
- index_of = Allocate_short_array(num_symbols + 1);
- next_rule = Allocate_short_array(num_rules + 1);
- rule_list = Allocate_short_array(num_rules + 1);
- symbol_list = Allocate_short_array(num_symbols + 1);
- shift_transition = Allocate_short_array(num_symbols + 1);
- rule_count = Allocate_short_array(num_rules + 1);
-
- new_shift = (struct new_shift_element *)
- calloc(max_la_state + 1,
- sizeof(struct new_shift_element));
- if (new_shift == NULL)
- nospace(__FILE__, __LINE__);
-
- look_ahead = (SET_PTR)
- calloc(1, term_set_size * sizeof(BOOLEAN_CELL));
- if (look_ahead == NULL)
- nospace(__FILE__, __LINE__);
-
- sp_action = (short **)
- calloc(num_symbols + 1, sizeof(short *));
- if (sp_action == NULL)
- nospace(__FILE__, __LINE__);
-
- is_conflict_symbol = (BOOLEAN *)
- calloc(num_symbols + 1, sizeof(BOOLEAN));
- if (is_conflict_symbol == NULL)
- nospace(__FILE__, __LINE__);
-
- sp_table = (struct sp_state_element **)
- calloc(STATE_TABLE_SIZE,
- sizeof(struct sp_state_element *));
- if (sp_table == NULL)
- nospace(__FILE__, __LINE__);
-
- new_action = (struct action_element **)
- calloc(num_states + 1, sizeof(struct action_element *));
- if (new_action == NULL)
- nospace(__FILE__, __LINE__);
-
- update_action = (struct update_action_element **)
- calloc(num_states + 1,
- sizeof(struct update_action_element *));
- if (update_action == NULL)
- nospace(__FILE__, __LINE__);
-
- /******************************************************************/
- /* Initialize all relevant sets and maps to the empty set. */
- /******************************************************************/
- rule_root = NIL;
- symbol_root = NIL;
-
- for ALL_RULES(i)
- rule_list[i] = OMEGA;
-
- for ALL_SYMBOLS(i)
- {
- symbol_list[i] = OMEGA;
- sp_rules[i] = NIL;
- sp_action[i] = NULL;
- }
-
- /******************************************************************/
- /* Construct a set of all symbols used in the right-hand side of */
- /* single production in symbol_list. The variable symbol_root */
- /* points to the root of the list. Also, construct a mapping from */
- /* each symbol into the set of single productions of which it is */
- /* the right-hand side. sp_rules is the base of that map and the */
- /* relevant sets are stored in the vector next_rule. */
- /******************************************************************/
- for ALL_RULES(rule_no)
- {
- if (rules[rule_no].sp)
- {
- i = rhs_sym[rules[rule_no].rhs];
- next_rule[rule_no] = sp_rules[i];
- sp_rules[i] = rule_no;
- if (symbol_list[i] == OMEGA)
- {
- symbol_list[i] = symbol_root;
- symbol_root = i;
- }
- }
- }
-
- /******************************************************************/
- /* Initialize the index_of vector and clear the stack (top). */
- /* Next, iterate over the list of right-hand side symbols used in */
- /* single productions and invoke compute_sp_map to partially */
- /* order these symbols (based on the ::= (or ->) relationship) as */
- /* well as their associated rules. (See compute_sp_map for detail)*/
- /* As the list of rules is constructed as a circular list to keep */
- /* it in proper order, it is turned into a linear list here. */
- /******************************************************************/
- for (i = symbol_root; i != NIL; i = symbol_list[i])
- index_of[i] = OMEGA;
- top = 0;
- for (i = symbol_root; i != NIL; i = symbol_list[i])
- {
- if (index_of[i] == OMEGA)
- compute_sp_map(i);
- }
-
- if (rule_root != NIL) /* make rule_list non-circular */
- {
- rule_no = rule_root;
- rule_root = rule_list[rule_no];
- rule_list[rule_no] = NIL;
- }
-
- /******************************************************************/
- /* Clear out all the sets in sp_rules and using the new revised */
- /* list of SP rules mark the new set of right-hand side symbols. */
- /* Note this code is important for consistency in case we are */
- /* removing single productions in an automaton containing */
- /* conflicts. If an automaton does not contain any conflict, the */
- /* new set of SP rules is always the same as the initial set. */
- /******************************************************************/
- for (i = symbol_root; i != NIL; i = symbol_list[i])
- sp_rules[i] = NIL;
-
- top = 0;
- for (rule_no = rule_root;
- rule_no != NIL; rule_no = rule_list[rule_no])
- {
- top++;
-
- i = rhs_sym[rules[rule_no].rhs];
- sp_rules[i] = OMEGA;
- }
-
- /******************************************************************/
- /* Initialize the base of the hash table for the new SP states. */
- /* Initialize the root pointer for the list of new states. */
- /* Initialize max_sp_state to num_states. It will be incremented */
- /* each time a new state is constructed. */
- /* Initialize the update_action table. */
- /* Initialize the is_conflict_symbol array for non_terminals. */
- /* Since nonterminals are not used as lookahead symbols, they are */
- /* never involved in conflicts. */
- /* Initialize the set/list (symbol_root, symbol_list) to the */
- /* empty set/list. */
- /******************************************************************/
- for (i = 0; i < STATE_TABLE_SIZE; i++)
- sp_table[i] = NULL;
-
- sp_state_root = NULL;
- max_sp_state = num_states;
-
- for ALL_STATES(state_no)
- update_action[state_no] = NULL;
-
- for ALL_NON_TERMINALS(i)
- is_conflict_symbol[i] = FALSE;
-
- symbol_root = NIL;
- for ALL_SYMBOLS(i)
- symbol_list[i] = OMEGA;
-
- /******************************************************************/
- /* Traverse all regular states and process the relevant ones. */
- /******************************************************************/
- for ALL_STATES(state_no)
- {
- struct node *item_ptr;
-
- new_action[state_no] = NULL;
-
- go_to = statset[state_no].go_to;
- sh = shift[statset[state_no].shift_number];
-
- /**************************************************************/
- /* If the state has no goto actions, it is not considered, as */
- /* no single productions could have been introduced in it. */
- /* Otherwise, we initialize index_of to the empty map and */
- /* presume that symbol_list is initialized to the empty set. */
- /**************************************************************/
- if (go_to.size > 0)
- {
- for ALL_SYMBOLS(i)
- index_of[i] = OMEGA;
-
- for ALL_TERMINALS(i)
- is_conflict_symbol[i] = FALSE;
- for (end_node = ((p = conflict_symbols[state_no]) == NULL);
- ! end_node; end_node = (p == conflict_symbols[state_no]))
- {
- p = p -> next;
- is_conflict_symbol[p -> value] = TRUE;
- }
-
- /**********************************************************/
- /* First, use index_of to map each nonterminal symbol on */
- /* which there is a transition in state_no into its index */
- /* in the goto map of state_no. */
- /* Note that this initialization must be executed first */
- /* before we process the next loop, because index_of is */
- /* a global variable that is used in the routine */
- /* compute_sp_action. */
- /**********************************************************/
- for (i = 1; i <= go_to.size; i++)
- index_of[GOTO_SYMBOL(go_to, i)] = i;
-
- /**********************************************************/
- /* Traverse first the goto map, then the shift map and */
- /* for each symbol that is the right-hand side of a single*/
- /* production on which there is a transition, compute the */
- /* lookahead set that can follow this transition and add */
- /* the symbol to the set of candidates (in symbol_list). */
- /**********************************************************/
- for (i = 1; i <= go_to.size; i++)
- {
- symbol = GOTO_SYMBOL(go_to, i);
- if (IS_SP_RHS(symbol))
- {
- compute_sp_action(state_no, symbol,
- GOTO_ACTION(go_to, i));
- symbol_list[symbol] = symbol_root;
- symbol_root = symbol;
- }
- }
-
- for (i = 1; i <= sh.size; i++)
- {
- symbol = SHIFT_SYMBOL(sh, i);
- index_of[symbol] = i;
- if (IS_SP_RHS(symbol))
- {
- compute_sp_action(state_no, symbol,
- SHIFT_ACTION(sh, i));
- symbol_list[symbol] = symbol_root;
- symbol_root = symbol;
- }
- }
-
- /**********************************************************/
- /* We now traverse the set of single productions in order */
- /* and for each rule that was introduced through closure */
- /* in the state (there is an action on both the left- and */
- /* right-hand side)... */
- /**********************************************************/
- for (rule_no = rule_root;
- rule_no != NIL; rule_no = rule_list[rule_no])
- {
- symbol = rhs_sym[rules[rule_no].rhs];
- if (symbol_list[symbol] != OMEGA)
- {
- lhs_symbol = rules[rule_no].lhs;
- if (index_of[lhs_symbol] != OMEGA)
- {
- if (symbol_list[lhs_symbol] == OMEGA)
- {
- compute_sp_action(state_no, lhs_symbol,
- GOTO_ACTION(go_to, index_of[lhs_symbol]));
- symbol_list[lhs_symbol] = symbol_root;
- symbol_root = lhs_symbol;
- }
- /******************************************************/
- /* Copy all reduce actions defined after the */
- /* transition on the left-hand side into the */
- /* corresponding action defined after the transition */
- /* on the right-hand side. If an action is defined */
- /* for the left-hand side - */
- /* */
- /* sp_action[lhs_symbol][i] != OMEGA */
- /* */
- /* - but not for the right-hand side - */
- /* */
- /* sp_action[symbol][i] == OMEGA */
- /* */
- /* it is an indication that after the transition on */
- /* symbol, the action on i is a lookahead shift. In */
- /* that case, no action is copied. */
- /******************************************************/
- for ALL_TERMINALS(i)
- {
- if (sp_action[lhs_symbol][i] != OMEGA &&
- sp_action[symbol][i] != OMEGA)
- sp_action[symbol][i] =
- sp_action[lhs_symbol][i];
- }
- }
- }
- }
-
- /**********************************************************/
- /* For each symbol that is the right-hand side of some SP */
- /* for which a reduce map is defined, we either construct */
- /* a new state if the transition is into a final state, */
- /* or we update the relevant reduce action of the state */
- /* into which the transition is made, otherwise. */
- /* */
- /* When execution of this loop is terminated the set */
- /* symbol_root/symbol_list is reinitialize to the empty */
- /* set. */
- /**********************************************************/
- for (symbol = symbol_root;
- symbol != NIL;
- symbol_list[symbol] = OMEGA, symbol = symbol_root)
- {
- symbol_root = symbol_list[symbol];
-
- if (IS_SP_RHS(symbol))
- {
- if (symbol IS_A_TERMINAL)
- action = SHIFT_ACTION(sh, index_of[symbol]);
- else action = GOTO_ACTION(go_to, index_of[symbol]);
-
- /******************************************************/
- /* If the transition is a lookahead shift, do nothing.*/
- /* If the action is a goto- or shift-reduce, compute */
- /* the relevant rule and item involved. */
- /* Otherwise, the action is a shift or a goto. If the */
- /* transition is into a final state then it is */
- /* processed as the case of read-reduce above. If */
- /* not, we invoke compute_update_actions to update */
- /* the relevant actions. */
- /******************************************************/
- if (action > num_states) /* lookahead shift */
- rule_no = OMEGA;
- else if (action < 0) /* read-reduce action */
- {
- rule_no = -action;
- item_no = adequate_item[rule_no] -> value;
- }
- else /* transition action */
- {
- item_ptr = statset[action].kernel_items;
- item_no = item_ptr -> value;
- if ((item_ptr -> next == NULL) &&
- (item_table[item_no].symbol == empty))
- rule_no = item_table[item_no].rule_number;
- else
- {
- compute_update_actions(state_no, action, symbol);
- rule_no = OMEGA;
- }
- }
-
- /******************************************************/
- /* If we have a valid SP rule we first construct the */
- /* set of rules in the range of the reduce map of the */
- /* right-hand side of the rule. If that set contains */
- /* a single rule then the action on the right-hand */
- /* side is redefined as the same action on the left- */
- /* hand side of the rule in question. Otherwise, we */
- /* create a new state for the final item of the SP */
- /* rule consisting of the reduce map associated with */
- /* the right-hand side of the SP rule and the new */
- /* action on the right-hand side is a transition into */
- /* this new state. */
- /******************************************************/
- if (rule_no != OMEGA)
- {
- if (IS_SP_RULE(rule_no))
- {
- struct action_element *p;
-
- sp_rule_count = 0;
- sp_action_count = 0;
- rule_head = NIL;
-
- for ALL_RULES(i)
- next_rule[i] = OMEGA;
-
- for ALL_TERMINALS(i)
- {
- rule_no = sp_action[symbol][i];
- if (rule_no != OMEGA)
- {
- sp_action_count++;
- if (next_rule[rule_no] == OMEGA)
- {
- sp_rule_count++;
- next_rule[rule_no] = rule_head;
- rule_head = rule_no;
- }
- }
- }
-
- if (sp_rule_count == 1 && IS_SP_RULE(rule_head))
- {
- lhs_symbol = rules[rule_head].lhs;
- action = GOTO_ACTION(go_to,
- index_of[lhs_symbol]);
- }
- else
- {
- action = sp_state_map(rule_head,
- item_no,
- sp_rule_count,
- sp_action_count,
- symbol);
- }
-
- p = allocate_action_element();
- p -> symbol = symbol;
- p -> action = action;
-
- p -> next = new_action[state_no];
- new_action[state_no] = p;
- }
- }
- }
- }
- }
- } /* for ALL_STATES(state_no) */
-
- /******************************************************************/
- /* We are now ready to extend all global maps based on states and */
- /* permanently install the new states. */
- /******************************************************************/
- statset = (struct statset_type *)
- realloc(statset,
- (max_sp_state + 1) * sizeof(struct statset_type));
- if (statset == NULL)
- nospace(__FILE__, __LINE__);
-
- reduce = (struct reduce_header_type *)
- realloc(reduce,
- (max_sp_state + 1) * sizeof(struct reduce_header_type));
- if (reduce == NULL)
- nospace(__FILE__, __LINE__);
-
- if (gd_index != NULL) /* see routine PRODUCE */
- {
- gd_index = (short *)
- realloc(gd_index, (max_sp_state + 2) * sizeof(short));
- if (gd_index == NULL)
- nospace(__FILE__, __LINE__);
-
- /**************************************************************/
- /* Each element gd_index[i] points to the starting location */
- /* of a slice in another array. The last element of the slice */
- /* can be computed as (gd_index[i+1] - 1). After extending */
- /* gd_index, we set each new element to point to the same */
- /* index as its previous element, making it point to a null */
- /* slice. */
- /**************************************************************/
- for (state_no = num_states + 2;
- state_no <= max_sp_state + 1; state_no++)
- gd_index[state_no] = gd_index[state_no - 1];
- }
-
- in_stat = (struct node **)
- realloc(in_stat,
- (max_sp_state + 1) * sizeof(struct node *));
- if (in_stat == NULL)
- nospace(__FILE__, __LINE__);
-
- for (state_no = num_states + 1; state_no <= max_sp_state; state_no++)
- in_stat[state_no] = NULL;
-
- /******************************************************************/
- /* We now adjust all references to a lookahead state. The idea is */
- /* offset the number associated with each lookahead state by the */
- /* number of new SP states that were added. */
- /******************************************************************/
- for (j = 1; j <= num_shift_maps; j++)
- {
- sh = shift[j];
- for (i = 1; i <= sh.size; i++)
- {
- if (SHIFT_ACTION(sh, i) > num_states)
- SHIFT_ACTION(sh, i) += (max_sp_state - num_states);
- }
- }
-
- for (state_no = num_states + 1; state_no <= max_la_state; state_no++)
- {
- if (lastats[state_no].in_state > num_states)
- lastats[state_no].in_state += (max_sp_state - num_states);
- }
-
- lastats -= (max_sp_state - num_states);
- max_la_state += (max_sp_state - num_states);
- SHORT_CHECK(max_la_state);
-
- /******************************************************************/
- /* We now permanently construct all the new SP states. */
- /******************************************************************/
- for (state = sp_state_root; state != NULL; state = state -> next)
- {
- struct action_element *actionp;
-
- int default_rule,
- reduce_size;
-
- state_no = state -> state_number;
-
- /**************************************************************/
- /* These states are identified as special SP states since */
- /* they have no kernel items. They also have no goto and */
- /* shift actions. */
- /**************************************************************/
- statset[state_no].kernel_items = NULL;
- statset[state_no].complete_items = state -> complete_items;
- statset[state_no].go_to.size = 0;
- statset[state_no].go_to.map = NULL;
- statset[state_no].shift_number = 0;
-
- /**************************************************************/
- /* Count the number of actions defined on each rule in the */
- /* range of the reduce map. */
- /**************************************************************/
- for (p = state -> rule_root; p != NULL; p = p -> next)
- rule_count[p -> value] = 0;
-
- for (actionp = state -> action_root;
- actionp != NULL; actionp = actionp -> next)
- rule_count[actionp -> action]++;
-
- /**************************************************************/
- /* Count the total number of reduce actions in the reduce map */
- /* and calculate the default. */
- /**************************************************************/
- reduce_size = 0;
- sp_rule_count = 0;
- for (p = state -> rule_root; p != NULL; rule_tail = p, p = p -> next)
- {
- reduce_size += rule_count[p -> value];
- if (rule_count[p -> value] > sp_rule_count)
- {
- sp_rule_count = rule_count[p -> value];
- default_rule = p -> value;
- }
- }
-
- free_nodes(state -> rule_root, rule_tail);
-
- /**************************************************************/
- /* Construct a permanent reduce map for this SP state. */
- /**************************************************************/
- num_reductions += reduce_size;
-
- red = Allocate_reduce_map(reduce_size);
- reduce[state_no] = red;
- REDUCE_SYMBOL(red, 0) = DEFAULT_SYMBOL;
- REDUCE_RULE_NO(red, 0) = default_rule;
-
- for (actionp = state -> action_root;
- actionp != NULL; actionp = actionp -> next)
- {
- REDUCE_SYMBOL(red, reduce_size) = actionp -> symbol;
- REDUCE_RULE_NO(red, reduce_size) = actionp -> action;
- reduce_size--;
- }
- }
-
- /******************************************************************/
- /* We are now ready to update some old actions and add new ones. */
- /* This may require that we create new shift maps. We */
- /* initialize top to 0 so we can use it as an index to allocate */
- /* elements from new_shift. We also initialize all the elements */
- /* of shift_table to NIL. Shift_table will be used as the base of */
- /* a hash table for the new shift maps. */
- /******************************************************************/
- top = 0;
- for (i = 0; i <= SHIFT_TABLE_UBOUND; i++)
- shift_table[i] = NIL;
-
- /******************************************************************/
- /* At most, the shift array contains 1..num_states elements. As, */
- /* each of these elements might be (theoretically) replaced by a */
- /* new one, we need to double its size. */
- /******************************************************************/
- shift = (struct shift_header_type *)
- realloc(shift,
- 2 * (num_states + 1) * sizeof(struct shift_header_type));
- if (shift == NULL)
- nospace(__FILE__, __LINE__);
-
- /******************************************************************/
- /* For each state with updates or new actions, take appropriate */
- /* actions. */
- /******************************************************************/
- for ALL_STATES(state_no)
- {
- BOOLEAN any_shift_action;
-
- /**************************************************************/
- /* Update reduce actions for final items of single productions*/
- /* that are in non-final states. */
- /**************************************************************/
- if (update_action[state_no] != NULL)
- {
- struct update_action_element *p;
-
- red = reduce[state_no];
- for (i = 1; i <= red.size; i++)
- index_of[REDUCE_SYMBOL(red, i)] = i;
-
- for (p = update_action[state_no]; p != NULL; p = p -> next)
- REDUCE_RULE_NO(red, index_of[p -> symbol]) = p -> action;
- }
-
- /**************************************************************/
- /* Update initial automaton with transitions into new SP */
- /* states. */
- /**************************************************************/
- if (new_action[state_no] != NULL)
- {
- struct action_element *p;
-
- /**********************************************************/
- /* Mark the index of each symbol on which there is a */
- /* transition and copy the shift map into the vector */
- /* shift_transition. */
- /**********************************************************/
- go_to = statset[state_no].go_to;
- for (i = 1; i <= go_to.size; i++)
- index_of[GOTO_SYMBOL(go_to, i)] = i;
-
- sh = shift[statset[state_no].shift_number];
- for (i = 1; i <= sh.size; i++)
- {
- index_of[SHIFT_SYMBOL(sh, i)] = i;
- shift_transition[SHIFT_SYMBOL(sh, i)] = SHIFT_ACTION(sh, i);
- }
-
- /**********************************************************/
- /* Iterate over the new action and update the goto map */
- /* directly for goto actions but update shift_transition */
- /* for shift actions. Also, keep track as to whether or */
- /* not there were any shift transitions at all... */
- /**********************************************************/
- any_shift_action = FALSE;
-
- for (p = new_action[state_no]; p != NULL; p = p -> next)
- {
- if (p -> symbol IS_A_NON_TERMINAL)
- {
- if (GOTO_ACTION(go_to, index_of[p -> symbol]) < 0 &&
- p -> action > 0)
- {
- num_goto_reduces--;
- num_gotos++;
- }
- GOTO_ACTION(go_to, index_of[p -> symbol]) = p -> action;
- }
- else
- {
- if (SHIFT_ACTION(sh, index_of[p -> symbol]) < 0 &&
- p -> action > 0)
- {
- num_shift_reduces--;
- num_shifts++;
- }
- shift_transition[p -> symbol] = p -> action;
-
- any_shift_action = TRUE;
- }
- }
-
- /**********************************************************/
- /* If there were any shift actions, a new shift map may */
- /* have been created. Hash shift_transition into the */
- /* shift hash table. */
- /**********************************************************/
- if (any_shift_action)
- {
- struct shift_header_type sh2;
- unsigned long hash_address;
-
- hash_address = sh.size;
- for (i = 1; i <= sh.size; i++) /* Compute Hash location */
- hash_address += SHIFT_SYMBOL(sh, i);
- hash_address %= SHIFT_TABLE_SIZE;
-
- /**************************************************************/
- /* Search HASH_ADDRESS location for shift map that matches */
- /* the shift map in shift_transition. If a match is found */
- /* we leave the loop prematurely, the search index j is not */
- /* NIL, and it identifies the shift map in the hash table */
- /* that matched the shift_transition. */
- /**************************************************************/
- for (j = shift_table[hash_address];
- j != NIL; j = new_shift[j].link)
- {
- sh2 = shift[new_shift[j].shift_number];
- if (sh.size == sh2.size)
- {
- for (i = 1; i <= sh.size; i++)
- if (SHIFT_ACTION(sh2, i) !=
- shift_transition[SHIFT_SYMBOL(sh2, i)])
- break;
- if (i > sh.size)
- break; /* for (j = shift_table[ ... */
- }
- }
-
- /**************************************************************/
- /* If j == NIL, the map at hand had not yet being inserted in */
- /* the table, it is inserted. Otherwise, we have a match, */
- /* and STATE_NO is reset to share the shift map previously */
- /* inserted that matches its shift map. */
- /**************************************************************/
- if (j == NIL)
- {
- sh2 = Allocate_shift_map(sh.size);
- for (i = 1; i <= sh.size; i++)
- {
- symbol = SHIFT_SYMBOL(sh, i);
- SHIFT_SYMBOL(sh2, i) = symbol;
- SHIFT_ACTION(sh2, i) = shift_transition[symbol];
- }
- num_shift_maps++;
- shift[num_shift_maps] = sh2;
-
- statset[state_no].shift_number = num_shift_maps;
-
- top++;
- new_shift[top].shift_number = num_shift_maps;
-
- new_shift[top].link = shift_table[hash_address];
- shift_table[hash_address] = top;
- }
- else
- {
- statset[state_no].shift_number =
- new_shift[j].shift_number;
- }
- }
- }
- }
-
- /******************************************************************/
- /* Free all nodes used in the construction of the conflict_symbols*/
- /* map as this map is no longer useful and its size is based on */
- /* the base value of num_states. */
- /******************************************************************/
- for ALL_STATES(state_no)
- {
- if (conflict_symbols[state_no] != NULL)
- {
- p = conflict_symbols[state_no] -> next;
- free_nodes(p, conflict_symbols[state_no]);
- }
- }
-
- /******************************************************************/
- /* All updates have now been made, adjust the number of regular */
- /* states to include the new SP states. */
- /******************************************************************/
- num_states = max_sp_state;
-
- /******************************************************************/
- /* Free all temporary space allocated earlier. */
- /******************************************************************/
- ffree(sp_rules);
- ffree(stack);
- ffree(index_of);
- ffree(next_rule);
- ffree(rule_list);
- ffree(symbol_list);
- ffree(shift_transition);
- ffree(rule_count);
- ffree(new_shift);
- ffree(look_ahead);
- for ALL_SYMBOLS(i)
- {
- if (sp_action[i] != NULL)
- {
- ffree(sp_action[i]);
- }
- }
- ffree(sp_action);
- ffree(is_conflict_symbol);
- ffree(sp_table);
- ffree(new_action);
- ffree(update_action);
-
- return;
- }
-