Skip to content

Commit

Permalink
Abstract Normal Form: with chains, *without* horizontals
Browse files Browse the repository at this point in the history
  • Loading branch information
grammarware committed Jul 4, 2012
1 parent 4bf06dc commit abfd7a0
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 36 deletions.
6 changes: 5 additions & 1 deletion shared/rascal/src/analyse/Prodsigs.rsc
Expand Up @@ -37,6 +37,7 @@ Footprint makefp(n, sequence(L))
default Footprint makefp(str n, BGFExpression x) = fpempty();

Signature makesig(BGFProduction p) = {<n,makefp(n,p.rhs)> | n <- usedNs(p.rhs)};
Signature makesig(BGFExpression e) = {<n,makefp(n,e )> | n <- usedNs(e )};

bool eqfp(fpnt(), fpnt()) = true;
bool eqfp(fpopt(), fpopt()) = true;
Expand All @@ -63,10 +64,12 @@ default bool equivfp(Footprint pi, Footprint xi) = eqfp(pi,xi);
// strong equivalence relies on natural equality of footprints
// (i.e., == of rels)
bool eqps(BGFProduction p1, BGFProduction p2) = eqps(makesig(p1),makesig(p2));
default bool eqps(Signature p, Signature q) = geqps(p,q,eqfp,true);
bool eqps(BGFExpression e1, BGFExpression e2) = eqps(makesig(e1),makesig(e2));
bool eqps(Signature p, Signature q) = geqps(p,q,eqfp,true);

// weak equivalence relies on equivalence of footprints
bool weqps(BGFProduction p1, BGFProduction p2) = weqps(makesig(p1),makesig(p2));
bool weqps(BGFExpression e1, BGFExpression e2) = weqps(makesig(e1),makesig(e2));
default bool weqps(Signature p, Signature q) = geqps(p,q,equivfp,false);

// footprint-comparator-parametrised equivalence
Expand All @@ -92,6 +95,7 @@ bool geqps(Signature p, Signature q, bool(Footprint,Footprint) cmp, bool strong)
return true;
}

NameMatch makenamematch(BGFExpression e1, BGFExpression e2) = makenamematch(makesig(e1),makesig(e2));
NameMatch makenamematch(BGFProduction p1, BGFProduction p2) = makenamematch(makesig(p1),makesig(p2));
NameMatch makenamematch(Signature p, Signature q)
{
Expand Down
62 changes: 58 additions & 4 deletions shared/rascal/src/converge/PureGuided.rsc
Expand Up @@ -24,17 +24,71 @@ bool conflicted(NameMatch a, NameMatch b)
return !isEmpty(a o b);
}

BGFProduction getSingleProd(set[str] ns, BGFProdList ps)
{
BGFProdList ps1 = [*prodsOfN(n,ps) | n <- ns];
if (len(ps1)!=1)
throw "Grammar not in ANF with <ps1>";
else
return ps1[0];
}

