js实现blockly后台解释器,可以单步执行,可以调用c/c++函数

实现原理

解析blockly语法树,使用js管理状态,实际使用lua执行,c/c++函数调用使用lua调用c/c++函数的能力

可以单行执行

已实现if功能

TODO

for循环功能 函数功能

单步执行效果图

直接执行效果图

源代码

javascript 复制代码
//0 暂停 1 单步执行 2 断点 
//创建枚举
var AstStatus = {
    PAUSE : 0,
    STEP :1,
    BREAK : 2,
    PASS:3
}

class ASTInterpreter {
    constructor(ast,funcs) {
        //执行状态,暂停 单步执行 断点
        this.status = AstStatus.STEP;
        //当前节点
        this.currentBlock = null;

        this.ast = ast;
        this.variables = {};
        this.userFuns={};
        this.functions=new Set();
        this.initVariables();
        this.initFunc(funcs);

        this.callback=console.log
    }

    addEventCallback(func){
        this.callback=func
    }

    initFunc(funcs){
        for (let item of funcs) {
            this.addFunction(item)
        }
    }

    initVariables() {
        let vars = this.ast.variables;
        for (let i = 0; i < vars.length; i++) {
            const varDef = vars[i];
            const varId = varDef.id;
            const varName = varDef.name;
            this.variables[varId] = varName;
        }
    }


    stepFunc(){
        this.executeBlock(this.currentBlock)
    }

    addFunction(key) {
        this.functions.add(key);
    }

    getBlockType(block){
        let type = block.type
        if(this.functions.has(type)){
            //说明是自定义函数
            return 'function'
        }else{
            return type
        }
    }

    execute() {
        if (this.ast && this.ast.blocks && this.ast.blocks.blocks) {
            const blocks = this.ast.blocks.blocks;
            for (let i = 0; i < blocks.length; i++) {
                const block = blocks[i];
                this.executeBlock(block);
            }
        }
    }

    executeBlock(block) {
        if (!block) return;



        let btype=this.getBlockType(block)
        let code = ''
        switch (btype) {
            case 'variables_set':
                //变量id
                const varId = block.fields.VAR.id;
                //解析右值
                const value = this.evaluateInput(block.inputs.VALUE.block);
                code +=this.variables[varId]+'='+value;
                break;
            case 'function':
                code += this.executeFunction(block);
                break;
            case 'controls_if':
                this.executeIf(block);
                break;
            case 'procedures_callnoreturn':
                
                this.executeCallNoReturn(block);
                break;
            case 'procedures_defnoreturn':
                this.executeDefNoReturn(block);
                break;
            default:
                console.error(`Unsupported block type: ${block.type}`);
        }
        if(code){
            this.execLine(code,block.id)
        }
        // Execute next block
        if (block.next && block.next.block) {
            this.currentBlock = block.next.block;
            if(this.status == AstStatus.STEP||this.status == AstStatus.PAUSE){
                
            }else{
                this.executeBlock(block.next.block);
            }
            
        }
    }

    //自定义函数定义 用户自己定义的函数不是系统的函数
    executeDefNoReturn(block){
        this.userFuns[block.fields.NAME]={
            params:block.extraState.params,
            block:block.inputs.STACK.block
        }
        return ''
    }

    //调用自定义函数 调用自己定义的函数
    executeCallNoReturn(block){
        //这里要隔离,不能影响其他变量,函数参数怎么传递,返回值怎么传递是个问题
        let extraInfo = block.extraState
        let name = extraInfo.name
        let args = block.inputs
        return ''
    }

