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

PRS_DECL.CPP

declarations

/*-------------------------------------------------------------------*
     Declaration Parser

     File:     prs_decl.cpp

     Module:   parser

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

#include "tpl_data.h"
#include <assert.h>
#include <stdlib.h>
#include <values.h>

/*
 *   External variables
 */
       /* in scn_main.cpp */
extern token_struct Token;
extern TOKEN_CODE Stmt_start_list[];
extern TOKEN_CODE Stmt_end_list[];
extern TOKEN_CODE Decl_start_list[];
extern TOKEN_CODE Follow_dimension_list[];

       /* in sym_tabl.cpp */
extern int Scope;
extern SYMTAB_NODE_PTR Symbol_table[];
extern TYPE_STRUCT_PTR Integer_typep, Real_typep,
                       Boolean_typep, Char_typep,
                       String_typep,  Null_typep;
       /* in exc_util */
extern bool Routine_flag;

/*
 *   Global declarations
 */
SYMTAB_NODE_PTR Last_rtne_idp;
int Int_stack[MAX_STACK_SIZE];
int Tos;

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

/*
 *   "declaration" calls routines to parse declarations
 *
 *   returns:  nothing
 */
void declaration()
{
    switch (Token.code)
    {
    case CONST:
        const_definition();                         // and get next token
        break;

    case VAR:
        var_declaration();                          // and get next token
        break;

    case TYPE:
        type_definition();                          // and get next token
        break;

    case LABEL:
        label_declaration();                        // and get next token
        break;

    default:
        assert(0);
        break;
    }
}

/*
 *   "const_definition" process:
 *
 *          const <id> : <type spec> := <expn>
 *
 *   returns:  nothing
 */
void const_definition()
{
    SYMTAB_NODE_PTR idp;                            // for id node creation
    TYPE_STRUCT_PTR expr_tp;

    get_token();                                    // after "const"

    if (Token.code != ID_TOKEN)
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        return;
    }

    idp = lookup(Token.lexeme, Symbol_table[Scope]);
    if (idp == NULL)
    {
        idp = insert(Token.lexeme, &Symbol_table[Scope]);
        idp->definition = CONST_DEFN;
        idp->typep = Null_typep;

        Last_rtne_idp->next = idp;
        idp->prev = Last_rtne_idp;
        Last_rtne_idp = idp;
    }
    else
        compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

    get_token();                                    // after <id>

    if (Token.code == COLON)
    {
        get_token();                                // after ":"
        idp->typep = do_type();                     // and get next token
        if (!Routine_flag)
            emit_alloc_data(idp);                   // add data item

        if_code_get_token_else_error(ASSIGN);

        emit_statement_marker(Token.file, Token.line);

        if (idp->typep == Integer_typep)
        {
            Tos = 0;                                // initialize int stack
            expr_tp = int_expression();             // evaluate integer
            idp->integer = pop_int_stack();         // get integer value
            emit_push_imm_integer(idp->integer);
        }
        else
            expr_tp = expression();                 // add expression code

        if (!assign_type_compatible(idp->typep, expr_tp))
            compile_error(M_INVALID, M_ASSIGNMENT, M_0);
        else
        {
            emit_mem_item(POP, idp, idp->typep);
            idp->initialized = true;
        }
    }
    else
    {
        compile_error(M_MISSING, M_COLON, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
    }
}

/*
 *   "var_declaration" processes:
 *
 *          var <id> {, <id> } : <type spec> [:= <expn>]
 *
 *   returns:  nothing
 */
