1 // ELCHNOSCompiler for AI004
8 function ELCHNOSCompiler_CompileException(errno, infoArray, lineCount){
10 this.infoArray = infoArray;
11 this.lineCount = lineCount;
13 ELCHNOSCompiler_CompileException.prototype = {
16 "Incompatible value attribute.",
17 "Unexpected identifier.",
18 "Unknown assembly language type.",
19 "Invalid expression of OSECPU Binary.",
20 "Binary translation error.",
22 getMessageString: function(){
24 if(!isNaN(this.lineCount)){
25 s += this.lineCount + ":";
27 s += "Error" + this.errno.toString().toUpperCase();
28 if(this.errno < 0 || this.errorMessageList.length <= this.errno){
31 s += ":" + this.errorMessageList[this.errno] + "\n";
34 s += " >" + this.infoArray.toString() + "\n";
39 // throw new ELCHNOSCompiler_CompileException(5, [""], this.lineCount);
42 function ELCHNOSCompiler(env){
46 this.separated = null;
47 this.bin = new Array();
49 this.structure = new Array();
50 this.currentStructure = this.structure;
51 this.structureStack = new Array();
53 //0はエントリポイント(main)用に予約
55 this.integerRegisterAllocationTable = new Array();
56 this.pointerRegisterAllocationTable = new Array();
58 ELCHNOSCompiler.prototype = {
93 "Incompatible value attribute.",
94 "Unexpected identifier.",
95 "Unknown assembly language type.",
96 "Invalid expression of OSECPU Binary.",
97 "Binary translation error.",
100 Flag_Sign_Signed : 0x00000001,
101 Flag_Sign_Unsigned : 0x00000002,
103 compile: function(str){
104 this.line = str.split("\n");
106 this.separated = str.splitByArraySeparatorSeparatedLong(this.keyWordList);
108 this.compile_removeComment();
111 this.separated.removeAllObject("\t");
112 this.separated.removeAllObject(" ");
115 var currentExpression = null;
116 var numValSignFlag = 0;
118 var pointerCount = 0;
126 //10: 変数・定数の前置属性・型・または識別子
127 //11: 変数・定数の識別子またはポインタ属性
128 //12: 変数・定数の後置属性・初期化式または終端記号、もしくは連続した変数宣言の区切り
129 //13: 変数・定数の初期化式または終端記号、もしくは連続した変数宣言の区切り
133 //17: 初期化式の値部分または終了括弧
134 //18: 初期化式の区切りまたは終了括弧
145 //70: OSECPUアセンブリ直接記述モード
146 //71: OSECPUアセンブリ評価式の内容または終端記号
148 for(var i = 0, iLen = this.separated.length; i < iLen; i++){
149 var s = this.separated[i].toLowerCase();
156 } else if(s == "signed" && (mode == 0 || mode == 10)){
158 if(numValSignFlag != 0){
159 throw new ELCHNOSCompiler_CompileException(1, [s], lineCount);
161 numValSignFlag |= this.Flag_Sign_Signed;
163 } else if(s == "unsigned" && (mode == 0 || mode == 10)){
165 if(numValSignFlag != 0){
166 throw new ELCHNOSCompiler_CompileException(1, [s], lineCount);
168 numValSignFlag |= this.Flag_Sign_Unsigned;
170 } else if(s == "char" && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
173 if(mode == 0 || mode == 10 || mode == 11){
176 } else if(s == "int" && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
179 if(mode == 0 || mode == 10 || mode == 11){
182 } else if(s == ";" && (mode == 0 || mode == 12 || mode == 13 || mode == 19 || mode == 60 || mode == 71)){
183 if(mode == 12 || mode == 13 || mode == 19){
187 currentExpression = null;
189 } else if(mode == 60 || mode == 71){
191 currentExpression = null;
194 } else if(mode == 71){
198 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
200 } else if(s == "=" && (mode == 13)){
205 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
207 } else if(s == "*" && (mode == 11)){
210 } else if(s == "," && (mode == 18 || mode == 12 || mode == 13 || mode == 53)){
214 } else if(mode == 12 || mode == 13 || mode == 53){
216 if(mode == 12 || mode == 13){
218 } else if(mode == 53){
221 currentExpression = null;
223 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
226 } else if(s == "[" && (mode == 12)){
229 } else if(s == "]" && (mode == 15)){
232 } else if(s == "{" && (mode == 16 || mode == 54)){
236 } else if(mode == 54){
238 currentExpression = null;
241 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
243 } else if(s == "}" && (mode == 17 || mode == 18 || mode == 0)){
244 if(mode == 17 || mode == 18){
247 } else if(mode == 0){
248 if(this.structureStack.length > 0){
249 this.restoreCurrentStructure();
251 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
254 } else if(s == "(" && (mode == 51)){
257 } else if(s == ")" && (mode == 52 || mode == 53)){
260 currentExpression = null;
261 for(var j = 0, jLen = this.currentStructure.length; j < jLen; j++){
263 this.currentStructure[j].argumentIndex = j;
266 } else if(s == "@asm" && (mode == 0)){
268 s = this.separated[i].toLowerCase();
272 throw new ELCHNOSCompiler_CompileException(3, [s], lineCount);
274 } else if(s == "@end" && (mode == 70)){
277 } else if(s == "procedure" && (mode == 0)){
279 var f = new ELCHNOSCompiler_ExpressionStructure_Function(this, lineCount);
280 this.currentStructure.push(f);
281 this.changeCurrentStructure(f.structure);
282 currentExpression = f;
285 } else if(s == "inline" && (mode == 50)){
286 currentExpression.isInline = true;
287 } else if(s == "for" && (mode == 0)){
290 s = this.separated[i];
292 var f = new ELCHNOSCompiler_ExpressionStructure_Loop_for(this, lineCount);
293 this.currentStructure.push(f);
294 this.changeCurrentStructure(f.structure);
295 currentExpression = f;
297 f.initializer = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
298 i = f.initializer.readExpressionToTerminator(i, ";");
300 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
301 i = f.conditonalExpression.readExpressionToTerminator(i, ";");
303 f.incrementalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
304 i = f.incrementalExpression.readExpressionToTerminator(i, ")");
307 if(this.separated[i] != "{"){
308 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
310 currentExpression = null;
312 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
314 } else if(s == "if" && (mode == 0)){
321 s = this.separated[i];
323 var f = new ELCHNOSCompiler_ExpressionStructure_if(this, lineCount);
324 this.currentStructure.push(f);
325 this.changeCurrentStructure(f.structure);
326 currentExpression = f;
328 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
329 i = f.conditonalExpression.readExpressionToTerminator(i, ")");
332 if(this.separated[i] != "{"){
333 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
335 currentExpression = null;
337 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
340 } else if(s == "remark" && (mode == 70)){
342 var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this, lineCount);
343 this.currentStructure.push(b);
348 s = this.separated[i];
350 var len = parseInt(s, 16);
353 throw new ELCHNOSCompiler_CompileException(4, [s], lineCount);
357 s = this.separated[i];
358 if(s.length == len * 2){
359 for(var j = 0; j < len; j++){
360 b.bin.push(parseInt(s.substr(j * 2, 2), 16));
363 throw new ELCHNOSCompiler_CompileException(4, [s], lineCount);
367 if(this.separated[i] != ";"){
368 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
370 //この命令は定数のみで構成されているのでコンパイル済みとマークする
374 } else if(s == "call" && (mode == 70)){
376 var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this, lineCount);
377 this.currentStructure.push(b);
381 s = this.separated[i].toLowerCase();
382 if((s.indexOf("p") == 0) && s.length == 3){
385 var labelID = this.allocateLabelID();
386 //PLIMM(P30, labelID)
390 b.appendInstruction_UINT32BE(labelID);
395 b.bin.push(parseInt(s.substr(1),16));
397 b.appendInstruction_LB(0x01, labelID);
404 if(this.separated[i] != ";"){
405 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
407 //この命令は定数のみで構成されているのでコンパイル済みとマークする
412 throw new ELCHNOSCompiler_CompileException(0, [s], lineCount);
415 } else if(mode == 11 || mode == 52){
418 var v = new ELCHNOSCompiler_ExpressionStructure_Variable(this, lineCount);
420 v.isSigned = (numValSignFlag == 0) ? false : (0 != (numValSignFlag & this.Flag_Sign_Signed));
421 s = this.separated[i];
422 v.isPointer = (pointerCount != 0) ? true : false;
425 throw new ELCHNOSCompiler_CompileException(2, [s], lineCount);
428 this.currentStructure.push(v);
429 currentExpression = v;
433 } else if(mode == 14){
434 currentExpression.length = parseInt(s);
436 } else if(mode == 17){
438 currentExpression.initValue.push(parseInt(s));
440 } else if(mode == 50){
443 currentExpression.identifier = this.separated[i];
446 if(mode == 0 || mode == 70 || mode == 60 || mode == 71){
448 s = this.separated[i];
449 if(mode == 0 || mode == 70){
451 var f = new ELCHNOSCompiler_ExpressionStructure_Expression(this, lineCount);
452 this.currentStructure.push(f);
453 currentExpression = f;
455 currentExpression.pushIdentifier(s);
458 } else if(mode == 70){
466 //0x00-0xff: そのまま使えるバイナリ
467 //0x10000000-0x1fffffff: 未決定の仮想整数レジスタ番号
468 //0x20000000-0x2fffffff: 未決定の仮想ポインタレジスタ番号
471 //OSECPUフロントエンドコードヘッダ
472 this.bin.push(0x05, 0xe1, 0x00);
474 for(var i = 0, iLen = this.structure.length; i < iLen; i++){
475 var b = this.structure[i].createBinary();
480 this.expandBinaryString();
481 this.assignRegister();
482 this.bin.logAsHexByte();
483 var cpu = new WebCPU();
484 cpu.loadBinaryText(this.bin.stringAsHexByte());
485 cpu.staticOptimize();
486 console.log(cpu.createBackendBinaryString());
490 if(e instanceof ELCHNOSCompiler_CompileException){
491 this.env.debug(e.getMessageString());
497 compile_removeComment: function(){
499 var commentLineStartIndex = -1;
500 var commentBlockStartIndex = -1;
501 var commentBlockCount = 0;
502 var linesInCommentBlock = 0;
504 for(var i = 0, iLen = this.separated.length; i < iLen; i++){
505 var s = this.separated[i];
506 if(commentLineStartIndex == -1){
509 commentLineStartIndex = i;
514 var len = i - commentLineStartIndex;
515 this.separated.splice(commentLineStartIndex, len);
518 commentLineStartIndex = -1;
523 if(commentBlockCount == 0){
524 commentBlockStartIndex = i;
527 } else if(s == "*/"){
530 if(commentBlockCount == 0){
531 var len = i - commentBlockStartIndex + 1;
532 var padding = new Array();
533 padding.push(commentBlockStartIndex);
535 for(var j = 0, jLen = linesInCommentBlock; j < jLen; j++){
538 this.separated.splice.apply(this.separated, padding);
539 i -= len - linesInCommentBlock;
540 iLen -= len - linesInCommentBlock;
541 linesInCommentBlock = 0;
542 } else if(commentBlockCount < 0){
543 this.env.debug("Too many block comment closure [].\n");
546 } else if(commentBlockCount > 0 && s == "\n"){
547 linesInCommentBlock++;
551 raiseError: function(errno, lineCount, infoArray){
552 if(errno < 0 || this.errorMessageList.length <= errno){
553 this.env.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":Unknown\n");
555 this.env.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":" + this.errorMessageList[errno] + "\n");
558 this.env.debug(" >" + infoArray.toString() + "\n");
561 changeCurrentStructure: function(newstructure){
562 this.structureStack.push(this.currentStructure);
563 this.currentStructure = newstructure;
565 restoreCurrentStructure: function(){
566 this.currentStructure = this.structureStack.pop();
568 searchIdentifier: function(identifier){
570 var cf = function(aryobj, obj){ return (aryobj.identifier == obj) };
572 o = this.currentStructure.isIncluded(identifier, cf);
574 for(var i = this.structureStack.length - 1; i >= 0; i--){
575 o = this.structureStack[i].isIncluded(identifier, cf);
583 isOperator: function(s){
599 allocateLabelID: function(){
601 return this.nextLabelID - 1;
603 virtualIntegerRegisterOffset: 0x10000000,
604 allocateIntegerRegister: function(owner){
605 //レジスタテーブルは先頭から番号の小さい順につめて格納する。
607 //0x10000000-0x1fffffff: 未決定の仮想整数レジスタ番号
609 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
610 if(this.integerRegisterAllocationTable[i][0] != i + this.virtualIntegerRegisterOffset){
613 this.integerRegisterAllocationTable.splice(i, 0, [i + this.virtualIntegerRegisterOffset, owner]);
618 //途中に空いているレジスタはなかったので追加
619 this.integerRegisterAllocationTable.push([i + this.virtualIntegerRegisterOffset, owner]);
621 return i + this.virtualIntegerRegisterOffset;
623 freeIntegerRegister: function(regID, owner){
624 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
625 if(this.integerRegisterAllocationTable[i][0] == regID){
628 if(this.integerRegisterAllocationTable[i][1] == owner){
630 this.integerRegisterAllocationTable.splice(i, 1);
636 throw new ELCHNOSCompiler_CompileException(0, ["freeIntegerRegister:regID not found."], -1);
639 virtualPointerRegisterOffset: 0x20000000,
640 allocatePointerRegister: function(owner){
641 //レジスタテーブルは先頭から番号の小さい順につめて格納する。
643 //0x20000000-0x2fffffff: 未決定の仮想ポインタレジスタ番号
645 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
646 if(this.pointerRegisterAllocationTable[i][0] != i + this.virtualPointerRegisterOffset){
648 this.pointerRegisterAllocationTable.splice(i, 0, [i + this.virtualPointerRegisterOffset, owner]);
652 //途中に空いているレジスタはなかったので追加
653 this.pointerRegisterAllocationTable.push([i + this.virtualPointerRegisterOffset, owner]);
655 return i + this.virtualPointerRegisterOffset;
657 freePointerRegister: function(regID, owner){
658 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
659 if(this.pointerRegisterAllocationTable[i][0] == regID){
662 if(this.pointerRegisterAllocationTable[i][1] == owner){
664 this.pointerRegisterAllocationTable.splice(i, 1);
670 throw new ELCHNOSCompiler_CompileException(0, ["freePointerRegister:regID not found."], -1);
673 freeAllRegisterOfOwner: function(owner){
674 //ownerが確保しているレジスタをすべて解放する
676 for(var i = 0, iLen = this.integerRegisterAllocationTable.length; i < iLen; i++){
677 if(this.integerRegisterAllocationTable[i][1] == owner){
679 this.integerRegisterAllocationTable.splice(i, 1);
684 for(var i = 0, iLen = this.pointerRegisterAllocationTable.length; i < iLen; i++){
685 if(this.pointerRegisterAllocationTable[i][1] == owner){
687 this.pointerRegisterAllocationTable.splice(i, 1);
692 expandBinaryString: function(){
695 var aryStack = new Array();
696 var indexStack = new Array();
697 for(var i = 0; ; i++){
698 if(ary[i] === undefined){
699 ary = aryStack.pop();
700 if(ary === undefined){
703 i = indexStack.pop();
705 if(ary[i] instanceof Array){
707 indexStack.push(i + 1);
710 } else if(ary[i] !== undefined){
716 assignRegister: function(){
717 for(var i = 0, iLen = this.bin.length; i < iLen; i++){
718 if(this.bin[i] > 0xff){
719 if(this.virtualIntegerRegisterOffset <= this.bin[i] && this.bin[i] <= this.virtualIntegerRegisterOffset + 0x1f){
720 //R00-R1fは無条件で割り当ててOK
721 this.bin[i] -= this.virtualIntegerRegisterOffset;
722 } else if(this.virtualPointerRegisterOffset <= this.bin[i] && this.bin[i] <= this.virtualPointerRegisterOffset + 0x1f - 1){
723 //P01-P1fは無条件で割り当ててOK
724 this.bin[i] -= this.virtualPointerRegisterOffset;
727 throw new ELCHNOSCompiler_CompileException(0, ["Sorry, but no more register."]);
732 saveBinary: function(){
733 var m = this.env.IOManager;
735 var v = new Uint8Array(this.bin);
736 var d = new Blob([v]);
738 m.showDownloadLink(d);