tuple[NameMatch,BGFProdList,BGFProdList]
matchProds(NameMatch known, BGFProdList mps, BGFProdList sps)
{
BGFProdList ps1 = [*prodsOfN(n,mps) | <n,_> <- known];
BGFProdList ps2 = [*prodsOfN(n,sps) | <n,_> <- known];
// TODO double-check
BGFProduction p1 = getSingleProd({n | <n,_> <- known},mps);
BGFProduction p2 = getSingleProd({n | <n,_> <- known},sps);

println("Trying to match production rules:");
for (p <- ps1) println(" <pp(p)>\t <pp(analyse::Prodsigs::makesig(p))>");
println(" <pp(p1)>\t <pp(analyse::Prodsigs::makesig(p1))>");
println(" vs");
for (p <- ps2) println(" <pp(p)>\t <pp(analyse::Prodsigs::makesig(p))>");
println(" <pp(p2)>\t <pp(analyse::Prodsigs::makesig(p2))>");
// check for strong prodsig-equivalence first
println("Looking for strong equivalence.");
if (production(_,_,choice(_)) !:= p1 && production(_,_,choice(_)) !:= p2)
{
// match p1.rhs vs p2.rhs
if (analyse::Prodsigs::eqps(p1,p2))
{
nm = analyse::Prodsigs::makenamematch(p1,p2);
println("Found prodsig-equivalent production rules: <pp(nm)>");
if (!isEmpty(nm-known))
println("Will assume that <pp(nm)> after <pp(known)>");
return <nm, mps - p1, sps - p2>;
}
}
elseif (production(_,_,choice(L1)) := p1 && production(_,_,choice(L2)) := p2)
{
// match L1 vs L2
for (e1 <- L1, e2 <- L2, nonterminal(n1) := e1, nonterminal(n2) := e2)
{
pps1 = prodsOfN(n1,mps);
switch(len(pps1))
{
case 0: ep1 = e1;
case 1: ep1 = pps1[0].rhs;
default: throw "Grammar not in ANF with <pps1>";
}
pps2 = prodsOfN(n2,sps);
switch(len(pps2))
{
case 0: ep2 = e2;
case 1: ep2 = pps2[0].rhs;
default: throw "Grammar not in ANF with <pps2>";
}
if (analyse::Prodsigs::eqps(e1,e2))
{
nm = analyse::Prodsigs::makenamematch(e1,e2);
println("Found prodsig-equivalent production rules: <pp(nm)>");
if (!isEmpty(nm-known))
println("Will assume that <pp(nm)> after <pp(known)>");
return <nm, mps - p1, sps - p2>;
}
}
}
else
throw "Choice vs no choice";
//println("<pp(analyse::Prodsigs::makesig(p1))> vs <pp(analyse::Prodsigs::makesig(p2))>");
//println("Equality: <analyse::Prodsigs::eqps(p1,p2)>; equivalence: <analyse::Prodsigs::weqps(p1,p2)>");
for (p1 <- ps1, p2 <- ps2, analyse::Prodsigs::eqps(p1,p2))
Expand Down
47 changes: 25 additions & 22 deletions shared/rascal/src/normal/ANF.rsc
Expand Up @@ -32,7 +32,7 @@ CBGFSequence normAllStages(BGFGrammar gr)
dropAllLabels,
dropAllSelectors,
dropAllTerminals,
//dropAllHorizontals,
dropAllHorizontals,
dropAllUnknowns,
dropAllChains
])
Expand All @@ -45,8 +45,7 @@ CBGFSequence normAllStages(BGFGrammar gr)
}
c += c1;
} while (!isEmpty(c1));
// TODO check for horizontal/vertical issue
// now g is normalised, but with possibly multiple productions per nonterminal
// introduce chain rules
for (n <- definedNs(g))
{
ps = prodsOfN(n,g.prods);
Expand All @@ -55,40 +54,44 @@ CBGFSequence normAllStages(BGFGrammar gr)
{
// go over all vertical production rules
for (p <- ps)
if (nonterminal(_) !:= p.rhs)
if (nonterminal(_) !:= p.rhs && val(_) !:= p.rhs)
{
c2 = [extract_inline(production("",uniqueName(n,allNs(g)),p.rhs),innt(n))];
// global extract can introduce conflicts with subsequent extracts,
// that's why we need to transform immediately
//println("Transforming <pp(g)>...");
g = transform(forward(c2),g);
c1 += c2;
}
c1 += horizontal_vertical(innt(n));
}
elseif (production(_,n,choice(L)) := ps[0])
{
//println("Horizontal!");
// go over all horizontal production rules
for (e <- L)
if (nonterminal(_) !:= e)
{
c2 = [extract_inline(production("",uniqueName(n,allNs(g)),e),innt(n))];
// global extract can introduce conflicts with subsequent extracts,
// that's why we need to transform immediately
g = transform(forward(c2),g);
c1 += c2;
}
//c1 += horizontal_vertical(innt(n));
}
//elseif (production(_,n,choice(L)) := ps[0])
//{
// //println("Horizontal!");
// // go over all horizontal production rules
// for (e <- L)
// if (nonterminal(_) !:= e)
// {
// c2 = [extract_inline(production("",uniqueName(n,allNs(g)),e),innt(n))];
// // global extract can introduce conflicts with subsequent extracts,
// // that's why we need to transform immediately
// g = transform(forward(c2),g);
// c1 += c2;
// }
//}
//else
// iprintln(ps);
}
//iprintln(c1);
// now we can have constuctions like this:
// expression ::= (expression1 | expression2 | expression3 | expression | id | number) ;
// with cleverly hidden reflexive chain rules
for (p <- g.prods, production(str l,str n,choice(L)) := p, [*L1,nonterminal(n),*L2] := L)
//for (p <- g.prods, production(str l,str n,choice(L)) := p, [*L1,nonterminal(n),*L2] := L)
// // the last expression is a traceable variant of "nonterminal(n) in L"
// c1 += removeH_addH(production(l,n,choice([*L1, marked(nonterminal(n)), *L2])));
for (p <- g.prods, production(str l,str n,nonterminal(n)) := p)
// the last expression is a traceable variant of "nonterminal(n) in L"
c1 += removeH_addH(production(l,n,choice([*L1, marked(nonterminal(n)), *L2])));
c1 += removeV_addV(p);
return c+c1;
}

