98fbed3188971f89623a921100123593b8d11143
[fleet.git] / src / edu / berkeley / fleet / assembler / Parser.java
1 package edu.berkeley.fleet.assembler;
2 import edu.berkeley.fleet.api.*;
3 import edu.berkeley.sbp.*;
4 import edu.berkeley.sbp.chr.*;
5 import edu.berkeley.sbp.misc.*;
6 import edu.berkeley.sbp.meta.*;
7 import edu.berkeley.sbp.bind.*;
8 import edu.berkeley.sbp.util.*;
9 import java.util.*;
10 import java.io.*;
11
12 /**
13  *  @author Adam Megacz <megacz@cs.berkeley.edu>
14  */
15 public class Parser {
16
17     Parser(Fleet fleet) {
18         expect = new ArrayList<Long>();
19         this.fleet = fleet;
20     }
21
22     //////////////////////////////////////////////////////////////////////////////
23
24     private Fleet fleet;
25     private ArrayList<String> imports = new ArrayList<String>();
26
27     private HashMap<String,Ship> shipMap = new HashMap<String,Ship>();
28
29     // codebags in numerical order
30     private ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
31     private HashMap<String,CodeBag> codeBagsByName = new HashMap<String,CodeBag>();
32     
33     private CodeBag getCodeBag(String name) {
34         CodeBag cb = codeBagsByName.get(name);
35         if (cb!=null) return cb;
36         return new CodeBag(name);
37     }
38
39     Tree<String> parse(Reader r) throws Exception {
40         InputStream grammarStream =
41             Parser.class.getClassLoader().getResourceAsStream("edu/berkeley/fleet/assembler/fleet.g");
42         CharParser metaGrammarParser   = new CharParser(MetaGrammar.newInstance());
43         Tree<String> parsedGrammar     = metaGrammarParser.parse(new CharInput(grammarStream)).expand1();
44         Union   grammar                = Grammar.create(parsedGrammar, "s", new Grammar.Bindings() { });
45         CharParser  parser             = new CharParser(grammar);
46         Tree tree = parser.parse(new CharInput(r)).expand1();
47         return tree;
48     }
49
50     public void parse(Reader r, OutputStream out) throws Exception {
51
52         // this needs to be "code bag zero"
53         CodeBag baseCodeBag = new CodeBag();
54         CodeBag rootCodeBag = new CodeBag();
55         baseCodeBag.add(new Instruction.Literal.CodeBagDescriptor(null, rootCodeBag.getFakeAddress(), 1));
56         walk((Tree<String>)parse(r), rootCodeBag);
57         if (fleet instanceof edu.berkeley.fleet.slipway.Slipway)
58             ((edu.berkeley.fleet.slipway.Slipway)fleet).dumpFabric(true);
59
60         // map from arbitrary identifiers to actual addresses
61         int[] codeBagMap = new int[codeBags.size()];
62         ByteArrayOutputStream baos = new ByteArrayOutputStream();
63         DataOutputStream dos       = new DataOutputStream(baos);
64         int count = 0;
65         for(int i=0; i<codeBags.size(); i++) {
66             CodeBag c = codeBags.get(i);
67             dos.flush();
68             codeBagMap[i] = count;
69             for(Instruction inst : c) {
70                 fleet.writeInstruction(dos, inst);
71                 count++;
72             }
73         }
74
75         // now write for real
76         dos = new DataOutputStream(out);
77         count = 0;
78         for(int i=0; i<codeBags.size(); i++) {
79             CodeBag c = codeBags.get(i);
80             dos.flush();
81             for(Instruction inst : c) {
82                 if (inst instanceof Instruction.Literal.CodeBagDescriptor) {
83                     dos.flush();
84                     Instruction.Literal.CodeBagDescriptor old = (Instruction.Literal.CodeBagDescriptor)inst;
85                     int offset = codeBagMap[(int)old.offset] - count;
86                     inst = new Instruction.Literal.CodeBagDescriptor(old.dest,
87                                                                      offset,
88                                                                      codeBags.get((int)old.offset).size());
89                 }
90                 fleet.writeInstruction(dos, inst);
91                 count++;
92             }
93         }
94         dos.flush();
95         out.flush();
96         out.close();
97     }
98
99     /** in the first pass, codebags are assigned "addresses" in arbitrary order */
100     void walk(Tree<String> t, CodeBag cb) {
101
102         String head = t.head();
103         if (head==null) {
104         } else if (head.equals("Program")) {
105             for(Tree<String> tc : t.child(0))
106                 walk(tc, cb);
107             if (t.size()>1)
108                 for(Tree<String> statement : t.child(1))
109                     fillCodeBag(statement, cb);
110    
111         } else if (head.equals("Import")) {
112             // ignored
113
114         } else if (head.equals("Ship")) {
115             String name = name(t.child(0));
116             String type = string(t.child(1));
117             Ship ship = null;
118
119             if (fleet instanceof Fleet.WithDynamicShips) {
120                 Fleet.WithDynamicShips dyn = ((Fleet.WithDynamicShips)fleet);
121                 ship = dyn.createShip(type, name);
122                 if (ship==null)
123                     throw new RuntimeException("couldn't find a ship called \""+type+"\"");
124             } else {
125                 ship = allocateShip(type);
126             }
127             shipMap.put(name, ship);
128
129         } else if (head.equals("Include")) {
130             try {
131                 walk(parse(new InputStreamReader(new FileInputStream(string(t.child(0))))), cb);
132             } catch (Exception e) {
133                 throw new RuntimeException(e);
134             }
135             
136         } else if (head.equals("Expect")) {
137             expect.add(Long.parseLong(string(t.child(0))));
138
139         }
140     }
141
142     String string(Tree<String> t) {
143         String ret = "";
144         if (t.head() != null) ret += t.head();
145         for(Tree<String> c : t)
146             ret += string(c);
147         return ret;
148     }
149
150     String name(Tree<String> t) {
151         return string(t.child(0))+string(t.child(1));
152     }
153
154     Destination portReference(Tree<String> t) {
155         if (!"Port".equals(t.head()) && !"SubPort".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head())) return null;
156         String shipName = name(t.child(0));
157         String portName = name(t.child(1));
158         String subPort = t.size()<3 ? null : name(t.child(2));
159         Ship ship = shipMap.get(shipName);
160         if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
161         BenkoBox ret = null;
162         for(BenkoBox b : ship.getBenkoBoxes())
163             if (b.getName().equals(portName)) {
164                 ret = b;
165             }
166         if (subPort != null)
167             for(Destination d : ret.getDestinations())
168                 if (d.getDestinationName().equals(subPort))
169                     return d;
170         if (ret==null)
171             throw new RuntimeException("no such benkobox \""+portName+"\" on ships of type \""+ship.getType()+"\"");
172         return ret;
173     }
174
175     private HashMap<String,Integer> numAllocated = new HashMap<String,Integer>();
176
177     Ship allocateShip(String shipType) {
178         int allocated = 0;
179         if (numAllocated.get(shipType) != null)
180             allocated = numAllocated.get(shipType);
181         numAllocated.put(shipType, allocated+1);
182         for(Iterator<Ship> it = fleet.iterator();
183             it.hasNext();
184             ) {
185             Ship s = it.next();
186             if (s.getType().equals(shipType)) {
187                 if (allocated == 0) return s;
188                 allocated--;
189             }
190         }
191         throw new RuntimeException("no more ships of type \""+shipType+"\"");
192     }
193
194     void fillCodeBag(Tree<String> t, CodeBag cb) {
195         if (t.head()==null) return;
196         else if (t.head().equals("NamedCodeBag")) {
197             CodeBag cb2 = getCodeBag(name(t.child(0)));
198             for(Tree<String> statement : t.child(1))
199                 fillCodeBag(statement, cb2);
200
201         } else if (t.head().equals("ShipSpecificLiteral")) {
202             String shipType = name(t.child(0).child(0));
203             String portName = name(t.child(0).child(1));
204             Ship chosenship = null;
205             for(Ship ship : fleet) {
206                 if (ship.getType().equals(shipType)) {
207                     chosenship = ship;
208                     break;
209                 }
210             }
211             long literal = chosenship.resolveLiteral(portName);
212             cb.add(new Instruction.Literal.Absolute(portReference(t.child(1)), literal));
213
214         } else if (t.head().equals("Literal")) {
215             long literal = Long.parseLong(string(t.child(0)));
216             cb.add(new Instruction.Literal.Absolute(portReference(t.child(1)), literal));
217
218         } else if (t.head().equals("CodeBagDescriptor")) {
219             String refname = name(t.child(0).child(0));
220             CodeBag cb2 = getCodeBag(refname);
221             cb.add(new Instruction.Literal.CodeBagDescriptor(portReference(t.child(1)), cb2.getFakeAddress(), 0));
222
223         } else if (t.head().equals("Fiber")) {
224             BenkoBox benkobox = (BenkoBox)portReference(t.child(0));
225             
226             OUTER: for(Tree tt : t.child(1)) {
227                 int count = 1;
228                 Tree ttx = null;
229                 boolean recycle = false;
230                 ttx = tt.child(1);
231                 if (tt.size() > 1 && tt.child(0).size()>0) {
232                     tt = tt.child(0).child(0);
233                     if (tt.head().equals("BrackStar")) {
234                         count = 0;
235                         recycle = false;
236                     } else if (tt.head().equals("ParenStar")) {
237                         count = 0;
238                         recycle = true;
239                     } else if (tt.head().equals("Brack")) {
240                         count = Integer.parseInt(string(tt.child(0)));
241                         recycle = false;
242                     } else if (tt.head().equals("Paren")) {
243                         count = Integer.parseInt(string(tt.child(0)));
244                         recycle = true;
245                     }
246                 }
247                 boolean tokenIn = false;
248                 boolean dataIn = false;
249                 boolean latch = false;
250                 boolean dataOut = false;
251                 boolean tokenOut = false;
252                 Destination dest = null;
253                 for(int i=0; i<ttx.size(); i++) {
254                     Tree ttt = ttx.child(i);
255                     if      ("Wait".equals(ttt.head()))    { tokenIn = true; }
256                     else if ("Nop".equals(ttt.head()))     { }
257                     else if ("KillStar".equals(ttt.head()))    {
258                         cb.add(new Instruction.Kill(benkobox, count, true));
259                         continue OUTER;
260                     } else if ("Kill".equals(ttt.head()))    {
261                         cb.add(new Instruction.Kill(benkobox, count, false));
262                         continue OUTER;
263                     }
264                     else if ("Discard".equals(ttt.head())) { dataIn = true; latch = false; }
265                     else if ("Take".equals(ttt.head()))    { dataIn = true; latch = true; }
266                     else if ("SendTo".equals(ttt.head()))  { dataOut = true; dest = portReference(ttt.child(0)); }
267                     else if ("Deliver".equals(ttt.head())) { dataOut = true;  }
268                     else if ("Ack".equals(ttt.head()))     { tokenOut = true; dest = portReference(ttt.child(0)); }
269                 }
270                 cb.add(new Instruction.Executable(benkobox,
271                                                   dest, count, tokenIn, dataIn,
272                                                   latch, dataOut, tokenOut, recycle));
273             }
274         }
275     }
276
277     private class CodeBag extends ArrayList<Instruction> {
278         public long address = -1;
279         public CodeBag() { codeBags.add(this); }
280         public CodeBag(String name) { this(); codeBagsByName.put(name, this); }
281         public long getFakeAddress() { return codeBags.indexOf(this); }
282         public boolean equals(Object o) { return this==o; }
283     }
284
285     // hideous hack
286     public static ArrayList<Long> expect;
287
288 }