/*
 *	parser.c
 *
 *	JoyToyインタプリタ
 *
 *	* Sun Jan 01 00:00:00 JST 2006 Naoyuki Sawa
 *	- 作成開始。
 *	* Tue Jan 31 00:00:00 JST 2006 Naoyuki Sawa
 *	- 1st リリース。
 *	* Sat Jun 17 05:26:02 JST 2006 Naoyuki Sawa
 *	- FIELD_OFFSET()→offsetof()に変更。
 */
#include "app.h"

/*****************************************************************************
 *	PARSER
 *****************************************************************************/

typedef struct _PARSER {
	int refcnt;
	PARSER_INTERFACE* parser_interface;
	//
	LEXER_INTERFACE** lexer;	/* Lexer(字句解析器) */
} PARSER;

IMPLEMENT_PARSER_INTERFACE(PARSER, parser)

const INTERFACE_MAP parser_interface_map[] = {
	{ PARSER_INTERFACE_ID, offsetof(PARSER, parser_interface), &parser_interface },
	{ 0/*終端*/ },
};

PARSER_INTERFACE**
parser_create(LEXER_INTERFACE** lexer)
{
	PARSER* this = calloc(1, sizeof(PARSER));
	if(!this) {
		DIE(); /* メモリ不足 */
	}
	this->refcnt = 1;
	apply_interface_map(this, parser_interface_map);

	/* Lexerを格納します。 */
	safe_assign(this->lexer, lexer);

	return &this->parser_interface;
}

static void
parser_delete(PARSER* this)
{
	/* Lexerを解放します。 */
	safe_release(this->lexer);

	free(this);
}

/*****************************************************************************
 *	PARSER_INTERFACE
 *****************************************************************************/

/* プログラムの構成要素を読み込むサブルーチン */
static JTCODE_INTERFACE** parser_program(PARSER* this);			/* プログラム */
static JTCODE_INTERFACE** parser_stmt(PARSER* this);			/* 文 */
static JTCODE_INTERFACE** parser_expr(PARSER* this);			/* 式 */
static JTCODE_INTERFACE** parser_simple_expr(PARSER* this);		/* 単純式 */
static JTCODE_INTERFACE** parser_term(PARSER* this);			/* 項 */
static JTCODE_INTERFACE** parser_factor(PARSER* this);			/* 因子 */

/* 上記のサブルーチンから利用するサブルーチン */
static JTCODE_INTERFACE** parser_var(PARSER* this);			/* 変数定義 */
static JTCODE_INTERFACE** parser_fun(PARSER* this, int method);		/* 関数定義 */
static JTCODE_INTERFACE** parser_block(PARSER* this);			/* ブロック */
static JTCODE_INTERFACE** parser_object(PARSER* this);			/* オブジェクト定義 */
static JTCODE_INTERFACE** parser_new(PARSER* this);			/* オブジェクト複製式 */
static LIST/*<JTCODE_INTERFACE**>*/ * parser_args(PARSER* this);	/* 実引数リスト ("argument"は、"実引数"という意味です) */
static LIST/*<JTSYMBOL_INTERFACE**>*/ * parser_params(PARSER* this);	/* 仮引数リスト ("parameter"は、"仮引数"という意味です) */

/*---------------------------------------------------------------------------*/

static JTCODE_INTERFACE**
parser_parse(PARSER_INTERFACE** intf)
{
	PARSER* this = CONTAINING_RECORD(intf, PARSER, parser_interface);
	return parser_program(this);
}

static JTCODE_INTERFACE**
parser_program(PARSER* this)
{
	return parser_stmt(this);
}

