correct
[repair.git] / Repair / RepairCompiler / MCC / IR / DotExpr.java
1 package MCC.IR;
2
3 import java.util.*;
4 import MCC.Compiler;
5
6 public class DotExpr extends Expr {
7
8     Expr left;
9     String field;
10     Expr index;
11
12     static boolean DOMEMCHECKS=false;
13     static boolean DOTYPECHECKS=false;
14     static boolean DONULL=false;
15
16
17     public DotExpr(Expr left, String field, Expr index) {
18         this.left = left;
19         this.field = field;
20         this.index = index;
21     }
22
23     public boolean isInvariant(Set vars) {
24         if (!left.isInvariant(vars))
25             return false;
26         if (intindex!=null)
27             return intindex.isInvariant(vars);
28         else
29             return true;
30     }
31
32     public Set findInvariants(Set vars) {
33         if (isInvariant(vars)) {
34             Set s=new HashSet();
35             s.add(this);
36             return s;
37         } else {
38             Set ls=left.findInvariants(vars);
39             if (intindex!=null) {
40                 ls.addAll(intindex.findInvariants(vars));
41                 Expr indexbound=((ArrayDescriptor)this.fd).getIndexBound();
42                 ls.addAll(indexbound.findInvariants(vars));
43                 if ((!(intindex instanceof IntegerLiteralExpr))||
44                     ((IntegerLiteralExpr) intindex).getValue() != 0) {
45                     FieldDescriptor fd=this.fd;
46                     if (fd instanceof ArrayDescriptor)
47                         fd=((ArrayDescriptor)fd).getField();
48                     Expr basesize = fd.getBaseSizeExpr();
49                     ls.addAll(basesize.findInvariants(vars));
50                 }
51             }
52             return ls;
53         }
54     }
55
56
57     public boolean isSafe() {
58         if (!left.isSafe())
59             return false;
60
61         FieldDescriptor tmpfd=fd;
62
63         if (tmpfd.getPtr()) // Pointers cound be invalid
64             return false;
65
66         if (tmpfd instanceof ArrayDescriptor) {
67             Expr arrayindex=((ArrayDescriptor)tmpfd).getIndexBound();
68             if (index instanceof IntegerLiteralExpr&&arrayindex instanceof IntegerLiteralExpr) {
69                 int indexvalue=((IntegerLiteralExpr)index).getValue();
70                 int arrayindexvalue=((IntegerLiteralExpr)arrayindex).getValue();
71                 if (indexvalue>=0&&indexvalue<arrayindexvalue)
72                     return true;
73             }
74             return false; // Otherwise, arrays could be out of bounds
75         }
76         return true;
77     }
78
79     public Set freeVars() {
80         Set lset=left.freeVars();
81         Set iset=null;
82         if (intindex!=null)
83             iset=intindex.freeVars();
84         if (lset==null)
85             return iset;
86         if (iset!=null)
87             lset.addAll(iset);
88         return lset;
89     }
90
91     /*
92     static int memoryindents = 0;
93
94     public static void generate_memory_endblocks(CodeWriter cr) {
95         while (memoryindents > 0) {
96             memoryindents --;
97             cr.endblock();
98         }
99         memoryindents = 0;
100     }
101     */
102
103     FieldDescriptor fd;
104     TypeDescriptor fieldtype;
105     Expr intindex;
106
107     public String name() {
108         String name=left.name()+"."+field;
109         if (index!=null)
110             name+="["+index.name()+"]";
111         return name;
112     }
113
114     public void findmatch(Descriptor d, Set s) {
115         if (d==fd)
116             s.add(this);
117         left.findmatch(d,s);
118         if (intindex!=null)
119             intindex.findmatch(d,s);
120     }
121
122     public Set useDescriptor(Descriptor d) {
123         HashSet newset=new HashSet();
124         if (d==fd)
125             newset.add(this);
126         newset.addAll(left.useDescriptor(d));
127         if (intindex!=null)
128             newset.addAll(intindex.useDescriptor(d));
129         return newset;
130     }
131
132     public boolean usesDescriptor(Descriptor d) {
133         if (d==fd)
134             return true;
135         return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
136     }
137
138     public boolean equals(Map remap, Expr e) {
139         if (e==null||!(e instanceof DotExpr))
140             return false;
141         DotExpr de=(DotExpr)e;
142         if (!de.field.equals(field))
143             return false;
144         if (index==null) {
145             if (de.index!=null)
146                 return false;
147         } else if (!index.equals(remap,de.index))
148             return false;
149         if (!left.equals(remap,de.left))
150             return false;
151         return true;
152     }
153
154
155     public Set getRequiredDescriptors() {
156         Set v = left.getRequiredDescriptors();
157
158         if (intindex != null) {
159             v.addAll(intindex.getRequiredDescriptors());
160         }
161         v.add(fd);
162         return v;
163     }
164
165     public Expr getExpr() {
166         return left;
167     }
168
169     public FieldDescriptor getField() {
170         return fd;
171     }
172
173     public Expr getIndex() {
174         return intindex;
175     }
176
177     private boolean exactalloc(TypeDescriptor td) {
178         if (!(td instanceof StructureTypeDescriptor))
179             return false;
180         StructureTypeDescriptor std=(StructureTypeDescriptor)td;
181         if (std.size()!=1) /* Just looking for arrays */
182             return false;
183         FieldDescriptor tmpfd=std.get(0);
184         if (!(tmpfd instanceof ArrayDescriptor))
185             return false;
186         ArrayDescriptor afd=(ArrayDescriptor)tmpfd;
187         TypeDescriptor elementdescriptor=afd.getType();
188         Expr sizeexpr=elementdescriptor.getSizeExpr();
189         if (!OpExpr.isInt(sizeexpr))
190             return false;
191         Expr indexbound=afd.getIndexBound();
192         if (indexbound instanceof DotExpr)
193             return true;
194         if ((indexbound instanceof OpExpr)&&
195             (((OpExpr)indexbound).getOpcode()==Opcode.MULT)&&
196             (((OpExpr)indexbound).getLeftExpr() instanceof DotExpr)&&
197             (((OpExpr)indexbound).getRightExpr() instanceof DotExpr))
198             return true;
199         return false;
200     }
201
202     public void generate(CodeWriter writer, VarDescriptor dest) {
203         VarDescriptor leftd = VarDescriptor.makeNew("left");
204
205         if (writer.getInvariantValue()!=null&&
206             writer.getInvariantValue().isInvariant(this)) {
207             writer.addDeclaration(getType().getGenerateType().getSafeSymbol().toString(), dest.getSafeSymbol());
208             writer.outputline(dest.getSafeSymbol()+"="+writer.getInvariantValue().getValue(this).getSafeSymbol()+";");
209             writer.outputline("maybe="+writer.getInvariantValue().getMaybe(this).getSafeSymbol()+";");
210             return;
211         }
212
213         writer.output("/* " +  leftd.getSafeSymbol() + " <-- ");
214         left.prettyPrint(writer);
215         writer.outputline("*/");
216
217         left.generate(writer, leftd);
218
219         writer.output("/* " +  leftd.getSafeSymbol() + " = ");
220         left.prettyPrint(writer);
221         writer.outputline("*/");
222
223         StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
224         Expr offsetbits;
225
226         // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor object that is in the vector list
227         // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array
228         // descriptor not the underlying field descriptor
229
230         /* we calculate the offset in bits */
231
232         offsetbits = struct.getOffsetExpr(fd);
233
234         FieldDescriptor fd=this.fd;
235         if (fd instanceof ArrayDescriptor)
236             fd=((ArrayDescriptor)fd).getField();
237         boolean doboundscheck=true;
238         boolean performedboundscheck=false;
239
240         writer.addDeclaration(getType().getGenerateType().toString(),dest.getSafeSymbol());
241         writer.outputline(dest.getSafeSymbol()+"=0;");
242
243         if (intindex != null) {
244             if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
245                 /* short circuit for constant 0 */
246             } else {
247                 Expr basesize = fd.getBaseSizeExpr();
248                 if (doboundscheck) {
249                     VarDescriptor indexvd=VarDescriptor.makeNew("index");
250                     indexvd.setType(ReservedTypeDescriptor.INT);
251                     writer.getSymbolTable().add(indexvd);
252
253                     writer.output("/* " + indexvd.getSafeSymbol() + " <-- ");
254
255                     intindex.prettyPrint(writer);
256                     writer.outputline("*/");
257                     intindex.generate(writer, indexvd);
258                     writer.output("/* " + indexvd.getSafeSymbol() + " = ");
259                     intindex.prettyPrint(writer);
260                     writer.outputline("*/");
261                     Expr indexbound=((ArrayDescriptor)this.fd).getIndexBound();
262                     VarDescriptor indexboundvd=VarDescriptor.makeNew("indexbound");
263
264                     indexbound.generate(writer,indexboundvd);
265
266                     writer.outputline("if ("+indexvd.getSafeSymbol()+">=0 &&"+indexvd.getSafeSymbol()+"<"+indexboundvd.getSafeSymbol()+")");
267                     writer.startblock();
268                     VarExpr indexve=new VarExpr(indexvd);
269                     offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, indexve));
270
271                     performedboundscheck=true;
272                 } else
273                     offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
274             }
275         }
276
277         final SymbolTable st = writer.getSymbolTable();
278         TypeDescriptor td2 = offsetbits.typecheck(new SemanticAnalyzer() {
279                 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
280                 public SymbolTable getSymbolTable() { return st; }
281             });
282
283         if (td2 == null) {
284             throw new IRException();
285         } else if (td2 != ReservedTypeDescriptor.INT) {
286             throw new IRException();
287         }
288
289         boolean dotypecheck = false;
290
291         VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
292         writer.output("/* " + ob.getSafeSymbol() + " <-- ");
293         offsetbits.prettyPrint(writer);
294         writer.outputline("*/");
295         offsetbits.generate(writer, ob);
296         writer.output("/* " + ob.getSafeSymbol() + " = ");
297         offsetbits.prettyPrint(writer);
298         writer.outputline("*/");
299
300         /* derive offset in bytes */
301         VarDescriptor offset = VarDescriptor.makeNew("offset");
302         writer.addDeclaration("int", offset.getSafeSymbol());
303         writer.outputline(offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
304
305         if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
306             VarDescriptor shift = VarDescriptor.makeNew("shift");
307             writer.addDeclaration("int", shift.getSafeSymbol());
308             writer.outputline(shift.getSafeSymbol() + " = " + ob.getSafeSymbol() +
309                               " - (" + offset.getSafeSymbol() + " << 3);");
310             int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
311
312             /* type var = ((*(int *) (base + offset)) >> shift) & mask */
313             writer.outputline("if ("+leftd.getSafeSymbol()+")");
314             writer.outputline(dest.getSafeSymbol() + " = ((*(int *)" +
315                               "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " +
316                               " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");
317             writer.outputline("else maybe=1;");
318         } else { /* a structure address or a ptr */
319             String ptr = fd.getPtr() ? "*(int *)" : "";
320             /* type var = [*(int *)] (base + offset) */
321             writer.outputline("if ("+leftd.getSafeSymbol()+")");
322             writer.startblock();
323             writer.outputline(dest.getSafeSymbol() +
324                               " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");
325             if (fd.getPtr()) {
326                 writer.outputline("if ("+dest.getSafeSymbol()+")");
327                 writer.startblock();
328
329
330                 if (DOTYPECHECKS||DOMEMCHECKS) {
331                     /* NEED TO CHECK IF THERE ARE VARIABLES TO PLAY WITH IN THE STRUCT!!!! */
332                     if (Compiler.EXACTALLOCATION&&exactalloc(td)) {
333                         writer.outputline("if (!assertexactmemory("+dest.getSafeSymbol()+", "+this.td.getId()+"))");
334                         {
335                             writer.startblock();
336                             /* Okay, we've failed to fit it in here */
337
338                             VarDescriptor highptr=VarDescriptor.makeNew("highptr");
339                             writer.addDeclaration("int", highptr.getSafeSymbol());
340                             writer.outputline(highptr.getSafeSymbol()+"=getendofblock("+dest.getSafeSymbol()+");");
341                             VarDescriptor size=VarDescriptor.makeNew("size");
342                             writer.addDeclaration("int", size.getSafeSymbol());
343                             writer.outputline(size.getSafeSymbol()+"="+highptr.getSafeSymbol()+"-"+dest.getSafeSymbol()+";");
344
345                             StructureTypeDescriptor std=(StructureTypeDescriptor)this.td;
346                             ArrayDescriptor afd=(ArrayDescriptor)std.get(0);
347                             TypeDescriptor elementdescriptor=afd.getType();
348                             Expr sizeexpr=elementdescriptor.getSizeExpr();
349                             int elementsize=OpExpr.getInt(sizeexpr);
350                             //convert size to bytes
351                             if (elementsize%8==0)
352                                 elementsize=elementsize/8;
353                             else
354                                 elementsize=(elementsize/8)+1;
355                             /* Basic sanity check */
356                             writer.outputline("if ("+size.getSafeSymbol()+"%"+
357                                               elementsize+"==0)");
358                             {
359                                 writer.startblock();
360                                 VarDescriptor numElements=VarDescriptor.makeNew("numberofelements");
361                                 writer.addDeclaration("int", numElements.getSafeSymbol());
362                                 writer.outputline(numElements.getSafeSymbol()+"="+size.getSafeSymbol()+"/"+elementsize+";");
363                                 Expr indexbound=afd.getIndexBound();
364                                 if  (indexbound instanceof DotExpr) {
365                                 /* NEED TO IMPLEMENT */
366
367                                     VarExpr ve=new VarExpr(numElements);
368                                     numElements.setType(ReservedTypeDescriptor.INT);
369                                     ve.td=ReservedTypeDescriptor.INT;
370                                     Updates u=new Updates(indexbound,ve);
371                                     UpdateNode un=new UpdateNode(null);
372                                     un.addUpdate(u);
373                                     un.generate(writer,false,false,null,null,null,null);
374                                     writer.outputline("free"+RepairGenerator.name+"("+RepairGenerator.newmodel.getSafeSymbol()+");");
375                                     writer.outputline("computesizes(thisvar);");
376                                     writer.outputline(RepairGenerator.name+"_staterecomputesizes(thisvar);");
377                                     writer.outputline("goto rebuild;");
378
379                                     //                                    writer.outputline("break;");
380                                     
381                                 } else if ((indexbound instanceof OpExpr)&&
382                                            (((OpExpr)indexbound).getOpcode()==Opcode.MULT)&&
383                                            (((OpExpr)indexbound).getLeftExpr() instanceof DotExpr)&&
384                                            (((OpExpr)indexbound).getRightExpr() instanceof DotExpr)) {
385
386                                     DotExpr leftexpr=(DotExpr)(((OpExpr)indexbound).getLeftExpr());
387                                     VarDescriptor leftside=VarDescriptor.makeNew("leftvalue");
388                                     writer.addDeclaration("int", leftside.getSafeSymbol());
389                                     leftexpr.generate(writer,leftside);
390                                     DotExpr rightexpr=(DotExpr)(((OpExpr)indexbound).getRightExpr());
391                                     VarDescriptor rightside=VarDescriptor.makeNew("rightvalue");
392                                     writer.addDeclaration("int", rightside.getSafeSymbol());
393                                     rightexpr.generate(writer,rightside);
394                                     writer.outputline("if (("+leftside.getSafeSymbol()+"!=0) &&("+numElements.getSafeSymbol()+"%"+leftside.getSafeSymbol()+"==0))");
395                                     {
396                                         writer.startblock();
397                                         VarDescriptor newvalue=VarDescriptor.makeNew("newvalue");
398                                         writer.addDeclaration("int", newvalue.getSafeSymbol());
399                                         writer.outputline(newvalue.getSafeSymbol()+"="+numElements.getSafeSymbol()+"/"+leftside.getSafeSymbol()+";");
400                                         VarExpr ve=new VarExpr(newvalue);
401                                         newvalue.setType(ReservedTypeDescriptor.INT);
402                                         ve.td=ReservedTypeDescriptor.INT;
403                                         Updates u=new Updates(rightexpr,ve);
404                                         UpdateNode un=new UpdateNode(null);
405                                         un.addUpdate(u);
406                                         un.generate(writer,false,false,null,null,null,null);
407                                         writer.outputline("free"+RepairGenerator.name+"("+RepairGenerator.newmodel.getSafeSymbol()+");");
408                                         writer.outputline("computesizes(thisvar);");
409                                         writer.outputline(RepairGenerator.name+"_staterecomputesizes(thisvar);");
410                                         writer.outputline("goto rebuild;");
411                                         //                                        writer.outputline("break;");
412                                         writer.endblock();
413                                     }
414                                     writer.outputline("else if (("+rightside.getSafeSymbol()+"!=0)&&("+numElements.getSafeSymbol()+"%"+rightside.getSafeSymbol()+"==0))");
415                                     {
416                                         writer.startblock();
417                                         VarDescriptor newvalue=VarDescriptor.makeNew("newvalue");
418                                         writer.addDeclaration("int", newvalue.getSafeSymbol());
419                                         writer.outputline(newvalue.getSafeSymbol()+"="+numElements.getSafeSymbol()+"/"+rightside.getSafeSymbol()+";");
420                                         VarExpr ve=new VarExpr(newvalue);
421                                         newvalue.setType(ReservedTypeDescriptor.INT);
422                                         ve.td=ReservedTypeDescriptor.INT;
423                                         Updates u=new Updates(leftexpr,ve);
424                                         UpdateNode un=new UpdateNode(null);
425                                         un.addUpdate(u);
426                                         un.generate(writer,false,false,null,null,null,null);
427                                         writer.outputline("free"+RepairGenerator.name+"("+RepairGenerator.newmodel.getSafeSymbol()+");");
428                                         writer.outputline("computesizes(thisvar);");
429                                         writer.outputline(RepairGenerator.name+"_staterecomputesizes(thisvar);");
430                                         writer.outputline("goto rebuild;");
431                                         //                                        writer.outputline("break;");
432                                         writer.endblock();
433                                     }
434
435
436                                 } else throw new Error("Should be here");
437
438                                 writer.endblock();
439                             }
440
441                             writer.endblock();
442                         }
443                             /*
444
445                               if (indexbound instanceof DotExpr)
446                               return true;
447                               if ((indexbound instanceof OpExpr)&&
448                               (((OpExpr)indexbound).getOpcode()==Opcode.MULT)&&
449                               (((OpExpr)indexbound).getLeftExpr() instanceof DotExpr)&&
450                               (((OpExpr)indexbound).getRightExpr() instanceof DotExpr))
451                               return true;
452                               return false;
453                             */
454
455
456                             /* Give up and null out bad pointer */
457                     }
458                     VarDescriptor typevar=VarDescriptor.makeNew("typechecks");
459                     if (DOMEMCHECKS&&(!DOTYPECHECKS)) {
460                         writer.addDeclaration("bool", typevar.getSafeSymbol());
461                         writer.outputline(typevar.getSafeSymbol()+"=assertvalidmemory(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
462                         dotypecheck = true;
463                     } else if (DOTYPECHECKS) {
464                         writer.addDeclaration("bool", typevar.getSafeSymbol());
465                         writer.outputline(typevar.getSafeSymbol()+"=assertvalidtype(" + dest.getSafeSymbol() + ", " + this.td.getId() + ");");
466                     }
467                     if (DOMEMCHECKS||DOTYPECHECKS) {
468                         writer.outputline("if (!"+typevar.getSafeSymbol()+")");
469                         writer.startblock();
470                         writer.outputline(dest.getSafeSymbol()+"=0;");
471                         if (DONULL)
472                             writer.outputline(ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")=0;");
473                         writer.endblock();
474                     }
475                 }
476
477                 writer.endblock();
478             }
479             writer.endblock();
480             writer.outputline("else maybe=1;");
481         }
482         if (performedboundscheck) {
483             writer.endblock();
484             writer.outputline(" else ");
485             writer.startblock();
486             writer.outputline(dest.getSafeSymbol()+"=0;");
487             writer.outputline("maybe=1;");
488             if (!Compiler.REPAIR)
489                 writer.outputline("printf(\"Array Index Out of Bounds\");");
490             writer.endblock();
491         }
492     }
493
494     private int bitmask(int bits) {
495         int mask = 0;
496
497         for (int i = 0; i < bits; i++) {
498             mask <<= 1;
499             mask += 1;
500         }
501
502         return mask;
503     }
504
505     public void prettyPrint(PrettyPrinter pp) {
506         left.prettyPrint(pp);
507         pp.output("." + field);
508         if (index != null) {
509             pp.output("[");
510             index.prettyPrint(pp);
511             pp.output("]");
512         }
513     }
514
515     public boolean isValue(TypeDescriptor td) {
516         FieldDescriptor tmpfd=fd;
517         if (tmpfd instanceof ArrayDescriptor)
518             tmpfd=((ArrayDescriptor)tmpfd).getField();
519         return (tmpfd.getPtr()||(tmpfd.getType() instanceof ReservedTypeDescriptor));
520     }
521
522     public boolean isPtr() {
523         FieldDescriptor tmpfd=fd;
524         if (tmpfd instanceof ArrayDescriptor)
525             tmpfd=((ArrayDescriptor)tmpfd).getField();
526         return tmpfd.getPtr();
527     }
528
529     boolean typechecked=false;
530     public TypeDescriptor typecheck(SemanticAnalyzer sa) {
531         if (typechecked)
532             return this.td;
533         else typechecked=true;
534         TypeDescriptor lefttype = left.typecheck(sa);
535         TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
536
537         {
538             /* finished typechecking...so we can fill the fields in */
539             StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
540             FieldDescriptor fd = struct.getField(field);
541             LabelDescriptor ld = struct.getLabel(field);
542             if (ld != null) { /* label */
543                 assert fd == null;
544                 fieldtype = ld.getType(); // d.s ==> Superblock, while,  d.b ==> Block
545                 fd = ld.getField();
546                 assert fd != null;
547                 assert intindex == null;
548                 intindex = ld.getIndex();
549             } else {
550                 if (fd==null) {
551                     throw new Error("Null fd for: "+field);
552                 }
553                 fieldtype = fd.getType();
554                 intindex=index;
555             }
556             this.fd=fd;
557             if (fieldtype instanceof MissingTypeDescriptor)
558                 throw new Error(fieldtype.getSymbol()+" type undefined!");
559         }
560
561         if ((lefttype == null) || (index != null && indextype == null)) {
562             return null;
563         }
564
565         if (indextype != null) {
566             if (indextype != ReservedTypeDescriptor.INT) {
567                 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
568                 return null;
569             }
570         }
571
572         if (lefttype instanceof StructureTypeDescriptor) {
573             StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
574             FieldDescriptor fd = struct.getField(field);
575             LabelDescriptor ld = struct.getLabel(field);
576
577             if (fd != null) { /* field */
578                 assert ld == null;
579
580                 if (indextype == null && fd instanceof ArrayDescriptor) {
581                     sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
582                     return null;
583                 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
584                     sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
585                     return null;
586                 }
587
588                 this.td = fd.getType();
589             } else if (ld != null) { /* label */
590                 assert fd == null;
591
592                 if (index != null) {
593                     sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
594                     return null;
595                 }
596
597                 this.td = ld.getType();
598             } else {
599                 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
600                 return null;
601             }
602
603             /* we promote bit, byte and short to integer types */
604             if (this.td == ReservedTypeDescriptor.BIT ||
605                 this.td == ReservedTypeDescriptor.BYTE ||
606                 this.td == ReservedTypeDescriptor.SHORT) {
607                 this.td = ReservedTypeDescriptor.INT;
608             }
609
610             return this.td;
611         } else {
612             sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");
613             return null;
614         }
615     }
616 }