/* $Id$ 
 *
 * ParserDriver: glue class to driver between scanner and parser.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

#ifndef __PARSER_DRIVER_HPP_INCLUDED
#define __PARSER_DRIVER_HPP_INCLUDED

/* attention, this file get's included in several nasty places:
   1) at the beginning of the generated scanner. Thus some glue 
      definitions to make it work.
   2) From the code-file of the parser
*/

#include <string>
#include <stdexcept>
#include <stack>
#include "FAUhdlParser.tab.hh"
#include "location.hh"
#include "frontend/ast/LibraryList.hpp"
#include "frontend/ast/Location.hpp"
#include "frontend/reporting/SyntaxError.hpp"
#include "frontend/misc/SymbolTable.hpp"
#include "frontend/misc/NameLookup.hpp"
#include "frontend/reporting/SyntaxError.hpp"
#include "frontend/reporting/CompileError.hpp"

namespace yy {
	class ParserDriver;
	class Identifier;
};

/* Announce to Flex the prototype we want for lexing function, ... */
#define YY_DECL								\
  yy::FAUhdlParser::token_type						\
  yy::FAUhdlScanner::yylex(yy::FAUhdlParser::semantic_type* yylval,	\
        yy::FAUhdlParser::location_type* yylloc,			\
        ParserDriver& driver)

/* redefine yyterminate, to be of the same type */
#define yyterminate() return token::t_EOF

namespace ast {
	class Symbol;
};

namespace yy {

class FAUhdlScanner;


/** Glue class, that connects the scanner and the parser.
 */
class ParserDriver {
public:
	/** c'tor 
	 *  @param symTab symbol table instance for the scanner. */
	ParserDriver(ast::SymbolTable& symTab);

	/** d'tor */
	virtual ~ParserDriver();

	/** glue function that will call the real flexer
         *  @param yylval Semantic value of scanned token.
         *  @param yylloc Location of scanned token.
         */
	int 
	yylex(
		yy::FAUhdlParser::semantic_type* yylval,
		yy::FAUhdlParser::location_type* yylloc
	);

	//! Report a parse error.
        /** Used as callback from the parser.
         *  @param l Location of parse errror.
         *  @param msg error message.
         */
	void 
	error(
		const yy::FAUhdlParser::location_type& l,
		const std::string& msg
	) /* throw(SyntaxError) */;

	/** Parse a file.
	 *  @exception runtime_error in case the file could not get opened.
	 *  @exception SyntaxError in case there were errors during parsing.
	 *  @param filename name of file
	 *  @param lib library name the file is in.
	 */
	void parse(
		const std::string& filename,
		const char *lib
		)	/* throw(std::runtime_error, SyntaxError, 
				ast::CompileError) */;

	//! Convert a string to lower case.
        /** The argument will get overwritten with the result.
         *  @param mixed convert this string to lower case
         */
	static void 
	toLower(std::string& mixed);

	//! Make an float/int from a vhdl based real/int literal.
	/** can be instantiated with any number type, that can be 
          * static_cast from long.
	  * @param number based vhdl float/int, e.g. 16#FF.1A#E+1
	  * @return value of the double
	  * @exception std::invalid_argument in case no base specifier
	  *            is present.
	  */
	template <typename T>
	static T 
	makeBased(std::string number) /* throw(std::invalid_argument) */;

	//! Make an float/int from a vhdl unbased real literal.
	/** can be instantiated with any number type, that can be 
          * static_cast from long.
	  * @param number vhdl float/int, e.g. 123.456E-14
	  * @return value of the double
	  */
	template <typename T>
	static T 
	makeBase10(std::string number);

	//! Remove double quotes from a string.
	/** will turn "" to ", and also remove the surrounding quotes.
	 *  @param s string to mangle.
	 *  @return correct string, caller needs to free the allocated mem.
	 */
	static std::string* 
	removeQuotes(std::string s);

	//! Normalize a vhdl bit string.
	/** Remove surrounding quotes and normalize to binary values.
	 *  @param s string that will get normalized.
	 *  @return normalized bit string.
	 *  @exception if the digit is bigger than allowed.
	 */
	static std::string* 
	makeBitString(std::string s) /* throw(std::out_of_range) */;

	//! build an ast::Location.
	/** build an ast::Location with the given yy::location and the current
          * file as filename.
          *
          * @param loc location in the parser.
          * @return Location with linenumber and filename.
          */
	ast::Location
	bl(const location& loc) const {
		return ast::Location(loc.begin.line, this->currentFile);
	}

	//! register given unit to current library.
	/** register the Library unit unit to the currently opened libary.
	 *  @param unit to register
	 */
	void registerLibUnit(ast::LibUnit *unit);

