0Pricing
C Academy · Aula

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

  1. Tokenizando a entrada
  2. Analisando expressões
  3. Avaliando a árvore
  4. Adicionando variáveis
← Voltar para C Academy