//
// Copyright (C) 2005 Stefan Seefeld
// All rights reserved.
// Licensed to the public under the terms of the GNU LGPL (>= 2),
// see the file COPYING for details.
//
#include <Synopsis/Buffer.hh>
#include <Synopsis/Lexer.hh>
#include <Synopsis/SymbolFactory.hh>
#include <Synopsis/Parser.hh>
#include <Synopsis/PTree.hh>
#include <Synopsis/PTree/Display.hh>
#include <Synopsis/SymbolLookup.hh>
#include <Synopsis/Trace.hh>
#include <fstream>

using namespace Synopsis;

int usage(const char *command)
{
  std::cerr << "Usage: " << command << " [-c] [-g <filename>] [-d] [-r]  [-s] [-e] <input>" << std::endl;
  return -1;
}

int main(int argc, char **argv)
{
  bool encoding = false;
  bool typeinfo = false;
  bool debug = false;
  SymbolFactory::Language language = SymbolFactory::NONE;
  int tokenset = Lexer::CXX | Lexer::GCC;
  int ruleset = Parser::CXX | Parser::GCC;
  std::string dotfile;
  const char *input = argv[1];
  if (argc == 1) return usage(argv[0]);
  for (int i = 1; i < argc - 1; ++i)
  {
    if (argv[i] == std::string("-g"))
    {
      // make sure an argument is provided
      if (++i == argc - 1 || argv[i][0] == '-')
      {
	usage(argv[0]);
	return -1;
      }
      dotfile = argv[i];
    }
    else if (argv[i] == std::string("-c"))
    {
      tokenset = Lexer::C | Lexer::GCC;
      if (language != SymbolFactory::NONE)
        language = SymbolFactory::CXX;
      ruleset = Parser::GCC;
    }
    else if (argv[i] == std::string("-s"))
    {
      language = tokenset & Lexer::CXX ? SymbolFactory::CXX : SymbolFactory::C99;
    }
    else if (argv[i] == std::string("-e")) encoding = true;
    else if (argv[i] == std::string("-r")) typeinfo = true;
    else if (argv[i] == std::string("-d")) debug = true;
    else return usage(argv[0]);
  }
  input = argv[argc - 1];
  try
  {
    if (debug) Trace::enable(Trace::ALL);

    PTree::Encoding::do_init_static();

    std::ifstream ifs(input);
    Buffer buffer(ifs.rdbuf(), input);
    Lexer lexer(&buffer, tokenset);
    SymbolFactory symbols(language);
    Parser parser(lexer, symbols, ruleset);
    PTree::Node *node = parser.parse();
    const Parser::ErrorList &errors = parser.errors();
    for (Parser::ErrorList::const_iterator i = errors.begin(); i != errors.end(); ++i)
      (*i)->write(std::cerr);

    if (!node) return -1;
    if (dotfile.empty())
    {
      PTree::display(node, std::cout, encoding, typeinfo);
    }
    else
    {
      std::ofstream os(dotfile.c_str());
      PTree::generate_dot_file(node, os);
    }
  }
  catch (const std::exception &e)
  {
    std::cerr << "Caught exception : " << e.what() << std::endl;
  }
}
