PragmaParser.java

package edu.udel.cis.vsl.tass.ast.impl;

import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.antlr.runtime.tree.CommonTree;
import org.antlr.runtime.tree.Tree;

import edu.udel.cis.vsl.tass.ast.IF.ASTNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.AbstractSyntaxTreeIF;
import edu.udel.cis.vsl.tass.ast.IF.IdentifierNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.PragmaParserIF;
import edu.udel.cis.vsl.tass.ast.IF.SequenceNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.AbstractFunctionDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.BoundVariableDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.FormalVariableDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.FunctionDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.GlobalVariableDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.declaration.VariableDeclarationNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.AssignmentNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.AssignmentNodeIF.AST_ASSIGNMENT_TYPE;
import edu.udel.cis.vsl.tass.ast.IF.expression.BindingExpressionNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.ExpressionNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.LHSExpressionNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.OperatorNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.PureExpressionNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.expression.VariableReferenceNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.statement.AssertStatementNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.statement.AssumeStatementNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.statement.LoopNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.statement.PragmaNodeIF;
import edu.udel.cis.vsl.tass.ast.IF.type.TypeNodeIF;
import edu.udel.cis.vsl.tass.ast.impl.pragmaParser.PragmaStringLexer;
import edu.udel.cis.vsl.tass.ast.impl.pragmaParser.PragmaStringParser;
import edu.udel.cis.vsl.tass.ast.impl.pragmaParser.PragmaStringParser.pragma_return;
import edu.udel.cis.vsl.tass.model.IF.SyntaxException;
import edu.udel.cis.vsl.tass.number.real.RealNumberFactory;

/**
 * This class traverses the AST and converts all valid TASS pragmas to the 
 * corresponding AST nodes.
 * 
 * @author Timothy Zirkel (zirkel)
 * 
 */
public class PragmaParser implements PragmaParserIF {

	private boolean verbose = false;
	private AbstractSyntaxTreeIF ast;
	private Map<String, VariableDeclarationNodeIF> inputVariables = new HashMap<String, VariableDeclarationNodeIF>();

	public PragmaParser() {

	}

	public PragmaParser(boolean verbose) {
		this.verbose = verbose;
	}

	/**
	 * Constructor that sets the AST, for testing purposes.
	 */
	public PragmaParser(AbstractSyntaxTreeIF ast) {
		this.ast = ast;
	}
	
	@Override
	public void transform(AbstractSyntaxTreeIF ast) throws SyntaxException {
		this.ast = ast;
		PragmaHelper helper = new PragmaHelper();
		helper.transform(ast);
		processAll(ast.rootNode().globalScopeNodes());
	}

	public void processAll(ASTNodeIF node) {
		if (node == null) {
			return;
		}
		for (int i = 0; i < node.numChildren(); i++) {
			ASTNodeIF currentChild = node.child(i);
			// If the child is a pragma, parse it and we're done.
			if (currentChild instanceof PragmaNodeIF)
				// Check for a syntax exception
				try {
					node.setChild(i, parsePragma((PragmaNodeIF) currentChild));
				} catch (SyntaxException e) {
					if (verbose) {
						System.out.println("Pragma node " + currentChild.id()
								+ ":\n     \"" + currentChild.toString()
								+ "\"\nis not a valid TASS pragma");
					}
				}
			// If the child is not a pragma, it needs to be recursively
			// processed.
			else
				processAll(currentChild);
		}
	}

