DeclarationAnalyzer.java

package edu.udel.cis.vsl.abc.analysis.entity;

import java.util.Collection;
import java.util.Iterator;

import edu.udel.cis.vsl.abc.ast.IF.AST;
import edu.udel.cis.vsl.abc.ast.entity.IF.Entity;
import edu.udel.cis.vsl.abc.ast.entity.IF.Function;
import edu.udel.cis.vsl.abc.ast.entity.IF.Label;
import edu.udel.cis.vsl.abc.ast.entity.IF.OrdinaryEntity;
import edu.udel.cis.vsl.abc.ast.entity.IF.ProgramEntity.LinkageKind;
import edu.udel.cis.vsl.abc.ast.entity.IF.Scope;
import edu.udel.cis.vsl.abc.ast.entity.IF.Scope.ScopeKind;
import edu.udel.cis.vsl.abc.ast.entity.IF.Typedef;
import edu.udel.cis.vsl.abc.ast.entity.IF.Variable;
import edu.udel.cis.vsl.abc.ast.node.IF.ASTNode;
import edu.udel.cis.vsl.abc.ast.node.IF.IdentifierNode;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.acsl.ContractNode;
import edu.udel.cis.vsl.abc.ast.node.IF.compound.CompoundInitializerNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.AbstractFunctionDefinitionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.DeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.FunctionDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.FunctionDefinitionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.InitializerNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.OrdinaryDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.TypedefDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ArrayLambdaNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.StringLiteralNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.CompoundStatementNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.GotoNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypeNode;
import edu.udel.cis.vsl.abc.ast.node.common.compound.CommonCompoundInitializerNode;
import edu.udel.cis.vsl.abc.ast.type.IF.ArrayType;
import edu.udel.cis.vsl.abc.ast.type.IF.DomainType;
import edu.udel.cis.vsl.abc.ast.type.IF.Field;
import edu.udel.cis.vsl.abc.ast.type.IF.FunctionType;
import edu.udel.cis.vsl.abc.ast.type.IF.ObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.QualifiedObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.StructureOrUnionType;
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.value.IF.Value;
import edu.udel.cis.vsl.abc.config.IF.Configurations.Language;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;
import edu.udel.cis.vsl.abc.token.IF.UnsourcedException;

/**
 * A tool to analyze declarations in an AST.
 * 
 * @author siegel
 */
public class DeclarationAnalyzer {

	// ***************************** Fields *******************************

	/**
	 * The entity analyzer controlling this declaration analyzer.
	 */
	private EntityAnalyzer entityAnalyzer;

	/**
	 * Analyzer used to analyze the ACSL specifications in the code.
	 */
	private AcslContractAnalyzer acslAnalyzer;

	/**
	 * Typedefs which name types in this set will be ignored in file scope.
	 */
	private Collection<String> ignoredTypes = null;

	// ************************** Constructors ****************************

	/**
	 * Creates new declaration analyzer with the given controlling entity
	 * analyzer.
	 * 
	 * @param entityAnalyzer
	 *            the entity analyzer in charge
	 */
	DeclarationAnalyzer(EntityAnalyzer entityAnalyzer) {
		this.entityAnalyzer = entityAnalyzer;
		this.acslAnalyzer = new AcslContractAnalyzer(entityAnalyzer,
				entityAnalyzer.conversionFactory);
	}

	// ************************* Exported Methods *************************

	/**
	 * Sets the ignoredTypes to the given collection. Elements are not copied.
	 * 
	 * @param ignoredTypes
	 *            names of types for which typedefs will be ignored
	 */
	void setIgnoredTypes(Collection<String> ignoredTypes) {
		this.ignoredTypes = ignoredTypes;
	}

