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

实现原理

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

TODO
for循环功能 函数功能

单步执行效果图
单步执行

直接执行效果图

直接执行

源代码

//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();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/762377.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Lipschitz 连续,绝对连续

1. Lipschitz 连续 经常听到这个名词&#xff0c; Lipschitz 连续比普通连续更强&#xff0c;不仅要求函数连续&#xff0c;还要求函数的梯度小于一个正实数。 在单变量实数函数上的定义可以是&#xff1a; 对于定义域内任意两个 x 1 x_1 x1​ and x 2 x_2 x2​, 存在一个…

AI与EHS管理结合:融合创新,赋能绿色安全生产

随着科技的不断进步&#xff0c;人工智能AI已经在我们的日常生活中扮演了重要角色。在环保、健康和安全这个重要领域&#xff0c;也就是我们常说的EHS管理中&#xff0c;AI也正发挥着神奇的作用。 咱们知道&#xff0c;一个公司要想好好运转&#xff0c;确保工人安全、保护环境…

SpringBoot实现图片添加水印

提示&#xff1a;今日完成图片添加水印功能 后续可能还会继续完善这个功能 文章目录 目录 文章目录 前端部分 后端 Xml Controller层 Sercive层 Service实现层 Config配置层 application.properties 文件后缀名获取 常量定义 前端部分 <!DOCTYPE html> <htm…

NC13611 树(dfs序+区间dp)

链接 思路&#xff1a; 容易知道对于同一种颜色的子图一定是仅由该颜色的点连通的。设我们要划分的个数为x&#xff08;x<k&#xff09;&#xff0c;也就是说我们要选出x-1条边&#xff0c;这里有种情况。那么我们需要选出x种颜色&#xff0c;这里有种情况。然后我们需要将…

samba服务的搭建与使用

关闭selinux #暂时关闭selinux 查看selinux状态 [rootlocalhost ~]# getenforce Disabled [rootlocalhost ~]# 如果此处是‘enforcing’&#xff0c;则执行下列代码 [rootlocalhost ~]# setenforce 0 再次查看selinux状态 [rootlocalhost ~]# getenforce permissive #永久关…

MySQL 常见存储引擎详解(一)

本篇主要介绍MySQL中常见的存储引擎。 目录 一、InnoDB引擎 简介 特性 最佳实践 创建InnoDB 存储文件 二、MyISAM存储引擎 简介 特性 创建MyISAM表 存储文件 存储格式 静态格式 动态格式 压缩格式 三、MEMORY存储引擎 简介 特点 创建MEMORY表 存储文件 内…

Ubuntu 24.04-自动安装-Nvidia驱动

教程 但在安全启动模式下可能会报错。 先在Nvidia官网找到GPU对应的驱动版&#xff0c; 1. 在软件与更新中选择合适的驱动 2. ubuntu自动安装驱动 sudo ubuntu-drivers autoinstall显示驱动 ubuntu-drivers devices3. 安装你想要的驱动 sudo apt install nvidia-driver-ve…

【UE 网络】多人游戏开发时应该如何区分客户端逻辑和服务端逻辑 入门篇

目录 0 引言1 服务器和客户端逻辑1.1 服务器职责1.2 客户端职责 2 函数会在客户端执行还是服务端&#xff1f;2.1 只在客户端执行的函数RepNotifyClient RPCMulticast RPC 2.2 只在服务端执行的函数GameModeServer RPC 2.3 在两端都可以执行的函数GetNetMode() 和 HasAuthority…

结构体------“成绩排序”---冒泡----与“输出最高成绩”区别

从大到小或者从小到大排序----冒泡排序---双重循环i,j 比较的时候用的是 排序的时候用的是整体 stu [ j1 ] 和 stu [ j ] 我写错为下面这个&#xff0c;交换的只是学生的出生日期&#xff0c;没有交换整体 #include<stdio.h> #include<string.h>struct student{ch…

EKF+UKF+CKF+PF的效果对比|三维非线性滤波|MATLAB例程

前言 标题里的EKF、UKF、CKF、PF分别为&#xff1a;扩展卡尔曼滤波、无迹卡尔曼滤波、容积卡尔曼滤波、粒子滤波。 EKF是扩展卡尔曼滤波&#xff0c;计算快&#xff0c;最常用于非线性状态方程或观测方程下的卡尔曼滤波。 但是EKF应对强非线性的系统时&#xff0c;估计效果不如…

