Skip to content

Commit a94b8cc

Browse files
committed
Wrote lexical scanner
1 parent dffcbcc commit a94b8cc

File tree

1 file changed

+276
-0
lines changed

1 file changed

+276
-0
lines changed

lexicalScanner.js

Lines changed: 276 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,276 @@
1+
'use strict';
2+
3+
const q = require('q'),
4+
util = require('util');
5+
6+
const cradle = require('./cradle');
7+
8+
const isAlpha = cradle.isAlpha,
9+
isDigit = cradle.isDigit,
10+
look = cradle.look,
11+
getChar = cradle.getChar,
12+
expected = cradle.expected,
13+
init = cradle.init;
14+
15+
const CR = '\r',
16+
LF = '\n',
17+
TAB = '\t';
18+
19+
const KWList = [
20+
'IF',
21+
'ELSE',
22+
'ENDIF',
23+
'END'
24+
];
25+
26+
// Token Types - must match array index of corresponding keyword
27+
// in KWList
28+
const IFSYM = 0,
29+
ELSESYM = 1,
30+
ENDIFSYM = 2,
31+
ENDSYM = 3,
32+
IDENT = 4,
33+
NUMBER = 5,
34+
OPERATOR = 6;
35+
36+
process.on('unhandledException', (err) => {
37+
console.log(err.stack);
38+
});
39+
40+
function lookup(s) {
41+
return KWList.indexOf(s);
42+
}
43+
44+
function isWhite(c) {
45+
return c === ' ' || c === TAB;
46+
}
47+
48+
function skipWhite() {
49+
return q()
50+
.then(() => {
51+
let nextChar = look();
52+
if (isWhite(nextChar)) {
53+
return getChar()
54+
.then(() => {
55+
return skipWhite();
56+
});
57+
}
58+
});
59+
}
60+
61+
function fin() {
62+
return q()
63+
.then(() => {
64+
let nextChar = look();
65+
if (nextChar === '\r')
66+
return getChar();
67+
})
68+
.then(() => {
69+
let nextChar = look();
70+
if (nextChar === '\n')
71+
return getChar();
72+
});
73+
}
74+
75+
76+
function isAlNum(c) {
77+
return isAlpha(c) || isDigit(c);
78+
}
79+
80+
function isOp(c) {
81+
return c === '+' || c === '-' || c === '*' || c === '/'
82+
|| c === '<' || c === '>' || c === ':' || c === '=';
83+
}
84+
85+
function getName() {
86+
let whileState = {
87+
x:''
88+
};
89+
function getNameInner() {
90+
let nextChar = look();
91+
if (isAlNum(nextChar)) {
92+
whileState.x = whileState.x + nextChar.toUpperCase();
93+
return getChar()
94+
.then(() => {
95+
return getNameInner();
96+
});
97+
}
98+
}
99+
100+
let nextChar = look();
101+
if (!isAlpha(nextChar)) {
102+
expected('Name');
103+
}
104+
105+
return getNameInner()
106+
.then(() => {
107+
return skipWhite();
108+
})
109+
.then(() => {
110+
return whileState.x;
111+
});
112+
}
113+
exports.getName = getName;
114+
115+
function getNum() {
116+
let whileState = {
117+
x: ''
118+
};
119+
function getNumInner() {
120+
let nextChar = look();
121+
if (isDigit(nextChar)) {
122+
whileState.x = whileState.x + nextChar;
123+
return getChar()
124+
.then(() => {
125+
return getNumInner();
126+
});
127+
}
128+
}
129+
130+
let nextChar = look();
131+
if (!isDigit(nextChar)) {
132+
expected('Integer')
133+
}
134+
135+
return getNumInner()
136+
.then(() => {
137+
return skipWhite();
138+
})
139+
.then(() => {
140+
return whileState.x;
141+
});
142+
}
143+
exports.getNum = getNum;
144+
145+
function getOp() {
146+
let whileState = {
147+
x: ''
148+
};
149+
150+
function getOpInner() {
151+
let nextChar = look();
152+
if (isOp(nextChar)) {
153+
whileState.x = whileState.x + nextChar;
154+
return getChar()
155+
.then(() => {
156+
return getOpInner();
157+
});
158+
}
159+
}
160+
161+
let nextChar = look();
162+
if (!isOp(nextChar)) {
163+
expected('Operator');
164+
}
165+
166+
return getOpInner()
167+
.then(() => {
168+
return skipWhite();
169+
})
170+
.then(() => {
171+
return whileState.x;
172+
});
173+
}
174+
175+
function scan() {
176+
177+
function eatCRs() {
178+
return q()
179+
.then(() => {
180+
let nextChar = look();
181+
if (nextChar === CR) {
182+
return fin()
183+
.then(() => {
184+
return eatCRs();
185+
});
186+
}
187+
});
188+
}
189+
190+
function afterCRs() {
191+
192+
let nextChar = look();
193+
if (isAlpha(nextChar)) {
194+
return getName()
195+
.then((name) => {
196+
let k = lookup(name),
197+
tokenType;
198+
if (k === -1) {
199+
tokenType = IDENT;
200+
} else {
201+
tokenType = k;
202+
}
203+
return skipWhite()
204+
.thenResolve({
205+
token: tokenType,
206+
value: name
207+
});
208+
});
209+
} else if (isDigit(nextChar)) {
210+
return getNum()
211+
.then((num) => {
212+
return skipWhite()
213+
.thenResolve({
214+
token: NUMBER,
215+
value: num
216+
});
217+
});
218+
} else if (isOp(nextChar)) {
219+
return getOp()
220+
.then((op) => {
221+
return skipWhite()
222+
.thenResolve({
223+
token: OPERATOR,
224+
value: op
225+
});
226+
});
227+
} else {
228+
return getChar()
229+
.then(() => {
230+
return skipWhite()
231+
.thenResolve({
232+
token: OPERATOR,
233+
value: nextChar
234+
});
235+
});
236+
}
237+
}
238+
239+
return eatCRs()
240+
.then(() => {
241+
return afterCRs();
242+
});
243+
}
244+
245+
function scanTokens() {
246+
return scan()
247+
.then((token) => {
248+
let output;
249+
switch (token.token) {
250+
case IDENT:
251+
output = 'Ident ';
252+
break;
253+
case NUMBER:
254+
output = 'Number ';
255+
break;
256+
case OPERATOR:
257+
output = 'Operator ';
258+
break;
259+
default:
260+
output = 'Keyword ';
261+
}
262+
output = output + token.value;
263+
console.log(output);
264+
if (token.token !== ENDSYM) {
265+
return scanTokens();
266+
}
267+
});
268+
}
269+
270+
init()
271+
.then(() => {
272+
return scanTokens();
273+
})
274+
.catch((err) => {
275+
console.log(err.stack);
276+
});

0 commit comments

Comments
 (0)