OpenMP2CIVLWorker.java

package edu.udel.cis.vsl.civl.transform.common;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.NoSuchElementException;

import edu.udel.cis.vsl.abc.ast.IF.AST;
import edu.udel.cis.vsl.abc.ast.IF.ASTFactory;
import edu.udel.cis.vsl.abc.ast.entity.IF.Entity;
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.ASTNode.NodeKind;
import edu.udel.cis.vsl.abc.ast.node.IF.IdentifierNode;
import edu.udel.cis.vsl.abc.ast.node.IF.NodePredicate;
import edu.udel.cis.vsl.abc.ast.node.IF.PairNode;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.compound.CompoundInitializerNode;
import edu.udel.cis.vsl.abc.ast.node.IF.compound.DesignationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.DeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.FieldDeclarationNode;
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.TypedefDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.VariableDeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.CompoundLiteralNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.ExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.FunctionCallNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.IdentifierExpressionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.IntegerConstantNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.OperatorNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.OperatorNode.Operator;
import edu.udel.cis.vsl.abc.ast.node.IF.label.SwitchLabelNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpDeclarativeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpExecutableNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpForNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpParallelNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpReductionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpSymbolReductionNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpSyncNode;
import edu.udel.cis.vsl.abc.ast.node.IF.omp.OmpWorksharingNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.AtomicNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.BlockItemNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.CivlForNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.CompoundStatementNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.DeclarationListNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.ExpressionStatementNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.ForLoopInitializerNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.ForLoopNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.IfNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.LoopNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.StatementNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.ArrayTypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.FunctionTypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.PointerTypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.StructureOrUnionTypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypeNode;
import edu.udel.cis.vsl.abc.ast.node.IF.type.TypedefNameNode;
import edu.udel.cis.vsl.abc.ast.type.IF.ArrayType;
import edu.udel.cis.vsl.abc.ast.type.IF.Field;
import edu.udel.cis.vsl.abc.ast.type.IF.PointerType;
import edu.udel.cis.vsl.abc.ast.type.IF.QualifiedObjectType;
import edu.udel.cis.vsl.abc.ast.type.IF.StandardBasicType;
import edu.udel.cis.vsl.abc.ast.type.IF.StandardBasicType.BasicTypeKind;
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.front.IF.CivlcTokenConstant;
import edu.udel.cis.vsl.abc.front.c.parse.COmpParser;
import edu.udel.cis.vsl.abc.token.IF.Source;
import edu.udel.cis.vsl.abc.token.IF.SyntaxException;
import edu.udel.cis.vsl.civl.config.IF.CIVLConfiguration;
import edu.udel.cis.vsl.civl.config.IF.CIVLConstants;
import edu.udel.cis.vsl.civl.model.IF.CIVLSyntaxException;
import edu.udel.cis.vsl.civl.model.IF.CIVLUnimplementedFeatureException;
import edu.udel.cis.vsl.civl.transform.IF.OpenMP2CIVLTransformer;
import edu.udel.cis.vsl.civl.util.IF.Pair;
import edu.udel.cis.vsl.civl.util.IF.Triple;

/**
 * See
 * 
 * https://vsl.cis.udel.edu/trac/civl/wiki/OpenMPTransformation
 * 
 * for documentation on this transformation.
 * 
 *
 */
public class OpenMP2CIVLWorker extends BaseWorker {

	/*
	 * ************************** Private Static Fields **********************
	 */

	final static String OMP_HEADER = "omp.h";

	private final static String OMP_SET_LOCK = "omp_set_lock";

	private final static String OMP_UNSET_LOCK = "omp_unset_lock";

	private final static String OMPPRE = "_omp_";

	/**
	 * The name of the identifier of the $omp_gteam variable in the final CIVL
	 * program.
	 */
	private final static String GTEAM = "_omp_gteam";

	/**
	 * The name of the identifier of the $omp_team variable in the final CIVL
	 * program.
	 */
	private final static String TEAM = "_omp_team";

	/**
	 * The name of $omp_gteam type in the final CIVL-C program.
	 */
	private final static String GTEAM_TYPE = "$omp_gteam";

	/**
	 * The name of $omp_team type in the final CIVL-C program.
	 */
	private final static String TEAM_TYPE = "$omp_team";

	/**
	 * The name of the function to create a new $omp_gws object in the final
	 * CIVL-C program.
	 */
	private final static String GTEAM_CREATE = "$omp_gteam_create";

	/**
	 * The name of the function to create a new $omp_ws object in the final
	 * CIVL-C program.
	 */
	private final static String TEAM_CREATE = "$omp_team_create";

	/**
	 * The name of $omp_gshared type in the final CIVL-C program.
	 */
	private static String GSHARED_TYPE = "$omp_gshared";

	/**
	 * The name of $omp_shared type in the final CIVL-C program.
	 */
	private static String SHARED_TYPE = "$omp_shared";

	/**
	 * The name of the function to create a new $omp_gshared object in the final
	 * CIVL-C program.
	 */
	private static String GSHARED_CREATE = "$omp_gshared_create";

	/**
	 * The name of the function to create a new $omp_shared object in the final
	 * CIVL-C program.
	 */
	private static String SHARED_CREATE = "$omp_shared_create";

	/**
	 * The name of the input variable denoting the number of OpenMP threads in
	 * the final CIVL-C program.
	 */
	private final static String NTHREADS = "_omp_nthreads";

	/**
	 * The name of the input variable denoting the number of OpenMP threads in
	 * the final CIVL-C program.
	 */
	private final static String THREADMAX = "_omp_thread_max";

	/**
	 * The name of the variable denoting the thread number in the CIVL_C
	 * program.
	 */
	private final static String TID = "_omp_tid";

	/* **************************** Instance Fields ************************* */
	/**
	 * Variable that is increment for naming of temp variables that are created
	 */
	private int tmpCount = 0;

	private int tempWriteCount = 0;

	/**
	 * Counter for locating $omp_arrive_loop functions
	 */
	private int ompArriveLoopCounter = 0;

	/**
	 * Counter for locating $omp_arrive_sections functions
	 */
	private int ompArriveSections = 0;

	/**
	 * Counter for locating $omp_arrive_single functions
	 */
	private int ompArriveSingle = 0;

	/**
	 * If the same variable is replaced in the same expression then use the temp
	 * name of the first one
	 */
	private ArrayList<Triple<String, StatementNode, String>> sharedReplaced = new ArrayList<Triple<String, StatementNode, String>>();

	SequenceNode<BlockItemNode> root;

	/**
	 * For each critical section encountered, create a new critical variable
	 */
	private ArrayList<String> criticalNames = new ArrayList<String>();
	private HashMap<ASTNode, ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>> sharedRead = new HashMap<ASTNode, ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>>();
	private HashMap<ASTNode, ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>> sharedWrite = new HashMap<ASTNode, ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>>();
	private ArrayList<TypedefDeclarationNode> structsDefsToAdd = new ArrayList<TypedefDeclarationNode>();
	private ArrayList<StructureOrUnionTypeNode> structsToAdd = new ArrayList<StructureOrUnionTypeNode>();
	private ArrayList<Triple<BlockItemNode, IdentifierNode, String>> tempVars = new ArrayList<Triple<BlockItemNode, IdentifierNode, String>>();

	private int lastLoopVar = -1;

	/**
	 * The command line configuration information.
	 */
	private CIVLConfiguration config;

	/* ****************************** Constructor ************************** */
	/**
	 * Creates a new instance of OpenMP2CIVLTransformer.
	 * 
	 * @param astFactory
	 *            The ASTFactory that will be used to create new nodes.
	 */
	public OpenMP2CIVLWorker(ASTFactory astFactory, CIVLConfiguration config) {
		super(OpenMP2CIVLTransformer.LONG_NAME, astFactory);
		this.identifierPrefix = "$omp_";
		this.config = config;
	}

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

	private void processOmpLockCalls(ASTNode node) {
		for (ASTNode child : node.children()) {
			if (child == null)
				continue;
			if (child instanceof FunctionCallNode) {
				FunctionCallNode funcCall = (FunctionCallNode) child;
				if (funcCall
						.getFunction() instanceof IdentifierExpressionNode) {
					SequenceNode<ExpressionNode> newArgs;
					IdentifierNode name = ((IdentifierExpressionNode) funcCall
							.getFunction()).getIdentifier();

					if (name.name().equals(OMP_SET_LOCK)
							|| name.name().equals(OMP_UNSET_LOCK)) {
						ExpressionNode oldArg = funcCall.getArgument(0);

						name.setName("$" + name.name());
						oldArg.parent().removeChild(oldArg.childIndex());
						newArgs = nodeFactory
								.newSequenceNode(
										this.newSource(
												"actual parameter list of "
														+ name,
												CivlcTokenConstant.ARGUMENT_LIST),
										"Actual parameters",
										Arrays.asList(oldArg,
												this.identifierExpression(
														this.newSource(TEAM,
																CivlcTokenConstant.IDENTIFIER),
														TEAM)));
						funcCall.setArguments(newArgs);
					}

				}

			}
			processOmpLockCalls(child);
		}
	}