	/**
	 * Processes a typedef declaration.
	 * 
	 * @param node
	 *            a typedef declaration node that has not yet been processes
	 * @throws SyntaxException
	 *             if anything is wrong with the typedef declaration
	 */
	void processTypedefDeclaration(TypedefDeclarationNode node)
			throws SyntaxException {
		IdentifierNode identifier = node.getIdentifier();
		String name = identifier.name();
		Scope scope = node.getScope();
		TypeNode typeNode = node.getTypeNode();

		if (ignoredTypes != null && ignoredTypes.contains(name)) {
			OrdinaryEntity entity = scope.getLexicalOrdinaryEntity(false, name);

			if (entity == null)
				throw error("Cannot find definition of system typedef", node);
			if (entity instanceof Typedef) {
				entityAnalyzer.typeAnalyzer.processTypeNode(typeNode);
				identifier.setEntity(entity);
				node.setEntity(entity);
				entity.addDeclaration(node);
			} else
				throw error("Expected system typedef, got " + entity, node);
		} else {
			Type type = entityAnalyzer.typeAnalyzer.processTypeNode(typeNode);
			OrdinaryEntity entity = scope.getOrdinaryEntity(false, name);
			Typedef typedef;

			if (entity != null) {
				Type oldType;

				if (!(entity instanceof Typedef))
					throw entityAnalyzer.error("Typedef name already used at "
							+ entity.getDefinition().getSource(), node);
				typedef = (Typedef) entity;
				oldType = typedef.getType();
				if (!type.equals(oldType))
					throw entityAnalyzer.error(
							"Redefiniton of typedef name with different type.  "
									+ "Original definition was at "
									+ typedef.getDefinition().getSource(),
							node);
			} else {
				typedef = entityAnalyzer.entityFactory.newTypedef(name, type);
				try {
					scope.add(typedef);
				} catch (UnsourcedException e) {
					throw entityAnalyzer.error(e, node);
				}
				typedef.setDefinition((TypedefDeclarationNode) node);
			}
			typedef.addDeclaration(node);
			node.setEntity(typedef);
			identifier.setEntity(typedef);
		}
	}

	/**
	 * Processes a variable declaration node. The declaration must not be for a
	 * function parameter.
	 * 
	 * @param node
	 *            a variable declaration node
	 * @return the {@link Variable} declared, which is either created by this
	 *         method if this is the first declaration of that variable, or is
	 *         the existing variable if this is not the first declaration of the
	 *         variable
	 * @throws SyntaxException
	 *             if anything is wrong with the declaration
	 */
	Variable processVariableDeclaration(VariableDeclarationNode node)
			throws SyntaxException {
		return processVariableDeclaration(node, false);
	}

	/**
	 * <p>
	 * Processes a function declaration. The type node should already have been
	 * processed and the type must be a {@link FunctionType}.
	 * </p>
	 * 
	 * <p>
	 * The declaration cannot be the declaration of a function parameter,
	 * because function parameters always have an {@link ObjectType}. If a
	 * parameter looks like it has a function type, an automatic conversion
	 * converts it to a pointer to that function type.
	 * </p>
	 * 
	 * <ul>
	 * <li>If a {@link Function} entity does not already exist for the function
	 * identified by this declaration, it is created.</li>
	 * <li>The {@link Function} is added to its definition scope, if it is not
	 * already there. The definition scope is the least scope greater than or
	 * equal to the scope in which this declaration occurs and containing a
	 * definition of a function with the same name as the given one. If no such
	 * scope exists, the definition scope is the root scope.</li>
	 * <li>The {@link Function} is added to the current scope (the declaration
	 * scope), if it is not already there.</li>
	 * <li>If the linkage is {@link LinkageKind#EXTERNAL} or
	 * {@link LinkageKind#INTERNAL}, and the definition scope is the root scope,
	 * and the function is newly created, it is added to the AST's list of
	 * internal and external entities.</li>
	 * <li>The type information from this declaration is merged with the
	 * existing type information (forming the composite type) for the function,
	 * if the function entity existed before processing this declaration.</li>
	 * <li>If this declaration is also a function definition, the body is
	 * processed.</li>
	 * <li>If there is a contract associated to this declaration, it is
	 * processed.</li>
	 * <li>If this function is called "main" and it is in the root scope, the
	 * AST's main function is set to this function.</li>
	 * </ul>
	 * 
	 * @param node
	 *            the function declaration node to be processed
	 * @return the {@link Function} entity, either newly created or already
	 *         existing
	 * @throws SyntaxException
	 *             if there is anything wrong with the type, contract (if one
	 *             exists), or body (if the declaration is a function
	 *             definition); if the function cannot be added to the
	 *             definition or declaration scope (for example, because an
	 *             object of the same name is already in one of those scopes);
	 *             or if the type of the existing function is not compatible
	 *             with the type specified by the declaration
	 */
	Function processFunctionDeclaration(FunctionDeclarationNode node)
			throws SyntaxException {
		TypeNode typeNode = node.getTypeNode();
		Type type = entityAnalyzer.typeAnalyzer.processTypeNode(typeNode,
				false);
		IdentifierNode identifier = node.getIdentifier();

		if (identifier == null)
			return null;

		String name = identifier.name();
		LinkageKind linkage = computeLinkageOfFunction(node);
		Scope defnScope = getDefinitionScope(node);
		boolean isRootScope = defnScope.getParentScope() == null;
		OrdinaryEntity existingEntity = defnScope.getOrdinaryEntity(false,
				name);
		Scope declScope = node.getScope();
		AST ast = node.getOwner();
		Function result;

		if (existingEntity == null) {
			result = entityAnalyzer.entityFactory.newFunction(name, linkage,
					type);
			try {
				defnScope.add(result);
			} catch (UnsourcedException e) {
				throw error(e, identifier);
			}
			if (isRootScope) {
				if (linkage != LinkageKind.NONE)
					ast.add(result);
				if (name.equals("main"))
					ast.setMain(result);
			}
		} else {
			if (!(existingEntity instanceof Function))
				throw error(
						"Function name " + name
								+ " conflicts with previous declaration.\n"
								+ "Previous declaration: " + existingEntity
										.getFirstDeclaration().getSource()
								+ "\n",
						node);
			result = (Function) existingEntity;
			addTypeToVariableOrFunction(typeNode, result);
			checkSystemLibraryForFunction((FunctionDeclarationNode) node,
					result);
		}
		if (defnScope != declScope
				&& declScope.getOrdinaryEntity(false, name) != result) {
			try {
				declScope.add(result);
			} catch (UnsourcedException e) {
				throw error(e, identifier);
			}
		}
		node.setEntity(result);
		identifier.setEntity(result);
		addDeclarationToFunction(result, node);

		CompoundStatementNode body = null;

		if (node instanceof FunctionDefinitionNode) {
			body = ((FunctionDefinitionNode) node).getBody();
			node.setIsDefinition(true);
			entityAnalyzer.statementAnalyzer.processCompoundStatement(body);
			processGotos(body);
		}

		SequenceNode<ContractNode> contract = node.getContract();

		if (contract != null)
			acslAnalyzer.processContractNodes(contract, result);
		if (node.isLogicFunction())
			result.setLogic(true);
		return result;
	}

