5 public class DotExpr extends Expr {
11 public DotExpr(Expr left, String field, Expr index) {
17 public Set getRequiredDescriptors() {
18 Set v = left.getRequiredDescriptors();
21 v.addAll(index.getRequiredDescriptors());
27 public void generate(CodeWriter writer, VarDescriptor dest) {
28 VarDescriptor leftd = VarDescriptor.makeNew("left");
30 writer.output("// " + leftd.getSafeSymbol() + " <-- ");
31 left.prettyPrint(writer);
32 writer.outputline("");
34 left.generate(writer, leftd);
36 writer.output("// " + leftd.getSafeSymbol() + " = ");
37 left.prettyPrint(writer);
38 writer.outputline("");
40 StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
41 FieldDescriptor fd = struct.getField(field);
42 LabelDescriptor ld = struct.getLabel(field);
43 TypeDescriptor fieldtype;
44 Expr intindex = index;
47 if (ld != null) { /* label */
49 fieldtype = ld.getType(); // d.s ==> Superblock, while, d.b ==> Block
52 assert intindex == null;
53 intindex = ld.getIndex();
55 fieldtype = fd.getType();
58 // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor obect that is in teh vector list
59 // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array
60 // descriptor not the underlying field descriptor
62 /* we calculate the offset in bits */
63 offsetbits = struct.getOffsetExpr(fd);
65 if (fd instanceof ArrayDescriptor) {
66 fd = ((ArrayDescriptor) fd).getField();
69 if (intindex != null) {
70 if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
71 /* short circuit for constant 0 */
73 Expr basesize = fd.getBaseSizeExpr();
74 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
78 final SymbolTable st = writer.getSymbolTable();
79 TypeDescriptor td = offsetbits.typecheck(new SemanticAnalyzer() {
80 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
81 public SymbolTable getSymbolTable() { return st; }
85 throw new IRException();
86 } else if (td != ReservedTypeDescriptor.INT) {
87 throw new IRException();
90 // #TBD#: ptr's to bits and byte's and stuff are a little iffy...
91 // right now, a bit* is the same as a int* = short* = byte* (that is there
92 // is no post-derefernce mask)
94 // #ATTN#: do we handle int* correctly? what is the correct behavior? we automatically
95 // dereference pointers, but for structures that means that if we have a nested structure
96 // we return an integer address to that nested structure. if we have a pointer to a
97 // structure else where we want that base address ... yeah so we *(int *) it... ok we are
100 boolean dotypecheck = false;
102 if (offsetbits instanceof IntegerLiteralExpr) {
103 int offsetinbits = ((IntegerLiteralExpr) offsetbits).getValue();
104 int offset = offsetinbits >> 3; /* offset in bytes */
106 if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
107 int shift = offsetinbits - (offset << 3);
108 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
110 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
111 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() +
113 "(" + leftd.getSafeSymbol() + " + " + offset + ")) " +
114 " >> " + shift + ") & 0x" + Integer.toHexString(mask) + ";");
115 } else { /* a structure address or a ptr! */
116 String ptr = fd.getPtr() ? "*(int *)" : "";
117 /* type var = [*(int *)] (base + offset) */
119 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
121 writer.outputline("int " + dest.getSafeSymbol() +
122 " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ");");
126 } else { /* offset in bits is an expression that must be generated */
127 VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
128 writer.output("// " + ob.getSafeSymbol() + " <-- ");
129 offsetbits.prettyPrint(writer);
130 writer.outputline("");
131 offsetbits.generate(writer, ob);
132 writer.output("// " + ob.getSafeSymbol() + " = ");
133 offsetbits.prettyPrint(writer);
134 writer.outputline("");
136 /* derive offset in bytes */
137 VarDescriptor offset = VarDescriptor.makeNew("offset");
138 writer.outputline("int " + offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
140 if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
141 VarDescriptor shift = VarDescriptor.makeNew("shift");
142 writer.outputline("int " + shift.getSafeSymbol() + " = " + ob.getSafeSymbol() +
143 " - (" + offset.getSafeSymbol() + " << 3);");
144 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
146 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
147 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() +
149 "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " +
150 " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");
151 } else { /* a structure address or a ptr */
152 String ptr = fd.getPtr() ? "*(int *)" : "";
153 /* type var = [*(int *)] (base + offset) */
155 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
157 writer.outputline("int " + dest.getSafeSymbol() +
158 " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");
164 if (dotypecheck) { /* typemap checks! */
166 // high is 'low' + sizeof(fd.getDataStructure) <<< can be cached!!
168 // #ATTN#: we need to get the size of the fieldtype (if its a label the type of the label, not the
169 // underlying field's type
171 Expr sizeofexpr = fieldtype.getSizeExpr();
172 VarDescriptor sizeof = VarDescriptor.makeNew("sizeof");
173 sizeofexpr.generate(writer, sizeof);
175 String low = dest.getSafeSymbol();
176 String high = VarDescriptor.makeNew("high").getSafeSymbol();
177 writer.outputline("int " + high + " = " + low + " + " + sizeof.getSafeSymbol() + ";");
178 writer.outputline("assertvalidmemory(" + low + ", " + high + ");");
183 private int bitmask(int bits) {
186 for (int i = 0; i < bits; i++) {
194 public void prettyPrint(PrettyPrinter pp) {
195 left.prettyPrint(pp);
196 pp.output("." + field);
199 index.prettyPrint(pp);
204 public TypeDescriptor typecheck(SemanticAnalyzer sa) {
205 TypeDescriptor lefttype = left.typecheck(sa);
206 TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
208 if ((lefttype == null) || (index != null && indextype == null)) {
212 if (indextype != null) {
213 if (indextype != ReservedTypeDescriptor.INT) {
214 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
219 if (lefttype instanceof StructureTypeDescriptor) {
220 StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
221 FieldDescriptor fd = struct.getField(field);
222 LabelDescriptor ld = struct.getLabel(field);
224 if (fd != null) { /* field */
227 if (indextype == null && fd instanceof ArrayDescriptor) {
228 sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
230 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
231 sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
235 this.td = fd.getType();
236 } else if (ld != null) { /* label */
240 sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
244 this.td = ld.getType();
246 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
250 /* we promote bit, byte and short to integer types */
251 if (this.td == ReservedTypeDescriptor.BIT ||
252 this.td == ReservedTypeDescriptor.BYTE ||
253 this.td == ReservedTypeDescriptor.SHORT) {
254 this.td = ReservedTypeDescriptor.INT;
259 sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");