/******************************************************************************
 * mod_uploader / TemplateParser.cpp
 ******************************************************************************
 * 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: TemplateParser.cpp 672 2005-09-13 13:27:42Z svn $
 *****************************************************************************/

#include "TemplateParser.h"
#include "Misc.h"

#include "apr_strings.h"

#include <stdlib.h>
#include <ctype.h>

#ifdef DEBUG
#include <iostream>
#include <iomanip>
#endif

#ifdef DEBUG_TemplateParser
#define DUMP_TOKEN TemplateLexer::dump_token(h->token, h->token_end)
#else
#define DUMP_TOKEN
#endif

const apr_size_t TemplateParser::NODE_POOL_NUM   = TPARSER_NODE_POOL_NUM;

#ifdef DEBUG
TemplateParser::node_type_str TemplateParser::node_type_list[] = {
    { TemplateParser::FOREACH,              "foreach"   },
    { TemplateParser::WHILE,                "while"     },
    { TemplateParser::IF,                   "if"        },
    { TemplateParser::PRINT,                "print"     },
    { TemplateParser::ARRAY_REF,            "array ref" },
    { TemplateParser::HASH_REF,             "hash ref"  },
    { TemplateParser::ASSIGNMENT,           "="         },
    { TemplateParser::PLUS_ASSIGNMENT,      "+="        },
    { TemplateParser::MINUS_ASSIGNMENT,     "-="        },
    { TemplateParser::NOTEQUAL,             "!="        },
    { TemplateParser::EQUAL,                "=="        },
    { TemplateParser::GREATER_THAN,         "\\>"       },
    { TemplateParser::LESS_THAN,            "\\<"       },
    { TemplateParser::PLUS,                 "+"         },
    { TemplateParser::MINUS,                "-"         },
    { TemplateParser::RESIDUE,              "%"         },
    { TemplateParser::PLUSPLUS,             "++"        },
    { TemplateParser::MINUSMINUS,           "--"        },
    { TemplateParser::BANK,                 "bank"      },
    { TemplateParser::INTEGER,              "integer"   },
    { TemplateParser::STRING,               "string"    },
    { TemplateParser::IDENTIFIER,           "identifier"},
};
#endif


/******************************************************************************
 * public メソッド
 *****************************************************************************/
TemplateParser::TemplateParser(apr_pool_t *pool)
    : pool_(pool),
      node_pool_(NULL),
      node_pool_end_(NULL)
{

}

TemplateParser::node *TemplateParser::parse(token_vector* tvector,
                                            ident_map *imap) {
    handle h(tvector, imap);

    return parse_program(&h);
}

#ifdef DEBUG
void TemplateParser::print_dot(node *node)
{
    cout << "digraph parse_tree {"              << endl;
    cout << "rankdir    = \"LR\""               << endl;
    cout << "ratio      = auto;"                << endl;
    cout << "node ["                            << endl;
    cout << "    fontname   = \"Helvetica\""    << endl;
    cout << "    fontsize   = \"8\""            << endl;
    cout << "    shape      = \"record\""       << endl;
    cout << "];"                                << endl;

    print_node(node);

    cout << "}"                             << endl;
}

apr_size_t TemplateParser::print_node(node *node)
{
    static apr_size_t id = 1;
    unsigned int branch_id;

    if (node->id == 0) {
        node->id = id++;
    }
    cout << "\"node_" << static_cast<unsigned int>(node->id) <<  "\" [" << endl;
    cout << "    label = \"" << get_node_type(node) << " | <0>left | <1>center | <2>right\"" << endl;
    cout << "];" << endl;

    if (node->branch.left != NULL) {
        branch_id = static_cast<unsigned int>(print_node(node->branch.left));

        cout << "\"node_" << static_cast<unsigned int>(node->id) << "\":0 -> \"node_" << branch_id << "\"" << endl;
    }
    if (node->branch.center != NULL) {
        branch_id = static_cast<unsigned int>(print_node(node->branch.center));

        cout << "\"node_" << static_cast<unsigned int>(node->id) << "\":1 -> \"node_" << branch_id << "\"" << endl;
    }
    if (node->branch.right != NULL) {
        branch_id = static_cast<unsigned int>(print_node(node->branch.right));

        cout << "\"node_" << static_cast<unsigned int>(node->id) << "\":2 -> \"node_" << branch_id << "\"" << endl;
    }

    return node->id;
}

