|
Server : Apache/2.4.62 System : FreeBSD fbsdweb2.web.rcn.net 14.1-RELEASE FreeBSD 14.1-RELEASE releng/14.1-n267679-10e31f0946d8 GENERIC amd64 User : www ( 80) PHP Version : 8.3.8 Disable Function : NONE Directory : /domains/markrose/ |
Upload File : |
<HTML>
<HEAD>
<meta http-equiv="content-type" content="text-html; charset=utf-8">
<TITLE>mg - Minimalism Gadget</TITLE>
<style>
h2
{color:#A60000;}
h3
{color:#C08700;}
h4
{color:#C08700;}
h5
{color:#C08700;}
h6
{color:#C08700;}
tt
{color:#A60000;
font-weight:bold;
font-family:"Gentium";}
</style>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<form action="" name="theform">
<script language="javascript" type="text/javascript">
// Script (C) 2018 by Mark Rosenfelder.
var theform;
var lex;
var ord;
// Random int from 0 to n
function randomInt(max)
{
return Math.floor(Math.random() * max) ;
}
// Return the word portion of a lexeme (before the :)
function theword(s)
{
var i = s.indexOf(':');
if (i == -1) return s;
return s.substr(0,i);
}
// Return the category of a lexeme (just after the :)
function thehead(s)
{
var spp = s.split(":")
if (spp.length < 2) return s;
var shpp = spp[1].split(" ");
return shpp[0];
}
// Search lexicon for items that want a following x
function wanters(lex, x)
{
var out = new Array();
for (var r = 0; r < lex.length; r++) {
var partz = lex[r].split(":");
if (partz.length == 1) continue;
var catz = partz[1].split(" ");
if (catz.length == 1) continue;
if (catz[0] == "A" && countA >= 2) continue;
if (catz[1] == x)
out.push(lex[r]);
}
return out;
}
// Create a terminal node from a string
function TermS(s, h)
{
var node = {head:"XP", term:true, left:"a" };
node.head = h;
node.left = s;
return node;
}
// Create a terminal node from a lexeme
function Term(lx)
{
return TermS( lx, thehead(lx) );
}
// Create a trace node based on another node
function Trace(b, h)
{
return TermS( "<<i>" + showterms(b).substr(1) + "</i>>:" + h, h);
}
// Find a word in the lexicon and return it as a node
function FindNode(tgt)
{
for (var r = 0; r < lex.length; r++) {
if (theword(lex[r]) == tgt)
return Term(lex[r]);
}
return null;
}
// Add to the output
function report(s)
{
var text = document.getElementById("mytext")
text.innerHTML = text.innerHTML + s;
}
var indent = 0;
// Output an entire tree
function showtree(tree)
{
var s = "";
if (tree.term) {
var lx = tree.left;
s += "<br>";
for (i = 0; i < indent; i++)
s += " ";
s += tree.head + ":" + theword(lx);
} else {
s += "<br>";
for (i = 0; i < indent; i++)
s += " ";
s += tree.head;
indent++;
s += showtree(tree.left);
s += showtree(tree.right);
indent -= 1;
}
return s;
}
// Output only the terminals
function showterms(tree)
{
var s = "";
if (tree.term) {
w = theword(tree.left);
if (w.charAt(0) != '&' && w!= "Past" && w != "Pres" && w != "Q" && w != "ø")
s += " " + w;
} else {
s += showterms(tree.left);
s += showterms(tree.right);
}
return s;
}
// Check the order of a/b from the order table.
// Return true iff we should place b first.
function Rev(a, b, h)
{
var ab = a.head + " " + b.head;
var ba = b.head + " " + a.head;
// Look through ord to see if we have this ordering
for (var i = 0; i < ord.length; i++) {
var s = ord[i];
var ss = s.split(":");
if (ss[0] == ab || ss[0] == ba) {
if (ss.length == 1 || ss[1] == h)
return ss[0] == ba;
}
}
return false;
}
// Create a node from two compatible nodes
function Merge(a, b, h)
{
var node = {head:"XP", term:false, left:"a", right:"b"};
node.head = h;
if (Rev(a, b, h)) {
node.left = b;
node.right = a;
} else {
node.left = a;
node.right = b;
}
Agree(a, b);
DoCase(a, b);
report("<p><b>Merge " + h + "</b>: " + showtree(node));
return node;
}
// Search a tree for any node of type h
// want D
// [P on [D [D the] [N mat]]]
// returns [D the]
function Find(tree, h)
{
if (tree.term) {
var lx = tree.left;
if (thehead(lx) == h) return tree;
} else {
var n = Find(tree.left, h);
if (n != null) return n;
n = Find(tree.right, h);
if (n != null) return n;
}
return null;
}
// Search for the parent of node n
function FindParent(tree, tgt)
{
if (tree.term) return null;
if (tree.left == tgt || tree.right == tgt) return tree;
var n = FindParent(tree.left, tgt);
if (n != null) return n;
n = FindParent(tree.right, tgt);
if (n != null) return n;
return null;
}
// Find the *container* of any node marked h.
// want D
// [P on [D [D the] [N mat]]]
// returns P
function Finddad(tree, h)
{
if (tree.term) return null;
if (tree.left.head == h || tree.right.head == h) return tree;
var n = Finddad(tree.left, h);
if (n != null) return n;
var n = Finddad(tree.right, h);
if (n != null) return n;
return null;
}
var onleft = false;
// Find the *container* of a *terminal* node marked h.
// want D
// [P on [D [D the] [N mat]]]
// returns D
function FindDadOfTerm(tree, h)
{
if (tree.term) return null;
if (tree.left.head == h && tree.left.term) {
onleft = true;
return tree;
}
if (tree.right.head == h && tree.right.term) {
onleft = false;
return tree;
}
var n = FindDadOfTerm(tree.left, h);
if (n != null) return n;
var n = FindDadOfTerm(tree.right, h);
if (n != null) return n;
return null;
}
// Copy features to a noun modifier
// Example:
// cats:N:p
// this:D N:p these
// change D to these
function Agree(mod, tree)
{
if (!mod.term) return false;
if (mod.head != "A" && mod.head != "D") return false;
var n = Find(tree, "N");
if (n == null) return false;
npp = n.left.split(":");
if (npp.length < 3) return false;
return Inflect(mod, npp[2]);
}
// Handle case assignment for pronouns
function DoCase(mod, n)
{
if (n.head != "D") return;
if (mod.head != "V" && mod.head != "P") return;
var n = Find(n, "N");
if (n == null) return;
npp = n.left.split(":");
if (npp.length < 4) return;
var f = npp[3];
if (mod.head == "P" && npp.length == 5)
f = npp[4];
n.left = f + ":" + npp[1] + ":" + npp[2] + ":" + npp[3];
}
// Copy tense + number to verb
// Example:
// cat:N:s
// Past:T VP:Past
// sit:V P D:Pasts sat Pastp sat Prog sitting …
// change verb to sat
function Tense(tree)
{
var t = Find(tree, "T");
var v = Find(tree, "V");
var n = Find(tree, "N");
if (t == null || v == null || n == null) return false;
tpp = t.left.split(":");
// If there's a modal, it has no features to copy; we're done
if (tpp.length < 3) return false;
var feat = tpp[2];
npp = n.left.split(":");
if (npp.length > 2) feat += npp[2];
return Inflect(v, feat);
}
// Given a verb and the desired form, change the verb to that form.
// Example:
// form = Prog
// sit:V P D:s sits Past sat Prog sitting Perf sat
// change "sit" to "sitting"
function Inflect(v, form)
{
var vl = v.left;
var vpp = vl.split(":");
if (vpp.length < 3) return;
var vforms = vpp[2].split(" ");
for (var i = 0; i < vforms.length; i += 2) {
if (vforms[i] == form) {
v.left = vforms[i+1] + ":" + vpp[1] + ":" + vpp[2];
return true;
}
}
return false;
}
// Get a word of type target
function getnode(target)
{
// Find all lexemes of the target category
var s = "<p>Candidate " + target + ": ";
var candz = new Array();
for (var j = 0; j < lex.length; j++) {
var lx = lex[j];
if (thehead(lx) == target) {
candz.push(lx);
s += theword(lx) + " ";
}
}
// Randomly select one
var m = randomInt(candz.length);
var node = Term(candz[m]);
s += "<br>Selecting " + showtree(node);
report(s);
return node;
}
// Given a lexeme, set the specifer. E.g.
// sleep:V P D:Press sleeps
// the specifier is D.
function setSpec(lx)
{
var partz = lx.split(":");
if (partz.length > 1) {
var catz = partz[1].split(" ");
if (catz.length > 2)
return catz[2];
}
return "";
}
// Get a word that wants type target
function getWant(target)
{
var s = "<p>Words that want " + target + ": ";
var w = wanters(lex, target);
if (w.length == 0)
return null;
for (var i = 0; i < w.length; i++)
s += theword(w[i]) + " ";
var m = 0;
if (w.length > 1)
m = randomInt(w.length);
var node = Term(w[m]);
s += "<br>Selecting " + showtree(node);
report(s);
return node;
}
var hasAux = false;
// Optionally apply an auxiliary
function Aux(tree, tgt)
{
// Find the auxiliary in the lexicon
for (var r = 0; r < lex.length; r++) {
var partz = lex[r].split(":");
if (partz.length == 1) continue;
var catz = partz[1].split(" ");
if (catz.length > 1 && catz[0] == "Aux" && catz[1] == tgt) {
// Bingo. Add it to the tree
var ct = "V";
if (catz[1] == "Neg") ct = "Neg";
var lx = partz[0] + ":" + ct + " VP:" + partz[2];
var a = Term(lx);
// Apply inflection to the verb
var v = Find(tree, "V");
Inflect(v, tgt);
if (ct == "V")
hasAux = true;
return Merge(a, tree, "VP");
}
}
return tree;
}
var countA = 0;
var theObj = null;
// Put together a tree of type target, starting with a noun
function gettree(target)
{
// Get an N node
var subtarg = "N";
var b = getnode(subtarg);
countA = 0;
if (theObj == null)
theObj = b;
// Pronouns automatically get a null D
var npp = b.left.split(":");
if (npp.length > 3) {
subtarg = "D";
var d = TermS("ø:" + subtarg, subtarg);
b = Merge(d, b, subtarg);
}
// Some nodes want *two* nodes
var spc = "";
// Repeat building process till we have a tree of type target
for (var h = subtarg; h != target; ) {
// Find a node that wants h
// But: some nodes want a third argument
if (spc != "") {
var tmp = spc;
spc = "";
var a = gettree(tmp);
b = Merge(a, b, "VP");
b = special(b, false);
h = b.head;
} else {
var a = getWant(h);
if (a == null) {
report("<p><b>No words found</b> that want " + h + ". Check the lexicon!");
return b;
}
spc = setSpec(a.left);
var h = a.head;
if (h == "A") {
h = b.head; // kludgy
countA += 1;
}
b = Merge(a, b, h);
}
}
return b;
}
// Move a subtree, extending the entire tree with it.
function Move(tree, h, newh)
{
var t = tree.left;
var tgt = Finddad(tree, h);
if (t == null || tgt == null) return tree;
// Find the target node, remembering what side it's on
var onleft = tgt.left.head == h;
var tn;
if (onleft) tn = tgt.left;
else tn = tgt.right;
// Create trace node
var tr = Trace(tn, h);
if (onleft) tgt.left = tr;
else tgt.right = tr;
// Extend tree with moved node
return Merge(tn, tree, newh);
}
// Given a node a, replace it with [b a].
// Leave a trace where b was.
// Warning: won't work if a is the highest node (a == tree)
function Prepend(tree, a, b)
{
var ad = FindParent(tree, a);
var bd = FindParent(tree, b);
// Merge a and b
var ab = Merge(b, a, a.head);
// Fix up a's parent to point to merged node
if (ad.left.head == a.head)
ad.left = ab;
else
ad.right = ab;
// Leave the trace, if b was already in the tree
if (bd != null) {
var tr = Trace(b, b.head);
if (bd.left.head == b.head)
bd.left = tr;
else
bd.right = tr;
}
report(showtree(tree));
}
// Special rules
// First set is for gettree; second set is for process
function special(tree, skip)
{
var sp = theform.spec.value.split("\n");
for (var i = 0; i < sp.length; i++) {
spr = sp[i];
if (spr == "+")
skip = !skip;
if (skip) continue;
spp = spr.split(":");
if (spp.length < 3) continue;
// Randomization
var pct = parseInt(spp[0], 10);
if (pct == 0) continue;
if (pct < 100 && randomInt(100) > pct) continue;
// Individual conditions
var cpp = spp[1].split(" ");
var stop = false;
for (var j = 0; !stop && j < cpp.length; j++) {
var cond = cpp[j];
if (cond == "!Aux")
stop = hasAux;
if (cond == "Aux")
stop = !hasAux;
if (cond == "Neg")
stop = Find(tree, "Neg") == null;
if (cond == "Tø") {
var t = Find(tree, "T");
stop = t == null || showterms(t).substr(1) != "";
}
if (cond == "ObjPron") {
var np = FindParent(tree, theObj);
var d = Find(np, "D");
stop = d == null || d.left != "ø:D";
if (!stop) {
var dp = FindParent(tree, np);
report( "<b>dp is " + dp.head );
if (dp != null && dp.head == "P")
stop = true;
}
}
if (cond == "Q") {
var q = Find(tree, "C");
stop = q == null || theword(q.left) != "Q";
}
if (cond == "NegQ") {
var n = Find(tree, "Neg");
if (n != null)
stop = false;
else {
var q = Find(tree, "C");
stop = q == null || theword(q.left) != "Q";
}
}
}
if (stop) continue;
var ru = spp[2];
report( "<p>Special rule: <b>" + ru + "</b>");
if (ru == "Aux") {
tree = Aux(tree, spp[3]);
}
if (ru == "Q") {
var c = TermS("Q:C", "C");
tree = Merge(c, tree, "CP");
}
if (ru.charAt(0) == "^") {
ru = ru.substring(1);
tree = Move(tree, ru, spp[3]);
}
if (ru == "OV") {
var v = Find(tree, "V");
var o = FindParent(tree, theObj);
Prepend(tree, v, o);
}
if (ru == "AuxMove") { // Could this be done with Prepend?
var t = Find(tree, "T");
var v = Find(tree, "V");
var a = TermS(v.left, "V");
var tt = Merge(a, t, "T");
tree.left = tt;
v.left = "<<i>" + showterms(v).substr(1) + "</i>>:V";
report(showtree(tree));
}
if (ru.indexOf('+') != -1) {
// Term movement
ndd = ru.split("+");
var ah = ndd[0];
var bh = ndd[1];
var a = Find(tree, ah);
var b;
var bd = null;
if (bh == bh.toLowerCase()) {
// bh gives an actual word
b = FindNode(bh);
} else {
// bh is a node
b = Find(tree, bh);
var bd = FindDadOfTerm(tree, bh);
}
Prepend(tree, a, b);
}
if (ru.indexOf('«') != -1) {
// Node movement - may only work for English C<T
// given either [T1 [T2 VP]]
// or [T1 [T2 [V T3]]]
// b is T2, bd is T1
ndd = ru.split("«");
var ah = ndd[0];
var bh = ndd[1];
var a = Find(tree, ah);
var b = Find(tree, bh);
var bd = FindParent(tree, b);
if (bd.right.head == "V" || bd.left.head == "V") {
b = bd;
}
Prepend(tree, a, b);
}
}
return tree;
}
// User hit the Generate button
function process()
{
//Read parameters
theform = document.theform;
// Read the lexicon
var s = theform.lex.value;
lex = s.split("\n");
// Read constituent order table
s = theform.ord.value;
ord = s.split("\n");
var text = document.getElementById("mytext")
text.innerHTML = "<p><b>Building tree</b>";
// Get ourselves a TP
hasAux = false;
theObj = null;
var tree = gettree("T");
// Failure condition - the rules are bad
if (tree.head != "T") return;
// Apply special rules
tree = special(tree, true);
// Correct tense/number
if (Tense(tree))
report( "<p>Corrected <b>Verb</b>: " + showtree(tree) );
// Final output goes *first*
var s = "<b>Generated sentence</b><i> " + showterms(tree) + "</i>";
if (tree.head == "CP")
s += "?"
else
s += ".";
text.innerHTML = s + text.innerHTML;
}
function helpme()
{
window.open("mghelp.html");
}
// Replace a textarea with the given array
function string2text(data, field)
{
var s = "";
for (var i = 0; i < data.length; i++) {
s += data[i];
if (i < data.length - 1) s += "\n";
}
document.getElementById(field).innerHTML = s;
}
function french()
{
var data = [
"le:D N:sf la pm les pf les",
"il:N:sn:le:lui",
"elle:N:sf:la:elle",
"ils:N:pm:les:eux",
"elles:N:pf:les:elles",
"chat:N:sm",
"chats:N:pm",
"souris:N:sf",
"souris:N:pf",
"chien:N:sm",
"chiens:N:pm",
"vache:N:sf",
"vaches:N:pf",
"dormir:V P D:Pressf dort Pressm dort Prespf dorment Prespm dorment Perf dormi",
"aimer:V D D:Pressf aime Pressm aime Prespf aiment Prespm aiment Perf aimé",
"voir:V D D:Pressf voit Pressf voit Prespf voient Prespm voient Perf vu",
"avoir:Aux Perf:Pressf a Pressm a Prespm ont Prespf ont",
"sur:P D",
"beau:A N:sf belle pm beaux pf belles",
"laid:A N:sf laide pm laids pf laides",
"rouge:A N:pm rouges pf rouges",
"vert:A N:sf verte pm verts pf vertes",
"brun:A N:sf brune pm bruns pf brunes",
"mignon:A N:sf mignonne pm mignons pf mignonnes",
"fou:A N:sf folle pm foux pf folles",
"Pres:T VP:Pres",
"pas:Aux Neg",
"ne:Neg"];
string2text(data, "lex");
data = [ "D N", "N A", "V P", "V N:V", "N V:VP", "T VP", "P D", "C T", "V VP", "Neg VP" ];
string2text(data, "ord");
data = [ "33::Aux:Perf", "33::Aux:Neg", "+",
"100:Aux Tø:AuxMove", "100::^D:TP", "100:!Aux Neg:T+V", "100:Neg:V+ne", "100:ObjPron:OV" ];
string2text(data, "spec" );
}
</script>
<table width="100%">
<tr><td bgcolor="#EEC25A">
<h2><br> <a href="kit.html"><img src="chomsky.gif" border=0 align="absmiddle" height="53" width="60"></a> mg</h2></td></tr>
</td></tr>
</table>
<i>This is a Javascript program which allows you to define the lexicon for a Minimalist grammar and build a random sentence node by node. Press Generate to test, and Help for documentation.
<p>Also see: <A href="markov.html">Markov generator</a>; <a href="ggg.html">Generative Grammar Gadget</a>; <a href="gtg.html">Generative Tree Gadget<a>.
<p>—Mark Rosenfelder, 2018</i>
<hr>
<table width="100%">
<tr>
<td>
Lexicon:
<br><textarea id="lex" name="lex" rows="10" cols="50">
the:D N
her:D N
his:D N
this:D N:p these
that:D N:p those
he:N:s:him
she:N:s:her
cat:N:s
cats:N:p
dog:N:s
dogs:N:p
frog:N:s
frogs:N:p
mouse:N:s
mice:N:p
mat:N:s
mats:N:p
sit:V P D:Press sits Pasts sat Pastp sat Prog sitting Perf sat
sleep:V P D:Press sleeps Pasts slept Pastp slept Prog sleeping Perf slept
hate:V D D:Press hates Pasts hated Pastp hated Prog hating Perf hated
love:V D D:Press loves Pasts loved Pastp loved Prog loving Perf loved
chase:V D D:Press chases Pasts chased Pastp chased Prog chasing Perf chased
have:Aux Perf:Press has Past had Pastp had Prog having Perf had
be:Aux Prog:Press is Presp are Pasts was Pastp were Prog being Perf been
do:V:Press does Pasts did Pastp did
not:Aux Neg
on:P D
by:P D
near:P D
big:A N
fat:A N
Past:T VP:Past
Pres:T VP:Pres
must:T VP
may:T VP
can:T VP</textarea>
</td>
<td width="30px"> </td>
<td>
Order:
<br><textarea id="ord" name="ord" rows="10" cols="20">
D N
A N
V P
V N:V
N V:VP
T VP
P D
C T
V VP
Neg VP
</textarea>
</td>
<td>
Special:
<br><textarea id="spec" name="spec" rows="10" cols="35">
33::Aux:Perf
25::Aux:Prog
25::Aux:Neg
+
100:Aux Tø:AuxMove
100::^D:TP
25::Q
100:!Aux NegQ Tø:T+do
100:Q:C«T
</textarea>
</td>
<td>
<p><input type="button" value="Generate" onClick="process();">
<p><input type="button" value="Help me!" onClick="helpme();">
<p><input type="button" value="French" onClick="french();">
</td>
</tr></table>
<hr>
<h3>Output</h3>
<br><div id="mytext"> </div>
</form>
<hr>
<center><A HREF="default.html"><img src="homeg.gif" border=0 alt="Home"></A></center>
</body>
</html>