작은 언어로 쓴 프로그램을 두 가지 변수 범위 규칙으로 각각 실행하고, 결과를 나란히 출력한다.
프로그램은 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
오류 목록00F8 ↓ · ⇧F8 ↑
입력(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 syslines = 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 printedfor 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]);}