	/**
	 * Processes a variable declaration node, creating the {@link Variable}
	 * entity if this is the definition, adding it to the appropriate scope,
	 * processing the type node, etc.
	 * 
	 * @param node
	 *            a variable declaration node; after the type node of this
	 *            declaration is processed, the resulting type must be an
	 *            {@link ObjectType}
	 * @param isParameter
	 *            is this variable a formal parameter in a function declaration
	 *            or definition
	 * @return the Variable represented by this declaration (either the existing
	 *         one or a new one)
	 * @throws SyntaxException
	 *             if there is any problem with the type node, or if a
	 *             conflicting declaration of this object already exists
	 */
	Variable processVariableDeclaration(VariableDeclarationNode node,
			boolean isParameter) throws SyntaxException {
		TypeNode typeNode = node.getTypeNode();
		ObjectType type = (ObjectType) entityAnalyzer.typeAnalyzer
				.processTypeNode(typeNode, isParameter);
		IdentifierNode identifier = node.getIdentifier();

		if (identifier == null)
			return null;

		String name = identifier.name();

		if (type.kind() == TypeKind.VOID)
			throw error("declaring variable " + name + " as void type", node);

		Scope scope = identifier.getScope();
		LinkageKind linkage = computeLinkage(node, isParameter, type);
		OrdinaryEntity entity = scope.getOrdinaryEntity(false, name);
		boolean oldInScope = entity != null;

		if (linkage == LinkageKind.NONE) {
			if (oldInScope)
				throw error("Redeclaration of identifier " + name
						+ " with no linkage. " + "Original declaration was at "
						+ entity.getDeclaration(0).getSource(), identifier);
			else
				entity = entityAnalyzer.entityFactory.newVariable(name, linkage,
						type);
		} else { // declaration node's linkage is EXTERNAL or INTERNAL
			AST ast = node.getOwner();

			if (!oldInScope)
				entity = ast.getInternalOrExternalEntity(name);
			if (entity == null) {
				entity = entityAnalyzer.entityFactory.newVariable(name, linkage,
						type);
				ast.add(entity);
			} else if (entity.getLinkage() != linkage) {
				throw error(
						"Disagreement on internal/external linkage between two declarations",
						node);
			} else {
				addTypeToVariableOrFunction(typeNode, entity);
			}
		}
		if (!oldInScope) {
			try {
				scope.add(entity);
			} catch (UnsourcedException e) {
				throw error(e, identifier);
			}
		}
		node.setEntity(entity);
		identifier.setEntity(entity);

		Variable result = (Variable) entity;

		addDeclarationToVariable(result, node);

		InitializerNode initializer = node.getInitializer();

		if (initializer != null) {
			processInitializer(initializer, type);
			// recursively check for the following rule:
			// For pure C programs, ABC strictly conforms C11 standard,
			// variable length array cannot be initialized.
			if (!type.isScalar())
				if (entityAnalyzer.configuration.getLanguage() == Language.C
						&& hasVariableLengthArray(type))
					throw error(
							"C language doesn't allow initializing variable "
									+ "length arrays.\nCIVL-C language, whose source"
									+ " files end with \".cvl\" or \".cvh\" suffix, supports such feature",
							node);
			// if this is a compound initializer, the type
			// of the initializer refines the type of the variable
			if (initializer instanceof CompoundInitializerNode)
				result.setType(entityAnalyzer.typeFactory.compositeType(type,
						((CompoundInitializerNode) initializer).getType()));
			if (initializer instanceof StringLiteralNode)
				result.setType(entityAnalyzer.typeFactory.compositeType(type,
						((StringLiteralNode) initializer).getType()));
			// if language is CIVL-C, apply CIVL-C extended rule for computing
			// the final type from declaration and initializer...
			if (!type.isScalar())
				if (entityAnalyzer.configuration
						.getLanguage() == Language.CIVL_C)
					result.setType(entityAnalyzer.typeFactory
							.compositeArrayTypeInDeclarationForCIVLC(type,
									result.getType()));
		}
		return result;
	}

