separated interpreter from assembler
[fleet.git] / src / edu / berkeley / fleet / assembler / Parser.java
similarity index 55%
rename from src/edu/berkeley/fleet/parser/Parser.java
rename to src/edu/berkeley/fleet/assembler/Parser.java
index 6c73537..7c9318e 100644 (file)
@@ -1,11 +1,7 @@
-package edu.berkeley.fleet.parser;
+package edu.berkeley.fleet.assembler;
 
 import edu.berkeley.fleet.api.*;
 
-// used only for special interpreter parsing extensions
-import edu.berkeley.fleet.interpreter.Interpreter;
-import edu.berkeley.fleet.interpreter.CodeBag;
-
 import edu.berkeley.sbp.*;
 import edu.berkeley.sbp.chr.*;
 import edu.berkeley.sbp.misc.*;
@@ -15,24 +11,27 @@ import edu.berkeley.sbp.util.*;
 import java.util.*;
 import java.io.*;
 
-// FIXME: eliminate use of CodeBag class
-
 /**
  *  @author Adam Megacz <megacz@cs.berkeley.edu>
- *  @author Thomas Kho <tkho@eecs.berkeley.edu>
  */
-public class Parser {
+class Parser {
 
-    public Parser(Fleet fleet) {
+    Parser(Fleet fleet) {
         this.fleet = fleet;
     }
 
     //////////////////////////////////////////////////////////////////////////////
 
-    private HashMap<String,Ship> shipMap =
-        new HashMap<String,Ship>();
+    private Fleet fleet;
+    private ArrayList<String> imports = new ArrayList<String>();
 
-    static Tree<String> parse(Reader r) throws Exception {
+    private HashMap<String,Ship> shipMap = new HashMap<String,Ship>();
+
+    // codebags in numerical order
+    private ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
+    private HashMap<String,CodeBag> codeBagsByName = new HashMap<String,CodeBag>();
+
+    Tree<String> parse(Reader r) throws Exception {
         InputStream grammarStream =
             Parser.class.getClassLoader().getResourceAsStream("edu/berkeley/fleet/parser/fleet.g");
         CharParser metaGrammarParser   = new CharParser(MetaGrammar.newInstance());
@@ -43,26 +42,93 @@ public class Parser {
         return tree;
     }
 
-    private Fleet fleet;
-    private ArrayList<String> imports = new ArrayList<String>();
+    public void parse(Reader r, OutputStream out) throws Exception {
+
+        // this needs to be "code bag zero"
+        CodeBag baseCodeBag = new CodeBag();
+        CodeBag rootCodeBag = new CodeBag();
+        baseCodeBag.add(new Instruction.Literal.CodeBagDescriptor(null, rootCodeBag.getFakeAddress(), 1));
+        walk((Tree<String>)parse(r), rootCodeBag);
+        
+        // map from arbitrary identifiers to actual addresses
+        int[] codeBagMap = new int[codeBags.size()];
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        CountingOutputStream cos   = new CountingOutputStream(baos);
+        DataOutputStream dos       = new DataOutputStream(cos);
+        for(int i=0; i<codeBags.size(); i++) {
+            CodeBag c = codeBags.get(i);
+            dos.flush();
+            codeBagMap[i] = cos.getCount();
+            for(Instruction inst : c)
+                fleet.writeInstruction(dos, inst);
+        }
+
+        // now write for real
+        dos = new DataOutputStream(out);
+        cos = new CountingOutputStream(dos);
+        for(int i=0; i<codeBags.size(); i++) {
+            CodeBag c = codeBags.get(i);
+            dos.flush();
+            for(Instruction inst : c) {
+                if (inst instanceof Instruction.Literal.CodeBagDescriptor) {
+                    dos.flush();
+                    cos.getCount();
+                    Instruction.Literal.CodeBagDescriptor old = (Instruction.Literal.CodeBagDescriptor)inst;
+                    int offset = fleet.computeOffset(cos.getCount(), codeBagMap[(int)old.offset]);
+                    inst = new Instruction.Literal.CodeBagDescriptor(old.dest,
+                                                                     offset,
+                                                                     codeBags.get((int)old.offset).size());
+                }
+                fleet.writeInstruction(dos, inst);
+            }
+        }
+        dos.flush();
+    }
+
+    public void parse(Reader r, ArrayList<Instruction> out) throws Exception {
+        // this needs to be "code bag zero"
+        CodeBag baseCodeBag = new CodeBag();
+        CodeBag rootCodeBag = new CodeBag();
+        Instruction inst0 = new Instruction.Literal.CodeBagDescriptor(null, rootCodeBag.getFakeAddress(), 1);
+        baseCodeBag.add(inst0);
+        walk((Tree<String>)parse(r), rootCodeBag);
 
+        // map from arbitrary identifiers to actual addresses
+        int[] codeBagMap = new int[codeBags.size()];
+        ArrayList<Instruction> temp = new ArrayList<Instruction>();
+        for(int i=0; i<codeBags.size(); i++) {
+            codeBagMap[i] = temp.size();
+            for(Instruction inst : codeBags.get(i))
+                temp.add(inst);
+        }
 
-    public CodeBag walk(Reader r) throws Exception {
-        return walk((Tree<String>)parse(r));
+        // now write for real
+        for(int i=0; i<codeBags.size(); i++) {
+            CodeBag c = codeBags.get(i);
+            for(Instruction inst : c) {
+                if (inst instanceof Instruction.Literal.CodeBagDescriptor) {
+                    Instruction.Literal.CodeBagDescriptor old = (Instruction.Literal.CodeBagDescriptor)inst;
+                    int offset = fleet.computeOffset(out.size(), codeBagMap[(int)old.offset]);
+                    inst = new Instruction.Literal.CodeBagDescriptor(old.dest,
+                                                                     offset,
+                                                                     codeBags.get((int)old.offset).size());
+                }
+                out.add(inst);
+            }
+        }
     }
 
-    CodeBag walk(Tree<String> t) {
-        CodeBag rootCodeBag = null;
+    /** in the first pass, codebags are assigned "addresses" in arbitrary order */
+    void walk(Tree<String> t, CodeBag cb) {
+
         String head = t.head();
         if (head==null) {
         } else if (head.equals("Program")) {
             for(Tree<String> tc : t.child(0))
-                walk(tc);
-            CodeBag cb = new CodeBag(null, null);
+                walk(tc, cb);
             if (t.size()>1)
                 for(Tree<String> statement : t.child(1))
                     fillCodeBag(statement, cb);
-            rootCodeBag = cb;
    
         } else if (head.equals("Import")) {
             imports.add(string(t.child(0)));
@@ -71,11 +137,13 @@ public class Parser {
             String name = name(t.child(0));
             String type = string(t.child(1));
             Ship ship = null;
-            if (fleet instanceof Fleet) {
+            if (fleet instanceof edu.berkeley.fleet.interpreter.Interpreter) {
+                edu.berkeley.fleet.interpreter.Interpreter interpreter =
+                    ((edu.berkeley.fleet.interpreter.Interpreter)fleet);
                 String classname = type;
                 boolean good = false;
                 for(String s : imports)
-                    if ((ship = ((Interpreter)fleet).tryCreate(s+"."+classname, name)) != null)
+                    if ((ship = interpreter.tryCreate(s+"."+classname, name)) != null)
                         break;
                 if (ship==null)
                     throw new RuntimeException("couldn't find a ship called \""+classname+"\"");
@@ -86,21 +154,20 @@ public class Parser {
 
         } else if (head.equals("Include")) {
             try {
-                walk(parse(new InputStreamReader(new FileInputStream(string(t.child(0))))));
+                walk(parse(new InputStreamReader(new FileInputStream(string(t.child(0))))), cb);
             } catch (Exception e) {
                 throw new RuntimeException(e);
             }
             
         } else if (head.equals("Memory")) {
-            if (((Interpreter)fleet).mem.length != 0)
+            if (((edu.berkeley.fleet.interpreter.Interpreter)fleet).mem.length != 0)
                 throw new RuntimeException("multiple memory directives found");
             Tree<String> m = t.child(0);
             int[] mem = new int[m.size()];
             for(int i=0; i<mem.length; i++)
                 mem[i] = Integer.parseInt(string(m.child(i)));
-            ((Interpreter)fleet).mem = mem;
+            ((edu.berkeley.fleet.interpreter.Interpreter)fleet).mem = mem;
         }
-        return rootCodeBag;
     }
 
     String string(Tree<String> t) {
@@ -148,7 +215,7 @@ public class Parser {
     void fillCodeBag(Tree<String> t, CodeBag cb) {
         if (t.head()==null) return;
         else if (t.head().equals("NamedCodeBag")) {
-            CodeBag cb2 = new CodeBag(cb, name(t.child(0)));
+            CodeBag cb2 = new CodeBag(name(t.child(0)));
             for(Tree<String> statement : t.child(1))
                 fillCodeBag(statement, cb2);
 
@@ -197,8 +264,32 @@ public class Parser {
                     else if ("Ack".equals(ttt.head()))     { tokenOut = true; dest = portReference(ttt.child(0)); }
                 }
                 cb.add(new Instruction.Executable(benkobox,
-                                                  dest, count, tokenIn, dataIn, latch, dataOut, tokenOut, recycle));
+                                                  dest, count, tokenIn, dataIn,
+                                                  latch, dataOut, tokenOut, recycle));
             }
         }
     }
+
+    private static class CountingOutputStream extends FilterOutputStream {
+        public CountingOutputStream(OutputStream os) { super(os); }
+        int count = 0;
+        public int getCount() { return count; }
+        public void write(int b) throws IOException {
+            super.write(b);
+            count++;
+        }
+        public void write(byte[] b, int off, int len) throws IOException {
+            super.write(b, off, len);
+            count += len;
+        }
+    }
+
+    private class CodeBag extends ArrayList<Instruction> {
+        public int address = -1;
+        public CodeBag() { codeBags.add(this); }
+        public CodeBag(String name) { this(); codeBagsByName.put(name, this); }
+        public long getFakeAddress() { return codeBags.indexOf(this); }
+        public boolean equals(Object o) { return this==o; }
+    }
+
 }