microPython的源码解析之 parsenum.c

本文深入解析MicroPython中用于解析数字的parsenum.c源码,包括解析整数、浮点数和复数的过程。文章通过详细讲解关键函数的功能和执行逻辑,帮助读者理解MicroPython核心解析器的实现。同时,文章提供了函数流程图以辅助理解。
摘要由CSDN通过智能技术生成

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


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


这段代码是一个解析整数和浮点数的函数,它支持从字符串中解析出整数、浮点数以及复数。代码中包含了大量的注释,解释了每个步骤的目的和操作。这段代码是MicroPython的一部分,MicroPython是一个为嵌入式系统设计的Python解释器。

#include <stdbool.h> // 包含布尔类型的定义
#include <stdlib.h> // 包含标准库定义

// 引入MicroPython运行时环境的头文件
#include "py/runtime.h"
#include "py/parsenumbase.h"
#include "py/parsenum.h"
#include "py/smallint.h"

#if MICROPY_PY_BUILTINS_FLOAT
// 如果启用了浮点数支持,则包含数学库
#include <math.h>
#endif

/**
 * 抛出异常,不返回。
 * 如果传入的lexer非空,则说明是解析器调用的本函数,需要将异常类型从ValueError转换为SyntaxError,并添加追踪信息。
 */
static NORETURN void raise_exc(mp_obj_t exc, mp_lexer_t *lex) {
   
    if (lex != NULL) {
   
        ((mp_obj_base_t *)MP_OBJ_TO_PTR(exc))->type = &mp_type_SyntaxError; // 将异常类型转换为语法错误
        mp_obj_exception_add_traceback(exc, lex->source_name, lex->tok_line, MP_QSTRnull); // 添加追踪信息
    }
    nlr_raise(exc); // 抛出异常
}

/**
 * 解析整数数值。
 * @param str_ 要解析的字符串
 * @param len 字符串的长度
 * @param base 进制基数
 * @param lex 词法分析器,可以为空
 * @return 解析后的整数对象
 */
