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

arithmetics_traced.cpp


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

Modified version of the arithmetic expression parser. Introduces grammar rule tracing facilities of the library. For more information, see grammar debugging and tracing.

// sample code: arithmetics_traced.cpp
// demonstrates stateful cttl parser

//#define NDEBUG    // must appear before assert.h is included to stop assertions from being compiled 
//#define CTTL_TRACE_EVERYTHING
#define CTTL_TRACE_RULES  //define to turn light tracing on
//#define CTTL_TRACE_TRIVIAL    //define for trace messages only mode

#include <iostream>
#include "cttl/cttl.h"

using namespace cttl;

struct parser {

    /*  Arithmetic expression grammar production rules in EBNF form:
     *
     * <expr> --> <term> ( '+' <term> | '-' <term> )*
     * <term> --> <factor> ( '*'  <factor> | '/'  <factor> )*
     * <factor> --> <prime> | '(' <expr> ')' | '-' <factor> | '+' <factor>
     * <prime> --> ( '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' )+
     * 
     */

    int ip_cnt;

    parser( int ip_cnt_ = 0 )
        :   ip_cnt( ip_cnt_ )
    {
    }

    size_t rule_factor( const_edge<>& universe_ )
    {
        return (

            ( isdigit & CTTL_RULE( parser::numeric_literal ) )
            |
            (
                '(' + CTTL_RULE( parser::rule_expr ) + ')'
            )
            |
            (
                '-' + ( CTTL_RULE( parser::rule_factor ) & CTTL_RULE( parser::unary_minus ) )
            )
            |
            (
                '+' + CTTL_RULE( parser::rule_factor )  // unary plus is simply ignored
            )
            |
            CTTL_RULE( parser::parse_error )

        ).match( universe_ )
        ;
    }

    size_t rule_term( const_edge<>& universe_ )
    {
        return (

            CTTL_RULE( parser::rule_factor )
            +
            *(
                (
                    ( '*' + CTTL_RULE( parser::rule_factor ) )
                    &
                    CTTL_RULE( parser::multiply )
                )
                |
                (
                    ( '/' + CTTL_RULE( parser::rule_factor ) )
                    &
                    CTTL_RULE( parser::divide )
                )
            )

        ).match( universe_ )
        ;
    }


    size_t rule_expr( const_edge<>& universe_ )
    {
        return (

            CTTL_RULE( parser::rule_term )
            +
            *(
                (
                    ( '+' + CTTL_RULE( parser::rule_term ) )
                    &
                    CTTL_RULE( parser::add )
                )
                |
                (
                    ( '-' + CTTL_RULE( parser::rule_term ) )
                    &
                    CTTL_RULE( parser::subtract )
                )
            )

        ).match( universe_ )
        ;
    }


    size_t numeric_literal( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t " << edge_.text() << std::endl;
        return edge_.second.offset();
    }

    size_t divide( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t DIV \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl;
        return edge_.second.offset();
    }

    size_t multiply( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t MUL \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl;
        return edge_.second.offset();
    }

    size_t add( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t ADD \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl;
        return edge_.second.offset();
    }

    size_t subtract( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R2" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t SUB \t R2, R1 \t; R2 = R2 " << edge_.text() << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t R2" << std::endl;
        return edge_.second.offset();
    }

    size_t unary_minus( const_edge<>& edge_ )
    {
        std::cout << "\t" << ++ip_cnt << "\t ;" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t POP \t R1" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t NEG \t R1 \t\t; R1 = -(" << edge_.text() << ")" << std::endl;
        std::cout << "\t" << ++ip_cnt << "\t PUSH \t R1" << std::endl;
        return edge_.second.offset();
    }

    size_t parse_error( const_edge<>& edge_ ) const
    {
        std::cout
            << "*** syntax error ***"
            << std::endl
            << edge_.parent().text()
            << std::endl
            ;

        for ( size_t pos = 0; pos < edge_.first.offset(); ++pos )
            std::cout << '\x20';

        std::cout << "^-- at position " << edge_.first.offset() << std::endl;
        return std::string::npos;
    }

};


int main(int argc, char* argv[])
{
    if ( argc == 1 ) {
        std::cout << "\t usage: enter arithmetic expression to parse" << std::endl;
        return 1;
    }

    // construct input string from arguments on the command line:
    input<> inp( &argv[ 1 ], ' ' );

    // construct universe to be parsed
    const_edge<> universe( new_edge( inp ) );

    // construct the parser:
    parser arithmetic_parser;

    // evaluate arithmetic expression:
    if ( CTTL_MEMBER_RULE( arithmetic_parser, &parser::rule_expr ).match( universe ) != std::string::npos ) {
        if( universe.length() ) {
            std::cout
                << std::endl
                << "*** error: parser terminated: ***"
                << std::endl
                << inp.text()
                << std::endl
                ;
            for ( size_t pos = 0; pos < universe.first.offset(); ++pos )
                std::cout << '\x20';

            std::cout << "^-- at position " << universe.first.offset() << std::endl;
        }

    } else
        std::cout << "*** parser terminated" << std::endl;

    return 0;
}

Providing that the user specifies command argument "2*-3", the program generates the following output:

Input:
    2*-3

