~ubuntu-branches/ubuntu/gutsy/jflex/gutsy

« back to all changes in this revision

Viewing changes to src/JFlex/DFA.java

  • Committer: Bazaar Package Importer
  • Author(s): Takashi Okamoto
  • Date: 2002-02-16 13:38:21 UTC
  • Revision ID: james.westby@ubuntu.com-20020216133821-5wsdprpt9xl7ondr
Tags: upstream-1.3.5
ImportĀ upstreamĀ versionĀ 1.3.5

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 
2
 * JFlex 1.3.5                                                             *
 
3
 * Copyright (C) 1998-2001  Gerwin Klein <lsf@jflex.de>                    *
 
4
 * All rights reserved.                                                    *
 
5
 *                                                                         *
 
6
 * This program is free software; you can redistribute it and/or modify    *
 
7
 * it under the terms of the GNU General Public License. See the file      *
 
8
 * COPYRIGHT for more information.                                         *
 
9
 *                                                                         *
 
10
 * This program is distributed in the hope that it will be useful,         *
 
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of          *
 
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
 
13
 * GNU General Public License for more details.                            *
 
14
 *                                                                         *
 
15
 * You should have received a copy of the GNU General Public License along *
 
16
 * with this program; if not, write to the Free Software Foundation, Inc., *
 
17
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA                 *
 
18
 *                                                                         *
 
19
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
 
20
 
 
21
package JFlex;
 
22
 
 
23
 
 
24
import java.io.*;
 
25
import java.util.*;
 
26
 
 
27
 
 
28
/**
 
29
 * DFA representation in JFlex.
 
30
 * Contains minimization algorithm.
 
31
 *
 
32
 * @author Gerwin Klein
 
33
 * @version JFlex 1.3.5, $Revision: 1.27 $, $Date: 2001/10/08 10:07:58 $
 
34
 */
 
