O léxico: tokens e lexers
A primeira etapa de todo compilador: transformar uma sequência de caracteres em uma lista de tokens com significado.
Ler código como palavras, não caracteres
Para um computador, seu código fonte é apenas uma string de caracteres.
A primeira tarefa do compilador é agrupar esses caracteres em unidades com significado:
tokens. let é um token keyword. 42 é um token number.
+ é um token operator. Espaços e comentários são descartados.
Esse processo se chama análise léxica (ou tokenização), feita pelo lexer (também chamado de scanner ou tokenizer). O lexer usa expressões regulares para reconhecer cada categoria de token. A saída é uma lista plana de tokens que o parser vai consumir.
Tokenize código em tempo real
Edite o código ou escolha um exemplo. Cada token aparece colorido por tipo. Passe o mouse para inspecionar.
Implementando um lexer
// Estrutura de um lexer simples em JavaScript const RULES = [ { type: "KEYWORD", pattern: /^(if|else|while|return|let|const)/ }, { type: "NUMBER", pattern: /^d+(.d+)?/ }, { type: "STRING", pattern: /^"[^"]*"/ }, { type: "IDENT", pattern: /^[a-zA-Z_]w*/ }, { type: "OP", pattern: /^[+-*/<>=!]+/ }, { type: "PUNC", pattern: /^[(){}[];,.]/ }, { type: "SPACE", pattern: /^s+/ }, ]; function lex(source) { const tokens = []; let i = 0; while (i < source.length) { let matched = false; for (const rule of RULES) { const m = source.slice(i).match(rule.pattern); if (m) { if (rule.type !== "SPACE") tokens.push({ type: rule.type, value: m[0] }); i += m[0].length; matched = true; break; } } if (!matched) throw new Error(`Char inesperado: ${source[i]}`); } return tokens; }
Saída de tokens
// Saída de lex("let x = 10 + y;") [ { type: "KEYWORD", value: "let" }, { type: "IDENT", value: "x" }, { type: "OP", value: "=" }, { type: "NUMBER", value: "10" }, { type: "OP", value: "+" }, { type: "IDENT", value: "y" }, { type: "PUNC", value: ";" }, ] // Whitespace e comentários: descartados (não viram tokens) // Cada token carrega: tipo + valor + posição (linha, coluna) na prática
Construa seu próprio lexer
Mini projeto: implemente um lexer que tokeniza expressões matemáticas: números (inteiros e decimais), operadores (+, -, *, /, ^), parênteses e variáveis. Ignore espaços. Retorne um array de tokens.
Projeto principal: implemente um lexer completo para um subconjunto de Python: keywords (if, else, while, def, return), identifiers, numbers, strings, operadores, e indentação (INDENT/DEDENT tokens — o grande desafio de Python). Teste com 20 programas de exemplo.
Desafio extra: implemente um lexer usando um DFA gerado manualmente para reconhecer floats, inteiros, strings com escape (\"), comentários de linha e bloco, e identificadores Unicode. Meça o throughput em linhas/segundo.
Teste sua intuição
Onde você encontra isso
Syntax highlighting
VS Code, Vim e todos os editores usam lexers para colorir código. O popular pacote shiki (usado neste site) tokeniza código com gramáticas TextMate e aplica cores por tipo de token.
Linters
ESLint, Pylint e Rubocop tokenizam antes de analisar. Algumas regras são puramente léxicas: no-trailing-spaces, max-line-length — não precisam do AST, só dos tokens.
WAF e SQL injection
Web Application Firewalls detectam SQL injection tokenizando o input: se tokens SQL (SELECT, DROP, UNION) aparecem em contexto inesperado, a request é bloqueada — sem precisar parsear SQL completo.
Markdown parsers
Remark, marked e commonmark usam lexers para tokenizar Markdown: detectam headings (# ), listas (- ), code fences (```), e então o parser constrói a AST que vira HTML.