Output:
--------------------@2*-3-198->parser::rule_expr@0-4
--------------------@2*-3? {;       0-4 
--------------------@2*-3---85->parser::rule_term@0-4
--------------------@2*-3?   {;     0-4 
--------------------@2*-3-----60->parser::rule_factor@0-4
--------------------@2*-3?     {|       0-4 
--------------------@2*-3?      {|      0-4 
--------------------@2*-3?       {|     0-4 
--------------------@2*-3?        {|        0-4 
--------------------@2*-3?         {&       0-4 
-----------------------2@|          $       1-4 
-----------------------@2-----------36->parser::numeric_literal@0-1
    1    ;
    2    PUSH    2
-----------------------@2+++++++++++36<-parser::numeric_literal@0-0 ''
                                   }
                                  }
                                 }
                                }
                               }
---------------------@*-3+++++60<-parser::rule_factor@0-1   '2'
---------------------@*-3?    {*        1-4 
---------------------@*-3?     {|       1-4 
---------------------@*-3?      {&      1-4 
---------------------@*-3?       {;     1-4 
----------------------2*@|        *     2-4 char
----------------------@-3---------64->parser::rule_factor@2-4
----------------------@-3?         {|       2-4 
----------------------@-3?          {|      2-4 
----------------------@-3?           {|     2-4 
----------------------@-3?            {|        2-4 
----------------------@-3?             {&       2-4 
~~~~~~~~~~~~~~~~~~~~~~2*@~              $       2-4 FAIL 
~~~~~~~~~~~~~~~~~~~~~~2*@~              &       2-4 FAIL 
                                       }
----------------------@-3?             {;       2-4 
----------------------@-3?              {;      2-4 
~~~~~~~~~~~~~~~~~~~~~~2*@~               (      2-4 FAIL char
                                        }
                                       }
~~~~~~~~~~~~~~~~~~~~~~2*@~             |        2-4 FAIL 
                                      }
----------------------@-3?            {;        2-4 
---------------------2*-@|             -        3-4 char
-----------------------@3?             {&       3-4 
-----------------------@3---------------43->parser::rule_factor@3-4
-----------------------@3?               {|     3-4 
-----------------------@3?                {|        3-4 
-----------------------@3?                 {|       3-4 
-----------------------@3?                  {|      3-4 
-----------------------@3?                   {&     3-4 
--------------------2*-3@|                    $     4-4 
-----------------------@3---------------------36->parser::numeric_literal@3-4
    3    ;
    4    PUSH    3
-----------------------@3+++++++++++++++++++++36<-parser::numeric_literal@3-3   ''
                                             }
                                            }
                                           }
                                          }
                                         }
------------------------@+++++++++++++++43<-parser::rule_factor@3-4 '3'
-----------------------@3---------------43->parser::unary_minus@3-4
    5    ;
    6    POP     R1
    7    NEG     R1         ; R1 = -(3)
    8    PUSH    R1
-----------------------@3+++++++++++++++43<-parser::unary_minus@3-3 ''
                                       }
                                      }
                                     }
                                    }
                                   }
------------------------@+++++++++64<-parser::rule_factor@2-4   '-3'
                                 }
---------------------@*-3--------66->parser::multiply@1-4
    9    ;
    10   POP     R1
    11   POP     R2
    12   MUL     R2, R1     ; R2 = R2 *-3
    13   PUSH    R2
---------------------@*-3++++++++66<-parser::multiply@1-1   ''
                                }
                               }
------------------------@?     {|       4-4 
------------------------@?      {&      4-4 
------------------------@?       {;     4-4 
~~~~~~~~~~~~~~~~~~~~2*-3@~        L     4-4 FAIL empty universe
                                 }
~~~~~~~~~~~~~~~~~~~~2*-3@~       &      4-4 FAIL 
                                }
------------------------@?      {&      4-4 
------------------------@?       {;     4-4 
~~~~~~~~~~~~~~~~~~~~2*-3@~        L     4-4 FAIL empty universe
                                 }
~~~~~~~~~~~~~~~~~~~~2*-3@~       &      4-4 FAIL 
                                }
~~~~~~~~~~~~~~~~~~~~2*-3@~      |       4-4 FAIL 
                               }
                              }
                             }
------------------------@+++85<-parser::rule_term@0-4   '2*-3'
------------------------@?  {*      4-4 
------------------------@?   {|     4-4 
------------------------@?    {&        4-4 
------------------------@?     {;       4-4 
~~~~~~~~~~~~~~~~~~~~2*-3@~      L       4-4 FAIL empty universe
                               }
~~~~~~~~~~~~~~~~~~~~2*-3@~     &        4-4 FAIL 
                              }
------------------------@?    {&        4-4 
------------------------@?     {;       4-4 
~~~~~~~~~~~~~~~~~~~~2*-3@~      L       4-4 FAIL empty universe
                               }
~~~~~~~~~~~~~~~~~~~~2*-3@~     &        4-4 FAIL 
                              }
~~~~~~~~~~~~~~~~~~~~2*-3@~    |     4-4 FAIL 
                             }
                            }
                           }
------------------------@+198<-parser::rule_expr@0-4    '2*-3'



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:44:54 2006 for Common Text Transformation Library by  doxygen 1.3.9.1