How do you build an AST (Abstract Syntax Tree) for left-associative operators using PEG.js?
I've tried to write some code based on the information I found on the internet, but I seem to have made a mistake.
The code I wrote generates an incorrect AST for most expressions.
Expression
12-6-4-2*1-1
Expected AST
{
"left": {
"left": {
"left": {
"left": 12,
"operator": "-",
"right": 6
},
"operator": "-",
"right": 4
},
"operator": "-",
"right": {
"left": 2,
"operator": "*",
"right": 1
}
},
"operator": "-",
"right": 1
}
Generated AST
{
"left": {
"left": {
"left": 12,
"operator": "-",
"right": 6
},
"operator": "-",
"right": 4
},
"operator": "-",
"right": {
"left": 2,
"operator": "*",
"right": {
"left": 1,
"operator": "-",
"right": 1
}
}
}
Code
{
function operator(first, rest) {
if (rest.length === 0) return first;
return { left: first, right: rest };
};
function makeOperator(left, operator, right) {
return { left: left, operator: operator[0], right: clean(right[1]) };
};
function clean(expression) {
if (!expression.right) return expression;
var result = makeOperator(expression.left, expression.right[0], expression.right[0]);
for (var counter = 1, len = expression.right.length; counter < len; counter++) {
result = makeOperator(result, expression.right[counter], expression.right[counter]);
}
return result;
};
}
Start = E
E
= expression:E1
{ return clean(expression); }
E1
= expression:E2 rest:(("+" / "-") E2)*
{ return operator(expression, rest); }
E2
= expression:Value rest:(("*" / "/") E1)*
{ return operator(expression, rest); }
Value
= Number
/ BracketedExpression
Number
= [1-9][0-9]*
{ return parseInt(text(), 10); }
BracketedExpression
= "(" expression:E1 ")"
{ return expression; }
I would really appreciate any help or example code on how to build ASTs for both left-associative and right-associative operators.
Edit: As @Bergi pointed out, the problem was that E2 used E1 as the expression for the rest of the operator list instead of Value. However, the code that Bergi wrote is much simpler than mine.