"use strict"; /** @fileOverview Implements `class page.EBNFP.Rep extends page.EBNF.Rep`. * @author Axel T. Schreiner <ats@cs.rit.edu> * @version 1.5.1 */ /** Creates a new representation of an iteration for EBNFP. * @class Represents an iteration for EBNFP. * * @example * some: item +; * many: item *; * optional: item ?; * * @private * * @param {epNode} _node body. * @param {number} _min minimum number of occurences, 0 or 1. * @param {number} _max maximum number of occurences, 1 or undefined. * * @property {epNode} node body. * @property {number} min minimum number of occurences, 0 or 1. * @property {number} max maximum number of occurences, 1 or undefined. * @property {page.BNF.NT} nt corresponding non-terminal for BNF. * @property {boolean} empty true if no input can be accepted. * @property {Map} first terminals at front, maps ord to {@link page.BNF.T}. * @property {Map} follow terminals following, maps ord to {@link page.BNF.T}. */ page.EBNFP.Rep = function (_node, _min, _max) { page.EBNF.Rep.call(this, _node, _min, _max); }; page.subclass(page.EBNFP.Rep, 'page.EBNFP.Rep', page.EBNF.Rep); /** Called once by {@link page.EBNFP#init} to recursively translate into BNF. * * a+ * a* * a? * * where `.min` and `.max` are `1:undefined`, `0:undefined`, or `0:1`, respectively, and are translated to * * $#: a $## %prec error; # .min == 1 * $##: %prec error; * $##: $## a; * $##: $## error; * * $#: $## %prec error; # if left-hand side is known * $##: %prec error; # .min == 0 * $##: $## a; * $##: $## error; * * $#: %prec error; # .min == 0, .max == 1 * $#: a; * * `error` depends on `_grammar.recover` * and `%prec error` is inserted if the grammar specifies `%right error`. * * @private * @override * @variation EBNFP * * @param {page.EBNFP} _grammar object to which the construct belongs. * @param {page.EBNF.NT} [_nt] left-hand side, if known; avoids the need for a fresh non-terminal. * * @returns {page.BNF.NT} non-terminal representing the translated construct. */ page.EBNFP.Rep.prototype.toBNF = function (_grammar, _nt) { _grammar.assert('__WHERE__', !this.nt); // insert error? var error = _grammar.bnf.token(); var prec = 'prec' in error && error.prec.assoc == 'right'; if (!_grammar.recover && !prec) error = null; var nt1, result = this.nt = _nt ? _nt : _grammar.bnf.nt('$'); // $# var at = _grammar.bnf.rules.length; // placeholder if (this.min == 0 && this.max == 1) // opt _grammar.bnf.rules.push(null, null); else { if (this.min == 1 || _nt) // some or many, explicit _nt _grammar.bnf.rules.push(null, null, null); else // many _grammar.bnf.rules.push(null, null); if (error) _grammar.bnf.rules.push(null); // +error } var node = this.node instanceof page.BNF.T ? this.node : this.node.toBNF(_grammar); if (this.min == 0 && this.max == 1) { // opt _grammar.bnf.rules[at++] = // $#: [%prec error] prec ? _grammar.bnf.rule(result, [ ], error) : _grammar.bnf.rule(result, [ ]); _grammar.bnf.rules[at++] = _grammar.bnf.rule(result, [ node ]); // $#: node } else { if (this.min == 1) { // some nt1 = _grammar.bnf.nt('$'); _grammar.bnf.rules[at++] = // $#: node $## [%prec error] prec ? _grammar.bnf.rule(result, [ node, nt1 ], error) : _grammar.bnf.rule(result, [ node, nt1 ]); } else if (_nt) { // many, explicit nt nt1 = _grammar.bnf.nt('$'); _grammar.bnf.rules[at++] = // $#: $## [%prec error] prec ? _grammar.bnf.rule(result, [ nt1 ], error) : _grammar.bnf.rule(result, [ nt1 ]); } else // many nt1 = result; _grammar.bnf.rules[at++] = // $##: [%prec error] prec ? _grammar.bnf.rule(nt1, [ ], error) : _grammar.bnf.rule(nt1, [ ]); _grammar.bnf.rules[at++] = _grammar.bnf.rule(nt1, [ nt1, node ]); // $##: $## node if (error) _grammar.bnf.rules[at] = _grammar.bnf.rule(nt1, [ nt1, error ]); // $##: $## error } return result; };