	/**
	 * Creates the declaration node for the input variable
	 * <code>_omp_thread_max</code>.
	 * 
	 * @param range
	 *            a source object specifying a specific range in the original
	 *            source into which the new declaration is going to be inserted;
	 *            the line numbers of this range will be included in output to
	 *            give an idea of the location into which the generated text was
	 *            inserted. It is probably somewhere near the beginning of the
	 *            file.
	 * 
	 * @return The declaration node of the input variable
	 *         <code>_omp_thread_max</code>.
	 */
	private VariableDeclarationNode threadMaxDeclaration() {
		final String place = "threadMaxDeclaration";
		TypeNode nthreadsType = nodeFactory.newBasicTypeNode(
				newSource(place, CivlcTokenConstant.INT), BasicTypeKind.INT);
		IdentifierNode identifierNode = nodeFactory.newIdentifierNode(
				newSource(place, CivlcTokenConstant.IDENTIFIER), THREADMAX);

		nthreadsType.setInputQualified(true);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				identifierNode, nthreadsType);
	}

	/**
	 * Creates the declaration node for the variable <code>gteam</code> , which
	 * is of <code>$omp_gteam</code> type and has an initializer to call
	 * <code>$omp_gteam_create()</code>. That is:
	 * <code>$omp_gteam gteam = $omp_gteam_create($here, NTHREADS)</code> .
	 * 
	 * @return The declaration node of the variable <code>gteam</code>.
	 */
	private VariableDeclarationNode gteamDeclaration() {
		TypeNode gteamType;
		ExpressionNode gteamCreate;
		final String place = "gteamDeclaration";
		gteamType = nodeFactory.newTypedefNameNode(
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.TYPE), GTEAM_TYPE),
				null);
		gteamCreate = nodeFactory.newFunctionCallNode(
				newSource(place, CivlcTokenConstant.CALL),
				this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						GTEAM_CREATE),
				Arrays.asList(
						nodeFactory.newHereNode(
								newSource(place, CivlcTokenConstant.HERE)),
						this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								NTHREADS)),
				null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.IDENTIFIER), GTEAM),
				gteamType, gteamCreate);
	}

	/**
	 * Creates the declaration node for the variable <code>team</code> , which
	 * is of <code>$omp_team</code> type and has an initializer to call
	 * <code>$omp_team_create()</code>. That is:
	 * <code>$omp_team team = $omp_team_create($here, gteam, _tid)</code> .
	 * 
	 * @return The declaration node of the variable <code>team</code>.
	 */
	private VariableDeclarationNode teamDeclaration() {
		TypeNode teamType;
		ExpressionNode teamCreate;
		final String place = "teamDelcaration";

		teamType = nodeFactory.newTypedefNameNode(
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.TYPE), TEAM_TYPE),
				null);
		teamCreate = nodeFactory.newFunctionCallNode(
				newSource(place, CivlcTokenConstant.CALL),
				this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						TEAM_CREATE),
				Arrays.asList(
						nodeFactory.newHereNode(
								newSource(place, CivlcTokenConstant.HERE)),
						this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								GTEAM),
						this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								TID)),
				null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.IDENTIFIER), TEAM),
				teamType, teamCreate);
	}

	/**
	 * Creates the declaration node for the variable <code>gshared</code>, which
	 * is of <code>$omp_gshared</code> type and has an initializer to call
	 * <code>$omp_gshared_create()</code>. That is: <code>$omp_gshared 
	 * x_gshared = $omp_gshared_create($omp_gteam, void *original)</code> .
	 * 
	 * @return The declaration node of the variable <code>x_gshared</code>.
	 */
	private VariableDeclarationNode gsharedDeclaration(
			IdentifierNode variable) {
		TypeNode gsharedType;
		ExpressionNode gsharedCreate;
		final String place = variable + "_gsharedDeclaration";

		TypeNode currentType = ((VariableDeclarationNode) ((Variable) variable
				.getEntity()).getFirstDeclaration()).getTypeNode().copy();

		ExpressionNode addressOf = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						variable.name())));

		gsharedType = nodeFactory.newTypedefNameNode(nodeFactory
				.newIdentifierNode(newSource(place, CivlcTokenConstant.TYPE),
						GSHARED_TYPE),
				null);

		if (currentType.isRestrictQualified() || currentType.isInputQualified()
				|| currentType.isVolatileQualified()) {
			addressOf = nodeFactory
					.newCastNode(newSource(place, CivlcTokenConstant.CAST),
							nodeFactory.newPointerTypeNode(
									newSource(place, CivlcTokenConstant.TYPE),
									nodeFactory.newVoidTypeNode(newSource(place,
											CivlcTokenConstant.VOID))),
							addressOf);
		}

		gsharedCreate = nodeFactory
				.newFunctionCallNode(
						newSource(place,
								CivlcTokenConstant.CALL),
						this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								GSHARED_CREATE),
						Arrays.asList(this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								GTEAM), addressOf),
						null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						OMPPRE + variable.name() + "_gshared"),
				gsharedType, gsharedCreate);
	}

	/**
	 * Creates the declaration node for the variable <code>shared</code>, which
	 * is of <code>$omp_shared</code> type and has an initializer to call
	 * <code>$omp_shared_create()</code>. That is: <code>$omp_shared 
	 * x_shared = $omp_shared_create($omp_team team, $omp_gshared gshared, 
	 * void *local, void *status)</code> .
	 * 
	 * @return The declaration node of the variable <code>x_shared</code>.
	 */
	private VariableDeclarationNode sharedDeclaration(IdentifierNode variable) {
		TypeNode sharedType;
		ExpressionNode sharedCreate;
		final String place = variable + "_sharedDeclaration";

		TypeNode currentType = ((VariableDeclarationNode) ((Variable) variable
				.getEntity()).getFirstDeclaration()).getTypeNode().copy();

		sharedType = nodeFactory.newTypedefNameNode(
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.TYPE), SHARED_TYPE),
				null);
		ExpressionNode addressOfLocalVar = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						OMPPRE + variable.name() + "_local")));
		ExpressionNode addressOfStatusVar = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						OMPPRE + variable.name() + "_status")));

		if (currentType.isRestrictQualified()
				|| currentType.isVolatileQualified()) {
			addressOfLocalVar = nodeFactory
					.newCastNode(newSource(place, CivlcTokenConstant.CAST),
							nodeFactory.newPointerTypeNode(
									newSource(place, CivlcTokenConstant.TYPE),
									nodeFactory.newVoidTypeNode(newSource(place,
											CivlcTokenConstant.VOID))),
							addressOfLocalVar);
		}

		sharedCreate = nodeFactory
				.newFunctionCallNode(newSource(place, CivlcTokenConstant.CALL),
						this.identifierExpression(newSource(place,
								CivlcTokenConstant.IDENTIFIER), SHARED_CREATE),
						Arrays.asList(
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										TEAM),
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										OMPPRE + variable.name() + "_gshared"),
								addressOfLocalVar, addressOfStatusVar),
						null);

		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						OMPPRE + variable.name() + "_shared"),
				sharedType, sharedCreate);
	}

	/**
	 * Creates the function call node for <code>destroy</code>, which is of void
	 * type. That is: <code>$omp_(g)team_destroy($omp_(g)team (g)team)
	 * </code> . This can be used to destroy gteam or team depending in the type
	 * parameter
	 * 
	 * @return The function call node of <code>$omp_(g)team_destroy</code>.
	 */
	private ExpressionStatementNode destroy(String type, String object) {
		final String place = "destroyCall";
		ExpressionNode function = this.identifierExpression(
				newSource(place, CivlcTokenConstant.IDENTIFIER),
				"$omp_" + type + "_destroy");

		return nodeFactory
				.newExpressionStatementNode(nodeFactory.newFunctionCallNode(
						newSource(place, CivlcTokenConstant.CALL), function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								object)),
						null));
	}

	/**
	 * Creates the function call node for <code>barrier_and_flush</code>, which
	 * is of void type. That is:
	 * <code>$omp_barrier_and_flush($omp_team team) </code> . This is used as a
	 * barrier and a flush on all shared objects owned by the team
	 * 
	 * @return The function call node of <code>$omp_barrier_and_flush</code>.
	 */
	private ExpressionStatementNode barrierAndFlush(String object) {
		final String place = "barrierAndFlushCall";
		ExpressionNode function = this.identifierExpression(
				newSource(place, CivlcTokenConstant.IDENTIFIER),
				"$omp_barrier_and_flush");

		return nodeFactory
				.newExpressionStatementNode(nodeFactory.newFunctionCallNode(
						newSource(place, CivlcTokenConstant.CALL), function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CivlcTokenConstant.IDENTIFIER),
								object)),
						null));
	}

	/**
	 * Creates the function call node for <code>write</code>, which is of void
	 * type. That is: <code> $omp_write($omp_shared shared, 
	 * void *ref, void *value)</code> . This is used to write to shared
	 * variables.
	 * 
	 * @return The function call node of <code>$omp_write</code>.
	 */
	private ExpressionStatementNode write(ExpressionNode variable,
			String sharedName, ExpressionNode writeName, Type origType) {
		final String place = sharedName + "_sharedWriteCall";
		ExpressionNode function = this.identifierExpression(
				newSource(place, CivlcTokenConstant.IDENTIFIER), "$omp_write");
		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF, Arrays.asList(variable));

		if (origType instanceof QualifiedObjectType
				&& ((QualifiedObjectType) origType).isVolatileQualified()) {
			addressOfVar = nodeFactory
					.newCastNode(newSource(place, CivlcTokenConstant.CAST),
							nodeFactory.newPointerTypeNode(
									newSource(place, CivlcTokenConstant.TYPE),
									nodeFactory.newVoidTypeNode(newSource(place,
											CivlcTokenConstant.VOID))),
							addressOfVar);
		}

		ExpressionNode addressOfTmp = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF, Arrays.asList(writeName));
		return nodeFactory
				.newExpressionStatementNode(nodeFactory.newFunctionCallNode(
						newSource(place, CivlcTokenConstant.CALL), function,
						Arrays.asList(
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										OMPPRE + sharedName + "_shared"),
								addressOfVar, addressOfTmp),
						null));
	}

	/**
	 * Creates the function call node for <code>read</code>, which is of void
	 * type. That is: <code> $omp_read($omp_shared shared, 
	 * void *result, void *ref)</code> . This is used to read shared variables.
	 * 
	 * @return The function call node of <code>$omp_read</code>.
	 */
	private ExpressionStatementNode read(ExpressionNode parent,
			String sharedName, String tmpName, Type origType) {
		final String place = sharedName + "_sharedReadCall";
		ExpressionNode function = this.identifierExpression(
				newSource(place, CivlcTokenConstant.IDENTIFIER), "$omp_read");

		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF, Arrays.asList(parent));

		if (origType instanceof QualifiedObjectType
				&& ((QualifiedObjectType) origType).isVolatileQualified()) {
			addressOfVar = nodeFactory
					.newCastNode(newSource(place, CivlcTokenConstant.CAST),
							nodeFactory.newPointerTypeNode(
									newSource(place, CivlcTokenConstant.TYPE),
									nodeFactory.newVoidTypeNode(newSource(place,
											CivlcTokenConstant.VOID))),
							addressOfVar);
		}

		ExpressionNode addressOfTmp = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						tmpName)));
		return nodeFactory
				.newExpressionStatementNode(nodeFactory.newFunctionCallNode(
						newSource(place, CivlcTokenConstant.CALL), function,
						Arrays.asList(
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										OMPPRE + sharedName + "_shared"),
								addressOfTmp, addressOfVar),
						null));
	}

	/**
	 * Creates the function call node for <code>apply_assoc</code>, which is of
	 * void type. That is: <code> $omp_apply_assoc($omp_shared shared, 
	 *  $operation op, void *local)</code> . This is used to apply associated
	 * operators.
	 * 
	 * @return The function call node of <code>$omp_apply_assoc</code>.
	 * @throws SyntaxException
	 */
	private ExpressionStatementNode applyAssoc(String variable,
			String operation) throws SyntaxException {
		final String place = variable + "applyAssoc(" + operation + ")";
		ExpressionNode function = this.identifierExpression(
				newSource(place, CivlcTokenConstant.IDENTIFIER),
				"$omp_apply_assoc");
		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CivlcTokenConstant.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						OMPPRE + variable + "_reduction")));
		if (operation.equals("PLUSEQ")) {
			operation = "CIVL_SUM";
			// op = nodeFactory.newIntegerConstantNode(source, representation)
		}

		return nodeFactory
				.newExpressionStatementNode(nodeFactory.newFunctionCallNode(
						newSource(place, CivlcTokenConstant.CALL), function,
						Arrays.asList(
								this.identifierExpression(newSource(place,
										CivlcTokenConstant.IDENTIFIER),
										OMPPRE + variable + "_shared"),
								nodeFactory.newIntegerConstantNode(
										newSource(place,
												CivlcTokenConstant.INTEGER_CONSTANT),
										"3"),
								addressOfVar),
						null));
	}

	/*
	 * ********************* Methods From TransformerWorker ******************
	 */

	/**
	 * Transform an AST of a OpenMP program in C into an equivalent AST of
	 * CIVL-C program.<br>
	 * 
	 * @param ast
	 *            The AST of the original OpenMP program in C.
	 * @return An AST of CIVL-C program equivalent to the original OpenMP
	 *         program.
	 * @throws SyntaxException
	 */
	@Override
	public AST transform(AST ast) throws SyntaxException {
		if (!this.hasHeader(ast, CIVLConstants.CIVL_OMP_IMP))
			return ast;

		root = ast.getRootNode();

		AST newAst;
		List<BlockItemNode> externalList;
		VariableDeclarationNode threadMax;
		SequenceNode<BlockItemNode> newRootNode;
		List<BlockItemNode> includedNodes = new ArrayList<>();
		// Now related assumes must go tightly with input variable declarations
		// because of the checking of array extent at where they declared:
		List<BlockItemNode> mainParametersAndAssumes = new ArrayList<>();
		int count;
		Triple<List<BlockItemNode>, List<BlockItemNode>, List<BlockItemNode>> result;
		String criticalDeclaration = "criticalDeclarations";

		assert this.astFactory == ast.getASTFactory();
		assert this.nodeFactory == astFactory.getNodeFactory();
		ast.release();

		// declaring $input int _omp_thread_max;
		threadMax = this.threadMaxDeclaration();

		SequenceNode<IdentifierExpressionNode> threadPrivateList;

		List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
		threadPrivateList = nodeFactory.newSequenceNode(
				newSource("threadList", CivlcTokenConstant.ARGUMENT_LIST),
				"threadPrivateList", list);

		// Recursive call to replace all omp code
		replaceOMPPragmas(root, null, null, null, null, threadPrivateList);

		// Add in statements for omp read and writes
		addStatements(sharedWrite, "write");
		addStatements(sharedRead, "read");

		// Eliminate extra barriers
		fix_duplicated_barrier_flush(root, false);

		result = this.program(root);
		includedNodes = result.second;
		mainParametersAndAssumes = result.third;

		externalList = new LinkedList<>();
		count = includedNodes.size();
		// adding nodes from header files.
		for (int i = 0; i < count; i++) {
			externalList.add(includedNodes.get(i));
		}
		count = mainParametersAndAssumes.size();
		// adding nodes from the arguments of the original main function.
		for (int i = 0; i < count; i++) {
			externalList.add(mainParametersAndAssumes.get(i));
		}
		// Add threadMax declaration
		externalList.add(threadMax);
		for (String name : criticalNames) {
			externalList
					.add(nodeFactory.newVariableDeclarationNode(
							newSource(criticalDeclaration,
									CivlcTokenConstant.DECLARATION),
							nodeFactory.newIdentifierNode(
									newSource(criticalDeclaration,
											CivlcTokenConstant.IDENTIFIER),
									name),
							nodeFactory.newBasicTypeNode(
									newSource(criticalDeclaration,
											CivlcTokenConstant.BOOL),
									BasicTypeKind.BOOL),
							nodeFactory.newBooleanConstantNode(
									newSource(criticalDeclaration, 0), false)));
		}

		externalList.addAll(result.first);
		newRootNode = nodeFactory.newSequenceNode(null, "TranslationUnit",
				externalList);
		completeSources(newRootNode);
		this.processOmpLockCalls(newRootNode);
		newAst = astFactory.newAST(newRootNode, ast.getSourceFiles(),
				ast.isWholeProgram());
		/*
		 * boolean ompHeader = false; for (SourceFile sourceFile :
		 * ast.getSourceFiles()) { String filename = sourceFile.getName();
		 * 
		 * if (filename.equals("omp.h")) { ompHeader = true; } } if (!ompHeader)
		 * { // This will also include the CIVLC standard header AST civlcOmpAST
		 * = this .parseSystemLibrary(new File(CPreprocessor.ABC_INCLUDE_PATH,
		 * CIVLConstants.CIVL_OMP), EMPTY_MACRO_MAP); newAst =
		 * this.combineASTs(civlcOmpAST, newAst); }
		 */
		return newAst;
	}

	private void addStatements(
			HashMap<ASTNode, ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>> sharedMap,
			String readWrite) {
		for (ASTNode key : sharedMap.keySet()) {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> statements = sharedMap
					.get(key);
			ASTNode parent = key.parent();
			if (parent instanceof ForLoopNode || parent instanceof IfNode) {
				createBody(key);
				parent = key.parent();
			}
			int index = key.childIndex();
			int i = 0;

			for (Pair<VariableDeclarationNode, ExpressionStatementNode> pair : statements) {
				if (pair.left != null) {
					insertChildAt(index + i, key.parent(), pair.left);
					i++;
				}
			}

			for (Pair<VariableDeclarationNode, ExpressionStatementNode> pair : statements) {
				if (pair.right != null) {
					if (readWrite.equals("write")) {
						insertChildAt(index + i + 1, key.parent(), pair.right);
					} else {
						insertChildAt(index + i, key.parent(), pair.right);

					}
					i++;
				}
			}
		}
	}

	/**
	 * Recursive method to replace all OpenMP pragmas and functions. The type of
	 * the node is checked and if it matches then the code is modified, deleted,
	 * or inserted to create a pure CIVL-C representation.
	 * 
	 * @param node
	 * @param privateIDs
	 * @param sharedIDs
	 * @param reductionIDs
	 * @param firstPrivateIDs
	 * @param threadPrivateIDs
	 * @throws SyntaxException
	 */
	@SuppressWarnings("unchecked")
	private void replaceOMPPragmas(ASTNode node,
			SequenceNode<IdentifierExpressionNode> privateIDs,
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			SequenceNode<IdentifierExpressionNode> reductionIDs,
			SequenceNode<IdentifierExpressionNode> firstPrivateIDs,
			SequenceNode<IdentifierExpressionNode> threadPrivateIDs)
			throws SyntaxException {

		// Check if a pragma is nested inside a parallel. If not then remove
		// the pragma
		if (node instanceof OmpExecutableNode) {
			if (!(node instanceof OmpParallelNode)) {
				// check if node is nested in omp parallel node
				ASTNode parent = node.parent();
				boolean nested = false;
				while (parent != null) {
					parent = parent.parent();
					if (parent instanceof OmpParallelNode) {
						nested = true;
						break;
					}
					if (parent instanceof CivlForNode) {
						if (((CivlForNode) parent).isParallel()) {
							nested = true;
							break;
						}
					}
				}
				if (!nested) {
					if (node instanceof OmpSyncNode) {
						ASTNode body = node.child(7);
						body.remove();
						int index = node.childIndex();
						ASTNode directParent = node.parent();
						node.remove();
						directParent.setChild(index, body);
						return;
					}
				}
			}

		}
		// Check if the node is a parallel node
		if (node instanceof OmpParallelNode) {
			List<BlockItemNode> items;
			CompoundStatementNode pragmaBody;
			VariableDeclarationNode gteamVar;
			SequenceNode<IdentifierExpressionNode> sharedList;
			SequenceNode<IdentifierExpressionNode> privateList;
			SequenceNode<IdentifierExpressionNode> firstPrivateList;
			SequenceNode<IdentifierExpressionNode> reductionList = null;
			SequenceNode<OmpReductionNode> ompReductionNode;
			Iterable<ASTNode> children;
			String parallelNode = "parallelPragma";
			items = new LinkedList<>();
			children = node.children();

			// int _nthreads = 1+$choose_int(_omp_thread_max);
			String nthreadDeclaration = "_nthreadsDeclaration";
			VariableDeclarationNode nthreads;
			ExpressionNode add;
			ExpressionNode numThreads = ((OmpParallelNode) node).numThreads();

			removeNodeFromParent(numThreads);

			// If there is no num_threads clause for the parallel pragma then
			// get the number of threads from the CIVL input.
			if (numThreads == null) {
				numThreads = this.identifierExpression(
						newSource(nthreadDeclaration,
								CivlcTokenConstant.IDENTIFIER),
						OMPPRE + "num_threads");
			}

			add = nodeFactory.newOperatorNode(
					newSource(nthreadDeclaration, CivlcTokenConstant.PLUS),
					Operator.PLUS,
					Arrays.asList(
							nodeFactory.newIntegerConstantNode(
									newSource(nthreadDeclaration,
											CivlcTokenConstant.INTEGER_CONSTANT),
									"1"),
							nodeFactory.newFunctionCallNode(
									newSource(nthreadDeclaration,
											CivlcTokenConstant.CHOOSE),
									this.identifierExpression(
											newSource(nthreadDeclaration,
													CivlcTokenConstant.IDENTIFIER),
											"$choose_int"),
									Arrays.asList(numThreads), null)));

			nthreads = nodeFactory.newVariableDeclarationNode(
					newSource(parallelNode, CivlcTokenConstant.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(nthreadDeclaration,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "nthreads"),
					nodeFactory.newBasicTypeNode(newSource(nthreadDeclaration,
							CivlcTokenConstant.INT), BasicTypeKind.INT),
					add);
			items.add(this.elaborateExpression(numThreads.copy()));
			items.add(nthreads);

			// $range thread_range = 0 .. nthreads-1;
			String threadRangeDeclaration = "thread_rangeDeclaration";
			VariableDeclarationNode threadRange;
			threadRange = nodeFactory.newVariableDeclarationNode(
					newSource(parallelNode, CivlcTokenConstant.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(threadRangeDeclaration,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "thread_range"),
					nodeFactory.newRangeTypeNode(newSource(
							threadRangeDeclaration, CivlcTokenConstant.RANGE)),
					nodeFactory.newRegularRangeNode(
							newSource(threadRangeDeclaration,
									CivlcTokenConstant.RANGE),
							nodeFactory.newIntegerConstantNode(
									newSource(threadRangeDeclaration,
											CivlcTokenConstant.INTEGER_CONSTANT),
									"0"),
							nodeFactory.newOperatorNode(
									newSource(threadRangeDeclaration,
											CivlcTokenConstant.SUB),
									Operator.MINUS,
									Arrays.asList(
											this.identifierExpression(
													newSource(
															threadRangeDeclaration,
															CivlcTokenConstant.IDENTIFIER),
													OMPPRE + "nthreads"),
											nodeFactory.newIntegerConstantNode(
													newSource(
															threadRangeDeclaration,
															CivlcTokenConstant.INTEGER_CONSTANT),
													"1")))));
			items.add(threadRange);

			// $domain(1) dom = ($domain){thread_range};
			String domainDeclaration = "domainDeclaration";
			List<PairNode<DesignationNode, InitializerNode>> initList = new ArrayList<PairNode<DesignationNode, InitializerNode>>();
			initList.add(nodeFactory.newPairNode(
					newSource(domainDeclaration, CivlcTokenConstant.STRUCT),
					(DesignationNode) null,
					(InitializerNode) this.identifierExpression(
							newSource(domainDeclaration,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "thread_range")));
			CompoundInitializerNode temp = nodeFactory
					.newCompoundInitializerNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.INITIALIZER_LIST),
							initList);
			CompoundLiteralNode cln = nodeFactory.newCompoundLiteralNode(
					newSource(domainDeclaration,
							CivlcTokenConstant.COMPOUND_LITERAL),
					nodeFactory.newDomainTypeNode(newSource(domainDeclaration,
							CivlcTokenConstant.DOMAIN)),
					temp);

			VariableDeclarationNode loopDomain;
			loopDomain = nodeFactory.newVariableDeclarationNode(
					newSource(parallelNode, CivlcTokenConstant.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "dom"),
					nodeFactory.newDomainTypeNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.DOMAIN),
							nodeFactory.newIntegerConstantNode(
									newSource(domainDeclaration,
											CivlcTokenConstant.INTEGER_CONSTANT),
									"1")),
					cln);
			items.add(loopDomain);

			// Declaring $omp_gteam gteam = $omp_gteam_create($here, nthreads);
			gteamVar = this.gteamDeclaration();
			items.add(gteamVar);

			// Get list of shared, private, and firstPrivate variables from the
			// OmpParallelNode
			sharedList = ((OmpParallelNode) node).sharedList();
			removeNodeFromParent(sharedList);
			privateList = ((OmpParallelNode) node).privateList();
			removeNodeFromParent(privateList);
			firstPrivateList = ((OmpParallelNode) node).firstprivateList();
			removeNodeFromParent(firstPrivateList);

			// Add implicit shared variables
			ArrayList<String> alreadyDeclVars = new ArrayList<String>();
			alreadyDeclVars.add("stdin");
			alreadyDeclVars.add("stdout");
			alreadyDeclVars.add("stderr");

			// Add varaible to already declared variables to decide what is to
			// be shared or private
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					String c = ((IdentifierExpressionNode) child)
							.getIdentifier().name();
					alreadyDeclVars.add(c);
				}
			}

			if (privateList != null) {
				for (ASTNode child : privateList.children()) {
					String c = ((IdentifierExpressionNode) child)
							.getIdentifier().name();
					alreadyDeclVars.add(c);
				}
			}

			if (threadPrivateIDs != null) {
				for (ASTNode child : threadPrivateIDs.children()) {
					String c = ((IdentifierExpressionNode) child)
							.getIdentifier().name();
					alreadyDeclVars.add(c);
				}
			}

			if (firstPrivateList != null) {
				for (ASTNode child : firstPrivateList.children()) {
					String c = ((IdentifierExpressionNode) child)
							.getIdentifier().name();
					alreadyDeclVars.add(c);
				}
			}

			ArrayList<String> implicitShared = new ArrayList<String>();
			if (sharedList == null) {
				List<IdentifierExpressionNode> list = new LinkedList<>();
				sharedList = nodeFactory.newSequenceNode(
						newSource("sharedList",
								CivlcTokenConstant.ARGUMENT_LIST),
						"sharedList", list);
			}
			ArrayList<String> loopVars = new ArrayList<String>();
			// Get implicit shared variable and remove any that are already
			// declared
			boolean removed = getImplicitShared(sharedList, node,
					alreadyDeclVars, implicitShared, loopVars, false);

			if (removed) {
				List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
				for (IdentifierExpressionNode id : sharedList) {
					if (id != null) {
						ASTNode parent = id.parent();
						int index = id.childIndex();
						parent.removeChild(index);
						list.add(id);
					}
				}
				sharedList = nodeFactory.newSequenceNode(
						newSource("sharedList",
								CivlcTokenConstant.ARGUMENT_LIST),
						"sharedList", list);
			}

			if (privateList == null) {
				List<IdentifierExpressionNode> list = new LinkedList<>();
				privateList = nodeFactory.newSequenceNode(
						newSource("privateList",
								CivlcTokenConstant.ARGUMENT_LIST),
						"privateList", list);
			}

			ArrayList<String> loopVariables = new ArrayList<String>();

			// Get variables from the loop and remove them from the list as
			// they are not to be treated liek shared variables
			getLoopVariables(node, alreadyDeclVars, privateList);
			removed = false;
			for (String varName : loopVariables) {
				for (IdentifierExpressionNode id : sharedList) {
					if (id != null) {
						if (id.getIdentifier().name().equals(varName)) {
							int index = id.childIndex();
							sharedList.removeChild(index);
							removed = true;
						}
					}

				}
			}

			for (IdentifierExpressionNode child : sharedList) {
				IdentifierNode id = child.getIdentifier();
				Type currentType = ((Variable) id.getEntity()).getType();
				if (currentType instanceof StructureOrUnionType) {
					String tag = ((StructureOrUnionType) currentType).getTag();
					if (tag.equals("omp_lock_t")) {
						child.remove();
						removed = true;
					}
				} else if (currentType instanceof QualifiedObjectType) {
					if (((QualifiedObjectType) currentType)
							.isInputQualified()) {
						child.remove();
						removed = true;
					}
				}
			}

			if (removed) {
				List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
				for (IdentifierExpressionNode id : sharedList) {
					if (id != null) {
						ASTNode parent = id.parent();
						int index = id.childIndex();
						parent.removeChild(index);
						list.add(id);
					}
				}
				sharedList = nodeFactory.newSequenceNode(
						newSource("sharedList",
								CivlcTokenConstant.ARGUMENT_LIST),
						"sharedList", list);
			}

			// Get list of reduction variables from the OmpParallelNode
			OmpSymbolReductionNode reductionNode = null;
			ompReductionNode = ((OmpParallelNode) node).reductionList();
			removeNodeFromParent(ompReductionNode);
			if (ompReductionNode != null) {
				reductionNode = (OmpSymbolReductionNode) ompReductionNode
						.child(0);
				reductionList = (SequenceNode<IdentifierExpressionNode>) reductionNode
						.child(0);
			}

			// Declaring $omp_gshared x_gshared = $omp_gshared_create(gteam, &x)
			// for each shared variable "x"
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					if (child != null) {
						VariableDeclarationNode gsharedVar;
						IdentifierNode c = ((IdentifierExpressionNode) child)
								.getIdentifier();

						gsharedVar = this.gsharedDeclaration(c);
						items.add(gsharedVar);
					}
				}
			}

			CivlForNode cfn;

			// Create the ForLoopInitializerNode for the CIVLForNode
			String parFor = "parFor";
			ForLoopInitializerNode initializerNode;
			initializerNode = nodeFactory.newForLoopInitializerNode(
					newSource(parFor, CivlcTokenConstant.INITIALIZER_LIST),
					Arrays.asList(nodeFactory.newVariableDeclarationNode(
							newSource(parFor, CivlcTokenConstant.DECLARATION),
							nodeFactory.newIdentifierNode(
									newSource(parFor,
											CivlcTokenConstant.IDENTIFIER),
									TID),
							nodeFactory.newBasicTypeNode(
									newSource(parFor, CivlcTokenConstant.INT),
									BasicTypeKind.INT))));

			List<BlockItemNode> parForItems = new LinkedList<>();

			// $omp_team team = $omp_team_create($here, gteam, _tid);
			parForItems.add(teamDeclaration());

			// Create local and status variables for each shared variable
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					if (child != null) {
						VariableDeclarationNode localSharedVar;
						VariableDeclarationNode statusSharedVar;

						IdentifierNode c = (IdentifierNode) child.child(0);
						String localDeclaration = "LocalSharedVarDeclaration";
						String statusDeclaration = "StatusSharedVarDeclaration";
						TypeNode privateType = ((VariableDeclarationNode) ((Variable) c
								.getEntity()).getFirstDeclaration())
										.getTypeNode().copy();
						if (privateType.isInputQualified()) {
							privateType.setInputQualified(false);
						}
						IdentifierNode localSharedIdentifer = nodeFactory
								.newIdentifierNode(
										newSource(c.name() + localDeclaration,
												CivlcTokenConstant.IDENTIFIER),
										OMPPRE + c.name() + "_local");
						IdentifierNode statusSharedIdentifer = nodeFactory
								.newIdentifierNode(
										newSource(c.name() + statusDeclaration,
												CivlcTokenConstant.IDENTIFIER),
										OMPPRE + c.name() + "_status");
						Type currentType = ((Variable) c.getEntity()).getType();

						if (privateType instanceof ArrayTypeNode
								&& currentType instanceof PointerType) {
							if (!(((PointerType) currentType)
									.referencedType() instanceof ArrayType)) {
								currentType = ((PointerType) currentType)
										.referencedType();
								while (currentType instanceof ArrayType) {
									currentType = ((ArrayType) currentType)
											.getElementType();
								}
								BasicTypeKind baseTypeKind = ((StandardBasicType) currentType)
										.getBasicTypeKind();

								privateType = nodeFactory.newPointerTypeNode(
										newSource(c.name() + "type",
												CivlcTokenConstant.TYPE),
										nodeFactory.newBasicTypeNode(
												newSource(localDeclaration,
														CivlcTokenConstant.TYPE),
												baseTypeKind));
							}
						}

						localSharedVar = nodeFactory.newVariableDeclarationNode(
								newSource(localDeclaration,
										CivlcTokenConstant.DECLARATION),
								localSharedIdentifer, privateType);

						TypeNode statusType = privateType.copy();
						TypeNode baseStatusType = statusType;

						while (statusType instanceof ArrayTypeNode && statusType
								.child(0) instanceof ArrayTypeNode) {
							statusType = (TypeNode) statusType.child(0);
						}
						if (statusType instanceof ArrayTypeNode) {
							statusType.setChild(0,
									nodeFactory.newBasicTypeNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.INT),
											BasicTypeKind.INT));
							statusSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											statusSharedIdentifer,
											baseStatusType);

						} else if (statusType instanceof PointerTypeNode) {
							statusType.setChild(0,
									nodeFactory.newBasicTypeNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.INT),
											BasicTypeKind.INT));
							statusSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											statusSharedIdentifer,
											baseStatusType);
						} else if (currentType instanceof StructureOrUnionType
								&& statusType instanceof TypedefNameNode) {
							TypedefNameNode status = (TypedefNameNode) statusType
									.copy();
							status.setName(nodeFactory.newIdentifierNode(
									newSource(statusDeclaration,
											CivlcTokenConstant.DECLARATION),
									status.getName().name() + "_status"));
							statusSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											statusSharedIdentifer, status);

							TypedefDeclarationNode structDef = nodeFactory
									.newTypedefDeclarationNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											nodeFactory.newIdentifierNode(
													newSource(statusDeclaration,
															CivlcTokenConstant.DECLARATION),
													status.getName().name()),
											nodeFactory
													.newStructOrUnionTypeNode(
															newSource(
																	statusDeclaration,
																	CivlcTokenConstant.DECLARATION),
															true,
															nodeFactory
																	.newIdentifierNode(
																			newSource(
																					statusDeclaration,
																					CivlcTokenConstant.DECLARATION),
																			status.getName()
																					.name()),
															null));

							boolean toAdd = true;
							for (TypedefDeclarationNode typeDefNode : structsDefsToAdd) {
								if (typeDefNode.getName()
										.equals(structDef.getName())) {
									toAdd = false;
								}
							}
							if (toAdd) {
								structsDefsToAdd.add(structDef);
							}

							StructureOrUnionType structType = (StructureOrUnionType) currentType;
							Iterable<Field> fields = structType.getFields();

							List<FieldDeclarationNode> fieldList = new LinkedList<FieldDeclarationNode>();

							for (Field field : fields) {
								IdentifierNode fieldName = nodeFactory
										.newIdentifierNode(
												newSource(statusDeclaration,
														CivlcTokenConstant.DECLARATION),
												field.getName());

								TypeNode intType = nodeFactory.newBasicTypeNode(
										newSource(statusDeclaration,
												CivlcTokenConstant.INT),
										BasicTypeKind.INT);

								FieldDeclarationNode fieldToAdd = nodeFactory
										.newFieldDeclarationNode(
												newSource(statusDeclaration,
														CivlcTokenConstant.DECLARATION),
												fieldName, intType);

								fieldList.add(fieldToAdd);
							}

							SequenceNode<FieldDeclarationNode> structDeclList = nodeFactory
									.newSequenceNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											"fieldList", fieldList);

							StructureOrUnionTypeNode structTypeToAdd = nodeFactory
									.newStructOrUnionTypeNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											true,
											nodeFactory.newIdentifierNode(
													newSource(statusDeclaration,
															CivlcTokenConstant.DECLARATION),
													status.getName().name()),
											structDeclList);

							toAdd = true;
							for (StructureOrUnionTypeNode typeNode : structsToAdd) {

								if (typeNode.getName()
										.equals(structTypeToAdd.getName())) {
									toAdd = false;
								}

							}
							if (toAdd) {
								structsToAdd.add(structTypeToAdd);
							}

						} else {
							statusSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(statusDeclaration,
													CivlcTokenConstant.DECLARATION),
											statusSharedIdentifer,
											nodeFactory.newBasicTypeNode(
													newSource(statusDeclaration,
															CivlcTokenConstant.INT),
													BasicTypeKind.INT));
						}

						parForItems.add(localSharedVar);
						parForItems.add(statusSharedVar);
					}
				}
			}

			// Declare $omp_shared x_shared = $omp_shared_create(team,
			// x_gshared, void *local, void, *status)
			// for each shared variable "x"
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					if (child != null) {
						VariableDeclarationNode sharedVar;
						IdentifierNode c = ((IdentifierExpressionNode) child)
								.getIdentifier();

						sharedVar = this.sharedDeclaration(c);
						parForItems.add(sharedVar);
					}
				}
			}

			// Add firstprivate variable declarations
			if (firstPrivateList != null) {
				for (ASTNode child : firstPrivateList.children()) {
					VariableDeclarationNode firstPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "first");
					parForItems.add(firstPrivate);
				}
			}

			// Add reduction variable declarations
			if (reductionList != null) {
				for (ASTNode child : reductionList.children()) {
					VariableDeclarationNode localPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "reduction");
					parForItems.add(localPrivate);
				}
			}

			// Declare local copies of the private variables
			if (privateList != null) {
				for (ASTNode child : privateList.children()) {
					VariableDeclarationNode localPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "regular");
					parForItems.add(localPrivate);
				}
			}

			// Add all children to the $par_for body
			int i = 0;
			for (ASTNode child : children) {
				node.removeChild(i);
				parForItems.add((BlockItemNode) child);
				i++;
			}

			// Apply association operator to all reduction variables
			if (reductionList != null) {
				for (ASTNode child : reductionList.children()) {
					String name = ((IdentifierNode) child.child(0)).name();
					String operator = reductionNode.operator().name();
					parForItems.add(applyAssoc(name, operator));
				}
			}

			// $omp_barrier_and_flush(team);
			parForItems.add(barrierAndFlush(TEAM));

			// $omp_shared_destroy(x_shared);
			// for each shared variable "x"
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					if (child != null) {
						IdentifierNode c = ((IdentifierExpressionNode) child)
								.getIdentifier();

						parForItems.add(destroy("shared",
								OMPPRE + c.name() + "_shared"));
					}
				}
			}

			// $omp_team_destroy(team);
			parForItems.add(destroy("team", TEAM));

			StatementNode parForBody;
			parForBody = nodeFactory.newCompoundStatementNode(
					newSource(parFor, CivlcTokenConstant.COMPOUND_STATEMENT),
					parForItems);

			// Create $par_for loop
			cfn = nodeFactory.newCivlForNode(
					newSource(parallelNode, CivlcTokenConstant.CIVLFOR), true,
					(DeclarationListNode) initializerNode,
					this.identifierExpression(
							newSource(parFor, CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "dom"),
					parForBody, null);

			int childrenAdded = items.size();

			// Add $par_for to the body
			items.add(cfn);

			// $omp_shared_destroy(x_gshared);
			// for each shared variable "x"
			if (sharedList != null) {
				for (ASTNode child : sharedList.children()) {
					if (child != null) {
						IdentifierNode c = ((IdentifierExpressionNode) child)
								.getIdentifier();

						items.add(destroy("gshared",
								OMPPRE + c.name() + "_gshared"));
					}
				}
			}

			// $omp_gteam_destroy(gteam);
			items.add(destroy("gteam", GTEAM));

			// Create the CompoundStatementNode of that replaces the
			// OmpParallelNode
			pragmaBody = nodeFactory.newCompoundStatementNode(
					newSource(parallelNode, COmpParser.PARALLEL), items);

			// Insert the CompoundStatementNode where the OmpParallelNode used
			// to be
			int index = node.childIndex();
			ASTNode parent = node.parent();
			parent.setChild(index, pragmaBody);
			children = pragmaBody.children();

			// Visit all the child to check for omp code
			for (ASTNode child : children) {
				if (child.childIndex() >= childrenAdded) {
					replaceOMPPragmas(child, privateList, sharedList,
							reductionList, firstPrivateList, threadPrivateIDs);
				}
			}
		} else if (node instanceof OmpForNode) {
			// Check if the node is a OmpForNode and transform the node
			ForLoopInitializerNode initializerNode;
			SequenceNode<OmpReductionNode> ompReductionNode;
			SequenceNode<IdentifierExpressionNode> reductionList = null;
			List<BlockItemNode> items;
			List<BlockItemNode> forItems;
			CompoundStatementNode pragmaBody;
			Iterable<ASTNode> children = node.children();
			items = new LinkedList<>();
			forItems = new LinkedList<>();
			VariableDeclarationNode loopDomain;
			int collapseLevel = ((OmpForNode) node).collapse();
			ASTNode body = null;
			ArrayList<Triple<ASTNode, ASTNode, ASTNode>> ranges = new ArrayList<>();
			ArrayList<IdentifierNode> loopVariables = new ArrayList<IdentifierNode>();
			SequenceNode<IdentifierExpressionNode> firstPrivateList,
					lastPrivateList;
			ForLoopNode currentLoop = null;
			ForLoopInitializerNode initializer;
			OmpSymbolReductionNode reductionNode = null;
			String forNode = "forPragma";

			// Get the list of reduction variables in the OmpForNode
			ompReductionNode = ((OmpForNode) node).reductionList();
			removeNodeFromParent(ompReductionNode);
			if (ompReductionNode != null) {
				reductionNode = (OmpSymbolReductionNode) ompReductionNode
						.child(0);
				reductionList = (SequenceNode<IdentifierExpressionNode>) reductionNode
						.child(0);
			}

			// Get the list of first private variables in the OmpForNode
			firstPrivateList = ((OmpForNode) node).firstprivateList();
			removeNodeFromParent(firstPrivateList);

			// Get the list of last private variables in the OmpForNode
			lastPrivateList = ((OmpForNode) node).lastprivateList();
			removeNodeFromParent(lastPrivateList);

			for (int i = 0; i < collapseLevel; i++) {
				Triple<ASTNode, ASTNode, ASTNode> lo_hi_step;

				if (i == 0) {
					currentLoop = (ForLoopNode) node.child(7);
					body = currentLoop.child(1);
				} else {
					currentLoop = (ForLoopNode) currentLoop.getBody();
					body = currentLoop.child(1);
				}
				initializer = currentLoop.getInitializer();
				lo_hi_step = canonicalForLoopBounds(currentLoop);
				ranges.add(new Triple<ASTNode, ASTNode, ASTNode>(
						lo_hi_step.first, lo_hi_step.second, lo_hi_step.third));
				// Initializer node only will be either IdentifierExpressionNode
				// or DeclarationNode.
				// The first child of the first child of both of them is
				// identifier node.
				loopVariables
						.add((IdentifierNode) initializer.child(0).child(0));
			}
			// For each of the ranges create a range variable
			int rangeNumber = 0;
			for (Triple<ASTNode, ASTNode, ASTNode> triple : ranges) {
				VariableDeclarationNode threadRange;
				String range = "rangeDeclaration";
				threadRange = nodeFactory.newVariableDeclarationNode(
						newSource(forNode, CivlcTokenConstant.DECLARATION),
						nodeFactory.newIdentifierNode(
								newSource(range, CivlcTokenConstant.IDENTIFIER),
								OMPPRE + "r"
										+ Integer.toString(rangeNumber + 1)),
						nodeFactory.newRangeTypeNode(
								newSource(range, CivlcTokenConstant.RANGE)),
						nodeFactory.newRegularRangeNode(
								newSource(range, CivlcTokenConstant.RANGE),
								(ExpressionNode) triple.first.copy(),
								(ExpressionNode) triple.second.copy(),
								(ExpressionNode) triple.third.copy()));
				items.add(threadRange);
				rangeNumber++;
			}

			// Create the right hand side of the domain variable declaration
			List<PairNode<DesignationNode, InitializerNode>> initList = new ArrayList<PairNode<DesignationNode, InitializerNode>>();

			String domainDeclaration = "domainDeclaration";

			for (int k = 1; k < rangeNumber + 1; k++) {
				initList.add(nodeFactory.newPairNode(
						newSource(domainDeclaration, CivlcTokenConstant.STRUCT),
						(DesignationNode) null,
						(InitializerNode) this.identifierExpression(
								newSource(domainDeclaration,
										CivlcTokenConstant.IDENTIFIER),
								OMPPRE + "r" + Integer.toString(k))));
			}

			CompoundInitializerNode temp = nodeFactory
					.newCompoundInitializerNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.INITIALIZER_LIST),
							initList);
			CompoundLiteralNode cln = nodeFactory.newCompoundLiteralNode(
					newSource(domainDeclaration,
							CivlcTokenConstant.COMPOUND_LITERAL),
					nodeFactory.newDomainTypeNode(newSource(domainDeclaration,
							CivlcTokenConstant.DOMAIN)),
					temp);

			// If there is only 1 child then make that the children
			// Else get the list from the OmpForNode body
			if (body instanceof CompoundStatementNode) {
				children = body.children();
			} else {
				ArrayList<ASTNode> tempList = new ArrayList<ASTNode>();
				tempList.add(body);
				Iterable<ASTNode> tempIterable = tempList;
				children = (Iterable<ASTNode>) tempIterable;
			}

			// Create loop_domain variable
			loopDomain = nodeFactory.newVariableDeclarationNode(
					newSource(forNode, CivlcTokenConstant.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "loop_domain"),
					nodeFactory.newDomainTypeNode(
							newSource(domainDeclaration,
									CivlcTokenConstant.DOMAIN),
							nodeFactory.newIntegerConstantNode(
									newSource(domainDeclaration,
											CivlcTokenConstant.INTEGER_CONSTANT),
									"1")),
					cln);
			items.add(loopDomain);

			int loopDecomp = config.ompLoopDecomp();

			// ($domain(1))$omp_arrive_loop(team, int, loop_domain, strategy)
			String myItersPlace = "myItersDeclaration";
			ExpressionNode ompArriveLoop = nodeFactory.newCastNode(
					newSource(myItersPlace, CivlcTokenConstant.CAST),
					nodeFactory.newDomainTypeNode(
							newSource(myItersPlace, CivlcTokenConstant.DOMAIN),
							nodeFactory.newIntegerConstantNode(
									newSource(myItersPlace,
											CivlcTokenConstant.INTEGER_CONSTANT),
									Integer.toString(collapseLevel))),
					nodeFactory.newFunctionCallNode(
							newSource(myItersPlace, CivlcTokenConstant.CALL),
							this.identifierExpression(
									newSource(myItersPlace,
											CivlcTokenConstant.IDENTIFIER),
									"$omp_arrive_loop"),
							Arrays.asList(
									this.identifierExpression(
											newSource(myItersPlace,
													CivlcTokenConstant.IDENTIFIER),
											TEAM),
									nodeFactory.newIntegerConstantNode(
											newSource(myItersPlace,
													CivlcTokenConstant.INTEGER_CONSTANT),
											this.ompArriveLoopCounter + ""),
									nodeFactory.newCastNode(
											newSource(myItersPlace,
													CivlcTokenConstant.CAST),
											nodeFactory.newDomainTypeNode(
													newSource(myItersPlace,
															CivlcTokenConstant.DOMAIN)),
											this.identifierExpression(
													newSource(myItersPlace,
															CivlcTokenConstant.IDENTIFIER),
													OMPPRE + "loop_domain")),
									nodeFactory.newIntegerConstantNode(
											newSource(myItersPlace,
													CivlcTokenConstant.INTEGER_CONSTANT),
											String.valueOf(loopDecomp))),
							null));
			this.ompArriveLoopCounter++;
			// Get correct level "n" for domain(n)
			IntegerConstantNode domainLevel = nodeFactory
					.newIntegerConstantNode(
							newSource(myItersPlace,
									CivlcTokenConstant.INTEGER_CONSTANT),
							String.valueOf(collapseLevel));

			// Add $domain(1) my_iters = ($domain(1))$omp_arrive_loop(team,
			// loop_domain);
			VariableDeclarationNode myIters;
			myIters = nodeFactory.newVariableDeclarationNode(
					newSource(forNode, CivlcTokenConstant.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(myItersPlace,
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "my_iters"),
					nodeFactory.newDomainTypeNode(
							newSource(myItersPlace, CivlcTokenConstant.DOMAIN),
							domainLevel),
					ompArriveLoop);
			items.add(myIters);

			// Add firstprivate variable declarations
			if (firstPrivateList != null) {
				for (ASTNode child : firstPrivateList.children()) {
					VariableDeclarationNode firstPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "first");
					items.add(firstPrivate);
				}
				firstPrivateIDs = firstPrivateList;
			}

			// Add reduction variable declarations
			if (reductionList != null) {
				for (ASTNode child : reductionList.children()) {
					VariableDeclarationNode localPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "reduction");
					items.add(localPrivate);
				}
				reductionIDs = reductionList;
			}

			// Declare local copies of the private variables
			if (lastPrivateList != null) {
				for (ASTNode child : lastPrivateList.children()) {
					VariableDeclarationNode localPrivate = addPrivateVariable(
							(IdentifierExpressionNode) child, "regular");
					items.add(localPrivate);
				}
			}

			String civlFor = "civlFor";
			CivlForNode cfn;

			List<VariableDeclarationNode> declarations = new ArrayList<VariableDeclarationNode>();
			for (IdentifierNode var : loopVariables) {
				declarations
						.add(nodeFactory.newVariableDeclarationNode(
								newSource(civlFor,
										CivlcTokenConstant.DECLARATION),
								var.copy(),
								nodeFactory.newBasicTypeNode(
										newSource(civlFor,
												CivlcTokenConstant.INT),
										BasicTypeKind.INT)));
			}

			initializerNode = nodeFactory.newForLoopInitializerNode(
					newSource(civlFor, CivlcTokenConstant.INITIALIZER_LIST),
					declarations);

			// Get the body of the OmpForNode and go down for loop children if
			// there is a collapse clause
			for (int i = 0; i < collapseLevel; i++) {
				if (i == 0) {
					currentLoop = (ForLoopNode) node.child(7);
				} else {
					currentLoop = (ForLoopNode) currentLoop.getBody();
				}
			}

			// Remove children from original for body and add to new for loop
			int i = 0;
			for (ASTNode child : children) {
				if (body instanceof CompoundStatementNode) {
					body.removeChild(i);
				} else {
					ASTNode bodyParent = body.parent();
					int bodyIndex = body.childIndex();
					bodyParent.removeChild(bodyIndex);
				}

				forItems.add((BlockItemNode) child);
				i++;
			}

			StatementNode forBody;
			forBody = nodeFactory.newCompoundStatementNode(
					newSource(civlFor, CivlcTokenConstant.COMPOUND_STATEMENT),
					forItems);

			// Create $for node with the original for body as its body
			cfn = nodeFactory.newCivlForNode(
					newSource(forNode, CivlcTokenConstant.CIVLFOR), false,
					(DeclarationListNode) initializerNode,
					nodeFactory.newIdentifierExpressionNode(
							newSource(civlFor,
									CivlcTokenConstant.INITIALIZER_LIST),
							nodeFactory.newIdentifierNode(
									newSource(civlFor,
											CivlcTokenConstant.IDENTIFIER),
									OMPPRE + "my_iters")),
					forBody, null);
			items.add(cfn);

			// Apply association operator to all reduction variables
			if (reductionList != null) {
				for (ASTNode child : reductionList.children()) {
					String name = ((IdentifierNode) child.child(0)).name();
					String operator = reductionNode.operator().name();
					items.add(applyAssoc(name, operator));
				}
			}

			// $barrier_and_flush(team);
			if (!((OmpForNode) node).nowait()) {
				items.add(barrierAndFlush(TEAM));
			}

			// Do lastprivate vars
			if (lastPrivateList != null) {
				for (ASTNode child : lastPrivateList.children()) {
					String name = ((IdentifierNode) child.child(0)).name();
					ExpressionNode arg1 = this.identifierExpression(
							newSource("lastPrivate",
									CivlcTokenConstant.IDENTIFIER),
							OMPPRE + name + "$_private");
					OperatorNode expression = nodeFactory.newOperatorNode(
							newSource("lastPrivate", CivlcTokenConstant.EXPR),
							Operator.ASSIGN, (ExpressionNode) child.copy(),
							arg1);
					ExpressionStatementNode statement = nodeFactory
							.newExpressionStatementNode(expression);

					int size = items.size();

					ASTNode lastChild = items.get(size - 1);

					Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
							null, statement);
					if (sharedWrite.containsKey(lastChild)) {
						ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedRead
								.get(lastChild);
						nodeToAdd.add(tempPair);
					} else {
						ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
						tempPairs.add(tempPair);
						sharedWrite.put(lastChild, tempPairs);
					}
				}
			}

			boolean removed = false;
			if (sharedIDs != null) {
				for (ASTNode child : sharedIDs.children()) {
					IdentifierExpressionNode idexp = (IdentifierExpressionNode) child;
					IdentifierNode id = idexp.getIdentifier();
					if (lastPrivateList != null) {
						for (ASTNode childPrivateList : lastPrivateList
								.children()) {
							IdentifierExpressionNode privateIdexp = (IdentifierExpressionNode) childPrivateList;
							IdentifierNode privateId = privateIdexp
									.getIdentifier();
							if (id.name().equals(privateId.name())) {
								child.remove();
								removed = true;
							}
						}
					}

				}
			}
			SequenceNode<IdentifierExpressionNode> newSharedList;
			List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
			if (removed) {
				for (ASTNode child : sharedIDs.children()) {
					if (child != null) {
						child.remove();
						list.add((IdentifierExpressionNode) child);
					}
				}
				newSharedList = nodeFactory.newSequenceNode(
						newSource("sharedList",
								CivlcTokenConstant.IDENTIFIER_LIST),
						"sharedList", list);
				sharedIDs = newSharedList;
			}

			if (lastPrivateList != null) {
				for (ASTNode child : lastPrivateList.children()) {
					if (child != null) {
						child.remove();
						privateIDs.addSequenceChild(
								(IdentifierExpressionNode) child);
					}
				}
			}

			// Insert the CompoundStatementNode where the OmpForNode used to be
			pragmaBody = nodeFactory.newCompoundStatementNode(
					newSource(forNode, CivlcTokenConstant.COMPOUND_STATEMENT),
					items);
			children = pragmaBody.children();
			int index = node.childIndex();
			ASTNode parent = node.parent();
			parent.setChild(index, pragmaBody);

			// Visit all of the children to check for omp code
			for (ASTNode child : children) {
				replaceOMPPragmas(child, privateIDs, sharedIDs, reductionIDs,
						firstPrivateIDs, threadPrivateIDs);
			}

		} else if (node instanceof OmpSyncNode) {
			String syncKind = ((OmpSyncNode) node).ompSyncNodeKind().toString();
			CompoundStatementNode body;
			LinkedList<BlockItemNode> items = new LinkedList<>();
			// Check the synckind
			if (syncKind.equals("MASTER")) {
				String syncNode = "masterNode";
				// Replace omp master with a check if _tid==0 and insert the omp
				// master body into that
				List<ExpressionNode> operands = new ArrayList<ExpressionNode>();
				operands.add(
						nodeFactory.newIdentifierExpressionNode(
								newSource(syncNode,
										CivlcTokenConstant.IDENTIFIER),
								nodeFactory.newIdentifierNode(
										newSource(syncNode,
												CivlcTokenConstant.IDENTIFIER),
										TID)));
				operands.add(
						nodeFactory.newIntegerConstantNode(
								newSource(syncNode,
										CivlcTokenConstant.INTEGER_CONSTANT),
								"0"));
				int i = 0;
				for (ASTNode child : node.children()) {
					node.removeChild(i);
					items.add((BlockItemNode) child);
					i++;
				}
				body = nodeFactory.newCompoundStatementNode(newSource(syncNode,
						CivlcTokenConstant.COMPOUND_STATEMENT), items);
				IfNode ifStatement = nodeFactory
						.newIfNode(newSource(syncNode, CivlcTokenConstant.IF),
								nodeFactory.newOperatorNode(
										newSource(syncNode,
												CivlcTokenConstant.EQUALS),
										Operator.EQUALS, operands),
								body);
				// Replace omp master with the new if statement
				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, ifStatement);

				Iterable<ASTNode> children = body.children();

				// Visit all the child to check for omp code
				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}

			} else if (syncKind.equals("OMPATOMIC")) {
				String atomicSrc = "ompAtomic";
				AtomicNode atomicNode;

				int i = 0;
				for (ASTNode child : node.children()) {
					if (child instanceof CompoundStatementNode) {
						int j = 0;
						for (ASTNode child2 : child.children()) {
							child.removeChild(j);
							items.add((BlockItemNode) child2);
							j++;
						}
						node.removeChild(i);
						i++;
					} else {
						node.removeChild(i);
						items.add((BlockItemNode) child);
						i++;
					}
				}

				body = nodeFactory.newCompoundStatementNode(newSource(atomicSrc,
						CivlcTokenConstant.COMPOUND_STATEMENT), items);

				atomicNode = nodeFactory.newAtomicStatementNode(
						newSource(atomicSrc, CivlcTokenConstant.ATOMIC), false,
						body);

				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, atomicNode);

				Iterable<ASTNode> children = body.children();

				// Visit all the child to check for omp code
				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}
			} else if (syncKind.equals("BARRIER")) {
				// Replace omp barrier with $omp_barrier_and_flush
				ExpressionStatementNode barrierAndFlush = barrierAndFlush(TEAM);
				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, barrierAndFlush);
			} else if (syncKind.equals("CRITICAL")) {
				// For an omp critical, check if there is a name for the
				// critical
				// If there is a name, get the name. Else, give it noname
				Iterable<ASTNode> children = node.children();
				String syncNode = "criticalNode";
				IdentifierNode criticalIDName = ((OmpSyncNode) node)
						.criticalName();
				removeNodeFromParent(criticalIDName);
				String criticalName = null;
				if (criticalIDName != null) {
					criticalName = "_critical_" + criticalIDName.name();
				} else {
					criticalName = "_critical_noname";
				}

				// Create expression and body of when node
				ExpressionNode notCritical = nodeFactory.newOperatorNode(
						newSource(syncNode, CivlcTokenConstant.NOT),
						Operator.NOT,
						Arrays.asList(this.identifierExpression(
								newSource(syncNode,
										CivlcTokenConstant.IDENTIFIER),
								criticalName)));
				ExpressionStatementNode criticalTrue = nodeFactory
						.newExpressionStatementNode(nodeFactory.newOperatorNode(
								newSource(syncNode, CivlcTokenConstant.ASSIGN),
								Operator.ASSIGN,
								Arrays.asList(
										this.identifierExpression(
												newSource(syncNode,
														CivlcTokenConstant.IDENTIFIER),
												criticalName),
										nodeFactory.newBooleanConstantNode(
												newSource(syncNode, 1),
												true))));

				// Create and add when node
				// $when (!_critical_a) _critical_a=$true;
				items.add(nodeFactory.newWhenNode(
						newSource(syncNode, CivlcTokenConstant.WHEN),
						notCritical, criticalTrue));
				// Put critical section body in the when body.
				int i = 0;
				for (ASTNode child : node.children()) {
					node.removeChild(i);
					items.add((BlockItemNode) child);
					i++;
				}
				items.add(nodeFactory.newExpressionStatementNode(
						nodeFactory.newFunctionCallNode(
								newSource("flush", CivlcTokenConstant.CALL),
								this.identifierExpression("$omp_flush_all"),
								Arrays.asList(this.identifierExpression(TEAM)),
								null)));
				// Make the critical variable false now
				ExpressionStatementNode criticalFalse = nodeFactory
						.newExpressionStatementNode(nodeFactory.newOperatorNode(
								newSource(syncNode, CivlcTokenConstant.ASSIGN),
								Operator.ASSIGN,
								Arrays.asList(
										this.identifierExpression(
												newSource(syncNode,
														CivlcTokenConstant.IDENTIFIER),
												criticalName),
										nodeFactory.newBooleanConstantNode(
												newSource(syncNode, 0),
												false))));
				items.add(criticalFalse);

				// Add body to the CompoundstatementNode and replace the omp
				// critical node with the CompoundStatementNode
				body = nodeFactory.newCompoundStatementNode(newSource(syncNode,
						CivlcTokenConstant.COMPOUND_STATEMENT), items);
				if (!criticalNames.contains(criticalName)) {
					criticalNames.add(criticalName);
				}
				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, body);

				children = body.children();

				// Visit all the child to check for omp code
				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}

			}
		} else if (node instanceof OmpWorksharingNode) {
			Iterable<ASTNode> children = node.children();
			String workshareKind = ((OmpWorksharingNode) node)
					.ompWorkshareNodeKind().toString();
			CompoundStatementNode body;
			LinkedList<BlockItemNode> items = new LinkedList<>();
			if (workshareKind.equals("SECTIONS")) {
				String sectionsPlace = "sections";
				SequenceNode<IdentifierExpressionNode> privateList = ((OmpWorksharingNode) node)
						.privateList();
				removeNodeFromParent(privateList);
				firstPrivateIDs = ((OmpWorksharingNode) node)
						.firstprivateList();
				removeNodeFromParent(firstPrivateIDs);
				int numberSections = 0;
				CompoundStatementNode pragmaBody = (CompoundStatementNode) node
						.child(7);
				ArrayList<LinkedList<BlockItemNode>> sectionsChildren = new ArrayList<LinkedList<BlockItemNode>>();
				for (ASTNode child : pragmaBody.children()) {
					if (child instanceof OmpWorksharingNode) {
						if (((OmpWorksharingNode) child).ompWorkshareNodeKind()
								.toString().equals("SECTION")) {
							LinkedList<BlockItemNode> sectionItems = new LinkedList<>();
							int i = 0;
							for (ASTNode sectionChild : child.children()) {
								child.removeChild(i);
								sectionItems.add((BlockItemNode) sectionChild);
								i++;
							}
							sectionsChildren.add(sectionItems);
							numberSections++;
						}
					}
				}

				ExpressionNode ompArriveSections = nodeFactory
						.newFunctionCallNode(
								newSource(sectionsPlace,
										CivlcTokenConstant.CALL),
								this.identifierExpression(
										newSource(sectionsPlace,
												CivlcTokenConstant.IDENTIFIER),
										"$omp_arrive_sections"),
								Arrays.asList(
										this.identifierExpression(
												newSource(sectionsPlace,
														CivlcTokenConstant.IDENTIFIER),
												TEAM),
										nodeFactory.newIntegerConstantNode(
												newSource(sectionsPlace,
														CivlcTokenConstant.INTEGER_CONSTANT),
												String.valueOf(
														this.ompArriveSections)),
										nodeFactory.newIntegerConstantNode(
												newSource(sectionsPlace,
														CivlcTokenConstant.INTEGER_CONSTANT),
												String.valueOf(
														numberSections))),
								null);
				this.ompArriveSections++;
				String mySecDeclaration = "my_secsDeclaration";
				VariableDeclarationNode my_secs;
				my_secs = nodeFactory.newVariableDeclarationNode(
						newSource(sectionsPlace,
								CivlcTokenConstant.DECLARATION),
						nodeFactory.newIdentifierNode(
								newSource(mySecDeclaration,
										CivlcTokenConstant.IDENTIFIER),
								"my_secs"),
						nodeFactory.newDomainTypeNode(
								newSource(mySecDeclaration,
										CivlcTokenConstant.DOMAIN),
								nodeFactory.newIntegerConstantNode(
										newSource(mySecDeclaration,
												CivlcTokenConstant.INTEGER_CONSTANT),
										"1")),
						ompArriveSections);
				items.add(my_secs);

				// Declare local copies of the private variables
				if (privateList != null) {
					for (ASTNode child : privateList.children()) {
						VariableDeclarationNode localPrivate = addPrivateVariable(
								(IdentifierExpressionNode) child, "regular");
						items.add(localPrivate);
					}
				}

				// Add firstprivate variable declarations
				if (firstPrivateIDs != null) {
					for (ASTNode child : firstPrivateIDs.children()) {
						VariableDeclarationNode firstPrivate = addPrivateVariable(
								(IdentifierExpressionNode) child, "first");
						items.add(firstPrivate);
					}
				}

				CivlForNode cfn;
				String civlFor = "civlFor";
				List<BlockItemNode> forItems = new LinkedList<>();

				// for loop;
				ForLoopInitializerNode initializerNode = nodeFactory
						.newForLoopInitializerNode(
								newSource(civlFor,
										CivlcTokenConstant.INITIALIZER_LIST),
								Arrays.asList(
										nodeFactory.newVariableDeclarationNode(
												newSource(civlFor,
														CivlcTokenConstant.DECLARATION),
												nodeFactory.newIdentifierNode(
														newSource(civlFor,
																CivlcTokenConstant.IDENTIFIER),
														"i$omp"),
												nodeFactory.newBasicTypeNode(
														newSource(civlFor,
																CivlcTokenConstant.INT),
														BasicTypeKind.INT))));

				StatementNode forBody;
				StatementNode switchBody;
				List<BlockItemNode> switchItems = new LinkedList<>();
				int caseNumber = 0;
				String caseItem = "caseItem";
				for (LinkedList<BlockItemNode> tempChildren : sectionsChildren) {
					StatementNode caseBody;
					List<BlockItemNode> caseItems = tempChildren;
					caseItems.add(nodeFactory.newBreakNode(
							newSource(caseItem, CivlcTokenConstant.BREAK)));
					caseBody = nodeFactory.newCompoundStatementNode(
							newSource(caseItem,
									CivlcTokenConstant.COMPOUND_STATEMENT),
							caseItems);
					SwitchLabelNode labelDecl = nodeFactory
							.newCaseLabelDeclarationNode(
									newSource(caseItem,
											CivlcTokenConstant.CASE),
									nodeFactory.newIntegerConstantNode(
											newSource(caseItem,
													CivlcTokenConstant.INTEGER_CONSTANT),
											String.valueOf(caseNumber)),
									caseBody);
					switchItems.add(nodeFactory.newLabeledStatementNode(
							newSource(caseItem,
									CivlcTokenConstant.CASE_LABELED_STATEMENT),
							labelDecl, caseBody));
					caseNumber++;
				}
				switchBody = nodeFactory.newCompoundStatementNode(
						newSource(civlFor,
								CivlcTokenConstant.COMPOUND_STATEMENT),
						switchItems);
				forItems.add(nodeFactory.newSwitchNode(
						newSource(civlFor, CivlcTokenConstant.SWITCH),
						this.identifierExpression(
								newSource(civlFor,
										CivlcTokenConstant.IDENTIFIER),
								"i$omp"),
						switchBody));
				forBody = nodeFactory.newCompoundStatementNode(
						newSource(civlFor,
								CivlcTokenConstant.COMPOUND_STATEMENT),
						forItems);

				cfn = nodeFactory.newCivlForNode(
						newSource(sectionsPlace, CivlcTokenConstant.CIVLFOR),
						false, (DeclarationListNode) initializerNode,
						nodeFactory.newIdentifierExpressionNode(
								newSource(civlFor,
										CivlcTokenConstant.IDENTIFIER),
								nodeFactory.newIdentifierNode(
										newSource(civlFor,
												CivlcTokenConstant.IDENTIFIER),
										"my_secs")),
						forBody, null);
				items.add(cfn);

				if (!((OmpWorksharingNode) node).nowait()) {
					items.add(barrierAndFlush(TEAM));
				}

				CompoundStatementNode sectionBody = nodeFactory
						.newCompoundStatementNode(
								newSource(sectionsPlace,
										CivlcTokenConstant.COMPOUND_STATEMENT),
								items);

				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, sectionBody);

				children = forBody.children();

				if (privateList != null) {
					for (ASTNode child : privateList.children()) {
						if (child != null) {
							child.remove();
							privateIDs.addSequenceChild(
									(IdentifierExpressionNode) child);
						}
					}
				}

				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}

			}
			if (workshareKind.equals("SINGLE")) {
				SequenceNode<IdentifierExpressionNode> privateList = ((OmpWorksharingNode) node)
						.privateList();
				removeNodeFromParent(privateList);
				SequenceNode<IdentifierExpressionNode> copyPrivateList = ((OmpWorksharingNode) node)
						.copyprivateList();
				removeNodeFromParent(copyPrivateList);

				boolean removed = false;
				for (ASTNode child : sharedIDs.children()) {
					IdentifierExpressionNode idexp = (IdentifierExpressionNode) child;
					IdentifierNode id = idexp.getIdentifier();
					if (privateList != null) {
						for (ASTNode childPrivateList : privateList
								.children()) {
							IdentifierExpressionNode privateIdexp = (IdentifierExpressionNode) childPrivateList;
							IdentifierNode privateId = privateIdexp
									.getIdentifier();
							if (id.name().equals(privateId.name())) {
								child.remove();
								removed = true;
							}
						}
					}
					if (copyPrivateList != null) {
						for (ASTNode childPrivateList : copyPrivateList
								.children()) {
							IdentifierExpressionNode privateIdexp = (IdentifierExpressionNode) childPrivateList;
							IdentifierNode privateId = privateIdexp
									.getIdentifier();
							if (id.name().equals(privateId.name())) {
								child.remove();
								removed = true;
							}
						}
					}

				}
				SequenceNode<IdentifierExpressionNode> newSharedList;
				List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
				if (removed) {
					for (ASTNode child : sharedIDs.children()) {
						if (child != null) {
							child.remove();
							list.add((IdentifierExpressionNode) child);
						}
					}
					newSharedList = nodeFactory.newSequenceNode(
							newSource("sharedList",
									CivlcTokenConstant.IDENTIFIER_LIST),
							"sharedList", list);
					sharedIDs = newSharedList;
				}

				String singlePlace = "single";
				ExpressionNode arriveSingle = nodeFactory.newFunctionCallNode(
						newSource("arrive", CivlcTokenConstant.CALL),
						this.identifierExpression(
								newSource("arrive",
										CivlcTokenConstant.IDENTIFIER),
								"$omp_arrive_single"),
						Arrays.asList(
								this.identifierExpression(
										newSource("arrive",
												CivlcTokenConstant.IDENTIFIER),
										TEAM),
								nodeFactory.newIntegerConstantNode(
										newSource("arrive",
												CivlcTokenConstant.INTEGER_CONSTANT),
										this.ompArriveSingle + "")),
						null);
				this.ompArriveSingle++;
				items.add(nodeFactory.newVariableDeclarationNode(
						newSource(singlePlace, CivlcTokenConstant.DECLARATION),
						nodeFactory.newIdentifierNode(
								newSource(singlePlace,
										CivlcTokenConstant.IDENTIFIER),
								"owner"),
						nodeFactory.newBasicTypeNode(
								newSource(singlePlace, CivlcTokenConstant.INT),
								BasicTypeKind.INT),
						arriveSingle));

				if (copyPrivateList != null) {
					for (ASTNode child : copyPrivateList.children()) {
						if (child != null) {
							VariableDeclarationNode localSharedVar;
							IdentifierNode c = (IdentifierNode) child.child(0);
							String localDeclaration = "LocalSharedVarDeclaration";
							TypeNode privateType = ((VariableDeclarationNode) ((Variable) c
									.getEntity()).getFirstDeclaration())
											.getTypeNode().copy();
							IdentifierNode localSharedIdentifer = nodeFactory
									.newIdentifierNode(
											newSource(
													c.name() + localDeclaration,
													CivlcTokenConstant.IDENTIFIER),
											OMPPRE + c.name() + "_private");
							Type currentType = ((Variable) c.getEntity())
									.getType();

							if (privateType instanceof ArrayTypeNode
									&& currentType instanceof PointerType) {
								if (!(((PointerType) currentType)
										.referencedType() instanceof ArrayType)) {
									currentType = ((PointerType) currentType)
											.referencedType();
									while (currentType instanceof ArrayType) {
										currentType = ((ArrayType) currentType)
												.getElementType();
									}
									BasicTypeKind baseTypeKind = ((StandardBasicType) currentType)
											.getBasicTypeKind();

									privateType = nodeFactory
											.newPointerTypeNode(
													newSource(
															c.name() + localDeclaration,
															CivlcTokenConstant.IDENTIFIER),
													nodeFactory
															.newBasicTypeNode(
																	newSource(
																			localDeclaration,
																			CivlcTokenConstant.TYPE),
																	baseTypeKind));
								}
							}

							ExpressionNode localCopyPrivate = this
									.identifierExpression(
											newSource(
													c.name() + localDeclaration,
													CivlcTokenConstant.IDENTIFIER),
											c.name());

							localSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(localDeclaration,
													CivlcTokenConstant.DECLARATION),
											localSharedIdentifer, privateType,
											localCopyPrivate);
							items.add(localSharedVar);
						}
					}
				}

				List<ExpressionNode> operands = new ArrayList<ExpressionNode>();
				operands.add(this.identifierExpression(
						newSource(singlePlace, CivlcTokenConstant.IDENTIFIER),
						"owner"));
				operands.add(this.identifierExpression(
						newSource(singlePlace, CivlcTokenConstant.IDENTIFIER),
						TID));

				CompoundStatementNode ifBody;
				LinkedList<BlockItemNode> ifItems = new LinkedList<>();

				// Declare local copies of the private variables
				if (privateList != null) {
					for (ASTNode child : privateList.children()) {
						VariableDeclarationNode localPrivate = addPrivateVariable(
								(IdentifierExpressionNode) child, "regular");
						ifItems.add(localPrivate);
					}
				}

				int i = 0;
				for (ASTNode child : node.children()) {
					node.removeChild(i);
					ifItems.add((BlockItemNode) child);
					i++;
				}
				ifBody = nodeFactory.newCompoundStatementNode(
						newSource(singlePlace,
								CivlcTokenConstant.COMPOUND_STATEMENT),
						ifItems);

				if (copyPrivateList != null) {
					for (ASTNode child : copyPrivateList.children()) {
						IdentifierNode c = ((IdentifierExpressionNode) child)
								.getIdentifier();

						ExpressionNode expression = nodeFactory.newOperatorNode(
								newSource("copyPrivate",
										CivlcTokenConstant.EXPR),
								Operator.ASSIGN,
								Arrays.asList(
										this.identifierExpression(
												newSource("copyPrivate",
														CivlcTokenConstant.IDENTIFIER),
												c.name()),
										this.identifierExpression(
												newSource("copyPrivate",
														CivlcTokenConstant.IDENTIFIER),
												OMPPRE + c.name()
														+ "_private")));
						ExpressionStatementNode statement = nodeFactory
								.newExpressionStatementNode(expression);

						int ifChildren = ifBody.numChildren();
						ASTNode lastChild = ifBody.child(ifChildren - 1);

						Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
								null, statement);
						if (sharedWrite.containsKey(lastChild)) {
							ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedRead
									.get(lastChild);
							nodeToAdd.add(tempPair);
						} else {
							ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
							tempPairs.add(tempPair);
							sharedWrite.put(lastChild, tempPairs);
						}

					}
				}

				IfNode ifStatement = nodeFactory.newIfNode(
						newSource(singlePlace, CivlcTokenConstant.IF),
						nodeFactory.newOperatorNode(
								newSource(singlePlace,
										CivlcTokenConstant.EQUALS),
								Operator.EQUALS, operands),
						ifBody);
				items.add(ifStatement);
				items.add(barrierAndFlush(TEAM));
				body = nodeFactory
						.newCompoundStatementNode(
								newSource(singlePlace,
										CivlcTokenConstant.COMPOUND_STATEMENT),
								items);

				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, body);

				children = ifBody.children();

				if (privateList != null) {
					for (ASTNode child : privateList.children()) {
						if (child != null) {
							child.remove();
							privateIDs.addSequenceChild(
									(IdentifierExpressionNode) child);
						}
					}
				}

				if (copyPrivateList != null) {
					for (ASTNode child : copyPrivateList.children()) {
						if (child != null) {
							child.remove();
							privateIDs.addSequenceChild(
									(IdentifierExpressionNode) child);
						}
					}
				}

				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}

			}
		} else if (node instanceof FunctionCallNode) {
			boolean replaced = replaceOmpFunction((FunctionCallNode) node);
			if (!replaced) {
				for (ASTNode child : node.children()) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}
			}
		} else if (node instanceof IdentifierNode) {
			if (privateIDs != null) {
				for (ASTNode child : privateIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						((IdentifierNode) node).setName(OMPPRE
								+ ((IdentifierNode) node).name() + "_private");
					}
				}
			}
			if (firstPrivateIDs != null) {
				for (ASTNode child : firstPrivateIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						((IdentifierNode) node).setName(OMPPRE
								+ ((IdentifierNode) node).name() + "_private");
					}
				}
			}
			if (reductionIDs != null) {
				for (ASTNode child : reductionIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						((IdentifierNode) node)
								.setName(OMPPRE + ((IdentifierNode) node).name()
										+ "_reduction");
					}
				}
			}
			if (sharedIDs != null
					&& ((IdentifierNode) node).getEntity() != null) {
				for (ASTNode child : sharedIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						ASTNode parent = getParentOfID((IdentifierNode) node);
						boolean sameName = false;
						for (Triple<String, StatementNode, String> tempName : sharedReplaced) {
							if (tempName.first
									.equals(((IdentifierNode) node).name())) {
								if (tempName.second.equals(parent)) {
									sameName = true;
									((IdentifierNode) node)
											.setName(tempName.third);
								}
							}
						}
						if (!sameName) {
							sharedRead((IdentifierNode) node,
									(BlockItemNode) parent, privateIDs,
									sharedIDs, reductionIDs, firstPrivateIDs);
						}

					}
				}
			}
			if (threadPrivateIDs != null) {
				for (ASTNode child : threadPrivateIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						ASTNode idExp = node.parent();
						IdentifierExpressionNode arg0 = (IdentifierExpressionNode) this
								.identifierExpression(
										newSource("threadPrivate",
												CivlcTokenConstant.IDENTIFIER),
										c.name() + "$omp_threadprivate");
						IdentifierExpressionNode arg1 = (IdentifierExpressionNode) this
								.identifierExpression(
										newSource("threadPrivate",
												CivlcTokenConstant.IDENTIFIER),
										TID);

						OperatorNode threadPrivateReplace = nodeFactory
								.newOperatorNode(
										newSource("threadPrivate",
												CivlcTokenConstant.EXPR),
										Operator.SUBSCRIPT, arg0, arg1);

						int index = idExp.childIndex();
						ASTNode parent = idExp.parent();
						parent.setChild(index, threadPrivateReplace);

					}
				}
			}

		} else if (node instanceof OperatorNode && sharedIDs != null
				&& isAssignmentOperator(
						((OperatorNode) node).getOperator().toString()) != 0) {

			int op = isAssignmentOperator(
					((OperatorNode) node).getOperator().toString());
			if (op != 0) {
				ASTNode lhs = node.child(0);
				while (!(lhs instanceof IdentifierNode)) {
					lhs = lhs.child(0);
				}

				for (ASTNode child : sharedIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) lhs).name())) {
						boolean isInReduction = false;
						if (reductionIDs != null) {
							for (ASTNode childReduction : reductionIDs
									.children()) {
								IdentifierNode cReduction = ((IdentifierExpressionNode) childReduction)
										.getIdentifier();
								if (cReduction.name().equals(
										((IdentifierNode) lhs).name())) {
									isInReduction = true;
								}
							}
						}
						if (!isInReduction) {
							sharedWrite((IdentifierNode) lhs, privateIDs,
									sharedIDs, reductionIDs, firstPrivateIDs,
									threadPrivateIDs, op);
						}
					}
				}

				for (int i = 0; i < node.numChildren(); i++) {
					ASTNode child = node.child(i);
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}
			}

		} else if (node instanceof OperatorNode) {
			for (int i = node.numChildren() - 1; i >= 0; i--) {
				replaceOMPPragmas(node.child(i), privateIDs, sharedIDs,
						reductionIDs, firstPrivateIDs, threadPrivateIDs);
			}
		} else if (node instanceof ForLoopNode && sharedIDs != null) {
			ASTNode oldBody;
			CompoundStatementNode whileBody;
			LinkedList<BlockItemNode> items = new LinkedList<BlockItemNode>();
			ExpressionNode incrementer = ((ForLoopNode) node).getIncrementer();
			ExpressionNode condition = ((ForLoopNode) node).getCondition();
			ForLoopInitializerNode initializer = ((ForLoopNode) node)
					.getInitializer();
			String forToWhile = "forToWhileTransforamtion";
			boolean found = containsSharedVar(incrementer, sharedIDs);
			found = found || containsSharedVar(condition, sharedIDs);
			found = found || containsSharedVar(initializer, sharedIDs);

			if (found) {
				condition.remove();
				incrementer.remove();
				initializer.remove();

				oldBody = ((ForLoopNode) node).getBody();
				if (oldBody instanceof CompoundStatementNode) {
					for (ASTNode child : oldBody.children()) {
						child.remove();
						items.add((BlockItemNode) child);
					}
				} else {
					oldBody.remove();
					items.add((BlockItemNode) oldBody);
				}

				if (((OperatorNode) incrementer)
						.getOperator() == Operator.COMMA) {
					OperatorNode op = (OperatorNode) incrementer;
					boolean added = false;
					while (op.getOperator() == Operator.COMMA && !added) {
						OperatorNode arg1 = (OperatorNode) op.getArgument(0);
						OperatorNode arg2 = (OperatorNode) op.getArgument(1);
						if (arg1.getOperator() != Operator.COMMA) {
							arg1.remove();
							items.add(nodeFactory
									.newExpressionStatementNode(arg1));
							added = true;
						} else {
							op = arg1;
						}
						if (arg2.getOperator() != Operator.COMMA) {
							arg2.remove();
							items.add(nodeFactory
									.newExpressionStatementNode(arg2));
							added = added && true;
						} else {
							op = arg2;
						}
					}
				} else {
					items.add(nodeFactory
							.newExpressionStatementNode(incrementer));
				}

				whileBody = nodeFactory
						.newCompoundStatementNode(
								newSource(forToWhile,
										CivlcTokenConstant.COMPOUND_STATEMENT),
								items);

				LoopNode whileNode = nodeFactory.newWhileLoopNode(
						newSource("forToWhile", CivlcTokenConstant.WHILE),
						condition, whileBody, null);

				LinkedList<ExpressionStatementNode> initializers = new LinkedList<ExpressionStatementNode>();
				if (((OperatorNode) initializer)
						.getOperator() == Operator.COMMA) {
					OperatorNode op = (OperatorNode) initializer;
					boolean added = false;
					while (op.getOperator() == Operator.COMMA && !added) {
						OperatorNode arg1 = (OperatorNode) op.getArgument(0);
						OperatorNode arg2 = (OperatorNode) op.getArgument(1);
						if (arg1.getOperator() != Operator.COMMA) {
							arg1.remove();
							initializers.add(nodeFactory
									.newExpressionStatementNode(arg1));
							added = true;
						} else {
							op = arg1;
						}
						if (arg2.getOperator() != Operator.COMMA) {
							arg2.remove();
							initializers.add(nodeFactory
									.newExpressionStatementNode(arg2));
							added = added && true;
						} else {
							op = arg2;
						}
					}
				} else {
					initializers.add(nodeFactory.newExpressionStatementNode(
							(ExpressionNode) initializer));
				}

				CompoundStatementNode body;
				LinkedList<BlockItemNode> forReplace = new LinkedList<BlockItemNode>();

				for (ExpressionStatementNode child : initializers) {
					forReplace.add(child);
				}

				forReplace.add(whileNode);
				body = nodeFactory.newCompoundStatementNode(
						newSource(forToWhile,
								CivlcTokenConstant.COMPOUND_STATEMENT),
						forReplace);

				int index = node.childIndex();
				ASTNode parent = node.parent();
				parent.setChild(index, body);

				Iterable<ASTNode> children = body.children();
				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}
			} else {
				Iterable<ASTNode> children = node.children();
				for (ASTNode child : children) {
					replaceOMPPragmas(child, privateIDs, sharedIDs,
							reductionIDs, firstPrivateIDs, threadPrivateIDs);
				}
			}

		} else if (node instanceof OmpDeclarativeNode) {
			// Create array of threadprivate vars for each var
			SequenceNode<IdentifierExpressionNode> vars = ((OmpDeclarativeNode) node)
					.variables();
			vars.remove();
			for (ASTNode child : vars.children()) {
				String c = ((IdentifierExpressionNode) child).getIdentifier()
						.name();
				IdentifierNode name = nodeFactory.newIdentifierNode(
						newSource("threadPrivate",
								CivlcTokenConstant.IDENTIFIER),
						c + "$omp_threadprivate");
				IdentifierNode id = ((IdentifierExpressionNode) child)
						.getIdentifier();
				TypeNode privateType = ((VariableDeclarationNode) ((Variable) id
						.getEntity()).getFirstDeclaration()).getTypeNode()
								.copy();
				IdentifierExpressionNode extent = (IdentifierExpressionNode) this
						.identifierExpression(
								newSource("threadPrivate",
										CivlcTokenConstant.IDENTIFIER),
								OMPPRE + "num_threads");
				ArrayTypeNode arrayType = nodeFactory.newArrayTypeNode(
						newSource("threadPrivate", CivlcTokenConstant.TYPE),
						privateType, extent);
				VariableDeclarationNode arrayNode = nodeFactory
						.newVariableDeclarationNode(
								newSource("threadPrivate",
										CivlcTokenConstant.DECLARATION),
								name, arrayType);
				int index = node.childIndex();
				ASTNode parent = node.parent();

				ASTNode nextNode = parent.child(index + 1);

				// Insert new nodes
				Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
						arrayNode, null);
				if (sharedWrite.containsKey(nextNode)) {
					ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedWrite
							.get(nextNode);
					nodeToAdd.add(tempPair);
				} else {
					ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
					tempPairs.add(tempPair);
					sharedWrite.put(nextNode, tempPairs);
				}
				threadPrivateIDs.addSequenceChild(
						(IdentifierExpressionNode) child.copy());
			}

			// Remove old node
			node.remove();

		} else if (node != null) {
			Iterable<ASTNode> children = node.children();
			for (ASTNode child : children) {
				replaceOMPPragmas(child, privateIDs, sharedIDs, reductionIDs,
						firstPrivateIDs, threadPrivateIDs);
			}
		}

	}

	/**
	 * Check if the current node contains a shared variable.
	 * 
	 * @param node
	 * @param sharedIDs
	 * @return If there is a shared variable in the node, return true.
	 */
	private boolean containsSharedVar(ASTNode node,
			SequenceNode<IdentifierExpressionNode> sharedIDs) {
		if (node instanceof IdentifierNode) {
			for (ASTNode child : sharedIDs.children()) {
				IdentifierNode c = ((IdentifierExpressionNode) child)
						.getIdentifier();
				if (c.name().equals(((IdentifierNode) node).name())) {
					return true;
				}
			}
		} else if (node != null) {
			Iterable<ASTNode> children = node.children();
			boolean found = false;
			for (ASTNode child : children) {
				return found || containsSharedVar(child, sharedIDs);
			}
		}
		return false;
	}

	/**
	 * Get the temp variable for a node. This method will generate a temp
	 * variable that is used in the omp_read or omp_write functions.
	 * 
	 * @param node
	 * @param readWrite
	 * @param count
	 * @return
	 */
	private Pair<VariableDeclarationNode, Integer> getTempVar(
			IdentifierNode node, String readWrite, int count) {
		VariableDeclarationNode temp;
		Type currentType = ((Variable) node.getEntity()).getType();
		int nodesDeep = 0;
		boolean pointer = false;
		while (currentType instanceof PointerType) {
			currentType = ((PointerType) currentType).referencedType();
			nodesDeep++;
			pointer = true;
		}

		if (currentType instanceof QualifiedObjectType) {
			currentType = ((QualifiedObjectType) currentType).getBaseType();
		}

		while (currentType instanceof ArrayType) {
			currentType = ((ArrayType) currentType).getElementType();
			nodesDeep++;
		}
		String place = node.name() + "Shared" + readWrite;

		BasicTypeKind baseTypeKind = null;

		// TODO: Figure out this function.
		if (currentType instanceof StandardBasicType) {
			baseTypeKind = ((StandardBasicType) currentType).getBasicTypeKind();
		} /*
			 * else if (currentType instanceof PointerType) { // If the data
			 * structure represents an array of pointers // Continue finding its
			 * fianl referenced basic type. while (currentType instanceof
			 * PointerType) { currentType = ((PointerType)
			 * currentType).referencedType(); nodesDeep++; pointer = true; }
			 * baseTypeKind = ((StandardBasicType)
			 * currentType).getBasicTypeKind(); }
			 */ else
			throw new CIVLUnimplementedFeatureException(
					"Arrays with non-basic element type in OMP shared variables: "
							+ "\n\tvariable name: "
							+ ((Variable) node.getEntity()).getName()
							+ "\n\tvariable type: "
							+ ((Variable) node.getEntity()).getType(),
					node.getSource());

		IdentifierNode tempID = nodeFactory.newIdentifierNode(
				newSource(place, CivlcTokenConstant.IDENTIFIER),
				OMPPRE + readWrite + String.valueOf(count));
		TypeNode declarationTypeNode = null;

		boolean parentIsFunctionCall = false;
		if (pointer) {
			parentIsFunctionCall = checkIfParentIsFunction(node);
		}

		boolean tempBool = true;

		if (currentType instanceof StructureOrUnionType) {
			StructureOrUnionTypeNode stn = (StructureOrUnionTypeNode) ((StructureOrUnionType) currentType)
					.getKey();
			StructureOrUnionTypeNode copy = stn.copy();
			copy.getStructDeclList().remove();
			declarationTypeNode = copy;
			tempBool = false;
			nodesDeep = 0;
		}

		if (parentIsFunctionCall && tempBool) {
			declarationTypeNode = nodeFactory.newPointerTypeNode(
					newSource(place, CivlcTokenConstant.TYPE),
					nodeFactory.newBasicTypeNode(
							newSource(place, CivlcTokenConstant.TYPE),
							baseTypeKind));
			nodesDeep--;
			while (nodesDeep > 0) {
				declarationTypeNode = nodeFactory.newPointerTypeNode(
						newSource(place, CivlcTokenConstant.POINTER),
						declarationTypeNode);
				nodesDeep--;
			}
		} else if (tempBool) {
			declarationTypeNode = nodeFactory.newBasicTypeNode(
					newSource(place, CivlcTokenConstant.TYPE), baseTypeKind);
		}

		temp = nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION), tempID,
				declarationTypeNode);

		Pair<VariableDeclarationNode, Integer> pair = new Pair<>(temp,
				nodesDeep);

		return pair;
	}

	/**
	 * Method to transform a shared write in C to CIVL-C
	 * 
	 * @param node
	 * @param privateIDs
	 * @param sharedIDs
	 * @param reductionIDs
	 * @param firstPrivateIDs
	 * @param threadPrivateIDs
	 * @param opCode
	 * @throws SyntaxException
	 * @throws NoSuchElementException
	 */
	private void sharedWrite(IdentifierNode node,
			SequenceNode<IdentifierExpressionNode> privateIDs,
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			SequenceNode<IdentifierExpressionNode> reductionIDs,
			SequenceNode<IdentifierExpressionNode> firstPrivateIDs,
			SequenceNode<IdentifierExpressionNode> threadPrivateIDs, int opCode)
			throws SyntaxException, NoSuchElementException {
		VariableDeclarationNode temp;
		Type currentType = ((Variable) node.getEntity()).getType();
		int nodesDeep = 0;
		Type origType = currentType;
		String place = node.name() + "SharedWrite";

		Pair<VariableDeclarationNode, Integer> pair = getTempVar(node, "write",
				tempWriteCount);

		temp = pair.left;
		nodesDeep = pair.right;

		ASTNode parentOfID = null;
		String nodeName = node.name();
		node.setName(OMPPRE + node.name() + "_local");
		ExpressionStatementNode writeCall = null;
		ExpressionStatementNode readCall = null;
		ASTNode statementParent = node.parent();

		// Get the parent of the identifer that is a StatementNode
		while (!(statementParent instanceof StatementNode)) {
			statementParent = statementParent.parent();
		}
		if (nodesDeep == 0) {
			parentOfID = node.parent();
			writeCall = write((ExpressionNode) parentOfID.copy(), nodeName,
					this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "write" + String.valueOf(tempWriteCount)),
					origType);
			if (opCode == 2) {
				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						OMPPRE + "write" + String.valueOf(tempWriteCount),
						origType);
			}
		} else {
			parentOfID = node.parent();
			while (nodesDeep > 0) {
				parentOfID = parentOfID.parent();
				nodesDeep--;
			}
			if (parentOfID instanceof OperatorNode) {
				checkArrayIndices((OperatorNode) parentOfID, privateIDs,
						sharedIDs, reductionIDs, firstPrivateIDs,
						threadPrivateIDs);
			}

			writeCall = write((ExpressionNode) parentOfID.copy(), nodeName,
					this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "write" + String.valueOf(tempWriteCount)),
					origType);
			if (opCode == 2) {
				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						OMPPRE + "write" + String.valueOf(tempWriteCount),
						origType);
			}
		}

		ASTNode parent = parentOfID.parent();
		int index = parentOfID.childIndex();
		parent.setChild(index, this.identifierExpression(
				OMPPRE + "write" + String.valueOf(tempWriteCount)));

		if (opCode == 2) {
			recordSharedReadWrite("read", null, readCall, statementParent);
		}

		recordSharedReadWrite("write", temp, writeCall, statementParent);

		tempWriteCount++;
	}

	/**
	 * Record shared read and write statements so that the omp_read and
	 * omp_write statements can be inserted.
	 * 
	 * @param readWrite
	 * @param decl
	 * @param statement
	 * @param statementParent
	 */
	private void recordSharedReadWrite(String readWrite,
			VariableDeclarationNode decl, ExpressionStatementNode statement,
			ASTNode statementParent) {
		Pair<VariableDeclarationNode, ExpressionStatementNode> pair = new Pair<>(
				decl, statement);

		if (readWrite.equals("write")) {
			if (sharedWrite.containsKey(statementParent)) {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedWrite
						.get(statementParent);
				nodeToAdd.add(pair);
			} else {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> pairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
				pairs.add(pair);
				sharedWrite.put(statementParent, pairs);
			}
		} else {
			if (sharedRead.containsKey(statementParent)) {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedRead
						.get(statementParent);
				nodeToAdd.add(pair);
			} else {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> pairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
				pairs.add(pair);
				sharedRead.put(statementParent, pairs);
			}

		}
	}

	/**
	 * If the node like a for or if and more than one statement added then a
	 * body needs to be created for the for or if node
	 * 
	 * @param node
	 */
	private void createBody(ASTNode node) {
		int index = node.childIndex();
		ASTNode parent = node.parent();
		CompoundStatementNode body;
		LinkedList<BlockItemNode> items = new LinkedList<>();

		parent.removeChild(index);
		items.add((BlockItemNode) node);
		body = nodeFactory.newCompoundStatementNode(
				newSource("ForBody", CivlcTokenConstant.COMPOUND_STATEMENT),
				items);
		parent.setChild(index, body);
	}

	/**
	 * Insert a nodeToInsert in position k of the parent.
	 * 
	 * @param k
	 * @param parent
	 * @param nodeToInsert
	 */
	private void insertChildAt(int k, ASTNode parent, ASTNode nodeToInsert) {
		int numChildren = parent.numChildren();

		if (k >= numChildren) {
			parent.setChild(k, nodeToInsert);
		} else {
			ASTNode current = parent.removeChild(k);
			ASTNode next = null;
			parent.setChild(k, nodeToInsert);
			if (current != null) {
				for (int i = k + 1; i <= numChildren; i++) {
					if (i == numChildren) {
						parent.setChild(i, current);
						break;
					}
					next = parent.child(i);
					if (next != null) {
						parent.removeChild(i);
						parent.setChild(i, current);
					} else {
						parent.setChild(i, current);
						break;
					}
					current = next;

				}
			}
		}

	}

	/**
	 * Take a node that is a FunctionCallNode of some OpenMP function and
	 * replace it with an equivalent function that is a CIVL-C function
	 * 
	 * @param node
	 * @return
	 * @throws SyntaxException
	 */
	private boolean replaceOmpFunction(FunctionCallNode node)
			throws SyntaxException {
		ExpressionNode function = node.getFunction();
		String functionName = null;
		if (function instanceof IdentifierExpressionNode) {
			functionName = ((IdentifierExpressionNode) function).getIdentifier()
					.name();
		}
		ASTNode replacementNode = null;
		String place;
		if (functionName != null) {
			switch (functionName) {
				case "omp_get_num_threads" :
					place = "omp_get_num_threads->" + OMPPRE + "nthreads";
					replacementNode = this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							NTHREADS);
					break;
				case "omp_get_num_procs" :
					place = "omp_get_num_procs->1";
					replacementNode = nodeFactory.newIntegerConstantNode(
							(newSource(place, CivlcTokenConstant.IDENTIFIER)),
							"1");
					break;
				case "omp_get_max_threads" :
					place = "omp_get_max_threads->" + OMPPRE + "nthreads";
					replacementNode = this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							THREADMAX);
					break;
				case "omp_get_thread_num" :
					place = "omp_get_thread_num->" + TID;
					replacementNode = this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							TID);
					break;
				case "omp_set_num_threads" :
					place = "omp_set_num_threads->" + OMPPRE + "num_threads";
					replacementNode = nodeFactory.newOperatorNode(
							newSource(place, CivlcTokenConstant.EXPR),
							Operator.ASSIGN,
							Arrays.asList(
									this.identifierExpression(
											newSource(place,
													CivlcTokenConstant.IDENTIFIER),
											OMPPRE + "num_threads"),
									node.getArgument(0).copy()));
					break;
			}
		}

		if (replacementNode != null) {
			ASTNode parent = node.parent();
			int index = node.childIndex();
			parent.setChild(index, replacementNode);
			return true;
		}

		return false;
	}

	/**
	 * Check the operator and return an int for which operator it is TODO add
	 * more operators as needed
	 * 
	 * @param operator
	 * @return
	 */
	private int isAssignmentOperator(String operator) {
		if (operator.equals("ASSIGN")) {
			return 1;
		} else if (operator.equals("PLUSEQ")) {
			return 2;
		}
		return 0;
	}

	/**
	 * Create a declaration for each private variable inside a parallel node
	 * 
	 * @param node
	 * @param privateKind
	 * @return
	 * @throws SyntaxException
	 */
	private VariableDeclarationNode addPrivateVariable(
			IdentifierExpressionNode node, String privateKind)
			throws SyntaxException {
		VariableDeclarationNode privateVariable;

		IdentifierNode c = node.getIdentifier();
		String place = c.name() + "$omp_privateDeclaration";
		TypeNode privateType = ((VariableDeclarationNode) ((Variable) c
				.getEntity()).getFirstDeclaration()).getTypeNode().copy();
		IdentifierNode privateIdentifer;
		if (privateKind.equals("first")) {
			privateIdentifer = nodeFactory.newIdentifierNode(
					newSource(place, CivlcTokenConstant.IDENTIFIER),
					OMPPRE + c.name() + "_private");
			privateVariable = nodeFactory.newVariableDeclarationNode(
					newSource(place, CivlcTokenConstant.DECLARATION),
					privateIdentifer, privateType,
					this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							c.name()));
		} else if (privateKind.equals("reduction")) {
			privateIdentifer = nodeFactory.newIdentifierNode(
					newSource(place, CivlcTokenConstant.IDENTIFIER),
					OMPPRE + c.name() + "_reduction");
			privateVariable = nodeFactory
					.newVariableDeclarationNode(
							newSource(place, CivlcTokenConstant.DECLARATION),
							privateIdentifer, privateType,
							nodeFactory.newIntegerConstantNode(
									newSource(place,
											CivlcTokenConstant.INTEGER_CONSTANT),
									"0"));
		} else {
			privateIdentifer = nodeFactory.newIdentifierNode(
					newSource(place, CivlcTokenConstant.IDENTIFIER),
					OMPPRE + c.name() + "_private");
			privateVariable = nodeFactory.newVariableDeclarationNode(
					newSource(place, CivlcTokenConstant.DECLARATION),
					privateIdentifer, privateType);
		}
		return privateVariable;
	}

	/**
	 * Method to get a statement that is the parent of some identifier
	 * 
	 * @param node
	 * @return Node that is the parent of the IdentiferNode
	 */
	private ASTNode getParentOfID(IdentifierNode node) {
		ASTNode parent = node.parent();
		while (!(parent instanceof StatementNode
				|| parent instanceof VariableDeclarationNode)) {
			parent = parent.parent();
		}
		return parent;
	}

	private boolean checkIfParentIsFunction(IdentifierNode node) {
		boolean parentFunction = false;
		ASTNode parent = node.parent();

		while (!(parent instanceof StatementNode)) {
			if (parent instanceof FunctionCallNode) {
				parentFunction = true;
			}
			parent = parent.parent();
		}

		return parentFunction;
	}

	private void removeNodeFromParent(ASTNode node) {
		if (node != null) {
			int index = node.childIndex();
			ASTNode parent = node.parent();
			parent.removeChild(index);
		}

	}

	/**
	 * Transform shared read from C to CIVL-C
	 * 
	 * @param node
	 * @param parentStatement
	 * @param privateIDs
	 * @param sharedIDs
	 * @param reductionIDs
	 * @param firstPrivateIDs
	 * @throws SyntaxException
	 * @throws NoSuchElementException
	 */
	private void sharedRead(IdentifierNode node, BlockItemNode parentStatement,
			SequenceNode<IdentifierExpressionNode> privateIDs,
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			SequenceNode<IdentifierExpressionNode> reductionIDs,
			SequenceNode<IdentifierExpressionNode> firstPrivateIDs)
			throws SyntaxException, NoSuchElementException {

		boolean alreadyUsed = false;
		boolean write = false;
		boolean updateRead = false;
		ExpressionStatementNode writeCall = null;
		ASTNode statementParent = null;
		ASTNode parentOfID = null;

		Type currentType = ((Variable) node.getEntity()).getType();
		int nodesDeep = 0;
		VariableDeclarationNode temp;
		Type origType = currentType;

		String place = node.name() + "SharedRead";
		Pair<VariableDeclarationNode, Integer> pair = getTempVar(node, "read",
				tmpCount);

		temp = pair.left;
		nodesDeep = pair.right;

		String nodeName = null;
		for (Triple<BlockItemNode, IdentifierNode, String> triple : tempVars) {
			if (triple.second.name().equals(OMPPRE + node.name() + "_local")) {
				ASTNode parent = node.parent();
				while (parent != null) {
					if (parent.equals(triple.first)
							&& parentStatement.equals(triple.first)) {
						nodeName = node.name();

						if (nodesDeep == 0) {
							parentOfID = node.parent();
						} else {
							parentOfID = node.parent();
							while (nodesDeep > 0) {
								parentOfID = parentOfID.parent();
								nodesDeep--;
							}
						}
						int index = parentOfID.childIndex();
						ASTNode directParent = parentOfID.parent();
						alreadyUsed = true;
						statementParent = node.parent();
						while (!(statementParent instanceof StatementNode
								|| statementParent instanceof VariableDeclarationNode)) {
							if (statementParent instanceof OperatorNode) {
								if (((OperatorNode) statementParent)
										.getOperator() == Operator.POSTDECREMENT
										|| ((OperatorNode) statementParent)
												.getOperator() == Operator.POSTINCREMENT) {
									write = true;
								}

							}
							statementParent = statementParent.parent();
						}

						writeCall = write(
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										triple.second.name()),
								nodeName,
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										triple.third),
								origType);
						directParent.setChild(index,
								this.identifierExpression(
										newSource(place,
												CivlcTokenConstant.IDENTIFIER),
										triple.third));

						break;
					}
					parent = parent.parent();
				}
			}
		}

		if (!alreadyUsed) {
			statementParent = node.parent();
			while (!(statementParent instanceof StatementNode
					|| statementParent instanceof VariableDeclarationNode)) {
				if (statementParent instanceof OperatorNode) {
					if (((OperatorNode) statementParent)
							.getOperator() == Operator.POSTDECREMENT
							|| ((OperatorNode) statementParent)
									.getOperator() == Operator.POSTINCREMENT) {
						write = true;
						updateRead = true;
					}

				}
				statementParent = statementParent.parent();
			}

			nodeName = node.name();
			node.setName(OMPPRE + node.name() + "_local");
			ExpressionStatementNode readCall = null;
			statementParent = node.parent();
			while (!(statementParent instanceof StatementNode
					|| statementParent instanceof VariableDeclarationNode)) {
				statementParent = statementParent.parent();
			}
			if (nodesDeep == 0) {
				parentOfID = node.parent();
				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						OMPPRE + "read" + String.valueOf(tmpCount), origType);
			} else {
				parentOfID = node.parent();
				while (nodesDeep > 0) {
					if (!(parentOfID.parent() instanceof IfNode)) {
						parentOfID = parentOfID.parent();
					}
					nodesDeep--;
				}

				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						OMPPRE + "read" + String.valueOf(tmpCount), origType);
			}

			Triple<BlockItemNode, IdentifierNode, String> tempName = new Triple<>(
					parentStatement, node,
					OMPPRE + "read" + String.valueOf(tmpCount));
			tempVars.add(tempName);

			ASTNode parent = parentOfID.parent();
			int index = parentOfID.childIndex();
			parent.setChild(index, this.identifierExpression(
					OMPPRE + "read" + String.valueOf(tmpCount)));

			if (statementParent instanceof LoopNode
					&& ((LoopNode) statementParent).getKind().name()
							.equals("WHILE")) {
				lastLoopVar = tmpCount;
			}

			recordSharedReadWrite("read", temp, readCall, statementParent);

			writeCall = write((ExpressionNode) parentOfID.copy(), nodeName,
					this.identifierExpression(
							newSource(place, CivlcTokenConstant.IDENTIFIER),
							OMPPRE + "read" + String.valueOf(tmpCount)),
					origType);

			tmpCount++;
		}

		if (write) {
			recordSharedReadWrite("write", null, writeCall, statementParent);

			if (updateRead && lastLoopVar != -1) {
				ExpressionStatementNode updateCall = read(
						(ExpressionNode) parentOfID.copy(), nodeName,
						OMPPRE + "read" + String.valueOf(lastLoopVar),
						origType);
				recordSharedReadWrite("write", null, updateCall,
						statementParent);
				lastLoopVar = -1;
			}
		}

	}

	private void getLoopVariables(ASTNode node,
			ArrayList<String> alreadyDeclVars,
			SequenceNode<IdentifierExpressionNode> privateIDs) {
		for (ASTNode child : node.children()) {
			if (child != null) {
				if (child instanceof OmpForNode) {
					StatementNode forLoopNode = ((OmpExecutableNode) child)
							.statementNode();
					if (forLoopNode instanceof ForLoopNode) {
						ForLoopInitializerNode flin = ((ForLoopNode) forLoopNode)
								.getInitializer();
						if (flin instanceof OperatorNode) {
							getInitializerName((OperatorNode) flin,
									alreadyDeclVars, privateIDs);
						} else if (flin instanceof DeclarationListNode) {
							getInitializerName((DeclarationListNode) flin,
									alreadyDeclVars);
						}
					}
				}
				getLoopVariables(child, alreadyDeclVars, privateIDs);
			}
		}
	}

	private void getInitializerName(OperatorNode node,
			ArrayList<String> alreadyDeclVars,
			SequenceNode<IdentifierExpressionNode> privateIDs) {
		if (node.getOperator().toString().equals("ASSIGN")) {
			IdentifierExpressionNode name = (IdentifierExpressionNode) node
					.getArgument(0);
			String strName = name.getIdentifier().name();
			if (!(alreadyDeclVars.contains(strName))) {
				alreadyDeclVars.add(strName);
				Entity entity = ((IdentifierExpressionNode) name)
						.getIdentifier().getEntity();
				IdentifierExpressionNode newNode = (IdentifierExpressionNode) name
						.copy();
				newNode.getIdentifier().setEntity(entity);
				privateIDs.addSequenceChild(newNode);
			}
		} else {
			for (ASTNode child : node.children()) {
				if (child instanceof OperatorNode) {
					getInitializerName((OperatorNode) child, alreadyDeclVars,
							privateIDs);
				}
			}
		}
	}

	private void getInitializerName(DeclarationListNode node,
			ArrayList<String> loopVariables) {

	}

	private boolean getImplicitShared(
			SequenceNode<IdentifierExpressionNode> sharedIDs, ASTNode node,
			ArrayList<String> declaredNodes, ArrayList<String> currentShared,
			ArrayList<String> loopVars, boolean removed) {
		for (ASTNode child : node.children()) {
			if (child != null
					&& !(child.parent() instanceof FunctionCallNode)) {
				if (child instanceof IdentifierExpressionNode) {
					String temp = ((IdentifierExpressionNode) child)
							.getIdentifier().name();
					boolean reductionNode = false;
					if (temp.contains("_reduction")) {
						temp = temp.replace("_reduction", "");
						reductionNode = true;
					}

					ASTNode parent = child;
					boolean functionParam = false;
					boolean loopVar = false;
					while (!(parent instanceof FunctionDefinitionNode)) {
						parent = parent.parent();
					}

					parent = child;
					while (!(parent instanceof FunctionDefinitionNode)) {
						if (parent instanceof OmpForNode) {
							OmpForNode forLoop = (OmpForNode) parent;
							ASTNode forNode = forLoop.statementNode();
							for (ASTNode forChild : forNode.children()) {
								if (forChild != null && forChild.equals(node)) {
									loopVar = true;
									loopVars.add(temp);
								}
							}
						}

						parent = parent.parent();
					}

					if ((!(declaredNodes.contains(temp)
							|| currentShared.contains(temp)))
							&& !loopVars.contains(temp) && !temp.equals(TID)
							&& !functionParam && !loopVar) {
						Entity entity = ((IdentifierExpressionNode) child)
								.getIdentifier().getEntity();
						IdentifierExpressionNode newNode = (IdentifierExpressionNode) child
								.copy();
						if (reductionNode) {
							newNode.getIdentifier().setName(temp);
						}

						newNode.getIdentifier().setEntity(entity);
						sharedIDs.addSequenceChild(newNode);
						currentShared.add(temp);
					}
				}

				if (child instanceof VariableDeclarationNode) {
					ASTNode parent = child;
					boolean functionParam = false;
					while (!(parent instanceof FunctionDefinitionNode)) {
						if (parent instanceof FunctionTypeNode) {
							functionParam = true;
						}
						parent = parent.parent();
					}
					if (!functionParam) {
						String temp = ((DeclarationNode) child).getIdentifier()
								.name();
						declaredNodes.add(temp);
						if (currentShared.contains(temp)) {
							currentShared.remove(temp);
						}
						for (IdentifierExpressionNode id : sharedIDs) {
							if (id != null) {
								if (id.getIdentifier().name().equals(temp)) {
									int index = id.childIndex();
									sharedIDs.removeChild(index);
									removed = true;
								}
							}

						}
					}
				}

				removed = getImplicitShared(sharedIDs, child, declaredNodes,
						currentShared, loopVars, removed) || removed;
			}
		}
		return removed;
	}

	private void checkArrayIndices(OperatorNode op,
			SequenceNode<IdentifierExpressionNode> privateIDs,
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			SequenceNode<IdentifierExpressionNode> reductionIDs,
			SequenceNode<IdentifierExpressionNode> firstPrivateIDs,
			SequenceNode<IdentifierExpressionNode> threadPrivateIDs)
			throws SyntaxException, NoSuchElementException {
		replaceOMPPragmas(op.child(1), privateIDs, sharedIDs, reductionIDs,
				firstPrivateIDs, threadPrivateIDs);
		ASTNode lhs = op.child(0);
		while (lhs instanceof OperatorNode) {
			replaceOMPPragmas(lhs.child(1), privateIDs, sharedIDs, reductionIDs,
					firstPrivateIDs, threadPrivateIDs);
			lhs = lhs.child(0);
		}
	}

	/**
	 * 
	 * Adds appropriate headers to the program
	 * 
	 * 
	 * @param root
	 *            The root node of the AST of the original OpenMP program.
	 * @return The function definition node of OpenMP, the list of AST nodes
	 *         that are parsed from header files and will be moved up to the
	 *         higher scope (i.e., the file scope of the final AST), and the
	 *         list of variable declaration nodes.
	 * @throws SyntaxException
	 */
	private Triple<List<BlockItemNode>, List<BlockItemNode>, List<BlockItemNode>> program(
			SequenceNode<BlockItemNode> root) throws SyntaxException {
		List<BlockItemNode> includedNodes = new ArrayList<>();
		List<BlockItemNode> varDeclsAndAssumps = new ArrayList<>();
		List<String> declIndentifiers = new LinkedList<>();
		List<BlockItemNode> items;
		int number;
		items = new LinkedList<>();
		number = root.numChildren();

		final String place = "numThreadsDeclaration";
		TypeNode nthreadsType = nodeFactory.newBasicTypeNode(
				newSource(place, CivlcTokenConstant.INT), BasicTypeKind.INT);
		IdentifierNode identifierNode = nodeFactory.newIdentifierNode(
				newSource(place, CivlcTokenConstant.IDENTIFIER),
				OMPPRE + "num_threads");

		items.add(nodeFactory.newVariableDeclarationNode(
				newSource(place, CivlcTokenConstant.DECLARATION),
				identifierNode, nthreadsType,
				this.identifierExpression(
						newSource(place, CivlcTokenConstant.IDENTIFIER),
						THREADMAX)));

		for (ASTNode node : structsDefsToAdd) {
			items.add((BlockItemNode) node);
		}

		for (ASTNode node : structsToAdd) {
			items.add((BlockItemNode) node);
		}

		for (int i = 0; i < number; i++) {
			BlockItemNode child = root.getSequenceChild(i);
			String sourceFile;

			if (child == null)
				continue;
			sourceFile = child.getSource().getFirstToken().getSourceFile()
					.getName();
			root.removeChild(i);
			if (sourceFile.equals("omp.cvl")) {
				includedNodes.add(child);
			} else if (sourceFile.endsWith(".cvh")
					|| sourceFile.equals("omp.cvl")
					|| sourceFile.equals("civlc.cvl")
					|| sourceFile.equals("concurrency.cvl")
					|| sourceFile.equals("stdio.cvl")
					|| sourceFile.equals("pthread.cvl")
					|| sourceFile.equals("string.cvl"))
				includedNodes.add(child);
			else if (sourceFile.endsWith(".h")) {
				if (child.nodeKind() == NodeKind.VARIABLE_DECLARATION) {
					VariableDeclarationNode variableDeclaration = (VariableDeclarationNode) child;
					if (sourceFile.equals("stdio.h"))
						// keep variable declaration nodes from stdio, i.e.,
						// stdout, stdin, etc.
						items.add(variableDeclaration);
					else
						// ignore the MPI_COMM_WORLD declaration in mpi.h.
						includedNodes.add(child);
				} else
					includedNodes.add(child);
			} else {
				if (isRelatedAssumptionNode(child, declIndentifiers)) {
					varDeclsAndAssumps.add(child);
					continue;
				}
				if (child.nodeKind() == NodeKind.VARIABLE_DECLARATION) {
					VariableDeclarationNode variable = (VariableDeclarationNode) child;
					if (variable.getTypeNode().isInputQualified()
							|| variable.getTypeNode().isOutputQualified()) {
						declIndentifiers.add(variable.getName());
						varDeclsAndAssumps.add(variable);
						continue;
					}
				}
				items.add(child);
			}
		}

		return new Triple<>(items, includedNodes, varDeclsAndAssumps);
	}

	/**
	 * Extracting bounds and step for ranges from a Canonical ForLoopNode
	 * 
	 * @param forloopNode
	 *            The AST Node represents a canonical for loop. (Pre-condition:
	 *            The for loop should be more strictly a canonical for loop.)
	 * @return A triple of lower bound , higher bound and step
	 * @throws SyntaxException
	 */
	private Triple<ASTNode, ASTNode, ASTNode> canonicalForLoopBounds(
			ForLoopNode forloopNode) throws SyntaxException {
		IdentifierNode loopVar;
		ForLoopInitializerNode initializer;
		IdentifierExpressionNode identExpr;
		ExpressionNode conditioner;
		ExpressionNode incrementor;
		OperatorNode incNode;
		ASTNode lo = null;
		ASTNode hi = null;
		ASTNode step = null;
		ASTNode one = nodeFactory.newIntegerConstantNode((Source) null, "1");
		ASTNode zero = nodeFactory.newIntegerConstantNode((Source) null, "0");
		ASTNode newHi;
		Operator incOp, stepSign;
		boolean isNegativeIncrement = false;

		initializer = forloopNode.getInitializer();
		conditioner = forloopNode.getCondition();
		incrementor = forloopNode.getIncrementer();
		// Initializer can either be a OperatorNode or a DeclarationListNode:
		// for(i = 0;...) or for(int i = 0; ...)
		if (initializer instanceof OperatorNode) {
			// OperatorNode means it's an assignment statement e.g. i = 0;
			// So the initial value is child(1).
			lo = initializer.child(1);
			// Obtain the identifierNode of the loop variable which will be used
			// to distinguish between a loop variable and a regular variable in
			// termination and incrementor.
			loopVar = ((IdentifierExpressionNode) initializer.child(0))
					.getIdentifier();
		} else if (initializer instanceof DeclarationListNode) {
			VariableDeclarationNode varDecNode = (VariableDeclarationNode) initializer
					.child(0);

			// The initializer has a similar form as "int i = 0"
			lo = varDecNode.getInitializer();
			loopVar = (IdentifierNode) varDecNode.getIdentifier();
		} else {
			throw new CIVLSyntaxException("OpenMP for loop initializer");
		}
		// The bound value in conditioner can either be in the left hand side or
		// right hand side of a comparison operator(GT, LT, GTE, LTE).
		if (conditioner instanceof OperatorNode) {
			if (conditioner.child(0) instanceof IdentifierExpressionNode) {
				identExpr = (IdentifierExpressionNode) conditioner.child(0);

				if (identExpr.getIdentifier().getEntity()
						.equals(loopVar.getEntity()))
					hi = conditioner.child(1);
			}
			if (hi == null && conditioner
					.child(1) instanceof IdentifierExpressionNode) {
				identExpr = (IdentifierExpressionNode) conditioner.child(1);

				if (identExpr.getIdentifier().getEntity()
						.equals(loopVar.getEntity()))
					hi = conditioner.child(0);
			}
		}
		if (hi == null)
			throw new CIVLSyntaxException("OpenMP for loop conditioner");
		// Incrementor has three basic forms. e.g. i++ (--), i+=1, i = i + 1,
		// what in common is all of them are operatorNodes.
		assert incrementor instanceof OperatorNode;
		incNode = (OperatorNode) incrementor;
		incOp = incNode.getOperator();
		if (incNode.getOperator() == Operator.ASSIGN) {
			assert incrementor.child(
					1) instanceof OperatorNode : "OpenMP for loop incrementor";
			incNode = (OperatorNode) incrementor.child(1);
			incOp = incNode.getOperator();
			if (incNode.child(0) instanceof IdentifierExpressionNode) {
				if (((IdentifierExpressionNode) incNode.child(0))
						.getIdentifier().getEntity()
						.equals(loopVar.getEntity()))
					step = incNode.child(1);
			} else
				step = incNode.child(0);

		} else {
			if (incNode.numChildren() == 1)
				step = nodeFactory
						.newIntegerConstantNode(incrementor.getSource(), "1");
			else if (incNode.numChildren() == 2)
				step = incNode.child(1);
		}
		// If the incrementor increase the loop variable or decrease it.
		if (incOp == Operator.POSTDECREMENT || incOp == Operator.MINUSEQ
				|| incOp == Operator.MINUS) {
			step = nodeFactory.newOperatorNode(incrementor.getSource(),
					Operator.MINUS, Arrays.asList((ExpressionNode) zero.copy(),
							(ExpressionNode) step.copy()));
			isNegativeIncrement = true;
		}
		newHi = nodeFactory.newOperatorNode(
				newSource("rangeHi", CivlcTokenConstant.EXPR), Operator.PLUS,
				Arrays.asList((ExpressionNode) lo.copy(),
						(ExpressionNode) hi.copy()));
		// If the termination bound is open, change the bound by one. (Since
		// canonical only accept integer loop variable, it's safe)
		if (((OperatorNode) conditioner).getOperator() == Operator.LT
				|| ((OperatorNode) conditioner).getOperator() == Operator.GT) {
			if (isNegativeIncrement) {
				stepSign = Operator.PLUS;
			} else
				stepSign = Operator.MINUS;
			newHi = nodeFactory.newOperatorNode(
					newSource("rangeHi", CivlcTokenConstant.EXPR), stepSign,
					Arrays.asList((ExpressionNode) hi.copy(),
							(ExpressionNode) one.copy()));
		} else
			newHi = hi.copy();
		// Since $range will always put the larger value at the right hand side
		// of the "..", so if the operator of the incrementor is -- -= or -, we
		// have to switch the high bound and the lower bound.
		if (isNegativeIncrement) {
			ASTNode temp = newHi;

			newHi = lo;
			lo = temp;
		}
		return new Triple<>(lo, newHi, step);
	}

	private void fix_duplicated_barrier_flush(ASTNode root, boolean isMain) {
		this.reduceDuplicateNode(root, new NodePredicate() {
			@Override
			public boolean holds(ASTNode node) {
				return isFunctionCallStatementNodeOf(node,
						"$omp_barrier_and_flush");

			}
		});

	}

	private boolean isFunctionCallStatementNodeOf(ASTNode node,
			String function) {
		if (node instanceof ExpressionStatementNode) {
			ExpressionNode expression = ((ExpressionStatementNode) node)
					.getExpression();

			if (expression instanceof FunctionCallNode) {
				ExpressionNode functionNode = ((FunctionCallNode) expression)
						.getFunction();

				if (functionNode instanceof IdentifierExpressionNode) {
					return ((IdentifierExpressionNode) functionNode)
							.getIdentifier().name().equals(function);
				}
			}
		}
		return false;
	}

}