idl_parser ::=
        #ignore(C++)
        #continue
        [
                '#' #!ignore ->'\n'
            |
                // à ce niveau, toutes les déclarations sont
                // placées dans la racine
                declaration(this)
        ]*
        #empty
        ;

// la déclaration sera contenue sous le noeud 'parent' passé
// en paramètre
declaration(parent : node) ::=
        #readIdentifier:sDecl
        declaration<sDecl>(parent)
        ;

declaration<"struct">(parent : node) ::=
        #continue
        identifier:sName
        => insert parent.structures[sName].name = sName;
        '{'
        [attribute_declaration(parent.structures[sName])]*
        '}'
        ';'
        ;

declaration<"typedef">(parent : node) ::=
            "sequence"
            '<'
            => local theType;
            type_name(theType)
            '>'
            identifier:sAlias
            ';'
            // arrivé au point-virgule, on est sûr d'avoir atteint la
            // fin de la séquence ;
            // recopie du sous-graphe du type
            => setall parent.sequences[sAlias] = theType;
        |
            ->';'
        ;
declaration<"interface">(parent : node) ::=
        #continue
        identifier:sName
        => insert parent.interfaces[sName].name = sName;
        // gardons une référence sur l'interface, cela facilitera
        // l'écriture du reste de la règle de production
        => localref interface = parent.interfaces[sName];
        [
            ':' #continue
            identifier:interface.inheritance
        ]?

        '{'
        [member_declaration(interface)]*
        '}'
        ';'
        ;

member_declaration(parent : node) ::= attribute_declaration(parent) | method_declaration(parent);

attribute_declaration(parent : node) ::=
        // la variable 'bReadonly' doit être déclarée à l'extérieur des
        // crochets, si l'on désire que sa portée les dépasse, et qu'elle
        // soit visible à la fin de la règle (la dernière ligne)
        => local bReadonly;
        [#readIdentifier:"readonly":bReadonly]?
        => local theType;
        type_name(theType)
        identifier:sName
        ';'
        => insert parent.attributes[sName].name = sName;
        // recopie du sous-graphe du type
        => setall parent.attributes[sName].type = theType;
        => if bReadonly insert parent.attributes[sName].readonly = bReadonly;
        ;

method_declaration(parent : node) ::=
        => local returnType; // là encore, cette variable doit se déclarer à l'extérieur des crochets
        [type_name(returnType) | #readIdentifier:"void"]
        identifier:sName
        '('
        #continue
        => insert parent.methods[sName].name = sName;
        => localref method = parent.methods[sName];
        // recopie du sous-graphe du type
        => setall method.type = returnType;
        [
            parameter(method)
            [',' #continue parameter(method)]*
        ]?
        ')'
        ';'
        ;

parameter(parent : node) ::=
        // autre façon de construire le graphe de parsing :
        // on alimente tout d'abord un graphe local puis,
        // si la règle de production s'avère valide, on
        // le recopie dans le graphe de parsing
        => local param;
        #readIdentifier:{"in", "inout", "out"}:param.mode
        type_name(param.type)
        identifier:param.name
        // on recopie tout le graphe local
        => setall parent.parameters[param.name] = param;
        ;

type_name(theType : node) ::=
        #readIdentifier:sType
        [
                // est-ce un type de base parmi ceux que l'on veut bien reconnaître ?
                #check(sType in {"boolean", "double", "long", "string"})
                => insert theType = sType;
            |
                // est-ce une interface ?
                #check(this.interfaces.findElement(sType))
                => insert theType = sType;
                => insert theType.is_interface = true;
            |
                // est-ce une structure ?
                #check(this.structures.findElement(sType))
                => insert theType = sType;
                => insert theType.is_structure = true;
            |
                // est-ce une séquence ?
                #check(this.sequences.findElement(sType))
                => {
                    // type faisant l'objet de la séquence, que l'on recopie
                    // dans la description de l'élément
                    setall theType.element = this.sequences[sType];
                    // ce type est une séquence
                    insert theType.is_sequence = true;
                }
        ]

        ;

identifier:value ::=
        #readIdentifier:identifier
        #check(!(identifier in {"abstract", "any", "attribute", "boolean", "case", "char", "component", "const", "consults",
                         "context", "custom", "default", "double", "emits", "enum", "eventtype", "exception", "factory",
                         "FALSE", "finder", "fixed", "float", "getraises", "home", "import", "in", "inout", "interface",
                         "local", "long", "manages", "module", "multiple", "native", "Object", "octet", "oneway", "out",
                         "primarykey", "private", "provides", "public", "publishes", "raises", "readonly", "sequence",
                         "setraises", "short", "string", "struct", "supports", "switch", "TRUE", "truncatable", "typedef",
                         "typeid", "typeprefix", "union", "unsigned", "uses", "ValueBase", "valuetype", "wchar", "wstring"}))
        ;

Generated by CodeWorker v3.8.2 from CWscript2HTML.cwp.