void var_declaration()
{
    SYMTAB_NODE_PTR idp, first_idp, last_idp;       // for id node creation
    TYPE_STRUCT_PTR expr_tp;                        // also for id nodes
    bool initialize_flag;                           // if true emit code

    // loop to process list of <id>, each of same type
    first_idp = NULL;
    initialize_flag = false;                        // default

    get_token();                                    // after "var"

    if (Token.code != ID_TOKEN)
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        return;
    }

    while (Token.code == ID_TOKEN)
    {
        idp = lookup(Token.lexeme, Symbol_table[Scope]);

        if (idp == NULL)
        {
            idp = insert(Token.lexeme, &Symbol_table[Scope]);
            idp->definition = VAR_DEFN;
            idp->typep = Null_typep;                // prevent errors

            // link <id>s together
            if (first_idp == NULL)
            {
                Last_rtne_idp->next = idp;          // previous declaration
                idp->prev = Last_rtne_idp;

                first_idp = idp;
                last_idp = idp;
            }
            else
            {
                last_idp->next = idp;
                idp->prev = last_idp;
                last_idp = idp;
            }
        }
        else
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

        get_token();                                // after <id>

        if (Token.code == COMMA)
            get_token();                            // after ","
    }

    Last_rtne_idp = idp;                            // for next declaration

    // type pointer is assigned to first_idp and copied later
    // to the other idp's
    if (Token.code == COLON)
    {
        get_token();                                // after ":"
        first_idp->typep = do_type();               // and get next token
        if (!Routine_flag)
        {
            emit_alloc_data(first_idp);             // add data item
            first_idp->initialized = true;          // no check of globals
        }

        if (Token.code == ASSIGN)
        {
            initialize_flag = true;
            get_token();                            // after ":="
            emit_statement_marker(Token.file, Token.line);

            expr_tp = expression();                 // add expression code

            if (!assign_type_compatible(first_idp->typep, expr_tp))
                compile_error(M_INVALID, M_ASSIGNMENT, M_0);
            else
            {
                emit_mem_item(POP, first_idp, first_idp->typep);
                first_idp->initialized = true;
            }
        }
    }
    else
    {
        compile_error(M_MISSING, M_COLON, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        return;
    }

    // copy first_idp type to all other variables in the list
    // and, if initialized, emit additional code
    for (idp = first_idp->next; idp != NULL; idp = idp->next)
    {
        idp->definition = first_idp->definition;
        idp->typep = first_idp->typep;
        idp->initialized = first_idp->initialized;

        if (!Routine_flag)
            emit_alloc_data(idp);                   // add data item

        if (initialize_flag == true)
        {
            // emit code to perform an assignment
            // to the other identifiers
            emit_statement_marker(Token.file, Token.line);
            emit_mem_item(PUSH, first_idp, first_idp->typep);
            emit_mem_item(POP, idp, idp->typep);
        }
    }
}

/*
 *   "type_definition" process:
 *
 *          type <id> : <type spec>
 *
 *   returns:  nothing
 */
void type_definition()
{
    SYMTAB_NODE_PTR idp;                            // for id node creation

    get_token();                                    // after "type"

    if (Token.code == ID_TOKEN)
    {
        idp = lookup(Token.lexeme, Symbol_table[Scope]);
        if (idp == NULL)                            // create a new type definition
        {
            idp = insert(Token.lexeme, &Symbol_table[Scope]);
            idp->definition = TYPE_DEFN;
        }
        else
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

        get_token();                                // after <id>

        if_code_get_token_else_error(COLON);

        idp->typep = do_type();                     // and get next token

        if (idp->typep->type_idp == NULL)
            idp->typep->type_idp = idp;
    }
    else
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
    }
}

/*
 *   "label_declaration" processes:
 *
 *          label <id> :
 *
 *   returns:  nothing
 */
void label_declaration()
{
    SYMTAB_NODE_PTR idp;

    get_token();                                    // after "label"

    if (Token.code != ID_TOKEN)
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        return;
    }

    idp = lookup(Token.lexeme, Symbol_table[Scope]);

    if (idp == NULL)
    {
        idp = insert(Token.lexeme, &Symbol_table[Scope]);
        idp->definition = LABEL_DEFN;
        idp->typep = Null_typep;
        idp->integer = next_code_label();
    }
    else
        compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

    get_token();                                    // after <id>
    if_code_get_token_else_error(COLON);
}

/*
 *   "do_type" processes type specifications by calling the
 *   appropriate procedure to create a type structure; the next
 *   global "Token" is obtained from the source file
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR do_type()
{
    SYMTAB_NODE_PTR idp;
    TYPE_STRUCT_PTR tp;

    switch (Token.code)
    {
    case ID_TOKEN:
        idp = search_symbol_tables(Token.lexeme);
        if (idp == NULL)
        {
            compile_error(M_UNDEFINED, M_IDENTIFIER, M_0);
            get_token();
            tp = Null_typep;
        }
        else if (idp->definition == TYPE_DEFN)
        {
            tp = named_type(idp);
        }
        else
        {
            compile_error(M_NOT, M_TYPE, M_IDENTIFIER, M_0);
            get_token();
            tp = Null_typep;
        }
        break;

    case CHAR: 
        get_token();                                // after "char"
        tp = Char_typep;
        break;

    case INT: 
        get_token();                                // after "int"
        tp = Integer_typep;
        break;

    case REAL: 
        get_token();                                // after "real"
        tp = Real_typep;
        break;

    case BOOLEAN: 
        get_token();                                // after "boolean"
        tp = Boolean_typep;
        break;

    case STRING: 
        tp = string_type();
        break;

    case ENUM: 
        tp = enumeration_type();
        break;

    case ARRAY: 
        tp = array_type();
        break;

    case RECORD:
        tp = record_type();
        break;

    case UNION:
        tp = union_type();
        break;

    default:
        compile_error(M_INVALID, M_TYPE, M_0);
        tp = Null_typep;
    }
    
    return tp;
}

/*
 *   "named_type" processes an identifier of a named type and returns
 *   a pointer to its type structure
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR named_type(SYMTAB_NODE_PTR idp)     // of type
{
    TYPE_STRUCT_PTR named_tp;                       // return value

    named_tp = idp->typep;
    get_token();                                    // after <id>

    return named_tp;
}

/*
 *   "string_type" processes:
 *
 *          string[(<expn>)]
 *
 *   by parsing it, creating a type structure, and returning a pointer
 *   to it
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR string_type()
{
    TYPE_STRUCT_PTR string_tp;                      // return value
    TYPE_STRUCT_PTR expr_tp;                        // of length
    int length;                                     // of string

    get_token();                                    // after "string"

    if (Token.code == L_PAREN)
    {
        get_token();                                // after "("

        Tos = 0;                                    // initialize int stack
        expr_tp = int_expression();                 // evaluate index

        if (expr_tp == Integer_typep)         
            length = pop_int_stack();
        else
            compile_error(M_INVALID, M_TYPE, M_0);     

        if (length <= MAX_STRING_LENGTH)
            string_tp = make_string_type_ptr(length);
        else
        {
            string_tp = String_typep;
            compile_error(M_INTEGER, M_OUT, M_OF, M_RANGE, M_0);
        }

        if_code_get_token_else_error(R_PAREN);
    }
    else
        string_tp = String_typep;

    return string_tp;
}

/*
 *   "enumeration_type" processes:
 *
 *          enum(<id> {, <id> })
 *
 *   by parsing it, creating a type structure, and returning a pointer
 *   to it
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR enumeration_type()
{
    SYMTAB_NODE_PTR idp, last_idp;                  // for <id>'s
    TYPE_STRUCT_PTR enum_tp;                        // return value
    int enum_value;                                 // values for <id>'s

    enum_tp = alloc_type_struct();
    enum_tp->form = ENUM_FORM;
    enum_tp->size = 1;
    enum_tp->type_idp = NULL;
    enum_tp->enumeration.field_symtab = NULL;

    get_token();                                    // after "enum"

    if_code_get_token_else_error(L_PAREN);

    enum_value = 0;
    last_idp = NULL;

    // loop to process list of identifiers
    while (Token.code == ID_TOKEN)
    {
        idp = lookup(Token.lexeme, enum_tp->enumeration.field_symtab);
        if (idp == NULL)
            idp = insert(Token.lexeme, &enum_tp->enumeration.field_symtab);
        else
            compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

        idp->typep = enum_tp;
        idp->definition = CONST_DEFN;
        idp->integer = enum_value;
        idp->initialized = true;

        enum_value++;                               // of next item

        // link constant id's together
        if (last_idp == NULL)
        {
            last_idp = idp;
            enum_tp->enumeration.first_idp = last_idp;
        }
        else
        {
            last_idp->next = idp;
            last_idp = idp;
        }

        get_token();                                // after <id>
        if (Token.code == COMMA)
            get_token();                            // after ","
    }

    if_code_get_token_else_error(R_PAREN);
    enum_tp->enumeration.max = enum_value - 1;

    return enum_tp;
}

/*
 *   "array_type" processes:
 *
 *          array(<index size> {, <index size> }) of <type spec>
 *
 *   by parsing it, creating a type structure and returning a pointer
 *   to it
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR array_type()
{
    TYPE_STRUCT_PTR array_tp, next_tp, tp;
    int index_size, elements, element_size, array_storage_size;

    tp = alloc_type_struct();
    array_tp = tp;                                  // save first type ptr
    elements = 1;                                   // at least 1
    get_token();                                    // after "array"

    if (Token.code != L_PAREN)
    {
        compile_error(M_MISSING, M_LPAREN, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        goto array_type_exit;
    }

    do 
    {
        get_token();                                // after "(" or ","
        elements = elements * get_array_index(tp);

        // chain indices together
        if (Token.code == COMMA)
        {
            next_tp = alloc_type_struct();
            tp->array.next_indexp = next_tp;
            tp = next_tp;
        }
    }
    while (Token.code == COMMA);

    if_code_get_token_else_error(R_PAREN);
    if_code_get_token_else_error(OF);

    array_tp->array.elmt_typep = do_type();         // and get next token

    element_size = array_tp->array.elmt_typep->size;
    array_storage_size = elements * element_size;
    array_tp->size = array_storage_size;

    if (array_storage_size > MAX_ARRAY_SIZE)
        compile_error(M_ARRAY, M_TOO, M_LARGE, M_0);

    // set index values for use in calculating memory offsets for
    // array elements; last index should have value 1
    tp = array_tp;
    while (tp != NULL)
    {
        index_size = tp->array.max_index + 1;       // zero based indices
        array_storage_size = array_storage_size / index_size;
        tp->array.val_index = array_storage_size;
        tp = tp->array.next_indexp;
    }

array_type_exit:
    return array_tp;
}

/*
 *   "get_array_index" processes the size of an array index
 *
 *   returns:  the size of the index
 */
int get_array_index(TYPE_STRUCT_PTR tp)             // of array index
{
    int size = 1;                                   // index size
    TYPE_STRUCT_PTR expr_tp;                        // of index

    Tos = 0;                                        // initialize int stack
    expr_tp = int_expression();                     // evaluate index

    if (expr_tp == Integer_typep)         
        size = pop_int_stack();
    else
        compile_error(M_INVALID, M_TYPE, M_0);     

    if ((size < 1) || (size > MAX_ARRAY_SIZE))
    {
        compile_error(M_INTEGER, M_OUT, M_OF, M_RANGE, M_0);
        size = 1;                                   // avoid division error
    }

    tp->form = ARRAY_FORM;
    tp->type_idp = NULL;
    tp->array.next_indexp = NULL;
    tp->array.max_index = size - 1;

    return size;
}

/*
 *   "record_type" processes:
 *
 *          record
 *            id {, id }:typeSpec
 *          { id {, id }:typeSpec }
 *          end record
 *
 *   by parsing it, creating a type structure and returning a pointer
 *   to it
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR record_type()
{
    TYPE_STRUCT_PTR record_tp;

    record_tp = alloc_type_struct();
    record_tp->form = RECORD_FORM;
    record_tp->size = 1;                            // to avoid error
    record_tp->type_idp = NULL;
    record_tp->record_struct.field_symtab = NULL;

    get_token();                                    // after "record"
    if (Token.code != ID_TOKEN)
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
    }
    else
        get_record_fields(record_tp);

    if_code_get_token_else_error(END);
    if_code_get_token_else_error(RECORD);

    return record_tp;
}

/*
 *   "get_record_fields" processes record field definitions.
 *
 *   returns:  nothing
 */
void get_record_fields(TYPE_STRUCT_PTR record_tp)   // of record
{
    SYMTAB_NODE_PTR idp, first_idp, last_idp;       // field idps
    SYMTAB_NODE_PTR prev_last_idp = NULL;           // last id of list
    TYPE_STRUCT_PTR tp;                             // of field
    int size;                                       // of field
    int offset = 0;

    // loop to process sublists, each of a type
    while (Token.code == ID_TOKEN)
    {
        first_idp = NULL;

        // loop to process each variable or field id in a sublist
        while (Token.code == ID_TOKEN)
        {
            idp = lookup(Token.lexeme, record_tp->record_struct.field_symtab);
            if (idp == NULL)
                idp = insert(Token.lexeme, &record_tp->record_struct.field_symtab);
            else
                compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

            idp->definition = FIELD_DEFN;

            // link ids together into a sublist
            if (first_idp == NULL)
            {
                last_idp = idp;
                first_idp = idp;
            }
            else
            {
                last_idp->next = idp;
                last_idp = idp;
            }

            get_token();                            // after <id>
            if (Token.code == COMMA)
                get_token();                        // after ","
        }

        // process the sublist's type
        if (Token.code == COLON)
        {
            get_token();                            // after ":"
            tp = do_type();                         // and get next token
            size = tp->size;
        }
        else
            compile_error(M_MISSING, M_COLON, M_0);

        // assign the offset and type to all fields in the sublist
        for (idp = first_idp; idp != NULL; idp = idp->next)
        {
            idp->typep = tp;
            idp->data_offset = offset;
            offset += size;
        }

        // link this sublist to the previous sublist
        if (prev_last_idp != NULL)
            prev_last_idp->next = first_idp;

        prev_last_idp = last_idp;

        // error synchronization
        if ((!token_in(Stmt_start_list))&&
            (!token_in(Decl_start_list))&&
            (!token_in(Stmt_end_list  )))
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        }
    }
    record_tp->size = offset;
}

/*
 *   "union_type" processes:
 *
 *          union
 *            id {, id }:typeSpec
 *          { id {, id }:typeSpec }
 *          end union
 *
 *   by parsing it, creating a type structure and returning a pointer
 *   to it
 *
 *   returns:  a pointer to the type structure
 */
TYPE_STRUCT_PTR union_type()
{
    TYPE_STRUCT_PTR union_tp;

    union_tp = alloc_type_struct();
    union_tp->form = UNION_FORM;
    union_tp->size = 1;                             // to avoid error
    union_tp->type_idp = NULL;
    union_tp->union_struct.field_symtab = NULL;

    get_token();                                    // after "union"

    if (Token.code != ID_TOKEN)
    {
        compile_error(M_MISSING, M_IDENTIFIER, M_0);
        synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
    }
    else
        get_union_fields(union_tp);

    if_code_get_token_else_error(END);
    if_code_get_token_else_error(UNION);

    return union_tp;
}

/*
 *   "get_union_fields" processes union field definitions.
 *
 *   returns:  nothing
 */
void get_union_fields(TYPE_STRUCT_PTR union_tp)     // of union
{
    SYMTAB_NODE_PTR idp, first_idp, last_idp;       // field idps
    SYMTAB_NODE_PTR prev_last_idp = NULL;           // last id of list
    TYPE_STRUCT_PTR tp;                             // of field
    int size = 0;                                   // of field
    int offset = 0;                                 // of field

    // loop to process sublists, each of a type
    while (Token.code == ID_TOKEN)
    {
        first_idp = NULL;

        // loop to process each variable or field id in a sublist
        while (Token.code == ID_TOKEN)
        {
            idp = lookup(Token.lexeme, union_tp->union_struct.field_symtab);
            if (idp == NULL)
                idp = insert(Token.lexeme, &union_tp->union_struct.field_symtab);
            else
                compile_error(M_REDEFINED, M_IDENTIFIER, M_0);

            idp->definition = FIELD_DEFN;

            // link ids together into a sublist
            if (first_idp == NULL)
            {
                last_idp = idp;
                first_idp = idp;
            }
            else
            {
                last_idp->next = idp;
                last_idp = idp;
            }

            get_token();                            // after <id>
            if (Token.code == COMMA)
                get_token();                        // after ","
        }

        // process the sublist's type
        if (Token.code == COLON)
        {
            get_token();                            // after ":"
            tp = do_type();                         // and get next token
            if (tp->size > size)                    // size of union
                size = tp->size;
        }
        else
            compile_error(M_MISSING, M_COLON, M_0);

        // assign the offset and type to all fields in the sublist
        for (idp = first_idp; idp != NULL; idp = idp->next)
        {
            idp->typep = tp;
            idp->data_offset = offset;
        }

        // link this sublist to the previous sublist
        if (prev_last_idp != NULL)
            prev_last_idp->next = first_idp;

        prev_last_idp = last_idp;

        // error synchronization
        if ((!token_in(Stmt_start_list))&&
            (!token_in(Decl_start_list))&&
            (!token_in(Stmt_end_list  )))
        {
            compile_error(M_SYNTAX, M_ERROR, M_0);
            synchronize(Stmt_start_list, Decl_start_list, Stmt_end_list);
        }
    }
    union_tp->size = size;
}

/*
 *   "push_int_stack" puts an integer on top of the integer stack
 *
 *   returns:  nothing
 */
void push_int_stack(int value)                      // the integer
{
    Tos++;
    if ((Tos > 0)&&(Tos < MAX_STACK_SIZE))
        Int_stack[Tos] = value;
}

/*
 *   "pop_int_stack" returns an integer from the top of the integer
 *   stack
 *
 *   returns:  the integer
 */
int pop_int_stack()
{
    int value;

    value = Int_stack[Tos];
    Tos--;
    return value;
}

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

Copyright © 2004, Stephen R. Schmitt