package pregroup;
//! Implementation of Moroz's algorithm
public class Parser
{
private PhraseString phrase;
//! Length of the TypePhrase
private int n;
//! What is a type reduction for the substring [i,j] ?
private TypeReduction[][] red;
//! Is the substring [i,j] reductible to 1 ?
private int[][] state;
//! Index of words
private int[] widx;
//! Comparator for the types
PartialComparator<String> comp;
public final static int UNDEF = -1;
public Parser(PhraseString phr, PartialComparator<String> c)
{
phrase = phr;
comp = c;
n = phrase.size();
red = new TypeReduction[n][n];
state = new int[n][n];
widx = new int[n];
for(int i = 0; i < n; i++)
{
if(i == 0)
widx[i] = 0;
else if(get(i).isLB())
widx[i] = widx[i-1] + 1;
else widx[i] = widx[i-1];
for(int j = 0; j < n; j++)
{
state[i][j] = UNDEF;
red[i][j] = null;
}
}
}
public boolean run()
{
return reductible(0,n-1);
}
private boolean reductible(int i, int j)
{
if(i < 0 || i >= n || j < 0 || j >= n || i > j)
return false;
if(state[i][j] != UNDEF)
return state[i][j] == 1;
boolean result = computeReductible(i,j);
state[i][j] = (result ? 1 : 0);
return result;
}
private boolean computeReductible(int i, int j)
{
// Base case
if(i == j && isType(i) && isUnit(i))
{
red[i][i] = empty();
return true;
}
if(j == i+1)
{
if(isType(i) && isType(j) && gcon(i,j))
{
red[i][j] = empty().link(i,j);
return true;
}
else return false;
}
if(isType(i) && isType(j)
&& isStar(i+1)
&& isStar(j-1)
&& widx[j] == widx[i]+1
&& gcon(i,j))
{
red[i][j] = empty().link(i,j);
return true;
}
if(isType(i) && isType(j))
{
// A1a
for(int k = i+1; k < j-1; k++)
if(isType(k) && reductible(i,k) && reductible(k+1,j))
{
red[i][j] = union(red[i][k], red[k+1][j]);
return true;
}
// A1b
for(int k = i+1; k < j-1; k++)
if(isRB(k) && isLB(k+1) && reductible(i,k) && reductible(k+1,j))
{
red[i][j] = union(red[i][k], red[k+1][j]);
return true;
}
// A2
if(gcon(i,j) && reductible(i+1, j-1))
{
red[i][j] = red[i+1][j-1].link(i, j);
return true;
}
}
// A3a
if(isLB(i) && isType(j))
{
for(int k = i+1; k < j && widx[k] == widx[i]; k++)
if(isStar(k) && reductible(k+1,j))
{
red[i][j] = red[k+1][j];
return true;
}
}
// A3b
if(isRB(j) && isType(i))
{
for(int k = j-1; k > i && widx[k] == widx[j]; k--)
if(isStar(k) && reductible(i,k-1))
{
red[i][j] = red[i][k-1];
return true;
}
}
// A4a
if(isType(i) && isType(j) && isStar(i+1) && gcon(i,j)
&& widx[i] != widx[j])
{
for(int k = i+1; k <j && widx[k] == widx[i]; k++)
if(isLB(k+1) && reductible(k+1,j-1))
{
red[i][j] = red[k+1][j-1].link(i, j);
return true;
}
}
// A4b
if(isType(i) && isType(j) && isStar(j-1) && gcon(i,j)
&& widx[i] != widx[j])
{
for(int k = j-1; k > i && widx[k] == widx[j]; k--)
if(isRB(k-1) && reductible(i+1,k-1))
{
red[i][j] = red[i+1][k-1].link(i, j);
return true;
}
}
// A4c
if(isType(i) && isType(j) &&
isStar(i+1) && isStar(j-1) &&
1 + widx[i] < widx[j] &&
gcon(i,j))
{
int k1, k2;
for(k1 = i+1; k1 < j && !isRB(k1); k1++);
for(k2 = j-1; k2 > i && !isLB(k2); k2--);
if(reductible(k1,k2))
{
red[i][j] = red[k1][k2].link(i, j);
return true;
}
}
// A5
if(isLB(i) && isRB(j))
{
for(int k1 = i+1; k1 < j && !isRB(k1); k1++)
{
if(isType(k1) && isStar(k1-1))
{
for(int k2 = j-1; k2 > i && !isLB(k2); k2--)
{
if(isType(k2) && isStar(k2+1) &&
reductible(k1,k2))
{
red[i][j] = red[k1][k2];
return true;
}
}
}
}
}
return false;
}
public TypeReduction getReduction()
{
return red[0][n-1];
}
private PhraseElem get(int pos)
{
return phrase.get(pos);
}
private SimpleType at(int pos)
{
return ((TypeElem)phrase.get(pos)).val;
}
private boolean isType(int pos)
{
return get(pos).isType();
}
private boolean isLB(int pos)
{
return get(pos).isLB();
}
private boolean isRB(int pos)
{
return get(pos).isRB();
}
private boolean isStar(int pos)
{
return get(pos).isStar();
}
private boolean isUnit(int pos)
{
return (isType(pos) && at(pos).isUnit());
}
private boolean gcon(int i, int j)
{
return (isType(i) && isType(j) &&
at(i).gcon(at(j), comp));
}
private static TypeReduction empty()
{
return TypeReduction.empty();
}
private static TypeReduction union(TypeReduction lhs, TypeReduction rhs)
{
return TypeReduction.union(lhs, rhs);
}
}