source: other-projects/rsyntax-textarea/devel-packages/jflex-1.4.3/src/JFlex/Emitter.java@ 25584

Last change on this file since 25584 was 25584, checked in by davidb, 12 years ago

Initial cut an a text edit area for GLI that supports color syntax highlighting

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