SetTypeAnalyzer.java
package edu.udel.cis.vsl.abc.analysis.entity;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.OperatorNode;
import edu.udel.cis.vsl.abc.ast.type.IF.ArithmeticType;
import edu.udel.cis.vsl.abc.ast.type.IF.ArrayType;
import edu.udel.cis.vsl.abc.ast.type.IF.IntegerType;
import edu.udel.cis.vsl.abc.ast.type.IF.ObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.PointerType;
import edu.udel.cis.vsl.abc.ast.type.IF.SetType;
import edu.udel.cis.vsl.abc.ast.type.IF.StandardSignedIntegerType.SignedIntKind;
import edu.udel.cis.vsl.abc.ast.type.IF.Type;
import edu.udel.cis.vsl.abc.ast.type.IF.Type.TypeKind;
import edu.udel.cis.vsl.abc.ast.type.IF.TypeFactory;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;
/**
* <p>
* This class provides static methods for helping analyzing expressions (in
* {@link ExpressionAnalyzer}) of {@link SetType}.
* </p>
*
*
* <p>
* The typing rules of expressions that may have {@link SetType} are defined as
* follows (<code>set</code> denotes an expression of set type; <code>e</code>
* denotes an expression of any type; for brevity {@link RangeType} here is
* considered as a {@link SetType}):
* <ul>
* <li><code>set->id</code>: if <code>set</code> has set type with element of
* struct type "s *", <code>set->id</code> has set type whose element type is
* decided by "s.id".</li>
*
* <li><code>set.id</code>: if <code>set</code> has set type with element of
* struct type "s", <code>set.id</code> has set type whose element type is
* decided by "s.id".</li>
*
* <li><code>*set</code>: if <code>set</code> has set type with element of "T *"
* type and "T" is not void, <code>*set</code> has set type whose element type
* is "T".</li>
*
* <li><code>&set</code>: if <code>set</code> has set type with element of "T"
* type, <code>&set</code> has set type with element of "T *" type.</li>
*
* <li><code>set[e]</code>: if <code>set</code> has set type with element of
* array type "T a[]" or pointer type "T *" and <code>e</code> has integer type
* or set type with integer element type, <code>set[e]</code> has set type with
* element type of "T".</li>
*
*
* <li><code>e[set]</code>: if <code>set</code> has set type with element of
* integer and <code>e</code> has array type "T a[]" or pointer type "T *",
* <code>e[set]</code> has set type with element type of "T"</li>
*
* <li><code>set + e</code> (or <code>e + set</code>): if <code>set</code> has
* set type with element of pointer type "T *" and <code>e</code> has integer
* type or set type with element of integer type, <code>set + e</code> has set
* type with element of pointer type "T *"; if <code>set</code> has set type
* with element of integer type and <code>e</code> has integer type or set type
* with element of integer type, <code>set + e</code> has set type with element
* of integer type.</li>
* </ul>
* </p>
*
* @author ziqingluo
*/
class SetTypeAnalyzer {
/**
* <p>
* Check if the given expression is a "memory location set" expression. An
* expression is a "memory location set expression" iff it has scalar type
* or set of scalar type and is a "lvalue" expression.
* </p>
*
* @param expr
* @return true iff the given expression is a "memory location set"
* expression; false, otherwise
* @throws SyntaxException
* when the given expression has mixed mem type
*/
static boolean isMemoryLocationSet(ExpressionAnalyzer primaryAnalyzer,
ExpressionNode expr) throws SyntaxException {
Type type = expr.getType();
if (type.kind() == TypeKind.SET)
type = ((SetType) type).elementType();
if (!type.isScalar())
return false;
return expr.isLvalue();
}
/* ******************** process ADDRESSOF ******************** */
/**
* <p>
* process an ADDRESSOF operation which may have {@link SetType}: if the
* sole operand has set of "T" type, the operation has set of "T *" type.
* </p>
* <p>
* <b>pre-condition:</b> the operand is an lvalue expression
* </p>
*
* @param primaryAnalyzer
* a reference to the {@link ExpressionAnalyzer}
* @param arg0
* the operand of the ADDRESSOF operation
* @param node
* the ADDRESSOF operation node
* @return true iff the operation node has been set to set of pointer type
*/
static boolean processSetTypeForADDRESSOF(
ExpressionAnalyzer primaryAnalyzer, ExpressionNode arg0,
OperatorNode node) {
if (arg0.getType().kind() == TypeKind.SET) {
Type elementType = ((SetType) arg0.getType()).elementType();
TypeFactory tf = primaryAnalyzer.typeFactory;
node.setInitialType(tf.theSetType(tf.pointerType(elementType)));
return true;
}
return false;
}
/* ******************** process SUBSCRIPT ******************** */
/**
* <p>
* process SUBSCRIPT operation if at least one of its operand has set type
* </p>
*
* @param primaryAnalyzer
* a reference to the {@link ExpressionAnalyzer}
* @param arg0
* the operand of the SUBSCRIPT operation
* @param arg1
* the operand of the SUBSCRIPT operation
* @param node
* the SUBSCRIPT operation node
* @return true iff the node has been set to set of "T" type where "T" is
* the referred type of "arg0" if "arg0" has pointer type or "T" is
* the element type of "arg0" if "arg0" has an array type; false
* otherwise
* @throws SyntaxException
* if the first operand does not have (set of) pointer to
* complete object type or (set of) array type, or the second
* argument does not have integer or set of integer type
*/
static boolean processSetTypeForSUBSCRIPT(
ExpressionAnalyzer primaryAnalyzer, ExpressionNode arg0,
ExpressionNode arg1, OperatorNode node) throws SyntaxException {
Type type0 = arg0.getType();
Type type1 = arg1.getType();
if (type0.kind() == TypeKind.SET || type1.kind() == TypeKind.SET
|| type1.kind() == TypeKind.RANGE) {
ObjectType elementType;
// process SUBSCRIPT expression "A[I]" of set type:
// if "A" has set type:
if (type0.kind() == TypeKind.SET) {
type0 = ((SetType) type0).elementType();
elementType = pointerReferredTypeORArrayElementType(
primaryAnalyzer, type0);
} else
elementType = pointerReferredTypeORArrayElementType(
primaryAnalyzer, type0);
if (elementType == null)
throw primaryAnalyzer.error(
"First argument to subscript operator not pointer to complete object type:\n",
node);
// if "I" has set type:
if (type1.kind() == TypeKind.SET) {
type1 = ((SetType) type1).elementType();
if (!(type1 instanceof IntegerType))
throw primaryAnalyzer.error("The term "
+ arg1.prettyRepresentation() + " in expression "
+ node.prettyRepresentation()
+ " shall have integer type or set of integer types",
node);
}
node.setInitialType(
primaryAnalyzer.typeFactory.theSetType(elementType));
return true;
}
return false;
}
/**
* Attempt to get the type of a SUBSCRIPT operation <code>a[i]</code> from
* the type of its "left-hand side" operand <code>a</code>. The type of
* <code>a</code> can only be either a pointer to a complete object type or
* an array type. If the type of <code>a</code> is neither the
* aforementioned two, return <code>null</code>.
*
* @param primaryAnalyzer
* a reference to the {@link ExpressionAnalyzer}
* @param type
* the type of the "left-hand side" operand <code>a</code> in a
* SUBSCRIPT operation <code>a[i]</code>
* @return the referred type of <code>a</code> if <code>a</code> has pointer
* type; or the element of <code>a</code> if <code>a</code> has
* array type; or <code>null</code> otherwise.
*/
static private ObjectType pointerReferredTypeORArrayElementType(
ExpressionAnalyzer primaryAnalyzer, Type type) {
if (primaryAnalyzer.isPointerToCompleteObjectType(type))
return (ObjectType) ((PointerType) type).referencedType();
else if (type.kind() == TypeKind.ARRAY)
return ((ArrayType) type).getElementType();
return null;
}
/* ******************** process DEREFERENCE ******************** */
/**
* <p>
* process DEREFERENCE operation if the operand has set of pointer type
* </p>
*
* @param primaryAnalyzer
* a reference to the {@link ExpressionAnalyzer}
* @param arg
* the operand of the DEREFERENCE operation
* @param node
* the DEREFERENCE operation node
* @return true iff the operand has set of "T *" type and the operation node
* has been set of "T" type
* @throws SyntaxException
* if the operand has set of non-pointer type
*/
static boolean processSetTypeForDEREFERENCE(
ExpressionAnalyzer primaryAnalyzer, ExpressionNode arg,
OperatorNode node) throws SyntaxException {
Type type = arg.getType();
if (arg.getType().kind() == TypeKind.SET) {
type = ((SetType) type).elementType();
if (!primaryAnalyzer.isPointerToCompleteObjectType(type))
throw primaryAnalyzer.error(
"Argument to * has non-pointer type: " + type, arg);
node.setInitialType(primaryAnalyzer.typeFactory.theSetType(
(ObjectType) ((PointerType) type).referencedType()));
return true;
}
return false;
}
/* ******************** process PLUS *************************** */
/**
* <p>
* process PLUS operation node if at least one operand has set type
* </p>
*
* @param expressionAnalyzer
* a reference to the {@link ExpressionAnalyzer}
* @param operand0
* one operand of the processing operation node
* @param operand1
* the other operand of the processing operation node
* @param node
* the operation node
* @return true iff the operation node has been set a set of integer or
* pointer type
*/
static boolean processSetTypeForPLUSOperands(
ExpressionAnalyzer expressionAnalyzer, ExpressionNode operand0,
ExpressionNode operand1, ExpressionNode node) {
TypeKind kind0 = operand0.getType().kind();
TypeKind kind1 = operand1.getType().kind();
if (!(kind0 == TypeKind.SET || kind0 == TypeKind.RANGE
|| kind1 == TypeKind.SET || kind1 == TypeKind.RANGE))
return false;
Type type0 = operand0.getType();
Type type1 = operand1.getType();
if (kind0 == TypeKind.SET)
type0 = ((SetType) type0).elementType();
if (expressionAnalyzer.isPointerToCompleteObjectType(type0))
return processSetTypeForPointerAdd(expressionAnalyzer.typeFactory,
operand0, operand1, node);
if (kind1 == TypeKind.SET)
type1 = ((SetType) type1).elementType();
if (expressionAnalyzer.isPointerToCompleteObjectType(type1))
return processSetTypeForPointerAdd(expressionAnalyzer.typeFactory,
operand1, operand0, node);
return processSetTypeForArithmeticAdd(expressionAnalyzer.typeFactory,
operand0, operand1, node);
}
/**
* <p>
* process "pointer addition" operation where at least one operand has set
* type
* </p>
*
* @param typeFactory
* a reference to {@link TypeFactory}
* @param pointer
* the operand has pointer type or set of pointer type
* @param offset
* the operand has integer type or set of integer type (range
* type)
* @param node
* the pointer addition operation node
* @return true iff the operation node has been set set of pointer type
*/
private static boolean processSetTypeForPointerAdd(TypeFactory typeFactory,
ExpressionNode pointer, ExpressionNode offset,
ExpressionNode node) {
PointerType pointerType;
Type offsetType = offset.getType();
if (pointer.getType().kind() == TypeKind.SET) {
pointerType = (PointerType) ((SetType) pointer.getType())
.elementType();
} else
pointerType = (PointerType) pointer.getType();
if (offset.getType().kind() == TypeKind.SET)
offsetType = ((SetType) offset.getType()).elementType();
if (offsetType.kind() != TypeKind.RANGE
&& !(offsetType instanceof IntegerType))
return false;
node.setInitialType(typeFactory.theSetType(pointerType));
return true;
}
/**
* <p>
* process operation node with arithmetic PLUS operator where at least one
* operand has set type
* </p>
*
* @param typeFactory
* a reference to {@link TypeFactory}
* @param num0
* one operand of a PLUS operation
* @param num1
* the other operand of a PLUS operation
* @param node
* the PLUS operation node
* @return true iff the PLUS operation node has been set of integer type
*
*/
private static boolean processSetTypeForArithmeticAdd(
TypeFactory typeFactory, ExpressionNode num0, ExpressionNode num1,
ExpressionNode node) {
TypeKind kind0 = num0.getType().kind();
TypeKind kind1 = num1.getType().kind();
Type elementType0, elementType1;
// element type of num0
if (kind0 == TypeKind.RANGE)
elementType0 = typeFactory.signedIntegerType(SignedIntKind.INT);
else if (kind0 == TypeKind.SET)
elementType0 = ((SetType) num0.getType()).elementType();
else
elementType0 = num0.getType();
// element type of num1
if (kind1 == TypeKind.RANGE)
elementType1 = typeFactory.signedIntegerType(SignedIntKind.INT);
else if (kind1 == TypeKind.SET)
elementType1 = ((SetType) num1.getType()).elementType();
else
elementType1 = num1.getType();
if (!(elementType0 instanceof ArithmeticType)
|| !(elementType1 instanceof ArithmeticType))
// regular type error:
return false;
ArithmeticType resultElementType = typeFactory
.usualArithmeticConversion((ArithmeticType) elementType0,
(ArithmeticType) elementType1);
node.setInitialType(typeFactory.theSetType(resultElementType));
return true;
}
}