static JTCODE_INTERFACE**
parser_stmt(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code1 = NULL;
	JTCODE_INTERFACE** code2 = NULL;
	JTCODE_INTERFACE** code3 = NULL;
	//
	int type;

	/* トークンがあれば... */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(token) {

		/* トークンのタイプによって... */
		type = (*token)->get_type(token);
		switch(type) {
		case TOKEN_TYPE_IF:
			/* 最初のトークンが'if'ならば、"if (式) 文 [ else 文 ]"を読み込みます。
			 * 最初のトークン'if'は、もう不要なので、なにもせずに、破棄します。
			 */

			/* '('を読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != '(')) {
				DIE(); /* 'if'の後に'('が無い */
			}

			/* 条件式を読み込みます。 */
			safe_attach(code1, parser_expr(this));
			if(!code1) {
				DIE(); /* 'if' '(' の後に式が無い */
			}

			/* ')'を読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != ')')) {
				DIE(); /* 'if' '(' 式 の後に')'が無い */
			}

			/* 条件式が真のときに実行する文を読み込みます。 */
			safe_attach(code2, parser_stmt(this));
			if(!code2) {
				DIE(); /* 'if' '(' 式 ')' の後に文が無い */
			}

			/* 次のトークンが'else'ならば... */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(token) {
				if((*token)->get_type(token) == TOKEN_TYPE_ELSE) {
					/* 条件式が偽のときに実行する文を読み込みます。 */
					safe_attach(code3, parser_stmt(this));
					if(!code3) {
						DIE(); /* 'if' '(' 式 ')' 'else' の後に文が無い */
					}
				} else {
					/* 'else'以外ならば、トークンを戻します。 */
					(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
				}
			}

			/* "文 <- if ( 式 ) 文 [ else 文 ]" とします。 */
			safe_attach(code1, jtif_create(code1, code2, code3));

			break;

		case TOKEN_TYPE_WHILE:
			/* 最初のトークンが'while'ならば、"while (式) 文"を読み込みます。
			 * 最初のトークン'while'は、もう不要なので、なにもせずに、破棄します。
			 */

			/* '('を読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != '(')) {
				DIE(); /* 'while'の後に'('が無い */
			}

			/* 条件式を読み込みます。 */
			safe_attach(code1, parser_expr(this));
			if(!code1) {
				DIE(); /* 'while' '(' の後に式が無い */
			}

			/* ')'を読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != ')')) {
				DIE(); /* 'while' '(' 式 の後に')'が無い */
			}

			/* 条件式が真の間、実行し続ける文を読み込みます。 */
			safe_attach(code2, parser_stmt(this));
			if(!code2) {
				DIE(); /* 'while' '(' 式 ')' の後に文が無い */
			}

			/* "文 <- while ( 式 ) 文" とします。 */
			safe_attach(code1, jtwhile_create(code1, code2));

			break;

		case TOKEN_TYPE_FUN:
			/* 最初のトークンが'fun'ならば、"fun シンボル ( シンボル, ... ) ブロック"を読み込みます。 */

			/* いったん、'fun'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* 関数定義を読み込みます。 */
			safe_attach(code1, parser_fun(this, 0/*通常の関数*/));

			break;

		case '{':
			/* 最初のトークンが'{'ならば、"{ 文 ... }"を読み込みます。 */

			/* いったん、'{'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* ブロックを読み込みます。 */
			safe_attach(code1, parser_block(this));

			break;

		default:
			/* 最初のトークンが上記以外ならば、式を読み込みます。 */

			/* 最初のトークンは、式の一部なので、まず、戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* "文 <- 式" とします。 */
			safe_attach(code1, parser_expr(this));

			/* ひとつの式から成る文は、';'で終端していることを確認し、読み飛ばします。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != ';')) {
				DIE(); /* 予期しないファイル終端、または、';'が無い */
			}

			break;
		}
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code2);
	safe_release(code3);

	return code1;
}

static JTCODE_INTERFACE**
parser_expr(PARSER* this)
{
	int type;
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code1 = NULL;
	JTCODE_INTERFACE** code2 = NULL;

	/* 単純式があれば... */
	safe_attach(code1, parser_simple_expr(this));
	if(code1) {
		for(;;) {
			/* 次のトークンを読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token) {
				DIE(); /* 予期しないファイル終端 */
			}

			/* 次のトークンがこれらの演算子ならば... */
			type = (*token)->get_type(token);
			if((type == '<') ||
			   (type == '>') ||
			   (type == TOKEN_TYPE_EQ) ||
			   (type == TOKEN_TYPE_NE) ||
			   (type == TOKEN_TYPE_LE) ||
			   (type == TOKEN_TYPE_GE)) {

				/* 次の単純式を読み込みます。 */
				safe_attach(code2, parser_simple_expr(this));
				if(!code2) {
					DIE(); /* 単純式が無い */
				}

				/* "式 <- 単純式 演算子 単純式" とします。 */
				safe_attach(code1, jtbinexpr_create(type, code1, code2));

			/* 次のトークンがこれらの演算子でなければ... */
			} else {

				/* 次のトークンを戻して抜けます。 */
				(*this->lexer)->unget_token(this->lexer, token);
				break;
			}
		}
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code2);

	return code1;
}

