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.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.ArrowNode;
import edu.udel.cis.vsl.abc.ast.node.IF.expression.CastNode;
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.expression.SizeofNode;
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.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.OmpExecutableNode;
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.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.parse.IF.CParser;
import edu.udel.cis.vsl.abc.parse.IF.OmpCParser;
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.model.IF.CIVLSyntaxException;
import edu.udel.cis.vsl.civl.util.IF.Pair;
import edu.udel.cis.vsl.civl.util.IF.Triple;

public class OpenMP2CIVLWorker extends BaseWorker {

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

	private static String OMP_SET_LOCK = "omp_set_lock";

	private static String OMP_UNSET_LOCK = "omp_unset_lock";

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

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

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

	/**
	 * The name of $omp_team type in the final CIVL-C program.
	 */
	private 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 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 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 static String NTHREADS = "_nthreads";

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

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

	/* **************************** Instance Fields ************************* */

	/**
	 * There are new nodes created by the transformer, other than parsing from
	 * some source file. All new nodes share the same source.
	 */
	@SuppressWarnings("unused")
	private Source source;

	/**
	 * 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>>();
	
	/**
	 * 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("OpenMPtoCIVLTransformer", 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;

				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,
							CParser.ARGUMENT_LIST), "Actual parameters", Arrays
							.asList(oldArg, this.identifierExpression(
									this.newSource(TEAM, CParser.IDENTIFIER),
									TEAM)));
					funcCall.setArguments(newArgs);
				}
			}
			processOmpLockCalls(child);
		}
	}

	/**
	 * Creates the declaration node for the input variable
	 * <code>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>THREAD_MAX</code>.
	 */
	private VariableDeclarationNode threadMaxDeclaration() {
		final String place = "threadMaxDeclaration";
		TypeNode nthreadsType = nodeFactory.newBasicTypeNode(
				newSource(place, CParser.INT), BasicTypeKind.INT);
		IdentifierNode identifierNode = nodeFactory.newIdentifierNode(
				newSource(place, CParser.IDENTIFIER), THREADMAX);

		nthreadsType.setInputQualified(true);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CParser.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, CParser.TYPE), GTEAM_TYPE),
				null);
		gteamCreate = nodeFactory
				.newFunctionCallNode(
						newSource(place, CParser.CALL),
						this.identifierExpression(
								newSource(place, CParser.IDENTIFIER),
								GTEAM_CREATE),
						Arrays.asList(nodeFactory.newHereNode(newSource(place,
								CParser.HERE)), this.identifierExpression(
								newSource(place, CParser.IDENTIFIER), NTHREADS)),
						null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CParser.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CParser.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, CParser.TYPE), TEAM_TYPE),
				null);
		teamCreate = nodeFactory
				.newFunctionCallNode(newSource(place, CParser.CALL), this
						.identifierExpression(
								newSource(place, CParser.IDENTIFIER),
								TEAM_CREATE),
						Arrays.asList(nodeFactory.newHereNode(newSource(place,
								CParser.HERE)), this.identifierExpression(
								newSource(place, CParser.IDENTIFIER), GTEAM),
								this.identifierExpression(
										newSource(place, CParser.IDENTIFIER),
										TID)), null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CParser.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CParser.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, CParser.AMPERSAND),
						Operator.ADDRESSOF,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.IDENTIFIER),
								variable.name())));

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

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

		gsharedCreate = nodeFactory.newFunctionCallNode(
				newSource(place, CParser.CALL), this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), GSHARED_CREATE),
				Arrays.asList(
						this.identifierExpression(
								newSource(place, CParser.IDENTIFIER), GTEAM),
						addressOf), null);
		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CParser.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CParser.IDENTIFIER), 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, CParser.TYPE),
						SHARED_TYPE), null);
		ExpressionNode addressOfLocalVar = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), variable.name()
								+ "_local")));
		ExpressionNode addressOfStatusVar = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), variable.name()
								+ "_status")));

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

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

		return nodeFactory.newVariableDeclarationNode(
				newSource(place, CParser.DECLARATION),
				nodeFactory.newIdentifierNode(
						newSource(place, CParser.IDENTIFIER), 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, CParser.IDENTIFIER), "$omp_" + type
						+ "_destroy");

		return nodeFactory.newExpressionStatementNode(nodeFactory
				.newFunctionCallNode(
						newSource(place, CParser.CALL),
						function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.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, CParser.IDENTIFIER), "$omp_barrier_and_flush");

		return nodeFactory.newExpressionStatementNode(nodeFactory
				.newFunctionCallNode(
						newSource(place, CParser.CALL),
						function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.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, CParser.IDENTIFIER), "$omp_write");
		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND), Operator.ADDRESSOF,
				Arrays.asList(variable));
		
		if (origType instanceof QualifiedObjectType && ((QualifiedObjectType) origType).isVolatileQualified()) {
			addressOfVar = nodeFactory.newCastNode(
					newSource(place, CParser.CAST),
					nodeFactory.newPointerTypeNode(newSource(place, CParser.TYPE),
							nodeFactory.newVoidTypeNode(newSource(place, CParser.VOID))),
							addressOfVar);
		}
		
		ExpressionNode addressOfTmp = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND), Operator.ADDRESSOF,
				Arrays.asList(writeName));
		return nodeFactory.newExpressionStatementNode(nodeFactory
				.newFunctionCallNode(newSource(place, CParser.CALL), function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.IDENTIFIER),
								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, CParser.IDENTIFIER), "$omp_read");

		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND), Operator.ADDRESSOF,
				Arrays.asList(parent));
		
		if (origType instanceof QualifiedObjectType && ((QualifiedObjectType) origType).isVolatileQualified()) {
			addressOfVar = nodeFactory.newCastNode(
					newSource(place, CParser.CAST),
					nodeFactory.newPointerTypeNode(newSource(place, CParser.TYPE),
							nodeFactory.newVoidTypeNode(newSource(place, CParser.VOID))),
							addressOfVar);
		}
		
		ExpressionNode addressOfTmp = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), tmpName)));
		return nodeFactory.newExpressionStatementNode(nodeFactory
				.newFunctionCallNode(newSource(place, CParser.CALL), function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.IDENTIFIER),
								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, CParser.IDENTIFIER), "$omp_apply_assoc");
		ExpressionNode addressOfVar = nodeFactory.newOperatorNode(
				newSource(place, CParser.AMPERSAND),
				Operator.ADDRESSOF,
				Arrays.asList(this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), variable
								+ "$omp_reduction")));
		if (operation.equals("PLUSEQ")) {
			operation = "CIVL_SUM";
			// op = nodeFactory.newIntegerConstantNode(source, representation)
		}

		return nodeFactory.newExpressionStatementNode(nodeFactory
				.newFunctionCallNode(newSource(place, CParser.CALL), function,
						Arrays.asList(this.identifierExpression(
								newSource(place, CParser.IDENTIFIER), variable
										+ "_shared"), nodeFactory
								.newIntegerConstantNode(newSource(place, CParser.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 {
		root = ast.getRootNode();
		AST newAst;
		List<BlockItemNode> externalList;
		VariableDeclarationNode threadMax;
		SequenceNode<BlockItemNode> newRootNode;
		List<BlockItemNode> includedNodes = new ArrayList<>();
		List<VariableDeclarationNode> mainParameters = new ArrayList<>();
		int count;
		Triple<List<BlockItemNode>, List<BlockItemNode>, List<VariableDeclarationNode>> result;
		String criticalDeclaration = "criticalDeclarations";
		AST civlcAST = this.parseSystemLibrary("civlc.cvh");
		AST civlcOmpAST = this.parseSystemLibrary("civl-omp.cvh");

		this.source = root.getSource();
		assert this.astFactory == ast.getASTFactory();
		assert this.nodeFactory == astFactory.getNodeFactory();
		ast.release();
		
		// declaring $input int THREAD_MAX;
		threadMax = this.threadMaxDeclaration();
		
		SequenceNode<IdentifierExpressionNode> threadPrivateList;
		
		List<IdentifierExpressionNode> list = new LinkedList<IdentifierExpressionNode>();
		threadPrivateList = nodeFactory.newSequenceNode(newSource("threadList", CParser.ARGUMENT_LIST), "threadPrivateList",
					list);
		
		
		// Recursive call to replace all omp code
		replaceOMPPragmas(root, null, null, null, null, threadPrivateList);

		for (ASTNode key : sharedWrite.keySet()) {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> statements = sharedWrite
					.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 (key instanceof ForLoopNode) {
					insertChildAt(index + i + 1, key.parent(), pair.right);
					i++;
				} else {
					insertChildAt(index + i + 1, key.parent(), pair.right);
					i++;
				}
			}
		}
		for (ASTNode key : sharedRead.keySet()) {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> statements = sharedRead
					.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++;
				}
				if (pair.right != null) {
					insertChildAt(index + i, key.parent(), pair.right);
					i++;
				}
			}
		}

		result = this.program(root);
		includedNodes = result.second;
		mainParameters = 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 = mainParameters.size();
		// adding nodes from the arguments of the original main function.
		for (int i = 0; i < count; i++) {
			externalList.add(mainParameters.get(i));
		}
		// Add threadMax declaration
		externalList.add(threadMax);
		for (String name : criticalNames) {
			externalList.add(nodeFactory.newVariableDeclarationNode(
					newSource(criticalDeclaration, CParser.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(criticalDeclaration, CParser.IDENTIFIER),
							name), nodeFactory.newBasicTypeNode(
							newSource(criticalDeclaration, CParser.BOOL),
							BasicTypeKind.BOOL), nodeFactory
							.newBooleanConstantNode(
									newSource(criticalDeclaration,
											CParser.FALSE), false)));
		}
		
		//addParallelDataStruct(externalList);
		
		externalList.addAll(result.first);
		newRootNode = nodeFactory.newSequenceNode(null, "TranslationUnit",
				externalList);
		completeSources(newRootNode);
		this.processOmpLockCalls(newRootNode);
		newAst = astFactory.newAST(newRootNode, ast.getSourceFiles());
		newAst = this.combineASTs(civlcOmpAST, newAst);
		newAst = this.combineASTs(civlcAST, newAst);
		//newAst.prettyPrint(System.out, true);
		return newAst;
	}

	@SuppressWarnings("unchecked")
	private void replaceOMPPragmas(ASTNode node,
			SequenceNode<IdentifierExpressionNode> privateIDs,
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			SequenceNode<IdentifierExpressionNode> reductionIDs,
			SequenceNode<IdentifierExpressionNode> firstPrivateIDs,
			SequenceNode<IdentifierExpressionNode> threadPrivateIDs)
			throws SyntaxException {
		
		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;
					}
				}
			}
			
			
		}
		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(THREAD_MAX);
			String nthreadDeclaration = "_nthreadsDeclaration";
			VariableDeclarationNode nthreads;
			ExpressionNode add;
			ExpressionNode numThreads = ((OmpParallelNode) node).numThreads();

			removeNodeFromParent(numThreads);

			if (numThreads == null) {
				numThreads = this.identifierExpression(
						newSource(nthreadDeclaration, CParser.IDENTIFIER),
						"$omp_numThreads");
			}

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

			nthreads = nodeFactory.newVariableDeclarationNode(
					newSource(parallelNode, CParser.DECLARATION), nodeFactory
							.newIdentifierNode(
									newSource(nthreadDeclaration,
											CParser.IDENTIFIER), "_nthreads"),
					nodeFactory.newBasicTypeNode(
							newSource(nthreadDeclaration, CParser.INT),
							BasicTypeKind.INT), add);
			items.add(nthreads);

			// $range thread_range = 0 .. nthreads-1;
			String threadRangeDeclaration = "thread_rangeDeclaration";
			VariableDeclarationNode threadRange;
			threadRange = nodeFactory
					.newVariableDeclarationNode(
							newSource(parallelNode, CParser.DECLARATION),
							nodeFactory
									.newIdentifierNode(
											newSource(threadRangeDeclaration,
													CParser.IDENTIFIER),
											"thread_range"),
							nodeFactory.newRangeTypeNode(newSource(
									threadRangeDeclaration, CParser.RANGE)),
							nodeFactory.newRegularRangeNode(
									newSource(threadRangeDeclaration,
											CParser.RANGE),
									nodeFactory.newIntegerConstantNode(
											newSource(threadRangeDeclaration,
													CParser.INTEGER_CONSTANT),
											"0"),
									nodeFactory.newOperatorNode(
											newSource(threadRangeDeclaration,
													CParser.SUB),
											Operator.MINUS,
											Arrays.asList(
													this.identifierExpression(
															newSource(
																	threadRangeDeclaration,
																	CParser.IDENTIFIER),
															"_nthreads"),
													nodeFactory
															.newIntegerConstantNode(
																	newSource(
																			threadRangeDeclaration,
																			CParser.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, CParser.STRUCT),
					(DesignationNode) null,
					(InitializerNode) this.identifierExpression(
							newSource(domainDeclaration, CParser.IDENTIFIER),
							"thread_range")));
			CompoundInitializerNode temp = nodeFactory
					.newCompoundInitializerNode(
							newSource(domainDeclaration,
									CParser.INITIALIZER_LIST), initList);
			CompoundLiteralNode cln = nodeFactory.newCompoundLiteralNode(
					newSource(domainDeclaration, CParser.COMPOUND_LITERAL),
					nodeFactory.newDomainTypeNode(newSource(domainDeclaration,
							CParser.DOMAIN)), temp);

			VariableDeclarationNode loopDomain;
			loopDomain = nodeFactory.newVariableDeclarationNode(
					newSource(parallelNode, CParser.DECLARATION), nodeFactory
							.newIdentifierNode(
									newSource(domainDeclaration,
											CParser.IDENTIFIER), "dom"),
					nodeFactory.newDomainTypeNode(
							newSource(domainDeclaration, CParser.DOMAIN),
							nodeFactory.newIntegerConstantNode(
									newSource(domainDeclaration,
											CParser.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");
			
			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", CParser.ARGUMENT_LIST), "sharedList",
						list);
			}
			boolean removed = getImplicitShared(sharedList, node,
					alreadyDeclVars, implicitShared, 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", CParser.ARGUMENT_LIST), "sharedList",
						list);
			}

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

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

			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", CParser.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);
					}
				}
			}
			/*
			String parData = "parData";
			TypedefNameNode parTeamArr = nodeFactory.newTypedefNameNode(nodeFactory.newIdentifierNode(newSource(parData, CParser.TYPE), "$omp_team"), null);
			PointerTypeNode dblpointerType = nodeFactory.newPointerTypeNode(newSource(parData, CParser.TYPE), nodeFactory.newPointerTypeNode(newSource(parData, CParser.TYPE), parTeamArr));
			PointerTypeNode pointerType = nodeFactory.newPointerTypeNode(newSource(parData, CParser.TYPE), parTeamArr.copy());

			CastNode mallocFunc = createMalloc(dblpointerType, pointerType, numThreads.copy());
			IdentifierExpressionNode parDataName = (IdentifierExpressionNode) this.identifierExpression(newSource(parData, CParser.IDENTIFIER), "parallelDataArr");
			OperatorNode mallocExp = nodeFactory.newOperatorNode(newSource(parData, CParser.EXPR), Operator.ASSIGN, Arrays.asList(parDataName ,mallocFunc));
			
			ExpressionStatementNode mallocParData = nodeFactory.newExpressionStatementNode(mallocExp);
			items.add(mallocParData);
			*/
			CivlForNode cfn;

			// Create the ForLoopInitializerNode for the CIVLForNode
			String parFor = "parFor";
			ForLoopInitializerNode initializerNode;
			initializerNode = nodeFactory.newForLoopInitializerNode(
					newSource(parFor, CParser.INITIALIZER_LIST),
					Arrays.asList(nodeFactory.newVariableDeclarationNode(
							newSource(parFor, CParser.DECLARATION),
							nodeFactory.newIdentifierNode(
									newSource(parFor, CParser.IDENTIFIER),
									"_tid"), nodeFactory.newBasicTypeNode(
									newSource(parFor, CParser.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,
												CParser.IDENTIFIER), c.name()
												+ "_local");
						IdentifierNode statusSharedIdentifer = nodeFactory
								.newIdentifierNode(
										newSource(c.name() + statusDeclaration,
												CParser.IDENTIFIER), 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", CParser.TYPE), nodeFactory.newBasicTypeNode(
												newSource(localDeclaration,
														CParser.TYPE),
												baseTypeKind));
							}
						}

						localSharedVar = nodeFactory
								.newVariableDeclarationNode(
										newSource(localDeclaration,
												CParser.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,
													CParser.INT),
											BasicTypeKind.INT));
							statusSharedVar = nodeFactory
									.newVariableDeclarationNode(
											newSource(statusDeclaration,
													CParser.DECLARATION),
											statusSharedIdentifer,
											baseStatusType);

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

							TypedefDeclarationNode structDef = nodeFactory
									.newTypedefDeclarationNode(
											newSource(statusDeclaration,
													CParser.DECLARATION),
											nodeFactory
													.newIdentifierNode(
															newSource(
																	statusDeclaration,
																	CParser.DECLARATION),
															status.getName()
																	.name()),
											nodeFactory
													.newStructOrUnionTypeNode(
															newSource(
																	statusDeclaration,
																	CParser.DECLARATION),
															true,
															nodeFactory
																	.newIdentifierNode(
																			newSource(
																					statusDeclaration,
																					CParser.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,
														CParser.DECLARATION),
												field.getName());

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

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

								fieldList.add(fieldToAdd);
							}

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

							StructureOrUnionTypeNode structTypeToAdd = nodeFactory
									.newStructOrUnionTypeNode(
											newSource(statusDeclaration,
													CParser.DECLARATION),
											true,
											nodeFactory
													.newIdentifierNode(
															newSource(
																	statusDeclaration,
																	CParser.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,
													CParser.DECLARATION),
											statusSharedIdentifer,
											nodeFactory.newBasicTypeNode(
													newSource(
															statusDeclaration,
															CParser.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);
				}
			}
			
			/*
			//Team
			String teamArr = "teamArray";
			ExpressionNode teamIDX = this.identifierExpression(newSource(teamArr, CParser.IDENTIFIER), "team");			
			ExpressionNode arrName = nodeFactory.newIdentifierExpressionNode(newSource(teamArr, CParser.IDENTIFIER), nodeFactory.newIdentifierNode(newSource(teamArr, CParser.IDENTIFIER), "parallelDataArr"));
			ExpressionNode currThread = nodeFactory.newIdentifierExpressionNode(newSource(teamArr, CParser.IDENTIFIER), nodeFactory.newIdentifierNode(newSource(teamArr, CParser.IDENTIFIER), "_tid"));
			ExpressionNode parDataIndex = nodeFactory.newOperatorNode(newSource(teamArr, CParser.EXPR), Operator.SUBSCRIPT,  Arrays.asList(arrName, currThread));
			
			OperatorNode teamAssignOp = nodeFactory.newOperatorNode(newSource(teamArr, CParser.EXPR), Operator.ASSIGN, Arrays.asList(parDataIndex, nodeFactory.newOperatorNode(newSource(teamArr, CParser.EXPR), Operator.ADDRESSOF, Arrays.asList(teamIDX))));
			ExpressionStatementNode teamAssign = nodeFactory.newExpressionStatementNode(teamAssignOp);
			parForItems.add(teamAssign);
			*/
			
			// 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", c.name() + "_shared"));
					}
				}
			}

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

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

			// Create $par_for loop
			cfn = nodeFactory.newCivlForNode(
					newSource(parallelNode, CParser.CIVLFOR),
					true,
					(DeclarationListNode) initializerNode,
					this.identifierExpression(
							newSource(parFor, CParser.IDENTIFIER), "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", c.name() + "_gshared"));
					}
				}
			}

			// $omp_gteam_destroy(gteam);
			items.add(destroy("gteam", "gteam"));
			
			/*
			//add free(parallelDataArr)
			ExpressionNode freeName = this.identifierExpression(newSource("free", CParser.IDENTIFIER), "$free");
			ExpressionNode parName = this.identifierExpression(newSource("free", CParser.IDENTIFIER), "parallelDataArr");
			FunctionCallNode freeArr = nodeFactory.newFunctionCallNode(source, freeName, Arrays.asList(parName), null);
			items.add(nodeFactory.newExpressionStatementNode(freeArr));
			*/
			// Create the CompoundStatementNode of that replaces the
			// OmpParallelNode
			pragmaBody = nodeFactory.newCompoundStatementNode(
					newSource(parallelNode, OmpCParser.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) {
			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";
			//ASTNode numIterations = null;

			// 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);
				//numIterations = lo_hi_step.second;
				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, CParser.DECLARATION),
						nodeFactory.newIdentifierNode(
								newSource(range, CParser.IDENTIFIER), "r"
										+ Integer.toString(rangeNumber + 1)),
						nodeFactory.newRangeTypeNode(newSource(range,
								CParser.RANGE)), nodeFactory
								.newRegularRangeNode(
										newSource(range, CParser.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, CParser.STRUCT),
						(DesignationNode) null, (InitializerNode) this
								.identifierExpression(
										newSource(domainDeclaration,
												CParser.IDENTIFIER), "r"
												+ Integer.toString(k))));
			}

			CompoundInitializerNode temp = nodeFactory
					.newCompoundInitializerNode(
							newSource(domainDeclaration,
									CParser.INITIALIZER_LIST), initList);
			CompoundLiteralNode cln = nodeFactory.newCompoundLiteralNode(
					newSource(domainDeclaration, CParser.COMPOUND_LITERAL),
					nodeFactory.newDomainTypeNode(newSource(domainDeclaration,
							CParser.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, CParser.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(domainDeclaration, CParser.IDENTIFIER),
							"loop_domain"), nodeFactory.newDomainTypeNode(
							newSource(domainDeclaration, CParser.DOMAIN),
							nodeFactory.newIntegerConstantNode(
									newSource(domainDeclaration,
											CParser.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, CParser.CAST),
							nodeFactory.newDomainTypeNode(
									newSource(myItersPlace, CParser.DOMAIN),
									nodeFactory.newIntegerConstantNode(
											newSource(myItersPlace,
													CParser.INTEGER_CONSTANT),
											Integer.toString(collapseLevel))),
							nodeFactory.newFunctionCallNode(
									newSource(myItersPlace, CParser.CALL),
									this.identifierExpression(
											newSource(myItersPlace,
													CParser.IDENTIFIER),
											"$omp_arrive_loop"),
									Arrays.asList(
											this.identifierExpression(
													newSource(myItersPlace,
															CParser.IDENTIFIER),
													TEAM),
											nodeFactory
													.newIntegerConstantNode(
															newSource(
																	myItersPlace,
																	CParser.INTEGER_CONSTANT),
															this.ompArriveLoopCounter
																	+ ""),
											nodeFactory
													.newCastNode(
															newSource(
																	myItersPlace,
																	CParser.CAST),
															nodeFactory
																	.newDomainTypeNode(newSource(
																			myItersPlace,
																			CParser.DOMAIN)),
															this.identifierExpression(
																	newSource(
																			myItersPlace,
																			CParser.IDENTIFIER),
																	"loop_domain")),
											nodeFactory
													.newIntegerConstantNode(
															newSource(
																	myItersPlace,
																	CParser.INTEGER_CONSTANT),
															String.valueOf(loopDecomp))),
									null));
			this.ompArriveLoopCounter++;
			// Get correct level "n" for domain(n)
			IntegerConstantNode domainLevel = nodeFactory
					.newIntegerConstantNode(
							newSource(myItersPlace, CParser.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, CParser.DECLARATION),
					nodeFactory.newIdentifierNode(
							newSource(myItersPlace, CParser.IDENTIFIER),
							"my_iters"), nodeFactory.newDomainTypeNode(
							newSource(myItersPlace, CParser.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, CParser.DECLARATION), var.copy(),
						nodeFactory.newBasicTypeNode(
								newSource(civlFor, CParser.INT),
								BasicTypeKind.INT)));
			}

			initializerNode = nodeFactory.newForLoopInitializerNode(
					newSource(civlFor, CParser.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, CParser.COMPOUND_STATEMENT), forItems);

			// Create $for node with the original for body as its body
			cfn = nodeFactory.newCivlForNode(
					newSource(forNode, CParser.CIVLFOR), false,
					(DeclarationListNode) initializerNode,
					nodeFactory.newIdentifierExpressionNode(
							newSource(civlFor, CParser.INITIALIZER_LIST),
							nodeFactory.newIdentifierNode(
									newSource(civlFor, CParser.IDENTIFIER),
									"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", CParser.IDENTIFIER), name + "$omp_private");
					OperatorNode expression = nodeFactory.newOperatorNode(newSource("lastPrivate", CParser.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", CParser.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, CParser.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, CParser.IDENTIFIER),
						nodeFactory
								.newIdentifierNode(
										newSource(syncNode, CParser.IDENTIFIER),
										"_tid")));
				operands.add(nodeFactory.newIntegerConstantNode(
						newSource(syncNode, CParser.INTEGER_CONSTANT), "0"));
				int i = 0;
				for (ASTNode child : node.children()) {
					node.removeChild(i);
					items.add((BlockItemNode) child);
					i++;
				}
				body = nodeFactory.newCompoundStatementNode(
						newSource(syncNode, CParser.COMPOUND_STATEMENT), items);
				IfNode ifStatement = nodeFactory.newIfNode(
						newSource(syncNode, CParser.IF), nodeFactory
								.newOperatorNode(
										newSource(syncNode, CParser.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, CParser.COMPOUND_STATEMENT), items);
				
				atomicNode = nodeFactory.newAtomicStatementNode(newSource(atomicSrc, CParser.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, CParser.NOT), Operator.NOT, Arrays
								.asList(this
										.identifierExpression(
												newSource(syncNode,
														CParser.IDENTIFIER),
												criticalName)));
				ExpressionStatementNode criticalTrue = nodeFactory
						.newExpressionStatementNode(nodeFactory.newOperatorNode(
								newSource(syncNode, CParser.ASSIGN),
								Operator.ASSIGN, Arrays.asList(this
										.identifierExpression(
												newSource(syncNode,
														CParser.IDENTIFIER),
												criticalName), nodeFactory
										.newBooleanConstantNode(
												newSource(syncNode,
														CParser.TRUE), true))));

				// Create and add when node
				// $when (!_critical_a) _critical_a=$true;
				items.add(nodeFactory.newWhenNode(
						newSource(syncNode, CParser.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", CParser.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, CParser.ASSIGN),
								Operator.ASSIGN, Arrays.asList(this
										.identifierExpression(
												newSource(syncNode,
														CParser.IDENTIFIER),
												criticalName), nodeFactory
										.newBooleanConstantNode(
												newSource(syncNode,
														CParser.FALSE), false))));
				items.add(criticalFalse);

				// Add body to the CompoundstatementNode and replace the omp
				// critical node with the CompoundStatementNode
				body = nodeFactory.newCompoundStatementNode(
						newSource(syncNode, CParser.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, CParser.CALL),
								this.identifierExpression(
										newSource(sectionsPlace,
												CParser.IDENTIFIER),
										"$omp_arrive_sections"),
								Arrays.asList(
										this.identifierExpression(
												newSource(sectionsPlace,
														CParser.IDENTIFIER),
												TEAM),
										nodeFactory
												.newIntegerConstantNode(
														newSource(
																sectionsPlace,
																CParser.INTEGER_CONSTANT),
														String.valueOf(this.ompArriveSections)),
										nodeFactory
												.newIntegerConstantNode(
														newSource(
																sectionsPlace,
																CParser.INTEGER_CONSTANT),
														String.valueOf(numberSections))),
								null);
				this.ompArriveSections++;
				String mySecDeclaration = "my_secsDeclaration";
				VariableDeclarationNode my_secs;
				my_secs = nodeFactory
						.newVariableDeclarationNode(
								newSource(sectionsPlace, CParser.DECLARATION),
								nodeFactory.newIdentifierNode(
										newSource(mySecDeclaration,
												CParser.IDENTIFIER), "my_secs"),
								nodeFactory.newDomainTypeNode(
										newSource(mySecDeclaration,
												CParser.DOMAIN),
										nodeFactory
												.newIntegerConstantNode(
														newSource(
																mySecDeclaration,
																CParser.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, CParser.INITIALIZER_LIST),
								Arrays.asList(nodeFactory
										.newVariableDeclarationNode(
												newSource(civlFor,
														CParser.DECLARATION),
												nodeFactory
														.newIdentifierNode(
																newSource(
																		civlFor,
																		CParser.IDENTIFIER),
																"i$omp"),
												nodeFactory.newBasicTypeNode(
														newSource(civlFor,
																CParser.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,
							CParser.BREAK)));
					caseBody = nodeFactory.newCompoundStatementNode(
							newSource(caseItem, CParser.COMPOUND_STATEMENT),
							caseItems);
					SwitchLabelNode labelDecl = nodeFactory
							.newCaseLabelDeclarationNode(
									newSource(caseItem, CParser.CASE),
									nodeFactory.newIntegerConstantNode(
											newSource(caseItem,
													CParser.INTEGER_CONSTANT),
											String.valueOf(caseNumber)),
									caseBody);
					switchItems.add(nodeFactory
							.newLabeledStatementNode(
									newSource(caseItem,
											CParser.CASE_LABELED_STATEMENT),
									labelDecl, caseBody));
					caseNumber++;
				}
				switchBody = nodeFactory.newCompoundStatementNode(
						newSource(civlFor, CParser.COMPOUND_STATEMENT),
						switchItems);
				forItems.add(nodeFactory.newSwitchNode(
						newSource(civlFor, CParser.SWITCH), this
								.identifierExpression(
										newSource(civlFor, CParser.IDENTIFIER),
										"i$omp"), switchBody));
				forBody = nodeFactory.newCompoundStatementNode(
						newSource(civlFor, CParser.COMPOUND_STATEMENT),
						forItems);

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

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

				CompoundStatementNode sectionBody = nodeFactory
						.newCompoundStatementNode(
								newSource(sectionsPlace,
										CParser.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", CParser.IDENTIFIER_LIST),
							"sharedList", list);
					sharedIDs = newSharedList;
				}

				String singlePlace = "single";
				ExpressionNode arriveSingle = nodeFactory
						.newFunctionCallNode(newSource("arrive", CParser.CALL), this.identifierExpression(
								newSource("arrive", CParser.IDENTIFIER), "$omp_arrive_single"), Arrays.asList(
								this.identifierExpression(newSource("arrive", CParser.IDENTIFIER), TEAM),
								nodeFactory.newIntegerConstantNode(newSource("arrive", CParser.INTEGER_CONSTANT),
										this.ompArriveSingle + "")), null);
				this.ompArriveSingle++;
				items.add(nodeFactory.newVariableDeclarationNode(
						newSource(singlePlace, CParser.DECLARATION),
						nodeFactory.newIdentifierNode(
								newSource(singlePlace, CParser.IDENTIFIER),
								"owner"), nodeFactory.newBasicTypeNode(
								newSource(singlePlace, CParser.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,
													CParser.IDENTIFIER),
											c.name() + "$omp_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,
															CParser.IDENTIFIER),
													nodeFactory
															.newBasicTypeNode(
																	newSource(
																			localDeclaration,
																			CParser.TYPE),
																	baseTypeKind));
								}
							}

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

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

				List<ExpressionNode> operands = new ArrayList<ExpressionNode>();
				operands.add(this.identifierExpression(
						newSource(singlePlace, CParser.IDENTIFIER), "owner"));
				operands.add(this.identifierExpression(
						newSource(singlePlace, CParser.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, CParser.COMPOUND_STATEMENT),
						ifItems);

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

						ExpressionNode expression = nodeFactory
								.newOperatorNode(
										newSource("copyPrivate", CParser.EXPR),
										Operator.ASSIGN,
										Arrays.asList(
												this.identifierExpression(
														newSource("copyPrivate", CParser.IDENTIFIER), c.name()),
												this.identifierExpression(
														newSource("copyPrivate", CParser.IDENTIFIER),
														c.name()
																+ "$omp_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, CParser.IF), nodeFactory
								.newOperatorNode(
										newSource(singlePlace, CParser.EQUALS),
										Operator.EQUALS, operands), ifBody);
				items.add(ifStatement);
				items.add(barrierAndFlush(TEAM));
				body = nodeFactory.newCompoundStatementNode(
						newSource(singlePlace, CParser.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) {
				/*
				String funcName = ((IdentifierExpressionNode) ((FunctionCallNode) node).getFunction()).getIdentifier().name();
				if(callees != null){
					for(Function call : callees){
						if(call.getName().equals(funcName)){
							FunctionDefinitionNode orphan = call.getDefinition();
							replaceOMPPragmas(orphan, privateIDs, sharedIDs,
									reductionIDs, firstPrivateIDs, threadPrivateIDs, callees);
							
							//Replace shared names and _tid
							boolean shared = checkSharedAndTid(orphan, sharedIDs);
							
							//Insert the needed functions
							if(shared){
								ASTNode parent = node;
								
								int insertAt = sharedIDs.numChildren()*3 + 1;
								while(parent != null){
									if(parent.getSource().getSummary(false).contains("parallelPragma")){
										CompoundStatementNode body = (CompoundStatementNode) ((CivlForNode) parent).getBody();
										FunctionDefinitionNode copy = orphan.copy();
										orphan.remove();
										//copy.setEntity(orphan.getEntity());
										insertChildAt(insertAt, body, copy);
										
										replaceOMPPragmas(copy, privateIDs, sharedIDs,
												reductionIDs, firstPrivateIDs, threadPrivateIDs, callees);
										
										System.out.println("HERE");
										break;
									}
									parent = parent.parent();
								}
							}
							
							/*
							if(shared){
								replaceSharedAndTid(orphan, sharedIDs);
								FunctionCallNode fcn = (FunctionCallNode) node;
								SequenceNode<ExpressionNode> args = fcn.getArguments();
								args.addSequenceChild(this.identifierExpression(newSource("newFuncArg", CParser.ARGUMENT_LIST), "_tid"));
								FunctionTypeNode funcTypeNode = orphan.getTypeNode();
								SequenceNode<VariableDeclarationNode> params = funcTypeNode.getParameters();
								VariableDeclarationNode newParam = nodeFactory.newVariableDeclarationNode(newSource("newFuncParam", CParser.PARAMETER_DECLARATION), nodeFactory.newIdentifierNode(newSource("newFuncParam", CParser.IDENTIFIER), "_tid"), nodeFactory.newBasicTypeNode(newSource("newFuncParam", CParser.TYPE), BasicTypeKind.INT));
								params.addSequenceChild(newParam);
							}
							*/							
				/*			
						}
					}
				}
				*/
				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(((IdentifierNode) node)
								.name() + "$omp_private");
					}
				}
			}
			if (firstPrivateIDs != null) {
				for (ASTNode child : firstPrivateIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						((IdentifierNode) node).setName(((IdentifierNode) node)
								.name() + "$omp_private");
					}
				}
			}
			if (reductionIDs != null) {
				for (ASTNode child : reductionIDs.children()) {
					IdentifierNode c = ((IdentifierExpressionNode) child)
							.getIdentifier();
					if (c.name().equals(((IdentifierNode) node).name())) {
						((IdentifierNode) node).setName(((IdentifierNode) node)
								.name() + "$omp_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", CParser.IDENTIFIER), c.name() + "$omp_threadprivate");
						IdentifierExpressionNode arg1 = (IdentifierExpressionNode) this.identifierExpression(newSource("threadPrivate", CParser.IDENTIFIER), "_tid");

						OperatorNode threadPrivateReplace = nodeFactory.newOperatorNode(newSource("threadPrivate", CParser.EXPR), Operator.SUBSCRIPT, arg0, arg1);
						
						int index = idExp.childIndex();
						ASTNode parent = idExp.parent();
						parent.setChild(index, threadPrivateReplace);
						
						//((IdentifierNode) node).setName(((IdentifierNode) node)
						//		.name() + "$omp_threadprivate");
					}
				}
			}

		} 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, CParser.COMPOUND_STATEMENT),
						items);

				LoopNode whileNode = nodeFactory.newWhileLoopNode(newSource("forToWhile", CParser.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, CParser.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", CParser.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", CParser.IDENTIFIER), "$omp_numThreads");
				ArrayTypeNode arrayType = nodeFactory.newArrayTypeNode(newSource("threadPrivate", CParser.TYPE), privateType, extent);
				VariableDeclarationNode arrayNode = nodeFactory.newVariableDeclarationNode(newSource("threadPrivate", CParser.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);
			}
		}

	}
	
	@SuppressWarnings("unused")
	private CastNode createMalloc(PointerTypeNode castType, TypeNode sizeType, ExpressionNode size){
		String place = "malloc";
		IdentifierExpressionNode mallocName = (IdentifierExpressionNode) this.identifierExpression(newSource(place, CParser.IDENTIFIER), "$malloc");
		IdentifierExpressionNode genRoot = (IdentifierExpressionNode) this.identifierExpression(newSource(place, CParser.IDENTIFIER), "$gen_root");
		SizeofNode sizeOf = nodeFactory.newSizeofNode(newSource(place, CParser.SIZEOF), sizeType);
		OperatorNode ops = nodeFactory.newOperatorNode(newSource(place, CParser.OPERATOR), Operator.TIMES, Arrays.asList(size ,sizeOf));
		FunctionCallNode mallFunc = nodeFactory.newFunctionCallNode(newSource(place, CParser.CALL), mallocName, Arrays.asList(genRoot, ops), null);
		
		return nodeFactory.newCastNode(newSource(place, CParser.CAST), castType, mallFunc);		
	}
	
	@SuppressWarnings("unused")
	private void addParallelDataStruct(List<BlockItemNode> externalList){
		String place = "parDataStruct";
		VariableDeclarationNode structArr = nodeFactory.newVariableDeclarationNode(newSource(place, CParser.DECLARATION), nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "parallelDataArr"), 
				nodeFactory.newPointerTypeNode(newSource(place, CParser.TYPE), nodeFactory.newPointerTypeNode(newSource(place, CParser.POINTER), nodeFactory.newTypedefNameNode(nodeFactory.newIdentifierNode(newSource(place, CParser.TYPE), "$omp_team"), null))));
		externalList.add(structArr);
	}
	
	@SuppressWarnings("unused")
	private boolean checkSharedAndTid(ASTNode node, SequenceNode<IdentifierExpressionNode> sharedIDs){		
		boolean found = false;
		if(node != null){
			if(node.getSource().getSummary(false).contains("parallelPragma")){
				return false;
			}
		}
		
		if (node instanceof IdentifierNode) {
			if(((IdentifierNode) node).name().equals("_tid")){
				return true;
			}
			
			if(sharedIDs !=null){
				for(IdentifierExpressionNode child : sharedIDs){
					IdentifierNode id = child.getIdentifier();
					if(((IdentifierNode) node).name().equals(id.name())){
						return true;
					}
				}
			}

		} else if (node != null) {
			Iterable<ASTNode> children = node.children();
			for (ASTNode child : children) {
				found = found || checkSharedAndTid(child, sharedIDs);
			}
		}
		return found;
	}
	
	@SuppressWarnings("unused")
	private void replaceSharedAndTid(FunctionDefinitionNode node, SequenceNode<IdentifierExpressionNode> sharedIDs) throws SyntaxException{				
		CompoundStatementNode body = ((FunctionDefinitionNode) node).getBody();

		String place = "orphanFunc";
		
		//$omp_team team = *parallelDataArr[_tid];
		IdentifierNode teamID = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "team");
		IdentifierNode teamTypeName = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "$omp_team");
		TypedefNameNode teamType = nodeFactory.newTypedefNameNode(teamTypeName, null);
		ExpressionNode arrName = this.identifierExpression(newSource(place, CParser.IDENTIFIER), "parallelDataArr");
		ExpressionNode tidName = this.identifierExpression(newSource(place, CParser.IDENTIFIER), "_tid");
		ExpressionNode array = nodeFactory.newOperatorNode(newSource(place, CParser.EXPR), Operator.SUBSCRIPT, Arrays.asList(arrName, tidName));
		ExpressionNode teamRhs = nodeFactory.newOperatorNode(newSource(place, CParser.EXISTS), Operator.DEREFERENCE, Arrays.asList(array));
		VariableDeclarationNode teamVar = nodeFactory.newVariableDeclarationNode(newSource(place, CParser.DECLARATION), teamID, teamType, teamRhs);
		insertChildAt(0, body, teamVar);

		//$omp_shared *sharedArr = team->shared;
		IdentifierNode sharedID = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "shared");
		IdentifierNode sharedArr = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "sharedArr");
		IdentifierNode sharedTypeName = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "$omp_shared");
		PointerTypeNode sharedType = nodeFactory.newPointerTypeNode(newSource(place, CParser.POINTER), nodeFactory.newTypedefNameNode(sharedTypeName, null));
		ExpressionNode leftName = this.identifierExpression(newSource(place, CParser.IDENTIFIER), "team");
		ArrowNode arrow = nodeFactory.newArrowNode(newSource(place, CParser.EXPR), leftName, sharedID);
		VariableDeclarationNode sharedVar = nodeFactory.newVariableDeclarationNode(newSource(place, CParser.DECLARATION), sharedArr, sharedType, arrow);
		insertChildAt(1, body, sharedVar);
		
		int i = 0;
		for (ASTNode child : sharedIDs.children()) {
			IdentifierNode c = ((IdentifierExpressionNode) child)
					.getIdentifier();
			if(!(c.name().equals("sum"))){
				ExpressionNode sharedName = this.identifierExpression(newSource(place, CParser.IDENTIFIER), "sharedArr");
				IntegerConstantNode indexNode = nodeFactory.newIntegerConstantNode(newSource(place, CParser.INTEGER_CONSTANT), String.valueOf(i));
				ExpressionNode newName = nodeFactory.newOperatorNode(newSource(place, CParser.EXPR), Operator.SUBSCRIPT, Arrays.asList(sharedName, indexNode));
				IdentifierNode localName = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), "local");
				ArrowNode arrowNode = nodeFactory.newArrowNode(newSource(place, CParser.EXPR), newName, localName);
				PointerTypeNode type = nodeFactory.newPointerTypeNode(newSource(place, CParser.POINTER), nodeFactory.newBasicTypeNode(newSource(place, CParser.TYPE), BasicTypeKind.FLOAT));

				CastNode cast = nodeFactory.newCastNode(newSource(place, CParser.CAST), type.copy(), arrowNode);

				IdentifierNode idNode = nodeFactory.newIdentifierNode(newSource(place, CParser.IDENTIFIER), c.name()+"_local");
				VariableDeclarationNode localVar = nodeFactory.newVariableDeclarationNode(newSource(place, CParser.DECLARATION), idNode, type, cast);
				insertChildAt(2, body, localVar);
			}
			i++;
		}
		
		replaceSharedInsert(node, sharedIDs);
		
		
		for (ASTNode key : sharedRead.keySet()) {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> statements = sharedRead
					.get(key);

			boolean inParallel = false;
			ASTNode parent = key;
			
			
			while(parent != null){
				if(parent.getSource().getSummary(false).contains("parallelPragma")){
					inParallel = true;
				}
				parent = parent.parent();
			}
			
			if(!inParallel){
				for (Pair<VariableDeclarationNode, ExpressionStatementNode> pair : statements) {
					if (pair.left != null) {
						replaceSharedInsert(pair.left, sharedIDs);
					}
					if (pair.right != null) {
						replaceSharedInsert(pair.right, sharedIDs);
					}
				}
			}
			
		}

	}
	
	private void replaceSharedInsert(ASTNode node, SequenceNode<IdentifierExpressionNode> sharedIDs) throws SyntaxException{
		String place = "replaceOrphanName";
		if (node instanceof IdentifierNode) {
			int i = 0;
			for (ASTNode child : sharedIDs.children()) {
				IdentifierNode c = ((IdentifierExpressionNode) child)
						.getIdentifier();
				if (((IdentifierNode) node).name().equals(c.name()+"_shared")) {
					ASTNode idExp = node.parent();
					
					//x_shared => sharedArr[i]
					ExpressionNode arrName = this.identifierExpression(newSource(place, CParser.IDENTIFIER), "sharedArr");
					IntegerConstantNode indexNode = nodeFactory.newIntegerConstantNode(newSource(place, CParser.INTEGER_CONSTANT), String.valueOf(i));
					ExpressionNode newName = nodeFactory.newOperatorNode(newSource(place, CParser.EXPR), Operator.SUBSCRIPT, Arrays.asList(arrName, indexNode));
					
					int index = idExp.childIndex();
					ASTNode parent = idExp.parent();
					parent.setChild(index, newName);
					
				}
				
				//if (((IdentifierNode) node).name().equals(c.name()+"_local")) {
					
					/*ASTNode parentExp = node;
					while(!(parentExp instanceof ExpressionNode)){
						parentExp = parentExp.parent();
					}
					
					ExpressionNode arrName = this.identifierExpression(source, "sharedArr");
					IntegerConstantNode indexNode = nodeFactory.newIntegerConstantNode(source, String.valueOf(1));
					ExpressionNode newName = nodeFactory.newOperatorNode(source, Operator.SUBSCRIPT, Arrays.asList(arrName, indexNode));
					IdentifierNode localName = nodeFactory.newIdentifierNode(source, "local");
					ArrowNode arrowNode = nodeFactory.newArrowNode(source, newName, localName);

					int index = parentExp.childIndex();
					ASTNode parent = parentExp.parent();
					
					parent.setChild(index, arrowNode);*/
					
					/*boolean toDo = true;
					ASTNode opParent = node;
					while(toDo && !(opParent instanceof OperatorNode && ((OperatorNode) opParent).getOperator().equals(Operator.ADDRESSOF))){
						opParent = opParent.parent();
						if(opParent instanceof VariableDeclarationNode){
							toDo = false;
						}
					}
					if(toDo){
						//ExpressionNode orig = ((OperatorNode) opParent).getArgument(0);
						//orig.remove();
						//ASTNode parent = opParent.parent();
						//int index = opParent.childIndex();
						//parent.setChild(index, orig);
						
						((OperatorNode) opParent).setOperator(Operator.DEREFERENCE);
					}
					*/
					
				//}
				
				i++;
			}

		} else if (node != null) {
			Iterable<ASTNode> children = node.children();
			for (ASTNode child : children) {
				replaceSharedInsert(child, sharedIDs);
			}
		}
	}

	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;
	}

	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;
		boolean pointer = false;
		Type origType = currentType;
		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() + "SharedWrite";

		BasicTypeKind baseTypeKind = ((StandardBasicType) currentType)
				.getBasicTypeKind();
		IdentifierNode tempID = nodeFactory.newIdentifierNode(
				newSource(place, CParser.IDENTIFIER),
				"tmpWrite" + String.valueOf(tempWriteCount));
		TypeNode declarationTypeNode = null;

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

		if (parentIsFunctionCall) {
			declarationTypeNode = nodeFactory.newPointerTypeNode(newSource(place, CParser.TYPE),
					nodeFactory.newBasicTypeNode(
							newSource(place, CParser.TYPE), baseTypeKind));
		} else {
			declarationTypeNode = nodeFactory.newBasicTypeNode(
					newSource(place, CParser.TYPE), baseTypeKind);
		}

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

		ASTNode parentOfID = null;
		String nodeName = node.name();
		node.setName(node.name() + "_local");
		ExpressionStatementNode writeCall = null;
		ExpressionStatementNode readCall = null;
		ASTNode statementParent = node.parent();
		while (!(statementParent instanceof StatementNode)) {
			statementParent = statementParent.parent();
		}
		if (nodesDeep == 0) {
			parentOfID = node.parent();
			writeCall = write(
					(ExpressionNode) parentOfID.copy(),
					nodeName,
					this.identifierExpression(
							newSource(place, CParser.IDENTIFIER), "tmpWrite"
									+ String.valueOf(tempWriteCount)), origType);
			if (opCode == 2) {
				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						"tmpWrite" + 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, CParser.IDENTIFIER), "tmpWrite"
									+ String.valueOf(tempWriteCount)), origType);
			if (opCode == 2) {
				readCall = read((ExpressionNode) parentOfID.copy(), nodeName,
						"tmpWrite" + String.valueOf(tempWriteCount), origType);
			}
		}

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

		if (opCode == 2) {
			Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
					null, readCall);
			if (sharedRead.containsKey(statementParent)) {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedRead
						.get(statementParent);
				nodeToAdd.add(tempPair);
			} else {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
				tempPairs.add(tempPair);
				sharedRead.put(statementParent, tempPairs);
			}
		}

		Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
				temp, writeCall);
		if (sharedWrite.containsKey(statementParent)) {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedWrite
					.get(statementParent);
			nodeToAdd.add(tempPair);
		} else {
			ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
			tempPairs.add(tempPair);
			sharedWrite.put(statementParent, tempPairs);
		}
		tempWriteCount++;
	}

	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", CParser.COMPOUND_STATEMENT), items);
		parent.setChild(index, body);
	}

	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;

				}
			}
		}

	}

	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;
		switch (functionName) {
		case "omp_get_num_threads":
			place = "omp_get_num_threads->_nthreads";
			replacementNode = this.identifierExpression(
					newSource(place, CParser.IDENTIFIER), NTHREADS);
			break;
		case "omp_get_num_procs":
			place = "omp_get_num_procs->1";
			replacementNode = nodeFactory.newIntegerConstantNode(
					(newSource(place, CParser.IDENTIFIER)), "1");
			break;
		case "omp_get_max_threads":
			place = "omp_get_max_threads->_nthreads";
			replacementNode = this.identifierExpression(
					newSource(place, CParser.IDENTIFIER), "THREAD_MAX");
			break;
		case "omp_get_thread_num":
			place = "omp_get_thread_num->_tid";
			replacementNode = this.identifierExpression(
					newSource(place, CParser.IDENTIFIER), TID);
			break;
		case "omp_set_num_threads":
			place = "omp_set_num_threads->$omp_numThreads";
			replacementNode = nodeFactory.newOperatorNode(newSource(place, CParser.EXPR),
					Operator.ASSIGN, Arrays.asList(this.identifierExpression(
							newSource(place, CParser.IDENTIFIER), "$omp_numThreads"), node.getArgument(0)
							.copy()));
			break;
		}

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

		return false;
	}

	private int isAssignmentOperator(String operator) {
		if (operator.equals("ASSIGN")) {
			return 1;
		} else if (operator.equals("PLUSEQ")) {
			return 2;
		}
		return 0;
	}

	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, CParser.IDENTIFIER), c.name()
							+ "$omp_private");
			privateVariable = nodeFactory.newVariableDeclarationNode(
					newSource(place, CParser.DECLARATION),
					privateIdentifer,
					privateType,
					this.identifierExpression(
							newSource(place, CParser.IDENTIFIER), c.name()));
		} else if (privateKind.equals("reduction")) {
			privateIdentifer = nodeFactory.newIdentifierNode(
					newSource(place, CParser.IDENTIFIER), c.name()
							+ "$omp_reduction");
			privateVariable = nodeFactory.newVariableDeclarationNode(
					newSource(place, CParser.DECLARATION), privateIdentifer,
					privateType,
					nodeFactory.newIntegerConstantNode(newSource(place, CParser.INTEGER_CONSTANT), "0"));
		} else {
			privateIdentifer = nodeFactory.newIdentifierNode(
					newSource(place, CParser.IDENTIFIER), c.name()
							+ "$omp_private");
			privateVariable = nodeFactory.newVariableDeclarationNode(
					newSource(place, CParser.DECLARATION), privateIdentifer,
					privateType);
		}
		return privateVariable;
	}

	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);
		}

	}

	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;
		ExpressionStatementNode writeCall = null;
		ASTNode statementParent = null;
		ASTNode parentOfID = null;
		
		Type currentType = ((Variable) node.getEntity()).getType();
		int nodesDeep = 0;
		boolean pointer = false;
		VariableDeclarationNode temp;
		Type origType = currentType;
		
		while (currentType instanceof PointerType) {
			currentType = ((PointerType) currentType).referencedType();
			pointer = true;
			nodesDeep++;
		}
		
		if (currentType instanceof QualifiedObjectType) {
			currentType = ((QualifiedObjectType) currentType).getBaseType();
		}


		while (currentType instanceof ArrayType) {
			currentType = ((ArrayType) currentType).getElementType();
			nodesDeep++;
		}
		String place = node.name() + "SharedRead";
		BasicTypeKind baseTypeKind = null;
		if (currentType instanceof StandardBasicType) {
			baseTypeKind = ((StandardBasicType) currentType).getBasicTypeKind();
		}
		IdentifierNode tempID = nodeFactory.newIdentifierNode(
				newSource(place, CParser.IDENTIFIER),
				"tmpRead" + String.valueOf(tmpCount));
		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;
			write = true;
			tempBool = false;
			//if(parentIsFunctionCall){
				nodesDeep = 0;
			//}
		}
		
		if (parentIsFunctionCall && tempBool) {
			declarationTypeNode = nodeFactory.newPointerTypeNode(newSource(place, CParser.TYPE),
					nodeFactory.newBasicTypeNode(
							newSource(place, CParser.TYPE), baseTypeKind));
			nodesDeep--;
			while(nodesDeep > 0){
				declarationTypeNode = nodeFactory.newPointerTypeNode(newSource(place, CParser.POINTER),
						declarationTypeNode);
				nodesDeep--;
			}
		}
		
		// else if(pointer){
		// declarationTypeNode = nodeFactory.newPointerTypeNode(source,
		// nodeFactory.newBasicTypeNode(
		// newSource(place, CParser.TYPE), baseTypeKind));
		// }
		else if(tempBool) {
			declarationTypeNode = nodeFactory.newBasicTypeNode(
					newSource(place, CParser.TYPE), baseTypeKind);
		}

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

						if (nodesDeep == 0) {
							parentOfID = node.parent();
						} else {
							parentOfID = node.parent();
							while (nodesDeep > 0) {
								parentOfID = parentOfID.parent();
								nodesDeep--;
							}
						}

						// node.setName(triple.third);
						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, CParser.IDENTIFIER),
								triple.second.name()), name,
								this.identifierExpression(
										newSource(place, CParser.IDENTIFIER),
										triple.third), origType);
						directParent
								.setChild(index, this.identifierExpression(
										newSource(place, CParser.IDENTIFIER), triple.third));

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

		if (!alreadyUsed) {
			temp = nodeFactory.newVariableDeclarationNode(
					newSource(place, CParser.DECLARATION), tempID,
					declarationTypeNode);

			String nodeName = node.name();
			node.setName(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,
						"tmpRead" + String.valueOf(tmpCount), origType);
			} else {
				parentOfID = node.parent();
				while (nodesDeep > 0) {
					parentOfID = parentOfID.parent();
					nodesDeep--;
				}

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

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

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

			Pair<VariableDeclarationNode, ExpressionStatementNode> tempPair = new Pair<>(
					temp, readCall);			
			
			if (sharedRead.containsKey(statementParent)) {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedRead
						.get(statementParent);
				nodeToAdd.add(tempPair);
			} else {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
				tempPairs.add(tempPair);
				sharedRead.put(statementParent, tempPairs);
			}

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

			tmpCount++;
		}

		if (write) {
			Pair<VariableDeclarationNode, ExpressionStatementNode> tempPairWrite = new Pair<>(
					null, writeCall);

			if (sharedWrite.containsKey(statementParent)) {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> nodeToAdd = sharedWrite
						.get(statementParent);
				nodeToAdd.add(tempPairWrite);
			} else {
				ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>> tempPairs = new ArrayList<Pair<VariableDeclarationNode, ExpressionStatementNode>>();
				tempPairs.add(tempPairWrite);
				sharedWrite.put(statementParent, tempPairs);
			}
		}

	}

	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,
			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("$omp_reduction")){
						temp = temp.replace("$omp_reduction", "");
						reductionNode = true;
					}
					if ((!(declaredNodes.contains(temp) || currentShared
							.contains(temp))) && !temp.equals("_tid") ) {
						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 FunctionCallNode){
					IdentifierExpressionNode idExp = (IdentifierExpressionNode) ((FunctionCallNode) child).getFunction();
					IdentifierNode id = idExp.getIdentifier();
					String funcName = id.name();
					
					removed = findFuncDef(funcName, root, sharedIDs, declaredNodes,
							currentShared, removed) || removed;
					
				}

				if (child instanceof VariableDeclarationNode) {
					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, removed) || removed;
			}
		}
		return removed;
	}
	
	private boolean findFuncDef(String funcName, ASTNode node, 
			SequenceNode<IdentifierExpressionNode> sharedIDs,
			ArrayList<String> declaredNodes, ArrayList<String> currentShared,
			boolean removed){
		boolean found = false;
		for (ASTNode child : node.children()) {
			if(child != null){
				if(child instanceof FunctionDefinitionNode){
					String name = ((DeclarationNode) child).getName();
					if(name.equals(funcName)){
						found = true;
						removed = getImplicitShared(sharedIDs, child, declaredNodes,
								currentShared, removed) || removed;
					}
				}
				if(!found){
					removed = findFuncDef(funcName, child, sharedIDs, declaredNodes,
						currentShared, 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<VariableDeclarationNode>> program(
			SequenceNode<BlockItemNode> root) throws SyntaxException {
		List<BlockItemNode> includedNodes = new ArrayList<>();
		List<VariableDeclarationNode> vars = new ArrayList<>();
		List<BlockItemNode> items;
		int number;
		items = new LinkedList<>();
		number = root.numChildren();

		final String place = "numThreadsDeclaration";
		TypeNode nthreadsType = nodeFactory.newBasicTypeNode(
				newSource(place, CParser.INT), BasicTypeKind.INT);
		IdentifierNode identifierNode = nodeFactory.newIdentifierNode(
				newSource(place, CParser.IDENTIFIER), "$omp_numThreads");

		items.add(nodeFactory.newVariableDeclarationNode(newSource(place, CParser.DECLARATION),
				identifierNode, nthreadsType, this.identifierExpression(
						newSource(place, CParser.IDENTIFIER), "THREAD_MAX")));

		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 (child.nodeKind() == NodeKind.VARIABLE_DECLARATION) {
					VariableDeclarationNode variable = (VariableDeclarationNode) child;
					if (variable.getTypeNode().isInputQualified()
							|| variable.getTypeNode().isOutputQualified()) {
						vars.add(variable);
						continue;
					}
				}
				items.add(child);
			}
		}

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

	/**
	 * 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", CParser.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", CParser.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);
	}
}