	@Override
	public ASTNodeIF parsePragma(PragmaNodeIF pragmaNode)
			throws SyntaxException {
		// TODO: The .replaceAll() calls are to deal with bugs in the XML->AST
		// build. Should eventually be removed.
		String pragmaString = pragmaNode.string().stringValue()
				.replaceAll("\n", "").replaceAll("null", "");
		CommonTree rootNode = prepareTree(pragmaString);
		ASTNodeIF newNode = pragmaNode;
		int rootNodeType = rootNode.getType();

		if (rootNodeType == PragmaStringLexer.SYSTEM) {
			/* Process a guard if one exists. */
			if (rootNode.getChild(1).getType() == PragmaStringLexer.GUARD) {
				ExpressionNodeIF guard;

				assert pragmaNode.nextNode() instanceof FunctionDeclarationNodeIF;
				guard = processExpression(rootNode.getChild(2));
				assert guard instanceof PureExpressionNodeIF;
				((FunctionDeclarationNodeIF) pragmaNode.nextNode())
						.setGuard((PureExpressionNodeIF) guard);
			}
		} else if (rootNodeType == PragmaStringLexer.ABSTRACT) {
			newNode = processAbstractFunctionDeclaration(rootNode);
		} else if (rootNodeType == PragmaStringLexer.STATEMENT) {
			newNode = processStatement(rootNode);
			if (newNode.annotation("invariant") != null) {
				LoopNodeIF nextNode;
				SequenceNodeIF<PureExpressionNodeIF> invariants;

				if (!(newNode instanceof PureExpressionNodeIF)) {
					throw new SyntaxException(pragmaNode,
							"Invariant must be a pure expression.");
				}
				if (!(pragmaNode.nextNode() instanceof LoopNodeIF)) {
					throw new SyntaxException(pragmaNode,
							"Invariants must come directly before loop statements.");
				}
				nextNode = (LoopNodeIF) pragmaNode.nextNode();
				if (nextNode.invariants() != null) {
					invariants = nextNode.invariants();
				} else {
					invariants = ast.factory().sequenceNode(PureExpressionNodeIF.class);
				}
				invariants.addSequenceChild((PureExpressionNodeIF) newNode);
				nextNode.setInvariants(invariants);
				// Since we added the invariant to the loop node, we don't
				// want it sitting as just an extra expression. Replace it with
				// the original pragma node.
				newNode = pragmaNode;
			}
		} else if (rootNodeType == PragmaStringLexer.PREFIX) {
			newNode = processPrefix(rootNode, pragmaNode);
			// A prefix will either be before a define or
			// before a global variable declaration. In the
			// former case, we need to add a new node for
			// a new declaration. In the latter,
			// the declaration is already there.
			if (newNode.equals(pragmaNode.nextNode())) {
				newNode = pragmaNode;
			}
		}
		newNode.setSource(pragmaNode.getSource());
		return newNode;
	}

	/**
	 * Process pragmas representing statements. The valid pragma statements are
	 * assert, assume, collective assert, joint assert, invariant, collective
	 * invariant, joint invariant.
	 * 
	 * @throws SyntaxException
	 *             if there are any syntax problems with the
	 *             assert/assume/invariant predicate.
	 */
	private ASTNodeIF processStatement(CommonTree node) throws SyntaxException {
		CommonTree child = (CommonTree) (node.getChild(0));

		switch (child.getType()) {
		case PragmaStringLexer.ASSERT_STMT:
			return processAssert(child);
		case PragmaStringLexer.ASSUME_STMT:
			return processAssume(child);
		case PragmaStringLexer.COLLECTIVE_ASSERT_STMT:
			return processCollectiveAssert(child);
		case PragmaStringLexer.COLLECTIVE_INVARIANT_STMT:
			return processCollectiveInvariant(child);
		case PragmaStringLexer.INVARIANT_STMT:
			return processInvariant(child);
		case PragmaStringLexer.JOINT_ASSERT_STMT:
			return processJointAssert(child);
		case PragmaStringLexer.JOINT_INVARIANT_STMT:
			return processJointInvariant(child);
		default:
			throw new SyntaxException("Unkown or unimplemented statement at "
					+ node.getChild(0).getLine() + ", "
					+ node.getChild(0).getCharPositionInLine() + ":"
					+ node.getText());
		}
	}

	private ASTNodeIF processAssert(CommonTree node) throws SyntaxException {
		AssertStatementNodeIF result = null;
		ExpressionNodeIF predicate = processExpression(node.getChild(1));
		String message = null;

		result = ast.factory().assertStatementNode(predicate);
		if (node.getChild(2).getType() != PragmaStringLexer.SEMI) {
			message = node.getChild(2).getText()
					.substring(1, node.getChild(2).getText().length() - 1);
			result.setAnnotation("message", message);
		}
		return result;
	}

	private ASTNodeIF processAssume(CommonTree node) throws SyntaxException {
		AssumeStatementNodeIF result = null;
		ExpressionNodeIF predicate = processExpression(node.getChild(1));

		result = ast.factory().assumeStatementNode(predicate);
		return result;
	}

