Інтерпретатори. Принципи написання інтерпретаторів на прикладі написання програми, що виконує команди і директиви язика асемблера процесора 8086, страница 2

        case  OP_SUB :   *op1 -= *op2; pswz = (*op1 == 0);     break;

        case  OP_PUSH:   push(*op1);   regval[RSP]++;          break;

        case  OP_POP :   *op1 = pop();                         break;

        case  OP_RET :   regval[RIP] = pop();                  break;

        case  OP_OR  :   *op1 |= *op2;                         break;

        case  OP_XOR :   *op1 ^= *op2;                         break;

        case  OP_AND :   *op1 &= *op2;                         break;

        case  OP_NOT :   *op1 = !*op1;                         break;

    }

}

int strconsist(char *s, char c)

{

    while(*s)

        if(*s++ == c)

            return 1;

    return 0;

}

char *parse(char *buf, char *str)

{

    char c;

    while(*str)

    {

        c = *str;

        if(!strconsist(separators, c))

        {

            if(strconsist(signs, c))

            {

                buf[0] = c;

                buf[1] = 0;

                parsetyp = PT_SIGN;

                return str+1;

            }

            while(*str &&

            (!strconsist(separators, *str)) &&

            (!strconsist(signs, *str)))

                *buf++ = *str++;

            *buf = 0;

                parsetyp = PT_WORD;

            return str;

        }

        str++;

    }

    *buf = 0;

    parsetyp = PT_EOST;

    return str;

}

int findstr(char *tab[], char *it)

{

    int cmdidx;

    cmdidx = 0;

    while(tab[cmdidx])

    {

        if(strcomp(tab[cmdidx], it))

            return cmdidx;

        cmdidx++;

    }

    return -1;

}

void main(void)

{

    int opcode, op1num, op2num, i,index, n;

    char *parsep;

    restart:

     printf("\nПрограмма обрабатывает команды\n");

    for (index = 0; index < sizeof(mnemonics)/2; index++)

     printf ("%s,",mnemonics[index]);

    printf("\n\nДля выхода из программы,не вводя команды нажмите ENTER ");

    printf("\n\nOperation > ");

    gets(cmdbuf);

    strupcase(cmdbuf);

    if(!cmdbuf[0])

        goto quit;

    parsep = cmdbuf;

    do {

        parsep = parse(lexbuf, parsep);

        if(parsetyp != PT_WORD)

        {

            printf("Must be command mnemonic");

            goto restart;

        }

        if(0 > (opcode = findstr(mnemonics, lexbuf)))

        {

            printf("Wrong command");

            goto restart;

        }

        parsep = parse(lexbuf, parsep);

        if(!operandcount[opcode])

        {

            if(parsetyp != PT_SIGN)

            {

                printf("This commands does not request an operands");

                goto restart;

            }

            if(lexbuf[0] != ';')

            {

                printf("Must be command delimiter (;) but not %c", lexbuf[0]);

                goto restart;

            }

            goto runcmd;

        }

        if(parsetyp != PT_WORD)

        {

            printf("First operand be register");

            printf(" Got: %d '%s'", parsetyp, lexbuf);

            goto restart;

        }

        if(0 > (op1num = findstr(registers, lexbuf)))

        {

            printf("Unknown register");

            goto restart;

        }

        if(operandcount[opcode] == 1)

            goto runcmd;

          parsep=parse(lexbuf,parsep);

          if (lexbuf[0]!=',')

          {

             printf("Must be ','");

             goto restart;

          }

        parsep = parse(lexbuf, parsep);

        if(parsetyp != PT_WORD)

        {

            printf("Second operand be register or number");

            goto restart;

        }

        if(0 > (op2num = findstr(registers, lexbuf)))

        {

            if(strtoi(lexbuf, &n))

            {

                printf("Unknown register or bad number");

                goto restart;

            }

            op2num = RIMM;

            regval[RIMM] = n;

        }

        runcmd:

        execcmd(opcode, &regval[op1num], &regval[op2num]);

        for(i = 0; i < (sizeof(registers)/2  - 1); i++)

        {

            printf("\t%s=%X(%d) ", registers[i], regval[i],regval[i]);

            if (!((i+1) % 3)) printf("\n");

        }

        printf("\n");

        for(i = 1; i < 16; i++)

        {

            if(regval[RSP] < i)

                break;

            printf("ST[%d]=%.2X(%d)  ",regval[RSP] - i, stack[regval[RSP] - i],stack[regval[RSP] - i] );

        }

        printf("\n");

        goto restart;

    } while(parsetyp);

    quit:;

}

6.  Результати виконання програми.

Результатом виконання програми є вміст імітованих регістрів :

Програма обробляє команди

MOV, DEC, INC, ADD, SUB, PUSH, POP, RET, OR, XOR, AND, NOT.

Для виходу з програми, не вводячи команди натисніть ENTER.

Operation > mov cx,-1

        AX=0(0)         BX=0(0)         CX=FFFF(-1)

        DX=0(0)         SP=0(0)          BP=0(0)

        SI=0(0)           DI=0(0)           IP=0(0)

Operation >push cx

        AX=0(0)         BX=0(0)         CX=FFFF(-1)

        DX=0(0)         SP=1(1)          BP=0(0)

        SI=0(0)           DI=0(0)           IP=0(0)

ST[0]=FFFF(-1)

Operation >pop ax

        AX=FFFF(-1)     BX=0(0)           CX=FFFF(-1)

        DX=0(0)             SP=FFFF(-1)     BP=0(0)

        SI=0(0)               DI=0(0)              IP=0(0)

7.  Висновки з проробленої роботи: У процесі лабораторної роботи були вивчені  принципи написання програм, що імітують виконання команд і директив язика асемблера.