Next: , Previous: , Up: Making Genparse Files   [Contents][Index]

2.5 C++ Output

All of our example so far have shown Genparse creating C code. Genparse also supports C++ output. This section examines the difference between C and C++ output and how to interface a program with a command line parsing class created by Genparse.

As with C output, Genparse creates two or three C++ output files: a header file, a parser class file, and a callback file. We’ll use mycopy4.gp as input to create these files. We invoke Genparse as follows.

genparse -l cpp -o mycopy4_clp mycopy4.gp

The three created files are named, mycopy4_clp.h, mycopy4_clp.cc, and mycopy4_clp_cb.cc. We’ll walk through each one in turn.


Next: , Previous: , Up: C++ Output   [Contents][Index]

2.5.1 Header File

The code for mycopy4_clp.h appears below.

/* mycopy4_clp.h */

#ifndef CMDLINE_H
#define CMDLINE_H

#include <iostream>
#include <string>
#include "mycopy4.h"

/*----------------------------------------------------------------------------
**
** class Cmdline
**
** command line parser class
**
**--------------------------------------------------------------------------*/

class Cmdline
{
private:
  /* parameters */
  int _i;
  std::string _o;
  bool _h;
  bool _v;

  /* other stuff to keep track of */
  std::string _program_name;
  int _optind;

public:
  /* constructor and destructor */
  Cmdline (int, char **) throw (std::string);
  ~Cmdline (){}

  /* usage function */
  void usage (int status);

  /* return next (non-option) parameter */
  int next_param () { return _optind; }

  /* callback functions */
  bool my_callback ();
  bool outfile_cb ();

  int i () { return _i; }
  std::string o () { return _o; }
  bool h () { return _h; }
  bool v () { return _v; }
};

#endif

The header file contains the definition of the command line parser class. The class defines a logical structure that puts different requirements on the main program than when the output code is in C. We summarize the differences between C and C++ output below.


Next: , Previous: , Up: C++ Output   [Contents][Index]

2.5.2 Parser File

The parser file defines the non-inlined member functions; i.e., the constructor and the usage function. The code for mycopy4_clp.cc appears below.

/* mycopy4_clp.cc */

#include <getopt.h>
#include <stdlib.h>
#include "mycopy4_clp.h"

/*----------------------------------------------------------------------------
**
** Cmdline::Cmdline ()
**
** Constructor method.
**
**--------------------------------------------------------------------------*/

Cmdline::Cmdline (int argc, char *argv[]) throw (std::string )
{
  extern char *optarg;
  extern int optind;
  int c;

  static struct option long_options[] =
  {
    {"iterations", required_argument, NULL, 'i'},
    {"outfile", required_argument, NULL, 'o'},
    {"help", no_argument, NULL, 'h'},
    {"version", no_argument, NULL, 'v'},
    {NULL, 0, NULL, 0}
  };

  _program_name += argv[0];

  /* default values */
  _i = 1;
  _h = false;
  _v = false;

  optind = 0;
  while ((c = getopt_long (argc, argv, "i:o:hv", long_options, &optind)) != EOF)
    {
      switch (c)
        {
        case 'i': 
          _i = atoi (optarg);
          if (_i < 1)
            {
              std::string s;
              s += "parameter range error: i must be >= 1";
              throw (s);
            }
          if (_i > MAX)
            {
              std::string s;
              s += "parameter range error: i must be <= MAX";
              throw (s);
            }
          break;

        case 'o': 
          _o = optarg;
          if (!outfile_cb ())
            this->usage (EXIT_FAILURE);
          break;

        case 'h': 
          _h = true;
          this->usage (EXIT_SUCCESS);
          break;

        case 'v': 
          _v = true;
          break;

        default:
          this->usage (EXIT_FAILURE);

        }
    } /* while */

  _optind = optind;
  if (!my_callback ())
    usage (EXIT_FAILURE);

}

