
var HSPonJS = {};
(function(){


//original:
//+ Jonas Raoni Soares Silva
//@ http://jsfromhell.com/classes/binary-parser [rev. #1]
//modified by: fujidig 2008

function BinaryParser(data, index, length) {
	if(index == undefined) index = 0;
	if(length == undefined) length = data.length;
	if(index + length > data.length) length = data.length - index;
	if(index >= data.length) length = 0;
	var b = this.buffer = new Array(length);
	for(var i = 0; i < length; i ++)
		b[length - i - 1] = data.charCodeAt(index + i);
	this.offset = 0;
}

(function() {
	var p = BinaryParser;
	p.CheckBufferError = function(message) { this.message = message; };
	p.CheckBufferError.prototype = new Error;
	p.CheckBufferError.prototype.name = 'BinaryParser.CheckBufferError';
	
	p.prototype = {
		readChar: function() {
			return this.readUChar() << 24 >> 24;
		},
		readUChar: function() {
			this.checkBuffer(this.offset + 1);
			var result = this.buffer[this.buffer.length - this.offset - 1];
			++ this.offset;
			return result;
		},
		readShort: function() {
			return this.readUShort() << 16 >> 16;
		},
		readUShort: function() {
			this.checkBuffer(this.offset + 2);
			var result = this.buffer[this.buffer.length - this.offset - 1];
			result |= this.buffer[this.buffer.length - this.offset - 2] << 8;
			this.offset += 2;
			return result;
		},
		readInt24: function() {
			return this.readUInt24() << 8 >> 8;
		},
		readUInt24: function() {
			this.checkBuffer(this.offset + 3);
			var result = this.buffer[this.buffer.length - this.offset - 1];
			result |= this.buffer[this.buffer.length - this.offset - 2] << 8;
			result |= this.buffer[this.buffer.length - this.offset - 3] << 16;
			this.offset += 3;
			return result;
		},
		readInt: function() {
			this.checkBuffer(this.offset + 4);
			var result = this.buffer[this.buffer.length - this.offset - 1];
			result |= this.buffer[this.buffer.length - this.offset - 2] << 8;
			result |= this.buffer[this.buffer.length - this.offset - 3] << 16;
			result |= this.buffer[this.buffer.length - this.offset - 4] << 24;
			this.offset += 4;
			return result;
		},
		readUInt: function() {
			return this.readInt() >>> 0;
		},
		readDouble: function() {
			return this.decodeFloat(52, 11, 8);
		},

		isEOS: function() {
			return this.buffer.length <= this.offset;
		},
		decodeFloat: function(precisionBits, exponentBits, bytes) {
			this.checkBuffer(this.offset + bytes);
			var bias = Math.pow(2, exponentBits - 1) - 1, signal = this.readBits(this.offset * 8 + precisionBits + exponentBits, 1),
				exponent = this.readBits(this.offset * 8 + precisionBits, exponentBits), significand = 0,
				divisor = 2, curByte = this.buffer.length + (-precisionBits>>3) - this.offset - 1,
				byteValue, startBit, mask;
			this.offset += bytes;
			do
				for(byteValue = this.buffer[ ++curByte ], startBit = precisionBits % 8 || 8, mask = 1 << startBit;
					mask >>= 1; (byteValue & mask) && (significand += 1 / divisor), divisor *= 2);
			while((precisionBits -= startBit));
			return exponent == (bias << 1) + 1 ? significand ? NaN : signal ? -Infinity : +Infinity
				: (1 + signal * -2) * (exponent || significand ? !exponent ? Math.pow(2, -bias + 1) * significand
				: Math.pow(2, exponent - bias) * (1 + significand) : 0);
		},
		readBits: function(start, length) {
			//shl fix: Henri Torgemane ~1996 (compressed by Jonas Raoni)
			function shl(a, b) {
				while(b--)a = ((a %= 0x7fffffff + 1) & 0x40000000) == 0x40000000 ? a * 2 : (a - 0x40000000) * 2 + 0x7fffffff + 1;
				return a;
			}
			if(start < 0 || length <= 0)
				return 0;
			this.checkBuffer(-(-(start + length) >> 3));
			for(var offsetLeft, offsetRight = start % 8, curByte = this.buffer.length - (start >> 3) - 1,
				lastByte = this.buffer.length + (-(start + length) >> 3), diff = curByte - lastByte,
				sum = ((this.buffer[ curByte ] >> offsetRight) & ((1 << (diff ? 8 - offsetRight : length)) - 1))
				+ (diff && (offsetLeft = (start + length) % 8) ? (this.buffer[ lastByte++ ] & ((1 << offsetLeft) - 1))
				<< (diff-- << 3) - offsetRight : 0); diff; sum += shl(this.buffer[ lastByte++ ], (diff-- << 3) - offsetRight)
			);
			return sum;
		},
		hasNeededBytes: function(neededBytes) {
			return this.buffer.length >= neededBytes;
		},
		checkBuffer: function(neededBytes) {
			if(!this.hasNeededBytes(neededBytes))
				throw new p.CheckBufferError("checkBuffer::missing bytes");
		}
	};
	
	p.readChar = function(data, index) {
		return new p(data, index, 1).readChar();
	};
	p.readUChar = function(data, index) {
		return new p(data, index, 1).readUChar();
	};
	p.readShort = function(data, index) {
		return new p(data, index, 2).readShort();
	};
	p.readUShort = function(data, index) {
		return new p(data, index, 2).readUShort();
	};
	p.readInt24 = function(data, index) {
		return new p(data, index, 3).readInt24();
	};
	p.readUInt24 = function(data, index) {
		return new p(data, index, 3).readUInt24();
	};
	p.readInt = function(data, index) {
		return new p(data, index, 4).readInt();
	};
	p.readUInt = function(data, index) {
		return new p(data, index, 4).readUInt();
	};
	p.readDouble = function(data, index) {
		return new p(data, index, 8).readDouble();
	};
})();

if(typeof HSPonJS != 'undefined') {
	HSPonJS.BinaryParser = BinaryParser;
}

// CP932 ( Windows Shift_JIS ) encoder / decoder
// original: Escape Codec Library Ver.041208
// modified by: fujidig 2008

//
// Escape Codec Library: ecl.js (Ver.041208)
//
// Copyright (C) http://nurucom-archives.hp.infoseek.co.jp/digital/

var CP932 = {
	Table: function(){var a="zKV33~jZ4zN=~ji36XazM93y!{~k2y!o~k0ZlW6zN?3Wz3W?{EKzK[33[`y|;-~j^YOTz$!~kNy|L1$353~jV3zKk3~k-4P4zK_2+~jY4y!xYHR~jlz$_~jk4z$e3X5He<0y!wy|X3[:~l|VU[F3VZ056Hy!nz/m1XD61+1XY1E1=1y|bzKiz!H034zKj~mEz#c5ZA3-3X$1~mBz$$3~lyz#,4YN5~mEz#{ZKZ3V%7Y}!J3X-YEX_J(3~mAz =V;kE0/y|F3y!}~m>z/U~mI~j_2+~mA~jp2;~m@~k32;~m>V}2u~mEX#2x~mBy+x2242(~mBy,;2242(~may->2&XkG2;~mIy-_2&NXd2;~mGz,{4<6:.:B*B:XC4>6:.>B*BBXSA+A:X]E&E<~r#z+625z s2+zN=`HXI@YMXIAXZYUM8X4K/:Q!Z&33 3YWX[~mB`{zKt4z (zV/z 3zRw2%Wd39]S11z$PAXH5Xb;ZQWU1ZgWP%3~o@{Dgl#gd}T){Uo{y5_d{e@}C(} WU9|cB{w}bzvV|)[} H|zT}d||0~{]Q|(l{|x{iv{dw}(5}[Z|kuZ }cq{{y|ij}.I{idbof%cu^d}Rj^y|-M{ESYGYfYsZslS`?ZdYO__gLYRZ&fvb4oKfhSf^d<Yeasc1f&a=hnYG{QY{D`Bsa|u,}Dl|_Q{C%xK|Aq}C>|c#ryW=}eY{L+`)][YF_Ub^h4}[X|?r|u_ex}TL@YR]j{SrXgo*|Gv|rK}B#mu{R1}hs|dP{C7|^Qt3|@P{YVV |8&}#D}ef{e/{Rl|>Hni}R1{Z#{D[}CQlQ||E}[s{SG_+i8eplY[=[|ec[$YXn#`hcm}YR|{Ci(_[ql|?8p3]-}^t{wy}4la&pc|3e{Rp{LqiJ],] `kc(]@chYnrM`O^,ZLYhZB]ywyfGY~aex!_Qww{a!|)*lHrM{N+n&YYj~Z b c#e_[hZSon|rOt`}hBXa^i{lh|<0||r{KJ{kni)|x,|0auY{D!^Sce{w;|@S|cA}Xn{C1h${E]Z-XgZ*XPbp]^_qbH^e[`YM|a||+=]!Lc}]vdBc=j-YSZD]YmyYLYKZ9Z>Xcczc2{Yh}9Fc#Z.l{}(D{G{{mRhC|L3b#|xK[Bepj#ut`H[,{E9Yr}1b{[e]{ZFk7[ZYbZ0XL]}Ye[(`d}c!|*y`Dg=b;gR]Hm=hJho}R-[n}9;{N![7k_{UbmN]rf#pTe[x8}!Qcs_rs[m`|>N}^V})7{^r|/E}),}HH{OYe2{Skx)e<_.cj.cjoMhc^d}0uYZd!^J_@g,[[[?{i@][|3S}Yl3|!1|eZ|5IYw|1D}e7|Cv{OHbnx-`wvb[6[4} =g+k:{C:}ed{S]|2M]-}WZ|/q{LF|dYu^}Gs^c{Z=}h>|/i|{W]:|ip{N:|zt|S<{DH[p_tvD{N<[8Axo{X4a.^o^X>Yfa59`#ZBYgY~_t^9`jZHZn`>G[oajZ;X,i)Z.^~YJe ZiZF^{][[#Zt^|]Fjx]&_5dddW]P0C[-]}]d|y {C_jUql] |OpaA[Z{lp|rz}:Mu#]_Yf6{Ep?f5`$[6^D][^u[$[6^.Z8]]ePc2U/=]K^_+^M{q*|9tYuZ,s(dS{i=|bNbB{uG}0jZOa:[-]dYtu3]:]<{DJ_SZIqr_`l=Yt`gkTnXb3d@kiq0a`Z{|!B|}e}Ww{Sp,^Z|0>_Z}36|]A|-t}lt{R6pi|v8hPu#{C>YOZHYmg/Z4nicK[}hF_Bg|YRZ7c|crkzYZY}_iXcZ.|)U|L5{R~qi^Uga@Y[xb}&qdbd6h5|Btw[}c<{Ds53[Y7]?Z<|e0{L[ZK]mXKZ#Z2^tavf0`PE[OSOaP`4gi`qjdYMgys/?[nc,}EEb,eL]g[n{E_b/vcvgb.{kcwi`~v%|0:|iK{Jh_vf5lb}KL|(oi=LrzhhY_^@`zgf[~g)[J_0fk_V{T)}I_{D&_/d9W/|MU[)f$xW}?$xr4<{Lb{y4}&u{XJ|cm{Iu{jQ}CMkD{CX|7A}G~{kt)nB|d5|<-}WJ}@||d@|Iy}Ts|iL|/^|no|0;}L6{Pm]7}$zf:|r2}?C_k{R(}-w|`G{Gy[g]bVje=_0|PT{^Y^yjtT[[[l!Ye_`ZN]@[n_)j3nEgMa]YtYpZy].d-Y_cjb~Y~[nc~sCi3|zg}B0}do{O^{|$`_|D{}U&|0+{J3|8*]iayx{a{xJ_9|,c{Ee]QXlYb]$[%YMc*]w[aafe]aVYi[fZEii[xq2YQZHg]Y~h#|Y:thre^@^|_F^CbTbG_1^qf7{L-`VFx Zr|@EZ;gkZ@slgko`[e}T:{Cu^pddZ_`yav^Ea+[#ZBbSbO`elQfLui}.F|txYcbQ`XehcGe~fc^RlV{D_0ZAej[l&jShxG[ipB_=u:eU}3e8[=j|{D(}dO{Do[BYUZ0/]AYE]ALYhZcYlYP/^-^{Yt_1_-;YT`P4BZG=IOZ&]H[e]YYd[9^F[1YdZxZ?Z{Z<]Ba2[5Yb[0Z4l?]d_;_)a?YGEYiYv`_XmZs4ZjY^Zb]6gqGaX^9Y}dXZr[g|]Y}K aFZp^k^F]M`^{O1Ys]ZCgCv4|E>}8eb7}l`{L5[Z_faQ|c2}Fj}hw^#|Ng|B||w2|Sh{v+[G}aB|MY}A{|8o}X~{E8paZ:]i^Njq]new)`-Z>haounWhN}c#{DfZ|fK]KqGZ=:u|fqoqcv}2ssm}.r{]{nIfV{JW)[K|,Z{Uxc|]l_KdCb%]cfobya3`p}G^|LZiSC]U|(X|kBlVg[kNo({O:g:|-N|qT}9?{MBiL}Sq{`P|3a|u.{Uaq:{_o|^S}jX{Fob0`;|#y_@[V[K|cw[<_ }KU|0F}d3|et{Q7{LuZttsmf^kYZ`Af`}$x}U`|Ww}d]| >}K,r&|XI|*e{C/a-bmr1fId4[;b>tQ_:]hk{b-pMge]gfpo.|(w[jgV{EC1Z,YhaY^q,_G[c_g[J0YX]`[h^hYK^_Yib,` {i6vf@YM^hdOKZZn(jgZ>bzSDc^Z%[[o9[2=/YHZ(_/Gu_`*|8z{DUZxYt^vuvZjhi^lc&gUd4|<UiA`z]$b/Z?l}YI^jaHxe|;F}l${sQ}5g}hA|e4}?o{ih}Uz{C)jPe4]H^J[Eg[|AMZMlc}:,{iz}#*|gc{Iq|/:|zK{l&}#u|myd{{M&v~nV};L|(g|I]ogddb0xsd7^V})$uQ{HzazsgxtsO^l}F>ZB]r|{7{j@cU^{{CbiYoHlng]f+nQ[bkTn/}<-d9q {KXadZYo+n|l[|lc}V2{[a{S4Zam~Za^`{HH{xx_SvF|ak=c^[v^7_rYT`ld@]:_ub%[$[m](Shu}G2{E.ZU_L_R{tz`vj(f?^}hswz}GdZ}{S:h`aD|?W|`dgG|if{a8|J1{N,}-Ao3{H#{mfsP|[ bzn+}_Q{MT{u4kHcj_q`eZj[8o0jy{p7}C|[}l){MuYY{|Ff!Ykn3{rT|m,^R|,R}$~Ykgx{P!]>iXh6[l[/}Jgcg{JYZ.^qYfYIZl[gZ#Xj[Pc7YyZD^+Yt;4;`e8YyZVbQ7YzZxXja.7SYl[s]2^/Ha$[6ZGYrb%XiYdf2]H]kZkZ*ZQ[ZYS^HZXcCc%Z|[(bVZ]]:OJQ_DZCg<[,]%Zaa [g{C00HY[c%[ChyZ,Z_`PbXa+eh`^&jPi0a[ggvhlekL]w{Yp^v}[e{~;k%a&k^|nR_z_Qng}[E}*Wq:{k^{FJZpXRhmh3^p>de^=_7`|ZbaAZtdhZ?n4ZL]u`9ZNc3g%[6b=e.ZVfC[ZZ^^^hD{E(9c(kyZ=bb|Sq{k`|vmr>izlH[u|e`}49}Y%}FT{[z{Rk}Bz{TCc/lMiAqkf(m$hDc;qooi[}^o:c^|Qm}a_{mrZ(pA`,}<2sY| adf_%|}`}Y5U;}/4|D>|$X{jw{C<|F.hK|*A{MRZ8Zsm?imZm_?brYWZrYx`yVZc3a@f?aK^ojEd {bN}/3ZH]/$YZhm^&j 9|(S|b]mF}UI{q&aM]LcrZ5^.|[j`T_V_Gak}9J[ ZCZD|^h{N9{~&[6Zd{}B}2O|cv]K}3s}Uy|l,fihW{EG`j_QOp~Z$F^zexS`dcISfhZBXP|.vn|_HYQ|)9|cr]<`&Z6]m_(ZhPcSg>`Z]5`~1`0Xcb4k1{O!bz|CN_T{LR|a/gFcD|j<{Z._[f)mPc:1`WtIaT1cgYkZOaVZOYFrEe[}T$}Ch}mk{K-^@]fH{Hdi`c*Z&|Kt{if[C{Q;{xYB`dYIX:ZB[}]*[{{p9|4GYRh2ao{DS|V+[zd$`F[ZXKadb*A] Ys]Maif~a/Z2bmclb8{Jro_rz|x9cHojbZ{GzZx_)]:{wAayeDlx}<=`g{H1{l#}9i|)=|lP{Qq}.({La|!Y{i2EZfp=c*}Cc{EDvVB|;g}2t{W4av^Bn=]ri,|y?|3+}T*ckZ*{Ffr5e%|sB{lx^0]eZb]9[SgAjS_D|uHZx]dive[c.YPkcq/}db{EQh&hQ|eg}G!ljil|BO]X{Qr_GkGl~YiYWu=c3eb}29v3|D|}4i||.{Mv})V{SP1{FX}CZW6{cm|vO{pS|e#}A~|1i}81|Mw}es|5[}3w{C`h9aL]o{}p[G`>i%a1Z@`Ln2bD[$_h`}ZOjhdTrH{[j_:k~kv[Sdu]CtL}41{I |[[{]Zp$]XjxjHt_eThoa#h>sSt8|gK|TVi[Y{t=}Bs|b7Zpr%{gt|Yo{CS[/{iteva|cf^hgn}($_c^wmb^Wm+|55jrbF|{9^ q6{C&c+ZKdJkq_xOYqZYSYXYl`8]-cxZAq/b%b*_Vsa[/Ybjac/OaGZ4fza|a)gY{P?| I|Y |,pi1n7}9bm9ad|=d{aV|2@[(}B`d&|Uz}B}{`q|/H|!JkM{FU|CB|.{}Az}#P|lk}K{|2rk7{^8^?`/|k>|Ka{Sq}Gz}io{DxZh[yK_#}9<{TRdgc]`~Z>JYmYJ]|`!ZKZ]gUcx|^E[rZCd`f9oQ[NcD_$ZlZ;Zr}mX|=!|$6ZPZYtIo%fj}CpcN|B,{VDw~gb}@hZg`Q{LcmA[(bo`<|@$|o1|Ss}9Z_}tC|G`{F/|9nd}i=}V-{L8aaeST]daRbujh^xlpq8|}zs4bj[S`J|]?G{P#{rD{]I`OlH{Hm]VYuSYUbRc*6[j`8]pZ[bt_/^Jc*[<Z?YE|Xb|?_Z^Vcas]h{t9|Uwd)_(=0^6Zb{Nc} E[qZAeX[a]P^|_J>e8`W^j_Y}R{{Jp__]Ee#e:iWb9q_wKbujrbR}CY`,{mJ}gz{Q^{t~N|? gSga`V_||:#mi}3t|/I`X{N*|ct|2g{km}gi|{={jC}F;|E}{ZZjYf*frmu}8Tdroi{T[|+~}HG{cJ}DM{Lp{Ctd&}$hi3|FZ| m}Kr|38}^c|m_|Tr{Qv|36}?Up>|;S{DV{k_as}BK{P}}9p|t`jR{sAm4{D=b4pWa[}Xi{EjwEkI}3S|E?u=X0{jf} S|NM|JC{qo^3cm]-|JUx/{Cj{s>{Crt[UXuv|D~|j|d{YXZR}Aq}0r}(_{pJfi_z}0b|-vi)Z mFe,{f4|q`b{}^Z{HM{rbeHZ|^x_o|XM|L%|uFXm}@C_{{Hhp%a7|0p[Xp+^K}9U{bP}: tT}B|}+$|b2|[^|~h{FAby[`{}xgygrt~h1[li`c4vz|,7p~b(|mviN}^pg[{N/|g3|^0c,gE|f%|7N{q[|tc|TKA{LU}I@|AZp(}G-sz{F |qZ{}F|f-}RGn6{Z]_5})B}UJ{FFb2]4ZI@v=k,]t_Dg5Bj]Z-]L]vrpdvdGlk|gF}G]|IW}Y0[G| /bo|Te^,_B}#n^^{QHYI[?hxg{[`]D^IYRYTb&kJ[cri[g_9]Ud~^_]<p@_e_XdNm-^/|5)|h_{J;{kacVopf!q;asqd}n)|.m|bf{QW|U)}b+{tL|w``N|to{t ZO|T]jF}CB|0Q{e5Zw|k |We}5:{HO{tPwf_uajjBfX}-V_C_{{r~gg|Ude;s+}KNXH}! `K}eW{Upwbk%ogaW}9EYN}YY|&v|SL{C3[5s.]Y]I]u{M6{pYZ`^,`ZbCYR[1mNg>rsk0Ym[jrE]RYiZTr*YJ{Ge|%-lf|y(`=[t}E6{k!|3)}Zk} ][G{E~cF{u3U.rJ|a9p#o#ZE|?|{sYc#vv{E=|LC}cu{N8`/`3`9rt[4|He{cq|iSYxY`}V |(Q|t4{C?]k_Vlvk)BZ^r<{CL}#h}R+[<|i=}X|{KAo]|W<`K{NW|Zx}#;|fe{IMr<|K~tJ_x}AyLZ?{GvbLnRgN}X&{H7|x~}Jm{]-| GpNu0}.ok>|c4{PYisrDZ|fwh9|hfo@{H~XSbO]Odv]%`N]b1Y]]|eIZ}_-ZA]aj,>eFn+j[aQ_+]h[J_m_g]%_wf.`%k1e#Z?{CvYu_B^|gk`Xfh^M3`afGZ-Z|[m{L}|k3cp[it ^>YUi~d>{T*}YJ{Q5{Jxa$hg|%4`}|LAgvb }G}{P=|<;Ux{_skR{cV|-*|s-{Mp|XP|$G|_J}c6cM{_=_D|*9^$ec{V;|4S{qO|w_|.7}d0|/D}e}|0G{Dq]Kdp{}dfDi>}B%{Gd|nl}lf{C-{y}|ANZr}#={T~|-(}c&{pI|ft{lsVP}){|@u}!W|bcmB{d?|iW|:dxj{PSkO|Hl]Li:}VYk@|2={fnWt{M3`cZ6|)}|Xj}BYa?vo{e4|L7|B7{L7|1W|lvYO}W8nJ|$Vih|{T{d*_1|:-n2dblk``fT{Ky|-%}m!|Xy|-a{Pz}[l{kFjz|iH}9N{WE{x,|jz}R {P|{D)c=nX|Kq|si}Ge{sh|[X{RF{t`|jsr*fYf,rK|/9}$}}Nf{y!1|<Std}4Wez{W${Fd_/^O[ooqaw_z[L`Nbv[;l7V[ii3_PeM}.h^viqYjZ*j1}+3{bt{DR[;UG}3Og,rS{JO{qw{d<_zbAh<R[1_r`iZTbv^^a}c{iEgQZ<exZFg.^Rb+`Uj{a+{z<[~r!]`[[|rZYR|?F|qppp]L|-d|}K}YZUM|=Y|ktm*}F]{D;g{uI|7kg^}%?Z%ca{N[_<q4xC]i|PqZC]n}.bDrnh0Wq{tr|OMn6tM|!6|T`{O`|>!]ji+]_bTeU}Tq|ds}n|{Gm{z,f)}&s{DPYJ`%{CGd5v4tvb*hUh~bf]z`jajiFqAii]bfy^U{Or|m+{I)cS|.9k:e3`^|xN}@Dnlis`B|Qo{`W|>||kA}Y}{ERYuYx`%[exd`]|OyiHtb}HofUYbFo![5|+]gD{NIZR|Go}.T{rh^4]S|C9_}xO^i`vfQ}C)bK{TL}cQ|79iu}9a];sj{P.o!f[Y]pM``Jda^Wc9ZarteBZClxtM{LW}l9|a.mU}KX}4@{I+f1}37|8u}9c|v${xGlz}jP{Dd1}e:}31}%3X$|22i<v+r@~mf{sN{C67G97855F4YL5}8f{DT|xy{sO{DXB334@55J1)4.G9A#JDYtXTYM4, YQD9;XbXm9SX]IB^4UN=Xn<5(;(F3YW@XkH-X_VM[DYM:5XP!T&Y`6|,^{IS-*D.H>:LXjYQ0I3XhAF:9:(==.F*3F1189K/7163D,:@|e2{LS36D4hq{Lw/84443@4.933:0307::6D7}&l{Mx657;89;,K5678H&93D(H<&<>0B90X^I;}Ag1{P%3A+>><975}[S{PZE453?4|T2{Q+5187;>447:81{C=hL6{Me^:=7ii{R=.=F<81;48?|h8}Uh{SE|,VxL{ST,7?9Y_5Xk3A#:$%YSYdXeKXOD8+TXh7(@>(YdXYHXl9J6X_5IXaL0N?3YK7Xh!1?XgYz9YEXhXaYPXhC3X`-YLY_XfVf[EGXZ5L8BXL9YHX]SYTXjLXdJ: YcXbQXg1PX]Yx4|Jr{Ys4.8YU+XIY`0N,<H%-H;:0@,74/:8546I=9177154870UC]d<C3HXl7ALYzXFXWP<<?E!88E5@03YYXJ?YJ@6YxX-YdXhYG|9o{`iXjY_>YVXe>AYFX[/(I@0841?):-B=14337:8=|14{c&93788|di{cW-0>0<097/A;N{FqYpugAFT%X/Yo3Yn,#=XlCYHYNX[Xk3YN:YRT4?)-YH%A5XlYF3C1=NWyY}>:74-C673<69545v {iT85YED=64=.F4..9878/D4378?48B3:7:7/1VX[f4{D,{l<5E75{dAbRB-8-@+;DBF/$ZfW8S<4YhXA.(5@*11YV8./S95C/0R-A4AXQYI7?68167B95HA1*<M3?1/@;/=54XbYP36}lc{qzSS38:19?,/39193574/66878Yw1X-87E6=;964X`T734:>86>1/=0;(I-1::7ALYGXhF+Xk[@W%TYbX7)KXdYEXi,H-XhYMRXfYK?XgXj.9HX_SX]YL1XmYJ>Y}WwIXiI-3-GXcYyXUYJ$X`Vs[7;XnYEZ;XF! 3;%8;PXX(N3Y[)Xi1YE&/ :;74YQ6X`33C;-(>Xm0(TYF/!YGXg8 9L5P01YPXO-5%C|qd{{/K/E6,=0144:361:955;6443@?B7*7:F89&F35YaX-CYf,XiFYRXE_e{}sF 0*7XRYPYfXa5YXXY8Xf8Y~XmA[9VjYj*#YMXIYOXk,HHX40YxYMXU8OXe;YFXLYuPXP?EB[QV0CXfY{:9XV[FWE0D6X^YVP*$4%OXiYQ(|xp|%c3{}V`1>Y`XH00:8/M6XhQ1:;3414|TE|&o@1*=81G8<3}6<|(f6>>>5-5:8;093B^3U*+*^*UT30XgYU&7*O1953)5@E78--F7YF*B&0:%P68W9Zn5974J9::3}Vk|-,C)=)1AJ4+<3YGXfY[XQXmT1M-XcYTYZXCYZXEYXXMYN,17>XIG*SaS|/eYJXbI?XdNZ+WRYP<F:R PXf;0Xg`$|1GX9YdXjLYxWX!ZIXGYaXNYm6X9YMX?9EXmZ&XZ#XQ>YeXRXfAY[4 ;0X!Zz0XdN$XhYL XIY^XGNXUYS/1YFXhYk.TXn4DXjB{jg|4DEX]:XcZMW=A.+QYL<LKXc[vV$+&PX*Z3XMYIXUQ:ZvW< YSXFZ,XBYeXMM)?Xa XiZ4/EXcP3%}&-|6~:1(-+YT$@XIYRBC<}&,|7aJ6}bp|8)K1|Xg|8C}[T|8Q.89;-964I38361<=/;883651467<7:>?1:.}le|:Z=39;1Y^)?:J=?XfLXbXi=Q0YVYOXaXiLXmJXO5?.SFXiCYW}-;|=u&D-X`N0X^,YzYRXO(QX_YW9`I|>hZ:N&X)DQXP@YH#XmNXi$YWX^=!G6YbYdX>XjY|XlX^XdYkX>YnXUXPYF)FXT[EVTMYmYJXmYSXmNXi#GXmT3X8HOX[ZiXN]IU2>8YdX1YbX<YfWuZ8XSXcZU%0;1XnXkZ_WTG,XZYX5YSX Yp 05G?XcYW(IXg6K/XlYP4XnI @XnO1W4Zp-9C@%QDYX+OYeX9>--YSXkD.YR%Q/Yo YUX].Xi<HYEZ2WdCE6YMXa7F)=,D>-@9/8@5=?7164;35387?N<618=6>7D+C50<6B03J0{Hj|N9$D,9I-,.KB3}m |NzE0::/81YqXjMXl7YG; [.W=Z0X4XQY]:MXiR,XgM?9$9>:?E;YE77VS[Y564760391?14941:0=:8B:;/1DXjFA-564=0B3XlH1+D85:0Q!B#:-6&N/:9<-R3/7Xn<*3J4.H:+334B.=>30H.;3833/76464665755:/83H6633:=;.>5645}&E|Y)?1/YG-,93&N3AE@5 <L1-G/8A0D858/30>8<549=@B8] V0[uVQYlXeD(P#ID&7T&7;Xi0;7T-$YE)E=1:E1GR):--0YI7=E<}n9|aT6783A>D7&4YG7=391W;Zx<5+>F#J39}o/|cc;6=A050EQXg8A1-}D-|d^5548083563695D?-.YOXd37I$@LYLWeYlX<Yd+YR A$;3-4YQ-9XmA0!9/XLY_YT(=5XdDI>YJ5XP1ZAW{9>X_6R(XhYO65&J%DA)C-!B:97#A9;@?F;&;(9=11/=657/H,<8}bz|j^5446>.L+&Y^8Xb6?(CYOXb*YF(8X`FYR(XPYVXmPQ%&DD(XmZXW??YOXZXfCYJ79,O)XnYF7K0!QXmXi4IYFRXS,6<%-:YO(+:-3Q!1E1:W,Zo}Am|n~;3580534*?3Zc4=9334361693:30C<6/717:<1/;>59&:4}6!|rS36=1?75<8}[B|s809983579I.A.>84758=108564741H*9E{L{|u%YQ<%6XfH.YUXe4YL@,>N}Tv|ve*G0X)Z;/)3@A74(4P&A1X:YVH97;,754*A66:1 D739E3553545558E4?-?K17/770843XAYf838A7K%N!YW4.$T19Z`WJ*0XdYJXTYOXNZ 1XaN1A+I&Xi.Xk3Z3GB&5%WhZ1+5#Y[X<4YMXhQYoQXVXbYQ8XSYUX4YXBXWDMG0WxZA[8V+Z8X;D],Va$%YeX?FXfX[XeYf<X:Z[WsYz8X_Y]%XmQ(!7BXIZFX]&YE3F$(1XgYgYE& +[+W!<YMYFXc;+PXCYI9YrWxGXY9DY[!GXiI7::)OC;*$.>N*HA@{C|}&k=:<TB83X`3YL+G4XiK]i}(fYK<=5$.FYE%4*5*H*6XkCYL=*6Xi6!Yi1KXR4YHXbC8Xj,B9ZbWx/XbYON#5B}Ue}+QKXnF1&YV5XmYQ0!*3IXBYb71?1B75XmF;0B976;H/RXU:YZX;BG-NXj;XjI>A#D3B636N;,*%<D:0;YRXY973H5)-4FXOYf0:0;/7759774;7;:/855:543L43<?6=E,.A4:C=L)%4YV!1(YE/4YF+ F3%;S;&JC:%/?YEXJ4GXf/YS-EXEYW,9;E}X$}547EXiK=51-?71C%?57;5>463553Zg90;6447?<>4:9.7538XgN{|!}9K/E&3-:D+YE1)YE/3;37/:05}n<}:UX8Yj4Yt864@JYK..G=.(A Q3%6K>3(P3#AYE$-6H/456*C=.XHY[#S.<780191;057C)=6HXj?955B:K1 E>-B/9,;5.!L?:0>/.@//:;7833YZ56<4:YE=/:7Z_WGC%3I6>XkC*&NA16X=Yz2$X:Y^&J48<99k8}CyB-61<18K946YO4{|N}E)YIB9K0L>4=46<1K0+R;6-=1883:478;4,S+3YJX`GJXh.Yp+Xm6MXcYpX(>7Yo,/:X=Z;Xi0YTYHXjYmXiXj;*;I-8S6N#XgY}.3XfYGO3C/$XjL$*NYX,1 6;YH&<XkK9C#I74.>}Hd`A748X[T450[n75<4439:18A107>|ET}Rf<1;14876/Yb983E<5.YNXd4149>,S=/4E/<306443G/06}0&}UkYSXFYF=44=-5095=88;63844,9E6644{PL}WA8:>)7+>763>>0/B3A545CCnT}Xm|dv}Xq1L/YNXk/H8;;.R63351YY747@15YE4J8;46;.38.>4A369.=-83,;Ye3?:3@YE.4-+N353;/;@(X[YYD>@/05-I*@.:551741Yf5>6A443<3535;.58/86=D4753442$635D1>0359NQ @73:3:>><Xn?;43C14 ?Y|X611YG1&<+,4<*,YLXl<1/AIXjF*N89A4Z576K1XbJ5YF.ZOWN.YGXO/YQ01:4G38Xl1;KI0YFXB=R<7;D/,/4>;$I,YGXm94@O35Yz66695385.>:6A#5}W7n^4336:4157597434433<3|XA}m`>=D>:4A.337370?-6Q96{`E|4A}C`|Qs{Mk|J+~r>|o,wHv>Vw}!c{H!|Gb|*Ca5}J||,U{t+{CN[!M65YXOY_*B,Y[Z9XaX[QYJYLXPYuZ%XcZ8LY[SYPYKZM<LMYG9OYqSQYM~[e{UJXmQYyZM_)>YjN1~[f3{aXFY|Yk:48YdH^NZ0|T){jVFYTZNFY^YTYN~[h{nPYMYn3I]`EYUYsYIZEYJ7Yw)YnXPQYH+Z.ZAZY]^Z1Y`YSZFZyGYHXLYG 8Yd#4~[i|+)YH9D?Y^F~Y7|-eYxZ^WHYdYfZQ~[j|3>~[k|3oYmYqY^XYYO=Z*4[]Z/OYLXhZ1YLZIXgYIHYEYK,<Y`YEXIGZI[3YOYcB4SZ!YHZ*&Y{Xi3~[l|JSY`Zz?Z,~[m|O=Yi>??XnYWXmYS617YVYIHZ(Z4[~L4/=~[n|Yu{P)|];YOHHZ}~[o33|a>~[r|aE]DH~[s|e$Zz~[t|kZFY~XhYXZB[`Y}~[u|{SZ&OYkYQYuZ2Zf8D~[v}% ~[w3},Q[X]+YGYeYPIS~[y}4aZ!YN^!6PZ*~[z}?E~[{3}CnZ=~[}}EdDZz/9A3(3S<,YR8.D=*XgYPYcXN3Z5 4)~[~}JW=$Yu.XX~] }KDX`PXdZ4XfYpTJLY[F5]X~[2Yp}U+DZJ::<446[m@~]#3}]1~]%}^LZwZQ5Z`/OT<Yh^ -~]&}jx[ ~m<z!%2+~ly4VY-~o>}p62yz!%2+Xf2+~ly4VY-zQ`z (=] 2z~o2",C={" ":0,"!":1},c=34,i=2,p,s="",u=String.fromCharCode,t=u(12539);while(++c<127)C[u(c)]=c^39&&c^92?i++:0;i=0;while(0<=(c=C[a.charAt(i++)]))if(16==c)if((c=C[a.charAt(i++)])<87){if(86==c)c=1879;while(c--)s+=u(++p)}else s+=s.substr(8272,360);else if(c<86)s+=u(p+=c<51?c-16:(c-55)*92+C[a.charAt(i++)]);else if((c=((c-86)*92+C[a.charAt(i++)])*92+C[a.charAt(i++)])<49152)s+=u(p=c<40960?c:c|57344);else{c&=511;while(c--)s+=t;p=12539}return s}(),

	encode: function(str){
		return str.replace(/[^\x00-\xff]/g,function(s){
			var c=s.charCodeAt(0),m;
			return 65376<c&&c<65440?String.fromCharCode(c-65216):(c=CP932.Table.indexOf(s))<0?"\x81\x45":String.fromCharCode((m=(c<8272?c:(c=CP932.Table.lastIndexOf(s)))/188|0)<31?m+129:m+193)+String.fromCharCode((c%=188)<63?c+64:c+65)
		})
	},
	decode: function(str){
		return str.replace(/[\x81-\x9f\xe0-\xfc][\x40-\x7e\x80-\xfc]|[\xa1-\xdf]/g,function(s){
			var c=s.charCodeAt(0),l=s.length;
			return 1==l?String.fromCharCode(c+65216):CP932.Table.charAt((c<160?c-129:c-193)*188+((c=s.charCodeAt(1))<127?c-64:c-65))
		})
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.CP932 = CP932;
}

var Utils = {
	getCStr: function(str, index) {
		var end = str.indexOf("\0", index);
		if(end < 0) end = str.length;
		return str.slice(index, end);
	},
	objectExtend: function(dest, src) {
		for(var p in src) {
			dest[p] = src[p];
		}
		return dest;
	},
	objectMerge: function(a, b) {
		return Utils.objectExtend(Utils.objectExtend({}, a), b);
	},
	aryPopN: function(ary, n) {
		var result = ary.slice(ary.length - n);
		ary.length -= n;
		return result;
	},
	strTimes: function(str, n) {
		var result = '';
		for(var i = 0; i < n; i ++) {
			result += str;
		}
		return result;
	},
	strToSource: function() {
		var table = [];
		(function() {
			for(var i = 0; i < 256; i ++) {
				table[i] = '\\x' + ((0x100+i).toString(16)).slice(1);
			}
			for(var i = 0x20; i <= 0x7e; i ++) {
				table[i] = String.fromCharCode(i);
			}
		//	table[0x08] = '\\b';
			table[0x09] = '\\t';
			table[0x0a] = '\\n';
		//	table[0x0b] = '\\v';
		//	table[0x0c] = '\\f';
			table[0x0d] = '\\r';
			table[0x22] = '\\"';
		//	table[0x27] = '\\\'';
			table[0x5c] = '\\\\';
		})();
		return function(str) {
			var len = str.length;
			var result = '"';
			for(var i = 0; i < len; i ++) {
				var c = str.charCodeAt(i);
				if(c < 0x100) {
					result += table[c];
				} else {
					result += '\\u' + (0x10000+c).toString(16).slice(1);
				}
			}
			return result + '"';
		}
	}(),
	numToSource: function(num) {
		if(num == 0 && 1 / num < 0) {
			return '-0';
		}
		return '' + num;
	}
};

function returnTrue() { return true; }
function returnFalse() { return false; }

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Utils = Utils;
}

function VCRandom() {
	this.x = 1;
}

VCRandom.prototype = {
	srand: function(s) {
		this.x = s|0;
	},
	rand: function() {
		this.x = (this.x*214013|0)+2531011|0;
		return (this.x >> 16) & 32767;
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.VCRandom = VCRandom;
}


var VarType = {
	NONE: 0,
	LABEL: 1,
	STR: 2,
	DOUBLE: 3,
	INT: 4,
	STRUCT: 5
};

var VarTypeNames = ['none', 'label', 'str', 'double', 'int', 'struct'];

if(typeof HSPonJS != 'undefined') {
	HSPonJS.VarType = VarType;
	HSPonJS.VarTypeNames = VarTypeNames;
}

var CalcCodeNames = 'add,sub,mul,div,mod,and,or,xor,eq,ne,gt,lt,gteq,lteq,rsh,lsh'.split(',');
var CalcCodeOperatorMarks = '+,-,*,/,\\,&,|,^,==,!=,>,<,>=,<=,>>,<<'.split(',');

var CalcCode = {
	ADD:   0,
	SUB:   1,
	MUL:   2,
	DIV:   3,
	MOD:   4,
	AND:   5,
	OR:    6,
	XOR:   7,
	EQ:    8,
	NE:    9,
	GT:   10,
	LT:   11,
	GTEQ: 12,
	LTEQ: 13,
	RSH:  14,
	LSH:  15
};

function getCalcCodeName(calcCode) {
	return CalcCodeNames[calcCode];
}

function getCalcCodeOperatorMarks(calcCode) {
	return CalcCodeOperatorMarks[calcCode];
}

function isCompareCalcCode(calcCode) {
	return CalcCode.EQ <= calcCode && calcCode <= CalcCode.LTEQ;
}

if(typeof HSPonJS != 'undefined') {
	HSPonJS.CalcCodeNames = CalcCodeNames;
	HSPonJS.CalcCodeOperatorMarks = CalcCodeOperatorMarks;
	HSPonJS.CalcCode = CalcCode;
	HSPonJS.getCalcCodeName = getCalcCodeName;
	HSPonJS.getCalcCodeOperatorMarks = getCalcCodeOperatorMarks;
}

var Formatter = {
	sprintf: function(format, args) {
		var argsIndex = 0;
		var re = /%[- #+0-9.]*[\s\S]?/g;
		var result = format.replace(re, function(str){
			var pos = 1; // '%'.length
			var flags = {};
			var width = 0;
			var prec = null;
			while(true) {
				var c = str.charAt(pos);
				switch(c) {
				case ' ': case '#': case '+': case '-': case '0':
					flags[c] = true;
					pos ++;
					continue;
				case '1': case '2': case '3': case '4': case '5':
				case '6': case '7': case '8': case '9':
					var matched = str.slice(pos).match(/^\d+/)[0];
					width = + matched;
					pos += matched.length;
					continue;
				case '.':
					pos ++;
					var matched = str.slice(pos).match(/^\d*/)[0];
					pos += matched.length;
					prec = matched.length > 0 ? + matched : 0;
					continue;
				default:
					break;
				}
				break;
			}
			var specifier = str.charAt(pos);
			if(specifier == '%') {
				return '%';
			}
			var arg = args[argsIndex++];
			if(!arg) {
				throw new HSPError(ErrorCode.NO_DEFAULT);
			}
			var convert = Formatter.ConvertTable[specifier];
			if(!convert) return specifier;
			return convert(arg, flags, width, prec);
		});
		if(argsIndex < args.length) {
			throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);
		}
		return Utils.getCStr(result);
	},
	sprintfForJS: function(format) {
		var args = [];
		for(var i = 1; i < arguments.length; i ++) {
			var arg = arguments[i];
			switch(typeof arg) {
			case 'number':
				args.push(new DoubleValue(arg));
				break;
			case 'string':
				args.push(new StrValue(arg));
				break;
			default:
				args.push(arg);
			}
		}
		return Formatter.sprintf(format, args);
	},
	addSpaces: function(str, flags, width) {
		var spaces = Utils.strTimes(' ', Math.max(width - str.length, 0));
		if(flags['-']) {
			return str + spaces;
		} else {
			return spaces + str;
		}
	},
	addZeros: function(str, width) {
		var length = width - str.length;
		var zeros = Utils.strTimes('0', Math.max(length, 0));
		return zeros + str;
	},
	signPrefix: function(isNegative, flags) {
		if(isNegative) {
			return '-';
		} else if(flags['+']) {
			return '+';
		} else if(flags[' ']) {
			return ' ';
		} else {
			return '';
		}
	},
	convertInt: function(val, flags, width, prec, signed, radix, pre) {
		if(!signed) {
			val >>>= 0;
		}
		var isNegative = val < 0;
		val = Math.abs(val);
		var str = val.toString(radix);
		var prefix = '';
		if(flags['#'] && val != 0) prefix = pre;
		if(signed) {
			prefix = Formatter.signPrefix(isNegative, flags);
		}
		if(prec != null) {
			if(prefix == '0' && prec > str.length) {
				prefix = '';
			}
			str = Formatter.addZeros(str, prec);
		} else if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width - prefix.length);
		}
		str = prefix + str;
		return Formatter.addSpaces(str, flags, width);
	},
	convertMemoryAddress: function(val, flags, width, prec) {
		return Formatter.convertInt(val, {'-': flags['-']}, width, 8, false, 16, '').toUpperCase();
	},
	convertExp: function(val, flags, width, prec) {
		if(prec == null) prec = 6;
		var isNegative = val != Math.abs(val);
		val = Math.abs(val);
		var mantissa, exponent;
		if(isNaN(val)) {
			mantissa = Formatter.convertNaN(prec);
			exponent = 0;
		} else if(val == Infinity) {
			mantissa = Formatter.convertInf(prec);
			exponent = 0;
		} else {
			var str = val.toExponential(Math.min(prec, 16));
			var matched = /^(\d(?:\.\d+)?)e([+-]\d+)$/.exec(str);
			mantissa = matched[1], exponent = parseInt(matched[2]);
			matched = /\.(\d+)e/.exec(str);
			if(matched && matched[1].length < prec) {
				mantissa += Utils.strTimes("0", prec - matched[1].length);
			}
		}
		if(flags['#'] && str.indexOf('.') == -1) mantissa += '.';
		str = mantissa + "e" + Formatter.convertInt(exponent, {'+': true}, 0, 3, true, 10, '');
		var prefix = Formatter.signPrefix(isNegative, flags);
		if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width - prefix.length);
		}
		str = prefix + str;
		return Formatter.addSpaces(str, flags, width);
	},
	convertFloatG: function(val, flags, width, prec) {
		if(prec == null) prec = 6;
		prec = Math.max(prec, 1);
		var str;
		var isNegative = val != Math.abs(val);
		val = Math.abs(val);
		if(isNaN(val) || val == Infinity || val == 0 || (1e-4 <= val && val < Math.pow(10, prec) - 0.5)) {
			var prec2;
			if(isNaN(val) || val == Infinity) {
				prec2 = prec - 1;
			} else if(val == 0.0) {
				prec2 = prec;
			} else {
				var exponent = Math.floor(Math.log(val) / Math.LN10);
				prec2 = prec - exponent - 1;
				if(prec == 1 && val * Math.pow(10, -exponent) >= 9.5) prec2 --;
			}
			str = Formatter.convertFloatSub(val, prec2);
			if(flags['#'] && str.indexOf('.') == -1) str += ".";
		} else {
			str = Formatter.convertExp(val, {'#': flags['#']}, 0, Math.min(prec - 1, 16));
		}
		if(!flags['#']) {
			str = str.replace(/\.([^e]*?)0+(?=e|$)/i, function(s, d) { return d.length > 0 ? '.' + d : ''; });
		}
		var prefix = Formatter.signPrefix(isNegative, flags);
		if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width - prefix.length);
		}
		str = prefix + str;
		return Formatter.addSpaces(str, flags, width);
	},
	convertFloat: function(val, flags, width, prec) {
		if(prec == null) prec = 6;
		var isNegative = val != Math.abs(val);
		val = Math.abs(val);
		var str = Formatter.convertFloatSub(val, prec);
		if(flags['#'] && str.indexOf('.') == -1) str += ".";
		var prefix = Formatter.signPrefix(isNegative, flags);
		if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width - prefix.length);
		}
		str = prefix + str;
		return Formatter.addSpaces(str, flags, width);
	},
	convertFloatSub: function(val, prec) {
		if(isNaN(val)) return Formatter.convertNaN(prec);
		if(val == Infinity) return Formatter.convertInf(prec);
		var exponent = val != 0 ? Math.floor(Math.log(val) / Math.LN10) : 0;
		var str;
		if(exponent < 0 && -exponent > prec) {
			var up = -exponent-1 == prec && val * Math.pow(10, prec) >= 0.5;
			if(prec == 0) {
				str = up ? '1' : '0';
			} else {
				str = '0.' + Utils.strTimes('0', prec - 1) + (up ? '1' : '0');
			}
			return str;
		}
		var i = 0;
		str = val.toExponential(Math.min(exponent + prec, 16));
		var matched = /^(\d(?:\.\d+)?)e([+-]\d+)$/.exec(str);
		var mantissa = matched[1], exponent = parseInt(matched[2]);
		var matched = /\.(\d+)e/.exec(str);
		if(matched && matched[1].length < exponent + prec) {
			mantissa += Utils.strTimes("0", exponent + prec - matched[1].length);
		}
		if(!matched && exponent + prec > 0) {
			mantissa += '.' + Utils.strTimes("0", exponent + prec);
		}
		str = mantissa;
		if(exponent > 0) {
			str = str.charAt(0) + str.substr(2, exponent) + (prec != 0 ? '.' + str.slice(2 + exponent) : '');
		} else if(exponent < 0) {
			str = '0.' + Utils.strTimes('0', -exponent-1) + str.charAt(0) + str.slice(2);
		}
		return str;
	},
	convertNaN: function(prec) {
		switch(prec) {
		case 0: return '1';
		case 1: return '1.$';
		case 2: return '1.#J';
		case 3: return '1.#IO';
		default:return '1.#IND' + Utils.strTimes('0', prec - 4);
		}
	},
	convertInf: function(prec) {
		switch(prec) {
		case 0: return '1';
		case 1: return '1.$';
		case 2: return '1.#J';
		case 3: return '1.#IO';
		default:return '1.#INF' + Utils.strTimes('0', prec - 4);
		}
	}
};

