KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > JFlex > PackEmitter


1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
2  * jflex 1.4 *
3  * Copyright (C) 1998-2004 Gerwin Klein <lsf@jflex.de> *
4  * All rights reserved. *
5  * *
6  * This program is free software; you can redistribute it and/or modify *
7  * it under the terms of the GNU General Public License. See the file *
8  * COPYRIGHT for more information. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License along *
16  * with this program; if not, write to the Free Software Foundation, Inc., *
17  * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *
18  * *
19  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

20
21 package JFlex;
22
23
24 /**
25  * Encodes <code>int</code> arrays as strings.
26  *
27  * Also splits up strings when longer than 64K in UTF8 encoding.
28  * Subclasses emit unpacking code.
29  *
30  * Usage protocol:
31  * <code>p.emitInit();</code><br>
32  * <code>for each data: p.emitData(data);</code><br>
33  * <code>p.emitUnpack();</code>
34  *
35  * @author Gerwin Klein
36  * @version $Revision: 1.6 $, $Date: 2004/04/12 10:07:47 $
37  */

38 public abstract class PackEmitter {
39
40   /** name of the generated array (mixed case, no yy prefix) */
41   protected String JavaDoc name;
42     
43   /** current UTF8 length of generated string in current chunk */
44   private int UTF8Length;
45
46   /** position in the current line */
47   private int linepos;
48   
49   /** max number of entries per line */
50   private static final int maxEntries = 16;
51   
52   /** output buffer */
53   protected StringBuffer JavaDoc out = new StringBuffer JavaDoc();
54
55   /** number of existing string chunks */
56   protected int chunks;
57     
58   /** maximum size of chunks */
59   // String constants are stored as UTF8 with 2 bytes length
60
// field in class files. One Unicode char can be up to 3
61
// UTF8 bytes. 64K max and two chars safety.
62
private static final int maxSize = 0xFFFF-6;
63   
64   /** indent for string lines */
65   private static final String JavaDoc indent = " ";
66   
67   /**
68    * Create new emitter for an array.
69    *
70    * @param name the name of the generated array
71    */

72   public PackEmitter(String JavaDoc name) {
73     this.name = name;
74   }
75   
76   /**
77    * Convert array name into all uppercase internal scanner
78    * constant name.
79    *
80    * @return <code>name</code> as a internal constant name.
81    * @see PackEmitter#name
82    */

83   protected String JavaDoc constName() {
84     return "ZZ_" + name.toUpperCase();
85   }
86   
87   /**
88    * Return current output buffer.
89    */

90   public String JavaDoc toString() {
91     return out.toString();
92   }
93
94   /**
95    * Emit declaration of decoded member and open first chunk.
96    */

97   public void emitInit() {
98     out.append(" private static final int [] ");
99     out.append(constName());
100     out.append(" = zzUnpack");
101     out.append(name);
102     out.append("();");
103     nl();
104     nextChunk();
105   }
106
107   /**
108    * Emit single unicode character.
109    *
110    * Updates length, position, etc.
111    *
112    * @param i the character to emit.
113    * @prec 0 <= i <= 0xFFFF
114    */

115   public void emitUC(int i) {
116     if (i < 0 || i > 0xFFFF)
117       throw new IllegalArgumentException JavaDoc("character value expected");
118   
119     // cast ok because of prec
120
char c = (char) i;
121      
122     printUC(c);
123     UTF8Length += UTF8Length(c);
124     linepos++;
125   }
126
127   /**
128    * Execute line/chunk break if necessary.
129    * Leave space for at least two chars.
130    */

131   public void breaks() {
132     if (UTF8Length >= maxSize) {
133       // close current chunk
134
out.append("\";");
135       nl();
136       
137       nextChunk();
138     }
139     else {
140       if (linepos >= maxEntries) {
141         // line break
142
out.append("\"+");
143         nl();
144         out.append(indent);
145         out.append("\"");
146         linepos = 0;
147       }
148     }
149   }
150   
151   /**
152    * Emit the unpacking code.
153    */

154   public abstract void emitUnpack();
155
156   /**
157    * emit next chunk
158    */

159   private void nextChunk() {
160     nl();
161     out.append(" private static final String ");
162     out.append(constName());
163     out.append("_PACKED_");
164     out.append(chunks);
165     out.append(" =");
166     nl();
167     out.append(indent);
168     out.append("\"");
169
170     UTF8Length = 0;
171     linepos = 0;
172     chunks++;
173   }
174   
175   /**
176    * emit newline
177    */

178   protected void nl() {
179     out.append(Out.NL);
180   }
181   
182   /**
183    * Append a unicode/octal escaped character
184    * to <code>out</code> buffer.
185    *
186    * @param c the character to append
187    */

188   private void printUC(char c) {
189     if (c > 255) {
190       out.append("\\u");
191       if (c < 0x1000) out.append("0");
192       out.append(Integer.toHexString(c));
193     }
194     else {
195       out.append("\\");
196       out.append(Integer.toOctalString(c));
197     }
198   }
199
200   /**
201    * Calculates the number of bytes a Unicode character
202    * would have in UTF8 representation in a class file.
203    *
204    * @param value the char code of the Unicode character
205    * @prec 0 <= value <= 0xFFFF
206    *
207    * @return length of UTF8 representation.
208    */

209   private int UTF8Length(char value) {
210     // if (value < 0 || value > 0xFFFF) throw new Error("not a char value ("+value+")");
211

212     // see JVM spec §4.4.7, p 111
213
if (value == 0) return 2;
214     if (value <= 0x7F) return 1;
215
216     // workaround for javac bug (up to jdk 1.3):
217
if (value < 0x0400) return 2;
218     if (value <= 0x07FF) return 3;
219
220     // correct would be:
221
// if (value <= 0x7FF) return 2;
222
return 3;
223   }
224
225   // convenience
226
protected void println(String JavaDoc s) {
227     out.append(s);
228     nl();
229   }
230 }
231
Popular Tags