Alright, so I don't know what's the problem with your code. It's not well formatted and it's too long. So I didn't read it. Nevertheless, here's how I would have written your program:
I'd split the program into a lexical analysis and a parsing phase. This makes your program more modular and easier to understand. I've already written a generic lexer and a shunting yard parser. So I'll use those to write the program.
First up, the lexical analyzer (I know that you didn't want to use regex and that you wrote your own expression parser, however this is the stuff regular expressions are good for, so):
const lexer = new Lexer();
lexer.addRule(/\s+/, () => {}); // skip whitespace
lexer.addRule(/[\+\-\*\/\(\)]/, lexeme => lexeme); // punctuators: + - * / ( )
lexer.addRule(/\-?(?:0|[1-9]\d*)(?:\.\d+)?/, lexeme => +lexeme); // numbers
Next we have the shunting yard parser:
const left1 = { associativity: "left", precedence: 1 };
const left2 = { associativity: "left", precedence: 2 };
const parser = new Parser({ "+": left1, "-": left1, "*": left2, "/": left2 });
Then we connect the lexer to the parser:
Array.fromIterator = it => Array.from({ [Symbol.iterator]: () => it });
const step = value => ({ done: value === undefined, value });
const parse = input => {
lexer.setInput(input);
const next = () => step(lexer.lex());
const tokens = Array.fromIterator({ next });
return parser.parse(tokens);
};
Now all you need to do is call the parse
function as follows:
const output = parse("9 - (5 * 2) + (7.66 / 3.21) * 3");
console.log(output); // [9, 5, 2, "*", "-", 7.66, 3.21, "/", 3, "*", "+"]
See the output for yourself.
const lexer = new Lexer();
lexer.addRule(/\s+/, () => {}); // skip whitespace
lexer.addRule(/[\+\-\*\/\(\)]/, lexeme => lexeme); // punctuators: + - * / ( )
lexer.addRule(/\-?(?:0|[1-9]\d*)(?:\.\d+)?/, lexeme => +lexeme); // numbers
const left1 = { associativity: "left", precedence: 1 };
const left2 = { associativity: "left", precedence: 2 };
const parser = new Parser({ "+": left1, "-": left1, "*": left2, "/": left2 });
Array.fromIterator = it => Array.from({ [Symbol.iterator]: () => it });
const step = value => ({ done: value === undefined, value });
const parse = input => {
lexer.setInput(input);
const next = () => step(lexer.lex());
const tokens = Array.fromIterator({ next });
return parser.parse(tokens);
};
const output = parse("9 - (5 * 2) + (7.66 / 3.21) * 3");
console.log(output); // [9, 5, 2, "*", "-", 7.66, 3.21, "/", 3, "*", "+"]
<script src="https://rawgit.com/aaditmshah/lexer/master/lexer.js"></script>
<script src="https://rawgit.com/aaditmshah/6683499/raw/875c795ec9160e095a4030e82d5a6e3416d9fdc7/shunt.js"></script>
It also correctly parses negative numbers:
const output = parse("9 - (3 * (-6))");
console.log(output); // [9, 3, -6, "*", "-"]
See the demo.
const lexer = new Lexer();
lexer.addRule(/\s+/, () => {}); // skip whitespace
lexer.addRule(/[\+\-\*\/\(\)]/, lexeme => lexeme); // punctuators: + - * / ( )
lexer.addRule(/\-?(?:0|[1-9]\d*)(?:\.\d+)?/, lexeme => +lexeme); // numbers
const left1 = { associativity: "left", precedence: 1 };
const left2 = { associativity: "left", precedence: 2 };
const parser = new Parser({ "+": left1, "-": left1, "*": left2, "/": left2 });
Array.fromIterator = it => Array.from({ [Symbol.iterator]: () => it });
const step = value => ({ done: value === undefined, value });
const parse = input => {
lexer.setInput(input);
const next = () => step(lexer.lex());
const tokens = Array.fromIterator({ next });
return parser.parse(tokens);
};
const output = parse("9 - (3 * (-6))");
console.log(output); // [9, 3, -6, "*", "-"]
<script src="https://rawgit.com/aaditmshah/lexer/master/lexer.js"></script>
<script src="https://rawgit.com/aaditmshah/6683499/raw/875c795ec9160e095a4030e82d5a6e3416d9fdc7/shunt.js"></script>
In addition it handles precedence and associativity rules to get rid of redundant parentheses:
const output = parse("9 - 3 * -6");
console.log(output); // [9, 3, -6, "*", "-"]
The demo.
const lexer = new Lexer();
lexer.addRule(/\s+/, () => {}); // skip whitespace
lexer.addRule(/[\+\-\*\/\(\)]/, lexeme => lexeme); // punctuators: + - * / ( )
lexer.addRule(/\-?(?:0|[1-9]\d*)(?:\.\d+)?/, lexeme => +lexeme); // numbers
const left1 = { associativity: "left", precedence: 1 };
const left2 = { associativity: "left", precedence: 2 };
const parser = new Parser({ "+": left1, "-": left1, "*": left2, "/": left2 });
Array.fromIterator = it => Array.from({ [Symbol.iterator]: () => it });
const step = value => ({ done: value === undefined, value });
const parse = input => {
lexer.setInput(input);
const next = () => step(lexer.lex());
const tokens = Array.fromIterator({ next });
return parser.parse(tokens);
};
const output = parse("9 - 3 * -6");
console.log(output); // [9, 3, -6, "*", "-"]
<script src="https://rawgit.com/aaditmshah/lexer/master/lexer.js"></script>
<script src="https://rawgit.com/aaditmshah/6683499/raw/875c795ec9160e095a4030e82d5a6e3416d9fdc7/shunt.js"></script>
Hope that helps.