	/**
	 * @param type
	 *            a type
	 * @return true iff the given type is or includes a sub-type which is an
	 *         array with variable length
	 */
	private boolean hasVariableLengthArray(Type type) {
		switch (type.kind()) {
			case ARRAY : {
				ArrayType arrType = (ArrayType) type;

				if (arrType.isVariableLengthArrayType())
					return true;
				else
					return hasVariableLengthArray(arrType.getElementType());
			}
			case QUALIFIED :
				return hasVariableLengthArray(
						((QualifiedObjectType) type).getBaseType());
			case STRUCTURE_OR_UNION : {
				StructureOrUnionType structOrUnionType = (StructureOrUnionType) type;

				if (structOrUnionType.getFields() != null)
					for (Field field : structOrUnionType.getFields())
						if (hasVariableLengthArray(field.getType()))
							return true;
			}
			default :
				return false;
		}
	}

	// ************************* Private Methods **************************

	/**
	 * Creates a sourced static exception.
	 * 
	 * @param message
	 *            the error message
	 * @param node
	 *            the node responsible for leading to the error
	 * @return the new exception
	 */
	private SyntaxException error(String message, ASTNode node) {
		return entityAnalyzer.error(message, node);
	}

	/**
	 * Creates a new sourced static exception from an unsourced exception by
	 * adding the source information from a given node.
	 * 
	 * @param e
	 *            the unsourced exception
	 * @param node
	 *            the node responsible for leading to the error, whose source
	 *            will be used to form the sourced exception
	 * @return the new sourced static exception
	 */
	private SyntaxException error(UnsourcedException e, ASTNode node) {
		return entityAnalyzer.error(e, node);
	}

	/**
	 * Processes and initializer node in a variable declaration.
	 * 
	 * @param initializer
	 *            the initializer node
	 * @param currentType
	 *            the type of the variable being initialized before processing
	 *            this initializer; must be non-<code>null</code>. Note the type
	 *            may change as the initializer is processed
	 * @throws SyntaxException
	 *             if anything is wrong with this initializer, for example, if
	 *             it has the wrong type
	 */
	private void processInitializer(InitializerNode initializer,
			ObjectType currentType) throws SyntaxException {
		assert currentType != null;
		if (initializer instanceof ArrayLambdaNode) {
			Type arrayLambdaType;

			entityAnalyzer.expressionAnalyzer
					.processArrayLambda((ArrayLambdaNode) initializer);
			arrayLambdaType = ((ArrayLambdaNode) initializer).getType();
			if (!currentType.compatibleWith(arrayLambdaType)) {
				throw error(
						"incompatible types between the variable declaration and the initializer"
								+ "\n\tvariable is declared as type "
								+ currentType + "\n\tintializer has type "
								+ arrayLambdaType,
						initializer);

			}
		} else if (initializer instanceof ExpressionNode) {
			ExpressionNode rhs = (ExpressionNode) initializer;

			entityAnalyzer.expressionAnalyzer
					.processExpression((ExpressionNode) initializer);
			try {
				entityAnalyzer.expressionAnalyzer.processAssignment(currentType,
						rhs);
			} catch (UnsourcedException e) {
				throw error(e, initializer);
			}
		} else if (initializer instanceof CompoundInitializerNode) {
			if (currentType.kind() == TypeKind.DOMAIN)
				entityAnalyzer.expressionAnalyzer
						.processCartesianDomainInitializer(
								(CompoundInitializerNode) initializer,
								(DomainType) currentType);
			else
				entityAnalyzer.compoundLiteralAnalyzer
						.processCompoundInitializer(
								(CommonCompoundInitializerNode) initializer,
								currentType);
		}
	}

