Initial commit

This commit is contained in:
Emily Eisenberg 2013-07-05 02:05:33 -07:00
commit 708a36502b
7 changed files with 372 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
parser.js
node_modules

8
Makefile Normal file
View File

@ -0,0 +1,8 @@
FILES=parser.js style.css build.js index.html
.PHONY: ship
ship: parser.js
scp $(FILES) prgmr:/var/www/www.rampancylabs.com/parser/
parser.js: parser.jison
./node_modules/.bin/jison parser.jison

163
build.js Normal file
View File

@ -0,0 +1,163 @@
var doParse = function(toparse, baseelem) {
var makeex = function(ex, base) {
for (var i = 0; i < ex.length; i++) {
var prev = i > 0 ? ex[i-1] : null;
var group = makegroup(ex[i], prev);
base.appendChild(group);
}
return base;
};
var makegroup = function(group, prev) {
if (group.type === "ord") {
var elem = document.createElement("span");
elem.className = "mord";
elem.appendChild(mathit(group.value));
return elem;
} else if (group.type === "bin") {
var elem = document.createElement("span");
if (prev == null || prev.type === "bin" || prev.type === "open") {
group.type = "ord";
elem.className = "mord";
} else {
elem.className = "mbin";
}
elem.appendChild(mathit(group.value));
return elem;
} else if (group.type === "sup") {
var elem = document.createElement("span");
elem.className = "mord";
makeex(group.value.base, elem);
var sup = document.createElement("span");
sup.className = "msup";
makeex(group.value.sup, sup);
elem.appendChild(sup);
return elem;
} else if (group.type === "sub") {
var elem = document.createElement("span");
elem.className = "mord";
makeex(group.value.base, elem);
var sub = document.createElement("span");
sub.className = "msub";
makeex(group.value.sub, sub);
elem.appendChild(sub);
return elem;
} else if (group.type === "supsub") {
var elem = document.createElement("span");
elem.className = "mord";
makeex(group.value.base, elem);
var supsub = document.createElement("span");
supsub.className = "msupsub";
var sup = document.createElement("span");
sup.className = "msup";
makeex(group.value.sup, sup);
var sub = document.createElement("span");
sub.className = "msub";
makeex(group.value.sub, sub);
supsub.appendChild(sup);
supsub.appendChild(sub);
elem.appendChild(supsub);
return elem;
} else if (group.type === "open") {
var elem = document.createElement("span");
elem.className = "mopen";
elem.appendChild(mathit(group.value));
return elem;
} else if (group.type === "close") {
var elem = document.createElement("span");
elem.className = "mclose";
elem.appendChild(mathit(group.value));
return elem;
} else if (group.type === "cdot") {
var elem = document.createElement("span");
elem.className = "mbin";
elem.appendChild(textit('\u22C5'));
return elem;
} else if (group.type === "frac") {
var frac = document.createElement("span");
frac.className = "mord mfrac";
var numer = document.createElement("span");
numer.className = "mfracnum";
makeex(group.value.numer, numer);
var mid = document.createElement("span");
mid.className = "mfracmid";
mid.appendChild(document.createElement("span"));
var denom = document.createElement("span");
denom.className = "mfracden";
makeex(group.value.denom, denom);
frac.appendChild(numer);
frac.appendChild(mid);
frac.appendChild(denom);
return frac;
} else {
console.log(group.type);
}
};
var charLookup = {
'*': '\u2217',
'-': '\u2212',
'cdot': '\u22C5'
};
var textit = function(value) {
if (value in charLookup) {
value = charLookup[value];
}
return document.createTextNode(value);
};
var mathit = function(value) {
var text = textit(value);
if (/[a-zA-Z]/.test(value)) {
var elem = document.createElement("span");
elem.className = "mathit";
elem.appendChild(text);
return elem;
} else {
return text;
}
};
var tree = parser.parse(toparse);
clearNode(baseelem);
makeex(tree, baseelem);
};
var clearNode = function(node) {
var children = node.childNodes;
for (var i = children.length - 1; i >= 0; i--) {
console.log(children[i]);
node.removeChild(children[i]);
}
};
window.onload = function() {
var input = document.getElementById("input");
var math = document.getElementById("math");
doParse(input.value, math);
input.oninput = function() {
doParse(input.value, math);
};
};

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!doctype html>
<html>
<head>
<title>MJLite Test</title>
<script src="parser.js" type="text/javascript"></script>
<script src="build.js" type="text/javascript"></script>
<link href="style.css" rel="stylesheet" type="text/css">
</head>
<body>
<input type="text" value="2x^2 + 3" id="input" />
<div id="math"></div>
</body>
</html>