	private ASTNodeIF processCollectiveAssert(CommonTree node)
			throws SyntaxException {
		AssertStatementNodeIF result = null;
		ExpressionNodeIF predicate = processExpression(node.getChild(1));
		String identifier = node.getChild(0).getText();

		result = ast.factory().assertStatementNode(predicate);
		result.setAnnotation("collective", true);
		result.setAnnotation("name", identifier);
		return result;
	}

	private ASTNodeIF processCollectiveInvariant(CommonTree node)
			throws SyntaxException {
		ASTNodeIF result = processInvariant(node);

		result.setAnnotation("collective", true);
		return result;
	}

	private ASTNodeIF processJointAssert(CommonTree node)
			throws SyntaxException {
		AssertStatementNodeIF result = null;
		ExpressionNodeIF predicate = processExpression(node.getChild(1));
		String identifier = node.getChild(0).getText();

		result = ast.factory().assertStatementNode(predicate);
		result.setAnnotation("joint", true);
		result.setAnnotation("name", identifier);
		return result;
	}

	private ASTNodeIF processInvariant(CommonTree node) throws SyntaxException {
		ExpressionNodeIF result = processExpression(node.getChild(1));
		String identifier = node.getChild(0).getText();

		if (!(result instanceof PureExpressionNodeIF)) {
			throw new SyntaxException("An invariant must be a pure expression.");
		}
		result.setAnnotation("invariant", true);
		result.setAnnotation("name", identifier);
		return result;
	}

	private ASTNodeIF processJointInvariant(CommonTree node)
			throws SyntaxException {
		ASTNodeIF result = processInvariant(node);

		result.setAnnotation("joint", true);
		return result;
	}

	private ASTNodeIF processAbstractFunctionDeclaration(CommonTree node)
			throws SyntaxException {
		AbstractFunctionDeclarationNodeIF result = null;
		TypeNodeIF type = processType(node.getChild(2).getText());
		IdentifierNodeIF identifier = ast.factory().identifierNode(
				node.getChild(3).getText());
		CommonTree contNode = (CommonTree) node.getChild(0);
		SequenceNodeIF<FormalVariableDeclarationNodeIF> formals;
		int continuity = 0;
		int bounded = 0;

		if (contNode.getType() != PragmaStringLexer.IGNORE) {
			continuity = Integer.parseInt(contNode.getText());
		}
		// TODO Add boundedness to grammar, handle it
		if (node.getChildCount() == 6) {
			formals = processFormals((CommonTree) node.getChild(4));
		} else {
			formals = ast.factory().sequenceNode(
					FormalVariableDeclarationNodeIF.class);
		}
		result = ast.factory().abstractFunctionDeclarationNode(identifier,
				type, formals, continuity, bounded);
		return result;
	}

	private SequenceNodeIF<FormalVariableDeclarationNodeIF> processFormals(
			CommonTree node) {
		// TODO Auto-generated method stub
		return null;
	}

	private ASTNodeIF processPrefix(CommonTree rootNode, PragmaNodeIF pragmaNode)
			throws SyntaxException {
		String prefix = rootNode.getChild(0).getText();
		GlobalVariableDeclarationNodeIF variable;
		/*
		 * Either this prefix is the line preceding a variable declaration, or
		 * it is the line preceding a define. In the define case, we should have
		 * preprocessed the file to include a type and identifier in this
		 * pragma. In these cases, we need to take that type and identifier and
		 * create a new GlobalVariableDeclarationNodeIF.
		 */
		if (rootNode.getChildCount() > 2) {
			IdentifierNodeIF name;
			TypeNodeIF type;
			ExpressionNodeIF inputAssumption;
			int numChildren = rootNode.getChildCount();

			name = ast.factory().identifierNode(
					rootNode.getChild(numChildren - 1).getText());
			type = processType(rootNode.getChild(numChildren - 2).getText());
			variable = ast.factory().globalVariableDeclarationNode(name, type);
			inputVariables.put(variable.identifier().name(), variable);
			if (numChildren == 4) {
				inputAssumption = processExpression(rootNode.getChild(1));
				inputAssumption.setSource(pragmaNode.getSource());
				variable.setInputAssumption(inputAssumption);
				variable.setSource(pragmaNode.getSource());
			}
		} else {
			variable = (GlobalVariableDeclarationNodeIF) pragmaNode.nextNode();
		}
		if (prefix.equals("input")) {
			variable.setIsInput(true);
		} else if (prefix.equals("output")) {
			variable.setIsOutput(true);
		} else if (prefix.equals("shared")) {
			variable.setIsShared(true);
		}
		return variable;
	}

