microPython的源码解析之 showbc.c

MicroPython 是一种适用于微控制器和其他受限环境的 Python 编程语言的实现。它旨在提供与 Python 3 语言的紧密兼容,同时考虑到内存和计算资源的限制。MicroPython 库是这门语言的核心组成部分,提供了一系列的模块和函数,使得开发者能够在硬件上执行各种任务。
下面将通过系列文章,逐一解读microPython,以便让读者了解掌握microPython的整个核心逻辑.,以便读者可以透过这个Python的最小内核,掌握Python解析器的核心实现逻辑,学习世界上最优秀的源码设计之一.


microPython Python最小内核源码解析
NI-motion运动控制c语言示例代码解析
python编程示例系列 python编程示例系列二
python的Web神器Streamlit


这段代码是一个用于打印MicroPython字节码的调试工具。它定义了一系列宏来解码字节码中的不同部分,如标签、字符串、指针和对象等。然后,它提供了两个主要的函数:mp_bytecode_printmp_bytecode_print2,用于递归地打印整个字节码对象的内容。这对于开发者在开发和调试MicroPython程序时非常有用,因为它可以显示程序的底层操作和流程。代码中的注释详细解释了每个步骤和指令的作用,有助于理解字节码的结构和执行逻辑。

#include <stdio.h>
#include <assert.h>

#include "py/bc0.h"
#include "py/emitglue.h"

#if MICROPY_DEBUG_PRINTERS

// 定义解码无符号整数的宏
#define DECODE_UINT {
      \
        unum = 0; \
        do {
      \
            unum = (unum << 7) + (*ip & 0x7f); \
        } while ((*ip++ & 0x80) != 0); \
}

// 定义解码无符号标签的宏
#define DECODE_ULABEL \
    do {
      \
        if (ip[0] & 0x80) {
      \
            unum = ((ip[0] & 0x7f) | (ip[1] << 7)); \
            ip += 2; \
        } else {
      \
            unum = ip[0]; \
            ip += 1; \
        } \
    } while (0)

// 定义解码有符号标签的宏
#define DECODE_SLABEL \
    do {
      \
        if (ip[0] & 0x80) {
      \
            unum = ((ip[0] & 0x7f) | (ip[1] << 7)) - 0x4000; \
            ip += 2; \
        } else {
      \
            unum = ip[0] - 0x40; \
            ip += 1; \
        } \
    } while (0)

// 定义解码字符串的宏
#if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
#define DECODE_QSTR \
    DECODE_UINT; \
    qst = qstr_table[unum]
#else
#define DECODE_QSTR \
    DECODE_UINT; \
    qst = unum;
#endif

// 定义解码指针的宏
#define DECODE_PTR \
    DECODE_UINT; \
    unum = (mp_uint_t)(uintptr_t)child_table[unum]

// 定义解码对象的宏
#define DECODE_OBJ \
    DECODE_UINT; \
    unum = (mp_uint_t)obj_table[unum]

// 打印字节码的函数
void mp_bytecode_print(const mp_print_t *print, const mp_raw_code_t *rc, size_t fun_data_len, const mp_module_constants_t *cm) {
   
    const byte *ip_start = rc->fun_data; // 指向函数数据的起始地址
    const byte *ip = rc->fun_data; // 指向当前处理的字节码

    // 解码序言部分
    MP_BC_PRELUDE_SIG_DECODE(ip); // 解码函数签名
    MP_BC_PRELUDE_SIZE_DECODE(ip); // 解码函数大小
    const byte *code_info = ip; // 指向代码信息的地址

    // 解码块名称和源文件
    qstr block_name = mp_decode_uint(&code_info); // 解码块名称
    #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
    block_name = cm->qstr_table[block_name]; // 获取块名称
    qstr source_file = cm->qstr_table[0]; // 获取源文件名称
    #else
    qstr source_file = cm->source_file; // 直接获取源文件名称
    #endif
    mp_printf(print, "文件 %s, 代码块 '%s' (描述符: %p, 字节码 @%p %u 字节)\n",
        qstr_str(source_file), qstr_str(block_name), rc, ip_start, (unsigned)fun_data_len);

    // 打印原始字节码
    size_t prelude_size = ip - ip_start + n_info + n_cell; // 计算序言大小
    mp_printf(print, "原始字节码 (code_info_size=%u, bytecode_size=%u):\n",
        (unsigned)prelude_size, (unsigned)(fun_data_len - prelude_size));
    for (size_t i = 0; i < fun_data_len; i++) {
   
        if (i > 0 && i % 16 == 0) {
   
            mp_printf(print, "\n");
        }
        mp_printf(print, " %02x", ip_start[i]); // 打印字节码
    }
    mp_printf(print, "\n");

    // 打印参数名称
    mp_printf(print, "参数名称:");
    for (mp_uint_t i = 0; i < n_pos_args + n_kwonly_args; i++) {
   
        qstr qst = mp_decode_uint(&code_info); // 解码参数名称
        #if MICROPY_EMIT_BYTECODE_USES_QSTR_TABLE
        qst = cm->qstr_table[qst]; // 获取参数名称
        #endif
        mp_printf(print, " %s", qstr_str(qst)); // 打印参数名称
    }
    mp_printf(print, "\n");

    mp_printf(print, "(N_STATE %u)\n", (unsigned)n_state); // 打印状态数量
    mp_printf(print, "(N_EXC_STACK %u)\n", (unsigned)n_exc_stack); // 打印异常堆栈数量

    // 跳过代码信息
    ip += n_info;
    const byte *line_info_top = ip; // 指向行号信息的顶部

    // 打印闭包变量的初始值
    
  • 10
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

openwin_top

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值