    //------------------------------------------------------------------------
    // Extended-BNF script for parsing a tiny modeling language.
    //
    // Called by "tinyDSL_leader.cws".
    //
    // Logical structure of the parse tree:
    //   |
    //   +- classes: array of classes, indexed by the class name,
    //      |
    //      +- name: the class name,
    //      |
    //      +- attributes: array of attributes, indexed by their name
    //         |
    //         +- name: attribute's name
    //         |
    //         +- aggregate (optional): 'true' if the attribute points to
    //         |                        object(s) that belong(s) to the class
    //         +- type: type specifier
    //            |
    //            +- name: "double", "string" or class name
    //            |
    //            +- isArray (optional): 'true' if the attribute is an array
    //------------------------------------------------------------------------

    tinyDSL    ::= #continue #ignore(C++) [class_definition]* #empty;

    class_definition    ::=
            #readIdentifier:"class" #continue #readIdentifier:sClassName
            => if this.classes.findElement(sClassName) error("class '" + sClassName + "' is already defined");
            => insert this.classes[sClassName].name = sClassName;
            [':' #continue #readIdentifier:this.classes[sClassName].superClass]?
            '{'
            [attribute_definition(this.classes[sClassName])]*
            '}'
            ;

    attribute_definition(theClass : node)    ::=
            #readIdentifier:sAttributeName
            => if theClass.attributes.findElement(sAttributeName) error("attribute '" + sAttributeName + "' already exists in class '" + theClass.name + "'");
            #continue
            => insert theClass.attributes[sAttributeName].name = sAttributeName;
            => localref theAttribute = theClass.attributes[sAttributeName];
            ':'
            [
                #readIdentifier:"aggregate"
                => insert theAttribute.aggregate = true;
            ]?
            type_specifier(theAttribute.type)
            => if theAttribute.aggregate && !theAttribute.type.isObject set theAttribute.aggregate = false;
            ';'
            ;

    type_specifier(theType : node)    ::=
            simple_type(theType)
            ['[' #continue ']' => insert theType.isArray = true;]?
            ;

    simple_type(theType : node)    ::=
            #readIdentifier:{"double", "string"}:theType.name
        |
            #readIdentifier:sClassName
            => {
                if !this.classes.findElement(sClassName) error("unknown simple type '" + sClassName + "'");
                insert theType.name = sClassName;
                insert theType.isObject = true;
            }
            ;

Generated by v4.1 from CWscript2HTML.cwp.