mcpField
C
compiler-frontend

compiler-frontend

github.com/mohitmishra786开发269311 次安装18 周前更新
代码仓库

关于 compiler-frontend

compiler-frontend 是一项面向构建编译器前端的 Agent 技能,适用于 C 或 Rust 项目,涵盖从词法与语法分析到类型检查、错误恢复及 LLVM IR 生成。

主要功能

  1. 01使用 DFA 或 flex 设计词法分析器
  2. 02使用 Pratt 方法解析表达式
  3. 03递归下降解析语句
  4. 04设计 AST 与作用域符号表
  5. 05类型检查与错误恢复
  6. 06生成 LLVM IR

适用场景

  1. 01实现编程语言或 DSL
  2. 02为解释器添加表达式解析
  3. 03构建带作用域的符号表
  4. 04从类型化 AST 生成 LLVM IR

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mohitmishra786/low-level-dev-skills --skill compiler-frontend

安装后在 Claude Code 中输入/compiler-frontend确认已加载。

详细介绍

编译器前端

用途

指导 Agent 构建编译器前端:词法分析器(手写 DFA 与 flex)、表达式的 Pratt 解析、语句的递归下降解析、AST 设计、使用带作用域的哈希映射构建符号表、类型检查基础、错误恢复策略,以及通过 C API 或 llvm-sys 生成 LLVM IR。

适用场景

  • 实现新的编程语言或 DSL
  • 为解释器或配置语言添加表达式解析
  • 在 C 或 Rust 中设计 AST 节点层级
  • 为变量和函数构建带作用域的符号表
  • 实现基本的类型推断或类型检查
  • 从带类型的 AST 生成 LLVM IR

工作流

1. 流水线概览
Source → Lexer (tokens) → Parser (AST) → Type checker → IR generator → LLVM IR
2. 词法分析器 — 手写 DFA
typedef enum {
    TOK_EOF, TOK_INT, TOK_IDENT, TOK_PLUS, TOK_MINUS,
    TOK_LPAREN, TOK_RPAREN, TOK_SEMI, TOK_EQ,
} TokenKind;

typedef struct {
    TokenKind kind;
    const char *start;
    int length;
    int64_t int_val;
} Token;

typedef struct {
    const char *src;
    int pos;
    int line;
} Lexer;

static void skip_whitespace(Lexer *l) {
    while (l->src[l->pos] == ' ' || l->src[l->pos] == '\n') l->pos++;
}

Token lexer_next(Lexer *l) {
    skip_whitespace(l);
    const char *start = &l->src[l->pos];

    if (isdigit(l->src[l->pos])) {
        int64_t val = 0;
        while (isdigit(l->src[l->pos]))
            val = val * 10 + (l->src[l->pos++] - '0');
        return (Token){ TOK_INT, start, l->pos - (start - l->src), val };
    }
    if (isalpha(l->src[l->pos])) {
        while (isalnum(l->src[l->pos])) l->pos++;
        return (Token){ TOK_IDENT, start, l->pos - (start - l->src), 0 };
    }
    char c = l->src[l->pos++];
    switch (c) {
        case '+': return (Token){ TOK_PLUS, start, 1, 0 };
        case '(': return (Token){ TOK_LPAREN, start, 1, 0 };
        case ')': return (Token){ TOK_RPAREN, start, 1, 0 };
        case ';': return (Token){ TOK_SEMI, start, 1, 0 };
        default:  return (Token){ TOK_EOF, start, 0, 0 };
    }
}
# flex alternative
flex lexer.l && gcc -o lexer lexer.tab.c -lfl
3. 表达式的 Pratt 解析
typedef enum { AST_INT, AST_BINOP, AST_VAR } AstKind;

typedef struct AstNode {
    AstKind kind;
    union {
        int64_t int_val;
        struct { int op; struct AstNode *lhs, *rhs; } binop;
        char *name;
    };
} AstNode;

// Binding powers: higher = tighter precedence
enum { BP_NONE = 0, BP_SUM = 10, BP_PRODUCT = 20 };

AstNode *parse_expression(Parser *p, int min_bp) {
    AstNode *left = parse_prefix(p);
    for (;;) {
        int lbp, rbp;
        if (!infix_binding_power(p->cur.kind, &lbp, &rbp) || lbp < min_bp)
            break;
        advance(p);
        AstNode *right = parse_expression(p, rbp);
        left = make_binop(p->cur.kind, left, right);
    }
    return left;
}

Pratt 解析可以简洁地处理运算符优先级,无需庞大的语法表。

