728x90

1. 바이트 코드 패턴 정의

  • 가상 머신 명령어를 인코딩한 데이터로 행동을 표현할 수 있는 유연함을 제공하는 패턴

 

2. 명령어 집합

enum Instruction
{
    INST_SET_HEALTH = 0x00,
    ISNT_SET_WISDOM = 0x01,
    INST_SET_AGILITY = 0x02,
    INST_PLAY_SOUND = 0x03,
    INST_SPAWN_PARTICLES = 0x04,
    INST_LITERAL = 0x05,
    INST_GET_HEALTH = 0x06,
    INST_GET_WISDOM = 0x07,
    INST_GET_AGILITY = 0x08,
    INST_ADD = 0x09,
};
  • 명령어는 열거형으로 표현할 수 있다.
  • 명령어들을 데이터로 인코딩하기 위해서는 열거형 값( Byte )을 배열에 저장하면 된다.
  • 데이터로 인코딩 된 명령어들은 열거형 값들의 배열, 즉 바이트들의 목록이다 보니 '바이트코드'라고 불린다.

 

3. 명령어를 해석하고 실행시키기 위한 API메서드

switch ( instruction )
    {
        case INST_SET_HEALTH:
        SetHealth( 0, 100 );
        break;
        
        case ISNT_SET_WISDOM:
        SetWisdom( 0, 100 );
        break;
        
        case INST_SET_AGILITY:
        SetAgility( 0, 100 );
        break;

        case INST_PLAY_SOUND:
        PlaySound( SoundData::SOUND_BANG );
        break;

        case INST_SPAWN_PARTICLES:
        SpawnParticles( Particle::PARTICLE_FLAME );
        break;
    }
  • 위와 같이 가상 머신( 인터프리터 )은 코드와 데이터를 연결한다.

 

4. VM에서 래핑 한 코드

class VM
{
public:
    void Interpret( char bytecode[], int size )
    {
        for ( int index = 0; index < size; ++index )
        {
            char instruction = bytecode[ index ];
            switch (instruction)
            {
                case INST_SET_HEALTH:
                // ..
                break;
            }
        }
    }
};
  • 바이트코드를 읽어 명령어를 실행한다.

 

5. 스택 머신을 이용한 명령어 실행 순서 제어

class VM
{
private:
    static const int MAX_STACK = 128;
    int stackSize;
    int stack[ MAX_STACK ];

private:
    void Push( int InValue )
    {
        // +스택 오버플로 검사
        stack[ stackSize++ ] = InValue;
    }

    int Pop()
    {
        // +스택 비어 있지 않은지 검사
        return stack[ --stackSize ];
    }

public:
    VM() : stackSize(0) {}
    void Interpret( char bytecode[], int size )
    {
        for ( int index = 0; index < size; ++index )
        {
            char instruction = bytecode[ index ];
            switch ( instruction )
            { 
               case INST_SET_HEALTH:
                {
                    int amount = Pop();
                    int wizard = Pop();
                    SetHealth( wizard, amount );
                }
                break;
                
                case INST_LITERAL:
                {
                // 바이트코드에서 다음 바이트 값을 읽는다.
                int value = bytecode[ ++index ];
                Push( value );
                }
                break;

                case INST_GET_HEALTH:
                {
                    int wizard = Pop();
                    Push( GetHealth( wizard ) );
                }
                break;

                case INST_ADD:
                {
                    int b = Pop();
                    int a = Pop();
                    Push( a + b );
                }
                break;
                
                //case ISNT_SET_WISDOM:
                //...     
                //case INST_SET_AGILITY:
                //...
                //case INST_PLAY_SOUND:
                //...
                //...
             }
        }
    }
};

명령어 및 스택 정보

  • 스택에서 값을 얻어오기 위해 리터럴 명령어를 추가한다.
  • 리터럴 값 이후에 나오는 바이트를 값으로 읽어 스택에 넣어 사용한다.
  • Get, Set 명령어를 통해 다양한 행동을 할 수 있도록 조합하여 사용한다.
반응형

+ Recent posts