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

« back to all changes in this revision

Viewing changes to src/JFlex/Emitter.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
import java.io.*;
 
24
import java.util.*;
 
25
import java.text.*;
 
26
import java.net.*;
 
27
 
 
28
/**
 
29
 * This class manages the actual code generation, putting
 
30
 * the scanner together, filling in skeleton sections etc.
 
31
 *
 
32
 * Table compression, String packing etc. is also done here.
 
33
 *
 
34
 * @author Gerwin Klein
 
35
 * @version JFlex 1.3.5, $Revision: 1.74 $, $Date: 2001/10/08 10:07:59 $
 
36
 */
 
37
final public class Emitter {
 
38
    
 
39
  // bit masks for state attributes
 
40
  static final private int FINAL = 1;
 
41
  static final private int PUSHBACK = 2;
 
42
  static final private int LOOKEND = 4;
 
43
  static final private int NOLOOK = 8;
 
44
 
 
45
  // maximum size of the compressed transition table
 
46
  // String constants are stored as UTF8 with 2 bytes length
 
47
  // field in class files. One Unicode char can be up to 3 
 
48
  // UTF8 bytes.
 
49
  // 64K max and some safety 
 
50
  static final int maxSize = 0xFFFF-6;
 
51
 
 
52
  static final private String date = (new SimpleDateFormat()).format(new Date());
 
53
 
 
54
  static public File directory;
 
55
 
 
56
  private File inputFile;
 
57
 
 
58
  private PrintWriter out;
 
59
  private Skeleton skel;
 
60
  private LexScan scanner;
 
61
  private LexParse parser;
 
62
  private DFA dfa;
 
63
 
 
64
  // for switch statement:
 
65
  // table[i][j] is the set of input characters that leads from state i to state j
 
66
  private CharSet table[][];
 
67
 
 
68
  private boolean isTransition[];
 
69
  
 
70
  // noTarget[i] is the set of input characters that have no target state in state i
 
71
  private CharSet noTarget[];
 
72
      
 
73
  // for row killing:
 
74
  private int numRows;
 
75
  private int [] rowMap;
 
76
  private boolean [] rowKilled;
 
77
  
 
78
  // for col killing:
 
79
  private int numCols;
 
80
  private int [] colMap;
 
81
  private boolean [] colKilled;
 
82
  
 
83
  private int numTableChunks;
 
84
 
 
85
  private CharClassIntervall [] intervalls;
 
86
  private int currentIntervall;
 
87
 
 
88
  public Emitter(File inputFile, LexParse parser, DFA dfa) throws IOException {
 
89
 
 
90
    String name = parser.scanner.className+".java";
 
91
 
 
92
    File outputFile = normalize(name, directory, inputFile);
 
93
 
 
94
    Out.println("Writing code to \""+outputFile+"\"");
 
95
    
 
96
    this.out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
 
97
    this.parser = parser;
 
98
    this.scanner = parser.scanner;
 
99
    this.inputFile = inputFile;
 
100
    this.dfa = dfa;
 
101
    this.skel = new Skeleton(out);
 
102
  }
 
103
 
 
104
 
 
105
  /**
 
106
   * Constructs a file in a path or in the same directory as
 
107
   * another file. Makes a backup if the file already exists.
 
108
   *
 
109
   * @param name  the name (without path) of the file
 
110
   * @param path  the path where to construct the file
 
111
   * @param input fallback location if path = <tt>null</tt>
 
112
   *              (expected to be a file in the directory to write to)   
 
113
   */
 
114
  public static File normalize(String name, File path, File input) {
 
115
    File outputFile;
 
116
 
 
117
    if ( directory == null ) 
 
118
      if ( input == null || input.getParent() == null )
 
119
        outputFile = new File(name);
 
120
      else
 
121
        outputFile = new File(input.getParent(), name);
 
122
    else 
 
123
      outputFile = new File(directory, name);
 
124
        
 
125
    if ( outputFile.exists() && !Main.no_backup ) {      
 
126
      File backup = new File( outputFile.toString()+"~" );
 
127
      
 
128
      if ( backup.exists() ) backup.delete();
 
129
      
 
130
      if ( outputFile.renameTo( backup ) )
 
131
        Out.println("Old file \""+outputFile+"\" saved as \""+backup+"\"");
 
132
      else
 
133
        Out.println("Couldn't save old file \""+outputFile+"\", overwriting!");
 
134
    }
 
135
 
 
136
    return outputFile;
 
137
  }
 
138
  
 
139
  private void println() {
 
140
    out.println();
 
141
  }
 
142
 
 
143
  private void println(String line) {
 
144
    out.println(line);
 
145
  }
 
146
 
 
147
  private void println(int i) {
 
148
    out.println(i);
 
149
  }
 
150
 
 
151
  private void print(String line) {
 
152
    out.print(line);
 
153
  }
 
154
 
 
155
  private void print(int i) {
 
156
    out.print(i);
 
157
  }
 
158
 
 
159
  private void print(int i, int tab) {
 
160
    int exp;
 
161
 
 
162
    if (i < 0) 
 
163
      exp = 1;
 
164
    else
 
165
      exp = 10;
 
166
 
 
167
    while (tab-- > 1) {
 
168
      if (Math.abs(i) < exp) print(" ");
 
169
      exp*= 10;
 
170
    }
 
171
 
 
172
    print(i);
 
173
  }
 
174
 
 
175
  private void printUC(int i) {
 
176
    if (i > 255) {
 
177
      print("\\u");
 
178
      if (i < 0x1000) print("0");
 
179
      print(Integer.toHexString(i));
 
180
    }
 
181
    else {
 
182
      print("\\");
 
183
      print(Integer.toOctalString(i));
 
184
    }
 
185
  }
 
186
 
 
187
  private void emitScanError() {
 
188
    print("  private void yy_ScanError(int errorCode)");
 
189
    
 
190
    if (scanner.scanErrorException != null) 
 
191
      print(" throws "+scanner.scanErrorException);
 
192
 
 
193
    println(" {");
 
194
 
 
195
    skel.emitNext();
 
196
 
 
197
    if (scanner.scanErrorException == null)
 
198
      println("    throw new Error(message);");
 
199
    else
 
200
      println("    throw new "+scanner.scanErrorException+"(message);");    
 
201
 
 
202
    skel.emitNext();
 
203
 
 
204
    print("  private void yypushback(int number) ");     
 
205
    
 
206
    if (scanner.scanErrorException == null)
 
207
      println(" {");
 
208
    else       
 
209
      println(" throws "+scanner.scanErrorException+" {");
 
210
  }
 
211
 
 
212
  private void emitMain() {
 
213
    if ( !(scanner.standalone || scanner.debugOption || scanner.cupDebug) ) return;
 
214
 
 
215
    if ( scanner.cupDebug ) {
 
216
      println("  /**");
 
217
      println("   * Converts an int token code into the name of the");
 
218
      println("   * token by reflection on the cup symbol class/interface "+scanner.cupSymbol);
 
219
      println("   *");
 
220
      println("   * This code was contributed by Karl Meissner <meissnersd@yahoo.com>"); 
 
221
      println("   * <a href=\"http://meissner.v0.net/msd.htm\">meissner.v0.net/msd.htm</a>");
 
222
      println("   */");
 
223
      println("  private String getTokenName(int token) {");
 
224
      println("    try {");
 
225
      println("      java.lang.reflect.Field [] class_fields = sym.class.getFields();");
 
226
      println("      for (int i = 0; i < class_fields.length; i++) {");
 
227
      println("        if (class_fields[i].getInt(null) == token) {");
 
228
      println("          return class_fields[i].getName();");
 
229
      println("        }");
 
230
      println("      }");
 
231
      println("    } catch (Exception e) {");
 
232
      println("      e.printStackTrace(System.err);");
 
233
      println("    }");
 
234
      println("");
 
235
      println("    return \"UNKNOWN TOKEN\";");
 
236
      println("  }");
 
237
      println("");
 
238
      println("  /**");
 
239
      println("   * Same as "+scanner.functionName+" but also prints the token to standard out");
 
240
      println("   * for debugging.");
 
241
      println("   *");
 
242
      println("   * This code was contributed by Karl Meissner <meissnersd@yahoo.com>"); 
 
243
      println("   * <a href=\"http://meissner.v0.net/msd.htm\">meissner.v0.net/msd.htm</a>");
 
244
      println("   */");
 
245
 
 
246
      print("  public ");
 
247
      if ( scanner.tokenType == null ) {
 
248
        if ( scanner.isInteger )
 
249
          print( "int" );
 
250
        else 
 
251
          if ( scanner.isIntWrap )
 
252
            print( "Integer" );
 
253
          else
 
254
            print( "Yytoken" );
 
255
      }
 
256
      else
 
257
        print( scanner.tokenType );
 
258
      
 
259
      print(" debug_");
 
260
      
 
261
      print(scanner.functionName);
 
262
      
 
263
      print("() throws java.io.IOException");
 
264
    
 
265
      if ( scanner.lexThrow != null ) {
 
266
        print(", ");
 
267
        print(scanner.lexThrow);
 
268
      }
 
269
 
 
270
      if ( scanner.scanErrorException != null ) {
 
271
        print(", ");
 
272
        print(scanner.scanErrorException);
 
273
      }
 
274
      
 
275
      println(" {");
 
276
 
 
277
      println("    java_cup.runtime.Symbol s = "+scanner.functionName+"();");
 
278
      print("    System.out.println( ");
 
279
      if (scanner.lineCount) print("\"line:\" + (yyline+1) + ");
 
280
      if (scanner.columnCount) print("\" col:\" + (yycolumn+1) + ");
 
281
      println("\" --\"+ yytext() + \"--\" + getTokenName(s.sym) + \"--\");");
 
282
      println("    return s;");
 
283
      println("  }");
 
284
      println("");
 
285
    }
 
286
 
 
287
    if ( scanner.standalone ) {
 
288
      println("  /**");
 
289
      println("   * Runs the scanner on input files.");
 
290
      println("   *");
 
291
      println("   * This is a standalone scanner, i.e. it will print any unmatched");
 
292
      println("   * text to System.out unchanged.");      
 
293
      println("   *");
 
294
      println("   * @param argv   the command line, contains the filenames to run");
 
295
      println("   *               the scanner on.");
 
296
      println("   */");
 
297
    }
 
298
    else {
 
299
      println("  /**");
 
300
      println("   * Runs the scanner on input files.");
 
301
      println("   *");
 
302
      println("   * This main method is the debugging routine for the scanner.");
 
303
      println("   * It prints debugging information about each returned token to");
 
304
      println("   * System.out until the end of file is reached, or an error occured.");
 
305
      println("   *"); 
 
306
      println("   * @param argv   the command line, contains the filenames to run");
 
307
      println("   *               the scanner on."); 
 
308
      println("   */"); 
 
309
    }      
 
310
    
 
311
    println("  public static void main(String argv[]) {");
 
312
    println("    if (argv.length == 0) {");
 
313
    println("      System.out.println(\"Usage : java "+scanner.className+" <inputfile>\");");
 
314
    println("    }");
 
315
    println("    else {");
 
316
    println("      for (int i = 0; i < argv.length; i++) {");
 
317
    println("        "+scanner.className+" scanner = null;");
 
318
    println("        try {");
 
319
    println("          scanner = new "+scanner.className+"( new java.io.FileReader(argv[i]) );");
 
320
 
 
321
    if ( scanner.standalone ) {      
 
322
      println("          while ( !scanner.yy_atEOF ) scanner."+scanner.functionName+"();");      
 
323
    }
 
324
    else if (scanner.cupDebug ) {
 
325
      println("          while ( !scanner.yy_atEOF ) scanner.debug_"+scanner.functionName+"();");            
 
326
    }
 
327
    else {
 
328
      println("          do {");
 
329
      println("            System.out.println(scanner."+scanner.functionName+"());");
 
330
      println("          } while (!scanner.yy_atEOF);");
 
331
      println("");
 
332
    }
 
333
 
 
334
    println("        }");
 
335
    println("        catch (java.io.FileNotFoundException e) {");
 
336
    println("          System.out.println(\"File not found : \\\"\"+argv[i]+\"\\\"\");");
 
337
    println("        }");
 
338
    println("        catch (java.io.IOException e) {");
 
339
    println("          System.out.println(\"IO error scanning file \\\"\"+argv[i]+\"\\\"\");");
 
340
    println("          System.out.println(e);");
 
341
    println("        }"); 
 
342
    println("        catch (Exception e) {");
 
343
    println("          System.out.println(\"Unexpected exception:\");");
 
344
    println("          e.printStackTrace();");
 
345
    println("        }"); 
 
346
    println("      }");
 
347
    println("    }");
 
348
    println("  }");
 
349
    println("");    
 
350
  }
 
351
  
 
352
  private void emitNoMatch() {
 
353
    println("            yy_ScanError(YY_NO_MATCH);");
 
354
  }
 
355
  
 
356
  private void emitNextInput() {
 
357
    println("          if (yy_currentPos_l < yy_endRead_l)");
 
358
    println("            yy_input = yy_buffer_l[yy_currentPos_l++];");
 
359
    println("          else if (yy_atEOF) {");
 
360
    println("            yy_input = YYEOF;");
 
361
    println("            break yy_forAction;");
 
362
    println("          }");
 
363
    println("          else {");
 
364
    println("            // store back cached positions");
 
365
    println("            yy_currentPos  = yy_currentPos_l;");
 
366
    println("            yy_markedPos   = yy_markedPos_l;");
 
367
    if ( scanner.lookAheadUsed ) 
 
368
      println("            yy_pushbackPos = yy_pushbackPos_l;");
 
369
    println("            boolean eof = yy_refill();");
 
370
    println("            // get translated positions and possibly new buffer");
 
371
    println("            yy_currentPos_l  = yy_currentPos;");
 
372
    println("            yy_markedPos_l   = yy_markedPos;");
 
373
    println("            yy_buffer_l      = yy_buffer;");
 
374
    println("            yy_endRead_l     = yy_endRead;");
 
375
    if ( scanner.lookAheadUsed ) 
 
376
      println("            yy_pushbackPos_l = yy_pushbackPos;");
 
377
    println("            if (eof) {");
 
378
    println("              yy_input = YYEOF;");
 
379
    println("              break yy_forAction;");  
 
380
    println("            }");
 
381
    println("            else {");
 
382
    println("              yy_input = yy_buffer_l[yy_currentPos_l++];");
 
383
    println("            }");
 
384
    println("          }"); 
 
385
  }
 
386
 
 
387
  private void emitHeader() {
 
388
    println("/* The following code was generated by JFlex "+Main.version+" on "+date+" */");   
 
389
    println(""); 
 
390
  } 
 
391
 
 
392
  private void emitUserCode() {
 
393
    if ( scanner.userCode.length() > 0 )
 
394
      println(scanner.userCode.toString());
 
395
  }
 
396
 
 
397
  private void emitClassName() {    
 
398
    println("/**");
 
399
    println(" * This class is a scanner generated by ");
 
400
    println(" * <a href=\"http://www.jflex.de/\">JFlex</a> "+Main.version);
 
401
    println(" * on "+date+" from the specification file");    
 
402
    try {
 
403
      println(" * <tt>"+toURL(inputFile)+"</tt>");      
 
404
    }
 
405
    catch (MalformedURLException e) {
 
406
      println(" * (couldn't find spec. file)");
 
407
    }
 
408
    println(" */");
 
409
    
 
410
 
 
411
    if ( scanner.isPublic ) print("public ");
 
412
 
 
413
    if ( scanner.isAbstract) print("abstract ");
 
414
   
 
415
    if ( scanner.isFinal ) print("final ");
 
416
    
 
417
    print("class ");
 
418
    print(scanner.className);
 
419
    
 
420
    if ( scanner.isExtending != null ) {
 
421
      print(" extends ");
 
422
      print(scanner.isExtending);
 
423
    }
 
424
 
 
425
    if ( scanner.isImplementing != null ) {
 
426
      print(" implements ");
 
427
      print(scanner.isImplementing);
 
428
    }   
 
429
    
 
430
    println(" {");
 
431
  }  
 
432
 
 
433
  private void emitLexicalStates() {
 
434
    Enumeration stateNames = scanner.states.names();
 
435
    
 
436
    while ( stateNames.hasMoreElements() ) {
 
437
      String name = (String) stateNames.nextElement();
 
438
      
 
439
      int num = scanner.states.getNumber(name).intValue();
 
440
 
 
441
      if (scanner.bolUsed)      
 
442
        println("  final public static int "+name+" = "+2*num+";");
 
443
      else
 
444
        println("  final public static int "+name+" = "+dfa.lexState[2*num]+";");
 
445
    }
 
446
    
 
447
    if (scanner.bolUsed) {
 
448
      println("");
 
449
      println("  /**");
 
450
      println("   * YY_LEXSTATE[l] is the state in the DFA for the lexical state l");
 
451
      println("   * YY_LEXSTATE[l+1] is the state in the DFA for the lexical state l");
 
452
      println("   *                  at the beginning of a line");
 
453
      println("   * l is of the form l = 2*k, k a non negative integer");
 
454
      println("   */");
 
455
      println("  private final static int YY_LEXSTATE[] = { ");
 
456
  
 
457
      int i, j = 0;
 
458
      print("    ");
 
459
 
 
460
      for (i = 0; i < dfa.lexState.length-1; i++) {
 
461
        print( dfa.lexState[i], 2 );
 
462
 
 
463
        print(", ");
 
464
 
 
465
        if (++j >= 16) {
 
466
          println();
 
467
          print("    ");
 
468
          j = 0;
 
469
        }
 
470
      }
 
471
            
 
472
      println( dfa.lexState[i] );
 
473
      println("  };");
 
474
 
 
475
    }
 
476
  }
 
477
 
 
478
  private void emitDynInitHead(int chunk) {
 
479
    println("  /** ");
 
480
    println("   * The packed transition table of the DFA (part "+chunk+")");
 
481
    println("   */");
 
482
    println("  final private static String yy_packed"+chunk+" = ");    
 
483
  }
 
484
 
 
485
  /**
 
486
   * Calculates the number of bytes a Unicode character
 
487
   * would have in UTF8 representation in a class file.
 
488
   *
 
489
   * @param value  the char code of the Unicode character
 
490
   *               (expected to satisfy 0 <= value <= 0xFFFF)
 
491
   *
 
492
   * @return length of UTF8 representation.
 
493
   */
 
494
  private int UTF8Length(int value) {
 
495
    if (value < 0 || value > 0xFFFF) throw new Error("not a char value ("+value+")");
 
496
 
 
497
    // see JVM spec ļæ½4.4.7, p 111
 
498
    if (value == 0) return 2;
 
499
    if (value <= 0x7F) return 1;
 
500
 
 
501
    // workaround for javac bug (up to jdk 1.3):
 
502
    if (value <  0x0400) return 2;
 
503
    if (value <= 0x07FF) return 3;
 
504
 
 
505
    // correct would be:
 
506
    // if (value <= 0x7FF) return 2;
 
507
    return 3;
 
508
  }
 
509
 
 
510
  private void emitDynamicInit() {    
 
511
    emitDynInitHead(numTableChunks++);
 
512
 
 
513
    int i,c;
 
514
    int n = 0;
 
515
    print("    \"");
 
516
    
 
517
    int count = 0;
 
518
    int value = dfa.table[0][0];
 
519
 
 
520
    // the current length of the resulting UTF8 String constant
 
521
    // in the class file. Must be smaller than 64K
 
522
    int UTF8Length = 0;    
 
523
    
 
524
    for (i = 0; i < dfa.numStates; i++) {
 
525
      if ( !rowKilled[i] ) {
 
526
        for (c = 0; c < dfa.numInput; c++) {
 
527
          if ( !colKilled[c] ) {
 
528
            if (dfa.table[i][c] == value) count++;
 
529
            else {
 
530
              printUC( count );
 
531
              printUC( value+1 );
 
532
 
 
533
              // calculate resulting UTF8 size
 
534
              UTF8Length += UTF8Length(count)+UTF8Length(value+1);
 
535
 
 
536
              n+= 2;
 
537
              if (n >= 16) {
 
538
                print("\"+");
 
539
                println();
 
540
                print("    \"");
 
541
                n = 0;
 
542
              }
 
543
              count = 1;
 
544
              value = dfa.table[i][c];
 
545
              
 
546
              if (UTF8Length >= maxSize) {
 
547
                // System.out.println("UTF8 size chunk "+(numTableChunks-1)+": "+Integer.toHexString(UTF8Length));
 
548
                UTF8Length = 0;
 
549
                println("\";");
 
550
                println();
 
551
                emitDynInitHead(numTableChunks++);
 
552
                print("    \"");
 
553
                n = 0;
 
554
              }
 
555
            }
 
556
          }
 
557
        }
 
558
      }
 
559
    }
 
560
 
 
561
    printUC( count );
 
562
    printUC( value+1 );
 
563
 
 
564
    UTF8Length += UTF8Length(count)+UTF8Length(value+1);
 
565
 
 
566
    // System.out.println("UTF8 size chunk "+(numTableChunks-1)+": "+Integer.toHexString(UTF8Length));
 
567
 
 
568
    println("\";");
 
569
 
 
570
    println();
 
571
    println("  /** ");
 
572
    println("   * The transition table of the DFA");
 
573
    println("   */");
 
574
    println("  final private static int yytrans [] = yy_unpack();");
 
575
    println();
 
576
  }
 
577
 
 
578
  private void emitDynamicInitFunction() {
 
579
    println();
 
580
    println("  /** ");
 
581
    println("   * Unpacks the split, compressed DFA transition table.");
 
582
    println("   *");
 
583
    println("   * @return the unpacked transition table");
 
584
    println("   */");
 
585
    println("  private static int [] yy_unpack() {");
 
586
    println("    int [] trans = new int["+(numRows*numCols)+"];");
 
587
    println("    int offset = 0;");
 
588
 
 
589
    for (int i = 0; i < numTableChunks; i++) {
 
590
      println("    offset = yy_unpack(yy_packed"+i+", offset, trans);");
 
591
    }
 
592
 
 
593
    println("    return trans;");
 
594
    println("  }");
 
595
 
 
596
    println();
 
597
    println("  /** ");
 
598
    println("   * Unpacks the compressed DFA transition table.");
 
599
    println("   *");
 
600
    println("   * @param packed   the packed transition table");
 
601
    println("   * @return         the index of the last entry");
 
602
    println("   */");
 
603
    println("  private static int yy_unpack(String packed, int offset, int [] trans) {");
 
604
    println("    int i = 0;       /* index in packed string  */");
 
605
    println("    int j = offset;  /* index in unpacked array */");
 
606
    println("    int l = packed.length();");
 
607
    println("    while (i < l) {");
 
608
    println("      int count = packed.charAt(i++);");
 
609
    println("      int value = packed.charAt(i++);");
 
610
    println("      value--;");
 
611
    println("      do trans[j++] = value; while (--count > 0);");
 
612
    println("    }");
 
613
    println("    return j;");
 
614
    println("  }");
 
615
  }
 
616
 
 
617
  private void emitCharMapInitFunction() {
 
618
 
 
619
    CharClasses cl = parser.getCharClasses();
 
620
    
 
621
    if ( cl.getMaxCharCode() < 256 ) return;
 
622
 
 
623
    println("");
 
624
    println("  /** ");
 
625
    println("   * Unpacks the compressed character translation table.");
 
626
    println("   *");
 
627
    println("   * @param packed   the packed character translation table");
 
628
    println("   * @return         the unpacked character translation table");
 
629
    println("   */");
 
630
    println("  private static char [] yy_unpack_cmap(String packed) {");
 
631
    println("    char [] map = new char[0x10000];");
 
632
    println("    int i = 0;  /* index in packed string  */");
 
633
    println("    int j = 0;  /* index in unpacked array */");
 
634
    println("    while (i < "+2*intervalls.length+") {");
 
635
    println("      int  count = packed.charAt(i++);");
 
636
    println("      char value = packed.charAt(i++);");
 
637
    println("      do map[j++] = value; while (--count > 0);");
 
638
    println("    }");
 
639
    println("    return map;");
 
640
    println("  }");
 
641
  }
 
642
 
 
643
  private void emitYYTrans() {    
 
644
 
 
645
    int i,c;
 
646
    int n = 0;
 
647
    
 
648
    println("  /** ");
 
649
    println("   * The transition table of the DFA");
 
650
    println("   */");
 
651
    println("  final private static int yytrans [] = {");
 
652
 
 
653
    boolean isFirstRow = true;
 
654
    
 
655
    print("    ");
 
656
    for (i = 0; i < dfa.numStates; i++) {
 
657
      
 
658
      if ( !rowKilled[i] ) {        
 
659
        for (c = 0; c < dfa.numInput; c++) {          
 
660
          if ( !colKilled[c] ) {            
 
661
            if (n >= 10) {
 
662
              println();
 
663
              print("    ");
 
664
              n = 0;
 
665
            }
 
666
            print( dfa.table[i][c] );
 
667
            if (i != dfa.numStates-1 || c != dfa.numInput-1)
 
668
              print( ", ");
 
669
            n++;
 
670
          }
 
671
        }
 
672
      }
 
673
    }
 
674
 
 
675
    println();
 
676
    println("  };");
 
677
  }
 
678
  
 
679
  private void emitRowMap() {
 
680
    reduceRows();
 
681
    
 
682
    println("  /** ");
 
683
    println("   * Translates a state to a row index in the transition table");    
 
684
    println("   */");
 
685
    println("  final private static int yy_rowMap [] = { ");
 
686
 
 
687
    int i;
 
688
    int n = 0;
 
689
    print("    ");
 
690
    
 
691
    for (i = 0; i < dfa.numStates-1; i++) {      
 
692
      print( rowMap[i]*numCols, 5 );
 
693
      print( ", " );
 
694
      
 
695
      if (++n >= 10) {
 
696
        println();
 
697
        print("    ");
 
698
        n = 0;
 
699
      }
 
700
    }
 
701
    
 
702
    print( rowMap[i]*numCols, 5 );
 
703
    println();
 
704
    println("  };");
 
705
    println();
 
706
   
 
707
    if (scanner.packed)
 
708
      emitDynamicInit();
 
709
    else
 
710
      emitYYTrans();
 
711
  }
 
712
 
 
713
  private void emitCharMapArrayUnPacked() {
 
714
   
 
715
    CharClasses cl = parser.getCharClasses();
 
716
    intervalls = cl.getIntervalls();
 
717
    
 
718
    println("");
 
719
    println("  /** ");
 
720
    println("   * Translates characters to character classes");
 
721
    println("   */");
 
722
    println("  final private static char [] yycmap = {");
 
723
  
 
724
    int n = 0;  // numbers of entries in current line    
 
725
    print("    ");
 
726
    
 
727
    int max =  cl.getMaxCharCode();
 
728
    int i = 0;     
 
729
    while ( i < intervalls.length && intervalls[i].start <= max ) {
 
730
 
 
731
      int end = Math.min(intervalls[i].end, max);
 
732
      for (int c = intervalls[i].start; c <= end; c++) {
 
733
 
 
734
        print(colMap[intervalls[i].charClass], 2);
 
735
 
 
736
        if (c < max) {
 
737
          print(", ");        
 
738
          if ( ++n >= 16 ) { 
 
739
            println();
 
740
            print("    ");
 
741
            n = 0; 
 
742
          }
 
743
        }
 
744
      }
 
745
 
 
746
      i++;
 
747
    }
 
748
 
 
749
    println();
 
750
    println("  };");
 
751
    println();
 
752
  }
 
753
 
 
754
  private void emitCharMapArray() {       
 
755
    CharClasses cl = parser.getCharClasses();
 
756
 
 
757
    if ( cl.getMaxCharCode() < 256 ) {
 
758
      emitCharMapArrayUnPacked();
 
759
      return;
 
760
    }
 
761
 
 
762
    // ignores cl.getMaxCharCode(), emits all intervalls instead
 
763
 
 
764
    intervalls = cl.getIntervalls();
 
765
    
 
766
    println("");
 
767
    println("  /** ");
 
768
    println("   * Translates characters to character classes");
 
769
    println("   */");
 
770
    println("  final private static String yycmap_packed = ");
 
771
  
 
772
    int n = 0;  // numbers of entries in current line    
 
773
    print("    \"");
 
774
    
 
775
    int i = 0; 
 
776
    while ( i < intervalls.length-1 ) {
 
777
      int count = intervalls[i].end-intervalls[i].start+1;
 
778
      int value = colMap[intervalls[i].charClass];
 
779
      
 
780
      printUC(count);
 
781
      printUC(value);
 
782
 
 
783
      if ( ++n >= 10 ) { 
 
784
        println("\"+");
 
785
        print("    \"");
 
786
        n = 0; 
 
787
      }
 
788
 
 
789
      i++;
 
790
    }
 
791
 
 
792
    printUC(intervalls[i].end-intervalls[i].start+1);
 
793
    printUC(colMap[intervalls[i].charClass]);
 
794
 
 
795
    println("\";");
 
796
    println();
 
797
 
 
798
    println("  /** ");
 
799
    println("   * Translates characters to character classes");
 
800
    println("   */");
 
801
    println("  final private static char [] yycmap = yy_unpack_cmap(yycmap_packed);");
 
802
    println();
 
803
  }
 
804
 
 
805
  private void emitAttributes() {
 
806
    
 
807
    if (dfa.numStates <= 0) return;
 
808
    
 
809
    println("  /**");
 
810
    println("   * YY_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>");
 
811
    println("   */");
 
812
    println("  private final static byte YY_ATTRIBUTE[] = {");
 
813
 
 
814
    int i,j, attribute;
 
815
    print("    ");
 
816
    
 
817
    for (i = 0, j = 0;  i < dfa.numStates-1; i++, j++) {
 
818
      
 
819
      if (j >= 16) {
 
820
        j = 0;
 
821
        println();
 
822
        print("    ");
 
823
      }
 
824
      
 
825
      attribute = 0;      
 
826
      if ( dfa.isFinal[i]    ) attribute = FINAL;
 
827
      if ( dfa.isPushback[i] ) attribute|= PUSHBACK;
 
828
      if ( dfa.isLookEnd[i]  ) attribute|= LOOKEND;
 
829
      if ( !isTransition[i]  ) attribute|= NOLOOK;
 
830
 
 
831
      print( attribute, 2 );
 
832
      print( ", " );      
 
833
    }
 
834
    
 
835
    attribute = 0;      
 
836
    if ( dfa.isFinal[dfa.numStates-1]    ) attribute = FINAL;
 
837
    if ( dfa.isPushback[dfa.numStates-1] ) attribute|= PUSHBACK;
 
838
    if ( dfa.isLookEnd[dfa.numStates-1]  ) attribute|= LOOKEND;
 
839
    if ( !isTransition[dfa.numStates-1]  ) attribute|= NOLOOK;
 
840
    
 
841
    print( attribute, 2 );
 
842
    println();
 
843
    println("  };");
 
844
    println();
 
845
  }
 
846
 
 
847
 
 
848
  private void emitClassCode() {
 
849
    if ( scanner.eofCode != null ) {
 
850
      println("  /** denotes if the user-EOF-code has already been executed */");
 
851
      println("  private boolean yy_eof_done;");
 
852
      println("");
 
853
    }
 
854
    
 
855
    if ( scanner.classCode != null ) {
 
856
      println("  /* user code: */");
 
857
      println(scanner.classCode);
 
858
    }
 
859
  }
 
860
 
 
861
  private void emitConstructorDecl() {
 
862
    
 
863
    print("  ");
 
864
 
 
865
    if ( scanner.isPublic ) print("public ");   
 
866
    print( scanner.className );      
 
867
    print("(java.io.Reader in)");
 
868
    
 
869
    if ( scanner.initThrow != null ) {
 
870
      print(" throws ");
 
871
      print( scanner.initThrow );
 
872
    }
 
873
    
 
874
    println(" {");
 
875
 
 
876
    if ( scanner.initCode != null ) {
 
877
      print("  ");
 
878
      print( scanner.initCode );
 
879
    }
 
880
 
 
881
    println("    this.yy_reader = in;");
 
882
 
 
883
    println("  }");
 
884
    println();
 
885
 
 
886
    
 
887
    println("  /**");
 
888
    println("   * Creates a new scanner.");
 
889
    println("   * There is also java.io.Reader version of this constructor.");
 
890
    println("   *");
 
891
    println("   * @param   in  the java.io.Inputstream to read input from.");
 
892
    println("   */");
 
893
 
 
894
    print("  ");
 
895
    if ( scanner.isPublic ) print("public ");    
 
896
    print( scanner.className );      
 
897
    print("(java.io.InputStream in)");
 
898
    
 
899
    if ( scanner.initThrow != null ) {
 
900
      print(" throws ");
 
901
      print( scanner.initThrow );
 
902
    }
 
903
    
 
904
    println(" {");    
 
905
    println("    this(new java.io.InputStreamReader(in));");
 
906
    println("  }");
 
907
  }
 
908
 
 
909
 
 
910
  private void emitDoEOF() {
 
911
    if ( scanner.eofCode == null ) return;
 
912
    
 
913
    println("  /**");
 
914
    println("   * Contains user EOF-code, which will be executed exactly once,");
 
915
    println("   * when the end of file is reached");
 
916
    println("   */");
 
917
    
 
918
    print("  private void yy_do_eof()");
 
919
    
 
920
    if ( scanner.eofThrow != null ) {
 
921
      print(" throws ");
 
922
      print(scanner.eofThrow);
 
923
    }
 
924
    
 
925
    println(" {");
 
926
    
 
927
    println("    if (!yy_eof_done) {");
 
928
    println("      yy_eof_done = true;");
 
929
    println("    "+scanner.eofCode );
 
930
    println("    }");
 
931
    println("  }");
 
932
    println("");
 
933
    println("");
 
934
  }
 
935
 
 
936
  private void emitLexFunctHeader() {
 
937
    
 
938
    print("  public ");
 
939
    
 
940
    if ( scanner.tokenType == null ) {
 
941
      if ( scanner.isInteger )
 
942
        print( "int" );
 
943
      else 
 
944
      if ( scanner.isIntWrap )
 
945
        print( "Integer" );
 
946
      else
 
947
        print( "Yytoken" );
 
948
    }
 
949
    else
 
950
      print( scanner.tokenType );
 
951
      
 
952
    print(" ");
 
953
    
 
954
    print(scanner.functionName);
 
955
      
 
956
    print("() throws java.io.IOException");
 
957
    
 
958
    if ( scanner.lexThrow != null ) {
 
959
      print(", ");
 
960
      print(scanner.lexThrow);
 
961
    }
 
962
 
 
963
    if ( scanner.scanErrorException != null ) {
 
964
      print(", ");
 
965
      print(scanner.scanErrorException);
 
966
    }
 
967
    
 
968
    println(" {");
 
969
    
 
970
    skel.emitNext();
 
971
 
 
972
    if ( scanner.useRowMap ) {
 
973
      println("    int [] yytrans_l = yytrans;");
 
974
      println("    int [] yy_rowMap_l = yy_rowMap;");
 
975
      println("    byte [] yy_attr_l = YY_ATTRIBUTE;");
 
976
 
 
977
    }
 
978
 
 
979
    if ( scanner.lookAheadUsed ) {
 
980
      println("    int yy_pushbackPos_l = yy_pushbackPos = -1;");
 
981
      println("    boolean yy_was_pushback;");
 
982
    }
 
983
 
 
984
    skel.emitNext();    
 
985
        
 
986
    if ( scanner.charCount ) {
 
987
      println("      yychar+= yy_markedPos_l-yy_startRead;");
 
988
      println("");
 
989
    }
 
990
    
 
991
    if ( scanner.lineCount || scanner.columnCount ) {
 
992
      println("      boolean yy_r = false;");
 
993
      println("      for (yy_currentPos_l = yy_startRead; yy_currentPos_l < yy_markedPos_l;");
 
994
      println("                                                             yy_currentPos_l++) {");
 
995
      println("        switch (yy_buffer_l[yy_currentPos_l]) {");      
 
996
      println("        case '\\u000B':"); 
 
997
      println("        case '\\u000C':"); 
 
998
      println("        case '\\u0085':");
 
999
      println("        case '\\u2028':"); 
 
1000
      println("        case '\\u2029':"); 
 
1001
      if ( scanner.lineCount )
 
1002
        println("          yyline++;");
 
1003
      if ( scanner.columnCount )
 
1004
        println("          yycolumn = 0;");
 
1005
      println("          yy_r = false;");
 
1006
      println("          break;");      
 
1007
      println("        case '\\r':");
 
1008
      if ( scanner.lineCount )
 
1009
        println("          yyline++;");
 
1010
      if ( scanner.columnCount )
 
1011
        println("          yycolumn = 0;");
 
1012
      println("          yy_r = true;");
 
1013
      println("          break;");
 
1014
      println("        case '\\n':");
 
1015
      println("          if (yy_r)");
 
1016
      println("            yy_r = false;");
 
1017
      println("          else {");
 
1018
      if ( scanner.lineCount )
 
1019
        println("            yyline++;");
 
1020
      if ( scanner.columnCount )
 
1021
        println("            yycolumn = 0;");
 
1022
      println("          }");
 
1023
      println("          break;");
 
1024
      println("        default:");
 
1025
      println("          yy_r = false;");
 
1026
      if ( scanner.columnCount ) 
 
1027
        println("          yycolumn++;");
 
1028
      println("        }");
 
1029
      println("      }");
 
1030
      println();
 
1031
 
 
1032
      if ( scanner.lineCount ) {
 
1033
        println("      if (yy_r) {");
 
1034
        println("        // peek one character ahead if it is \\n (if we have counted one line too much)");
 
1035
        println("        boolean yy_peek;");
 
1036
        println("        if (yy_markedPos_l < yy_endRead_l)");
 
1037
        println("          yy_peek = yy_buffer_l[yy_markedPos_l] == '\\n';");
 
1038
        println("        else if (yy_atEOF)");
 
1039
        println("          yy_peek = false;");
 
1040
        println("        else {");
 
1041
        println("          boolean eof = yy_refill();");
 
1042
        println("          yy_markedPos_l = yy_markedPos;");
 
1043
        println("          yy_buffer_l = yy_buffer;");
 
1044
        println("          if (eof) ");
 
1045
        println("            yy_peek = false;");
 
1046
        println("          else ");
 
1047
        println("            yy_peek = yy_buffer_l[yy_markedPos_l] == '\\n';");
 
1048
        println("        }");
 
1049
        println("        if (yy_peek) yyline--;");
 
1050
        println("      }");
 
1051
      }
 
1052
    }
 
1053
 
 
1054
    if ( scanner.bolUsed ) {
 
1055
      // yy_markedPos > yy_startRead <=> last match was not empty
 
1056
      // if match was empty, last value of yy_atBOL can be used
 
1057
      // yy_startRead is always >= 0
 
1058
      println("      if (yy_markedPos_l > yy_startRead) {");
 
1059
      println("        switch (yy_buffer_l[yy_markedPos_l-1]) {");
 
1060
      println("        case '\\n':");
 
1061
      println("        case '\\u000B':"); 
 
1062
      println("        case '\\u000C':"); 
 
1063
      println("        case '\\u0085':");
 
1064
      println("        case '\\u2028':"); 
 
1065
      println("        case '\\u2029':"); 
 
1066
      println("          yy_atBOL = true;"); 
 
1067
      println("          break;"); 
 
1068
      println("        case '\\r': "); 
 
1069
      println("          if (yy_markedPos_l < yy_endRead_l)");
 
1070
      println("            yy_atBOL = yy_buffer_l[yy_markedPos_l] != '\\n';");
 
1071
      println("          else if (yy_atEOF)");
 
1072
      println("            yy_atBOL = false;");
 
1073
      println("          else {");
 
1074
      println("            boolean eof = yy_refill();");
 
1075
      println("            yy_markedPos_l = yy_markedPos;");
 
1076
      println("            yy_buffer_l = yy_buffer;");
 
1077
      println("            if (eof) ");
 
1078
      println("              yy_atBOL = false;");
 
1079
      println("            else ");
 
1080
      println("              yy_atBOL = yy_buffer_l[yy_markedPos_l] != '\\n';");
 
1081
      println("          }");      
 
1082
      println("          break;"); 
 
1083
      println("        default:"); 
 
1084
      println("          yy_atBOL = false;"); 
 
1085
      println("        }"); 
 
1086
      println("      }"); 
 
1087
    }
 
1088
 
 
1089
    skel.emitNext();
 
1090
    
 
1091
    if (scanner.bolUsed) {
 
1092
      println("      if (yy_atBOL)");
 
1093
      println("        yy_state = YY_LEXSTATE[yy_lexical_state+1];");
 
1094
      println("      else");    
 
1095
      println("        yy_state = YY_LEXSTATE[yy_lexical_state];");
 
1096
      println();
 
1097
    }
 
1098
    else {
 
1099
      println("      yy_state = yy_lexical_state;");
 
1100
      println();
 
1101
    }
 
1102
 
 
1103
    if (scanner.lookAheadUsed)
 
1104
      println("      yy_was_pushback = false;");
 
1105
 
 
1106
    skel.emitNext();
 
1107
  }
 
1108
 
 
1109
  
 
1110
  private void emitGetRowMapNext() {
 
1111
    println("          int yy_next = yytrans_l[ yy_rowMap_l[yy_state] + yycmap_l[yy_input] ];");
 
1112
 
 
1113
    println("          if (yy_next == "+dfa.NO_TARGET+") break yy_forAction;");
 
1114
    println("          yy_state = yy_next;");
 
1115
    println();
 
1116
 
 
1117
    println("          int yy_attributes = yy_attr_l[yy_state];");
 
1118
 
 
1119
    if ( scanner.lookAheadUsed ) {
 
1120
      println("          if ( (yy_attributes & "+PUSHBACK+") == "+PUSHBACK+" )");
 
1121
      println("            yy_pushbackPos_l = yy_currentPos_l;");
 
1122
      println();
 
1123
    }
 
1124
 
 
1125
    println("          if ( (yy_attributes & "+FINAL+") == "+FINAL+" ) {");
 
1126
    if ( scanner.lookAheadUsed ) 
 
1127
      println("            yy_was_pushback = (yy_attributes & "+LOOKEND+") == "+LOOKEND+";");
 
1128
 
 
1129
    skel.emitNext();
 
1130
    
 
1131
    println("            if ( (yy_attributes & "+NOLOOK+") == "+NOLOOK+" ) break yy_forAction;");
 
1132
 
 
1133
    skel.emitNext();    
 
1134
  }  
 
1135
 
 
1136
  private void emitTransitionTable() {
 
1137
    transformTransitionTable();
 
1138
    
 
1139
    println("          yy_input = yycmap_l[yy_input];");
 
1140
    println();
 
1141
 
 
1142
    if ( scanner.lookAheadUsed ) 
 
1143
      println("          boolean yy_pushback = false;");
 
1144
      
 
1145
    println("          boolean yy_isFinal = false;");
 
1146
    println("          boolean yy_noLookAhead = false;");
 
1147
    println();
 
1148
    
 
1149
    println("          yy_forNext: { switch (yy_state) {");
 
1150
 
 
1151
    for (int state = 0; state < dfa.numStates; state++)
 
1152
      if (isTransition[state]) emitState(state);
 
1153
 
 
1154
    println("            default:");
 
1155
    println("              yy_ScanError(YY_ILLEGAL_STATE);");
 
1156
    println("              break;");
 
1157
    println("          } }");
 
1158
    println();
 
1159
    
 
1160
    println("          if ( yy_isFinal ) {");
 
1161
    
 
1162
    if ( scanner.lookAheadUsed ) 
 
1163
      println("            yy_was_pushback = yy_pushback;");
 
1164
    
 
1165
    skel.emitNext();
 
1166
    
 
1167
    println("            if ( yy_noLookAhead ) break yy_forAction;");
 
1168
 
 
1169
    skel.emitNext();    
 
1170
  }
 
1171
 
 
1172
 
 
1173
  /**
 
1174
   * Escapes all " ' \ tabs and newlines
 
1175
   */
 
1176
  private String escapify(String s) {
 
1177
    StringBuffer result = new StringBuffer(s.length()*2);
 
1178
    
 
1179
    for (int i = 0; i < s.length(); i++) {
 
1180
      char c = s.charAt(i);
 
1181
      switch (c) {
 
1182
      case '\'': result.append("\\\'"); break;
 
1183
      case '\"': result.append("\\\""); break;
 
1184
      case '\\': result.append("\\\\"); break;
 
1185
      case '\t': result.append("\\t"); break;
 
1186
      case '\r': if (i+1 == s.length() || s.charAt(i+1) != '\n') result.append("\"+yy_NL+\""); 
 
1187
                 break;
 
1188
      case '\n': result.append("\"+yy_NL+\""); break;
 
1189
      default: result.append(c);
 
1190
      }
 
1191
    }
 
1192
 
 
1193
    return result.toString();
 
1194
  }
 
1195
 
 
1196
  private void emitActions() {
 
1197
    Hashtable actionTable = new Hashtable();
 
1198
 
 
1199
    for (int i = 0; i < dfa.numStates; i++) 
 
1200
      if ( dfa.isFinal[i] ) {
 
1201
        Action action = dfa.action[i];
 
1202
        if ( actionTable.get(action) == null ) 
 
1203
          actionTable.put(action, new StateSet(i));
 
1204
        else
 
1205
          ((StateSet) actionTable.get(action)).addState(i);
 
1206
      }
 
1207
 
 
1208
    int i = dfa.numStates+1;  
 
1209
    Enumeration actions = actionTable.keys();
 
1210
    while ( actions.hasMoreElements() ) {
 
1211
      Action action   = (Action)   actions.nextElement();
 
1212
      StateSet states = (StateSet) actionTable.get(action);
 
1213
 
 
1214
      StateSetEnumerator s = states.states();
 
1215
      while ( s.hasMoreElements() ) 
 
1216
        println("        case "+s.nextElement()+": "); 
 
1217
      
 
1218
      if ( scanner.debugOption ) {
 
1219
        print("          System.out.println(");
 
1220
        if ( scanner.lineCount )
 
1221
          print("\"line: \"+(yyline+1)+\" \"+");
 
1222
        if ( scanner.columnCount )
 
1223
          print("\"col: \"+(yycolumn+1)+\" \"+");
 
1224
        println("\"match: --\"+yytext()+\"--\");");        
 
1225
        print("          System.out.println(\"action ["+action.priority+"] {");
 
1226
        print(escapify(action.content));
 
1227
        println("}\");");
 
1228
      }
 
1229
      
 
1230
      println("          { "+action.content+" }");
 
1231
      println("        case "+(i++)+": break;"); 
 
1232
    }
 
1233
  }
 
1234
 
 
1235
  private void emitEOFVal() {
 
1236
    EOFActions eofActions = parser.getEOFActions();
 
1237
 
 
1238
    if ( scanner.eofCode != null ) 
 
1239
      println("            yy_do_eof();");
 
1240
      
 
1241
    if ( eofActions.numActions() > 0 ) {
 
1242
      println("            switch (yy_lexical_state) {");
 
1243
      
 
1244
      Enumeration stateNames = scanner.states.names();
 
1245
 
 
1246
      // record lex states already emitted:
 
1247
      Hashtable used = new Hashtable();
 
1248
 
 
1249
      // pick a start value for break case labels. 
 
1250
      // must be larger than any value of a lex state:
 
1251
      int last = dfa.numStates;
 
1252
      
 
1253
      while ( stateNames.hasMoreElements() ) {
 
1254
        String name = (String) stateNames.nextElement();
 
1255
        int num = scanner.states.getNumber(name).intValue();
 
1256
        Action action = eofActions.getAction(num);
 
1257
 
 
1258
        // only emit code if the lex state is not redundant, so
 
1259
        // that case labels don't overlap
 
1260
        // (redundant = points to the same dfa state as another one).
 
1261
        // applies only to scanners that don't use BOL, because
 
1262
        // in BOL scanners lex states get mapped at runtime, so
 
1263
        // case labels will always be unique.
 
1264
        boolean unused = true;                
 
1265
        if (!scanner.bolUsed) {
 
1266
          Integer key = new Integer(dfa.lexState[2*num]);
 
1267
          unused = used.get(key) == null;
 
1268
          
 
1269
          if (!unused) 
 
1270
            Out.warning("Lexical states <"+name+"> and <"+used.get(key)+"> are equivalent.");
 
1271
          else
 
1272
            used.put(key,name);
 
1273
        }
 
1274
 
 
1275
        if (action != null && unused) {
 
1276
          println("            case "+name+":");
 
1277
          println("              { "+action.content+" }");
 
1278
          println("            case "+(++last)+": break;");
 
1279
        }
 
1280
      }
 
1281
      
 
1282
      println("            default:");
 
1283
    }
 
1284
 
 
1285
    if (eofActions.getDefault() != null) 
 
1286
      println("              { " + eofActions.getDefault().content + " }");
 
1287
    else if ( scanner.eofVal != null ) 
 
1288
      println("              { " + scanner.eofVal + " }");
 
1289
    else if ( scanner.isInteger ) 
 
1290
      println("            return YYEOF;");
 
1291
    else
 
1292
      println("            return null;");
 
1293
 
 
1294
    if (eofActions.numActions() > 0)
 
1295
      println("            }");
 
1296
  }
 
1297
  
 
1298
  private void emitState(int state) {
 
1299
    
 
1300
    println("            case "+state+":");
 
1301
    println("              switch (yy_input) {");
 
1302
   
 
1303
    int defaultTransition = getDefaultTransition(state);
 
1304
    
 
1305
    for (int next = 0; next < dfa.numStates; next++) {
 
1306
            
 
1307
      if ( next != defaultTransition && table[state][next] != null ) {
 
1308
        emitTransition(state, next);
 
1309
      }
 
1310
    }
 
1311
    
 
1312
    if ( defaultTransition != dfa.NO_TARGET && noTarget[state] != null ) {
 
1313
      emitTransition(state, dfa.NO_TARGET);
 
1314
    }
 
1315
    
 
1316
    emitDefaultTransition(state, defaultTransition);
 
1317
    
 
1318
    println("              }");
 
1319
    println("");
 
1320
  }
 
1321
  
 
1322
  private void emitTransition(int state, int nextState) {
 
1323
 
 
1324
    CharSetEnumerator chars;
 
1325
    int num;
 
1326
    
 
1327
    if (nextState != dfa.NO_TARGET) 
 
1328
      chars = table[state][nextState].characters();
 
1329
    else 
 
1330
      chars = noTarget[state].characters();
 
1331
  
 
1332
    print("                case ");
 
1333
    print((int)chars.nextElement());
 
1334
    print(": ");
 
1335
    
 
1336
    while ( chars.hasMoreElements() ) {
 
1337
      println();
 
1338
      print("                case ");
 
1339
      print((int)chars.nextElement());
 
1340
      print(": ");
 
1341
    } 
 
1342
    
 
1343
    if ( nextState != dfa.NO_TARGET ) {
 
1344
      if ( dfa.isFinal[nextState] )
 
1345
        print("yy_isFinal = true; ");
 
1346
        
 
1347
      if ( dfa.isPushback[nextState] ) 
 
1348
        print("yy_pushbackPos_l = yy_currentPos_l; ");
 
1349
      
 
1350
      if ( dfa.isLookEnd[nextState] )
 
1351
        print("yy_pushback = true; ");
 
1352
 
 
1353
      if ( !isTransition[nextState] )
 
1354
        print("yy_noLookAhead = true; ");
 
1355
        
 
1356
      if ( nextState == state ) 
 
1357
        println("yy_state = "+nextState+"; break yy_forNext;");
 
1358
      else
 
1359
        println("yy_state = "+nextState+"; break yy_forNext;");
 
1360
    }
 
1361
    else
 
1362
      println("break yy_forAction;");
 
1363
  }
 
1364
  
 
1365
  private void emitDefaultTransition(int state, int nextState) {
 
1366
    print("                default: ");
 
1367
    
 
1368
    if ( nextState != dfa.NO_TARGET ) {
 
1369
      if ( dfa.isFinal[nextState] )
 
1370
        print("yy_isFinal = true; ");
 
1371
        
 
1372
      if ( dfa.isPushback[nextState] ) 
 
1373
        print("yy_pushbackPos_l = yy_currentPos_l; ");
 
1374
 
 
1375
      if ( dfa.isLookEnd[nextState] )
 
1376
        print("yy_pushback = true; ");
 
1377
          
 
1378
      if ( !isTransition[nextState] )
 
1379
        print("yy_noLookAhead = true; ");
 
1380
        
 
1381
      if ( nextState == state ) 
 
1382
        println("yy_state = "+nextState+"; break yy_forNext;");
 
1383
      else
 
1384
        println("yy_state = "+nextState+"; break yy_forNext;");
 
1385
    }
 
1386
    else
 
1387
      println( "break yy_forAction;" );
 
1388
  }
 
1389
  
 
1390
  private void emitPushback() {
 
1391
    println("      if (yy_was_pushback)");
 
1392
    println("        yy_markedPos = yy_pushbackPos_l;");
 
1393
  }
 
1394
  
 
1395
  private int getDefaultTransition(int state) {
 
1396
    int max = 0;
 
1397
    
 
1398
    for (int i = 0; i < dfa.numStates; i++) {
 
1399
      if ( table[state][max] == null )
 
1400
        max = i;
 
1401
      else
 
1402
      if ( table[state][i] != null && table[state][max].size() < table[state][i].size() )
 
1403
        max = i;
 
1404
    }
 
1405
    
 
1406
    if ( table[state][max] == null ) return dfa.NO_TARGET;
 
1407
    if ( noTarget[state] == null ) return max;
 
1408
    
 
1409
    if ( table[state][max].size() < noTarget[state].size() ) 
 
1410
      max = dfa.NO_TARGET;
 
1411
    
 
1412
    return max;
 
1413
  }
 
1414
 
 
1415
  // for switch statement:
 
1416
  private void transformTransitionTable() {
 
1417
    
 
1418
    int numInput = parser.getCharClasses().getNumClasses()+1;
 
1419
 
 
1420
    int i;    
 
1421
    char j;
 
1422
    
 
1423
    table = new CharSet[dfa.numStates][dfa.numStates];
 
1424
    noTarget = new CharSet[dfa.numStates];
 
1425
    
 
1426
    for (i = 0; i < dfa.numStates;  i++) 
 
1427
      for (j = 0; j < dfa.numInput; j++) {
 
1428
 
 
1429
        int nextState = dfa.table[i][j];
 
1430
        
 
1431
        if ( nextState == dfa.NO_TARGET ) {
 
1432
          if ( noTarget[i] == null ) 
 
1433
            noTarget[i] = new CharSet(numInput, colMap[j]);
 
1434
          else
 
1435
            noTarget[i].add(colMap[j]);
 
1436
        }
 
1437
        else {
 
1438
          if ( table[i][nextState] == null ) 
 
1439
            table[i][nextState] = new CharSet(numInput, colMap[j]);
 
1440
          else
 
1441
            table[i][nextState].add(colMap[j]);
 
1442
        }
 
1443
      }
 
1444
  }
 
1445
 
 
1446
  private void findActionStates() {
 
1447
    isTransition = new boolean [dfa.numStates];
 
1448
    
 
1449
    for (int i = 0; i < dfa.numStates;  i++) {
 
1450
      char j = 0;
 
1451
      while ( !isTransition[i] && j < dfa.numInput )
 
1452
        isTransition[i] = dfa.table[i][j++] != dfa.NO_TARGET;
 
1453
    }
 
1454
  }
 
1455
 
 
1456
  
 
1457
  private void reduceColumns() {
 
1458
    colMap = new int [dfa.numInput];
 
1459
    colKilled = new boolean [dfa.numInput];
 
1460
 
 
1461
    int i,j,k;
 
1462
    int translate = 0;
 
1463
    boolean equal;
 
1464
 
 
1465
    numCols = dfa.numInput;
 
1466
 
 
1467
    for (i = 0; i < dfa.numInput; i++) {
 
1468
      
 
1469
      colMap[i] = i-translate;
 
1470
      
 
1471
      for (j = 0; j < i; j++) {
 
1472
        
 
1473
        // test for equality:
 
1474
        k = -1;
 
1475
        equal = true;        
 
1476
        while (equal && ++k < dfa.numStates) 
 
1477
          equal = dfa.table[k][i] == dfa.table[k][j];
 
1478
        
 
1479
        if (equal) {
 
1480
          translate++;
 
1481
          colMap[i] = colMap[j];
 
1482
          colKilled[i] = true;
 
1483
          numCols--;
 
1484
          break;
 
1485
        } // if
 
1486
      } // for j
 
1487
    } // for i
 
1488
  }
 
1489
  
 
1490
  private void reduceRows() {
 
1491
    rowMap = new int [dfa.numStates];
 
1492
    rowKilled = new boolean [dfa.numStates];
 
1493
    
 
1494
    int i,j,k;
 
1495
    int translate = 0;
 
1496
    boolean equal;
 
1497
 
 
1498
    numRows = dfa.numStates;
 
1499
 
 
1500
    // i is the state to add to the new table
 
1501
    for (i = 0; i < dfa.numStates; i++) {
 
1502
      
 
1503
      rowMap[i] = i-translate;
 
1504
      
 
1505
      // check if state i can be removed (i.e. already
 
1506
      // exists in entries 0..i-1)
 
1507
      for (j = 0; j < i; j++) {
 
1508
        
 
1509
        // test for equality:
 
1510
        k = -1;
 
1511
        equal = true;
 
1512
        while (equal && ++k < dfa.numInput) 
 
1513
          equal = dfa.table[i][k] == dfa.table[j][k];
 
1514
        
 
1515
        if (equal) {
 
1516
          translate++;
 
1517
          rowMap[i] = rowMap[j];
 
1518
          rowKilled[i] = true;
 
1519
          numRows--;
 
1520
          break;
 
1521
        } // if
 
1522
      } // for j
 
1523
    } // for i
 
1524
    
 
1525
  } 
 
1526
 
 
1527
  public void emit() {    
 
1528
 
 
1529
    if (scanner.functionName == null) 
 
1530
      scanner.functionName = "yylex";
 
1531
 
 
1532
    reduceColumns();
 
1533
    findActionStates();
 
1534
 
 
1535
    emitHeader();
 
1536
    emitUserCode();
 
1537
    emitClassName();
 
1538
    
 
1539
    skel.emitNext();
 
1540
    
 
1541
    println("  final private static int YY_BUFFERSIZE = "+scanner.bufferSize+";");
 
1542
 
 
1543
    if (scanner.debugOption) {
 
1544
      println("  final private static String yy_NL = System.getProperty(\"line.separator\");");
 
1545
    }
 
1546
 
 
1547
    skel.emitNext();
 
1548
 
 
1549
    emitLexicalStates();
 
1550
   
 
1551
    emitCharMapArray();
 
1552
    
 
1553
    if (scanner.useRowMap) 
 
1554
      emitRowMap();
 
1555
    
 
1556
    skel.emitNext();
 
1557
    
 
1558
    if (scanner.useRowMap) 
 
1559
      emitAttributes();
 
1560
    
 
1561
    skel.emitNext();
 
1562
    
 
1563
    emitClassCode();
 
1564
    
 
1565
    skel.emitNext();
 
1566
    
 
1567
    emitConstructorDecl();
 
1568
    
 
1569
    if (scanner.packed)
 
1570
      emitDynamicInitFunction();
 
1571
    
 
1572
    emitCharMapInitFunction();
 
1573
 
 
1574
    skel.emitNext();
 
1575
    
 
1576
    emitScanError();
 
1577
 
 
1578
    skel.emitNext();        
 
1579
 
 
1580
    emitDoEOF();
 
1581
    
 
1582
    skel.emitNext();
 
1583
    
 
1584
    emitLexFunctHeader();
 
1585
    
 
1586
    emitNextInput();
 
1587
 
 
1588
    if (scanner.useRowMap)
 
1589
      emitGetRowMapNext();
 
1590
    else
 
1591
      emitTransitionTable();
 
1592
        
 
1593
    if (scanner.lookAheadUsed) 
 
1594
      emitPushback();
 
1595
    
 
1596
    skel.emitNext();
 
1597
    
 
1598
    emitActions();
 
1599
    
 
1600
    skel.emitNext();
 
1601
    
 
1602
    emitEOFVal();
 
1603
    
 
1604
    skel.emitNext();
 
1605
    
 
1606
    emitNoMatch();
 
1607
 
 
1608
    skel.emitNext();
 
1609
    
 
1610
    emitMain();
 
1611
    
 
1612
    skel.emitNext();
 
1613
 
 
1614
    out.close();
 
1615
  } 
 
1616
 
 
1617
  /**
 
1618
   * Converts an abstract pathname into a <code>file:</code> URL.  The
 
1619
   * exact form of the URL is system-dependent.  If it can be determined that
 
1620
   * the file denoted by this abstract pathname is a directory, then the
 
1621
   * resulting URL will end with a slash.
 
1622
   */
 
1623
  public static URL toURL(File file) throws MalformedURLException {
 
1624
    String path = file.getAbsolutePath();
 
1625
    if (File.separatorChar != '/') {
 
1626
            path = path.replace(File.separatorChar, '/');
 
1627
    }
 
1628
    if (!path.startsWith("/")) {
 
1629
      path = "/" + path;
 
1630
    }
 
1631
    if (!path.endsWith("/") && file.isDirectory()) {
 
1632
      path = path + "/";
 
1633
    }
 
1634
    return new URL("file", "", path);
 
1635
  }
 
1636
}