/* --- Copyright Jonathan Meyer 1997. All rights reserved. ----------------- > File: jasmin/src/jasmin/ClassFile.java > Purpose: Uses a parser and the JAS package to create Java class files > Author: Jonathan Meyer, 10 July 1996 */ package jasmin; /* * This class is a bit monolithic, and should probably be converted into * several smaller classes. However, for this specific application, * its acceptable. * */ import jas.*; import java.io.InputStream; import java.io.OutputStream; import java.io.DataOutputStream; import java.io.IOException; import java.util.*; /** * A ClassFile object is used to represent the binary data that makes up a * Java class file - it also serves as the public * API to the Jasmin assembler, though users should beware: the API * is likely to change in future versions (though its such a small API * at the moment that changes are likely to have only a small impact).<p> * * To assemble a file, you first construct a jasmin.ClassFile object, then * call readJasmin() to read in the contents of a Jasmin assembly file, then * call write() to write out the binary representation of the class file.<p> * * There are a few other utility methods as well. See Main.java for an example * which uses all of the public methods provided in ClassFile. * * @author Jonathan Meyer * @version 1.05, 8 Feb 1997 */ public class ClassFile { // state info for the class being built String filename; ClassEnv class_env; String class_name; String source_name; Scanner scanner; // state info for the current method being defined String method_name; String method_signature; short method_access; ExceptAttr except_attr; Catchtable catch_table; LocalVarTableAttr var_table; LineTableAttr line_table; CodeAttr code; InnerClassAttr inner_class_attr; Hashtable labels; boolean methSynth; boolean methDepr; String methSigAttr; VisibilityAnnotationAttr methAnnotAttrVis; VisibilityAnnotationAttr methAnnotAttrInvis; ParameterVisibilityAnnotationAttr methParamAnnotAttrVis; ParameterVisibilityAnnotationAttr methParamAnnotAttrInvis; ElemValPair methAnnotDef; int line_label_count, line_num; boolean auto_number; // state info for lookupswitch and tableswitch instructions Vector switch_vec; int low_value; int high_value; int lastInstSize; Method currentMethod; Var currentField; VisibilityAnnotationAttr vis_annot_attr; public void addSootCodeAttr(String name, String value) { class_env.addCPItem(new AsciiCP(name)); code.addSootCodeAttr(name, value); } public void addGenericAttrToMethod(String name, byte[] value) { if(currentMethod == null) System.err.println("Error: no field in scope to add attribute onto."); else { class_env.addCPItem(new AsciiCP(name)); currentMethod.addGenericAttr(new GenericAttr(name, value)); } } public void addGenericAttrToField(String name, byte[] value) { if(currentField == null) System.err.println("Error: no field in scope to add attribute onto."); else { class_env.addCPItem(new AsciiCP(name)); currentField.addGenericAttr(new GenericAttr(name, value)); } } public void addDeprecatedToField(){ if (currentField == null){ System.err.println("Error: no field in scope to add deprecated attribute onto"); } else { //System.out.println("adding deprec to field" ); currentField.addDeprecatedAttr(new DeprecatedAttr()); } } public void addGenericAttrToClass(GenericAttr g) { class_env.addGenericAttr(g); } static final String BGN_METHOD = "bgnmethod:"; static final String END_METHOD = "endmethod:"; // number of errors reported in a file. int errors; // // Error reporting method // void report_error(String msg) { // Print out filename/linenumber/message System.err.print(filename + ":"); System.err.print(scanner.line_num); System.err.println(": " + msg + "."); if (scanner.char_num >= 0) { System.err.println(scanner.line.toString()); // Print out where on the line the scanner got to int i; for (i = 0; i < scanner.char_num; i++) { if (scanner.line.charAt(i) == '\t') { System.err.print("\t"); } else { System.err.print(" "); } } System.err.println("^"); } errors++; } // // called by the .source directive // void setSource(String name) { source_name = name; } // // called by the .class directive // void setClass(String name, short acc) { class_name = name; class_env.setClass(new ClassCP(name)); class_env.setClassAccess(acc); } // // called by the .super directive // void setSuperClass(String name) { class_env.setSuperClass(new ClassCP(name)); } // // called by the .no_super directive // (for java.lang.Object only) void setNoSuperClass() { class_env.setNoSuperClass(); } // // called by the .implements directive // void addInterface(String name) { class_env.addInterface(new ClassCP(name)); } void addClassDeprAttr(Object res){ if (res != null){ class_env.setClassDepr(new DeprecatedAttr()); } } void addClassSigAttr(Object res){ if (res != null){ class_env.setClassSigAttr(new SignatureAttr((String)res)); } } void addClassAnnotAttrVisible(Object res){ if (res != null){ class_env.setClassAnnotAttrVis((VisibilityAnnotationAttr)res); } } void addClassAnnotAttrInvisible(Object res){ if (res != null){ class_env.setClassAnnotAttrInvis((VisibilityAnnotationAttr)res); } } void addField(short access, String name, String sig, Object value, Object dep_attr, Object sig_attr, Object vis_annot_attr, Object vis_annot_attr2){ addField(access, name, sig, value, null, dep_attr, sig_attr, vis_annot_attr, vis_annot_attr2); } // // called by the .field directive // void addField(short access, String name, String sig, Object value, String synth, Object dep_attr, Object sig_attr, Object vis_annot_attr, Object vis_annot_attr2) { if (value == null) { // defining a field which doesn't have an initial value if (synth == null){ currentField = new Var(access, new AsciiCP(name), new AsciiCP(sig), null); } else { currentField = new Var(access, new AsciiCP(name), new AsciiCP(sig), null, new SyntheticAttr()); } if(dep_attr != null){ currentField.addDeprecatedAttr(new DeprecatedAttr()); } if(sig_attr != null){ currentField.addSignatureAttr(new SignatureAttr((String)sig_attr)); } if (vis_annot_attr != null){ VisibilityAnnotationAttr attribute = (VisibilityAnnotationAttr)vis_annot_attr; if(attribute.getKind().equals("RuntimeVisible")) currentField.addVisibilityAnnotationAttrVis(attribute); else currentField.addVisibilityAnnotationAttrInvis(attribute); } if (vis_annot_attr2 != null){ VisibilityAnnotationAttr attribute = (VisibilityAnnotationAttr)vis_annot_attr2; if(attribute.getKind().equals("RuntimeVisible")) currentField.addVisibilityAnnotationAttrVis(attribute); else currentField.addVisibilityAnnotationAttrInvis(attribute); } /*currentField = new Var(access, new AsciiCP(name), new AsciiCP(sig), null);*/ class_env.addField(currentField); } else { // defining a field with an initial value... // create a constant pool entry for the initial value CP cp = null; // correctness patch due to Brian Demsky (bdemsky@mit.edu) // it's strange that Soot doesn't trigger this bug. if (sig.equals("I")||sig.equals("Z")||sig.equals("C")||sig.equals("B")||sig.equals("S")) { cp = new IntegerCP(((Number)value).intValue()); } else if (sig.equals("F")) { cp = new FloatCP(((Number)value).floatValue()); } else if (sig.equals("D")) { cp = new DoubleCP(((Number)value).doubleValue()); } else if (sig.equals("J")) { cp = new LongCP(((Number)value).longValue()); } else if (sig.equals("Ljava/lang/String;")) { cp = new StringCP((String)value); } // add the field if (synth == null){ currentField = new Var(access, new AsciiCP(name), new AsciiCP(sig), new ConstAttr(cp)); } else { currentField = new Var(access, new AsciiCP(name), new AsciiCP(sig), new ConstAttr(cp), new SyntheticAttr()); } if(dep_attr != null){ currentField.addDeprecatedAttr(new DeprecatedAttr()); } if(sig_attr != null){ currentField.addSignatureAttr(new SignatureAttr((String)sig_attr)); } class_env.addField(currentField); } } // // called by the .method directive to start the definition for a method // void newMethod(String name, String signature, int access) { // set method state variables labels = new Hashtable(); method_name = name; code = null; except_attr = null; catch_table = null; var_table = null; line_table = null; line_label_count = 0; method_signature = signature; method_access = (short)access; methSynth = false; methDepr = false; methSigAttr = null; methAnnotAttrVis = null; methAnnotAttrInvis = null; methParamAnnotAttrVis = null; methParamAnnotAttrInvis = null; methAnnotDef = null; } // // called by the .end method directive to end the definition for a method // void endMethod() throws jasError { if (code != null) { plantLabel(END_METHOD); if (catch_table != null) { code.setCatchtable(catch_table); } if (var_table != null) { code.setLocalVarTable(var_table); } if (line_table != null) { code.setLineTable(line_table); } code.setLabelTable(labels); } if (!methSynth){ currentMethod = new Method(method_access, new AsciiCP(method_name), new AsciiCP(method_signature), code, except_attr); } else { currentMethod = new Method(method_access, new AsciiCP(method_name), new AsciiCP(method_signature), code, except_attr, new SyntheticAttr()); } if (methDepr){ currentMethod.addDeprecatedAttr(new DeprecatedAttr()); } if (methSigAttr != null){ currentMethod.addSignatureAttr(new SignatureAttr(methSigAttr)); } if (methAnnotAttrVis != null){ currentMethod.addVisAnnotationAttr(methAnnotAttrVis); } if (methAnnotAttrInvis != null){ currentMethod.addInvisAnnotationAttr(methAnnotAttrInvis); } if (methParamAnnotAttrVis != null){ currentMethod.addVisParamAnnotationAttr(methParamAnnotAttrVis); } if (methParamAnnotAttrInvis != null){ currentMethod.addInvisParamAnnotationAttr(methParamAnnotAttrInvis); } if (methAnnotDef != null){ methAnnotDef.setNoName(); currentMethod.addAnnotationDef(new AnnotationDefaultAttr(methAnnotDef)); } class_env.addMethod( currentMethod); // clear method state variables code = null; labels = null; method_name = null; code = null; except_attr = null; catch_table = null; line_table = null; var_table = null; methSynth = false; methDepr = false; methSigAttr = null; methAnnotAttrVis = null; methParamAnnotAttrVis = null; methAnnotDef = null; } // // plant routines - these use addInsn to add instructions to the // code for the current method. // // // used for instructions that take no arguments // void plant(String name) throws jasError { InsnInfo insn = InsnInfo.get(name); autoNumber(); if (insn.args.equals("")) { Insn inst = new Insn(insn.opcode); _getCode().addInsn(inst); } else if (insn.name.equals("wide")) { // don't do anything for this one... } else { throw new jasError("Missing arguments for instruction " + name); } } // // used for iinc // void plant(String name, int v1, int v2) throws jasError { autoNumber(); if (name.equals("iinc")) { Insn inst = new IincInsn(v1, v2); _getCode().addInsn(inst); } else { throw new jasError("Bad arguments for instruction " + name); } } // // used for instructions that take an integer parameter // void plant(String name, int val) throws jasError { InsnInfo insn = InsnInfo.get(name); CodeAttr code = _getCode(); autoNumber(); Insn inst = null; if (insn.args.equals("i")) { inst = new Insn(insn.opcode, val); } else if (insn.args.equals("constant")) { inst = new Insn(insn.opcode, new IntegerCP(val)); } else if (insn.args.equals("bigconstant")) { inst = new Insn(insn.opcode, new LongCP(val)); } else { throw new jasError("Bad arguments for instruction " + name); } code.addInsn(inst); } // // used for ldc and other instructions that take a numeric argument // void plant(String name, Number val) throws jasError { InsnInfo insn = InsnInfo.get(name); CodeAttr code = _getCode(); autoNumber(); Insn inst = null; if (insn.args.equals("i") && (val instanceof Integer)) { inst = new Insn(insn.opcode, val.intValue()); } else if (insn.args.equals("constant")) { if (val instanceof Integer || val instanceof Long) { inst = new Insn(insn.opcode, new IntegerCP(val.intValue())); } else if (val instanceof Float || val instanceof Double) { inst = new Insn(insn.opcode, new FloatCP(val.floatValue())); } } else if (insn.args.equals("bigconstant")) { if (val instanceof Integer || val instanceof Long) { inst = new Insn(insn.opcode, new LongCP(val.longValue())); } else if (val instanceof Float || val instanceof Double) { inst = new Insn(insn.opcode, new DoubleCP(val.doubleValue())); } } else { throw new jasError("Bad arguments for instruction " + name); } _getCode().addInsn(inst); } // // used for ldc <quoted-string> // void plantString(String name, String val) throws jasError { //System.out.println("plant string"); InsnInfo insn = InsnInfo.get(name); autoNumber(); Insn inst = null; if (insn.args.equals("constant")) { inst = new Insn(insn.opcode, new StringCP(val)); } else { throw new jasError("Bad arguments for instruction " + name); } code.addInsn(inst); } // // used for invokeinterface and multianewarray // void plant(String name, String val, int nargs) throws jasError { InsnInfo insn = InsnInfo.get(name); CodeAttr code = _getCode(); autoNumber(); Insn inst = null; if (insn.args.equals("interface")) { String split[] = ScannerUtils.splitClassMethodSignature(val); inst = new InvokeinterfaceInsn( new InterfaceCP(split[0], split[1], split[2]), nargs); } else if (insn.args.equals("marray")) { inst = new MultiarrayInsn(new ClassCP(val), nargs); } else { throw new jasError("Bad arguments for instruction " + name); } code.addInsn(inst); } // // used for instructions that take a word as a parameter // (e.g. branches, newarray, invokemethod) // void plant(String name, String val) throws jasError { //System.out.println("plant name, val: "+val); InsnInfo insn = InsnInfo.get(name); CodeAttr code = _getCode(); autoNumber(); Insn inst = null; if (insn.args.equals("method")) { String split[] = ScannerUtils.splitClassMethodSignature(val); inst = new Insn(insn.opcode, new MethodCP(split[0], split[1], split[2])); } else if (insn.args.equals("constant")) { //System.out.println("constant"); inst = new Insn(insn.opcode, new ClassCP(val)); } else if (insn.args.equals("atype")) { int atype = 0; if (val.equals("boolean")) { atype = 4; } else if (val.equals("char")) { atype = 5; } else if (val.equals("float")) { atype = 6; } else if (val.equals("double")) { atype = 7; } else if (val.equals("byte")) { atype = 8; } else if (val.equals("short")) { atype = 9; } else if (val.equals("int")) { atype = 10; } else if (val.equals("long")) { atype = 11; } else { throw new jasError("Bad array type: " + name); } inst = new Insn(insn.opcode, atype); } else if (insn.args.equals("label")) { inst = new Insn(insn.opcode, getLabel(val)); } else if (insn.args.equals("class")) { inst = new Insn(insn.opcode, new ClassCP(val)); } else { throw new jasError("Bad arguments for instruction " + name); } code.addInsn(inst); } // // used for instructions that take a field and a signature as parameters // (e.g. getstatic, putstatic) // void plant(String name, String v1, String v2) throws jasError { InsnInfo info = InsnInfo.get(name); CodeAttr code = _getCode(); autoNumber(); Insn inst = null; if (info.args.equals("field")) { String split[] = ScannerUtils.splitClassField(v1); inst = new Insn(info.opcode, new FieldCP(split[0], split[1], v2)); } else { throw new jasError("Bad arguments for instruction " + name); } code.addInsn(inst); } // // Lookupswitch instruction // void newLookupswitch() throws jasError { switch_vec = new Vector(); autoNumber(); }; void addLookupswitch(int val, String label) throws jasError { switch_vec.addElement(new Integer(val)); switch_vec.addElement(getLabel(label)); }; void endLookupswitch(String deflabel) throws jasError { int n = switch_vec.size() >> 1; int offsets[] = new int[n]; Label labels[] = new Label[n]; Enumeration e = switch_vec.elements(); int i = 0; while (e.hasMoreElements()) { offsets[i] = ((Integer)e.nextElement()).intValue(); labels[i] = (Label)e.nextElement(); i++; } _getCode().addInsn(new LookupswitchInsn(getLabel(deflabel), offsets, labels)); } // // Tableswitch instruction // void newTableswitch(int lowval) throws jasError { newTableswitch(lowval, -1); }; void newTableswitch(int lowval, int hival) throws jasError { switch_vec = new Vector(); low_value = lowval; high_value = hival; autoNumber(); }; void addTableswitch(String label) throws jasError { switch_vec.addElement(getLabel(label)); }; void endTableswitch(String deflabel) throws jasError { int n = switch_vec.size(); Label labels[] = new Label[n]; Enumeration e = switch_vec.elements(); int i = 0; while (e.hasMoreElements()) { labels[i] = (Label)e.nextElement(); i++; } if (high_value != -1 && (high_value != low_value + n - 1)) { report_error("tableswitch - given incorrect value for <high>"); } _getCode().addInsn(new TableswitchInsn(low_value, low_value + n - 1, getLabel(deflabel), labels)); } // Used by the parser to tell ClassFile what the line number // for the next statement is. ClassFile's autoNumber mechanism // uses this info. void setLine(int l) { line_num = l; } // // If auto_number is true, output debugging line number table // for Jasmin assembly instructions. // void autoNumber() throws jasError { if (auto_number) { // use the line number of the last token addLineInfo(line_num); } } // // Label management // // // gets the Label object for a label, creating it if it doesn't exist // Label getLabel(String name) throws jasError { // check that we are inside of a method definition if (method_name == null) { throw new jasError( "illegal use of label outside of method definition"); } Label lab = (Label)labels.get(name); if (lab == null) { lab = new Label(name); labels.put(name, lab); } return lab; } // // defines a label // void plantLabel(String name) throws jasError { // unsure what happens if you use a label twice? _getCode().addInsn(getLabel(name)); } // // used by the .var directive // void addVar(String startLab, String endLab, String name, String sig, int var_num) throws jasError { if (startLab == null) { startLab = BGN_METHOD; } if (endLab == null) { endLab = END_METHOD; } Label slab, elab; slab = getLabel(startLab); elab = getLabel(endLab); if (var_table == null) { var_table = new LocalVarTableAttr(); } var_table.addEntry(new LocalVarEntry(slab, elab, name, sig, var_num)); } // // used by .line directive // void addLineInfo(int line_num) throws jasError { String l = "L:" + (line_label_count++); if (line_table == null) { line_table = new LineTableAttr(); } plantLabel(l); line_table.addEntry(getLabel(l), line_num); } void addLine(int line_num) throws jasError { if (!auto_number) { addLineInfo(line_num); } } // // used by the .throws directive // void addThrow(String name) throws jasError { // check that we are inside of a method definition if (method_name == null) { throw new jasError( "illegal use of .throw outside of method definition"); } if (except_attr == null) { except_attr = new ExceptAttr(); } except_attr.addException(new ClassCP(name)); } // // used by the .catch directive // void addCatch(String name, String start_lab, String end_lab, String branch_lab) throws jasError { ClassCP class_cp; // check that we are inside of a method definition if (method_name == null) { throw new jasError( "illegal use of .catch outside of method definition"); } if (catch_table == null) { catch_table = new Catchtable(); } if (name.equals("all")) { class_cp = null; } else { class_cp = new ClassCP(name); } catch_table.addEntry(getLabel(start_lab), getLabel(end_lab), getLabel(branch_lab), class_cp); } // // used by the .limit stack directive // void setStackSize(short v) throws jasError { _getCode().setStackSize(v); } // // used by the .limit vars directive // void setVarSize(short v) throws jasError { _getCode().setVarSize(v); } // --- Private stuff --- // // returns the code block, creating it if it doesn't exist // CodeAttr _getCode() throws jasError { // check that we are inside of a method definition if (method_name == null) { throw new jasError( "illegal use of instruction outside of method definition"); } if (code == null) { code = new CodeAttr(); plantLabel(BGN_METHOD); } return (code); } void addInnerClassAttr(){ } void addInnerClassSpec(String inner_class_name, String outer_class_name, String inner_name, short access){ if (inner_class_attr == null){ inner_class_attr = new InnerClassAttr(); } //inner_class_attr.addInnerClassSpec(new InnerClassSpecAttr(new ClassCP(inner_class_name), new ClassCP(outer_class_name), new AsciiCP(inner_name), access)); inner_class_attr.addInnerClassSpec(new InnerClassSpecAttr(inner_class_name, outer_class_name, inner_name, access)); } void endInnerClassAttr(){ class_env.finishInnerClassAttr(inner_class_attr); } void addClassSynthAttr(){ class_env.setClassSynth(true); } void addMethSynthAttr(){ methSynth = true; } void addMethDeprAttr(){ methDepr = true; } void addMethSigAttr(String s){ methSigAttr = s; } void addEnclMethAttr(String cls, String meth, String sig){ class_env.addEnclMethAttr(new EnclMethAttr(cls, meth, sig)); } void addMethAnnotAttrVisible(Object attr){ methAnnotAttrVis = (VisibilityAnnotationAttr)attr; } void addMethAnnotAttrInvisible(Object attr){ methAnnotAttrInvis = (VisibilityAnnotationAttr)attr; } void addMethParamAnnotAttrVisible(Object attr){ methParamAnnotAttrVis = (ParameterVisibilityAnnotationAttr)attr; } void addMethParamAnnotAttrInvisible(Object attr){ methParamAnnotAttrInvis = (ParameterVisibilityAnnotationAttr)attr; } void addMethAnnotDefault(Object attr){ methAnnotDef = (ElemValPair)attr; } VisibilityAnnotationAttr makeVisibilityAnnotation(Object tval, Object list){ return new VisibilityAnnotationAttr((String)tval, (ArrayList)list); } ParameterVisibilityAnnotationAttr makeParameterVisibilityAnnotation(Object kind, Object list){ return new ParameterVisibilityAnnotationAttr((String)kind+"Parameter", (ArrayList)list); } void endVisibilityAnnotation(){ } /*void addAnnotAttrToField(){ System.out.println("curr Field: "+currentField); if (currentField != null){ currentField.addVisibilityAnnotationAttr(vis_annot_attr, class_env); } }*/ AnnotationAttr currAnn = null; ArrayList makeNewAnnotAttrList(Object annot){ ArrayList list = new ArrayList(); list.add(annot); return (ArrayList)list; } ArrayList mergeNewAnnotAttr(Object list, Object elem){ ((ArrayList)list).add(elem); return (ArrayList)list; } ArrayList makeNewAnnotationList(Object elem){ ArrayList list = new ArrayList(); list.add(elem); return (ArrayList)list; } ArrayList mergeNewAnnotation(Object list, Object elem){ ((ArrayList)list).add(elem); return (ArrayList)list; } AnnotationAttr makeAnnotation(String type, Object elems){ return new AnnotationAttr(type, (ArrayList)elems); } void endAnnotation(){ if (vis_annot_attr == null){ vis_annot_attr = new VisibilityAnnotationAttr(); } vis_annot_attr.addAnnotation(currAnn); } ArrayList makeNewElemValPairList(Object elem){ ArrayList list = new ArrayList(); list.add(elem); return list; } ArrayList mergeNewElemValPair(Object list, Object elem){ ((ArrayList)list).add(elem); return (ArrayList)list; } ElemValPair makeConstantElem(String name, char kind, Object val){ //System.out.println("making constant elem val pair: "+val); ElemValPair result = null; //System.out.println("val: "+val); switch(kind){ case 'S' : { } case 'B' : { } case 'Z' : { } case 'C' : { } case 'I' : { result = new IntElemValPair(name, kind, ((Integer)val).intValue()); break; } case 'J' : { result = new LongElemValPair(name, kind, ((Number)val).longValue()); break; } case 'F' : { result = new FloatElemValPair(name, kind, ((Number)val).floatValue()); break; } case 'D' : { result = new DoubleElemValPair(name, kind, ((Number)val).doubleValue()); break; } case 's' : { result = new StringElemValPair(name, kind, (String)val); break; } } return result; } ElemValPair makeEnumElem(String name, char kind, String tval, String cval){ return new EnumElemValPair(name, kind, tval, cval); } ElemValPair makeClassElem(String name, char kind, String cval){ return new ClassElemValPair(name, kind, cval); } ElemValPair makeAnnotElem(String name, char kind, Object attr){ return new AnnotElemValPair(name, kind, (AnnotationAttr)attr); } ElemValPair makeArrayElem(String name, char kind, Object list){ ArrayElemValPair elem = new ArrayElemValPair(name, kind, (ArrayList)list); elem.setNoName(); return elem; } void endAnnotElem(){ } void endArrayElem(){ } // PUBLIC API TO JASMIN: /** Makes a new ClassFile object, used to represent a Java class file. * You can then use readJasmin to read in a class file stored in * Jasmin assembly format. */ public ClassFile() { } /** * Parses a Jasmin file, converting it internally into a binary * representation. * If something goes wrong, this throws one of * an IOException, or a jasError, or one of a few other exceptions. * I'll tie this down more formally in the next version. * * @param input is the stream containing the Jasmin assembly code for the * class. * * @param name is the name of the stream. This name will be * concatenated to error messages printed to System.err. * * @param numberLines true if you want Jasmin to generate line * numbers automatically, based on the assembly source, or * false if you are using the ".line" directive and don't * want Jasmin to help out. */ public void readJasmin(InputStream input, String name, boolean numberLines) throws IOException, Exception { // initialize variables for error reporting errors = 0; filename = name; source_name = name; // if numberLines is true, we output LineTableAttr's that indicate what line // numbers the Jasmin code falls on. auto_number = numberLines; // Parse the input file class_env = new ClassEnv(); scanner = new Scanner(input); parser parse_obj = new parser(this, scanner); if (false) { // for debugging // parse_obj.debug_parse(); } else { parse_obj.parse(); } } /** * Returns the number of warnings/errors encountered while parsing a file. * 0 if everything went OK. */ public int errorCount() { return errors; } /** * Returns the name of the class in the file (i.e. the string given to * the .class parameter in Jasmin) * */ public String getClassName() { return class_name; } /** * Writes the binary data for the class represented by this ClassFile * object to the specified * output stream, using the Java Class File format. Throws either an * IOException or a jasError if something goes wrong. */ public void write(OutputStream outp) throws IOException, jasError { class_env.setSource(source_name); class_env.write(new DataOutputStream(outp)); } }; /* --- Revision History --------------------------------------------------- --- Jonathan Meyer, April 11 1997 Fixed bug where source_name was not being set in class_env. --- Jonathan Meyer, Mar 1 1997 Renamed "Jasmin" class "ClassFile". --- Jonathan Meyer, Feb 8 1997 Converted to non-static. Made a public API. Split off InsnInfo to a separate file. --- Jonathan Meyer, Oct 1 1996 Added addInterface method, used by the .implements directive. --- Jonathan Meyer, July 25 1996 Added setLine and line_num, to fix problem with autoNumber. Added report_error method. --- Jonathan Meyer, July 24 1996 added version constant. */