static JTCODE_INTERFACE**
parser_simple_expr(PARSER* this)
{
	int type;
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code1 = NULL;
	JTCODE_INTERFACE** code2 = NULL;

	/* 項があれば... */
	safe_attach(code1, parser_term(this));
	if(code1) {
		for(;;) {
			/* 次のトークンを読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token) {
				DIE(); /* 予期しないファイル終端 */
			}

			/* 次のトークンがこれらの演算子ならば... */
			type = (*token)->get_type(token);
			if((type == '+') ||
			   (type == '-') ||
			   (type == TOKEN_TYPE_OR)) {

				/* 次の項を読み込みます。 */
				safe_attach(code2, parser_term(this));
				if(!code2) {
					DIE(); /* 項が無い */
				}

				/* "式 <- 項 演算子 項" とします。 */
				safe_attach(code1, jtbinexpr_create(type, code1, code2));

			/* 次のトークンがこれらの演算子でなければ... */
			} else {

				/* 次のトークンを戻して抜けます。 */
				(*this->lexer)->unget_token(this->lexer, token);
				break;
			}
		}
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code2);

	return code1;
}

static JTCODE_INTERFACE**
parser_term(PARSER* this)
{
	int type;
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code1 = NULL;
	JTCODE_INTERFACE** code2 = NULL;

	/* 因子があれば... */
	safe_attach(code1, parser_factor(this));
	if(code1) {
		for(;;) {
			/* 次のトークンを読み込みます。 */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token) {
				DIE(); /* 予期しないファイル終端 */
			}

			/* 次のトークンがこれらの演算子ならば... */
			type = (*token)->get_type(token);
			if((type == '*') ||
			   (type == '/') ||
			   (type == TOKEN_TYPE_AND)) {

				/* 次の因子を読み込みます。 */
				safe_attach(code2, parser_factor(this));
				if(!code2) {
					DIE(); /* 因子が無い */
				}

				/* "式 <- 因子 演算子 因子" とします。 */
				safe_attach(code1, jtbinexpr_create(type, code1, code2));

			/* 次のトークンがこれらの演算子でなければ... */
			} else {

				/* 次のトークンを戻して抜けます。 */
				(*this->lexer)->unget_token(this->lexer, token);
				break;
			}
		}
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code2);

	return code1;
}

