千家信息网

Solidity的Yul是什么

发表于:2026-11-03 作者:千家信息网编辑
千家信息网最后更新 2026年11月03日,这篇文章主要讲解了"Solidity的Yul是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Solidity的Yul是什么"吧!Yul (先前被也
千家信息网最后更新 2026年11月03日Solidity的Yul是什么

这篇文章主要讲解了"Solidity的Yul是什么",文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习"Solidity的Yul是什么"吧!

Yul (先前被也被称为 JULIA 或 IULIA)是一种可以编译到各种不同后端的中间语言( 以太坊虚拟机Ethereum Virtual Machine(EVM) 1.0,以太坊虚拟机Ethereum Virtual Machine(EVM) 1.5,而 eWASM 也在计划中)。 正因为如此,它被设计成为这三种平台的可用的共同标准。 它已经可以用于 Solidity 内部的"内联汇编",并且未来版本的 Solidity 编译器甚至会将 Yul 用作中间语言。 为 Yul 构建高级的优化器阶段也将会很容易。

Yul 的核心组件是函数,代码块,变量,字面量,for 循环,if 条件语句,switch 条件语句,表达式和变量赋值。

Yul 是强类型的,变量和字面量都需要通过前缀符号来指明类型。支持的类型有:bool, u8, s8, u32, s32, u64, s64, u128, s128, u256 和 s256。

Yul 本身甚至不提供操作符。如果目标平台是 以太坊虚拟机Ethereum Virtual Machine(EVM),则操作码将作为内置函数提供,但如果后端平台发生了变化,则可以重新实现它们。 有关强制性的内置函数的列表,请参阅下面的章节。

以下示例程序假定 以太坊虚拟机Ethereum Virtual Machine(EVM) 操作码 mul,div 和 mo 是原生支持或可以作为函数用以计算指数的。

{   function power(base:u256, exponent:u256) -> result:u256   {       switch exponent       case 0:u256 { result := 1:u256 }       case 1:u256 { result := base }       default:       {           result := power(mul(base, base), div(exponent, 2:u256))           switch mod(exponent, 2:u256)               case 1:u256 { result := mul(base, result) }       }   }}也可用 for 循环代替递归来实现相同的功能。这里,我们需要 以太坊虚拟机Ethereum Virtual Machine(EVM) 操作码 lt(小于)和 add 可用。{   function power(base:u256, exponent:u256) -> result:u256   {       result := 1:u256       for { let i := 0:u256 } lt(i, exponent) { i := add(i, 1:u256) }       {           result := mul(result, base)       }   }}

1

Yul语言说明

本章介绍 Yul 代码。Yul 代码通常放置在一个 Yul 对象中,它将在下一节中介绍。

语法:

代码块 = '{' 语句* '}'语句 =   代码块 |   函数定义 |   变量声明 |   赋值 |   表达式 |   Switch |   For 循环 |   循环中断函数定义 =   'function' 标识符 '(' 带类型的标识符列表? ')'   ( '->' 带类型的标识符列表 )? 代码块变量声明 =   'let' 带类型的标识符列表 ( ':=' 表达式 )?赋值 =   标识符列表 ':=' 表达式表达式 =   函数调用 | 标识符 | 字面量If 条件语句 =   'if' 表达式 代码块Switch 条件语句 =   'switch' 表达式 Case* ( 'default' 代码块 )?Case =   'case' 字面量 代码块For 循环 =   'for' 代码块 表达式 代码块 代码块循环中断 =   'break' | 'continue'函数调用 =   标识符 '(' ( 表达式 ( ',' 表达式 )* )? ')'标识符 = [a-zA-Z_$] [a-zA-Z_0-9]*标识符列表 = 标识符 ( ',' 标识符)*类型名 = 标识符 | 内置的类型名内置的类型名 = 'bool' | [us] ( '8' | '32' | '64' | '128' | '256' )带类型的标识符列表 = 标识符 ':' 类型名 ( ',' 标识符 ':' 类型名 )*字面量 =   (数字字面量 | 字符串字面量 | 十六进制字面量 | True字面量 | False字面量) ':' 类型名数字字面量 = 十六进制数字 | 十进制数字十六进制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"'True字面量 = 'true'False字面量 = 'false'十六进制数字 = '0x' [0-9a-fA-F]+十进制数字 = [0-9]+

语法层面的限制

Switches 必须至少有一个 case(包括 default )。 如果表达式的所有可能值都被覆盖了,那么不应该允许使用 default (即带 bool 表达式的 switch 语句同时具有 true case 和 false case 的情况下不应再有 default 语句)。

每个表达式都求值为零个或多个值。 标识符和字面量求值为一个值,函数调用求值为所调用函数的返回值。

在变量声明和赋值中,右侧表达式(如果存在)求值后,必须得出与左侧变量数量相等的值。 这是唯一允许求值出多个值的表达式。

那种同时又是语句的表达式(即在代码块的层次)求值结果必须只有零个值。

在其他所有情况中,表达式求值后必须仅有一个值。

continue 和 break 语句只能用在循环体中,并且必须与循环处于同一个函数中(或者两者都必须在顶层)。

for 循环的条件部分的求值结果只能为一个值。

字面量不可以大于它们本身的类型。已定义的最大类型宽度为 256 比特。

作用域规则

Yul 中的作用域是与块(除了函数和 for 循环,如下所述)和所有引入新的标识符到作用域中的声明 ( FunctionDefinition ,VariableDeclaration )紧密绑定的。

标识符在将其定义的块中可见(包括所有子节点和子块)。 作为例外,for 循环的 "init" 部分中(第一个块)定义的标识符在 for 循环的所有其他部分(但不在循环之外)中都是可见的。 在 for 循环的其他部分声明的标识符遵守常规的作用域语法规则。 函数的参数和返回参数在函数体中可见,并且它们的名称不能相同。

变量只能在声明后引用。 尤其是,变量不能在它们自己的变量声明的右边被引用。 函数可以在声明之前被引用(如果它们是可见的)。

Shadowing 是不被允许的,即是说,你不能在同名标识符已经可见的情况下又定义该标识符,即使它是不可访问的。

在函数内,不可能访问声明在函数外的变量。

形式规范

我们通过在 AST 的各个节点上提供重载的求值函数 E 来正式指定 Yul。 任何函数都可能有副作用,所以 E 接受两个状态对象和 AST 节点作为它的参数,并返回两个新的状态对象和数量可变的其他值。

这两个状态对象是全局状态对象(在 以太坊虚拟机Ethereum Virtual Machine(EVM) 的上下文中是 内存memory,存储storage 和区块链的状态)和本地状态对象(局部变量的状态,即 以太坊虚拟机Ethereum Virtual Machine(EVM) 中堆栈的某个段)。 如果 AST 节点是一个语句,E 将返回两个状态对象和一个用于 break 和 continue 语句的 "mode"。 如果 AST 节点是表达式,则 E 返回两个状态对象,并返回与表达式求值结果相同数量的值。

在这份高层次的描述中,并没有对全局状态的确切本质进行说明。 本地状态 L 是标识符 i 到值 v 的映射,表示为 L[i] = v。 对于标识符 v, 我们用 $v 作为标识符的名字。

我们将为 AST 节点使用解构符号。

E(G, L, <{St1, ..., Stn}>: Block) =   let G1, L1, mode = E(G, L, St1, ..., Stn)   let L2 be a restriction of L1 to the identifiers of L   G1, L2, modeE(G, L, St1, ..., Stn: Statement) =   if n is zero:       G, L, regular   else:       let G1, L1, mode = E(G, L, St1)       if mode is regular then           E(G1, L1, St2, ..., Stn)       otherwise           G1, L1, modeE(G, L, FunctionDefinition) =   G, L, regularE(G, L, : VariableDeclaration) =   E(G, L, : Assignment)E(G, L, : VariableDeclaration) =   let L1 be a copy of L where L1[$vari] = 0 for i = 1, ..., n   G, L1, regularE(G, L, : Assignment) =   let G1, L1, v1, ..., vn = E(G, L, rhs)   let L2 be a copy of L1 where L2[$vari] = vi for i = 1, ..., n   G, L2, regularE(G, L, : ForLoop) =   if n >= 1:       let G1, L1, mode = E(G, L, i1, ..., in)       // 由于语法限制,mode 必须是规则的       let G2, L2, mode = E(G1, L1, for {} condition post body)       // 由于语法限制,mode 必须是规则的       let L3 be the restriction of L2 to only variables of L       G2, L3, regular   else:       let G1, L1, v = E(G, L, condition)       if v is false:           G1, L1, regular       else:           let G2, L2, mode = E(G1, L, body)           if mode is break:               G2, L2, regular           else:               G3, L3, mode = E(G2, L2, post)               E(G3, L3, for {} condition post body)E(G, L, break: BreakContinue) =   G, L, breakE(G, L, continue: BreakContinue) =   G, L, continueE(G, L, : If) =   let G0, L0, v = E(G, L, condition)   if v is true:       E(G0, L0, body)   else:       G0, L0, regularE(G, L, : Switch) =   E(G, L, switch condition case l1:t1 st1 ... case ln:tn stn default {})E(G, L, : Switch) =    let G0, L0, v = E(G, L, condition)    // i = 1 .. n    // 对字面量求值,上下文无关    let _, _, v1 = E(G0, L0, l1)    ...    let _, _, vn = E(G0, L0, ln)    if there exists smallest i such that vi = v:        E(G0, L0, sti)    else:        E(G0, L0, st')E(G, L, : Identifier) =   G, L, L[$name]E(G, L, : FunctionCall) =   G1, L1, vn = E(G, L, argn)   ...   G(n-1), L(n-1), v2 = E(G(n-2), L(n-2), arg2)   Gn, Ln, v1 = E(G(n-1), L(n-1), arg1)   Let  ret1, ..., retm block>   be the function of name $fname visible at the point of the call.   Let L' be a new local state such that    L'[$parami] = vi and L'[$reti] = 0 for all i.    Let G'', L'', mode = E(Gn, L', block)   G'', Ln, L''[$ret1], ..., L''[$retm]E(G, L, l: HexLiteral) = G, L, hexString(l),   where hexString decodes l from hex and left-aligns it into 32 bytesE(G, L, l: StringLiteral) = G, L, utf8EncodeLeftAligned(l),   where utf8EncodeLeftAligned performs a utf8 encoding of l   and aligns it left into 32 bytesE(G, L, n: HexNumber) = G, L, hex(n)   where hex is the hexadecimal decoding functionE(G, L, n: DecimalNumber) = G, L, dec(n),   where dec is the decimal decoding function

类型转换函数

Yul 不支持隐式类型转换,因此存在提供显式转换的函数。 在将较大类型转换为较短类型时,如果发生溢出,则可能会发生运行时异常。

下列类型的"截取式"转换是允许的:

  • bool

  • u32

  • u64

  • u256

  • s256

低级函数

以下函数必须可用:

后端

后端或目标负责将 Yul 翻译到特定字节码。 每个后端都可以暴露以后端名称为前缀的函数。 我们为两个建议的后端保留 evm_ 和 ewasm_ 前缀。

后端: EVM

目标 以太坊虚拟机Ethereum Virtual Machine(EVM) 将具有所有用 evm_ 前缀暴露的 以太坊虚拟机Ethereum Virtual Machine(EVM) 底层操作码。

后端: "EVM 1.5"

TBD

后端: eWASM

TBD

2

Yul对象说明

语法:

顶层对象 = 'object' '{' 代码? ( 对象 | 数据 )* '}'对象 = 'object' 字符串字面量 '{' 代码? ( 对象 | 数据 )* '}'代码 = 'code' 代码块数据 = 'data' 字符串字面量 十六进制字面量十六进制字面量 = 'hex' ('"' ([0-9a-fA-F]{2})* '"' | '\'' ([0-9a-fA-F]{2})* '\'')字符串字面量 = '"' ([^"\r\n\\] | '\\' .)* '"'

在上面,代码块 指的是前一章中解释的 Yul 代码语法中的 代码块。

Yul 对象示例如下:

..code:// 代码由单个对象组成。 单个 "code" 节点是对象的代码。// 每个(其他)命名的对象或数据部分都被序列化// 并可供特殊内置函数:datacopy / dataoffset / datasize 用于访问object {   code {       let size = datasize("runtime")       let offset = allocate(size)       // 这里,对于 eWASM 变为一个内存到内存的拷贝,对于 EVM 则相当于 codecopy       datacopy(dataoffset("runtime"), offset, size)       // 这是一个构造函数,并且运行时代码会被返回       return(offset, size)   }   data "Table2" hex"4123"   object "runtime" {       code {           // 运行时代码           let size = datasize("Contract2")           let offset = allocate(size)           // 这里,对于 eWASM 变为一个内存到内存的拷贝,对于 EVM 则相当于 codecopy           datacopy(dataoffset("Contract2"), offset, size)           // 构造函数参数是一个数字 0x1234           mstore(add(offset, size), 0x1234)           create(offset, add(size, 32))       }       // 内嵌对象。使用场景是,外层是一个工厂合约,而 Contract2 将是由工厂生成的代码       object "Contract2" {           code {               // 代码在这 ...           }           object "runtime" {               code {                   // 代码在这 ...               }            }            data "Table1" hex"4123"       }   }}

感谢各位的阅读,以上就是"Solidity的Yul是什么"的内容了,经过本文的学习后,相信大家对Solidity的Yul是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是,小编将为大家推送更多相关知识点的文章,欢迎关注!

函数 代码 标识 标识符 字面 类型 表达式 对象 循环 变量 语句 状态 以太 数字 节点 语法 两个 十六进制 内存 字符 数据库的安全要保护哪些东西 数据库安全各自的含义是什么 生产安全数据库录入 数据库的安全性及管理 数据库安全策略包含哪些 海淀数据库安全审计系统 建立农村房屋安全信息数据库 易用的数据库客户端支持安全管理 连接数据库失败ssl安全错误 数据库的锁怎样保障安全 互联网加科技 百单网互联网科技有限公司 中国互联网科技工作委员会毛军 涨乐互联网科技 互联网下的科技发展 万易互联网科技有限公司 互联网科技公司官网 智慧科技互联网 善班互联网科技有限公司 互联网 视角下的科技创新 长亮科技互联网金融 海南购全球互联网科技 黑科技闪耀互联网之光 青岛科技大学互联网大赛研究生 本届互联网博览会上的黑科技 伍佰万互联网科技怎么赚钱 新氧科技和美国互联网有关系吗 上海同邻互联网科技有限公司规模 版纳互联网科技选哪家 广州三三互联网科技有限公司 狮子座互联网科技 善班互联网科技 丰台科技园 互联网 广州善班互联网科技 滨湖区互联网智能科技产品供应 互联网软件和科技 武汉健翔互联网络科技有限公司 互联网科技公司实习生 新兴科技互联网创新大赛颁奖典礼 好易买互联网科技
0