	private ExpressionNodeIF processExpression(Tree node)
			throws SyntaxException {
		if (node.getChild(0).getType() == PragmaStringLexer.ASSIGN_EXPR) {
			// expr: assign_expr
			return processAssignment(node.getChild(0));
		} else if (node.getChild(0).getType() == PragmaStringLexer.CONDITIONAL_EXPR) {
			return processConditional(node.getChild(0));
		} else {
			// expr: quantifier_expr
			return processQuantifier(node.getChild(0));
		}
	}

	private ExpressionNodeIF processQuantifier(Tree node)
			throws SyntaxException {
		TypeNodeIF type = null;
		IdentifierNodeIF identifier = null;
		BoundVariableDeclarationNodeIF variable = null;
		BindingExpressionNodeIF.Quantifier quantifier = null;
		PureExpressionNodeIF constraint = null;
		PureExpressionNodeIF boundExpression = null;
		BindingExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processLogicalOr(node.getChild(0));
		} else {
			int expressionIndex = 3;

			type = processType(node.getChild(1).getText());
			identifier = ast.factory().identifierNode(
					node.getChild(2).getText());
			switch (node.getChild(0).getChild(0).getType()) {
			case PragmaStringLexer.FORALL:
				quantifier = BindingExpressionNodeIF.Quantifier.FORALL;
				break;
			case PragmaStringLexer.EXISTS:
				quantifier = BindingExpressionNodeIF.Quantifier.EXISTS;
				break;
			// TODO implement other quantifier types in grammar
			}
			variable = ast.factory().boundVariableDeclarationNode(identifier,
					type, null);
			if (node.getChild(3).getType() == PragmaStringLexer.BAR) {
				constraint = (PureExpressionNodeIF) processExpression(node
						.getChild(4));
				expressionIndex = 5;
			} else {
				constraint = ast.factory().integerLiteralNode(null,
						ast.factory().booleanTypeNode(), 1);
			}
			boundExpression = (PureExpressionNodeIF) processExpression(node
					.getChild(expressionIndex));
			result = ast.factory().bindingExpressionNode(quantifier, variable,
					constraint, boundExpression);
			variable.setContainingExpression(result);
		}
		return result;
	}

	private ExpressionNodeIF processLogicalOr(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processLogicalAnd(node.getChild(0));
		} else {
			ExpressionNodeIF left = null;
			ExpressionNodeIF right;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				if (i == 0) {
					left = processLogicalAnd(node.getChild(i));
				} else {
					left = result;
				}
				right = processLogicalAnd(node.getChild(i + 2));
				result = ast.factory().operatorNode(
						OperatorNodeIF.AST_OPERATOR.LOGICAL_OR, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processLogicalAnd(Tree node)
			throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			if (node.getChild(0).getType() == PragmaStringLexer.ADDITIVE_EXPR) {
				return processAdditive(node.getChild(0));
			}
			return processEquality(node.getChild(0));
		} else {
			ExpressionNodeIF left = null;
			ExpressionNodeIF right;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				if (i == 0) {
					// FIXME: Again, not sure why this changed from the old
					// front-end. The pragma parser is better, but parts may
					// still need to be rewritten.
					if (node.getChild(0).getType() == PragmaStringLexer.EQUALITY_EXPR) {
						left = processEquality(node.getChild(i));
					} else {
						left = processLogicalAnd(node.getChild(i));
					}
				} else {
					left = result;
				}
				if (node.getChild(i + 2).getType() == PragmaStringLexer.EQUALITY_EXPR) {
					right = processEquality(node.getChild(i + 2));
				} else {
					right = processLogicalAnd(node.getChild(i + 2));
				}
				result = ast.factory().operatorNode(
						OperatorNodeIF.AST_OPERATOR.LOGICAL_AND, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processEquality(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processRelational(node.getChild(0));
		} else {
			ExpressionNodeIF left = null;
			ExpressionNodeIF right;
			OperatorNodeIF.AST_OPERATOR operator;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				if (i == 0) {
					left = processLogicalAnd(node.getChild(i));
				} else {
					left = result;
				}
				if (node.getChild(i + 1).getText().equalsIgnoreCase("==")) {
					operator = OperatorNodeIF.AST_OPERATOR.EQUALS;
				} else if (node.getChild(i + 1).getText()
						.equalsIgnoreCase("!=")) {
					operator = OperatorNodeIF.AST_OPERATOR.NOT_EQUALS;
				} else {
					throw new SyntaxException("Invalid operator type");
				}
				right = processLogicalAnd(node.getChild(i + 2));
				result = ast.factory().operatorNode(operator, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processRelational(Tree node)
			throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processAdditive(node.getChild(0));
		} else {
			String operatorString;
			OperatorNodeIF.AST_OPERATOR operator;
			ExpressionNodeIF left, right;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				operatorString = node.getChild(i + 1).getText();
				if (operatorString.equalsIgnoreCase("<")) {
					operator = OperatorNodeIF.AST_OPERATOR.LESS_THAN;
				} else if (operatorString.equalsIgnoreCase("<=")) {
					operator = OperatorNodeIF.AST_OPERATOR.LEQ;
				} else if (operatorString.equalsIgnoreCase(">")) {
					operator = OperatorNodeIF.AST_OPERATOR.GREATER_THAN;
				} else if (operatorString.equalsIgnoreCase(">=")) {
					operator = OperatorNodeIF.AST_OPERATOR.GTE;
				} else {
					throw new SyntaxException("Invalid operator type: "
							+ operatorString);
				}
				if (i == 0) {
					left = processAdditive(node.getChild(i));
				} else {
					left = result;
				}
				right = processAdditive(node.getChild(i + 2));
				result = ast.factory().operatorNode(operator, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processAdditive(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processMultiplicative(node.getChild(0));
		} else {
			OperatorNodeIF.AST_OPERATOR operator;
			ExpressionNodeIF left, right;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				if (node.getChild(i + 1).getText().equalsIgnoreCase("+")) {
					operator = OperatorNodeIF.AST_OPERATOR.ADD;
				} else if (node.getChild(i + 1).getText().equalsIgnoreCase("-")) {
					operator = OperatorNodeIF.AST_OPERATOR.SUBTRACT;
				} else {
					throw new SyntaxException("Invalid operator type: "
							+ node.getChild(i + 1).getText());
				}
				if (i == 0) {
					left = processMultiplicative(node.getChild(i));
				} else {
					left = result;
				}
				right = processMultiplicative(node.getChild(i + 2));
				result = ast.factory().operatorNode(operator, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processMultiplicative(Tree node)
			throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			// FIXME: Not sure why this has changed from the original front-end,
			// but check if this is actually a primary expression. If it is,
			// call processPrimary() directly on the whole node instead of the
			// child. Maybe there's a better way to do this?
			// i.e. have a processNode() method that takes a node, looks at its
			// type, and calls the appropriate method rather than depending on
			// number of children, etc.?
			if (node.getType() == PragmaStringLexer.PRIMARY_EXPR) {
				return processPrimary(node);
			}
			return processUnary(node.getChild(0));
		} else {
			String operatorString;
			OperatorNodeIF.AST_OPERATOR operator;
			ExpressionNodeIF left, right;

			for (int i = 0; i < node.getChildCount() - 2; i += 2) {
				operatorString = node.getChild(i + 1).getText();
				if (operatorString.equalsIgnoreCase("*")) {
					operator = OperatorNodeIF.AST_OPERATOR.MULTIPLY;
				} else if (operatorString.equalsIgnoreCase("/")) {
					operator = OperatorNodeIF.AST_OPERATOR.DIVIDE;
				} else if (operatorString.equalsIgnoreCase("%")) {
					operator = OperatorNodeIF.AST_OPERATOR.MODULO;
				} else {
					throw new SyntaxException("Invalid operator type: "
							+ operatorString);
				}
				if (i == 0) {
					left = processMultiplicative(node.getChild(i));
				} else {
					left = result;
				}
				right = processMultiplicative(node.getChild(i + 2));
				result = ast.factory().operatorNode(operator, left, right);
			}
		}
		return result;
	}

	private ExpressionNodeIF processConditional(Tree node)
			throws SyntaxException {
		ExpressionNodeIF result = null;
		if (node.getChildCount() == 1) {
			return processLogicalOr(node.getChild(0));
		} else {
			ExpressionNodeIF predicate = processLogicalOr(node.getChild(0));
			ExpressionNodeIF trueExpr = processExpression(node.getChild(1));
			ExpressionNodeIF falseExpr = processExpression(node.getChild(2));
			result = ast.factory().operatorNode(
					OperatorNodeIF.AST_OPERATOR.COND, predicate, trueExpr,
					falseExpr);
		}
		return result;
	}

	private ExpressionNodeIF processAssignment(Tree node)
			throws SyntaxException {
		AssignmentNodeIF result;

		if (node.getChildCount() == 3) {
			ExpressionNodeIF leftHandSide = processUnary(node.getChild(0));
			Tree operator = node.getChild(1);
			ExpressionNodeIF rightHandSide = processAssignment(node.getChild(2));

			if (!(leftHandSide instanceof LHSExpressionNodeIF)) {
				throw new SyntaxException("Left value expected in assignment.");
			}
			result = ast.factory().assignmentNode(
					(LHSExpressionNodeIF) leftHandSide, rightHandSide);
			if (operator.equals(PragmaStringParser.PLUS_ASSIGN)) {
				result.setAssignmentType(AST_ASSIGNMENT_TYPE.ADDITION);
			} else if (operator.equals(PragmaStringParser.SUB_ASSIGN)) {
				result.setAssignmentType(AST_ASSIGNMENT_TYPE.SUBTRACTION);
			} else if (operator.equals(PragmaStringParser.MULTI_ASSIGN)) {
				result.setAssignmentType(AST_ASSIGNMENT_TYPE.MULTIPLICATION);
			} else if (operator.equals(PragmaStringParser.DIV_ASSIGN)) {
				result.setAssignmentType(AST_ASSIGNMENT_TYPE.DIVISION);
			} else if (!operator.equals(PragmaStringParser.ASSIGN)) {
				throw new SyntaxException("The assignment type " + operator.getText() + " is not yet supported.");
			}
		} else {
			return processConditional(node.getChild(0));
		}
		return result;
	}

	private ExpressionNodeIF processUnary(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			// FIXME: Not sure why this has changed from the original front-end,
			// but check if this is actually a primary expression. If it is,
			// call processPrimary() directly on the whole node instead of the
			// child. Maybe there's a better way to do this?
			// i.e. have a processNode() method that takes a node, looks at its
			// type, and calls the appropriate method rather than depending on
			// number of children, etc.?
			if (node.getType() == PragmaStringLexer.PRIMARY_EXPR) {
				return processPrimary(node);
			}
			return processPostfix(node.getChild(0));
		} else {
			if (node.getChild(0).getType() == PragmaStringParser.SIZEOF) {
				TypeNodeIF operand = null;

				// sizeof int
				if (node.getChild(1).getType() == PragmaStringParser.TYPE_NAME) {
					operand = processType(node.getChild(1).getText());
				}
				// sizeof(a)
				else {
					// TODO Do analysis of the type of the resulting expression
				}
				result = ast.factory().sizeOfNode(operand);
			} else if (node.getChild(0).getType() == PragmaStringParser.CAST) {
				TypeNodeIF castType = processType(node.getChild(1).getText());

				result = ast.factory().castNode(castType,
						processUnary(node.getChild(2)));
			} else if (node.getChild(0).getType() == PragmaStringParser.UNARY_OP) {
				String operatorString = node.getChild(0).getChild(0).getText();
				OperatorNodeIF.AST_OPERATOR operator = null;
				ExpressionNodeIF operand = processUnary(node.getChild(1));

				if (operatorString.equalsIgnoreCase("+")) {
					operator = OperatorNodeIF.AST_OPERATOR.ADD;
				} else if (operatorString.equalsIgnoreCase("-")) {
					operator = OperatorNodeIF.AST_OPERATOR.NEGATIVE;
				} else if (operatorString.equalsIgnoreCase("!")) {
					operator = OperatorNodeIF.AST_OPERATOR.LOGICAL_NOT;
				} else if (operatorString.equalsIgnoreCase("~")) {
					operator = OperatorNodeIF.AST_OPERATOR.BIT_NOT;
				} else if (operatorString.equalsIgnoreCase("*")) {
					return ast.factory().dereferenceNode(operand);
				} else if (operatorString.equalsIgnoreCase("&")) {
					operator = OperatorNodeIF.AST_OPERATOR.ADDRESS_OF;
				} else if (operatorString.equalsIgnoreCase("++")) {
					// TODO: Handle prefix vs postfix
					if (!(operand instanceof LHSExpressionNodeIF)) {
						throw new SyntaxException(
								"Operand for an increment must be a left hand side expression");
					}
					return ast.factory().incrementNode(
							(LHSExpressionNodeIF) operand, true, true);
				} else if (operatorString.equalsIgnoreCase("--")) {
					// TODO: Handle prefix vs postfix
					if (!(operand instanceof LHSExpressionNodeIF)) {
						throw new SyntaxException(
								"Operand for a decrement must be a left hand side expression");
					}
					return ast.factory().incrementNode(
							(LHSExpressionNodeIF) operand, true, false);
				} else {
					throw new SyntaxException("Unknown operator type: "
							+ operatorString);
				}
				result = ast.factory().operatorNode(operator, operand);
			}
		}
		return result;
	}

	private ExpressionNodeIF processPostfix(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;

		if (node.getChildCount() == 1) {
			return processPrimary(node.getChild(0));
		} else {
			ExpressionNodeIF body = processPrimary(node.getChild(0));
			result = processPostfixSuffix(body, node.getChild(1));
		}
		return result;
	}

	private ExpressionNodeIF processPostfixSuffix(ExpressionNodeIF body,
			Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;
		int type = node.getChild(0).getType();
		
		// struct member reference
		if (type == PragmaStringLexer.DOT) {
			ExpressionNodeIF temp = null;
			String fieldName = node.getChild(1).getText();
			IdentifierNodeIF fieldID = ast.factory().identifierNode(fieldName);
			if (!(body instanceof LHSExpressionNodeIF)) {
				throw new SyntaxException(body, "The struct to which a field belongs must be a left-hand side expression.");
			}
			temp = ast.factory().fieldReferenceNode((LHSExpressionNodeIF) body, fieldID);
			
			// Check for additional suffixes
			if (node.getChildCount() == 3) {
				result = this.processPostfixSuffix(temp, node.getChild(2));
			} else {
				result = temp;
			}
		}
		// TODO Auto-generated method stub
		return result;
	}

	private ExpressionNodeIF processPrimary(Tree node) throws SyntaxException {
		ExpressionNodeIF result = null;
		if (node.getChildCount() == 1) {
			if (node.getChild(0).getType() == PragmaStringLexer.CONSTANT) {
				result = processLiteral(node.getChild(0));
			} else if (node.getChild(0).getType() == PragmaStringLexer.EVALUATED_FUNCTION_EXPR) {
				result = processEvaluatedFunction(node.getChild(0));
			} else if (node.getChild(0).getType() == PragmaStringLexer.DERIVATIVE_EXPR) {
				result = processDerivative(node.getChild(0));
			} else if (node.getChild(0).getType() == PragmaStringLexer.SPEC_EXPR) {
				result = processSpecExpression(node.getChild(0));
			} else {
				IdentifierNodeIF identifier = ast.factory().identifierNode(
						node.getChild(0).getText());
				
				result = ast.factory().variableReferenceNode();
				((VariableReferenceNodeIF) result).setName(identifier.name());
			}
		} else {
			result = processExpression(node.getChild(0));
		}
		return result;
	}

	private ExpressionNodeIF processSpecExpression(Tree child) {
		// TODO Auto-generated method stub
		return null;
	}

	private ExpressionNodeIF processDerivative(Tree child) {
		// TODO Auto-generated method stub
		return null;
	}

	private ExpressionNodeIF processEvaluatedFunction(Tree child) {
		// TODO Auto-generated method stub
		return null;
	}

	private ExpressionNodeIF processLiteral(Tree node) throws SyntaxException {
		ExpressionNodeIF expr = null;
		String text;

		switch (node.getChild(0).getType()) {
		case PragmaStringLexer.TRUE:
			expr = ast.factory().integerLiteralNode(null,
					ast.factory().booleanTypeNode(), 1);
			break;
		case PragmaStringLexer.FALSE:
			expr = ast.factory().integerLiteralNode(null,
					ast.factory().booleanTypeNode(), 0);
			break;
		case PragmaStringLexer.INT_LITERAL:
			// TODO Handle all the different types of ints/doubles
			text = node.getChild(0).getText();
			text = text.replaceAll("u", "");
			text = text.replaceAll("U", "");
			text = text.replaceAll("l", "");
			text = text.replaceAll("L", "");
			expr = ast.factory().integerLiteralNode(null,
					ast.factory().integerTypeNode(), Integer.parseInt(text));
			break;
		case PragmaStringLexer.REAL_LITERAL:
			text = node.getChild(0).getText();
			text = text.replaceAll("F", "");
			text = text.replaceAll("f", "");
			expr = ast.factory().realLiteralNode(null,
					ast.factory().realTypeNode(),
					new RealNumberFactory().rational(text));
			break;
		case PragmaStringLexer.CHAR_LITERAL:
			char[] charValue = node.getChild(0).getText().toCharArray();
			if (charValue.length - 2 > 1) {
				throw new SyntaxException(
						"Char value have length greater than 1.");
			}
			char value = charValue[1];
			expr = ast.factory().characterLiteralNode(null,
					ast.factory().characterTypeNode(), value);
			break;
		// TODO Handle string literals, figure out if we still need system
		// variables
		// case PragmaStringLexer.STRING_LITERAL:
		// String string = node.getChild(0).getText();
		// char[] charArray = string.toCharArray();
		// // subtract 2 to get rid of leading and trailing "
		// int numChars = charArray.length - 2;
		// ASTExpressionIF[] charLiterals = new ASTExpressionIF[numChars];
		// ASTTypeIF charType = new ASTCharType();
		// ASTIntegerLiteral extent = new ASTIntegerLiteral(numChars);
		// ASTArrayType arrayType = new ASTArrayType(charType, extent);
		//
		// for (int i = 0; i < numChars; i++) {
		// charLiterals[i] = new ASTCharLiteral(charType, charArray[i + 1]);
		// }
		// expr = new ASTArrayLiteral(arrayType, charLiterals);
		// break;
		// case PragmaStringLexer.SYS_VAR:
		// if (node.getChild(0).getText().equals("PID")) {
		// expr = new ASTSystemVariable(new ASTIntegerType(), SYS_VAR.PID);
		// } else {
		// expr = new ASTSystemVariable(new ASTIntegerType(),
		// SYS_VAR.NPROCS);
		// }
		// break;
		default:
			throw new SyntaxException("Unknown constant type: "
					+ node.getChild(0));
		}
		return expr;
	}

	private TypeNodeIF processType(String type) {
		if (type.equals("int")) {
			return ast.factory().integerTypeNode();
		} else if (type.equals("char")) {
			return ast.factory().characterTypeNode();
		} else if (type.equals("_Bool")) {
			return ast.factory().booleanTypeNode();
		}
		// TODO Add additional types
		return null;
	}

	private CommonTree prepareTree(String pragma) throws SyntaxException {
		// Using the generated lexer and parser to build the ANTLR tree.
		PragmaStringLexer lex = new PragmaStringLexer(new ANTLRStringStream(
				pragma));
		CommonTokenStream tokens = new CommonTokenStream(lex);
		PragmaStringParser parser = new PragmaStringParser(tokens);
		pragma_return r = null;
		try {
			r = parser.pragma();
		} catch (RecognitionException e) {
			throw new SyntaxException(parser.getSourceName()
					+ " parsed unsuccessfully: \n" + e.getMessage());
		}
		// Get the number of syntax errors from the lexer/parser.
		int errors = parser.getNumberOfSyntaxErrors();
		if (errors > 0) {
			throw new SyntaxException(parser.getSourceName()
					+ " parsed unsuccessfully.");
		}
		return (CommonTree) r.getTree();
	}

	@Override
	public String name() {
		return "pragmaParser";
	}

}