mp_obj_t mp_parse_num_integer(const char *restrict str_, size_t len, int base, mp_lexer_t *lex) {
   
    const byte *restrict str = (const byte *)str_; // 将字符串转换为字节指针
    const byte *restrict top = str + len; // 指向字符串的末尾
    bool neg = false; // 标记是否有负号
    mp_obj_t ret_val; // 解析结果

    // 检查基数是否在有效范围内
    if ((base != 0 && base < 2) || base > 36) {
   
        mp_raise_ValueError(MP_ERROR_TEXT("int() arg 2 must be >= 2 and <= 36")); // 抛出值错误
    }

    // 跳过字符串前的空白字符
    for (; str < top && unichar_isspace(*str); str++) {
   
    }

    // 解析可选的符号
    if (str < top) {
   
        if (*str == '+') {
   
            str++;
        } else if (*str == '-') {
   
            str++;
            neg = true; // 设置负号标志
        }
    }

    // 解析可选的基数前缀
    str += mp_parse_num_base((const char *)str, top - str, &base);

    // 字符串应该是一个整数
    mp_int_t int_val = 0; // 整数数值
    const byte *restrict str_val_start = str; // 字符串数值的起始位置
    for (; str < top; str++) {
   
        // 获取下一个数字字符
        mp_uint_t dig = *str;
        if ('0' <= dig && dig <= '9') {
   
            dig -= '0'; // 转换为0-9的数字
        } else if (dig == '_') {
   
            continue; // 跳过下划线字符
        } else {
   
            dig |= 0x20; // 将字符转换为小写
            if ('a' <= dig && dig <= 'z') {
   
                dig -= 'a' - 10; // 转换为10-35的数字
            } else {
   
                // 未知字符
                break;
            }
        }
        if (dig >= (mp_uint_t)base) {
   
            break; // 数字超出基数范围
        }

        // 添加下一个数字并检查是否溢出
        if (mp_small_int_mul_overflow(int_val, base)) {
   
            goto overflow; // 溢出处理
        }
        int_val = int_val * base + dig;
        if (!MP_SMALL_INT_FITS(int_val)) {
   
            goto overflow; // 溢出处理
        }
    }

    // 如果有负号,则取反数值
    if (neg) {
   
        int_val = -int_val;
    }

    // 创建小整数对象
    ret_val = MP_OBJ_NEW_SMALL_INT(int_val);

have_ret_val:
    // 检查是否解析了有效内容
    if (str == str_val_start) {
   
        goto value_error; // 未解析到有效内容,抛出值错误
    }

    // 跳过字符串后的空白字符
    for (; str < top && unichar_isspace(*str); str++) {
   
    }

    // 检查是否到达字符串末尾
    if (str != top) {
   
        goto value_error; // 未到达末尾,抛出值错误
    }

    // 返回解析结果对象
    return ret_val;

overflow:
    // 整数溢出,使用长整型重新解析
    {
   
        const char *s2 = (const char *)str_val_start;
        ret_val = mp_obj_new_int_from_str_len(&s2, top - str_val_start, neg, base); // 创建新的整数对象
        str = (const byte *)s2; // 更新字符串指针
        goto have_ret_val; // 跳转到解析结果
    }

value_error:
    // 抛出值错误
    {
   
        #if MICROPY_ERROR_REPORTING <= MICROPY_ERROR_REPORTING_TERSE
        mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_ValueError,
            MP_ERROR_TEXT("invalid syntax for integer")); // 创建值错误异常
        raise_exc(exc, lex); // 抛出异常
        #elif MICROPY_ERROR_REPORTING == MICROPY_ERROR_REPORTING_NORMAL
        mp_obj_t exc = mp_obj_new_exception_msg_varg(&mp_type_ValueError,
            MP_ERROR_TEXT("invalid syntax for integer with base %d"), base); // 创建带参数的值错误异常
        raise_exc(exc, lex); // 抛出异常
        #else
        vstr_t vstr; // 可变字符串
        mp_print_t print; // 打印结构体
        vstr_init_print(&vstr, 50, &print); // 初始化可变字符串
        mp_printf(&print, "invalid syntax for integer with base %d: ", base); // 打印错误信息
        mp_str_print_quoted(&print, str_val_start, top - str_val_start, true); // 打印字符串
        mp_obj_t exc = mp_obj_new_exception_arg1(&mp_type_ValueError,
            mp_obj_new_str_from_utf8_vstr(&vstr)); // 创建异常对象
        raise_exc(exc, lex); // 抛出异常
        #endif
    }
}

// 定义浮点数解析的状态枚举
enum {
   
    REAL_IMAG_STATE_START = 0, // 初始状态
    REAL_IMAG_STATE_HAVE_REAL = 1, // 已解析实部
    REAL_IMAG_STATE_HAVE_IMAG = 2, // 已解析虚部
};

#if MICROPY_PY_BUILTINS_FLOAT
// 如果启用了浮点数支持,则定义相关常量和枚举
// DEC_VAL_MAX 用于在不溢出的情况下保留精度
// SMALL_NORMAL_VAL 是最小的正常浮点数的10的幂
// EXACT_POWER_OF_10 是可以在浮点数中精确表示的10的最大幂
#if MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_FLOAT
#define DEC_VAL_MAX 1e20F // 单精度浮点数的最大值
#define SMALL_NORMAL_VAL (1e-37F) // 单精度浮点数的最小正常值
#define SMALL_NORMAL_EXP (-37) // 单精度浮点数的最小指数
#define EXACT_POWER_OF_10 (9) // 单精度浮点数的精确10的幂的最大值
#elif MICROPY_FLOAT_IMPL == MICROPY_FLOAT_IMPL_DOUBLE
#define DEC_VAL_MAX 1e200 // 双精度浮点数的最大值
#define SMALL_NORMAL_VAL (1e-307) // 双精度浮点数的最小正常值
#define SMALL_NORMAL_EXP (-307) // 双精度浮点数的最小指数
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

openwin_top

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

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

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

打赏作者

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

抵扣说明:

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

余额充值