static JTCODE_INTERFACE**
parser_factor(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code1 = NULL;
	JTCODE_INTERFACE** code2 = NULL;
	JTSYMBOL_INTERFACE** symbol = NULL;
	//
	int type;
	LIST/*<JTCODE_INTERFACE**>*/ * args_list;

	/* トークンがあれば... */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(token) {

		/* タイプ、値を取得します。 */
		type = (*token)->get_type(token);
		safe_attach(code1, (*token)->get_code(token));

		/* トークンのタイプによって... */
		switch(type) {
		case TOKEN_TYPE_INT:
			/** no job **/
			goto L_EXIT;

		case TOKEN_TYPE_STRING:
			/** no job **/
			goto L_EXIT;

		case TOKEN_TYPE_SYMBOL:
			safe_assign_interface(symbol, code1, JTSYMBOL_INTERFACE);
			if(!symbol) {
				DIE(); /* 有り得ない */
			}
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(token) {
				type = (*token)->get_type(token);
				switch(type) {
				case '=':
					/* シンボル '=' 式 */
					safe_attach(code2, parser_expr(this));
					if(!code2) {
						DIE(); /* シンボル '=' の後に式が無い */
					}
					safe_attach(code1, jtbinexpr_create(type, code1, code2));
					break;

				case '(':
					/* シンボル '(' 実引数リスト ')' */

					/* いったん、'('を戻します。 */
					(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

					/* 実引数リストを読み込みます。 */
					args_list = parser_args(this);

					/* 関数呼び出しを作成します。 */
					safe_attach(code1, jtfuncall_create(symbol, args_list));

					/* 実引数リストを削除します。 */
					list_delete(args_list);

					break;

				default:
					/* シンボル */
					(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
					break;
				}
			}
			goto L_EXIT;

		case TOKEN_TYPE_TRUE:
			safe_attach(code1, jtbool_create(1));
			goto L_EXIT;

		case TOKEN_TYPE_FALSE:
			safe_attach(code1, jtbool_create(0));
			goto L_EXIT;

		case TOKEN_TYPE_VAR:
			/* 最初のトークンが'var'ならば、"var シンボル"、または、"var シンボル = 式"を読み込みます。 */

			/* いったん、'var'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* 変数定義を読み込みます。 */
			safe_attach(code1, parser_var(this));

			goto L_EXIT;

		case TOKEN_TYPE_OBJECT:
			/* 最初のトークンが'object'ならば、"object { スロット並び }"を読み込みます。 */

			/* いったん、'object'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* オブジェクト定義を読み込みます。 */
			safe_attach(code1, parser_object(this));

			goto L_EXIT;

		case TOKEN_TYPE_NEW:
			/* 最初のトークンが"new"ならば、"new シンボル"、または、"new シンボル { 初期化ブロック }"を読み込みます。 */

			/* いったん、'new'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

			/* オブジェクト複製式を読み込みます。 */
			safe_attach(code1, parser_new(this));

			goto L_EXIT;

		case '-':
		case '!':
			safe_attach(code1, parser_factor(this));
			if(!code1) {
				DIE(); /* '-'、'!'の後に因子が無い */
			}
			safe_attach(code1, jtunexpr_create(type, code1));
			goto L_EXIT;

		case '(':
			safe_attach(code1, parser_expr(this));
			if(!code1) {
				DIE(); /* '('の後に式が無い */
			}
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			type = (*token)->get_type(token);
			if(type != ')') {
				DIE(); /* '(' 式 の後に')'が無い */
			}
			goto L_EXIT;

		default:
			DIE(); /* 不明なトークン */
		}
L_EXIT:
		/*{{メッセージ式の処理*/
		for(;;) {

			/* 因子の後に'.'が有ったら... */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token) {
				break;
			}
			if((*token)->get_type(token) != '.') {
				(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
				break;
			}

			/* 因子 '.' シンボル */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != TOKEN_TYPE_SYMBOL)) {
				DIE(); /* 因子 '.' の後にシンボルが無い */
			}
			safe_attach(code2, (*token)->get_code(token));
			safe_assign_interface(symbol, code2, JTSYMBOL_INTERFACE);
			if(!symbol) {
				DIE(); /* 有り得ない */
			}

			/* 因子 '.' シンボル の後に、'('、または、'='が有ったら... */
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(token && ((*token)->get_type(token) == '(')) {
				/* "因子 <- 因子.シンボル(実引数リスト)" とします。 */
				(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
				args_list = parser_args(this);
				safe_attach(code1, jtdotcall_create(code1, symbol, args_list));
				list_delete(args_list);
			} else if(token && ((*token)->get_type(token) == '=')) {
				/* "因子 <- 因子.シンボル = 式" とします。 */
				safe_attach(code2, parser_expr(this));
				if(!code2) {
					DIE(); /* 因子 '.' シンボル '=' の後に式が無い */
				}
				safe_attach(code1, jtdotassign_create(code1, symbol, code2));
			} else {
				/* "因子 <- 因子.シンボル" とします。 */
				if(token) {
					(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
				}
				safe_attach(code1, jtdotexpr_create(code1, symbol));
			}
		}
		/*}}メッセージ式の処理*/
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code2);
	safe_release(symbol);

	return code1;
}

static JTCODE_INTERFACE**
parser_var(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	JTSYMBOL_INTERFACE** symbol = NULL;

	/* 最初のトークンが'var'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_VAR)) {
		DIE(); /* 予期しないファイル終端、または、'var'が無い */
	}

	/* 変数名を表すシンボルを読み込みます。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_SYMBOL)) {
		DIE(); /* 'var'の後にシンボルが無い */
	}
	safe_attach(code, (*token)->get_code(token));
	safe_assign_interface(symbol, code, JTSYMBOL_INTERFACE);
	if(!symbol) {
		DIE(); /* 有り得ない */
	}

	/* 変数の初期値を読み込みます。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(token && ((*token)->get_type(token) == '=')) {
		/* 'var' シンボル の後に'='が有れば、変数の初期値を表す式を読み込みます。 */
		safe_attach(code, parser_expr(this));
		if(!code) {
			DIE(); /* シンボル '=' の後に式が無い */
		}
	} else {
		/* 'var' シンボル の後に'='が無ければ、暗黙の初期値を与えます。
		 * - 暗黙の初期値として、falseを用いることにしました。
		 *   特に理由はないので、0や""に変更しても構いません。
		 */
		safe_attach(code, jtbool_create(0));
		(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
	}

	/* 変数定義を作成します。 */
	safe_attach(code, jtvar_create(symbol, code));

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(symbol);

	return code;
}

