/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* JFlex 1.8.2 *
* Copyright (C) 1998-2018 Gerwin Klein <lsf@jflex.de> *
* All rights reserved. *
* *
* License: BSD *
* *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package jflex.generator;
import java.util.Locale;
import jflex.logging.Out;
Encodes int
arrays as strings. Also splits up strings when longer than 64K in UTF8 encoding. Subclasses emit unpacking code.
Usage protocol: p.emitInit();
for each data: p.emitData(data);
p.emitUnpack();
Author: Gerwin Klein Version: JFlex 1.8.2
/**
* Encodes {@code int} arrays as strings.
*
* <p>Also splits up strings when longer than 64K in UTF8 encoding. Subclasses emit unpacking code.
*
* <p>Usage protocol: {@code p.emitInit();}<br>
* {@code for each data: p.emitData(data);}<br>
* {@code p.emitUnpack();}
*
* @author Gerwin Klein
* @version JFlex 1.8.2
*/
public abstract class PackEmitter {
name of the generated array (mixed case, no yy prefix) /** name of the generated array (mixed case, no yy prefix) */
protected String name;
current UTF8 length of generated string in current chunk /** current UTF8 length of generated string in current chunk */
private int UTF8Length;
position in the current line /** position in the current line */
private int linepos;
max number of entries per line /** max number of entries per line */
private static final int maxEntries = 16;
output buffer /** output buffer */
protected StringBuilder out = new StringBuilder();
number of existing string chunks /** number of existing string chunks */
protected int chunks;
maximum size of chunks /** maximum size of chunks */
// String constants are stored as UTF8 with 2 bytes length
// field in class files. One Unicode char can be up to 3
// UTF8 bytes. 64K max and two chars safety.
private static final int maxSize = 0xFFFF - 6;
indent for string lines /** indent for string lines */
private static final String indent = " ";
Create new emitter for an array.
Params: - name – the name of the generated array
/**
* Create new emitter for an array.
*
* @param name the name of the generated array
*/
public PackEmitter(String name) {
this.name = name;
}
Convert array name into all uppercase internal scanner constant name.
See Also: Returns: name
as a internal constant name.
/**
* Convert array name into all uppercase internal scanner constant name.
*
* @return {@code name} as a internal constant name.
* @see PackEmitter#name
*/
protected String constName() {
return "ZZ_" + name.toUpperCase(Locale.ENGLISH);
}
Return current output buffer.
Returns: a String
object.
/**
* Return current output buffer.
*
* @return a {@link java.lang.String} object.
*/
@Override
public String toString() {
return out.toString();
}
Emit declaration of decoded member and open first chunk. /** Emit declaration of decoded member and open first chunk. */
public void emitInit() {
out.append(" private static final int [] ");
out.append(constName());
out.append(" = zzUnpack");
out.append(name);
out.append("();");
nl();
nextChunk();
}
Emit single unicode character.
Updates length, position, etc.
Params: - i – the character to emit.
/**
* Emit single unicode character.
*
* <p>Updates length, position, etc.
*
* @param i the character to emit.
*/
public void emitUC(int i) {
if (i < 0 || i > 0xFFFF) {
throw new IllegalArgumentException("character value expected");
}
// cast ok because of prec
char c = (char) i;
printUC(c);
UTF8Length += Utf8Length(c);
linepos++;
}
Execute line/chunk break if necessary. Leave space for at least two chars. /** Execute line/chunk break if necessary. Leave space for at least two chars. */
public void breaks() {
if (UTF8Length >= maxSize) {
// close current chunk
out.append("\";");
nl();
nextChunk();
} else {
if (linepos >= maxEntries) {
// line break
out.append("\"+");
nl();
out.append(indent);
out.append("\"");
linepos = 0;
}
}
}
Emit the unpacking code. /** Emit the unpacking code. */
public abstract void emitUnpack();
emit next chunk /** emit next chunk */
private void nextChunk() {
nl();
out.append(" private static final String ");
out.append(constName());
out.append("_PACKED_");
out.append(chunks);
out.append(" =");
nl();
out.append(indent);
out.append("\"");
UTF8Length = 0;
linepos = 0;
chunks++;
}
emit newline /** emit newline */
protected void nl() {
out.append(Out.NL);
}
Append a unicode/octal escaped character to out
buffer. Params: - c – the character to append
/**
* Append a unicode/octal escaped character to {@code out} buffer.
*
* @param c the character to append
*/
private void printUC(char c) {
if (c > 255) {
out.append("\\u");
if (c < 0x1000) out.append("0");
out.append(Integer.toHexString(c));
} else {
out.append("\\");
out.append(Integer.toOctalString(c));
}
}
Calculates the number of bytes a Unicode character would have in UTF8 representation in a class
file.
Params: - value – the char code of the Unicode character
Returns: length of UTF8 representation.
/**
* Calculates the number of bytes a Unicode character would have in UTF8 representation in a class
* file.
*
* @param value the char code of the Unicode character
* @return length of UTF8 representation.
*/
private static int Utf8Length(int value) {
// see JVM spec section 4.4.7, p 111
if (value == 0) return 2;
if (value <= 0x7F) return 1;
// workaround for javac bug (up to jdk 1.3):
if (value < 0x0400) return 2;
if (value <= 0x07FF) return 3;
// correct would be:
// if (value <= 0x7FF) return 2;
return 3;
}
// convenience
println.
Params: - s – a
String
object.
/**
* println.
*
* @param s a {@link java.lang.String} object.
*/
protected void println(String s) {
out.append(s);
nl();
}
}