Tokenizando a entrada
Transforme texto em tokens.
Tokenizando a entrada é uma aula grátis de C Academy no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de C Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de C Academy inclui 4 aulas no total.
O que é um Tokenizador?
Um interpretador começa transformando texto bruto em tokens — as menores unidades com significado. Para a cadeia 3 + 4 * 2, o tokenizador (ou analisador léxico) emite números e operadores.
Essa etapa remove os espaços em branco e classifica cada grupo de caracteres, para que o analisador sintático nunca lide com bytes brutos.
Um Tipo de Token
Modelamos cada token com uma etiqueta de enumeração e um conteúdo. Os números carregam um valor inteiro; os operadores e parênteses precisam apenas do seu tipo.
Manter o valor dentro da estrutura evita analisar novamente a origem mais tarde.
typedef enum {
TOK_NUM, TOK_PLUS, TOK_MINUS,
TOK_STAR, TOK_SLASH,
TOK_LPAREN, TOK_RPAREN, TOK_EOF
} TokKind;
typedef struct {
TokKind kind;
int value; /* used when kind == TOK_NUM */
} Token;Posição de Varredura
O analisador léxico percorre a origem com um ponteiro cursor. Um pequeno auxiliar consulta o caractere atual sem consumi-lo, retornando '\0' no final.
A aritmética de ponteiros mantém o analisador rápido e simples.
static const char *src;
static char peek(void) {
return *src;
}
static char advance(void) {
return *src++;
}Ignorando Espaços em Branco
Antes de ler um token, descartamos espaços e tabulações. O isspace padrão de <ctype.h> lida com todos os caracteres de espaço em branco.
Aqui, as quebras de linha contam como espaços em branco, portanto a expressão pode ocupar várias linhas.
#include <ctype.h>
static void skip_ws(void) {
while (isspace((unsigned char)peek()))
advance();
}Analisando Lexicamente um Número
Quando o cursor está sobre um dígito, acumulamos os dígitos consecutivos em um inteiro. Multiplicar por dez e adicionar cada dígito constrói o valor da esquerda para a direita.
O laço para no primeiro caractere que não é um dígito, deixando o cursor pronto para o próximo token.
static int lex_number(void) {
int n = 0;
while (isdigit((unsigned char)peek())) {
n = n * 10 + (advance() - '0');
}
return n;
}A Função next_token
A rotina principal ignora os espaços em branco e então decide com base no caractere atual. Os dígitos se tornam um TOK_NUM; cada operador é associado ao seu próprio tipo.
Ao alcançar o NUL terminador, produzimos TOK_EOF, o sinal para parar.
static Token next_token(void) {
skip_ws();
char c = peek();
if (c == '\0') return (Token){TOK_EOF, 0};
if (isdigit((unsigned char)c))
return (Token){TOK_NUM, lex_number()};
advance();
switch (c) {
case '+': return (Token){TOK_PLUS, 0};
case '-': return (Token){TOK_MINUS, 0};
case '*': return (Token){TOK_STAR, 0};
case '/': return (Token){TOK_SLASH, 0};
case '(': return (Token){TOK_LPAREN, 0};
case ')': return (Token){TOK_RPAREN, 0};
}
return (Token){TOK_EOF, 0};
}Executando o Analisador Léxico
Aqui está um programa completo que tokeniza uma expressão e imprime o tipo de cada token. Os números também têm seus valores impressos.
Observe que o laço termina quando lê TOK_EOF.
#include <stdio.h>
#include <ctype.h>
typedef enum { TOK_NUM, TOK_PLUS, TOK_STAR, TOK_EOF } TokKind;
typedef struct { TokKind kind; int value; } Token;
static const char *src;
static char peek(void){ return *src; }
static char advance(void){ return *src++; }
static Token next_token(void){
while (isspace((unsigned char)peek())) advance();
char c = peek();
if (c=='\0') return (Token){TOK_EOF,0};
if (isdigit((unsigned char)c)){
int n=0; while(isdigit((unsigned char)peek())) n=n*10+(advance()-'0');
return (Token){TOK_NUM,n};
}
advance();
if (c=='+') return (Token){TOK_PLUS,0};
return (Token){TOK_STAR,0};
}
int main(void){
src = "12 + 3 * 4";
Token t;
do {
t = next_token();
if (t.kind==TOK_NUM) printf("NUM %d\n", t.value);
else if (t.kind==TOK_PLUS) printf("PLUS\n");
else if (t.kind==TOK_STAR) printf("STAR\n");
else printf("EOF\n");
} while (t.kind != TOK_EOF);
return 0;
}Antecipação de Um Token
Os analisadores sintáticos normalmente precisam inspecionar o próximo token antes de consumi-lo. Armazenamos um token em um current global e o preenchemos novamente após cada correspondência.
Essa antecipação de um único token é suficiente para nossa gramática LL(1).
static Token current;
static void init_lexer(const char *s) {
src = s;
current = next_token();
}
static Token cur(void) { return current; }
static void bump(void) { current = next_token(); }Relatando Erros Léxicos
Um caractere desconhecido — por exemplo, $ ou @ — não deve simplesmente desaparecer. Um analisador léxico robusto relata o byte incorreto e é encerrado.
Falhar rapidamente no analisador léxico impede que as etapas posteriores recebam tokens inválidos.
#include <stdio.h>
#include <stdlib.h>
static void lex_error(char c) {
fprintf(stderr, "lex error: unexpected '%c'\n", c);
exit(1);
}Operadores com Vários Caracteres
As linguagens reais têm tokens como == ou <=. Para analisá-los, consultamos um caractere adicional depois do primeiro.
Se o próximo byte completar o operador, consumimos ambos; caso contrário, emitimos a forma de um único caractere.
/* fragment: distinguish '=' from '==' */
if (peek() == '=') {
advance();
if (peek() == '=') { advance(); /* TOK_EQ */ }
else { /* TOK_ASSIGN */ }
}Por que os Tokens são Importantes
Ao agrupar caracteres em tokens, o analisador sintático trabalha com um fluxo limpo e tipado. A precedência dos operadores, o agrupamento e os erros ficam mais fáceis de compreender.
Em seguida, forneceremos esses tokens a um analisador sintático de descida recursiva.
Verificação Rápida
Pense no que o analisador léxico produz para os símbolos de agrupamento.
Recapitulação
Você construiu um analisador léxico: um tipo de token, um cursor de varredura, ignorância de espaços em branco, análise léxica de números e um despachante next_token com antecipação de um token.
Esses tokens são a entrada da análise sintática, que constrói uma árvore de sintaxe a partir deles.
Perguntas Frequentes
A aula “Tokenizando a entrada” é grátis?
Sim — o texto completo de “Tokenizando a entrada” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de C Academy, atualize para CoddyKit PRO. O curso de C Academy inclui 4 aulas no total.
O que vou aprender em “Tokenizando a entrada”?
Transforme texto em tokens. Você pratica C Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar C Academy?
Nenhuma experiência prévia é necessária. C Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Tokenizando a entrada”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de C Academy?
Sim. Cada aula de C Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Tokenizando a entrada
- Analisando expressões
- Avaliando a árvore
- Adicionando variáveis