static JTCODE_INTERFACE**
parser_fun(PARSER* this, int method)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	JTSYMBOL_INTERFACE** symbol = NULL;
	//
	LIST/*<JTSYMBOL_INTERFACE**>*/ * params_list;

	/* 最初のトークンが'fun'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_FUN)) {
		DIE(); /* 予期しないファイル終端、または、'fun'が無い */
	}

	/* 関数名を表すシンボルを読み込みます。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_SYMBOL)) {
		DIE(); /* 'fun'の後にシンボルが無い */
	}
	safe_attach(code, (*token)->get_code(token));
	safe_assign_interface(symbol, code, JTSYMBOL_INTERFACE);
	if(!symbol) {
		DIE(); /* 有り得ない */
	}

	/* 仮引数リストを読み込みます。 */
	params_list = parser_params(this);

	/* ブロックを読み込みます。 */
	safe_attach(code, parser_block(this));

	/* 関数定義を作成します。 */
	safe_attach(code, jtfun_create(symbol, params_list, code, method));

	/* 仮引数リストを削除します。 */
	list_delete(params_list);

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(symbol);

	return code;
}

static JTCODE_INTERFACE**
parser_block(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	//
	LIST/*<JTCODE_INTERFACE**>*/ * stmt_list;

	/* 最初のトークンが'{'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != '{')) {
		DIE(); /* 予期しないファイル終端、または、'{'が無い */
	}

	/* 空の文リストを作成します。 */
	stmt_list = list_create(&jtcode_list_info);

	/* ブロックが終了するまで... */
	for(;;) {
		/* 次のトークンが'}'ならば、'}'を読み飛ばし、ブロックを終了します。 */
		safe_attach(token, (*this->lexer)->get_token(this->lexer));
		if(!token) {
			DIE(); /* 予期しないファイル終端 */
		}
		if((*token)->get_type(token) == '}') {
			break;
		}
		(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

		/* 文を読み込み、文リストに追加します。 */
		safe_attach(code, parser_stmt(this));
		if(!code) {
			DIE(); /* 予期しないファイル終端、または、文が無い */
		}
		list_add(stmt_list, code);
	}

	/* ブロックを作成します。 */
	safe_attach(code, jtblock_create(stmt_list));

	/* 文リストを削除します。 */
	list_delete(stmt_list);

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);

	return code;
}

