import std.stdio,std.conv, std.algorithm, std.container,std.array,std.range,std.string,std.typecons,std.numeric,std.math,std.random,std.functional;

void main(){
	int w,h;
	while(read(w,h),w|h){		
		auto land = readMatrix(w,h);
		auto seeked = Matrix!(bool)(w,h);

		void SEEK (Pos p,ref Pos[] seeking,ref char type){
			if(!p.inRange(w,h))return;
			if(seeked[p])return;
			if(land[p] == 'W' || land[p] == 'B') {
				if(type == '.') type = land[p];
				else if(type != land[p]) type = 'X';
				return ;
			}
			seeking ~= p;
			seeked[p] = true;
			foreach(dpos;DPos) SEEK(p + dpos,seeking,type);
		}

		int B ,W;
		foreach(y;iota(h)){
			foreach(x;iota(w)){
				Pos[] seeking;
				char type = '.';
				SEEK(Pos(x,y),seeking,type);
				if(seeking.length == 0) continue;
				if(type == 'B') B += seeking.length;
				if(type == 'W') W += seeking.length;
			}
		}
		writeln(B," ",W);
	}
}


////////////////////////////////////LIB72//////////////////////////
const readMixin = q{ auto line = readln().split();foreach(i,ref arg; args){ if (i >= line.length) return;arg = line[i].to!(typeof(arg));}};
void read(T...)  (auto ref T args){mixin(readMixin);}
void readArray(T)(auto ref T args){mixin(readMixin);}
int  read(){int n;read(n);return n;}
const Dx = [1,0,-1,0], Dy = [0,1,0,-1];
const DPos = [Pos(1,0),Pos(0,1),Pos(-1,0),Pos(0,-1)];
void times(int n,void delegate() stmt){ foreach(i;iota(n))stmt();}

auto dot(R1,R2)(R1 a,R2 b) { 
	ElementType!(R1) res=0;
	for(;!a.empty&&!b.empty;a.popFront(),b.popFront())
		res+=a.front*b.front;
	return res;
}
struct infIota { 
	int i=0;
	enum empty=false;
	int front(){return i;}
	void popFront(){i++;}
}
struct Pos{ 
	int x,y,z;
	bool inRange(int w,int h,int Z=1){
		return x>=0 && y >= 0 && z >=0 && x < w && y < h && z < Z;
	}
	Pos opBinary(string op)(Pos rhs) {
		return Pos ( mixin( "x"~op~"rhs.x" ),
					 mixin( "y"~op~"rhs.y" ),
					 mixin( "z"~op~"rhs.z" ));
	}
	void opOpAssign(string op)(Pos lhs) {
		mixin("x"~op~"=lhs.x;");
		mixin("y"~op~"=lhs.y;");
		mixin("z"~op~"=lhs.z;");
	}
}
struct Matrix(T){
	private T[][] data;
	this(int w,int h){ data = new T[][](w,h);}
	this(ref T[][] data_){ data = data_;}
	T opIndexAssign(T v, size_t x, size_t y){return data[x][y] = v;}
	T opIndexAssign(T v, Pos p){return opIndexAssign(v,p.x,p.y);}
	T opIndex(size_t x, size_t y){return data[x][y];}
	T opIndex(Pos p){return opIndex(p.x,p.y);}
	ref T opCall(Pos p){return data[p.x][p.y];}
	auto W()const{return data.length;}	
	auto H()const{return data[0].length;}	
	void toString(scope void delegate(const(char)[]) sink) const{
		foreach(y;iota(H())) {
			foreach(x;iota(W()))sink(data[x][y].to!string);
			if(y != H()-1)sink("\n");
		}
    }
}
auto readMatrix(int w,int h){ 
	auto M=new char[][](w,h);
	foreach(y;iota(h)) foreach(int x,c;readln().chomp) M[x][y] = c;		
	return Matrix!(char)(M);
}

////////////////////////////////////LIB72//////////////////////////

void rep(int[] ms,void delegate(int,int) f){
	for(int i0;i0<ms[0];i0++) 
		for(int i1;i1<ms[1];i1++) 
			f(i0,i1);
}
//[3,4,5,6].REP!((i,j,k,l)=>{});