C Academy · Lektion

Lägg till variabler

Lagra och hämta värden.

Lektion 4 av 413 steg

Lägg till variabler är en gratis lektion i C Academy på CoddyKit. Detta är lektion 4 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för C Academy, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i C Academy innehåller totalt 4 lektioner.

Bortom aritmetik

För att stödja x = 5 och senare x + 1 behöver tolken identifierare och en plats där deras värden kan lagras. Den lagringsplatsen är miljön.

Vi utökar lexern, parsern och evalueringen så att de hanterar namn och tilldelning.

Lexa identifierare

En identifierare börjar med en bokstav eller ett understreck och fortsätter med bokstäver, siffror eller understreck. Vi kopierar namnet till tokenen.

En buffert med fast storlek håller exemplet enkelt; riktiga lexrar internar namn.

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

En variabelnod

AST:t får två nya nodtyper: en variabelreferens och en tilldelning. Båda lagrar variabelnamnet.

Tilldelningen sparar även uttrycket vars värde den lagrar.

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;

Miljön

Miljön mappar namn till värden. En enkel linjär array med namn/värde-par räcker för en liten tolk.

Större språk använder hashtabeller för uppslagning i O(1) och nästlade scope.

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

Tilldela en variabel

En tilldelning uppdaterar antingen en befintlig plats eller lägger till en ny. Linjär sökning håller koden kort.

Genom att returnera det lagrade värdet kan tilldelningar användas som uttryck, till exempel 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;
}

Läsa en variabel

Uppslagningen söker efter namnet och returnerar dess värde. En referens till en odefinierad variabel är ett körtidsfel.

Genom att fånga detta här får användaren ett tydligt meddelande i stället för ett skräpvärde.

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

Parsa tilldelning

Tilldelning har lägst prioritet och är högerassociativ. Vi parsar en faktor; om den är en fristående identifierare följd av = bygger vi en assign-nod.

Annars är identifieraren bara en variabelläsning.

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

Evaluera variabler

Evaluatorn får två nya fall. En variabelnod slår upp namnet i miljön; en assign-nod evaluerar sitt värdeuttryck och lagrar det.

Båda återanvänder hjälpfunktionerna env_get och 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;
}

Ett fungerande REPL-steg

Detta program lagrar en variabel och läser sedan tillbaka den i ett uttryck – allt via miljön. Det motsvarar en rad i en riktig tolk.

Kör programmet för att se hur tilldelning och uppslagning samverkar.

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

Scope och skuggning

En enda platt miljö är global. Riktiga språk lägger till nästlade scope så att en funktions lokala variabler inte skriver över namn i yttre scope.

Det implementerar du genom att kedja miljöer: uppslagningen går från det innersta scopet och utåt.

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

Nästa steg

När variablerna finns på plats kan du lägga till satser, villkor och funktioner. Var och en är en ny nodtyp plus ett eval-fall.

Härifrån kan samma lexer-parser-evaluator-pipeline växa till ett riktigt litet språk.

Snabb kontroll

Fundera på vilket ansvar miljön har.

Sammanfattning

Du lade till identifierare i lexern, var/assign-noder i AST:t, en miljö med set och get samt eval-fall för läsningar och tilldelningar.

Tolken kommer nu ihåg tillstånd – grunden för satser och funktioner.

Gratis att börja

Lär dig C med en AI-lärare – gratis

Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.

Kurser
39
Lektioner
144

Vanliga frågor

Är lektionen ”Lägg till variabler” gratis?

Ja – hela texten till ”Lägg till variabler” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i C Academy, kan Ni uppgradera till CoddyKit PRO. Kursen i C Academy innehåller totalt 4 lektioner.

Vad lär jag mig i ”Lägg till variabler”?

Lagra och hämta värden. Ni övar på C Academy med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.

Behöver jag någon erfarenhet för att börja lära mig C Academy?

Du behöver inga förkunskaper. Utbildningen i C Academy på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 4 av 4.

Hur lång tid tar lektionen ”Lägg till variabler”?

De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.

Kan jag skriva och köra kod i den här C Academy-lektionen?

Ja. Varje C Academy-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.

Alla lektioner i den här kursen

  1. Tokenisera indata
  2. Parsa uttryck
  3. Utvärdera trädet
  4. Lägg till variabler
← Tillbaka till C Academy