抱歉占用公共资源,大家别猜啦,我们在一起了@Yaker

家人们上午好呀

这里是超绝脱单牛一枚

没错,我和Yaker有一个孩子(bushi

今天我们的孩子YakLang来给大家介绍介绍,ta对块作用域的处理方式

image

image

image


在编程中,作用域(Scope)指的是变量、函数和对象的可访问性和生命周期的范围。不同的编程语言可能对作用域有不同的定义和实现。

块级作用域(Block Scope)是指在代码块(如条件语句、循环、函数等)内部定义的变量仅在该块内可访问的特性。这一概念在许多现代高级编程语言中得到了广泛应用。

那么在 yaklang 中是如何处理块级作用域的呢?

首先查看如下的 golang if 语句

if a := 0; a > 0 {a = 1
} else {a := 2
}

可以发现,上述代码实际上形成了如下的 block 结构:

image


想必细心的同学已经发现了,在 true block 中的表达式会影响外部的 global block 并且生成 phi 值,而 false block 则不会。

那么 yaklang 是如何区分是否生成 phi 的呢?这就涉及到了 scope 的3种常规操作:sub,merge,cover。

image

Phi值是什么?

在编程语言和编译器设计中,phi 值(φ 值)是一种用于静态单赋值形式(Static Single Assignment, SSA)中的概念

当控制流图中的某个节点(如条件分支)需要根据不同的路径选择变量的值时就会生成 phi 值,phi 值用于描述一个变量在当前作用域中可能存在的所有值

Scope 常规操作:
Sub(产生子作用域)

定义:以一个 scope 为父类,产生该 scope 的子作用域(在查找变量时可以通过_parent 指针索引到父类 scope)。

实例:

if a := 1; a > 0 { // condition block sub true blockprintln(a) // 1
}
Cover(覆盖)

定义:当一个变量在内部 scope 被重新赋值时,内部作用域的变量将“覆盖”外部作用域中同名的变量。这意味着在内部作用域中,引用该变量时将使用新定义的值。

实例:

a := 1
{a = 2 // true block cover to condition block
}
println(a) // 2
Merge(合并)

定义:在作用域中,合并通常指将多个作用域中的变量或命名空间组合在一起,以便可以访问所有变量。这种合并可能发生在不同的作用域级别之间,特别是在模块或命名空间中。

实例:

if a > 0 {a = 1
} else {a = 2
} 
// true block, false block merge to global block
println(a) // phi(a)[1,2]

简单来说,cover 会使非本地的变量影响到外部,而 merge 则会合并多个 scope 以生成 phi 值。

yaklang 中的 local value

在 yaklang 中有一个 local 标志位来记录变量是否在当前作用域中创建,还是这个例子:

if a := 0 /* local value(condition block) */; a > 0 {a = 1 /* not local value(true block) */a = 2 /* not local value(true block) */
} else {a := 3 /* local value(false block) */
}

如果在某个 scope 中产生了一个非本地变量,那么在当前 scope 中将会生成一个 capture value,而 merge 正是通过 capture value 来生产 phi 值的。

image

了解了以上知识以后,我们来看一个复杂一点的案例:

if a := 0; a > 0 {a = 1a = 2b = 1
} else {a := 2
}println(a) // undefined
println(b) // phi(b)[0,1]

详细的处理过程如下:

首先从 global scope 中 sub 一个 condition scope,然后再分别从 condition scope 中 sub true scope 和 false scope。

在 true scope 中存在非本地变量 “a” 与 “b”,然后分别生成对应的 capture value(capture value 会记录当前 scope 中非本地变量的最后一次赋值)。

当 true block 和 false block 都处理完毕以后,程序就会将 true scope 和 false scope merge 到一起,由于检测到 capture value,因此会生成 phi 值(分别是 phi(a)[0,2] 和 phi(b)[0,1])。

在 yaklang 中,最后两步处理比较特殊:

程序会选择在 condition scope 中 sub 一个新的 scope(condition scope end),然后将 merge 后的 scope 直接 cover 到新的 scope 上。

接着从 global scope 中 sub 一个新的 scope(global scope end),然后将之前 cover 后的 scope 直接 cover 到该 scope 上。

这样处理的目的是为了确保最后生成的 global scope end 是 global scope 的直接子类(没有任何的中间 scope)。

流程图如下:

image

PS:从代码层面来看,流程图可能有所不同,因为在我们实际的代码中 merge 方法里面包含了 cover 的代码,因此在代码流程图中没有 merge scope 这一步。

最后形成如下结构:

if-condition :conditiontrue -> if-truefalse -> if-false
if-true:bodyif-true -> if-done
if-false:// else or else-if(else-body)(
condition
true -> if-true2
false-> if-false2)if-false -> if-done
if-done:// next code

