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

news2024/11/16 19:52:17

家人们上午好呀

这里是超绝脱单牛一枚

没错,我和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 block
    println(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 = 1
    a = 2
    b = 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 :
          condition
          true -> if-true
          false -> if-false
if-true:
          body
          if-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 main

import "fmt"

func main() {
        b := 0
        if a := 0; a > 0 {
                a = 1
                a = 2
                b = 1
        } else {
                a := 2
        }
        println(a) // undefined
        println(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> 0
        If [<boolean> false] true -> if.true-2, false -> if.false-3
if.true-2: <- if-condition-1
        jump -> if.done-4
if.false-3: <- if-condition-1
        jump -> 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: a

Values: 1
        0 (t35): [Function] Function-println    14:2 - 14:9: println

Values: 2
        0 (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.coloradmin.cn/o/2157440.html

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

相关文章

文件查找和打包压缩【1.7】

文件查找和打包压缩【1.7】 八、文件查找和打包压缩8.1 文件查找8.1.1 locate8.1.2 findfind8.1.2.1 指定搜索目录层级8.1.2.2 先处理文件再处理目录8.1.2.3 根据文件名和inode查找8.1.2.4 根据属主属组查找8.1.2.5 根据文件类型查找8.1.2.6 空文件或目录8.1.2.7 组合条件8.1.2…

Vue项目之Element-UI(Breadcrumb)动态面包屑效果 el-breadcrumb

效果预览 需要导航的页面Vue.js 最笨的方法就是在每个需要面包屑的页面中固定写好 <template><div class="example-container"><el-breadcrumb separator="/"

不再错过任何一个区块!用Node.js + WebSocket轻松实现区块链实时监控

文章目录 前言一、WebSocket是什么&#xff1f;二、项目结构三、代码实现1. 后端实现2. 前端实现 四、启动项目总结 前言 随着区块链技术的发展&#xff0c;实时监控区块链网络中的区块和交易信息变得越来越重要。无论是开发去中心化应用&#xff08;DApp&#xff09;&#xf…

【WebGIS实例】(17)下载瓦片底图并实现离线加载——以天地图为例

前言 在有些项目中&#xff0c;会有部署到无法访问互联网的内网环境中&#xff0c;这时候就会有离线部署应用和地图服务等需求了。 本博客是本着交流学习的目的&#xff0c;分享一个离线瓦片地图的获取方案&#xff0c;以天地图为案例&#xff0c;实现步骤&#xff1a; 安装…

读书笔记——DDIA-v2 设计数据密集型应用(第二版)

ddia-v2中文版地址&#xff1a;https://github.com/Vonng/ddia/tree/v2 ddia-v2看完感觉爱不释手&#xff0c;只要是数据相关的知识都娓娓道来&#xff0c;为什么会这样&#xff1f;现在是怎样的&#xff1f;这样有什么问题&#xff1f;其中的看法和想法实在精辟、干练&#xf…

典型的MVC设计模式:使用JSP和JavaBean相结合的方式来动态生成网页内容典型的MVC设计模式

先看代码与实现&#xff1a; 文件结构 triangle_area4.jsp <% page contentType"text/html;charsetUTF-8" pageEncoding"UTF-8" %> <html> <body> <%--<jsp:useBean>&#xff1a;用于在JSP中实例化JavaBean。在这里&#xff0c…

感知笔记1:ROS 视觉- 跟随红球

- 目录 - 如何在 ROS 中可视化 RGB 相机。如何作为机器人切换主题。如何创建 blob 检测器。如何获取要跟踪的颜色的颜色编码。如何使用 blob 检测数据并移动 RGB 相机以跟踪 blob。 机器人技术中最常见的传感器是不起眼的 RGB 摄像头。它用于从基本颜色跟踪&#xff08;blob 跟…

解决 TortoiseGitPlink Fatal Error:深入解析

解决 TortoiseGitPlink Fatal Error&#xff1a;深入解析 在 Windows 平台上&#xff0c;开发者使用 Git 和 TortoiseGit 进行版本控制时&#xff0c;有时会遇到 TortoiseGitPlink Fatal Error。该错误通常是在推送/拉取代码时&#xff0c;客户端未能提供正确的 SSH 密钥。 1…

Linux之实战命令06:locate应用实例(四十)

简介&#xff1a; CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布&#xff1a;《Android系统多媒体进阶实战》&#x1f680; 优质专栏&#xff1a; Audio工程师进阶系列【原创干货持续更新中……】&#x1f680; 优质专栏&#xff1a; 多媒体系统工程师系列【…

Maven-四、继承

Maven进阶 文章目录 Maven进阶前言继承设置继承依赖管理总结 前言 一个项目中的不同模块可能引用的是同一个依赖&#xff0c;在这种情况下&#xff0c;单独在某个模块内引用太麻烦&#xff0c;于是maven使用继承的思想&#xff0c;在父模块中配置依赖包&#xff0c;其他需要这…

实战OpenCV之直方图

基础入门 直方图是对数据分布情况的图形表示&#xff0c;特别适用于图像处理领域。在图像处理中&#xff0c;直方图通常用于表示图像中像素值的分布情况。直方图由一系列矩形条&#xff08;也被称为bin&#xff09;组成&#xff0c;每个矩形条的高度表示某个像素值&#xff08;…

3.6 第四行之__ipipe_init_proc()

点击查看系列文章 》 Interrupt Pipeline系列文章大纲-CSDN博客 原创不易&#xff0c;需要大家多多鼓励&#xff01;您的关注、点赞、收藏就是我的创作动力&#xff01; 3.6 第四行之__ipipe_init_proc() __ipipe_init_proc()并不是直接在start_kernel中调用&#xff0c;它的…

JavaScript高级——事件循环模型

1、 2、所有代码分类 ① 初始化执行代码&#xff08;同步代码&#xff09;&#xff1a;包含绑定 dom 事件监听&#xff0c;设置定时器&#xff0c;发送 ajax 请求的代码 ② 回调执行代码&#xff08;异步代码&#xff09;&#xff1a;处理回调逻辑 3、js 引擎执行代码的基本流…

【Linux篇】网络编程基础(笔记)

目录 一、服务器模型 1. C/S 模型 2. P2P模型 二、服务器编程框架 1. I/O处理单元 2. 逻辑单元 3. 网络存储单元 4. 请求队列 三、网络编程基础API 1. socket 地址处理 API &#xff08;1&#xff09;主机字节序和网络字节序 &#xff08;2&#xff09;通用socket地…

论文阅读:A Generalization of Transformer Networks to Graphs

论文阅读&#xff1a;A Generalization of Transformer Networks to Graphs 论文地址1 摘要2 贡献Graph TransformerOn Graph Sparsity&#xff08;图稀疏&#xff09;On Positional Encodings&#xff08;位置编码&#xff09;3 Graph Transformer Architecture&#xff08;架…

GPT实现联网,NextChat插件的配置说明

简介 NextChat开源版本已支持插件调用。 不过&#xff0c;插件的配置略复杂&#xff0c;为了降低普通用户的配置难度&#xff0c;本文基于中转API做详细配置说明&#xff0c;后续如果有新增插件&#xff0c;本文也将同步更新配置说明。 在配置具体插件之前&#xff0c;你需要…

Spring后端直接用枚举类接收参数,自定义通用枚举类反序列化器

在使用枚举类做参数时&#xff0c;一般会让前端传数字&#xff0c;后端将数字转为枚举类&#xff0c;当枚举类很多时&#xff0c;很可能不知道这个code该对应哪个枚举类。能不能后端直接使用枚举类接收参数呢&#xff0c;可以&#xff0c;但是受限。 Spring反序列默认使用的是J…

The NCCoE’s Automation of the CMVP

Earlier today at the ICMC24, we heard from a panel about the US National Cybersecurity Center of Excellence’s (NCCoE) work on the Automated Cryptographic Module Validation Program (ACMVP), which intends to tackle the troublingly long queue times we’ve se…

Apifox 「定时任务」操作指南,解锁自动化测试的新利器

定时任务是按照预设时间自动执行的任务&#xff0c;它可以有效解决一些常见问题&#xff0c;比如频繁执行的回归测试和大规模的接口测试&#xff0c;这些任务需要在固定时间点或间隔周期内自动运行&#xff0c;以确保软件的持续集成和持续交付过程中的稳定性和可靠性。通过使用…

实操学习——个人资料的录入、修改、密码的修改

实操学习——个人资料的录入、修改、密码的修改 一、个人资料的录入和修改知识补充&#xff1a;装饰器二、密码的修改知识补充&#xff1a;docker的关闭与启动 一、个人资料的录入和修改 在users的app下创建一个用户详情表 from django.contrib.auth.models import User from…