~ubuntu-branches/ubuntu/raring/weka/raring

« back to all changes in this revision

Viewing changes to weka/core/parser/java_cup/lalr_state.java

  • Committer: Bazaar Package Importer
  • Author(s): Torsten Werner, Soeren Sonnenburg, Torsten Werner
  • Date: 2008-08-10 21:27:05 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080810212705-tr8etpnkdx2ziktp
Tags: 3.5.8-1
[ Soeren Sonnenburg ]
* Bump Standards Version to 3.8.0.
* Remove references to non-free Java in debian/copyright.

[ Torsten Werner ]
* new upstream release
* Switch to openjdk-6.
* Move package to main.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * STANDARD ML OF NEW JERSEY COPYRIGHT NOTICE, LICENSE AND DISCLAIMER.
 
3
 * 
 
4
 * Copyright (c) 1989-1998 by Lucent Technologies
 
5
 * 
 
6
 * Permission to use, copy, modify, and distribute this software and its
 
7
 * documentation for any purpose and without fee is hereby granted, provided
 
8
 * that the above copyright notice appear in all copies and that both the
 
9
 * copyright notice and this permission notice and warranty disclaimer appear
 
10
 * in supporting documentation, and that the name of Lucent Technologies, Bell
 
11
 * Labs or any Lucent entity not be used in advertising or publicity pertaining
 
12
 * to distribution of the software without specific, written prior permission.
 
13
 *
 
14
 * Lucent disclaims all warranties with regard to this software, including all
 
15
 * implied warranties of merchantability and fitness. In no event shall Lucent
 
16
 * be liable for any special, indirect or consequential damages or any damages
 
17
 * whatsoever resulting from loss of use, data or profits, whether in an action
 
18
 * of contract, negligence or other tortious action, arising out of or in
 
19
 * connection with the use or performance of this software. 
 
20
 *
 
21
 * Taken from this URL:
 
22
 * http://www.smlnj.org/license.html
 
23
 * 
 
