0Pricing
C Academy · Lesson

Adding Variables

Store and recall values.

Adding Variables is a free C Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the C Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.

Beyond Arithmetic

To support x = 5 and later x + 1, the interpreter needs identifiers and a place to store their values. That store is the environment.

We will extend the lexer, parser, and evaluator to handle names and assignment.

Lexing Identifiers

An identifier starts with a letter or underscore and continues with letters, digits, or underscores. We copy the name into the token.

A fixed-size buffer keeps the example simple; real lexers intern names.

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

A Variable Node

The AST gains two node kinds: a variable reference and an assignment. Each stores the variable name.

Assignment also keeps the expression whose value it stores.

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;

The Environment

The environment maps names to values. A simple linear array of name/value pairs suffices for a small interpreter.

Larger languages use hash tables for O(1) lookup and nested scopes.

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

Setting a Variable

Assigning either updates an existing slot or appends a new one. Linear search keeps the code short.

Returning the stored value lets assignments be used as expressions, like 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;
}

Reading a Variable

Lookup scans for the name and returns its value. Referencing an undefined variable is a runtime error.

Catching this here gives a clear message instead of returning a garbage value.

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

Parsing Assignment

Assignment has the lowest precedence and is right-associative. We parse a factor; if it is a bare identifier followed by =, we build an assign node.

Otherwise the identifier is just a variable read.

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

Evaluating Variables

The evaluator gains two cases. A variable node looks its name up in the environment; an assign node evaluates its value expression and stores it.

Both reuse the env_get and env_set helpers.

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

A Working REPL Step

This program stores a variable, then reads it back in an expression — all through the environment. It models one line of a real interpreter.

Run it to see assignment and lookup cooperate.

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

Scopes and Shadowing

A single flat environment is global. Real languages add nested scopes so a function's locals do not clobber outer names.

You implement this by chaining environments: lookup walks from the innermost scope outward.

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

Where to Go Next

With variables in place you can add statements, conditionals, and functions. Each is a new node kind plus an eval case.

From here, the same lexer-parser-evaluator pipeline scales into a real little language.

Quick Check

Think about what the environment is responsible for.

Recap

You added identifiers to the lexer, var/assign nodes to the AST, an environment with set and get, and eval cases for reads and assignments.

The interpreter now remembers state — the foundation for statements and functions.

Frequently asked questions

Is the “Adding Variables” lesson free?

Yes — the full text of “Adding Variables” is free to read here on the web, and the C Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the C Academy course, upgrade to CoddyKit PRO.

What will I learn in “Adding Variables”?

Store and recall values. You practise C Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.

Do I need any experience to start C Academy?

No prior experience is required. C Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.

How long does the “Adding Variables” lesson take?

Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.

Can I write and run code in this C Academy lesson?

Yes. Every C Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.

All lessons in this course

  1. Tokenizing Input
  2. Parsing Expressions
  3. Evaluating the Tree
  4. Adding Variables
← Back to C Academy