AST解web控制流平坦化

  • 此代码可以解决大部分 while if else 控制流平坦化
  • 原理:
    • 先将 if 语句转为 switch 语句,再将 switch 分支合并,最后删除已合并的分支(具体看代码)
  • 实现效果图
    在这里插入图片描述
  • 首先安装依赖:
npm install @babel/parser
npm install @babel/generator
npm install @babel/traverse        
npm install @babel/types

代码:

/*
* 控制流平坦化 if语句转 switch* */
function del_code(name, consequent) {// 删除合并分支后多余的 赋值和break代码let assignment_bool, break_bool;for (let i = consequent.length - 1; i >= 0; i--) {if (consequent[i].type === "BreakStatement") {if (break_bool) {consequent.splice(i, 1);} else {break_bool = true;}} else if (consequent[i].type === "ExpressionStatement" && consequent[i].expression.type === "AssignmentExpression" && consequent[i].expression.left.name === name) {if (assignment_bool) {consequent.splice(i, 1);} else {assignment_bool = true;}}}
}function merge_branch(name, key, cases_dict) {// 用于递归合并 switch 分支let {consequent} = cases_dict[key];let value = -1;for (let i in consequent) {if (consequent[i].type === "ExpressionStatement" && consequent[i].expression.type === "AssignmentExpression" && consequent[i].expression.left.name === name && consequent[i].expression.right.type === "NumericLiteral") {value = consequent[i].expression.right.value;break;}}if (value !== -1 && cases_dict.hasOwnProperty(value)) {del_cases_dict[value] = 1;return consequent.concat(merge_branch(name, value, cases_dict));    // 继续下一分支的合并}return consequent;
}const fs = require('fs');
const {parse} = require("@babel/parser");
const traverse = require("@babel/traverse").default;
const generator = require("@babel/generator").default;
const types = require("@babel/types");const js_code = fs.readFileSync("./test.js", 'utf8');
const ast_code = parse(js_code);switch_cases_dict = {};
break_node = types.breakStatement();traverse(ast_code, {'IfStatement': {enter(path) {var name = path.node.test.left.name;if (path.node.test.operator === "===") {  // 如果判断符号是 ===if (switch_cases_dict[name] === undefined) {switch_cases_dict[name] = [];}path.node.consequent.body.push(break_node);switch_cases_dict[name].push(types.switchCase(path.node.test.right, path.node.consequent.body));if (path.node.alternate.type === 'BlockStatement') {path.node.alternate.body.push(break_node);let num = path.node.test.right.value + 1;switch_cases_dict[name].push(types.switchCase(types.numericLiteral(num),path.node.alternate.body,));}}},exit(path) {var name = path.node.test.left.name;if (path.parentPath.parentPath.type === "WhileStatement" && switch_cases_dict[name].length !== 0) {console.log(name, "if 已替换 switch");path.replaceWith(types.switchStatement(discriminant = types.identifier(name),cases = switch_cases_dict[name]));}}},'SwitchStatement': {enter(path) {del_cases_dict = {}; // 待删除的 分支语句let cases_dict = {};let cases_list = path.node.cases;let {name} = path.node.discriminant;if (switch_cases_dict.hasOwnProperty(name)) {console.log(name, "switch 分支合并");for (let i in cases_list) {cases_dict[cases_list[i].test.value] = cases_list[i]}for (let key in cases_dict) {   // 合并分支并删除多余代码cases_dict[key].consequent = merge_branch(name, key, cases_dict);del_code(name, cases_dict[key].consequent);}for (let key in del_cases_dict) {delete cases_dict[key]; // 删除多余分支}path.node.cases = Object.values(cases_dict);}},}
})// console.log(generator(ast_code).code)
fs.writeFileSync("./demo.js", generator(ast_code).code, 'utf8')

注:以上js解出来的代码在某些分支会出现多次 return 语句,当然,并不影响运行。我暂时没找到出现这种问题的原因在哪里,如果您找到请务必和我说下,另您也可以在 del_code 函数中删除多的 return 语句

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

指针基础 - golang版

文章目录 1、指针2、基础语法2.1 定义指针2.2 取地址操作符 &2.3 解引用操作符 * 3、实战用法3.1 指针作为函数参数3.2 指针和结构体3.3 指针和接收者 1、指针 变量是存储值的地方;指针的值是一个变量的地址;不是所有的值都有地址,但是所…

【K8s】如何使用Kubernetes Ingress: Contour

使用Kubernetes Ingress: Contour 目录 使用Kubernetes Ingress: Contour没有 Ingress 控制器的情况Ingress 控制器的优势部署 Contour看到 Contour 在运行中总结推荐超级课程: Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战在处理Kubernetes时会遇到…

Java后端八股-------并发编程

图中的 synchronized方法如果没有锁,那么可能会有超卖,数据错误等情况。 加锁之后会按顺序售卖。 synchronized的底层是monitor。 线程没有竞争关系的时候,引入了轻量级锁,当需要处理竞争关系的时候一定要用到重量级锁(线程的…

数据挖掘与大数据的结合

随着大数据技术的不断发展和普及,数据挖掘在大数据环境下的应用也变得更加广泛和深入。以下将探讨大数据技术对数据挖掘的影响,以及如何利用大数据技术处理海量数据并进行有效的数据挖掘,同时分析大数据环境下的数据挖掘挑战和解决方案。 1.…

【Flutter】IOS运行工程二次启动崩溃问题。

问题 IOS14设备,切后台划掉,二次启动崩溃,看crash日志 一直提示第三方plugin注册问题。 一个一个尝试注掉,发现依然不行,创建了一个原生app,运行复现发现没问题,大概率是flutter的问题。 结论…

【RK32388 Android10, UNIK 4G模块导致usb hub出现 EMI】

文章目录 【RK32388 Android10, UNIK 4G模块导致usb hub出现 EMI 】背景调试过程解决相机掉线id变号发现EMI 出现 【RK32388 Android10, UNIK 4G模块导致usb hub出现 EMI 】 背景 在Android10 unik 的版本提测中,发现了一个问题&#xff0c…

Golang高效流控实践

流控对于构建高可靠弹性系统至关重要,本文介绍了Golang内置的流控组件,通过该组件就可以打造适合各种业务场景的流控系统。原文: Rate Limiting in Go: Controlling Traffic with Efficiency[1] Jon Cellier Unsplash 导言 流控(Rate limiting)是构建可扩…

Javaweb day17 day18 day19

mysql-DDL 数据库操作 写法 客户端工具 (也可以使用idea) 表 写法 约束 数据类型 案例 写法 表的查询修改删除 写法 删除

RTC的Google拥塞控制算法 rmcat-gcc-02

摘要 本文档描述了使用时的两种拥塞控制方法万维网(RTCWEB)上的实时通信;一种算法是基于延迟策略,一种算法是基于丢包策略。 1.简介 拥塞控制是所有共享网络的应用程序的要求互联网资源 [RFC2914]。 实时媒体的拥塞控制对于许…

Lua中文语言编程源码-第四节,更改linit.c初始化库函数, 使Lua加载中文库关键词(与所有的基础库相关)

源码已经更新在CSDN的码库里: git clone https://gitcode.com/funsion/CLua.git 在src文件夹下的linit.c初始化库的函数,用于lua.c和其他客户端。 增加加载中文库宏名列表,保留英文库宏名列表。 原始的代码为: static const …

​​SQLiteC/C++接口详细介绍之sqlite3类(十)

返回目录:SQLite—免费开源数据库系列文章目录 上一篇:SQLiteC/C接口详细介绍之sqlite3类(九) 下一篇:​​SQLiteC/C接口详细介绍之sqlite3类(十一) 30.sqlite3_enable_load_extension&#x…

venv uvicorn python 虚拟服务器外网无法访问

python -m venv .venv source ./.venv/bin/activate pip install -r requirements.txt ./run.sh source ./.venv/bin/activate uvicorn main:app --reload 虚拟web服务器外网访问控制台启动命令用以下代码启动 uvicorn main:app --host 0.0.0.0 --port 8501 --reload 启动到后…

生命周期模型

1. 编码修补模型(Code-and-Fix Model) 定义:这是一种非正式的软件开发过程,开发者开始编写代码,然后在发现问题时修复它们,没有明确的需求分析和设计阶段。特征: 开始编码而不进行大量的设计或…

【Git】本地仓库关联远程仓库

Git 本地项目关联远程仓库 本地 本地已有项目 ● 项目 07.GitLocalTest 包含有一个js ○ test.js 远程仓库 ● 远程仓库地址 ○ https://github.com/Sonnenlicht77/gitTest.git ○ 仓库只有一个 readme.md 关联 1.本地 1.1 本地仓库 ● git init ● git add . ● gi…

掌握人工智能:人工智能工程师必须了解的顶级编程语言

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗?订阅我们的简报,深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同,从行业内部的深度分析和实用指南中受益。不要错过这个机会,成为AI领…

单片机FLASH深度解析和编程实践(下)

本篇文章将同大家分享单片机FLASH编程的相关寄存器和寄存器操作及库函数操作。本篇文章依然以STM32单片机为例进行解析。有关FLASH的基本原理和实现方法,大家可以参考上一篇文章:单片机FLASH深度解析和编程实践(上)-CSDN博客 目录…

探索设计模式的魅力:探索发布-订阅模式的深度奥秘-实现高效、解耦的系统通信

​🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,并坚持默默的做事。 探索发布-订阅模式的深度奥秘:实现高效、解耦的系统通信 文章目录 一、案例场景&am…

Python深度学习之路:TensorFlow与PyTorch对比【第140篇—Python实现】

Python深度学习之路:TensorFlow与PyTorch对比 在深度学习领域,TensorFlow和PyTorch是两个备受青睐的框架,它们为开发人员提供了强大的工具来构建和训练神经网络模型。本文将对这两个框架进行对比,探讨它们的优势和劣势&#xff0…

macOS上基于httpd-dav搭建WebDav服务

文章目录 配置 Apache httpd修改 ServerName启动验证 httpd 服务启用 Dav 扩展服务配置 配置 httpd 扩展 Dav 服务设置共享目录文件夹配置 DavLockDB 目录创建 WebDAV 访客用户 httpd-dav.conf 主要改动部分BasicDigest共享多个目录 授予 httpd 完全磁盘访问权限验证更新配置重…

自适应日落动态卡通动画404页面模板

源码介绍 自适应日落动态卡通动画404页面模板,源码由HTMLCSSJS组成,记事本打开源码文件可以进行内容文字之类的修改,双击html文件可以本地运行效果,也可以上传到服务器里面 下载地址 自适应日落动态卡通动画404页面模板