compiler-frontend
Use when building a lexer, Pratt or recursive-descent parser, AST, symbol table, type checker, or LLVM IR emitter for a language or DSL. Not for optimizing IR: use llvm-passes.
Install / Use
npx skills add OutlineDriven/outline-driven-development --skill compiler-frontendInstalls into whichever agent you are using.
SKILL.md
Installable skill definition
Quality Score
Category
Development & EngineeringSupported Platforms
Tags
Our assessment of compiler-frontend
compiler-frontend scores 60/100 on our quality scale, 4063rd of 4,599 Development & Engineering skills we index.
Its SKILL.md is 11 KB long, split into 6 sections and no code examples: a thorough specification that gives an agent plenty to work with.
It has no GitHub stars yet, so there is no community track record; judge it on its content.
Maintenance, license and trust
- We could not determine when the repository was last updated.
- Our last check on 2026-10-20 found the source still online.
- No license is declared. By default that means all rights are reserved: you can read it, but reusing or redistributing it is not clearly permitted. Ask the author before building on it commercially.
- Its trust signals score 68/100, with 3 cautions from licensing, adoption, age or documentation. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
compiler-frontend compared with similar skills
All 4 of these similar skills score higher than compiler-frontend; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| compiler-frontend (this skill)by OutlineDriven | 60 | 0 | — | SKILL.md |
| taste-skillby Leonxlnx | 100 | 99.8k | today | CLAUDE.md |
| ai-job-searchby MadsLorentzen | 100 | 60.2k | today | CLAUDE.md |
| claude-howtoby luongnv89 | 100 | 42.1k | today | CLAUDE.md |
| algorithmic-artby anthropics | 100 | 177.9k | 28d ago | SKILL.md |
Frequently asked questions
- How do I install compiler-frontend?
- Run
npx skills add OutlineDriven/outline-driven-development --skill compiler-frontend. The install tabs above show the steps for each supported agent. - Which AI agents does compiler-frontend work with?
- It is written for Universal, as a SKILL.md file. Other agents that read the same format can often use it too.
- Is compiler-frontend safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It declares no license and scores 68/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is compiler-frontend still maintained?
- We could not determine when the repository was last updated.
Skill content
View source on GitHubname: compiler-frontend description: 'Use when building a lexer, Pratt or recursive-descent parser, AST, symbol table, type checker, or LLVM IR emitter for a language or DSL. Not for optimizing IR: use llvm-passes.'
Compiler frontend
Contract
| Field | Bound contract | |---|---| | Trigger | A user implements a language or DSL, adds expression parsing to an interpreter or config format, designs AST nodes in C or Rust, needs scoped symbols, basic type checking, error recovery, or wants a typed AST lowered to LLVM IR. | | Authority | Reversible local: writes only the frontend source files the user names inside the project; rollback is version control. No remote mutation. | | Side effect | Frontend source files are created or edited; a test input is lexed, parsed, checked, and, when requested, emitted as IR and verified. | | Done | Each requested stage compiles, runs on the supplied test inputs, and the verification named for that stage passes: token stream matches, precedence tests pass, undefined and mismatched types are reported, generated IR passes the LLVM verifier. |
Inputs
- Language description (required): the token set, the grammar or a set of example programs, and the operators with their precedence and associativity.
- Implementation language (required): C or Rust. C samples below use the LLVM C API in
llvm-c/; in Rust use theinkwellorllvm-syscrates. - Requested stages (required): any subset of lexer, parser, symbol table, type checker, IR emitter.
- Test inputs (required): at least one valid program per stage and one program with an error the stage must report.
Procedure
-
Fix the pipeline: source to lexer (tokens) to parser (AST) to type checker to IR generator to LLVM IR. Write down which stages this task delivers. Done when: the delivered stages and their input and output types are listed.
-
Write the lexer as a hand-written state machine. Tokens carry a kind, a pointer into the source, a length, and any literal value. Skip whitespace, then dispatch on the first character: digits build an integer, letters build an identifier, single characters map to punctuation.
typedef enum { TOK_EOF, TOK_INT, TOK_IDENT, TOK_PLUS, TOK_MINUS, TOK_LPAREN, TOK_RPAREN, TOK_SEMI, TOK_EQ, TOK_RETURN } 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; Token lexer_next(Lexer *l) { while (l->src[l->pos] == ' ' || l->src[l->pos] == '\n') l->pos++; const char *start = &l->src[l->pos]; if (isdigit((unsigned char)l->src[l->pos])) { int64_t val = 0; while (isdigit((unsigned char)l->src[l->pos])) val = val * 10 + (l->src[l->pos++] - '0'); return (Token){ TOK_INT, start, (int)(&l->src[l->pos] - start), val }; } if (isalpha((unsigned char)l->src[l->pos])) { while (isalnum((unsigned char)l->src[l->pos])) l->pos++; return (Token){ TOK_IDENT, start, (int)(&l->src[l->pos] - start), 0 }; } switch (l->src[l->pos++]) { 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 }; } }A generated lexer is the alternative when the token set is large:
flex lexer.l && gcc -o lexer lex.yy.c -lfl. With flex, order rules so the longest match wins and keywords precede the identifier rule. Done when: every test input produces the expected token stream, including the EOF token. -
Parse expressions with a Pratt parser. Each infix operator has a left and a right binding power; a higher power binds tighter, and right associativity is a right power one below the left. The loop consumes operators while their left power is at least the minimum.
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; 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; int op = p->cur.kind; advance(p); AstNode *right = parse_expression(p, rbp); left = make_binop(op, left, right); } return left; }Capture the operator before
advance; readingp->cur.kindafter the recursive call returns the wrong token. Done when: a table of expressions with expected trees passes, including mixed precedence and associativity cases. -
Parse statements with recursive descent, one function per nonterminal. Every branch must consume at least one token or return; a branch that neither advances nor returns is the cause of an infinite loop.
AstNode *parse_statement(Parser *p) { if (p->cur.kind == TOK_IDENT && peek(p) == TOK_EQ) { char *name = take_ident(p); 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); }Done when: every statement form in the test inputs parses and every branch is audited for token progress.
-
Build the symbol table as a chain of scopes. Lookup walks from the innermost scope to the root; definition writes only into the current scope, so shadowing an outer name is allowed and redefining a name in the same scope is an error.
typedef struct Symbol { char *name; Type *type; LLVMValueRef llvm_val; struct Symbol *next; } Symbol; typedef struct Scope { Symbol *symbols; 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 *sym); if (!sym) abort(); sym->name = strdup(name); sym->type = type; sym->llvm_val = NULL; sym->next = s->symbols; s->symbols = sym; }Replace the linked list with a hash map when scopes hold more than a few dozen names. Done when: shadowing resolves to the inner name and a same-scope duplicate is rejected.
-
Type-check by walking the AST and returning a type per node. Integers have the integer type; a variable takes its symbol's type or reports "undefined"; a binary operation requires equal operand types.
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(); }For an ML-style language with inference, assign a type variable to each unknown and unify on constraints (Hindley-Milner); this is a separate stage, not a change to the checker above. Done when: each error test input produces the expected diagnostic and valid inputs pass.
-
Recover from syntax errors with panic mode: on error, advance until a synchronizing token, then resume. Pick the synchronizing set per nonterminal (statement end
;, block end}, statement-start keywords).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); } }Error productions for common mistakes and single-token insertion or deletion are the next steps when the frontend serves an editor. Done when: an input with two independent errors reports both, not a cascade from the first.
-
Emit LLVM IR from the typed AST through the C API. Create types from a context, build instructions through a builder, and use the typed load: the untyped
LLVMBuildLoadis gone from the current C API (LLVM 23.1.0) andLLVMInt32Type()without a context is deprecated.#include <llvm-c/Core.h> #include <llvm-c/Analysis.h> LLVMContextRef ctx; LLVMModuleRef module; LLVMBuilderRef builder; LLVMValueRef codegen_expr(Scope *s, AstNode *node) { switch (node->kind) { case AST_INT: return LLVMConstInt(LLVMInt32TypeInContext(ctx), (unsigned long long)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 LLVMBuildLoad2(builder, LLVMInt32TypeInContext(ctx), sym->llvm_val, node->name); } } return NULL; }After emitting, dump and verify:
LLVMDumpModule(module);andLLVMVerifyModule(module, LLVMReturnStatusAction, &err);whereLLVMVerifyModuleis declared inllvm-c/Analysis.h. Done when: the verifier returns success on every valid test input.
Failure and recovery
| Failure class | Behavior |
|---|---|
| Parser loops forever | A branch consumed no token. Audit every branch of the failing nonterminal for advance or return; add the missing progress. |
| Wrong precedence | Binding powers are wrong. Fix the table and re-run the expression table test. |
| Duplicate symbol accepted or shadowing rejected | Lookup and define use the wrong scope. Lookup walks parents; define writes the current scope only. |
| LLVM verifier fails | An IR type mismatch, usually signedness, pointer level, or a load with the wrong type argument. Read the verifier message; fix the emitter for that node kind. |
| flex token clash | Overlapping patterns. Rely on longest match and order keyword rules before the identifier rule. |
| Error cascade | No synchronization. Implement panic-mode recovery per step 7. |
No partial result is claimed complete. If a stage cannot finish, the report states which stages passed their verification and which are blocked.
Output
A frontend delivery containing:
- Files written: each source file created or edited, per stage.
- Verification: per stage, the test inputs run and the observed token stream, tree, diagnostic, or verifier result.
- Open decisions: any grammar ambiguity or type rule the language description left undefined, with the choice made.
Related Skills
taste-skill
99.8kAgent skills that give coding agents taste: art direction, reference images and a browser check instead of generic AI pages
ai-job-search
60.2kThe job search that runs on your machine. AI job application framework built on Claude Code: evaluate postings, tailor CVs, write cover letters, prep interviews. Fork it and own it.
claude-howto
42.1kA visual, example-driven guide to Claude Code — from basic concepts to advanced agents, with copy-paste templates that bring immediate value.
algorithmic-art
177.9kCreating algorithmic art using p5.js with seeded randomness and interactive parameter exploration. Use this when users request creating art using code, generative art, algorithmic art, flow fields, or particle systems.
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
