首页
社区
课程
招聘
[分享]Lexer简单词法解析器入门
发表于: 1天前 361

[分享]Lexer简单词法解析器入门

1天前
361

前言

在上章实现了简单的解释器, 紧接着需要实现将 "a = 1 + 2" 这样的字符串语法编译成 MOV R0, 1; ADD R0, 2; 这样的代码, 这其中就需要用到词法分析器

将"a = 1 + 2"字符串形式分为{"a", "=", "1", "+", "2"}为第一步, 第二步还需分类{"1", "2"}为数字, {"a"}为变量, {"=", "+"}为操作符

并且还需适配无论是 "a=1+2" 还是 "a = 1 + 2" 又或者 "a =1 +2" 等形式都能正常识别

一、定义类型和结构

定义基础类型,其中包含变量、数字、操作符、结束符等,目前操作符只实现加法 后续可自由添加补充

enum TokenType {
    TOK_IDENT,   // 变量名:a, b
    TOK_NUMBER,  // 数字:1, 2
    TOK_PLUS,    // +
    TOK_ASSIGN,  // =
    TOK_END      // 结束
};

定义Token结构,其中包含类型和原始文本

struct Token {
    TokenType type;
    std::string text; // 原始文本(如 "a", "123")
};

二、定义词法解析函数

此函数为核心解析函数,调用者通过调用Lexer(const std::string& input)构造方法对input和pos进行赋值,再调用std::vector<Token> tokenize()进行词法分析

其中词法分析tokenize函数为单字符循环分析,逻辑为遇到空格跳过,支持对于变量、数字、符号的识别

并且实现了Token readIdent()读取完整变量名,逻辑为变量名由字母+数字组成,循环读取直到遇到空格或其他符号,以及readNumber() 读取完整数字的实现

class Lexer {
public:
    Lexer(const std::string& input)
        : input(input), pos(0) {
    }

    std::vector&lt;Token&gt; tokenize() {
        std::vector&lt;Token&gt; tokens;

        while (pos < input.size()) {
            char c = input[pos];

            // 1. 跳过空格
            if (isspace(c)) {
                pos++;
                continue;
            }

            // 2. 标识符(变量名)
            if (isalpha(c)) {
                tokens.push_back(readIdent());
                continue;
            }

            // 3. 数字
            if (isdigit(c)) {
                tokens.push_back(readNumber());
                continue;
            }

            // 4. 符号
            switch (c) {
            case '+':
                tokens.push_back({ TOK_PLUS, "+" });
                pos++;
                break;
            case '=':
                tokens.push_back({ TOK_ASSIGN, "=" });
                pos++;
                break;
            default:
                // 未知字符
                pos++;
                break;
            }
        }
        //在 token 列表末尾加一个“结束标记”
        tokens.push_back({ TOK_END, "" });
        return tokens;
    }

private:
    std::string input;
    size_t pos;
    //读取一个“变量名”
    Token readIdent() {
        size_t start = pos;
        while (pos < input.size() && isalnum(input[pos])) {//变量名组成: 字母 + 数字
            pos++;
        }
        return { TOK_IDENT, input.substr(start, pos - start) };
    }
    //读取一个完整数字
    Token readNumber() {
        size_t start = pos;
        while (pos < input.size() && isdigit(input[pos])) {
            pos++;
        }
        return { TOK_NUMBER, input.substr(start, pos - start) };
    }
};

三、测试

通过测试不同字符"a = 1 + 2"、"a=1+2"、"a=1+ 2"可正常识别,输入字符串输出token集合,token中又包含已分类好的类型以及字符串,方便后续处理

void Test1(const std::string str)
{
    Lexer lexer(str);
    auto tokens = lexer.tokenize();

    for (auto& t : tokens) {
        std::cout << t.text << " ";
    }
    std::cout << std::endl;
}


int main() {
    Test1("a = 1 + 2");
    Test1("a= 1 + 2");
    Test1("a=1 + 2");
    Test1("a=1+ 2");
    Test1("a=1+2");
}

总结

此节为实现简单的词法解析器,为后续实现完整编译器做准备,欢迎讨论 如有错漏 请留言!


[培训]《冰与火的战歌:Windows内核攻防实战》!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 1
支持
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回