Expand Down Expand Up @@ -136,7 +139,7 @@ BGFProduction markAllTerminals(BGFProduction p) = visit(p) {case terminal(t) =>
public void main()
{
for (src <- ["antlr","dcg","ecore","emf","jaxb","om","python","rascal-a","rascal-c","sdf","txl","xsd"])
//for (src <- ["txl"])
//for (src <- ["xsd"])
{
println("Reading <src>...");
BGFGrammar g = readBGF(|home:///projects/slps/topics/convergence/guided/bgf/<src>.bgf|);
Expand Down
35 changes: 26 additions & 9 deletions topics/convergence/guided/bgf/master.bgf
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
program ::= function+ trailing??
function ::= name argument+ expression (separator+)??
expression ::= aexpr | argument | bexpr | cexpr | lexpr
bexpr ::= expr expr
aexpr ::= name expression+
cexpr ::= expr expr expr
expression ::= expression
program ::= function+
function ::= name argument+ expression
expression ::= apply | argument | binary | conditional | lexpr
binary ::= expression operator expression
apply ::= name expression+
conditional ::= expression expression expression
argument ::= name
lexpr ::= number
-->
Expand Down Expand Up @@ -56,6 +55,24 @@ lexpr ::= number
</bgf:production>
<bgf:production>
<nonterminal>expression</nonterminal>
<bgf:expression>
<nonterminal>apply</nonterminal>
</bgf:expression>
</bgf:production>
<bgf:production>
<nonterminal>expression</nonterminal>
<bgf:expression>
<nonterminal>binary</nonterminal>
</bgf:expression>
</bgf:production>
<bgf:production>
<nonterminal>expression</nonterminal>
<bgf:expression>
<nonterminal>conditional</nonterminal>
</bgf:expression>
</bgf:production>
<bgf:production>
<nonterminal>apply</nonterminal>
<bgf:expression>
<sequence>
<bgf:expression>
Expand All @@ -72,7 +89,7 @@ lexpr ::= number
</bgf:expression>
</bgf:production>
<bgf:production>
<nonterminal>expression</nonterminal>
<nonterminal>binary</nonterminal>
<bgf:expression>
<sequence>
<bgf:expression>
Expand All @@ -88,7 +105,7 @@ lexpr ::= number
</bgf:expression>
</bgf:production>
<bgf:production>
<nonterminal>expression</nonterminal>
<nonterminal>conditional</nonterminal>
<bgf:expression>
<sequence>
<bgf:expression>
Expand Down

0 comments on commit abfd7a0

Please sign in to comment.