0Pricing
C Academy · Lección

Añadir variables

Almacene y recupere valores

Añadir variables es una lección gratuita de C Academy en CoddyKit. Esta es la lección 4 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C Academy incluye 4 lecciones en total.

Más allá de la aritmética

Para admitir x = 5 y después x + 1, el intérprete necesita identificadores y un lugar donde almacenar sus valores. Ese almacén es el entorno.

Ampliaremos el lexer, el parser y el evaluador para gestionar nombres y asignaciones.

Análisis léxico de identificadores

Un identificador empieza por una letra o un guion bajo y continúa con letras, dígitos o guiones bajos. Copiamos el nombre en el token.

Un búfer de tamaño fijo mantiene sencillo el ejemplo; los lexers reales internan los nombres.

#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;
}

Un nodo de variable

El AST incorpora dos tipos de nodo: una referencia a variable y una asignación. Cada uno almacena el nombre de la variable.

La asignación también conserva la expresión cuyo valor almacena.

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;

El entorno

El entorno asocia nombres con valores. Para un intérprete pequeño basta con un arreglo lineal sencillo de pares nombre/valor.

Los lenguajes más grandes usan tablas hash para obtener búsquedas O(1) y ámbitos anidados.

#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 */

Asignación de una variable

Al asignar, se actualiza una posición existente o se añade una nueva. La búsqueda lineal mantiene el código breve.

Devolver el valor almacenado permite usar las asignaciones como expresiones, por ejemplo 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;
}

Lectura de una variable

La búsqueda recorre los nombres hasta encontrarlo y devuelve su valor. Hacer referencia a una variable no definida es un error de ejecución.

Detectarlo aquí proporciona un mensaje claro en lugar de devolver un valor basura.

#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);
}

Análisis de una asignación

La asignación tiene la precedencia más baja y es asociativa por la derecha. Analizamos un factor; si es un identificador aislado seguido de =, construimos un nodo de asignación.

De lo contrario, el identificador solo representa una lectura de variable.

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();
}

Evaluación de variables

El evaluador incorpora dos casos. Un nodo de variable busca su nombre en el entorno; un nodo de asignación evalúa su expresión de valor y la almacena.

Ambos reutilizan los auxiliares env_get y 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;
}

Un paso funcional del REPL

Este programa almacena una variable y después la lee en una expresión, todo mediante el entorno. Modela una línea de un intérprete real.

Ejecútelo para ver cómo cooperan la asignación y la búsqueda.

#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;
}

Ámbitos y ocultación

Un único entorno plano es global. Los lenguajes reales añaden ámbitos anidados para que las variables locales de una función no sobrescriban los nombres externos.

Esto se implementa encadenando entornos: la búsqueda recorre los ámbitos desde el más interno hacia afuera.

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

El siguiente paso

Con las variables ya disponibles, puede añadir sentencias, condicionales y funciones. Cada elemento requiere un nuevo tipo de nodo y un caso en eval.

A partir de aquí, la misma cadena lexer-parser-evaluador puede ampliarse hasta convertirse en un pequeño lenguaje real.

Comprobación rápida

Reflexione sobre la responsabilidad del entorno.

Repaso

Ha añadido identificadores al lexer, nodos var/assign al AST, un entorno con operaciones de asignación y lectura, y casos de eval para las lecturas y las asignaciones.

Ahora el intérprete conserva el estado: la base para incorporar sentencias y funciones.

Preguntas frecuentes

¿La lección «Añadir variables» es gratis?

Sí — el texto completo de «Añadir variables» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C Academy, actualiza a CoddyKit PRO. El curso de C Academy incluye 4 lecciones en total.

¿Qué aprenderé en «Añadir variables»?

Almacene y recupere valores Practicas C Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar C Academy?

No se requiere experiencia previa. C Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 4 de 4.

¿Cuánto tiempo toma la lección «Añadir variables»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de C Academy?

Sí. Cada lección de C Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Tokenizar la entrada
  2. Analizar expresiones
  3. Evaluar el árbol
  4. Añadir variables
← Volver a C Academy