教程系列 的子部分

5.1 编译原理


目录


引言


编译原理是将文本字符流,通过一系列的分析、转换,最后生成确定的指令文件的数据分析转换技术。

编译器是利用编译原理,将一种程序(源程序)翻译成另一种程序(目标程序)的计算机程序。业界也将编译器分为三个部分:前端、中端、后端。

编译器所做的工作流程如下图所示。

编译总流程 编译总流程

编译原理 的子部分

第1章

词法分析

1 序

词法分析就是将代码字符流,按照一定的规则进行分析,获取符合词法规则的字符串,并进行信息标注,为语法分析提供单词(Token)流。

2 目录


词法分析 的子部分

1.1 Token 定义


1 词法规则


词法分析按照规定的规则,可以从字符流中获取数据。

规则定义为以下几类:

  • 标识符:由字母、数字、下划线( _ )构成,但是不得由数字为起始;其中存在特殊的字符串为关键字。
  • 普通数字字面量:由数字和’.‘组成,其中分为整数、浮点数;
  • 2进制数字字面量:由 ‘0B’起始,多个 ‘0’或'1’构成。
  • 16进制数字字面量:由 ‘0X’起始,多个 十六进制字符 构成。
  • 字符字面量:由 ‘‘‘起始和结尾,中间为可打印的字符。

2 Token 分类


3 位置信息


3 Token 定义


1.2 Lexer 实现


待续

1.3 工程文件解析


待续

语法分析 的子部分

2.1 类型系统设计与实现


待续

2.2 抽象语法树设计与实现


待续

2.3 代码文件文件管理


待续

2.4 顶层语法解析实现


待续

2.5 解析表达式


待续

2.6 解析声明


待续

2.7 解析声明续


待续

第3章

语义分析

1 序

语义分析就是分析语法树中所有的符号是否存在声明,从语义层次进一步规范程序所表达的含义。

  • 分析符号的含义和类型。
  • 分析变量的位置偏移。
  • 分析表达式的类型,并进行类型匹配。

