microPython的源码解析之 lexer.c

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

microPython Python最小内核源码解析

这段代码是MicroPython词法分析器的一部分,它负责将输入的源代码文本分解成一系列的标记(tokens)。词法分析器是编译器或解释器的第一个阶段,它读取源代码并将其分解成更小的、有意义的单元,以便后续的解析和编译阶段可以处理。代码中包含了许多辅助函数,用于处理各种语言结构,如字符串字面量、标识符、关键字、操作符等。此外,还提供了创建和释放词法分析器实例的函数,以及从不同来源(如内存、文件等)创建词法分析器的辅助函数。

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

// 引入MicroPython的读取器、词法分析器和运行时环境的头文件
#include "py/reader.h"
#include "py/lexer.h"
#include "py/runtime.h"

#if MICROPY_ENABLE_COMPILER

// 定义制表符的宽度为8个字符
#define TAB_SIZE (8)

// 定义词法分析器结束符
#define MP_LEXER_EOF ((unichar)MP_READER_EOF)
// 获取当前字符
#define CUR_CHAR(lex) ((lex)->chr0)

// 判断当前是否为词法分析器的结束
static bool is_end(mp_lexer_t *lex) {
   
    return lex->chr0 == MP_LEXER_EOF;
}

// 判断当前字符是否为换行符
static bool is_physical_newline(mp_lexer_t *lex) {
   
    return lex->chr0 == '\n';
}

// 判断当前字符是否为指定字符
static bool is_char(mp_lexer_t *lex, byte c) {
   
    return lex->chr0 == c;
}

// 判断当前字符是否为指定字符之一
static bool is_char_or(mp_lexer_t *lex, byte c1, byte c2) {
   
    return lex->chr0 == c1 || lex->chr0 == c2;
}

// 判断当前字符是否为指定的三个字符之一
static bool is_char_or3(mp_lexer_t *lex, byte c1, byte c2, byte c3) {
   
    return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3;
}

// 如果启用了格式化字符串,添加判断当前字符是否为指定的四个字符之一
#if MICROPY_PY_FSTRINGS
static bool is_char_or4(mp_lexer_t *lex, byte c1, byte c2, byte c3, byte c4) {
   
    return lex->chr0 == c1 || lex->chr0 == c2 || lex->chr0 == c3 || lex->chr0 == c4;
}
#endif

// 判断下一个字符是否为指定字符
static bool is_char_following(mp_lexer_t *lex, byte c) {
   
    return lex->chr1 == c;
}

// 判断下一个字符是否为指定字符之一
static bool is_char_following_or(mp_lexer_t *lex, byte c1, byte c2) {
   
    return lex->chr1 == c1 || lex->chr1 == c2;
}

// 判断接下来的两个字符是否为指定字符之一
static bool is_char_following_following_or(mp_lexer_t *lex, byte c1, byte c2) {
   
    return lex->chr2 == c1 || lex->chr2 == c2;
}

// 判断当前和下一个字符是否分别为指定的两个字符
static bool is_char_and(mp_lexer_t *lex, byte c1, byte c2) {
   
    return lex->chr0 == c1 && lex->chr1 == c2;
}

// 判断当前字符是否为空白字符
static bool is_whitespace(mp_lexer_t *lex) {
   
    return unichar_isspace(lex->chr0);
}

// 判断当前字符是否为字母
static bool is_letter(mp_lexer_t *lex) {
   
    return unichar_isalpha(lex->chr0);
}

// 判断当前字符是否为数字
static bool is_digit(mp_lexer_t *lex) {
   
    return unichar_isdigit(lex->chr0);
}

// 判断下一个字符是否为数字
static bool is_following_digit(mp_lexer_t *lex) {
   
    return unichar_isdigit(lex->chr1);
}

// 判断下一个字符是否为基数字符(二进制、八进制、十六进制)
static bool is_following_base_char(mp_lexer_t *lex) {
   
    const unichar chr1 = lex->chr1 | 0x20;
    return chr1 == 'b' || chr1 == 'o' || chr1 == 'x';
}

// 判断下一个字符是否为八进制数字
static bool is_following_odigit(mp_lexer_t *lex) {
   
    return lex->chr1 >= '0' && lex->chr1 <= '7';
}

// 判断当前字符是否为字符串或字节类型的开始
static bool is_string_or_bytes(mp_lexer_t *lex) {
   
    return is_char_or(lex, '\'', '\"')
           #if MICROPY_PY_FSTRINGS
           || (is_char_or4(lex, 'r', 'u', 'b', 'f') && is_char_following_or(lex, '\'', '\"'))
           || (((is_char_and(lex, 'r', 'f') || is_char_and(lex, 'f', 'r'))
               && is_char_following_following_or(lex, '\'', '\"')))
           #else
           || (is_char_or3(lex, 'r', 'u', 'b') && is_char_following_or(lex, '\'', '\"'))
           #endif
           || ((is_char_and(lex, 'r', 'b') || is_char_and(lex, 'b', 'r'))
               && is_char_following_following_or(lex, '\'', '\"'));
}

