MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.
这段代码是一个C语言的源文件,它实现了一个微型Python解释器的字节码生成器。代码中包含了很多与生成和操作Python字节码相关的函数。
#include <stdbool.h> // 包含布尔类型的定义
#include <stdint.h> // 包含固定宽度整数类型的定义
#include <stdio.h> // 包含标准输入输出库
#include <string.h> // 包含字符串操作函数
#include <unistd.h> // 包含UNIX标准工具库
#include <assert.h> // 包含断言宏
// 包含MicroPython特有的头文件
#include "py/mpstate.h"
#include "py/smallint.h"
#include "py/emit.h"
#include "py/bc0.h"
// 条件编译,只有在启用编译器的情况下才编译以下代码
#if MICROPY_ENABLE_COMPILER
// 定义一个临时数据的大小,用于编码最大的无符号整数
#define DUMMY_DATA_SIZE (MP_ENCODE_UINT_MAX_BYTES)
// 定义字节码发射器的结构体
struct _emit_t {
// 临时数据,用于存储字节码和代码信息
byte dummy_data[DUMMY_DATA_SIZE];
// 当前遍历的阶段
pass_kind_t pass : 8;
// 如果设置为true,则代码生成器应该抑制发射代码,因为它是死代码
bool suppress;
// 栈大小
int stack_size;
// 指向公共发射器的指针
mp_emit_common_t *emit_common;
// 指向当前作用域的指针
scope_t *scope;
// 上一条源代码行的偏移量和行号
mp_uint_t last_source_line_offset;
mp_uint_t last_source_line;
// 标签的最大数量
size_t max_num_labels;
// 标签偏移量的数组
size_t *label_offsets;
// 代码信息的偏移量和大小
size_t code_info_offset;
size_t code_info_size;
// 字节码的偏移量和大小
size_t bytecode_offset;
size_t bytecode_size;
// 存储字节码和代码信息的指针
byte *code_base;
// 标记是否溢出
bool overflow;
// 信息的数量和单元格的数量
size_t n_info;
size_t n_cell;
};
// 创建一个新的字节码发射器
emit_t *emit_bc_new(mp_emit_common_t *emit_common) {
emit_t *emit = m_new0(emit_t, 1);
emit->emit_common = emit_common;
return emit;
}
// 设置发射器的最大标签数量
void emit_bc_set_max_num_labels(emit_t *emit, mp_uint_t max_num_labels) {
emit->max_num_labels = max_num_labels;
emit->label_offsets = m_new(size_t, emit->max_num_labels);
}
// 释放发射器占用的资源
void emit_bc_free(emit_t *emit) {
m_del(size_t, emit->label_offsets, emit->max_num_labels);
m_del_obj(emit_t, emit);
}
// 通过这个函数来发射代码信息
static uint8_t *emit_get_cur_to_write_code_info(void *emit_in, size_t num_bytes_to_write) {
emit_t *emit = emit_in;
if (emit->pass < MP_PASS_EMIT) {
// 在非发射阶段,更新偏移量但不写入实际数据
emit->code_info_offset += num_bytes_to_write;
return emit->dummy_data;
} else {
// 在发射阶段,确保写入的字节不会超出代码信息的大小
assert(emit->code_info_offset + num_bytes_to_write <= emit->code_info_size);
byte *c = emit->code_base + emit->code_info_offset;
emit->code_info_offset += num_bytes_to_write;
return c;
}
}
// 发射一个字节的代码信息
static void emit_write_code_info_byte(emit_t *emit, byte val) {
*emit_get_cur_to_write_code_info(emit, 1) = val;
}
// 发射一个qstr(字符串)的代码信息
static void emit_write_code_info_qstr(emit_t *emit, qstr qst) {
// 编码并发射qstr
mp_encode_uint(emit, emit_get_cur_to_write_code_info, mp_emit_common_use_qstr(emit->emit_common, qst));
}
#if MICROPY_ENABLE_SOURCE_LINE
// 发射源代码行号信息
static void emit_write_code_info_bytes_lines(emit_t *emit, mp_uint_t bytes_to_skip, mp_uint_t lines_to_skip) {
assert(bytes_to_skip > 0 || lines_to_skip > 0);
while (bytes_to_skip > 0 || lines_to_skip > 0) {
mp_uint_t b, l;
if (lines_to_skip <= 6 || bytes_to_skip > 0xf) {
// 使用0b0LLBBBBB编码
b = MIN(bytes_to_skip, 0x1f);
if (b < bytes_to_skip) {
// 无法跳过任何行,直到跳过所有字节
l = 0;
} else {
l = MIN(lines_to_skip, 0x3);
}
*emit_get_cur_to_write_code_info(emit, 1) = b | (l << 5);
} else {
// 使用0b1LLLBBBB 0bLLLLLLLL编码(低位在第二字节)
b = MIN(bytes_to_skip, 0xf);
l = MIN(lines_to_skip, 0x7ff);
byte *ci = emit_get_cur_to_write_code_info(emit, 2);
ci[0] = 0x80 | b | ((l >> 4) & 0x70);
ci[1] = l;
}
bytes_to_skip -= b;
lines_to_skip -= l;
}
}
#endif
// 通过这个函数来发射字节码
static uint8_t *emit_get_cur_to_write_bytecode(void *emit_in, size_t num_bytes_to_write) {
emit_t *emit = emit_in;
if (emit->suppress) {
// 如果抑制发射,则不写入实际数据
return emit->dummy_data;
}
if (emit->pass < MP_PASS_EMIT) {
// 在非发射阶段,更新偏移量但不写入实际数据
emit->bytecode_offset += num_bytes_to_write;
return emit->dummy_data;
} else {
// 在发射阶段,确保写入的字节不会超出字节码的大小
assert(emit->bytecode_offset + num_bytes_to_write <= emit->bytecode_size);
byte *c = emit->code_base + emit->code_info_size + emit->bytecode_offset;
emit->bytecode_offset += num_bytes_to_write;
return c;
}
}
// 发射一个字节的原始字节码
static void emit_write_bytecode_raw_byte(emit_t *emit, byte b1) {
byte *c = emit_get_cur_to_write_bytecode(emit, 1);
c[0] = b1;
}
// 发射一个字节的字节码,并调整栈大小
static void emit_write_bytecode_byte(emit_t *emit, int stack_adj, byte b1) {
mp_emit_bc_adjust_stack_size(emit, stack_adj);
byte *c = emit_get_cur_to_write_bytecode(emit, 1);
c[0] = b1;
}
// 发射一个字节的字节码,并编码一个整数
static void emit_write_bytecode_byte_int(emit_t *emit, int stack_adj, byte b1, mp_int_t num) {
emit_write_bytecode_byte(emit, stack_adj, b1);
// 将每个7位存储在一个单独的字节中,这就是需要的字节数
byte buf[MP_ENCODE_UINT_MAX_BYTES];
byte *p = buf + sizeof(buf);
// 我们以小端序编码,但以大端序存储,以帮助解码
do {
*--p = num & 0x7f;
num >>= 7;
} while (num != 0 && num != -1);
// 确保我们存储的最高位(掩码0x40)与数字的符号相匹配
// 如果不是,则存储一个额外的字节只为了编码符号
if (num == -1 && (*p & 0x40) == 0) {
*--p = 0x7f;
} else if (num == 0 && (*p & 0x40) != 0) {
*--p = 0;
}
byte *c = emit_get_cur_to_write_bytecode(emit, buf + sizeof(buf) - p);
while (p != buf + sizeof(buf) - 1) {
*c++ = *p++ | 0x80;
}
*c = *p;
}
// 发射一个字节的字节码,并编码一个无符号整数
static void emit_write_bytecode_byte_uint(emit_t *emit, int stack_adj, byte b, mp_uint_tval) {
emit_write_bytecode_byte(emit, stack_adj, b);
mp_encode_uint(emit, emit_get_cur_to_write_bytecode, val);
}
// 发射一个字节的字节码,并编码一个常量
static void emit_write_bytecode_byte_const(emit_t *emit, int stack_adj, byte b, mp_uint_t n) {
emit_write_bytecode_byte_uint(emit, stack_adj, b, n);
}
// 发射一个字节的字节码,并编码一个字符串
static void emit_write_bytecode_byte_qstr(emit_t *emit, int stack_adj, byte b, qstr qst) {
emit_write_bytecode_byte_uint(emit, stack_adj, b, mp_emit_common_use_qstr(emit->emit_common, qst));
}
// 发射一个字节的字节码,并编码一个对象
static void emit_write_bytecode_byte_obj(emit_t *emit, int stack_adj, byte b, mp_obj_t obj) {
emit_write_bytecode_byte_const(emit, stack_adj, b, mp_emit_common_use_const_obj(emit->emit_common, obj));
}
// 发射一个字节的字节码,并编码一个子代码对象
static void emit_write_bytecode_byte_child(emit_t *emit, int stack_adj, byte b, mp_raw_code_t *rc) {
emit_write_bytecode_byte_const(emit, stack_adj, b,
mp_emit_common_alloc_const_child(emit->emit_common, rc));
#if MICROPY_PY_SYS_SETTRACE
// 设置子代码对象的行号定义
rc->line_of_definition = emit->last_source_line;