/*****************************************************************************/
/*!
 * \file parser.cpp
 * \brief The top-level API to the parser.  See parser.h for details.
 * 
 * Author: Sergey Berezin
 * 
 * Created: Wed Feb  5 11:46:57 2003
 *
 * 
 *
 * License to use, copy, modify, sell and/or distribute this software
 * and its documentation for any purpose is hereby granted without
 * royalty, subject to the terms and conditions defined in the \ref
 * LICENSE file provided with this distribution.
 * 
 * 
 * 
 */
/*****************************************************************************/
#include 
#include 
#include 
#include 
#include "parser_temp.h"
#include "parser.h"
using namespace std;
// The communication entry points of the actual parsers
// for smtlib language (smtlib.y and smtlib.lex)
extern int smtlibparse(); 
extern void *smtlib_createBuffer(int);
extern void smtlib_deleteBuffer(void *);
extern void smtlib_switchToBuffer(void *);
extern int smtlib_bufSize();
extern void *smtlibBufState();
void smtlib_setInteractive(bool);
namespace CVC3 {
  // The global pointer to ParserTemp.  Each instance of class Parser
  // sets this pointer before any calls to the lexer.  We do it this
  // way because flex and bison use global vars, and we want each
  // Parser object to appear independent.  
  // FIXME: This should probably go away eventually, when I figure out
  // flex++   -- Sergey.
  ParserTemp* parserTemp;
  int ParserTemp::error(const string& s) {
    // FIXME: Fail better?
    std::cerr << "error: " << s << "\n";
    exit(1);
    return 0;
  }
  // Internal storage class; I'll use member names without 'd_'s here
  class ParserData {
  public:
    // Is the input given by the file name or as istream?
    bool useName;
    ParserTemp temp;
    // Internal buffer used by the parser
    void* buffer;
  };
  // Constructors
  Parser::Parser(bool interactive, const std::string& fileName)
    : d_data(new ParserData) {
    if(fileName == "") {
      // Use std::cin
      d_data->useName = false;
      d_data->temp.is = &cin;
      d_data->temp.fileName = "stdin";
      d_data->temp.interactive = interactive;
    } else {
      // Open the file by name
      d_data->useName = true;
      d_data->temp.fileName = fileName;
      d_data->temp.is = new ifstream(fileName.c_str());
      if (!(*d_data->temp.is)) {
        // FIXME: Fail better?
        std::cerr << "error: File not found: " << fileName << "\n";
        exit(1);
      }
      d_data->temp.interactive = false;
    }
    initParser();
  }
  Parser::Parser(std::istream& is, bool interactive)
    : d_data(new ParserData) {
    d_data->useName = false;
    d_data->temp.is = &is;
    d_data->temp.fileName = "stdin";
    d_data->temp.interactive = interactive;
    initParser();
  }
    
  // Destructor
  Parser::~Parser() {
    if(d_data->useName) // Stream is ours; delete it
      delete d_data->temp.is;
    deleteParser();
    delete d_data;
  }
  // Initialize the actual parser
  void Parser::initParser() {
    d_data->buffer = smtlib_createBuffer(smtlib_bufSize());
    d_data->temp.lineNum = 1;
  }
  // Clean up the parser's internal data structures
  void Parser::deleteParser() {
    smtlib_deleteBuffer(d_data->buffer);
  }
    
  Expr Parser::next() {
    // If no more commands are available, return a Null Expr
    if(d_data->temp.done) return NULL;//Expr();
    // Set the global var so the parser uses the right stream and EM
    parserTemp = &(d_data->temp);
    // Switch to our buffer, in case there are multiple instances of
    // the parser running
    smtlib_switchToBuffer(d_data->buffer);
    smtlib_setInteractive(d_data->temp.interactive);
    smtlibparse();
    // Reset the prompt to the main one
    d_data->temp.setPrompt1();
    return d_data->temp.expr;
  }
  bool Parser::done() const { return d_data->temp.done; }
  void Parser::printLocation(ostream & out) const
  {
      out << d_data->temp.fileName << ":" << d_data->temp.lineNum;
  }
  void Parser::reset()
  {
    d_data->temp.expr = NULL;//Expr();
  }
  
} // end of namespace CVC3