	/**
	 * Gets the "definition scope" of a function declaration. The function
	 * declaration must occur in a block scope or file scope, and it can NOT be
	 * a function parameter.
	 * 
	 * The "definition scope" is the least (non-strict) ancestor scope of the
	 * scope in which the declaration occurs containing a definition of the
	 * function name, or the root scope if there is no such ancestor.
	 * 
	 * @param functionDeclNode
	 *            the node for the function declaration.
	 * @return the definition scope
	 */
	private Scope getDefinitionScope(OrdinaryDeclarationNode functionDeclNode) {
		IdentifierNode identifier = functionDeclNode.getIdentifier();
		String name = identifier.name();
		Scope defnScope = functionDeclNode.getScope(),
				parentScope = defnScope.getParentScope();

		while (parentScope != null) {
			if (defnScope.getFunctionNames().contains(name))
				break;
			defnScope = parentScope;
			parentScope = defnScope.getParentScope();
		}
		return defnScope;
	}

	/**
	 * Computes the linkage kind of any function declaration node. This is
	 * computed as follows:
	 * <ul>
	 * <li>if the node is a function parameter declaration, NO linkage</li>
	 * <li>if the node is not in a block or file scope, NO linkage</li>
	 * <li>if the declaration contains "static" then INTERNAL linkage (but an
	 * error if analyzing in C mode and in block scope)</li>
	 * <li>otherwise, if there is a previous visible declaration of this
	 * identifier, and the previous linkage is INTERNAL or EXTERNAL, then return
	 * the previous linkage</li>
	 * <li>otherwise, EXTERNAL linkage.</li>
	 * </ul>
	 * 
	 * @param node
	 *            the function declaration node
	 * @return the kind of linkage
	 * @throws SyntaxException
	 *             if this analysis is taking place in C (not CIVL-C) mode and
	 *             the declaration "static" is used in a block scope
	 */
	private LinkageKind computeLinkageOfFunction(OrdinaryDeclarationNode node)
			throws SyntaxException {
		Scope scope = node.getScope();
		ScopeKind scopeKind = scope.getScopeKind();

		if (scopeKind != ScopeKind.BLOCK && scopeKind != ScopeKind.FILE)
			return LinkageKind.NONE;
		if (node.hasStaticStorage()) {
			if (scopeKind == ScopeKind.BLOCK && !civl())
				throw error("C11 6.7.1(7) states: \"The declaration of an "
						+ " identifier for a function that has block scope shall "
						+ "have no explicit storage-class specifier other than extern.\"",
						node);
			return LinkageKind.INTERNAL;
		}

		IdentifierNode identifier = node.getIdentifier();

		if (identifier == null)
			error("Function declaration missing identifier", node);

		String name = identifier.name();

		assert name != null;

		OrdinaryEntity previous = scope.getLexicalOrdinaryEntity(false, name);

		if (previous == null) {
			return LinkageKind.EXTERNAL;
		} else {
			LinkageKind previousLinkage = previous.getLinkage();

			if (previousLinkage == LinkageKind.INTERNAL
					|| previousLinkage == LinkageKind.EXTERNAL)
				return previousLinkage;
			else
				return LinkageKind.EXTERNAL;
		}
	}

	// an object which is not function type
	private LinkageKind computeLinkageOfObject(OrdinaryDeclarationNode node,
			boolean isParameter) {
		if (isParameter)
			return LinkageKind.NONE;

		IdentifierNode identifier = node.getIdentifier();
		Scope scope = node.getScope();
		boolean isFileScope = scope.getScopeKind() == ScopeKind.FILE;

		if (identifier == null)
			return LinkageKind.NONE;
		if (isFileScope && node.hasStaticStorage()) {
			return LinkageKind.INTERNAL;
		}
		if (node.hasExternStorage()) {
			OrdinaryEntity previous = scope.getLexicalOrdinaryEntity(false,
					identifier.name());

			if (previous == null) {
				return LinkageKind.EXTERNAL;
			} else {
				LinkageKind previousLinkage = previous.getLinkage();

				if (previousLinkage == LinkageKind.INTERNAL
						|| previousLinkage == LinkageKind.EXTERNAL)
					return previousLinkage;
				else
					return LinkageKind.EXTERNAL;
			}
		}
		if (isFileScope && hasNoStorageClass(node))
			return LinkageKind.EXTERNAL;
		return LinkageKind.NONE;
	}

