|
<< Previous 1
2 3
4 5
Notice the type byte is not included here. That's read
by the parser to determine which subclass to use. We really don't need it
once the subclass instances are created because the subclass objects know
their own type.
The following is the complete parser that handles primitives and
aggregate types: /**
* Created on Oct 8, 2005 5:03:27 PM
*
* @author Madhu Siddalingaiah
* http://www.madhu.com
*/
package com.madhu.picovm;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Comparator;
public class Parser {
private InputStream in;
private int count;
private Comparator fieldComparator;
public Parser() {
}
public Object parse(InputStream in, Class clazz) throws Exception {
this.in = in;
fieldComparator = new FieldComparator();
return parse(clazz);
}
public Object parse(Class clazz) throws Exception {
if (clazz.isPrimitive()) {
if (clazz == Byte.TYPE) {
return new Byte((byte) readBytes(1));
} else if (clazz == Short.TYPE) {
return new Short((short) readBytes(2));
} else if (clazz == Integer.TYPE) {
return new Integer((int) readBytes(4));
} else if (clazz == Long.TYPE) {
return new Long(readBytes(8));
} else if (clazz == Float.TYPE) {
return new Float(Float.intBitsToFloat((int) readBytes(4)));
} else if (clazz == Double.TYPE) {
return new Double(Double.longBitsToDouble(readBytes(8)));
}
throw new IllegalArgumentException("Unsupported primitive " + clazz);
}
if (clazz.isArray()) {
String name = clazz.getName();
String subtype = name.substring(2);
Class aclass;
switch (name.charAt(1)) {
case 'Z': aclass = Boolean.TYPE; break;
case 'B': aclass = Byte.TYPE; break;
case 'S': aclass = Short.TYPE; break;
case 'C': aclass = Character.TYPE; break;
case 'I': aclass = Integer.TYPE; break;
case 'J': aclass = Long.TYPE; break;
case 'F': aclass = Float.TYPE; break;
case 'D': aclass = Double.TYPE; break;
case 'L': aclass =
Class.forName(subtype.substring(0, subtype.length()-1));
break;
default: throw new AssertionError("Unknown type: " + name);
}
int n = count;
Object array = Array.newInstance(aclass, n);
for (int i=0; i<n; i+=1) {
Object value = parse(aclass);
Array.set(array, i, value);
// hack for constant pool
if (value.getClass() == DoubleEntry.class ||
value.getClass() == LongEntry.class) {
i += 1;
}
}
return array;
}
if (Modifier.isAbstract(clazz.getModifiers())) {
Object[] subTypes =
(Object[]) clazz.getDeclaredField("SUBTYPES").get(null);
Class typeClass =
(Class) clazz.getDeclaredField("TYPECLASS").get(null);
Object type = parse(typeClass);
for (int i=0; i<subTypes.length; i+=2) {
if (type.equals(subTypes[i])) {
return parse((Class) subTypes[i+1]);
}
}
throw new IllegalArgumentException("no match for subclass type " + type);
}
Field[] fields = clazz.getDeclaredFields();
// field order is not guaranteed, so sort them by trailing number
Arrays.sort(fields, fieldComparator);
Object object = clazz.newInstance();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
field.set(object, parse(field.getType()));
// hack for constant_pool_count
if (field.getName().startsWith("constant_pool_count")) {
count -= 1;
}
}
return object;
}
class FieldComparator implements Comparator {
/**
* Order by trailing number in the field name
* @see java.util.Comparator#compare(java.lang.Object, java.lang.Object)
*/
public int compare(Object o1, Object o2) {
return getFieldNumber(o1) - getFieldNumber(o2);
}
private int getFieldNumber(Object o) {
Field f = (Field) o;
String name = f.getName();
int us = name.lastIndexOf('_');
return Integer.parseInt(name.substring(us+1));
}
}
/**
* @return a 64 bit value repesenting up to 8 bytes
*/
private long readBytes(int size) throws IOException {
long value = 0;
for (int i=0; i<size; i+=1) {
value <<= 8;
value |= in.read();
}
count = (int) value;
return value;
}
}
Next: Grammar and main()
1
2 3
4 5
Next>>
|