001: /*
002: * xtc - The eXTensible Compiler
003: * Copyright (C) 2006-2007 Robert Grimm
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License
007: * version 2 as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: *
014: * You should have received a copy of the GNU General Public License
015: * along with this program; if not, write to the Free Software
016: * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
017: * USA.
018: */
019: package xtc.type;
020:
021: import java.io.IOException;
022:
023: import java.math.BigInteger;
024:
025: /**
026: * Representation of a reference. A reference represents a specific
027: * region of memory. It has a type, which determines the layout of
028: * the referenced memory region. Furthermore, it may optionally have
029: * a base and an offset, indicating a memory region relative to
030: * another. The optional base is a reference, and the optional offset
031: * is either an index or a field.
032: *
033: * @author Robert Grimm
034: * @version $Revision: 1.12 $
035: */
036: public abstract class Reference {
037:
038: /** The type. */
039: protected Type type;
040:
041: /**
042: * Create a new reference. Note that this constructor resolves the
043: * specified type.
044: *
045: * @param type The type.
046: */
047: public Reference(Type type) {
048: this .type = type.resolve();
049: }
050:
051: /**
052: * Normalize this reference. This method adjusts the internal type
053: * and should be called from constructors that explicitly set the
054: * type (instead of just using a base reference's type).
055: */
056: protected void normalize() {
057: while (type.isArray()) {
058: type = type.toArray().getType().resolve();
059: }
060: }
061:
062: /**
063: * Get this reference's type.
064: *
065: * @return The type.
066: */
067: public Type getType() {
068: return type;
069: }
070:
071: /**
072: * Determine whether this reference is a null reference. Note that
073: * a reference other than {@link NullReference#NULL} may still
074: * return <code>true</code>; notably, an index reference with a null
075: * base and a zero offset still is null.
076: *
077: * @see NullReference
078: *
079: * @return <code>true</code> if this reference is a null
080: * reference.
081: */
082: public boolean isNull() {
083: return false;
084: }
085:
086: /**
087: * Determine whether this reference is a string reference.
088: *
089: * @see StringReference
090: *
091: * @return <code>true</code> if this reference is a string
092: * reference.
093: */
094: public boolean isString() {
095: return false;
096: }
097:
098: /**
099: * Determine whether this reference is a variable reference.
100: *
101: * @see VariableReference
102: *
103: * @return <code>true</code> if this reference is a variable
104: * reference.
105: */
106: public boolean isVariable() {
107: return false;
108: }
109:
110: /**
111: * Determine whether this reference is a static reference.
112: *
113: * @see StaticReference
114: *
115: * @return <code>true</code> if this reference is a static
116: * reference.
117: */
118: public boolean isStatic() {
119: return false;
120: }
121:
122: /**
123: * Determine whether this reference is a dynamic reference.
124: *
125: * @see DynamicReference
126: *
127: * @return <code>true</code> if this reference is a dynamic
128: * reference.
129: */
130: public boolean isDynamic() {
131: return false;
132: }
133:
134: /**
135: * Determine whether this reference represents a prefix operator in
136: * C syntax.
137: *
138: * @return <code>true</code> if this reference represents a
139: * prefix operator.
140: */
141: public boolean isPrefix() {
142: return false;
143: }
144:
145: /**
146: * Determine whether this reference is a cast reference.
147: *
148: * @return <code>true</code> if this reference is a cast
149: * reference.
150: */
151: public boolean isCast() {
152: return false;
153: }
154:
155: /**
156: * Determine whether this reference is an indirect reference.
157: *
158: * @return <code>true</code> if this reference is an indirect
159: * reference.
160: */
161: public boolean isIndirect() {
162: return false;
163: }
164:
165: /**
166: * Determine whether this reference has a base.
167: *
168: * @see RelativeReference
169: *
170: * @return <code>true</code> if this reference has a base.
171: */
172: public boolean hasBase() {
173: return false;
174: }
175:
176: /**
177: * Get this reference's base.
178: *
179: * @see RelativeReference
180: *
181: * @return The base.
182: * @throws IllegalStateException Signals that this reference does
183: * not have a base.
184: */
185: public Reference getBase() {
186: throw new IllegalStateException("not a relative reference");
187: }
188:
189: /**
190: * Determine whether this reference has an index.
191: *
192: * @see IndexReference
193: *
194: * @return <code>true</code> if this reference has an index.
195: */
196: public boolean hasIndex() {
197: return false;
198: }
199:
200: /**
201: * Get this reference's index.
202: *
203: * @return The index.
204: * @throws IllegalStateException Signals that this reference does
205: * not have an index.
206: */
207: public BigInteger getIndex() {
208: throw new IllegalStateException("not an index reference");
209: }
210:
211: /**
212: * Determine whether this reference has a field.
213: *
214: * @see FieldReference
215: *
216: * @return <code>true</code> if this reference has a field.
217: */
218: public boolean hasField() {
219: return false;
220: }
221:
222: /**
223: * Get this reference's field.
224: *
225: * @return The field.
226: * @throws IllegalStateException Signals that this reference does
227: * not have a field.
228: */
229: public String getField() {
230: throw new IllegalStateException("not a field reference");
231: }
232:
233: /**
234: * Determine whether this reference has an absolute memory location.
235: *
236: * @return <code>true</code> if this reference has an absolute
237: * memory location.
238: */
239: public boolean hasLocation() {
240: return false;
241: }
242:
243: /**
244: * Get this reference's absolute memory location.
245: *
246: * @return The memory location.
247: * @throws IllegalStateException Signals that this reference does
248: * not have an absolute memory location.
249: */
250: public BigInteger getLocation() {
251: throw new IllegalStateException();
252: }
253:
254: /**
255: * Determine whether this reference represents a compile-time
256: * constant memory location.
257: *
258: * @return <code>true</code> if this reference represents a
259: * compile-time memory location.
260: */
261: public boolean isConstant() {
262: return false;
263: }
264:
265: /**
266: * Indirect this reference. This method determines the appropriate
267: * reference when using a pointer-decayed type. For arrays and
268: * functions, it simly returns this reference. For all other types,
269: * it returns an indirect reference, with this reference as the
270: * base.
271: *
272: * @param type The reference's declared type (before pointer decay).
273: */
274: public Reference indirect(Type type) {
275: Type resolved = type.resolve();
276: if (resolved.isArray() || resolved.isFunction()) {
277: return this ;
278: } else {
279: return new IndirectReference(this );
280: }
281: }
282:
283: /**
284: * Add the specified value to this reference.
285: *
286: * @param val The value.
287: * @return A reference with an index increased by <code>val</code>.
288: */
289: public Reference add(long val) {
290: if (0 == val) {
291: return this ;
292: } else {
293: return add(BigInteger.valueOf(val));
294: }
295: }
296:
297: /**
298: * Add the specified value to this reference.
299: *
300: * @param val The value.
301: * @return A reference with an index increased by <code>val</code>.
302: */
303: public Reference add(BigInteger val) {
304: if (val.signum() == 0) {
305: return this ;
306: } else {
307: return new IndexReference(this , val);
308: }
309: }
310:
311: /**
312: * Subtract the specified value from this reference.
313: *
314: * @param val The value.
315: * @return A reference with an index decreased by <code>val</code>.
316: */
317: public Reference subtract(long val) {
318: if (0 == val) {
319: return this ;
320: } else {
321: return subtract(BigInteger.valueOf(val));
322: }
323: }
324:
325: /**
326: * Subtract the specified value from this reference.
327: *
328: * @param val The value.
329: * @return A reference with an index decreased by <code>val</code>.
330: */
331: public Reference subtract(BigInteger val) {
332: if (val.signum() == 0) {
333: return this ;
334: } else {
335: return new IndexReference(this , val.negate());
336: }
337: }
338:
339: /**
340: * Determine the difference between the two references.
341: *
342: * @param ref The other reference.
343: * @return The difference or <code>null</code> if the difference
344: * cannot be statically determined.
345: */
346: public BigInteger difference(Reference ref) {
347: if (hasIndex() && ref.hasIndex()) {
348: IndexReference r1 = (IndexReference) this ;
349: IndexReference r2 = (IndexReference) ref;
350:
351: if (r1.base.equals(r2.base)) {
352: return r1.index.subtract(r2.index);
353: }
354:
355: } else if (hasIndex()) {
356: IndexReference r1 = (IndexReference) this ;
357:
358: if (r1.base.equals(ref)) {
359: return r1.index;
360: }
361:
362: } else if (ref.hasIndex()) {
363: IndexReference r2 = (IndexReference) ref;
364:
365: if (this .equals(r2.base)) {
366: return r2.index.negate();
367: }
368: }
369:
370: return null;
371: }
372:
373: /**
374: * Write a human readable representation to the specified
375: * appendable.
376: *
377: * @param out The appendable.
378: * @throws IOException Signals an I/O error.
379: */
380: public abstract void write(Appendable out) throws IOException;
381:
382: public String toString() {
383: StringBuilder buf = new StringBuilder();
384: try {
385: write(buf);
386: } catch (IOException x) {
387: assert false;
388: }
389: return buf.toString();
390: }
391:
392: }
|