Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1320556
  • 博文数量: 179
  • 博客积分: 4141
  • 博客等级: 中将
  • 技术积分: 2083
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-21 20:04
文章存档

2024年(1)

2019年(13)

2016年(1)

2014年(16)

2011年(8)

2010年(25)

2009年(115)

分类:

2009-06-12 16:01:03

Assembly Transducer

Time Limit:2sMemory limit:32M
Accepted Submit:18Total Submit:105

As you know, assembly language is great and can do many things that can’t be done with advanced languages. Now, we have a fraction of assembly code, can you give the result?

We define a subset of common assembly language as follows (all in uppercase):

  1. only four registers are used : AX, BX, CX, DX
  2. MOV OPERAND1 OPERAND2
    copy the value of OPERAND2 to OPERAND1, OPERAND can be the register (AX, BX, CX, DX) or memory address (register or digits in [ ] ) or integer, but never with two memory address. All digits are described in decimal, for example:
    MOV AX BX
    MOV [AX] BX
    MOV AX [DX]
    MOV BX [100]
    MOV AX 100
  3. ADD OPERAND1 OPERAND2
    add the value of OPERAND2 to OPERAND1, other definitions are the same as item 2
  4. SUB OPERAND1 OPERAND2
    subtract the value of OPERAND2 from OPERAND1, other definitions are the same as item 2
  5. CMP OPERAND1 OPERAND2
    compare the value of OPERAND1 with that of OPERAND2, the result will be useful in JE or JNE operator, other definitions are the same as item 2
  6. JMP LABEL
    jump to the instruction following the label, the label is a string in uppercase characters or digits ending with colon, a label can have at most 10 characters. For instance:
    LABEL: MOV AX BX
    JMP LABEL
    LP:
    JMP LP
    the label will not be reserved words such as JMP, MOV, etc.
  7. JE LABLE
    following the CMP instruction immediately, if the value of OPERAND1 equals that of OPERAND2, jump to the label defined in item 6
  8. JNE LABLE
    following the CMP instruction immediately, if the value of OPERAND1 doesn't equal that of OPERAND2, jump to the label defined in item 6
  9. LOOP LABLE
    first decrease CX by 1, if CX is not equal to 0, jump to the label defined in item 6
  10. Immediates specified in OPERAND are in the range of [-32768, 32767]. Overflow is allowed in our language. For instance, add 1 to 32767, the answer is -32768.
Input

There multiple test cases. Each test case contains no more than 25 lines, ending with a single line “END”. At first, all registers are initialized to 0. The memory address is from 0 ~ 32767. All words are separated by spaces. There is a blank line between test cases.

Output

For each test case, print the value of AX, BX, CX, DX in a single line, separated by a space. Note: the assembly instructions will be always legal. There will never be any endless loop in the fraction.

Sample input
MOV  CX  2
TAB: ADD AX -1
ADD BX 1
ADD DX 2
SUB CX 1
CMP 0 CX
JNE TAB
END
Sample output
-2 2 0 4

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define mem_size 32768

short pc;
short memory[mem_size];
short registers[4];
char regs[][10] = {"AX", "BX", "CX", "DX"};

#define IS_DOUBLE(x) (((x) == OP_MOV) || ((x) == OP_SUB) || ((x) == OP_ADD) || ((x) == OP_CMP))
#define IS_SINGLE(x) (((x) == OP_JMP) || ((x) == OP_JE) || ((x) == OP_JNE) || ((x) == OP_LOOP))
#define IS_END(x) ((x) == OP_END)

typedef enum
{
    OP_NULL, OP_MOV, OP_ADD, OP_SUB, OP_CMP, OP_JMP, OP_JE, OP_JNE, OP_LOOP, OP_END
}op_type;

struct Insn_type
{
    char name[10];
    op_type type;
};
struct Insn_type insn_type[] =
{
    {"MOV", OP_MOV},
    {"ADD", OP_ADD},
    {"SUB", OP_SUB},
    {"CMP", OP_CMP},
    {"JMP", OP_JMP},
    {"JE", OP_JE},
    {"JNE", OP_JNE},
    {"LOOP", OP_LOOP},
    {"END", OP_END}
};
#define insn_type_num 9

#define OPND_NULL 0
#define OPND_IMM 1
#define OPND_REG 0x2
#define OPND_MEM 0x5
#define OPND_INDIR_MEM 0x6

struct Insn_info
{
    op_type type;
    short opnd_type[2];
    short opnd[2];
    char label[20];
};
struct Insn_info insn_code[50];
short code_num;

struct label_info
{
    char name[20];
    short addr;
};
struct label_info label[30];
short label_num;

short get_insn_type(char *code)
{
    short i;

    for (i = 0; i < insn_type_num; ++i)
    {
        if (strcmp(code, insn_type[i].name) == 0)
            break;
    }
    return i;
}