	/**
	 * <p>
	 * Computes the linkage specified by an ordinary declaration. See C11 6.2.2
	 * for the rules on determining linkage.
	 * </p>
	 * 
	 * <p>
	 * Note: "The declaration of an identifier for a function that has block
	 * scope shall have no explicit storage-class specifier other than extern."
	 * (C11 6.7.1(7)).
	 * </p>
	 * 
	 * @param node
	 *            an ordinary declaration
	 * @return the kind of linkage
	 * @throws SyntaxException
	 *             if the language is C and this is the declaration of a
	 *             block-scope function and the declaration contains a storage
	 *             class specifier that is not "extern". (This is prohibited by
	 *             C11, but is allowed in CIVL-C.)
	 */
	private LinkageKind computeLinkage(OrdinaryDeclarationNode node,
			boolean isParameter, Type type) throws SyntaxException {
		if (type.kind() == TypeKind.FUNCTION)
			return computeLinkageOfFunction(node);
		else
			return computeLinkageOfObject(node, isParameter);
	}

	// /**
	// * <p>
	// * Processes an ordinary declaration, i.e., one which declares a variable
	// or
	// * function (and not a structure/union member, enumerator, or typedef),
	// and
	// * returns the corresponding {@link Entity}. Does all of the following:
	// * </p>
	// *
	// * <ul>
	// * <li>processes the declaration node's type node</li>
	// * <li>if the declaration node's identifier is <code>null</code>, returns
	// * <code>null</code></li>
	// * <li>if the declared {@link Entity} has not yet been encountered, an
	// * {@link Entity} object is created and added to the appropriate scope.
	// The
	// * new entity will have type and linkage as specified by the declaration.
	// * </li>
	// * <li>if on the other hand the entity already exists, the declaration's
	// * linkage is checked for consistency with that of the existing entity,
	// the
	// * entity's type is updated to be the composite type of its current type
	// and
	// * the type of the declaration</li>
	// * <li>in either case, the declaration node and its identifier node will
	// * have the entity field set, and this method returns the entity (old or
	// * new).</li>
	// * <li>if this declares a function called "main", the AST to which the
	// * declaration node belong has its "main function" field set to the
	// function
	// * entity.</li>
	// * </ul>
	// *
	// * <p>
	// * Note: This method does not do everything needed to process an ordinary
	// * declaration. It just does the stuff that is common to both an object
	// and
	// * function declaration.
	// * </p>
	// *
	// * <p>
	// * Note that an entity can belong to multiple scopes! It is added to every
	// * scope in which it is declared. An {@link Entity} with no linkage can
	// * belong to only one scope. An {@link Entity} with internal or external
	// * linkage can belong to multiple scopes.
	// * </p>
	// *
	// *
	// * @param node
	// * the declaration node
	// * @param isParameter
	// * is the declaration the declaration of a function parameter?
	// * @throws SyntaxException
	// * if the type or linkage specified by the declaration node is
	// * not compatible with that of earlier declarations
	// */
	// public OrdinaryEntity processOrdinaryDeclaration(
	// OrdinaryDeclarationNode node, boolean isParameter)
	// throws SyntaxException {
	// TypeNode typeNode = node.getTypeNode();
	// Type type = entityAnalyzer.typeAnalyzer.processTypeNode(typeNode,
	// isParameter);
	//
	// if (type.kind() == TypeKind.FUNCTION)
	// return processFunctionDeclaration(node, isParameter, type);
	// else
	// return processVariableDeclaration(node, isParameter, type);
	// }

	/**
	 * Checks consistency of library names between a {@link Function} and a
	 * function declaration. If both specify system functions and the library
	 * names of those system functions are not equal, an exception is thrown. If
	 * either is not a system function, or if the library names are equal, a
	 * no-op.
	 * 
	 * @param functionNode
	 *            a declaration of a function
	 * @param entity
	 *            a function entity
	 * @throws SyntaxException
	 *             if the declaration indicates it is a system function
	 *             declaration and <code>entity</code> is a system function and
	 *             the library names of those two system functions differ
	 */
	private void checkSystemLibraryForFunction(
			FunctionDeclarationNode functionNode, Function entity)
			throws SyntaxException {
		String entityLib = entity.systemLibrary();

		if (entityLib != null) {
			String funcLib = functionNode.getSystemLibrary();

			if (funcLib != null)
				if (!entityLib.equals(funcLib))
					throw error(
							"Disagreement on system library between two declarations of a system function",
							functionNode);
		}
	}

