#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <sstream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <numeric>
#include <cctype>
#include <tuple>
#include <array>
#include <climits>
#include <bitset>
#include <cassert>

#ifdef _MSC_VER
#include <agents.h>
#endif

#define FOR(i, a, b) for(int i = (a); i < (int)(b); ++i)
#define rep(i, n) FOR(i, 0, n)
#define ALL(v) v.begin(), v.end()
#define REV(v) v.rbegin(), v.rend()
#define MEMSET(v, s) memset(v, s, sizeof(v))
#define UNIQUE(v) (v).erase(unique(ALL(v)), (v).end())
#define MP make_pair
#define MT make_tuple

using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<int, int> P;

const int N = 260;
const int K = 555;
int ok[K][K];
vector<int> G[K];

int id[55][55];
char field[55][55];
int visit[55][55];

char ch[K];
int dp[K][K][2][2];
vector<int> ord;

inline int check(int c1, int c2){
	return ch[c1] - 'a' == ch[c2] - 'A';
}

int rec(int l, int r, int a, int b){
	if (r - l <= 1) return !a && !b && check(ord[l], ord[r]);
	int &res = dp[l][r][a][b];
	if (res + 1) return res;
	res = 0;

	if (!a && !b && check(ord[l], ord[r])){
		res = 1 + rec(l, r, 1, 1);
	}

	for (int k = l + 1; k < r; ++k){
		if (ok[ord[l]][ord[k]] && ok[ord[k]][ord[r]]){
			res = max(res, rec(l, k, a, 1) + rec(k, r, 0, b));
			res = max(res, rec(l, k, a, 0) + rec(k, r, 1, b));
		}
	}
	return res;
}

int h, w;
void dfs(int r, int c, int v){
	visit[r][c] = 1;
	rep(i, 2){
		int nr = r + i, nc = c + !i;
		if (nr < 0 || nc < 0 || nr >= h || nc >= w) continue;
		if (field[nr][nc] == '#') continue;
		if (visit[nr][nc]) continue;
		if (id[nr][nc] >= 0){
			G[v].push_back(id[nr][nc]);
			ok[v][id[nr][nc]] = 1;
		}
		dfs(nr, nc, v);
	}
}

void tdfs(int v, vector<int> &visit, vector<int> &res){
	visit[v] = 1;
	for (auto to : G[v]){
		if (visit[to]) continue;
		tdfs(to, visit, res);
	}
	res.push_back(v);
}

vector<int> tsort(int n){
	vector<int> vis(n), res;
	rep(i, n) if(!vis[i]) tdfs(i, vis, res);
	reverse(ALL(res));
	return res;
}

int main(){
	cin.tie(0);
	ios::sync_with_stdio(false);
	cout.setf(ios::fixed);
	cout.precision(20);

	while (cin >> h >> w, h){
		rep(i, h) cin >> field[i];
		rep(i, w) field[h][i] = "#."[i == w - 1];
		++h;

		MEMSET(id, -1);
		MEMSET(ch, 0);
		int num = 0;
		rep(i, h) rep(j, w){
			if (isupper(field[i][j]) || islower(field[i][j])){
				ch[num] = field[i][j];
				id[i][j] = num++;
			}
		}
		int SRC = num++;
		int SNK = num++;
		id[h - 1][w - 1] = SNK;

		MEMSET(visit, 0);
		MEMSET(ok, 0);
		rep(i, num) G[i].clear();
		dfs(0, -1, SRC);
		rep(i, h) rep(j, w) if (!visit[i][j]) field[i][j] = '#';
		rep(i, h) rep(j, w){
			if (id[i][j] >= 0){
				MEMSET(visit, 0);
				dfs(i, j, id[i][j]);
			}
		}

		if (!ok[SRC][SNK]){
			cout << -1 << endl;
			continue;
		}

		ord = tsort(num);
		MEMSET(dp, -1);

		int r = -1;
		rep(i, num) if (ord[i] == SNK) r = i;

		cout << rec(0, r, 0, 0) << endl;
	}
}