	//! lookup a symbol in the SymbolTable and return the according token.
	/** wrapper to coordinate between SymbolTable and Scanner.
	 *  @param id string of the identifier
	 *  @param semanticValue semantic value that will get filled in.
	 *  @param loc location of the identifier
	 *  @return identifier token type.
	 */
	FAUhdlParser::token_type 
	getTokenForId(
		const char *id, 
		ast::NodeFactory::Identifier *&semanticValue,
		const FAUhdlParser::location_type &loc) const;

	//! build the SimpleName of an operator.
	/** Build the SimpleName of an operator, look it up in the 
	 *  SymbolTable and complain, if no candidates are found.
	 *
	 *  @param op name of the operator.
	 *  @param loc location of the operator symbol
	 *  @return created SimpleName.
	 */
	ast::SimpleName*
	buildOperatorName(
		const char *op, 
		const FAUhdlParser::location_type &loc) const;

	//! register all symbols in symbols with type
	/** register all symbols named in symbols into the current
	 *  region of the symbolTable.
	 *  
	 *  @param symbols list of symbols to register.
	 *  @param type type to register symbols.
	 */
	template <typename T>
	void registerSymbolDecls(
		const T *symbols,
		enum ast::symType type
		);

	/** scanner instance */
	FAUhdlScanner *scanner;
	
	/** top DesignUnitList */
	ast::LibraryList *topNode;

	/** current library */
	ast::Library *currentLibrary;

	/** symboltable instance for scanner */
	ast::SymbolTable &symbolTable;

	/** glue frontend for SymbolTable while parsing */
	ast::NameLookup &nameLookup;

	/** should identifiers get looked up and reported as individual 
	 *  ID_* instances?
	 */
	bool lookupIdentifiers;

	/** current label (or NULL) for the sequential/concurrent statement */
	std::string *label;

	/** top will point to the current callable, so that a return statement
	 *  can lookup to which it applies.
	 *  If empty (i.e. outside of a subprogram), no return statement is 
	 *  allowed.
	 */
	std::stack<ast::Callable*> subprogStack;

private:
	//! Convert an integer string to a long int.
	/** @param intval sequence of characteres [0-9a-zA-Z], with an 
         *         optional prefix of + or -.
         *  @param base base multiplier.
         *  @return value of intval.
         *  @exception invalid_argument intval contains other characters
         *  @exception out_of_range intval characters have greater value
         *	        than base
         */
	static long 
	makeLong(const std::string& intval, unsigned char base)
		/* throw(std::invalid_argument, std::out_of_range) */;

	//! Determine the value of a ascii (extended) digit.
	/** @param c ascii digit.
	 *  @return value of the digit or -1 if out of range.
	 */
	static int
	getDigitValue(char c);

	//! Normalize a hex bit string.
	/** @return normalized bit string. Caller must free it.
	 *  @param s vhdl hex bit string
	 */
	static std::string* 
	makeHexBitString(std::string& s);
	
	//! Normalize a octal bit string.
	/** @return normalized string. Caller must free it.
	 *  @param s vhdl octal bit string.
	 *  @exception std::out_of_range if a digit is not an octal
	 *                  digit.
	 */
	static std::string* 
	makeOctBitString(std::string& s) /* throw(std::out_of_range) */;

	//! Convert sting number to T.
	/** @param val value of actual number +-[0-9a-zA-Z] optional with .
         *  @param exponent value of exponent (base 10): [eE]?[+-]?[0-9]*
         *  @param base base multiplier.
         *  @return value of number.
         *
         *  Note: val and exponent may get modified.
         */
	template <typename T>
	static T 
	makeNumberFromParts(
		std::string& val,
		std::string& exponent,
		unsigned char base
	);

	//! reduce candidates to the correct token type.
	/** reduce the list of candidate symbols candidates to the
	 *  corresponding token type for the parser.
	 *  @param candidates list of symbol candidates.
	 *  @return corresponding token type for candidates.
	 */
	static FAUhdlParser::token_type
	reduceSymbolToToken(std::list<ast::Symbol*> candidates);

	//! report that id could not have been found.
	/** report an error that the identifier id could not get looked up.
	 *  @param id identifier without symbol.
	 *  @param loc corresponding location
	 */
	void reportNameError(
		const char *id, 
		const FAUhdlParser::location_type &loc) const;

	/** name of the current file */
	const std::string* currentFile;

	/** current location of scanner. */
	FAUhdlParser::location_type *currentLoc;
}; /* class declaration */

}; /* namespace yy */

/* include template definition */
#include "ParserDriver.tpp"

#endif /* __PARSER_DRIVER_HPP_INCLUDED */