24
 * This license is compatible with the GNU GPL (see section "Standard ML of New
 
25
 * Jersey Copyright License"):
 
26
 * http://www.gnu.org/licenses/license-list.html#StandardMLofNJ
 
27
 */
 
28
 
 
29
/*
 
30
 * Copyright 1996-1999 by Scott Hudson, Frank Flannery, C. Scott Ananian
 
31
 */
 
32
 
 
33
package weka.core.parser.java_cup;
 
34
 
 
35
import java.util.Hashtable;
 
36
import java.util.Enumeration;
 
37
import java.util.Stack;
 
38
 
 
39
/** This class represents a state in the LALR viable prefix recognition machine.
 
40
 *  A state consists of an LALR item set and a set of transitions to other 
 
41
 *  states under terminal and non-terminal symbols.  Each state represents
 
42
 *  a potential configuration of the parser.  If the item set of a state 
 
43
 *  includes an item such as: <pre>
 
44
 *    [A ::= B * C d E , {a,b,c}]
 
45
 *  </pre> 
 
46
 *  this indicates that when the parser is in this state it is currently 
 
47
 *  looking for an A of the given form, has already seen the B, and would
 
48
 *  expect to see an a, b, or c after this sequence is complete.  Note that
 
49
 *  the parser is normally looking for several things at once (represented
 
50
 *  by several items).  In our example above, the state would also include
 
51
 *  items such as: <pre>
 
52
 *    [C ::= * X e Z, {d}]
 
53
 *    [X ::= * f, {e}]
 
54
 *  </pre> 
 
55
 *  to indicate that it was currently looking for a C followed by a d (which
 
56
 *  would be reduced into a C, matching the first symbol in our production 
 
57
 *  above), and the terminal f followed by e.<p>
 
58
 *
 
59
 *  At runtime, the parser uses a viable prefix recognition machine made up
 
60
 *  of these states to parse.  The parser has two operations, shift and reduce.
 
61
 *  In a shift, it consumes one Symbol and makes a transition to a new state.
 
62
 *  This corresponds to "moving the dot past" a terminal in one or more items
 
63
 *  in the state (these new shifted items will then be found in the state at
 
64
 *  the end of the transition).  For a reduce operation, the parser is 
 
65
 *  signifying that it is recognizing the RHS of some production.  To do this
 
66
 *  it first "backs up" by popping a stack of previously saved states.  It 
 
67
 *  pops off the same number of states as are found in the RHS of the 
 
68
 *  production.  This leaves the machine in the same state is was in when the
 
69
 *  parser first attempted to find the RHS.  From this state it makes a 
 
70
 *  transition based on the non-terminal on the LHS of the production.  This
 
71
 *  corresponds to placing the parse in a configuration equivalent to having 
 
72
 *  replaced all the symbols from the the input corresponding to the RHS with 
 
73
 *  the symbol on the LHS.
 
74
 *
 
75
 * @see     weka.core.parser.java_cup.lalr_item
 
76
 * @see     weka.core.parser.java_cup.lalr_item_set
 
77
 * @see     weka.core.parser.java_cup.lalr_transition
 
78
 * @version last updated: 7/3/96
 
79
 * @author  Frank Flannery
 
80
 *  
 
81
 */
 
82
 
 
83
public class lalr_state {
 
84
  /*-----------------------------------------------------------*/
 
85
  /*--- Constructor(s) ----------------------------------------*/
 
86
  /*-----------------------------------------------------------*/
 
87
       
 
88
  /** Constructor for building a state from a set of items.
 
89
   * @param itms the set of items that makes up this state.
 
90
   */
 
91
  public lalr_state(lalr_item_set itms) throws internal_error
 
92
   {
 
93
     /* don't allow null or duplicate item sets */
 
94
     if (itms == null)
 
95
       throw new internal_error(
 
96
         "Attempt to construct an LALR state from a null item set");
 
97
 
 
98
     if (find_state(itms) != null)
 
99
       throw new internal_error(
 
100
         "Attempt to construct a duplicate LALR state");
 
101
 
 
102
     /* assign a unique index */
 
103
      _index = next_index++;
 
104
 
 
105
     /* store the items */
 
106
     _items = itms;
 
107
 
 
108
     /* add to the global collection, keyed with its item set */
 
109
     _all.put(_items,this);
 
110
   }
 
111
 
 
112
  /*-----------------------------------------------------------*/
 
113
  /*--- (Access to) Static (Class) Variables ------------------*/
 
114
  /*-----------------------------------------------------------*/
 
115
 
 
116
  /** Collection of all states. */
 
117
  protected static Hashtable _all = new Hashtable();
 
118
 
 
119
  /** Collection of all states. */
 
120
  public static Enumeration all() {return _all.elements();}
 
121
 
 
122
  //Hm Added clear  to clear all static fields
 
123
  public static void clear() {
 
124
      _all.clear();
 
125
      _all_kernels.clear();
 
126
      next_index=0;
 
127
  }
 
128
  
 
129
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
130
 
 
131
  /** Indicate total number of states there are. */
 
132
  public static int number() {return _all.size();}
 
133
 
 
134
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
135
 
 
136
  /** Hash table to find states by their kernels (i.e, the original, 
 
137
   *  unclosed, set of items -- which uniquely define the state).  This table 
 
138
   *  stores state objects using (a copy of) their kernel item sets as keys. 
 
139
   */
 
140
  protected static Hashtable _all_kernels = new Hashtable();
 
141
 
 
142
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
143
 
 
144
  /** Find and return state with a given a kernel item set (or null if not 
 
145
   *  found).  The kernel item set is the subset of items that were used to
 
146
   *  originally create the state.  These items are formed by "shifting the
 
147
   *  dot" within items of other states that have a transition to this one.
 
148
   *  The remaining elements of this state's item set are added during closure.
 
149
   * @param itms the kernel set of the state we are looking for. 
 
150
   */
 
151
  public static lalr_state find_state(lalr_item_set itms)
 
152
    {
 
153
      if (itms == null) 
 
154
        return null;
 
155
      else
 
156
        return (lalr_state)_all.get(itms);
 
157
    }
 
158
 
 
159
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
160
 
 
161
  /** Static counter for assigning unique state indexes. */
 
162
  protected static int next_index = 0;
 
163
 
 
164
  /*-----------------------------------------------------------*/
 
165
  /*--- (Access to) Instance Variables ------------------------*/
 
166
  /*-----------------------------------------------------------*/
 
167
 
 
168
  /** The item set for this state. */
 
169
  protected lalr_item_set _items;
 
170
 
 
171
  /** The item set for this state. */
 
172
  public lalr_item_set items() {return _items;}
 
173
 
 
174
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
175
 
 
176
  /** List of transitions out of this state. */
 
177
  protected lalr_transition _transitions = null;
 
178
 
 
179
  /** List of transitions out of this state. */
 
180
  public lalr_transition transitions() {return _transitions;}
 
181
 
 
182
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
183
 
 
184
  /** Index of this state in the parse tables */
 
185
  protected int _index;
 
186
 
 
187
  /** Index of this state in the parse tables */
 
188
  public int index() {return _index;}
 
189
 
 
190
  /*-----------------------------------------------------------*/
 
191
  /*--- Static Methods ----------------------------------------*/
 
192
  /*-----------------------------------------------------------*/
 
193
 
 
194
  /** Helper routine for debugging -- produces a dump of the given state
 
195
    * onto System.out.
 
196
    */
 
197
  protected static void dump_state(lalr_state st) throws internal_error
 
198
    {
 
199
      lalr_item_set itms;
 
200
      lalr_item itm;
 
201
      production_part part;
 
202
 
 
203
      if (st == null) 
 
204
        {
 
205
          System.out.println("NULL lalr_state");
 
206
          return;
 
207
        }
 
208
 
 
209
      System.out.println("lalr_state [" + st.index() + "] {");
 
210
      itms = st.items();
 
211
      for (Enumeration e = itms.all(); e.hasMoreElements(); )
 
212
        {
 
213
          itm = (lalr_item)e.nextElement();
 
214
          System.out.print("  [");
 
215
          System.out.print(itm.the_production().lhs().the_symbol().name());
 
216
          System.out.print(" ::= ");
 
217
          for (int i = 0; i<itm.the_production().rhs_length(); i++)
 
218
            {
 
219
              if (i == itm.dot_pos()) System.out.print("(*) ");
 
220
              part = itm.the_production().rhs(i);
 
221
              if (part.is_action()) 
 
222
                System.out.print("{action} ");
 
223
              else
 
224
                System.out.print(((symbol_part)part).the_symbol().name() + " ");
 
225
            }
 
226
          if (itm.dot_at_end()) System.out.print("(*) ");
 
227
          System.out.println("]");
 
228
        }
 
229
      System.out.println("}");
 
230
    }
 
231
 
 
232
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
233
 
 
234
  /** Propagate lookahead sets through the constructed viable prefix 
 
235
   *  recognizer.  When the machine is constructed, each item that results
 
236
      in the creation of another such that its lookahead is included in the
 
237
      other's will have a propagate link set up for it.  This allows additions
 
238
      to the lookahead of one item to be included in other items that it 
 
239
      was used to directly or indirectly create.
 
240
   */
 
241
  protected static void propagate_all_lookaheads() throws internal_error
 
242
    {
 
243
      /* iterate across all states */
 
244
      for (Enumeration st = all(); st.hasMoreElements(); )
 
245
        {
 
246
          /* propagate lookaheads out of that state */
 
247
          ((lalr_state)st.nextElement()).propagate_lookaheads();
 
248
        }
 
249
    }
 
250
 
 
251
  /*-----------------------------------------------------------*/
 
252
  /*--- General Methods ---------------------------------------*/
 
253
  /*-----------------------------------------------------------*/
 
254
 
 
255
  /** Add a transition out of this state to another.
 
256
   * @param on_sym the symbol the transition is under.
 
257
   * @param to_st  the state the transition goes to.
 
258
   */
 
259
  public void add_transition(symbol on_sym, lalr_state to_st) 
 
260
    throws internal_error
 
261
    {
 
262
      lalr_transition trans;
 
263
 
 
264
      /* create a new transition object and put it in our list */
 
265
      trans = new lalr_transition(on_sym, to_st, _transitions);
 
266
      _transitions = trans;
 
267
    }
 
268
 
 
269
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
270
 
 
271
  /** Build an LALR viable prefix recognition machine given a start 
 
272
   *  production.  This method operates by first building a start state
 
273
   *  from the start production (based on a single item with the dot at
 
274
   *  the beginning and EOF as expected lookahead).  Then for each state
 
275
   *  it attempts to extend the machine by creating transitions out of
 
276
   *  the state to new or existing states.  When considering extension
 
277
   *  from a state we make a transition on each symbol that appears before
 
278
   *  the dot in some item.  For example, if we have the items: <pre>
 
279
   *    [A ::= a b * X c, {d,e}]
 
280
   *    [B ::= a b * X d, {a,b}]
 
281
   *  </pre>
 
282
   *  in some state, then we would be making a transition under X to a new
 
283
   *  state.  This new state would be formed by a "kernel" of items 
 
284
   *  corresponding to moving the dot past the X.  In this case: <pre>
 
285
   *    [A ::= a b X * c, {d,e}]
 
286
   *    [B ::= a b X * Y, {a,b}]
 
287
   *  </pre>
 
288
   *  The full state would then be formed by "closing" this kernel set of 
 
289
   *  items so that it included items that represented productions of things
 
290
   *  the parser was now looking for.  In this case we would items 
 
291
   *  corresponding to productions of Y, since various forms of Y are expected
 
292
   *  next when in this state (see lalr_item_set.compute_closure() for details 
 
293
   *  on closure). <p>
 
294
   *
 
295
   *  The process of building the viable prefix recognizer terminates when no
 
296
   *  new states can be added.  However, in order to build a smaller number of
 
297
   *  states (i.e., corresponding to LALR rather than canonical LR) the state 
 
298
   *  building process does not maintain full loookaheads in all items.  
 
299
   *  Consequently, after the machine is built, we go back and propagate 
 
300
   *  lookaheads through the constructed machine using a call to 
 
301
   *  propagate_all_lookaheads().  This makes use of propagation links 
 
302
   *  constructed during the closure and transition process.
 
303
   *
 
304
   * @param start_prod the start production of the grammar
 
305
   * @see   weka.core.parser.java_cup.lalr_item_set#compute_closure
 
306
   * @see   weka.core.parser.java_cup.lalr_state#propagate_all_lookaheads
 
307
   */
 
308
 
 
309
  public static lalr_state build_machine(production start_prod) 
 
310
    throws internal_error
 
311
    {
 
312
      lalr_state    start_state;
 
313
      lalr_item_set start_items;
 
314
      lalr_item_set new_items;
 
315
      lalr_item_set linked_items;
 
316
      lalr_item_set kernel;
 
317
      Stack         work_stack = new Stack();
 
318
      lalr_state    st, new_st;
 
319
      symbol_set    outgoing;
 
320
      lalr_item     itm, new_itm, existing, fix_itm;
 
321
      symbol        sym, sym2;
 
322
      Enumeration   i, s, fix;
 
323
 
 
324
      /* sanity check */
 
325
      if (start_prod == null)
 
326
        throw new internal_error(
 
327
          "Attempt to build viable prefix recognizer using a null production");
 
328
 
 
329
      /* build item with dot at front of start production and EOF lookahead */
 
330
      start_items = new lalr_item_set();
 
331
 
 
332
      itm = new lalr_item(start_prod);
 
333
      itm.lookahead().add(terminal.EOF);
 
334
 
 
335
      start_items.add(itm);
 
336
 
 
337
      /* create copy the item set to form the kernel */
 
338
      kernel = new lalr_item_set(start_items);
 
339
 
 
340
      /* create the closure from that item set */
 
341
      start_items.compute_closure();
 
342
 
 
343
      /* build a state out of that item set and put it in our work set */
 
344
      start_state = new lalr_state(start_items);
 
345
      work_stack.push(start_state);
 
346
 
 
347
      /* enter the state using the kernel as the key */
 
348
      _all_kernels.put(kernel, start_state);
 
349
 
 
350
      /* continue looking at new states until we have no more work to do */
 
351
      while (!work_stack.empty())
 
352
        {
 
353
          /* remove a state from the work set */
 
354
          st = (lalr_state)work_stack.pop();
 
355
 
 
356
          /* gather up all the symbols that appear before dots */
 
357
          outgoing = new symbol_set();
 
358
          for (i = st.items().all(); i.hasMoreElements(); )
 
359
            {
 
360
              itm = (lalr_item)i.nextElement();
 
361
 
 
362
              /* add the symbol before the dot (if any) to our collection */
 
363
              sym = itm.symbol_after_dot();
 
364
              if (sym != null) outgoing.add(sym);
 
365
            }
 
366
 
 
367
          /* now create a transition out for each individual symbol */
 
368
          for (s = outgoing.all(); s.hasMoreElements(); )
 
369
            {
 
370
              sym = (symbol)s.nextElement();
 
371
 
 
372
              /* will be keeping the set of items with propagate links */
 
373
              linked_items = new lalr_item_set();
 
374
 
 
375
              /* gather up shifted versions of all the items that have this
 
376
                 symbol before the dot */
 
377
              new_items = new lalr_item_set();
 
378
              for (i = st.items().all(); i.hasMoreElements();)
 
379
                {
 
380
                  itm = (lalr_item)i.nextElement();
 
381
 
 
382
                  /* if this is the symbol we are working on now, add to set */
 
383
                  sym2 = itm.symbol_after_dot();
 
384
                  if (sym.equals(sym2))
 
385
                    {
 
386
                      /* add to the kernel of the new state */
 
387
                      new_items.add(itm.shift());
 
388
 
 
389
                      /* remember that itm has propagate link to it */
 
390
                      linked_items.add(itm);
 
391
                    }
 
392
                }
 
393
 
 
394
              /* use new items as state kernel */
 
395
              kernel = new lalr_item_set(new_items);
 
396
 
 
397
              /* have we seen this one already? */
 
398
              new_st = (lalr_state)_all_kernels.get(kernel);
 
399
 
 
400
              /* if we haven't, build a new state out of the item set */
 
401
              if (new_st == null)
 
402
                {
 
403
                  /* compute closure of the kernel for the full item set */
 
404
                  new_items.compute_closure();
 
405
 
 
406
                  /* build the new state */
 
407
                  new_st = new lalr_state(new_items);
 
408
 
 
409
                  /* add the new state to our work set */
 
410
                  work_stack.push(new_st);
 
411
 
 
412
                  /* put it in our kernel table */
 
413
                  _all_kernels.put(kernel, new_st);
 
414
                }
 
415
              /* otherwise relink propagation to items in existing state */
 
416
              else 
 
417
                {
 
418
                  /* walk through the items that have links to the new state */
 
419
                  for (fix = linked_items.all(); fix.hasMoreElements(); )
 
420
                    {
 
421
                      fix_itm = (lalr_item)fix.nextElement();
 
422
 
 
423
                      /* look at each propagate link out of that item */
 
424
                      for (int l =0; l < fix_itm.propagate_items().size(); l++)
 
425
                        {
 
426
                          /* pull out item linked to in the new state */
 
427
                          new_itm = 
 
428
                            (lalr_item)fix_itm.propagate_items().elementAt(l);
 
429
 
 
430
                          /* find corresponding item in the existing state */
 
431
                          existing = new_st.items().find(new_itm);
 
432
 
 
433
                          /* fix up the item so it points to the existing set */
 
434
                          if (existing != null)
 
435
                            fix_itm.propagate_items().setElementAt(existing ,l);
 
436
                        }
 
437
                    }
 
438
                }
 
439
 
 
440
              /* add a transition from current state to that state */
 
441
              st.add_transition(sym, new_st);
 
442
            }
 
443
        }
 
444
 
 
445
      /* all done building states */
 
446
 
 
447
      /* propagate complete lookahead sets throughout the states */
 
448
      propagate_all_lookaheads();
 
449
 
 
450
      return start_state;
 
451
    }
 
452
 
 
453
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
454
 
 
455
  /** Propagate lookahead sets out of this state. This recursively 
 
456
   *  propagates to all items that have propagation links from some item 
 
457
   *  in this state. 
 
458
   */
 
459
  protected void propagate_lookaheads() throws internal_error
 
460
    {
 
461
      /* recursively propagate out from each item in the state */
 
462
      for (Enumeration itm = items().all(); itm.hasMoreElements(); )
 
463
        ((lalr_item)itm.nextElement()).propagate_lookaheads(null);
 
464
    }
 
465
 
 
466
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
467
 
 
468
  /** Fill in the parse table entries for this state.  There are two 
 
469
   *  parse tables that encode the viable prefix recognition machine, an 
 
470
   *  action table and a reduce-goto table.  The rows in each table 
 
471
   *  correspond to states of the machine.  The columns of the action table
 
472
   *  are indexed by terminal symbols and correspond to either transitions 
 
473
   *  out of the state (shift entries) or reductions from the state to some
 
474
   *  previous state saved on the stack (reduce entries).  All entries in the
 
475
   *  action table that are not shifts or reduces, represent errors.    The
 
476
   *  reduce-goto table is indexed by non terminals and represents transitions 
 
477
   *  out of a state on that non-terminal.<p>
 
478
   *  Conflicts occur if more than one action needs to go in one entry of the
 
479
   *  action table (this cannot happen with the reduce-goto table).  Conflicts
 
480
   *  are resolved by always shifting for shift/reduce conflicts and choosing
 
481
   *  the lowest numbered production (hence the one that appeared first in
 
482
   *  the specification) in reduce/reduce conflicts.  All conflicts are 
 
483
   *  reported and if more conflicts are detected than were declared by the
 
484
   *  user, code generation is aborted.
 
485
   *
 
486
   * @param act_table    the action table to put entries in.
 
487
   * @param reduce_table the reduce-goto table to put entries in.
 
488
   */
 
489
  public void build_table_entries(
 
490
    parse_action_table act_table, 
 
491
    parse_reduce_table reduce_table)
 
492
    throws internal_error
 
493
    {
 
494
      parse_action_row our_act_row;
 
495
      parse_reduce_row our_red_row;
 
496
      lalr_item        itm;
 
497
      parse_action     act, other_act;
 
498
      symbol           sym;
 
499
      terminal_set     conflict_set = new terminal_set();
 
500
 
 
501
      /* pull out our rows from the tables */
 
502
      our_act_row = act_table.under_state[index()];
 
503
      our_red_row = reduce_table.under_state[index()];
 
504
 
 
505
      /* consider each item in our state */
 
506
      for (Enumeration i = items().all(); i.hasMoreElements(); )
 
507
        {
 
508
          itm = (lalr_item)i.nextElement();
 
509
         
 
510
 
 
511
          /* if its completed (dot at end) then reduce under the lookahead */
 
512
          if (itm.dot_at_end())
 
513
            {
 
514
              act = new reduce_action(itm.the_production());
 
515
 
 
516
              /* consider each lookahead symbol */
 
517
              for (int t = 0; t < terminal.number(); t++)
 
518
                {
 
519
                  /* skip over the ones not in the lookahead */
 
520
                  if (!itm.lookahead().contains(t)) continue;
 
521
 
 
522
                  /* if we don't already have an action put this one in */
 
523
                  if (our_act_row.under_term[t].kind() == 
 
524
                      parse_action.ERROR)
 
525
                    {
 
526
                      our_act_row.under_term[t] = act;
 
527
                    }
 
528
                  else
 
529
                    {
 
530
                      /* we now have at least one conflict */
 
531
                      terminal term = terminal.find(t);
 
532
                      other_act = our_act_row.under_term[t];
 
533
 
 
534
                      /* if the other act was not a shift */
 
535
                      if ((other_act.kind() != parse_action.SHIFT) && 
 
536
                          (other_act.kind() != parse_action.NONASSOC))
 
537
                        {
 
538
                        /* if we have lower index hence priority, replace it*/
 
539
                          if (itm.the_production().index() < 
 
540
                              ((reduce_action)other_act).reduce_with().index())
 
541
                            {
 
542
                              /* replace the action */
 
543
                              our_act_row.under_term[t] = act;
 
544
                            }
 
545
                        } else {
 
546
                          /*  Check precedences,see if problem is correctable */
 
547
                          if(fix_with_precedence(itm.the_production(), 
 
548
                                                 t, our_act_row, act)) {
 
549
                            term = null;
 
550
                          }
 
551
                        }
 
552
                      if(term!=null) {
 
553
 
 
554
                        conflict_set.add(term);
 
555
                      }
 
556
                    }
 
557
                }
 
558
            }
 
559
        }
 
560
 
 
561
      /* consider each outgoing transition */
 
562
      for (lalr_transition trans=transitions(); trans!=null; trans=trans.next())
 
563
        {
 
564
          /* if its on an terminal add a shift entry */
 
565
          sym = trans.on_symbol();
 
566
          if (!sym.is_non_term())
 
567
            {
 
568
              act = new shift_action(trans.to_state());
 
569
 
 
570
              /* if we don't already have an action put this one in */
 
571
              if ( our_act_row.under_term[sym.index()].kind() == 
 
572
                   parse_action.ERROR)
 
573
                {
 
574
                  our_act_row.under_term[sym.index()] = act;
 
575
                }
 
576
              else
 
577
                {
 
578
                  /* we now have at least one conflict */
 
579
                  production p = ((reduce_action)our_act_row.under_term[sym.index()]).reduce_with();
 
580
 
 
581
                  /* shift always wins */
 
582
                  if (!fix_with_precedence(p, sym.index(), our_act_row, act)) {
 
583
                    our_act_row.under_term[sym.index()] = act;
 
584
                    conflict_set.add(terminal.find(sym.index()));
 
585
                  }
 
586
                }
 
587
            }
 
588
          else
 
589
            {
 
590
              /* for non terminals add an entry to the reduce-goto table */
 
591
              our_red_row.under_non_term[sym.index()] = trans.to_state();
 
592
            }
 
593
        }
 
594
 
 
595
      /* if we end up with conflict(s), report them */
 
596
      if (!conflict_set.empty())
 
597
        report_conflicts(conflict_set);
 
598
    }
 
599
 
 
600
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
601
 
 
602
    
 
603
  /** Procedure that attempts to fix a shift/reduce error by using
 
604
   * precedences.  --frankf 6/26/96
 
605
   *  
 
606
   *  if a production (also called rule) or the lookahead terminal
 
607
   *  has a precedence, then the table can be fixed.  if the rule
 
608
   *  has greater precedence than the terminal, a reduce by that rule
 
609
   *  in inserted in the table.  If the terminal has a higher precedence, 
 
610
   *  it is shifted.  if they have equal precedence, then the associativity
 
611
   *  of the precedence is used to determine what to put in the table:
 
612
   *  if the precedence is left associative, the action is to reduce. 
 
613
   *  if the precedence is right associative, the action is to shift.
 
614
   *  if the precedence is non associative, then it is a syntax error.
 
615
   *
 
616
   *  @param p           the production
 
617
   *  @param term_index  the index of the lokahead terminal
 
618
   *  @param parse_action_row  a row of the action table
 
619
   *  @param act         the rule in conflict with the table entry
 
620
   */
 
621
 
 
622
    protected boolean fix_with_precedence(
 
623
                        production       p,
 
624
                        int              term_index,
 
625
                        parse_action_row table_row,
 
626
                        parse_action     act)
 
627
 
 
628
      throws internal_error {
 
629
 
 
630
      terminal term = terminal.find(term_index);
 
631
 
 
632
      /* if the production has a precedence number, it can be fixed */
 
633
      if (p.precedence_num() > assoc.no_prec) {
 
634
 
 
635
        /* if production precedes terminal, put reduce in table */
 
636
        if (p.precedence_num() > term.precedence_num()) {
 
637
          table_row.under_term[term_index] = 
 
638
            insert_reduce(table_row.under_term[term_index],act);
 
639
          return true;
 
640
        } 
 
641
 
 
642
        /* if terminal precedes rule, put shift in table */
 
643
        else if (p.precedence_num() < term.precedence_num()) {
 
644
          table_row.under_term[term_index] = 
 
645
            insert_shift(table_row.under_term[term_index],act);
 
646
          return true;
 
647
        } 
 
648
        else {  /* they are == precedence */
 
649
 
 
650
          /* equal precedences have equal sides, so only need to 
 
651
             look at one: if it is right, put shift in table */
 
652
          if (term.precedence_side() == assoc.right) {
 
653
          table_row.under_term[term_index] = 
 
654
            insert_shift(table_row.under_term[term_index],act);
 
655
            return true;
 
656
          }
 
657
 
 
658
          /* if it is left, put reduce in table */
 
659
          else if (term.precedence_side() == assoc.left) {
 
660
            table_row.under_term[term_index] = 
 
661
              insert_reduce(table_row.under_term[term_index],act);
 
662
            return true;
 
663
          }
 
664
 
 
665
          /* if it is nonassoc, we're not allowed to have two nonassocs
 
666
             of equal precedence in a row, so put in NONASSOC */
 
667
          else if (term.precedence_side() == assoc.nonassoc) {
 
668
            table_row.under_term[term_index] = new nonassoc_action();
 
669
            return true;
 
670
          } else {
 
671
            /* something really went wrong */
 
672
            throw new internal_error("Unable to resolve conflict correctly");
 
673
          }
 
674
        }
 
675
      }
 
676
      /* check if terminal has precedence, if so, shift, since 
 
677
         rule does not have precedence */
 
678
      else if (term.precedence_num() > assoc.no_prec) {
 
679
         table_row.under_term[term_index] = 
 
680
           insert_shift(table_row.under_term[term_index],act);
 
681
         return true;
 
682
      }
 
683
       
 
684
      /* otherwise, neither the rule nor the terminal has a precedence,
 
685
         so it can't be fixed. */
 
686
      return false;
 
687
    }
 
688
 
 
689
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
690
 
 
691
 
 
692
  /*  given two actions, and an action type, return the 
 
693
      action of that action type.  give an error if they are of
 
694
      the same action, because that should never have tried
 
695
      to be fixed 
 
696
     
 
697
  */
 
698
    protected parse_action insert_action(
 
699
                                        parse_action a1,
 
700
                                        parse_action a2,
 
701
                                        int act_type) 
 
702
      throws internal_error
 
703
    {
 
704
      if ((a1.kind() == act_type) && (a2.kind() == act_type)) {
 
705
        throw new internal_error("Conflict resolution of bogus actions");
 
706
      } else if (a1.kind() == act_type) {
 
707
        return a1;
 
708
      } else if (a2.kind() == act_type) {
 
709
        return a2;
 
710
      } else {
 
711
        throw new internal_error("Conflict resolution of bogus actions");
 
712
      }
 
713
    }
 
714
 
 
715
    /* find the shift in the two actions */
 
716
    protected parse_action insert_shift(
 
717
                                        parse_action a1,
 
718
                                        parse_action a2) 
 
719
      throws internal_error  
 
720
    {
 
721
      return insert_action(a1, a2, parse_action.SHIFT);
 
722
    }
 
723
 
 
724
    /* find the reduce in the two actions */
 
725
    protected parse_action insert_reduce(
 
726
                                        parse_action a1,
 
727
                                        parse_action a2) 
 
728
      throws internal_error
 
729
    {
 
730
      return insert_action(a1, a2, parse_action.REDUCE);
 
731
    }
 
732
 
 
733
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
734
 
 
735
  /** Produce warning messages for all conflicts found in this state.  */
 
736
  protected void report_conflicts(terminal_set conflict_set)
 
737
    throws internal_error
 
738
    {
 
739
      lalr_item    itm, compare;
 
740
      symbol       shift_sym;
 
741
 
 
742
      boolean      after_itm;
 
743
 
 
744
      /* consider each element */
 
745
      for (Enumeration itms = items().all(); itms.hasMoreElements(); )
 
746
        {
 
747
          itm = (lalr_item)itms.nextElement();
 
748
 
 
749
          /* clear the S/R conflict set for this item */
 
750
 
 
751
          /* if it results in a reduce, it could be a conflict */
 
752
          if (itm.dot_at_end())
 
753
            {
 
754
              /* not yet after itm */
 
755
              after_itm = false;
 
756
 
 
757
              /* compare this item against all others looking for conflicts */
 
758
              for (Enumeration comps = items().all(); comps.hasMoreElements(); )
 
759
                {
 
760
                  compare = (lalr_item)comps.nextElement();
 
761
 
 
762
                  /* if this is the item, next one is after it */
 
763
                  if (itm == compare) after_itm = true;
 
764
 
 
765
                  /* only look at it if its not the same item */
 
766
                  if (itm != compare)
 
767
                    {
 
768
                      /* is it a reduce */
 
769
                      if (compare.dot_at_end())
 
770
                        {
 
771
                          /* only look at reduces after itm */
 
772
                          if (after_itm)
 
773
                            /* does the comparison item conflict? */
 
774
                            if (compare.lookahead().intersects(itm.lookahead()))
 
775
                              /* report a reduce/reduce conflict */
 
776
                              report_reduce_reduce(itm, compare);
 
777
                        }
 
778
                    }
 
779
                }
 
780
              /* report S/R conflicts under all the symbols we conflict under */
 
781
              for (int t = 0; t < terminal.number(); t++)
 
782
                if (conflict_set.contains(t))
 
783
                  report_shift_reduce(itm,t);
 
784
            }
 
785
        }
 
786
    }
 
787
 
 
788
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
789
 
 
790
  /** Produce a warning message for one reduce/reduce conflict. 
 
791
   *
 
792
   * @param itm1 first item in conflict.
 
793
   * @param itm2 second item in conflict.
 
794
   */
 
795
  protected void report_reduce_reduce(lalr_item itm1, lalr_item itm2)
 
796
    throws internal_error
 
797
    {
 
798
      boolean comma_flag = false;
 
799
      
 
800
      String message = "*** Reduce/Reduce conflict found in state #"+index()+"\n" +
 
801
      "  between " + itm1.to_simple_string() + "\n" +
 
802
      "  and     " + itm2.to_simple_string() + "\n" +
 
803
          "  under symbols: {";
 
804
      for (int t = 0; t < terminal.number(); t++)
 
805
        {
 
806
          if (itm1.lookahead().contains(t) && itm2.lookahead().contains(t))
 
807
            {
 
808
              if (comma_flag) message+=(", "); else comma_flag = true;
 
809
              message += (terminal.find(t).name());
 
810
            }
 
811
        }
 
812
      message += "}\n  Resolved in favor of ";
 
813
      if (itm1.the_production().index() < itm2.the_production().index())
 
814
        message+="the first production.\n";
 
815
      else
 
816
        message+="the second production.\n";
 
817
 
 
818
      /* count the conflict */
 
819
      emit.num_conflicts++;
 
820
      ErrorManager.getManager().emit_warning(message);
 
821
    }
 
822
 
 
823
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
824
 
 
825
  /** Produce a warning message for one shift/reduce conflict.
 
826
   *
 
827
   * @param red_itm      the item with the reduce.
 
828
   * @param conflict_sym the index of the symbol conflict occurs under.
 
829
   */
 
830
  protected void report_shift_reduce(
 
831
    lalr_item red_itm, 
 
832
    int       conflict_sym)
 
833
    throws internal_error
 
834
    {
 
835
      lalr_item    itm;
 
836
      symbol       shift_sym;
 
837
 
 
838
      /* emit top part of message including the reduce item */
 
839
      String message = "*** Shift/Reduce conflict found in state #"+index()+"\n" +
 
840
      "  between " + red_itm.to_simple_string()+"\n";
 
841
 
 
842
      /* find and report on all items that shift under our conflict symbol */
 
843
      for (Enumeration itms = items().all(); itms.hasMoreElements(); )
 
844
        {
 
845
          itm = (lalr_item)itms.nextElement();
 
846
 
 
847
          /* only look if its not the same item and not a reduce */
 
848
          if (itm != red_itm && !itm.dot_at_end())
 
849
            {
 
850
              /* is it a shift on our conflicting terminal */
 
851
              shift_sym = itm.symbol_after_dot();
 
852
              if (!shift_sym.is_non_term() && shift_sym.index() == conflict_sym)
 
853
                {
 
854
                  /* yes, report on it */
 
855
                  message += "  and     " + itm.to_simple_string()+"\n";
 
856
                }
 
857
            }
 
858
        }
 
859
      message += "  under symbol "+ terminal.find(conflict_sym).name() + "\n"+
 
860
      "  Resolved in favor of shifting.\n";
 
861
 
 
862
      /* count the conflict */
 
863
      emit.num_conflicts++;
 
864
      ErrorManager.getManager().emit_warning(message);
 
865
    }
 
866
 
 
867
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
868
 
 
869
  /** Equality comparison. */
 
870
  public boolean equals(lalr_state other)
 
871
    {
 
872
      /* we are equal if our item sets are equal */
 
873
      return other != null && items().equals(other.items());
 
874
    }
 
875
 
 
876
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
877
 
 
878
  /** Generic equality comparison. */
 
879
  public boolean equals(Object other)
 
880
    {
 
881
      if (!(other instanceof lalr_state))
 
882
        return false;
 
883
      else
 
884
        return equals((lalr_state)other);
 
885
    }
 
886
 
 
887
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
888
 
 
889
  /** Produce a hash code. */
 
890
  public int hashCode()
 
891
    {
 
892
      /* just use the item set hash code */
 
893
      return items().hashCode();
 
894
    }
 
895
 
 
896
  /*. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .*/
 
897
 
 
898
  /** Convert to a string. */
 
899
  public String toString()
 
900
    {
 
901
      String result;
 
902
      lalr_transition tr;
 
903
 
 
904
      /* dump the item set */
 
905
      result = "lalr_state [" + index() + "]: " + _items + "\n";
 
906
 
 
907
      /* do the transitions */
 
908
      for (tr = transitions(); tr != null; tr = tr.next())
 
909
        {
 
910
          result += tr;
 
911
          result += "\n";
 
912
        }
 
913
 
 
914
      return result;
 
915
    }
 
916
 
 
917
  /*-----------------------------------------------------------*/
 
918
}