Skip to content

Instantly share code, notes, and snippets.

@KKostya
Last active August 29, 2015 14:12
Show Gist options
  • Save KKostya/1e39e2b70c877a7f53d3 to your computer and use it in GitHub Desktop.
Save KKostya/1e39e2b70c877a7f53d3 to your computer and use it in GitHub Desktop.
Token stream visual
<!DOCTYPE html>
<meta charset="utf-8">
<style>
.link { stroke: #999; }
</style>
<body>
<script src="http://d3js.org/d3.v3.min.js"></script>
<script>
function formatNode()
{
var margins = {topbottom:5, leftright:4}
var node = d3.select(this);
var rect = node.select("rect");
node.select("text")
.each(function(){
var box = this.getBBox();
rect.attr("width",box.width + 2*margins.leftright)
.attr("height",box.height + 2*margins.topbottom)
d3.select(this)
.attr("x", -box.x+margins.leftright)
.attr("y", -box.y+margins.topbottom);
});
}
function svgNodes()
{
var x0 = 0, y0 = 0;
function my(nodes) {
var spacing = 3;
nodes.each(formatNode);
// I dont need that here....
// Positions are to be set externally
var x = x0;
nodes.each(function(){
var node = d3.select(this);
var rect = node.select("rect");
node.attr("transform", "translate("+x+","+y0+")");
x = x + parseInt(rect.attr("width")) + spacing;
});
}
my.margins = function(_) { if (!arguments.length) return margins; margins = _; return my; };
my.x = function(_) { if (!arguments.length) return x0; x0 = _; return my; };
my.y = function(_) { if (!arguments.length) return y0; y0 = _; return my; };
return my;
}
var tokens = [
"42", "*", "(", "111", "+", "101", ")", "*", "(", "785", "+", "432", ")" ];
var width = 960, height = 500;
var svg = d3.select("body").append("svg")
.attr("width", width)
.attr("height", height)
.append("g")
.attr("transform", "translate(40,0)");
var colorings = [
{ regex:/^[0-9]+$/ , color:"#7fc97f"},
{ regex:/^[*+-\/]$/, color:"#beaed4"},
{ regex:/^[\(\)]$/ , color:"#fdc086"},
]
var nodes = svg.selectAll(".node").data(tokens);
nodes.exit().remove()
nodesEnter = nodes.enter().append("g");
nodesEnter.append("rect")
.attr("rx", 5).attr("ry", 5).attr("height", 17).attr("width",150)
.attr("stroke", "#000000");
nodesEnter.append("text")
.attr("text-anchor", "middle").attr("dy", 1.1 / 2 + 0.5 + 'em');
nodes.select("text").text(String);
nodes.select("rect").attr("fill", function(d){
// Array.some() simulates "break from foreach" loop functionality
// retcolor is closured for return value
var retcolor = "#c7c4df";
colorings.some(function(col){
if (!col.regex.test(d)) return false;
retcolor = col.color;
return true;
});
return retcolor;
});
nodes.call(svgNodes().x(300).y(300));
// Preparing force layout
var force = d3.layout.force()
.size([width, height])
.nodes([{}]) // initialize with a single node
.linkDistance(30)
.charge(-200)
.on("tick", tick);
var ntnode = svg.selectAll(".ntnode"),
link = svg.selectAll(".link"),
nodes = force.nodes(),
links = force.links();
function tick() {
link.attr("x1", function(d) { return d.source.x; })
.attr("y1", function(d) { return d.source.y; })
.attr("x2", function(d) { return d.target.x; })
.attr("y2", function(d) { return d.target.y; });
ntnode.attr("transform",
function(d){return "translate("+d.x+","+d.y+")";});
}
function restart() {
link = link.data(links);
link.enter().insert("line", ".ntnode").attr("class", "link");
ntnode = ntnode.data(nodes);
ntnode.exit().remove();
ntnodesEnter = ntnode.enter().append("g");
ntnodesEnter.attr("class", "ntnode");
ntnodesEnter.append("rect")
.attr("rx", 5).attr("ry", 5).attr("height", 17).attr("width",150)
.attr("stroke", "#000000").attr("fill","#FFFFFF");
ntnodesEnter.append("text")
.attr("text-anchor", "middle").attr("dy", 1.1 / 2 + 0.5 + 'em');
ntnodesEnter.select("text")
.text(function(d){return d.name;});
ntnodesEnter.each(formatNode);
ntnode.call(force.drag);
force.start();
}
// p-p-p-parsing!.....
var ptable = d3.map();
ptable.set( "E", d3.map({"(":["T","EE"], "int":["T", "EE"]}));
ptable.set( "T", d3.map({"(":["F","TT"], "int":["F", "TT"]}));
ptable.set("EE", d3.map({"+":["+","T","EE"], ")":"$", "$":"$"}));
ptable.set("TT", d3.map({"+":"$", "*":["*","F","TT"], ")":"$", "$":"$"}));
ptable.set( "F", d3.map({"(":["(","E",")"], "int":["int"]}));
var tstack = [{name:"E", prnt:null}]; // For graph building nodes should carry info about their parents
tokens.forEach(function(t){
var tk = /^[0-9]+$/.test(t) ? "int" : t;
var next = tstack.pop();
while(ptable.has(next.name))
{
var ruleRHS = ptable.get(next.name).get(tk);
if(!ruleRHS) throw "brick. Parse failed.";
if(ruleRHS != "$")
{
next.x = width*Math.random();
next.y = height*Math.random();
nodes.push(next);
if(next.prnt) links.push({target:next, source:next.prnt});
restart();
ruleRHS.slice(0).reverse().forEach(function(x){tstack.push({name:x, prnt:next});});
}
next = tstack.pop();
}
if(tk != next.name) throw "baby. Parse failed.";
});
</script>
</body>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment