Created
July 29, 2024 03:17
-
-
Save dongyuwei/7afe283e1e4332ba7f00ce53155acda5 to your computer and use it in GitHub Desktop.
Top Down Operator Precedence: basic implementation in JavaScript
This file contains 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
const PRECEDENCE = { | |
"=": 1, | |
"+": 2, | |
"-": 2, | |
"*": 3, | |
"/": 3, | |
"(": 0, | |
")": 0 | |
}; | |
class Token { | |
constructor(type, value) { | |
this.type = type; | |
this.value = value; | |
} | |
} | |
class Lexer { | |
constructor(input) { | |
this.input = input; | |
this.position = 0; | |
} | |
nextToken() { | |
while (this.position < this.input.length) { | |
const char = this.input[this.position]; | |
if (/\s/.test(char)) { | |
this.position++; | |
continue; | |
} | |
if (/[a-zA-Z_]/.test(char)) { | |
let value = ''; | |
while (this.position < this.input.length && /[a-zA-Z_]/.test(this.input[this.position])) { | |
value += this.input[this.position++]; | |
} | |
return new Token('IDENTIFIER', value); | |
} | |
if (/[0-9]/.test(char)) { | |
let value = ''; | |
while (this.position < this.input.length && /[0-9]/.test(this.input[this.position])) { | |
value += this.input[this.position++]; | |
} | |
return new Token('NUMBER', parseInt(value, 10)); | |
} | |
if (char in PRECEDENCE) { | |
this.position++; | |
return new Token(char, char); | |
} | |
throw new Error(`Unexpected character: ${char}`); | |
} | |
return new Token('EOF', null); | |
} | |
} | |
class Parser { | |
constructor(lexer) { | |
this.lexer = lexer; | |
this.token = this.lexer.nextToken(); | |
} | |
parseExpression(precedence) { | |
let left = this.parsePrefix(); | |
while (precedence < this.getPrecedence()) { | |
left = this.parseInfix(left); | |
} | |
return left; | |
} | |
parsePrefix() { | |
const token = this.token; | |
if (token.type === 'NUMBER' || token.type === 'IDENTIFIER') { | |
this.nextToken(); | |
return token; | |
} | |
if (token.type === '(') { | |
this.nextToken(); | |
const expr = this.parseExpression(0); | |
if (this.token.type !== ')') { | |
throw new Error("Expected ')'"); | |
} | |
this.nextToken(); | |
return expr; | |
} | |
throw new Error(`Unexpected token: ${token.type}`); | |
} | |
parseInfix(left) { | |
const token = this.token; | |
const precedence = this.getPrecedence(); | |
this.nextToken(); | |
const right = this.parseExpression(precedence); | |
return { type: 'BINARY', operator: token.type, left, right }; | |
} | |
getPrecedence() { | |
return PRECEDENCE[this.token.type] || 0; | |
} | |
nextToken() { | |
this.token = this.lexer.nextToken(); | |
} | |
} | |
Author
dongyuwei
commented
Jul 29, 2024
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment