添加变量
存储并取回值。
添加变量 是 CoddyKit 上的免费 C Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 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);
}解析赋值
赋值的优先级最低,并且具有右结合性。我们先解析一个因子;如果它是一个裸标识符,后面紧跟=,就构建一个赋值节点。
否则,该标识符就只是一次变量读取。
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();
}计算变量
求值器增加了两种情况。变量节点会在环境中查找其名称;赋值节点会计算它的值表达式并将结果存储起来。
两者都会复用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;下一步方向
有了变量之后,您就可以添加语句、条件和函数。每一种功能都对应一种新的节点类型以及一个求值分支。
从这里开始,同一套词法分析器—解析器—求值器流水线可以扩展为真正的小型语言。
快速检查
思考一下环境负责什么。
回顾
您为词法分析器添加了标识符,为 AST 添加了变量/赋值节点,添加了支持设置和获取的环境,并为读取和赋值添加了求值分支。
现在,解释器可以记住状态,这为语句和函数奠定了基础。
常见问题解答
「添加变量」课时是免费的吗?
是的 — 「添加变量」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。
「添加变量」这节课中我会学到什么?
存储并取回值。 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 C Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「添加变量」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 C Academy 课中编写并运行代码吗?
能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。