상세 컨텐츠

본문 제목

5일만에 뚝딱 스크립트 언어 만들기 PGLight (4/5)

프로그래밍/PG어

by ∫2tdt=t²+c 2013. 6. 24. 02:45

본문




짠, 저번에 파싱을 통해서 추상언어트리를 만드는걸 했구요, 이제는 가상머신을 구현해볼 차례입니다. 말이 거창하게 가상머신인데, 알고보면 간단한 놈이에요. 명령어를 받아들여서, 해석하고, 그에 따라 적당한 행동을 하면 됩니다. (CPU의 작동원리랑 거의 비슷해요!)

다만 실제로 구현할때 까다로운 부분은 메모리를 관리하는 겁니다. 가비지 컬렉션을 구현해야하니까요. 근데 그런거 없고 그냥 닥치고 shared_ptr로도 어느정도 메모리 관리를 할 수 있어요.

PGLight가 채택한 명령어 체계는 스택기반의 0주소 명령어에요. 스택기반의 명령어 체계는 트리를 후위순회(post order)하면 쉽게 얻어질 수 있고 피연산자의 주소를 계산하는 일이 없어서 코드 생성작업이 간단하기 때문이죠.

일단 스택에 보관될 자료타입에 대해서 정의하는 일이 필요합니다. 동적타이핑 언어답게 자료타입은 자유롭게 변경이 가능합니다. 그렇기에 변수 하나는 반드시 스택 1칸을 차지하므로 명령어를 단순하고 일관적으로 만들수 있습니다.


먼저 PGLight가 지원하는 자료타입이에요.


단순 타입

void : (값이 음슴ㅋ)

정수

실수 : (32비트 부동소수점 float. 64비트는 걍 지원안했음. 쓸일이 없어서...)

문자열 : (UTF-8 포맷이 원칙입니다)

부울

시간

쓰레드


복합 타입

배열

사전 : (키는 단순 타입만 사용할수 있도록 제한했습니다)


호출가능한 타입

함수 : (PGLight 언어의 함수)

C언어 함수 : (외부 C언어 함수)

클로져 : (변수가 캡쳐된 함수)


언어 내부적으로 사용되는 타입

레퍼런스 : (클로져에서 캡쳐된 변수들의 데이터를 공유하기 위해 사용됩니다)

배열 반복자 : (for문에서 배열을 순회하기 위해 사용됩니다)

사전 반복자 : (for문에서 사전을 순회하기 위해 사용됩니다)


정리해보니깐 타입이 은근 많네요. 우리는 이런 타입들을 모두 표현할 추상 클래스를 만들어야합니다ㅋ


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
class PGLCompoundData
{
public:
    enum Type
    {
        None,
        Integer,
        Real,
        String,
        Boolean,
        Array,
        Dictionary,
        Function,
        CFunction,
        Closure,
        Ref,
        CVectorIter,
        CMapIter,
        Thread,
        Time,
    };
    enum Cmp
    {
        EQ, // ==
        NEQ, // !=
        GT, // >
        GTE, // >=
        LS, // <
        LSE, // <=
    };
    virtual Type GetType() const = 0;
//현재 객체의 타입을 반환합니다.
    virtual ~PGLCompoundData() {}
 
    virtual bool Compare(const PGLCompoundData* o) const = 0;
// 현재 객체와 o를 비교(< 연산)합니다. 정렬하는데 사용됨
    virtual string DebugInfo() const = 0;
// 디버깅에 필요한 정보를 문자열로 반환합니다.
 
    virtual shared_ptr<PGLCompoundData> OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateSub(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateMul(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateMod(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperatePow(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateAnd(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateOr(
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateDot(
        const string& right) const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateSign() const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateNot() const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const {return nullptr;}
// 여기까진 연산작업입니다. 연산이 불가능할 경우에는 nullptr를 호출해요.
 
    virtual void Next() {}
    virtual bool IsNotEnd() const {return false;}
    virtual shared_ptr<PGLCompoundData> GetKey() const {return nullptr;}
    virtual shared_ptr<PGLCompoundData> GetValue() const {return nullptr;}
// 반복자를 위한 함수들이에요
    virtual shared_ptr<PGLCompoundData> Copy() const {return nullptr;}
// 깊은 복사를 수행하는 함수입니다
};

자, 이를 바탕으로 이제 각각의 데이터 타입을 선언해 봅시다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// 단순 타입을 표현하는 클래스. 별건 없어요..
class PGLFirstData : public PGLCompoundData
{
public:
    virtual Type GetType() const = 0;
    virtual ~PGLFirstData() {}
};
 
// void타입을 표현합니다
class PGLVoidData : public PGLFirstData
{
public:
    Type GetType() const override {return None;}
    virtual bool Compare(const PGLCompoundData* o) const;
    string DebugInfo() const {return "null";}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLVoidData>();}
};
 
// 정수 타입
class PGLIntData : public PGLFirstData
{
public:
    int data;
    PGLIntData(int _d = 0) : data(_d) {}
    Type GetType() const override {return Integer;}
    virtual bool Compare(const PGLCompoundData* o) const;
    virtual shared_ptr<PGLCompoundData> OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateSub(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateMul(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateMod(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperatePow(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateSign() const;
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const;
// 각각의 연산들은 이따가 구현하는걸로
    string DebugInfo() const {char buf[32]; sprintf_s(buf, 32, "%d", data); return buf;}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLIntData>(data);}
};
 
// 실수 타입
class PGLRealData : public PGLFirstData
{
public:
    float data;
    PGLRealData(float _d = 0) : data(_d) {}
    Type GetType() const override {return Real;}
    virtual bool Compare(const PGLCompoundData* o) const;
    virtual shared_ptr<PGLCompoundData> OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateSub(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateMul(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateMod(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperatePow(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateSign() const;
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const;
// 각각 연산들은 이따 구현하는걸로
    string DebugInfo() const {char buf[32]; sprintf_s(buf, 32, "%f", data); return buf;}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLRealData>(data);}
};
 
// 문자열 타입
class PGLStringData : public PGLFirstData
{
public:
    string data;
    PGLStringData(string _d = string()) : data(_d) {}
    Type GetType() const override {return String;}
    virtual bool Compare(const PGLCompoundData* o) const;
    virtual shared_ptr<PGLCompoundData> OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const;
// 역시나 연산은 이따 구현하는걸로
    string DebugInfo() const {return "\""   data   "\"";}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLStringData>(data);}
};
 
// 부울 타입
class PGLBooleanData : public PGLFirstData
{
public:
    bool data;
    PGLBooleanData(bool _d = false) : data(_d) {}
    Type GetType() const override {return Boolean;}
    virtual bool Compare(const PGLCompoundData* o) const;
    virtual shared_ptr<PGLCompoundData> OperateAnd(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateOr(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateNot() const;
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const;
    string DebugInfo() const {return data ? "true" : "false";}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLBooleanData>(data);}
};
 
// 함수 타입
class PGLFunctionData : public PGLFirstData
{
protected:
public:
    int data; // 함수의 주소에요
    bool memberFunc;
    PGLFunctionData(int _d = false) : data(_d), memberFunc(false) {}
    Type GetType() const override {return Function;}
    virtual bool Compare(const PGLCompoundData* o) const;
    string DebugInfo() const {char buf[32]; sprintf_s(buf, 32, "%x", data); return buf;}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLFunctionData>(data);}
};
 
 
// C함수 타입
class PGLCFunctionData : public PGLFirstData
{
protected:
public:
    void* data;
    PGLCFunctionData(void* _d = false) : data(_d) {}
    Type GetType() const override {return CFunction;}
    virtual bool Compare(const PGLCompoundData* o) const;
    string DebugInfo() const {char buf[32]; sprintf_s(buf, 32, "%x", data); return buf;}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLCFunctionData>(data);}
};
 
// 시간 타입
class PGLTimeData : public PGLFirstData
{
public:
    time_t data;
    PGLTimeData(time_t _d = 0) : data(_d) {}
    Type GetType() const override {return Time;}
    virtual bool Compare(const PGLCompoundData* o) const;
    virtual shared_ptr<PGLCompoundData> OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateSub(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateMul(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const;
    virtual shared_ptr<PGLCompoundData> OperateDot(const string& right) const;
    string DebugInfo() const {char buf[64]; ctime_s(buf, 64, &data); return buf;}
    virtual shared_ptr<PGLCompoundData> Copy() const {return make_shared<PGLTimeData>(data);}
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
// 반복되는 비교 코드를 아예 템플릿화했어요ㅋ
template<typename Ty1, typename Ty2> bool compare(Ty1 a, Ty2 b, PGLCompoundData::Cmp cmp)
{
    switch(cmp)
    {
    case PGLCompoundData::EQ:
        return a == b;
    case PGLCompoundData::NEQ:
        return a != b;
    case PGLCompoundData::GT:
        return a > b;
    case PGLCompoundData::GTE:
        return a >= b;
    case PGLCompoundData::LS:
        return a < b;
    case PGLCompoundData::LSE:
        return a <= b;
    }
    return false;
}
 
// 정수의 더하기 연산
shared_ptr<PGLCompoundData> PGLIntData::OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
//우항이 정수 타입일 경우
    case Integer:
        return make_shared<PGLIntData>
            (data   ((PGLIntData*)right.get())->data);
//우항이 실수 타입일 경우
    case Real:
        return make_shared<PGLRealData>
            (data   ((PGLRealData*)right.get())->data);
//우항이 문자열 타입일 경우 문자열로 변환해서 합칩니다
    case String:
        {
            char buf[16];
            _itoa_s(data, buf, 16, 10);
            return make_shared<PGLStringData>
                (buf   ((PGLStringData*)right.get())->data);
        }
//나머지는 연산 실패
    default:
        return nullptr;
    }
}
 
// 정수의 빼기 연산
shared_ptr<PGLCompoundData> PGLIntData::OperateSub(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLIntData>
            (data - ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>
            (data - ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 정수의 곱하기 연산
shared_ptr<PGLCompoundData> PGLIntData::OperateMul(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLIntData>
            (data * ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>
            (data * ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 정수의 나누기 연산
shared_ptr<PGLCompoundData> PGLIntData::OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLIntData>(data / ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>(data / ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 정수의 나머지 연산
shared_ptr<PGLCompoundData> PGLIntData::OperateMod(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLIntData>(data % ((PGLIntData*)right.get())->data);
//우항이 실수 타입이면 fmod를 사용합니다
    case Real:
        return make_shared<PGLRealData>(fmodf(data, ((PGLRealData*)right.get())->data));
    default:
        return nullptr;
    }
}
 
// 정수의 거듭제곱 연산
shared_ptr<PGLCompoundData> PGLIntData::OperatePow(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLIntData>((int)pow(data, ((PGLIntData*)right.get())->data));
    case Real:
        return make_shared<PGLRealData>(powf(data, ((PGLRealData*)right.get())->data));
    default:
        return nullptr;
    }
}
 
// 정수의 -부호 연산. 간단하죠
shared_ptr<PGLCompoundData> PGLIntData::OperateSign() const
{
    return make_shared<PGLIntData>(-data);
}
 
// 정수의 비교연산
shared_ptr<PGLCompoundData> PGLIntData::OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLBooleanData>(compare(data, ((PGLIntData*)right.get())->data, cmp));
    case Real:
        return make_shared<PGLBooleanData>(compare(data, ((PGLIntData*)right.get())->data, cmp));
    default:
        return nullptr;
    }
}
 
// 실수의 덧셈연산
shared_ptr<PGLCompoundData> PGLRealData::OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(data   ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>(data   ((PGLRealData*)right.get())->data);
    case String:
        {
            char buf[16];
            sprintf_s(buf, 16, "%.3f", data);
            return make_shared<PGLStringData>(buf   ((PGLStringData*)right.get())->data);
        }
    default:
        return nullptr;
    }
}
 
// 실수의 뺄셈 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateSub(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(data - ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>(data - ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 실수의 곱셈 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateMul(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(data * ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>(data * ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 실수의 나눗셈 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(data / ((PGLIntData*)right.get())->data);
    case Real:
        return make_shared<PGLRealData>(data / ((PGLRealData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 실수의 나머지 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateMod(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(fmodf(data, ((PGLRealData*)right.get())->data));
    case Real:
        return make_shared<PGLRealData>(fmodf(data, ((PGLRealData*)right.get())->data));
    default:
        return nullptr;
    }
}
 
// 실수의 거듭제곱 연산
shared_ptr<PGLCompoundData> PGLRealData::OperatePow(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLRealData>(pow(data, ((PGLIntData*)right.get())->data));
    case Real:
        return make_shared<PGLRealData>(powf(data, ((PGLRealData*)right.get())->data));
    default:
        return nullptr;
    }
}
 
// 실수의 -부호 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateSign() const
{
    return make_shared<PGLRealData>(-data);
}
 
// 실수의 비교 연산
shared_ptr<PGLCompoundData> PGLRealData::OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLBooleanData>(compare(data, ((PGLIntData*)right.get())->data, cmp));
    case Real:
        return make_shared<PGLBooleanData>(compare(data, ((PGLIntData*)right.get())->data, cmp));
    default:
        return nullptr;
    }
}
 
// 문자열 더하기 연산
shared_ptr<PGLCompoundData> PGLStringData::OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case String:
        return make_shared<PGLStringData>(data   ((PGLStringData*)right.get())->data);
    case Integer:
        {
            char buf[16];
            _itoa_s(((PGLIntData*)right.get())->data, buf, 16, 10);
            return make_shared<PGLStringData>(data   buf);
        }
    case Real:
        {
            char buf[16];
            sprintf_s(buf, 16, "%.3f", ((PGLRealData*)right.get())->data);
            return make_shared<PGLStringData>(data   buf);
        }
    default:
        return nullptr;
    }
}
 
// 문자열 비교 연산
shared_ptr<PGLCompoundData> PGLStringData::OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case String:
        return make_shared<PGLBooleanData>(compare(data, ((PGLStringData*)right.get())->data, cmp));
    default:
        return nullptr;
    }
}
 
// 부울의 and 연산
shared_ptr<PGLCompoundData> PGLBooleanData::OperateAnd(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Boolean:
        return make_shared<PGLBooleanData>(data && ((PGLBooleanData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 부울의 or 연산
shared_ptr<PGLCompoundData> PGLBooleanData::OperateOr(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Boolean:
        return make_shared<PGLBooleanData>(data || ((PGLBooleanData*)right.get())->data);
    default:
        return nullptr;
    }
}
 
// 부울의 not 연산
shared_ptr<PGLCompoundData> PGLBooleanData::OperateNot() const
{
    return make_shared<PGLBooleanData>(!data);
}
 
// 부울의 비교 연산
shared_ptr<PGLCompoundData> PGLBooleanData::OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Boolean:
        return make_shared<PGLBooleanData>(compare(data, ((PGLBooleanData*)right.get())->data, cmp));
    default:
        return nullptr;
    }
}
 
// 시간의 덧셈 연산
shared_ptr<PGLCompoundData> PGLTimeData::OperateAdd(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
// 시간은 시간끼리만 더하고 뺄수 있어요
    case Time:
        return make_shared<PGLTimeData>
            (data   static_pointer_cast<PGLTimeData>(right)->data);
    default:
        return nullptr;
    }
}
 
// 시간의 뺄셈연산
shared_ptr<PGLCompoundData> PGLTimeData::OperateSub(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Time:
        return make_shared<PGLTimeData>
            (data - static_pointer_cast<PGLTimeData>(right)->data);
    default:
        return nullptr;
    }
}
 
// 시간의 곱셈연산
shared_ptr<PGLCompoundData> PGLTimeData::OperateMul(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
// 시간은 정수/실수하고만 곱하고 나눌수 있어요
    case Integer:
        return make_shared<PGLTimeData>
            (data * static_pointer_cast<PGLIntData>(right)->data);
    case Real:
        return make_shared<PGLTimeData>
            ((time_t)(data * static_pointer_cast<PGLRealData>(right)->data));
    default:
        return nullptr;
    }
}
 
shared_ptr<PGLCompoundData> PGLTimeData::OperateDiv(
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Integer:
        return make_shared<PGLTimeData>
            (data / static_pointer_cast<PGLIntData>(right)->data);
    case Real:
        return make_shared<PGLTimeData>
            ((time_t)(data / static_pointer_cast<PGLRealData>(right)->data));
    default:
        return nullptr;
    }
}
 
bool PGLTimeData::Compare(const PGLCompoundData* o) const
{
    if(GetType() < o->GetType()) return true;
    if(GetType() > o->GetType()) return false;
    return data < ((const PGLTimeData*)o)->data;
}
 
shared_ptr<PGLCompoundData> PGLTimeData::OperateCmp(Cmp cmp,
        const shared_ptr<PGLCompoundData>& right) const
{
    switch(right->GetType())
    {
    case Time:
        return ConvertToPGLType(compare(data, static_pointer_cast<PGLTimeData>(right)->data, cmp));
    default:
        return nullptr;
    }
}
 
// dot연산은 내적이 아니라 type.abs ~~에서마냥 마침표를 찍어서 참조하는 연산을 가리킵니다.
// 이름을 잘못지은거같네요
shared_ptr<PGLCompoundData> PGLTimeData::OperateDot(const string& right) const
{
// 우항을 따라 알맞은 메소드를 반환해줍니다.
// PGLTimeLibrary는 말그대로 시간 관련 연산을 모아둔 라이브러리입니다.
// ConvertToPGLType 템플릿을 이용해 C언어함수를 PGLCFunctionType으로 만들어줍니다
    if(right == "@second")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::second);
    }
    if(right == "@minute")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::minute);
    }
    if(right == "@hour")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::hour);
    }
    if(right == "@day")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::day);
    }
    if(right == "@date")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::date);
    }
    if(right == "@gmdate")
    {
        return ConvertToPGLType<void*>(PGLTimeLibrary::gmdate);
    }
    return nullptr;
}