    async executeIf(block) {
        let extraInfo = block.extraState
        let ifprefix = 'IF'
        let doprefix = 'DO'
        let isElse = false
        let isEIf = false
        if(extraInfo){
            //说明有else
            isElse=true
            if(extraInfo.elseIfCount){
                //说明有else if
                isEIf = true
            }
        }

        let idx=[0];
        if(isEIf){
            //extraInfo.elseIfCount是一个int类型,我要直线这个int类型的值
            for (let i = 0; i < extraInfo.elseIfCount; i++) {
                idx.push(i+1)
            }
        }

        let isMatch = false
        for (let i = 0; i < idx.length; i++) {
            const index = idx[i];
            const condition = await this.evaluateCondition(block.inputs[ifprefix + index].block)
            if (condition) {
                //满足条件执行对应分支
                this.executeBlock(block.inputs[doprefix + index].block)
                isMatch=true
                break
            }
        }

        //说明都不匹配 执行else block
        if(isElse&&!isMatch){
            this.executeBlock(block.inputs.ELSE.block)
        }

        return ''
    }



    executeFunction(block){
        if (!block) return;
        let funcName=block.type
        let params=block.inputs
        let paramArr=[]
        for(let key in params){
            let param=params[key]
            if(param.block){
                let paramValue=this.evaluateInput(param.block)
                paramArr.push(paramValue)
            }
        }
        //解析函数的参数名
        //执行自定义函数
        console.log(1,params)
        return `${funcName}(${paramArr.join(',')})`
    }

    generateMixed(n) {
        let chars = ['A','B','C','D','E','F','G','H','I','J','K','L','M',
                    'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'];
        let res = "";
        for(let i = 0; i < n ; i++) {
           let id = Math.floor(Math.random()*chars.length);
           res += chars[id];
        }
        return res;
    }

    execLine(code,id){
        //发送到服务器获取结果
        //执行事件
        this.callback({
            id,
            name:'call'
        })
        console.log('exec '+code)
    }

    async evaluateCondition(block){
        if (!block) return;

        let op = block.fields.OP
        let left = this.evaluateInput(block.inputs.A.block)
        let right = this.evaluateInput(block.inputs.B.block)
        //发送到服务器获取结果
        //随机生成变量,服务器会返回这个变量值,这个变量值是boolean类型
        let key = this.generateMixed(5)
        switch (op) {
            case 'EQ':
                op = '=='
                break;
            case 'NEQ':
                op = '!='
                break;
            case 'LT':
                op = '<'
                break;
            case 'LTE':
                op = '<='
                break;
            case 'GT':
                op = '>'
                break;
            case 'GTE':
                op = '>='
                break;
            default:
                console.error(`Unsupported condition operator: ${op}`);
                break;
        }
        var code = `${key} = (${left} ${op} ${right})`
        var id=block.id
        await this.callback({
            id,
            name:'call'
        })
        console.log('eval '+code)
        return true
    }

    evaluateInput(input) {
        if (!input) return null;

        let block = input;
        let btype=this.getBlockType(block)
        switch (btype) {
            case 'text'://普通text 常量节点
                return `'${block.fields.TEXT}'`;
            case 'math_number':
                return block.fields.NUM;
            case 'variables_get'://变量赋值给变量
                const varId = block.fields.VAR.id;
                return this.variables[varId];//返回变量的名字
            case 'function'://函数的返回值赋值给变量
                return this.executeFunction(block); // Recursively execute custom types
            default:
                console.error(`Unsupported input block type: ${block.type}`);
                return null;
        }
    }

}

// Example usage



var funs = ['create_mat','create_hobj','write_mat','printlog','test_tpl']
const interpreter = new ASTInterpreter(ast,funs);

interpreter.execute();
相关推荐
开心工作室_kaic8 分钟前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js
有梦想的刺儿27 分钟前
webWorker基本用法
前端·javascript·vue.js
霁月风39 分钟前
设计模式——适配器模式
c++·适配器模式
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
清灵xmf1 小时前
TypeScript 类型进阶指南
javascript·typescript·泛型·t·infer
咖啡里的茶i1 小时前
Vehicle友元Date多态Sedan和Truck
c++
小白学大数据1 小时前
JavaScript重定向对网络爬虫的影响及处理
开发语言·javascript·数据库·爬虫
海绵波波1071 小时前
Webserver(4.9)本地套接字的通信
c++
@小博的博客1 小时前
C++初阶学习第十弹——深入讲解vector的迭代器失效
数据结构·c++·学习
qq_390161772 小时前
防抖函数--应用场景及示例
前端·javascript