short decode_insn_info(char *insn, short index)
{
    short i;
    char *p = insn;

    insn_code[code_num].opnd_type[index] = 0;
    if (*p == '[')
    {
        ++p;
        insn_code[code_num].opnd_type[index] |= 4;
    }

    for (i = 0; i < 4; ++i)
    {
        if (regs[i][0] == *p)
            break;
    }
    if (i != 4)
    {
        insn_code[code_num].opnd_type[index] |= 0x2;
        insn_code[code_num].opnd[index] = i;
        return 0;
    }
    
    insn_code[code_num].opnd_type[index] |= 1;
    insn_code[code_num].opnd[index] = atoi(p);

    return 0;
}

#define get_val(ipc, index, val) \
{\
    if (insn_code[ipc].opnd_type[index] & 1)\
        val = insn_code[ipc].opnd[index];\
    if (insn_code[ipc].opnd_type[index] & 2)\
        val = registers[insn_code[ipc].opnd[index]];\
    if (insn_code[ipc].opnd_type[index] & 4)\
        val = memory[val];\
}\

short * get_addr(short ipc, short index)
{
    short val;
    short *p = NULL;

    if (insn_code[ipc].opnd_type[index] & 1)
        val = insn_code[ipc].opnd[index];
    if (insn_code[ipc].opnd_type[index] & 2)
    {
        p = &registers[insn_code[ipc].opnd[index]];
        val = *p;
    }
    if (insn_code[ipc].opnd_type[index] & 4)
        p = &memory[val];

    return p;
}

short get_label_addr(char *p)
{
    short i;

    for (i = 0; i < label_num; ++i)
    {
        if (strcmp(p, label[i].name) == 0)
            break;
    }

    return label[i].addr;
}

int main()
{
    short a, b;
    short val, flag_cmp;
    short i, code_count;
    short *addr = NULL;
    char *p = NULL;
    char str[100];
    char code[100], opnd1[100], opnd2[100];

    while(gets(str))
    {
        code_count = 0;
        code_num = 0;
        label_num = 0;
        while (1)
        {
            p = str;
            sscanf(p, "%s", code);
            if (code[strlen(code) - 1] == ':')
            {
                strcpy(label[label_num].name, code);
                label[label_num].name[strlen(label[label_num].name) - 1] = '\0';
                label[label_num].addr = code_count;
                while (*p == ' ') ++p;
                p = p + strlen(code);
                ++label_num;
            }

            if (sscanf(p, "%s", code) == 1)
            {
                i = get_insn_type(code);
                while (*p == ' ') ++p;
                p = p + strlen(code);
                insn_code[code_num].type = insn_type[i].type;
                if (IS_DOUBLE(insn_type[i].type))
                {
                    sscanf(p, "%s %s", opnd1, opnd2);
                    decode_insn_info(opnd1, 0);
                    decode_insn_info(opnd2, 1);
                }
                else if (IS_SINGLE(insn_type[i].type))
                {
                    sscanf(p, "%s", opnd1);
                    strcpy(insn_code[code_num].label, opnd1);
                }
                else
                    break;
                
                ++code_num;
                ++code_count;
            }
            gets(str);
        }

        for (i = 0; i < code_num; ++i)
        {
            if (insn_code[i].type == OP_JNE || insn_code[i].type == OP_JE || insn_code[i].type == OP_LOOP || insn_code[i].type == OP_JMP)
                insn_code[i].opnd[0] = get_label_addr(insn_code[i].label);
        }

        pc = 0;
        memset(registers, 0, sizeof(registers));
        while(!IS_END(insn_code[pc].type))
        {
            switch(insn_code[pc].type)
            {
            case OP_MOV:
                get_val(pc, 1, val);
                addr = get_addr(pc, 0);
                *addr = val;
                ++pc;
                break;
            case OP_ADD:
                get_val(pc, 1, val);
                addr = get_addr(pc, 0);
                *addr += val;
                ++pc;
                break;
            case OP_SUB:
                get_val(pc, 1, val);
                addr = get_addr(pc, 0);
                *addr -= val;
                ++pc;
                break;
            case OP_CMP:
                get_val(pc, 0, a);
                get_val(pc, 1, b);
                flag_cmp = a - b;
                ++pc;
                break;
            case OP_JE:
                if (flag_cmp == 0)
                    pc = insn_code[pc].opnd[0];
                else
                    ++pc;
                break;
            case OP_JNE:
                if (flag_cmp != 0)
                    pc = insn_code[pc].opnd[0];
                else
                    ++pc;
                break;
            case OP_LOOP:
                --registers[2];
                if (registers[2] != 0)
                    pc = insn_code[pc].opnd[0];
                else
                    ++pc;
                break;
            case OP_JMP:
                pc = insn_code[pc].opnd[0];
                break;
            default:
                break;
            }
        }

        printf("%d %d %d %d\n", registers[0], registers[1], registers[2], registers[3]);
    }

    return 0;
}

阅读(1564) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~