{ }codelper
변수 범위사전 찾기재귀P0245

정적 범위와 동적 범위로 두 번 돌리기

작은 언어로 쓴 프로그램을 두 가지 변수 범위 규칙으로 각각 실행하고, 결과를 나란히 출력한다. 프로그램은 n줄이고, 줄마다 명령이 하나 있다. def f 줄부터 end 줄까지는 함수 f의 정의이고, 그 사이의 줄들이 f의 몸체다. 함수 정의는 맨 바깥에만 있고, 함수 안에 함수를 정의하지 않는다. 함수 정의 밖의 줄들이 맨 바깥 명령이고, 위에서부터 차례로 실행한다. 함수 정의 자체는 실행하지 않으며, 함수는 정의가 프로그램의 어디에 있든 부를 수 있다. 변수는 '칸'에 들어 있다.
맨 바깥 명령은 전역 칸을 쓴다. 함수를 부를 때마다 빈 칸을 새로 만들고, 그 함수의 몸체를 그 칸에서 실행한다.
함수가 끝나면 그 칸은 사라진다. 명령은 다섯 가지다. - var x v: 지금 칸에 변수 x를 만들고 값 v를 넣는다.
지금 칸에 x가 이미 있으면 그 값만 v로 바꾼다. - set x v: x를 찾아 그 값을 v로 바꾼다. - add x v: x를 찾아 그 값에 v를 더한다. - print x: x를 찾아 그 값을 출력한다.
찾지 못하면 ?를 출력한다. - call f: 함수 f를 부른다.
f가 끝나면 다음 명령으로 간다. set과 add는 x를 찾지 못하면 아무것도 하지 않는다.
새 변수를 만들지 않는다. '찾기'는 정해진 차례대로 칸들을 보며 x가 들어 있는 첫 칸을 고르는 것이다.
그 차례가 범위 규칙이다. 정적 범위에서는 지금 칸을 보고, 그다음 전역 칸을 본다. 동적 범위에서는 지금 칸, 지금 함수를 부른 함수의 칸, 그 함수를 부른 함수의 칸, … 차례로 보고, 마지막에 전역 칸을 본다. 맨 바깥에서는 지금 칸이 곧 전역 칸이다. 변수 이름과 함수 이름은 따로 센다.
같은 이름이 변수와 함수에 함께 쓰일 수 있다. 프로그램을 정적 범위로 한 번, 동적 범위로 한 번, 처음 상태에서 따로 실행한다.
두 실행에서 print가 실행되는 횟수는 같다. print가 실행될 때마다 한 줄에, 정적 범위로 실행했을 때의 출력과 동적 범위로 실행했을 때의 출력을 빈칸 하나로 나눠 출력하라.

입력
첫 줄에 n, 다음 n줄에 명령이 하나씩 주어진다.
1 ≤ n ≤ 1,000.
이름은 영어 소문자로 시작하는 영어 소문자·숫자 1~10글자다.
모든 v와, 실행하는 동안 변수가 갖는 모든 값은 -10^9 이상 10^9 이하의 정수다.
def마다 짝이 되는 end가 있고, 같은 이름의 함수를 두 번 정의하지 않으며, call로 부르는 함수는 모두 정의되어 있다.
함수는 직접이든 다른 함수를 거쳐서든 자기 자신을 부르지 않는다.
두 실행 모두에서 실행되는 명령(call 포함)은 50,000개 이하, 한꺼번에 열려 있는 함수 호출은 30개 이하, 실행되는 print는 1개 이상 5,000개 이하다
출력
print가 실행된 횟수만큼의 줄
예시 1 · stdin
13
var x 1
def show
print x
end
def change
var x 2
call show
set x 3
call show
end
call change
print x
call show
stdout
1 2
1 3
1 1
1 1
예시 2 · stdin
21
def inc
add n 1
print n
end
def run
var n 10
call inc
call inc
end
var n 0
call run
print n
def peek
print m
end
def outer
var m 5
call peek
end
call outer
call peek
stdout
1 11
2 12
2 0
? 5
? ?
main.py
입력(stdin)

실행하면 이 줄들이 차례로 input()·표준 입력으로 들어가요(실행 중에 묻지 않아요).

$ 준비됐어요

코드를 입력해 풀려면 PC에서 열어 주세요. 모바일에서는 문제와 풀이를 볼 수 있어요.

다른 언어로는?언어별 풀이 보기 · 8개 언어 풀이

8개 언어는 모두 정적 범위예요.
함수 안에서 보이는 이름은 '어디서 불렀나'가 아니라 '어디에 쓰여 있나'로 정해져요.
동적 범위는 옛 Lisp, Emacs Lisp(기본값), bash 함수의 local, Perl local에서 볼 수 있어요.
첫 예시의 show는 정적 범위에서 늘 전역 x(1)를 보고, 동적 범위에서는 자기를 부른 change의 x(2, 3)를 봐요.
풀이는 칸마다 사전 하나를 두고 칸들을 목록(스택)에 쌓아요: Python dict 목록, JS·TS Map[], Java List<Map<String, Integer>>, C# List<Dictionary<string, int>>, C++ std::vector<std::unordered_map<…>>, 크레이콘 사전() 목록이에요.
C에는 사전이 없어 이름을 번호로 바꾼 뒤 (번호, 값) 묶음을 한 줄로 쌓고 칸마다 시작 자리를 기억해요.
call은 칸 하나를 쌓고 몸체를 되부름으로 실행한 뒤 칸을 걷어 내요.
정적 찾기는 맨 위 칸과 0번 칸만, 동적 찾기는 맨 위부터 0번까지 차례로 봐요.
각 언어의 실제 규칙과 견주어 볼 점: Python은 함수 안에서 값을 넣는 이름을 그 함수 전체의 지역 변수로 보고, 바깥 것을 고치려면 global·nonlocal을 써요.
이 문제의 set은 반대로 찾은 칸을 고쳐요.
크레이콘은 맨 위(함수 밖)에서 만든 변수에 함수 안에서 넣으면 그 변수가 바뀌고, 함수 안에서 처음 만든 이름은 그 함수의 것이라 밖에서 쓰면 검사기가 막아요.
JS의 var는 함수 범위, let·const는 블록 범위예요.
C·C++·Java·C#은 블록 범위이고, Java·C#은 안쪽 블록에서 바깥 지역 변수와 같은 이름을 다시 선언하지 못하게 막아요.
함정 ① 동적 범위를 지금 칸과 전역만으로 찾기, 정적 범위인데 부른 함수의 칸까지 찾기.
② 동적 범위를 전역부터 찾기(가장 가까운 칸이 먼저예요).
③ 함수가 끝나도 칸을 남겨 다음 호출이 지난 값을 보기(C의 static 지역 변수 같은 동작).
④ set이 못 찾으면 지금 칸에 새로 만들기(Python식 대입).
⑤ var가 이미 보이는 변수를 고치기(var는 늘 지금 칸이에요).

