Skip to content

Instantly share code, notes, and snippets.

@sue71 sue71/parser.ts
Last active Feb 2, 2018

Embed
What would you like to do?
simple LL-parser
declare const process: any;
const stdin = process.openStdin();
enum TokenType {
VarName = 'VarName',
Assign = 'Assign',
Plus = 'Plus',
Minus = 'Minus',
Multi = 'Multi',
Divi = 'Divi',
Number = 'Number',
Print = 'Print',
Lparen = 'Lparen',
Rparen = 'Rparen',
Unknown = 'Unknown'
}
const isToken = (token: Token, type: TokenType) => {
return token.type === type;
};
class Token {
constructor(
public type: TokenType, public value: number, public raw: string) {}
}
class Parser {
stack = [];
vars = [];
currentLine: string = '';
currentPointer: number = 0;
token = undefined;
constructor() {
stdin.addListener('data', d => {
const inputText = d.toString().trim();
this.currentLine = inputText;
this.currentPointer = 0;
try {
this.statement();
} catch (e) {
console.error(e);
process.exit(1);
}
});
}
//
statement() {
let token = this.nextToken();
switch (token.type) {
case TokenType.Print:
this.expression();
const value = this.stack.pop();
console.info(value);
break;
case TokenType.VarName:
if (!this.isToken(this.nextToken(), TokenType.Assign)) {
throw new Error(`Invalid token: ${token.value}`);
}
this.expression();
this.setVar(token.value, this.popStack());
break;
}
}
//
expression() {
let token = this.term();
while (this.isToken(token, TokenType.Plus) ||
this.isToken(token, TokenType.Minus)) {
let op = token.type;
token = this.term();
this.operate(op);
}
}
//
term(): Token {
let token = this.factor();
while (this.isToken(token, TokenType.Multi) ||
this.isToken(token, TokenType.Divi)) {
let op = token.type;
token = this.factor();
this.operate(op);
}
return token;
}
// 因子
factor(): Token {
let token = this.nextToken();
switch (token.type) {
case TokenType.VarName:
this.pushStack(this.vars[token.value]);
return this.nextToken();
case TokenType.Number:
this.pushStack(token.value);
return this.nextToken();
case TokenType.Lparen:
token = this.nextToken();
this.expression();
token = this.nextToken();
if (!this.isToken(token, TokenType.Rparen)) {
throw new Error('');
}
return this.nextToken();
}
return this.nextToken();
}
// 演算実行
operate(op: TokenType) {
let b = this.stack.pop(), a = this.stack.pop();
switch (op) {
case TokenType.Plus:
this.pushStack(a + b);
break;
case TokenType.Minus:
this.pushStack(a - b);
break;
case TokenType.Multi:
this.pushStack(a * b);
break;
case TokenType.Divi:
this.pushStack(a / b);
break;
}
}
character(): string {
let character = this.currentLine[this.currentPointer];
if (/\s/.test(character)) {
return this.nextCharacter();
}
return character;
}
nextCharacter(): string {
let character = this.currentLine[++this.currentPointer];
if (/\s/.test(character)) {
return this.nextCharacter();
}
return character;
}
nextToken(): Token {
let character = this.character();
let token = new Token(TokenType.Unknown, 0, character);
if (character === undefined) {
return token;
}
if (this.isNumber(character)) {
let numberText = '';
while (this.isNumber(character)) {
numberText += character;
character = this.nextCharacter();
}
token.type = TokenType.Number;
token.value = parseInt(numberText, 10);
return token;
}
if (this.isVariable(character)) {
token.type = TokenType.VarName;
token.value = character.charCodeAt(0) - 'a'.charCodeAt(0);
this.nextCharacter();
return token;
}
switch (character) {
case '+':
token.type = TokenType.Plus;
break;
case '-':
token.type = TokenType.Minus;
break;
case '*':
token.type = TokenType.Multi;
break;
case '/':
token.type = TokenType.Divi;
break;
case '=':
token.type = TokenType.Assign;
break;
case '?':
token.type = TokenType.Print;
break;
case '(':
token.type = TokenType.Lparen;
break;
case ')':
token.type = TokenType.Rparen;
break;
default:
token.type = TokenType.Unknown;
}
this.nextCharacter();
return token;
}
isToken(token: Token, type: TokenType) {
return token.type == type;
}
isNumber(text: string): boolean {
return /\d+/.test(text);
}
isVariable(text: string): boolean {
return /[a-z]+/.test(text);
}
setVar(index: number, value: number) {
this.vars[index] = value;
}
pushStack(token) {
this.stack.push(token);
}
popStack(): number {
return this.stack.pop();
}
}
new Parser();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.