If you’re using Flex/Bison, you get location tracking for free with the location feature. Well, almost. In your lexer, you’ll have to set yylloc by hand:

%{
  #define YY_USER_ACTION yylloc->columns(yyleng);
  yylloc->step();
  char string_buf[500];
  char *string_buf_ptr;
%}

In your AST nodes, you’ll have to embed location (the type defined in the generated location.hh):

class Value {
protected:
  Type *VTy;
  location SourceLoc;
public:
  void setSourceLocation(location SrcLoc);
  location getSourceLocation();
  // ...
}

And in your parser, you’ll have to set it using the @N:

rvalue:
                INTEGER[I]
                {
                  auto Int = $I;
                  Int->setSourceLocation(@1);
                  $$ = Int;
                }

Now we have a unified framework for lexing and parsing errors, and post-parsing errors (like semantic errors). It’s just a matter of writing the function to print the ^ and ~~~:

  std::string FaultyLine;
  for (unsigned int i = 0; i < Location.begin.line; i++)
    std::getline(*InStream, FaultyLine);

  *ErrorStream << FaultyLine << std::endl << std::setfill(' ')
               << std::setw(Location.begin.column)
               << ColorCode(ANSI_COLOR_GREEN) << '^';
  unsigned int end_col = Location.end.column > 0 ? Location.end.column - 1 : 0;
  if (end_col != Location.begin.column)
    *ErrorStream << std::setfill('~')
                 << std::setw(end_col - Location.begin.column) << '~';
  *ErrorStream << ColorCode(ANSI_COLOR_RESET) << std::endl;

One last detail: ColorCode is provided to make sure that the color characters don’t mess up the setw and alignment.

class ColorCode
{
  std::string ColorF;
public:
  ColorCode(std::string Color) : ColorF(Color) {}
  // Necessary to prevent color codes from messing up setw
  friend std::ostream& operator<<(std::ostream& Dest, ColorCode const& Code)
  {
    auto OsBuf = Dest.rdbuf();
    if (OsBuf == std::cout.rdbuf() || OsBuf == std::cerr.rdbuf())
      for (char ch : Code.ColorF) {
        Dest.put(ch);
      }
    return Dest;
  }
};