Mokey-ast

Apr 12, 2026

1087 words

5 min read

zig

Note: This page does not support English, using the default language version

ast的定义

简单的介绍

Monkey 分为表达式和语句.学过rust可能好理解一些 其中语句只有: Let语句, Return语句, 表达式语句, 还有比较特殊的块语句 表达式有: if-else ,bool 表达式, 函数调用等.

TIP

书里面对于这个语法要求很严格, 像是()这些不可以省的, 后面具体解析的时候可以发现

Statement定义

pub const Statement = union(enum) {
    let_statement: *LetStatement,
    return_statement: *ReturnStatement,
    expression: *ExpressionStatement,
    block: *BlockStatement,
    pub fn tokenLiteral(self: *const Statement) []const u8 {
        return switch (self.*) {
            .let_statement => |ls| ls.token.Literal,
            .return_statement => |rs| rs.token.Literal,
            .expression => |es| es.tokenLiteral(),
            .block => |bs| bs.token.Literal,
        };
    }

    pub fn string(self: *Statement, allocator: std.mem.Allocator) std.mem.Allocator.Error![]const u8 {
        return switch (self.*) {
            .let_statement => |s| s.string(allocator),
            .return_statement => |s| s.string(allocator),
            .expression => |s| s.string(allocator),
            .block => |s| s.string(allocator),
        };
    }
};
pub const Expression = union(enum) {
    identifier: *Identifier,
    boolean: *Boolean,
    integer: *IntegerLiteral,
    prefix: *PrefixExpression,
    infix: *InfixExpression,
    if_expr: *IfExpression,
    function: *FunctionLiteral,
    call: *CallExpression,
    pub fn tokenLiteral(self: *Expression) []const u8 {
        return switch (self.*) {
            .identifier => |i| i.token.Literal,
            .boolean => |b| b.token.Literal,
            .integer => |il| il.token.Literal,
            .prefix => |pe| pe.token.Literal,
            .infix => |ie| ie.token.Literal,
            .if_expr => |ie| ie.token.Literal,
            .function => |fl| fl.token.Literal,
            .call => |ce| ce.token.Literal,
        };
    }
    pub fn string(self: *Expression, allocator: std.mem.Allocator) std.mem.Allocator.Error![]const u8 {
        return switch (self.*) {
            .identifier => |e| e.string(allocator),
            .boolean => |e| e.string(allocator),
            .integer => |e| e.string(allocator),
            .prefix => |e| e.string(allocator),
            .infix => |e| e.string(allocator),
            .if_expr => |e| e.string(allocator),
            .function => |e| e.string(allocator),
            .call => |e| e.string(allocator),
        };
    }
};

tokenLiteralstring 方法是为了调试, 和书中保持同步, 这两个枚举中的想当于一个分发器.

LetStatement

pub const LetStatement = struct {
    token: token.Token,
    name: *Identifier,
    value: ?*Expression,
    pub fn tokenLiteral(self: *LetStatement) []const u8 {
        return self.token.Literal;
    }
    pub fn string(self: *LetStatement, gpa: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        try buf.appendSlice(gpa, self.token.Literal);
        try buf.append(gpa, ' ');
        const ns = try self.name.string(gpa);
        defer gpa.free(ns);
        try buf.appendSlice(gpa, ns);
        try buf.appendSlice(gpa, " = ");
        if (self.value) |stmt| {
            const vs = try stmt.string(gpa);
            defer gpa.free(vs);
            try buf.appendSlice(gpa, vs);
        }
        try buf.append(gpa, ';');
        return buf.toOwnedSlice(gpa);
    }
};

let [identifier] = [expression] 的形式

ReturnStatement

pub const ReturnStatement = struct {
    token: token.Token,
    return_value: ?*Expression,
    pub fn tokenLiteral(self: *ReturnStatement) []const u8 {
        return self.token.Literal;
    }
    pub fn string(self: *ReturnStatement, allocator: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        try buf.appendSlice(allocator, self.token.Literal);
        try buf.append(allocator, ' ');
        if (self.return_value) |item| {
            const vs = try item.string(allocator);
            defer allocator.free(vs);
            try buf.appendSlice(allocator, vs);
        }
        try buf.append(allocator, ';');
        return buf.toOwnedSlice(allocator);
    }
};

return [expression]

ExpressionStatement

pub const ExpressionStatement = struct {
    token: token.Token,
    expression: ?*Expression,

    pub fn tokenLiteral(self: *ExpressionStatement) []const u8 {
        return self.token.Literal;
    }

    pub fn string(self: *ExpressionStatement, allocator: std.mem.Allocator) ![]const u8 {
        if (self.expression) |exp| {
            return exp.string(allocator);
        }
        return "";
    }
};

像是 5 + 5;这样的

BlockStatement

pub const BlockStatement = struct {
    token: token.Token,
    statements: std.ArrayList(*Statement),

    pub fn tokenLiteral(self: *BlockStatement) []const u8 {
        return self.token.Literal;
    }
    pub fn string(self: *BlockStatement, allocator: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        for (self.statements.items) |value| {
            const s = try value.string(allocator);
            defer allocator.free(s);
            try buf.appendSlice(allocator, s);
        }
        return buf.toOwnedSlice(allocator);
    }
};