Formatter.ConvertTable = {
	'E': function(val, flags, width, prec) {
		val = val.toDoubleValue()._value;
		return Formatter.convertExp(val, flags, width, prec).toUpperCase();
	},
	'G': function(val, flags, width, prec) {
		val = val.toDoubleValue()._value;
		return Formatter.convertFloatG(val, flags, width, prec).toUpperCase();
	},
	'X': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, false, 16, '0X').toUpperCase();
	},
	'c': function(val, flags, width, prec) {
		var str = String.fromCharCode(val.toIntValue()._value & 0xff);
		if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width);
		}
		return Formatter.addSpaces(str, flags, width);
	},
	'd': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, true, 10, '');
	},
	'e': function(val, flags, width, prec) {
		val = val.toDoubleValue()._value;
		return Formatter.convertExp(val, flags, width, prec);
	},
	'f': function(val, flags, width, prec) {
		val = val.toDoubleValue()._value;
		return Formatter.convertFloat(val, flags, width, prec);
	},
	'g': function(val, flags, width, prec) {
		val = val.toDoubleValue()._value;
		return Formatter.convertFloatG(val, flags, width, prec);
	},
	'i': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, true, 10, '');
	},
	'o': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, false, 8, '0');
	},
	'p': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertMemoryAddress(val, flags, width, prec);
	},
	's': function(val, flags, width, prec) {
		var str = val.toStrValue()._value;
		if(prec != null) {
			str = str.slice(0, prec);
		}
		if(flags['0'] && !flags['-']) {
			str = Formatter.addZeros(str, width);
		}
		return Formatter.addSpaces(str, flags, width);
	},
	'u': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, false, 10, '');
	},
	'x': function(val, flags, width, prec) {
		val = val.toIntValue()._value;
		return Formatter.convertInt(val, flags, width, prec, false, 16, '0x');
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Formatter = Formatter;
}


var ErrorCode = {
	NONE:                       0,
	UNKNOWN_CODE:               1,
	SYNTAX:                     2,
	ILLEGAL_FUNCTION:           3,
	WRONG_EXPRESSION:           4,
	NO_DEFAULT:                 5,
	TYPE_MISMATCH:              6,
	ARRAY_OVERFLOW:             7,
	LABEL_REQUIRED:             8,
	TOO_MANY_NEST:              9,
	RETURN_WITHOUT_GOSUB:      10,
	LOOP_WITHOUT_REPEAT:       11,
	FILE_IO:                   12,
	PICTURE_MISSING:           13,
	EXTERNAL_EXECUTE:          14,
	PRIORITY:                  15,
	TOO_MANY_PARAMETERS:       16,
	TEMP_BUFFER_OVERFLOW:      17,
	WRONG_NAME:                18,
	DIVIDED_BY_ZERO:           19,
	BUFFER_OVERFLOW:           20,
	UNSUPPORTED_FUNCTION:      21,
	EXPRESSION_COMPLEX:        22,
	VARIABLE_REQUIRED:         23,
	INTEGER_REQUIRED:          24,
	BAD_ARRAY_EXPRESSION:      25,
	OUT_OF_MEMORY:             26,
	TYPE_INITALIZATION_FAILED: 27,
	NO_FUNCTION_PARAMETERS:    28,
	STACK_OVERFLOW:            29,
	INVALID_PARAMETER:         30,
	INVALID_ARRAYSTORE:        31,
	INVALID_FUNCPARAM:         32,
	WINDOW_OBJECT_FULL:        33,
	INVALID_ARRAY:             34,
	STRUCT_REQUIRED:           35,
	INVALID_STRUCT_SOURCE:     36,
	INVALID_TYPE:              37,
	DLL_ERROR:                 38,
	COMDLL_ERROR:              39,
	NORETVAL:                  40,
	FUNCTION_SYNTAX:           41,
	INTJUMP:                   42,
	EXITRUN:                   43,
	MAX:                       44,
	
	// 拡張エラー
	EXERROR_START:           1024,
	UNINITIALIZED_VARIABLE:  1025
};

var ErrorMessages = [
	"",												// 0
	"システムエラーが発生しました",					// 1
	"文法が間違っています",							// 2
	"パラメータの値が異常です",						// 3
	"計算式でエラーが発生しました",					// 4
	"パラメータの省略はできません",					// 5
	"パラメータの型が違います",						// 6
	"配列の要素が無効です",							// 7
	"有効なラベルが指定されていません",				// 8
	"サブルーチンやループのネストが深すぎます",		// 9
	"サブルーチン外のreturnは無効です",				// 10
	"repeat外でのloopは無効です",					// 11
	"ファイルが見つからないか無効な名前です",		// 12
	"画像ファイルがありません",						// 13
	"外部ファイル呼び出し中のエラーです",			// 14
	"計算式でカッコの記述が違います",				// 15
	"パラメータの数が多すぎます",					// 16
	"文字列式で扱える文字数を越えました",			// 17
	"代入できない変数名を指定しています",			// 18
	"0で除算しました",								// 19
	"バッファオーバーフローが発生しました",			// 20
	"サポートされない機能を選択しました",			// 21
	"計算式のカッコが深すぎます",					// 22
	"変数名が指定されていません",					// 23
	"整数以外が指定されています",					// 24
	"配列の要素書式が間違っています",				// 25
	"メモリの確保ができませんでした",				// 26
	"タイプの初期化に失敗しました",					// 27
	"関数に引数が設定されていません",				// 28
	"スタック領域のオーバーフローです",				// 29
	"無効な名前がパラメーターに指定されています",	// 30
	"異なる型を持つ配列変数に代入しました",			// 31
	"関数のパラメーター記述が不正です",				// 32
	"オブジェクト数が多すぎます",					// 33
	"配列・関数として使用できない型です",			// 34
	"モジュール変数が指定されていません",			// 35
	"モジュール変数の指定が無効です",				// 36
	"変数型の変換に失敗しました",					// 37
	"外部DLLの呼び出しに失敗しました",				// 38
	"外部オブジェクトの呼び出しに失敗しました",		// 39
	"関数の戻り値が設定されていません。",			// 40
	"関数を命令として記述しています。\n(HSP2から関数化された名前を使用している可能性があります)",			// 41
	"*"
];

var ExErrorMessages = [
	"",											// 1024
	"未初期化の変数を参照しました"				// 1025
];

function getErrorMessage(errorCode) {
	if(0 <= errorCode && errorCode < ErrorMessages.length) {
		return ErrorMessages[errorCode];
	}
	if(ErrorCode.EXERROR_START <= errorCode && errorCode < ErrorCode.EXERROR_START + ExErrorMessages.length) {
		return ExErrorMessages[errorCode - ErrorCode.EXERROR_START];
	}
	return undefined;
}

function HSPException() {}

function StopException() {}
StopException.prototype = new HSPException;

function EndException(status) {
	this.status = status;
}
EndException.prototype = new HSPException;

function WaitException(msec) {
	this.msec = msec;
}
WaitException.prototype = new HSPException;

function FileReadException(path, success, error) {
	this.path = path;
	this.success = success;
	this.error = error;
}
FileReadException.prototype = new HSPException;

function VoidException() {
}
VoidException.prototype = new HSPException;

function HSPError(errcode, message) {
	this.errcode = errcode;
	this.message = message;
}
HSPError.prototype = new HSPException;
HSPError.prototype.getErrorMessage = function() {
	if(this.message != undefined) return this.message;
	return getErrorMessage(this.errcode);
};


if(typeof HSPonJS != 'undefined') {
	HSPonJS.ErrorCode = ErrorCode;
	HSPonJS.ErrorMessages = ErrorMessages;
	HSPonJS.HSPException = HSPException;
	HSPonJS.WaitException = WaitException;
	HSPonJS.StopException = StopException;
	HSPonJS.EndException = EndException;
	HSPonJS.FileReadException = FileReadException;
	HSPonJS.VoidException = VoidException;
	HSPonJS.HSPError = HSPError;
	HSPonJS.getErrorMessage = getErrorMessage;
}

function AXData(data) {
	this.data = data;
	var p = new BinaryParser(data, 0, 96);
	this.h1          = p.readChar();
	this.h2          = p.readChar();
	this.h3          = p.readChar();
	this.h4          = p.readChar();
	if(this.h1 != 0x48 || this.h2 != 0x53 || this.h3 != 0x50 || this.h4 != 0x33) {
		throw new Error('invalid hsp object data');
	}
	this.version     = p.readInt();
	this.max_val     = p.readInt();
	this.allsize     = p.readInt();
	this.pt_cs       = p.readInt();
	this.max_cs      = p.readInt();
	this.pt_ds       = p.readInt();
	this.max_ds      = p.readInt();
	this.pt_ot       = p.readInt();
	this.max_ot      = p.readInt();
	this.pt_dinfo    = p.readInt();
	this.max_dinfo   = p.readInt();
	this.pt_linfo    = p.readInt();
	this.max_linfo   = p.readInt();
	this.pt_finfo    = p.readInt();
	this.max_finfo   = p.readInt();
	this.pt_minfo    = p.readInt();
	this.max_minfo   = p.readInt();
	this.pt_finfo2   = p.readInt();
	this.max_finfo2  = p.readInt();
	this.pt_hpidat   = p.readInt();
	this.max_hpi     = p.readShort();
	this.max_varhpi  = p.readShort();
	this.bootoption  = p.readInt();
	this.runtime     = p.readInt();
	this.cs = data.substr(this.pt_cs, this.max_cs);
	this.ds = data.substr(this.pt_ds, this.max_ds);
	this.ot = data.substr(this.pt_ot, this.max_ot);
	this.dinfo = data.substr(this.pt_dinfo, this.max_dinfo);
	this.linfo = data.substr(this.pt_linfo, this.max_linfo);
	this.finfo = data.substr(this.pt_finfo, this.max_finfo);
	this.minfo = data.substr(this.pt_minfo, this.max_minfo);
	this.finfo2 = data.substr(this.pt_finfo2, this.max_finfo2);
	this.hpidat = data.substr(this.pt_hpidat, this.max_hpi);
	this.tokens = this.createTokens();
	this.variableNames = this.createVariableNames();
	this.funcsInfo = this.createFuncsInfo();
	this.prmsInfo = this.createPrmsInfo();
	
	p = new BinaryParser(this.ot);
	this.labels = [];
	this.labelsMap = {}; // key: position in cs, val: array of label ids
	
	var i = 0;
	while(!p.isEOS()) {
		var pos = p.readInt();
		if(pos in this.labelsMap) {
			this.labelsMap[pos].push(i);
		} else {
			this.labelsMap[pos] = [i];
		}
		this.labels.push(pos);
		i ++;
		
	}
}

AXData.prototype = {
	createTokens: function() {
		var tokens = [];
		var cs = new BinaryParser(this.cs);
		var dinfo = new BinaryParser(this.dinfo);
		var pos = 0;
		var fileName, lineNo, lineSize = 0;
		while(!cs.isEOS()) {
			
			var c = cs.readUShort();
			var type = c & 0x1fff;
			var ex1 = (c & 0x2000) != 0;
			var ex2 = (c & 0x4000) != 0;
			var code;
			if(c & 0x8000) {
				code = cs.readInt();
			} else {
				code = cs.readUShort();
			}
			var skipOffset = undefined;
			if(type == Token.Type.CMPCMD) {
				skipOffset = cs.readUShort();
			}
			var size = cs.offset / 2 - pos;
			while(true) {
				var dinfoPos = dinfo.offset;
				var ofs = dinfo.readUChar();
				if(ofs == 255) {
					dinfo.offset = dinfoPos;
					break;
				}
				if(ofs == 254) {
					var dsOffset = dinfo.readUInt24();
					if(dsOffset != 0 || fileName == undefined) {
						fileName = this.getDSStr(dsOffset);
					}
					lineNo = dinfo.readUShort();
					continue;
				}
				if(ofs == 253) {
					dinfo.readUInt24();
					dinfo.readUShort();
					continue;
				}
				if(ofs == 252) {
					ofs = dinfo.readUShort();
				}
				if(lineSize < ofs) {
					dinfo.offset = dinfoPos;
					break;
				}
				lineSize = 0;
				lineNo ++;
			}
			lineSize += size;
			tokens.push(new Token(this, type, ex1, ex2, code,
			                      fileName, lineNo, pos, size, skipOffset));
			pos += size;
		}
		return tokens;
	},
	createVariableNames: function() {
		var variableNames = new Array(this.max_val);
		var dinfo = new BinaryParser(this.dinfo);
		var i = 0;
		while(true) {
			var ofs = dinfo.readUChar();
			if(ofs == 255) break;
			if(ofs == 254) {
				dinfo.readUInt24();
				dinfo.readUShort();
			}
			if(ofs == 253) {
				variableNames[i++] = this.getDSStr(dinfo.readUInt24());
				dinfo.readUShort();
			}
			if(ofs == 252) {
				ofs = dinfo.readUShort();
			}
		}
		return variableNames;
	},
	createFuncsInfo: function() {
		var funcsInfo = [];
		var finfo = new BinaryParser(this.finfo);
		while(!finfo.isEOS()) {
			var index = finfo.readShort();
			var subid = finfo.readShort();
			var prmindex = finfo.readInt();
			var prmmax = finfo.readInt();
			var nameidx = finfo.readInt();
			var size = finfo.readInt();
			var otindex = finfo.readInt();
			var funcflag = finfo.readInt();
			var name = this.getDSStr(nameidx);
			funcsInfo.push({index: index,
			                subid: subid,
			                prmindex: prmindex,
			                prmmax: prmmax,
			                nameidx: nameidx,
			                size: size,
			                otindex: otindex,
			                funcflag: funcflag,
			                name: name});
		}
		return funcsInfo;
	},
	createPrmsInfo: function() {
		var prmsInfo = [];
		var minfo = new BinaryParser(this.minfo);
		while(!minfo.isEOS()) {
			var mptype = minfo.readShort();
			var subid = minfo.readShort();
			var offset = minfo.readInt();
			prmsInfo.push({mptype: mptype,
			               subid: subid,
			               offset: offset});
		}
		return prmsInfo;
	},
	getDSStr: function(index) {
		return Utils.getCStr(this.ds, index);
	},
	getDSDouble: function(index) {
		return BinaryParser.readDouble(this.ds, index);
	}
};

function Token(objectData, type, ex1, ex2, code,
                           fileName, lineNo, pos, size, skipOffset) {
	this.type = type;
	this.ex1 = ex1;
	this.ex2 = ex2;
	this.code = this.val = code;
	this.fileName = fileName;
	this.lineNo = lineNo;
	this.pos = pos;
	this.size = size;
	this.skipOffset = skipOffset;
	if(type == Token.Type.STRING) {
		this.val = objectData.getDSStr(code);
	} else if(type == Token.Type.DNUM) {
		this.val = objectData.getDSDouble(code);
	}
}

Token.Type = {
	MARK:       0,
	VAR:        1,
	STRING:     2,
	DNUM:       3,
	INUM:       4,
	STRUCT:     5,
	XLABEL:     6,
	LABEL:      7,
	INTCMD:     8,
	EXTCMD:     9,
	EXTSYSVAR: 10,
	CMPCMD:    11,
	MODCMD:    12,
	INTFUNC:   13,
	SYSVAR:    14,
	PROGCMD:   15,
	DLLFUNC:   16,
	DLLCTRL:   17,
	USERDEF:   18
};

var MPType = {
	NONE:          0,
	VAR:           1,
	STRING:        2,
	DNUM:          3,
	INUM:          4,
	STRUCT:        5,
	LABEL:         7,
	LOCALVAR:     -1,
	ARRAYVAR:     -2,
	SINGLEVAR:    -3,
	FLOAT:        -4,
	STRUCTTAG:    -5,
	LOCALSTRING:  -6,
	MODULEVAR:    -7,
	PPVAL:        -8,
	PBMSCR:       -9,
	PVARPTR:     -10,
	IMODULEVAR:  -11,
	IOBJECTVAR:  -12,
	LOCALWSTR:   -13,
	FLEXSPTR:    -14,
	FLEXWPTR:    -15,
	PTR_REFSTR:  -16,
	PTR_EXINFO:  -17,
	PTR_DPMINFO: -18,
	NULLPTR:     -19,
	TMODULEVAR:  -20
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.AXData = AXData;
	HSPonJS.Token = Token;
	HSPonJS.MPType = MPType;
}

