Last active
July 24, 2016 15:00
-
-
Save bakso/5fe7be46242c34a37e4d44acfa60f139 to your computer and use it in GitHub Desktop.
Caculator implement by lexer and parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict' | |
const EOF = "EOF" | |
class Lexer { | |
constructor(input) { | |
this.input = input | |
this.index = -1 | |
this.currentChar = null | |
this.step() | |
} | |
nextToken() { | |
if(this.currentChar === undefined) { | |
return { | |
type: EOF | |
} | |
} | |
if(this.currentChar.trim() === '') { | |
this.step() | |
return this.nextToken() | |
} | |
var token = {} | |
if(this.matchNumber()) { | |
token.type = 'number' | |
token.text = this.number() | |
} else if(this.matchOperator()) { | |
token.type = 'operator' | |
token.text = this.operator() | |
this.step() | |
} else if(this.matchPair()) { | |
token.type = 'pair' | |
token.text = this.pair() | |
this.step() | |
} else { | |
throw new Error("Unexpect identifier: " + this.currentChar + " at column: " + (this.index + 1)) | |
} | |
return token | |
} | |
step() { | |
this.currentChar = this.input[++this.index] | |
} | |
lastChar() { | |
return this.index >= this.input.length | |
} | |
matchNumber() { | |
return /[\d\.]/.test(this.currentChar) | |
} | |
number() { | |
var buf = [] | |
buf.push(this.currentChar) | |
this.step() | |
while(!this.lastChar() && this.matchNumber()) { | |
buf.push(this.currentChar) | |
this.step() | |
} | |
return buf.join('') | |
} | |
matchOperator() { | |
var char = this.currentChar | |
return char === '+' || char === '-' || char === '*' || char === '/' | |
} | |
operator() { | |
return this.currentChar | |
} | |
matchPair() { | |
var char = this.currentChar | |
return char === '(' || char === ')' | |
} | |
pair() { | |
return this.currentChar | |
} | |
} | |
class Parser { | |
constructor(input) { | |
this.lexer = input | |
} | |
compute() { | |
return this.parseExpression() | |
} | |
getToken() { | |
var token | |
if(this.token) { | |
token = this.token | |
this.token = null | |
} else { | |
token = this.lexer.nextToken() | |
} | |
return token | |
} | |
unGetToken(token) { | |
this.token = token | |
} | |
parseExpression() { | |
var v1, v2 | |
var v1 = this.parseTerm() | |
while(true) { | |
var token = this.getToken() | |
if(token.type !== 'operator' || (token.text !== '+' && token.text !== '-')) { | |
this.unGetToken(token) | |
break | |
} | |
v2 = this.parseTerm() | |
if(token.text === '+') { | |
v1 += v2 | |
} else if(token.text === '-') { | |
v1 -= v2 | |
} | |
} | |
console.log(v1) | |
return v1 | |
} | |
parseTerm() { | |
var v1, v2 | |
var v1 = this.parsePrimaryExpression() | |
while(true) { | |
var token = this.getToken() | |
if(token.type !== 'operator' || (token.text !== '*' && token.text !== '/')) { | |
this.unGetToken(token) | |
break | |
} | |
v2 = this.parsePrimaryExpression() | |
if(token.text === '*') { | |
v1 *= v2 | |
} else if(token.text === '/') { | |
v1 /= v2 | |
} | |
} | |
return v1 | |
} | |
parsePrimaryExpression() { | |
var token = this.lexer.nextToken() | |
var neg = false | |
var ret = 0 | |
if (token.type === 'operator' && (token.text === '-' || token.text === '+')) { | |
if (token.text === '-') { | |
neg = true | |
} | |
token = this.lexer.nextToken() | |
} | |
if(token.type === 'number') { | |
ret = parseInt(token.text, 10) | |
} else if(token.type === 'pair' && token.text === '(') { | |
ret = this.parseExpression() | |
var token = this.getToken() | |
if(token.type !== 'pair' || token.text !== ')') { | |
throw new Error('Expect ")" end.') | |
} | |
} | |
if (neg) { | |
ret = -ret | |
} | |
return ret | |
} | |
} | |
var lexer = new Lexer("-(11+1)*(-1/(3+1))") | |
var parser = new Parser(lexer) | |
console.log(parser.compute()) | |
// while (true) { | |
// var token = lexer.nextToken() | |
// if (token.type === EOF) { | |
// break | |
// } else { | |
// console.log(token) | |
// } | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment