1 cananian 1.1.2.1  // Code.java, created Tue Jan 25 23:41:07 2000 by cananian
  2 cananian 1.1.2.1  // Copyright (C) 2000 C. Scott Ananian <cananian@alumni.princeton.edu>
  3 cananian 1.1.2.1  // Licensed under the terms of the GNU GPL; see COPYING for details.
  4 cananian 1.1.2.1  package harpoon.IR.Assem;
  5 cananian 1.1.2.1  
  6 kkz      1.1.2.6  import harpoon.Analysis.Maps.Derivation;
  7 cananian 1.1.2.2  import harpoon.ClassFile.HClass;
  8 cananian 1.1.2.2  import harpoon.ClassFile.HCode;
  9 cananian 1.1.2.2  import harpoon.ClassFile.HCodeElement;
 10 cananian 1.1.2.2  import harpoon.ClassFile.HMethod;
 11 cananian 1.1.2.1  import harpoon.Backend.Generic.Frame;
 12 cananian 1.1.2.2  import harpoon.Temp.Label;
 13 cananian 1.1.2.2  import harpoon.Temp.Temp;
 14 cananian 1.1.2.2  import harpoon.Temp.TempFactory;
 15 cananian 1.1.2.2  import harpoon.Util.ArrayFactory;
 16 cananian 1.1.2.2  import harpoon.Util.Util;
 17 cananian 1.8      import net.cscott.jutil.GenericMultiMap;
 18 cananian 1.7      import harpoon.Util.Collections.Graph;
 19 cananian 1.8      import net.cscott.jutil.MultiMap;
 20 cananian 1.8      import net.cscott.jutil.UnmodifiableIterator;
 21 cananian 1.1.2.1  
 22 cananian 1.1.2.2  import java.io.BufferedReader;
 23 cananian 1.1.2.2  import java.io.IOException;
 24 cananian 1.1.2.2  import java.io.PrintWriter;
 25 cananian 1.1.2.2  import java.io.StringReader;
 26 cananian 1.7      import java.util.AbstractSet;
 27 cananian 1.1.2.2  import java.util.Arrays;
 28 cananian 1.6      import java.util.ConcurrentModificationException;
 29 cananian 1.1.2.2  import java.util.HashSet;
 30 cananian 1.1.2.2  import java.util.Iterator;
 31 cananian 1.1.2.2  import java.util.List;
 32 cananian 1.1.2.2  import java.util.NoSuchElementException;
 33 cananian 1.1.2.2  import java.util.Set;
 34 cananian 1.1.2.1  /**
 35 cananian 1.1.2.1   * <code>IR.Assem.Code</code> is an abstract superclass of codeviews
 36 cananian 1.1.2.1   * which use <code>Instr</code>s.
 37 cananian 1.1.2.1   * 
 38 cananian 1.1.2.1   * @author  C. Scott Ananian <cananian@alumni.princeton.edu>
 39 cananian 1.8       * @version $Id: Code.java,v 1.8 2004/02/08 01:55:08 cananian Exp $
 40 cananian 1.1.2.1   */
 41 cananian 1.7      public abstract class Code extends HCode<Instr>
 42 cananian 1.7          implements Graph<Instr,InstrEdge> {
 43 cananian 1.1.2.1      private static boolean DEBUG = true;
 44 cananian 1.1.2.1  
 45 cananian 1.1.2.1      /** The method that this code view represents. */
 46 cananian 1.1.2.1      protected HMethod parent;
 47 cananian 1.1.2.1      /** The root Instr of the Instrs composing this code view. */
 48 cananian 1.1.2.1      protected Instr instrs;
 49 cananian 1.1.2.1      /** Instruction factory. */
 50 cananian 1.1.2.1      protected final InstrFactory inf;
 51 cananian 1.1.2.1      /** The Frame associated with this codeview. */
 52 cananian 1.1.2.1      protected final Frame frame;
 53 cananian 1.6          /** Keep track of modifications to this <code>Code</code> so that the
 54 cananian 1.6           *  <code>getElementsI()</code> <code>Iterator</code> can fail-fast. */
 55 cananian 1.6          int modCount=0;
 56 pnkfelix 1.1.2.4  
 57 pnkfelix 1.1.2.4      private InstrFactory newINF(final HMethod parent) {
 58 pnkfelix 1.1.2.4          return newINF(parent, getName());
 59 pnkfelix 1.1.2.4      }
 60 pnkfelix 1.1.2.4  
 61 cananian 1.1.2.1      /** Creates a new <code>InstrFactory</code> for this codeview.
 62 cananian 1.1.2.1       *
 63 cananian 1.1.2.1       *  @param  parent  The method which this codeview corresponds to.
 64 pnkfelix 1.1.2.4       *  @param  codeName The String that would be returned by a call
 65 pnkfelix 1.1.2.4       *                   to <code>Code.this.getName()</code>.
 66 cananian 1.1.2.1       *  @return         Returns a new instruction factory for the scope
 67 cananian 1.1.2.1       *                  of the parent method and this codeview.
 68 cananian 1.1.2.1       */
 69 pnkfelix 1.1.2.4      private InstrFactory newINF(final HMethod parent, String codeName) {
 70 cananian 1.1.2.1          final String scope = parent.getDeclaringClass().getName() + "." +
 71 pnkfelix 1.1.2.4              parent.getName() + parent.getDescriptor() + "/" + codeName;
 72 cananian 1.1.2.1          return new InstrFactory() {
 73 cananian 1.1.2.1              private final TempFactory tf = Temp.tempFactory(scope);
 74 cananian 1.1.2.1              private int id = 0;
 75 cananian 1.1.2.1              public TempFactory tempFactory() { return tf; }
 76 cananian 1.3.2.2              public Code getParent() { return Code.this; }
 77 cananian 1.1.2.1              public Frame getFrame() { return frame; }
 78 cananian 1.1.2.1              public synchronized int getUniqueID() { return id++; }
 79 cananian 1.1.2.1          };
 80 pnkfelix 1.1.2.4      }
 81 pnkfelix 1.1.2.4  
 82 pnkfelix 1.1.2.4      /** constructor. */
 83 pnkfelix 1.1.2.4      protected Code(HMethod parent, Frame frame, String codeName) {
 84 pnkfelix 1.1.2.4          this.parent = parent;
 85 pnkfelix 1.1.2.4          this.instrs = null;
 86 pnkfelix 1.1.2.4          this.inf = newINF(parent, codeName);
 87 pnkfelix 1.1.2.4          this.frame = frame;
 88 cananian 1.1.2.1      }
 89 cananian 1.1.2.1     
 90 cananian 1.1.2.1      /** constructor. */
 91 cananian 1.1.2.1      protected Code(HMethod parent, Frame frame) {
 92 cananian 1.1.2.1          this.parent = parent;
 93 cananian 1.1.2.1          this.instrs = null;
 94 cananian 1.1.2.1          this.inf = newINF(parent);
 95 cananian 1.1.2.1          this.frame = frame;
 96 cananian 1.1.2.1      }
 97 cananian 1.1.2.14 
 98 cananian 1.1.2.1      public HMethod getMethod() { return parent; }
 99 cananian 1.3.2.2      public Instr getRootElement() { return instrs; }
100 cananian 1.3.2.2      public Instr[] getLeafElements() { return null; }
101 cananian 1.1.2.1  
102 cananian 1.1.2.1      /** Returns an <code>Iterator</code> over the instructions in this
103 cananian 1.1.2.1          codeview.  
104 cananian 1.1.2.1       *
105 cananian 1.1.2.1       *  @return         An iterator over the <code>Instr</code>s
106 cananian 1.1.2.1       *                  making up this code view.  The root Instr is
107 cananian 1.1.2.1       *                  the first element in the iteration. */
108 cananian 1.3.2.2      public Iterator<Instr> getElementsI() { 
109 cananian 1.3.2.2          return new UnmodifiableIterator<Instr>() {
110 cananian 1.6                  // record # of modifications to enable fail-fast.
111 cananian 1.6                  int modCount = Code.this.modCount;
112 cananian 1.6                  // setup starting point.
113 cananian 1.3.2.2              Instr instr = getRootElement();
114 cananian 1.1.2.1              public boolean hasNext() { return (instr != null); }
115 cananian 1.3.2.2              public Instr next() {
116 cananian 1.6                      if (modCount != Code.this.modCount)
117 cananian 1.6                          throw new ConcurrentModificationException();
118 cananian 1.1.2.1                  if (instr == null) throw new NoSuchElementException();
119 cananian 1.1.2.1                  Instr r = instr;
120 cananian 1.1.2.1                  instr = r.getNext();
121 cananian 1.1.2.1                  return r;
122 cananian 1.1.2.1              }
123 cananian 1.1.2.1          };
124 cananian 1.1.2.1      }
125 cananian 1.1.2.1      
126 cananian 1.1.2.1      /** Returns an array factory to create the instruction elements
127 cananian 1.1.2.1       *  of this codeview.
128 cananian 1.1.2.1       *
129 cananian 1.1.2.1       *  @return         An ArrayFactory which produces Instrs.
130 cananian 1.1.2.1       */
131 cananian 1.3.2.2      public ArrayFactory<Instr> elementArrayFactory() { 
132 cananian 1.1.2.1          return Instr.arrayFactory; 
133 cananian 1.7          }
134 cananian 1.7      
135 cananian 1.7          // Graph interface
136 cananian 1.7          public Set<Instr> nodes() {
137 cananian 1.7              final List<Instr> l = getElementsL();
138 cananian 1.7              return new AbstractSet<Instr>() {
139 cananian 1.7                  public Iterator<Instr> iterator() { return l.iterator(); }
140 cananian 1.7                  public int size() { return l.size(); }
141 cananian 1.7              };
142 cananian 1.1.2.1      }
143 cananian 1.1.2.1  
144 cananian 1.1.2.1      /** Allows access to the InstrFactory used by this codeview.
145 cananian 1.1.2.1       *
146 cananian 1.1.2.1       *  @return         The InstrFactory used by this codeview.
147 cananian 1.1.2.1       */
148 cananian 1.1.2.1      public InstrFactory getInstrFactory() {
149 cananian 1.1.2.1          return inf;
150 cananian 1.1.2.1      }
151 cananian 1.1.2.1  
152 cananian 1.1.2.1      public Frame getFrame() {
153 cananian 1.1.2.1          return frame;
154 pnkfelix 1.1.2.10     }
155 pnkfelix 1.1.2.10     
156 pnkfelix 1.1.2.10     /** Prints the assembly instructions of <code>this</code> to
157 pnkfelix 1.1.2.13         System.out.
158 pnkfelix 1.1.2.10         @see Code#print(java.io.PrintWriter)
159 pnkfelix 1.1.2.10     */
160 pnkfelix 1.1.2.10     public void print() {
161 pnkfelix 1.1.2.10         print(new java.io.PrintWriter(System.out));
162 cananian 1.1.2.1      }
163 pnkfelix 1.1.2.13     
164 pnkfelix 1.1.2.13     /** Prints the assembly instructions of <code>this</code> to
165 pnkfelix 1.1.2.13         <code>pw</code>.  Default implementation is just a wrapper
166 pnkfelix 1.1.2.13         call to <code>myPrint(pw, true, false)</code>, which turns
167 pnkfelix 1.1.2.13         each Instr into its architecture specific assembly format and
168 pnkfelix 1.1.2.13         omits Instr ID number information.
169 pnkfelix 1.1.2.13     */
170 cananian 1.3.2.2      public void print(java.io.PrintWriter pw, PrintCallback<Instr> callback) {
171 cananian 1.1.2.15         myPrint(pw, true, false, callback);
172 pnkfelix 1.1.2.13     }
173 pnkfelix 1.1.2.13     
174 pnkfelix 1.1.2.17     /** Simple wrapper around myPrint passing a nop PrintCallback. */
175 pnkfelix 1.1.2.17     public final void myPrint(java.io.PrintWriter apw, boolean assem) {
176 cananian 1.3.2.2          myPrint(apw, assem, new PrintCallback<Instr>());
177 pnkfelix 1.1.2.17     }
178 pnkfelix 1.1.2.16 
179 cananian 1.1.2.1      /** Displays the assembly instructions of this codeview. Attempts
180 cananian 1.1.2.1       *  to do so in a well-formatted, easy to read way. <BR>
181 cananian 1.1.2.1       *  XXX - currently uses generic, not so easy to read, printer.
182 cananian 1.1.2.1       *
183 pnkfelix 1.1.2.16      *  @deprecated Use Code#myPrint(PrintWriter,boolean,PrintCallback)
184 pnkfelix 1.1.2.16      * 
185 pnkfelix 1.1.2.13      *  @param  pw    The PrintWriter to send the formatted output to.
186 pnkfelix 1.1.2.13      *  @param  assem If true, uses <code>toAssem(Instr)</code> to
187 pnkfelix 1.1.2.13      *          convert Instrs to assembly form.  Else just calls
188 pnkfelix 1.1.2.13      *          <code>Instr.toString()</code>. 
189 pnkfelix 1.1.2.13      *  @param  annotateID If true, prints out the ID for each Instr
190 pnkfelix 1.1.2.13      *          before printing the Instr itself.
191 pnkfelix 1.1.2.13      *  @see Code#toAssem
192 cananian 1.1.2.1       */
193 pnkfelix 1.1.2.16     protected final void myPrint(java.io.PrintWriter apw, 
194 pnkfelix 1.1.2.16                                  boolean assem,
195 pnkfelix 1.1.2.16                                  final boolean annotateID,
196 cananian 1.3.2.2                                   final PrintCallback<Instr> callback) {
197 cananian 1.3.2.2          myPrint(apw, assem, new PrintCallback<Instr>() {
198 cananian 1.3.2.2                  public void printBefore(java.io.PrintWriter pw, Instr hce ){
199 pnkfelix 1.1.2.16                     callback.printBefore(pw,hce);
200 pnkfelix 1.1.2.16                     if (annotateID) {
201 cananian 1.3.2.2                          pw.print( hce.getID() );
202 pnkfelix 1.1.2.16                         pw.print( '\t' );
203 pnkfelix 1.1.2.16                     }
204 pnkfelix 1.1.2.16                 }
205 cananian 1.3.2.2                  public void printAfter(java.io.PrintWriter pw, Instr hce ){
206 pnkfelix 1.1.2.16                     callback.printAfter(pw, hce);
207 pnkfelix 1.1.2.16                 }
208 pnkfelix 1.1.2.16             });
209 pnkfelix 1.1.2.16     }
210 pnkfelix 1.1.2.16 
211 pnkfelix 1.1.2.16     /** Displays the assembly instructions of this codeview. Attempts
212 pnkfelix 1.1.2.16      *  to do so in a well-formatted, easy to read way. <BR>
213 pnkfelix 1.1.2.16      *  XXX - currently uses generic, not so easy to read, printer.
214 pnkfelix 1.1.2.16      *
215 pnkfelix 1.1.2.16      *  @param  pw    The PrintWriter to send the formatted output to.
216 pnkfelix 1.1.2.16      *  @param  assem If true, uses <code>toAssem(Instr)</code> to
217 pnkfelix 1.1.2.16      *          convert Instrs to assembly form.  Else just calls
218 pnkfelix 1.1.2.16      *          <code>Instr.toString()</code>. 
219 pnkfelix 1.1.2.16      *  @see Code#toAssem
220 pnkfelix 1.1.2.16      */
221 pnkfelix 1.1.2.16     protected final void myPrint(java.io.PrintWriter pw, 
222 pnkfelix 1.1.2.16                                  boolean assem,
223 cananian 1.3.2.2                                   PrintCallback<Instr> callback) {
224 cananian 1.1.2.1          final HashSet outputLabels = new HashSet();
225 cananian 1.1.2.5          final MultiMap labelsNeeded = new GenericMultiMap();
226 cananian 1.1.2.1  
227 cananian 1.1.2.9          for (Instr instr=instrs; instr != null; instr=instr.getNext()) {
228 pnkfelix 1.1.2.12             StringBuffer str = new StringBuffer();
229 pnkfelix 1.1.2.13 
230 cananian 1.1.2.1              if (instr instanceof InstrLABEL ||
231 cananian 1.1.2.1                  instr instanceof InstrDIRECTIVE) {
232 cananian 1.1.2.1  
233 pnkfelix 1.1.2.13                 str.append(instr.toString());
234 cananian 1.1.2.1  
235 cananian 1.1.2.1              } else {
236 cananian 1.1.2.1                  try {
237 pnkfelix 1.1.2.17                     String asmstr = (assem?toAssem(instr):instr.toString());
238 pnkfelix 1.1.2.17                     // adding one because reader requires sz > 0
239 cananian 1.1.2.1                      BufferedReader reader = 
240 pnkfelix 1.1.2.11                         new BufferedReader
241 pnkfelix 1.1.2.17                             (new StringReader(asmstr),1+asmstr.length());
242 cananian 1.1.2.1                      String s = reader.readLine();
243 cananian 1.1.2.1                      while (s != null) {
244 pnkfelix 1.1.2.7                          str.append("\t"+ s);
245 cananian 1.1.2.1                          s = reader.readLine();
246 pnkfelix 1.1.2.7                          if (s!=null) str.append("\n");
247 cananian 1.1.2.1                      }
248 cananian 1.1.2.1                  } catch (IOException e ) {
249 cananian 1.3.2.1                      assert false : "IOException " + e.toString() + 
250 cananian 1.1.2.1                                  " should not be thrown during assembly"+
251 cananian 1.3.2.1                                  " code processing.";
252 cananian 1.1.2.1                  }
253 cananian 1.1.2.1              }
254 cananian 1.1.2.1  
255 cananian 1.1.2.15             callback.printBefore(pw, instr);
256 pnkfelix 1.1.2.16             pw.print(str.toString()); // FSK: was println!
257 cananian 1.1.2.15             callback.printAfter(pw, instr);
258 pnkfelix 1.1.2.16             pw.println();             // FSK: moved after callback
259 cananian 1.1.2.1          }
260 cananian 1.1.2.1          
261 cananian 1.1.2.1          pw.flush();
262 cananian 1.1.2.1  
263 cananian 1.1.2.1      }
264 cananian 1.1.2.1  
265 cananian 1.1.2.1      /** Produces an assembly code string for <code>instr</code>.
266 cananian 1.1.2.1       *  Uses getRegisterName() to do register name string mapping.
267 cananian 1.1.2.1       */
268 cananian 1.1.2.1      public String toAssem(Instr instr) {
269 cananian 1.1.2.1          String assem = instr.getAssem();
270 pnkfelix 1.1.2.12         StringBuffer s = new StringBuffer(assem.length());
271 cananian 1.1.2.1          
272 cananian 1.1.2.1          int len = assem.length();
273 cananian 1.1.2.1          for(int i=0; i<len; i++) {
274 cananian 1.1.2.1              char c = assem.charAt(i);
275 cananian 1.1.2.1              switch(c) {
276 cananian 1.1.2.1              case '`':
277 cananian 1.1.2.1                  Temp temp = null;
278 cananian 1.1.2.1                  Label label = null;
279 cananian 1.1.2.1                  boolean getReg = false;
280 cananian 1.1.2.1                  i++; c = assem.charAt(i);
281 cananian 1.1.2.1                  switch(c) {
282 cananian 1.1.2.1                  case 'd': {
283 cananian 1.1.2.1                      i++; int n = Character.digit(assem.charAt(i), 10);
284 cananian 1.1.2.1                      if (n < instr.def().length) {
285 cananian 1.1.2.1                          temp = instr.def()[n];
286 cananian 1.1.2.1                          getReg = true;
287 cananian 1.1.2.1                      } else {
288 cananian 1.3.2.1                          assert false : "index mismatch in "+assem + 
289 cananian 1.3.2.1                                      " " + Arrays.asList(instr.def());
290 cananian 1.1.2.1                          s.append("d?");
291 cananian 1.1.2.1                      }
292 cananian 1.1.2.1                      break;
293 cananian 1.1.2.1                  }
294 cananian 1.1.2.1                  case 's': {
295 cananian 1.1.2.1                      i++; int n = Character.digit(assem.charAt(i), 10);
296 cananian 1.1.2.1                      if (n < instr.use().length) {
297 cananian 1.1.2.1                          temp = instr.use()[n];
298 cananian 1.1.2.1                          getReg = true;
299 cananian 1.1.2.1                      } else {
300 cananian 1.3.2.1                          assert false : "index mismatch in "+assem + 
301 cananian 1.3.2.1                                      " " + Arrays.asList(instr.use());
302 cananian 1.1.2.1                          s.append("s?");
303 cananian 1.1.2.1                      }
304 cananian 1.1.2.1                      break;
305 cananian 1.1.2.1                  }
306 cananian 1.1.2.1                  case 'L': {
307 cananian 1.1.2.1                      i++; int n = Character.digit(assem.charAt(i), 10);
308 cananian 1.1.2.1                      if (n < instr.getTargets().size()) {
309 cananian 1.1.2.1                          label = (Label) instr.getTargets().get(n);
310 cananian 1.1.2.1                          s.append(label);
311 cananian 1.1.2.1                      } else {
312 cananian 1.3.2.1                          assert false : "index mismatch in "+assem + 
313 cananian 1.3.2.1                                      " " + Arrays.asList(instr.use());
314 cananian 1.1.2.1                          s.append("L?");
315 cananian 1.1.2.1                      }
316 cananian 1.1.2.1                      break;
317 cananian 1.1.2.1                  }
318 cananian 1.1.2.1                  case '`':
319 cananian 1.1.2.1                      s.append("`");
320 cananian 1.1.2.1                      break;
321 cananian 1.1.2.1                  default:
322 cananian 1.3.2.1                      assert false : "error parsing "+assem;
323 cananian 1.1.2.1                  }
324 cananian 1.1.2.1                  
325 cananian 1.1.2.1                  if (getReg) {
326 cananian 1.1.2.1                      char lastChar = ' ';
327 pnkfelix 1.1.2.12                     StringBuffer var = new StringBuffer(assem.length());
328 cananian 1.1.2.1                      boolean more = true;
329 cananian 1.1.2.1                      while(more && i<(assem.length()-1)) {
330 cananian 1.1.2.1                          i++; c = assem.charAt(i);
331 cananian 1.1.2.1                          if (!Character.isLetterOrDigit(c)) {
332 cananian 1.1.2.1                              lastChar = c;
333 cananian 1.1.2.1                              more = false;
334 cananian 1.1.2.1                          } else {
335 cananian 1.1.2.1                              var.append(c);
336 cananian 1.1.2.1                          }
337 cananian 1.1.2.1                      }
338 cananian 1.1.2.1                      /*
339 cananian 1.3.2.1                      assert ( ! mustGetRegs ) ||
340 cananian 1.1.2.1                                   frame.getRegFileInfo().isRegister(temp) ||
341 cananian 1.3.2.1                                   registerAssigned(instr, temp) : ("final assembly output for "+
342 cananian 1.1.2.1                                   "Instr: "+instr+" must have "+
343 cananian 1.1.2.1                                   "reg assigned to Temp: "+temp);
344 cananian 1.1.2.1                      */
345 cananian 1.1.2.1                      s.append(getRegisterName(instr, temp,
346 cananian 1.1.2.1                                               var.toString()));
347 cananian 1.1.2.1                      s.append(lastChar);
348 cananian 1.1.2.1                  }
349 cananian 1.1.2.1  
350 cananian 1.1.2.1                  break;
351 cananian 1.1.2.1                  
352 cananian 1.1.2.1              default: 
353 cananian 1.1.2.1                  s.append(c);
354 cananian 1.1.2.1              }
355 cananian 1.1.2.1          }
356 cananian 1.1.2.1  
357 pnkfelix 1.1.2.8          // return formatCommentedInstr(s.toString(),instr.toString());
358 pnkfelix 1.1.2.8          return s.toString();
359 cananian 1.1.2.1      }
360 kkz      1.1.2.6  
361 kkz      1.1.2.6      /** Returns the <code>Derivation</code> associated with
362 kkz      1.1.2.6          <code>this</code>. Returns <code>null</code> if
363 kkz      1.1.2.6          <code>Derivation</code> information is not available.
364 kkz      1.1.2.6      */
365 kkz      1.1.2.6      public Derivation getDerivation() { return null; }
366 cananian 1.1.2.1  
367 cananian 1.1.2.1      /** Returns an assembly code identifier for the register that
368 cananian 1.1.2.1          <code>val</code> will be stored into.
369 cananian 1.1.2.1      */
370 pnkfelix 1.1.2.3      public abstract String getRegisterName(Instr i, Temp val, 
371 pnkfelix 1.1.2.3                                             String suffix);
372 pnkfelix 1.1.2.8  
373 pnkfelix 1.1.2.8      /** Returns an assembly code String version of <code>exec</code>
374 pnkfelix 1.1.2.8          with <code>orig</code> in the comments for <code>exec</code>.
375 pnkfelix 1.1.2.8          <BR> <B>requires:</B> <code>exec</code> and <code>orig</code>
376 pnkfelix 1.1.2.8               have the same number of lines
377 pnkfelix 1.1.2.8          <BR> <B>effects:</B>
378 pnkfelix 1.1.2.8               let s be a new empty string 
379 pnkfelix 1.1.2.8               in for each line:le in <code>exec</code>,
380 pnkfelix 1.1.2.8                      let lo be the next line of <code>orig</code> ;
381 pnkfelix 1.1.2.12                     s += (le + " @" + lo)
382 pnkfelix 1.1.2.8                  return s
383 pnkfelix 1.1.2.8      */
384 pnkfelix 1.1.2.8      public static String formatCommentedInstr(String exec, String orig) {
385 pnkfelix 1.1.2.12         StringBuffer sb = new StringBuffer(exec.length() + orig.length()); 
386 pnkfelix 1.1.2.8          try {
387 pnkfelix 1.1.2.8              BufferedReader er = new BufferedReader(new StringReader(exec));
388 pnkfelix 1.1.2.8              BufferedReader or = new BufferedReader(new StringReader(orig));
389 pnkfelix 1.1.2.8              String e = er.readLine();
390 pnkfelix 1.1.2.8              String o = or.readLine();
391 pnkfelix 1.1.2.8              while(e != null) {
392 pnkfelix 1.1.2.8                  sb.append(e + " @ " + o);
393 pnkfelix 1.1.2.8                  e = er.readLine();
394 pnkfelix 1.1.2.8                  o = or.readLine();
395 pnkfelix 1.1.2.8              }
396 pnkfelix 1.1.2.8              return sb.toString();
397 pnkfelix 1.1.2.8          } catch (IOException e) {
398 cananian 1.3.2.1              assert false;
399 pnkfelix 1.1.2.8              return "died";
400 pnkfelix 1.1.2.8          }
401 pnkfelix 1.1.2.8      }
402 cananian 1.1.2.1  }
403 cananian 1.2