对于一个 if 语句而言,yaklang 将其 scope 分为了3个大的部分:global scope,if scope,if scope end:

if scope 和 if scope end 都以 global scope 为父类

if scope end 被 if scope 所覆盖

最后在 if 语句执行完毕以后,将当前作用域标记为 if scope end。

实际上的处理也应该是这样:

if 语句后的代码可以通过父类的 global scope 查找到 global scope 中的变量

在 if scope 中对外部作用域的影响(例如生成 phi 值)被 cover 到当前作用域中(if scope end)

我们可以利用 yaklang 跑一个 golang 的代码,查看 yaklang 对于块作用域的处理效果:

func TestTemp(t *testing.T) {t.Run("temp", func(t *testing.T) {test.CheckPrintlnValue(`package mainimport "fmt"func main() {b := 0if a := 0; a > 0 {a = 1a = 2b = 1} else {a := 2}println(a) // undefinedprintln(b) // phi(b)[0,1]
}`, []string{"Undefined-a","phi(b)[1,0]"}, t)})
}
package: main library
@init
type: (any) -> any
entry-0:extern type:
main
type: () -> null
entry-0:jump -> if-condition-1
if-condition-1: <- entry-0<boolean> t22 = <number> 0 gt <number> 0If [<boolean> false] true -> if.true-2, false -> if.false-3
if.true-2: <- if-condition-1jump -> if.done-4
if.false-3: <- if-condition-1jump -> if.done-4
if.done-4: <- if.true-2 if.false-3<any> t33 = phi [<number> 1, if.true-2] [<number> 0, entry-0]<any> t34 = phi [<number> 2, if.true-2] [<number> 0, if-condition-1]<any> t36 = undefined-a<number, error> t37 = call <func(...interface {}) (int, error)> println (<any> t36) binding[] member[]<number, error> t38 = call <func(...interface {}) (int, error)> println (<any> t33) binding[] member[]extern type:
error:[ warn] (GO):   not find variable a in current scope: 14:10 - 14:11: aValues: 10 (t35): [Function] Function-println    14:2 - 14:9: printlnValues: 20 (t37): [Call  ] Function-println(Undefined-a) 14:2 - 14:12: println(a)1 (t38): [Call  ] Function-println(phi(b)[1,0]) 15:2 - 15:12: println(b)[INFO] 2024-09-19 13:20:49 [utils4frontend:135] got :[Undefined-a phi(b)[1,0]]
[INFO] 2024-09-19 13:20:49 [utils4frontend:137] want :[Undefined-a phi(b)[1,0]]

可以发现,yaklang 不仅对块作用域有明确的标识,还分析了各个块的逻辑关系,生产的 phi 值也有明确的来源,最后在查找的过程中也区分开了变量 “a” 与变量 “b” 的作用域范围。

在 yaklang 中,目前已经对 if,loop,try-catch,switch,break,continue 都有了比较完善的处理,和对 goto 的部分处理(正在开发)。

END

YAK官方资源

Yak 语言官方教程:
https://yaklang.com/docs/intro/

Yakit 视频教程:
https://space.bilibili.com/437503777

Github下载地址:
https://github.com/yaklang/yakit
https://github.com/yaklang/yaklang

Yakit官网下载地址:
https://yaklang.com/

Yakit安装文档:
https://yaklang.com/products/download_and_install

Yakit使用文档:
https://yaklang.com/products/intro/

