Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

overloaded operators


SourceForge.net Logo     CTTL on    
    SourceForge    
    Download    
    Latest    
    Documentation    
    Index    
    Library    
    News    
    CVS    
    Repository    
   Other    
   Links    

See also:

For resemblance of built-in types, scalar primitives are accompanied by a set of overloaded arithmetic, logical, assignment, and subscript access operators. Together with overloaded operators, scalar primitives are building blocks of lambda expressions.

Besides arithmetic and logical operators, the library provides overloaded subscript access operators for objects accessible in this way.

The following code instantiates lambda primitive named output, which refers to STL output iterator adaptor std::ostream_iterator( std::cout, " " ):

#include <iostream>
#include <iterator>

void f()
{
    lambda< std::ostream_iterator< int > >::scalar
        output( std::ostream_iterator< int >( std::cout, " " ) );
    ( *output++ = scalar( 5 ) ).evaluate();
}

Lambda expression *output++ = scalar( 5 ) sends integer 5 to the standard output. Overloaded dereference and post-increment operators were used in accordance with output iterator requirements. Comma operator allows grouping of two sub-expressions, evaluating them from left to right. Previous example could be rewritten using two sub-expressions,

    ( *output = scalar( 5 ), output++ ).evaluate();

or using pre-increment operator,

    ( *output = scalar( 5 ), ++output ).evaluate();

or we can split the original into two separately evaluated lambda expressions,

    ( *output = scalar( 5 ) ).evaluate();
    ( ++output ).evaluate();

In every case the outcome is the same.



The next example shows access to the element of vector via overloaded subscript operator:

void f()
{
        std::vector< std::string > vec( 1 );
        lambda< std::vector< std::string > >::scalar_reference
            vec_ref( &vec );
        lambda< std::string >::scalar str( std::string( "ABC" ) );
        ( vec_ref[ 0 ] = str ).evaluate();
}

Vector of strings vec is constructed with one element. The vector is referenced by vec_ref scalar primitive. Another scalar primitive, str instantiates string object, initialized with text "ABC". Lambda expression vec_ref[ 0 ] = str assigns new string to the first element of vector.

Once we know how to instantiate scalars, writing lambda expressions is easy: there is little difference between lambda and native C++ expressions.


connecting lambda expressions with CTTL grammar rules


Lambda expression joined with CTTL grammar yields another grammar expression. Grammar expression R and integral lambda expression L are joined by the following operators:

   R + L
   R & L
   R | L

where

'+' is CTTL binary sequence operator;
'&' is CTTL binary set intersection operator;
'|' is CTTL binary set union operator.

Reversed connections are also acceptable:

   L + R
   L & R
   L | R

CTTL lambda expression supports match evaluation, which makes lambda behave like in-line semantic action, invoked by grammar expression. As such, lambda expressions control the flow of CTTL grammars in accordance with integral result of L.

If result is zero, evaluation fails, and L becomes a stop symbol. Otherwise, L behaves like epsilon parser, successfully matching an empty string. Therefore, integral lambda expression represents a boolean switch parser, which may fail or succeed, but has no side effects on the state of the parseable universe.


Kleene star modifier (epsilon parser)


Not all lambda expressions return integral result type. More so, result of expression from earlier example, *output++ = scalar( 5 ) should not be used, as required by rules imposed by STL output iterators.

Often no action is required until entire subset of grammar succeeds. However, as each token gets parsed, the data must be accumulated somewhere. It could be accomplished by lambda expression that has no impact on the grammar evaluation. Results of such expression should not interfere with grammar flow in any way.

Kleene star operator turns lambda expression into a grammar unit that always succeeds:

	R + *L
	R & *L
	R | *L

Expression *L matches empty symbol in the input language, and leaves input universe unmodified. By meaning, kleene star preempts C++ dereference operator. For example, notice the use of two unary * operators in a row:

void f()
{
        std::vector< int > vect( 3 );
        input<> inp( "abc" );
        const_edge<> universe( new_edge( inp ) );
        size_t result = (
            symbol( true )
            +
            **scalar( action(
                &vect,
                std::mem_fun( &std::vector< int >::size )
            ))
        ).match( universe );

        assert( result != std::string::npos );
        assert( universe.first.offset() == 0 );
}

First * is kleene modifier. It converts lambda expression

            *scalar( action(
                &vect,
                std::mem_fun( &std::vector< int >::size )
            ))

into parser that always succeeds. The second * is dereference operator, applied to scalar primitive encapsulating closure object, created by the action() helper. When closure is dereferenced, actual member function call is made. If dereference was not used, e. g.

        size_t result = (
            symbol( true )
            +
            *scalar( action(   // problem: vector< int >::size() not called!
                &vect,
                std::mem_fun( &std::vector< int >::size )
            ))
        ).match( universe );

no actual call to vector< int >::size() would take place.


Kleene plus modifier (direct parser)


Unary plus operator interprets result of integer lambda expression L and moves upper bound of the parseable universe forward as if there was a match of the corresponding amount of characters.

In other words, kleene plus operator in front of lambda expression specifies the length of matched symbol immediately at the current position of the universe. This type of parser is called direct parser, since it consumes a number of input characters specified by the result of lambda function. If result is equal to std::string::npos, the universe is not affected, as it signals evaluation failure, and is processed by surrounding grammar accordingly.

By meaning, kleene plus preempts arithmetic plus operator. For example, the following grammar expression matches lowercase or uppercase letter 'A' followed by a single character:

    void f()
    {
        input<> inp( "a bc" );
        const_edge< policy_space<> > universe = new_edge( inp );
        size_t result = (
            (
                symbol( 'A' )
                |
                'a'
            )
            +
            +scalar( 1 )
        ).match( universe );

        assert( result != std::string::npos );
        assert( universe.first.offset() == 2 );
    }

Please note that resulting universe.first.offset() is equal to 2. This is because direct parser, produced by +scalar( 1 ), is completely ignorant of white space policy and always interacts with grammar in strict mode.

The white space in text "a bc" is strictly interpreted by grammar

            (
                symbol( 'A' )
                |
                'a'
            )
            +
            +scalar( 1 )

despite automatic white space processing requested by the universe, declared with policy_space.

If symbol() lexeme was used instead of +scalar( 1 ), then resulting universe.first.offset() would be equal to 3. Since symbol() conforms to white space sensitivity rules, it skips white space and than matches a single character.



Copyright © 1997-2006 Igor Kholodov mailto:cttl@users.sourceforge.net.

Permission to copy, use, modify, sell and distribute this document is granted provided this copyright notice appears in all copies. This document is provided "as is" without express or implied warranty, and with no claim as to its suitability for any purpose.


Generated on Thu Nov 2 17:48:53 2006 for CTTL Lambda Expression by  doxygen 1.3.9.1