With recursive descent parsers, an Abstract Syntax Tree (AST) can be thought of as a subset of the full parse tree.
Each node of the AST holds the phrase that was matched at the corresponding parse tree node.
The AST is very useful for translating the parsed string.
apg
parsers generate ASTs and apg-exp
uses the AST internally for all except the test()
functions.
Additionally, it always makes it available to the user as well.
This example assumes that you are already familiar with the AST object in apg
parsers.
If not, check out the ./src/ast
examples to get started.
We will use the floating point grammar and put the numbers in normal form as we did in the ./src/Folat
example
except this time we will do it with a translation of the AST.
(function ast() {
const apgJs = require('apg-js');
const writeHtml = require('../writeHtml');
const Float = require('./grammars/float');
const { apgExp: ApgExp } = apgJs;
const { apgLib } = apgJs;
const id = apgLib.ids;
const { charsToString } = apgLib.utils;
const astFloat = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.sign = '';
data.integer = '0';
data.fraction = '0';
data.esign = '+';
data.exp = 0;
} else if (state === id.SEM_POST) {
const exponent = data.exp === 0 ? '' : `e${data.esign}${data.exp}`;
data.normal = `${data.sign + data.integer}.${data.fraction}${exponent}`;
}
return ret;
};
const astSign = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
if (chars[phraseIndex] === 45) {
data.sign = '-';
}
}
return ret;
};
const astInteger = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.integer = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astFraction = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.fraction = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astEsign = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
data.esign = charsToString(chars, phraseIndex, phraseLength);
}
return ret;
};
const astExp = function (state, chars, phraseIndex, phraseLength, data) {
const ret = id.SEM_OK;
if (state === id.SEM_PRE) {
const exp = charsToString(chars, phraseIndex, phraseLength);
data.exp = parseInt(exp, 10);
}
return ret;
};
try {
let result;
let str;
let html;
const grammar = new Float();
console.log();
console.log('AST demonstration');
str = '';
str += '|||123|||123.|||.123|||-1.23|||+.123|||123.e2|||+.123E+1|||-123.123456789e-10|||';
str += '123e0|||+1.23e-0|||-.123e-001|||123e-000|||';
console.log();
console.log('input string:');
console.log(str);
const flags = 'g';
const exp = new ApgExp(grammar, flags);