var ISeq;
var ISeqElem;
var Label;
var Insn;
var getInsnCodeName;

(function() {

ISeq = function() {
	this.firstGuard = new ISeqElem;
	this.lastGuard = new ISeqElem;
	link(this.firstGuard, this.lastGuard);
}

function link() {
	for(var i = 0; i < arguments.length - 1; i ++) {
		var a = arguments[i];
		var b = arguments[i+1];
		if(a) a.next = b;
		if(b) b.prev = a;
	}
}

ISeq.link = link;

ISeq.prototype = {
	first: function() {
		return this.firstGuard.next;
	},
	last: function() {
		return this.lastGuard.prev;
	},
	push: function(elem) {
		link(this.last(), elem, this.lastGuard);
		return this;
	},
	pop: function() {
		return this.last().remove();
	},
	shift: function() {
		return this.first().remove();
	},
	unshift: function(elem) {
		return this.first().insertBefore(elem);
	},
	forEach: function(callback) {
		var elem = this.first();
		var end = this.lastGuard;
		while(elem != end) {
			var next = elem.next;
			callback(elem);
			elem = next;
		}
	},
	forEachOnlyInsn: function(callback) {
		var elem = this.first();
		while(elem) {
			var next = elem.next;
			if(elem.type == ISeqElem.Type.INSN) {
				callback(elem);
			}
			elem = next;
		}
	},
	getLength: function() {
		var length = 0;
		this.forEach(function() { length ++; });
		return length;
	},
	toString: function() {
		return '<ISeq:len='+this.getLength()+'>';
	},
	firstInsn: function() {
		return this.firstGuard.getNextInsn();
	}
};

ISeqElem = function() {
	this.prev = null;
	this.next = null;
};

ISeqElem.Type = {
	NONE:  0,
	INSN:  1,
	LABEL: 2
};

ISeqElem.prototype = {
	type: ISeqElem.Type.NONE,
	remove: function() {
		link(this.prev, this.next);
		link(null, this, null);
		return this;
	},
	replace: function(insn) {
		link(this.prev, insn, this.next);
		link(null, this, null);
	},
	insertAfter: function() {
		var args = [this];
		args.push.apply(args, arguments);
		args.push(this.next);
		link.apply(null, args);
	},
	insertBefore: function(insn) {
		var args = [this.prev];
		args.push.apply(args, arguments);
		args.push(this);
		link.apply(null, args);
	},
	getNextInsn: function() {
		var elem = this.next;
		while(elem) {
			if(elem.type == ISeqElem.Type.INSN) {
				return elem;
			}
			elem = elem.next;
		}
		return null;
	},
	getPrevInsn: function() {
		var elem = this.prev;
		while(elem) {
			if(elem.type == ISeqElem.Type.INSN) {
				return elem;
			}
			elem = elem.prev;
		}
		return null;
	},
	getNextElem: function() {
		var elem = this.next;
		while(elem) {
			if(elem.type == ISeqElem.Type.INSN || elem.type == ISeqElem.Type.NONE) {
				return elem;
			}
			elem = elem.next;
		}
		return null;
	},
	getPrevElem: function() {
		var elem = this.prev;
		while(elem) {
			if(elem.type == ISeqElem.Type.INSN || elem.type == ISeqElem.Type.NONE) {
				return elem;
			}
			elem = elem.prev;
		}
		return null;
	}
};

Label = function() {
	ISeqElem.call(this);
	this.pos_ = -1;
};

Label.prototype = new ISeqElem;

Utils.objectExtend(Label.prototype, {
	toString: function() {
		return '<Label:'+this.pos_+'>';
	},
	getInsn: function() {
		return this.getNextInsn();
	},
	getPos: function() {
		return this.pos_;
	},
	definePos: function() {
		var insn = this.getInsn();
		if(insn) {
			this.pos_ = insn.index;
		}
	},
	type: ISeqElem.Type.LABEL
});

Insn = function(code, opts, fileName, lineNo) {
	ISeqElem.call(this);
	this.code = code;
	this.opts = opts;
	this.fileName = fileName;
	this.lineNo = lineNo;
	this.index = -1;
};

Insn.prototype = new ISeqElem;

Utils.objectExtend(Insn.prototype, {
	toString: function() {
		return '<Insn:'+getInsnCodeName(this.code)+' <' + this.opts.join(', ') + '> ('+this.fileName + ':' + this.lineNo+')>';
	},
	clone: function() {
		return new Insn(this.code, this.opts, this.fileName, this.lineNo);
	},
	type: ISeqElem.Type.INSN
});

var codeNames = [
	'NOP',
	'PUSH_VAR',
	'GET_VAR',
	'POP',
	'POP_N',
	'DUP',
	'GOTO',
	'IFNE',
	'IFEQ',
	'ASSIGN',
	'COMPOUND_ASSIGN',
	'INC',
	'DEC',
	'CALL_BUILTIN_CMD',
	'CALL_BUILTIN_FUNC',
	'CALL_USERDEF_CMD',
	'CALL_USERDEF_FUNC',
	'NEWMOD',
	'RETURN',
	'REPEAT',
	'LOOP',
	'CONTINUE',
	'BREAK',
	'FOREACH',
	'EACHCHK',
	'GOSUB',
	'GOTO_EXPR',
	'GOSUB_EXPR',
	'EXGOTO',
	'ON'
];

getInsnCodeName = function(insnCode) {
	return codeNames[insnCode];
}

Insn.Code = {};
(function() {
	for(var i = 0; i < codeNames.length; i ++) {
		var name = codeNames[i];
		Insn.Code[name] = i;
	}
})();

})();

if(typeof HSPonJS != 'undefined') {
	HSPonJS.ISeq = ISeq;
	HSPonJS.ISeqElem = ISeqElem;
	HSPonJS.Label = Label;
	HSPonJS.Insn = Insn;
	HSPonJS.getInsnCodeName = getInsnCodeName;
}

function UserDefFunc(isCType, name, label, paramTypes) {
	this.isCType = isCType;
	this.name = name;
	this.label = label;
	this.paramTypes = paramTypes;
}

UserDefFunc.prototype.toString = function() {
	return '<UserDefFunc:'+this.name+' isCType='+this.isCType+', label='+this.label+', paramTypes=['+this.paramTypes.join(', ')+']>';
};

function Module(name, constructor, destructor, membersCount) {
	this.name = name;
	this.constructor = constructor;
	this.destructor = destructor;
	this.membersCount = membersCount;
}

Module.prototype.toString = function() {
	return '<Module:'+this.name+' membersCount='+this.membersCount+'>';
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.UserDefFunc = UserDefFunc;
	HSPonJS.Module = Module;
}


var BuiltinFuncNames = [];

BuiltinFuncNames[Token.Type.INTCMD] = {
	0x000: 'onexit',
	0x001: 'onerror',
	0x002: 'onkey',
	0x003: 'onclick',
	0x004: 'oncmd',
	0x011: 'exist',
	0x012: 'delete',
	0x013: 'mkdir',
	0x014: 'chdir',
	0x015: 'dirlist',
	0x016: 'bload',
	0x017: 'bsave',
	0x018: 'bcopy',
	0x019: 'memfile',
	0x01a: 'poke',
	0x01b: 'wpoke',
	0x01c: 'lpoke',
	0x01d: 'getstr',
	0x01e: 'chdpm',
	0x01f: 'memexpand',
	0x020: 'memcpy',
	0x021: 'memset',
	0x022: 'notesel',
	0x023: 'noteadd',
	0x024: 'notedel',
	0x025: 'noteload',
	0x026: 'notesave',
	0x027: 'randomize',
	0x028: 'noteunsel',
	0x029: 'noteget',
	0x02a: 'split'
};

BuiltinFuncNames[Token.Type.EXTCMD] = {
	0x000: 'button',
	0x001: 'chgdisp',
	0x002: 'exec',
	0x003: 'dialog',
	0x008: 'mmload',
	0x009: 'mmplay',
	0x00a: 'mmstop',
	0x00b: 'mci',
	0x00c: 'pset',
	0x00d: 'pget',
	0x00e: 'syscolor',
	0x00f: 'mes',
	0x010: 'title',
	0x011: 'pos',
	0x012: 'circle',
	0x013: 'cls',
	0x014: 'font',
	0x015: 'sysfont',
	0x016: 'objsize',
	0x017: 'picload',
	0x018: 'color',
	0x019: 'palcolor',
	0x01a: 'palette',
	0x01b: 'redraw',
	0x01c: 'width',
	0x01d: 'gsel',
	0x01e: 'gcopy',
	0x01f: 'gzoom',
	0x020: 'gmode',
	0x021: 'bmpsave',
	0x022: 'hsvcolor',
	0x023: 'getkey',
	0x024: 'listbox',
	0x025: 'chkbox',
	0x026: 'combox',
	0x027: 'input',
	0x028: 'mesbox',
	0x029: 'buffer',
	0x02a: 'screen',
	0x02b: 'bgscr',
	0x02c: 'mouse',
	0x02d: 'objsel',
	0x02e: 'groll',
	0x02f: 'line',
	0x030: 'clrobj',
	0x031: 'boxf',
	0x032: 'objprm',
	0x033: 'objmode',
	0x034: 'stick',
	0x035: 'grect',
	0x036: 'grotate',
	0x037: 'gsquare',
	0x038: 'gradf',
	0x039: 'objimage',
	0x03a: 'objskip',
	0x03b: 'objenable'
};

BuiltinFuncNames[Token.Type.EXTSYSVAR] = {
	0x000: 'mousex',
	0x001: 'mousey',
	0x002: 'mousew',
	0x003: 'hwnd',
	0x004: 'hinstance',
	0x005: 'hdc',
	0x100: 'ginfo',
	0x101: 'objinfo',
	0x102: 'dirinfo',
	0x103: 'sysinfo'
};

BuiltinFuncNames[Token.Type.CMPCMD] = {
	0x000: 'if',
	0x001: 'else'
};

BuiltinFuncNames[Token.Type.INTFUNC] = {
	0x000: 'int',
	0x001: 'rnd',
	0x002: 'strlen',
	0x003: 'length',
	0x004: 'length2',
	0x005: 'length3',
	0x006: 'length4',
	0x007: 'vartype',
	0x008: 'gettime',
	0x009: 'peek',
	0x00a: 'wpeek',
	0x00b: 'lpeek',
	0x00c: 'varptr',
	0x00d: 'varuse',
	0x00e: 'noteinfo',
	0x00f: 'instr',
	0x010: 'abs',
	0x011: 'limit',
	0x100: 'str',
	0x101: 'strmid',
	0x103: 'strf',
	0x104: 'getpath',
	0x105: 'strtrim',
	0x180: 'sin',
	0x181: 'cos',
	0x182: 'tan',
	0x183: 'atan',
	0x184: 'sqrt',
	0x185: 'double',
	0x186: 'absf',
	0x187: 'expf',
	0x188: 'logf',
	0x189: 'limitf'
};

BuiltinFuncNames[Token.Type.SYSVAR] = {
	0x000: 'system',
	0x001: 'hspstat',
	0x002: 'hspver',
	0x003: 'stat',
	0x004: 'cnt',
	0x005: 'err',
	0x006: 'strsize',
	0x007: 'looplev',
	0x008: 'sublev',
	0x009: 'iparam',
	0x00a: 'wparam',
	0x00b: 'lparam',
	0x00c: 'refstr',
	0x00d: 'refdval'
};

BuiltinFuncNames[Token.Type.PROGCMD] = {
	0x000: 'goto',
	0x001: 'gosub',
	0x002: 'return',
	0x003: 'break',
	0x004: 'repeat',
	0x005: 'loop',
	0x006: 'continue',
	0x007: 'wait',
	0x008: 'await',
	0x009: 'dim',
	0x00a: 'sdim',
	0x00b: 'foreach',
	0x00c: 'eachchk',
	0x00d: 'dimtype',
	0x00e: 'dup',
	0x00f: 'dupptr',
	0x010: 'end',
	0x011: 'stop',
	0x012: 'newmod',
	0x013: 'setmod',
	0x014: 'delmod',
	0x016: 'mref',
	0x017: 'run',
	0x018: 'exgoto',
	0x019: 'on',
	0x01a: 'mcall',
	0x01b: 'assert',
	0x01c: 'logmes'
};

BuiltinFuncNames[Token.Type.DLLCTRL] = {
	0x000: 'newcom',
	0x001: 'querycom',
	0x002: 'delcom',
	0x003: 'cnvstow',
	0x004: 'comres',
	0x005: 'axobj',
	0x006: 'winobj',
	0x007: 'sendmsg',
	0x008: 'comevent',
	0x009: 'comevarg',
	0x00a: 'sarrayconv',
	0x100: 'callfunc',
	0x101: 'cnvwtos',
	0x102: 'comevdisp',
	0x103: 'libptr'
};

var BuiltinFuncNameToIdTable = {};
(function() {
	for(var type in BuiltinFuncNames) {
		var t = BuiltinFuncNames[type];
		for(var subid in t) {
			BuiltinFuncNameToIdTable[t[subid]] = subid << 13 | type;
		}
	}
})();

function getTypeByTypeAndSubid(typeAndSubid) {
	return typeAndSubid & 0x1fff;
}

function getSubidByTypeAndSubid(typeAndSubid) {
	return typeAndSubid >> 13;
}


/*
a = gets nil; 0
b = a.scan(/^\t"\$([0-9a-f]+) (\d+) (\w+)",$/).group_by{|s,t,n|t.to_i}
typenames = gets(nil).scan(/^\t(\w+)/).flatten
c = Hash[*b.to_a.sort_by{|k,v|k}.flatten(1)]
c.values[1].reject!{|id,t,name|name=="print"}
c.map{|t,x| "Names[Token.Type.%s] = {\n%s\n};" % [typenames[t], x.map{|id,_,name|"\t0x#{id}: '#{name}'"}.join(",\n")]}.join("\n\n")c
*/

if(typeof HSPonJS != 'undefined') {
	HSPonJS.BuiltinFuncNames = BuiltinFuncNames;
	HSPonJS.BuiltinFuncNameToIdTable = BuiltinFuncNameToIdTable;
}

function Value() {}

Value.prototype = {
	add: function(rhs) {
		throw this._unsupportedError('+');
	},
	sub: function(rhs) {
		throw this._unsupportedError('-');
	},
	mul: function(rhs) {
		throw this._unsupportedError('*');
	},
	div: function(rhs) {
		throw this._unsupportedError('/');
	},
	mod: function(rhs) {
		throw this._unsupportedError('\\');
	},
	and: function(rhs) {
		throw this._unsupportedError('&');
	},
	or: function(rhs) {
		throw this._unsupportedError('|');
	},
	xor: function(rhs) {
		throw this._unsupportedError('^');
	},
	eq: function(rhs) {
		throw this._unsupportedError('==');
	},
	ne: function(rhs) {
		throw this._unsupportedError('!=');
	},
	gt: function(rhs) {
		throw this._unsupportedError('>');
	},
	lt: function(rhs) {
		throw this._unsupportedError('<');
	},
	gteq: function(rhs) {
		throw this._unsupportedError('>=');
	},
	lteq: function(rhs) {
		throw this._unsupportedError('<=');
	},
	rsh: function(rhs) {
		throw this._unsupportedError('>>');
	},
	lsh: function(rhs) {
		throw this._unsupportedError('<<');
	},
	type: VarType.NONE,
	toIntValue: function() {
		throw this._convertError("int");
	},
	toDoubleValue: function() {
		throw this._convertError("double");
	},
	toStrValue: function() {
		throw this._convertError("str");
	},
	toValue: function() {
		return this;
	},
	_unsupportedError: function(op) {
		return new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                    VarTypeNames[this.type]+" 型は `"+op+"' 演算子をサポートしていません");
	},
	_convertError: function(type) {
		return new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                    VarTypeNames[this.type]+" 型は "+type + " に変換できません");
	},
	toString: function() {
		return '<Value>';
	},
	isUsing: function() {
		return null;
	},
	isVariable: function() {
		return false;
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Value = Value;
}

function LabelValue(pos) {
	if(pos != undefined) {
		this.pos = pos;
	} else {
		this.pos = -1;
	}
}

LabelValue.prototype = new Value;

Utils.objectExtend(LabelValue.prototype, {
	toString: function() {
		return '<LabelValue:'+this.pos+'>';
	},
	type: VarType.LABEL,
	isUsing: function() {
		return true;
	}
});

LabelValue.EMPTY = new LabelValue;
LabelValue.EMPTY.isUsing = function() { return false; };

if(typeof HSPonJS != 'undefined') {
	HSPonJS.LabelValue = LabelValue;
}


/**
 * 文字列値のクラス（不変）
 * @param str CP932 エンコード済みの文字列
 */
function StrValue(str) {
	this._value = '' + str;
}

StrValue.prototype = new Value;

StrValue.EMPTY_STR = new StrValue('');
StrValue.of = function(str) {
	if(str.length == 0) {
		return StrValue.EMPTY_STR;
	}
	return new StrValue(str);
};

