chilon::parser tutorial - part 6

The previous example will be extended to allow functions to be nested recursively. The new test data:

var _one

function command1(parameter, friend) {
    var v1

    function nested1(p1) {
        var n1v1
    }

    function nested2(p2) {
        function nested2nested1(p21) {}

        var n2v2

        function nested2nested2(p22a, p22b) {
            var n2n2v1
        }
    }
}

var _two_two_

The new code to parse it:

typedef lexeme<
    choice< char_range<a,z, A,Z>, char_<'_'> >,
    many< choice<
            char_range<a,z, A,Z, '0', '9'>,
            char_<'_'> > > >
identifier;

typedef sequence<char_<v,a,r>, identifier> variable;

// A shortcut I like to use.
#define node_member_(N) CHILON_NODE_MEMBER(N)

// Inherting from `node' in this way allows CHILON_NODE_MEMBER to be used.
struct function : node<function> {
    typedef sequence<char_<f,u,n,c,t,i,o,n>, identifier> name;
    typedef joined<char_<','>, identifier>               arguments;

    // A function can now consist of variables and nested functions.
    // `node' is used within this parser to allow `function' to refer
    // to itself. It must always be used to protect parsers that would
    // otherwise create a circular type dependancy and a compiler error.
    // `node' has simple to follow restrictions on its use, see the
    // next comment for more information.
    typedef many<
        choice<
            node<function>,
            variable
        >
    > elements;

    stored<arguments>::type  arguments_;
    stored<elements>::type   elements_;
    range                    name_;

    // By defining the following typedef, `function' can now be passed to
    // any chilon parse function and is parsed using the corresponding type:
    // Doing this also allows the type to be used with `node'.
    typedef sequence<
        node_member_(name),
        char_<'('>,
        node_member_(arguments),
        char_<')'>,
        char_<'{'>,
        node_member_(elements),
        char_<'}'>
    > parser_type;
};

template <class O>
void print_args(int const indent, O& stream, function const& func) {
    stream << "function " << func.name_ << "(\n";
    chilon::print_indent(indent + 1, stream);
    stream << "arguments: ";
    chilon::print_args(indent + 1, stream, func.arguments_);
    stream << "\n";
    chilon::print_indent(indent + 1, stream);
    stream << "elements: ";
    chilon::print_args(indent + 1, stream, func.elements_);
    stream << "\n";
    chilon::print_indent(indent, stream);
    stream << ")";
}

int main(int argc, char *argv[]) {
    // function used directly in choice due to the `type' definition
    // discussed in the previous comment.
    return test< many< choice<
        variable,
        function
    > > >(argc, argv);
}

The new output:

[
    "_one"
    function command1(
        arguments: [
            "parameter"
            "friend"
        ]
        elements: [
            "v1"
            function nested1(
                arguments: [ "p1" ]
                elements: [ "n1v1" ]
            )
            function nested2(
                arguments: [ "p2" ]
                elements: [
                    function nested2nested1(
                        arguments: [ "p21" ]
                        elements: []
                    )
                    "n2v2"
                    function nested2nested2(
                        arguments: [
                            "p22a"
                            "p22b"
                        ]
                        elements: [ "n2n2v1" ]
                    )
                ]
            )
        ]
    )
    "_two_two_"
]

The above source code repeated without comments and printing code:

typedef lexeme<
    choice< char_range<a,z, A,Z>, char_<'_'> >,
    many< choice< char_range<a,z, A,Z, '0', '9'>, char_<'_'> > > >
identifier;

typedef sequence<char_<v,a,r>, identifier> variable;

#define node_member_(N) CHILON_NODE_MEMBER(N)

struct function : node<function> {
    typedef sequence<char_<f,u,n,c,t,i,o,n>, identifier>  name;
    typedef joined<char_<','>, identifier>                arguments;
    typedef many< choice< node<function>, variable > >    elements;

    stored<arguments>::type  arguments_;
    stored<elements>::type   elements_;
    range                    name_;

    typedef sequence<
        node_member_(name),
        char_<'('>, node_member_(arguments), char_<')'>,
        char_<'{'>, node_member_(elements), char_<'}'>
    > type;
};

int main(int argc, char *argv[]) {
    return test< many< choice< variable, function > > >(argc, argv);
}
previous | next