使用 go-control-plane 自定义服务网格控制面

写在前面 阅读本文需要最起码了解envoy相关的概念 本文只是一个类似于demo的测试&#xff0c;只为了学习istio&#xff0c;更好的理解istio中的控制面和数据面&#xff08;pilot -> proxy&#xff09;是如何交互的&#xff0c;下图的蓝色虚线 先说go-control-plane是什么…

Linux——移动文件或目录,查找文件,which命令

移动文件或目录 作用 - mv命令用于剪切或重命名文件 格式 bash mv [选项] 源文件名称 目标文件名称 注意 - 剪切操作不同于复制操作&#xff0c;因为它会把源文件删除掉&#xff0c;只保留剪切后的文件。 - 如果在同一个目录中将某个文件剪切后还粘贴到当前目录下&#xff0c;…

onnx模型转rknn到部署

简介 最近开始用3568的板子&#xff0c;之前是在用3399&#xff0c;cpu的话3399比3568强&#xff0c;但是3568有1T的npu算力&#xff0c;所以模型移植过来用npu使用&#xff0c;之前用ncnn感觉太慢了&#xff0c;rk的npu使用没有开源&#xff0c;所以没法兼容&#xff0c;只能跑…

基于pycharm对每个工程配置python环境

目录 1 生成环境2 配置pycharm 1 生成环境 设定一个存放虚拟环境的目录&#xff0c;比如可以放在如下目录下&#xff1a; /Users/Name/PycharmProjects/env 然后生成虚拟环境&#xff0c;执行如下操作&#xff1a; python3 -m venv /Users/Name/PycharmProjects/env/agent_pr…

本周波动预警!7月将一路上涨,牛市“复苏“?低于6万美元的比特币,是熊市陷阱吗?

比特币在第三季度伊始发出了一些积极信号。随着上周末的涨势&#xff0c;BTC/USD最高一度达到63818美元&#xff0c;这让人对比特币能否重拾牛市信心满怀希望。不过&#xff0c;在冲破关键阻力位64000美元之前&#xff0c;市场参与者仍保持谨慎态度。比特币要想维系开头的牛市态…

AI系统:未来科技的驱动力

引言 人工智能&#xff08;Artificial Intelligence, AI&#xff09;是一门研究如何使计算机模拟、延伸和扩展人类智能的学科。自20世纪50年代起&#xff0c;人工智能作为一项科学研究领域开始兴起。早期的AI系统主要集中在简单的任务&#xff0c;如棋类游戏和数学证明。随着计…

KUKA机器人中断编程2—中断相关的指令

在进行中断编程时&#xff0c;涉及到多个指令&#xff0c;包括:DECL、ON、OFF、GLOBAL、BRAKE、RESUME等。 1、中断声明 事件和子程序通过INTERRUPT DECL ... WHEN .. DO .. 来定义。 语法:INTERRUPT DECL Prio WHEN 事件 DO 中断程序 例如:INTERRUPT DECL 19 WHEN $IN[1]TRU…

锁相环相位噪声仿真代码-汇总

24小时自动发货 所设计的压控振荡器输入电压为0.625V时&#xff0c;输出大致为500Mhz&#xff1b;输入电压为1.559时&#xff0c;输出电压大致为1Ghz 1.文件夹里面各个文件作用&#xff08;包括参考书PLL PHASE NOISE ANALYSIS、lee的射频微电子、以及前人留下的matlab文件还有…

MATLAB-振动问题:单自由度阻尼振动系统受迫振动

一、基本理论 二、MATLAB实现 单自由度阻尼振动系统受迫振动&#xff0c;MATLAB代码如下&#xff1a; clear; clc; close allA 1; psi 0; F0 10; D 20; Rm 0.5; M 1; omega 2; delta Rm / (2*M); omega0 sqrt(D / M); Omega sqrt(omega0^2 - delta^2); Zm Rm i *…

经典文献阅读之--iDet3D(交互式3D目标检测器)

Tip: 如果你在进行深度学习、自动驾驶、模型推理、微调或AI绘画出图等任务&#xff0c;并且需要GPU资源&#xff0c;可以考虑使用UCloud云计算旗下的Compshare的GPU算力云平台。他们提供高性价比的4090 GPU&#xff0c;按时收费每卡2.6元&#xff0c;月卡只需要1.7元每小时&…