/*************************************************************************
 * Copyright (C) 2018-2022 Blue Brain Project
 *
 * This file is part of NMODL distributed under the terms of the GNU
 * Lesser General Public License. See top-level LICENSE file for details.
 *************************************************************************/

#pragma once

#include "parser/c/c11_parser.hpp"

/**
 * Flex expects the declaration of yylex to be defined in the macro YY_DECL
 * and C++ parser class expects it to be declared.
 */
#ifndef YY_DECL
#define YY_DECL nmodl::parser::CParser::symbol_type nmodl::parser::CLexer::next_token()
#endif

/**
 * For creating multiple (different) lexer classes, we can use `-P` flag
 * (or prefix option) to rename each `NmodlFlexLexer` to some other name like
 * `xxFlexLexer`. And then include <FlexLexer.h> in other sources once per
 * lexer class, first renaming `yyFlexLexer` as shown below.
 */
#ifndef __FLEX_LEXER_H
#define yyFlexLexer CFlexLexer
#include "FlexLexer.h"
#endif

namespace nmodl {
namespace parser {

/**
 * @addtogroup lexer
 * @{
 */

/**
 * \class CLexer
 * \brief Represent Lexer/Scanner class for C (11) language parsing
 *
 * Lexer defined to add some extra function to the scanner class from flex.
 * Flex itself creates yyFlexLexer class, which we renamed using macros to
 * NmodlFlexLexer. But we change the context of the generated yylex() function
 * because the yylex() defined in NmodlFlexLexer has no parameters. Also, note
 * that implementation of the member functions are in nmodl.l file due to use
 * of macros.
 */
class CLexer: public CFlexLexer {
  public:
    /** Reference to driver object which contains this lexer instance. This is
     * used for error reporting and checking macro definitions. */

    /**
     * \brief Reference to driver object where this lexer resides
     *
     * The driver object can be used from lexer to store/retrieve some
     * global information. Currently this is used for storing all token
     * encountered during lexing.
     */
    CDriver& driver;

    /// location of the parsed token
    location loc;

    /// \name Ctor & dtor
    /// \{

    /**
     * \brief CLexer constructor
     *
     * @param driver CDriver where this lexer resides
     * @param in Input stream from where tokens will be read
     * @param out Output stream where output will be sent
     */
    explicit CLexer(CDriver& driver, std::istream* in = nullptr, std::ostream* out = nullptr)
        : CFlexLexer(in, out)
        , driver(driver) {}

    ~CLexer() override = default;

    /// \}

    /**
     * \brief Function for lexer to scan token (replacement for \c yylex())
     *
     * This is main lexing function generated by `flex` according to the macro
     * declaration \c YY_DECL. The generated bison parser then calls this virtual
     * function to fetch new tokens. Note that \c yylex() has different declaration
     * and hence can't be used for new lexer.
     *
     * @return Symbol encapsulating parsed token
     */
    virtual CParser::symbol_type next_token();

    /**
     * \brief Get the type of token just parsed
     *
     * Check if parsed token is either \c enum, \c typedef or \c identifier.
     *
     * \attention Not needed anymore and could be removed?
     *
     * @return Symbol encapsulating parsed token
     */
    CParser::symbol_type get_token_type();
};

/** @} */  // end of lexer

}  // namespace parser
}  // namespace nmodl
