5 public class DotExpr extends Expr {
11 public Set freeVars() {
12 Set lset=left.freeVars();
15 iset=index.freeVars();
24 static int memoryindents = 0;
26 public static void generate_memory_endblocks(CodeWriter cr) {
27 while (memoryindents > 0) {
36 TypeDescriptor fieldtype;
39 public String name() {
40 String name=left.name()+"."+field;
42 name+="["+index.name()+"]";
46 public boolean usesDescriptor(Descriptor d) {
49 return left.usesDescriptor(d)||((intindex!=null)&&intindex.usesDescriptor(d));
52 public boolean equals(Map remap, Expr e) {
53 if (e==null||!(e instanceof DotExpr))
55 DotExpr de=(DotExpr)e;
56 if (!de.field.equals(field))
61 } else if (!index.equals(remap,de.index))
63 if (!left.equals(remap,de.left))
69 public DotExpr(Expr left, String field, Expr index) {
75 public Set getRequiredDescriptors() {
76 Set v = left.getRequiredDescriptors();
79 v.addAll(index.getRequiredDescriptors());
84 public Expr getExpr() {
88 public FieldDescriptor getField() {
92 public Expr getIndex() {
96 public void generate(CodeWriter writer, VarDescriptor dest) {
97 VarDescriptor leftd = VarDescriptor.makeNew("left");
99 writer.output("// " + leftd.getSafeSymbol() + " <-- ");
100 left.prettyPrint(writer);
101 writer.outputline("");
103 left.generate(writer, leftd);
105 writer.output("// " + leftd.getSafeSymbol() + " = ");
106 left.prettyPrint(writer);
107 writer.outputline("");
109 StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
110 Expr intindex = index;
113 // #ATTN#: getOffsetExpr needs to be called with the fielddescriptor obect that is in teh vector list
114 // this means that if the field is an arraydescriptor you have to call getOffsetExpr with the array
115 // descriptor not the underlying field descriptor
117 /* we calculate the offset in bits */
118 offsetbits = struct.getOffsetExpr(fd);
120 if (fd instanceof ArrayDescriptor) {
121 fd = ((ArrayDescriptor) fd).getField();
124 if (intindex != null) {
125 if (intindex instanceof IntegerLiteralExpr && ((IntegerLiteralExpr) intindex).getValue() == 0) {
126 /* short circuit for constant 0 */
128 Expr basesize = fd.getBaseSizeExpr();
129 offsetbits = new OpExpr(Opcode.ADD, offsetbits, new OpExpr(Opcode.MULT, basesize, intindex));
133 final SymbolTable st = writer.getSymbolTable();
134 TypeDescriptor td = offsetbits.typecheck(new SemanticAnalyzer() {
135 public IRErrorReporter getErrorReporter() { throw new IRException("badness"); }
136 public SymbolTable getSymbolTable() { return st; }
140 throw new IRException();
141 } else if (td != ReservedTypeDescriptor.INT) {
142 throw new IRException();
145 // #TBD#: ptr's to bits and byte's and stuff are a little iffy...
146 // right now, a bit* is the same as a int* = short* = byte* (that is there
147 // is no post-derefernce mask)
149 // #ATTN#: do we handle int* correctly? what is the correct behavior? we automatically
150 // dereference pointers, but for structures that means that if we have a nested structure
151 // we return an integer address to that nested structure. if we have a pointer to a
152 // structure else where we want that base address ... yeah so we *(int *) it... ok we are
155 boolean dotypecheck = false;
157 if (offsetbits instanceof IntegerLiteralExpr) {
158 int offsetinbits = ((IntegerLiteralExpr) offsetbits).getValue();
159 int offset = offsetinbits >> 3; /* offset in bytes */
161 if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
162 int shift = offsetinbits - (offset << 3);
163 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
165 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
166 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() +
168 "(" + leftd.getSafeSymbol() + " + " + offset + ")) " +
169 " >> " + shift + ") & 0x" + Integer.toHexString(mask) + ";");
170 } else { /* a structure address or a ptr! */
171 String ptr = fd.getPtr() ? "*(int *)" : "";
172 /* type var = [*(int *)] (base + offset) */
174 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
176 writer.outputline("int " + dest.getSafeSymbol() +
177 " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset + ");");
181 } else { /* offset in bits is an expression that must be generated */
182 VarDescriptor ob = VarDescriptor.makeNew("offsetinbits");
183 writer.output("// " + ob.getSafeSymbol() + " <-- ");
184 offsetbits.prettyPrint(writer);
185 writer.outputline("");
186 offsetbits.generate(writer, ob);
187 writer.output("// " + ob.getSafeSymbol() + " = ");
188 offsetbits.prettyPrint(writer);
189 writer.outputline("");
191 /* derive offset in bytes */
192 VarDescriptor offset = VarDescriptor.makeNew("offset");
193 writer.outputline("int " + offset.getSafeSymbol() + " = " + ob.getSafeSymbol() + " >> 3;");
195 if (fd.getType() instanceof ReservedTypeDescriptor && !fd.getPtr()) {
196 VarDescriptor shift = VarDescriptor.makeNew("shift");
197 writer.outputline("int " + shift.getSafeSymbol() + " = " + ob.getSafeSymbol() +
198 " - (" + offset.getSafeSymbol() + " << 3);");
199 int mask = bitmask(((IntegerLiteralExpr)fd.getType().getSizeExpr()).getValue());
201 /* type var = ((*(int *) (base + offset)) >> shift) & mask */
202 writer.outputline(getType().getGenerateType() + " " + dest.getSafeSymbol() +
204 "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ")) " +
205 " >> " + shift.getSafeSymbol() + ") & 0x" + Integer.toHexString(mask) + ";");
206 } else { /* a structure address or a ptr */
207 String ptr = fd.getPtr() ? "*(int *)" : "";
208 /* type var = [*(int *)] (base + offset) */
210 // #ATTN: was 'getType.getGeneratedType()' instead of 'int' but all pointers are represented
212 writer.outputline("int " + dest.getSafeSymbol() +
213 " = " + ptr + "(" + leftd.getSafeSymbol() + " + " + offset.getSafeSymbol() + ");");
219 if (dotypecheck) { /* typemap checks! */
221 // high is 'low' + sizeof(fd.getDataStructure) <<< can be cached!!
223 // #ATTN#: we need to get the size of the fieldtype (if its a label the type of the label, not the
224 // underlying field's type
226 Expr sizeofexpr = fieldtype.getSizeExpr();
227 VarDescriptor sizeof = VarDescriptor.makeNew("sizeof");
228 sizeofexpr.generate(writer, sizeof);
230 String low = dest.getSafeSymbol();
231 String high = VarDescriptor.makeNew("high").getSafeSymbol();
232 writer.outputline("int " + high + " = " + low + " + " + sizeof.getSafeSymbol() + ";");
233 writer.outputline("assertvalidmemory(" + low + ", " + high + ");");
235 // we need to null value check and conditionalize the rest of the rule... we'll use a hack
236 // here where we store the number of indents in this class... and then provide a static
237 // method to unwind...
238 //writer.outputline("// assertvalidmemory ");
239 //DotExpr.memoryindents++;
240 //writer.outputline("if (" + dest.getSafeSymbol() + " != NULL)");
241 //writer.startblock();
246 private int bitmask(int bits) {
249 for (int i = 0; i < bits; i++) {
257 public void prettyPrint(PrettyPrinter pp) {
258 left.prettyPrint(pp);
259 pp.output("." + field);
262 index.prettyPrint(pp);
267 public TypeDescriptor typecheck(SemanticAnalyzer sa) {
268 TypeDescriptor lefttype = left.typecheck(sa);
269 TypeDescriptor indextype = index == null ? null : index.typecheck(sa);
272 /* finished typechecking...so we can fill the fields in */
273 StructureTypeDescriptor struct = (StructureTypeDescriptor) left.getType();
274 FieldDescriptor fd = struct.getField(field);
275 LabelDescriptor ld = struct.getLabel(field);
276 if (ld != null) { /* label */
278 fieldtype = ld.getType(); // d.s ==> Superblock, while, d.b ==> Block
281 assert intindex == null;
282 intindex = ld.getIndex();
284 fieldtype = fd.getType();
290 if ((lefttype == null) || (index != null && indextype == null)) {
294 if (indextype != null) {
295 if (indextype != ReservedTypeDescriptor.INT) {
296 sa.getErrorReporter().report(null, "Index must be of type 'int' not '" + indextype.getSymbol() + "'");
301 if (lefttype instanceof StructureTypeDescriptor) {
302 StructureTypeDescriptor struct = (StructureTypeDescriptor) lefttype;
303 FieldDescriptor fd = struct.getField(field);
304 LabelDescriptor ld = struct.getLabel(field);
306 if (fd != null) { /* field */
309 if (indextype == null && fd instanceof ArrayDescriptor) {
310 sa.getErrorReporter().report(null, "Must specify an index what accessing array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
312 } else if (indextype != null && !(fd instanceof ArrayDescriptor)) {
313 sa.getErrorReporter().report(null, "Cannot specify an index when accessing non-array field '" + struct.getSymbol() + "." + fd.getSymbol() + "'");
317 this.td = fd.getType();
318 } else if (ld != null) { /* label */
322 sa.getErrorReporter().report(null, "A label cannot be accessed as an array");
326 this.td = ld.getType();
328 sa.getErrorReporter().report(null, "No such field or label '" + field + "' in structure '" + struct.getSymbol() + "'");
332 /* we promote bit, byte and short to integer types */
333 if (this.td == ReservedTypeDescriptor.BIT ||
334 this.td == ReservedTypeDescriptor.BYTE ||
335 this.td == ReservedTypeDescriptor.SHORT) {
336 this.td = ReservedTypeDescriptor.INT;
341 sa.getErrorReporter().report(null, "Left hand side of . expression must be a structure type, not '" + lefttype.getSymbol() + "'");