常见问题速查:
https://yaklang.com/products/FAQ

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

Java反序列化CC1-TransformedMap链学习

学习参考&#xff1a;Java反序列化CC1链TransformedMap 核心是要学会基本EXP编写&#xff0c;还有怎么找传递链。 链子尾部 这里有一个能反射调用任意类&#xff0c;任意方法的&#xff1a; 以这个漏洞点写EXP&#xff0c;由于这个是public的InvokerTransformer&#xff0c;所…

如何基于scrcpy改造实现大厂一键连招/触摸宏功能(带java源码)-千里马安卓framework实战

背景&#xff1a; 前面公众号文章已经分享过如何实现这种大厂里面一键连招&#xff0c;触摸宏的功能&#xff0c;原理本身是对dev/input下面的节点进行读取保存文件&#xff0c;然后在读取文件进行写入dev/input下面的节点&#xff0c;从而实现了触摸事件的读取和写入&#xf…

初始main方法,标识符和关键字

1. 初识Java的main方法 1.1 main方法示例 public class HelloWorld{public static void main(String[] args){System.out.println("Hello,world");} }图解&#xff1a; 通过上述代码&#xff0c;我们可以看到一个完整的Java程序的结构&#xff0c;Java程序的结构…

C. Lazy Narek (Codeforces Round 972 (Div. 2))

C. Lazy Narek 思路: 动态规划 dp dp[i] 表示 目前寻找的字符下标为i 时的最大分数&#xff08;<i<4&#xff09; 从前往后遍历字符串&#xff0c;每个字符串找5次&#xff0c;找完后把dp取max 注意找的过程中不能修改原dp数组&#xff0c;因为这5次查找是并行的&#x…

STM32引脚输入

文章目录 前言一、看原理图二、开始编程1.开启时钟2.配置GPIOA.0 上拉输入3.读取 GPIOA.0 引脚 GPIOA_IDR 0位上是1&#xff08;按键松开&#xff09;&#xff0c;输入就是高电平&#xff0c;否则就是低电平&#xff08;按键按下&#xff09; 三、完整程序四 测试效果总结 前言…

故障诊断 | 基于双路神经网络的滚动轴承故障诊断

故障诊断 | 基于双路神经网络的滚动轴承故障诊断 目录 故障诊断 | 基于双路神经网络的滚动轴承故障诊断效果一览基本介绍程序设计参考资料效果一览 基本介绍 基于双路神经网络的滚动轴承故障诊断 融合了原始振动信号 和 二维信号时频图像的多输入(多通道)故障诊断方法 单路和双…

快速生成应用:AI大模型与低代码平台如何无缝结合提升效率?

引言&#xff1a;数字化时代的开发挑战 在数字化转型的浪潮中&#xff0c;快速响应市场需求已成为企业的核心竞争力。AI大模型与低代码平台的结合&#xff0c;为应用开发提供了一条更加智能、快速的路径。通过自动代码生成、智能推荐和持续优化&#xff0c;这一无缝结合大幅提升…

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-19

计算机前沿技术-人工智能算法-大语言模型-最新论文阅读-2024-09-19 1. SAM4MLLM: Enhance Multi-Modal Large Language Model for Referring Expression Segmentation Authors: Yi-Chia Chen, Wei-Hua Li, Cheng Sun, Yu-Chiang Frank Wang, Chu-Song Chen SAM4MLLM: 增强多模…

21 基于51单片机的隧道车辆检测系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 以AT89C51单片机为控制核心&#xff0c;实现对隧道环境的监测。采用模块化设计&#xff0c; 共分以下几个功能模块&#xff1a; 单片机最小系统模块、电源模块、气体传感模块、和显示模块等。 通过…

在电脑中增加一个新盘

找到此电脑右击找到管理点进去 找到磁盘管理点进去 找到D盘&#xff0c;点击D盘然后右击找到压缩卷点击&#xff0c;之后按照自己的意愿分盘容量 然后就一直点下一页 返回去就能看到新加卷F盘了 在此电脑中也可以查看 完成

ToB项目身份认证(一):基于目录的用户管理、LDAP和Active Directory简述

