//------------------------------------------------------------------------
// 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.2 from CWscript2HTML.cwp.