const char *TemplateParser::get_node_type(node * const node)
{    for (apr_size_t i = 0; i < sizeof(node_type_list)/sizeof(node_type_str); i++) {
        if (node->type == node_type_list[i].type) {
            return node_type_list[i].str;
        }
    }

    return NULL;
}
#endif


/******************************************************************************
 * private メソッド
 *****************************************************************************/
/**
 * <pre>
 * PROGRAM    ::= STMT_LIST
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_program(handle *h)
{
    return parse_stmt_list(h);
}

/**
 * <pre>
 * STMT_LIST  ::= STMT*
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_stmt_list(handle *h)
{
    node *curr_node = NULL;
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    left = parse_stmt(h);
    if (left == NULL) {
        return NULL;
    }

    node = create_node(BANK);
    node->branch.left = left;

    curr_node = node;
    while (h->token != h->token_end) {
        left = parse_stmt(h);

        if (left == NULL) {
            break;
        }

        curr_node->branch.right = create_node(BANK);

        curr_node = curr_node->branch.right;
        curr_node->branch.left = left;
    }

    return node;
}

/**
 * <pre>
 * STMT       ::= FOREACH | WHILE | IF | PRINT | EXPR ';'
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_stmt(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    switch ((*(h->token))->type) {
    case TemplateLexer::FOREACH:       // FOREACH
        node = parse_foreach(h);
        break;
    case TemplateLexer::WHILE:         // WHILE
        node = parse_while(h);
        break;
    case TemplateLexer::IF:            // IF
        node = parse_if(h);
        break;
    case TemplateLexer::PRINT:         // PRINT
        node = parse_print(h);
        break;
    default:                           // EXPR ';'
        node = parse_expr(h);

        if (node == NULL) {
            return NULL;
        }
        if ((h->token == h->token_end) ||
            ((*(h->token))->type != TemplateLexer::DELIMITER)) {
            DUMP_TOKEN;
            throw "STMT のパースに失敗しました．(expected DELIMITER)";
        }
        h->token++;
        break;
    }

    return node;
}

/**
 * <pre>
 * FOREACH    ::= 'foreach' '(' VARIABLE 'in' VARIABLE ')' '{' STMT_LIST  '}'
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_foreach(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::FOREACH) {
        return NULL;
    }

    node = create_node((*(h->token))->type);
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_LEFT)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected PAREN_LEFT)";
    }
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::IDENTIFIER)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected IDENTIFIER)";
    }
    node->branch.left = create_node((*(h->token))->type);
    node->branch.left->i_val = (*(h->token))->i_val;
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::IN)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected IN)";
    }
    h->token++;

    node->branch.center = parse_variable(h);
    if (node->branch.center == NULL) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected VARIABLE)";
    }

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_RIGHT)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected PAREN_RIGHT)";
    }
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_LEFT)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected BRACE_LEFT)";
    }
    h->token++;

    node->branch.right = parse_stmt_list(h);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_RIGHT)) {
        DUMP_TOKEN;
        throw "FOREACH のパースに失敗しました．(expected BRACE_RIGHT)";
    }
    h->token++;

    return node;
}

/**
 * <pre>
 * WHILE      ::= 'while' '(' VARIABLE 'in' VARIABLE ')' '{' STMT_LIST  '}'
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_while(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::WHILE) {
        return NULL;
    }

    node = create_node((*(h->token))->type);
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_LEFT)) {
        DUMP_TOKEN;
        throw "WHILE のパースに失敗しました．(expected PAREN_LEFT)";
    }
    h->token++;

    node->branch.left = parse_compare(h);
    if (node->branch.left == NULL) {
        DUMP_TOKEN;
        throw "WHILE のパースに失敗しました．(expected COMPARE)";
    }

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_RIGHT)) {
        DUMP_TOKEN;
        throw "WHILE のパースに失敗しました．(expected PAREN_RIGHT)";
    }
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_LEFT)) {
        DUMP_TOKEN;
        throw "WHILE のパースに失敗しました．(expected BRACE_LEFT)";
    }
    h->token++;

    node->branch.right = parse_stmt_list(h);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_RIGHT)) {
        DUMP_TOKEN;
        throw "WHILE のパースに失敗しました．(expected BRACE_RIGHT)";
    }
    h->token++;

    return node;
}

/**
 * <pre>
 * IF         ::= 'if' '(' COMPARE ')' '{' STMT_LIST '}' ELSE_
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_if(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::IF) {
        return NULL;
    }
    node = create_node((*(h->token))->type);
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_LEFT)) {
        DUMP_TOKEN;
        throw "IF のパースに失敗しました．(expected PAREN_LEFT)";
    }
    h->token++;

    node->branch.center = parse_compare(h);
    if (node->branch.center == NULL) {
        DUMP_TOKEN;
        throw "IF のパースに失敗しました．(expected COMPARE)";
    }

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::PAREN_RIGHT)) {
        DUMP_TOKEN;
        throw "IF のパースに失敗しました．(expected PAREN_RIGHT)";
    }
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_LEFT)) {
        DUMP_TOKEN;
        throw "IF のパースに失敗しました．(expected BRACE_LEFT)";
    }
    h->token++;

    node->branch.left = parse_stmt_list(h);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_RIGHT)) {
        DUMP_TOKEN;
        throw "IF のパースに失敗しました．(expected BRACE_RIGHT)";
    }
    h->token++;

    node->branch.right = parse_else_(h);

    return node;
}

/**
 * <pre>
 * ELSE_      ::= 'else' '{' STMT_LIST '}' | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_else_(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::ELSE) { // ε
        return NULL;
    }
    h->token++;

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_LEFT)) {
        DUMP_TOKEN;
        throw "ELSE_ のパースに失敗しました．(expected BRACE_LEFT)";
    }
    h->token++;

    node = parse_stmt_list(h);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::BRACE_RIGHT)) {
        DUMP_TOKEN;
        throw "ELSE_ のパースに失敗しました．(expected BRACE_RIGHT)";
    }
    h->token++;

    return node;
}

/**
 * <pre>
 * PRINT      ;;= 'print' EXPR_LIST ';'
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_print(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::PRINT) {
        return NULL;
    }
    node = create_node((*(h->token))->type);
    h->token++;

    node->branch.left = parse_expr_list(h);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::DELIMITER)) {
        DUMP_TOKEN;
        throw "PRINT のパースに失敗しました．(expected DELIMITER)";
    }
    h->token++;

    return node;
}

/**
 * <pre>
 * EXPR_LIST  ::= EXPR (',' EXPR)*
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_expr_list(handle *h)
{
    node *curr_node = NULL;
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    left = parse_expr(h);
    if (left == NULL) {
        return NULL;
    }

    node = create_node(BANK);
    node->branch.left = left;

    curr_node = node;
    while (h->token != h->token_end) {
        if ((*(h->token))->type == TemplateLexer::COMMA) {
            h->token++;

            curr_node->branch.right = create_node(BANK);

            curr_node = curr_node->branch.right;
            curr_node->branch.left = parse_expr(h);

            if (curr_node->branch.left == NULL) {
                DUMP_TOKEN;
                throw "EXPR_LIST のパースに失敗しました．(expected EXPR)";
            }
        } else {
            break;
        }
    }

    return node;
}

/**
 * <pre>
 * EXPR       ::= ASSIGN | COMPARE
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_expr(handle *h)
{
    if (h->token == h->token_end) {
        return NULL;
    }

    if (((*(h->token))->type == TemplateLexer::IDENTIFIER) &&
        ((h->token+1) != h->token_end) &&
        (((*(h->token+1))->type == TemplateLexer::ASSIGNMENT) ||
         ((*(h->token+1))->type == TemplateLexer::PLUS_ASSIGNMENT) ||
         ((*(h->token+1))->type == TemplateLexer::MINUS_ASSIGNMENT))) { // ASSIGNMENT
        return parse_assign(h);
    } else {                           // COMPARE
        return parse_compare(h);
    }
}

/**
 * <pre>
 * ASSIGN     ::= IDENTIFIER ASSIGN_OP COMPARE
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_assign(handle *h)
{
    node *left = NULL;
    node *right = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::IDENTIFIER) {
        DUMP_TOKEN;
        throw "ASSIGN のパースに失敗しました．(expected VARIABLE)";
    }
    left = create_node((*(h->token))->type);
    left->i_val = (*(h->token))->i_val;
    h->token++;

    if (((*(h->token))->type != TemplateLexer::ASSIGNMENT) &&
        ((*(h->token))->type != TemplateLexer::PLUS_ASSIGNMENT) &&
        ((*(h->token))->type != TemplateLexer::MINUS_ASSIGNMENT)) {
        DUMP_TOKEN;
        throw "ASSIGN のパースに失敗しました．(expected ASSIGN_OP)";
    }

    node = create_node((*(h->token))->type);
    h->token++;

    right = parse_compare(h);
    if (right == NULL) {
        DUMP_TOKEN;
        throw "ASSIGN のパースに失敗しました．(expected COMPARE)";
    }

    node->branch.left = left;
    node->branch.right = right;

    return node;
}

/**
 * <pre>
 * COMPARE    ::= ARITHMETIC COMPARE_
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_compare(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    left = parse_arithmetic(h);
    if (left == NULL) {
        return NULL;
    }

    node = parse_compare_(h);
    if (node == NULL) {
        node = left;
    } else {
        node->branch.left = left;
    }

    return node;
}

/**
 * <pre>
 * COMPARE_   ::= COMPARE_OP ARITHMETIC | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_compare_(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if (((*(h->token))->type != TemplateLexer::EQUAL) &&
        ((*(h->token))->type != TemplateLexer::NOTEQUAL) &&
        ((*(h->token))->type != TemplateLexer::GREATER_THAN) &&
        ((*(h->token))->type != TemplateLexer::LESS_THAN)) { // ε
        return NULL;
    }

    node = create_node((*(h->token))->type);
    h->token++;

    node->branch.right = parse_arithmetic(h);
    if (node->branch.right == NULL) {
        DUMP_TOKEN;
        throw "COMPARE_ のパースに失敗しました．(expected ARITHMETIC)";
    }

    return node;
}

/**
 * <pre>
 * ARITHMETIC ::= MULTIPLY ARITHMETIC_
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_arithmetic(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    left = parse_multiply(h);
    if (left == NULL) {
        return NULL;
    }

    node = parse_arithmetic_(h);
    if (node == NULL) {
        node = left;
    } else {
        node->branch.left = left;
    }

    return node;
}

/**
 * <pre>
 * ARITHMETIC_::= '+' MULTIPLY ARITHMETIC_ | '-' MULTIPLY ARITHMETIC_ | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_arithmetic_(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    switch ((*(h->token))->type) {
    case TemplateLexer::PLUS:          // '+' MULTIPLY ARITHMETIC_
    case TemplateLexer::MINUS:         // '-' MULTIPLY ARITHMETIC_
        left = create_node((*(h->token))->type);
        h->token++;

        left->branch.right = parse_multiply(h);
        if (left->branch.right == NULL) {
            DUMP_TOKEN;
            throw "ARITHMETIC_ のパースに失敗しました．(expected MULTIPLY)";
        }

        node = parse_arithmetic_(h);
        if (node == NULL) {
            node = left;
        } else {
            node->branch.left = left;
        }
        break;
    default:                           // ε
        break;
    }

    return node;
}

/**
 * <pre>
 * MULTIPLY   ::= TERM MULTIPLY_
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_multiply(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    left = parse_term(h);
    if (left == NULL) {
        return NULL;
    }

    node = parse_multiply_(h);
    if (node == NULL) {
        node = left;
    } else {
        node->branch.left = left;
    }

    return node;
}

/**
 * <pre>
 * MULTIPLY_  ::= '%' TERM MULTIPLY_ | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_multiply_(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    switch ((*(h->token))->type) {
    case TemplateLexer::RESIDUE:       // '%' TERM MULTIPLY_
        left = create_node((*(h->token))->type);
        h->token++;

        left->branch.right = parse_term(h);
        if (left->branch.right == NULL) {
            DUMP_TOKEN;
            throw "MULTIPLY_ のパースに失敗しました．(expected TERM)";
        }

        node = parse_multiply_(h);
        if (node == NULL) {
            node = left;
        } else {
            node->branch.left = left;
        }
        break;
    default:                           // ε
        break;
    }

    return node;
}

/**
 * <pre>
 * TERM       ::= MONADIC_OP VARIABLE | VARIABLE MONADIC_OP |
 *                VARIABLE | INTEGER | STRING | '(' EXPR ')'
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_term(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    switch ((*(h->token))->type) {
    case TemplateLexer::PLUSPLUS:
    case TemplateLexer::MINUSMINUS:     // MONADIC_OP VARIABLE
        node = create_node((*(h->token))->type);
        h->token++;

        node->branch.right = parse_variable(h);
        if (node->branch.right == NULL) {
            DUMP_TOKEN;
            throw "TERM のパースに失敗しました．(expected VARIABLE)";
        }

        break;
    case TemplateLexer::IDENTIFIER:     // VARIABLE | VARIABLE MONADIC_OP
        node = parse_variable(h);
        if ((h->token != h->token_end) &&
            (((*(h->token))->type == TemplateLexer::PLUSPLUS) ||
             ((*(h->token))->type == TemplateLexer::MINUSMINUS))) {
            left = node;
            node = create_node((*(h->token))->type);
            node->branch.left = left;
            h->token++;
        }
        break;
    case TemplateLexer::INTEGER:        // INTEGER
        node = create_node((*(h->token))->type);
        node->i_val = (*(h->token))->i_val;
        h->token++;
        break;
    case TemplateLexer::STRING:         // STRING
        node = create_node((*(h->token))->type);
        node->s_val = (*(h->token))->s_val;
        h->token++;
        break;
    case TemplateLexer::PAREN_LEFT:     // '(' EXPR ')'
        h->token++;
        node = parse_expr(h);

        if ((node == NULL) ||
            (h->token == h->token_end) ||
            ((*(h->token))->type != TemplateLexer::PAREN_RIGHT)) {
            DUMP_TOKEN;
            throw "TERM のパースに失敗しました．(expected EXPR PAREN_RIGHT)";
        }
        h->token++;
        break;
    default:
        break;
    }

    return node;
}

/**
 * <pre>
 * VARIABLE   ::= IDENTIFIER VARIABLE_
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_variable(handle *h)
{
    node *left = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::IDENTIFIER) {
        return NULL;
    }

    left = create_node((*(h->token))->type);
    left->i_val = (*(h->token))->i_val;
    h->token++;

    node = parse_variable_(h);

    if (node == NULL) {
        node = left;
    } else {
        node->branch.left = left;
    }

    return node;
}

/**
 * <pre>
 * VARIABLE_  ::= '.' IDENTIFIER | '[' (INTEGER | IDENTIFIER) ']' VARIABLE__ | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_variable_(handle *h)
{
    node *right = NULL;
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type == TemplateLexer::DOT) { // '.' IDENTIFIER
        h->token++;
        node = create_node(HASH_REF);

        if ((h->token == h->token_end) ||
            ((*(h->token))->type != TemplateLexer::IDENTIFIER)) {
            DUMP_TOKEN;
            throw "VARIABLE_ のパースに失敗しました．(expected IDENTIFIER)";
        }
        node->branch.right = create_node((*(h->token))->type);
        node->branch.right->i_val = (*(h->token))->i_val;
        h->token++;
    } else if ((*(h->token))->type == TemplateLexer::BRACKET_LEFT) { // '[' (INTEGER | IDENTIFIER) ']' VARIABLE__
        h->token++;
        node = create_node(ARRAY_REF);

        if ((h->token != h->token_end) &&
            ((*(h->token))->type == TemplateLexer::INTEGER)) {
            right = create_node((*(h->token))->type);
            right->i_val = (*(h->token))->i_val;
            h->token++;
        } else if ((h->token != h->token_end) &&
            ((*(h->token))->type == TemplateLexer::IDENTIFIER)) {
            right = create_node((*(h->token))->type);
            right->i_val = (*(h->token))->i_val;
            h->token++;
        } else {
            DUMP_TOKEN;
            throw "VARIABLE_ のパースに失敗しました．(expected IDENTIFIER | IDENTIFIER)";
        }

        if ((h->token == h->token_end) ||
            ((*(h->token))->type != TemplateLexer::BRACKET_RIGHT)) {
            DUMP_TOKEN;
            throw "VARIABLE_ のパースに失敗しました．(expected BRACKET_RIGHT)";
        }
        h->token++;

        node->branch.right = parse_variable__(h);
        if (node->branch.right == NULL) {
            node->branch.right = right;
        } else {
            node->branch.right->branch.left = right;
        }
    }

    return node;
}

/**
 * <pre>
 * VARIABLE__ ::= '.' IDENTIFIER | ε
 * </pre>
 */
