700f74e486400f3ffde1d98c3f420850bd0d4cc0
[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.util.*;
8 import static edu.berkeley.fleet.util.BitManipulations.*;
9 import edu.berkeley.fleet.two.*;
10 import edu.berkeley.fleet.api.Instruction.Set;
11 import static edu.berkeley.fleet.api.Instruction.*;
12 import static edu.berkeley.fleet.api.Instruction.Set.*;
13 import static edu.berkeley.fleet.api.Predicate.*;
14 import edu.berkeley.fleet.two.*;
15 import edu.berkeley.fleet.fpga.*;
16 import edu.berkeley.fleet.interpreter.*;
17 import java.util.*;
18 import java.io.*;
19
20
21 /**
22  *  @author Adam Megacz <megacz@cs.berkeley.edu>
23  */
24 public class Parser {
25
26     private static final BitVector SIGNAL_ZERO = new BitVector(1);
27     private static final BitVector SIGNAL_ONE  = new BitVector(1);
28     static {
29         SIGNAL_ONE.set(0,true);
30     }
31     
32     /** WARNING: this class may change in the future; it is not a stable interface */
33     public Parser(Fleet fleet) {
34         expect = new ArrayList<Long>();
35         this.fleet = fleet;
36     }
37
38     //////////////////////////////////////////////////////////////////////////////
39
40     private Fleet fleet;
41     private ArrayList<String> imports = new ArrayList<String>();
42
43     private HashMap<String,Ship> shipMap = new HashMap<String,Ship>();
44
45     // codebags in numerical order
46     private ArrayList<CodeBag> codeBags = new ArrayList<CodeBag>();
47     private HashMap<String,CodeBag> codeBagsByName = new HashMap<String,CodeBag>();
48     
49     private CodeBag getCodeBag(String name) {
50         CodeBag cb = codeBagsByName.get(name);
51         if (cb!=null) return cb;
52         return new CodeBag(name);
53     }
54
55     private static Union grammar;
56     private static synchronized Union getGrammar() throws Exception {
57         if (grammar != null) return grammar;
58         InputStream grammarStream =
59             Parser.class.getClassLoader().getResourceAsStream("edu/berkeley/fleet/assembler/fleet.g");
60         CharParser metaGrammarParser   = new CharParser(GrammarAST.getMetaGrammar());
61         Tree<String> parsedGrammar     = metaGrammarParser.parse(new CharInput(grammarStream)).expand1();
62         grammar                        = GrammarAST.buildFromAST(parsedGrammar, "s", new GrammarAST.ImportResolver() {
63                 public InputStream getImportStream(String importname) { return null; }
64             });
65         return grammar;
66     }
67
68     // FIXME: this ought to be cached via serialization, I think
69     private static CharParser cp = null;
70     Tree<String> parseIt(Reader r) throws Exception {
71         if (cp==null)
72             cp = new CharParser(getGrammar());
73         CharInput ci = new CharInput(r);
74         Forest f = cp.parse(ci);
75         return f.expand1();
76     }
77
78     public Instruction[] parse(Reader r) throws Exception {
79         // this needs to be "code bag zero"
80         CodeBag baseCodeBag = new CodeBag();
81         CodeBag rootCodeBag = new CodeBag();
82         skip = false;
83         Tree<String> parsed = (Tree<String>)parseIt(r);
84         walk(parsed, rootCodeBag);
85
86         // map from arbitrary identifiers to actual addresses
87         int[] codeBagMap = new int[codeBags.size()];
88         int count = 0;
89         for(int i=0; i<codeBags.size(); i++) {
90             CodeBag c = codeBags.get(i);
91             codeBagMap[i] = count;
92             for(Instruction inst : c) {
93                 count++;
94             }
95         }
96
97         // now write for real
98         count = 0;
99         ArrayList<Instruction> ret = new ArrayList<Instruction>();
100         for(int i=0; i<codeBags.size(); i++) {
101             CodeBag c = codeBags.get(i);
102             for(int j=0; j<c.size(); j++) {
103                 Instruction inst = c.get(j);
104                 if (c.isCBD.contains(j)) {
105                     Set old = (Set)inst;
106                     long lit = 0;
107                     lit = ((FleetTwoFleet)fleet).CBD_SIZE.setval(lit, codeBags.get((int)old.immediate).size());
108                     lit = ((FleetTwoFleet)fleet).CBD_OFFSET.setval(lit, codeBagMap[(int)old.immediate]);
109                     inst = new Set(old.dock, false, IgnoreFlagD, SetDest.DataLatch, lit);
110                 }
111                 ret.add(inst);
112                 count++;
113             }
114         }
115         long startcbd = 0;
116         for(int i=0; i<codeBags.size(); i++) {
117             if (codeBags.get(i)==rootCodeBag) {
118                 long lit = 0;
119                 lit = ((FleetTwoFleet)fleet).CBD_SIZE.setval(lit, codeBags.get(i).size());
120                 lit = ((FleetTwoFleet)fleet).CBD_OFFSET.setval(lit, codeBagMap[i]);
121                 startcbd = lit;
122             }
123         }
124         if (codeBags.size()<=2)
125             return (Instruction[])ret.toArray(new Instruction[0]);
126         return fixup((Instruction[])ret.toArray(new Instruction[0]), startcbd);
127     }
128
129     private Instruction[] fixup(Instruction[] instructions, long startcbd) {
130         ArrayList<Instruction> ret = new ArrayList<Instruction>();
131         Fleet fpga = fleet;
132
133         Dock inAddrWrite = null;
134         Dock inDataWrite = null;
135         Dock inCBD       = null;
136         Dock out         = null;
137         Dock debugIn     = null;
138         Dock ihorn       = null;
139
140         for(Ship ship : fpga) {
141             if ("Memory".equals(ship.getType()) && ship.getOrdinal()==0) {
142                 inAddrWrite = ship.getDock("inAddrWrite");
143                 inDataWrite = ship.getDock("inDataWrite");
144                 inCBD = ship.getDock("inCBD");
145                 out = ship.getDock("out");
146                 ihorn = out;
147                 //ihorn = ship.getDock("outIhorn");
148             }
149             if ("Debug".equals(ship.getType()) && ship.getOrdinal()==0) {
150                 debugIn = ship.getDock("in");
151             }
152         }
153
154         for(int i=0; i<instructions.length; i++) {
155             long lit = ((FleetTwoFleet)fpga).writeInstruction(instructions[i], out);
156             ret.add(discard(out));
157             ret.add(new Instruction.Shift(inDataWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, lit))));
158             ret.add(new Instruction.Shift(inDataWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18,  0, lit))));
159             ret.add(deliver(inDataWrite));
160             ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, i))));
161             ret.add(new Instruction.Shift(inAddrWrite, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18,  0, i))));
162             ret.add(deliver(inAddrWrite));
163         }
164         ret.add(new Instruction.Shift(inCBD, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(36, 19, startcbd))));
165         ret.add(new Instruction.Shift(inCBD, false, IgnoreFlagD, new BitVector(fpga.getShiftWidth()).set(getField(18,  0, startcbd))));
166         ret.add(wait(inCBD));
167         ret.add(deliver(inCBD));
168         ret.add(sendto(out, out.getPath(inCBD.getDataDestination(),null)));
169
170         int count = (int)((FleetTwoFleet)fleet).CBD_SIZE.getval(startcbd);
171         // FIXME FIXME FIXME!
172         int MAX_ILC = 31;
173         int num_instrs = 0;
174         while(count > 0) {
175             int num = Math.min(count, MAX_ILC);
176             num_instrs+=2;
177             count -= num;
178             ret.add(new Instruction.Set(ihorn, false, IgnoreFlagD, SetDest.InnerLoopCounter, num));
179             ret.add(new Instruction.Move(ihorn, false, IgnoreFlagD, false, null,false,true,true,true,true,false));
180         }
181         if (num_instrs > ihorn.getInstructionFifoSize()) throw new RuntimeException();
182
183         return (Instruction[])ret.toArray(new Instruction[0]);
184     }
185
186     /** in the first pass, codebags are assigned "addresses" in arbitrary order */
187     void walk(Tree<String> t, CodeBag cb) {
188
189         String head = t.head();
190         if (head==null) {
191         } else if (head.equals("Program")) {
192             for(Tree<String> tc : t.child(0))
193                 walk(tc, cb);
194             if (t.size()>1)
195                 for(Tree<String> statement : t.child(1))
196                     fillCodeBag(statement, cb);
197    
198         } else if (head.equals("#ship")) {
199             String name = name(t.child(0));
200             String type = string(t.child(1));
201             Ship ship = allocateShip(type);
202             shipMap.put(name, ship);
203
204         } else if (head.equals("#expect")) {
205             expect.add(number(t.child(0)));
206         } else if (head.equals("#skip")) {
207             skip = true;
208
209         }
210     }
211
212     private static String string(Tree<String> t) {
213         String ret = "";
214         if (t.head() != null) ret += t.head();
215         for(Tree<String> c : t)
216             ret += string(c);
217         return ret;
218     }
219
220     private static String stringBody(Tree<String> t) {
221         String ret = "";
222         for(Tree<String> c : t)
223             ret += string(c);
224         return ret;
225     }
226
227     private static String name(Tree<String> t) {
228         return string(t.child(0))+string(t.child(1));
229     }
230
231     Path path(Dock dock, Tree<String> t) {
232         if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head())) return null;
233         String shipName = name(t.child(0));
234         String portName = name(t.child(1));
235         Ship ship = shipMap.get(shipName);
236         if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
237         Destination ret = null;
238         Dock bb = null;
239         for(Dock b : ship)
240             if (b.getName().equals(portName)) {
241                 bb = b;
242             }
243         if (bb==null)
244             throw new RuntimeException("no such dock \""+portName+"\"");
245         if (t.size() >= 3) {
246             if (":i".equals(t.child(2).head())) return dock.getPath(bb.getInstructionDestination(),SIGNAL_ZERO);
247             if (":1".equals(t.child(2).head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ONE);
248             if (":0".equals(t.child(2).head())) return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
249         }
250         return dock.getPath(bb.getDataDestination(),SIGNAL_ZERO);
251     }
252
253     Dock dock(Tree<String> t) {
254         if (!"Dock".equals(t.head()) && !"Destination".equals(t.head()) && !"ShipSpecificLiteral".equals(t.head()))
255             throw new RuntimeException(t+"");
256         String shipName = name(t.child(0));
257         String portName = name(t.child(1));
258         Ship ship = shipMap.get(shipName);
259         if (ship==null) throw new RuntimeException("no such ship \""+shipName+"\"");
260         Dock bb = null;
261         for(Dock b : ship)
262             if (b.getName().equals(portName))
263                 return b;
264         throw new RuntimeException("no such dock \""+portName+"\"");
265     }
266
267     private HashMap<String,Integer> numAllocated = new HashMap<String,Integer>();
268
269     Ship allocateShip(String shipType) {
270         int allocated = 0;
271         if (numAllocated.get(shipType) != null)
272             allocated = numAllocated.get(shipType);
273         numAllocated.put(shipType, allocated+1);
274         for(Iterator<Ship> it = fleet.iterator();
275             it.hasNext();
276             ) {
277             Ship s = it.next();
278             if (s.getType().equals(shipType)) {
279                 if (allocated == 0) return s;
280                 allocated--;
281             }
282         }
283         if (fleet instanceof FleetWithDynamicShips) {
284             FleetWithDynamicShips dyn = ((FleetWithDynamicShips)fleet);
285             Ship ship = dyn.createShip(shipType, shipType+allocated);
286             if (ship==null)
287                 throw new RuntimeException("couldn't find a ship called \""+shipType+"\"");
288             return ship;
289         } else {
290             throw new RuntimeException("no more ships of type \""+shipType+"\"");
291         }
292     }
293
294     private long parseSSL(Tree t) {
295         String shipType = name(t.child(0));
296         String portName = name(t.child(1));
297         Ship chosenship = null;
298         for(Ship ship : fleet) {
299             if (ship.getType().equals(shipType)) {
300                 chosenship = ship;
301                 break;
302             }
303         }
304         if (chosenship==null) throw new RuntimeException("no ships of type " + shipType);
305         Dock chosenport = chosenship.getDock(portName);
306         Tree specs = t.child(2);
307         long literal = 0;
308         for(int i=0; i<specs.size(); i++) {
309             Tree tt = specs.child(i);
310             literal |= resolveLiteral(chosenport, stringBody(tt));
311         }
312         return literal;
313     }
314
315     private static long resolveLiteral(Dock dd, String s) {
316         long val = 0;
317         long ret = 0;
318         boolean hasval = false;
319         if (s.indexOf('=') != -1) {
320             val = Long.parseLong(s.substring(s.indexOf('=')+1));
321             s = s.substring(0, s.indexOf('='));
322             hasval = true;
323         }
324         ShipDescription.Constant c = ((FleetTwoDock)dd).getDockConstant(s);
325         if (c==null) throw new RuntimeException("no constant " + s + " on dock " + dd);
326         ret |= c.setbits;
327         ret &= ~c.clearbits;
328         if (hasval)
329             ret |= ((~(0xffffffffffffffffL << c.numberWidth)) & val) << c.numberOffset;
330         return ret;
331     }
332
333     private static FlagFunction parseFlags(Tree<String> t) {
334         FlagFunction ret = FlagFunction.ZERO;
335         for(int i=0; i<t.size(); i++) {
336             String s = t.child(i).head();
337             if (s.equals("0"))  ret = ret.add(FlagFunction.ZERO);
338             if (s.equals("1"))  ret = ret.add(FlagFunction.ONE);
339             if (s.equals("a"))  ret = ret.add(FlagA);
340             if (s.equals("!a")) ret = ret.add(NotFlagA);
341             if (s.equals("b"))  ret = ret.add(FlagB);
342             if (s.equals("!b")) ret = ret.add(NotFlagB);
343             if (s.equals("c"))  ret = ret.add(FlagC);
344             if (s.equals("!c")) ret = ret.add(NotFlagC);
345         }
346         return ret;
347     }
348
349     private int anoncount = 1;
350     void fillCodeBag(Tree<String> t, CodeBag cb) {
351         if (t.head()==null) return;
352         else if (t.head().equals("CodeBagDef")) {
353             CodeBag cb2 = getCodeBag(name(t.child(0)));
354             for(Tree<String> statement : t.child(1))
355                 fillCodeBag(statement, cb2);
356
357         } else if (t.head().equals("Fiber")) {
358             Dock dock = (Dock)dock(t.child(0));
359             
360             OUTER: for(Tree tt : t.child(1)) {
361
362                 if ("tail".equals(tt.head()))    {
363                     cb.add(new Tail(dock));
364                     continue;
365                 } else if ("head".equals(tt.head()))    {
366                     cb.add(new Head(dock));
367                     continue;
368                 }
369
370                 int count = 1;
371                 Predicate predicate = Default;
372                 boolean looping = false;
373                 boolean interruptible = false;
374                 for(int i=0; i<tt.child(0).size(); i++) {
375                     Tree ttt = tt.child(0).child(i);
376                     if ("[a]".equals(ttt.head()))  predicate = FlagA;
377                     if ("[b]".equals(ttt.head()))  predicate = FlagB;
378                     if ("[c]".equals(ttt.head()))  predicate = FlagC;
379                     if ("[!a]".equals(ttt.head())) predicate = NotFlagA;
380                     if ("[!b]".equals(ttt.head())) predicate = NotFlagB;
381                     if ("[!c]".equals(ttt.head())) predicate = NotFlagC;
382                     if ("[*]".equals(ttt.head()))  predicate = IgnoreFlagD;
383                     if ("[d]".equals(ttt.head()))  predicate = FlagD;
384                     if ("[Rq]".equals(ttt.head()))  looping = true;
385                 }
386                 tt = tt.child(1);
387                 if ("flags".equals(tt.head()))    {
388                     cb.add(new Set(dock, looping, predicate, parseFlags(tt.child(0)), parseFlags(tt.child(1))));
389                     continue;
390                 } else if ("olc=word".equals(tt.head()))    {
391                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.DataLatch));
392                     continue;
393                 } else if ("ilc=word".equals(tt.head()))    {
394                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.DataLatch));
395                     continue;
396                 } else if ("*".equals(tt.head()))    {
397                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, SetSource.Infinity));
398                     continue;
399                 } else if ("olc=int".equals(tt.head()))    {
400                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, (number(tt.child(0)))));
401                     continue;
402                 } else if ("ilc=int".equals(tt.head()))    {
403                     cb.add(new Set(dock, looping, predicate, SetDest.InnerLoopCounter, (number(tt.child(0)))));
404                     continue;
405                 } else if ("--".equals(tt.head())) {
406                     cb.add(new Set(dock, looping, predicate, SetDest.OuterLoopCounter, SetSource.Decrement));
407                     continue;
408                 } else if ("nop".equals(tt.head())) {
409                     if (tt.size() > 0 && "[T]".equals(tt.child(0).head())) interruptible = true;
410                     cb.add(new Move(dock, looping, predicate, interruptible, null, false, false, false, false, false, false));
411                 } else if ("shift".equals(tt.head())) {
412                     cb.add(new Shift(dock, looping, predicate,
413                                      new BitVector(dock.getShip().getFleet().getShiftWidth()).set(number(tt.child(0)))));
414                     continue;
415                 } else if ("flush".equals(tt.head())) {
416                     cb.add(new Flush(dock, looping, predicate));
417                     continue;
418                 } else if ("abort".equals(tt.head())) {
419                     cb.add(new Abort(dock, predicate));
420                     continue;
421                 } else if ("word".equals(tt.head())) {
422                     long literal = 0;
423                     if (tt.child(0).head().equals("CodeBagBody")) {
424                         Tree<String> tq = tt;
425                         CodeBag cb2 = getCodeBag("anon"+(anoncount++));
426                         for(Tree<String> statement : tq.child(0))
427                             fillCodeBag(statement, cb2);
428                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
429                         continue OUTER;
430                     } else if (tt.child(0).head().equals("Name")) {
431                         String refname = name(tt.child(0));
432                         CodeBag cb2 = getCodeBag(refname);
433                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (cb2.getFakeAddress())), true);
434                         continue OUTER;
435                     } else if (tt.child(0).head().equals("[")) {
436                         literal = parseSSL(tt.child(0));
437                     } else {
438                         literal = number(tt.child(0));
439                     }
440                     count = 1;
441                     /*
442                     if ("int".equals(tt.child(1).head())) {
443                         count = (int)number(tt.child(1));
444                     } else if ("forever".equals(tt.child(1).head())) {
445                         count = 0;
446                     }
447                     */
448
449
450                     if (((FleetTwoFleet)fleet).isSmallEnoughToFit(literal)) {
451                         cb.add(new Set(dock, looping, predicate, SetDest.DataLatch, (literal)));
452                     } else {
453                         int counter = 0;
454                         while(counter < dock.getShip().getFleet().getWordWidth()) counter += fleet.getShiftWidth();
455                         while(counter > 0) {
456                             cb.add(new Shift(dock, looping, predicate,
457                                              new BitVector(dock.getShip().getFleet().getShiftWidth())
458                                              .set(getField(counter-1, counter-fleet.getShiftWidth(), literal))));
459                             counter -= fleet.getShiftWidth();
460                         }
461                     }
462                         
463                     continue;
464                 }
465                 Tree ttx = null;
466                 boolean requeue = false;
467                 if ("[T]".equals(tt.child(0).head()))  interruptible = true;
468                 ttx = tt.child(tt.size()-1);
469                 boolean tokenIn = false;
470                 boolean dataIn = false;
471                 boolean latch = false;
472                 boolean dataOut = false;
473                 boolean tokenOut = false;
474                 boolean dispatch = false;
475                 boolean localLiteral = false;
476                 boolean ignoreUntilLast = false;
477                 long literal = 0;
478                 Path path = null;
479                 for(int i=0; i<ttx.size(); i++) {
480                     Tree ttt = ttx.child(i);
481                     if      ("recv token".equals(ttt.head()))    { tokenIn = true; }
482                     else if ("discard".equals(ttt.head())) { dataIn = true; latch = false; }
483                     else if ("take".equals(ttt.head()))    { dataIn = true; latch = true; }
484                     else if ("collect".equals(ttt.head()))    {
485                         if (dock.isInputDock())
486                             throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
487                         dataIn = true;
488                         latch = true;
489                     }
490                     else if ("collect path".equals(ttt.head()))    {
491                         if (dock.isInputDock())
492                             throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
493                         dataIn = true;
494                         latch = false;
495                         dispatch = true;
496                     }
497                     else if ("collect packet".equals(ttt.head()))    {
498                         if (dock.isInputDock())
499                             throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
500                         dataIn = true;
501                         latch = true;
502                         dispatch = true;
503                     }
504                     else if ("collect nothing".equals(ttt.head()))    {
505                         if (dock.isInputDock())
506                             throw new RuntimeException("you can't use \"collect\" at input docks; try \"recv\" instead");
507                         dataIn = true;
508                     }
509                     else if ("recv".equals(ttt.head()))    {
510                         if (dock.isOutputDock())
511                             throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
512                         dataIn = true;
513                         latch = true;
514                     }
515                     else if ("recv path".equals(ttt.head()))    {
516                         if (dock.isOutputDock())
517                             throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
518                         dataIn = true;
519                         latch = false;
520                         dispatch = true;
521                     }
522                     else if ("recv packet".equals(ttt.head()))    {
523                         if (dock.isOutputDock())
524                             throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
525                         dataIn = true;
526                         latch = true;
527                         dispatch = true;
528                     }
529                     else if ("recv nothing".equals(ttt.head()))    {
530                         if (dock.isOutputDock())
531                             throw new RuntimeException("you can't use \"recv\" at input docks; try \"collect\" instead");
532                         dataIn = true;
533                     }
534                     else if ("send".equals(ttt.head()))  {
535                         dataOut = true;
536                     }
537                     else if ("send to".equals(ttt.head()))  { dataOut = true; path = path(dock, ttt.child(0)); }
538                     else if ("deliver".equals(ttt.head())) { dataOut = true;  }
539                     else if ("send token".equals(ttt.head()))     { tokenOut = true; }
540                     else if ("send token to".equals(ttt.head()))     { tokenOut = true; path = path(dock, ttt.child(0)); }
541                 }
542                 cb.add(new Move(dock, looping, predicate,
543                                 interruptible, path, tokenIn, dataIn,
544                                 latch, dispatch, dataOut, tokenOut));
545             }
546         }
547     }
548
549     private class CodeBag extends ArrayList<Instruction> {
550         public long address = -1;
551         public final String name;
552         private HashSet<Integer> isCBD = new HashSet<Integer>();
553         public CodeBag() { codeBags.add(this); this.name = "root"; }
554         public CodeBag(String name) { codeBags.add(this); codeBagsByName.put(name, this); this.name = name; }
555         public long getFakeAddress() { return codeBags.indexOf(this); }
556         public boolean equals(Object o) { return this==o; }
557         public void add(Instruction i, boolean isCBD) {
558             if (isCBD) this.isCBD.add(size());
559             add(i);
560         }
561     }
562
563     // hideous hack
564     public static ArrayList<Long> expect;
565     public static boolean         skip;
566
567     private static long number(Tree t) {
568         String ret = "";
569         for(Object c : t.child(2)) ret += ((Tree)c).head();
570         boolean negative = "-".equals(t.child(0).head());
571         ret = ret.trim();
572         long val = 0;
573         if      ("0x".equals(t.child(1).head())) val = Long.parseLong(ret, 16);
574         else if ("0b".equals(t.child(1).head())) val = Long.parseLong(ret, 2);
575         else                                     val = Long.parseLong(ret);
576         if (negative) val = -1L * val;
577         return val;
578     }
579     /**
580      *  This interface marks Fleets which can create ships on the fly, like the fleeterpreter;
581      *  if available, the parser will use this interface to create ships out of #ship definitions.
582      */
583     public static interface FleetWithDynamicShips {
584         public Ship createShip(String shiptype, String shipname);
585     }
586
587     private static Move discard(Dock dock)           { return new Move(dock, false, IgnoreFlagD, false, null, false, true,  false, false, false, false); }
588     private static Move deliver(Dock dock)           { return new Move(dock, false, IgnoreFlagD, false, null, false, false, false, false, true,  false); }
589     private static Move wait(Dock dock)              { return new Move(dock, false, IgnoreFlagD, false, null, true,  false, false, false, false, false); }
590     private static Move sendto(Dock dock, Path path) { return new Move(dock, false, IgnoreFlagD, false, path, false, false, false, false, true,  false); }
591 }