0Pricing
C Academy · Aula

Adicionando variáveis

Armazene e recupere valores.

Adicionando variáveis é uma aula grátis de C Academy no CoddyKit. Esta é a aula 4 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.

Além da aritmética

Para aceitar x = 5 e depois x + 1, o interpretador precisa de identificadores e de um lugar para armazenar seus valores. Esse armazenamento é o ambiente.

Estenderemos o analisador léxico, o analisador sintático e o avaliador para tratar nomes e atribuições.

Analisando identificadores

Um identificador começa com uma letra ou sublinhado e continua com letras, dígitos ou sublinhados. Copiamos o nome para o token.

Um buffer de tamanho fixo mantém o exemplo simples; analisadores léxicos reais internam os nomes.

#include <ctype.h>
#include <string.h>

typedef struct { TokKind kind; int value; char name[32]; } Token;

static Token lex_ident(void) {
  Token t; t.kind = TOK_IDENT; int i = 0;
  while (isalnum((unsigned char)peek()) || peek() == '_')
    if (i < 31) t.name[i++] = advance(); else advance();
  t.name[i] = '\0';
  return t;
}

Um nó de variável

A AST ganha dois tipos de nós: uma referência a variável e uma atribuição. Cada um armazena o nome da variável.

A atribuição também mantém a expressão cujo valor armazena.

typedef struct Node {
  enum { N_NUM, N_BINOP, N_VAR, N_ASSIGN } kind;
  int value; char op; char name[32];
  struct Node *left, *right;  /* assign uses right as value expr */
} Node;

O ambiente

O ambiente associa nomes a valores. Um simples vetor linear de pares nome/valor é suficiente para um interpretador pequeno.

Linguagens maiores usam tabelas de dispersão para obter busca O(1) e escopos aninhados.

#define MAX_VARS 64

typedef struct {
  char names[MAX_VARS][32];
  int  values[MAX_VARS];
  int  count;
} Env;

static Env env;  /* global for this tiny example */

Atribuindo a uma variável

A atribuição atualiza uma posição existente ou acrescenta uma nova. A busca linear mantém o código curto.

Retornar o valor armazenado permite usar atribuições como expressões, por exemplo y = (x = 3).

#include <string.h>

static int env_set(const char *name, int v) {
  for (int i = 0; i < env.count; i++)
    if (strcmp(env.names[i], name) == 0) {
      env.values[i] = v; return v;
    }
  strcpy(env.names[env.count], name);
  env.values[env.count] = v;
  env.count++;
  return v;
}

Lendo uma variável

A busca percorre os nomes e retorna o valor correspondente. Referenciar uma variável não definida é um erro em tempo de execução.

Detectar isso aqui produz uma mensagem clara em vez de retornar um valor inválido.

#include <stdio.h>
#include <stdlib.h>

static int env_get(const char *name) {
  for (int i = 0; i < env.count; i++)
    if (strcmp(env.names[i], name) == 0)
      return env.values[i];
  fprintf(stderr, "undefined variable: %s\n", name);
  exit(1);
}

Analisando uma atribuição

A atribuição tem a menor precedência e é associativa à direita. Analisamos um fator; se ele for um identificador isolado seguido de =, construímos um nó de atribuição.

Caso contrário, o identificador é apenas uma leitura de variável.

static Node *parse_assign(void) {
  if (cur().kind == TOK_IDENT) {
    char saved[32]; strcpy(saved, cur().name);
    bump();
    if (cur().kind == TOK_ASSIGN) {
      bump();
      Node *val = parse_assign();
      return assign_node(saved, val);
    }
    return var_node(saved);  /* not an assignment */
  }
  return parse_expr();
}

Avaliando variáveis

O avaliador ganha dois casos. Um nó de variável procura seu nome no ambiente; um nó de atribuição avalia sua expressão de valor e a armazena.

Ambos reutilizam os auxiliares env_get e env_set.

int eval(Node *n) {
  switch (n->kind) {
    case N_NUM:    return n->value;
    case N_VAR:    return env_get(n->name);
    case N_ASSIGN: return env_set(n->name, eval(n->right));
    case N_BINOP: {
      int l = eval(n->left), r = eval(n->right);
      switch (n->op) {
        case '+': return l + r; case '-': return l - r;
        case '*': return l * r; case '/': return l / r;
      }
    }
  }
  return 0;
}

Uma etapa funcional do REPL

Este programa armazena uma variável e depois a lê novamente em uma expressão — tudo por meio do ambiente. Ele modela uma linha de um interpretador real.

Execute-o para ver a atribuição e a busca trabalhando em conjunto.

#include <stdio.h>
#include <string.h>

#define MAX_VARS 64
static char names[MAX_VARS][32];
static int  values[MAX_VARS];
static int  count;

static int env_set(const char *n,int v){
  for(int i=0;i<count;i++) if(!strcmp(names[i],n)){values[i]=v;return v;}
  strcpy(names[count],n); values[count]=v; count++; return v;
}
static int env_get(const char *n){
  for(int i=0;i<count;i++) if(!strcmp(names[i],n)) return values[i];
  return 0;
}

int main(void){
  env_set("x", 5);            /* x = 5 */
  int r = env_get("x") + 1;   /* x + 1 */
  printf("x = %d\n", env_get("x"));
  printf("x + 1 = %d\n", r);
  return 0;
}

Escopos e ocultação

Um único ambiente plano é global. Linguagens reais adicionam escopos aninhados para que as variáveis locais de uma função não sobrescrevam nomes externos.

O senhor implementa isso encadeando ambientes: a busca percorre do escopo mais interno para os externos.

typedef struct Env {
  char names[MAX_VARS][32];
  int  values[MAX_VARS];
  int  count;
  struct Env *parent;  /* enclosing scope */
} Env;

Para onde seguir

Com as variáveis prontas, o senhor pode adicionar instruções, condicionais e funções. Cada um é um novo tipo de nó mais um caso em eval.

A partir daqui, o mesmo fluxo de análise léxica, análise sintática e avaliação pode crescer até se tornar uma pequena linguagem real.

Verificação rápida

Pense pelo que o ambiente é responsável.

Recapitulação

O senhor adicionou identificadores ao analisador léxico, nós de variável e atribuição à AST, um ambiente com definição e leitura, além de casos em eval para leituras e atribuições.

Agora o interpretador memoriza estado — a base para instruções e funções.

Perguntas Frequentes

A aula “Adicionando variáveis” é grátis?

Sim — o texto completo de “Adicionando variáveis” é 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 “Adicionando variáveis”?

Armazene e recupere valores. 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 4 de 4.

Quanto tempo leva a aula “Adicionando variáveis”?

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