在ToB的项目里&#xff0c;公司部门之间是树状的关系&#xff0c;成员结构也类似。由于windows的使用范围很广&#xff0c;尤其是在企业里&#xff0c;所以它集成的Active Directory域服务往往企业应用需要兼容的。 什么是基于目录的用户管理&#xff1f; 基于目录的用户管理…

双十一快来了!什么值得买?分享五款高品质好物~

双十一大促再次拉开帷幕&#xff0c;面对众多优惠是否感到选择困难&#xff1f;为此&#xff0c;我们精心筛选了一系列适合数字生活的好物&#xff0c;旨在帮助每一位朋友都能轻松找到心仪之选。这份推荐清单&#xff0c;不仅实用而且性价比高&#xff0c;是您双十一购物的不二…

cc2530使用(SmartRF Flash Programmer)烧录hex固件

1图标 2IAR生成HEX文件 2-1勾选他 2-2生成对应的文件&#xff08;勾选他并改后缀&#xff09; &#xff08;选择他&#xff09; 点击OK即可 3&#xff08;选择文件&#xff0c;插入板子&#xff08;会显示对应的板子&#xff09;&#xff0c;烧录即可&#xff09;

LeetcodeTop100 刷题总结(二)

LeetCode 热题 100&#xff1a;https://leetcode.cn/studyplan/top-100-liked/ 文章目录 八、二叉树94. 二叉树的中序遍历&#xff08;递归与非递归&#xff09;补充&#xff1a;144. 二叉树的前序遍历&#xff08;递归与非递归&#xff09;补充&#xff1a;145. 二叉树的后序遍…

注册商标的有关流程

注册商标的有关流程 在商业活动中&#xff0c;商标作为企业品牌的重要组成部分&#xff0c;不仅代表着企业的形象和信誉&#xff0c;更是企业资产的重要部分。因此&#xff0c;了解并遵循注册商标的流程&#xff0c;对于保护企业的合法权益至关重要。 一、确定商标注册范围并进…

大模型学习方向不知道的,看完这篇学习思路好清晰!!

入门大模型并没有想象中复杂&#xff0c;尤其对于普通程序员&#xff0c;建议采用从外到内的学习路径。下面我们通过几个步骤来探索如何系统学习大模型&#xff1a; 1️⃣初步理解应用场景与人才需求 大模型的核心应用涵盖了智能体&#xff08;AI Agent&#xff09;、微调&…

【TPAMI 2024】告别误差,OPAL算法如何让光场视差估计变得轻而易举?

题目&#xff1a;OPAL: Occlusion Pattern Aware Loss for Unsupervised Light Field Disparity Estimation OPAL&#xff1a;面向无监督光场视差估计的遮挡模式感知损失 作者&#xff1a;Peng Li; Jiayin Zhao; Jingyao Wu; Chao Deng; Yuqi Han; Haoqian Wang; Tao Yu 摘要…

一个永久的.NET渗透工具和知识仓库

01前言 为了更好地应对基于.NET技术栈的风险识别和未知威胁&#xff0c;.NET安全攻防帮会从创建以来一直聚焦于.NET领域的安全攻防技术&#xff0c;定位于高质量安全攻防社区&#xff0c;也得到了许多师傅们的支持和信任&#xff0c;通过帮会深度连接入圈的师傅们&#xff0c;…

计算机毕业设计推荐-基于PHP的律所预约服务管理系统

精彩专栏推荐订阅&#xff1a;在下方主页&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb;&#x1f447;&#x1f3fb; &#x1f496;&#x1f525;作者主页&#xff1a;计算机毕设木哥&#x1f525; &#x1f496; 文章目录 一、基于PHP的律…

61.【C语言】数据在内存中的存储

1.前置知识 整数在内存中以补码形式存储 有符号整数三种码均有符号位,数值位 正整数:原码反码补码 负整数:原码≠反码≠补码 2.解释 int arr[] {1,2,3,4,5}; VSx86Debug环境下,内存窗口输入&arr VSx64Debug环境下,内存窗口输入&arr 存放的顺序都一样,均是小端序…