text: //  Copyright (c) 2001-2011 Hartmut Kaiser
  //
  //  Distributed under the Boost Software License, Version 1.0. (See accompanying
  //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  
  #include <boost/spirit/include/lex_lexertl.hpp>
  
  #include <boost/core/lightweight_test.hpp>
  
  #ifdef _MSC_VER
  // bogus https://developercommunity.visualstudio.com/t/buggy-warning-c4709/471956
  # pragma warning(disable: 4709) // comma operator within array index expression
  #endif
  
  namespace lex = boost::spirit::lex;
  
  typedef lex::lexertl::token<std::string::iterator> token_type;
  typedef lex::lexertl::actor_lexer<token_type> lexer_type;
  
  ///////////////////////////////////////////////////////////////////////////////
  static bool found_identifier_flag = false;
  
  ///////////////////////////////////////////////////////////////////////////////
  void found_identifier_sa0()
  {
      found_identifier_flag = true;
  }
  
  template <typename Lexer>
  struct lexer_sa0 : lex::lexer<Lexer>
  {
      lexer_sa0() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa0];
      }
      lex::token_def<> identifier;
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  static std::string found_identifier_str;
  
  void found_identifier_sa2(std::string::iterator& start
    , std::string::iterator& end)
  {
      found_identifier_flag = true;
      found_identifier_str = std::string(start, end);
  }
  
  template <typename Lexer>
  struct lexer_sa2 : lex::lexer<Lexer>
  {
      lexer_sa2() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa2];
      }
      lex::token_def<> identifier;
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  void found_identifier_sa3_normal(std::string::iterator& start
    , std::string::iterator& end, BOOST_SCOPED_ENUM(lex::pass_flags)& pass)
  {
      BOOST_TEST(pass == lex::pass_flags::pass_normal);
  
      found_identifier_flag = true;
      found_identifier_str = std::string(start, end);
  }
  
  template <typename Lexer>
  struct lexer_sa3_normal : lex::lexer<Lexer>
  {
      lexer_sa3_normal() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa3_normal];
      }
      lex::token_def<> identifier;
  };
  
  void found_identifier_sa3_fail(std::string::iterator&, std::string::iterator&
    , BOOST_SCOPED_ENUM(lex::pass_flags)& pass)
  {
      pass = lex::pass_flags::pass_fail;
  }
  
  template <typename Lexer>
  struct lexer_sa3_fail : lex::lexer<Lexer>
  {
      lexer_sa3_fail() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa3_fail];
      }
      lex::token_def<> identifier;
  };
  
  void found_identifier_sa3_ignore(std::string::iterator&, std::string::iterator&
    , BOOST_SCOPED_ENUM(lex::pass_flags)& pass)
  {
      pass = lex::pass_flags::pass_ignore;
  }
  
  template <typename Lexer>
  struct lexer_sa3_ignore : lex::lexer<Lexer>
  {
      lexer_sa3_ignore() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa3_ignore];
      }
      lex::token_def<> identifier;
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  static std::size_t found_identifier_id = 0;
  
  void found_identifier_sa4(std::string::iterator& start
    , std::string::iterator& end, BOOST_SCOPED_ENUM(lex::pass_flags)& pass
    , std::size_t id)
  {
      BOOST_TEST(pass == lex::pass_flags::pass_normal);
  
      found_identifier_flag = true;
      found_identifier_str = std::string(start, end);
      found_identifier_id = id;
  }
  
  template <typename Lexer>
  struct lexer_sa4 : lex::lexer<Lexer>
  {
      lexer_sa4() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa4];
      }
      lex::token_def<> identifier;
  };
  
  void found_identifier_sa4_id(std::string::iterator& start
    , std::string::iterator& end, BOOST_SCOPED_ENUM(lex::pass_flags)& pass
    , std::size_t& id)
  {
      BOOST_TEST(pass == lex::pass_flags::pass_normal);
  
      found_identifier_flag = true;
      found_identifier_str = std::string(start, end);
      found_identifier_id = id;
      id = 1;
  }
  
  template <typename Lexer>
  struct lexer_sa4_id : lex::lexer<Lexer>
  {
      lexer_sa4_id() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [&found_identifier_sa4_id];
      }
      lex::token_def<> identifier;
  };
  
  static std::size_t found_identifier_id2 = 0;
  
  bool identifier_token(token_type const& t)
  {
      found_identifier_id2 = t.id();
      return true;
  }
  
  ///////////////////////////////////////////////////////////////////////////////
  struct found_identifier_sa5
  {
      template <typename Context>
      void operator()(std::string::iterator& /*start*/
        , std::string::iterator& /*end*/, BOOST_SCOPED_ENUM(lex::pass_flags)& pass
        , std::size_t& /*id*/, Context& ctx)
      {
          BOOST_TEST(pass == lex::pass_flags::pass_normal);
  
          found_identifier_flag = true;
          found_identifier_str = std::string(ctx.get_value().begin(), ctx.get_value().end());
      }
  };
  
  template <typename Lexer>
  struct lexer_sa5 : lex::lexer<Lexer>
  {
      lexer_sa5() 
      {
          identifier = "[a-zA-Z][_a-zA-Z0-9]*";
          this->self += identifier [found_identifier_sa5()];
      }
      lex::token_def<> identifier;
  };
  
  ///////////////////////////////////////////////////////////////////////////////
  int main()
  {
      std::string identifier ("id_1234");
      std::string::iterator first = identifier.begin();
      std::string::iterator last = identifier.end();
  
      // test semantic action taking no arguments
      found_identifier_flag = false;
      {
          lexer_sa0<lexer_type> sa0;
          BOOST_TEST(lex::tokenize(first, last, sa0));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
      }
  
      // test semantic action taking two arguments (iterator pair for matched 
      // sequence)
      found_identifier_flag = false;
      found_identifier_str.clear();
      first = identifier.begin();
      {
          lexer_sa2<lexer_type> sa2;
          BOOST_TEST(lex::tokenize(first, last, sa2));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
          BOOST_TEST(found_identifier_str == identifier);
      }
  
      // test semantic action taking three arguments (iterator pair for matched 
      // sequence and pass_flags) - pass_flags::pass_normal
      found_identifier_flag = false;
      found_identifier_str.clear();
      first = identifier.begin();
      {
          lexer_sa3_normal<lexer_type> sa3;
          BOOST_TEST(lex::tokenize(first, last, sa3));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
          BOOST_TEST(found_identifier_str == identifier);
      }
  
      // test semantic action taking three arguments (iterator pair for matched 
      // sequence and pass_flags) - pass_flags::pass_fail
      first = identifier.begin();
      {
          lexer_sa3_fail<lexer_type> sa3;
          BOOST_TEST(!lex::tokenize(first, last, sa3));
          BOOST_TEST(first != last);
      }
  
      // test semantic action taking three arguments (iterator pair for matched 
      // sequence and pass_flags) - pass_flags::pass_ignore
      first = identifier.begin();
      {
          lexer_sa3_ignore<lexer_type> sa3;
          BOOST_TEST(lex::tokenize(first, last, sa3));
          BOOST_TEST(first == last);
      }
  
      // test semantic action taking four arguments (iterator pair for matched 
      // sequence and pass_flags, and token id)
      found_identifier_flag = false;
      found_identifier_str.clear();
      first = identifier.begin();
      found_identifier_id = 0;
      {
          lexer_sa4<lexer_type> sa4;
          BOOST_TEST(lex::tokenize(first, last, sa4));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
          BOOST_TEST(found_identifier_str == identifier);
          BOOST_TEST(found_identifier_id == lex::min_token_id);
      }
  
      found_identifier_flag = false;
      found_identifier_str.clear();
      first = identifier.begin();
      found_identifier_id = 0;
      found_identifier_id2 = 0;
      {
          lexer_sa4_id<lexer_type> sa4;
          BOOST_TEST(lex::tokenize(first, last, sa4, identifier_token));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
          BOOST_TEST(found_identifier_str == identifier);
          BOOST_TEST(found_identifier_id == lex::min_token_id);
          BOOST_TEST(found_identifier_id2 == 1);
      }
  
      // test semantic action taking four arguments (iterator pair for matched 
      // sequence and pass_flags, token id, and context)
      found_identifier_flag = false;
      found_identifier_str.clear();
      first = identifier.begin();
      found_identifier_id = 0;
      found_identifier_id2 = 0;
      {
          lexer_sa5<lexer_type> sa5;
          BOOST_TEST(lex::tokenize(first, last, sa5));
          BOOST_TEST(first == last);
          BOOST_TEST(found_identifier_flag);
          BOOST_TEST(found_identifier_str == identifier);
      }
  
      return boost::report_errors();
  }
  