/*----------------------------------------------------------------------------
**
** Cmdline::usage ()
**
** Print out usage information, then exit.
**
**--------------------------------------------------------------------------*/

void Cmdline::usage (int status)
{
  if (status != EXIT_SUCCESS)
    std::cerr << "Try `" << _program_name << " --help' for more information.\n";
  else
    {
      std::cout << "\
usage: " << _program_name << " [ -iohv ] file\n\
Print a file for a number of times to stdout.\n\
   [ -i ] [ --iterations ] (type=INTEGER, range=1...MAX, default=1)\n\
          Number of times to output <file>.\n\
          do it like this\n\
   [ -o ] [ --outfile ] (type=STRING)\n\
          Output file.\n\
   [ -h ] [ --help ] (type=FLAG)\n\
          Display this help and exit.\n\
   [ -v ] [ --version ] (type=FLAG)\n\
          Output version information and exit.\n";
    }
  exit (status);
}

As can be seen from this example, the C++ parser is very similar to the C parser we discussed in Parser Files. The main differences are that all strings are stored in C++ string format4.

It is important to note that the callback file is actually included into the parser file. This is because callbacks are implemented as member functions of the parser class, and most C++ compilers will not allow splitting a class’s member functions across more than one file. The bottom line of all this is that you don’t have to link in the callback file, just the parser file.


Next: , Previous: , Up: C++ Output   [Contents][Index]

2.5.3 Callback File

The callback file defines skeleton callback routines for the user to fill in. Their syntax is virtually identical to the C output case, except that their return values are bool rather than int. The code for mycopy4_clp_cb.cc appears below.

/* mycopy4_clp_cb.cc */

#include "mycopy4_clp.h"

/*----------------------------------------------------------------------------
**
** Cmdline::my_callback ()
**
** Global callback.
**
**--------------------------------------------------------------------------*/

bool Cmdline::my_callback ()
{
  return true;
}

/*----------------------------------------------------------------------------
**
** Cmdline::outfile_cb ()
**
** Parameter callback.
**
**--------------------------------------------------------------------------*/

bool Cmdline::outfile_cb ()
{
  return true;
}

Previous: , Up: C++ Output   [Contents][Index]

2.5.4 Main Program

Due to the syntactic differences between C and C++, the C++ main program must interact with the command line parser class in a different fashion than in the C case. The code for mycopy4.cc appears below.

/* mycopy4.cc */

#include <cstdlib>
#include <iostream>
#include <fstream>
#include "mycopy4_clp.h"

using namespace std;

#define VERSION "3.0"

int main (int argc, char *argv[])
{
  int i;
  char c;
  ifstream input_file;
  ofstream output_file;
  bool ofile = false, ifile = false;

  Cmdline cl (argc, argv);

  if (cl.v ())
    {
      cout << argv[0] << " version " << VERSION << endl;
      exit (0);
    }

  if (!cl.o ().empty ())
    {
      output_file.open (cl.o ().c_str ());
      ofile = true;
    }
  
  if (cl.next_param ())
    {
      input_file.open (argv[cl.next_param ()]);
      ifile = true;
    }

  for (i = 0; i < cl.i (); i++)
    {
      if (ifile) c = input_file.get ();
      else cin >> c;

      while (c != EOF)
	{
	  if (ofile) output_file.put (c);
	  else cout << c;

	  if (ifile) c = input_file.get ();
	  else cin >> c;
	}
      if (ifile) 
	{
	  input_file.clear ();
	  input_file.seekg (0);
	}
    }
  
  input_file.close ();
  output_file.close ();

  return 0;
}

Although mycopy4 provide almost identical output and functionality as that of mycopy3, it must access all command line parameters and related information through the command line parser class interface.


Footnotes

(4)

Older C++ compilers may not support built-in strings. If this is a problem, upgrade your compiler! It’s too old anyway.


Previous: , Up: C++ Output   [Contents][Index]