// 判断当前字符是否为标识符的开头
static bool is_head_of_identifier(mp_lexer_t *lex) {
   
    return is_letter(lex) || lex->chr0 == '_' || lex->chr0 >= 0x80;
}

// 判断当前字符是否为标识符的一部分
static bool is_tail_of_identifier(mp_lexer_t *lex) {
   
    return is_head_of_identifier(lex) || is_digit(lex);
}

// 读取下一个字符
static void next_char(mp_lexer_t *lex) {
   
    // 如果当前字符是换行符,更新行号和列号
    if (lex->chr0 == '\n') {
   
        ++lex->line;
        lex->column = 1;
    } else if (lex->chr0 == '\t') {
   
        // 如果当前字符是制表符,根据制表符宽度调整列号
        lex->column = (((lex->column - 1 + TAB_SIZE) / TAB_SIZE) * TAB_SIZE) + 1;
    } else {
   
        // 否则,列号加1
        ++lex->column;
    }

    // 将输入队列向前移动一位
    lex->chr0 = lex->chr1;
    lex->chr1 = lex->chr2;

    // 从读取器或格式化字符串参数中读取下一个字节
    #if MICROPY_PY_FSTRINGS
    if (lex->fstring_args_idx) {
   
        // 如果有保存的字符,说明当前正在注入格式化字符串参数
        if (lex->fstring_args_idx < lex->fstring_args.len) {
   
            lex->chr2 = lex->fstring_args.buf[lex->fstring_args_idx++];
        } else {
   
            // 没有更多的格式化字符串参数字节
            lex->chr2 = '\0';
        }

        if (lex->chr0 == '\0') {
   
            // 消费完所有格式化字符串数据,恢复保存的输入队列
            lex->chr0 = lex->chr0_saved;
            lex->chr1 = lex->chr1_saved;
            lex->chr2 = lex->chr2_saved;
            // 停止消费格式化字符串参数数据
            vstr_reset(&lex->fstring_args);
            lex->fstring_args_idx = 0;
        }
    } else {
   
        // 否则,从读取器中读取下一个字节
        lex->chr2 = lex->reader.readbyte(lex->reader.data);
    }

    // 如果下一个字符是回车符,将其转换为换行符
    if (lex->chr1 == '\r') {
   
        lex->chr1 = '\n';
        if (lex->chr2 == '\n') {
   
            // 回车换行是单个换行,丢弃多余的换行符
            lex->chr2 = lex->reader.readbyte(lex->reader.data);
        }
    }

    // 检查是否需要在文件末尾插入换行符
    if (lex->chr2 == MP_LEXER_EOF && lex->chr1 != MP_LEXER_EOF && lex->chr1 != '\n') {
   
        lex->chr2 = '\n';
    }
}

// 压入缩进级别
static void indent_push(mp_lexer_t *lex, size_t indent) {
   
    if (lex->num_indent_level >= lex->alloc_indent_level) {
   
        // 如果当前的缩进级别数量超过了分配的级别,重新分配更多空间
        lex->indent_level = m_renew(uint16_t, lex->indent_level, lex->alloc_indent_level, lex->alloc_indent_level + MICROPY_ALLOC_LEXEL_INDENT_INC);
        lex->alloc_indent_level += MICROPY_ALLOC_LEXEL_INDENT_INC;
    }
    lex->indent_level[lex->num_indent_level++] = indent;
}

// 获取当前的缩进级别
static size_t indent_top(mp_lexer_t *lex) {
   
    return lex->indent_level[lex->num_indent_level - 1];
}

// 弹出缩进级别
static void indent_pop(mp_lexer_t *lex) {
   
    lex->num_indent_level -= 1;
}

// 操作符编码,用于快速匹配和识别操作符
// 每个操作符由一个或多个字符组成,根据字符的位置确定操作符的开始、结束或继续
static const char *const tok_enc =
    "()[]{},;~"   // 单个字符的操作符
    ":e="         // : :=
    "<e=c<e="     // < <= << <<=
    ">e=c>e="     // > >= >> >>=
    "*e=c*e="     // * *= ** **=
    "+e="         // + +=
    "-e=e>"       // - -= ->
    "&e="         // & &=
    "|e="         // | |=
    "/e=c/e="     // / /= // //=
    "%e="         // % %=
    "^e="         // ^ ^=
    "@e="         // @ @=
    "=e="         // = ==
    "!.";         // 特殊情况的开始:!= . ...

