1 // ELCHNOSCompiler for AI004
3 function ELCHNOSCompiler(env){
9 this.structure = new Array();
10 this.currentStructure = this.structure;
11 this.structureStack = new Array();
13 //0はエントリポイント(main)用に予約
16 ELCHNOSCompiler.prototype = {
50 "Incompatible value attribute.",
51 "Unexpected identifier.",
52 "Unknown assembly language type.",
53 "Invalid expression of OSECPU Binary."
56 Flag_Sign_Signed : 0x00000001,
57 Flag_Sign_Unsigned : 0x00000002,
59 compile: function(str){
60 this.line = str.split("\n");
62 this.separated = str.splitByArraySeparatorSeparatedLong(this.keyWordList);
64 this.compile_removeComment();
67 this.separated.removeAllObject("\t");
68 this.separated.removeAllObject(" ");
70 console.log(this.separated);
73 var currentExpression = null;
74 var numValSignFlag = 0;
79 //var DestinationOperand = null;
81 var unexpected = false;
88 //10: 変数・定数の前置属性・型・または識別子
89 //11: 変数・定数の識別子またはポインタ属性
90 //12: 変数・定数の後置属性・初期化式または終端記号、もしくは連続した変数宣言の区切り
91 //13: 変数・定数の初期化式または終端記号、もしくは連続した変数宣言の区切り
107 //70: OSECPUアセンブリ直接記述モード
108 //71: OSECPUアセンブリ評価式の内容または終端記号
109 for(var i = 0, iLen = this.separated.length; i < iLen; i++){
110 var s = this.separated[i].toLowerCase();
111 //this.env.debug((i + 1) + ":" + s + "\n");
118 } else if(s == "signed" && (mode == 0 || mode == 10)){
120 if(numValSignFlag == 0){
121 numValSignFlag |= this.Flag_Sign_Signed;
127 } else if(s == "unsigned" && (mode == 0 || mode == 10)){
129 if(numValSignFlag == 0){
130 numValSignFlag |= this.Flag_Sign_Unsigned;
136 } else if(s == "char" && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
139 if(mode == 0 || mode == 10 || mode == 11){
142 } else if(s == "int" && (mode == 0 || mode == 10 || mode == 11 || mode == 52)){
145 if(mode == 0 || mode == 10 || mode == 11){
148 } else if(s == ";" && (mode == 0 || mode == 12 || mode == 13 || mode == 19 || mode == 60 || mode == 71)){
149 if(mode == 12 || mode == 13 || mode == 19){
153 console.log(currentExpression);
154 currentExpression = null;
156 } else if(mode == 60 || mode == 71){
158 console.log(currentExpression);
159 currentExpression = null;
162 } else if(mode == 71){
168 } else if(s == "=" && (mode == 13)){
175 } else if(s == "*" && (mode == 11)){
178 } else if(s == "," && (mode == 18 || mode == 12 || mode == 13 || mode == 53)){
182 } else if(mode == 12 || mode == 13 || mode == 53){
184 if(mode == 12 || mode == 13){
186 } else if(mode == 53){
189 console.log(currentExpression);
190 currentExpression = null;
195 } else if(s == "[" && (mode == 12)){
198 } else if(s == "]" && (mode == 15)){
201 } else if(s == "{" && (mode == 16 || mode == 54)){
205 } else if(mode == 54){
207 currentExpression = null;
212 } else if(s == "}" && (mode == 17 || mode == 18 || mode == 0)){
213 if(mode == 17 || mode == 18){
216 } else if(mode == 0){
217 if(this.structureStack.length > 0){
218 console.log(this.currentStructure);
219 this.restoreCurrentStructure();
224 } else if(s == "(" && (mode == 51)){
227 } else if(s == ")" && (mode == 52 || mode == 53)){
230 console.log(currentExpression);
231 currentExpression = null;
232 for(var j = 0, jLen = this.currentStructure.length; j < jLen; j++){
234 this.currentStructure[j].argumentIndex = j;
237 } else if(s == "@asm" && (mode == 0)){
239 s = this.separated[i].toLowerCase();
246 } else if(s == "@end" && (mode == 70)){
249 } else if(s == "procedure" && (mode == 0)){
251 var f = new ELCHNOSCompiler_ExpressionStructure_Function(this);
252 this.currentStructure.push(f);
253 this.changeCurrentStructure(f.structure);
254 currentExpression = f;
257 } else if(s == "inline" && (mode == 50)){
258 currentExpression.isInline = true;
259 } else if(s == "for" && (mode == 0)){
270 s = this.separated[i];
272 var f = new ELCHNOSCompiler_ExpressionStructure_Loop_for(this);
273 this.currentStructure.push(f);
274 this.changeCurrentStructure(f.structure);
275 currentExpression = f;
277 f.initializer = new ELCHNOSCompiler_ExpressionStructure_Expression(this);
279 s = this.separated[i];
283 f.initializer.pushIdentifier(s);
288 console.log(f.initializer);
291 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this);
293 s = this.separated[i];
297 f.conditonalExpression.pushIdentifier(s);
302 console.log(f.conditonalExpression);
306 f.incrementalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this);
308 s = this.separated[i];
312 f.incrementalExpression.pushIdentifier(s);
317 console.log(f.incrementalExpression);
322 if(this.separated[i] != "{"){
325 currentExpression = null;
330 } else if(s == "if" && (mode == 0)){
337 s = this.separated[i];
339 var f = new ELCHNOSCompiler_ExpressionStructure_if(this);
340 this.currentStructure.push(f);
341 this.changeCurrentStructure(f.structure);
342 currentExpression = f;
344 f.conditonalExpression = new ELCHNOSCompiler_ExpressionStructure_Expression(this);
346 s = this.separated[i];
350 f.conditonalExpression.pushIdentifier(s);
355 console.log(f.conditonalExpression);
359 if(this.separated[i] != "{"){
362 currentExpression = null;
368 } else if(s == "remark" && (mode == 70)){
370 var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this);
371 this.currentStructure.push(b);
376 s = this.separated[i];
378 var len = parseInt(s, 16);
387 s = this.separated[i];
388 if(s.length == len * 2){
389 for(var j = 0; j < len; j++){
390 b.bin.push(parseInt(s.substr(j * 2, 2), 16));
400 if(this.separated[i] != ";"){
403 //この命令は定数のみで構成されているのでコンパイル済みとマークする
408 } else if(s == "call" && (mode == 70)){
410 var b = new ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(this);
411 this.currentStructure.push(b);
415 s = this.separated[i].toLowerCase();
416 if((s.indexOf("p") == 0) && s.length == 3){
419 var labelID = this.allocateLabelID();
420 //PLIMM(P30, labelID)
424 b.bin.push((labelID >> 24) & 0xFF);
425 b.bin.push((labelID >> 16) & 0xFF);
426 b.bin.push((labelID >> 8) & 0xFF);
427 b.bin.push(labelID & 0xFF);
432 b.bin.push(parseInt(s.substr(1),16));
437 b.bin.push((labelID >> 24) & 0xFF);
438 b.bin.push((labelID >> 16) & 0xFF);
439 b.bin.push((labelID >> 8) & 0xFF);
440 b.bin.push(labelID & 0xFF);
447 if(this.separated[i] != ";"){
450 //この命令は定数のみで構成されているのでコンパイル済みとマークする
459 } else if(mode == 11 || mode == 52){
462 var v = new ELCHNOSCompiler_ExpressionStructure_Variable(this);
464 v.isSigned = (numValSignFlag == 0) ? false : (0 != (numValSignFlag & this.Flag_Sign_Signed));
465 s = this.separated[i];
466 v.isPointer = (pointerCount != 0) ? true : false;
471 this.currentStructure.push(v);
472 currentExpression = v;
480 } else if(mode == 14){
481 currentExpression.length = parseInt(s);
483 } else if(mode == 17){
485 currentExpression.initValue.push(parseInt(s));
487 } else if(mode == 50){
490 currentExpression.identifier = this.separated[i];
493 if(mode == 0 || mode == 70 || mode == 60 || mode == 71){
495 s = this.separated[i];
496 if(mode == 0 || mode == 70){
498 var f = new ELCHNOSCompiler_ExpressionStructure_Expression(this);
499 this.currentStructure.push(f);
500 currentExpression = f;
502 currentExpression.pushIdentifier(s);
506 } else if(mode == 70){
514 s = this.separated[i];
515 this.raiseError(errno, lineCount, [s, mode]);
516 console.log(this.structure);
520 console.log(this.structure);
522 compile_removeComment: function(){
524 var commentLineStartIndex = -1;
525 var commentBlockStartIndex = -1;
526 var commentBlockCount = 0;
527 var linesInCommentBlock = 0;
529 for(var i = 0, iLen = this.separated.length; i < iLen; i++){
530 var s = this.separated[i];
531 if(commentLineStartIndex == -1){
534 commentLineStartIndex = i;
539 var len = i - commentLineStartIndex;
540 this.separated.splice(commentLineStartIndex, len);
543 commentLineStartIndex = -1;
548 if(commentBlockCount == 0){
549 commentBlockStartIndex = i;
552 } else if(s == "*/"){
555 if(commentBlockCount == 0){
556 var len = i - commentBlockStartIndex + 1;
557 var padding = new Array();
558 padding.push(commentBlockStartIndex);
560 for(var j = 0, jLen = linesInCommentBlock; j < jLen; j++){
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.env.debug("Too many block comment closure [].\n");
571 } else if(commentBlockCount > 0 && s == "\n"){
572 linesInCommentBlock++;
576 raiseError: function(errno, lineCount, infoArray){
577 if(errno < 0 || this.errorMessageList.length <= errno){
578 this.env.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":Unknown\n");
580 this.env.debug(lineCount + ":Error" + errno.toString().toUpperCase() + ":" + this.errorMessageList[errno] + "\n");
583 this.env.debug(" >" + infoArray.toString() + "\n");
586 changeCurrentStructure: function(newstructure){
587 this.structureStack.push(this.currentStructure);
588 this.currentStructure = newstructure;
590 restoreCurrentStructure: function(){
591 this.currentStructure = this.structureStack.pop();
593 searchIdentifier: function(identifier){
595 var cf = function(aryobj, obj){ return (aryobj.identifier == obj) };
597 o = this.currentStructure.isIncluded(identifier, cf);
599 for(var i = this.structureStack.length - 1; i >= 0; i--){
600 o = this.structureStack[i].isIncluded(identifier, cf);
608 isOperator: function(s){
624 allocateLabelID: function(){
626 return this.nextLabelID - 1;
630 function ELCHNOSCompiler_ExpressionStructure_Variable(compiler){
631 this.compiler = compiler;
634 this.isSigned = false;
635 this.isPointer = false;
636 this.identifier = null;
637 this.initValue = new Array();
638 //引数として渡されるものであれば、引数の左から数えて何番目かが入る。
639 this.argumentIndex = -1;
641 ELCHNOSCompiler_ExpressionStructure_Variable.prototype = {
645 function ELCHNOSCompiler_ExpressionStructure_Function(compiler){
646 this.compiler = compiler;
647 this.structure = new Array();
648 this.identifier = null;
650 ELCHNOSCompiler_ExpressionStructure_Function.prototype = {
654 function ELCHNOSCompiler_ExpressionStructure_Loop_for(compiler){
655 this.compiler = compiler;
656 this.structure = new Array();
657 this.initializer = null;
658 this.conditonalExpression = null;
659 this.incrementalExpression = null;
660 this.isInline = false;
662 ELCHNOSCompiler_ExpressionStructure_Loop_for.prototype = {
666 function ELCHNOSCompiler_ExpressionStructure_if(compiler){
667 this.compiler = compiler;
668 this.structure = new Array();
669 this.conditonalExpression = null;
671 ELCHNOSCompiler_ExpressionStructure_if.prototype = {
675 function ELCHNOSCompiler_ExpressionStructure_Expression(compiler){
676 this.compiler = compiler;
677 this.evalStack = new Array();
678 this.evalOperatorStack = new Array();
679 this.lastOperatorPriority = ELCHNOSCompiler_ExpressionStructure_Expression.prototype.operatorPriorityList.length;
680 this.startBracketIndexStack = new Array();
682 ELCHNOSCompiler_ExpressionStructure_Expression.prototype = {
683 //drawLine(1 + 4, x0, y0, x1, y1, col);
684 //-> drawLine 1 4 + x0 y0 x1 y1 col ()
685 //f(g(1 + 4 * (2 - 3)), 4 * 2 + 1);
686 //-> f g 1 4 2 3 - * + () 4 2 * 1 + ()
688 operatorPriorityList: [
698 pushOperand: function(identifier){
700 //数値ならば数値自体もしくは等価な文字列
701 //オブジェクトであればそのオブジェクトのインスタンスを渡す
702 this.evalStack.push(identifier);
704 pushOperator: function(operator){
708 //開き括弧のevalOperatorStack内でのIndexを記憶
709 if(this.evalStack[this.evalStack.length - 1] instanceof ELCHNOSCompiler_ExpressionStructure_Function){
711 //-(index + 1)で記憶しておく
712 this.startBracketIndexStack.push(-(this.evalOperatorStack.length + 1));
715 this.startBracketIndexStack.push(this.evalOperatorStack.length);
717 this.evalOperatorStack.push(operator);
718 } else if(operator == ")"){
720 //開き括弧までのOperatorを順にevalStackにpushして、括弧内の式を完結させる
721 var i = this.startBracketIndexStack.pop();
723 var o = this.evalOperatorStack.pop();
726 } else if(o === undefined){
728 this.compiler.unexpected = true;
731 this.evalStack.push(o);
735 this.evalStack.push("()");
737 } else if(operator == ","){
740 var o = this.evalOperatorStack.pop();
743 this.evalOperatorStack.push(o);
745 } else if(o === undefined){
749 this.evalStack.push(o);
753 var p = this.getOperatorPriority(operator);
754 if(this.lastOperatorPriority >= p){
756 this.evalOperatorStack.push(operator);
758 //優先順位がより高い演算子を先に積んでおき、そのあと自分をとっておく
759 for(var i = 0, iLen = this.evalOperatorStack.length; i < iLen; i++){
760 var o = this.evalOperatorStack.pop();
761 if(this.getOperatorPriority(o) < p){
762 this.evalStack.push(o);
764 this.evalOperatorStack.push(o);
768 this.evalOperatorStack.push(operator);
770 this.lastOperatorPriority = p;
773 pushIdentifier: function(identifier){
775 //自動的にオペランドか演算子かを判別し、適切にプッシュする。
776 //識別子は大文字小文字を区別できる状態で渡すようにする
779 if(this.isOperator(identifier)){
781 this.pushOperator(identifier);
783 var o = this.compiler.searchIdentifier(identifier);
787 } else if(!isNaN(identifier)){
789 this.pushOperand(parseInt(identifier));
792 var s = identifier.toLowerCase();
793 if((s.indexOf("r") == 0 || s.indexOf("p") == 0) && s.length == 3){
797 this.compiler.unexpected = true;
802 getOperatorPriority: function(operator){
803 for(var i = 0, iLen = this.operatorPriorityList.length; i < iLen; i++){
804 if(this.operatorPriorityList[i] == operator){
810 isOperator: function(s){
828 function ELCHNOSCompiler_ExpressionStructure_OSECPUBinary(compiler){
829 this.compiler = compiler;
830 this.bin = new Array();
831 this.isCompiled = false;
833 ELCHNOSCompiler_ExpressionStructure_OSECPUBinary.prototype = {