OSDN Git Service

elccコンパイラの最適化機能を向上。
[chnosproject/AI004.git] / elcc / elcc.js
1 // ELCHNOSCompiler for AI004
2 // AI004(WebCPU)がなければ動作しない。
3
4 //手順:
5 //トークン分割
6 //構造解析・式の逆ポーランド化
7 //中間バイナリ化
8
9 function ELCHNOSCompiler_CompileException(errno, infoArray, lineCount){
10         this.errno = errno;
11         this.infoArray = infoArray;
12         this.lineCount = lineCount;
13 }
14 ELCHNOSCompiler_CompileException.prototype = {
15         errorMessageList: [
16                 "Trap.",
17                 "Incompatible value attribute.",
18                 "Unexpected identifier.",
19                 "Unknown assembly language type.",
20                 "Invalid expression of OSECPU Binary.",
21                 "Binary translation error.",
22         ],
23         getMessageString: function(){
24                 var s = "";
25                 if(!isNaN(this.lineCount)){
26                         s += this.lineCount + ":";
27                 }
28                 s += "Error" + this.errno.toString().toUpperCase();
29                 if(this.errno < 0 || this.errorMessageList.length <= this.errno){
30                         s += ":Unknown\n";
31                 } else{
32                         s += ":" + this.errorMessageList[this.errno] + "\n";
33                 }
34                 if(this.infoArray){
35                         s += "  >" + this.infoArray.join("\n  > ") + "\n";
36                 }
37                 return s;
38         },
39 }
40 // throw new ELCHNOSCompiler_CompileException(5, [""], this.lineCount);
41
42
43 function ELCHNOSCompiler(printFunc, downloadBoxDOMObject){
44         //printFunc省略時はconsole.logに出力。
45         if(printFunc){
46                 this.debug = printFunc;
47         } else{
48                 this.debug = function(s){ console.log(s); };
49         }
50         this.downloadBoxDOMObject = downloadBoxDOMObject;
51         
52         this.reset();
53         //0はエントリポイント(main)用に予約
54         this.nextLabelID = 1;
55         this.integerRegisterAllocationTable = new Array();
56         this.pointerRegisterAllocationTable = new Array();
57 }
58 ELCHNOSCompiler.prototype = {
59         keyWordList: [
60                 "@asm",
61                 "@end",
62                 "//",
63                 "/*",
64                 "*/",
65                 "!=",
66                 "==",
67                 "+=",
68                 "-=",
69                 "*=",
70                 "/=",
71                 "<=",
72                 "++",
73                 "--",
74                 "\n",
75                 "\t",
76                 " ",
77                 "{",
78                 "}",
79                 "(",
80                 ")",
81                 ";",
82                 ",",
83                 "[",
84                 "]",
85                 "=",
86                 "+",
87                 "-",
88                 "*",
89                 "/",
90                 "#",
91         ],
92         errorMessageList: [
93                 "Trap.",
94                 "Incompatible attribute.",
95                 "Unexpected identifier.",
96                 "Unknown assembly language type.",
97                 "Invalid expression of OSECPU Binary.",
98                 "Binary translation error.",
99         ],
100         
101         Flag_Sign_Signed                        : 0x00000001,
102         Flag_Sign_Unsigned                      : 0x00000002,
103         reset: function(){
104                 this.line = null;
105                 this.separated = null;
106                 this.bin = new Array();
107                 
108                 this.structure = new Array();
109                 this.currentStructure = this.structure;
110                 this.structureStack = new Array();
111                 
112                 //0はエントリポイント(main)用に予約
113                 this.nextLabelID = 1;
114                 this.integerRegisterAllocationTable = new Array();
115                 this.pointerRegisterAllocationTable = new Array();
116         },
117         compile: function(str){
118                 //戻り値はコンパイルされたバイナリのHex文字列。nullの場合コンパイル失敗。
119                 this.reset();
120                 //
121                 this.line = str.split("\n");
122                 //分割
123                 this.separated = str.splitByArraySeparatorSeparatedLong(this.keyWordList);
124                 //コメント除去
125                 this.compile_removeComment();
126                 
127                 //不要な文字を削除
128                 this.separated.removeAllObject("\t");
129                 this.separated.removeAllObject(" ");
130                 
131                 //メイン処理
132                 var currentExpression = null;
133                 var numValSignFlag = 0;
134                 var numValBits = 0;
135                 var pointerCount = 0;
136                 var lineCount = 1;
137                 var mode = 0;
138                 var o;
139                 var f;
140                         //次に期待する値を示す。
141                         // 0: 何が来るかわからない
142                         //
143                         //10: 変数・定数の前置属性・型・または識別子
144                         //11: 変数・定数の識別子またはポインタ属性
145                         //12: 変数・定数の後置属性・初期化式または終端記号、もしくは連続した変数宣言の区切り
146                         //13: 変数・定数の初期化式または終端記号、もしくは連続した変数宣言の区切り
147                         //14: 配列長の数値部分
148                         //15: 配列長指定終了の閉じ括弧
149                         //16: 初期化式の開始括弧もしくは値
150                         //17: 初期化式の値部分または終了括弧
151                         //18: 初期化式の区切りまたは終了括弧
152                         //19: 終端記号
153                         //
154                         //50: 関数名または関数属性
155                         //51: 引数開始括弧
156                         //52: 引数or引数終了括弧
157                         //53: 引数区切りor引数終了括弧
158                         //54: 関数内部開始括弧
159                         //
160                         //60: 評価式の内容または終端記号
161                         //
162                         //70: OSECPUアセンブリ直接記述モード
163                         //71: OSECPUアセンブリ評価式の内容または終端記号
164                 try{
165                         for(var i = 0, iLen = this.separated.length; i < iLen; i++){
166                                 var s = this.separated[i].toLowerCase();
167                                 
168                                 if(s == "\n"){
169                                         //デバッグ用行数カウント
170                                         lineCount++;
171                                         continue;
172                                 //予約語
173                                 } else if(s == "signed" && (mode == 0 || mode == 10)){
174                                         //符号あり
175                                         if(numValSignFlag != 0){
176                                                 throw new ELCHNOSCompiler_CompileException(1, [s], lineCount);
177                                         }
178                                         numValSignFlag |= this.Flag_Sign_Signed;
179                                         mode = 10;
180                                 } else if(s == "unsigned" && (mode == 0 || mode == 10)){
181                                         //符号なし
182                                         if(numValSignFlag != 0){
183                                                 throw new ELCHNOSCompiler_CompileException(1, [s], lineCount);
184                                         }
185                                         numValSignFlag |= this.Flag_Sign_Unsigned;
186                                         mode = 10;
187                                 } else if(s == "char"  && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
188                                         //char 8bit符号あり
189                                         numValBits = 8;
190                                         if(mode == 0 || mode == 10 || mode == 11){
191                                                 mode = 11;
192                                         }
193                                 } else if(s == "int" && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
194                                         //int 32bit符号あり
195                                         numValBits = 32;
196                                         if(mode == 0 || mode == 10 || mode == 11){
197                                                 mode = 11;
198                                         }
199                                 } else if(s == ";" && (mode == 0 || mode == 12 || mode == 13 || mode == 19 || mode == 60 || mode == 71)){
200                                         if(mode == 12 || mode == 13 || mode == 19){
201                                                 //変数または定数の定義終了
202                                                 numValBits = 0;
203                                                 numValSignFlag = 0;
204                                                 currentExpression = null;
205                                                 mode = 0;
206                                         } else if(mode == 60 || mode == 71){
207                                                 //評価式終端
208                                                 currentExpression = null;
209                                                 if(mode == 60){
210                                                         mode = 0;
211                                                 } else if(mode == 71){
212                                                         mode = 70;
213                                                 }
214                                         } else{
215                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
216                                         }
217                                 } else if(s == "=" && (mode == 13)){
218                                         if(mode == 13){
219                                                 //変数・定数初期化式開始
220                                                 mode = 16;
221                                         } else{
222                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
223                                         }
224                                 } else if(s == "*" && (mode == 11)){
225                                         //ポインタ属性の付加
226                                         pointerCount++;
227                                 } else if(s == "," && (mode == 18 || mode == 12 || mode == 13 || mode == 53)){
228                                         if(mode == 18){
229                                                 //初期化式の区切り
230                                                 mode = 17;
231                                         } else if(mode == 12 || mode == 13 || mode == 53){
232                                                 //連続した変数宣言の区切り
233                                                 if(mode == 12 || mode == 13){
234                                                         mode = 11;
235                                                 } else if(mode == 53){
236                                                         mode = 52;
237                                                 }
238                                                 currentExpression = null;
239                                         } else{
240                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
241                                         }
242                                 //括弧系
243                                 } else if(s == "[" && (mode == 12)){
244                                         //配列の長さの定義開始
245                                         mode = 14;
246                                 } else if(s == "]" && (mode == 15)){
247                                         //配列の長さの定義終了
248                                         mode = 13;
249                                 } else if(s == "{" && (mode == 16 || mode == 54)){
250                                         if(mode == 16){
251                                                 //初期化式の開始括弧
252                                                 mode = 17;
253                                         } else if(mode == 54){
254                                                 //54: 関数内部開始括弧
255                                                 currentExpression = null;
256                                                 mode = 0;
257                                         } else{
258                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
259                                         }
260                                 } else if(s == "}" && (mode == 17 || mode == 18 || mode == 0)){
261                                         if(mode == 17 || mode == 18){
262                                                 //初期化式の終了括弧
263                                                 mode = 19;
264                                         } else if(mode == 0){
265                                                 if(this.structureStack.length > 0){
266                                                         this.restoreCurrentStructure();
267                                                 } else{
268                                                         throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
269                                                 }
270                                         }
271                                 } else if(s == "(" && (mode == 51)){
272                                         //51: 引数開始括弧
273                                         mode = 52;
274                                 } else if(s == ")" && (mode == 52 || mode == 53)){
275                                         //52: 引数or引数終了括弧
276                                         //53: 引数区切りor引数終了括弧
277                                         currentExpression = null;
278                                         for(var j = 0, jLen = this.currentStructure.length; j < jLen; j++){
279                                                 //引数番号を付与
280                                                 this.currentStructure[j].argumentIndex = j;
281                                         }
282                                         mode = 54;
283                                 } else if(s == "@asm" && (mode == 0)){
284                                         i++;
285                                         s = this.separated[i].toLowerCase();
286                                         if(s == "osecpu"){
287                                                 mode = 70;
288                                         } else{
289                                                 throw new ELCHNOSCompiler_CompileException(3, [s], lineCount);
290                                         }
291                                 } else if(s == "@end" && (mode == 70)){
292                                         mode = 0;
293                                 //リストにない予約語
294                                 } else if(s == "procedure" && (mode == 0)){
295                                         //関数宣言
296                                         var f = new ELCHNOSCompiler_ExpressionStructure_Function(this, lineCount);
297                                         this.currentStructure.push(f);
298                                         this.changeCurrentStructure(f.structure);
299                                         currentExpression = f;
300                                         
301                                         mode = 50;
302                                 } else if(s == "inline" && (mode == 50)){
303                                         currentExpression.isInline = true;
304                                 } else if(s == "for" && (mode == 0)){
305                                         //forループ
306                                         i++;
307                                         s = this.separated[i];
308                                         if(s == "("){
309                                                 var f = new ELCHNOSCompiler_ExpressionStructure_Loop_for(this, lineCount);
310                                                 this.currentStructure.push(f);
311                                                 this.changeCurrentStructure(f.structure);
312                                                 currentExpression = f;
313                                                 //初期化式
314                                                 f.initializer = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
315                                                 i = f.initializer.readExpressionToTerminator(i, ";");
316                                                 //条件評価式
317                                                 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
318                                                 i = f.conditonalExpression.readExpressionToTerminator(i, ";");
319                                                 //更新式
320                                                 f.incrementalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
321                                                 i = f.incrementalExpression.readExpressionToTerminator(i, ")");
322                                                 //開始括弧
323                                                 i++;
324                                                 if(this.separated[i] != "{"){
325                                                         throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
326                                                 }
327                                                 currentExpression = null;
328                                         } else{
329                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
330                                         }
331                                 } else if(s == "if" && (mode == 0)){
332                                         //if文
333                                         //条件評価式-?>L2
334                                         //実行部分
335                                         //(break->L2)
336                                         //L2:
337                                         i++;
338                                         s = this.separated[i];
339                                         if(s == "("){
340                                                 var f = new ELCHNOSCompiler_ExpressionStructure_if(this, lineCount);
341                                                 this.currentStructure.push(f);
342                                                 this.changeCurrentStructure(f.structure);
343                                                 currentExpression = f;
344                                                 //条件評価式
345                                                 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
346                                                 i = f.conditonalExpression.readExpressionToTerminator(i, ")");
347                                                 //開始括弧
348                                                 i++;
349                                                 if(this.separated[i] != "{"){
350                                                         throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
351                                                 }
352                                                 currentExpression = null;
353                                         } else{
354                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
355                                         }
356                                 //OSECPUアセンブリ
357                                 } else if(s == "remark" && (mode == 70)){
358                                         //超手抜き
359                                         var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this, lineCount);
360                                         this.currentStructure.push(b);
361                                         //FE    len     ...
362                                         b.bin.push(0xfe);
363                                         //len
364                                         i++;
365                                         s = this.separated[i];
366                                         if(s.length == 2){
367                                                 var len = parseInt(s, 16);
368                                                 b.bin.push(len);
369                                         } else{
370                                                 throw new ELCHNOSCompiler_CompileException(4, [s], lineCount);
371                                         }
372                                         //data
373                                         i++;
374                                         s = this.separated[i];
375                                         if(s.length == len * 2){
376                                                 for(var j = 0; j < len; j++){
377                                                         b.bin.push(parseInt(s.substr(j * 2, 2), 16));
378                                                 }
379                                         } else{
380                                                 throw new ELCHNOSCompiler_CompileException(4, [s], lineCount);
381                                         }
382                                         //終端
383                                         i++;
384                                         if(this.separated[i] != ";"){
385                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
386                                         } else{
387                                                 //この命令は定数のみで構成されているのでコンパイル済みとマークする
388                                                 b.isCompiled = true;
389                                                 b = null;
390                                         }
391                                 } else if(s == "call" && (mode == 70)){
392                                         //超手抜き
393                                         var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this, lineCount);
394                                         this.currentStructure.push(b);
395                                         
396                                         //第二引数が何か確認する
397                                         i++;
398                                         s = this.separated[i].toLowerCase();
399                                         if((s.indexOf("p") == 0) && s.length == 3){
400                                                 //ポインタレジスタをcall
401                                                 //新しいラベル番号をもらう
402                                                 var labelID = this.allocateLabelID();
403                                                 //PLIMM(P30, labelID)
404                                                         //03    reg0    imm32
405                                                 b.bin.push(0x03);
406                                                 b.bin.push(0x30);
407                                                 b.appendInstruction_UINT32BE(labelID);
408                                                 //PCP(P3F, Pxx)
409                                                         //1E    reg0P   reg1P
410                                                 b.bin.push(0x1e);
411                                                 b.bin.push(0x3f);
412                                                 b.bin.push(parseInt(s.substr(1),16));
413                                                 
414                                                 b.appendInstruction_LB(0x01, labelID);
415                                                 //[FE] [01] [00]
416                                                 b.bin.push(0xfe);
417                                                 b.bin.push(0x01);
418                                                 b.bin.push(0x00);
419                                                 //終端記号
420                                                 i++;
421                                                 if(this.separated[i] != ";"){
422                                                         throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
423                                                 } else{
424                                                         //この命令は定数のみで構成されているのでコンパイル済みとマークする
425                                                         b.isCompiled = true;
426                                                         b = null;
427                                                 }
428                                         } else{
429                                                 throw new ELCHNOSCompiler_CompileException(0, [s], lineCount);
430                                         }
431                                 //予約語以外
432                                 } else if(mode == 11 || mode == 52){
433                                         //変数または定数の宣言
434                                         //52: 引数名
435                                         var v = new ELCHNOSCompiler_ExpressionStructure_Variable(this, lineCount);
436                                         v.bits = numValBits;
437                                         v.isSigned = (numValSignFlag == 0) ? false : (0 != (numValSignFlag & this.Flag_Sign_Signed));
438                                         s = this.separated[i];
439                                         v.isPointer = (pointerCount != 0) ? true : false;
440                                         pointerCount = 0;
441                                         if(s.length <= 0){
442                                                 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
443                                         }
444                                         v.identifier = s;
445                                         this.currentStructure.push(v);
446                                         currentExpression = v;
447                                         //mode:11->12
448                                         //mode:52->53
449                                         mode++;
450                                 } else if(mode == 14){
451                                         currentExpression.length = parseInt(s);
452                                         mode = 15;
453                                 } else if(mode == 17){
454                                         //定数値のみ対応
455                                         currentExpression.initValue.push(parseInt(s));
456                                         mode = 18;
457                                 } else if(mode == 50){
458                                         //関数名
459                                         //大文字小文字を区別
460                                         currentExpression.identifier = this.separated[i];
461                                         mode = 51;
462                                 } else{
463                                         if(mode == 0 || mode == 70 || mode == 60 || mode == 71){
464                                                 //大文字小文字を区別
465                                                 s = this.separated[i];
466                                                 if(mode == 0 || mode == 70){
467                                                         //最初の左辺だったら追加処理
468                                                         var f = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
469                                                         this.currentStructure.push(f);
470                                                         currentExpression = f;
471                                                 }
472                                                 currentExpression.pushIdentifier(s);
473                                                 if(mode == 0){
474                                                         mode = 60;
475                                                 } else if(mode == 70){
476                                                         mode = 71;
477                                                 }
478                                         }
479                                 }
480                         }
481                         //中間バイナリ生成
482                         //バックエンドコードの中間表現を出力。
483                         //0x00-0xff: そのまま使えるバイナリ
484                         //0x10000000-0x1fffffff: 未決定の仮想整数レジスタ番号
485                         //0x20000000-0x2fffffff: 未決定の仮想ポインタレジスタ番号
486                         this.errno = 5;
487                         
488                         //OSECPUフロントエンドコードヘッダ
489                         this.bin.push(0x05, 0xe1, 0x00);
490                         
491                         for(var i = 0, iLen = this.structure.length; i < iLen; i++){
492                                 var b = this.structure[i].createBinary();
493                                 if(b !== undefined){
494                                         this.bin.push(b);
495                                 }
496                         }
497                         this.expandBinaryString();
498                         this.assignRegister();
499                         this.bin.logAsHexByte(this.debug);
500                         this.debug("(" + this.bin.length + "Bytes)\n");
501                         //
502                         //最適化(試験中)
503                         //
504                         var cpu = new WebCPU();
505                         cpu.loadBinaryText(this.bin.stringAsHexByte());
506                         cpu.staticOptimize();
507                         var binStr = cpu.createBackendBinaryString();
508                         this.debug(binStr);
509                         this.debug("(" + (binStr.length >> 1) + "Bytes)\n");
510                         //
511                 } catch(e){
512                         //全エラー処理
513                         if(e instanceof ELCHNOSCompiler_CompileException){
514                                 this.debug(e.getMessageString());
515                                 return null;
516                         } else{
517                                 throw e;
518                         }
519                 }
520                 return binStr;
521         },
522         compile_removeComment: function(){
523                 //コメント削除
524                 var commentLineStartIndex = -1;
525                 var commentBlockStartIndex = -1;
526                 var commentBlockCount = 0;
527                 var linesInCommentBlock = 0;
528                 
529                 for(var i = 0, iLen = this.separated.length; i < iLen; i++){
530                         var s = this.separated[i];
531                         if(commentLineStartIndex == -1){
532                                 if(s == "//" || s == "#"){
533                                         //行コメント開始
534                                         commentLineStartIndex = i;
535                                 }
536                         } else{
537                                 if(s == "\n"){
538                                         //行コメント終了
539                                         var len = i - commentLineStartIndex;
540                                         this.separated.splice(commentLineStartIndex, len);
541                                         iLen -= len;
542                                         i -= len;
543                                         commentLineStartIndex = -1;
544                                 }
545                         }
546                         if(s == "/*"){
547                                 //ブロックコメント開始
548                                 if(commentBlockCount == 0){
549                                         commentBlockStartIndex = i;
550                                 }
551                                 commentBlockCount++;
552                         } else if(s == "*/"){
553                                 //ブロックコメント終了
554                                 commentBlockCount--;
555                                 if(commentBlockCount == 0){
556                                         var len = i - commentBlockStartIndex + 1;
557                                         var padding = new Array();
558                                         padding.push(commentBlockStartIndex);
559                                         padding.push(len);
560                                         for(var j = 0, jLen = linesInCommentBlock; j < jLen; j++){
561                                                 padding.push("\n");
562                                         }
563                                         this.separated.splice.apply(this.separated, padding);
564                                         i -= len - linesInCommentBlock;
565                                         iLen -= len - linesInCommentBlock;
566                                         linesInCommentBlock = 0;
567                                 } else if(commentBlockCount < 0){
568                                         this.debug("Too many block comment closure [].\n");
569                                         return;
570                                 }
571                         } else if(commentBlockCount > 0 && s == "\n"){
572                                 linesInCommentBlock++;
573                         }
574                 }
575         },
576         raiseError: function(errno, lineCount, infoArray){
577                 if(errno < 0 || this.errorMessageList.length <= errno){
578                         this.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":Unknown\n");
579                 } else{
580                         this.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":" + this.errorMessageList[errno] + "\n");
581                 }
582                 if(infoArray){
583                         this.debug("  >" + infoArray.toString() + "\n");
584                 }
585         },
586         changeCurrentStructure: function(newstructure){
587                 this.structureStack.push(this.currentStructure);
588                 this.currentStructure = newstructure;
589         },
590         restoreCurrentStructure: function(){
591                 this.currentStructure = this.structureStack.pop();
592         },
593         searchIdentifier: function(identifier){
594                 var o;
595                 var cf = function(aryobj, obj){ return (aryobj.identifier == obj) };
596                 
597                 o = this.currentStructure.isIncluded(identifier, cf);
598                 if(!o){
599                         for(var i = this.structureStack.length - 1; i >= 0; i--){
600                                 o = this.structureStack[i].isIncluded(identifier, cf);
601                                 if(o){
602                                         break;
603                                 }
604                         }
605                 }
606                 return o;
607         },
608         isOperator: function(s){
609                 return (
610                         s == "=" ||
611                         s == "+" ||
612                         s == "-" ||
613                         s == "*" ||
614                         s == "/" ||
615                         s == "!=" ||
616                         s == "++" ||
617                         s == "<" ||
618                         s == "(" ||
619                         s == ")"||
620                         s == "," ||
621                         false
622                 );
623         },
624         allocateLabelID: function(){
625                 this.nextLabelID++;
626                 return this.nextLabelID - 1;
627         },
628         virtualIntegerRegisterOffset: 0x10000000,
629         allocateIntegerRegister: function(owner){
630                 //レジスタテーブルは先頭から番号の小さい順につめて格納する。
631                 //[regID, owner]
632                 //0x10000000-0x1fffffff: 未決定の仮想整数レジスタ番号
633                 var freeRegID = 0;
634                 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
635                         if(this.integerRegisterAllocationTable[i][0] != i + this.virtualIntegerRegisterOffset){
636                                 //空いているレジスタ番号を見つけた
637                                 if(i > 0x20){
638                                         this.integerRegisterAllocationTable.splice(i, 0, [i + this.virtualIntegerRegisterOffset, owner]);
639                                 }
640                         }
641                 }
642                 if(i == iLen){
643                         //途中に空いているレジスタはなかったので追加
644                         this.integerRegisterAllocationTable.push([i + this.virtualIntegerRegisterOffset, owner]);
645                 }
646                 return i + this.virtualIntegerRegisterOffset;
647         },
648         freeIntegerRegister: function(regID, owner){
649                 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
650                         if(this.integerRegisterAllocationTable[i][0] == regID){
651                                 //レジスタ番号を見つけた
652                                 //オーナーが一致するか確認
653                                 if(this.integerRegisterAllocationTable[i][1] == owner){
654                                         //一致したので解放する
655                                         this.integerRegisterAllocationTable.splice(i, 1);
656                                 }
657                                 break;
658                         }
659                 }
660                 if(i == iLen){
661                         throw new ELCHNOSCompiler_CompileException(0, ["freeIntegerRegister:regID not found."], -1);
662                 }
663         },
664         virtualPointerRegisterOffset: 0x20000000,
665         allocatePointerRegister: function(owner){
666                 //レジスタテーブルは先頭から番号の小さい順につめて格納する。
667                 //[regID, owner]
668                 //0x20000000-0x2fffffff: 未決定の仮想ポインタレジスタ番号
669                 var freeRegID = 0;
670                 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
671                         if(this.pointerRegisterAllocationTable[i][0] != i + this.virtualPointerRegisterOffset){
672                                 //空いているレジスタ番号を見つけた
673                                 this.pointerRegisterAllocationTable.splice(i, 0, [i + this.virtualPointerRegisterOffset, owner]);
674                         }
675                 }
676                 if(i == iLen){
677                         //途中に空いているレジスタはなかったので追加
678                         this.pointerRegisterAllocationTable.push([i + this.virtualPointerRegisterOffset, owner]);
679                 }
680                 return i + this.virtualPointerRegisterOffset;
681         },
682         freePointerRegister: function(regID, owner){
683                 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
684                         if(this.pointerRegisterAllocationTable[i][0] == regID){
685                                 //レジスタ番号を見つけた
686                                 //オーナーが一致するか確認
687                                 if(this.pointerRegisterAllocationTable[i][1] == owner){
688                                         //一致したので解放する
689                                         this.pointerRegisterAllocationTable.splice(i, 1);
690                                 }
691                                 break;
692                         }
693                 }
694                 if(i == iLen){
695                         throw new ELCHNOSCompiler_CompileException(0, ["freePointerRegister:regID not found."], -1);
696                 }
697         },
698         freeAllRegisterOfOwner: function(owner){
699                 //ownerが確保しているレジスタをすべて解放する
700                 //IntegerRegister
701                 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
702                         if(this.integerRegisterAllocationTable[i][1] == owner){
703                                 //見つけた
704                                 this.integerRegisterAllocationTable.splice(i, 1);
705                                 iLen--;
706                         }
707                 }
708                 //PointerRegister
709                 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
710                         if(this.pointerRegisterAllocationTable[i][1] == owner){
711                                 //見つけた
712                                 this.pointerRegisterAllocationTable.splice(i, 1);
713                                 iLen--;
714                         }
715                 }
716         },
717         expandBinaryString: function(){
718                 //入れ子構造になっている配列を一次元配列に展開して返す。
719                 var ary = this.bin;
720                 var b = new Array();
721                 var aryStack = new Array();
722                 var indexStack = new Array();
723                 for(var i = 0; ; i++){
724                         if(ary[i] === undefined){
725                                 ary = aryStack.pop();
726                                 if(ary === undefined){
727                                         break;
728                                 }
729                                 i = indexStack.pop();
730                         }
731                         if(ary[i] instanceof Array){
732                                         aryStack.push(ary);
733                                         indexStack.push(i + 1);
734                                         ary = ary[i];
735                                         i = -1;
736                         } else if(ary[i] !== undefined){
737                                         b.push(ary[i]);
738                         }
739                 }
740                 this.bin = b;
741         },
742         assignRegister: function(){
743                 for(var i = 0, iLen = this.bin.length; i < iLen; i++){
744                         if(this.bin[i] > 0xff){
745                                 if(this.virtualIntegerRegisterOffset <= this.bin[i] && this.bin[i] <= this.virtualIntegerRegisterOffset + 0x1f){
746                                         //R00-R1fは無条件で割り当ててOK
747                                         this.bin[i] -= this.virtualIntegerRegisterOffset;
748                                 } else if(this.virtualPointerRegisterOffset <= this.bin[i] && this.bin[i] <= this.virtualPointerRegisterOffset + 0x1f - 1){
749                                         //P01-P1fは無条件で割り当ててOK
750                                         this.bin[i] -= this.virtualPointerRegisterOffset;
751                                         this.bin[i] += 1;
752                                 } else{
753                                         throw new ELCHNOSCompiler_CompileException(0, ["Sorry, but no more register."]);
754                                 }
755                         }
756                 }
757         },
758         saveBinary: function(){
759                 var cl = this.bin;
760                 var v = new Uint8Array(this.bin);
761                 var d = new Blob([v]);
762                 var url;
763                 if(d){
764                         if(window.URL){
765                                 url = window.URL.createObjectURL(d);
766                         } else if(window.webkitURL){
767                                 url = window.webkitURL.createObjectURL(d);
768                         } else{
769                                 window.alert("Can't create URL");
770                         }
771                         if(url){
772                                 if(this.downloadBoxDOMObject){
773                                         this.downloadBoxDOMObject.innerHTML = "<a href='" + url + "' target='_blank'>右クリックしてダウンロード</a>";
774                                 } else{
775                                         this.debug("BinarySaved: " + url + "\n");
776                                 }
777                         }
778                 }
779         },
780         
781 }
782