static JTCODE_INTERFACE**
parser_object(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	JTVAR_INTERFACE** field = NULL;
	JTFUN_INTERFACE** method = NULL;
	JTSYMBOL_INTERFACE** name = NULL;
	//
	int type;
	MAP/*<JTSYMBOL_INTERFACE**,JTCODE_INTERFACE**>*/ * slots_table;

	/* 最初のトークンが'object'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_OBJECT)) {
		DIE(); /* 予期しないファイル終端、または、'object'が無い */
	}

	/* 次のトークンが'{'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != '{')) {
		DIE(); /* 予期しないファイル終端、または、'{'が無い */
	}

	/* 空のスロットテーブルを作成します。 */
	slots_table = map_create(&jtsymbol_to_jtcode_map_info);

	/* スロット並びが終了するまで... */
	for(;;) {
		/* 次のトークンを読み込み、'}'ならば、スロット並びを終了します。 */
		safe_attach(token, (*this->lexer)->get_token(this->lexer));
		if(!token) {
			DIE(); /* 予期しないファイル終端 */
		}
		type = (*token)->get_type(token);
		if(type == '}') {
			break; /* ブロック終了 */
		}

		/* いったん、'var'、または、'fun'を戻します。 */
		(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

		/* スロットを一つ、読み込みます。 */
		switch(type) {
		case TOKEN_TYPE_VAR:
			/* フィールド変数定義"var シンボル [ = 式 ] ;"を読み込みます。 */
			safe_attach(code, parser_var(this));
			safe_attach(token, (*this->lexer)->get_token(this->lexer));
			if(!token || ((*token)->get_type(token) != ';')) {
				DIE(); /* 予期しないファイル終端、または、';'が無い */
			}

			/* フィールド変数をスロットテーブルに登録するための、名前を取得します。 */
			safe_assign_interface(field, code, JTVAR_INTERFACE);
			if(!field) {
				DIE(); /* 有り得ない */
			}
			safe_attach(name, (*field)->get_name(field));

			break;

		case TOKEN_TYPE_FUN:
			/* メソッド定義"fun シンボル(...) { ... }"を読み込みます。 */
			safe_attach(code, parser_fun(this, 1/*メソッド*/));
			/* メソッドの後には、';'は不要です。 */

			/* メソッドをスロットテーブルに登録するための、名前を取得します。 */
			safe_assign_interface(method, code, JTFUN_INTERFACE);
			if(!method) {
				DIE(); /* 有り得ない */
			}
			safe_attach(name, (*method)->get_name(method));

			break;

		default:
			DIE(); /* 不明なトークン */
		}

		/* スロットを、スロットテーブルに登録します。 */
		if(map_contains(slots_table, name)) {
			DIE(); /* 二重定義 */
		}
		map_put(slots_table, name, code);
	}

	/* オブジェクトを作成します。 */
	safe_attach(code, jtobject_create(slots_table));

	/* スロットテーブルを削除します。 */
	map_delete(slots_table);

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(field);
	safe_release(method);
	safe_release(name);

	return code;
}

static JTCODE_INTERFACE**
parser_new(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	JTCODE_INTERFACE** body = NULL;
	JTSYMBOL_INTERFACE** symbol = NULL;

	/* 最初のトークンが'new'であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_NEW)) {
		DIE(); /* 予期しないファイル終端、または、'new'が無い */
	}

	/* 複製元のオブジェクト名を表すシンボルを読み込みます。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != TOKEN_TYPE_SYMBOL)) {
		DIE(); /* 'new'の後にシンボルが無い */
	}
	safe_attach(code, (*token)->get_code(token));
	safe_assign_interface(symbol, code, JTSYMBOL_INTERFACE);
	if(!symbol) {
		DIE(); /* 有り得ない */
	}

	/* 'new' シンボル の後に '{' が有れば、初期化ブロックを読み込みます。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(token) {
		if((*token)->get_type(token) == '{') {
			/* いったん、'{'を戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
			/* 初期化ブロックを読み込みます。 */
			safe_attach(body, parser_block(this));
		} else {
			/* '{'以外ならば、トークンを戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */
		}
	}

	/* オブジェクト複製式を作成します。 */
	safe_attach(code, jtnew_create(symbol, body/*初期化ブロックが無ければNULL*/));

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(body);
	safe_release(symbol);

	return code;
}