TemplateParser::node *TemplateParser::parse_variable__(handle *h)
{
    node *node = NULL;

    if (h->token == h->token_end) {
        return NULL;
    }

    if ((*(h->token))->type != TemplateLexer::DOT) { // ε
        return NULL;
    }

    h->token++;
    node = create_node(HASH_REF);

    if ((h->token == h->token_end) ||
        ((*(h->token))->type != TemplateLexer::IDENTIFIER)) {
        DUMP_TOKEN;
        throw "VARIABLE__ のパースに失敗しました．(expected IDENTIFIER)";
    }

    node->branch.right = create_node(STRING); // 識別子から文字列に戻す
    node->branch.right->s_val = h->imap->at((*(h->token))->i_val);
    h->token++;

    return node;
}

TemplateParser::node *TemplateParser::create_node(node_type type)
{
    if (node_pool_ == node_pool_end_) {
        APR_PCALLOC(node_pool_, node *, pool_, sizeof(node)*NODE_POOL_NUM);

        node_pool_end_ = node_pool_ + NODE_POOL_NUM;
    }

    node *node = node_pool_++;

    node->type = type;
#ifdef DEBUG_TemplateParser
    node->id = 0;
#endif

    return node;
}

TemplateParser::node *TemplateParser::create_node(TemplateLexer::token_type type)
{
    node_type ntype;

    // びみょー．こんなことしなくていい気もするけど，両者の間で意味合い
    // がちょっと違うし，どうしたものか．
    switch (type) {
    case TemplateLexer::FOREACH            : ntype = FOREACH;           break;
    case TemplateLexer::WHILE              : ntype = WHILE;             break;
    case TemplateLexer::IF                 : ntype = IF;                break;
    case TemplateLexer::PRINT              : ntype = PRINT;             break;
    case TemplateLexer::STRING             : ntype = STRING;            break;
    case TemplateLexer::IDENTIFIER         : ntype = IDENTIFIER;        break;
    case TemplateLexer::INTEGER            : ntype = INTEGER;           break;
    case TemplateLexer::ASSIGNMENT         : ntype = ASSIGNMENT;        break;
    case TemplateLexer::PLUS_ASSIGNMENT    : ntype = PLUS_ASSIGNMENT;   break;
    case TemplateLexer::MINUS_ASSIGNMENT   : ntype = MINUS_ASSIGNMENT;  break;
    case TemplateLexer::EQUAL              : ntype = EQUAL;             break;
    case TemplateLexer::NOTEQUAL           : ntype = NOTEQUAL;          break;
    case TemplateLexer::GREATER_THAN       : ntype = GREATER_THAN;      break;
    case TemplateLexer::LESS_THAN          : ntype = LESS_THAN;         break;
    case TemplateLexer::PLUS               : ntype = PLUS;              break;
    case TemplateLexer::MINUS              : ntype = MINUS;             break;
    case TemplateLexer::RESIDUE            : ntype = RESIDUE;           break;
    case TemplateLexer::PLUSPLUS           : ntype = PLUSPLUS;          break;
    case TemplateLexer::MINUSMINUS         : ntype = MINUSMINUS;        break;
    default                                : ntype = DEFAULT;           break;
    }

    return create_node(ntype);
}