4. 语句的递归下降解析
AstNode *parse_statement(Parser *p) {
    if (match(p, TOK_IDENT) && peek(p) == TOK_EQ) {
        char *name = p->prev.text;
        advance(p);  // =
        AstNode *expr = parse_expression(p, BP_NONE);
        expect(p, TOK_SEMI);
        return make_assign(name, expr);
    }
    if (match(p, TOK_RETURN)) {
        AstNode *expr = parse_expression(p, BP_NONE);
        expect(p, TOK_SEMI);
        return make_return(expr);
    }
    return parse_expression_statement(p);
}
5. AST 和符号表
typedef struct Symbol {
    char *name;
    Type *type;
    LLVMValueRef llvm_val;  // after codegen
    struct Symbol *next;
} Symbol;

typedef struct Scope {
    Symbol *symbols;       // hash map bucket chain
    struct Scope *parent;
} Scope;

Symbol *scope_lookup(Scope *s, const char *name) {
    for (Scope *cur = s; cur; cur = cur->parent) {
        for (Symbol *sym = cur->symbols; sym; sym = sym->next)
            if (strcmp(sym->name, name) == 0)
                return sym;
    }
    return NULL;
}

void scope_define(Scope *s, const char *name, Type *type) {
    Symbol *sym = malloc(sizeof(Symbol));
    sym->name = strdup(name);
    sym->type = type;
    sym->next = s->symbols;
    s->symbols = sym;
}
6. 类型检查器(基础)
typedef enum { TY_INT, TY_BOOL, TY_FUNC, TY_VOID } TypeKind;

Type *check_expr(Scope *s, AstNode *node) {
    switch (node->kind) {
    case AST_INT: return type_int();
    case AST_VAR: {
        Symbol *sym = scope_lookup(s, node->name);
        if (!sym) error("undefined variable %s", node->name);
        return sym->type;
    }
    case AST_BINOP: {
        Type *lt = check_expr(s, node->binop.lhs);
        Type *rt = check_expr(s, node->binop.rhs);
        if (!type_equal(lt, rt))
            error("type mismatch in binary op");
        return lt;
    }
    }
    return type_void();
}

Hindley-Milner(完整推断):分配类型变量,并根据约束进行合一——适用于类 ML 语言。

7. 错误恢复
策略适用场景
恐慌模式跳过标记,直到遇到同步标记(;、})
同步集合为每个非终结符定义恢复标记
错误产生式为常见错误编写语法规则
单标记插入/删除适用于 IDE 的恢复方式
void synchronize(Parser *p) {
    advance(p);
    while (p->cur.kind != TOK_EOF) {
        if (p->prev.kind == TOK_SEMI) return;
        if (p->cur.kind == TOK_RETURN || p->cur.kind == TOK_IDENT) return;
        advance(p);
    }
}
8. LLVM IR 生成
#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>

LLVMModuleRef module;
LLVMBuilderRef builder;

LLVMValueRef codegen_expr(Scope *s, AstNode *node) {
    switch (node->kind) {
    case AST_INT:
        return LLVMConstInt(LLVMInt32Type(), node->int_val, 1);
    case AST_BINOP: {
        LLVMValueRef l = codegen_expr(s, node->binop.lhs);
        LLVMValueRef r = codegen_expr(s, node->binop.rhs);
        if (node->binop.op == TOK_PLUS)
            return LLVMBuildAdd(builder, l, r, "add");
        break;
    }
    case AST_VAR: {
        Symbol *sym = scope_lookup(s, node->name);
        return LLVMBuildLoad(builder, sym->llvm_val, node->name);
    }
    }
    return NULL;
}
# Dump IR
LLVMDumpModule(module);
# Verify
char *err = NULL;
LLVMVerifyModule(module, LLVMReturnStatusAction, &err);

Rust:使用 inkwell 或 llvm-sys crate,获得更安全的绑定。

常见问题

症状原因修复方法
解析器无限循环出错时未前进检查所有分支是否都会前进到下一个标记
运算符优先级错误绑定力设置不正确使用表格测试表达式
作用域内符号重复未检查遮蔽读取时只查找父作用域;定义时仅查找当前作用域
LLVM 验证失败IR 中的类型不匹配检查有无符号性和指针层级
flex 标记冲突模式重叠使用最长匹配;调整规则顺序
错误级联没有同步机制实现恐慌模式恢复

相关技能

  • skills/compiler-internals/llvm-passes — 优化生成的 IR
  • skills/compiler-internals/jit-compilation — 执行生成的 IR
  • skills/compiler-internals/mlir — 用于 DSL 的更高级 IR
  • skills/compilers/llvm — 作为 LLVM 用户使用 opt、llc
  • skills/low-level-programming/interpreters — 字节码 VM 替代方案
  • skills/languages/carbon-lang — 现代语言前端示例

评论

支持 Markdown