Changeset 22454

Show
Ignore:
Timestamp:
11/01/08 00:02:06 (5 years ago)
Author:
fujidig
Message:

goto, gosub, exgoto, on を instruction 化。

Location:
lang/javascript/hsp-on-js/trunk/src
Files:
4 modified

Legend:

Unmodified
Added
Removed
  • lang/javascript/hsp-on-js/trunk/src/builtin-funcs.js

    r22332 r22454  
    77 
    88BuiltinFuncs[Token.Type.PROGCMD] = { 
    9         0x00: function goto_(label) { 
    10                 this.scanArgs(arguments, 'l'); 
    11                 this.pc = label.toValue().pos - 1; 
    12         }, 
    13         0x01: function gosub(label) { 
    14                 this.scanArgs(arguments, 'l'); 
    15                 this.subroutineJump(label.toValue()); 
    16         }, 
    179        0x07: function wait(n) { 
    1810                this.scanArgs(arguments, 'N'); 
     
    6860                default: 
    6961                        throw new HSPError(ErrorCode.UNSUPPORTED_FUNCTION); 
    70                 } 
    71         }, 
    72         0x18: function exgoto(v, mode, b, label) { 
    73                 this.scanArgs(arguments, 'vnnl'); 
    74                 this.scanArg(v, 'i'); 
    75                 var a = v.toIntValue()._value; 
    76                 mode = mode.toIntValue()._value; 
    77                 b = b.toIntValue()._value; 
    78                 label = label.toValue(); 
    79                 if(mode >= 0) { 
    80                         if(a >= b) { 
    81                                 this.pc = label.pos - 1; 
    82                         } 
    83                 } else { 
    84                         if(a <= b) { 
    85                                 this.pc = label.pos - 1; 
    86                         } 
    87                 } 
    88         }, 
    89         0x19: function on(n, jumpType) { 
    90                 this.scanArgs(arguments, 'Njl*'); 
    91                 n = n ? n.toIntValue()._value : 0; 
    92                 if(!(0 <= n && n < arguments.length - 2)) { 
    93                         return; 
    94                 } 
    95                 var label = arguments[n + 2].toValue(); 
    96                 if(jumpType == JumpType.GOTO) { 
    97                         this.pc = label.pos - 1; 
    98                 } else { 
    99                         this.subroutineJump(label); 
    10062                } 
    10163        } 
  • lang/javascript/hsp-on-js/trunk/src/compiler.js

    r22332 r22454  
    127127                                this.tokensPos += 2; 
    128128                        } else { 
    129                                 this.compileCommand(sequence); 
     129                                this.tokensPos ++; 
     130                                var argc = this.compileParameters(sequence); 
     131                                if(argc != 1) throw this.error('goto の引数の数が違います', token); 
     132                                this.pushNewInsn(sequence, Instruction.Code.GOTO_EXPR, [], token); 
     133                        } 
     134                        break; 
     135                case 0x01: // gosub 
     136                        var labelToken = this.ax.tokens[this.tokensPos + 1]; 
     137                        if(labelToken && labelToken.type == Token.Type.LABEL && !labelToken.ex2 && (!this.ax.tokens[this.tokensPos + 2] || this.ax.tokens[this.tokensPos + 2].ex1)) { 
     138                                this.pushNewInsn(sequence, Instruction.Code.GOSUB, 
     139                                                 [this.labels[labelToken.code]]); 
     140                                this.tokensPos += 2; 
     141                        } else { 
     142                                this.tokensPos ++; 
     143                                var argc = this.compileParameters(sequence); 
     144                                if(argc != 1) throw this.error('gosub の引数の数が違います', token); 
     145                                this.pushNewInsn(sequence, Instruction.Code.GOSUB_EXPR, [], token); 
    130146                        } 
    131147                        break; 
     
    219235                        if(argc != 1) throw this.error('delmod の引数の数が違います', token); 
    220236                        this.pushNewInsn(sequence, Instruction.Code.DELMOD, [], token); 
     237                        break; 
     238                case 0x18: // exgoto 
     239                        this.tokensPos ++; 
     240                        // exgoto <添字指定のない静的変数>, p2, p3, <ラベルリテラル> を最適化 
     241                        var pos = this.tokensPos; 
     242                        var varToken = this.ax.tokens[pos]; 
     243                        if(!varToken.ex1 && !varToken.ex2 && 
     244                           varToken.type == Token.Type.VAR && this.ax.tokens[pos + 1].ex2) { 
     245                                pos ++; 
     246                                var secondParamPos = pos; 
     247                                pos += this.skipParameter(pos); 
     248                                var thirdParamPos = pos; 
     249                                pos += this.skipParameter(pos); 
     250                                var labelToken = this.ax.tokens[pos]; 
     251                                if(labelToken && !labelToken.ex1 && 
     252                                   labelToken.type == Token.Type.LABEL && this.ax.tokens[pos+1]) { 
     253                                        // p2 が整数リテラルの場合はさらに最適化 
     254                                        if(secondParamPos + 1 == thirdParamPos && this.ax.tokens[secondParamPos].type == Token.Type.INUM) { 
     255                                                this.tokensPos = thirdParamPos; 
     256                                                this.compileParameter(sequence); 
     257                                                if(this.ax.tokens[secondParamPos].code >= 0) { 
     258                                                        this.pushNewInsn(sequence, Instruction.Code.EXGOTO_OPT2, 
     259                                                                         [varToken.code, this.labels[labelToken.code]], token); 
     260                                                } else { 
     261                                                        this.pushNewInsn(sequence, Instruction.Code.EXGOTO_OPT3, 
     262                                                                         [varToken.code, this.labels[labelToken.code]], token); 
     263                                                } 
     264                                                this.tokensPos = pos + 1; 
     265                                                break; 
     266                                        } 
     267                                        this.tokensPos = secondParamPos; 
     268                                        this.compileParameter(sequence); 
     269                                        this.compileParameter(sequence); 
     270                                        this.pushNewInsn(sequence, Instruction.Code.EXGOTO_OPT1, 
     271                                                         [varToken.code, this.labels[labelToken.code]], token); 
     272                                        this.tokensPos = pos + 1; 
     273                                        break; 
     274                                } 
     275                        } 
     276                        var argc = this.compileParameters(sequence); 
     277                        if(argc != 4) throw this.error('exgoto の引数の数が違います', token); 
     278                        this.pushNewInsn(sequence, Instruction.Code.EXGOTO, [], token); 
     279                        break; 
     280                case 0x19: // on 
     281                        this.tokensPos ++; 
     282                        var paramToken = this.ax.tokens[this.tokensPos]; 
     283                        if(paramToken.ex1 || paramToken.ex2) { 
     284                                throw this.error('パラメータは省略できません', token); 
     285                        } 
     286                        this.compileParameter(sequence); 
     287                        var jumpTypeToken = this.ax.tokens[this.tokensPos]; 
     288                        if(jumpTypeToken.ex1 || jumpTypeToken.type != Token.Type.PROGCMD || jumpTypeToken.code > 1) { 
     289                                throw this.error('goto / gosub が指定されていません', token); 
     290                        } 
     291                        var isGosub = jumpTypeToken.code == 1; 
     292                        this.tokensPos ++; 
     293                        var argc = this.compileParametersSub(sequence); 
     294                        this.pushNewInsn(sequence, Instruction.Code.ON, [argc, isGosub], token); 
    221295                        break; 
    222296                default: 
     
    347421                        token = this.ax.tokens[this.tokensPos]; 
    348422                        if(token && token.ex2) return; 
     423                } 
     424        }, 
     425        skipParameter: function skipParameter(pos) { 
     426                var size = 0; 
     427                var parenLevel = 0; 
     428                while(true) { 
     429                        var token = this.ax.tokens[pos + size]; 
     430                        if(!token || token.ex1) return size; 
     431                        if(token.type == Token.Type.MARK) { 
     432                                switch(token.val) { 
     433                                case 40: 
     434                                        parenLevel ++; 
     435                                        break; 
     436                                case 41: 
     437                                        if(parenLevel == 0) return size; 
     438                                        parenLevel --; 
     439                                        if(parenLevel == 0) return size + 1; 
     440                                        break; 
     441                                case 63: 
     442                                        return size + 1; 
     443                                        break; 
     444                                } 
     445                        } 
     446                        size ++; 
     447                        token = this.ax.tokens[pos + size]; 
     448                        if(parenLevel == 0 && token && token.ex2) { 
     449                                return size; 
     450                        } 
    349451                } 
    350452        }, 
  • lang/javascript/hsp-on-js/trunk/src/evaluator.js

    r22332 r22454  
    389389                        } 
    390390                        break; 
     391                case Instruction.Code.GOSUB: 
     392                        this.subroutineJump(insn.opts[0].pos); 
     393                        break; 
     394                case Instruction.Code.GOTO_EXPR: 
     395                        this.pc = this.scanArg(this.stack.pop(), 'l').toValue().pos - 1; 
     396                        break; 
     397                case Instruction.Code.GOSUB_EXPR: 
     398                        this.subroutineJump(this.scanArg(this.stack.pop(), 'l').toValue().pos); 
     399                        break; 
     400                case Instruction.Code.EXGOTO: 
     401                        var pos = this.scanArg(this.stack.pop(), 'l').toValue().pos; 
     402                        var b = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     403                        var mode = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     404                        var a = this.scanArg(this.scanArg(this.stack.pop(), 'v'), 'i').toIntValue()._value; 
     405                        if(mode >= 0) { 
     406                                if(a >= b) this.pc = pos - 1; 
     407                        } else { 
     408                                if(a <= b) this.pc = pos - 1; 
     409                        } 
     410                        break; 
     411                case Instruction.Code.EXGOTO_OPT1: 
     412                        var a = this.scanArg(this.variables[insn.opts[0]].at(0), 'i').toIntValue()._value; 
     413                        var pos = insn.opts[1].pos; 
     414                        var b = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     415                        var mode = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     416                        if(mode >= 0) { 
     417                                if(a >= b) this.pc = pos - 1; 
     418                        } else { 
     419                                if(a <= b) this.pc = pos - 1; 
     420                        } 
     421                        break; 
     422                case Instruction.Code.EXGOTO_OPT2: 
     423                        var a = this.scanArg(this.variables[insn.opts[0]].at(0), 'i').toIntValue()._value; 
     424                        var pos = insn.opts[1].pos; 
     425                        var b = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     426                        if(a >= b) this.pc = pos - 1; 
     427                        break; 
     428                case Instruction.Code.EXGOTO_OPT3: 
     429                        var a = this.scanArg(this.variables[insn.opts[0]].at(0), 'i').toIntValue()._value; 
     430                        var pos = insn.opts[1].pos; 
     431                        var b = this.scanArg(this.stack.pop(), 'n').toIntValue()._value; 
     432                        if(a <= b) this.pc = pos - 1; 
     433                        break; 
     434                case Instruction.Code.ON: 
     435                        var argc = insn.opts[0]; 
     436                        var isGosub = insn.opts[1]; 
     437                        for(var i = this.stack.length - argc, l = this.stack.length; i < l; i ++) { 
     438                                this.scanArg(this.stack[i], 'l'); 
     439                        } 
     440                        var n = this.scanArg(this.stack[this.stack.length - argc - 1], 'n').toIntValue()._value; 
     441                        if(!(0 <= n && n < argc)) break; 
     442                        var pos = this.stack[this.stack.length - argc + n].toValue().pos; 
     443                        this.stack.length -= argc + 1; 
     444                        if(isGosub) { 
     445                                this.subroutineJump(pos); 
     446                        } else { 
     447                                this.pc = pos - 1; 
     448                        } 
     449                        break; 
    391450                default: 
    392451                        throw new Error("未対応の命令コード: "+insn.code); 
     
    465524                this.pc = userDefFunc.label.pos - 1; 
    466525        }, 
    467         subroutineJump: function subroutineJump(label) { 
     526        subroutineJump: function subroutineJump(pos) { 
    468527                if(this.frameStack.length >= 256) { 
    469528                        throw new HSPError(ErrorCode.STACK_OVERFLOW); 
    470529                } 
    471530                this.frameStack.push(new Frame(this.pc + 1, null, null)); 
    472                 this.pc = label.pos - 1; 
     531                this.pc = pos - 1; 
    473532        }, 
    474533        popIndices: function popIndices(argc) { 
     
    654713                if(arg == undefined) { 
    655714                        if(isOptionalArguments) { 
    656                                 return; 
     715                                return arg; 
    657716                        } else { 
    658717                                throw new HSPError(ErrorCode.NO_DEFAULT); 
     
    708767                        break; 
    709768                } 
     769                return arg; 
    710770        } 
    711771}; 
  • lang/javascript/hsp-on-js/trunk/src/instruction.js

    r22332 r22454  
    5656        'BREAK', 
    5757        'FOREACH', 
    58         'EACHCHK' 
     58        'EACHCHK', 
     59        'GOSUB', 
     60        'GOTO_EXPR', 
     61        'GOSUB_EXPR', 
     62        'EXGOTO', 
     63        'EXGOTO_OPT1', 
     64        'EXGOTO_OPT2', 
     65        'EXGOTO_OPT3', 
     66        'ON' 
    5967]; 
    6068