Utils.objectExtend(StrValue.prototype, {
	add: function(rhs) {
		return new StrValue(this._value + rhs.toStrValue()._value);
	},
	eq: function(rhs) {
		return IntValue.of(this._value == rhs.toStrValue()._value);
	},
	ne: function(rhs) {
		var l = this._value, r = rhs.toStrValue()._value;
		if(l == r) {
			return IntValue.of(0);
		} else if(l > r) {
			return IntValue.of(1);
		} else {
			return IntValue.of(-1);
		}
	},
	gt: function(rhs) {
		return IntValue.of(this._value > rhs.toStrValue()._value);
	},
	lt: function(rhs) {
		return IntValue.of(this._value < rhs.toStrValue()._value);
	},
	gteq: function(rhs) {
		return IntValue.of(this._value >= rhs.toStrValue()._value);
	},
	lteq: function(rhs) {
		return IntValue.of(this._value <= rhs.toStrValue()._value);
	},
	type: VarType.STR,
	toIntValue: function() {
		if(this._value.charAt(0) == '$') {
			var n = 0;
			for(var i = 1; i < this._value.length; i ++) {
				n *= 16;
				var c = this._value.charCodeAt(i);
				if(0x30 <= c && c <= 0x39) { // '0' .. '9'
					n += c - 0x30;
				} else if(0x41 <= c && c <= 0x46) { // 'A' .. 'F'
					n += c - 0x41 + 10;
				} else if(0x61 <= c && c <= 0x66) { // 'a' .. 'f'
					n += c - 0x61 + 10;
				} else {
					// オフィシャル HSP で '0'..'9', 'A'..'F', 'a'..'f' 以外の文字は
					//  '0' と同じと認識するという謎の動作を行うのでひとまずそれと同じ動作をする
					// break;
				}
			}
			return new IntValue(n);
		}
		return new IntValue(parseInt(this._value, 10));
	},
	toDoubleValue: function() {
		var n = parseFloat(this._value);
		if(isNaN(n)) n = 0;
		return new DoubleValue(n);
	},
	toStrValue: function() {
		return this;
	},
	toString: function() {
		return '<StrValue:'+this._value+'>';
	},
	indexOf: function(pattern, fromIndex) {
		// ネイティブの String#indexOf でマッチする部分を探し、
		// マッチした部分が二バイト文字の途中からでないか 1 バイトずつ戻っていきながらチェックする
		
		function isSJISSecondByte(str, index, begin) {
			var result = false;
			while(true) {
				if(index == begin) return result;
				var c = str.charCodeAt(index - 1);
				if(!((0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xFC))) {
					return result;
				}
				index --;
				result = ! result;
			}
		}
		var str = this._value;
		var length = str.length;
		var pos = fromIndex;
		var patternLength = pattern.length;
		if(patternLength == 0) return -1;
		var c = pattern.charCodeAt(0);
		if(!((0x40 <= c && c <= 0x7E) || (0x80 <= c <= 0xFC))) {
			// pattern の一文字目が SJIS 第二バイトの範囲外なら String#indexOf の結果をそのまま返す
			return str.indexOf(pattern, pos);
		}
		while(true) {
			var index = str.indexOf(pattern, pos);
			if(index == -1) return -1;
			if(!isSJISSecondByte(str, index, pos)) {
				return index;
			}
			pos = index + 1;
		}
	},
	lineIndex: function(lineNumber) {
		if(lineNumber < 0) return null;
		var str = this._value;
		var i = 0;
		var result;
		var tag = new Object;
		try {
			str.replace(/.*(?:\r\n|[\r\n]|.$)/g, function(s, l) {
				if(i++ == lineNumber) {
					result = l;
					throw tag;
				}
			});
			return null;
		} catch(e) {
			if(e !== tag) throw e;
			return result;
		}
	},
	lineLength: function(index) {
		var str = this._value;
		return /[\r\n]|$/.exec(str.slice(index)).index;
	},
	lineLengthIncludeCR: function(index) {
		var str = this._value;
		var matched = /\r\n|[\r\n]|$/.exec(str.slice(index));
		return matched.index + matched[0].length;
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.StrValue = StrValue;
}

function DoubleValue(value) {
	this._value = +value;
}

DoubleValue.prototype = new Value;

DoubleValue.ZERO = new DoubleValue(0);
DoubleValue.of = function(value) {
	if(value == 0) {
		return DoubleValue.ZERO;
	}
	return new DoubleValue(value);
};

Utils.objectExtend(DoubleValue.prototype, {
	add: function(rhs) {
		return new DoubleValue(this._value + rhs.toDoubleValue()._value);
	},
	sub: function(rhs) {
		return new DoubleValue(this._value - rhs.toDoubleValue()._value);
	},
	mul: function(rhs) {
		return new DoubleValue(this._value * rhs.toDoubleValue()._value);
	},
	div: function(rhs) {
		return new DoubleValue(this._value / rhs.toDoubleValue()._value);
	},
	mod: function(rhs) {
		return new DoubleValue(this._value % rhs.toDoubleValue()._value);
	},
	eq: function(rhs) {
		return IntValue.of(this._value == rhs.toDoubleValue()._value);
	},
	ne: function(rhs) {
		return IntValue.of(this._value != rhs.toDoubleValue()._value);
	},
	gt: function(rhs) {
		return IntValue.of(this._value > rhs.toDoubleValue()._value);
	},
	lt: function(rhs) {
		return IntValue.of(this._value < rhs.toDoubleValue()._value);
	},
	gteq: function(rhs) {
		return IntValue.of(this._value >= rhs.toDoubleValue()._value);
	},
	lteq: function(rhs) {
		return IntValue.of(this._value <= rhs.toDoubleValue()._value);
	},
	type: VarType.DOUBLE,
	toIntValue: function() {
		return new IntValue(this._value);
	},
	toDoubleValue: function() {
		return this;
	},
	toStrValue: function() {
		return new StrValue(Formatter.convertFloat(this._value, {}, 0, null));
	},
	toString: function() {
		return '<DoubleValue:'+this._value+'>';
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.DoubleValue = DoubleValue;
}

function IntValue(value) {
	this._value = value|0;
}

IntValue.prototype = new Value;

(function(){
	var cache = new Array(256);
	for(var i = 0; i < 256; i ++) {
		cache[i] = new IntValue(i-128);
	}
	
	IntValue.of = function(value) {
		value = value|0;
		if(-128 <= value && value <= 127) {
			return cache[value+128];
		}
		return new IntValue(value);
	};
})();

Utils.objectExtend(IntValue.prototype, {
	add: function(rhs) {
		return new IntValue(this._value + rhs.toIntValue()._value);
	},
	sub: function(rhs) {
		return new IntValue(this._value - rhs.toIntValue()._value);
	},
	mul: function(rhs) {
		return new IntValue(this._value * rhs.toIntValue()._value);
	},
	div: function(rhs) {
		var rhsValue = rhs.toIntValue()._value;
		if(rhsValue == 0) {
			throw new HSPError(ErrorCode.DIVIDED_BY_ZERO);
		}
		return new IntValue(this._value / rhsValue);
	},
	mod: function(rhs) {
		var rhsValue = rhs.toIntValue()._value;
		if(rhsValue == 0) {
			throw new HSPError(ErrorCode.DIVIDED_BY_ZERO);
		}
		return new IntValue(this._value % rhsValue);
	},
	and: function(rhs) {
		return new IntValue(this._value & rhs.toIntValue()._value);
	},
	or: function(rhs) {
		return new IntValue(this._value | rhs.toIntValue()._value);
	},
	xor: function(rhs) {
		return new IntValue(this._value ^ rhs.toIntValue()._value);
	},
	eq: function(rhs) {
		return IntValue.of(this._value == rhs.toIntValue()._value);
	},
	ne: function(rhs) {
		return IntValue.of(this._value != rhs.toIntValue()._value);
	},
	gt: function(rhs) {
		return IntValue.of(this._value > rhs.toIntValue()._value);
	},
	lt: function(rhs) {
		return IntValue.of(this._value < rhs.toIntValue()._value);
	},
	gteq: function(rhs) {
		return IntValue.of(this._value >= rhs.toIntValue()._value);
	},
	lteq: function(rhs) {
		return IntValue.of(this._value <= rhs.toIntValue()._value);
	},
	rsh: function(rhs) {
		return new IntValue(this._value >> rhs.toIntValue()._value);
	},
	lsh: function(rhs) {
		return new IntValue(this._value << rhs.toIntValue()._value);
	},
	type: VarType.INT,
	toIntValue: function() {
		return this;
	},
	toDoubleValue: function() {
		return new DoubleValue(this._value);
	},
	toStrValue: function() {
		return new StrValue(this._value);
	},
	toString: function() {
		return '<IntValue:'+this._value+'>';
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.IntValue = IntValue;
}

function StructValue(module, members) {
	this.module = module;
	this.members = members;
}

StructValue.prototype = new Value;

Utils.objectExtend(StructValue.prototype, {
	eq: function(rhs) {
		if(rhs.type != VarType.STRUCT) return IntValue.of(false);
		return IntValue.of(this.members == rhs.members);
	},
	ne: function(rhs) {
		if(rhs.type != VarType.STRUCT) return IntValue.of(true);
		return IntValue.of(this.members != rhs.members);
	},
	type: VarType.STRUCT,
	toString: function() {
		return '<StructValue: module='+this.module.name+'>';
	},
	isUsing: function() {
		return true;
	}
});


StructValue.EMPTY = new StructValue(null, null);
StructValue.EMPTY.toString = function() { return '<StructValue: EMPTY>'; };
StructValue.EMPTY.isUsing = function() { return false; };

if(typeof HSPonJS != 'undefined') {
	HSPonJS.StructValue = StructValue;
}

function JumpType() {}
JumpType.prototype = new Value;
JumpType.GOTO = new JumpType;
JumpType.GOTO.toString = function() { return '<JumpType:GOTO>'; };
JumpType.GOSUB = new JumpType;
JumpType.GOSUB.toString = function() { return '<JumpType:GOSUB>'; };


if(typeof HSPonJS != 'undefined') {
	HSPonJS.JumpType = JumpType;
}


function StrBuffer(length) {
	// this._length >= this._str.length
	// this._length の方が大きいとき、その分後ろに '\0' がついているものとして扱う
	this._str = "";
	this._length = length;
	this._valCache = StrValue.EMPTY_STR;
}

StrBuffer.prototype = {
	assign: function(val) {
		if(val._value.length + 1 >= this._length) {
			this._length = val._value.length + 1;
			this._str = val._value;
		} else if(val._value.length + 1 >= this._str.length) {
			this._str = val._value;
		} else {
			this._str = val._value + "\0" + this._str.slice(val._value.length + 1);
		}
		this._valCache = val;
	},
	getValue: function() {
		if(!this._valCache) {
			this._valCache = new StrValue(Utils.getCStr(this._str));
		}
		return this._valCache;
	},
	getbyte: function(pos) {
		if(!(0 <= pos && pos < this._length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		if(pos < this._str.length) {
			return this._str.charCodeAt(pos);
		}
		return 0;
	},
	setbyte: function(pos, val) {
		var str = this._str;
		if(!(0 <= pos && pos < this._length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		if(pos < str.length) {
			this._str = str.slice(0, pos) + String.fromCharCode(val & 0xff) + str.slice(pos + 1);
		} else {
			this._str += Utils.strTimes("\0", pos - str.length) + String.fromCharCode(val & 0xff);
		}
		this._valCache = null;
	},
	getbytes: function(pos, length) {
		if(!(0 <= pos && pos + length <= this._length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		if(pos + length <= this._str.length) {
			return this._str.substr(pos, length);
		}
		return this._str.slice(pos) + Utils.strTimes("\0", length - (this._str.length - pos));
	},
	setbytes: function(pos, buf) {
		var str = this._str;
		if(!(0 <= pos && pos + buf.length <= this._length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		if(pos + buf.length <= str.length) {
			this._str = str.slice(0, pos) + buf + str.slice(pos + buf.length);
		} else if(pos >= str.length) {
			this._str = str + Utils.strTimes("\0", pos - str.length) + buf;
		} else {
			this._str = str.slice(0, pos) + buf;
		}
		this._valCache = null;
	},
	getByteSize: function() {
		return this._length;
	},
	expandByteSize: function(size) {
		if(this._length >= size) return;
		this._length = size;
	},
	splice: function(index, length, sub) {
		// (index >= 0 && length >= 0 && index + length <= this.getByteSize()) の条件が偽のときの動作は未定義とする
		var str = this._str;
		if(index < str.length) {
			this._str = str.slice(0, index) + sub + str.slice(index + length);
		} else {
			this._str = str + Utils.strTimes("\0", index - str.length) + sub;
		}
		this._length += sub.length - length;
		this._valCache = null;
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.StrBuffer = StrBuffer;
}


function HSPArray() {
	this.l0 = 1;
	this.l1 = 0;
	this.l2 = 0;
	this.l3 = 0;
}

HSPArray.prototype = {
	assign: function(offset, rhs) {
		this.values[offset] = rhs;
	},
	expand: function(indices) {
		if(indices.length > 4) {
			throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		}
		if(this.getOffset(indices) != null) return false;
		var lastDimension = this.countDimensions() - 1;
		var l0 = this.l0;
		var l1 = this.l1;
		var l2 = this.l2;
		var l3 = this.l3;
		if(indices.length > 0 && indices[0] >= l0) {
			if(lastDimension > 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
			l0 = indices[0] + 1;
		}
		if(indices.length > 1 && indices[1] >= l1) {
			if(lastDimension > 1) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
			l1 = indices[1] + 1;
		}
		if(indices.length > 2 && indices[2] >= l2) {
			if(lastDimension > 2) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
			l2 = indices[2] + 1;
		}
		if(indices.length > 3 && indices[3] >= l3) {
			if(lastDimension > 3) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
			l3 = indices[3] + 1;
		}
		switch(indices.length) {
		case 4:
			if(indices[3] < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		case 3:
			if(indices[2] < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		case 2:
			if(indices[1] < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		case 1:
			if(indices[0] < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		}
		this.l0 = l0;
		this.l1 = l1;
		this.l2 = l2;
		this.l3 = l3;
		this.fillUpElements(this.allLength());
		return true;
	},
	expand1D: function(index) {
		if(index < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		if(index < this.l0) return false;
		if(this.l1) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		this.l0 = index + 1;
		this.fillUpElements(this.l0);
		return true;
	},
	getOffset: function(indices) {
		if(indices.length > this.countDimensions()) {
			return null;
		}
		var offset = 0;
		switch(indices.length) {
		case 4:
			if(!(0 <= indices[3] && indices[3] < this.l3)) return null;
			offset = (offset + indices[3]) * this.l2;
		case 3:
			if(!(0 <= indices[2] && indices[2] < this.l2)) return null;
			offset = (offset + indices[2]) * this.l1;
		case 2:
			if(!(0 <= indices[1] && indices[1] < this.l1)) return null;
			offset = (offset + indices[1]) * this.l0;
		case 1:
			if(!(0 <= indices[0] && indices[0] < this.l0)) return null;
			offset = offset + indices[0];
		}
		return offset;
	},
	countDimensions: function() {
		if(!this.l1) return 1;
		if(!this.l2) return 2;
		if(!this.l3) return 3;
		return 4;
	},
	allLength: function() {
		var length = this.l0;
		if(this.l1) length *= this.l1;
		if(this.l2) length *= this.l2;
		if(this.l3) length *= this.l3;
		return length;
	},
	setLength: function(l0, l1, l2, l3) {
		if(l0 < 0 || l1 < 0 || l2 < 0 || l3 < 0) {
			throw new HSPError(ErrorCode.ILLEGAL_FUNCTION, '配列の要素数に負の数が指定されています');
		}
		if(l3) {
			if(!l2) l2 = 1;
			if(!l1) l1 = 1;
		} else if(l2) {
			if(!l1) l1 = 1;
		}
		if(!l0) l0 = 1;
		this.l0 = l0;
		this.l1 = l1;
		this.l2 = l2;
		this.l3 = l3;
	},
	at: function(offset) {
		return this.values[offset];
	},
	getL0: function() { return this.l0; },
	getL1: function() { return this.l1; },
	getL2: function() { return this.l2; },
	getL3: function() { return this.l3; },
	getbyte: function(offset, bytesOffset) {
		throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                   VarTypeNames[this.type]+" 型はメモリ読み込みに対応していません");
	},
	setbyte: function(offset, bytesOffset, val) {
		throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                   VarTypeNames[this.type]+" 型はメモリ書き込みに対応していません");
	},
	getbytes: function(offset, bytesOffset, length) {
		var result = "";
		for(var i = 0; i < length; i ++) {
			result += String.fromCharCode(this.getbyte(offset, bytesOffset + i));
		}
		return result;
	},
	setbytes: function(offset, bytesOffset, buf) {
		for(var i = 0; i < buf.length; i ++) {
			this.setbyte(offset, bytesOffset + i, buf.charCodeAt(i));
		}
	},
	getByteSize: function(offset) {
		throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                   VarTypeNames[this.type]+" 型はメモリ読み込みに対応していません");
	},
	expandByteSize: function(offset, size) {
		throw new HSPError(ErrorCode.TYPE_MISMATCH,
		                   VarTypeNames[this.type]+" 型はメモリ領域の拡張に対応していません");
	},
	ref: function(offset) {
		return new Reference(this, offset);
	},
	bufferAt: function(offset) {
		throw new HSPError(ErrorCode.TYPE_MISMATCH);
	},
	inc: function(offset) {
		throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                   VarTypeNames[this.type]+" 型はインクリメントに対応していません");
	},
	dec: function(offset) {
		throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION,
		                   VarTypeNames[this.type]+" 型はデクリメントに対応していません");
	},
	getValues: function() {
		return this.values;
	},
	getValuesStartOffset: function() {
		return 0;
	},
	fillBytes: function(offset, val, length, bytesOffset) {
		if(length <= 0) return;
		this.setbytes(offset, bytesOffset, Utils.strTimes(String.fromCharCode(val), length));
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.HSPArray = HSPArray;
}

function Reference(value, offset) {
	this.value = value;
	this.base = offset;
	this.l0 = value.values.length - offset;
	this.type = value.type;
}

Reference.prototype = {
	assign: function(offset, rhs) {
		return this.value.assign(this.base + offset, rhs);
	},
	expand: function(indices) {
		var offset = indices.length > 0 ? indices[0] : 0;
		if(indices.length > 1 || offset < 0 || offset >= this.l0) {
			throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		}
		return false;
	},
	expand1D: function(index) {
		if(index < 0 || index >= this.l0) {
			throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		}
		return false;
	},
	getOffset: function(indices) {
		var offset = indices.length > 0 ? indices[0] : 0;
		if(indices.length > 1 || offset < 0 || offset >= this.l0) {
			return null;
		}
		return offset;
	},
	at: function(offset) {
		return this.value.at(this.base + offset);
	},
	getL0: function() {
		return this.l0;
	},
	getL1: function() {
		return 0;
	},
	getL2: function() {
		return 0;
	},
	getL3: function() {
		return 0;
	},
	getbyte: function(offset, bytesOffset) {
		return this.value.getbyte(this.base + offset, bytesOffset);
	},
	setbyte: function(offset, bytesOffset, val) {
		return this.value.setbyte(this.base + offset, bytesOffset, val);
	},
	getbytes: function(offset, bytesOffset, length) {
		return this.value.getbytes(this.base + offset, bytesOffset, length);
	},
	setbytes: function(offset, bytesOffset, buf) {
		return this.value.setbytes(this.base + offset, bytesOffset, buf);
	},
	getByteSize: function(offset) {
		return this.value.getByteSize(this.base + offset);
	},
	expandByteSize: function(offset, size) {
		return this.value.expandByteSize(this.base + offset, size);
	},
	bufferAt: function(offset) {
		return this.value.bufferAt(this.base + offset);
	},
	ref: function(offset) {
		if(offset == 0) {
			return this;
		}
		return new Reference(this.value, this.base + offset);
	},
	inc: function(offset) {
		return this.value.inc(this.base + offset);
	},
	dec: function(offset) {
		return this.value.dec(this.base + offset);
	},
	getValues: function() {
		return this.value.getValues();
	},
	getValuesStartOffset: function() {
		return this.base;
	},
	fillBytes: function(offset, val, length, bytesOffset) {
		return this.value.fillBytes(this.base + offset, val, length, bytesOffset);
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Reference = Reference;
}


function UninitializedArray(varName) {
	HSPArray.call(this);
	this.varName = varName;
}

UninitializedArray.prototype = new HSPArray;

Utils.objectExtend(UninitializedArray.prototype, {
	type: 0,
	assign: function(offset, rhs) {
		throw this.uninitializedError();
	},
	at: function(offset) {
		throw this.uninitializedError();
	},
	getbyte: function(offset, bytesOffset) {
		throw this.uninitializedError();
	},
	setbyte: function(offset, bytesOffset, val) {
		throw this.uninitializedError();
	},
	getbytes: function(offset, bytesOffset, length) {
		throw this.uninitializedError();
	},
	setbytes: function(offset, bytesOffset, buf) {
		throw this.uninitializedError();
	},
	getByteSize: function(offset) {
		throw this.uninitializedError();
	},
	expandByteSize: function(offset, size) {
		throw this.uninitializedError();
	},
	ref: function(offset) {
		throw this.uninitializedError();
	},
	bufferAt: function(offset) {
		throw this.uninitializedError();
	},
	inc: function(offset) {
		throw this.uninitializedError();
	},
	dec: function(offset) {
		throw this.uninitializedError();
	},
	getValues: function() {
		throw this.uninitializedError();
	},
	getValuesStartOffset: function() {
		throw this.uninitializedError();
	},
	expand: function(indices) {
		throw this.uninitializedError();
	},
	expand1D: function(index) {
		throw this.uninitializedError();
	},
	uninitializedError: function() {
		return new HSPError(ErrorCode.UNINITIALIZED_VARIABLE, "未初期化の変数 `"+this.varName+"' を参照しました");
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.UninitializedArray = UninitializedArray;
}


function LabelArray() {
	HSPArray.call(this);
	this.values = [LabelValue.EMPTY];
}

LabelArray.prototype = new HSPArray();

Utils.objectExtend(LabelArray.prototype, {
	fillUpElements: function(newLen) {
		var empty = LabelValue.EMPTY;
		for(var i = this.values.length; i < newLen; i ++) {
			this.values[i] = empty;
		}
	},
	type: VarType.LABEL
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.LabelArray = LabelArray;
}


function StrArray() {
	HSPArray.call(this);
	this.values = [new StrBuffer(64)];
}

StrArray.prototype = new HSPArray();

Utils.objectExtend(StrArray.prototype, {
	assign: function(offset, rhs) {
		this.values[offset].assign(rhs);
	},
	fillUpElements: function(newLen) {
		for(var i = this.values.length; i < newLen; i ++) {
			this.values[i] = new StrBuffer(64);
		}
	},
	at: function(offset) {
		return this.values[offset].getValue();
	},
	type: VarType.STR,
	strDim: function(strLength, l0, l1, l2, l3) {
		if(strLength < 64) {
			strLength = 64;
		}
		this.setLength(l0, l1, l2, l3);
		var len = this.allLength();
		for(var i = 0; i < len; i ++) {
			this.values[i] = new StrBuffer(strLength);
		}
	},
	getbyte: function(offset, bytesOffset) {
		return this.values[offset].getbyte(bytesOffset);
	},
	setbyte: function(offset, bytesOffset, val) {
		this.values[offset].setbyte(bytesOffset, val);
	},
	getbytes: function(offset, bytesOffset, length) {
		return this.values[offset].getbytes(bytesOffset, length);
	},
	setbytes: function(offset, bytesOffset, buf) {
		this.values[offset].setbytes(bytesOffset, buf);
	},
	getByteSize: function(offset) {
		return this.values[offset].getByteSize();
	},
	expandByteSize: function(offset, size) {
		this.values[offset].expandByteSize(size);
	},
	bufferAt: function(offset) {
		return this.values[offset];
	},
	inc: function(offset) {
		var buf = this.values[offset];
		buf.assign(new StrValue(buf.getValue()._value + '1'));
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.StrArray = StrArray;
}

function DoubleArray() {
	HSPArray.call(this);
	this.values = [new DoubleValue(0)];
}

DoubleArray.prototype = new HSPArray();

Utils.objectExtend(DoubleArray.prototype, {
	fillUpElements: function(newLen) {
		var zero = new DoubleValue(0);
		for(var i = this.values.length; i < newLen; i ++) {
			this.values[i] = zero;
		}
	},
	type: VarType.DOUBLE,
	inc: function(offset) {
		this.values[offset] = new DoubleValue(this.values[offset]._value + 1);
	},
	dec: function(offset) {
		this.values[offset] = new DoubleValue(this.values[offset]._value - 1);
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.DoubleArray = DoubleArray;
}

function IntArray() {
	HSPArray.call(this);
	this.values = [new IntValue(0)];
}

IntArray.prototype = new HSPArray();

Utils.objectExtend(IntArray.prototype, {
	fillUpElements: function(newLen) {
		var zero = new IntValue(0);
		for(var i = this.values.length; i < newLen; i ++) {
			this.values[i] = zero;
		}
	},
	type: VarType.INT,
	getbyte: function(offset, bytesOffset) {
		var i = offset + (bytesOffset >> 2);
		if(!(0 <= i && i < this.values.length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		return this.values[i]._value >> (bytesOffset % 4 * 8) & 0xff;
	},
	setbyte: function(offset, bytesOffset, val) {
		var i = offset + (bytesOffset >> 2);
		if(!(0 <= i && i < this.values.length)) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		var value = this.values[i]._value;
		value &= ~(0xff << (bytesOffset % 4 * 8));
		value |= (val & 0xff) << (bytesOffset % 4 * 8);
		this.values[i] = new IntValue(value);
	},
	getByteSize: function(offset) {
		return (this.values.length - offset) * 4;
	},
	inc: function(offset) {
		this.values[offset] = new IntValue(this.values[offset]._value + 1);
	},
	dec: function(offset) {
		this.values[offset] = new IntValue(this.values[offset]._value - 1);
	},
	fillBytes: function(offset, val, length, bytesOffset) {
		var values = this.values;
		var idx = offset + (bytesOffset >> 2);
		var ofs = bytesOffset & 3;
		if(bytesOffset < 0 || idx + ((length + ofs + 3) >> 2) > values.length) {
			throw new HSPError(ErrorCode.BUFFER_OVERFLOW);
		}
		if(length <= 0) return;
		if(ofs) {
			var l = 4 - ofs;
			if(l > length) { l = length; }
			var v = values[idx]._value;
			if(ofs == 1) {
				if(l == 1) { v = v & 0xffff00ff | (val << 8); }
				else if(l == 2) { v = v & 0xff0000ff | (val << 8) | (val << 16); }
				else { v = v & 0x000000ff | (val << 8) | (val << 16) | (val << 24); }
			} else if(ofs == 2) {
				if(l == 1) { v = v & 0xff00ffff | (val << 16); }
				else { v = v & 0x0000ffff | (val << 16) | (val << 24); }
			} else {
				v = v & 0x00ffffff | (val << 24);
			}
			values[idx] = new IntValue(v);
			length -= l;
			if(length == 0) return;
			idx ++;
		}
		var l = idx + (length >> 2);
		var value = new IntValue(val | val << 8 | val << 16 | val << 24);
		
		while(idx < l) {
			values[idx++] = value;
		}
		var l = length & 3;
		if(l) {
			var v = values[idx]._value;
			if(l == 1) {
				v = v & 0xffffff00 | val;
			} else if(l == 2) {
				v = v & 0xffff0000 | val | val << 8;
			} else {
				v = v & 0xff000000 | val | val << 8 | val << 16;
			}
			values[idx] = new IntValue(v);
		}
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.IntArray = IntArray;
}

function StructArray() {
	HSPArray.call(this);
	this.values = [StructValue.EMPTY];
	this.searchFrom = 0;
}

StructArray.prototype = new HSPArray();

Utils.objectExtend(StructArray.prototype, {
	assign: function(offset, rhs) {
		this.values[offset] = rhs;
		if(rhs == StructValue.EMPTY && offset < this.searchFrom) {
			this.searchFrom = offset;
		}
	},
	fillUpElements: function(newLen) {
		var empty = StructValue.EMPTY;
		for(var i = this.values.length; i < newLen; i ++) {
			this.values[i] = empty;
		}
	},
	type: VarType.STRUCT,
	// 配列インデックスを返す
	newmod: function(module) {
		var len = this.l0;
		var index;
		for(index = this.searchFrom; index < len; index ++) {
			if(this.values[index] == StructValue.EMPTY) {
				break;
			}
		}
		if(index == len) {
			if(this.l1) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
			++ this.l0;
		}
		this.searchFrom = index + 1;
		var members = [];
		for(var i = 0; i < module.membersCount; i ++) {
			members[i] = new Variable;
		}
		this.values[index] = new StructValue(module, members);
		return index;
	}
});

if(typeof HSPonJS != 'undefined') {
	HSPonJS.StructArray = StructArray;
}

function Variable() {
	this.value = new IntArray();
}

function newArray(type) {
	switch(type) {
	case 1: // VarType.LABEL
		return new LabelArray();
	case 2: // VarType.STR
		return new StrArray();
	case 3: // VarType.DOUBLE
		return new DoubleArray();
	case 4: // VarType.INT
		return new IntArray();
	case 5: // VarType.STRUCT
		return new StructArray();
	default:
		return null;
	}
}

Variable.prototype = {
	assign: function(indices, rhs) {
		this.value.expand(indices);
		if(this.value.type != rhs.type) {
			if(this.value.getOffset(indices) != 0) {
				throw new HSPError(ErrorCode.INVALID_ARRAYSTORE,
				VarTypeNames[this.value.type]+' 型の配列変数に '+VarTypeNames[rhs.type]+' 型の値を代入しました');
			}
			this.reset(rhs.type);
			this.value.expand(indices);
		}
		var offset = this.value.getOffset(indices);
		return this.value.assign(offset, rhs);
	},
	reset: function(type) {
		var ary = newArray(type);
		if(!ary) {
			throw new HSPError(ErrorCode.TYPE_MISMATCH, VarTypeNames[type]+' 型の値は変数に代入できません');
		}
		this.value = ary;
	},
	expand: function(indices) {
		return this.value.expand(indices);
	},
	expand1D: function(index) {
		return this.value.expand1D(index);
	},
	at: function(offset) {
		return this.value.at(offset);
	},
	getL0: function() {
		return this.value.getL0();
	},
	getL1: function() {
		return this.value.getL1();
	},
	getL2: function() {
		return this.value.getL2();
	},
	getL3: function() {
		return this.value.getL3();
	},
	dim: function(type, l0, l1, l2, l3) {
		var ary = newArray(type);
		if(!ary) {
			throw new HSPError(ErrorCode.ILLEGAL_FUNCTION, '異常な変数型の値です');
		}
		ary.setLength(l0, l1, l2, l3);
		ary.fillUpElements(ary.allLength());
		this.value = ary;
	},
	getbyte: function(offset, bytesOffset) {
		return this.value.getbyte(offset, bytesOffset);
	},
	setbyte: function(offset, bytesOffset, val) {
		return this.value.setbyte(offset, bytesOffset, val);
	},
	getbytes: function(offset, bytesOffset, length) {
		return this.value.getbytes(offset, bytesOffset, length);
	},
	setbytes: function(offset, bytesOffset, buf) {
		return this.value.setbytes(offset, bytesOffset, buf);
	},
	getByteSize: function(offset) {
		return this.value.getByteSize(offset);
	},
	expandByteSize: function(offset, size) {
		return this.value.expandByteSize(offset, size);
	},
	bufferAt: function(offset) {
		return this.value.bufferAt(offset);
	},
	ref: function(offset) {
		return this.value.ref(offset);
	},
	inc: function(offset) {
		return this.value.inc(offset);
	},
	dec: function(offset) {
		return this.value.dec(offset);
	},
	fillBytes: function(offset, val, length, bytesOffset) {
		return this.value.fillBytes(offset, val, length, bytesOffset);
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Variable = Variable;
	HSPonJS.newArray = newArray;
}


function VariableAgent() {
	this.variable = null;
}

VariableAgent.prototype = {
	add: function(rhs) {
		return this.toValue().add(rhs);
	},
	sub: function(rhs) {
		return this.toValue().sub(rhs);
	},
	mul: function(rhs) {
		return this.toValue().mul(rhs);
	},
	div: function(rhs) {
		return this.toValue().div(rhs);
	},
	mod: function(rhs) {
		return this.toValue().mod(rhs);
	},
	and: function(rhs) {
		return this.toValue().and(rhs);
	},
	or: function(rhs) {
		return this.toValue().or(rhs);
	},
	xor: function(rhs) {
		return this.toValue().xor(rhs);
	},
	eq: function(rhs) {
		return this.toValue().eq(rhs);
	},
	ne: function(rhs) {
		return this.toValue().ne(rhs);
	},
	gt: function(rhs) {
		return this.toValue().gt(rhs);
	},
	lt: function(rhs) {
		return this.toValue().lt(rhs);
	},
	gteq: function(rhs) {
		return this.toValue().gteq(rhs);
	},
	lteq: function(rhs) {
		return this.toValue().lteq(rhs);
	},
	rsh: function(rhs) {
		return this.toValue().rsh(rhs);
	},
	lsh: function(rhs) {
		return this.toValue().lsh(rhs);
	},
	toIntValue: function() {
		return this.toValue().toIntValue();
	},
	toDoubleValue: function() {
		return this.toValue().toDoubleValue();
	},
	toStrValue: function() {
		return this.toValue().toStrValue();
	},
	isUsing: function() {
		return this.toValue().isUsing();
	},
	getbyte: function(bytesOffset) {
		return this.variable.value.getbyte(this.getOffset(), bytesOffset);
	},
	setbyte: function(bytesOffset, val) {
		return this.variable.value.setbyte(this.getOffset(), bytesOffset, val);
	},
	getbytes: function(bytesOffset, length) {
		return this.variable.value.getbytes(this.getOffset(), bytesOffset, length);
	},
	setbytes: function(bytesOffset, buf) {
		return this.variable.value.setbytes(this.getOffset(), bytesOffset, buf);
	},
	getByteSize: function() {
		return this.variable.value.getByteSize(this.getOffset());
	},
	expandByteSize: function(size) {
		return this.variable.value.expandByteSize(this.getOffset(), size);
	},
	ref: function() {
		return this.variable.value.ref(this.getOffset());
	},
	getBuffer: function() {
		return this.variable.value.bufferAt(this.getOffset());
	},
	inc: function() {
		return this.variable.value.inc(this.getOffset());
	},
	dec: function() {
		return this.variable.value.dec(this.getOffset());
	},
	fillBytes: function(val, length, bytesOffset) {
		return this.variable.value.fillBytes(this.getOffset(), val, length, bytesOffset);
	},
	toValue: function() {
		return this.variable.value.at(this.getOffset());
	},
	isVariable: function() {
		return true;
	},
	indices: null
};

function VariableAgent0D(variable) {
	this.variable = variable;
}

VariableAgent0D.prototype = new VariableAgent;

Utils.objectExtend(VariableAgent0D.prototype, {
	getOffset: function() {
		return 0;
	},
	toValue: function() {
		return this.variable.value.at(0);
	},
	assign: function(rhs) {
		var type = rhs.type;
		var variable = this.variable;
		if(variable.value.type != type) {
			variable.reset(type);
		}
		variable.value.assign(0, rhs);
	},
	expand: function() {
		return this;
	},
	offset: 0,
	existSubscript: false
});

function VariableAgent1D(variable, offset) {
	this.variable = variable;
	this.offset = offset;
}

VariableAgent1D.prototype = new VariableAgent;

Utils.objectExtend(VariableAgent1D.prototype, {
	getOffset: function() {
		var offset = this.offset;
		if(0 <= offset && offset < this.variable.value.getL0()) {
			return offset;
		} else {
			throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		}
	},
	assign: function(rhs) {
		var offset = this.offset;
		var variable = this.variable;
		var array = variable.value;
		var type = rhs.type;
		if(array.type != type) {
		    if(offset == 0) {
		        variable.reset(type);
		        array = variable.value;
		    } else {
		        throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);
		    }
		}
		array.expand1D(offset);
		array.assign(offset, rhs);
	},
	expand: function() {
		this.variable.value.expand1D(this.offset);
		return this;
	},
	existSubscript: true
});

function VariableAgentMD(variable, indices) {
	this.variable = variable;
	this.indices = indices;
}

VariableAgentMD.prototype = new VariableAgent;

Utils.objectExtend(VariableAgentMD.prototype, {
	getOffset: function() {
		var offset = this.variable.value.getOffset(this.indices);
		if(offset == null) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);
		return offset;
	},
	assign: function(rhs) {
		return this.variable.assign(this.indices, rhs);
	},
	expand: function() {
		this.variable.expand(this.indices);
		return this;
	},
	existSubscript: true
});



if(typeof HSPonJS != 'undefined') {
	HSPonJS.VariableAgent = VariableAgent;
	HSPonJS.VariableAgent0D = VariableAgent0D;
	HSPonJS.VariableAgent1D = VariableAgent1D;
	HSPonJS.VariableAgentMD = VariableAgentMD;
	
}

function ParamInfo(node, stackSize) {
	this.node = node;
	this.stackSize = stackSize;
}

Utils.objectExtend(ParamInfo.prototype, {
	toString: function() {
		return '<ParamInfo: '+this.node+'>';
	},
	getPureNode: function() {
		return this.node.toPureNode();
	}
});

function Node() {}
Utils.objectExtend(Node.prototype, {
	isVarNode:     function() { return false; },
	isArgNode:     function() { return false; },
	isLiteralNode: function() { return false; },
	isLabelNode:   function() { return false; },
	isDefaultNode: function() { return false; },
	isOperateNode: function() { return false; },
	isFuncallNode: function() { return false; },
	isUserDefFuncall: function() { return false; },
	isBuiltinFuncall: function() { return false; },
	isInlineExprBuiltinFuncall: function() { return false; },
	isGetStackNode: function() { return false; },
	toPureNode: function() { return this; }
});

var NodeType = {
	VAR:     1,
	ARG:     2,
	LITERAL: 3,
	LABEL:   4,
	DEFAULT: 5,
	OPERATE: 6,
	USERDEF_FUNCALL: 7,
	BUILTIN_FUNCALL: 8,
	INLINE_EXPR_BUILTIN_FUNCALL: 9,
	GET_STACK: 10
};

function VarNode(varData, indexNodes, onlyValue, token) {
	this.varData = varData;
	this.indexNodes = indexNodes;
	this.onlyValue = onlyValue;
	this.token = token;
}
VarNode.prototype = new Node;
Utils.objectExtend(VarNode.prototype, {
	nodeType: NodeType.VAR,
	isVarNode: function() { return true; },
	toString: function() {
		return '<VarNode:'+this.varData+',['+this.indexNodes+']'+
		       (!this.onlyValue?',var':'')+
		       (this.ignoreIndices?'ignore idicies':'')+'>';
	},
	getValueType: function() {
		return 0;
	}
});

function ArgNode(id) {
	this.id = id;
}
ArgNode.prototype = new Node;
Utils.objectExtend(ArgNode.prototype, {
	nodeType: NodeType.ARG,
	isArgNode: function() { return true; },
	toString: function() {
		return '<ArgNode:'+this.id+'>';
	},
	getValueType: function() {
		return 0;
	}
});

function LiteralNode(val) {
	this.val = val;
}
LiteralNode.prototype = new Node;
Utils.objectExtend(LiteralNode.prototype, {
	nodeType: NodeType.LITERAL,
	isLiteralNode: function() { return true; },
	toString: function() {
		return '<LiteralNode:'+this.val+'>';
	},
	getValueType: function() {
		return this.val.type;
	}
});

function LabelNode(lobj) {
	this.lobj = lobj;
}
LabelNode.prototype = new Node;
Utils.objectExtend(LabelNode.prototype, {
	nodeType: NodeType.LABEL,
	isLabelNode: function() { return true; },
	toString: function() {
		return '<LabelNode:'+this.lobj+'>';
	},
	getValueType: function() {
		return VarType.LABEL;
	},
	getLabelPos: function() {
		return this.lobj.getPos();
	}
});

function DefaultNode() {
}
DefaultNode.prototype = new Node;
Utils.objectExtend(DefaultNode.prototype, {
	nodeType: NodeType.DEFAULT,
	isDefaultNode: function() { return true; },
	toString: function() {
		return '<DefaultNode>';
	},
	getValueType: function() {
		return 0;
	}
});

function OperateNode(calcCode, lhsNode, rhsNode) {
	this.calcCode = calcCode;
	this.lhsNode = lhsNode;
	this.rhsNode = rhsNode;
}
OperateNode.prototype = new Node;
Utils.objectExtend(OperateNode.prototype, {
	nodeType: NodeType.OPERATE,
	isOperateNode: function() { return true; },
	toString: function() {
		return '<OperateNode:'+this.calcCode+' '+this.lhsNode+' '+this.rhsNode+'>';
	},
	getValueType: function() {
		if(isCompareCalcCode(this.calcCode)) {
			return VarType.INT;
		}
		return this.lhsNode.getValueType();
	}
});

function FuncallNode(paramNodes) {
	this.paramNodes = paramNodes;
}
FuncallNode.prototype = new Node;
Utils.objectExtend(FuncallNode.prototype, {
	isFuncallNode: function() { return true; }
});

function UserDefFuncallNode(userDefFunc, paramNodes, token) {
	this.userDefFunc = userDefFunc;
	this.paramNodes = paramNodes;
	this.token = token;
}
UserDefFuncallNode.prototype = new FuncallNode;
Utils.objectExtend(UserDefFuncallNode.prototype, {
	nodeType: NodeType.USERDEF_FUNCALL,
	isUserDefFuncallNode: function() { return true; },
	toString: function() {
		return '<UserDefFuncallNode:'+this.userDefFunc+', ['+this.paramNodes+']>';
	},
	getValueType: function() {
		return 0;
	}
});

function BuiltinFuncallNode(groupId, subId, paramNodes, token) {
	this.groupId = groupId;
	this.subId = subId;
	this.paramNodes = paramNodes;
	this.token = token;
}
BuiltinFuncallNode.prototype = new FuncallNode;
Utils.objectExtend(BuiltinFuncallNode.prototype, {
	nodeType: NodeType.BUILTIN_FUNCALL,
	isBuiltinFuncallNode: function() { return true; },
	toString: function() {
		return '<BuiltinFuncallNode:'+this.groupId+', '+this.subId+', ['+this.paramNodes+']>';
	},
	getValueType: function() {
		return 0;
	}
});

function InlineExprBuiltinFuncall(groupId, subId, builtinFuncInfo, paramInfos) {
	this.groupId = groupId;
	this.subId = subId;
	this.builtinFuncInfo = builtinFuncInfo;
	this.paramInfos = paramInfos;
}
InlineExprBuiltinFuncall.prototype = new FuncallNode;
Utils.objectExtend(InlineExprBuiltinFuncall.prototype, {
	nodeType: NodeType.INLINE_EXPR_BUILTIN_FUNCALL,
	isInlineExprBuiltinFuncall: function() { return true; },
	toString: function() {
		return '<InlineExprBuiltinFuncall:'+this.groupId+', '+this.subId+', ['+this.paramNodes+']>';
	},
	getValueType: function() {
		return this.builtinFuncInfo.returnValueType || 0;
	}
});

function GetStackNode(originalNode) {
	this.originalNode = originalNode;
}
GetStackNode.prototype = new Node;
Utils.objectExtend(GetStackNode.prototype, {
	nodeType: NodeType.GET_STACK,
	isGetStackNode: function() { return true; },
	toString: function() {
		return '<GetStackNode'/*+':'+this.originalNode*/+'>';
	},
	getValueType: function() {
		return this.originalNode.getValueType();
	},
	toPureNode: function() {
		return this.originalNode;
	}
});

function traverseParamInfo(paramInfo, callback) {
	function traverseNode(node) {
		callback(node);
		switch(node.nodeType) {
		case NodeType.VAR:
			traverseNodes(node.indexNodes);
			break;
		case NodeType.ARG:
			break;
		case NodeType.LITERAL:
			break;
		case NodeType.LABEL:
			break;
		case NodeType.DEFAULT:
			break;
		case NodeType.OPERATE:
			traverseNode(node.rhsNode);
			traverseNode(node.lhsNode);
			break;
		case NodeType.USERDEF_FUNCALL:
		case NodeType.BUILTIN_FUNCALL:
			traverseNodes(node.paramNodes);
			break;
		case NodeType.INLINE_EXPR_BUILTIN_FUNCALL:
			traverseParamInfos(node.paramInfos);
		case NodeType.GET_STACK:
			break;
		default:
			throw new Error('must not happen');
		}
	}
	function traverseNodes(nodes) {
		for(var i = 0; i < nodes.length; i ++) {
			traverseNode(nodes[i]);
		}
	}
	function traverseParamInfos(paramInfos) {
		for(var i = 0; i < paramInfos.length; i ++) {
			traverseNode(paramInfos[i].node);
		}
	}
	traverseNode(paramInfo.node);
}

function isDefaultParamInfo(paramInfo) {
	return !paramInfo || paramInfo.node.isDefaultNode();
}

if(typeof HSPonJS != 'undefined') {
	HSPonJS.ParamInfo = ParamInfo;
	HSPonJS.Node = Node;
	HSPonJS.NodeType = NodeType;
	HSPonJS.VarNode = VarNode;
	HSPonJS.ArgNode = ArgNode;
	HSPonJS.LiteralNode = LiteralNode;
	HSPonJS.DefaultNode = DefaultNode;
	HSPonJS.OperateNode = OperateNode;
	HSPonJS.FuncallNode = FuncallNode;
	HSPonJS.UserDefFuncallNode = UserDefFuncallNode;
	HSPonJS.BuiltinFuncallNode = BuiltinFuncallNode;
	HSPonJS.GetStackNode = GetStackNode;
	HSPonJS.traverseParamInfo = traverseParamInfo;
	HSPonJS.isDefaultParamInfo = isDefaultParamInfo;
}
function Compiler(ax) {
	this.ax = ax;
	this.tokensPos = 0;
	this.labels = this.makeLabels();
	this.ifLabels = {};
	this.userDefFuncs = [];
	this.staticVarTags = this.makeStaticVarTags();
}

function CompileError(message, hspFileName, hspLineNumber) {
	this.message = message;
	this.hspFileName = hspFileName;
	this.hspLineNumber = hspLineNumber;
}
CompileError.prototype = new Error;
CompileError.prototype.name = 'CompileError';

function VariableData(proxyVarType, id) {
	this.proxyVarType = proxyVarType;
	this.id = id;
}

VariableData.prototype = {
	toString: function() {
		var type;
		var outputId = true;
		switch(this.proxyVarType) {
		case ProxyVarType.STATIC:
			type = 'static';
			break;
		case ProxyVarType.THISMOD:
			type = 'thismod';
			outputId = false;
			break;
		case ProxyVarType.MEMBER:
			type = 'member';
			break;
		case ProxyVarType.ARG_VAR:
			type = 'var arg';
			break;
		case ProxyVarType.ARG_ARRAY:
			type = 'array arg';
			break;
		case ProxyVarType.ARG_LOCAL:
			type = 'local arg';
			break;
		case ProxyVarType.ARG_NOTVAR:
			type = 'arg';
			break;
		default:
			type = this.proxyVarType;
		}
		return '<VariableData: '+type+(outputId?'#'+this.id:'')+'>';
	},
	isVariableAgentVarData: function() {
		var type = this.proxyVarType;
		return type == ProxyVarType.THISMOD || type == ProxyVarType.ARG_VAR;
	}
};

function StaticVariableTag(name) {
	this.name = name;
}

StaticVariableTag.prototype.toString = function() {
	return '<StaticVariableTag:'+this.name+'>';
};

var ProxyVarType = {
	STATIC: 0,
	THISMOD: 1,
	MEMBER: 2,
	ARG_VAR: 3,
	ARG_ARRAY: 4,
	ARG_LOCAL: 5,
	ARG_NOTVAR: 6
};

Compiler.prototype = {
	compile: function() {
		var sequence = new ISeq;
		while(this.tokensPos < this.ax.tokens.length) {
			var token = this.ax.tokens[this.tokensPos];
			if(!token.ex1) {
				throw this.error();
			}
			this.pushLabels(sequence, token.pos);
			this.compileStatement(sequence);
		}
		this.removeDeadCode(sequence);
		this.peepholeOptimize(sequence);
		this.defineInsnIndex(sequence);
		this.defineLabelPos(sequence);
		var result = this.sequenceToArray(sequence);
		this.deleteLink(sequence);
		return result;
	},
	pushLabels: function(sequence, pos) {
		var labelIDs = this.ax.labelsMap[pos];
		if(labelIDs) {
			for(var i = 0; i < labelIDs.length; i ++) {
				var labelID = labelIDs[i];
				sequence.push(this.labels[labelID]);
			}
		}
		var labels = this.ifLabels[pos];
		if(labels) {
			for(var i = 0; i < labels.length; i ++) {
				sequence.push(labels[i]);
			}
		}
		delete this.ifLabels[pos];
	},
	makeLabels: function() {
		var len = this.ax.labels.length;
		var labels = [];
		for(var i = 0; i < len; i ++) {
			labels[i] = new Label;
		}
		return labels;
	},
	makeStaticVarTags: function() {
		var tags = [];
		var len = this.ax.max_val;
		var varNames = this.ax.variableNames;
		for(var i = 0; i < len; i ++) {
			tags[i] = new StaticVariableTag(varNames[i]);
		}
		return tags;
	},
	defineInsnIndex: function(sequence) {
		var index = 0;
		sequence.forEachOnlyInsn(function(insn) {
			insn.index = index++;
		});
	},
	defineLabelPos: function(sequence) {
		sequence.forEach(function(elem) {
			if(elem.type != ISeqElem.Type.LABEL) return;
			elem.definePos();
		});
	},
	sequenceToArray: function(sequence) {
		var result = [];
		sequence.forEachOnlyInsn(function(insn) {
			result.push(insn);
		});
		return result;
	},
	deleteLink: function(sequence) {
		var elem = sequence.first();
		while(elem) {
			var next = elem.next;
			elem.next = elem.prev = null;
			elem = next;
		}
		ISeq.link(sequence.firstGuard, sequence.lastGuard);
	},
	removeDeadCode: function(sequence) {
		sequence.forEachOnlyInsn(function(insn) {
			insn.alive = false;
		});
		var insns = [sequence.firstInsn()];
		while(insns.length) {
			var insn = insns.pop();
			while(insn) {
				if(insn.alive) break;
				insn.alive = true;
				var code = insn.code;
				var opts = insn.opts;
				if(code == Insn.Code.GOTO || code == Insn.Code.CONTINUE || code == Insn.Code.BREAK) {
					insn = insn.opts[0].getInsn();
					continue;
				}
				if(code == Insn.Code.CALL_BUILTIN_CMD &&
				   opts[0] == Token.Type.PROGCMD &&
				   (opts[1] == 0x10 ||  // end
				    opts[1] == 0x11)) { // stop
					break;
				}
				this.markInsnOpts(insns, code, opts);
				if(code == Insn.Code.GOTO_EXPR || code == Insn.Code.RETURN) {
					break;
				}
				insn = insn.getNextInsn();
			}
		}
		sequence.forEachOnlyInsn(function(insn) {
			if(!insn.alive) {
				insn.remove();
			}
		});
	},
	markInsnOpts: function(insns, code, opts) {
		switch(code) {
		case Insn.Code.NOP:
			break;
		case Insn.Code.PUSH_VAR:
		case Insn.Code.GET_VAR:
			this.markParamInfos(insns, opts[1]);
			break;
		case Insn.Code.POP:
		case Insn.Code.POP_N:
		case Insn.Code.DUP:
			break;
		case Insn.Code.IFNE:
		case Insn.Code.IFEQ:
			this.markLabel(insns, opts[0]);
			this.markParamInfo(insns, opts[1]);
			break;
		case Insn.Code.ASSIGN:
			this.markParamInfos(insns, opts[1]);
			this.markParamInfos(insns, opts[2]);
			break;
		case Insn.Code.COMPOUND_ASSIGN:
			this.markParamInfos(insns, opts[2]);
			this.markParamInfo(insns, opts[3]);
			break;
		case Insn.Code.INC:
		case Insn.Code.DEC:
			this.markParamInfos(insns, opts[1]);
			break;
		case Insn.Code.CALL_BUILTIN_CMD:
		case Insn.Code.CALL_BUILTIN_FUNC:
			this.markParamInfos(insns, opts[2]);
			break;
		case Insn.Code.CALL_USERDEF_CMD:
		case Insn.Code.CALL_USERDEF_FUNC:
			this.markLabel(insns, opts[0].label);
			this.markParamInfos(insns, opts[1]);
			break;
		case Insn.Code.NEWMOD:
			this.markParamInfo(insns, opts[0]);
			this.markModule(insns, opts[1]);
			if(opts[2]) {
				this.markParamInfos(insns, opts[2]);
			}
			break;
		case Insn.Code.RETURN:
			if(opts[0]) {
				this.markParamInfo(insns, opts[0]);
			}
			break;
		case Insn.Code.REPEAT:
			this.markLabel(insns, opts[0]);
			this.markParamInfos(insns, opts[1]);
			break;
		case Insn.Code.LOOP:
			break;
		case Insn.Code.CONTINUE:
			this.markLabel(insns, opts[0]);
			if(opts[1]) {
				this.markParamInfo(insns, opts[1]);
			}
			break;
		case Insn.Code.BREAK:
			this.markLabel(insns, opts[0]);
			break;
		case Insn.Code.FOREACH:
			break;
		case Insn.Code.EACHCHK:
			this.markLabel(insns, opts[0]);
			this.markParamInfo(insns, opts[1]);
			break;
		case Insn.Code.GOSUB:
			this.markLabel(insns, opts[0]);
			break;
		case Insn.Code.GOTO_EXPR:
		case Insn.Code.GOSUB_EXPR:
			this.markParamInfo(insns, opts[0]);
			break;
		case Insn.Code.EXGOTO:
			this.markParamInfos(insns, opts[0]);
			break;
		case Insn.Code.ON:
			this.markParamInfos(insns, opts[1]);
			this.markParamInfo(insns, opts[2]);
			break;
		default:
			throw new Error('must not happen');
		}
	},
	markLabel: function(insns, label) {
		insns.push(label.getInsn());
	},
	markModule: function(insns, module) {
		if(module.constructor) {
			this.markLabel(insns, module.constructor.label);
		}
		if(module.destructor) {
			this.markLabel(insns, module.destructor.label);
		}
	},
	markParamInfo: function(insns, paramInfo) {
		var self = this;
		traverseParamInfo(paramInfo, function(node) {
			if(!node.isLabelNode()) return;
			self.markLabel(insns, node.lobj);
		});
	},
	markParamInfos: function(insns, paramInfos) {
		for(var i = 0; i < paramInfos.length; i ++) {
			this.markParamInfo(insns, paramInfos[i]);
		}
	},
	peepholeOptimize: function(sequence) {
		var insn = sequence.firstInsn();
		while(insn) {
			var nextInsn = insn.getNextInsn();
			var prevInsn = insn.getPrevInsn();
			if(insn.code == Insn.Code.GOTO) {
				var destInsn = insn.opts[0].getInsn();
				if(destInsn == nextInsn) {
					// GOTO命令でジャンプ先が次の命令の場合、削除する
					insn.remove();
				} else if(destInsn != insn &&
				          destInsn.code == Insn.Code.GOTO &&
				          insn.opts[0] != destInsn.opts[0]) {
					// GOTO命令(a)のジャンプ先がGOTO命令(b)だったら、(a)のジャンプ先を(b)のジャンプ先に変更する
					insn.opts[0] = destInsn.opts[0];
					continue;
				} else if(prevInsn &&
				   (prevInsn.code == Insn.Code.IFEQ ||
				    prevInsn.code == Insn.Code.IFNE) &&
				   nextInsn == prevInsn.opts[0].getInsn()) {
					// 「IFEQ L1; GOTO L2; L1: ...」 => 「IFNE L2」
					if(prevInsn.code == Insn.Code.IFEQ) {
						prevInsn.code = Insn.Code.IFNE;
					}else {
						prevInsn.code = Insn.Code.IFEQ;
					}
					prevInsn.opts[0] = insn.opts[0];
					insn.remove();
				}
			}
			if(insn.code == Insn.Code.IFEQ || insn.code == Insn.Code.IFNE) {
				// 「IFEQ L1; ...; L1: GOTO L2」 => 「IFEQ L2」
				var destInsn = insn.opts[0].getInsn();
				if(destInsn.code == Insn.Code.GOTO) {
					insn.opts[0] = destInsn.opts[0];
				}
			}
			insn = nextInsn;
		}
	},
	pushNewInsn: function(sequence, code, opts, token) {
		if(!token) token = this.ax.tokens[this.tokensPos];
		sequence.push(new Insn(code, opts, token.fileName, token.lineNo));
	},
	getFinfoIdByMinfoId: function(minfoId) {
		var funcsInfo = this.ax.funcsInfo;
		for(var i = 0; i < funcsInfo.length; i ++) {
			var funcInfo = funcsInfo[i];
			if(funcInfo.prmindex <= minfoId && minfoId < funcInfo.prmindex + funcInfo.prmmax) {
				return i;
			}
		}
		return null;
	},
	error: function(message, token) {
		if(!token) token = this.ax.tokens[this.tokensPos];
		return new CompileError(message, token.fileName, token.lineNo);
	},
	compileStatement: function(sequence) {
		var token = this.ax.tokens[this.tokensPos];
		switch(token.type) {
		case Token.Type.VAR:
		case Token.Type.STRUCT:
			this.compileAssignment(sequence);
			break;
		case Token.Type.CMPCMD:
			this.compileBranchCommand(sequence);
			break;
		case Token.Type.PROGCMD:
			this.compileProgramCommand(sequence);
			break;
		case Token.Type.MODCMD:
			this.compileUserDefCommand(sequence);
			break;
		case Token.Type.INTCMD:
			this.compileBasicCommand(sequence);
			break;
		case Token.Type.EXTCMD:
			this.compileGuiCommand(sequence);
			break;
		case Token.Type.DLLFUNC:
		case Token.Type.DLLCTRL:
			this.compileCommand(sequence);
			break;
		default:
			throw this.error("命令コード " + token.type + " は解釈できません。");
		}
	},
	compileAssignment: function(sequence) {
		var varToken = this.ax.tokens[this.tokensPos];
		var varData = this.getVariableData(true);
		++ this.tokensPos;
		var indexNodes = this.getVariableSubscriptNodes();
		var token = this.ax.tokens[this.tokensPos++];
		if(!(token && token.type == Token.Type.MARK)) {
			throw this.error();
		}
		if(this.ax.tokens[this.tokensPos].ex1 && (token.val == 0 || token.val == 1)) {
			// インクリメント / デクリメント
			var indexParamInfos = this.compileNodes(sequence, indexNodes);
			this.pushNewInsn(sequence, Insn.Code.INC + token.val, [varData, indexParamInfos], token);
			return;
		}
		var rhsParamInfos = this.compileParameters(sequence, true, returnTrue);
		var indexParamInfos = this.compileNodes(sequence, indexNodes);
		if(token.val != 8) { // CALCCODE_EQ
			// 複合代入
			if(rhsParamInfos.length != 1) {
				throw this.error("複合代入のパラメータの数が間違っています。", token);
			}
			this.pushNewInsn(sequence, Insn.Code.COMPOUND_ASSIGN, [token.val, varData, indexParamInfos, rhsParamInfos[0]], token);
			return;
		}
		if(rhsParamInfos.length == 0) {
			throw this.error("代入のパラメータの数が間違っています。", token);
		}
		this.pushNewInsn(sequence, Insn.Code.ASSIGN, [varData, indexParamInfos, rhsParamInfos], token);
	},
	compileProgramCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos];
		switch(token.code) {
		case 0x00: // goto
			var labelToken = this.ax.tokens[this.tokensPos + 1];
			if(labelToken && labelToken.type == Token.Type.LABEL && !labelToken.ex2 && (!this.ax.tokens[this.tokensPos + 2] || this.ax.tokens[this.tokensPos + 2].ex1)) {
				this.pushNewInsn(sequence, Insn.Code.GOTO,
				                 [this.labels[labelToken.code]]);
				this.tokensPos += 2;
			} else {
				this.tokensPos ++;
				var paramInfos = this.compileParameters(sequence, false, returnTrue);
				if(paramInfos.length != 1) throw this.error('goto の引数の数が違います', token);
				this.pushNewInsn(sequence, Insn.Code.GOTO_EXPR, [paramInfos[0]], token);
			}
			break;
		case 0x01: // gosub
			var labelToken = this.ax.tokens[this.tokensPos + 1];
			if(labelToken && labelToken.type == Token.Type.LABEL && !labelToken.ex2 && (!this.ax.tokens[this.tokensPos + 2] || this.ax.tokens[this.tokensPos + 2].ex1)) {
				this.pushNewInsn(sequence, Insn.Code.GOSUB,
				                 [this.labels[labelToken.code]]);
				this.tokensPos += 2;
			} else {
				this.tokensPos ++;
				var paramInfos = this.compileParameters(sequence, false, returnTrue);
				if(paramInfos.length != 1) throw this.error('gosub の引数の数が違います', token);
				this.pushNewInsn(sequence, Insn.Code.GOSUB_EXPR, [paramInfos[0]], token);
			}
			break;
		case 0x02: // return
			this.tokensPos ++;
			if(this.ax.tokens[this.tokensPos].ex2) throw this.error('パラメータは省略できません', token);
			var existReturnValue = !this.ax.tokens[this.tokensPos].ex1;
			var paramInfo = null;
			if(existReturnValue) {
				paramInfo = this.compileParameter(sequence, true, returnTrue);
				if(this.getParametersNodesSub().length > 0) throw this.error('return の引数が多すぎます', token);
			}
			this.pushNewInsn(sequence, Insn.Code.RETURN, [paramInfo], token);
			break;
		case 0x03: // break
			this.tokensPos ++;
			var labelToken = this.ax.tokens[this.tokensPos++];
			if(labelToken.type != Token.Type.LABEL) {
				throw this.error();
			}
			if(this.getParametersNodes().length > 0) throw this.error('break の引数が多すぎます', token);
			this.pushNewInsn(sequence, Insn.Code.BREAK,
			                 [this.labels[labelToken.code]], token);
			break;
		case 0x04: // repeat
			this.tokensPos ++;
			var labelToken = this.ax.tokens[this.tokensPos++];
			if(labelToken.type != Token.Type.LABEL) {
				throw this.error();
			}
			var paramInfos = this.compileParameters(sequence, false, returnTrue, paramInfos);
			if(paramInfos.length > 2) throw this.error('repeat の引数が多すぎます', token);
			this.pushNewInsn(sequence, Insn.Code.REPEAT,
			                 [this.labels[labelToken.code], paramInfos], token);
			break;
		case 0x05: // loop
			this.tokensPos ++;
			if(this.getParametersNodes().length > 0) throw this.error('loop の引数が多すぎます', token);
			this.pushNewInsn(sequence, Insn.Code.LOOP, [], token);
			break;
		case 0x06: // continue
			this.tokensPos ++;
			var labelToken = this.ax.tokens[this.tokensPos++];
			if(labelToken.type != Token.Type.LABEL) {
				throw this.error();
			}
			var paramInfos = this.compileParameters(sequence, false, returnTrue);
			if(paramInfos.length > 1) throw this.error('continue の引数が多すぎます', token);
			this.pushNewInsn(sequence, Insn.Code.CONTINUE,
			                 [this.labels[labelToken.code], paramInfos[0]], token);
			break;
		case 0x0b: // foreach
			this.tokensPos ++;
			var labelToken = this.ax.tokens[this.tokensPos++];
			if(labelToken.type != Token.Type.LABEL) {
				throw this.error();
			}
			if(this.getParametersNodes().length > 0) throw this.error();
			this.pushNewInsn(sequence, Insn.Code.FOREACH,
			                 [this.labels[labelToken.code]], token);
			break;
		case 0x0c: // eachchk
			this.tokensPos ++;
			var labelToken = this.ax.tokens[this.tokensPos++];
			if(labelToken.type != Token.Type.LABEL) {
				throw this.error();
			}
			var paramInfos = this.compileParameters(sequence);
			if(paramInfos.length != 1) throw this.error('foreach の引数の数が違います', token);
			this.pushNewInsn(sequence, Insn.Code.EACHCHK,
			                 [this.labels[labelToken.code], paramInfos[0]], token);
			break;
		case 0x12: // newmod
			this.tokensPos ++;
			if(this.ax.tokens[this.tokensPos].ex2) {
				throw this.error('パラメータは省略できません');
			}
			var varNode = this.getVarNode(true, false);
			var structToken = this.ax.tokens[this.tokensPos++];
			var prmInfo = this.ax.prmsInfo[structToken.code];
			if(structToken.type != Token.Type.STRUCT || prmInfo.mptype != MPType.STRUCTTAG) {
				throw this.error('モジュールが指定されていません', structToken);
			}
			var module = this.getUserDefFunc(prmInfo.subid);
			var paramInfos = null;
			var argc;
			if(module.constructor) {
				paramInfos = this.compileNodes(sequence, this.getUserDefFuncallParamNodes(module.constructor, false, false));
				argc = paramInfos.length;
			} else {
				argc = this.getParametersNodesSub().length;
			}
			this.pushNewInsn(sequence, Insn.Code.NEWMOD,
				             [this.compileNode(sequence, varNode), module, paramInfos, argc], token);
			break;
		case 0x18: // exgoto
			// exgoto の第一引数は変数だが、値しか使わない
			// FIXME 添え字つきのときに配列拡張していない
			this.tokensPos ++;
			var paramInfos = this.compileParameters(sequence, false, returnTrue);
			if(paramInfos.length != 4) throw this.error('exgoto の引数の数が違います', token);
			this.pushNewInsn(sequence, Insn.Code.EXGOTO, [paramInfos], token);
			break;
		case 0x19: // on
			// ON 命令はラベルを評価してから、インデックスを評価するのでコンパイルする順番は インデックス -> ラベルで問題ない
			this.tokensPos ++;
			var paramToken = this.ax.tokens[this.tokensPos];
			if(paramToken.ex1 || paramToken.ex2) {
				throw this.error('パラメータは省略できません', token);
			}
			var indexParamInfo = this.compileParameter(sequence, true);
			var jumpTypeToken = this.ax.tokens[this.tokensPos];
			if(jumpTypeToken.ex1 || jumpTypeToken.type != Token.Type.PROGCMD || jumpTypeToken.code > 1) {
				throw this.error('goto / gosub が指定されていません', token);
			}
			var isGosub = jumpTypeToken.code == 1;
			this.tokensPos ++;
			var labelParamInfos = this.compileParametersSub(sequence, false, returnTrue);
			this.pushNewInsn(sequence, Insn.Code.ON, [isGosub, labelParamInfos, indexParamInfo], token);
			break;
		default:
			this.compileCommand(sequence);
		}
	},
	compileBasicCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos];
		switch(token.code) {
		case 0x00: // onexit
		case 0x01: // onerror
		case 0x02: // onkey
		case 0x03: // onclick
		case 0x04: // oncmd
			this.tokensPos ++;
			var paramInfos = [this.compileOptionalJumpType(sequence)];
			this.compileParameters(sequence, false, returnTrue, paramInfos);
			this.pushNewInsn(sequence, Insn.Code.CALL_BUILTIN_CMD,
			                 [token.type, token.code, paramInfos], token);
			break;
		default:
			this.compileCommand(sequence);
		}
	},
	compileGuiCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos];
		switch(token.code) {
		case 0x00: // button
			this.tokensPos ++;
			var paramInfos = [this.compileOptionalJumpType(sequence)];
			this.compileParameters(sequence, false, returnTrue, paramInfos);
			this.pushNewInsn(sequence, Insn.Code.CALL_BUILTIN_CMD,
			                 [token.type, token.code, paramInfos], token);
			break;
		default:
			this.compileCommand(sequence);
		}
	},
	compileCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos++];
		var paramInfos = this.compileParameters(sequence, false, this.builtinFuncParametersCallback(token.type, token.code));
		this.pushNewInsn(sequence, Insn.Code.CALL_BUILTIN_CMD,
		                 [token.type, token.code, paramInfos], token);
	},
	builtinFuncParametersCallback: function(type, subid) {
		var i = 0;
		var info = BuiltinFuncInfos[type][subid];
		return info ? function() { return info.notReceiveVar(i++) } : returnFalse;
	},
	compileBranchCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos++];
		var skipTo = token.pos + token.size + token.skipOffset;
		var label = new Label;
		if(skipTo in this.ifLabels) {
			this.ifLabels[skipTo].push(label);
		} else {
			this.ifLabels[skipTo] = [label];
		}
		var nodes = this.getParametersNodes(true, returnTrue);
		if(token.code == 0) { // 'if'
			if(nodes.length != 1) throw this.error("if の引数の数が間違っています。", token);
			var paramInfo = this.compileNode(sequence, nodes[0]);
			// if の条件式がリテラルのとき最適化
			var node = paramInfo.node;
			if(node.isLiteralNode() &&
			   (node.val.type == VarType.INT || node.val.type == VarType.DOUBLE)) {
				if(!node.val._value) {
					this.pushNewInsn(sequence, Insn.Code.GOTO, [label], token);
				}
				return;
			}
			this.pushNewInsn(sequence, Insn.Code.IFEQ, [label, paramInfo], token);
		} else {
			if(nodes.length != 0) throw this.error("else の引数の数が間違っています。", token);
			this.pushNewInsn(sequence, Insn.Code.GOTO, [label], token);
		}
	},
	compileParameters: function(sequence, cannotBeOmitted, notReceiveVarCallback, result) {
		return this.compileParameters0(sequence, cannotBeOmitted, notReceiveVarCallback, result, true);
	},
	compileParametersSub: function(sequence, cannotBeOmitted, notReceiveVarCallback, result) {
		return this.compileParameters0(sequence, cannotBeOmitted, notReceiveVarCallback, result, false);
	},
	compileParameters0: function(sequence, cannotBeOmitted, notReceiveVarCallback, result, isHead) {
		if(!result) result = [];
		var len = result.length;
		this.getParametersNodes0(cannotBeOmitted, notReceiveVarCallback, result, isHead);
		for(var i = result.length - 1; i >= len; i --) {
			result[i] = this.compileNode(sequence, result[i]);
		}
		return result;
	},
	compileParameter: function(sequence, notReceiveVar) {
		return this.compileNode(sequence, this.getParameterNode(notReceiveVar));
	},
	compileNodes: function(sequence, nodes) {
		var paramInfos = [];
		for(var i = nodes.length - 1; i >= 0; i --) {
			paramInfos[i] = this.compileNode(sequence, nodes[i]);
		}
		return paramInfos;
	},
	compileNode: function(sequence, root) {
		var stackSize = 0;
		var propname = 0;
		var rootWrapper = [root];
		var self = this;
		function traverse(parent, propname) {
			var node = parent[propname];
			switch(node.nodeType) {
			case NodeType.VAR:
				if(node.indexNodes.length > 0) {
					parent[propname] = new GetStackNode(node);
					stackSize ++;
					self.pushNewInsn(sequence,
					                 node.onlyValue ? Insn.Code.GET_VAR : Insn.Code.PUSH_VAR,
					                 [node.varData, self.compileNodes(sequence, node.indexNodes)],
					                 node.token);
				}
				break;
			case NodeType.ARG:
				break;
			case NodeType.LITERAL:
				break;
			case NodeType.LABEL:
				break;
			case NodeType.DEFAULT:
				break;
			case NodeType.OPERATE:
				traverse(node, 'rhsNode');
				traverse(node, 'lhsNode');
				break;
			case NodeType.USERDEF_FUNCALL:
				parent[propname] = new GetStackNode(node);
				stackSize ++;
				var paramInfos = self.compileNodes(sequence, node.paramNodes);
				self.pushNewInsn(sequence,
				                 Insn.Code.CALL_USERDEF_FUNC,
				                 [node.userDefFunc, paramInfos],
				                 node.token);
				break;
			case NodeType.BUILTIN_FUNCALL:
				var paramInfos = self.compileNodes(sequence, node.paramNodes);
				var info = BuiltinFuncInfos[node.groupId][node.subId];
				if(info && info.isInlineExpr) {
					parent[propname] = new InlineExprBuiltinFuncall(node.groupId, node.subId, info, paramInfos);
					break;
				}
				parent[propname] = new GetStackNode(node);
				stackSize ++;
				self.pushNewInsn(sequence,
				                 Insn.Code.CALL_BUILTIN_FUNC,
				                 [node.groupId, node.subId, paramInfos],
				                 node.token);
				break;
			default:
				throw new Error('must not happen');
			}
		}
		traverse(rootWrapper, 0);
		return new ParamInfo(rootWrapper[0], stackSize);
	},
	getParametersNodes: function(cannotBeOmitted, notReceiveVarCallback, nodes) {
		return this.getParametersNodes0(cannotBeOmitted, notReceiveVarCallback, nodes, true);
	},
	getParametersNodesSub: function(cannotBeOmitted, notReceiveVarCallback, nodes) {
		return this.getParametersNodes0(cannotBeOmitted, notReceiveVarCallback, nodes, false);
	},
	getParametersNodes0: function(cannotBeOmitted, notReceiveVarCallback, nodes, isHead) {
		if(!notReceiveVarCallback) notReceiveVarCallback = returnFalse;
		if(!nodes) nodes = [];
		if(isHead && this.ax.tokens[this.tokensPos].ex2) {
			if(cannotBeOmitted) {
				throw this.error('パラメータの省略はできません');
			}
			nodes.push(new DefaultNode);
		}
		while(true) {
			var token = this.ax.tokens[this.tokensPos];
			if(!token || token.ex1) break;
			if(token.type == Token.Type.MARK) {
				if(token.code == 63) { // '?'
					if(cannotBeOmitted) {
						throw this.error('パラメータの省略はできません');
					}
					nodes.push(new DefaultNode);
					this.tokensPos ++;
					continue;
				}
				if(token.code == 41) { // ')'
					break;
				}
			}
			var notReceiveVar = notReceiveVarCallback();
			nodes.push(this.getParameterNode(notReceiveVar));
		}
		return nodes;
	},
	getParameterNode: function(notReceiveVar) {
		var headPos = this.tokensPos;
		var stack = [];
		LOOP: while(true) {
			var token = this.ax.tokens[this.tokensPos];
			if(!token || token.ex1) break;
			switch(token.type) {
			case Token.Type.MARK:
				var calcCode = token.code;
				if(calcCode == 41) { // ')'
					break LOOP;
				}
				if(stack.length < 2) {
					throw this.error("演算のためのオペランドが足りません");
				}
				var rhs = stack.pop();
				var lhs = stack.pop();
				stack.push(this.compileOperator(calcCode, lhs, rhs));
				this.tokensPos ++;
				break;
			case Token.Type.VAR:
			case Token.Type.STRUCT:
				stack.push(this.getVarNode(false, true));
				break;
			case Token.Type.STRING:
				stack.push(new LiteralNode(new StrValue(token.val)));
				this.tokensPos ++;
				break;
			case Token.Type.DNUM:
				stack.push(new LiteralNode(new DoubleValue(token.val)));
				this.tokensPos ++;
				break;
			case Token.Type.INUM:
				stack.push(new LiteralNode(new IntValue(token.val)));
				this.tokensPos ++;
				break;
			case Token.Type.LABEL:
				stack.push(new LabelNode(this.labels[token.code]));
				this.tokensPos ++;
				break;
			case Token.Type.EXTSYSVAR:
				stack.push(this.getExtSysvarCallNode());
				break;
			case Token.Type.SYSVAR:
				stack.push(this.getSysvarCallNode());
				break;
			case Token.Type.MODCMD:
				stack.push(this.getUserDefFuncallNode());
				break;
			case Token.Type.INTFUNC:
			case Token.Type.DLLFUNC:
			case Token.Type.DLLCTRL:
				stack.push(this.getFuncallNode());
				break;
			default:
				throw this.error("命令コード " + token.type + " は解釈できません。");
			}
			token = this.ax.tokens[this.tokensPos];
			if(token && token.ex2) break;
		}
		if(stack.length > 1) {
			throw this.error("オペランドが余っています");
		}
		var node = stack[0];
		if(!notReceiveVar && node.isVarNode()) {
			node.onlyValue = false;
		}
		return node;
	},
	isOnlyVar: function(pos, headPos) {
		if(pos != headPos) return false;
		var nextTokenPos = pos + 1;
		nextTokenPos += this.skipParenAndParameters(nextTokenPos);
		var nextToken = this.ax.tokens[nextTokenPos];
		return (!nextToken || nextToken.ex1 || nextToken.ex2 || this.isRightParenToken(nextToken));
	},
	skipParameter: function(pos) {
		var size = 0;
		var parenLevel = 0;
		while(true) {
			var token = this.ax.tokens[pos + size];
			if(!token || token.ex1) return size;
			if(token.type == Token.Type.MARK) {
				switch(token.val) {
				case 40:
					parenLevel ++;
					break;
				case 41:
					if(parenLevel == 0) return size;
					parenLevel --;
					break;
				case 63:
					return size + 1;
					break;
				}
			}
			size ++;
			token = this.ax.tokens[pos + size];
			if(parenLevel == 0 && token && token.ex2) {
				return size;
			}
		}
	},
	skipParameters: function(pos) {
		var skipped = 0;
		var size = 0;
		while((skipped = this.skipParameter(pos + size))) {
			size += skipped;
		}
		return size;
	},
	skipParenAndParameters: function(pos) {
		var parenToken = this.ax.tokens[pos];
		if(!(parenToken && parenToken.type == Token.Type.MARK && parenToken.code == 40)) {
			return 0;
		}
		var size = 1;
		size += this.skipParameters(pos + size);
		parenToken = this.ax.tokens[pos + size];
		if(!(parenToken && parenToken.type == Token.Type.MARK && parenToken.code == 41)) {
			throw this.error('関数パラメータの後ろに閉じ括弧がありません。', parenToken);
		}
		return size + 1;
	},
	compileOperator: function(calcCode, lhs, rhs) {
		if(!(0 <= calcCode && calcCode < 16)) {
			throw this.error("演算子コード " + token.code + " は解釈できません。", token);
		}
		if(lhs.isLiteralNode() && rhs.isLiteralNode()) {
			try {
				var result = this.operate(lhs.val, rhs.val, calcCode);
				return new LiteralNode(result);
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		return new OperateNode(calcCode, lhs, rhs);
	},
	operate: function(lhs, rhs, calcCode) {
		switch(calcCode) {
		case  0: return lhs.add(rhs);
		case  1: return lhs.sub(rhs);
		case  2: return lhs.mul(rhs);
		case  3: return lhs.div(rhs);
		case  4: return lhs.mod(rhs);
		case  5: return lhs.and(rhs);
		case  6: return lhs.or(rhs);
		case  7: return lhs.xor(rhs);
		case  8: return lhs.eq(rhs);
		case  9: return lhs.ne(rhs);
		case 10: return lhs.gt(rhs);
		case 11: return lhs.lt(rhs);
		case 12: return lhs.gteq(rhs);
		case 13: return lhs.lteq(rhs);
		case 14: return lhs.rsh(rhs);
		case 15: return lhs.lsh(rhs);
		default:  throw new Error('must not happen');
		}
	},
	getVarNode: function(mustBeVar, onlyValue) {
		var token = this.ax.tokens[this.tokensPos];
		var varData = this.getVariableData(mustBeVar);
		++ this.tokensPos;
		if(varData.proxyVarType == ProxyVarType.ARG_NOTVAR) {
			return new ArgNode(varData.id);
		}
		var indexNodes = this.getVariableSubscriptNodes();
		return new VarNode(varData, indexNodes, onlyValue, token);
	},
	getExtSysvarCallNode: function() {
		var token = this.ax.tokens[this.tokensPos];
		if(token.code >= 0x100) {
			return this.getFuncallNode();
		} else {
			return this.getSysvarCallNode();
		}
	},
	getSysvarCallNode: function() {
		var token = this.ax.tokens[this.tokensPos++];
		return new BuiltinFuncallNode(token.type, token.code, [], token);
	},
	compileOptionalJumpType: function(sequence) {
		var token = this.ax.tokens[this.tokensPos];
		var jumpType;
		if(!token.ex1 && token.type == Token.Type.PROGCMD && token.val == 0) {
			this.tokensPos ++;
			return this.compileNode(sequence, new LiteralNode(JumpType.GOTO));
		} else if(!token.ex1 && token.type == Token.Type.PROGCMD && token.val == 1) {
			this.tokensPos ++;
			return this.compileNode(sequence, new LiteralNode(JumpType.GOSUB));
		} else {
			return this.compileNode(sequence, new DefaultNode);
		}
	},
	getUserDefFuncallNode: function() {
		var token = this.ax.tokens[this.tokensPos++];
		var userDefFunc = this.getUserDefFunc(token.code);
		var nodes = this.getUserDefFuncallParamNodes(userDefFunc, true, true);
		return new UserDefFuncallNode(userDefFunc, nodes, token);
	},
	compileUserDefCommand: function(sequence) {
		var token = this.ax.tokens[this.tokensPos++];
		var userDefFunc = this.getUserDefFunc(token.code);
		var paramInfos = this.compileNodes(sequence, this.getUserDefFuncallParamNodes(userDefFunc, false, true));
		this.pushNewInsn(sequence, Insn.Code.CALL_USERDEF_CMD,
		                 [userDefFunc, paramInfos], token);
	},
	getUserDefFuncallParamNodes: function(userDefFunc, isCType, isHead) {
		var argsCount = 0; // 仮引数の現在位置
		var nodes = [];
		function nextMPType() {
			do {
				var mptype = userDefFunc.paramTypes[argsCount++];
			} while(mptype == MPType.LOCALVAR);
			return mptype;
		}
		if(isHead && isCType) this.compileLeftParen();
		if(isHead && this.ax.tokens[this.tokensPos].ex2) {
			nodes.push(new DefaultNode());
			nextMPType();
		}
		while(true) {
			var token = this.ax.tokens[this.tokensPos];
			if(!token || token.ex1) break;
			if(token.type == Token.Type.MARK) {
				if(token.code == 63) { // '?'
					this.tokensPos ++;
					nodes.push(new DefaultNode());
					nextMPType();
					continue;
				}
				if(token.code == 41) { // ')'
					break;
				}
			}
			var mptype = nextMPType();
			var notReceiveVar = mptype != MPType.SINGLEVAR &&
			                    mptype != MPType.MODULEVAR &&
			                    mptype != MPType.ARRAYVAR;
			var node = this.getParameterNode(notReceiveVar);
			nodes.push(node);
		}
		if(isCType) this.compileRightParen();
		return nodes;
	},
	getUserDefFunc: function(finfoId) {
		var func = this.userDefFuncs[finfoId];
		if(func) return func;
		var funcInfo = this.ax.funcsInfo[finfoId];
		if(funcInfo.index == -3) { // STRUCTDAT_INDEX_STRUCT
			var destructor = funcInfo.otindex != 0 ? this.getUserDefFunc(funcInfo.otindex) : null;
			var constructorFinfoId = this.ax.prmsInfo[funcInfo.prmindex].offset;
			var constructor = constructorFinfoId != -1 ? this.getUserDefFunc(constructorFinfoId) : null;
			return this.userDefFuncs[finfoId] = new Module(funcInfo.name, constructor, destructor, funcInfo.prmmax - 1);
		}
		var isCType = funcInfo.index == -2; // STRUCTDAT_INDEX_CFUNC
		var paramTypes = [];
		for(var i = 0; i < funcInfo.prmmax; i ++) {
			paramTypes[i] = this.ax.prmsInfo[funcInfo.prmindex + i].mptype;
		}
		return this.userDefFuncs[finfoId] = new UserDefFunc(isCType, funcInfo.name, this.labels[funcInfo.otindex], paramTypes);
	},
	getFuncallNode: function() {
		var token = this.ax.tokens[this.tokensPos++];
		this.compileLeftParen();
		var nodes = this.getParametersNodes(false, this.builtinFuncParametersCallback(token.type, token.code));
		this.compileRightParen();
		var groupId = token.type;
		var subId = token.code;
		var allLiteralParam = true;
		for(var i = 0; i < nodes.length; i ++) {
			if(!nodes[i].isLiteralNode()) {
				allLiteralParam = false;
				break;
			}
		}
		if(allLiteralParam) {
			var func = BuiltinFuncInfos[groupId];
			func = func && func[subId];
			func = func && func.compileTimeFunc;
			if(func) {
				var args = [];
				for(var i = 0; i < nodes.length; i ++) {
					args[i] = nodes[i].val;
				}
				try {
					return new LiteralNode(func.apply(null, args));
				} catch(e) {
					if(!(e instanceof HSPError)) {
						throw e;
					}
				}
			}
		}
		return new BuiltinFuncallNode(groupId, subId, nodes, token);
	},
	compileLeftParen: function() {
		var parenToken = this.ax.tokens[this.tokensPos++];
		if(!(parenToken && parenToken.type == Token.Type.MARK && parenToken.code == 40)) {
			throw this.error('関数名の後ろに開き括弧がありません。', parenToken);
		}
	},
	compileRightParen: function() {
		var parenToken = this.ax.tokens[this.tokensPos++];
		if(!(parenToken && parenToken.type == Token.Type.MARK && parenToken.code == 41)) {
			throw this.error('関数パラメータの後ろに閉じ括弧がありません。', parenToken);
		}
	},
	getVariableData: function(mustBeVar) {
		var token = this.ax.tokens[this.tokensPos];
		var type;
		var id;
		if(token.type == Token.Type.VAR) {
			type = ProxyVarType.STATIC;
			id = this.staticVarTags[token.code];
		} else if(token.type == Token.Type.STRUCT) {
			type = this.getProxyVarType();
			if(mustBeVar && type == ProxyVarType.ARG_NOTVAR) {
				throw this.error('変数が指定されていません');
			}
			if(type != ProxyVarType.THISMOD) {
				var funcInfo = this.ax.funcsInfo[this.getFinfoIdByMinfoId(token.code)];
				if(type == ProxyVarType.MEMBER) {
					id = token.code - funcInfo.prmindex - 1;
				} else {
					id = token.code - funcInfo.prmindex;
				}
			}
		} else {
			if(!mustBeVar) throw new Error('must not happen');
			throw this.error('変数が指定されていません');
		}
		return new VariableData(type, id);
	},
	getProxyVarType: function() {
		var token = this.ax.tokens[this.tokensPos];
		if(token.code == -1) {
			if(this.isLeftParenToken(this.ax.tokens[this.tokensPos + 1])) {
				throw this.error('thismod に添字を指定しています');
			}
			return ProxyVarType.THISMOD;
		}
		var prmInfo = this.ax.prmsInfo[token.code];
		if(prmInfo.subid >= 0) {
			return ProxyVarType.MEMBER;
		}
		switch(prmInfo.mptype) {
		case MPType.LOCALVAR:
			return ProxyVarType.ARG_LOCAL;
		case MPType.ARRAYVAR:
			return ProxyVarType.ARG_ARRAY;
		case MPType.SINGLEVAR:
			if(this.isLeftParenToken(this.ax.tokens[this.tokensPos + 1])) {
				throw this.error('パラメータタイプ var の変数に添字を指定しています');
			}
			return ProxyVarType.ARG_VAR;
		default:
			if(this.isLeftParenToken(this.ax.tokens[this.tokensPos + 1])) {
				throw this.error('変数でないエイリアスに添字を指定しています');
			}
			return ProxyVarType.ARG_NOTVAR;
		}
	},
	isLeftParenToken: function(token) {
		return token && token.type == Token.Type.MARK && token.code == 40;
	},
	isRightParenToken: function(token) {
		return token && token.type == Token.Type.MARK && token.code == 41;
	},
	getVariableSubscriptNodes: function() {
		if(!this.isLeftParenToken(this.ax.tokens[this.tokensPos])) {
			return [];
		}
		this.tokensPos ++;
		var nodes = this.getParametersNodes(true, returnTrue);
		if(nodes.length == 0) {
			throw this.error('配列変数の添字が空です');
		}
		if(!this.isRightParenToken(this.ax.tokens[this.tokensPos++])) {
			throw this.error('配列変数の添字の後ろに閉じ括弧がありません。', parenToken);
		}
		return nodes;
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Compiler = Compiler;
	HSPonJS.CompileError = CompileError;
	HSPonJS.VariableData = VariableData;
	HSPonJS.ProxyVarType = ProxyVarType;
	HSPonJS.StaticVariableTag = StaticVariableTag;
}

function MainLoopGenerator(sequence) {
	this.sequence_ = sequence;
	this.literals_ = [];
	this.staticVarTags_ = [];
	this.registeredObjects_ = [];
	this.registeredObjectTags_ = [];
	this.lines_ = [];
	this.indent_ = 0;
	this.id = MainLoopGenerator.count++;
	this.registerPropName = '_hsponjs_mainloop_registered_id_' + this.id;
	this.staticVarTagsPropName = 'staticvartags_id_' + this.id;
}

MainLoopGenerator.count = 0;

MainLoopGenerator.Result = function(mainLoop, literals, staticVarTags, registeredObjects) {
	this.mainLoop = mainLoop;
	this.literals = literals;
	this.staticVarTags = staticVarTags;
	this.registeredObjects = registeredObjects;
}

function _defaultExpr(expr) {
	if(expr != null) {
		return expr;
	}
	return 'throwHSPError('+ErrorCode.NO_DEFAULT+')';
}

var _isDefault = isDefaultParamInfo;

MainLoopGenerator.prototype = {
	generate: function() {
		try {
			var mainLoop = this.generateMainLoop();
			return new MainLoopGenerator.Result(mainLoop, this.literals_, this.staticVarTags_, this.registeredObjects_);
		} finally {
			this.removeRegisteredObjectsPropName();
		}
	},
	generateMainLoop: function() {
		var src = '';
		for(var prop in HSPonJS) {
			src += 'var '+prop+' = HSPonJS.'+prop+';\n';
		}
		src += 'return function() {\n';
		src += 'var stack = this.stack;\n';
		src += 'var literals = this.literals;\n';
		src += 'var variables = this.variables;\n';
		src += 'var registeredObjects = this.registeredObjects;\n';
		src += this.generateMainLoopSrc() + '\n};';
		return Function(src)();
	},
	generateMainLoopSrc: function() {
		var sequence = this.sequence_;
		this.push('for(;;) {');
		this.incIndent();
		this.push('switch(this.pc) {');
		for(var pc = 0; pc < sequence.length; pc ++) {
			var insn = sequence[pc];
			this.push('case '+pc+':'); this.incIndent();
			this.pushInsnCode(insn, pc);
			this.push('this.pc ++;');
			this.decIndent();
		}
		this.push('}');
		this.decIndent();
		this.push('}');
		return this.lines_.join("\n");
	},
	pushInsnCode: function(insn, pc) {
		var opts = insn.opts;
		switch(insn.code) {
		case Insn.Code.NOP:
			this.pushCode_NOP(insn, pc);
			break;
		case Insn.Code.PUSH_VAR:
			this.pushCode_PUSH_VAR(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.GET_VAR:
			this.pushCode_GET_VAR(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.POP:
			this.pushCode_POP(insn, pc);
			break;
		case Insn.Code.POP_N:
			this.pushCode_POP_N(insn, pc, opts[0]);
			break;
		case Insn.Code.DUP:
			this.pushCode_DUP(insn, pc);
			break;
		case Insn.Code.GOTO:
			this.pushCode_GOTO(insn, pc, opts[0]);
			break;
		case Insn.Code.IFNE:
			this.pushCode_IFNE(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.IFEQ:
			this.pushCode_IFEQ(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.ASSIGN:
			this.pushCode_ASSIGN(insn, pc, opts[0], opts[1], opts[2]);
			break;
		case Insn.Code.COMPOUND_ASSIGN:
			this.pushCode_COMPOUND_ASSIGN(insn, pc, opts[0], opts[1], opts[2], opts[3]);
			break;
		case Insn.Code.INC:
			this.pushCode_INC(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.DEC:
			this.pushCode_DEC(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.CALL_BUILTIN_CMD:
			this.pushCode_CALL_BUILTIN_CMD(insn, pc, opts[0], opts[1], opts[2]);
			break;
		case Insn.Code.CALL_BUILTIN_FUNC:
			this.pushCode_CALL_BUILTIN_FUNC(insn, pc, opts[0], opts[1], opts[2]);
			break;
		case Insn.Code.CALL_USERDEF_CMD:
			this.pushCode_CALL_USERDEF_CMD(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.CALL_USERDEF_FUNC:
			this.pushCode_CALL_USERDEF_FUNC(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.NEWMOD:
			this.pushCode_NEWMOD(insn, pc, opts[0], opts[1], opts[2], opts[3]);
			break;
		case Insn.Code.RETURN:
			this.pushCode_RETURN(insn, pc, opts[0]);
			break;
		case Insn.Code.REPEAT:
			this.pushCode_REPEAT(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.LOOP:
			this.pushCode_LOOP(insn, pc);
			break;
		case Insn.Code.CONTINUE:
			this.pushCode_CONTINUE(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.BREAK:
			this.pushCode_BREAK(insn, pc, opts[0]);
			break;
		case Insn.Code.FOREACH:
			this.pushCode_FOREACH(insn, pc);
			break;
		case Insn.Code.EACHCHK:
			this.pushCode_EACHCHK(insn, pc, opts[0], opts[1]);
			break;
		case Insn.Code.GOSUB:
			this.pushCode_GOSUB(insn, pc, opts[0]);
			break;
		case Insn.Code.GOTO_EXPR:
			this.pushCode_GOTO_EXPR(insn, pc, opts[0]);
			break;
		case Insn.Code.GOSUB_EXPR:
			this.pushCode_GOSUB_EXPR(insn, pc, opts[0]);
			break;
		case Insn.Code.EXGOTO:
			this.pushCode_EXGOTO(insn, pc, opts[0]);
			break;
		case Insn.Code.ON:
			this.pushCode_ON(insn, pc, opts[0], opts[1], opts[2]);
			break;
		default:
			throw new Error('must not happen');
		}
	},
	pushCode_NOP: function(insn, pc) {
	},
	pushCode_PUSH_VAR: function(insn, pc, varData, indexParamInfos) {
		this.pushCodeToGetVariable(varData, indexParamInfos);
	},
	pushCode_GET_VAR: function(insn, pc, varData, indexParamInfos) {
		this.pushCodeToGetArrayValue(varData, indexParamInfos);
	},
	pushCode_POP: function(insn, pc) {
		this.push('stack.pop();');
	},
	pushCode_POP_N: function(insn, pc, n) {
		this.pushCodeToStackPop(n);
	},
	pushCode_DUP: function(insn, pc) {
		this.push('stack.push(stack[stack.length-1]);');
	},
	pushCode_GOTO: function(insn, pc, label) {
		this.push('this.pc = '+label.getPos()+';');
		this.push('continue;');
	},
	pushCode_IFNE: function(insn, pc, label, paramInfo) {
		this.pushCodeToBranch(label, paramInfo, false);
	},
	pushCode_IFEQ: function(insn, pc, label, paramInfo) {
		this.pushCodeToBranch(label, paramInfo, true);
	},
	pushCode_ASSIGN: function(insn, pc, varData, indexParamInfos, rhsParamInfos) {
		this.pushCodeToAssign(varData, indexParamInfos, rhsParamInfos);
	},
	pushCode_COMPOUND_ASSIGN: function(insn, pc, calcCode, varData, indexParamInfos, rhsParamInfo) {
		this.pushCodeToCompoundAssign(calcCode, varData, indexParamInfos, rhsParamInfo);
	},
	pushCode_INC: function(insn, pc, varData, indexParamInfos) {
		this.pushCodeToInc(varData, indexParamInfos);
	},
	pushCode_DEC: function(insn, pc, varData, indexParamInfos) {
		this.pushCodeToDec(varData, indexParamInfos);
	},
	pushCode_CALL_BUILTIN_CMD: function(insn, pc, type, subid, paramInfos) {
		this.pushCodeToCallBuiltinFunc(type, subid, paramInfos, false);
	},
	pushCode_CALL_BUILTIN_FUNC: function(insn, pc, type, subid, paramInfos) {
		this.pushCodeToCallBuiltinFunc(type, subid, paramInfos, true);
	},
	pushCode_CALL_USERDEF_CMD: function(insn, pc, userDefFunc, paramInfos) {
		this.pushCodeToCallUserdefFunc(userDefFunc, paramInfos, pc);
	},
	pushCode_CALL_USERDEF_FUNC: function(insn, pc, userDefFunc, paramInfos) {
		this.pushCodeToCallUserdefFunc(userDefFunc, paramInfos, pc);
	},
	pushCode_NEWMOD: function(insn, pc, varParamInfo, module, paramInfos, argc) {
		var moduleExpr = this.getRegisteredObjectExpr(module);
		var constructor = module.constructor;
		if(!constructor && argc > 0) {
			this.push('throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);')
			return;
		}
		var variableExpr = this.getNoSubscriptVariableParamExpr(varParamInfo);
		this.push('var variable = '+variableExpr+';');
		this.push('if(variable.value.type != '+VarType.STRUCT+') {');
		this.push('    variable.value = new StructArray();');
		this.push('}');
		this.push('var array = variable.value;');
		this.push('var offset = array.newmod('+moduleExpr+');');
		if(constructor) {
			this.pushCodeToCallUserdefFunc(constructor, paramInfos, pc, 'new VariableAgent1D(variable, offset)');
		}
	},
	pushCode_RETURN: function(insn, pc, paramInfo) {
		this.push('if(this.frameStack.length == 0) {');
		this.push('    throw new HSPError(ErrorCode.RETURN_WITHOUT_GOSUB);');
		this.push('}');
		if(paramInfo) {
			this.push('var val = '+this.getParamExpr(paramInfo)+';');
			this.push('var frame = this.frameStack.pop();');
			this.push('this.args = frame.prevArgs;');
			this.push('if(frame.userDefFunc && frame.userDefFunc.isCType) {');
			this.push('stack.push(val);');
			this.push('} else {');
			this.incIndent();
			this.push('switch(val.type) {');
			this.push('case '+VarType.STR+':');
			this.push('    this.refstr.assign(0, val);');
			this.push('    break;');
			this.push('case '+VarType.DOUBLE+':');
			this.push('    this.refdval.assign(0, val);');
			this.push('    break;');
			this.push('case '+VarType.INT+':');
			this.push('    this.stat.assign(0, val);');
			this.push('    break;');
			this.push('default:');
			this.push('    throw new HSPError(ErrorCode.TYPE_MISMATCH);');
			this.push('}');
			this.decIndent();
			this.push('}');
		} else {
			this.push('var frame = this.frameStack.pop();');
			this.push('this.args = frame.prevArgs;');
			this.push('if(frame.userDefFunc && frame.userDefFunc.isCType) {');
			this.push('    throw new HSPError(ErrorCode.NORETVAL);');
			this.push('}');
		}
		this.push('this.pc = frame.pc;');
		this.push('continue;');
	},
	pushCode_REPEAT: function(insn, pc, label, paramInfos) {
		this.pushCodeToStartLoop();
		if(paramInfos.length >= 1 && !paramInfos[0].node.isDefaultNode()) {
			this.push('this.cntEnd = '+this.getIntParamNativeValueExpr(paramInfos[0])+';');
			this.push('if(this.cntEnd < 0) this.cntEnd = Infinity;');
		} else {
			this.push('this.cntEnd = Infinity;');
		}
		if(paramInfos.length == 2) {
			this.push('this.cnt = '+this.getIntParamNativeValueExpr(paramInfos[1])+';');
		} else {
			this.push('this.cnt = 0;');
		}
		this.push('if(this.cntEnd == 0) {');
		this.push('    this.pc = '+label.getPos()+';');
		this.push('    continue;');
		this.push('}');
		this.push('this.cntEnd += this.cnt;');
		this.push('this.loopStartPos = '+(pc + 1)+';');
		this.push('this.looplev ++;');
	},
	pushCode_LOOP: function(insn, pc) {
		this.push('if(this.looplev == 0) {');
		this.push('    throw new HSPError(ErrorCode.LOOP_WITHOUT_REPEAT);');
		this.push('}');
		this.push('this.cnt ++;');
		this.push('if(this.cnt < this.cntEnd) {');
		this.push('    this.pc = this.loopStartPos;');
		this.push('    continue;');
		this.push('}');
		this.pushCodeToEndLoop();
	},
	pushCode_CONTINUE: function(insn, pc, label, paramInfo) {
		this.push('if(this.looplev == 0) {');
		this.push('    throw new HSPError(ErrorCode.LOOP_WITHOUT_REPEAT);');
		this.push('}');
		var newCntExpr;
		if(paramInfo) {
			newCntExpr = '(this.cnt = '+this.getIntParamNativeValueExpr(paramInfo)+')';
		} else {
			newCntExpr = '++this.cnt';
		}
		this.push('if('+newCntExpr+' >= this.cntEnd) {');
		this.incIndent();
		this.pushCodeToEndLoop();
		this.push('this.pc = '+label.getPos()+';');
		this.decIndent();
		this.push('} else {');
		this.push('    this.pc = this.loopStartPos;');
		this.push('}');
		this.push('continue;');
	},
	pushCode_BREAK: function(insn, pc, label) {
		this.push('if(this.looplev == 0) {');
		this.push('    throw new HSPError(ErrorCode.LOOP_WITHOUT_REPEAT);');
		this.push('}');
		this.pushCodeToEndLoop();
		this.push('this.pc = '+label.getPos()+';');
		this.push('continue;');
	},
	pushCode_FOREACH: function(insn, pc) {
		this.pushCodeToStartLoop();
		this.push('this.cnt = 0;');
		this.push('this.cntEnd = Infinity;');
		this.push('this.loopStartPos = '+(pc + 1)+';');
		this.push('this.looplev ++;');
	},
	pushCode_EACHCHK: function(insn, pc, label, paramInfo) {
		var pos = label.getPos();
		this.push('if(this.looplev == 0) {');
		this.push('    throw new HSPError(ErrorCode.LOOP_WITHOUT_REPEAT);')
		this.push('}')
		this.push('var array = '+this.getNoSubscriptVariableParamExpr(paramInfo)+'.value;');
		this.push('if(this.cnt >= array.getL0()) {')
		this.pushCodeToEndLoop();
		this.push('    this.pc = '+pos+';');
		this.push('    continue;');
		this.push('}');
		this.push('if(array.at(this.cnt).isUsing() == false) {'); // label 型 や struct 型の empty を飛ばす
		this.push('    this.cnt ++;');
		this.push('    if(this.cnt >= this.cntEnd) {');
		this.pushCodeToEndLoop();
		this.push('        this.pc = '+pos+';');
		this.push('    } else {');
		this.push('        this.pc = this.loopStartPos;');
		this.push('    }');
		this.push('    continue;');
		this.push('}');
	},
	pushCode_GOSUB: function(insn, pc, label) {
		this.push('this.pc = '+label.getPos()+';');
		this.pushCodeToJumpSubroutine(pc);
		this.push('continue;');
	},
	pushCode_GOTO_EXPR: function(insn, pc, paramInfo) {
		this.push('this.pc = '+this.getLabelParamNativeValueExpr(paramInfo)+';');
		this.push('continue;');
	},
	pushCode_GOSUB_EXPR: function(insn, pc, paramInfo) {
		this.push('this.pc = '+this.getLabelParamNativeValueExpr(paramInfo)+';');
		this.pushCodeToJumpSubroutine(pc);
		this.push('continue;');
	},
	pushCode_EXGOTO: function(insn, pc, paramInfos) {
		var counterParamInfo = paramInfos[0];
		var stepParamInfo    = paramInfos[1];
		var endParamInfo     = paramInfos[2];
		var labelParamInfo   = paramInfos[3];
		if(!counterParamInfo.getPureNode().isVarNode()) {
			this.push('throw new HSPError(ErrorCode.VARIABLE_REQUIRED);');
			return;
		}
		this.push('var counter = '+this.getStrictIntParamNativeValueExpr(counterParamInfo)+';');
		var stepExpr = this.getIntParamNativeValueExpr(stepParamInfo);
		if(stepParamInfo.stackSize != 0) {
			this.push('var step = '+stepExpr+';');
			stepExpr = 'step';
		}
		var endExpr = this.getIntParamNativeValueExpr(endParamInfo);
		if(endParamInfo.stackSize != 0) {
			this.push('var end = '+endExpr+';');
			endExpr = 'end';
		}
		var posExpr = this.getLabelParamNativeValueExpr(labelParamInfo);
		if(labelParamInfo.stackSize != 0) {
			this.push('var pos = '+posExpr+';');
			posExpr = 'pos';
		}
		this.push('if('+stepExpr+' >= 0) {');
		this.push('    if(counter >= '+endExpr+') { this.pc = '+posExpr+'; continue; }');
		this.push('} else {');
		this.push('    if(counter <= '+endExpr+') { this.pc = '+posExpr+'; continue; }');
		this.push('}');
	},
	pushCode_ON: function(insn, pc, isGosub, labelParamInfos, indexParamInfo) {
		var labelsIndex = null;
		var labelExprs = [];
		for(var i = 0; i < labelParamInfos.length; i ++) {
			var paramInfo = labelParamInfos[i];
			if(paramInfo.node.isLabelNode()) {
				labelExprs[i] = '' + paramInfo.node.getLabelPos();
			} else {
				if(labelsIndex == null) {
					this.push('var labels = [];');
					labelsIndex = 0;
				}
				this.push('labels['+labelsIndex+'] = '+this.getLabelParamNativeValueExpr(labelParamInfos[i])+';');
				labelExprs[i] = 'labels['+labelsIndex+']';
				labelsIndex ++;
			}
		}
		var indexExpr = this.getIntParamNativeValueExpr(indexParamInfo);
		this.push('switch('+indexExpr+') {');
		for(var i = 0; i < labelParamInfos.length; i ++) {
			this.push('case '+i+': this.pc = '+labelExprs[i]+'; break;');
		}
		this.push('default: this.pc ++; continue;');
		this.push('}');
		if(isGosub) {
			this.pushCodeToJumpSubroutine(pc);
		}
		this.push('continue;');
	},
	pushCodeToBranch: function(label, paramInfo, reverse) {
		var expr = this.getIntParamNativeValueExpr(paramInfo);
		if(reverse) {
			expr = '!' + expr;
		}
		this.push('if('+expr+') {');
		this.push('    this.pc = '+label.getPos()+';');
		this.push('    continue;');
		this.push('}');
	},
	pushCodeToStartLoop: function() {
		this.push('if(this.looplev >= 31) {');
		this.push('    throw new HSPError(ErrorCode.TOO_MANY_NEST);');
		this.push('}');
		this.push('this.cntStack[this.looplev] = this.cnt;');
		this.push('this.cntEndStack[this.looplev] = this.cntEnd;');
		this.push('this.loopStartPosStack[this.looplev] = this.loopStartPos;');
	},
	pushCodeToEndLoop: function() {
		this.push('this.looplev --;');
		this.push('this.cnt = this.cntStack[this.looplev];');
		this.push('this.cntEnd = this.cntEndStack[this.looplev];');
		this.push('this.loopStartPos = this.loopStartPosStack[this.looplev];');
	},
	pushCodeToCallBuiltinFunc: function(type, subid, paramInfos, ctype) {
		var info = BuiltinFuncInfos[type][subid];
		if(info && info.func) {
			this.pushCodeToBuiltinFuncInline(info, paramInfos);
			return;
		}
		this.push('throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION);');
	},
	pushCodeToCheckSublev: function() {
		this.push('if(this.frameStack.length >= 256) {');
		this.push('    throw new HSPError(ErrorCode.STACK_OVERFLOW);');
		this.push('}');
	},
	pushCodeToJumpSubroutine: function(pc) {
		this.pushCodeToCheckSublev();
		this.push('this.frameStack.push(new Frame('+(pc + 1)+', null, this.args));');
	},
	pushCodeToGetArrayValue: function(varData, indexParamInfos) {
		var result = this.getArrayAndOffsetExpr(varData, indexParamInfos);
		var arrayExpr = result[0];
		var offsetExpr = result[1];
		this.push('stack.push('+arrayExpr+'.at('+offsetExpr+'));');
	},
	pushCodeToGetVariable: function(varData, indexParamInfos) {
		var result;
		if(varData.isVariableAgentVarData()) {
			result = this.getVariableAgentExpr(varData);
		} else {
			var variableExpr = this.getVariableExpr(varData);
			if(indexParamInfos.length == 0) {
				result = 'new VariableAgent0D('+variableExpr+')';
			} else if(indexParamInfos.length == 1) {
				var paramInfo = indexParamInfos[0];
				this.push('var offset = '+this.getStrictIntParamNativeValueExpr(paramInfo)+';');
				result = 'new VariableAgent1D('+variableExpr+', offset)';
			} else {
				this.pushCodeToGetIndices(indexParamInfos);
				result = 'new VariableAgentMD('+variableExpr+', indices)';
			}
		}
		this.push('stack.push('+result+');');
	},
	pushCodeToAssign: function(varData, indexParamInfos, rhsParamInfos) {
		if(varData.isVariableAgentVarData()) {
			this.pushCodeToVariableAgentAssign(varData, rhsParamInfos);
		} else {
			this.push('var variable = '+this.getVariableExpr(varData)+';');
			if(indexParamInfos.length == 0) {
				this.pushCodeTo0DAssign(rhsParamInfos);
			} else if(indexParamInfos.length == 1) {
				this.pushCodeTo1DAssign(indexParamInfos[0], rhsParamInfos);
			} else {
				this.pushCodeToMDAssign(indexParamInfos, rhsParamInfos);
			}
		}
	},
	pushCodeToVariableAgentAssign: function(varData, paramInfos) {
		if(paramInfos.length == 1) {
			this.push(this.getVariableAgentExpr(varData)+'.assign('+this.getParamExpr(paramInfos[0])+');');
		} else {
			this.push('var agent = '+this.getVariableAgentExpr(varData)+';');
			this.push('var variable = agent.variable;');
			this.push('if(agent.indices) {');
			this.push('    var indices = agent.indices.slice();');
			for(var i = 0; i < paramInfos.length; i ++) {
				this.push('    variable.assign(indices, '+this.getParamExpr(paramInfos[i])+');');
				if(i != paramInfos.length - 1) {
					this.push('    indices[0] ++;');
				}
			}
			this.push('} else {'); this.incIndent();
			this.push('var offset = agent.offset;');
			this.pushCodeTo1DMultipleAssign(paramInfos);
			this.decIndent(); this.push('}');
		}
	},
	pushCodeTo0DAssign: function(paramInfos) {
		if(paramInfos.length == 1) {
			this.push('var rhs = '+this.getParamExpr(paramInfos[0])+';');
			this.push('if(variable.value.type != rhs.type) {');
			this.push('    variable.reset(rhs.type);');
			this.push('}');
			this.push('variable.value.assign(0, rhs);');
		} else {
			this.push('var rhs = '+this.getParamExpr(paramInfos[0])+';');
			this.push('var type = rhs.type;');
			this.push('if(variable.value.type != type) {');
			this.push('    variable.reset(type);');
			this.push('}');
			this.push('var array = variable.value;');
			this.push('array.expand1D('+(paramInfos.length-1)+');');
			this.push('array.assign(0, rhs);');
			for(var i = 1; i < paramInfos.length; i ++) {
				this.push('var rhs = '+this.getParamExpr(paramInfos[i])+';');
				this.push('if(rhs.type != type) throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
				this.push('array.assign('+i+', rhs);');
			}
		}
	},
	pushCodeTo1DAssign: function(indexParamInfo, rhsParamInfos) {
		this.push('var offset = '+this.getStrictIntParamNativeValueExpr(indexParamInfo)+';');
		if(rhsParamInfos.length == 1) {
			this.push('var rhs = '+this.getParamExpr(rhsParamInfos[0])+';');
			this.push('if(variable.value.type != rhs.type) {');
			this.push('    if(offset == 0) {');
			this.push('        variable.reset(rhs.type);');
			this.push('    } else {');
			this.push('        throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
			this.push('    }');
			this.push('}');
			this.push('variable.value.expand1D(offset);');
			this.push('variable.value.assign(offset, rhs);');
		} else {
			this.pushCodeTo1DMultipleAssign(rhsParamInfos);
		}
	},
	pushCodeToMDAssign: function(indexParamInfos, rhsParamInfos) {
		this.pushCodeToGetIndices(indexParamInfos);
		for(var i = 0; i < rhsParamInfos.length; i ++) {
			this.push('variable.assign(indices, '+this.getParamExpr(rhsParamInfos[i])+');');
			if(i != rhsParamInfos.length - 1) {
				this.push('indices[0] ++;');
			}
		}
	},
	pushCodeTo1DMultipleAssign: function(paramInfos) {
		this.push('if(offset < 0) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);');
		this.push('var rhs = '+this.getParamExpr(paramInfos[0])+';');
		this.push('var type = rhs.type;');
		this.push('if(variable.value.type != type) {');
		this.push('    if(offset == 0) {');
		this.push('        variable.reset(type);');
		this.push('    } else {');
		this.push('        throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
		this.push('    }');
		this.push('}');
		this.push('var array = variable.value;');
		this.push('array.expand1D(offset + '+(paramInfos.length-1)+');');
		this.push('array.assign(offset, rhs);');
		for(var i = 1; i < paramInfos.length; i ++) {
			this.push('var rhs = '+this.getParamExpr(paramInfos[i])+';');
			this.push('if(rhs.type != type) throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
			this.push('array.assign(offset + '+i+', rhs);');
		}
	},
	pushCodeToCompoundAssign: function(calcCode, varData, indexParamInfos, rhsParamInfo) {
		if(varData.isVariableAgentVarData()) {
			this.push('var agent = '+this.getVariableAgentExpr(varData)+';');
			this.push('agent.assign(agent.toValue().'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
			return;
		}
		if(!isCompareCalcCode(calcCode)) {
			this.push('var array = '+this.getVariableExpr(varData)+'.value;');
			if(indexParamInfos.length == 0) {
				this.push('array.assign(0, array.at(0).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
			} else if(indexParamInfos.length == 1) {
				this.push('var offset = '+this.getStrictIntParamNativeValueExpr(indexParamInfos[0])+';');
				this.push('array.expand1D(offset);');
				this.push('array.assign(offset, array.at(offset).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
			} else {
				this.pushCodeToGetIndices(indexParamInfos);
				this.push('array.expand(indices);');
				this.push('var offset = array.getOffset(indices);');
				this.push('array.assign(offset, array.at(offset).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
			}
			return;
		} 
		this.push('var array = '+this.getVariableExpr(varData)+'.value;');
		if(indexParamInfos.length == 0) {
			this.push('if(array.type != '+VarType.INT+') {');
			this.push('    throw new HSPError(ErrorCode.TYPE_MISMATCH);');
			this.push('}');
			this.push('array.assign(0, array.at(0).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
		} else if(indexParamInfos.length == 1) {
			this.push('var offset = '+this.getStrictIntParamNativeValueExpr(indexParamInfos[0])+';');
			this.push('if(array.type != '+VarType.INT+') {');
			this.push('    if(offset == 0) {');
			this.push('        throw new HSPError(ErrorCode.TYPE_MISMATCH);');
			this.push('    } else {');
			this.push('        throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
			this.push('    }');
			this.push('}');
			this.push('array.expand1D(offset);');
			this.push('array.assign(offset, array.at(offset).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
		} else {
			this.pushCodeToGetIndices(indexParamInfos);
			this.push('array.expand(indices);');
			this.push('var offset = array.getOffset(indices);');
			this.push('if(array.type != '+VarType.INT+') {');
			this.push('    if(offset == 0) {');
			this.push('        throw new HSPError(ErrorCode.TYPE_MISMATCH);');
			this.push('    } else {');
			this.push('        throw new HSPError(ErrorCode.INVALID_ARRAYSTORE);');
			this.push('    }');
			this.push('}');
			this.push('array.assign(offset, array.at(offset).'+getCalcCodeName(calcCode)+'('+this.getParamExpr(rhsParamInfo)+'));');
		}
	},
	pushCodeToIncDec: function(methodName, varData, indexParamInfos) {
		if(varData.isVariableAgentVarData()) {
			this.push('var agent = '+this.getVariableAgentExpr(varData)+';');
			this.push('agent.expand().'+methodName+'();');
			return;
		}
		this.push('var array = '+this.getVariableExpr(varData)+'.value;');
		if(indexParamInfos.length == 0) {
			this.push('array.'+methodName+'(0);');
		} else if(indexParamInfos.length == 1) {
			this.push('var offset = '+this.getStrictIntParamNativeValueExpr(indexParamInfos[0])+';');
			this.push('array.expand1D(offset);');
			this.push('array.'+methodName+'(offset);');
		} else {
			this.pushCodeToGetIndices(indexParamInfos);
			this.push('array.expand(indices);');
			this.push('var offset = array.getOffset(indices);');
			this.push('array.'+methodName+'(offset);');
		}
	},
	pushCodeToInc: function(varData, indexParamInfos) {
		this.pushCodeToIncDec('inc', varData, indexParamInfos);
	},
	pushCodeToDec: function(varData, indexParamInfos) {
		this.pushCodeToIncDec('dec', varData, indexParamInfos);
	},
	pushCodeToCallUserdefFunc: function(userDefFunc, paramInfos, pc, constructorThismodExpr) {
		var userDefFuncExpr = this.getRegisteredObjectExpr(userDefFunc);
		var paramMax = paramInfos.length;
		var mptypes = userDefFunc.paramTypes;
		var argMax = mptypes.length;
		var recvArgMax = 0; // local を除いた仮引数の数
		for(var i = 0; i < argMax; i ++) {
			var mptype = mptypes[i];
			var paramInfo = paramInfos[recvArgMax];
			if(mptype == MPType.LOCALVAR || mptype == MPType.IMODULEVAR) continue;
			if(mptype == MPType.ARRAYVAR && paramInfo &&
			   !paramInfo.getPureNode().isVarNode()) {
				this.push('throw new HSPError(ErrorCode.VARIABLE_REQUIRED);');
				return;
			} else if((!paramInfo || paramInfo.node.isDefaultNode()) && mptype != MPType.INUM) {
				this.push('throw new HSPError(ErrorCode.NO_DEFAULT);');
				return;
			}
			recvArgMax ++;
		}
		if(recvArgMax < paramMax) {
			this.push('throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);');
			return;
		}
		this.push('var args = [];');
		this.pushCodeToSetupArguments(mptypes, paramInfos, constructorThismodExpr);
		this.pushCodeToCheckSublev();
		this.push('this.frameStack.push(new Frame('+(pc + 1)+', '+userDefFuncExpr+', args, this.args));');
		this.push('this.args = args;');
		this.push('this.pc = '+userDefFunc.label.getPos()+';');
		this.push('continue;');
	},
	pushCodeToSetupArguments: function(mptypes, paramInfos, constructorThismodExpr) {
		var argMax = mptypes.length;
		var origArgsCount = 0;
		for(var i = 0; i < argMax; i ++) {
			var mptype = mptypes[i];
			var paramInfo = paramInfos[origArgsCount];
			switch(mptype) {
			case MPType.DNUM:
				this.push('args['+i+'] = '+this.getDoubleParamExpr(paramInfo)+';');
				break;
			case MPType.INUM:
				if(!paramInfo || paramInfo.node.isDefaultNode()) {
					this.push('args['+i+'] = IntValue.of(0);');
				} else {
					this.push('args['+i+'] = '+this.getIntParamExpr(paramInfo)+';');
				}
				break;
			case MPType.STRUCT:
				this.push('args['+i+'] = '+this.getStructParamExpr(paramInfo)+';');
				break;
			case MPType.LABEL:
				this.push('args['+i+'] = '+this.getLabelParamExprAllowNull(paramInfo)+';');
				break;
			case MPType.LOCALVAR:
				this.push('args['+i+'] = new Variable;');
				continue;
			case MPType.ARRAYVAR:
				var node = paramInfo.node;
				if(node.isVarNode()) {
					this.push('args['+i+'] = '+this.getVariableExpr(node.varData)+';');
				} else {
					this.push('args['+i+'] = '+this.getParamExpr(paramInfo)+'.expand().variable;');
				}
				break;
			case MPType.SINGLEVAR:
			case MPType.MODULEVAR:
				var node = paramInfo.node;
				if(node.isVarNode()) {
					this.push('args['+i+'] = '+this.getNewVariableAgentExpr(node.varData)+';');
				} else if(node.isGetStackNode() && node.originalNode.isVarNode()) {
					this.push('args['+i+'] = '+this.getParamExpr(paramInfo)+'.expand();');
				} else {
					this.push('var arg = new VariableAgent0D(new Variable);');
					this.push('arg.assign('+this.getParamExpr(paramInfo)+');');
					this.push('args['+i+'] = arg;');
				}
				break;
			case MPType.LOCALSTRING:
				this.push('args['+i+'] = '+this.getStrParamExpr(paramInfo)+';');
				break;
			case MPType.IMODULEVAR:
				this.push('args['+i+'] = '+constructorThismodExpr+';');
				continue;
			default:
				throw new Error('未対応のパラメータタイプ: '+mptype);
			}
			origArgsCount ++;
		}
	},
	pushCodeToGetIndices: function(indexParamInfos) {
		this.push('var indices = [];');
		for(var i = 0; i < indexParamInfos.length; i ++) {
			this.push('indices['+i+'] = '+this.getStrictIntParamNativeValueExpr(indexParamInfos[i])+';');
		}
	},
	getArrayAndOffsetExpr: function(varData, indexParamInfos) {
		if(varData.isVariableAgentVarData()) {
			this.push('var agent = '+this.getVariableAgentExpr(varData)+';');
			return ['agent.variable.value', 'agent.getOffset()'];
		}
		var arrayExpr = this.getVariableExpr(varData)+'.value';
		var offsetExpr = 'offset';
		if(indexParamInfos.length == 0) {
			offsetExpr = '0';
		} else if(indexParamInfos.length == 1) {
			var paramInfo = indexParamInfos[0];
			this.push('var array = '+arrayExpr+';');
			arrayExpr = 'array';
			this.push('var offset = '+this.getStrictIntParamNativeValueExpr(paramInfo)+';');
			this.push('if(!(0 <= offset && offset < array.getL0())) {');
			this.push('    throw new HSPError(ErrorCode.ARRAY_OVERFLOW);');
			this.push('}');
		} else {
			this.push('var array = '+arrayExpr+';');
			arrayExpr = 'array';
			this.pushCodeToGetIndices(indexParamInfos);
			this.push('var offset = array.getOffset(indices);');
			this.push('if(offset == null) throw new HSPError(ErrorCode.ARRAY_OVERFLOW);');
		}
		return [arrayExpr, offsetExpr];
	},
	getNoSubscriptVariableParamExpr: function(paramInfo) {
		if(isDefaultParamInfo(paramInfo)) {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
		var node = paramInfo.node.toPureNode();
		if(!node.isVarNode() || node.onlyValue) {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
		if(node.indexNodes.length > 0) {
			// 添え字指定があってスタック上に VariableAgent が積まれていてもエラーで落とすので pop する必要はない
			return 'throwHSPError('+ErrorCode.BAD_ARRAY_EXPRESSION+')';
		}
		var varData = node.varData;
		if(node.varData.isVariableAgentVarData()) {
			this.push('var agent = '+this.getVariableAgentExpr(varData)+';');
			this.push('if(agent.existSubscript) {')
			this.push('    throw new HSPError(ErrorCode.BAD_ARRAY_EXPRESSION);');
			this.push('}');
			return 'agent.variable';
		}
		return this.getVariableExpr(varData);
	},
	getVariableParamExpr: function(paramInfo) {
		if(isDefaultParamInfo(paramInfo)) {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
		var node = paramInfo.node;
		if(node.isVarNode()) {
			return this.getVariableExpr(node.varData);
		} else if(node.isGetStackNode() && node.originalNode.isVarNode()) {
			return this.getParamExpr(paramInfo)+'.expand().variable';
		} else {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
	},
	getVariableAgentParamExpr: function(paramInfo) {
		if(isDefaultParamInfo(paramInfo)) {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
		var node = paramInfo.node;
		if(node.isVarNode()) {
			return this.getNewVariableAgentExpr(node.varData);
		} else if(node.isGetStackNode() && node.originalNode.isVarNode()) {
			return this.getParamExpr(paramInfo)+'.expand()';
		} else {
			return 'throwHSPError('+ErrorCode.VARIABLE_REQUIRED+')';
		}
	},
	getIntParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo);
		}
		if(node.isLiteralNode() && node.val.type == VarType.DOUBLE) {
			return this.getParamExpr(new ParamInfo(new LiteralNode(node.val.toIntValue())));
		}
		if(node.getValueType() == VarType.DOUBLE) {
			return this.getParamExpr(paramInfo)+'.toIntValue()';
		}
		return 'checkTypeNumber('+this.getParamExpr(paramInfo)+').toIntValue()';
	},
	getDoubleParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.DOUBLE) {
			return this.getParamExpr(paramInfo);
		}
		if(node.isLiteralNode() && node.val.type == VarType.INT) {
			return this.getParamExpr(new ParamInfo(new LiteralNode(node.val.toDoubleValue())));
		}
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo)+'.toDoubleValue()';
		}
		return 'checkTypeNumber('+this.getParamExpr(paramInfo)+').toDoubleValue()';
	},
	getStrParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.STR) {
			return this.getParamExpr(paramInfo);
		}
		return 'checkTypeStr('+this.getParamExpr(paramInfo)+')';
	},
	getLabelParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.LABEL) {
			return this.getParamExpr(paramInfo);
		}
		return 'checkTypeLabel('+this.getParamExpr(paramInfo)+')';
	},
	getLabelParamExprAllowNull: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.LABEL) {
			return this.getParamExpr(paramInfo);
		}
		return 'checkTypeLabelAllowNull('+this.getParamExpr(paramInfo)+')';
	},
	getStructParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.getValueType() == VarType.STRUCT) {
			return this.getParamExpr(paramInfo);
		}
		return 'checkTypeStruct('+this.getParamExpr(paramInfo)+')';
	},
	getIntParamNativeValueExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode() && 
		   (node.val.type == VarType.INT || node.val.type == VarType.DOUBLE)) {
			return '' + node.val.toIntValue()._value;
		}
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		if(node.getValueType() == VarType.DOUBLE) {
			return '('+this.getParamExpr(paramInfo)+'._value|0)';
		}
		return '(checkTypeNumber('+this.getParamExpr(paramInfo)+')._value|0)';
	},
	getStrictIntParamNativeValueExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode() && node.val.type == VarType.INT) {
			return '' + node.val._value;
		}
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		return 'checkTypeInt('+this.getParamExpr(paramInfo)+')._value';
	},
	getDoubleParamNativeValueExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		var type = node.getValueType();
		if(node.isLiteralNode() && (type == VarType.INT || type == VarType.DOUBLE)) {
			return Utils.numToSource(node.val._value);
		}
		if(type == VarType.INT || type == VarType.DOUBLE) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		return 'checkTypeNumber('+this.getParamExpr(paramInfo)+')._value';
	},
	getStrParamNativeValueExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode() && node.getValueType() == VarType.STR) {
			return Utils.strToSource(node.val._value);
		}
		return this.getStrParamExpr(paramInfo)+'._value';
	},
	getLabelParamNativeValueExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLabelNode()) {
			return '' + node.getLabelPos();
		}
		return 'checkTypeLabel('+this.getParamExpr(paramInfo)+').pos';
	},
	getIntConvertedParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return this.getParamExpr(new ParamInfo(new LiteralNode(node.val.toIntValue())));
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		return this.getParamExpr(paramInfo)+'.toIntValue()';
	},
	getDoubleConvertedParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return this.getParamExpr(new ParamInfo(new LiteralNode(node.val.toDoubleValue())));
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		return this.getParamExpr(paramInfo)+'.toDoubleValue()';
	},
	getStrConvertedParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return this.getParamExpr(new ParamInfo(new LiteralNode(node.val.toStrValue())));
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		return this.getParamExpr(paramInfo)+'.toStrValue()';
	},
	getIntConvertedNativeValueParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return '' + node.val.toIntValue()._value;
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		if(node.getValueType() == VarType.DOUBLE) {
			return '('+this.getParamExpr(paramInfo)+'._value|0)';
		}
		return this.getParamExpr(paramInfo)+'.toIntValue()._value';
	},
	getDoubleConvertedNativeValueParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return Utils.numToSource(node.val.toDoubleValue()._value);
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		if(node.getValueType() == VarType.INT) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		if(node.getValueType() == VarType.DOUBLE) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		return this.getParamExpr(paramInfo)+'.toDoubleValue()._value';
	},
	getStrConvertedNativeValueParamExpr: function(paramInfo, defaultExpr) {
		if(_isDefault(paramInfo)) return _defaultExpr(defaultExpr);
		var node = paramInfo.node;
		if(node.isLiteralNode()) {
			try {
				return Utils.strToSource(node.val.toStrValue()._value);
			} catch(e) {
				if(!(e instanceof HSPError)) throw e;
			}
		}
		if(node.getValueType() == VarType.STR) {
			return this.getParamExpr(paramInfo)+'._value';
		}
		if(node.getValueType() == VarType.INT) {
			return '("" + '+this.getParamExpr(paramInfo)+'._value)';
		}
		return this.getParamExpr(paramInfo)+'.toStrValue()._value';
	},
	getParamIntLiteralValue: function(paramInfo) {
		if(!paramInfo) return null;
		var node = paramInfo.node;
		if(!node.isLiteralNode()) return null;
		var value = node.val;
		var type = value.type;
		if(type == VarType.INT || type == VarType.DOUBLE) {
			return value._value | 0;
		}
		return null;
	},
	getParamExpr: function(paramInfo) {
		if(!paramInfo) {
			return 'throwHSPError('+ErrorCode.NO_DEFAULT+')';
		}
		var result = this.getParamExpr0(paramInfo.node);
		return result;
	},
	getParamExpr0: function(node) {
		switch(node.nodeType) {
		case NodeType.VAR:
			if(node.indexNodes.length > 0) {
				throw new Error('must not happen');
			}
			if(node.varData.isVariableAgentVarData()) {
				return this.getVariableAgentExpr(node.varData)+'.toValue()';
			}
			return this.getVariableExpr(node.varData)+'.value.at(0)';
		case NodeType.ARG:
			return 'this.getArg('+node.id+')';
		case NodeType.LITERAL:
			return this.getLiteralExpr(node.val);
		case NodeType.LABEL:
			return this.getLiteralExpr(new LabelValue(node.getLabelPos()));
		case NodeType.DEFAULT:
			return 'throwHSPError('+ErrorCode.NO_DEFAULT+')';
		case NodeType.OPERATE:
			return '('+this.getParamExpr0(node.lhsNode)+').'+getCalcCodeName(node.calcCode)+'('+this.getParamExpr0(node.rhsNode)+')';
		case NodeType.INLINE_EXPR_BUILTIN_FUNCALL:
			var info = node.builtinFuncInfo;
			return this.getBuiltinFuncInlineExpr(info, node.paramInfos);
		case NodeType.GET_STACK:
			return 'stack.pop()';
		default:
			throw new Error('must not happen');
		}
	},
	getBuiltinFuncInlineExpr: function(builtinFuncInfo, paramInfos) {
		var len = paramInfos.length;
		var argsMax = builtinFuncInfo.argsMax;
		if(argsMax != null && argsMax < len) {
			return 'throwHSPError('+ErrorCode.TOO_MANY_PARAMETERS+')';
		}
		paramInfos = paramInfos.concat();
		for(var i = len; i < argsMax; i++) {
			paramInfos[i] = null;
		}
		return builtinFuncInfo.func(this, paramInfos);
	},
	pushCodeToBuiltinFuncInline: function(builtinFuncInfo, paramInfos) {
		var len = paramInfos.length;
		var argsMax = builtinFuncInfo.argsMax;
		if(argsMax != null && argsMax < len) {
			this.push('throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);');
			return;
		}
		paramInfos = paramInfos.concat();
		for(var i = len; i < argsMax; i++) {
			paramInfos[i] = null;
		}
		builtinFuncInfo.func(this, paramInfos);
	},
	getNewVariableAgentExpr: function(varData) {
		if(varData.isVariableAgentVarData()) {
			return this.getVariableAgentExpr(varData);
		}
		return 'new VariableAgent0D('+this.getVariableExpr(varData)+')';
	},
	getVariableExpr: function(varData) {
		if(varData.isVariableAgentVarData()) {
			return this.getVariableAgentExpr(varData)+'.variable';
		}
		var type = varData.proxyVarType;
		var id = varData.id;
		switch(type) {
		case ProxyVarType.STATIC:
			return 'variables['+this.registerStaticVarTags(id)+']';
		case ProxyVarType.MEMBER:
			return 'this.getThismod().toValue().members['+id+']';
		case ProxyVarType.ARG_ARRAY:
		case ProxyVarType.ARG_LOCAL:
			return 'this.getArg('+id+')';
		default:
			throw new Error('must not happen');
		}
	},
	getVariableAgentExpr: function(varData) {
		switch(varData.proxyVarType) {
		case ProxyVarType.THISMOD:
			return 'this.getThismod()';
		case ProxyVarType.ARG_VAR:
			return 'this.getArg('+varData.id+')';
		default:
			throw new Error('must not happen');
		}
	},
	getLiteralExpr: function(literal) {
		var literals = this.literals_;
		var pos = literals.length;
		literals[pos] = literal;
		return 'literals['+pos+']';
	},
	registerStaticVarTags: function(staticVarTag) {
		var propname = this.staticVarTagsPropName;
		if(typeof staticVarTag[propname] != 'undefined') {
			return staticVarTag[propname];
		}
		var staticVarTags = this.staticVarTags_;
		var id = staticVarTags.length;
		staticVarTag[propname] = id;
		staticVarTags[id] = staticVarTag;
		return id;
	},
	getRegisteredObjectExpr: function(object, tag) {
		var propname = this.registerPropName;
		var id;
		if(!tag) tag = object;
		if(propname in tag) {
			id = tag[propname];
		} else {
			var list = this.registeredObjects_;
			id = list.length;
			list[id] = object;
			this.registeredObjectTags_[id] = tag;
			tag[propname] = id;
		}
		return 'registeredObjects['+id+']';
	},
	removeRegisteredObjectsPropName: function() {
		this.removeObjectsPropName(this.registeredObjectTags_, this.registerPropName);
		this.removeObjectsPropName(this.staticVarTags_, this.staticVarTagsPropName);
	},
	removeObjectsPropName: function(objects, propname) {
		for(var i = 0; i < objects.length; i ++) {
			delete objects[i][propname];
		}
	},
	pushCodeToStackPop: function(size) {
		if(size == 0) {
			// nothing
		} else if(size == 1) {
			this.push('-- stack.length;');
		} else {
			this.push('stack.length -= '+size+';');
		}
	},
	toSimpleExpr: function(expr, defaultVarName) {
		if(/^(?:[$A-Za-z][$0-9A-Za-z]*|-?[0-9]+)$/.test(expr)) {
			// 単一の変数か整数リテラルならそのまま
			return expr;
		}
		this.push('var '+defaultVarName+' = '+expr+';');
		return defaultVarName;
	},
	push: function(line) {
		this.lines_.push(Utils.strTimes('\t', this.indent_) + line);
	},
	incIndent: function() {
		this.indent_ ++;
	},
	decIndent: function() {
		this.indent_ --;
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.MainLoopGenerator = MainLoopGenerator;
}

var BuiltinFuncInfos = [];

(function(){
	for(var i = 0; i < 18; i ++) {
		BuiltinFuncInfos[i] = [];
	}
})();

function BuiltinFuncInfo() {
	this.func = null;
	this.isInlineExpr = false;
	this.receiveVarList = null;
	this.defaultReceiveVar = true;
	this.argsMax = null;
	this.returnValueType = null;
	this.compileTimeFunc = null;
}

BuiltinFuncInfo.prototype = {
	notReceiveVar: function(n) {
		if(this.receiveVarList && 0 <= n && n <= this.receiveVarList.length) {
			return !this.receiveVarList[n];
		}
		return !this.defaultReceiveVar;
	},
	reset: function() {
		BuiltinFuncInfo.call(this);
	}
};

function builtinFunc(name) {
	var typeAndSubid = BuiltinFuncNameToIdTable[name];
	if(!typeAndSubid) throw new Error("unknown builtin func name: `"+name+"'");
	var type = getTypeByTypeAndSubid(typeAndSubid);
	var subid = getSubidByTypeAndSubid(typeAndSubid);
	var infos = BuiltinFuncInfos[type];
	var info = infos[subid];
	if(info) return info;
	return infos[subid] = new BuiltinFuncInfo;
}

function defineInlineBuiltinFunc(name, receiveVarList, func) {
	var info = builtinFunc(name);
	info.reset();
	info.func = func;
	info.isExprCallback = returnFalse;
	info.receiveVarList = receiveVarList;
	info.argsMax = receiveVarList.length;
}

function defineInlineExprBuiltinFunc(name, receiveVarList, returnValueType, func) {
	var info = builtinFunc(name);
	info.reset();
	info.func = func;
	info.isInlineExpr = true;
	info.isExprCallback = returnTrue;
	info.receiveVarList = receiveVarList;
	info.argsMax = receiveVarList.length;
	info.returnValueType = returnValueType;
}

function defineCompileTimeBuiltinFunc(name, func) {
	var info = builtinFunc(name);
	info.compileTimeFunc = func;
}

function defineSysVar(name, returnValueType, expr) {
	defineInlineExprBuiltinFunc(name, [], returnValueType, function(){ return expr; });
}

defineInlineBuiltinFunc('wait', [false], function(g, paramInfos) {
	g.push('throw new WaitException('+g.getIntParamNativeValueExpr(paramInfos[0], 100)+' * 10);');
});

defineInlineBuiltinFunc('await', [false], function(g, paramInfos) {
	g.push('if(this.lastWaitTime) {');
	g.push('    throw new WaitException(this.lastWaitTime + '+g.getIntParamNativeValueExpr(paramInfos[0], 0)+' - new Date);');
	g.push('} else {');
	g.push('    throw new WaitException('+g.getIntParamNativeValueExpr(paramInfos[0], 0)+');');
	g.push('}');
});

defineInlineBuiltinFunc('dim', [true, false, false, false, false], function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	var l0Expr = g.getIntParamNativeValueExpr(paramInfos[1], 0);
	var l1Expr = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var l2Expr = g.getIntParamNativeValueExpr(paramInfos[3], 0);
	var l3Expr = g.getIntParamNativeValueExpr(paramInfos[4], 0);
	g.push(variableExpr+'.dim('+VarType.INT+', '+l0Expr+', '+l1Expr+', '+l2Expr+', '+l3Expr+');');
});

defineInlineBuiltinFunc('sdim', [true, false, false, false, false, false], function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	var strLenExpr = g.getIntParamNativeValueExpr(paramInfos[1], 64);
	var l0Expr = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var l1Expr = g.getIntParamNativeValueExpr(paramInfos[3], 0);
	var l2Expr = g.getIntParamNativeValueExpr(paramInfos[4], 0);
	var l3Expr = g.getIntParamNativeValueExpr(paramInfos[5], 0);
	g.push('('+variableExpr+'.value = new StrArray).strDim('+strLenExpr+', '+l0Expr+', '+l1Expr+', '+l2Expr+', '+l3Expr+');');
});

defineInlineBuiltinFunc('dimtype', [true, false, false, false, false, false], function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	var typeExpr = g.getIntParamNativeValueExpr(paramInfos[1], 0);
	var l0Expr = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var l1Expr = g.getIntParamNativeValueExpr(paramInfos[3], 0);
	var l2Expr = g.getIntParamNativeValueExpr(paramInfos[4], 0);
	var l3Expr = g.getIntParamNativeValueExpr(paramInfos[5], 0);
	g.push(variableExpr+'.dim('+typeExpr+', '+l0Expr+', '+l1Expr+', '+l2Expr+', '+l3Expr+');');
});

defineInlineBuiltinFunc('dup', [true, true], function(g, paramInfos) {
	var destVarExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	var srcVarAgentExpr = g.getVariableAgentParamExpr(paramInfos[1]);
	g.push(destVarExpr+'.value = '+srcVarAgentExpr+'.ref();');
});

defineInlineBuiltinFunc('end', [false], function(g, paramInfos) {
	g.push('throw new EndException('+g.getIntParamNativeValueExpr(paramInfos[0], 0)+');');
});

defineInlineBuiltinFunc('stop', [false], function(g, paramInfos) {
	g.push('throw new StopException;');
});

defineInlineBuiltinFunc('delmod', [true], function(g, paramInfos) {
	g.push('var agent = '+g.getVariableAgentParamExpr(paramInfos[0])+';');
	g.push('if(agent.variable.value.type != '+VarType.STRUCT+') {');
	g.push('    throw new HSPError(ErrorCode.TYPE_MISMATCH);');
	g.push('}');
	g.push('agent.assign(StructValue.EMPTY);');
});

defineInlineBuiltinFunc('mref', [true, false], function(g, paramInfos) {
	g.push('var variable = '+g.getNoSubscriptVariableParamExpr(paramInfos[0])+';');
	g.push('switch('+g.getIntParamNativeValueExpr(paramInfos[1], 0)+') {');
	g.push('case 64:');
	g.push('    variable.value = this.stat;');
	g.push('    break;');
	g.push('case 65:');
	g.push('    variable.value = this.refstr;');
	g.push('    break;');
	g.push('default:');
	g.push('    throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION);');
	g.push('}');
});

defineSysVar('system', VarType.INT, 'new IntValue(0)');
defineSysVar('stat', VarType.INT, 'this.stat.at(0)');
defineSysVar('cnt', VarType.INT, 'new IntValue(this.cnt)');
defineSysVar('err', VarType.INT, 'new IntValue(this.err)');
defineSysVar('strsize', VarType.INT, 'new IntValue(this.strsize)');
defineSysVar('looplev', VarType.INT, 'new IntValue(this.looplev)');
defineSysVar('sublev', VarType.INT, 'new IntValue(this.frameStack.length)');
defineSysVar('iparam', VarType.INT, 'new IntValue(this.iparam)');
defineSysVar('wparam', VarType.INT, 'new IntValue(this.wparam)');
defineSysVar('lparam', VarType.INT, 'new IntValue(this.lparam)');
defineSysVar('refstr', VarType.STR, 'this.refstr.at(0)');
defineSysVar('refdval', VarType.DOUBLE, 'this.refdval.at(0)');

defineInlineBuiltinFunc('onerror', [false, false], function(g, paramInfos) {
	var jumpType = getJumpType(paramInfos[0]);
	if(jumpType == JumpType.GOSUB) {
		g.push('throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION);');
		return;
	}
	var paramInfo = paramInfos[1];
	if(!paramInfo) {
		g.push('throw new HSPError(ErrorCode.NO_DEFAULT);');
		return;
	}
	var node = paramInfo.node;
	var type = node.getValueType();
	if(type == VarType.INT || type == VarType.DOUBLE) {
		setEnabled();
		return;
	}
	if(type == VarType.LABEL) {
		setPos();
		return;
	}
	
	if(jumpType) {
		setPos();
	} else {
		g.push('var val = '+g.getParamExpr(paramInfo)+';');
		g.push('switch(val.type) {');
		g.push('case '+VarType.LABEL+':');
		setPos();
		g.push('break;');
		g.push('case '+VarType.DOUBLE+':');
		g.push('case '+VarType.INT+':');
		setEnabled();
		g.push('break;');
		g.push('default:');
		g.push('throw new HSPError(ErrorCode.TYPE_MISMATCH);');
		g.push('}');
	}
	
	function getJumpType(paramInfo) {
		var node = paramInfo.node;
		if(node.isLiteralNode() && (node.val == JumpType.GOTO || node.val == JumpType.GOSUB)) {
			return node.val;
		} else if(node.isDefaultNode()) {
			return null;
		} else {
			throw new Error('must not happen');
		}
	}
	function setPos() {
		g.push('this.onerrorEvent.pos = '+g.getLabelParamNativeValueExpr(paramInfo)+';');
		g.push('this.onerrorEvent.enabled = true;');
	}
	function setEnabled() {
		if(jumpType) {
			g.push('throw new HSPError(ErrorCode.LABEL_REQUIRED);');
		} else {
			g.push('this.onerrorEvent.enabled = '+g.getIntParamNativeValueExpr(paramInfo)+' != 0;');
		}
	}
});

defineInlineBuiltinFunc('exist', [false], function(g, paramInfos) {
	var successCallbackExpr = 'function(data) { this.strsize = data.length; }';
	var errorCallbackExpr = 'function() { this.strsize = -1; }';
	g.push('this.fileRead('+g.getStrParamNativeValueExpr(path)+', '+successCallbackExpr+', '+errorCallbackExpr+')');
});

defineInlineBuiltinFunc('bload', [false, true], function(g, paramInfos) {
	// FIXME 第三引数のサイズ、第四引数のオフセットに対応
	var funcExpr = g.getRegisteredObjectExpr(bload_internal);
	g.push(funcExpr+'(this, '+g.getStrParamNativeValueExpr(paramInfos[0])+', '+g.getVariableAgentParamExpr(paramInfos[1])+');');
});
function bload_internal(evaluator, path, v) {
	evaluator.fileRead(
		path,
		function(data) {
			var size = v.getByteSize();
			v.setbytes(0, CP932.encode(data).substr(0, size));
		},
		function() {
			throw new HSPError(ErrorCode.FILE_IO);
		});
}

function getArrayOrAgentExpr(g, paramInfo) {
	var node = paramInfo && paramInfo.node;
	if(paramInfo && node.isVarNode() && !node.varData.isVariableAgentVarData()) {
		return [g.getVariableExpr(node.varData)+'.value', true];
	} else {
		var expr = g.getVariableAgentParamExpr(paramInfo);
		return [expr, false];
	}
}

defineInlineBuiltinFunc('poke', [true, false, false], function(g, paramInfos) {
	var r = getArrayOrAgentExpr(g, paramInfos[0]);
	var arrayExpr = r[0];
	if(paramInfos[0].stackSize) {
		g.push('var agent = '+arrayExpr+';');
		arrayExpr = 'agent';
	}
	var arrayIndexArg = r[1] ? '0, ' : '';
	var valueParamInfo = paramInfos[2];
	var type = valueParamInfo ? valueParamInfo.node.getValueType() : 0;
	var offsetExpr = g.getIntParamNativeValueExpr(paramInfos[1]);
	if(type == VarType.INT) {
		g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+', '+g.getIntParamNativeValueExpr(valueParamInfo)+');');
		return;
	}
	if(paramInfos[1].stackSize) {
		g.push('var offset = '+offsetExpr+';');
		offsetExpr = 'offset';
	}
	if(type == VarType.STR) {
		g.push('var val = '+g.getStrParamNativeValueExpr(valueParamInfo)+';');
		g.push(arrayExpr+'.setbytes('+arrayIndexArg+offsetExpr+', val + "\\0");');
		g.push('this.strsize = val.length;');
		return;
	}
	g.push('var val = '+g.getParamExpr(valueParamInfo)+';');
	g.push('switch(val.type) {');
	g.push('case '+VarType.STR+':');
	g.push('    '+arrayExpr+'.setbytes('+arrayIndexArg+offsetExpr+', val._value + "\\0");');
	g.push('    this.strsize = val._value.length;');
	g.push('    break;');
	g.push('case '+VarType.INT+':');
	g.push('    '+arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+', val._value);');
	g.push('    break;');
	g.push('default:');
	g.push('    throw new HSPError(ErrorCode.TYPE_MISMATCH);');
	g.push('}');
});

defineInlineBuiltinFunc('wpoke', [true, false, false], function(g, paramInfos) {
	var r = getArrayOrAgentExpr(g, paramInfos[0]);
	var arrayExpr = g.toSimpleExpr(r[0], r[1] ? 'array' : 'agent');
	var arrayIndexArg = r[1] ? '0, ' : '';
	var offsetExpr = g.toSimpleExpr(g.getIntParamNativeValueExpr(paramInfos[1], 0), 'offset');
	var valExpr = g.toSimpleExpr(g.getIntParamNativeValueExpr(paramInfos[2], 0), 'val');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+', '+valExpr+');');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+' + 1, '+valExpr+' >> 8);');
});

defineInlineBuiltinFunc('lpoke', [true, false, false], function(g, paramInfos) {
	var r = getArrayOrAgentExpr(g, paramInfos[0]);
	var arrayExpr = g.toSimpleExpr(r[0], r[1] ? 'array' : 'agent');
	var arrayIndexArg = r[1] ? '0, ' : '';
	var offsetExpr = g.toSimpleExpr(g.getIntParamNativeValueExpr(paramInfos[1], 0), 'offset');
	var valExpr = g.toSimpleExpr(g.getIntParamNativeValueExpr(paramInfos[2], 0), 'val');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+', '+valExpr+');');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+' + 1, '+valExpr+' >> 8);');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+' + 2, '+valExpr+' >> 16);');
	g.push(arrayExpr+'.setbyte('+arrayIndexArg+offsetExpr+' + 3, '+valExpr+' >> 24);');
});

defineInlineBuiltinFunc('getstr', [true, false, false, false, false], function(g, paramInfos) {
	var destExpr = g.getVariableAgentParamExpr(paramInfos[0]);
	var srcExpr = g.getVariableAgentParamExpr(paramInfos[1]);
	var indexExpr = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var separatorExpr = g.getIntParamNativeValueExpr(paramInfos[3], 0)+' & 0xff';
	var lengthExpr = g.getIntParamNativeValueExpr(paramInfos[4], 1024);
	g.push(g.getRegisteredObjectExpr(getstr_internal)+'(this, '+destExpr+', '+srcExpr+', '+indexExpr+', '+separatorExpr+', '+lengthExpr+');');
});

function getstr_internal(evaluator, dest, src, index, separator, length) {
	var result = "";
	var i = 0;
	var c;
	while(i < length) {
		c = src.getbyte(index + i);
		if(c == 0) break;
		i ++;
		if(c == separator) {
			break;
		}
		if(c == 13) {
			if(src.getbyte(index + i) == 10) i ++;
			break;
		}
		result += String.fromCharCode(c);
		if((0x81 <= c && c <= 0x9F) || (0xE0 <= c && c <= 0xFC)) {
			if(i >= length) break;
			var c2 = src.getbyte(index + i);
			if(c2 == 0) break;
			result += String.fromCharCode(c2);
			i ++;
		}
	}
	dest.assign(new StrValue(result));
	evaluator.strsize = i;
	evaluator.stat.assign(0, new IntValue(c));
}

defineInlineBuiltinFunc('memexpand', [true, false], function(g, paramInfos) {
	g.push(g.getVariableAgentParamExpr(paramInfos[0])+'.expandByteSize('+g.getIntParamNativeValueExpr(paramInfos[1], 0)+');');
});

function toSimpleExprIfUsedStack(g, varName, paramInfo, expr) {
	if(paramInfo && paramInfo.stackSize) {
		return g.toSimpleExpr(expr, varName);
	} else {
		return expr;
	}
}

defineInlineBuiltinFunc('memcpy', [true, true, false, false, false], function(g, paramInfos) {
	var destExpr       = g.getVariableAgentParamExpr (paramInfos[0]);
	var srcExpr        = g.getVariableAgentParamExpr (paramInfos[1]);
	var lengthExpr     = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var destOffsetExpr = g.getIntParamNativeValueExpr(paramInfos[3], 0);
	var srcOffsetExpr  = g.getIntParamNativeValueExpr(paramInfos[4], 0);
	g.push(g.getRegisteredObjectExpr(memcpy_internal)+'('+destExpr+', '+srcExpr+', '+lengthExpr+', '+destOffsetExpr+', '+srcOffsetExpr+');');
});

function memcpy_internal(dest, src, length, destOffset, srcOffset) {
	dest.setbytes(destOffset, src.getbytes(srcOffset, length));
}

defineInlineBuiltinFunc('memset', [true, false, false, false], function(g, paramInfos) {
	var agentExpr  = g.getVariableAgentParamExpr (paramInfos[0]);
	var valExpr    = g.getIntParamNativeValueExpr(paramInfos[1], 0) + ' & 0xff';
	var lengthExpr = g.getIntParamNativeValueExpr(paramInfos[2], 0);
	var offsetExpr = g.getIntParamNativeValueExpr(paramInfos[3], 0);
	g.push(agentExpr+'.fillBytes('+valExpr+', '+lengthExpr+', '+offsetExpr+');');
});

defineInlineBuiltinFunc('notesel', [true], function(g, paramInfos) {
	g.push('var agent = '+g.getVariableAgentParamExpr(paramInfos[0])+';');
	g.push('if(agent.variable.value.type != VarType.STR) {');
	g.push('    agent.assign(StrValue.EMPTY_STR);');
	g.push('}');
	g.push('this.selectNote(agent);');
});

defineInlineBuiltinFunc('noteadd', [false, false, false], function(g, paramInfos) {
	g.push(g.getRegisteredObjectExpr(noteadd_internal)+'(this.getNote(), '+g.getStrParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+' != 0);');
});

function noteadd_internal(note, line, lineNumber, overwrite) {
	var index = note.getValue().lineIndex(lineNumber);
	if(index == null) {
		if(lineNumber >= 0) return;
		var str = note.getValue()._value;
		index = str.length;
		if(index != 0) {
			var c = str.charCodeAt(index - 1);
			if(c != 0x0d && c != 0x0a) {
				note.assign(new StrValue(str + "\r\n"));
				index += 2;
			}
		}
	}
	if(!overwrite) {
		note.splice(index, 0, line._value + "\r\n");
		return;
	}
	var length = note.getValue().lineLength(index);
	note.splice(index, length, line._value);
}

defineInlineBuiltinFunc('notedel', [false], function(g, paramInfos) {
	g.push(g.getRegisteredObjectExpr(notedel_internal)+'(this.getNote(), '+g.getIntParamNativeValueExpr(paramInfos[0], 0)+');');
});

function notedel_internal(note, lineNumber) {
	var val = note.getValue();
	var index = val.lineIndex(lineNumber);
	if(index == null) return;
	var length = val.lineLengthIncludeCR(index);
	note.splice(index, length, '');
}

defineInlineBuiltinFunc('noteload', [false], function(g, paramInfos) {
	g.push(g.getRegisteredObjectExpr(noteload_internal)+'(this, '+g.getStrParamNativeValueExpr(paramInfos[0])+');');
});

function noteload_internal(evaluator, path) {
	var note = evaluator.getNote();
	evaluator.fileRead(
		path,
		function(data) {
			data = CP932.encode(data) + "\0";
			note.expandByteSize(data.length);
			note.setbytes(0, data);
		},
		function() {
			throw new HSPError(ErrorCode.FILE_IO);
		});
}

defineInlineBuiltinFunc('randomize', [false], function(g, paramInfos) {
	g.push('this.random.srand('+g.getIntParamNativeValueExpr(paramInfos[0], 'new Date()|0')+');');
});

defineInlineBuiltinFunc('noteunsel', [], function(g, paramInfos) {
	g.push('this.undoNote();');
});

defineInlineBuiltinFunc('noteget', [true, false], function(g, paramInfos) {
	g.push(g.getRegisteredObjectExpr(noteget_internal)+'(this.getNote().getValue(), '+g.getVariableAgentParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1])+');');
});

function noteget_internal(val, dest, lineNumber) {
	var str = val._value;
	var index = val.lineIndex(lineNumber);
	if(index == null) {
		dest.assign(StrValue.EMPTY_STR);
		return;
	}
	var length = val.lineLength(index);
	dest.assign(new StrValue(str.substr(index, length)));
}

defineInlineExprBuiltinFunc('int', [false], VarType.INT, function(g, paramInfos) {
	return g.getIntConvertedParamExpr(paramInfos[0]);
});

defineCompileTimeBuiltinFunc('int', function(val) {
	scanArgs(arguments, '.', 1);
	return val.toIntValue();
});

defineInlineExprBuiltinFunc('rnd', [false], VarType.INT, function(g, paramInfos) {
	var paramInfo = paramInfos[0];
	var value = g.getParamIntLiteralValue(paramInfo);
	if(value != null && value != 0) {
		return 'new IntValue(this.random.rand() % '+value+')';
	}
	return g.getRegisteredObjectExpr(rnd_internal)+'(this, '+g.getIntParamNativeValueExpr(paramInfos[0])+')';
});
function rnd_internal(evaluator, n) {
	if(n == 0) {
		throw new HSPError(ErrorCode.DIVIDED_BY_ZERO);
	}
	return new IntValue(evaluator.random.rand() % n);
}

defineInlineExprBuiltinFunc('strlen', [false], VarType.INT, function(g, paramInfos) {
	return 'new IntValue('+g.getStrParamNativeValueExpr(paramInfos[0])+'.length)';
});

defineCompileTimeBuiltinFunc('strlen', function(str) {
	scanArgs(arguments, 's', 1);
	return new IntValue(str._value.length);
});

defineInlineExprBuiltinFunc('length', [true], VarType.INT, function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	return 'new IntValue('+variableExpr+'.getL0())';
});

defineInlineExprBuiltinFunc('length2', [true], VarType.INT, function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	return 'new IntValue('+variableExpr+'.getL1())';
});

defineInlineExprBuiltinFunc('length3', [true], VarType.INT, function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	return 'new IntValue('+variableExpr+'.getL2())';
});

defineInlineExprBuiltinFunc('length4', [true], VarType.INT, function(g, paramInfos) {
	var variableExpr = g.getNoSubscriptVariableParamExpr(paramInfos[0]);
	return 'new IntValue('+variableExpr+'.getL3())';
});

defineInlineExprBuiltinFunc('vartype', [true], VarType.INT, function(g, paramInfos) {
	if(paramInfos[0] && paramInfos[0].getPureNode().isVarNode()) {
		return 'new IntValue('+g.getVariableParamExpr(paramInfos[0])+'.value.type)';
	} else {
		return g.getRegisteredObjectExpr(vartype_internal)+'('+g.getStrParamNativeValueExpr(paramInfos[0])+')';
	}
}); 
function vartype_internal(name) {
	for(var i = 0; i < VarTypeNames.length; i ++) {
		if(VarTypeNames[i] == name) {
			return new IntValue(i);
		}
	}
	throw new HSPError(ErrorCode.ILLEGAL_FUNCTION, '指定された名前の変数型は存在しません');
}

defineCompileTimeBuiltinFunc('vartype', function(name) {
	scanArgs(arguments, 's', 1);
	return vartype_internal(name._value);
});

(function() {
	var internalFunc = createInternalFunc();
	defineInlineExprBuiltinFunc('gettime', [false], VarType.INT, function(g, paramInfos) {
		if(ommitable(paramInfos[0])) {
			return getExpr(paramInfos[0].node.val._value, 'new Date()');
		} else {
			return g.getRegisteredObjectExpr(internalFunc)+'('+g.getIntParamNativeValueExpr(paramInfos[0])+')';
		}
	});

	function ommitable(paramInfo) {
		if(!paramInfo) return false;
		var node = paramInfo.node;
		if(!node.isLiteralNode()) return false;
		var val = node.val;
		return val.type == VarType.INT && -1 <= val._value && val._value <= 7;
	}
	function createInternalFunc() {
		var code = '';
		code += 'var IntValue = HSPonJS.IntValue;\n';
		code += 'var HSPError = HSPonJS.HSPError;\n';
		code += 'return function(n) {\n';
		code += 'var date = new Date;\n';
		code += 'switch(n) {\n';
		for(var i = -1; i <= 7; i ++) {
			code += 'case '+i+':\n';
			code += '    return '+getExpr(i, 'date')+';\n';
		}
		code += 'default:\n';
		code += '    throw new HSPError(ErrorCode.ILLEGAL_FUNCTION);\n';
		code += '}\n'
		code += '};';
		return new Function(code)();
	}
	function getExpr(n, dateExpr) {
		switch(n) {
		case -1:
			return 'new IntValue('+dateExpr+' - this.startTime)';
		case 0:
			return 'new IntValue('+dateExpr+'.getFullYear())';
		case 1:
			return 'new IntValue('+dateExpr+'.getMonth() + 1)';
		case 2:
			return 'new IntValue('+dateExpr+'.getDay())';
		case 3:
			return 'new IntValue('+dateExpr+'.getDate())';
		case 4:
			return 'new IntValue('+dateExpr+'.getHours())';
		case 5:
			return 'new IntValue('+dateExpr+'.getMinutes())';
		case 6:
			return 'new IntValue('+dateExpr+'.getSeconds())';
		case 7:
			return 'new IntValue('+dateExpr+'.getMilliseconds())';
		default:
			throw new Error('must not happen');
		}
	}
})();

defineInlineExprBuiltinFunc('peek', [true, false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(peek_internal)+'('+g.getVariableAgentParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+')';
});

function peek_internal(v, n) {
	if(n < 0) {
		throw new HSPError(ErrorCode.ILLEGAL_FUNCTION);
	}
	return new IntValue(v.getbyte(n));
}

defineInlineExprBuiltinFunc('wpeek', [true, false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(wpeek_internal)+'('+g.getVariableAgentParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+')';
});

function wpeek_internal(v, n) {
	if(n < 0) {
		throw new HSPError(ErrorCode.ILLEGAL_FUNCTION);
	}
	return new IntValue(v.getbyte(n) | v.getbyte(n + 1) << 8);
}

defineInlineExprBuiltinFunc('lpeek', [true, false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(lpeek_internal)+'('+g.getVariableAgentParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+')';
});

function lpeek_internal(v, n) {
	if(n < 0) {
		throw new HSPError(ErrorCode.ILLEGAL_FUNCTION);
	}
	return new IntValue(v.getbyte(n) | v.getbyte(n + 1) << 8 | v.getbyte(n + 2) << 16 | v.getbyte(n + 3) << 24);
}

defineInlineExprBuiltinFunc('varuse', [false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(varuse_internal)+'('+g.getParamExpr(paramInfos[0])+')';
});

function varuse_internal(v) {
	var using = v.isUsing();
	if(using == null) {
		throw new HSPError(ErrorCode.TYPE_MISMATCH, VarTypeNames[v.type] + ' 型は varuse をサポートしていません');
	}
	return new IntValue(using);
}

defineInlineExprBuiltinFunc('noteinfo', [false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(noteinfo_internal)+'(this, '+g.getIntParamNativeValueExpr(paramInfos[0])+')';
});

function noteinfo_internal(evaluator, n) {
	switch(n) {
	case 0: // notemax
		var lines = evaluator.getNote().getValue()._value.split(/\r\n|[\r\n]/);
		var len = lines.length;
		if(!lines[len-1]) len --;
		return new IntValue(len);
	case 1: // notesize
		return new IntValue(evaluator.getNote().getValue()._value.length);
	default:
		throw new HSPError(ErrorCode.ILLEGAL_FUNCTION);
	}
}

defineInlineExprBuiltinFunc('instr', [false, false, false], VarType.INT, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(instr_internal)+'('+g.getStrParamExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1], 0)+', '+g.getStrParamNativeValueExpr(paramInfos[2])+')';
});

function instr_internal(str, fromIndex, pattern) {
	var index = str.toStrValue().indexOf(pattern, fromIndex);
	if(index >= 0) index -= fromIndex;
	return new IntValue(index);
}

defineInlineExprBuiltinFunc('abs', [false], VarType.INT, function(g, paramInfos) {
	return 'new IntValue(Math.abs('+g.getIntParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('limit', [false, false, false], VarType.INT, function(g, paramInfos) {
	return 'new IntValue('+g.getRegisteredObjectExpr(limit_internal)+'('+g.getIntParamNativeValueExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1])+', '+g.getIntParamNativeValueExpr(paramInfos[2])+'))';
});

function limit_internal(val, min, max) {
	if(val > max) {
		return max;
	}
	if(val < min) {
		return min;
	}
	return val;
}

defineInlineExprBuiltinFunc('str', [false], VarType.STR, function(g, paramInfos) {
	return g.getStrConvertedParamExpr(paramInfos[0]);
});

defineCompileTimeBuiltinFunc('str', function(val) {
	scanArgs(arguments, '.', 1);
	return val.toStrValue();
});

defineInlineExprBuiltinFunc('strmid', [false, false, false], VarType.STR, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(strmid_internal)+'('+g.getStrParamNativeValueExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1])+', '+g.getIntParamNativeValueExpr(paramInfos[2])+')';
});