static LIST/*<JTCODE_INTERFACE**>*/ *
parser_args(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	//
	int i;
	int type;
	LIST/*<JTCODE_INTERFACE**>*/ * args_list;

	/* 最初のトークンが'('であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != '(')) {
		DIE(); /* 予期しないファイル終端、または、'('が無い */
	}

	/* 空の実引数リストを作成します。 */
	args_list = list_create(&jtcode_list_info);

	/* 実引数リストが終了するまで... */
	for(i = 0; /** no job **/; i++) {
		safe_attach(token, (*this->lexer)->get_token(this->lexer));
		if(!token) {
			DIE(); /* 予期しないファイル終端 */
		}
		type = (*token)->get_type(token);

		/* '('の直後には、引数無しで')'が現れるか、または、式が現れます。 */
		if(!i) {
			if(type == ')') {
				/* ')'を読み飛ばし、実引数リストを終了します。 */
				break;
			}
			/* ')'でなければ、式の一部なので、戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

		/* '(' 式 の後は、')'で実引数リストを終了するか、または、','で継続します。 */
		} else { /* '(' 式 の後 */
			if(type == ')') {
				/* ')'を読み飛ばし、実引数リストを終了します。 */
				break;
			} else if(type == ',') {
				/* ','を読み飛ばし、実引数リストを継続します。 */
				/** no job **/
			} else {
				DIE(); /* 式の後に、')'、または、','が無い */
			}
		}

		/* 式を読み込み、実引数リストに追加します。 */
		safe_attach(code, parser_expr(this));
		if(!code) {
			DIE(); /* 予期しないファイル終端、または、式が無い */
		}
		list_add(args_list, code);
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code);

	return args_list;
}

static LIST/*<JTSYMBOL_INTERFACE**>*/ *
parser_params(PARSER* this)
{
	TOKEN_INTERFACE** token = NULL;
	JTCODE_INTERFACE** code = NULL;
	JTSYMBOL_INTERFACE** symbol = NULL;
	//
	int i;
	int type;
	LIST/*<JTSYMBOL_INTERFACE**>*/ * params_list;

	/* 最初のトークンが'('であることを確認し、読み飛ばします。 */
	safe_attach(token, (*this->lexer)->get_token(this->lexer));
	if(!token || ((*token)->get_type(token) != '(')) {
		DIE(); /* 予期しないファイル終端、または、'('が無い */
	}

	/* 空の仮引数リストを作成します。 */
	params_list = list_create(&jtsymbol_list_info);

	/* 仮引数リストが終了するまで... */
	for(i = 0; /** no job **/; i++) {
		safe_attach(token, (*this->lexer)->get_token(this->lexer));
		if(!token) {
			DIE(); /* 予期しないファイル終端 */
		}
		type = (*token)->get_type(token);

		/* '('の直後には、仮引数無しで')'が現れるか、または、シンボルが現れます。 */
		if(!i) {
			if(type == ')') {
				/* ')'を読み飛ばし、仮引数リストを終了します。 */
				break;
			}
			/* ')'でなければ、シンボルの一部なので、戻します。 */
			(*this->lexer)->unget_token(this->lexer, token); /* 忘れないで!! */

		/* '(' シンボル の後は、')'で仮引数リストを終了するか、または、','で継続します。 */
		} else { /* '(' シンボル の後 */
			if(type == ')') {
				/* ')'を読み飛ばし、仮引数リストを終了します。 */
				break;
			} else if(type == ',') {
				/* ','を読み飛ばし、仮引数リストを継続します。 */
				/** no job **/
			} else {
				DIE(); /* シンボルの後に、')'、または、','が無い */
			}
		}

		/* シンボルを読み込み、仮引数リストに追加します。 */
		safe_attach(token, (*this->lexer)->get_token(this->lexer));
		if(!token || ((*token)->get_type(token) != TOKEN_TYPE_SYMBOL)) {
			DIE(); /* 予期しないファイル終端、または、シンボルが無い */
		}
		safe_attach(code, (*token)->get_code(token));
		safe_assign_interface(symbol, code, JTSYMBOL_INTERFACE);
		if(!symbol) {
			DIE(); /* 有り得ない */
		}
		list_add(params_list, symbol);
	}

	/* 不要になったインターフェイスを解放します。 */
	safe_release(token);
	safe_release(code);
	safe_release(symbol);

	return params_list;
}