这个是{}中的语句

Expression定义

太多了, 挑几个重要的说吧

PrefixExpression

pub const PrefixExpression = struct {
    token: token.Token, // 前缀操作符 token
    operator: []const u8,
    right: ?*Expression,

    pub fn tokenLiteral(self: *PrefixExpression) []const u8 {
        return self.token.Literal;
    }

    pub fn string(self: *PrefixExpression, allocator: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        try buf.append(allocator, '(');
        try buf.appendSlice(allocator, self.operator);
        if (self.right) |r| {
            const rs = try r.string(allocator);
            defer allocator.free(rs);
            try buf.appendSlice(allocator, rs);
        }
        try buf.append(allocator, ')');
        return buf.toOwnedSlice(allocator);
    }
};

对于形如: -5, !true, !-5这样的表达式

InfixExpression

pub const InfixExpression = struct {
    token: token.Token, // 操作符 token,'+'
    left: ?*Expression,
    operator: []const u8,
    right: ?*Expression,

    pub fn tokenLiteral(self: *InfixExpression) []const u8 {
        return self.token.Literal;
    }

    pub fn string(self: *InfixExpression, allocator: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        try buf.append(allocator, '(');
        if (self.left) |l| {
            const ls = try l.string(allocator);
            defer allocator.free(ls);
            try buf.appendSlice(allocator, ls);
        }
        try buf.append(allocator, ' ');
        try buf.appendSlice(allocator, self.operator);
        try buf.append(allocator, ' ');
        if (self.right) |r| {
            const rs = try r.string(allocator);
            defer allocator.free(rs);
            try buf.appendSlice(allocator, rs);
        }
        try buf.append(allocator, ')');
        return buf.toOwnedSlice(allocator);
    }
};

5 + 5 这样的

IfExpression

pub const IfExpression = struct {
    token: token.Token,
    condition: ?*Expression,
    consequence: ?*BlockStatement,
    alternative: ?*BlockStatement,

    pub fn tokenLiteral(self: *IfExpression) []const u8 {
        return self.token.Literal;
    }

    pub fn string(self: *IfExpression, allocator: std.mem.Allocator) ![]const u8 {
        var buf: std.ArrayList(u8) = .empty;
        try buf.appendSlice(allocator, "if");
        if (self.condition) |cond| {
            const cs = try cond.string(allocator);
            defer allocator.free(cs);
            try buf.append(allocator, ' ');
            try buf.appendSlice(allocator, cs);
        }
        try buf.append(allocator, ' ');
        if (self.consequence) |cons| {
            const cs = try cons.string(allocator);
            defer allocator.free(cs);
            try buf.appendSlice(allocator, cs);
        }
        if (self.alternative) |alt| {
            try buf.appendSlice(allocator, "else ");
            const as = try alt.string(allocator);
            defer allocator.free(as);
            try buf.appendSlice(allocator, as);
        }
        return buf.toOwnedSlice(allocator);
    }
};

if (a == 5) {[statements]} 这样的, 一定要严格写括号!

FunctionLiteral

pub const FunctionLiteral = struct {
    token: token.Token,
    parameters: std.ArrayListUnmanaged(*Identifier),
    body: ?*BlockStatement,

    pub fn tokenLiteral(self: *FunctionLiteral) []const u8 {
        return self.token.Literal;
    }
    pub fn string(self: *FunctionLiteral, allocator: std.mem.Allocator) ![]const u8 {
        var buf = std.ArrayList(u8).empty;
        try buf.appendSlice(allocator, self.token.Literal);
        try buf.append(allocator, '(');
        for (self.parameters.items, 0..) |parm, i| {
            if (i > 0) try buf.appendSlice(allocator, ", ");
            const ps = try parm.string(allocator);
            defer allocator.free(ps);
            try buf.appendSlice(allocator, ps);
        }
        try buf.appendSlice(allocator, ") ");
        if (self.body) |b| {
            const bs = try b.string(allocator);
            defer allocator.free(bs);
            try buf.appendSlice(allocator, bs);
        }
        return try buf.toOwnedSlice(allocator);
    }
};

fn(x,y) {}

CallExpression

pub const CallExpression = struct {
    token: token.Token,
    function: ?*Expression,
    arguments: std.ArrayListUnmanaged(*Expression),

    pub fn tokenLiteral(self: *CallExpression) []const u8 {
        return self.token.Literal;
    }

    pub fn string(self: *CallExpression, allocator: std.mem.Allocator) ![]const u8 {
        var buf = std.ArrayList(u8).empty;
        if (self.function) |f| {
            const fs = try f.string(allocator);
            defer allocator.free(fs);
            try buf.appendSlice(allocator, fs);
        }
        try buf.append(allocator, '(');
        for (self.arguments.items, 0..) |arg, i| {
            if (i > 0) try buf.appendSlice(allocator, ", ");
            const arg_str = try arg.string(allocator);
            defer allocator.free(arg_str);
            try buf.appendSlice(allocator, arg_str);
        }
        try buf.append(allocator, ')');
        return buf.toOwnedSlice(allocator);
    }
};

add(5,1)

后记

这也没什么好说的.

Enter keywords to start searching