function strmid_internal(str, index, length) {
	if(index < 0) {
		index = str.length - length;
		if(index < 0) index = 0;
	}
	return new StrValue(str.substr(index, length));
}

defineInlineExprBuiltinFunc('strf', [], VarType.STR, function(g, paramInfos) {
	var args = '';
	for(var i = 1; i < paramInfos.length; i ++) {
		if (i != 1) args += ',';
		args += g.getParamExpr(paramInfos[i]);
	}
	return 'new StrValue(Formatter.sprintf('+g.getStrParamNativeValueExpr(paramInfos[0])+', ['+args+']))';
});
builtinFunc('strf').argsMax = null;
builtinFunc('strf').defaultReceiveVar = false;

defineInlineExprBuiltinFunc('getpath', [false], VarType.STR, function(g, paramInfos) {
	return g.getRegisteredObjectExpr(getpath_internal)+'('+g.getStrParamNativeValueExpr(paramInfos[0])+', '+g.getIntParamNativeValueExpr(paramInfos[1])+')';
});

function getpath_internal(path, flags) {
	if(flags & 16) {
		var re = /((?:[\x81-\x9f\xe0-\xfc][\s\S]|[^A-Z])*)([A-Z]*)/g;
		path = path.replace(re, function(s,a,b) {
			return a + b.toLowerCase();
		});
	}
	var dir = /^(?:\w:)?(?:(?:[^\x81-\x9f\xe0-\xfc]|[\x81-\x9f\xe0-\xfc][\s\S])*[\/\\])?/.exec(path)[0];
	var ext = /(?:\.[^.\/\\]*)?$/.exec(path)[0];
	var basename = path.slice(dir.length, path.length - ext.length);
	if(flags & 8) {
		path = basename + ext;
	} else if(flags & 32) {
		path = dir;
	}
	var result = path;
	switch(flags & 7) {
	case 1:
		result = path.slice(0, path.length - ext.length);
		break;
	case 2:
		result = ext;
		break;
	}
	return new StrValue(result);
}