	/**
	 * Given a type node and an existing {@link Function} or {@link Variable}
	 * entity, this method adds the type specified by the type node to the
	 * existing type of the entity. By "add" we mean it forms the "composite
	 * type" and updates the type of the entity to that composite type.
	 * 
	 * @param typeNode
	 *            a type node
	 * @param entity
	 *            a {@link Function} or {@link Variable}
	 * @throws SyntaxException
	 *             if the type specified by the type node and the type of the
	 *             entity are not compatible
	 */
	private void addTypeToVariableOrFunction(TypeNode typeNode,
			OrdinaryEntity entity) throws SyntaxException {
		if (typeNode != null) {
			Type type = typeNode.getType();
			Type oldType = entity.getType();

			if (type == null)
				throw error("Internal error: type not processed", typeNode);
			if (oldType == null)
				entity.setType(type);
			else {
				if (!oldType.compatibleWith(type))
					throw error(
							"Redeclaration of entity with incompatible type: "
									+ entity.getName() + "\nOriginal type: "
									+ oldType + "\nNew type: " + type,
							typeNode);
				entity.setType(entityAnalyzer.typeFactory.compositeType(oldType,
						type));
			}
		}
	}

	/**
	 * <p>
	 * Adds a declaration of a variable to that variable.
	 * </p>
	 * 
	 * <p>
	 * Preconditions: the {@link TypeNode} of <code>declaration</code> has
	 * already been processed and its {@link Type} set. If the declaration has a
	 * non-<code>null</code> {@link InitializerNode}, the initializer node has
	 * been processed. The linkage of <code>variable</code> has been set
	 * appropriately.
	 * </p>
	 * 
	 * <p>
	 * Each variable maintains a list of all of its declarations. This method
	 * will do the following: (1) if the initializer is present, checks that
	 * there is no previous initializer for <code>variable</code>, and then make
	 * this declaration the definition. (2) if the initializer is not present
	 * but the linkage of <code>variable</code> is {@link LinkageKind#NONE}, the
	 * declaration is also the definition and the definition of the variable is
	 * set to the declaration as well. (3) the alignment specifiers of the
	 * declaration are processed and added to the variable's lists.
	 * </p>
	 * 
	 * @param variable
	 *            a non-<code>null</code> {@link Variable}
	 * @param declaration
	 *            a declaration of <code>variable</code>
	 * @throws SyntaxException
	 *             if the type of <code>declaration</code> is incompatible with
	 *             that of <code>variable</code>
	 */
	private void addDeclarationToVariable(Variable variable,
			VariableDeclarationNode declaration) throws SyntaxException {
		InitializerNode initializer = declaration.getInitializer();
		SequenceNode<TypeNode> typeAlignmentSpecifiers = declaration
				.typeAlignmentSpecifiers();
		SequenceNode<ExpressionNode> constantAlignmentSpecifiers = declaration
				.constantAlignmentSpecifiers();

		if (initializer != null) {
			InitializerNode oldInitializer = variable.getInitializer();

			if (oldInitializer != null)
				throw error("Re-initialization of variable "
						+ variable.getName() + ". First was at "
						+ oldInitializer.getSource() + ".", initializer);
			variable.setInitializer(initializer);
			variable.setDefinition(declaration);
			declaration.setIsDefinition(true);
		} else if (variable.getLinkage() == LinkageKind.NONE) {
			variable.setDefinition(declaration);
			declaration.setIsDefinition(true);
		}
		if (typeAlignmentSpecifiers != null) {
			for (TypeNode child : typeAlignmentSpecifiers)
				variable.addTypeAlignment(
						entityAnalyzer.typeAnalyzer.processTypeNode(child));
		}
		if (constantAlignmentSpecifiers != null) {
			for (ExpressionNode expression : constantAlignmentSpecifiers) {
				Value constant = entityAnalyzer.valueOf(expression);

				if (constant == null)
					throw error("Value for enumerator must be constant",
							expression);
				variable.addConstantAlignment(constant);
			}
		}
		// TODO: set storage duration. See C11 Sec. 6.2.4.
		variable.addDeclaration(declaration);
	}

