OSDN Git Service

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