-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPostfixExpression.ts
More file actions
110 lines (97 loc) · 4.35 KB
/
Copy pathPostfixExpression.ts
File metadata and controls
110 lines (97 loc) · 4.35 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
import { Token } from "./tokens/Token";
import { EvalToken } from "./tokens/EvalToken";
import { InfixExpression } from "./InfixExpression";
import { ScalarToken } from "./tokens/ScalarToken";
import { OperatorToken } from "./tokens/OperatorToken";
import { FunctionToken } from "./tokens/FunctionToken";
import { EnclosureToken } from "./tokens/EnclosureToken";
import { Scope } from "./Scope";
export class PostfixExpression {
private infixExpression : InfixExpression;
private tokens : Array<Token>;
constructor(infixString : string) {
this.infixExpression = new InfixExpression(infixString);
this.tokens = this.infixToPostfix(this.infixExpression.getTokens());
}
private getAssociativity(token : Token) : number {
if(token instanceof OperatorToken) {
return (token as OperatorToken).getAssociativity();
} else if (token instanceof FunctionToken) {
return OperatorToken.ASSOCIATIVITY.RIGHT;
} else {
return Number.NaN;
}
}
private getPrecedence(token : Token) : number {
if(token instanceof OperatorToken) {
return (token as OperatorToken).getPrecidence();
} else if(token instanceof FunctionToken) {
return 10;
} else {
return Number.NaN;
}
}
public infixToPostfix(infixExpression : Array<Token>) : Array<Token> {
let result = Array<Token>();
let outputQueue = Array<Token>();
let operatorsStack = Array<Token>();
let token;
for(let i = 0; i < infixExpression.length; i++) {
token = infixExpression[i];
if(token instanceof ScalarToken) {
outputQueue.push(token);
} else if(token instanceof OperatorToken) {
let o1 = token;
let o2 = operatorsStack[operatorsStack.length - 1];
while((o2 instanceof OperatorToken || o2 instanceof FunctionToken) && (((o1.getAssociativity()) === ASSOC.Left && this.getPrecedence(o1) <= this.getPrecedence(o2))
|| (this.getAssociativity(o1) === ASSOC.Right && this.getPrecedence(o1) < this.getPrecedence(o2)))) {
outputQueue.push(operatorsStack.pop() as Token);
o2 = operatorsStack[operatorsStack.length - 1];
}
operatorsStack.push(o1);
} else if(token instanceof FunctionToken) {
operatorsStack.push(token);
} else if(token instanceof EnclosureToken) {
if((token as EnclosureToken).getType() === EnclosureToken.TYPES.PAREN) {
if((token as EnclosureToken).getSide() === EnclosureToken.SIDES.OPEN) {
operatorsStack.push(token);
} else {
while((operatorsStack[operatorsStack.length - 1] as EnclosureToken).getSide() !== EnclosureToken.SIDES.OPEN) {
outputQueue.push(operatorsStack.pop() as Token);
}
operatorsStack.pop();
}
} else {
throw "Only paren style enclosures are supported at this time";
}
} else {
throw `Unknown token: ${token}`;
}
}
return result;
}
public eval(scope : Scope) : Number {
if(this.tokens.length < 1) {
return Number.NaN;
}
let tempStack = Array<Token>();
let i = this.tokens.length - 1;
while(i > 0) {
let token = this.tokens[i--];
if(token instanceof OperatorToken) {
// tempStack.pop(), tempStack.pop()
tempStack.push(new ScalarToken((token as OperatorToken).eval(scope)));
} else if(token instanceof FunctionToken) {
let args = Array<Token>();
for(let i = 0; i < (token as FunctionToken).getNumArguments(); i++) {
args.push(tempStack.pop() as Token);
}
tempStack.push(new ScalarToken((token as FunctionToken).eval(scope)));
} else {
tempStack.push(token)
}
}
// TODO there should be some check that everything in a postfix expression must be evaluatable
return (tempStack.pop() as EvalToken).eval(scope);
}
}6