0Pricing
C Academy · บทเรียน

เพิ่มตัวแปร

จัดเก็บและเรียกคืนค่า

เพิ่มตัวแปร เป็นบทเรียน C Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน C Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

ก้าวข้ามการคำนวณเลขคณิต

เพื่อรองรับ x = 5 และต่อมาคือ x + 1 ตัวแปลผลจำเป็นต้องมี ตัวระบุ และที่เก็บค่าสำหรับตัวระบุเหล่านั้น ที่เก็บนี้เรียกว่าสภาพแวดล้อม

เราจะขยายตัววิเคราะห์คำศัพท์ ตัวแยกวิเคราะห์ และตัวประเมินผล เพื่อจัดการชื่อและการกำหนดค่า

การวิเคราะห์คำศัพท์ของตัวระบุ

ตัวระบุเริ่มต้นด้วยตัวอักษรหรือขีดล่าง และต่อด้วยตัวอักษร ตัวเลข หรือขีดล่าง เราจะคัดลอกชื่อลงในโทเค็น

บัฟเฟอร์ขนาดคงที่ทำให้ตัวอย่างเรียบง่าย ส่วนตัววิเคราะห์คำศัพท์จริงจะเก็บชื่อไว้ในตารางร่วม

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

โหนดตัวแปร

AST จะมีชนิดโหนดเพิ่มขึ้นสองชนิด ได้แก่ การอ้างอิงตัวแปรและการกำหนดค่า แต่ละชนิดจะเก็บชื่อตัวแปรไว้

การกำหนดค่ายังเก็บนิพจน์ที่ให้ค่าซึ่งจะถูกจัดเก็บด้วย

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(1) และรองรับขอบเขตตัวแปรที่ซ้อนกัน

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

การกำหนดค่าตัวแปร

การกำหนดค่าอาจอัปเดตช่องที่มีอยู่ หรือเพิ่มช่องใหม่ต่อท้าย การค้นหาแบบเชิงเส้นช่วยให้โค้ดสั้น

การคืนค่าที่จัดเก็บไว้ทำให้สามารถใช้การกำหนดค่าเป็นนิพจน์ได้ เช่น 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;
}

การอ่านค่าตัวแปร

การค้นหาจะสแกนหาชื่อแล้วคืนค่าของชื่อนั้น การอ้างอิงตัวแปรที่ไม่ได้กำหนดค่าถือเป็นข้อผิดพลาดขณะทำงาน

การตรวจจับกรณีนี้ตรงจุดดังกล่าวทำให้ได้ข้อความที่ชัดเจน แทนที่จะคืนค่าขยะ

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

การแยกวิเคราะห์การกำหนดค่า

การกำหนดค่ามีลำดับความสำคัญต่ำที่สุดและจับกลุ่มจากขวาไปซ้าย เราจะแยกวิเคราะห์ตัวประกอบก่อน หากเป็นตัวระบุเดี่ยวที่ตามด้วย = เราจะสร้าง assign node

มิฉะนั้น ตัวระบุนั้นก็เป็นเพียงการอ่านค่าตัวแปร

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

การประเมินผลตัวแปร

ตัวประเมินผลจะมีกรณีเพิ่มขึ้นสองกรณี โหนดตัวแปรจะค้นหาชื่อในสภาพแวดล้อม ส่วน assign node จะประเมินนิพจน์ค่าของตัวเองแล้วจัดเก็บค่านั้น

ทั้งสองกรณีใช้ตัวช่วย env_get และ 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;
}

ขั้นตอนหนึ่งของ REPL ที่ทำงานได้

โปรแกรมนี้จัดเก็บตัวแปร แล้วอ่านตัวแปรนั้นกลับมาในนิพจน์ โดยทำงานผ่านสภาพแวดล้อมทั้งหมด เป็นแบบจำลองของหนึ่งบรรทัดในตัวแปลผลจริง

เรียกใช้เพื่อดูการทำงานร่วมกันของการกำหนดค่าและการค้นหา

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

ขอบเขตตัวแปรและการบดบังชื่อ

สภาพแวดล้อมแบบแบนเพียงหนึ่งเดียวถือเป็นระดับโกลบอล ภาษาจริงเพิ่มขอบเขตตัวแปรที่ซ้อนกัน เพื่อไม่ให้ตัวแปรภายในฟังก์ชันเขียนทับชื่อด้านนอก

คุณจะทำเช่นนี้ได้โดยเชื่อมสภาพแวดล้อมเข้าด้วยกัน การค้นหาจะเดินจากขอบเขตด้านในสุดออกไปด้านนอก

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

ขั้นต่อไป

เมื่อมีตัวแปรแล้ว คุณสามารถเพิ่มคำสั่ง เงื่อนไข และฟังก์ชันได้ แต่ละอย่างคือชนิดโหนดใหม่พร้อมกรณีการประเมินผล

จากจุดนี้ กระบวนการตัววิเคราะห์คำศัพท์-ตัวแยกวิเคราะห์-ตัวประเมินผลแบบเดิมสามารถขยายไปเป็นภาษาขนาดเล็กที่ใช้งานได้จริง

ตรวจสอบความเข้าใจ

ลองคิดว่าสภาพแวดล้อมมีหน้าที่รับผิดชอบอะไร

สรุปทบทวน

คุณได้เพิ่มตัวระบุให้ตัววิเคราะห์คำศัพท์ เพิ่มโหนด var/assign ให้ AST เพิ่มสภาพแวดล้อมที่มีการกำหนดค่าและการอ่านค่า รวมถึงเพิ่มกรณีการประเมินผลสำหรับการอ่านและการกำหนดค่า

ตอนนี้ตัวแปลผลจดจำสถานะได้แล้ว ซึ่งเป็นพื้นฐานสำหรับคำสั่งและฟังก์ชัน

คำถามที่พบบ่อย

บทเรียน “เพิ่มตัวแปร” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “เพิ่มตัวแปร” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส C Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส C Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “เพิ่มตัวแปร”

จัดเก็บและเรียกคืนค่า คุณปฏิบัติ C Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน C Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน C Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “เพิ่มตัวแปร” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน C Academy นี้ได้ไหม

ได้ บทเรียน C Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. แยกข้อมูลนำเข้าเป็นโทเคน
  2. แยกวิเคราะห์นิพจน์
  3. ประเมินค่าต้นไม้
  4. เพิ่มตัวแปร
← กลับไปที่ C Academy