/******************************************************************************
 * mod_uploader / TemplateLexer.h
 ******************************************************************************
 * Copyright (C) 2005 Tetsuya Kimata <kimata@acapulco.dyndns.org>
 *
 * All rights reserved.
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any
 * damages arising from the use of this software.
 *
 * Permission is granted to anyone to use this software for any
 * purpose, including commercial applications, and to alter it and
 * redistribute it freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must
 *    not claim that you wrote the original software. If you use this
 *    software in a product, an acknowledgment in the product
 *    documentation would be appreciated but is not required.
 *
 * 2. Altered source versions must be plainly marked as such, and must
 *    not be misrepresented as being the original software.
 *
 * 3. This notice may not be removed or altered from any source
 *    distribution.
 *
 * $Id: TemplateLexer.h 543 2005-08-31 17:25:22Z svn $
 *****************************************************************************/

#ifndef TEMPLATELEXER_H
#define TEMPLATELEXER_H

#include "apr_pools.h"

#include <string>
#include <vector>

#ifdef HAVE_CONFIG_H
#include "mod_uploader_config.h"
#endif

#undef IN // for Visual C++

using namespace std;

/**
 * @brief テンプレートを字句解析するクラス．
 *
 * <pre>
 * STRING           ::= '"' (ALPHABET | DIGIT | ...)* '"'
 * IDENTIFIER       ::= ALPHABET (ALPHABET | DIGIT | '_')+
 * INTEGER          ::= ('+' | '-')? (DIGIT)+
 * ASSIGN_OP        ::= '='
 * COMPARE_OP       ::= '==' | '!=' | '>' | '<'
 * ARITHMETIC_OP	::= '+' | '-'
 * MULTIPLY_OP      ::= '%'
 * MONADIC_OP       ::= '++' | '--'
 * ALPHABET         ::= 'a' | 'b' | ... | 'z' | 'A' | 'B' | ... | 'Z'
 * DIGIT            ::= '0' | '1' | ... | '9'
 * </pre>
 */
class TemplateLexer
{
public:
    enum token_type {
        FOREACH,                // foreach
        WHILE,                  // while
        IF,                     // if
        ELSE,                   // else
        PRINT,                  // print
        IN,                     // in

        STRING,                 // 文字列
        IDENTIFIER,             // 識別子
        INTEGER,                // 整数

        ASSIGNMENT,             // =
        PLUS_ASSIGNMENT,        // +=
        MINUS_ASSIGNMENT,       // -=

        EQUAL,                  // ==
        NOTEQUAL,               // !=
        GREATER_THAN,           // >
        LESS_THAN,              // <

        PLUS,                   // +
        MINUS,                  // -
        RESIDUE,                // %
        PLUSPLUS,               // ++
        MINUSMINUS,             // --

        BRACE_LEFT,             // {
        BRACE_RIGHT,            // }
        PAREN_LEFT,             // (
        PAREN_RIGHT,            // )
        BRACKET_LEFT,           // [
        BRACKET_RIGHT,          // ]

        DOT,                    // .
        COMMA,                  // ,
        DELIMITER,              // ;

        DEFAULT
    };


    typedef struct Token {
        token_type type;
        union {
            int i_val;
            const char *s_val;
        };
    } token;
    typedef vector<token *> token_vector;
    typedef vector<const char *> ident_map;

    TemplateLexer(apr_pool_t *pool, const char* input, apr_size_t length);
    ~TemplateLexer();
    token_vector *get_token_list();
    ident_map *get_ident_map();

#ifdef DEBUG
    static void dump_token(token_vector::const_iterator start,
                           token_vector::const_iterator end);
    static void dump_token(token_vector *tvector);
    static void print_token(token *token, ident_map *imap=NULL);
    static const char *get_token_type(token *token);
#endif

private:
    static const char CODE_BEGIN_STR[];
    static const char CODE_END_STR[];

    static const char FOREACH_STR[];
    static const char WHILE_STR[];
    static const char IF_STR[];
    static const char ELSE_STR[];
    static const char PRINT_STR[];
    static const char IN_STR[];

    static const char ASSIGNMENT_CHAR;
    static const char PLUS_ASSIGNMENT_STR[];
    static const char MINUS_ASSIGNMENT_STR[];

    static const char VARIABLE_CHAR;

    static const char EQUAL_STR[];
    static const char NOTEQUAL_STR[];
    static const char GREATER_THAN_CHAR;
    static const char LESS_THAN_CHAR;

    static const char PLUS_CHAR;
    static const char MINUS_CHAR;
    static const char RESIDUE_CHAR;

    static const char QUOTE_CHAR;
    static const char ESCAPE_CHAR;
    static const char BRACE_LEFT_CHAR;
    static const char BRACE_RIGHT_CHAR;
    static const char PAREN_LEFT_CHAR;
    static const char PAREN_RIGHT_CHAR;
    static const char BRACKET_LEFT_CHAR;
    static const char BRACKET_RIGHT_CHAR;

    static const char DOT_CHAR;
    static const char COMMA_CHAR;
    static const char DELIMITER_CHAR;

    static const apr_size_t TOKEN_POOL_NUM;

    typedef struct Handle {
        const char *input;
        const char *input_start;
        const char *input_end;

        Handle(const char *data, apr_size_t length)
        {
            set_input(data, length);
        }

        void set_input(const char *data, apr_size_t length)
        {
            input = data;
            input_start = data;
            input_end = data + length;
        }
    } handle;

#ifdef DEBUG
    typedef struct {
        token_type type;
        const char *str;
    } token_type_str;

    static token_type_str token_type_list[];
#endif

    apr_pool_t *pool_;
    apr_pool_t *tmp_pool_;

    handle handle_;
    token_vector tvector_;
    ident_map imap_;

    token *token_pool_;
    token *token_pool_end_;

    bool is_done_;

    TemplateLexer(const TemplateLexer&);
    TemplateLexer &operator=(const TemplateLexer&);

    void exec();
    token *get_token(handle *h, bool is_expr_only=false);
    token *read_tmpl_string(handle *h);
    apr_size_t get_imap_id(const char * const start, apr_size_t length);

    token *create_token(token_type type=DEFAULT);
};

#endif

// Local Variables:
// mode: c++
// buffer-file-coding-system: euc-japan-dos
// End:
