| home | contents | previous | next page | send comment | send link | add bookmark |

PRS_EMIT.CPP

intermediate code

/*-------------------------------------------------------------------*
     Interpreter statement emitter

     File:     prs_emit.cpp

     Module:   parser

     by:  Stephen R. Schmitt
 *-------------------------------------------------------------------*/

#include "tpl_data.h"
#include <assert.h>
#include <alloc.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

/*
 *   External variables
 */
       /* in tpl_main.cpp */
extern bool Debug_flag;
#ifdef DEBUG
extern FILE *c_out, *d_out;
#endif
       /* in sym_tabl.cpp */
extern TYPE_STRUCT_PTR Integer_typep, Real_typep,
                       Boolean_typep, Char_typep,
                       String_typep,  Null_typep;
       /* in exc_main.cpp */
extern bool Routine_flag;
extern MEMORY_PTR *CSeg;
extern MEMORY_PTR DSeg;

/*
 *   Global declarations
 */
int CI;
int TI;
int Routine_number;
int Data_item;
MEMORY_PTR Code_buffer;
MEMORY_PTR Temp_buffer;
int Code_label[MAX_LABELS];
int Label_count;

/*-------------------------------------------------------------------*
                         Code Section
 *-------------------------------------------------------------------*/

/*
 *   "init_emit" creates code buffers and sets code index
 *   values to starting values
 *
 *   returns:  nothing
 */
void init_emit()
{
    Routine_number = 2;                             // main->0, program->1
    Data_item = 1;

    Code_buffer = new MEMORY[MAX_CODE_SIZE];
    if (Code_buffer == NULL)
        runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

    Temp_buffer = new MEMORY[MAX_DATA_SIZE];
    if (Temp_buffer == NULL)
        runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

    CSeg = new MEMORY_PTR[MAX_CODE_SEGMENTS];
    if (CSeg == NULL)
        runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

    DSeg = new MEMORY[MAX_DATA_SIZE];
    if (DSeg == NULL)
        runtime_error(M_OUT, M_OF, M_MEMORY, M_0);
    else
        memset(DSeg, '\0', MAX_DATA_SIZE * sizeof(MEMORY));

    init_code_segment();
}

/*
 *   "init_code_segment" resets counters and clears label list
 *
 *   returns:  nothing
 */
void init_code_segment()
{
    CI = 0;
    Label_count = 0;

    for (int i = 0; i < MAX_LABELS; i++)
        Code_label[i] = 0;
}

/*
 *   "exit_emit" deletes code buffers
 *
 *   returns:  nothing
 */
void exit_emit()
{
   assert(Code_buffer != NULL);
   delete Code_buffer;
   assert(Temp_buffer != NULL);
   delete Temp_buffer;
}

/*
 *   "emit_code_segment" copies a code buffer into a code segment
 *
 *   returns:  index number of the segment
 */
void emit_code_segment(SYMTAB_NODE_PTR idp)         // of subroutine
{
    int i, j, n;
    int number = idp->routine.segment;
    SYMTAB_NODE_PTR rtne_idp = idp;

    if (Routine_flag)                               // in subprogram
    {
        Temp_buffer[0].op.code1 = PUSH;
        Temp_buffer[0].op.code2 = REG_BP;
        Temp_buffer[1].op.code1 = MOV_bp_sp;
        n = idp->routine.parm_count;                // number of formals
        for (i = 0; i < n; i++)                     // find last formal parm
            idp = idp->next;

        TI = 2;                                     // initialize
        idp = idp->next;                            // first local
        while (idp != NULL)                         // push onto stack
        {
            emit_alloc_data(idp);                   // increment TI
            idp = idp->next;
        }

        CSeg[number] = new MEMORY[CI + TI + 1];
        if (CSeg[number])
        {
            for (i = 0; i < TI; i++)
                CSeg[number][i] = Temp_buffer[i];

            fixup_code_buffer_addresses(TI);

            for (j = 0; j < CI; j++, i++)
                CSeg[number][i] = Code_buffer[j];

            CSeg[number][CI + TI].op.code1 = NO_CODE;
        }
        else
            runtime_error(M_OUT, M_OF, M_MEMORY, M_0);
    }
    else                                            // in main program
    {
        CSeg[number] = new MEMORY[CI + 1];
        if (CSeg[number])
        {
            for (i = 0; i < CI; i++)
                CSeg[number][i] = Code_buffer[i];

            CSeg[number][CI].op.code1 = NO_CODE;
        }
        else
            runtime_error(M_OUT, M_OF, M_MEMORY, M_0);
    }

    D(fprintf(c_out, "%d items of size %d bytes\n", (CI + TI), sizeof(MEMORY)));

    init_code_segment();

    idp = rtne_idp;                                 // prevent warning
#ifdef DEBUG
    list_segment(idp);
#endif
}

/*
 *   "fixup_code_buffer_addresses" changes label values to offsets
 *
 *   returns:  nothing
 */
void fixup_code_buffer_addresses(int ti)
{
    int iptr = 0;
    int index;
    OPCODE op = Code_buffer[iptr].op.code1;         // first instruction

    while (iptr < CI)                               // end of segment
    {
        switch (op)
        {
        case STATEMENT:
            iptr++;
            break;

        case PUSH:
            op = Code_buffer[iptr].op.code2;
            switch (op)
            {
            case IMM_64:
            case IMM_32:
            case IMM_16:
            case IMM_8:
            case IMM_STR:
                iptr++;
                break;
            }
            break;

        case JMP:
        case JNZ:
        case JZ:
            index = Code_buffer[iptr].op.offset;
            Code_buffer[iptr].op.offset = Code_label[index] + ti;
            break;
        }
        iptr++;
        op = Code_buffer[iptr].op.code1;
    }
}

/*
 *   "emit_pop_local_parm" emits code to pop local parameters on return
 *   from a declared program, procedure, or function.  Local parameters
 *   follow formal parameters.
 *
 *   returns:  nothing
 */
void emit_pop_local_parm(SYMTAB_NODE_PTR idp)       // of subroutine
{
    SYMTAB_NODE_PTR last_idp;

    int n = idp->routine.parm_count;                // number of formals
    int m = -1;                                     // init count
    while (idp != NULL)                             // when end of chain found
    {
        last_idp = idp;                             // save last idp
        idp = idp->next;
        m++;                                        // count total
    }

    m -= n;                                         // number of locals
    idp = last_idp;                                 // pop last one first
    for (int i = 0; i < m; i++)
    {
        delete_data(idp);
        idp = idp->prev;                            // pop in reverse order
    }
}

/*
 *   "emit_pop_formal_parm" emits code to pop formal parameters on
 *   return from a declared procedure or function.  The first n
 *   parameters after the subroutine idp are formal parameters.
 *
 *   returns:  nothing
 */
void emit_pop_formal_parm(SYMTAB_NODE_PTR idp)
{
    int n, i;

    n = idp->routine.parm_count;                    // number of formals
    for (i = 0; i < n; i++)                         // find last formal parm
        idp = idp->next;

    for (i = 0; i < n; i++)                         // pop from last to first
    {
        delete_data(idp);
        idp = idp->prev;
    }
}

/*
 *   "emit_operator" generates code item
 *
 *   returns:  nothing
 */
void emit_operator(OPCODE code1, OPCODE code2, int segment, int offset)
{
    if (CI > MAX_CODE_SIZE)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        Code_buffer[CI].op.code1 = code1;
        Code_buffer[CI].op.code2 = code2;
        Code_buffer[CI].op.segment = segment;
        Code_buffer[CI].op.offset = offset;
        CI++;
    }
}

/*
 *   "emit_op_reg_imm" generates code for an immediate register operation.
 *
 *   returns:  nothing
*/
void emit_op_reg_imm(OPCODE code, int value)
{
    assert(code == ADD_xi_imm || code == MOV_ax_imm || code == MOV_bx_imm);

    emit_operator(code, NO_CODE, 0, value);
}


/*
 *   "emit_index" adds index value to code segment
 *
 *   returns:  nothing
 */
void emit_index(int value)                          // to insert
{
    if (CI > MAX_CODE_SIZE)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        Code_buffer[CI].index = value;
        CI++;
    }
}

/*
 *   "emit_char" adds a character to code segment
 *
 *   returns:  nothing
 */
void emit_char(char value)                          // to insert
{
    if (CI > MAX_CODE_SIZE)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        Code_buffer[CI].byte = value;
        CI++;
    }
}

/*
 *   "emit_integer" adds an integer value to code segment
 *
 *   returns:  nothing
 */
void emit_integer(long value)                       // to insert
{
    if (CI > MAX_CODE_SIZE)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        Code_buffer[CI].integer = value;
        CI++;
    }
}

/*
 *   "emit_real" adds real number value to code segment
 *
 *   returns:  nothing
 */
void emit_real(double value)                        // to insert
{
    if (CI > MAX_CODE_SIZE)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        Code_buffer[CI].real = value;
        CI++;
    }
}

/*
 *   "emit_string" adds a string to the code segment.
 *
 *   returns:  nothing
 */
void emit_string(char *value)                       // to insert
{
    int length = strlen(value);

    if (CI > MAX_CODE_SIZE - 1)
        runtime_error(M_CODE, M_SEGMENT, M_OVERFLOW, M_0);
    else
    {
        char *p = new char[length + 1];
        if (p)
        {
            Code_buffer[CI].string.ptr = p;
            Code_buffer[CI].string.len = length;
            Code_buffer[CI].string.sig = SIGNATURE;
            strcpy(Code_buffer[CI].string.ptr, value);
        }
        else
            runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

        CI++;
    }
}

/*
 *   "emit_code_label" adds a label offset value to the code segment
 *   label list.  The offset value is the current location of
 *   the code index.
 *
 *   returns:  nothing
 */
void emit_code_label(int number)                    // label number
{
    assert(number < MAX_LABELS);
    Code_label[number] = CI;                        // assign code index
}

/*
 *   "next_code_label" returns the next label number.
 *
 *   returns:  label number
 */
int next_code_label()
{
    Label_count++;

    if (Label_count > MAX_LABELS)
        compile_error(M_TOO, M_MANY, M_LABELS, M_0);

    return Label_count;
}

/*
 *   "emit_statement_marker" inserts debugging code to locate the
 *   current source line.
 *
 *   returns:  nothing
 */
void emit_statement_marker(char *file,              // source file name
                           int   line)              // source line number
{
    if (Debug_flag)                                 // only in debug mode
    {
        emit_operator(STATEMENT, NO_CODE, 0, line);
        emit_string(file);
    }
}

/*
 *   "emit_push_imm_char" generates code to push a character
 *   onto the runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_imm_char(char value)                 // value to push
{
    emit_operator(PUSH, IMM_8, 0, 0);
    emit_char(value);
}

/*
 *   "emit_push_imm_index" generates code to push an index value
 *   onto the runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_imm_index(int value)                 // value to push
{
    emit_operator(PUSH, IMM_16, 0, 0);
    emit_index(value);
}

/*
 *   "emit_push_imm_integer" generates code to push an integer onto the
 *   runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_imm_integer(long value)              // value to push
{
    emit_operator(PUSH, IMM_32, 0, 0);
    emit_integer(value);
}

/*
 *   "emit_push_imm_real" generates code to push a real value
 *   onto the runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_imm_real(double value)               // value to push
{
    emit_operator(PUSH, IMM_64, 0, 0);
    emit_real(value);
}

/*
 *   "emit_push_imm_string" generates code to push a string onto the
 *   runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_imm_string(char *value)              // value to push
{
    emit_operator(PUSH, IMM_STR, 0, 0);
    emit_string(value);
}

/*
 *   "emit_push_address" generates code to push an address
 *   onto the runtime stack.
 *
 *   returns:  nothing
 */
void emit_push_address(SYMTAB_NODE_PTR idp)         // of item
{
    int offset = find_offset(idp);
    int segment = find_segment(idp);

    if (idp->definition == VARPARM_DEFN)
        emit_operator(PUSH, ADDR_ADDR, segment, offset);
    else
        emit_operator(PUSH, ADDR, segment, offset);
}

/*
 *   "emit_mem_item" generates code to push or pop a declared item
 *   onto or from the runtime stack.
 *
 *   returns:  nothing
 */
void emit_mem_item(OPCODE code1,                    // push or pop
                   SYMTAB_NODE_PTR mem_idp,         // of id
                   TYPE_STRUCT_PTR mem_tp)          // of item
{
    OPCODE code2;
    TYPE_STRUCT_PTR tp = mem_idp->typep;

    if (tp == Null_typep)                           // source code error
        code2 = NO_CODE;
    else if (tp == Real_typep)
        code2 = MEM_64;
    else if (tp == Integer_typep)
        code2 = MEM_32;
    else if ((tp == Boolean_typep)||(tp->form == ENUM_FORM))
        code2 = MEM_16;
    else if (tp == Char_typep)
        code2 = MEM_8;
    else if (tp->form == STRING_FORM)
    {
        if (mem_tp == Char_typep)
            code2 = MEM_STR_8_xi;
        else
            code2 = MEM_STR;
    }
    else if ((tp->form == ARRAY_FORM )||
             (tp->form == RECORD_FORM)||
             (tp->form == UNION_FORM ))
    {
        if (mem_tp == Null_typep)                   // source code error
            code2 = NO_CODE;
        else if (mem_tp == Real_typep)
            code2 = MEM_64_xi;
        else if (mem_tp == Integer_typep)
            code2 = MEM_32_xi;
        else if ((mem_tp == Boolean_typep  )||
                 (mem_tp->form == ENUM_FORM))
            code2 = MEM_16_xi;
        else if (mem_tp == Char_typep)
            code2 = MEM_8_xi;
        else if (mem_tp->form == STRING_FORM)
            code2 = MEM_STR_xi;
        else
            assert(0);
    }
    else
        assert(0);

    int offset  = find_offset(mem_idp);
    int segment = find_segment(mem_idp);

    emit_operator(code1, code2, segment, offset);
}

/*
 *   "emit_var_item" generates code to push or pop a var parameter 
 *   onto or from the runtime stack
 *
 *   returns:  nothing
 */
void emit_var_item(OPCODE code1,                    // push or pop
                   SYMTAB_NODE_PTR var_idp,         // of id
                   TYPE_STRUCT_PTR var_tp )         // of item
{
    OPCODE code2;
    TYPE_STRUCT_PTR tp = var_idp->typep;

    if (tp == Null_typep)                           // source code error
        code2 = NO_CODE;
    else if (tp == Real_typep)
        code2 = PTR_64;
    else if (tp == Integer_typep)
        code2 = PTR_32;
    else if ((tp == Boolean_typep)||(tp->form == ENUM_FORM))
        code2 = PTR_16;
    else if (tp == Char_typep)
        code2 = PTR_8;
    else if (tp->form == STRING_FORM)
    {
        if (var_tp == Char_typep)
            code2 = PTR_STR_8_xi;
        else
            code2 = PTR_STR;
    }
    else if ((tp->form == ARRAY_FORM )||
             (tp->form == RECORD_FORM)||
             (tp->form == UNION_FORM ))
    {
        if (var_tp == Null_typep)                   // source code error
            code2 = NO_CODE;
        else if (var_tp == Real_typep)
            code2 = PTR_64_xi;
        else if (var_tp == Integer_typep)
            code2 = PTR_32_xi;
        else if ((var_tp == Boolean_typep)||(var_tp->form == ENUM_FORM))
            code2 = PTR_16_xi;
        else if (var_tp == Char_typep)
            code2 = PTR_8_xi;
        else if (var_tp->form == STRING_FORM)
            code2 = PTR_STR_xi;
        else
            assert(0);
    }
    else
        assert(0);

    int offset  = find_offset(var_idp);
    int segment = find_segment(var_idp);

    emit_operator(code1, code2, segment, offset);
}

/*
 *   "emit_return_value" generates code to return a value from a
 *   function
 *
 *   returns:  nothing
 */
void emit_return_value(SYMTAB_NODE_PTR rtne_idp)
{
    OPCODE code;
    TYPE_STRUCT_PTR tp = rtne_idp->typep;

    if (tp == Null_typep)                           // source code error
        code = NO_CODE;
    else if (tp == Real_typep)
        code = MEM_64;
    else if (tp == Integer_typep)
        code = MEM_32;
    else if ((tp == Boolean_typep)||(tp->form == ENUM_FORM))
        code = MEM_16;
    else if (tp == Char_typep)
        code = MEM_8;
    else if (tp->form == STRING_FORM)
        code = MEM_STR;
    else
        assert(0);

    int offset = - rtne_idp->routine.parm_count - 2;

    emit_operator(POP, code, 1, offset);
}

/*
 *   "find_offset" obtains the offset address of a stack or data item
 *   Stack items are relative to the value of the base pointer.  When
 *   a subrountine is called items are placed on the stack as shown:
 *
 *        local2         SP = BP + 2
 *        local1         SP = BP + 1
 *        old BP         SP = BP
 *        old SN, IP     SP = BP - 1
 *        arg2           SP = BP - 2
 *        arg1           SP = BP - 3
 *        retval         SP = BP - 4
 *
 *   When declared, formal parameters precede locals in the chain of
 *   identifiers starting at the subroutine's
 *
 *   returns:  offset value
 */
int find_offset(SYMTAB_NODE_PTR item_idp)           // of this item
{
    SYMTAB_NODE_PTR idp;
    int offset, parm_count;

    // search backward until a routine idp is found
    idp = item_idp;
    while ((idp->definition != MAIN_DEFN)&&
           (idp->definition != PROG_DEFN)&&
           (idp->definition != PROC_DEFN)&&
           (idp->definition != FUNC_DEFN))
        idp = idp->prev;

    parm_count = idp->routine.parm_count;           // formal parameters

    // count forward until the item's idp is found
    idp = idp->next;
    offset = 1;
    while (idp != item_idp)
    {
        if (idp->definition == VARPARM_DEFN)
            offset++;
        else
            offset += idp->typep->size;

        idp = idp->next;
    }

    if (offset > parm_count)                        // is a local
        offset = offset - parm_count;
    else                                            // is an argument
        offset = offset - parm_count - 2;

    return offset;
}

/*
 *   "find_segment" obtains the segment index number of the routine
 *   containing the stack or data item
 *
 *   returns:  segment index
 */
int find_segment(SYMTAB_NODE_PTR item_idp)          // of this item
{
    SYMTAB_NODE_PTR idp = item_idp->prev;

    // search backward until a routine idp is found
    while ((idp->definition != MAIN_DEFN) &&
           (idp->definition != PROG_DEFN) &&
           (idp->definition != PROC_DEFN) &&
           (idp->definition != FUNC_DEFN))
        idp = idp->prev;

    return idp->routine.segment;
}

/*
 *   "emit_alloc_data" emits code to push data onto stack
 *
 *   returns:  nothing
 */
void emit_alloc_data(SYMTAB_NODE_PTR idp)
{
    if (idp->typep->form == ARRAY_FORM)
        emit_alloc_array(idp->typep);
    else if (idp->typep->form == RECORD_FORM)
        emit_alloc_record(idp->typep);
    else if (idp->typep->form == UNION_FORM)
        emit_alloc_union(idp->typep);
    else if (idp->typep->form == STRING_FORM)
    {
        int length = idp->typep->array.max_index + 1; // zero based!

        if (Routine_flag)
            Temp_buffer[TI++].op.code1 = INC_sp_string;
        else
        {
            D(fprintf(d_out, "%4d  %s:str\n", Data_item, idp->name));

            if (Data_item > MAX_DATA_SIZE)
                runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);

            char *p = new char[length + 1];
            if (p)
            {
                DSeg[Data_item].string.ptr = p;
                DSeg[Data_item].string.len = length;
                DSeg[Data_item].string.sig = SIGNATURE;
            }
            else
                runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

            Data_item++;
        }
    }
    else
    {
        if (Routine_flag)
            Temp_buffer[TI++].op.code1 = INC_sp;
        else
        {
            D(fprintf(d_out, "%4d  %s\n", Data_item, idp->name));

            if (Data_item > MAX_DATA_SIZE)
                runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);
            
            Data_item++;
        }
    }
}

/*
 *   "emit_alloc_array" allocates memory for an array
 *
 *   returns:  next item number 
 */
void emit_alloc_array(TYPE_STRUCT_PTR tp)
{
    int index = 0;
    TYPE_STRUCT_PTR elmt_tp = tp->array.elmt_typep;
    assert(elmt_tp->size != 0);
    int size = tp->size / elmt_tp->size;

    while (size > 0)
    {
        D(if (!Routine_flag) fprintf(d_out, "%4d  (%d)\n", Data_item, index));

        if (elmt_tp->form == ARRAY_FORM)
            emit_alloc_array(elmt_tp);
        else if (elmt_tp->form == RECORD_FORM)
            emit_alloc_record(elmt_tp);
        else if (elmt_tp->form == UNION_FORM)
            emit_alloc_union(elmt_tp);
        else if (elmt_tp->form == STRING_FORM)
        {
            int length = elmt_tp->array.max_index + 1; // zero based!

            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp_string;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);
            
                char *p = new char[length + 1];
                if (p)
                {
                    DSeg[Data_item].string.ptr = p;
                    DSeg[Data_item].string.len = length;
                    DSeg[Data_item].string.sig = SIGNATURE;
                }
                else
                    runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

                Data_item++;
            }
        }
        else
        {
            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);
            
                Data_item++;
            }
        }

        index++;
        size--;
    }
}

/*
 *   "emit_alloc_record" allocates memory for a record
 *
 *   returns:  next item number
 */
void emit_alloc_record(TYPE_STRUCT_PTR tp)
{
    SYMTAB_NODE_PTR item_idp = tp->record_struct.field_symtab;

    while (item_idp != NULL)
    {
        D(if (!Routine_flag) fprintf(d_out, "%4d  .%s\n", Data_item, item_idp->name));

        if (item_idp->typep->form == ARRAY_FORM)
            emit_alloc_array(item_idp->typep);
        else if (item_idp->typep->form == RECORD_FORM)
            emit_alloc_record(item_idp->typep);
        else if (item_idp->typep->form == UNION_FORM)
            emit_alloc_union(item_idp->typep);
        else if (item_idp->typep->form == STRING_FORM)
        {
            int length = item_idp->typep->array.max_index + 1; // zero based

            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp_string;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);

                char *p = new char[length + 1];
                if (p)
                {
                    DSeg[Data_item].string.ptr = p;
                    DSeg[Data_item].string.len = length;
                    DSeg[Data_item].string.sig = SIGNATURE;
                }
                else
                    runtime_error(M_OUT, M_OF, M_MEMORY, M_0);

                Data_item++;
            }
        }
        else
        {
            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);

                Data_item++;
            }
        }

        item_idp = item_idp->next;
    }
}

/*
 *   "emit_alloc_union" allocates memory for a union
 *
 *   returns:  next item number
 */
void emit_alloc_union(TYPE_STRUCT_PTR tp)
{
    SYMTAB_NODE_PTR item_idp = tp->union_struct.field_symtab;

    while (item_idp != NULL)
    {
        D(if (!Routine_flag) fprintf(d_out, "%4d  .%s\n", Data_item, item_idp->name));

        if (item_idp->typep->form == ARRAY_FORM)
            emit_alloc_array(item_idp->typep);
        else if (item_idp->typep->form == RECORD_FORM)
            emit_alloc_record(item_idp->typep);
        else if (item_idp->typep->form == UNION_FORM)
            emit_alloc_union(item_idp->typep);
        else if (item_idp->typep->form == STRING_FORM)
        {
            int length = item_idp->typep->array.max_index + 1; // zero based!

            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp_string;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);

                char *p = new char[length + 1];
                if (p)
                {
                    DSeg[Data_item].string.ptr = p;
                    DSeg[Data_item].string.len = length;
                    DSeg[Data_item].string.sig = SIGNATURE;
                }
                else
                    runtime_error(M_OUT, M_OF, M_MEMORY, M_0);
            }
        }
        else
        {
            if (Routine_flag)
                Temp_buffer[TI++].op.code1 = INC_sp;
            else
            {
                if (Data_item > MAX_DATA_SIZE)
                    runtime_error(M_DATA, M_SEGMENT, M_OVERFLOW, M_0);
            }
        }

        item_idp = item_idp->next;
    }
    Data_item++;
}

/*
 *   "delete_data" emits code to delete data from the stack
 *
 *   returns:  nothing
 */
void delete_data(SYMTAB_NODE_PTR idp)
{
    if (idp->definition == VARPARM_DEFN)
        emit_operator(DEC_sp, NO_CODE, 0, 0);
    else if (idp->typep->form == ARRAY_FORM)
        delete_array(idp->typep);
    else if (idp->typep->form == RECORD_FORM)
        delete_record(idp->typep);
    else if (idp->typep->form == UNION_FORM)
        delete_union(idp->typep);
    else if (idp->typep->form == STRING_FORM)
        emit_operator(DEC_sp_string, NO_CODE, 0, 0);
    else
        emit_operator(DEC_sp, NO_CODE, 0, 0);
}

/*
 *   "delete_array" de-allocates memory for an array
 *
 *   returns:  next item number
 */
void delete_array(TYPE_STRUCT_PTR tp)
{
    TYPE_STRUCT_PTR elmt_tp = tp->array.elmt_typep;
    int size = tp->size / elmt_tp->size;

    while (size > 0)
    {
        if (elmt_tp->form == ARRAY_FORM)
            delete_array(elmt_tp);
        else if (elmt_tp->form == RECORD_FORM)
            delete_record(elmt_tp);
        else if (elmt_tp->form == UNION_FORM)
            delete_union(elmt_tp);
        else if (elmt_tp->form == STRING_FORM)
            emit_operator(DEC_sp_string, NO_CODE, 0, 0);
        else
            emit_operator(DEC_sp, NO_CODE, 0, 0);

        size--;
    }
}

/*
 *   "delete_record" de-allocates memory for a record
 *
 *   returns:  next item number
 */
void delete_record(TYPE_STRUCT_PTR tp)
{
    SYMTAB_NODE_PTR item_idp = tp->record_struct.field_symtab;

    while (item_idp != NULL)
    {
        if (item_idp->typep->form == ARRAY_FORM)
            delete_array(item_idp->typep);
        else if (item_idp->typep->form == RECORD_FORM)
            delete_record(item_idp->typep);
        else if (item_idp->typep->form == UNION_FORM)
            delete_union(item_idp->typep);
        else if (item_idp->typep->form == STRING_FORM)
            emit_operator(DEC_sp_string, NO_CODE, 0, 0);
        else
            emit_operator(DEC_sp, NO_CODE, 0, 0);

        item_idp = item_idp->next;
    }
}

/*
 *   "delete_union" de-allocates memory for a union
 *
 *   returns:  next item number
 */
void delete_union(TYPE_STRUCT_PTR tp)
{
    SYMTAB_NODE_PTR item_idp = tp->union_struct.field_symtab;

    while (item_idp != NULL)
    {
        if (item_idp->typep->form == ARRAY_FORM)
            delete_array(item_idp->typep);
        else if (item_idp->typep->form == RECORD_FORM)
            delete_record(item_idp->typep);
        else if (item_idp->typep->form == UNION_FORM)
            delete_union(item_idp->typep);
        else if (item_idp->typep->form == STRING_FORM)
            emit_operator(DEC_sp_string, NO_CODE, 0, 0);
        else
            emit_operator(DEC_sp, NO_CODE, 0, 0);

        item_idp = item_idp->next;
    }
}

#ifdef DEBUG

/*
 *   array of strings must match enumerated opcodes defined
 *   in tpl_data.h
 */
char *Op[] = {
   "NO_CODE", "STATEMENT", "EXITZ", "SKIP", "UNSKIP",
   "PUSH", "POP", "REG_BP", "ADDR", "ADDR_ADDR",
   "IMM_64", "IMM_32", "IMM_16", "IMM_8", "IMM_STR",
   "MEM_64", "MEM_32", "MEM_16", "MEM_8", "MEM_STR",
   "MEM_64_xi", "MEM_32_xi", "MEM_16_xi", "MEM_8_xi",
   "MEM_STR_8_xi", "MEM_STR_xi",
   "PTR_64", "PTR_32", "PTR_16", "PTR_8", "PTR_STR",
   "PTR_64_xi", "PTR_32_xi", "PTR_16_xi", "PTR_8_xi",
   "PTR_STR_8_xi", "PTR_STR_xi",
   "INC_sp", "INC_sp_string", "DEC_sp", "DEC_sp_string",
   "ADD_xi_offset", "ADD_xi_imm",
   "MOV_ax_imm", "MOV_bx_imm",
   "MOV_bp_sp",
   "PUT_str", "GET_str", "GET_item", 
   "FORMAT_STR", "FORMAT_CHR", "FORMAT_INDEX", 
   "SET_file_ptr", "SET_stdin", "SET_stdout", "FLUSH_stdin",
   "RMUL", "RDIV", "RADD", "RSUB", "RNEG", "RPOW",
   "IMUL", "IDIV", "IADD", "ISUB", "INEG", "IPOW", "IMOD",
   "STRCAT", 
   "TEST_INDEX", "TEST_NUMBER", "TEST_STRING", "TEST_CHAR",
   "TEST_EQ", "TEST_NE", "TEST_GT", "TEST_GE", "TEST_LT", "TEST_LE",
   "LOGIC_OR", "LOGIC_AND", "LOGIC_NOT",
   "LOGIC_NOR", "LOGIC_NAND", "LOGIC_XOR",
   "JMP", "JNZ", "JZ",
   "CALL", "RETF", "CALL_stnd", "RETP",
   "SF_ARCCOS", "SF_ARCSIN", "SF_ARCTAN", "SF_COS", "SF_COSH",
   "SP_CURSOR", "SF_GETKEY",
   "SF_EXP", "SF_GETEXP", "SF_LN", "SF_LOG2", "SF_LOG10",
   "SF_SIN", "SF_SINH", "SF_SQRT",
   "SF_TAN", "SF_TANH",
   "SF_ABS", "SF_ARCTANXY",
   "SF_CEIL", "SF_FLOOR", "SF_ROUND", "SF_SIGN",
   "SF_CHR", "SF_CLOSE", "SF_EOFF",
   "SF_EREALSTR", "SF_FREALSTR",
   "SF_INDEX", "SF_INTREAL", "SF_INTSTR", "SF_LENGTH", "SP_LOCATE",
   "SF_ORD", "SF_MAX", "SF_MIN", "SF_OPEN", 
   "SP_PUTCH", "SP_PUTSTR", "SP_PUTLINE", "SP_PUTPIXEL",
   "SF_PRED", "SF_SUCC",
   "SF_RAND", "SF_RANDINT", "SP_RANDOMIZE", "SP_RANDSEED",
   "SF_REALSTR", "SF_REPEAT", 
   "SP_SCROLL", "SF_SETEXP", "SP_SETVIDEO", "SF_STRINT", "SF_STRREAL",
   "SF_VIDEOMODE", "SF_VIDEOTYPE",
   "SP_WATCH"
};

/*
 *   "list_segment" decodes instructions for debugging
 *
 *   returns:  nothing
 */
void list_segment(SYMTAB_NODE_PTR idp)
{
    char byte;
    int snum, iptr = 0;
    int segment, offset, index;
    long integer;
    double real;
    char string[64];
    OPCODE op;

    snum = idp->routine.segment;
    fprintf(c_out, "begin: \"%s\" cseg: %d\n", idp->name, snum);

    op = CSeg[snum][iptr].op.code1;                 // first instruction

    while (op != NO_CODE)                           // end of segment
    {
        fprintf(c_out, "%3d ", iptr);               // item

        switch (op)
        {
        case STATEMENT:
            index = CSeg[snum][iptr].op.offset;
            iptr++;
            strcpy(string, CSeg[snum][iptr].string.ptr);
            fprintf(c_out,
                     "%s file: %s line: %d\n",
                     Op[op], string, index);
            break;

        case PUSH:
            fprintf(c_out, "%s ", Op[op]);
            op = CSeg[snum][iptr].op.code2;
            switch (op)
            {
            case REG_BP:
                fprintf(c_out, "%s\n", Op[op]);
                break;

            case IMM_64:
                iptr++;
                real = CSeg[snum][iptr].real;
                fprintf(c_out, "%s val: %lg\n", Op[op], real);
                break;

            case IMM_32:
                iptr++;
                integer = CSeg[snum][iptr].integer;
                fprintf(c_out, "%s val: %ld\n", Op[op], integer);
                break;

            case IMM_16:
                iptr++;
                index = CSeg[snum][iptr].index;
                fprintf(c_out, "%s val: %d\n", Op[op], index);
                break;

            case IMM_8:
                iptr++;
                byte = CSeg[snum][iptr].byte;
                fprintf(c_out, "%s val: %c\n", Op[op], byte);
                break;

            case IMM_STR:
                iptr++;
                index = CSeg[snum][iptr].string.len;
                strcpy(string, CSeg[snum][iptr].string.ptr);
                if (string[0] == '\n') string[0] = 25;
                fprintf(c_out, "%s len: %d str: %s\n", Op[op], index, string);
                break;

            case ADDR:
            case ADDR_ADDR:
            case MEM_64:
            case MEM_32:
            case MEM_16:
            case MEM_8:
            case MEM_STR:
            case MEM_64_xi:
            case MEM_32_xi:
            case MEM_16_xi:
            case MEM_8_xi:
            case MEM_STR_8_xi:
            case MEM_STR_xi:
            case PTR_64:
            case PTR_32:
            case PTR_16:
            case PTR_8:
            case PTR_STR:
            case PTR_64_xi:
            case PTR_32_xi:
            case PTR_16_xi:
            case PTR_8_xi:
            case PTR_STR_8_xi:
            case PTR_STR_xi:
                segment = CSeg[snum][iptr].op.segment;
                offset  = CSeg[snum][iptr].op.offset;
                fprintf(c_out, "%s dseg: %d off: %d\n", Op[op], segment, offset);
                break;
            }
            break;

        case POP:
            fprintf(c_out, "%s ", Op[op]);
            op = CSeg[snum][iptr].op.code2;
            switch (op)
            {
            case REG_BP:
                fprintf(c_out, "%s\n", Op[op]);
                break;

            case MEM_64:
            case MEM_32:
            case MEM_16:
            case MEM_8:
            case MEM_STR:
            case MEM_64_xi:
            case MEM_32_xi:
            case MEM_16_xi:
            case MEM_8_xi:
            case MEM_STR_8_xi:
            case MEM_STR_xi:
            case PTR_64:
            case PTR_32:
            case PTR_16:
            case PTR_8:
            case PTR_STR:
            case PTR_64_xi:
            case PTR_32_xi:
            case PTR_16_xi:
            case PTR_8_xi:
            case PTR_STR_8_xi:
            case PTR_STR_xi:
                segment = CSeg[snum][iptr].op.segment;
                offset  = CSeg[snum][iptr].op.offset;
                fprintf(c_out, "%s dseg: %d off: %d\n", Op[op], segment, offset);
                break;
            }
            break;

        case CALL:
            segment = CSeg[snum][iptr].op.segment;
            fprintf(c_out, "%s cseg: %d\n", Op[op], segment);
            break;

        case EXITZ:
        case SKIP:
        case UNSKIP:
        case MOV_bp_sp:
        case RETF:
        case RETP:
        case INC_sp:
        case INC_sp_string:
        case DEC_sp:
        case DEC_sp_string:
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case ADD_xi_offset:
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case ADD_xi_imm:
        case MOV_ax_imm:
        case MOV_bx_imm:
            offset = CSeg[snum][iptr].op.offset;
            fprintf(c_out, "%s val: %d\n", Op[op], offset);
            break;

        case PUT_str:
        case GET_str:
        case GET_item:
        case FORMAT_STR:
        case FORMAT_CHR:
        case FORMAT_INDEX:
        case SET_file_ptr:
        case SET_stdin:
        case SET_stdout:
        case FLUSH_stdin:
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case RMUL:
        case RDIV:
        case RADD:
        case RSUB:
        case RNEG:
        case RPOW:
        case IMUL:
        case IDIV:
        case IADD:
        case ISUB:
        case INEG:
        case IPOW:
        case IMOD:
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case STRCAT:
            fprintf(c_out, "%s ", Op[op]);
            op = CSeg[snum][iptr].op.code2;
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case TEST_NUMBER:
        case TEST_INDEX:
        case TEST_STRING:
        case TEST_CHAR:
            fprintf(c_out, "%s ", Op[op]);
            op = CSeg[snum][iptr].op.code2;
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case LOGIC_NOT:
        case LOGIC_OR:
        case LOGIC_AND:
        case LOGIC_NOR:
        case LOGIC_NAND:
        case LOGIC_XOR:
            fprintf(c_out, "%s\n", Op[op]);
            break;

        case JMP:
        case JNZ:
        case JZ:
            offset = CSeg[snum][iptr].op.offset;
            fprintf(c_out, "%s loc: %d\n", Op[op], offset);
            break;

        case CALL_stnd:
            fprintf(c_out, "%s ", Op[op]);
            op = CSeg[snum][iptr].op.code2;
            fprintf(c_out, "%s\n", Op[op]);
            break;

        default:
            exit_interpreter();
            break;
        }
        iptr++;
        op = CSeg[snum][iptr].op.code1;
    }

    fprintf(c_out, "memory available: %lu bytes\n", (unsigned long) coreleft());
    fprintf(c_out, "end: \"%s\" cseg: %d\n\n", idp->name, snum);
}

#endif

| home | contents | previous | next page | send comment | send link | add bookmark |

Copyright © 2004, Stephen R. Schmitt