# C++ skeleton for Bison

# Copyright (C) 2002-2007, 2009-2012 Free Software Foundation, Inc.

# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


b4_output_begin([b4_dir_prefix[]position.hh])
b4_copyright([Positions for Bison parsers in C++],
             [2002-2007, 2009-2012])[

/**
 ** \file ]b4_dir_prefix[position.hh
 ** Define the ]b4_namespace_ref[::position class.
 */

]b4_cpp_guard_open([b4_dir_prefix[]position.hh])[

# include <algorithm> // std::max
# include <iostream>
# include <string>

]b4_null_define[

]b4_namespace_open[
  /// Abstract a position.
  class position
  {
  public:
]m4_ifdef([b4_location_constructors], [[
    /// Construct a position.
    explicit position (]b4_percent_define_get([[filename_type]])[* f = YY_NULL,
                       unsigned int l = ]b4_location_initial_line[u,
                       unsigned int c = ]b4_location_initial_column[u)
      : filename (f)
      , line (l)
      , column (c)
    {
    }

]])[
    /// Initialization.
    void initialize (]b4_percent_define_get([[filename_type]])[* fn = YY_NULL,
                     unsigned int l = ]b4_location_initial_line[u,
                     unsigned int c = ]b4_location_initial_column[u)
    {
      filename = fn;
      line = l;
      column = c;
    }

    /** \name Line and Column related manipulators
     ** \{ */
    /// (line related) Advance to the COUNT next lines.
    void lines (int count = 1)
    {
      column = ]b4_location_initial_column[u;
      line += count;
    }

    /// (column related) Advance to the COUNT next columns.
    void columns (int count = 1)
    {
      column = std::max (]b4_location_initial_column[u, column + count);
    }
    /** \} */

    /// File name to which this position refers.
    ]b4_percent_define_get([[filename_type]])[* filename;
    /// Current line number.
    unsigned int line;
    /// Current column number.
    unsigned int column;
  };

  /// Add and assign a position.
  inline position&
  operator+= (position& res, const int width)
  {
    res.columns (width);
    return res;
  }

  /// Add two position objects.
  inline const position
  operator+ (const position& begin, const int width)
  {
    position res = begin;
    return res += width;
  }

  /// Add and assign a position.
  inline position&
  operator-= (position& res, const int width)
  {
    return res += -width;
  }

  /// Add two position objects.
  inline const position
  operator- (const position& begin, const int width)
  {
    return begin + -width;
  }
]b4_percent_define_flag_if([[define_location_comparison]], [[
  /// Compare two position objects.
  inline bool
  operator== (const position& pos1, const position& pos2)
  {
    return (pos1.line == pos2.line
            && pos1.column == pos2.column
            && (pos1.filename == pos2.filename
                || (pos1.filename && pos2.filename
                    && *pos1.filename == *pos2.filename)));
  }

  /// Compare two position objects.
  inline bool
  operator!= (const position& pos1, const position& pos2)
  {
    return !(pos1 == pos2);
  }
]])[
  /** \brief Intercept output stream redirection.
   ** \param ostr the destination output stream
   ** \param pos a reference to the position to redirect
   */
  template <typename YYChar>
  inline std::basic_ostream<YYChar>&
  operator<< (std::basic_ostream<YYChar>& ostr, const position& pos)
  {
    if (pos.filename)
      ostr << *pos.filename << ':';
    return ostr << pos.line << '.' << pos.column;
  }

]b4_namespace_close[
]b4_cpp_guard_close([b4_dir_prefix[]position.hh])
b4_output_end()


b4_output_begin([b4_dir_prefix[]location.hh])
b4_copyright([Locations for Bison parsers in C++],
             [2002-2007, 2009-2012])[

/**
 ** \file ]b4_dir_prefix[location.hh
 ** Define the ]b4_namespace_ref[::location class.
 */

]b4_cpp_guard_open([b4_dir_prefix[]location.hh])[

# include "position.hh"

]b4_namespace_open[

  /// Abstract a location.
  class location
  {
  public:
]m4_ifdef([b4_location_constructors], [
    /// Construct a location from \a b to \a e.
    location (const position& b, const position& e)
      : begin (b)
      , end (e)
    {
    }

    /// Construct a 0-width location in \a p.
    explicit location (const position& p = position ())
      : begin (p)
      , end (p)
    {
    }

    /// Construct a 0-width location in \a f, \a l, \a c.
    explicit location (]b4_percent_define_get([[filename_type]])[* f,
                       unsigned int l = ]b4_location_initial_line[u,
                       unsigned int c = ]b4_location_initial_column[u)
      : begin (f, l, c)
      , end (f, l, c)
    {
    }

])[
    /// Initialization.
    void initialize (]b4_percent_define_get([[filename_type]])[* f = YY_NULL,
                     unsigned int l = ]b4_location_initial_line[u,
                     unsigned int c = ]b4_location_initial_column[u)
    {
      begin.initialize (f, l, c);
      end = begin;
    }

    /** \name Line and Column related manipulators
     ** \{ */
  public:
    /// Reset initial location to final location.
    void step ()
    {
      begin = end;
    }

    /// Extend the current location to the COUNT next columns.
    void columns (unsigned int count = 1)
    {
      end += count;
    }

    /// Extend the current location to the COUNT next lines.
    void lines (unsigned int count = 1)
    {
      end.lines (count);
    }
    /** \} */


  public:
    /// Beginning of the located region.
    position begin;
    /// End of the located region.
    position end;
  };

  /// Join two location objects to create a location.
  inline const location operator+ (const location& begin, const location& end)
  {
    location res = begin;
    res.end = end.end;
    return res;
  }

  /// Add two location objects.
  inline const location operator+ (const location& begin, unsigned int width)
  {
    location res = begin;
    res.columns (width);
    return res;
  }

  /// Add and assign a location.
  inline location& operator+= (location& res, unsigned int width)
  {
    res.columns (width);
    return res;
  }
]b4_percent_define_flag_if([[define_location_comparison]], [[
  /// Compare two location objects.
  inline bool
  operator== (const location& loc1, const location& loc2)
  {
    return loc1.begin == loc2.begin && loc1.end == loc2.end;
  }

  /// Compare two location objects.
  inline bool
  operator!= (const location& loc1, const location& loc2)
  {
    return !(loc1 == loc2);
  }
]])[
  /** \brief Intercept output stream redirection.
   ** \param ostr the destination output stream
   ** \param loc a reference to the location to redirect
   **
   ** Avoid duplicate information.
   */
  template <typename YYChar>
  inline std::basic_ostream<YYChar>&
  operator<< (std::basic_ostream<YYChar>& ostr, const location& loc)
  {
    position last = loc.end - 1;
    ostr << loc.begin;
    if (last.filename
	&& (!loc.begin.filename
	    || *loc.begin.filename != *last.filename))
      ostr << '-' << last;
    else if (loc.begin.line != last.line)
      ostr << '-' << last.line  << '.' << last.column;
    else if (loc.begin.column != last.column)
      ostr << '-' << last.column;
    return ostr;
  }

]b4_namespace_close[

]b4_cpp_guard_close([b4_dir_prefix[]location.hh])
b4_output_end()
