In order to try to implement a PEG in JavaScript that doesn't make older browsers crash from stack overflows, I would like to make a parsing expression grammar that parses a string in a non-recursive way. How do you do this? It feels mind bending.
Say you have a structure like this:
- A
grammarhas many expressions - An
expressionhas manymatchers - A
matcherhas manytokens(or whatever is a better word for it) - A
tokencan either point to anotherexpression, or be a primitive string or regular expression. So if it points to another expression, this is where the recursion starts.
So say you define the hierarchy like this:
var grammar = new Grammar('math');
var expression = grammar.expression;
expression('math')
.match(':number', ':operator', ':number', function(left, operator, right){
switch (operator) {
case '+': return left + right;
case '-': return left - right;
case '*': return left * right;
case '/': return left / right;
}
});
expression('number')
.match(/\d+/, parseInt);
expression('operator')
.match('+')
.match('-')
.match('*')
.match('/');
var val = grammar.parse('6*8'); // 42
When you call grammar.parse, it starts at the root expression (which has the same name as it, so "math"). Then it iterates through each matcher, then each token, and if the token is an expression, recurses. Basically this (the parser will keep track of the offset/position of the string it's matching the patterns against; this is just pseudocode):
function parse(str, expression, position) {
var result = [];
expression.matchers.forEach(function(matcher){
matcher.tokens.forEach(function(token){
var val;
if (token.expression) {
val = parse(str, token.expression, position);
} else {
val = token.parse(str, position);
}
if (val) result.push(val);
});
});
return result;
}
parse('6*8', grammar.root, 0);
So for a simple expression like 6*8 there's very little recursion, but you could quickly get to a complex expression with many levels of nesting. Plus multiply the nesting by all those nested for loops, and the stack becomes large (I don't actually use forEach, I use for loops, but in the for loop it calls a function most of the time, so it ends up being pretty much the same).
The question is, how do you "flatten this out"? Instead of doing recursion, how do you make this so it's essentially like this:
while (token = stack.pop()) {
val = token.parse(val);
if (val) result.push(val);
}
I'm not looking for the details of how to implement a solution to this specific PEG problem, I am more just looking for the general way you keep track of the recursive state in a non-recursive way.
new Context(grammar)). So it would have propertiesexpressionStack,matcherStack, andtokenStack, and keep track of the indices for each. But then that seems complicated, so not sure if that is the way...