formal-language/grammar

View on GitHub
src/ll1/_compile.js

Summary

Maintainability
A
3 hrs
Test Coverage
import {_chain} from '@iterable-iterator/chain';
import {filter} from '@iterable-iterator/filter';
import {iter} from '@iterable-iterator/iter';
import {map} from '@iterable-iterator/map';
import {next} from '@iterable-iterator/next';

import EW from '../grammar/EW.js';
import alphabet from '../grammar/alphabet.js';

import _first from './_first.js';
import _follow from './_follow.js';
import first from './first.js';

/**
 * Generates the rows of the predictive parsing table for a grammar.
 * Corresponds to Algorithm 4.31 in Dragon Book (2006) on page 224.
 *
 * @param {Map} productions
 * @returns {Iterable}
 */
export default function* _compile(productions) {
    const abc = alphabet(productions);

    const phi = _first(productions);
    const pho = _follow(phi, productions);

    const FIRST = (rule) => first(phi, rule);

    const dflt = {}; // Dummy object

    for (const [A, rules] of productions) {
        const m = map(
            (a) => [
                a,
                next(
                    // eslint-disable-next-line new-cap
                    iter(filter((r) => FIRST(rules.get(r)).has(EW), rules.keys())),
                    dflt,
                ),
            ],
            filter((a) => pho.get(A).has(a) && !phi.get(A).has(a), abc),
        );

        const n = map(
            (a) => [
                a,
                next(
                    // eslint-disable-next-line new-cap
                    iter(filter((r) => FIRST(rules.get(r)).has(a), rules.keys())),
                    dflt,
                ),
            ],
            filter((a) => a !== EW, abc),
        );

        yield [A, new Map(filter(([_k, v]) => v !== dflt, _chain([m, n])))];
    }
}