이런식으로 연산을 구현해나가면 됩니다.
코드에 shared_ptr이 남발되고 있습니다... 매번 포인터 참조를 하느라 가상머신 성능이 썩 좋지는 않겠지만 그래도 가비지 컬렉팅은 모두 스마트 포인터에게 양도하는걸로...ㅋ

자 그러면 이제 가상머신을 위한 명령어를 짜봅시다. 명령어는 바이트 단위가 아니라 short 단위(2바이트)로 구성됩니다. 별 이유는 없고, 그냥 2바이트로 넉넉하게 잡아놨는데... 별 쓸모는 없네요. (다시 줄여도 괜찮을거같아요ㅋ)
명령어는 오퍼랜드를 하나 가질수 있도록 약속을 세웠습니다. 그러니깐 명령어들은 모두 2바이트에서 4바이트 사이로 결정되겠네요.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
enum class PGLOpcode : short
{
    NOP, // 아무 것도 하지 않음
    PUSH, // 리터럴/전역변수[오퍼랜드1]을 스택에 넣는다
    STORE, // 스택에서 자료를 빼서 전역변수[오퍼랜드1]로 설정한다
    COPY, // 베이스스택   오퍼랜드1 위치에 있는 자료를 스택에 넣는다
    WRITE, // 스택에서 자료 하나를 빼서 베이스스택   오퍼랜드1 위치에 덮어쓴다
    POP, // 스택에서 오퍼랜드1개의 자료를 빼낸다
    CALL, // 스택에서 주소를 꺼내고, 오퍼랜드1개의 인자를 사용하여 함수 호출
    THISCALL, // 스택에서 주소를 꺼내고 this와 오퍼랜드1개의 인자를 사용하여 함수 호출
    RETURN, // 반환값을 오퍼랜드1개로 설정하고, 이전 주소로 복귀
    YIELD, // 반환값을 오퍼랜드1개로 설정하고, 현 스레드 실행을 중지하고, 부모 스레드에게 권한을 넘긴다
    ADD, // 스택에서 2개를 뽑아 더한 결과를 스택에 넣는다
    SUB, // 스택에서 2개를 뽑아 뺀 결과를 스택에 넣는다
    MUL, // 스택에서 2개를 뽑아 곱한 결과를 스택에 넣는다
    DIV, // 스택에서 2개를 뽑아 나눈 결과를 스택에 넣는다
    MOD, // 스택에서 2개를 뽑아 나머지 구한 결과를 스택에 넣는다
    POW, // 스택에서 2개를 뽑아 n승한 결과를 스택에 넣는다
    SIGN, // 스택에서 1개를 뽑아 부호를 반전하여 스택에 넣는다
    EQ, // 스택에서 2개를 뽑아 == 연산 결과를 스택에 넣는다
    NEQ, // 스택에서 2개를 뽑아 != 연산 결과를 스택에 넣는다
    GT, // >
    GTE, // >=
    LS, // <
    LSE, // <=
    AND, // 스택에서 2개를 뽑아 and 연산한 결과를 스택에 넣는다
    OR, // or
    NOT, // not
    JMP, // 현재 주소에서 오퍼랜드1변위로 점프한다
    UNLESSJMP, // 스택에서 1개를 뽑아, 그 값이 거짓이면, 현재 주소에서 오퍼랜드1변위로 점프한다
    PUSHNULL, // 스택에 null을 넣는다
    ASSEMBLE, // 스택에서 오퍼랜드1개를 뽑아 배열로 만들어 스택에 넣는다
    NEWDICT, // 스택에서 2* 오퍼랜드1개를 뽑아, 차례로 키, 값으로 하는 사전을 만들어 스택에 넣는다
    AT, // 스택에서 배열 혹은 사전과 키를 뽑아, 키에 해당하는 값을 스택에 넣는다
    LEN, // 스택에서 배열 혹은 사전을 뽑고 그 크기를 구하여 스택에 넣는다
    ATD, // 스택에서 배열을 뽑고, 오퍼랜드1번째 원소를 스택에 넣는다
    MAKECLOSURE, // 스택에서 함수 주소와 배열을 꺼내 클로져로 묶고, 결과를 스택에 넣는다
    SET, // 스택에서 자료와 배열 혹은 사전과 키를 뽑아, 키에 해당하는 값을 자료로 설정한다
    SETD, // 스택에서 자료와 배열을 뽑아, 그 배열의 오퍼랜드1번째 원소로 설정한다
    REF, // 스택에서 자료를 뽑아, 레퍼런스하여 스택에 넣는다
    DEREF, // 스택에서 자료를 뽑아, 디레퍼런스하여 스택에 넣는다
    COPYDEREF, // COPY   DEREF
    SETDDEREF, // 스택에서 자료와 배열을 뽑아, 그 배열의 오퍼랜드1번째 원소가 가리키는 값을 그것으로 설정한다
    WRITEDEREF, // 스택에서 자료 하나를 빼서 베이스스택   오퍼랜드1위치가 가리키는 값을 그것으로 설정한다
    PUSHBEGIN, // 스택 꼭대기에 위치한 배열 혹은 사전에서 순회 첫 지점의 정보를 담는 자료를 스택에 넣는다
    ISNOTEND, // 스택 꼭대기에 위치한 순회 지점이 끝에 다다랐으면 거짓, 아니면 참을 스택에 넣는다
    NEXT, // 스택 꼭대기에 위치한 순회 지점을 다음으로 설정한다
    PUSHKEYVAL, // 스택 꼭대기에 위치한 순회 지점에서 키와 값을 뽑아 스택에 넣는다
    FIND, // 스택에서 배열 혹은 사전과 키를 뽑에 키에 해당하는 값을 스택에 넣는다. 값이 없을 경우 런타임 에러
    FINDP, // 스택에서 배열 혹은 사전과 키를 뽑에 키에 해당하는 값을 스택에 넣고 배열 혹은 사전을 다시 넣는다. 값이 없을 경우 런타임 에러.
};

으갸갸. 명령어가 많죠? (생각보다 많은 편은 아닙니다.) 요 명령어들만 있으면 모든 연산이 가능하다는게 놀라울 정도네요.

간단히 훑어보자면
스택에 자료를 넣거나 스택에 있는 자료를 외부로 저장하는 명령어들이 있어요
PUSH, POP, STORE, COPY, WRITE, PUSHNULL

PUSH 같은 경우는 스택에 자료를 넣는놈인데, 뒤에 오는 피연산자는 넣을 자료의 주소를 설정합니다. PGLight어 타입이 다양하고 길어서 코드 안에 직접 자료를 넣을순 없구요, 그 대신에 전역변수와 리터럴들이 모여있는 글로벌 데이터 존을 만들었어요. 거기에서 값을 찾아와서 스택에 넣어주는 역할을 합니다.

POP은 그냥 스택에서 자료를 빼는 녀석이구요

STORE 같은 경우는 글로벌 데이터 존에 자료를 입력하는 역할을 합니다. 값을 읽어오는 PUSH의 반대지요.

COPY는 스택에 있는 자료를 복사해서 마지막에 추가하는 역할을 합니다. 지역변수는 스택에 차곡차곡 저장되거든요. 지역변수 값을 불러올때 사용합니다. 그래서 이놈의 피연산자는 베이스 스택으로부터의 위치를 지정합니다.

WRITE는 스택에 있는 값을 덮어쓰는데 사용됩니다. 지역변수의 값을 설정할때 사용하는거죠. 그래서 이놈 역시 피연산자가 베이스 스택으로부터의 위치를 지정합니다.

PUSHNULL은 널 값을 넣어주는 명령어입니다.


호출과 관련된 명령어들이 있어요

CALL, THISCALL, RETURN, YIELD

CALL은 함수 호출입니다. 피연산자로 함수의 인수 갯수가 들어갑니다. 인수에 앞서 먼저 호출할 함수가 스택에 들어있어야하겠죠. 이 함수가 일반 함수인지, C함수인지, 클로져인지 구분하여 적절하게 다른 일을 하는게 포인트입니다. 당연히 베이스 스택과 호출 스택을 쌓는 역할도 하죠

THISCALL은 클래스 메소드를 위한 함수 호출입니다. 이걸로 함수를 호출할 경우에는 첫번째 인자로 this가 넘어가게 됩니다.

RETURN 은 반환이죠. 함수 수행을 중지하고 호출했던 곳으로 돌아갑니다. 당연히 베이스 스택과 호출 스택을 정리하는 역할도 합니다. 만약 돌아갈 곳이 없는 상태에서 RETURN이 호출되면 실행을 정지합니다.

YIELD는 return과 비슷하지만, 쓰레드의 수행을 일시 정지하고, 자신을 생성시킨 부모 쓰레드에게로 돌아가는 일을 합니다.


연산과 관련된 명령어들이 있어요

산술 ADD, SUB, MUL, DIV, MOD, POW, SIGN

비교 EQ, NEQ, GT, GTE, LS, LSE

논리 AND, OR, NOT


흐름제어와 관련된 명령어들이 있어요

JMP, UNLESSJMP

JMP는 무조건 분기입니다. 분기되는 위치는 상대주소(현재 실행되는 주소를 중심으로하는 변위)로 피연산자에 지정됩니다.

UNLESSJUMP는 조건문과 반복문을 위한 조건분기입니다. 스택에서 가져온 값이 거짓일때 분기를 해요. (왜 거짓일때 분기하도록 했느냐하면, if문과 while문 작동방식이 그렇거든요.) 역시나 피연산자로 상대주소를 지정합니다.


배열, 사전과 관련된 명령어

ASSEMBLE, NEWDICT, AT, ATD, LEN, SET, SETD

ASSEMBLE은 새 배열을 만들어요

NEWDICT는 새 사전을 만들구요

AT은 배열, 사전을 참조합니다.

ATD는 배열을 참조하는데, 참조하는 위치를 스택에서 가져오는것이 아니라 피연산자로 지정합니다. 클로저 구현에 중요하게 사용됩니다.

LEN은 배열, 사전의 크기를 얻어와요

SET은 배열, 사전의 값을 설정해요

SETD는 배열의 값을 설정하는데, 참조하는 위치를 스택에서 가져오는게 아니라 피연산자로 지정합니다.


클로저와 관련된 명령어

MAKECLOSURE, REF, DEREF, COPYDEREF, SETDDEREF, WRITEDEREF

MAKECLOSURE는 함수 주소와 캡쳐 변수 배열을 이용해 클로저 타입을 만듭니다. 이때 캡쳐되는 변수들은 레퍼런스화 되어있어야해요

REF는 스택에 있는 자료를 레퍼런스화하는데 사용합니다. 그 결과 그 값을 여러곳에서 공유하는게 가능해집니다 (c언어의 포인터 & 연산)

DEREF는 스택에 있는 레퍼런스화된 자료를 참조해서 그 값을 가져오는데 사용합니다. (c언어의 포인터 * 연산)

COPYDEREF 는 COPY DEREF를 합친거에요

SETDDEREF 는 SETD DEREF

WRITEDEREF는 WRITE DEREF


순회와 관련된 명령어

PUSHBEGIN, ISNOTEND, NEXT, PUSHKEYVAL

PUSHBEGIN은 배열, 사전의 순회를 시작하기 위해 첫 반복자를 얻는데 사용됩니다

ISNOTEND는 스택에 있는 반복자가 끝에 다다르지 않았으면 참을 스택에 넣습니다

NEXT는 스택에 있는 반복자를 다음으로 넘기구요

PUSHKEYVAL은 스택에 있는 반복자에서 키와 값을 얻어옵니다



명령어를 짰으니, 명령어를 실행하는 머신을 만들어야겠죠?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
//모든 스레드가 공유하는 자원들을 관리하고
//스레드를 생성하는 역할을 합니다
class PGLVM
{
    friend class PGLVMThread;
protected:
    vector<short> m_codes;
// 코드
    vector<PGLVMDebugInfo> m_debugInfo;
// 코드에 대한 디버그 정보
    vector<shared_ptr<PGLCompoundData>> m_literal;
// 리터럴/전역 변수 공간입니다
    vector<string> m_globDebugInfo;
// 리터럴/전역 변수 공간에 대한 디버그 정보
public:
    PGLVM(const FinalData& fd);
    ~PGLVM();
    shared_ptr<PGLVMThread> NewThread();
    string _GetDisassembly(const short* codes, size_t size);
    string GetDisassembly(const char* funcName = nullptr);
};
 
//실제로 코드를 실행하는 역할을 담당합니다.
class PGLVMThread
{
protected:
    int m_pc;
// 프로그램 카운터. 현재 실행되고 있는 코드의 주소입니다
    vector<shared_ptr<PGLCompoundData>> m_stack;
// 스택입니다
    vector<int> m_stackBase;
// 베이스주소 스택입니다
    vector<int> m_callstack;
// 호출주소 스택입니다
    PGLVM* m_mainVM;
    string m_err;
// 에러를 저장하는 놈
    size_t m_retCnt;
// 반환인수 개수
    int m_state;
// 현재 상태. 실행중인지 정지인지
public:
    int ProcNOP();
    int ProcPUSH();
    int ProcSTORE();
    int ProcCOPY();
    int ProcWRITE();
    int ProcPOP();
    int ProcCALL();
    int ProcTHISCALL();
    int ProcRETURN();
    int ProcYIELD();
    int ProcADD();
    int ProcSUB();
    int ProcMUL();
    int ProcDIV();
    int ProcMOD();
    int ProcPOW();
    int ProcSIGN();
    int ProcEQ();
    int ProcNEQ();
    int ProcGT();
    int ProcGTE();
    int ProcLS();
    int ProcLSE();
    int ProcAND();
    int ProcOR();
    int ProcNOT();
    int ProcJMP();
    int ProcUNLESSJMP();
    int ProcPUSHNULL();
    int ProcASSEMBLE();
    int ProcNEWDICT();
    int ProcAT();
    int ProcLEN();
    int ProcATD();
    int ProcMAKECLOSURE();
    int ProcSET();
    int ProcSETD();
    int ProcREF();
    int ProcDEREF();
    int ProcCOPYDEREF();
    int ProcSETDDEREF();
    int ProcWRITEDEREF();
    int ProcPUSHBEGIN();
    int ProcISNOTEND();
    int ProcNEXT();
    int ProcPUSHKEYVAL();
    int ProcFIND();
    int ProcFINDP();
 
    PGLVMThread(PGLVM* vm);
    ~PGLVMThread() {}
    PGLVM* GetVM() const {return m_mainVM;}
    int Entry(int paramCnt);
// 스택에서 paramCnt만큼의 인수를 가져오고, 함수객체를 가져와 함수를 호출합니다.
// 처음에 특정함수를 호출하며 쓰레드를 시작하기 위해 사용합니다.
    int Resume();
// 정지된 쓰레드 재개
    int Receive(const shared_ptr<PGLVMThread>& from, int cnt);
// 다른 쓰레드로부터 cnt개만큼의 자료를 받아옵니다
    int GetState() const {return m_state;}
    void PushError(PGLVMError e, int addr);
    shared_ptr<PGLCompoundData> GetParameter(int i);
    size_t GetParameterCnt() const;
    void SetReturnCnt(size_t i);
    size_t GetReturnCnt() const {return m_retCnt;}
    void PushNull();
    void Push(const shared_ptr<PGLCompoundData>& data);
    string GetErrMsg() const {return m_err;}
};


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
/*
각각의 명령어들은 단순해서 구현하는게 어렵지 않습니다.
오퍼랜드를 가져와서, 그에 맞는 행동을 하는게 전부
*/
int PGLVMThread::ProcNOP()
{
    return -1;
}
 
int PGLVMThread::ProcPUSH()
{
    short operand = m_mainVM->m_codes[m_pc++];
    m_stack.push_back(m_mainVM->m_literal[operand]);
    return -1;
}
 
int PGLVMThread::ProcSTORE()
{
    short operand = m_mainVM->m_codes[m_pc++];
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    m_mainVM->m_literal[operand] = m_stack.back();
    m_stack.pop_back();
    return -1;
}
 
int PGLVMThread::ProcCOPY()
{
    short operand = m_mainVM->m_codes[m_pc++];
    if(m_stackBase.empty())
    {
        PushError(PGLVMError::no_stackbase, m_pc - 2);
        return PGL_RUNERR;
    }
    auto v = m_stack[m_stackBase.back()   operand];
    m_stack.push_back(v);
    return -1;
}
 
int PGLVMThread::ProcWRITE()
{
    short operand = m_mainVM->m_codes[m_pc++];
    if(m_stackBase.empty())
    {
        PushError(PGLVMError::no_stackbase, m_pc - 2);
        return PGL_RUNERR;
    }
    m_stack[m_stackBase.back()   operand] = m_stack.back();
    m_stack.pop_back();
    return -1;
}
 
int PGLVMThread::ProcPOP()
{
    short operand = m_mainVM->m_codes[m_pc++];
    for(int i = 0; i < operand;   i) m_stack.pop_back();
    return -1;
}
 
int PGLVMThread::ProcCALL()
{
    short operand = m_mainVM->m_codes[m_pc++];
    auto call = *(m_stack.end() - operand - 1);
    m_stackBase.push_back(m_stack.size() - operand);
    m_callstack.push_back(m_pc);
    switch(call->GetType())
    {
    case PGLFirstData::Function:
        m_pc = ((PGLFunctionData*)call.get())->data;
        break;
    case PGLFirstData::CFunction:
        {
            int ret = ((PGL_CFunc)(((PGLCFunctionData*)call.get())->data))(this);
            m_pc = m_callstack.back();
            m_callstack.pop_back();
            // 스택 정리, return 될 값들만 남기고 모두 지운다
            m_stack.erase(m_stack.begin()  + m_stackBase.back() - 1, m_stack.end() - m_retCnt);
            m_stackBase.pop_back();
            if(ret != PGL_OK) return ret;
        }
        break;
    case PGLFirstData::Closure:
        m_stack.insert(m_stack.end() - operand, ((PGLClosureData*)call.get())->context);
        m_pc = ((PGLClosureData*)call.get())->func->data;
        break;
    default:
        PushError(PGLVMError::not_callable, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcTHISCALL()
{
    short operand = m_mainVM->m_codes[m_pc++];
    auto call = *(m_stack.end() - operand - 2);
    m_stackBase.push_back(m_stack.size() - operand - 1);
    m_callstack.push_back(m_pc);
 
    shared_ptr<PGLFunctionData> func;
    switch(call->GetType())
    {
    case PGLFirstData::Function:
        func = static_pointer_cast<PGLFunctionData>(call);
        break;
    case PGLFirstData::Closure:
        func = static_pointer_cast<PGLClosureData>(call)->func;
        break;
    case PGLFirstData::CFunction:
        {
            int ret = ((PGL_CFunc)(((PGLCFunctionData*)call.get())->data))(this);
            m_pc = m_callstack.back();
            m_callstack.pop_back();
            // 스택 정리, return 될 값들만 남기고 모두 지운다
            m_stack.erase(m_stack.begin() + m_stackBase.back() - 1, m_stack.end() - m_retCnt);
            m_stackBase.pop_back();
            if(ret != PGL_OK) return ret;
        }
        return -1;
    default:
        PushError(PGLVMError::not_callable, m_pc - 2);
        return PGL_RUNERR;
    }
 
    if(call->GetType() == PGLFirstData::Closure)
    {
        m_stack.insert(m_stack.end() - operand - 1, ((PGLClosureData*)call.get())->context);
    }
 
    m_pc = func->data;
    // this 인자가 필요없는 경우 제거한다
    if(!func->memberFunc)
    {
        m_stack.erase(m_stack.end() - operand - 1);
    }
 
    return -1;
}
 
int PGLVMThread::ProcRETURN()
{
    short operand = m_mainVM->m_codes[m_pc++];
    //되돌아갈 곳이 없으면 정상 종료
    if(m_callstack.empty()) return PGL_OK;
    m_pc = m_callstack.back();
    m_callstack.pop_back();
     
    // 스택 정리, return 될 값들만 남기고 모두 지운다
    m_stack.erase(m_stack.begin()   m_stackBase.back() - 1, m_stack.end() - operand);
    m_stackBase.pop_back();
    return -1;
}
 
int PGLVMThread::ProcYIELD()
{
    short operand = m_mainVM->m_codes[m_pc++];
    m_retCnt = operand;
    return PGL_YIELD;
}
 
int PGLVMThread::ProcADD()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateAdd(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_add, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcSUB()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateSub(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_sub, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcMUL()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateMul(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_mul, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcDIV()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateDiv(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_div, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcMOD()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateMod(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_mod, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
int PGLVMThread::ProcPOW()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperatePow(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_pow, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcAND()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateAnd(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_and, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcOR()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateOr(m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_or, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcEQ()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::EQ, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcNEQ()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::NEQ, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcGT()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::GT, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcGTE()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::GTE, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcLS()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::LS, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcLSE()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& a = *(m_stack.end()-2);
    a = a->OperateCmp(PGLCompoundData::LSE, m_stack.back());
    m_stack.pop_back();
    if(!a)
    {
        PushError(PGLVMError::unable_cmp, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcSIGN()
{
    if(m_stack.size() < 1)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    m_stack.back() = m_stack.back()->OperateSign();
    if(!m_stack.back())
    {
        PushError(PGLVMError::unable_sign, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcNOT()
{
    if(m_stack.size() < 1)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    m_stack.back() = m_stack.back()->OperateNot();
    if(!m_stack.back())
    {
        PushError(PGLVMError::unable_not, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcJMP()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    m_pc  = operand;
    return -1;
}
 
int PGLVMThread::ProcUNLESSJMP()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    auto value = m_stack.back();
    m_stack.pop_back();
    if(value->GetType() == PGLFirstData::Boolean)
    {
        if(static_pointer_cast<PGLBooleanData>(value)->data == false)
        {
            m_pc  = operand;
        }
    }
    else
    {
        PushError(PGLVMError::expect_bool, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcPUSHNULL()
{
    m_stack.push_back(shared_ptr<PGLFirstData>(new PGLVoidData));
    return -1;
}
 
int PGLVMThread::ProcASSEMBLE()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stack.size() < operand)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    auto arr = shared_ptr<PGLArrayData>(new PGLArrayData);
    move(m_stack.end() - operand, m_stack.end(), back_inserter(arr->data));
    m_stack.erase(m_stack.end() - operand, m_stack.end());
    m_stack.push_back(arr);
    return -1;
}
 
int PGLVMThread::ProcNEWDICT()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stack.size() < 2*operand)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    auto dict = shared_ptr<PGLDictionaryData>(new PGLDictionaryData);
    for(int i = 0; i < operand;   i)
    {
        auto val = m_stack.back();
        m_stack.pop_back();
        auto key = m_stack.back();
        m_stack.pop_back();
 
        switch(key->GetType())
        {
        case PGLCompoundData::Array:
        case PGLCompoundData::Dictionary:
        case PGLCompoundData::Closure:
            PushError(PGLVMError::compound_key, m_pc - 2);
            return PGL_RUNERR;
        }
        dict->data[static_pointer_cast<PGLFirstData>(key)] = val;
    }
    m_stack.push_back(dict);
    return -1;
}
 
int PGLVMThread::ProcAT()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto key = m_stack.back();
    m_stack.pop_back();
    auto cont = m_stack.back();
    m_stack.pop_back();
 
    switch(key->GetType())
    {
    case PGLCompoundData::Array:
    case PGLCompoundData::Dictionary:
    case PGLCompoundData::Closure:
        PushError(PGLVMError::compound_key, m_pc - 1);
        return PGL_RUNERR;
    }
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        if(key->GetType() != PGLCompoundData::Integer)
        {
            PushError(PGLVMError::compound_key, m_pc - 1);
            return PGL_RUNERR;
        }
        m_stack.push_back(
            ((PGLArrayData*)(cont.get()))->data[((PGLIntData*)(key.get()))->data]);
        break;
    case PGLCompoundData::Dictionary:
        {
            auto p = ((PGLDictionaryData*)(cont.get()))->data[static_pointer_cast<PGLFirstData>(key)];
            if(!p) p = shared_ptr<PGLFirstData>(new PGLVoidData);
            m_stack.push_back(p);
        }
        break;
    default:
        if(key->GetType() == PGLCompoundData::String)
        {
            auto p = cont->OperateDot(static_pointer_cast<PGLStringData>(key)->data);
            if(!p)
            {
                PushError(PGLVMError::unable_dereference, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(p);
        }
        else
        {
            PushError(PGLVMError::unable_dereference, m_pc - 1);
            return PGL_RUNERR;
        }
    }
    return -1;
}
 
int PGLVMThread::ProcLEN()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto cont = m_stack.back();
    m_stack.pop_back();
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        m_stack.push_back(make_shared<PGLIntData>(
            ((PGLArrayData*)(cont.get()))->data.size()));
        break;
    case PGLCompoundData::Dictionary:
        m_stack.push_back(make_shared<PGLIntData>(
            ((PGLDictionaryData*)(cont.get()))->data.size()));
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcATD()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    auto cont = m_stack.back();
    m_stack.pop_back();
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        m_stack.push_back(
            ((PGLArrayData*)(cont.get()))->data[operand]);
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcMAKECLOSURE()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto caps = m_stack.back();
    m_stack.pop_back();
    auto func = m_stack.back();
    m_stack.pop_back();
 
    if(caps->GetType() != PGLCompoundData::Array)
    {
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    if(func->GetType() != PGLCompoundData::Function)
    {
        PushError(PGLVMError::not_callable, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto cls = make_shared<PGLClosureData>();
    cls->func = static_pointer_cast<PGLFunctionData>(func);
    cls->context = static_pointer_cast<PGLArrayData>(caps);
    m_stack.push_back(cls);
    return -1;
}
 
int PGLVMThread::ProcSET()
{
    if(m_stack.size() < 3)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto key = m_stack.back();
    m_stack.pop_back();
    auto cont = m_stack.back();
    m_stack.pop_back();
    auto value = m_stack.back();
    m_stack.pop_back();
 
    switch(key->GetType())
    {
    case PGLCompoundData::Array:
    case PGLCompoundData::Dictionary:
    case PGLCompoundData::Closure:
        PushError(PGLVMError::compound_key, m_pc - 1);
        return PGL_RUNERR;
    }
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        if(key->GetType() != PGLCompoundData::Integer)
        {
            PushError(PGLVMError::compound_key, m_pc - 1);
            return PGL_RUNERR;
        }
        ((PGLArrayData*)(cont.get()))->data[((PGLIntData*)(key.get()))->data] = value;
        break;
    case PGLCompoundData::Dictionary:
        {
            ((PGLDictionaryData*)(cont.get()))->data[static_pointer_cast<PGLFirstData>(key)] = value;
        }
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcSETD()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    auto cont = m_stack.back();
    m_stack.pop_back();
    auto value = m_stack.back();
    m_stack.pop_back();
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        {
            auto& v = ((PGLArrayData*)(cont.get()))->data[operand];
            v = value;
        }
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcREF()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto value = m_stack.back();
    m_stack.pop_back();
    m_stack.push_back(make_shared<PGLRefData>(value));
    return -1;
}
 
int PGLVMThread::ProcDEREF()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto value = m_stack.back();
    m_stack.pop_back();
     
    if(value->GetType() != PGLCompoundData::Ref)
    {
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    m_stack.push_back(static_pointer_cast<PGLRefData>(value)->data);
    return -1;
}
 
int PGLVMThread::ProcCOPYDEREF()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stackBase.empty())
    {
        PushError(PGLVMError::no_stackbase, m_pc - 2);
        return PGL_RUNERR;
    }
    auto v = m_stack[m_stackBase.back()   operand];
    if(v->GetType() == PGLCompoundData::Ref)
    {
        m_stack.push_back(static_pointer_cast<PGLRefData>(v)->data);
    }
    else
    {
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcSETDDEREF()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 2);
        return PGL_RUNERR;
    }
    auto cont = m_stack.back();
    m_stack.pop_back();
    auto value = m_stack.back();
    m_stack.pop_back();
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        {
            auto& v = ((PGLArrayData*)(cont.get()))->data[operand];
            if(v->GetType() == PGLCompoundData::Ref)
            {
                static_pointer_cast<PGLRefData>(v)->data = value;
                break;
            }
        }
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcWRITEDEREF()
{
    short operand = m_mainVM->m_codes[m_pc  ];
    if(m_stackBase.empty())
    {
        PushError(PGLVMError::no_stackbase, m_pc - 2);
        return PGL_RUNERR;
    }
    auto value = m_stack.back();
    m_stack.pop_back();
    auto& v = m_stack[m_stackBase.back()   operand];
    if(v->GetType() == PGLCompoundData::Ref)
    {
        static_pointer_cast<PGLRefData>(v)->data = value;
    }
    else
    {
        PushError(PGLVMError::unable_dereference, m_pc - 2);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcPUSHBEGIN()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto value = m_stack.back();
    switch(value->GetType())
    {
    case PGLCompoundData::Array:
        m_stack.push_back(make_shared<PGLCVectorIterData>(*static_pointer_cast<PGLArrayData>(value)));
        break;
    case PGLCompoundData::Dictionary:
        m_stack.push_back(make_shared<PGLCMapIterData>(*static_pointer_cast<PGLDictionaryData>(value)));
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcISNOTEND()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto value = m_stack.back();
    m_stack.pop_back();
    switch(value->GetType())
    {
    case PGLCompoundData::CVectorIter:
    case PGLCompoundData::CMapIter:
        m_stack.push_back(make_shared<PGLBooleanData>(value->IsNotEnd()));
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcNEXT()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto& value = m_stack.back();
    switch(value->GetType())
    {
    case PGLCompoundData::CVectorIter:
    case PGLCompoundData::CMapIter:
        value->Next();
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcPUSHKEYVAL()
{
    if(m_stack.empty())
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
 
    auto value = m_stack.back();
    switch(value->GetType())
    {
    case PGLCompoundData::CVectorIter:
    case PGLCompoundData::CMapIter:
        m_stack.push_back(value->GetKey());
        m_stack.push_back(value->GetValue());
        break;
    default:
        PushError(PGLVMError::unable_dereference, m_pc - 1);
        return PGL_RUNERR;
    }
    return -1;
}
 
int PGLVMThread::ProcFIND()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto key = m_stack.back();
    m_stack.pop_back();
    auto cont = m_stack.back();
    m_stack.pop_back();
 
    switch(key->GetType())
    {
    case PGLCompoundData::Array:
    case PGLCompoundData::Dictionary:
    case PGLCompoundData::Closure:
        PushError(PGLVMError::compound_key, m_pc - 1);
        return PGL_RUNERR;
    }
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        if(key->GetType() != PGLCompoundData::Integer)
        {
            PushError(PGLVMError::compound_key, m_pc - 1);
            return PGL_RUNERR;
        }
        else
        {
            int i = static_pointer_cast<PGLIntData>(key)->data;
            if(i >= static_pointer_cast<PGLArrayData>(cont)->data.size())
            {
                PushError(PGLVMError::not_found, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(static_pointer_cast<PGLArrayData>(cont)->data[i]);
        }
        break;
    case PGLCompoundData::Dictionary:
        {
            auto k = static_pointer_cast<PGLFirstData>(key);
            auto it = static_pointer_cast<PGLDictionaryData>(cont)->data.find(k);
            if(it == static_pointer_cast<PGLDictionaryData>(cont)->data.end())
            {
                PushError(PGLVMError::not_found, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(it->second);
        }
        break;
    default:
        if(key->GetType() == PGLCompoundData::String)
        {
            auto p = cont->OperateDot(static_pointer_cast<PGLStringData>(key)->data);
            if(!p)
            {
                PushError(PGLVMError::unable_dereference, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(p);
        }
        else
        {
            PushError(PGLVMError::unable_dereference, m_pc - 1);
            return PGL_RUNERR;
        }
    }
    return -1;
}
 
int PGLVMThread::ProcFINDP()
{
    if(m_stack.size() < 2)
    {
        PushError(PGLVMError::stack_underflow, m_pc - 1);
        return PGL_RUNERR;
    }
    auto key = m_stack.back();
    m_stack.pop_back();
    auto cont = m_stack.back();
    m_stack.pop_back();
 
    switch(key->GetType())
    {
    case PGLCompoundData::Array:
    case PGLCompoundData::Dictionary:
    case PGLCompoundData::Closure:
        PushError(PGLVMError::compound_key, m_pc - 1);
        return PGL_RUNERR;
    }
 
    switch(cont->GetType())
    {
    case PGLCompoundData::Array:
        if(key->GetType() != PGLCompoundData::Integer)
        {
            PushError(PGLVMError::compound_key, m_pc - 1);
            return PGL_RUNERR;
        }
        else
        {
            int i = static_pointer_cast<PGLIntData>(key)->data;
            if(i >= static_pointer_cast<PGLArrayData>(cont)->data.size())
            {
                PushError(PGLVMError::not_found, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(static_pointer_cast<PGLArrayData>(cont)->data[i]);
        }
        break;
    case PGLCompoundData::Dictionary:
        {
            auto k = static_pointer_cast<PGLFirstData>(key);
            auto it = static_pointer_cast<PGLDictionaryData>(cont)->data.find(k);
            if(it == static_pointer_cast<PGLDictionaryData>(cont)->data.end())
            {
                PushError(PGLVMError::not_found, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(it->second);
        }
        break;
    default:
        if(key->GetType() == PGLCompoundData::String)
        {
            auto p = cont->OperateDot(static_pointer_cast<PGLStringData>(key)->data);
            if(!p)
            {
                PushError(PGLVMError::unable_dereference, m_pc - 1);
                return PGL_RUNERR;
            }
            m_stack.push_back(p);
        }
        else
        {
            PushError(PGLVMError::unable_dereference, m_pc - 1);
            return PGL_RUNERR;
        }
    }
    m_stack.push_back(cont);
    return -1;
}
 
int PGLVMThread::Entry(int paramCnt)
{
    short operand = paramCnt;
    auto call = *(m_stack.end() - operand - 1);
    m_stackBase.push_back(m_stack.size() - operand);
    switch(call->GetType())
    {
    case PGLFirstData::Function:
        m_pc = ((PGLFunctionData*)call.get())->data;
        break;
    case PGLFirstData::CFunction:
        {
            int ret = ((PGL_CFunc)(((PGLCFunctionData*)call.get())->data))(this);
            if(ret != PGL_OK) return ret;
            m_pc = m_callstack.back();
            m_callstack.pop_back();
            // 스택 정리, return 될 값들만 남기고 모두 지운다
            m_stack.erase(m_stack.begin()   m_stackBase.back() - 1, m_stack.end() - m_retCnt);
            m_stackBase.pop_back();
        }
        break;
    case PGLFirstData::Closure:
        m_stack.insert(m_stack.end() - operand, ((PGLClosureData*)call.get())->context);
        m_pc = ((PGLClosureData*)call.get())->func->data;
        break;
    default:
        PushError(PGLVMError::not_callable, m_pc - 2);
        return PGL_RUNERR;
    }
    m_state = PGL_ENTRY;
    return PGL_OK;
}
 
int PGLVMThread::Resume()
{
    m_state = PGL_RUNNING;
#define PROC(p) case PGLOpcode::p: ret = Proc##p(); if(ret >= 0) return m_state = ret; break;
    int ret;
    while(m_pc < m_mainVM->m_codes.size())
    {
        switch(m_mainVM->m_codes[m_pc  ])
        {
        PROC(NOP)
        PROC(PUSH)
        PROC(STORE)
        PROC(COPY)
        PROC(WRITE)
        PROC(POP)
        PROC(THISCALL)
        PROC(CALL)
        PROC(RETURN)
        PROC(YIELD)
        PROC(ADD)
        PROC(SUB)
        PROC(MUL)
        PROC(DIV)
        PROC(MOD)
        PROC(POW)
        PROC(SIGN)
        PROC(EQ)
        PROC(NEQ)
        PROC(GT)
        PROC(GTE)
        PROC(LS)
        PROC(LSE)
        PROC(AND)
        PROC(OR)
        PROC(NOT)
        PROC(JMP)
        PROC(UNLESSJMP)
        PROC(PUSHNULL)
        PROC(ASSEMBLE)
        PROC(NEWDICT)
        PROC(AT)
        PROC(LEN)
        PROC(ATD)
        PROC(MAKECLOSURE)
        PROC(SET)
        PROC(SETD)
        PROC(REF)
        PROC(DEREF)
        PROC(COPYDEREF)
        PROC(SETDDEREF)
        PROC(WRITEDEREF)
        PROC(PUSHBEGIN)
        PROC(ISNOTEND)
        PROC(NEXT)
        PROC(PUSHKEYVAL)
        PROC(FIND)
        PROC(FINDP)
        }
    }
    m_state = PGL_OK;
    return PGL_OK;
}

길기는 무지막지하게 긴데, 실제로는 별 내용없는 코드입니다. 에뮬레이터 구현하는게 이런 뻘뻘한 느낌이겠죠 아마...?

실제로 이런 명령어들을 통해 어떻게 함수가 호출되고, 클로저가 구현되며, YIELDING이 가능한지는 다음으로 넘겨야할거 같네요. 글이 너무 길어져서...




관련글 더보기

댓글 영역