	/**
	 * <p>
	 * Adds a declaration of a function to the {@link Function} entity. Each
	 * {@link Entity} maintains a list of the declarations of that entity. This
	 * method adds the given declaration to that list.
	 * </p>
	 * 
	 * <p>
	 * It also does the following:
	 * </p>
	 * 
	 * <p>
	 * If this is the first declaration of the function, it sets the flags for
	 * the inline, Noreturn, Atomic, and CIVL's "system" function specifiers in
	 * the {@link Function} to the values specified in the declaration.
	 * </p>
	 * 
	 * <p>
	 * If this is not the first declaration of the function, this method checks
	 * that the Noreturn specifiers on the previous declaration and this
	 * declaration agree.
	 * </p>
	 * 
	 * <p>
	 * If this is a function definition (not just declaration), this method
	 * checks that there is no previous definition of this function (a function
	 * can have only one definition). It then sets the definition field of the
	 * {@link Function} to this declaration.
	 * </p>
	 * 
	 * @param function
	 *            the {@link Function} entity
	 * @param declaration
	 *            a declaration of that function
	 * @throws SyntaxException
	 *             if there is disagreement on the Noreturn specifier among the
	 *             declarations of the function, or if this is a second
	 *             definition of that function
	 */
	private void addDeclarationToFunction(Function function,
			FunctionDeclarationNode declaration) throws SyntaxException {
		Iterator<DeclarationNode> declarationIter = function.getDeclarations()
				.iterator();

		if (!declarationIter.hasNext()) {
			if (declaration.hasInlineFunctionSpecifier())
				function.setIsInlined(true);
			if (declaration.hasNoreturnFunctionSpecifier())
				function.setDoesNotReturn(true);
			if (declaration.hasAtomicFunctionSpecifier())
				function.setAtomic(true);
			if (declaration.hasSystemFunctionSpecifier()) {
				function.setSystemFunction(true);
				if (declaration.getSystemLibrary() != null)
					function.setSystemLibrary(declaration.getSystemLibrary());
			}
			if (declaration.hasStatefFunctionSpecifier())
				function.setStateFunction(true);
			if (declaration.hasPureFunctionSpecifier())
				function.setPure(true);
			if (declaration instanceof AbstractFunctionDefinitionNode)
				function.setAbstract(true);
		} else if (declaration.hasNoreturnFunctionSpecifier() != function
				.doesNotReturn()) {
			// all declarations must agree on the Noreturn specifier...
			throw error(
					"Disagreement on Noreturn function specifier at function declaration.\n"
							+ "  Previous declaration was at "
							+ declarationIter.next().getSource(),
					declaration);
		}
		if (declaration instanceof FunctionDefinitionNode) {
			FunctionDefinitionNode previousDefinition = function
					.getDefinition();

			if (previousDefinition != null)
				throw error(
						"Redefinition of function.  Previous definition was at "
								+ previousDefinition.getSource(),
						declaration);
			function.setDefinition(declaration);
		}
		function.addDeclaration(declaration);
	}

	private boolean hasNoStorageClass(OrdinaryDeclarationNode node) {
		if (node.hasExternStorage() || node.hasStaticStorage())
			return false;
		if (node instanceof VariableDeclarationNode)
			return !(((VariableDeclarationNode) node).hasRegisterStorage()
					|| ((VariableDeclarationNode) node).hasAutoStorage());
		return true;
	}

	/**
	 * Processes all the "goto" nodes that are in the sub-tree rooted at
	 * <code>node</code>. The {@link IdentifierNode}s in those goto statements
	 * have their entity fields set to the {@link Label} entity specified by the
	 * identifier.
	 * 
	 * @param node
	 *            a node in the AST
	 * @throws SyntaxException
	 *             if a "goto" statement refers to a label which does not exist
	 */
	private void processGotos(ASTNode node) throws SyntaxException {
		Iterable<ASTNode> childIter = node.children();

		if (node instanceof GotoNode) {
			IdentifierNode identifier = ((GotoNode) node).getLabel();
			String name = identifier.name();
			Scope scope = node.getScope();
			Label label = scope.getLexicalLabel(name);

			if (label == null)
				throw error("Goto statement refers to non-existent label",
						identifier);
			identifier.setEntity(label);
		}
		for (ASTNode child : childIter) {
			if (child != null)
				processGotos(child);
		}
	}

	/**
	 * Is the language being processed CIVL-C?
	 * 
	 * @return <code>true</code> iff the language is CIVL-C
	 */
	private boolean civl() {
		return entityAnalyzer.language == Language.CIVL_C;
	}

}