defineInlineExprBuiltinFunc('sin', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.sin('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('cos', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.cos('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('tan', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.tan('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('atan', [false, false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.atan2('+g.getDoubleParamNativeValueExpr(paramInfos[0])+', '+g.getDoubleParamNativeValueExpr(paramInfos[1], 1)+'))';
});

defineInlineExprBuiltinFunc('sqrt', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.sqrt('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('double', [false], VarType.DOUBLE, function(g, paramInfos) {
	return g.getDoubleConvertedParamExpr(paramInfos[0]);
});

defineCompileTimeBuiltinFunc('double', function(val) {
	scanArgs(arguments, '.', 1);
	return val.toDoubleValue();
});

defineInlineExprBuiltinFunc('absf', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.abs('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('expf', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.exp('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('logf', [false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue(Math.log('+g.getDoubleParamNativeValueExpr(paramInfos[0])+'))';
});

defineInlineExprBuiltinFunc('limitf', [false, false, false], VarType.DOUBLE, function(g, paramInfos) {
	return 'new DoubleValue('+g.getRegisteredObjectExpr(limitf_internal)+'('+g.getDoubleParamNativeValueExpr(paramInfos[0])+', '+g.getDoubleParamNativeValueExpr(paramInfos[1])+', '+g.getDoubleParamNativeValueExpr(paramInfos[2])+'))';
});

function limitf_internal(val, min, max) {
	if(val > max) {
		return max;
	}
	if(val < min) {
		return min;
	}
	return val;
}

if(typeof HSPonJS != 'undefined') {
	HSPonJS.BuiltinFuncInfos = BuiltinFuncInfos;
	HSPonJS.BuiltinFuncInfo = BuiltinFuncInfo;
	HSPonJS.builtinFunc = builtinFunc;
	HSPonJS.defineInlineBuiltinFunc = defineInlineBuiltinFunc;
	HSPonJS.defineInlineExprBuiltinFunc = defineInlineExprBuiltinFunc;
	HSPonJS.defineCompileTimeBuiltinFunc = defineCompileTimeBuiltinFunc;
	HSPonJS.defineSysVar = defineSysVar;
}


function Evaluator(sequence, generateResult, options) {
	this.options = Utils.objectMerge(options, Evaluator.defaultOptions);
	this.stack = [];
	this.pc = 0;
	this.sequence = sequence;
	this.mainLoop = generateResult.mainLoop;
	this.literals = generateResult.literals;
	this.staticVarTags = generateResult.staticVarTags;
	this.registeredObjects = generateResult.registeredObjects;
	this.variables = null;
	this.cnt = 0;
	this.cntStack = [];
	this.cntEnd = 0;
	this.cntEndStack = [];
	this.loopStartPos = 0;
	this.loopStartPosStack = [];
	this.looplev = 0;
	this.frameStack = [];
	this.args = null;
	this.oldNotes = [];
	this.oldNotesPos = 0;
	this.note = null;
	this.stat = new IntArray();
	this.refdval = new DoubleArray();
	this.refstr = new StrArray();
	this.strsize = 0;
	this.iparam = 0;
	this.wparam = 0;
	this.lparam = 0;
	this.err = 0;
	this.random = new VCRandom();
	this.onerrorEvent = new Event();
	this.startTime = 0;
}

Evaluator.defaultOptions = {
	errorAtUseOfUninitializedVariable: false
};

function Frame(pc, userDefFunc, args, prevArgs) {
	this.pc = pc;
	this.userDefFunc = userDefFunc;
	this.args = args;
	this.prevArgs = prevArgs;
}

function Event() {
	this.enabled = false;
	this.pos = null;
	this.isGosub = false;
}

function throwHSPError(errorCode) {
	throw new HSPError(errorCode);
}

function _assert(cond) {
	if(!cond) throw new Error('assertion fault');
}

_assert(VarType.LABEL === 1);
_assert(VarType.STR === 2);
_assert(VarType.DOUBLE === 3);
_assert(VarType.INT === 4);
_assert(VarType.STRUCT === 5);

function checkTypeInt(val) {
	if(val.type != 4) { // VarType.INT
		throw typeMismatchError(val.type, 4);
	}
	return val;
}

function checkTypeDouble(val) {
	if(val.type != 3) { // VarType.DOUBLE
		throw typeMismatchError(val.type, 3);
	}
	return val;
}

function checkTypeNumber(val) {
	var type = val.type;
	if(type != 4 && // VarType.INT
	   type != 3) { // VarType.DOUBLE
		throw typeMismatchErrorIntOrDouble(type);
	}
	return val;
}

function checkTypeStr(val) {
	if(val.type != 2) { // VarType.STR
		throw typeMismatchError(val.type, 2);
	}
	return val;
}

function checkTypeLabel(val) {
	if(val.type != 1 || // VarType.LABEL
	   !val.isUsing()) {
		throw new HSPError(ErrorCode.LABEL_REQUIRED);
	}
	return val;
}

function checkTypeLabelAllowNull(val) {
	if(val.type != 1) { // VarType.LABEL
		throw new HSPError(ErrorCode.LABEL_REQUIRED);
	}
	return val;
}

function checkTypeStruct(val) {
	if(val.type != 5) { // VarType.STRUCT
		throw typeMismatchError(val.type, 5);
	}
	return val;
}

function scanArgs(args, format, requiredArgsCount) {
	for(var i = 0; i < format.length; i ++) {
		scanArg(args[i], format.charAt(i), i >= requiredArgsCount);
	}
	if(i < args.length) {
		throw new HSPError(ErrorCode.TOO_MANY_PARAMETERS);
	}
}

function scanArg(arg, c, isOptionalArguments) {
	if(arg == undefined) {
		if(isOptionalArguments) {
			return arg;
		} else {
			throw new HSPError(ErrorCode.NO_DEFAULT);
		}
	}
	switch(c) {
	case 'i':
		checkTypeInt(arg);
		break;
	case 'd':
		checkTypeDouble(arg);
		break;
	case 'n':
		checkTypeNumber(arg);
		break;
	case 's':
		checkTypeStr(arg);
		break;
	case 'l':
		checkTypeLabel(arg);
		break;
	case '.':
		break;
	}
	return arg;
}
function typeMismatchError(actualType, expectedType) {
	return typeMismatchError0(actualType, VarTypeNames[expectedType]+' 型');
}
function typeMismatchErrorIntOrDouble(actualType) {
	return typeMismatchError0(actualType, 'int 型か double 型');
}
function typeMismatchError0(actualType, expected) {
	return new HSPError(ErrorCode.TYPE_MISMATCH, 'パラメータの型が違います。'+VarTypeNames[actualType]+' 型ではなく、'+expected+'の値を指定しなければいけません');
}

function compileAndCreateEvaluator(ax) {
	var axdata = new AXData(ax);
	var compiler = new Compiler(axdata);
	var sequence = compiler.compile();
	var generator = new MainLoopGenerator(sequence);
	return new Evaluator(sequence, generator.generate());
}

Evaluator.prototype = {
	evaluate: function() {
		this.variables = this.buildVariables();
		this.startTime = +new Date;
		try {
			this.mainLoop();
		} catch(e) {
			this.disposeException(e);
		}
	},
	resume: function(callback) {
		try {
			if(callback) callback();
			this.pc ++;
			this.mainLoop();
		} catch(e) {
			this.disposeException(e);
		}
	},
	resumeWithEvent: function(event) {
		try {
			if(event.isGosub) {
				if(this.frameStack.length >= 256) {
					throw new HSPError(ErrorCode.STACK_OVERFLOW);
				}
				this.frameStack.push(new Frame(this.pc + 1, null, this.args));
			} else {
				this.looplev = 0;
				this.frameStack.length = 0;
				this.stack.length = 0;
			}
			this.pc = event.pos;
			this.mainLoop();
		} catch(e) {
			this.disposeException(e);
		}
	},
	buildVariables: function() {
		var varCount = this.staticVarTags.length;
		var variables = new Array(varCount);
		for(var i = 0; i < varCount; i ++) {
			variables[i] = new Variable;
		}
		if(this.options.errorAtUseOfUninitializedVariable) {
			for(var i = 0; i < varCount; i ++) {
				variables[i].value = new UninitializedArray(this.staticVarTags[i].name);
			}
		}
		return variables;
	},
	disposeException: function(e) {
		if(!(e instanceof HSPException)) {
			this.onInternalError(e);
		} else if(e instanceof HSPError) {
			if(this.onerrorEvent.enabled && this.onerrorEvent.pos != null) {
				this.wparam = this.err = e.errcode;
				var insn = this.sequence[this.pc];
				this.lparam = insn ? insn.lineNo : 0;
				this.resumeWithEvent(this.onerrorEvent);
			} else {
				this.onError(e);
			}
		} else if(e instanceof StopException) {
			this.onStop(e);
		} else if(e instanceof EndException) {
			this.onEnd(e);
		} else if(e instanceof WaitException) {
			this.onWait(e);
		} else if(e instanceof FileReadException) {
			this.onFileRead(e);
		} else if(e instanceof VoidException) {
		}
	},
	onInternalError: function(e) {
		throw e;
	},
	onStop: function() {
	},
	selectNote: function(v) {
		if(this.note) {
			this.oldNotes[this.oldNotesPos] = this.note;
			this.oldNotesPos = (this.oldNotesPos + 1) % 256;
		}
		this.note = v;
	},
	undoNote: function() {
		this.oldNotesPos = (this.oldNotesPos - 1 + 256) % 256;
		this.note = this.oldNotes[this.oldNotesPos];
		this.oldNotes[this.oldNotesPos] = null;
	},
	getNote: function() {
		if(!this.note) {
			throw new HSPError(ErrorCode.ILLEGAL_FUNCTION, 'ノートパッドが選択されていません');
		}
		return this.note.getBuffer();
	},
	fileRead: function(path, success, error) {
		throw new FileReadException(path, success, error);
	},
	getArg: function(argNum) {
		var args = this.args;
		if(!args) {
			throw new HSPError(ErrorCode.INVALID_PARAMETER);
		}
		return args[argNum];
	},
	getThismod: function() {
		var thismod = this.getArg(0);
		if(!(thismod instanceof VariableAgent && thismod.variable.value.type == VarType.STRUCT && thismod.isUsing())) {
			throw new HSPError(ErrorCode.INVALID_STRUCT_SOURCE);
		}
		return thismod;
	},
	getErrorOutput: function(e) {
		var insn = this.sequence[this.pc];
		var lines = [];
		lines.push('#Error '+e.errcode+': '+e.getErrorMessage());
		var backTrace = this.getBackTrace();
		var needToOmit = e.errcode == ErrorCode.STACK_OVERFLOW && backTrace.length >= 50;
		for(var i = 0; i < backTrace.length; i ++) {
			var fileName = backTrace[i][0];
			var lineNo   = backTrace[i][1];
			var funcName = backTrace[i][2];
			var frame    = backTrace[i][3];
			var location;
			if(fileName != null && lineNo != null) {
				location = fileName+':'+lineNo;
			} else {
				location = '(unknown location)';
			}
			if(funcName != null) {
				funcName = "`" + funcName + "'";
			} else if(!frame) {
				funcName = '(top level)';
			} else if(!frame.userDefFunc) {
				funcName = '(a sub routine)';
			}
			lines.push((i==0?'     ':'from ')+location+': in '+funcName);
			if(needToOmit && i == 7) {
				var nextIndex = backTrace.length - 4;
				lines.push(' ... '+(nextIndex - i - 1)+' levels...');
				i = nextIndex - 1;
			}
		}
		return lines.join("\n");
	},
	getBackTrace: function() {
		var result = [];
		var sequence = this.sequence;
		var frameStack = this.frameStack;
		var frameStackPos = frameStack.length;
		var pc = this.pc;
		var builtinFuncName = this.getBuiltinFuncName(sequence[pc]);
		if(builtinFuncName != undefined) {
			result.push([null, null, builtinFuncName+'@hsp', null]);
		}
		for(;;) {
			var insn = sequence[pc];
			var frame = frameStack[--frameStackPos];
			var fileName = null;
			var lineNo = null;
			var funcName = null;
			if(insn) {
				fileName = insn.fileName;
				lineNo = insn.lineNo;
			}
			if(frame && frame.userDefFunc) {
				funcName = frame.userDefFunc.name;
			}
			result.push([fileName, lineNo, funcName, frame]);
			if(!frame) break;
			pc = frame.pc - 1;
		}
		return result;
	},
	getBuiltinFuncName: function(insn) {
		if(insn.code != Insn.Code.CALL_BUILTIN_CMD &&
		   insn.code != Insn.Code.CALL_BUILTIN_FUNC) {
			return undefined;
		}
		var type = insn.opts[0];
		var subid = insn.opts[1];
		var names = BuiltinFuncNames[type];
		if(!names) return undefined;
		return names[subid];
	}
};

if(typeof HSPonJS != 'undefined') {
	HSPonJS.Evaluator = Evaluator;
	HSPonJS.Frame = Frame;
	HSPonJS.Event = Event;
	HSPonJS.throwHSPError = throwHSPError;
	HSPonJS.checkTypeInt = checkTypeInt;
	HSPonJS.checkTypeDouble = checkTypeDouble;
	HSPonJS.checkTypeNumber = checkTypeNumber;
	HSPonJS.checkTypeStr = checkTypeStr;
	HSPonJS.checkTypeLabel = checkTypeLabel;
	HSPonJS.checkTypeLabelAllowNull = checkTypeLabelAllowNull;
	HSPonJS.checkTypeStruct = checkTypeStruct;
	HSPonJS.scanArgs = scanArgs;
	HSPonJS.scanArg = scanArg;
	HSPonJS.compileAndCreateEvaluator = compileAndCreateEvaluator;
}



})();


