forked from rebeccamurphy/TS-Compiler
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
154 lines (140 loc) · 5.75 KB
/
index.html
File metadata and controls
154 lines (140 loc) · 5.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<!DOCTYPE HTML>
<html>
<head>
<title>Alan and Rebecca's Bitchin Compiler Template</title>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<link rel="stylesheet" type="text/css" href="dist/styles/compiler.css" />
<link rel="stylesheet" href="dist/styles/bootstrap.min.css">
</head>
<body onload="init();">
<h1>Project Zero Compiler</h1>
<hr>
<p>. . . <em>a simple parser for a simple grammar</em>:</p>
<pre>
G ::== E
E ::== D O E | D
D ::== 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
O ::== + | -
</pre>
<div style="text-align:center;">
<input type="button" id="btnCompile" value="Compile" onclick="btnCompile_click();"/>
</div>
<div>
<div class="source">
<textarea id="taSourceCode"></textarea>
<textarea id="taOutput"></textarea>
</div>
</div>
<div>
<img style="display:block; margin-left:auto; margin-right:auto;"
src="dist/images/CompilerPhases.png"
alt="Compiler Phases" />
</div>
<!-- Client-side code down here, per the YSlow advice. -->
<script type="text/javascript" src="dist/scripts/utils.js"></script>
<script type="text/javascript" src="dist/scripts/lexer.js"></script>
<script type="text/javascript" src="dist/scripts/globals.js"></script>
<script type="text/javascript">
function init() {
// Clear the message box.
document.getElementById("taOutput").value = "";
// Set the initial values for our globals.
tokens = "";
tokenIndex = 0;
currentToken = ' ';
errorCount = 0;
}
function btnCompile_click() {
// This is executed as a result of the user pressing the
// "compile" button between the two text areas, above.
// Note the <input> element's event handler: onclick="btnCompile_click();
init();
putMessage("Compilation Started");
// Grab the tokens from the lexer . . .
tokens = _Lexer.lex();
putMessage("Lex returned [" + tokens + "]");
// . . . and parse!
parse();
}
function putMessage(msg) {
document.getElementById("taOutput").value += msg + "\n";
}
// TODO: These parse routines really should be in TypeScript.
// This exercise is left to the student. Consider it project 0.5 .
function parse() {
putMessage("Parsing [" + tokens + "]");
// Grab the next token.
currentToken = getNextToken();
// A valid parse derives the G(oal) production, so begin there.
parseG();
// Report the results.
putMessage("Parsing found " + errorCount + " error(s).");
}
function parseG() {
// A G(oal) production can only be an E(xpression), so parse the E production.
parseE();
}
function parseE() {
// All E productions begin with a digit, so make sure that we have one.
checkToken("digit");
// Look ahead 1 char (which is now in currentToken because checkToken
// consumes another one) and see which E production to follow.
if (currentToken != EOF) {
// We're not done, we expect to have an op.
checkToken("op");
parseE();
} else {
// There is nothing else in the token stream,
// and that's cool since E ::== digit is valid.
putMessage("EOF reached");
}
}
function checkToken(expectedKind) {
// Validate that we have the expected token kind and et the next token.
switch(expectedKind) {
case "digit": putMessage("Expecting a digit");
if (currentToken=="0" || currentToken=="1" || currentToken=="2" ||
currentToken=="3" || currentToken=="4" || currentToken=="5" ||
currentToken=="6" || currentToken=="7" || currentToken=="8" ||
currentToken=="9")
{
putMessage("Got a digit!");
}
else
{
errorCount++;
putMessage("NOT a digit. Error at position " + tokenIndex + ".");
}
break;
case "op": putMessage("Expecting an operator");
if (currentToken=="+" || currentToken=="-")
{
putMessage("Got an operator!");
}
else
{
errorCount++;
putMessage("NOT an operator. Error at position " + tokenIndex + ".");
}
break;
default: putMessage("Parse Error: Invalid Token Type at position " + tokenIndex + ".");
break;
}
// Consume another token, having just checked this one, because that
// will allow the code to see what's coming next... a sort of "look-ahead".
currentToken = getNextToken();
}
function getNextToken() {
var thisToken = EOF; // Let's assume that we're at the EOF.
if (tokenIndex < tokens.length)
{
// If we're not at EOF, then return the next token in the stream and advance the index.
thisToken = tokens[tokenIndex];
putMessage("Current token:" + thisToken);
tokenIndex++;
}
return thisToken;
}
</script>
</body>
</html>