7
package.json Normal file
View File

@ -0,0 +1,7 @@
{
"name": "mjlite",
"version": "0.0.1",
"devDependencies": {
"jison": "~0.4.6"
}
}

81
parser.jison Normal file
View File

@ -0,0 +1,81 @@
/* description: Parses end executes mathematical expressions. */
/* lexical grammar */
%lex
%%
\s+ /* skip whitespace */
cdot return 'CDOT'
frac return 'FRAC'
[/a-zA-Z0-9] return 'ORD'
[*+-] return 'BIN'
\^ return '^'
[_] return '_'
[{] return '{'
[}] return '}'
[(] return 'OPEN'
[)] return 'CLOSE'
[\\] return '\\'
<<EOF>> return 'EOF'
/lex
/* operator associations and precedence */
%left '^'
%left '_'
%left 'ORD'
%left 'BIN'
%left SUPSUB
%start expression
%% /* language grammar */
expression
: ex EOF
{return $1;}
;
ex
:
{$$ = [];}
| group ex
{$$ = $1.concat($2);}
| group '^' group ex
{$$ = [{type: 'sup', value: {base: $1, sup: $3}}].concat($4);}
| group '_' group ex
{$$ = [{type: 'sub', value: {base: $1, sub: $3}}].concat($4);}
| group '^' group '_' group ex %prec SUPSUB
{$$ = [{type: 'supsub', value: {base: $1, sup: $3, sub: $5}}].concat($6);}
| group '_' group '^' group ex %prec SUPSUB
{$$ = [{type: 'supsub', value: {base: $1, sup: $5, sub: $3}}].concat($6);}
;
group
: atom
{$$ = $1;}
| '{' ex '}'
{$$ = $2;}
| '\\' func
{$$ = $2;}
;
func
: 'CDOT'
{$$ = [{type: 'bin', value: yytext}];}
| 'FRAC' group group
{$$ = [{type: 'frac', value: {numer: $2, denom: $3}}];}
;
atom
: 'ORD'
{$$ = [{type: 'ord', value: yytext}];}
| 'BIN'
{$$ = [{type: 'bin', value: yytext}];}
| 'OPEN'
{$$ = [{type: 'open', value: yytext}];}
| 'CLOSE'
{$$ = [{type: 'close', value: yytext}];}
;

98
style.css Normal file
View File

@ -0,0 +1,98 @@
@font-face {
font-family: MathJax_Main;
src: url("http://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Regular.otf");
}
@font-face {
font-family: MathJax_Main;
src: url("http://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Main-Italic.otf");
font-style: italic;
}
@font-face {
font-family: MathJax_Math;
src: url("http://cdn.mathjax.org/mathjax/latest/fonts/HTML-CSS/TeX/otf/MathJax_Math-Italic.otf");
font-style: italic;
}
/*
thin space: 1/6 quad
medium space: 2/9 quad
thick space: 5/18 quad
things to do:
^ _ and styles
\sin
\sum, \int, \lim
\frac
\sqrt
big parens
*/
body {
margin: 0px;
padding: 0px;
}
input {
margin: 0px;
font-size: 100%;
}
#math {
font-family: MathJax_Main;
}
.mathit {
font: italic 100% MathJax_Math;
}
.mord + .mbin {
margin-left: 0.22222em;
}
.mbin + .mord {
margin-left: 0.22222em;
}
.msub {
vertical-align: bottom;
font-size: 70%;
position: relative;
top: 0.2em;
}
.msup {
position: relative;
top: -0.5em;
font-size: 70%;
}
.msupsub {
display: inline-table;
table-layout: fixed;
vertical-align: middle;
}
.msupsub > .msup, .msupsub > .msub {
display: table-row;
vertical-align: baseline;
line-height: 1em;
}
.mfrac {
display: inline-table;
vertical-align: 0.88em;
}
.mfracnum, .mfracmid, .mfracden {
display: table-row;
text-align: center;
}
.mfracmid > span {
background: black;
display: block;
height: 0.05em;
min-height: 1px;
}