2 目录


    第4章

    中间优化

    第5章

    目标生成

    第6章

    中间代码

    第7章

    指令集

    1 序

    指令集可分为两大类,真实硬件指令集和虚拟机指令集。

    真实硬件指令集又分为两类:

    • CISC (复杂指令集):CISC 以 X86 系列为代表,指令系统较为复杂,硬件实现也比较复杂。
    • RISC (精简指令集):RISC 的指令系统较为精简,目的是降低硬件实现的复杂度,以 RISC-V 、ARM为代表。

    虚拟机指令集可分为三种:

    • 基于栈的指令集:纯栈操作,所有的运算都基于栈,其中以 Java 字节码指令集为代表。
    • 基于寄存器的指令集:纯寄存器操作,所有的运算基于寄存器,其中以安卓的 Dalvik 字节码指令集为代表。
    • 基于栈和寄存器的指令集:混合式操作,类似于 RISC 指令集,但是又与真实硬件系统有差异。

    虚拟机的指令与设计的字节码保存文件存在较强相关性,所以要真正理解虚拟机指令,还需要理解字节码文件的存储格式。

    2 目录


    指令集 的子部分

    7.1 基于栈的指令集


    基于栈的指令集参考Java的指令集。

    7.2 基于寄存器的指令集


    Dalvik 字节码指令集的字节码指令集不支持无符号整数运算,因此参照 Dalvik 设计了以下指令集。

    基于纯寄存器的指令集,指令系统存在下列的要求:

    • 每条指令按照 16 bit 对齐。
    • 寄存器的索引位宽有 4 bit、8 bit、16 bit。
    • 最多支持 65536 个寄存器。
    • 每个寄存器 32 bit。
    • 64 bit寄存器由相邻的两个 32 bit 寄存器组合而成。
    • 指令操作码位宽为 8 bit。
    • 指令中可有子操作码,具体位宽看具体的指令格式。
    • 32 bit 寄存器内可以存储 32 bit的整数、浮点数。
    • 64 bit 寄存器内可以存储 64 bit的整数、浮点数。
    • 位宽小于 32 位的值,需要进行扩展(零扩展、符号扩展)到 32 bit。
    • 助记符中的 I 表示寄存器索引,后面的数字表示索引位宽

    指令格式

    总体格式:

    操作码 + [ 操作子码 ] + ( 操作数 )*
    
    • 操作子码可选。
    • 操作数可以有多个。

    寄存器位宽索引支持的寄存器数量:

    位宽寄存器数量索引范围
    4 bit16[ 0, 15 ]
    8 bit256[ 0, 255 ]
    16 bit65536[ 0, 65535 ]

    空指令

    文本格式: nop

    助记符操作码对齐注解
    格式8 bit8bit指令宽度:16 bit
    nop0空操作,用于对齐

    常量赋值指令

    文本格式: op des, imm

    助记符操作码目的寄存器立即数注解
    8 bit4 bit4 bit4 bit 立即数,指令宽度:16 bit
    const-w32-I4-i4desimmimm 为有符号整数,有符号扩展至 32 bit。
    const-w64-I4-i4desimmimm 为有符号整数,有符号扩展至 32 bit。
    const-w32-I4-u4desimmimm 为无符号整数,无符号扩展至 32 bit。
    const-w64-I4-u4desimmimm 为无符号整数,无符号扩展至 32 bit。
    8 bit8 bit16 bit16 bit 立即数,指令宽度:32 bit
    const-w32-I8-i16desimmimm 为有符号整数,有符号扩展至 32 bit。
    const-w64-I8-i16desimmimm 为有符号整数,有符号扩展至 64 bit。
    const-w32-I8-u16desimmimm 为无符号整数,无符号扩展至 32 bit。
    const-w64-I8-u16desimmimm 为无符号整数,无符号扩展至 64 bit。
    const-w32-I8-L16desimmimm 为无符号整数。imm 存放在寄存器的低 16 bit,不改变高 16 bit。
    const-w32-I8-H16desimmimm 为无符号整数。imm 存放在寄存器的高 16 bit,不改变低 16 bit。
    8 bit8 bit32 bit32 bit 立即数,指令宽度:48 bit
    const-w32-I8desimm原样拷贝,支持32 bit 整数和浮点。
    const-w64-I8-i32desimmimm 为有符号整数,有符号扩展至 64 bit。
    const-w64-I8-u32desimmimm 为无符号整数,无符号扩展至 64 bit。
    8 bit8 bit64 bit64 bit 立即数,指令宽度:80 bit
    const-w64-I8desimm原样拷贝,支持64 bit整数和浮点。

    文本格式:op.sub des,imm

    助记符操作码操作子码目的寄存器立即数注解
    8 bit8 bit8 bit8 bit指令宽度:32 bit
    const-w32-I8subopdesimmimm 为无符号整数

    操作子码定义

    助记符操作子码注解
    B0imm存放在寄存器的第 1 个字节,不改变其他字节。
    B1imm存放在寄存器的第 2 个字节,不改变其他字节。
    B2imm存放在寄存器的第 3 个字节,不改变其他字节。
    B3imm存放在寄存器的第 4 个字节,不改变其他字节。

    寄存器赋值指令

    文本格式:op des,src

    文本格式:op des,src

    助记符操作码目的寄存器源寄存器注解
    8 bit4 bit4 bit指令宽度:16 bit
    move-w32-I4dessrc32 位寄存器值传递
    move-w64-I4dessrc64 位寄存器值传递
    8 bit8 bit16 bit指令宽度:32 bit
    move-w32-I8I16dessrc32 位寄存器值传递
    move-w64-I8I16dessrc64 位寄存器值传递

    文本格式:op.sub des,src

    助记符操作码操作子码目的寄存器源寄存器注解
    8 bit8 bit8 bit8 bit指令宽度:32 bit
    mov-I8subdessrc
    8 bit8 bit16 bit16 bit指令宽度:48 bit
    mov-I16subdessrc

    操作子码定义

    助记符含义:

    • 目标位宽-源数据获取转换位宽

      • i:符号扩展。
      • u:零扩展。
      • 只有目标位宽时,表示源位宽直接拷贝传递。
    • 目标类型-源类型

      • 表示从源类型转换到目标类型
    助记符操作子码注解
    w32-B0-i80获取寄存器的第 1 个字节,进行符号扩展到 32 位
    w32-B0-u81获取寄存器的第 1 个字节,进行零扩展到 32 位
    w32-B1-i82获取寄存器的第 2 个字节,进行符号扩展到 32 位
    w32-B1-u83获取寄存器的第 2 个字节,进行零扩展到 32 位
    w32-B2-i84获取寄存器的第 3 个字节,进行符号扩展到 32 位
    w32-B2-u85获取寄存器的第 3 个字节,进行零扩展到 32 位
    w32-B3-i86获取寄存器的第 4 个字节,进行符号扩展到 32 位
    w32-B3-u87获取寄存器的第 4 个字节,进行零扩展到 32 位
    w32-L16-i168获取寄存器的低 16 位,进行符号扩展到 32 位
    w32-L16-u169获取寄存器的低 16 位,进行零扩展到 32 位
    w32-H16-i1610获取寄存器的高 16 位,进行符号扩展到 32 位
    w32-H16-u1611获取寄存器的高 16 位,进行零扩展到 32 位
    w321232 位原值拷贝传递
    w64-B0-i813获取寄存器的第 1 个字节,进行符号扩展到 64 位
    w64-B0-u814获取寄存器的第 1 个字节,进行零扩展到 64 位
    w64-B1-i815获取寄存器的第 2 个字节,进行符号扩展到 64 位
    w64-B1-u816获取寄存器的第 2 个字节,进行零扩展到 64 位
    w64-B2-i817获取寄存器的第 3 个字节,进行符号扩展到 64 位
    w64-B2-u818获取寄存器的第 3 个字节,进行零扩展到 64 位
    w64-B3-i819获取寄存器的第 4 个字节,进行符号扩展到 64 位
    w64-B3-u820获取寄存器的第 4 个字节,进行零扩展到 64 位
    w64-L16-i1621获取寄存器的低 16 位,进行符号扩展到 32 位
    w64-L16-u1622获取寄存器的低 16 位,进行零扩展到 32 位
    w64-H16-i1623获取寄存器的高 16 位,进行符号扩展到 32 位
    w64-H16-u1624获取寄存器的高 16 位,进行零扩展到 32 位
    w64-i3225获取寄存器的 32 位,进行符号扩展到 64 位
    w64-u3226获取寄存器的 32 位,进行零扩展到 64 位
    w642764 位原值拷贝传递
    i32-f322832 位有符号整数转 32 位浮点数
    i32-f642932 位有符号整数转 64 位浮点数
    u32-f323032 位无符号整数转 32 位浮点数
    u32-f643132 位无符号整数转 64 位浮点数
    i64-f323264 位有符号整数转 32 位浮点数
    i64-f643364 位有符号整数转 32 位浮点数
    u64-f323464 位无符号整数转 32 位浮点数
    u64-f643564 位无符号整数转 64 位浮点数
    f32-i323632 位浮点数转 32 位有符号
    f32-i643732 位浮点数转 64 位有符号
    f32-u323832 位浮点数转 32 位无符号
    f32-u643932 位浮点数转 64 位无符号
    f32-f644932 位浮点数转 64 位浮点数
    f64-i324164 位浮点数转 32 位有符号
    f64-i644264 位浮点数转 64 位有符号
    f64-u324364 位浮点数转 32 位无符号
    f64-u644464 位浮点数转 64 位无符号
    f64-f324564 位浮点数转 32 位浮点数

    数学运算指令

    • 有二地址、三地址分类。
    • 每类的主操作码不一致。

    三地址操作

    三地址文本格式: op.sub des,src,src2

    助记符操作码操作子码目的寄存器源寄存器源操作数注解
    8 bit8 bit8 bit4 bit4 bit指令宽度:32 bit
    math-I4subdessrcsrc2
    8 bit8 bit16 bit8 bit8 bit指令宽度:48 bit
    math-I16I8subdessrcsrc2
    8 bit8 bit16 bit16 bit16 bit指令宽度:64 bit
    math-I16subdessrcsrc2

    子码定义

    助记符操作子码注解
    add-int32032 位有符号 加 +
    sub-int32132 位有符号 减 -
    mul-int32232 位有符号 乘 *
    div-int32332 位有符号 除 /
    mod-int32432 位有符号 模 %
    add-uint32532 位无符号 加 +
    sub-uint32632 位无符号 减 -
    mul-uint32732 位无符号 乘 *
    div-uint32832 位无符号 除 /
    mod-uint32932 位无符号 模 %
    add-int641064 位有符号 加 +
    sub-int641164 位有符号 减 -
    mul-int641264 位有符号 乘 *
    div-int641364 位有符号 除 /
    mod-int641464 位有符号
    add-uint641564 位无符号 加 +
    sub-uint641664 位无符号 减 -
    mul-uint641764 位无符号 乘 *
    div-uint641864 位无符号 除 /
    mod-uint641964 位无符号 模 %
    add-flt322032 位浮点 加 +
    sub-flt322132 位浮点 减 -
    mul-flt322232 位浮点 乘 *
    div-flt322332 位浮点 除 /
    mod-flt322432 位浮点 模 %
    add-flt642564 位浮点 加 +
    sub-flt642664 位浮点 减 -
    mul-flt642764 位浮点 乘 *
    div-flt642864 位浮点 除 /
    mod-flt642964 位浮点 模 %
    sl-w323032 位 左移
    sr-w323132 位 右移
    sra-w323232 位 算术右移
    rol-w323332 位 循环左移
    ror-w323432 位 循环右移
    and-w323532 位 位与
    or-w323632 位 位或
    xor-w323732 位 位异或
    sl-w643864 位 左移
    sr-w643964 位 右移
    sra-w644064 位 算术右移
    rol-w324164 位 循环左移
    ror-w324264 位 循环右移
    and-w644364 位 位与
    or-w644464 位 位或
    xor-w644564 位 位异或
    andl-w324632 位 逻辑与
    orl-w324732 位 逻辑或
    cmp-int3248src < src2 : des=-1
    cmp-uint3249src == src2 : des=0
    cmp-int6450src > src2 : des=1
    cmp-uint6451
    cmp-flt3252
    cmp-flt6453

    二地址操作

    二地址文本格式: op.sub des,src

    助记符操作码操作子码目的寄存器源寄存器源操作数注解
    8 bit8 bit8 bit8 bit指令宽度:32 bit
    math-I8subdessrc
    8 bit8 bit16 bit16 bit指令宽度:48 bit
    math-I16subdessrc

    子码定义

    助记符操作子码注解
    not-w32032 位 按位取反
    not-w64164 位 按位取反
    inv-w32232 位 逻辑取反
    inv-w64364 位 逻辑取反
    neg-int32432 位 符号取反
    neg-int64564 位 符号取反
    neg-flt32632 位 符号取反
    neg-flt64764 位 符号取反
    abs-int32832 位 取绝对值
    abs-int64964 位 取绝对值
    abs-flt321032 位 取绝对值
    abs-flt641164 位 取绝对值
    sin-flt3212三角函数
    cos-flt3213三角函数
    tan-flt3214三角函数
    asin-flt3215三角函数
    acos-flt3216三角函数
    atan-flt3217三角函数
    sin-flt6418三角函数
    cos-flt6419三角函数
    tan-flt6420三角函数
    asin-flt6421三角函数
    acos-flt6422三角函数
    atan-flt6423三角函数

    跳转指令

    直接跳转指令

    文本格式: goto imm

    助记符操作码对齐立即数注解
    8 bit8 bit指令宽度: 16 bit
    goto8imm8 bit有符号偏移
    8 bit8 bit16 bit指令宽度: 32 bit
    goto16imm
    8 bit8 bit32 bit指令宽度: 48 bit
    goto32imm

    分支跳转指令

    文本格式
    jbr src,src2,imm
    jbr src,imm
    
    • 类型编码:标识操作数的类型。
    • 操作子码:标识比较方法。
    • 和 0 比较时,无源操作数 src2。
    助记符操作码操作子码类型码源操作数源操作数立即数注解
    8 bit4 bit4 bit
    8 bit8 bit16 bit指令宽度: 32 bit
    8 bit8 bit32 bit指令宽度: 32 bit
    16 bit16 bit16 bit指令宽度: 32 bit
    16 bit16 bit32 bit指令宽度: 32 bit
    srcsrc2imm
    操作子码
    助记符操作子码注解
    eq0if( src == src2 ) goto imm
    ne1if( src != src2 ) goto imm
    lt2if( src < src2 ) goto imm
    le3if( src <= src2 ) goto imm
    gt4if( src > src2 ) goto imm
    ge5if( src >= src2 ) goto imm
    eqz6if( src == 0 ) goto imm
    nez7if( src != 0 ) goto imm
    ltz8if( src < 0 ) goto imm
    lez9if( src <= 0 ) goto imm
    gtz10if( src > 0 ) goto imm
    gez11if( src >= 0 ) goto imm

    注意: 和 0 比较时,无源操作数 src2。

    类型码
    助记符操作子码注解
    int32032 位有符号比较
    uint32132 位无符号比较
    int64264 位有符号比较
    uint64364 位无符号比较
    flt32432 位浮点数比较
    flt64564 位浮点数比较

    返回指令

    文本格式: op src op imm

    助记符操作码操作子码立即数码源操作数注解
    8 bit8 bit指令宽度: 16 bit
    return-void无参数返回
    return-w32-I8返回 32 bit 值
    return-w64-I8返回 64 bit 值
    8 bit4 bit4 bit16/32/64 bit
    操作子码
    助记符操作子码注解
    I160寄存器索引16位
    int321立即数转换到32位有符号整数
    uint322立即数转换到32位有符号整数
    int643立即数转换到32位有符号整数
    uint644立即数转换到32位有符号整数
    flt325立即数转换到32位有符号整数
    flt646立即数转换到32位有符号整数
    立即数码
    助记符操作子码注解
    B16016 位立即数
    B32132 位立即数
    B64264 位立即数

    函数调用指令

    不固定参数调用

    文本格式:op argcnt, arg,arg2,…,func

    助记符操作码参数个数参数寄存器函数注解
    8 bit8 bit16 bit32 bit
    invoke-virtual-nofixargcntarg…func调用虚函数
    invoke-direct-nofixargcntarg…func直接调用函数
    invoke-static-nofixargcntarg…func调用静态函数
    invoke-interface-nofixargcntarg…func调用接口函数
    invoke-native-nofixargcntarg…func调用C语言函数

    范围参数调用

    文本格式:op argcnt,start, end,func

    助记符操作码参数个数起始寄存器结束寄存器索引函数注解
    8 bit8 bit16 bit16 bit32 bit
    invoke-virtual-rangeargcntarg…func调用虚函数
    invoke-direct-rangeargcntarg…func直接调用函数
    invoke-static-rangeargcntarg…func调用静态函数
    invoke-interface-rangeargcntarg…func调用接口函数
    invoke-native-rangeargcntarg…func调用C语言函数

    获取返回值指令

    文本格式:op des

    助记符操作码对齐源寄存器注解
    8 bit8 bit指令宽度: 16 bit
    get-result-w32-I8des获取32位返回值
    get-result-w64-I8des获取64位返回值
    get-result-obj-I8des获取对象返回值
    8 bit8 bit16 bit指令宽度: 32 bit
    get-result-w32-I16des获取32位返回值
    get-result-w64-I16des获取64位返回值
    get-result-obj-I16des获取对象返回值

    异常处理指令

    文本格式:op des

    助记符操作码对齐源寄存器注解
    8 bit8 bit指令宽度: 16 bit
    get-exception-I8des获取异常对象
    throw-I8src抛出异常对象
    8 bit8 bit16 bit指令宽度: 32 bit
    get-exception-I16des获取异常对象
    throw-I16src抛出异常对象

    7.3 基于栈和寄存器的指令集


    本章节描述的是作者按照 RISC 指令系统设计的虚拟机指令集。

    其类似与硬件指令集,可作为编译器后端指令系统目标,用于提供类似硬件指令系统环境,避免编译原理初学者陷入对硬件指令系统不了解的深渊。 降低学习难度,提高学习效率。

    这类指令的主要特点如下:

    • 1 寄存器的数量固定;
    • 2 指令所操作的寄存器数量固定;
    • 3 指令的含义简单;

    1 寄存器

    虚拟机的寄存器分为三种:

    • 1 整数寄存器:主要用于整数运算,位宽为 64 bit,根据指令的含义可选择 32 bit 和 64 bit 运算模式。
    • 2 浮点寄存器:主要用于浮点数运算,位宽为 64 bit,和通用寄存器一致,可选择位宽模式。
    • 3 系统寄存器:对用户不可见,与虚拟机运行系统相关,对其进行操作隐藏在相关指令的实现细节中。
    • 4 根据指令格式,整数寄存器、浮点寄存器最多可以有32个。

    2 指令格式

    每条指令是 32bit 大小对齐的,其中最低 9bit 是操作码,其余23bit作为操作数或者操作码的补充。如下表所示:

    操作码操作数
    9 bit23 bit

    2.1 格式1

    操作码操作数
    9 bit23 bit

    2.2 格式2

    多数指令使用此格式。

    操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit

    2.3 格式3

    该格式主要用于比较指令后的三元选择赋值操作。

    操作码目的操作数源操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit5 bit3 bit

    2.4 格式4

    当指令中需要使用立即数时,且在指令中没有足够的空间可以存储时,可以使用指令后跟32bit对齐的立即数操作数。

    • 32bit立即数:32bit 指令跟 1 个 32bit 立即数,虚拟机解析执行时,按照指令表达的语义参与运算。
    • 64bit立即数:32bit 指令跟 2 个 32bit 立即数,虚拟机解析执行时,按照指令表达的语义,组合成 64bit,后参与运算。
    • 其他位宽的立即数类似。

    格式如下所示:

    指令立即数 1立即数 2立即数 n
    32 bit32 bit32 bit32 bit

    3 寄存器与寄存器—指令集

    3.1 空指令

    空指令一般用于对齐,在本指令集中没有特殊含义,执行空操作。

    格式如下:

    助记符操作码操作数
    9 bit23 bit
    Nop00

    3.2 算术运算

    算术运算包含 +、-、*、/、%,支持的运算类型有 int32、uint32、int64、uint64、flt32、flt64。

    • 文本格式: op des,src,src2
    • 指令含义:des = src op src2
    • 子操作码:可以用于将运算结果进行截断、扩展。
    • 助记符后缀的数字(32、64)标识指令运算使用的寄存器位宽。
    • 助记符后缀的 i 表示进行有符号运算。
    • 助记符后缀的 u 表示进行无符号运算。
    • 助记符后缀的 f 表示进行有符号运算。

    指令格式如下所示:

    助记符操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit
    add-i32dessrcsrc2
    sub-i32dessrcsrc2
    mul-i32dessrcsrc2
    div-i32dessrcsrc2
    mod-i32dessrcsrc2
    add-u32dessrcsrc2
    sub-u32dessrcsrc2
    mul-u32dessrcsrc2
    div-u32dessrcsrc2
    mod-u32dessrcsrc2
    add-i64dessrcsrc2
    sub-i64dessrcsrc2
    mul-i64dessrcsrc2
    div-i64dessrcsrc2
    mod-i64dessrcsrc2
    add-u64dessrcsrc2
    sub-u64dessrcsrc2
    mul-u64dessrcsrc2
    div-u64dessrcsrc2
    mod-u64dessrcsrc2
    add-f32dessrcsrc2
    sub-f32dessrcsrc2
    mul-f32dessrcsrc2
    div-f32dessrcsrc2
    add-f64dessrcsrc2
    sub-f64dessrcsrc2
    mul-f64dessrcsrc2
    div-f64dessrcsrc2

    3.2 位运算

    位运算包括位相关的与、或、非、异或、移位、取反等运算。

    支持的运算类型有 uint32、uint64。

    • 文本格式: op des,src,src2
    • 指令含义:des = src op src2
    • 子操作码:可以用于将运算结果进行截断、扩展。
    • i32:表示进行 32bit 的位运算。
    • i64:表示进行 64bit 的位运算。
    • 位运算都是看作无符号运算。

    指令格式如下所示:

    助记符操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit
    sl-i32dessrcsrc2
    sr-i32dessrcsrc2
    sra-i32dessrcsrc2
    and-i32dessrcsrc2
    or-i32dessrcsrc2
    xor-i32dessrcsrc2
    andn-i32dessrcsrc2
    orn-i32dessrcsrc2
    xorn-i32dessrcsrc2
    not-i32dessrcsrc2
    sl-i64dessrcsrc2
    sr-i64dessrcsrc2
    sra-i64dessrcsrc2
    and-i64dessrcsrc2
    or-i64dessrcsrc2
    xor-i64dessrcsrc2
    andn-i64dessrcsrc2
    orn-i64dessrcsrc2
    xorn-i64dessrcsrc2
    not-i64dessrcsrc2

    3.3 逻辑比较

    逻辑比较运算包括:<、>、<=、>=、==、!=、 ==0、!=0. 支持的运算类型有 int32、uint32、int64、uint64、flt32\flt64。

    • 文本格式: op des,src,src2
    • 指令含义:des = src op src2
    • 子操作码:可以用于标识比较的方法。
    • 比较的结果,存储在整数寄存器中,且使用位宽 64 bit,即des是整数寄存器。

    指令格式如下所示:

    助记符操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit
    cmp-i32dessrcsrc2
    cmp-u32dessrcsrc2
    cmp-i64dessrcsrc2
    cmp-u64dessrcsrc2
    cmp-f32dessrcsrc2
    cmp-f64dessrcsrc2

    操作子码定义如下:

    助记符操作码含义
    lt<
    le<=
    gt>
    ge>=
    eq==
    ne!=
    ez==0,此时没有源操作数src2
    nz!=0,此时没有源操作数src2

    当不使用操作子码,而是使用下面方式运算:

    • src < src2,设置des寄存器为 -1。
    • src == src2,设置des寄存器为 0。
    • src > src2,设置des寄存器为 -1。

    3.4 条件赋值

    条件赋值指令使用比较指令的结果,对另外 2 个源操作数进行选择,传递个目标操作数。

    指令格式如下所示:

    助记符操作码目的操作数源操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit5 bit3 bit
    sel-i32dessrcsrc2cond
    sel-u32dessrcsrc2cond
    sel-i64dessrcsrc2cond
    sel-u64dessrcsrc2cond
    sel-f32dessrcsrc2cond
    sel-f64dessrcsrc2cond

    当比较系列指令使用操作子码方式时:

    • cond == 0 :des = src
    • cond != 0 :des = src2

    当比较系列指令不使用操作子码方式时,本系列指令要求使用操作子码进行判断:

    操作子码定义如下:

    助记符操作码含义
    lt< :des = cond == -1 ? src : src2
    le<= :des = cond < 1 ? src : src2
    gt> :des = cond == 1 ? src : src2
    ge>= :des = cond > -1 ? src : src2
    eq== :des = cond == 0 ? src : src2
    ne!= :des = cond != 0 ? src : src2

    3.5 赋值指令

    此系列包括寄存器间赋值或类型转换。

    助记符操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit
    movdessrc

    操作子码用于获取源操作数并转换到响应的类型。

    操作子码定义如下:

    助记符操作码含义
    i8-i32
    u8-i32
    i8-i64
    u8-u64
    i16-i32
    u16-i32
    i16-i64
    u16-i64
    i32_i32
    i32-i64
    i32-f32
    i32-f64
    u32-u32
    u32-u64
    u32-f32
    u32-f64
    i64-i64
    i64-f32
    i64-f64
    u64-u64
    u64-f32
    u64-f64
    f32-i32
    f32-u32
    f32-i64
    f32-u64
    f32-f32
    f32-f64
    f64-i32
    f64-u32
    f64-i64
    f64-u64
    f64-f32
    f64-f64
    f32-bit-u32位转换
    u32-bit-f32位转换
    f64-bit-u64位转换
    u64-bit-f64位转换

    3.6 加载存储指令

    此系列指令功能是从内存中读取、存储特定类型数据。

    助记符操作码目的操作数源操作数源操作数操作子码注释
    9 bit5 bit5 bit5 bit8 bit
    loaddesbaseoffset从基址内存中获取数据
    storedesbaseoffset
    gloaddesbaseoffset从全局内存中获取数据
    gstoredesbaseoffset

    操作子码定义如下:

    助记符操作码含义
    i8
    u8
    i16
    u16
    i32
    u32
    i64
    u64
    f32
    f64

    3.7 出入栈指令

    此系列指令用于将数据入栈,同时可以进行类型转换。 注意:入栈数据应当进行 32bit 对齐。以加快虚拟机执行速度数据

    助记符操作码目的操作数源操作数源操作数操作子码
    9 bit5 bit5 bit5 bit8 bit
    pushdes
    popdes
    操作子码定义如下:
    助记符操作码含义
    i8
    u8
    i16
    u16
    i32
    u32
    i64
    u64
    f32
    f64

    3.8 栈内存分配释放

    此系列指令用于栈内存分配释放。 注意:立即数是无符号整数。

    助记符操作码目的操作数立即数注释
    9 bit5 bit18 bit
    growndesimm分配栈内存,将分配后的栈指针值传递到 des 寄存器
    9 bit23 bit释放栈内存,
    shrunkimm

    3.9 跳转指令

    • 跳转的偏移量是无符号整数值;
    • 相对于函数代码的起始地址;
    • 偏移量是偏移的指令条数;
    助记符操作码目的操作数立即数注释
    9 bit23 bit
    jmpimm直接跳转
    9 bit5 bit18 bit
    jmpxreg偏移量在 reg 寄存器中
    9 bit5 bit18 bit
    jtabregimmreg 表示偏移量索引,imm表示偏移量数组中偏移数据条数,指令后面接 32 bit 对齐的偏移量数组

    3.10 分支指令

    此系列指令用于条件分支跳转。

    助记符操作码目的操作数源操作数源操作数操作子码偏移立即数
    9 bit5 bit5 bit5 bit8 bit32 bit
    jbr-i32srcsrc2condoffset
    jbr-u32srcsrc2condoffset
    jbr-i64srcsrc2condoffset
    jbr-u64srcsrc2condoffset
    jbr-f32srcsrc2condoffset
    jbr-f64srcsrc2condoffset

    操作子码定义如下:

    助记符操作码含义
    lt<
    le<=
    gt>
    ge>=
    eq==
    ne!=
    ez==0,此时没有源操作数src2
    nz!=0,此时没有源操作数src2

    3.11 函数指令

    助记符操作码目的操作数立即数注释
    9 bit23 bit32 bit
    callimmimm表示函数的偏移量或者是编号,看虚拟机的具体实现
    9 bit5 bit18 bit
    callxregreg 寄存器中保存函数的偏移量或者是编号,看虚拟机的具体实现
    9 bit23 bit
    ret函数返回

    4 寄存器与立即数–指令集

    待续

    语言定义 的子部分

    8.1 语法定义


    语法使用非严格的EBNF语法描述。

    文件单元
    FileUnit = PkgDef (ImportDef) Decl*
    
    包定义
    PkgDef = package ID (.ID)*
    
    依赖导入(可选)
    ImportDef = 'import' STRING as ID; |'{' (STRING as ID; )* '}'
    声明定义
    Decl = ScopeDecl | VarDecl | FuncDecl | EnumDecl | StructDecl | UnionDecl | InterfaceDecl | ClassDecl | EntrustDecl | ~
    
    表达式
    Exp = BaseExp | DotExp | UnaryExp | BinaryExp | TernaryExp | NewExp | PriorityExp
    
    基础表达式
    BaseExp = IDExp | ConstExp | CallExp | ArrarExp | ThisExp | SuperExp
    IDExp = ID
    ConstExp = c
    CallExp = ID '(' ArgList')'
    ArrarExp = ID '[' Exp ']'
    ThisExp = 'this'
    SuperExp = 'super'
    
    成员访问表达式
    DotExp = BaseExp ( '.' BaseExp)*  //BaseExp不得是ConstExp
    
    一元表达式
    UnaryExp = UnaryOP BaseExp
    UnaryOP = '-' | '+' | '--' | '++' | '~' | '!'
    二元表达式
    BinaryExp = Exp BinaryOP Exp
    BinaryOP = '+' | '-' | '*' | '/' | '%' |
                '&' | '|' | '&&' | '||' |
                '<<' | '>>' | '>>>' |
                '<' | '>' | '<=' | '>=' |
                '==' | '!=' | '=' |
                
    三元表达式
    TernaryExp = Exp '?' Exp ':' Exp
    
    括号表达式
    PriorityExp = '(' Exp ')'
    
    作用域声明
    ScopeDecl = ( 'public' | 'protected' | 'private' ) ':'
    
    变量声明
    VarDecl = Scope Type 'id' [=initExp] ';'
    Scope = ['public' | 'protected' | 'private'| 'extern' | 'static'] 
    Type = ['const' ] 'id'( '.' 'id')*
    
    代理变量
    Scope Type 'id''(' [ arglist] ')' 'delegate' ';'
    
    闭包变量
    Scope Type 'id''(' [ arglist] ')' 'closure' ';'
    
    函数申明
    VarDecl = Scope Type 'id''(' [ arglist] ')'[@override] [@cfun] [const] [final] (';' |  funbody )
    arglist = argitem (',' argitem)*
    argitem = type ['id']
    funbody = BlkState
    BlkState = '{' [Statement] '}'
    Statement = ( BlkState | ExpState | IfState | ElseifState |
    			ElseState | SwitchState | ForState | DoState |
    			WhileState | GotoState | BreakState | ContinueState |
    			ReturnState )*
    	
    
    TypeDecl = EnumDecl | StructDecl |  UnionDecl |EntrustDecl
    FuncDecl = Type 'id''(' [ arglist] ')' '=' Serial
    	Serial = 'u32'
    	枚举声明
    	EnumDecl = 'enum' id [: BaseType]'{' EnumItem* '}'
    	BaseType = 基本整数类型
    	EnumItem = 'id'[=initExp] ','

    8.2 代码结构


    每一个文件都必须定义一个作用域名,其他内容在此作用域定义。

    生成的声明符号都在该作用域内,只能通过该作用域才能访问代码文件中声明的符号内容。

    代码结构

    包声明

    package pkg.pkg2;
    

    依赖单元

    Import file=“dir/file.ext”;
    Import file2=“dir/file2.ext”;
    

    或者

    Import{
    
    	file=“dir/file.ext” ;
    	file2=“dir/file2.ext”;
    }
    

    枚举定义

    enum name : int32{
        item=0,
        item2=23,
        …
    }
    

    结构体定义

    Struct name{
    	Int32 i32;
    	Union{
    		Int32 s32;
    		Flt32 f32;
        }
    }
    

    联合体定义

    Union name{
    	Int32 s32;
    	Flt32 f32;
    	Struct{…}
    }
    

    接口定义

    Interface IFather{
        void eat(int32 arg);
    }
    Interface IFather2{
        void say(int32 arg);
    }
    Interface IChild :[ IFather,IFather2 ]{
        void walk(int32 arg);
    }
    

    类定义

    Class Parent {
    Private:
            Int32 mI32;
    Public	Flt32 mF32;
    Public:
        Void print(){}
    Protected void toString(){}
        Virtual void vfun()=0;
    }
    
    Class child: Parent :[ IChild ]{
        void eat(int32 arg) @override{}
        void say(int32 arg) @override{}
        void walk(int32 arg) @override{}
        void vfun()@override{}
    }

    8.3 关键字


    airlang 的关键字分为两种:普通关键字,宏关键字。 两者差别不大,但是宏关键字有特殊的标记作用,一般用于注解一些信息。

    宏关键字

    关键字注解
    @file代码中获取文件的名称字符串
    @line代码中获取代码所作行号数字
    @func代码中获取函数声明字符串
    @debug用于标记只在debug标志下启用的代码
    @NotNulptr用于标记需要检查函数的指针参数非空
    @override标记非静态成员函数是重写父类的函数

    普通关键字

    固定位宽类型关键字注解位宽(bit)
    void空,一般用于表示无返回值0
    bool布尔类型8
    flt3232位单精度浮点32
    flt6464位双精度浮点32
    int88位有符号整数8
    int168位有符号整数16
    int328位有符号整数32
    int648位有符号整数64
    uint88位无符号整数8
    uint1616位无符号整数16
    uint3232位无符号整数32
    uint6464位无符号整数64
    char字符8

    可变位宽类型的位宽由编译的目标CPU架构有关。

    可变位宽类型关键字注解CPU32CPU64
    sint有符号整数3264
    uint无符号整数3264
    uintptr指针3264
    cstring字符串指针3264
    修饰关键字注解
    static静态
    public完全公开的
    protected对部分成员公开的
    private私有的 成员
    const常量化,只读
    friend友元定义
    分支关键字注解
    if比较分支
    elsif次比较分支
    else比较默认分支
    for循环
    foreach循环
    while循环
    do循环
    break跳出循环
    continue继续下一轮循环
    goto跳转到标签
    return函数返回
    类型定义关键字注解
    enum枚举
    struct结构体
    union联合体
    interface接口
    class
    entrust委托指针
    其他关键字注解
    false
    true
    nullptr
    this
    super

    8.4 操作符


    成员访问操作符

    成员访问操作符的优先级最高。

    成员访问操作符优先级注解
    .0成员访问
    .?0带null检查的成员访问

    一元操作符

    一元操作符优先级一致,主要查看其声明的先后顺序。

    一元操作符优先级注解
    ~-10按位取反
    !-10逻辑取反
    --10符号取反
    +-10取绝对值
    ++-10自增
    ---10自减

    二元操作符

    在语法解析表达式中,二元表达式最复杂的。

    二元操作符优先级注解
    *-20乘运算操作符
    /-20除运算操作符
    %-20模运算操作符
    +-30加运算操作符
    --30减运算操作符
    <<-40左移操作符
    >>-40逻辑右移操作符
    >>>-40算术右移操作符
    <-50小于操作符
    <=-50小于等于操作符
    >-50大于于操作符
    >=-50大于等于操作符
    ==-60等于操作符
    !=-60不等于操作符
    &-70位与操作符
    ^-71位异或操作符
    |-72位或操作符
    &&-80逻辑与操作符
    ||-81逻辑或操作符

    三元操作符

    三元操作符主要用于比较赋值、简单的比较分支操作。

    三元操作符优先级注解
    ? :-90

    赋值操作符

    赋值类操作符的优先级一致,优先级最低。

    赋值操作符优先级注解
    =-100赋值操作符
    *=-100乘运算复合赋值操作符
    /=-100除运算复合赋值操作符
    %=-100模运算复合赋值操作符
    +=-100加运算复合赋值操作符
    -=-100减运算复合赋值操作符
    &=-100位与运算复合赋值操作符
    =-100位或运算复合赋值操作符
    ^=-100位异或运算复合赋值操作符
    ~=-100位取反运算复合赋值操作符
    <<=-100左移运算复合赋值操作符
    >>=-100逻辑右移运算复合赋值操作符
    >>>=-100算术右移运算复合赋值操作符

    其他操作符

    括号表达式中的括号操作符,用于提升表达式的优先级,在算符优先解析算法,该系列是作为基本表达式进行解析的。

    括号操作符优先级注解
    ()-10括号操作符
    []-10数组下标
    cast-10静态类型转换
    dyn_cast-10动态类型转换
    ()-10函数调用

    8.5 类型系统


    基本类型

    固定位宽类型注解位宽(bit)
    void空,一般用于表示无返回值
    bool布尔类型8
    flt3232位单精度浮点32
    flt6464位双精度浮点32
    int88位有符号整数8
    int168位有符号整数16
    int328位有符号整数32
    int648位有符号整数64
    uint88位无符号整数8
    uint1616位无符号整数16
    uint3232位无符号整数32
    uint6464位无符号整数64
    char字符8

    可变位宽类型的位宽由编译的目标CPU架构有关。

    可变位宽类型注解CPU32CPU64
    sint有符号整数3264
    uint无符号整数3264
    uintptr指针3264
    cstring字符串指针3264

    枚举类型

    枚举定义只能是定义整数类的值,其占用的字节数、有无符号性,通过基类标识指定。

    如下所示:

    enum Color:uint32{
        Red,
        Black,
    }

    结构体

    结构体在airlang中是值类型,不会进入GC系统,除通过API分配独立的堆内存。

    一般用于构成类中的共同属性。

    struct Vec2{
        int32 x;
        int32 y;
    }
    struct Vec3 :Vec2{
        int32 z;
    }

    联合体

    union Int32{
        int32 i32;
        struct{
            int8 [4] v4;
        }
    }

    接口

    interface IEvent{
        void eat();
    }

    class Parent{
     int32 i32;
    
     void doing(){} 
    }
    class Child :Parent <IEvent>{
        int64 i64;
        void eat()@override{}
    }

    委托

    entrust Func = void (int32,int64)@clang;