Pythonmain.py · 53 줄
import sys lines = sys.stdin.read().split("\n")n = int(lines[0])funcs = {}   # 함수 이름 → 몸체 명령들main = []    # 맨 바깥 명령들body = Nonefor line in lines[1:1 + n]:    t = line.split()    if t[0] == "def":        body = funcs[t[1]] = []    elif t[0] == "end":        body = None    else:        (main if body is None else body).append(t)  def run(dynamic):    frames = [{}]  # frames[0]은 맨 바깥(전역), 끝이 지금 실행 중인 함수의 칸    printed = []     def find(name):        """이름을 가진 칸(사전)을 찾는다. 없으면 None."""        # 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역        order = reversed(frames) if dynamic else (frames[-1], frames[0])        for frame in order:            if name in frame:                return frame        return None     def execute(cmds):        for cmd in cmds:            op = cmd[0]            if op == "var":                frames[-1][cmd[1]] = int(cmd[2])            elif op in ("set", "add"):                frame = find(cmd[1])                if frame is not None:                    frame[cmd[1]] = int(cmd[2]) if op == "set" else frame[cmd[1]] + int(cmd[2])            elif op == "print":                frame = find(cmd[1])                printed.append("?" if frame is None else str(frame[cmd[1]]))            else:  # call                frames.append({})  # 부를 때마다 빈 칸에서 시작한다                execute(funcs[cmd[1]])                frames.pop()       # 끝나면 그 칸은 사라진다     execute(main)    return printed  for a, b in zip(run(False), run(True)):    print(a, b)
JavaScriptmain.js · 43 줄
const lines = require("fs").readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const funcs = new Map(); // 함수 이름 → 몸체 명령들const main = []; // 맨 바깥 명령들let body = null;for (const line of lines.slice(1, 1 + n)) {  const t = line.trim().split(" ");  if (t[0] === "def") funcs.set(t[1], (body = []));  else if (t[0] === "end") body = null;  else (body ?? main).push(t);} function run(dynamic) {  const frames = [new Map()]; // frames[0]은 전역, 끝이 지금 실행 중인 함수의 칸  const printed = [];  // 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역  const find = (name) => {    const order = dynamic ? [...frames].reverse() : [frames[frames.length - 1], frames[0]];    return order.find((f) => f.has(name));  };  const execute = (cmds) => {    for (const [op, name, arg] of cmds) {      if (op === "var") {        frames[frames.length - 1].set(name, Number(arg));      } else if (op === "set" || op === "add") {        const f = find(name);        if (f) f.set(name, op === "set" ? Number(arg) : f.get(name) + Number(arg));      } else if (op === "print") {        const f = find(name);        printed.push(f ? String(f.get(name)) : "?");      } else {        frames.push(new Map()); // 부를 때마다 빈 칸에서 시작한다        execute(funcs.get(name));        frames.pop(); // 끝나면 그 칸은 사라진다      }    }  };  execute(main);  return printed;} const lex = run(false), dyn = run(true);console.log(lex.map((v, i) => `${v} ${dyn[i]}`).join("\n"));
TypeScriptmain.ts · 48 줄
import { readFileSync } from "node:fs"; type Frame = Map<string, number>;const lines: string[] = readFileSync(0, "utf8").split("\n");const n = Number(lines[0]);const funcs = new Map<string, string[][]>(); // 함수 이름 → 몸체 명령들const main: string[][] = []; // 맨 바깥 명령들let body: string[][] | null = null;for (const line of lines.slice(1, 1 + n)) {  const t = line.trim().split(" ");  if (t[0] === "def") {    body = [];    funcs.set(t[1], body);  } else if (t[0] === "end") body = null;  else (body ?? main).push(t);} function run(dynamic: boolean): string[] {  const frames: Frame[] = [new Map()]; // frames[0]은 전역, 끝이 지금 실행 중인 함수의 칸  const printed: string[] = [];  // 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역  const find = (name: string): Frame | undefined => {    const order = dynamic ? [...frames].reverse() : [frames[frames.length - 1], frames[0]];    return order.find((f) => f.has(name));  };  const execute = (cmds: string[][]): void => {    for (const [op, name, arg] of cmds) {      if (op === "var") {        frames[frames.length - 1].set(name, Number(arg));      } else if (op === "set" || op === "add") {        const f = find(name);        if (f) f.set(name, op === "set" ? Number(arg) : (f.get(name) ?? 0) + Number(arg));      } else if (op === "print") {        const f = find(name);        printed.push(f ? String(f.get(name)) : "?");      } else {        frames.push(new Map()); // 부를 때마다 빈 칸에서 시작한다        execute(funcs.get(name) ?? []);        frames.pop(); // 끝나면 그 칸은 사라진다      }    }  };  execute(main);  return printed;} const lex = run(false), dyn = run(true);console.log(lex.map((v, i) => `${v} ${dyn[i]}`).join("\n"));
JavaMain.java · 78 줄
import java.io.BufferedReader;import java.io.InputStreamReader;import java.io.IOException;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map; public class Main {    static Map<String, List<String[]>> funcs = new HashMap<>(); // 함수 이름 → 몸체 명령들    static List<Map<String, Integer>> frames;                   // 0번이 전역, 끝이 지금 함수의 칸    static boolean dynamic;    static List<String> printed;     // 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역    static Map<String, Integer> find(String name) {        int top = frames.size() - 1;        if (dynamic) {            for (int i = top; i >= 0; i--)                if (frames.get(i).containsKey(name)) return frames.get(i);            return null;        }        if (frames.get(top).containsKey(name)) return frames.get(top);        if (frames.get(0).containsKey(name)) return frames.get(0);        return null;    }     static void execute(List<String[]> cmds) {        for (String[] c : cmds) {            switch (c[0]) {                case "var" -> frames.get(frames.size() - 1).put(c[1], Integer.parseInt(c[2]));                case "set", "add" -> {                    Map<String, Integer> f = find(c[1]);                    if (f != null) f.put(c[1], c[0].equals("set") ? Integer.parseInt(c[2]) : f.get(c[1]) + Integer.parseInt(c[2]));                }                case "print" -> {                    Map<String, Integer> f = find(c[1]);                    printed.add(f == null ? "?" : String.valueOf(f.get(c[1])));                }                default -> {                    frames.add(new HashMap<>()); // 부를 때마다 빈 칸에서 시작한다                    execute(funcs.get(c[1]));                    frames.remove(frames.size() - 1); // 끝나면 그 칸은 사라진다                }            }        }    }     static List<String> run(List<String[]> main, boolean dyn) {        dynamic = dyn;        frames = new ArrayList<>();        frames.add(new HashMap<>());        printed = new ArrayList<>();        execute(main);        return printed;    }     public static void main(String[] args) throws IOException {        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));        int n = Integer.parseInt(in.readLine().trim());        List<String[]> main = new ArrayList<>(), body = null;        for (int i = 0; i < n; i++) {            String[] t = in.readLine().trim().split(" ");            if (t[0].equals("def")) {                body = new ArrayList<>();                funcs.put(t[1], body);            } else if (t[0].equals("end")) {                body = null;            } else {                (body == null ? main : body).add(t);            }        }        List<String> lex = run(main, false), dyn = run(main, true);        StringBuilder out = new StringBuilder();        for (int i = 0; i < lex.size(); i++) out.append(lex.get(i)).append(' ').append(dyn.get(i)).append('\n');        System.out.print(out);    }}
C#Main.cs · 81 줄
using System;using System.Collections.Generic;using System.Text; class Program{    static Dictionary<string, List<string[]>> funcs = new(); // 함수 이름 → 몸체 명령들    static List<Dictionary<string, int>> frames = new();     // 0번이 전역, 끝이 지금 함수의 칸    static bool dynamic;    static List<string> printed = new();     // 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역    static Dictionary<string, int> Find(string name)    {        int top = frames.Count - 1;        if (dynamic)        {            for (int i = top; i >= 0; i--)                if (frames[i].ContainsKey(name)) return frames[i];            return null;        }        if (frames[top].ContainsKey(name)) return frames[top];        if (frames[0].ContainsKey(name)) return frames[0];        return null;    }     static void Execute(List<string[]> cmds)    {        foreach (string[] c in cmds)        {            switch (c[0])            {                case "var":                    frames[^1][c[1]] = int.Parse(c[2]);                    break;                case "set":                case "add":                    var f = Find(c[1]);                    if (f != null) f[c[1]] = c[0] == "set" ? int.Parse(c[2]) : f[c[1]] + int.Parse(c[2]);                    break;                case "print":                    var g = Find(c[1]);                    printed.Add(g == null ? "?" : g[c[1]].ToString());                    break;                default:                    frames.Add(new Dictionary<string, int>()); // 부를 때마다 빈 칸에서 시작한다                    Execute(funcs[c[1]]);                    frames.RemoveAt(frames.Count - 1); // 끝나면 그 칸은 사라진다                    break;            }        }    }     static List<string> Run(List<string[]> main, bool dyn)    {        dynamic = dyn;        frames = new List<Dictionary<string, int>> { new() };        printed = new List<string>();        Execute(main);        return printed;    }     static void Main()    {        int n = int.Parse(Console.ReadLine().Trim());        var main = new List<string[]>();        List<string[]> body = null;        for (int i = 0; i < n; i++)        {            string[] t = Console.ReadLine().Trim().Split(' ');            if (t[0] == "def") funcs[t[1]] = body = new List<string[]>();            else if (t[0] == "end") body = null;            else (body ?? main).Add(t);        }        var lex = Run(main, false);        var dyn = Run(main, true);        var sb = new StringBuilder();        for (int i = 0; i < lex.Count; i++) sb.Append(lex[i]).Append(' ').Append(dyn[i]).Append('\n');        Console.Write(sb);    }}
C++main.cpp · 76 줄
#include <iostream>#include <sstream>#include <string>#include <unordered_map>#include <vector> using Frame = std::unordered_map<std::string, int>;struct Cmd {    std::string op, name;    int arg;}; std::unordered_map<std::string, std::vector<Cmd>> funcs; // 함수 이름 → 몸체 명령들std::vector<Frame> frames;                               // 0번이 전역, 끝이 지금 함수의 칸bool dynamic;std::vector<std::string> printed; // 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역Frame *find(const std::string &name) {    if (dynamic) {        for (auto it = frames.rbegin(); it != frames.rend(); ++it)            if (it->count(name)) return &*it;        return nullptr;    }    if (frames.back().count(name)) return &frames.back();    if (frames.front().count(name)) return &frames.front();    return nullptr;} void execute(const std::vector<Cmd> &cmds) {    for (const Cmd &c : cmds) {        if (c.op == "var") {            frames.back()[c.name] = c.arg;        } else if (c.op == "set" || c.op == "add") {            if (Frame *f = find(c.name)) (*f)[c.name] = c.op == "set" ? c.arg : (*f)[c.name] + c.arg;        } else if (c.op == "print") {            Frame *f = find(c.name);            printed.push_back(f ? std::to_string(f->at(c.name)) : "?");        } else {            // 부를 때마다 빈 칸에서 시작한다. push_back이 vector를 옮길 수 있어 칸을 가리키는 포인터는 오래 들지 않는다            frames.emplace_back();            execute(funcs[c.name]);            frames.pop_back(); // 끝나면 그 칸은 사라진다        }    }} std::vector<std::string> run(const std::vector<Cmd> &main, bool dyn) {    dynamic = dyn;    frames.assign(1, Frame{});    printed.clear();    execute(main);    return printed;} int main() {    int n;    std::string line;    std::getline(std::cin, line);    n = std::stoi(line);    std::vector<Cmd> main;    std::vector<Cmd> *body = nullptr;    for (int i = 0; i < n; i++) {        std::getline(std::cin, line);        std::istringstream ss(line);        Cmd c{"", "", 0};        ss >> c.op >> c.name >> c.arg;        if (c.op == "def") body = &funcs[c.name];        else if (c.op == "end") body = nullptr;        else (body ? *body : main).push_back(c);    }    auto lex = run(main, false), dyn = run(main, true);    std::string out;    for (size_t i = 0; i < lex.size(); i++) out += lex[i] + " " + dyn[i] + "\n";    std::cout << out;}
Cmain.c · 121 줄
#include <stdio.h>#include <string.h> enum { VAR, SET, ADD, PRINT, CALL };typedef struct { int op, id, arg; } Cmd; /* id: 변수 번호, call이면 함수 번호 */ static char vname[1000][11], fname[1000][11];static int nv, nf;static Cmd cmds[1000];static int ncmd;static int fstart[1000], fend[1000]; /* 함수 몸체는 cmds[fstart, fend) */static int mainlist[1000], nmain;    /* 맨 바깥 명령의 번호들 */ /* 칸 하나는 (변수 번호, 값) 묶음들. 모든 칸을 한 줄로 쌓고, 칸마다 시작 자리를 둔다 */static int ent_id[1000], ent_val[1000], nent;static int frame_at[64], depth; /* frame_at[d]: d번 칸의 시작. 0번이 전역 */static int dynamic;static char printed[2][50000][12];static int nprinted; static int intern(char names[][11], int *count, const char *s) {    for (int i = 0; i < *count; i++)        if (strcmp(names[i], s) == 0) return i;    strcpy(names[*count], s);    return (*count)++;} /* d번 칸에서 변수 id의 자리(없으면 -1) */static int in_frame(int d, int id) {    int end = d == depth ? nent : frame_at[d + 1];    for (int e = frame_at[d]; e < end; e++)        if (ent_id[e] == id) return e;    return -1;} /* 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역 */static int find(int id) {    int e;    if (dynamic) {        for (int d = depth; d >= 0; d--)            if ((e = in_frame(d, id)) >= 0) return e;        return -1;    }    if ((e = in_frame(depth, id)) >= 0) return e;    return depth > 0 ? in_frame(0, id) : -1;} static void exec_one(const Cmd *c); static void call(int f) {    depth++;    frame_at[depth] = nent; /* 부를 때마다 빈 칸에서 시작한다 */    for (int i = fstart[f]; i < fend[f]; i++) exec_one(&cmds[i]);    nent = frame_at[depth]; /* 끝나면 그 칸은 사라진다 */    depth--;} static void exec_one(const Cmd *c) {    int e;    switch (c->op) {    case VAR:        if ((e = in_frame(depth, c->id)) < 0) {            e = nent++;            ent_id[e] = c->id;        }        ent_val[e] = c->arg;        break;    case SET:    case ADD:        if ((e = find(c->id)) >= 0) ent_val[e] = c->op == SET ? c->arg : ent_val[e] + c->arg;        break;    case PRINT:        e = find(c->id);        if (e < 0) strcpy(printed[dynamic][nprinted++], "?");        else snprintf(printed[dynamic][nprinted++], 12, "%d", ent_val[e]);        break;    case CALL:        call(c->id);        break;    }} int main(void) {    int n, cur = -1;    scanf("%d", &n);    for (int i = 0; i < n; i++) {        char op[8], name[11];        scanf("%7s", op);        if (strcmp(op, "end") == 0) {            fend[cur] = ncmd;            cur = -1;            continue;        }        scanf("%10s", name);        if (strcmp(op, "def") == 0) {            cur = intern(fname, &nf, name);            fstart[cur] = ncmd;            continue;        }        Cmd c = {0, 0, 0};        if (strcmp(op, "call") == 0) {            c.op = CALL;            c.id = intern(fname, &nf, name); /* 뒤에서 정의되는 함수도 번호를 먼저 받는다 */        } else {            c.op = strcmp(op, "var") == 0 ? VAR : strcmp(op, "set") == 0 ? SET : strcmp(op, "add") == 0 ? ADD : PRINT;            c.id = intern(vname, &nv, name);            if (c.op != PRINT) scanf("%d", &c.arg);        }        if (cur < 0) mainlist[nmain++] = ncmd;        cmds[ncmd++] = c;    }    int count = 0;    for (dynamic = 0; dynamic <= 1; dynamic++) {        nent = depth = nprinted = 0;        frame_at[0] = 0;        for (int i = 0; i < nmain; i++) exec_one(&cmds[mainlist[i]]);        count = nprinted;    }    for (int i = 0; i < count; i++) printf("%s %s\n", printed[0][i], printed[1][i]);    return 0;}
Craykonmain.cray · 116 줄
n = 콘솔.줄읽기().수로변환();funcs = 사전(); // 함수 이름 → 몸체 명령들main = []; // 맨 바깥 명령들body = 빈값;반복 (i = 0; i < n; i++){    t = 콘솔.줄읽기().공백제거().나누기(" ");    만약 (t[0] == "def")    {        body = [];        funcs[t[1]] = body;    }    아니면 만약 (t[0] == "end")    {        body = 빈값;    }    아니면 만약 (body == 빈값)    {        main.넣기(t);    }    아니면    {        body.넣기(t);    }} frames = []; // 0번이 전역, 끝이 지금 실행 중인 함수의 칸dynamic = 거짓;printed = []; // 이름을 가진 칸의 번호(없으면 -1)// 정적: 지금 칸 → 전역. 동적: 지금 칸 → 부른 함수의 칸 → … → 전역찾기(name){    top = frames.개수 - 1;    만약 (dynamic)    {        반복 (d = top; d >= 0; d--)        {            만약 (frames[d].있나(name))            {                돌려주기 d;            }        }        돌려주기 -1;    }    만약 (frames[top].있나(name))    {        돌려주기 top;    }    만약 (frames[0].있나(name))    {        돌려주기 0;    }    돌려주기 -1;} 실행(cmds){    각각 (c 에서 cmds)    {        선택 (c[0])        {            경우 "var":                frames[frames.개수 - 1][c[1]] = c[2].수로변환();                그만;            경우 "set":            경우 "add":                d = 찾기(c[1]);                만약 (d >= 0)                {                    만약 (c[0] == "set")                    {                        frames[d][c[1]] = c[2].수로변환();                    }                    아니면                    {                        frames[d][c[1]] = frames[d][c[1]] + c[2].수로변환();                    }                }                그만;            경우 "print":                d = 찾기(c[1]);                만약 (d >= 0)                {                    printed.넣기("" + frames[d][c[1]]);                }                아니면                {                    printed.넣기("?");                }                그만;            그밖에:                frames.넣기(사전()); // 부를 때마다 빈 칸에서 시작한다                실행(funcs[c[1]]);                frames.자리빼기(frames.개수 - 1); // 끝나면 그 칸은 사라진다                그만;        }    }} 돌리기(동적인가){    dynamic = 동적인가;    frames = [사전()];    printed = [];    실행(main);    돌려주기 printed;} lex = 돌리기(거짓);dyn = 돌리기(참);반복 (i = 0; i < lex.개수; i++){    콘솔.쓰기(lex[i] + " " + dyn[i]);}