private void matchProcedureDeclarations() {
		dispatchEvent(ParserEvent.BEGAN_PARSING_NON_TERMINAL_SYMBOL, "ProcDecl");

		boolean hasReturnType = false;

		ProcedureBuilder.getInstance().startBuilding();

		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Keyword.PROCEDURE);
		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Token.Type.IDENTIFIER);
		String name = TokenIterator.getInstance().getCurrent().getValue().toString();
		ProcedureBuilder.getInstance().setName(name);
		if (ProcedureBuilder.getInstance().containsPromise(name)) {
			ProcedureBuilder.getInstance().swap(ProcedureBuilder.getInstance().getPromise(name));
		} else {
			ScopeManager.getInstance().getProgramScope().insert(name, ProcedureBuilder.getInstance().peekDeclaration());
		}

		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.OPENING_PARENTHESIS);
		if (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Token.Type.IDENTIFIER)) {
			ProcedureBuilder.getInstance().setParameters(matchFormals(name));
		}

		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.CLOSING_PARENTHESIS);

		if (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Reserved.Symbol.COLON)) {
			SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.COLON);
			SemanticValidator.getInstance().validateIsOfTypeInteger(TokenIterator.getInstance().peek().getValue().toString());
			ProcedureBuilder.getInstance().setReturnType(matchType(name));
			hasReturnType = true;
		}
		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.SEMICOLON);

		LinkedHashMap<List<Token>, Type> localVariables = new LinkedHashMap<List<Token>, Type>();
		while (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Reserved.Keyword.VAR)) {
			SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Keyword.VAR);
			while (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Token.Type.IDENTIFIER)) {
				List<Token> identifiers = matchIdentifierList();
				SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.COLON);
				localVariables.put(identifiers, matchType(TokenIterator.getInstance().getName(identifiers)));
				SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.SEMICOLON);
			}
		}
		ProcedureBuilder.getInstance().setLocalVariables(localVariables);

		if (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Reserved.Keyword.BEGIN)) {
			SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Keyword.BEGIN);
			ProcedureBuilder.getInstance().setInstructions(matchInstructions());
		}

		if (SyntacticValidator.getInstance().isNextToken(ProductionRule.OPTIONAL, Reserved.Keyword.RETURN)) {
			SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Keyword.RETURN);
			Expression expression = matchExpression();
			SemanticValidator.getInstance().validateExpressionIsOfTypeInteger(expression);
			ProcedureBuilder.getInstance().setReturnExpression(expression);
		} else if (hasReturnType) {
			SemanticValidator.getInstance().validateProcedureHasReturnExpression(ProcedureBuilder.getInstance().getDeclaration());
		}

		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Keyword.END);
		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Token.Type.IDENTIFIER);
		String name1 = TokenIterator.getInstance().getCurrent().getValue().toString();
		SemanticValidator.getInstance().validateProcedureIdentifier(name, name1);
		SyntacticValidator.getInstance().matchNextToken(ProductionRule.REQUIRED, Reserved.Symbol.SEMICOLON);

		ProcedureBuilder.getInstance().getDeclaration();

		ProcedureBuilder.getInstance().reset();
		if (ProcedureBuilder.getInstance().containsPromise(name)) {
			ProcedureBuilder.getInstance().finalizeSwap(ProcedureBuilder.getInstance().getPromise(name));
		}
		dispatchEvent(ParserEvent.FINISHED_PARSING_NON_TERMINAL_SYMBOL, "ProcDecl");
	}