1
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
3
* Copyright (C) 1998-2001 Gerwin Klein <lsf@jflex.de> *
4
* All rights reserved. *
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. *
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. *
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 *
19
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
29
* This class manages the actual code generation, putting
30
* the scanner together, filling in skeleton sections etc.
32
* Table compression, String packing etc. is also done here.
34
* @author Gerwin Klein
35
* @version JFlex 1.3.5, $Revision: 1.74 $, $Date: 2001/10/08 10:07:59 $
37
final public class Emitter {
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;
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
49
// 64K max and some safety
50
static final int maxSize = 0xFFFF-6;
52
static final private String date = (new SimpleDateFormat()).format(new Date());
54
static public File directory;
56
private File inputFile;
58
private PrintWriter out;
59
private Skeleton skel;
60
private LexScan scanner;
61
private LexParse parser;
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[][];
68
private boolean isTransition[];
70
// noTarget[i] is the set of input characters that have no target state in state i
71
private CharSet noTarget[];
75
private int [] rowMap;
76
private boolean [] rowKilled;
80
private int [] colMap;
81
private boolean [] colKilled;
83
private int numTableChunks;
85
private CharClassIntervall [] intervalls;
86
private int currentIntervall;
88
public Emitter(File inputFile, LexParse parser, DFA dfa) throws IOException {
90
String name = parser.scanner.className+".java";
92
File outputFile = normalize(name, directory, inputFile);
94
Out.println("Writing code to \""+outputFile+"\"");
96
this.out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
98
this.scanner = parser.scanner;
99
this.inputFile = inputFile;
101
this.skel = new Skeleton(out);
106
* Constructs a file in a path or in the same directory as
107
* another file. Makes a backup if the file already exists.
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)
114
public static File normalize(String name, File path, File input) {
117
if ( directory == null )
118
if ( input == null || input.getParent() == null )
119
outputFile = new File(name);
121
outputFile = new File(input.getParent(), name);
123
outputFile = new File(directory, name);
125
if ( outputFile.exists() && !Main.no_backup ) {
126
File backup = new File( outputFile.toString()+"~" );
128
if ( backup.exists() ) backup.delete();
130
if ( outputFile.renameTo( backup ) )
131
Out.println("Old file \""+outputFile+"\" saved as \""+backup+"\"");
133
Out.println("Couldn't save old file \""+outputFile+"\", overwriting!");
139
private void println() {
143
private void println(String line) {
147
private void println(int i) {
151
private void print(String line) {
155
private void print(int i) {
159
private void print(int i, int tab) {
168
if (Math.abs(i) < exp) print(" ");
175
private void printUC(int i) {
178
if (i < 0x1000) print("0");
179
print(Integer.toHexString(i));
183
print(Integer.toOctalString(i));
187
private void emitScanError() {
188
print(" private void yy_ScanError(int errorCode)");
190
if (scanner.scanErrorException != null)
191
print(" throws "+scanner.scanErrorException);
197
if (scanner.scanErrorException == null)
198
println(" throw new Error(message);");
200
println(" throw new "+scanner.scanErrorException+"(message);");
204
print(" private void yypushback(int number) ");
206
if (scanner.scanErrorException == null)
209
println(" throws "+scanner.scanErrorException+" {");
212
private void emitMain() {
213
if ( !(scanner.standalone || scanner.debugOption || scanner.cupDebug) ) return;
215
if ( scanner.cupDebug ) {
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);
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>");
223
println(" private String getTokenName(int token) {");
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();");
231
println(" } catch (Exception e) {");
232
println(" e.printStackTrace(System.err);");
235
println(" return \"UNKNOWN TOKEN\";");
239
println(" * Same as "+scanner.functionName+" but also prints the token to standard out");
240
println(" * for debugging.");
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>");
247
if ( scanner.tokenType == null ) {
248
if ( scanner.isInteger )
251
if ( scanner.isIntWrap )
257
print( scanner.tokenType );
261
print(scanner.functionName);
263
print("() throws java.io.IOException");
265
if ( scanner.lexThrow != null ) {
267
print(scanner.lexThrow);
270
if ( scanner.scanErrorException != null ) {
272
print(scanner.scanErrorException);
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;");
287
if ( scanner.standalone ) {
289
println(" * Runs the scanner on input files.");
291
println(" * This is a standalone scanner, i.e. it will print any unmatched");
292
println(" * text to System.out unchanged.");
294
println(" * @param argv the command line, contains the filenames to run");
295
println(" * the scanner on.");
300
println(" * Runs the scanner on input files.");
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.");
306
println(" * @param argv the command line, contains the filenames to run");
307
println(" * the scanner on.");
311
println(" public static void main(String argv[]) {");
312
println(" if (argv.length == 0) {");
313
println(" System.out.println(\"Usage : java "+scanner.className+" <inputfile>\");");
316
println(" for (int i = 0; i < argv.length; i++) {");
317
println(" "+scanner.className+" scanner = null;");
319
println(" scanner = new "+scanner.className+"( new java.io.FileReader(argv[i]) );");
321
if ( scanner.standalone ) {
322
println(" while ( !scanner.yy_atEOF ) scanner."+scanner.functionName+"();");
324
else if (scanner.cupDebug ) {
325
println(" while ( !scanner.yy_atEOF ) scanner.debug_"+scanner.functionName+"();");
329
println(" System.out.println(scanner."+scanner.functionName+"());");
330
println(" } while (!scanner.yy_atEOF);");
335
println(" catch (java.io.FileNotFoundException e) {");
336
println(" System.out.println(\"File not found : \\\"\"+argv[i]+\"\\\"\");");
338
println(" catch (java.io.IOException e) {");
339
println(" System.out.println(\"IO error scanning file \\\"\"+argv[i]+\"\\\"\");");
340
println(" System.out.println(e);");
342
println(" catch (Exception e) {");
343
println(" System.out.println(\"Unexpected exception:\");");
344
println(" e.printStackTrace();");
352
private void emitNoMatch() {
353
println(" yy_ScanError(YY_NO_MATCH);");
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;");
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;");
382
println(" yy_input = yy_buffer_l[yy_currentPos_l++];");
387
private void emitHeader() {
388
println("/* The following code was generated by JFlex "+Main.version+" on "+date+" */");
392
private void emitUserCode() {
393
if ( scanner.userCode.length() > 0 )
394
println(scanner.userCode.toString());
397
private void emitClassName() {
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");
403
println(" * <tt>"+toURL(inputFile)+"</tt>");
405
catch (MalformedURLException e) {
406
println(" * (couldn't find spec. file)");
411
if ( scanner.isPublic ) print("public ");
413
if ( scanner.isAbstract) print("abstract ");
415
if ( scanner.isFinal ) print("final ");
418
print(scanner.className);
420
if ( scanner.isExtending != null ) {
422
print(scanner.isExtending);
425
if ( scanner.isImplementing != null ) {
426
print(" implements ");
427
print(scanner.isImplementing);
433
private void emitLexicalStates() {
434
Enumeration stateNames = scanner.states.names();
436
while ( stateNames.hasMoreElements() ) {
437
String name = (String) stateNames.nextElement();
439
int num = scanner.states.getNumber(name).intValue();
442
println(" final public static int "+name+" = "+2*num+";");
444
println(" final public static int "+name+" = "+dfa.lexState[2*num]+";");
447
if (scanner.bolUsed) {
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");
455
println(" private final static int YY_LEXSTATE[] = { ");
460
for (i = 0; i < dfa.lexState.length-1; i++) {
461
print( dfa.lexState[i], 2 );
472
println( dfa.lexState[i] );
478
private void emitDynInitHead(int chunk) {
480
println(" * The packed transition table of the DFA (part "+chunk+")");
482
println(" final private static String yy_packed"+chunk+" = ");
486
* Calculates the number of bytes a Unicode character
487
* would have in UTF8 representation in a class file.
489
* @param value the char code of the Unicode character
490
* (expected to satisfy 0 <= value <= 0xFFFF)
492
* @return length of UTF8 representation.
494
private int UTF8Length(int value) {
495
if (value < 0 || value > 0xFFFF) throw new Error("not a char value ("+value+")");
497
// see JVM spec ļæ½4.4.7, p 111
498
if (value == 0) return 2;
499
if (value <= 0x7F) return 1;
501
// workaround for javac bug (up to jdk 1.3):
502
if (value < 0x0400) return 2;
503
if (value <= 0x07FF) return 3;
506
// if (value <= 0x7FF) return 2;
510
private void emitDynamicInit() {
511
emitDynInitHead(numTableChunks++);
518
int value = dfa.table[0][0];
520
// the current length of the resulting UTF8 String constant
521
// in the class file. Must be smaller than 64K
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++;
533
// calculate resulting UTF8 size
534
UTF8Length += UTF8Length(count)+UTF8Length(value+1);
544
value = dfa.table[i][c];
546
if (UTF8Length >= maxSize) {
547
// System.out.println("UTF8 size chunk "+(numTableChunks-1)+": "+Integer.toHexString(UTF8Length));
551
emitDynInitHead(numTableChunks++);
564
UTF8Length += UTF8Length(count)+UTF8Length(value+1);
566
// System.out.println("UTF8 size chunk "+(numTableChunks-1)+": "+Integer.toHexString(UTF8Length));
572
println(" * The transition table of the DFA");
574
println(" final private static int yytrans [] = yy_unpack();");
578
private void emitDynamicInitFunction() {
581
println(" * Unpacks the split, compressed DFA transition table.");
583
println(" * @return the unpacked transition table");
585
println(" private static int [] yy_unpack() {");
586
println(" int [] trans = new int["+(numRows*numCols)+"];");
587
println(" int offset = 0;");
589
for (int i = 0; i < numTableChunks; i++) {
590
println(" offset = yy_unpack(yy_packed"+i+", offset, trans);");
593
println(" return trans;");
598
println(" * Unpacks the compressed DFA transition table.");
600
println(" * @param packed the packed transition table");
601
println(" * @return the index of the last entry");
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);");
613
println(" return j;");
617
private void emitCharMapInitFunction() {
619
CharClasses cl = parser.getCharClasses();
621
if ( cl.getMaxCharCode() < 256 ) return;
625
println(" * Unpacks the compressed character translation table.");
627
println(" * @param packed the packed character translation table");
628
println(" * @return the unpacked character translation table");
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);");
639
println(" return map;");
643
private void emitYYTrans() {
649
println(" * The transition table of the DFA");
651
println(" final private static int yytrans [] = {");
653
boolean isFirstRow = true;
656
for (i = 0; i < dfa.numStates; i++) {
658
if ( !rowKilled[i] ) {
659
for (c = 0; c < dfa.numInput; c++) {
660
if ( !colKilled[c] ) {
666
print( dfa.table[i][c] );
667
if (i != dfa.numStates-1 || c != dfa.numInput-1)
679
private void emitRowMap() {
683
println(" * Translates a state to a row index in the transition table");
685
println(" final private static int yy_rowMap [] = { ");
691
for (i = 0; i < dfa.numStates-1; i++) {
692
print( rowMap[i]*numCols, 5 );
702
print( rowMap[i]*numCols, 5 );
713
private void emitCharMapArrayUnPacked() {
715
CharClasses cl = parser.getCharClasses();
716
intervalls = cl.getIntervalls();
720
println(" * Translates characters to character classes");
722
println(" final private static char [] yycmap = {");
724
int n = 0; // numbers of entries in current line
727
int max = cl.getMaxCharCode();
729
while ( i < intervalls.length && intervalls[i].start <= max ) {
731
int end = Math.min(intervalls[i].end, max);
732
for (int c = intervalls[i].start; c <= end; c++) {
734
print(colMap[intervalls[i].charClass], 2);
754
private void emitCharMapArray() {
755
CharClasses cl = parser.getCharClasses();
757
if ( cl.getMaxCharCode() < 256 ) {
758
emitCharMapArrayUnPacked();
762
// ignores cl.getMaxCharCode(), emits all intervalls instead
764
intervalls = cl.getIntervalls();
768
println(" * Translates characters to character classes");
770
println(" final private static String yycmap_packed = ");
772
int n = 0; // numbers of entries in current line
776
while ( i < intervalls.length-1 ) {
777
int count = intervalls[i].end-intervalls[i].start+1;
778
int value = colMap[intervalls[i].charClass];
792
printUC(intervalls[i].end-intervalls[i].start+1);
793
printUC(colMap[intervalls[i].charClass]);
799
println(" * Translates characters to character classes");
801
println(" final private static char [] yycmap = yy_unpack_cmap(yycmap_packed);");
805
private void emitAttributes() {
807
if (dfa.numStates <= 0) return;
810
println(" * YY_ATTRIBUTE[aState] contains the attributes of state <code>aState</code>");
812
println(" private final static byte YY_ATTRIBUTE[] = {");
817
for (i = 0, j = 0; i < dfa.numStates-1; i++, j++) {
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;
831
print( attribute, 2 );
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;
841
print( attribute, 2 );
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;");
855
if ( scanner.classCode != null ) {
856
println(" /* user code: */");
857
println(scanner.classCode);
861
private void emitConstructorDecl() {
865
if ( scanner.isPublic ) print("public ");
866
print( scanner.className );
867
print("(java.io.Reader in)");
869
if ( scanner.initThrow != null ) {
871
print( scanner.initThrow );
876
if ( scanner.initCode != null ) {
878
print( scanner.initCode );
881
println(" this.yy_reader = in;");
888
println(" * Creates a new scanner.");
889
println(" * There is also java.io.Reader version of this constructor.");
891
println(" * @param in the java.io.Inputstream to read input from.");
895
if ( scanner.isPublic ) print("public ");
896
print( scanner.className );
897
print("(java.io.InputStream in)");
899
if ( scanner.initThrow != null ) {
901
print( scanner.initThrow );
905
println(" this(new java.io.InputStreamReader(in));");
910
private void emitDoEOF() {
911
if ( scanner.eofCode == null ) return;
914
println(" * Contains user EOF-code, which will be executed exactly once,");
915
println(" * when the end of file is reached");
918
print(" private void yy_do_eof()");
920
if ( scanner.eofThrow != null ) {
922
print(scanner.eofThrow);
927
println(" if (!yy_eof_done) {");
928
println(" yy_eof_done = true;");
929
println(" "+scanner.eofCode );
936
private void emitLexFunctHeader() {
940
if ( scanner.tokenType == null ) {
941
if ( scanner.isInteger )
944
if ( scanner.isIntWrap )
950
print( scanner.tokenType );
954
print(scanner.functionName);
956
print("() throws java.io.IOException");
958
if ( scanner.lexThrow != null ) {
960
print(scanner.lexThrow);
963
if ( scanner.scanErrorException != null ) {
965
print(scanner.scanErrorException);
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;");
979
if ( scanner.lookAheadUsed ) {
980
println(" int yy_pushbackPos_l = yy_pushbackPos = -1;");
981
println(" boolean yy_was_pushback;");
986
if ( scanner.charCount ) {
987
println(" yychar+= yy_markedPos_l-yy_startRead;");
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;");
1007
println(" case '\\r':");
1008
if ( scanner.lineCount )
1009
println(" yyline++;");
1010
if ( scanner.columnCount )
1011
println(" yycolumn = 0;");
1012
println(" yy_r = true;");
1014
println(" case '\\n':");
1015
println(" if (yy_r)");
1016
println(" yy_r = false;");
1018
if ( scanner.lineCount )
1019
println(" yyline++;");
1020
if ( scanner.columnCount )
1021
println(" yycolumn = 0;");
1024
println(" default:");
1025
println(" yy_r = false;");
1026
if ( scanner.columnCount )
1027
println(" yycolumn++;");
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;");
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;");
1047
println(" yy_peek = yy_buffer_l[yy_markedPos_l] == '\\n';");
1049
println(" if (yy_peek) yyline--;");
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;");
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;");
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;");
1080
println(" yy_atBOL = yy_buffer_l[yy_markedPos_l] != '\\n';");
1083
println(" default:");
1084
println(" yy_atBOL = false;");
1091
if (scanner.bolUsed) {
1092
println(" if (yy_atBOL)");
1093
println(" yy_state = YY_LEXSTATE[yy_lexical_state+1];");
1095
println(" yy_state = YY_LEXSTATE[yy_lexical_state];");
1099
println(" yy_state = yy_lexical_state;");
1103
if (scanner.lookAheadUsed)
1104
println(" yy_was_pushback = false;");
1110
private void emitGetRowMapNext() {
1111
println(" int yy_next = yytrans_l[ yy_rowMap_l[yy_state] + yycmap_l[yy_input] ];");
1113
println(" if (yy_next == "+dfa.NO_TARGET+") break yy_forAction;");
1114
println(" yy_state = yy_next;");
1117
println(" int yy_attributes = yy_attr_l[yy_state];");
1119
if ( scanner.lookAheadUsed ) {
1120
println(" if ( (yy_attributes & "+PUSHBACK+") == "+PUSHBACK+" )");
1121
println(" yy_pushbackPos_l = yy_currentPos_l;");
1125
println(" if ( (yy_attributes & "+FINAL+") == "+FINAL+" ) {");
1126
if ( scanner.lookAheadUsed )
1127
println(" yy_was_pushback = (yy_attributes & "+LOOKEND+") == "+LOOKEND+";");
1131
println(" if ( (yy_attributes & "+NOLOOK+") == "+NOLOOK+" ) break yy_forAction;");
1136
private void emitTransitionTable() {
1137
transformTransitionTable();
1139
println(" yy_input = yycmap_l[yy_input];");
1142
if ( scanner.lookAheadUsed )
1143
println(" boolean yy_pushback = false;");
1145
println(" boolean yy_isFinal = false;");
1146
println(" boolean yy_noLookAhead = false;");
1149
println(" yy_forNext: { switch (yy_state) {");
1151
for (int state = 0; state < dfa.numStates; state++)
1152
if (isTransition[state]) emitState(state);
1154
println(" default:");
1155
println(" yy_ScanError(YY_ILLEGAL_STATE);");
1160
println(" if ( yy_isFinal ) {");
1162
if ( scanner.lookAheadUsed )
1163
println(" yy_was_pushback = yy_pushback;");
1167
println(" if ( yy_noLookAhead ) break yy_forAction;");
1174
* Escapes all " ' \ tabs and newlines
1176
private String escapify(String s) {
1177
StringBuffer result = new StringBuffer(s.length()*2);
1179
for (int i = 0; i < s.length(); i++) {
1180
char c = s.charAt(i);
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+\"");
1188
case '\n': result.append("\"+yy_NL+\""); break;
1189
default: result.append(c);
1193
return result.toString();
1196
private void emitActions() {
1197
Hashtable actionTable = new Hashtable();
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));
1205
((StateSet) actionTable.get(action)).addState(i);
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);
1214
StateSetEnumerator s = states.states();
1215
while ( s.hasMoreElements() )
1216
println(" case "+s.nextElement()+": ");
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));
1230
println(" { "+action.content+" }");
1231
println(" case "+(i++)+": break;");
1235
private void emitEOFVal() {
1236
EOFActions eofActions = parser.getEOFActions();
1238
if ( scanner.eofCode != null )
1239
println(" yy_do_eof();");
1241
if ( eofActions.numActions() > 0 ) {
1242
println(" switch (yy_lexical_state) {");
1244
Enumeration stateNames = scanner.states.names();
1246
// record lex states already emitted:
1247
Hashtable used = new Hashtable();
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;
1253
while ( stateNames.hasMoreElements() ) {
1254
String name = (String) stateNames.nextElement();
1255
int num = scanner.states.getNumber(name).intValue();
1256
Action action = eofActions.getAction(num);
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;
1270
Out.warning("Lexical states <"+name+"> and <"+used.get(key)+"> are equivalent.");
1275
if (action != null && unused) {
1276
println(" case "+name+":");
1277
println(" { "+action.content+" }");
1278
println(" case "+(++last)+": break;");
1282
println(" default:");
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;");
1292
println(" return null;");
1294
if (eofActions.numActions() > 0)
1298
private void emitState(int state) {
1300
println(" case "+state+":");
1301
println(" switch (yy_input) {");
1303
int defaultTransition = getDefaultTransition(state);
1305
for (int next = 0; next < dfa.numStates; next++) {
1307
if ( next != defaultTransition && table[state][next] != null ) {
1308
emitTransition(state, next);
1312
if ( defaultTransition != dfa.NO_TARGET && noTarget[state] != null ) {
1313
emitTransition(state, dfa.NO_TARGET);
1316
emitDefaultTransition(state, defaultTransition);
1322
private void emitTransition(int state, int nextState) {
1324
CharSetEnumerator chars;
1327
if (nextState != dfa.NO_TARGET)
1328
chars = table[state][nextState].characters();
1330
chars = noTarget[state].characters();
1333
print((int)chars.nextElement());
1336
while ( chars.hasMoreElements() ) {
1339
print((int)chars.nextElement());
1343
if ( nextState != dfa.NO_TARGET ) {
1344
if ( dfa.isFinal[nextState] )
1345
print("yy_isFinal = true; ");
1347
if ( dfa.isPushback[nextState] )
1348
print("yy_pushbackPos_l = yy_currentPos_l; ");
1350
if ( dfa.isLookEnd[nextState] )
1351
print("yy_pushback = true; ");
1353
if ( !isTransition[nextState] )
1354
print("yy_noLookAhead = true; ");
1356
if ( nextState == state )
1357
println("yy_state = "+nextState+"; break yy_forNext;");
1359
println("yy_state = "+nextState+"; break yy_forNext;");
1362
println("break yy_forAction;");
1365
private void emitDefaultTransition(int state, int nextState) {
1366
print(" default: ");
1368
if ( nextState != dfa.NO_TARGET ) {
1369
if ( dfa.isFinal[nextState] )
1370
print("yy_isFinal = true; ");
1372
if ( dfa.isPushback[nextState] )
1373
print("yy_pushbackPos_l = yy_currentPos_l; ");
1375
if ( dfa.isLookEnd[nextState] )
1376
print("yy_pushback = true; ");
1378
if ( !isTransition[nextState] )
1379
print("yy_noLookAhead = true; ");
1381
if ( nextState == state )
1382
println("yy_state = "+nextState+"; break yy_forNext;");
1384
println("yy_state = "+nextState+"; break yy_forNext;");
1387
println( "break yy_forAction;" );
1390
private void emitPushback() {
1391
println(" if (yy_was_pushback)");
1392
println(" yy_markedPos = yy_pushbackPos_l;");
1395
private int getDefaultTransition(int state) {
1398
for (int i = 0; i < dfa.numStates; i++) {
1399
if ( table[state][max] == null )
1402
if ( table[state][i] != null && table[state][max].size() < table[state][i].size() )
1406
if ( table[state][max] == null ) return dfa.NO_TARGET;
1407
if ( noTarget[state] == null ) return max;
1409
if ( table[state][max].size() < noTarget[state].size() )
1410
max = dfa.NO_TARGET;
1415
// for switch statement:
1416
private void transformTransitionTable() {
1418
int numInput = parser.getCharClasses().getNumClasses()+1;
1423
table = new CharSet[dfa.numStates][dfa.numStates];
1424
noTarget = new CharSet[dfa.numStates];
1426
for (i = 0; i < dfa.numStates; i++)
1427
for (j = 0; j < dfa.numInput; j++) {
1429
int nextState = dfa.table[i][j];
1431
if ( nextState == dfa.NO_TARGET ) {
1432
if ( noTarget[i] == null )
1433
noTarget[i] = new CharSet(numInput, colMap[j]);
1435
noTarget[i].add(colMap[j]);
1438
if ( table[i][nextState] == null )
1439
table[i][nextState] = new CharSet(numInput, colMap[j]);
1441
table[i][nextState].add(colMap[j]);
1446
private void findActionStates() {
1447
isTransition = new boolean [dfa.numStates];
1449
for (int i = 0; i < dfa.numStates; i++) {
1451
while ( !isTransition[i] && j < dfa.numInput )
1452
isTransition[i] = dfa.table[i][j++] != dfa.NO_TARGET;
1457
private void reduceColumns() {
1458
colMap = new int [dfa.numInput];
1459
colKilled = new boolean [dfa.numInput];
1465
numCols = dfa.numInput;
1467
for (i = 0; i < dfa.numInput; i++) {
1469
colMap[i] = i-translate;
1471
for (j = 0; j < i; j++) {
1473
// test for equality:
1476
while (equal && ++k < dfa.numStates)
1477
equal = dfa.table[k][i] == dfa.table[k][j];
1481
colMap[i] = colMap[j];
1482
colKilled[i] = true;
1490
private void reduceRows() {
1491
rowMap = new int [dfa.numStates];
1492
rowKilled = new boolean [dfa.numStates];
1498
numRows = dfa.numStates;
1500
// i is the state to add to the new table
1501
for (i = 0; i < dfa.numStates; i++) {
1503
rowMap[i] = i-translate;
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++) {
1509
// test for equality:
1512
while (equal && ++k < dfa.numInput)
1513
equal = dfa.table[i][k] == dfa.table[j][k];
1517
rowMap[i] = rowMap[j];
1518
rowKilled[i] = true;
1527
public void emit() {
1529
if (scanner.functionName == null)
1530
scanner.functionName = "yylex";
1541
println(" final private static int YY_BUFFERSIZE = "+scanner.bufferSize+";");
1543
if (scanner.debugOption) {
1544
println(" final private static String yy_NL = System.getProperty(\"line.separator\");");
1549
emitLexicalStates();
1553
if (scanner.useRowMap)
1558
if (scanner.useRowMap)
1567
emitConstructorDecl();
1570
emitDynamicInitFunction();
1572
emitCharMapInitFunction();
1584
emitLexFunctHeader();
1588
if (scanner.useRowMap)
1589
emitGetRowMapNext();
1591
emitTransitionTable();
1593
if (scanner.lookAheadUsed)
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.
1623
public static URL toURL(File file) throws MalformedURLException {
1624
String path = file.getAbsolutePath();
1625
if (File.separatorChar != '/') {
1626
path = path.replace(File.separatorChar, '/');
1628
if (!path.startsWith("/")) {
1631
if (!path.endsWith("/") && file.isDirectory()) {
1634
return new URL("file", "", path);