// 根据操作符编码确定操作符的类型
static const uint8_t tok_enc_kind[] = {
   
    MP_TOKEN_DEL_PAREN_OPEN, MP_TOKEN_DEL_PAREN_CLOSE,
    MP_TOKEN_DEL_BRACKET_OPEN, MP_TOKEN_DEL_BRACKET_CLOSE,
    MP_TOKEN_DEL_BRACE_OPEN, MP_TOKEN_DEL_BRACE_CLOSE,
    MP_TOKEN_DEL_COMMA, MP_TOKEN_DEL_SEMICOLON, MP_TOKEN_OP_TILDE,

    MP_TOKEN_DEL_COLON, MP_TOKEN_OP_ASSIGN,
    MP_TOKEN_OP_LESS, MP_TOKEN_OP_LESS_EQUAL, MP_TOKEN_OP_DBL_LESS, MP_TOKEN_DEL_DBL_LESS_EQUAL,
    MP_TOKEN_OP_MORE, MP_TOKEN_OP_MORE_EQUAL, MP_TOKEN_OP_DBL_MORE, MP_TOKEN_DEL_DBL_MORE_EQUAL,
    MP_TOKEN_OP_STAR, MP_TOKEN_DEL_STAR_EQUAL, MP_TOKEN_OP_DBL_STAR, MP_TOKEN_DEL_DBL_STAR_EQUAL,
    MP_TOKEN_OP_PLUS, MP_TOKEN_DEL_PLUS_EQUAL,
    MP_TOKEN_OP_MINUS, MP_TOKEN_DEL_MINUS_EQUAL, MP_TOKEN_DEL_MINUS_MORE,
    MP_TOKEN_OP_AMPERSAND, MP_TOKEN_DEL_AMPERSAND_EQUAL,
    MP_TOKEN_OP_PIPE, MP_TOKEN_DEL_PIPE_EQUAL,
    MP_TOKEN_OP_SLASH, MP_TOKEN_DEL_SLASH_EQUAL, MP_TOKEN_OP_DBL_SLASH, MP_TOKEN_DEL_DBL_SLASH_EQUAL,
    MP_TOKEN_OP_PERCENT, MP_TOKEN_DEL_PERCENT_EQUAL,
    MP_TOKEN_OP_CARET, MP_TOKEN_DEL_CARET_EQUAL,
    MP_TOKEN_OP_AT, MP_TOKEN_DEL_AT_EQUAL,
    MP_TOKEN_DEL_EQUAL, MP_TOKEN_OP_DBL_EQUAL,
};

// 关键字列表,必须与lexer.h中的枚举顺序相同,并按strcmp排序
static const char *const tok_kw[] = {
   
    "False", "None"
  • 42
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
2022 / 01/ 30: 新版esptool 刷micropython固件指令不是 esptool.py cmd... 而是 esptool cmd... 即可;另外rshell 在 >= python 3.10 的时候出错解决方法可以查看:  已于2022年发布的: 第二章:修复rshell在python3.10出错 免费内容: https://edu.csdn.net/course/detail/29666 micropython语法和python3一样,编写起来非常方便。如果你快速入门单片机玩物联网而且像轻松实现各种功能,那绝力推荐使用micropython。方便易懂易学。 同时如果你懂C语音,也可以用C写好函数并编译进micropython固件里然后进入micropython调用(非必须)。 能通过WIFI联网(2.1章),也能通过sim卡使用2G/3G/4G/5G联网(4.5章)。 为实现语音控制,本教程会教大家使用tensorflow利用神经网络训练自己的语音模型并应用。为实现通过网页控制,本教程会教大家linux(debian10 nginx->uwsgi->python3->postgresql)网站前后台入门。为记录单片机传输过来的数据, 本教程会教大家入门数据库。  本教程会通过通俗易懂的比喻来讲解各种原理与思路,并手把手编写程序来实现各项功能。 本教程micropython版本是 2019年6月发布的1.11; 更多内容请看视频列表。  学习这门课程之前你需要至少掌握: 1: python3基础(变量, 循环, 函数, 常用库, 常用方法)。 本视频使用到的零件与淘宝上大致价格:     1: 超声波传感器(3)     2: MAX9814麦克风放大模块(8)     3: DHT22(15)     4: LED(0.1)     5: 8路5V低电平触发继电器(12)     6: HX1838红外接收模块(2)     7:红外发射管(0.1),HX1838红外接收板(1)     other: 电表, 排线, 面包板(2)*2,ESP32(28)  

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

openwin_top

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

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

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

打赏作者

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

抵扣说明:

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

余额充值