35
final public class DFA implements ErrorMessages { 
 
36
 
 
37
  /**
 
38
   * The initial number of states 
 
39
   */
 
40
  private static final int STATES = 500;
 
41
  
 
42
  /**
 
43
   * The code for "no target state" in the transition table.
 
44
   */
 
45
  public static final int NO_TARGET = -1;
 
46
 
 
47
  /**
 
48
   * table[current_state][character] is the next state for <code>current_state</code>
 
49
   * with input <code>character</code>, <code>NO_TARGET</code> if there is no transition for
 
50
   * this input in <code>current_state</code>
 
51
   */
 
52
  int [][] table;
 
53
 
 
54
 
 
55
  /**
 
56
   * <code>isFinal[state] == true</code> <=> the state <code>state</code> is 
 
57
   * a final state.
 
58
   */
 
59
  boolean [] isFinal;
 
60
 
 
61
  /**
 
62
   * <code>isPushback[state] == true</code> <=> the state <code>state</code> is 
 
63
   * a final state of an expression that can only be matched when followed by
 
64
   * a certain lookaead.
 
65
   */
 
66
  boolean [] isPushback;
 
67
 
 
68
 
 
69
  /**
 
70
   * <code>isLookEnd[state] == true</code> <=> the state <code>state</code> is 
 
71
   * a final state of a lookahead expression.
 
72
   */
 
73
  boolean [] isLookEnd;
 
74
 
 
75
 
 
76
  /**
 
77
   * <code>action[state]</code> is the action that is to be carried out in
 
78
   * state <code>state</code>, <code>null</code> if there is no action.
 
79
   */
 
80
  Action [] action;
 
81
 
 
82
  /**
 
83
   * lexState[i] is the start-state of lexical state i
 
84
   */
 
85
  int lexState [];
 
86
 
 
87
  /**
 
88
   * The number of states in this DFA
 
89
   */
 
90
  int numStates;
 
91
 
 
92
 
 
93
  /**
 
94
   * The current maximum number of input characters
 
95
   */
 
96
  int numInput;
 
97
    
 
98
 
 
99
  /**
 
100
   * all actions that are used in this DFA
 
101
   */
 
102
  Hashtable usedActions = new Hashtable();
 
103
 
 
104
  public DFA(int numLexStates, int numInp) {
 
105
    numInput = numInp; 
 
106
    
 
107
    int statesNeeded = Math.max(numLexStates, STATES);
 
108
    
 
109
    table       = new int [statesNeeded] [numInput];
 
110
    action      = new Action [statesNeeded];
 
111
    isFinal     = new boolean [statesNeeded];
 
112
    isPushback  = new boolean [statesNeeded];
 
113
    isLookEnd   = new boolean [statesNeeded];
 
114
    lexState    = new int [numLexStates];
 
115
    numStates   = 0;
 
116
 
 
117
    for (int i = 0; i < statesNeeded; i++) {
 
118
      for (char j = 0; j < numInput; j++)
 
119
              table [i][j] = NO_TARGET;    
 
120
    }
 
121
  }
 
122
 
 
123
 
 
124
  public void setLexState(int lState, int trueState) {
 
125
    lexState[lState] = trueState;
 
126
  }
 
127
 
 
128
  private void ensureStateCapacity(int newNumStates) {
 
129
 
 
130
    int oldLength = isFinal.length;
 
131
    
 
132
    if ( newNumStates < oldLength ) return;
 
133
      
 
134
    int newLength = oldLength*2;
 
135
    while ( newLength <= newNumStates ) newLength*= 2;
 
136
 
 
137
    boolean [] newFinal    = new boolean [newLength];
 
138
    boolean [] newPushback = new boolean [newLength];
 
139
    boolean [] newLookEnd  = new boolean [newLength];
 
140
    Action  [] newAction   = new Action  [newLength];
 
141
    int [] []  newTable    = new int [newLength] [numInput];
 
142
    
 
143
    System.arraycopy(isFinal,0,newFinal,0,numStates);
 
144
    System.arraycopy(isPushback,0,newPushback,0,numStates);
 
145
    System.arraycopy(isLookEnd,0,newLookEnd,0,numStates);
 
146
    System.arraycopy(action,0,newAction,0,numStates);
 
147
    System.arraycopy(table,0,newTable,0,oldLength);
 
148
  
 
149
    int i,j;
 
150
  
 
151
    for (i = oldLength; i < newLength; i++) {
 
152
      for (j = 0; j < numInput; j++) {
 
153
        newTable[i][j] = NO_TARGET;
 
154
      }
 
155
    }
 
156
 
 
157
    isFinal    = newFinal;
 
158
    isPushback = newPushback;
 
159
    isLookEnd  = newLookEnd;
 
160
    action     = newAction;
 
161
    table      = newTable;
 
162
  }
 
163
 
 
164
 
 
165
  public void setAction(int state, Action stateAction) {
 
166
    action[state]    = stateAction;
 
167
    if (stateAction != null) {
 
168
      isLookEnd[state] = stateAction.isLookAction;
 
169
      usedActions.put(stateAction,stateAction);
 
170
    }
 
171
  }
 
172
  
 
173
  public void setFinal(int state, boolean isFinalState) {
 
174
    isFinal[state] = isFinalState;
 
175
  }
 
176
 
 
177
  public void setPushback(int state, boolean isPushbackState) {
 
178
    isPushback[state] = isPushbackState;
 
179
  }
 
180
 
 
181
 
 
182
  public void addTransition(int start, char input, int dest) {
 
183
    int max = Math.max(start,dest)+1;
 
184
    ensureStateCapacity(max);
 
185
    if (max > numStates) numStates = max;
 
186
 
 
187
    //  Out.debug("Adding DFA transition ("+start+", "+(int)input+", "+dest+")");
 
188
 
 
189
    table[start][input] = dest;
 
190
  }
 
191
 
 
192
 
 
193
 
 
194
  public String toString() {
 
195
    StringBuffer result = new StringBuffer();
 
196
 
 
197
    for (int i=0; i < numStates; i++) {
 
198
      result.append("State ");
 
199
      if ( isFinal[i] ) result.append("[FINAL] ");
 
200
      if ( isPushback[i] ) result.append("[PUSH] ");
 
201
      result.append(i+":"+Out.NL);
 
202
     
 
203
      for (char j=0; j < numInput; j++) {
 
204
              if ( table[i][j] >= 0 ) 
 
205
                result.append("  with "+(int)j+" in "+table[i][j]+Out.NL);      
 
206
      }
 
207
    }
 
208
    
 
209
    return result.toString();    
 
210
  }
 
211
  
 
212
  
 
213
  public void writeDot(File file) {
 
214
    try {
 
215
      PrintWriter writer = new PrintWriter(new FileWriter(file));
 
216
      writer.println(dotFormat());
 
217
      writer.close();
 
218
    }
 
219
    catch (IOException e) {
 
220
      Out.error(ErrorMessages.FILE_WRITE, file);
 
221
      throw new GeneratorException();
 
222
    }
 
223
  }
 
224
 
 
225
 
 
226
  public String dotFormat() {
 
227
    StringBuffer result = new StringBuffer();
 
228
 
 
229
    result.append("digraph DFA {"+Out.NL);
 
230
    result.append("rankdir = LR"+Out.NL);
 
231
 
 
232
    for (int i=0; i < numStates; i++) {
 
233
      if ( isFinal[i] || isPushback[i] ) result.append(i);
 
234
      if ( isFinal[i] ) result.append(" [shape = doublecircle]");
 
235
      if ( isPushback[i] ) result.append(" [shape = box]");
 
236
      if ( isFinal[i] || isPushback[i] ) result.append(Out.NL);
 
237
    }
 
238
 
 
239
    for (int i=0; i < numStates; i++) {
 
240
      for (int input = 0; input < numInput; input++) {
 
241
              if ( table[i][input] >= 0 ) {
 
242
          result.append(i+" -> "+table[i][input]);
 
243
          result.append(" [label=\"["+input+"]\"]"+Out.NL);
 
244
          //          result.append(" [label=\"["+classes.toString(input)+"]\"]\n");
 
245
        }
 
246
      }
 
247
    }
 
248
 
 
249
    result.append("}"+Out.NL);
 
250
 
 
251
    return result.toString();
 
252
  }
 
253
 
 
254
 
 
255
  // check if all actions can actually be matched in this DFA
 
256
  public void checkActions(LexScan scanner, LexParse parser) {
 
257
    EOFActions eofActions = parser.getEOFActions();
 
258
    Enumeration l = scanner.actions.elements();
 
259
 
 
260
    while (l.hasMoreElements()) {
 
261
      Object next = l.nextElement();
 
262
      if ( usedActions.get(next) != next && !eofActions.isEOFAction(next) ) 
 
263
        Out.warning(scanner.file, NEVER_MATCH, ((Action) next).priority-1, -1);
 
264
    }
 
265
  }
 
266
 
 
267
 
 
268
  public void minimize() {
 
269
    
 
270
    int i,j;
 
271
    char c;
 
272
 
 
273
    Out.print(numStates+" states before minimization, ");
 
274
 
 
275
    if (numStates == 0) {
 
276
      Out.error(ZERO_STATES);
 
277
      throw new GeneratorException();
 
278
    }
 
279
 
 
280
    if (Main.no_minimize) {
 
281
      Out.println("minimization skipped.");
 
282
      return;
 
283
    }
 
284
 
 
285
    // notequiv[i][j] == true <=> state i and state j are equivalent
 
286
    boolean [] [] equiv = new boolean [numStates] [];
 
287
 
 
288
    // list[i][j] contains all pairs of states that have to be marked "not equivalent"
 
289
    // if states i and j are recognized to be not equivalent
 
290
    StatePairList [] [] list = new StatePairList [numStates] [];
 
291
 
 
292
    // construct a triangular matrix equiv[i][j] with j < i
 
293
    // and mark pairs (final state, not final state) as not equivalent
 
294
    for (i = 1; i < numStates; i++) {
 
295
      list[i] = new StatePairList[i];
 
296
      equiv[i] = new boolean [i];
 
297
      for (j = 0; j < i; j++) {
 
298
        // i and j are equivalent, iff :
 
299
        // i and j are both final and their actions are equivalent and have same pushback behaviour or
 
300
        // i and j are both not final
 
301
 
 
302
        if ( isFinal[i] && isFinal[j] && (isPushback[i] == isPushback[j]) && (isLookEnd[i] == isLookEnd[j]) ) 
 
303
          equiv[i][j] = action[i].isEquiv(action[j]);        
 
304
        else
 
305
          equiv[i][j] = !isFinal[j] && !isFinal[i] && (isPushback[i] == isPushback[j]) && (isLookEnd[i] == isLookEnd[j]);
 
306
      }
 
307
    }
 
308
 
 
309
 
 
310
    for (i = 1; i < numStates; i++) {
 
311
      
 
312
      // Out.debug("Testing state "+i);
 
313
 
 
314
      for (j = 0; j < i; j++) {
 
315
        
 
316
        if ( equiv[i][j] ) {
 
317
  
 
318
          for (c = 0; c < numInput; c++) {
 
319
  
 
320
            if (equiv[i][j]) {              
 
321
 
 
322
              int p = table[i][c]; 
 
323
              int q = table[j][c];
 
324
              if (p < q) {
 
325
                int t = p;
 
326
                p = q;
 
327
                q = t;
 
328
              }
 
329
              if ( p >= 0 || q >= 0 ) {
 
330
                // Out.debug("Testing input '"+c+"' for ("+i+","+j+")");
 
331
                // Out.debug("Target states are ("+p+","+q+")");
 
332
                if ( p!=q && (p == -1 || q == -1 || !equiv[p][q]) ) {
 
333
                  equiv[i][j] = false;
 
334
                  if (list[i][j] != null) list[i][j].markAll(list,equiv);
 
335
                }
 
336
                // printTable(equiv);
 
337
              } // if (p >= 0) ..
 
338
            } // if (equiv[i][j]
 
339
          } // for (char c = 0; c < numInput ..
 
340
                  
 
341
          // if i and j are still marked equivalent..
 
342
          
 
343
          if ( equiv[i][j] ) {
 
344
         
 
345
            // Out.debug("("+i+","+j+") are still marked equivalent");
 
346
      
 
347
            for (c = 0; c < numInput; c++) {
 
348
      
 
349
              int p = table[i][c];
 
350
              int q = table[j][c];
 
351
              if (p < q) {
 
352
                int t = p;
 
353
                p = q;
 
354
                q = t;
 
355
              }
 
356
              
 
357
              if (p != q && p >= 0 && q >= 0) {
 
358
                if ( list[p][q] == null ) {
 
359
                  list[p][q] = new StatePairList();
 
360
                }
 
361
                list[p][q].addPair(i,j);
 
362
              }
 
363
            }      
 
364
          }
 
365
          else {
 
366
            // Out.debug("("+i+","+j+") are not equivalent");
 
367
          }
 
368
          
 
369
              } // of first if (equiv[i][j])
 
370
      } // of for j
 
371
    } // of for i
 
372
    // }
 
373
 
 
374
    // printTable(equiv);
 
375
 
 
376
    // transform the transition table 
 
377
    
 
378
    // trans[i] is the state j that will replace state i, i.e. when 
 
379
    // states i and j are equivalent
 
380
    int trans [] = new int [numStates];
 
381
    
 
382
    // kill[i] is true, iff state i is redundant and can be removed
 
383
    boolean kill [] = new boolean [numStates];
 
384
    
 
385
    // move[i] is the amount line i has to be moved in the transitiontable
 
386
    // (because states j < i have been removed)
 
387
    int move [] = new int [numStates];
 
388
    
 
389
    // fill arrays trans[] and kill[]
 
390
    for (i = 0; i < numStates; i++) {
 
391
      trans[i] = i;
 
392
      for (j = 0; j < i; j++) 
 
393
        if (equiv[i][j]) {
 
394
          trans[i] = j;
 
395
          kill[i] = true;
 
396
          break;
 
397
        }
 
398
    }
 
399
    
 
400
    // fill array move[]
 
401
    int amount = 0;
 
402
    for (i = 0; i < numStates; i++) {
 
403
      if ( kill[i] ) 
 
404
        amount++;
 
405
      else
 
406
        move[i] = amount;
 
407
    }
 
408
    
 
409
    // j is now the index in the new transition table
 
410
    
 
411
    // the transition table is transformed in place 
 
412
    // (without using a new array)
 
413
    for (i = 0, j = 0; i < numStates; i++) {
 
414
      
 
415
      // we only copy lines that have not been removed
 
416
      if ( !kill[i] ) {
 
417
        
 
418
        // translate the target states 
 
419
        for (c = 0; c < numInput; c++) {
 
420
          if ( table[i][c] >= 0 ) {
 
421
            table[j][c] = trans[ table[i][c] ];
 
422
            table[j][c]-= move[ table[j][c] ];
 
423
          }
 
424
          else {
 
425
            table[j][c] = table[i][c];
 
426
          }
 
427
        }
 
428
 
 
429
        isFinal[j] = isFinal[i];
 
430
        isPushback[j] = isPushback[i];
 
431
        isLookEnd[j] = isLookEnd[i];
 
432
        action[j] = action[i];
 
433
        
 
434
        j++;
 
435
      }
 
436
    }
 
437
    
 
438
    numStates = j;
 
439
    
 
440
    // translate lexical states
 
441
    for (i = 0; i < lexState.length; i++) {
 
442
      lexState[i] = trans[ lexState[i] ];
 
443
      lexState[i]-= move[ lexState[i] ];
 
444
    }
 
445
  
 
446
    Out.println(numStates+" states in minimized DFA");  
 
447
  }
 
448
 
 
449
  public void printTable(boolean [] [] equiv) {
 
450
 
 
451
    Out.dump("Equivalence table is : ");
 
452
    for (int i = 1; i < numStates; i++) {
 
453
      String line = i+" :";
 
454
      for (int j = 0; j < i; j++) {
 
455
              if (equiv[i][j]) 
 
456
                line+= " E";
 
457
        else
 
458
                line+= " x";
 
459
      }
 
460
      Out.dump(line);
 
461
    }
 
462
  }
 
463
 
 
464
}