/******************************************************************************
 * テスト
 *****************************************************************************/
#ifdef DEBUG_TemplateParser
#include "apr_general.h"
#include "apr_file_io.h"
#include "apr_mmap.h"

void usage(const char *prog_name)
{
    cerr << "Usage: " << prog_name << " <INPUT>" << endl;
}

int main(int argc, const char * const *argv)
{
    apr_pool_t *pool;
    apr_file_t *fd;
    apr_mmap_t *file_map;
    apr_finfo_t info;
    TemplateParser::node *node;

    apr_app_initialize(&argc, &argv, NULL);
    apr_pool_create(&pool, NULL);

    try {
        if (argc != 2) {
            throw "入力用のファイルが指定されていません．";
        }

        if (apr_file_open(&fd, argv[1], APR_READ,
                          APR_OS_DEFAULT, pool) != APR_SUCCESS) {
            throw "ファイルの open に失敗しました．";
        }

        if (apr_file_info_get(&info, APR_FINFO_SIZE, fd) != APR_SUCCESS) {
            throw "ファイルサイズを取得できませんでした．";
        }

        if (apr_mmap_create(&file_map, fd, 0,
                            static_cast<apr_size_t>(info.size), APR_MMAP_READ,
                            pool) != APR_SUCCESS) {
            throw "ファイルの mmap に失敗しました．";
        }

        TemplateLexer lexer(pool,
                            static_cast<const char *>(file_map->mm),
                            static_cast<apr_size_t>(info.size));
        TemplateParser parser(pool);
        node = parser.parse(lexer.get_token_list(), lexer.get_ident_map());
        TemplateParser::print_dot(node);

        if (apr_mmap_delete(file_map) != APR_SUCCESS) {
            throw "ファイルの munmap に失敗しました．";
        }

        if (apr_file_close(fd) != APR_SUCCESS) {
            throw "ファイルの close に失敗しました．";
        }
    } catch(const char *message) {
        cerr << "Error: " << message << endl;
        usage(argv[0]);

        return EXIT_FAILURE;
    }

    apr_terminate();

    return EXIT_SUCCESS;

}
#endif

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