/* l2xidecl.c LTX2X interpreter parsing routines for declarations */ /* Written by: Peter Wilson, CUA pwilson@cme.nist.gov */ /* This code is partly based on algorithms presented by Ronald Mak in */ /* "Writing Compilers & Interpreters", John Wiley & Sons, 1991 */ #include #include "l2xicmon.h" #include "l2xierr.h" #include "l2xiscan.h" #include "l2xisymt.h" #include "l2xiprse.h" #include "l2xiidbg.h" #ifndef l2xicpr_h #include "l2xicpr.h" #endif #include "listsetc.h" /* EXTERNALS */ extern TOKEN_CODE token; extern char word_string[]; extern LITERAL literal; extern SYMTAB_NODE_PTR symtab_display[]; extern int level; extern SYMTAB_NODE_PTR string_idp; /* FORWARDS */ TYPE_STRUCT_PTR identifier_type(), enumeration_type(), subrange_type(), array_type(); TYPE_STRUCT_PTR get_type(), get_array_type(), get_bound_spec_type(); TYPE_STRUCT_PTR an_entity(), a_type(), get_bls_type(); TOKEN_CODE express_decl_list[] = {XENTITY, TYPE, XRULE, FUNCTION, PROCEDURE, 0}; /***************************************************************************/ /* declarations(rtn_idp) Call routines to process constant definitions, */ /* type definitions, variable declarations, */ /* procedure definitions, function definitions. */ /* at entry, token is one of declaration_start_list bag */ /* at exit, token is the one following all declarations (e.g., start */ /* of assignment statement) */ declarations(rtn_idp) SYMTAB_NODE_PTR rtn_idp; /* program or routine id */ { entry_debug("declarations"); /* for EXPRESS */ /* loop for general declarations */ while (token_in(express_decl_list)) { switch (token) { case XENTITY: { an_entity(); break; } case TYPE: { a_type(); break; } case XRULE: { a_rule(); break; } case PROCEDURE: { a_procedure(); break; } case FUNCTION: { a_function(); break; } default: { error(UNIMPLEMENTED_FEATURE); break; } } /* end switch */ } /* end while over general declarations */ if (token == XCONSTANT) { get_token(); constant_block(); } if (token == XLOCAL) { get_token(); local_block(rtn_idp); } exit_debug("declarations"); return; } /* end declarations */ /***************************************************************************/ /***************************************************************************/ /* skip_declarations(rtn_idp) Skip declaration parsing */ skip_declarations(rtn_idp) SYMTAB_NODE_PTR rtn_idp; /* program id */ { SYMTAB_NODE_PTR const_idp; /* constant id */ char tmp_buff[MAX_SOURCE_LINE_LENGTH]; entry_debug("skip_declarations"); strcpy(tmp_buff, word_string); strcpy(word_string, "_ZeRo"); search_and_enter_local_symtab(const_idp); strcpy(word_string, tmp_buff); const_idp->defn.key = CONST_DEFN; const_idp->defn.info.constant.value.integer = 0; const_idp->typep = integer_typep; analyze_const_defn(const_idp); exit_debug("skip_declarations"); return; } /* end SKIP_DECLARATIONS */ /***************************************************************************/ /* EXPRESS CONSTANTS and LOCALS */ /***************************************************************************/ /* constant_block() Process EXPRESS constant block */ /* CONSTANT { } END_CONSTANT ; */ /* at entry, current token is CONSTANT */ /* at exit, current token is after the semicolon */ constant_block() { entry_debug("constant_block"); error(UNIMPLEMENTED_FEATURE); while (token != XEND_CONSTANT) { get_token(); } get_token(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); exit_debug("constant_block"); return; } /* end CONSTANT_BLOCK */ /***************************************************************************/ /***************************************************************************/ /* a_constant_definition() Process EXPRESS constant */ /* : := ; */ /* at entry, current token is */ /* at exit, current token is after closing semicolon */ a_constant_definition() { SYMTAB_NODE_PTR type_idp; /* constant id */ if (token != IDENTIFIER) { error(UNEXPECTED_TOKEN); return; } search_and_enter_local_symtab(type_idp); type_idp->defn.key = TYPE_DEFN; get_token(); if_token_get_else_error(COLON, MISSING_COLON); /* process the type */ type_idp->typep = get_type(); if (type_idp->typep->type_idp == NULL) { type_idp->typep->type_idp = type_idp; } get_token(); if_token_get_else_error(COLONEQUAL, MISSING_COLONEQUAL); /* process the expression */ /* SKIP THIS FOR NOW */ while (token != SEMICOLON) { get_token(); } get_token(); return; } /* end A_CONSTANT_DEFINITION */ /***************************************************************************/ /***************************************************************************/ /* local_block(rtn_idp) Process EXPRESS local block */ /* LOCAL { } END_LOCAL ; */ /* at entry, current token is the one after LOCAL */ /* at exit, current token is after closing semicolon */ local_block(rtn_idp) SYMTAB_NODE_PTR rtn_idp; /* id of routine */ { entry_debug("local_block"); local_decls(rtn_idp, STACK_FRAME_HEADER_SIZE + rtn_idp->defn.info.routine.parm_count); exit_debug("local_block"); return; } /* end LOCAL_BLOCK */ /***************************************************************************/ /***************************************************************************/ /* local_decls(rtn_idp, record_tp, offset) Process EXPRESS local variables */ /* at entry, current token is */ /* at exit, current token is after closing END_LOCAL ; */ local_decls(rtn_idp, offset) SYMTAB_NODE_PTR rtn_idp; int offset; { SYMTAB_NODE_PTR idp, first_idp, last_idp; /* variable ids */ SYMTAB_NODE_PTR prev_last_idp = NULL; /* last id of a list */ TYPE_STRUCT_PTR tp; /* type */ int size; int total_size = 0; entry_debug("local_decls"); /* loop to process sublist, each of a single type */ while (token == IDENTIFIER) { /* loop over semicolon seperated list */ first_idp = NULL; /* loop to process each var in a list */ while (token == IDENTIFIER) { /* loop over comma seperated list */ search_and_enter_local_symtab(idp); idp->defn.key = VAR_DEFN; idp->label_index = 0; /* link ids into a sublist */ if (first_idp == NULL) { first_idp = last_idp = idp; if (rtn_idp->defn.info.routine.locals == NULL) { rtn_idp->defn.info.routine.locals = idp; } } else { last_idp->next = idp; last_idp = idp; } get_token(); if_token_get(COMMA); } /* end while over a comma seperated list */ /* Process the sublist's type */ if_token_get_else_error(COLON, MISSING_COLON); tp = get_type(); size = tp->size; /* Assign the offset and the type to all ids in the list */ for (idp = first_idp; idp != NULL; idp = idp->next) { idp->typep = tp; total_size += size; idp->defn.info.data.offset = offset++; analyze_var_decl(idp); } /* end for */ /* link this sublist to previous sublist */ if (prev_last_idp != NULL) prev_last_idp->next = first_idp; prev_last_idp = last_idp; /* optional expression here SKIP FOR NOW */ get_token(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); } /* end while over semicolon seperated list */ if_token_get_else_error(XEND_LOCAL, MISSING_END); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); rtn_idp->defn.info.routine.total_local_size = total_size; exit_debug("local_decls"); return; } /* end LOCAL_DECLS */ /***************************************************************************/ /***************************************************************************/ /* an_entity() Process an EXPRESS entity */ /* ENTITY END_ENTITY ; */ /* at entry, current token = ENTITY */ /* at exit, current token is after END_ENTITY ; */ TYPE_STRUCT_PTR an_entity() { SYMTAB_NODE_PTR idp; /* entity id */ TYPE_STRUCT_PTR entity_tp = alloc_struct(TYPE_STRUCT); entry_debug("an_entity (l2xidecl.c)"); entity_tp->form = ENTITY_FORM; entity_tp->type_idp = NULL; entity_tp->info.entity.attribute_symtab = NULL; get_token(); /* name of the entity */ if (token != IDENTIFIER) { error(UNEXPECTED_TOKEN); } search_and_enter_local_symtab(idp); idp->defn.key = TYPE_DEFN; idp->label_index = 0; idp->typep = entity_tp; get_token(); /* semicolon */ if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); attribute_declarations(NULL, entity_tp, 0); analyze_type_defn(idp); /* skip to the end */ while (token != XEND_ENTITY) { get_token(); } get_token(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); exit_debug("an_entity"); return(entity_tp); } /* end AN_ENTITY */ /***************************************************************************/ /***************************************************************************/ /* a_type() Process an EXPRESS type */ /* TYPE END_TYPE ; */ /* at entry, current token = TYPE */ /* at exit, current token is after END_TYPE ; */ TYPE_STRUCT_PTR a_type() { SYMTAB_NODE_PTR type_idp; /* the TYPE id */ TYPE_STRUCT_PTR tsp; /* type structure pointer */ entry_debug("a_type (l2xidecl.c)"); get_token(); /* the type id */ if (token != IDENTIFIER) { error(UNEXPECTED_TOKEN); exit_debug("a_type"); return(&dummy_type); } search_and_enter_local_symtab(type_idp); type_idp->defn.key = TYPE_DEFN; get_token(); if_token_get_else_error(EQUAL, MISSING_EQUAL); /* process the type */ if (token == XENUMERATION) { /* an ENUMERATION type */ get_token(); if_token_get_else_error(OF, MISSING_OF); if (token != LPAREN) { error(MISSING_LPAREN); } /* process the enumeration */ type_idp->typep = enumeration_type(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); } else { /* an ordinary type */ type_idp->typep = get_type(); get_token(); if (token != SEMICOLON) error(MISSING_SEMICOLON); } if (type_idp->typep->type_idp == NULL) type_idp->typep->type_idp = type_idp; analyze_type_defn(type_idp); /* skip to end of definition */ while (token != XEND_TYPE) { get_token(); } get_token(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); exit_debug("a_type"); return(type_idp->typep); } /* end A_TYPE */ /***************************************************************************/ /***************************************************************************/ /* a_rule() Process an EXPRESS rule */ /* RULE END_RULE ; */ /* at entry, current token = RULE */ /* at exit, current token is after END_RULE ; */ a_rule() { error(UNIMPLEMENTED_FEATURE); while (token != XEND_RULE) { get_token(); } get_token(); if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); return; } /* end A_RULE */ /***************************************************************************/ /* CONSTANTS */ /* TYPES */ /***************************************************************************/ /* get_type() Process a type identifier. Call the function to make the */ /* type structure, and return pointer to it. */ /* at entry, token is the id */ /* at exit, token is unaltered */ TYPE_STRUCT_PTR get_type() { TYPE_STRUCT_PTR tsp; entry_debug("get_type"); if (token_in(simple_type_list)) { /* predefined simple type */ switch (token) { case XINTEGER : { tsp = integer_typep; break; } case XREAL : { tsp = real_typep; break; } case XBOOLEAN : { tsp = boolean_typep; break; } case XLOGICAL : { tsp = logical_typep; break; } case XSTRING : { tsp = make_string_typep(0); break; } default : { error(UNIMPLEMENTED_SIMPLE_TYPE); tsp = &dummy_type; break; } } /* end switch */ exit_debug("get_type"); return(tsp); } /* end predefined simple types */ if (token_in(aggregation_type_list)) { /* predefined aggregation type */ switch (token) { case ARRAY : { return(get_array_type()); break; } case XBAG: case XLIST: case SET: { return(get_bls_type()); break; } default : { error(UNIMPLEMENTED_AGGREGATION_TYPE); tsp = &dummy_type; break; } } /* end switch */ exit_debug("get_type"); return(tsp); } /* end predefined aggregation types */ switch (token) { case IDENTIFIER: { SYMTAB_NODE_PTR idp; search_all_symtab(idp); if (idp == NULL) { error(UNDEFINED_IDENTIFIER); exit_debug("get_type"); return(&dummy_type); } else if (idp->defn.key == TYPE_DEFN) { exit_debug("get_type"); return(identifier_type(idp)); } /* else if (idp->defn.key == CONST_DEFN) { exit_debug("get_type"); return(subrange_type(idp)); } */ else { error(NOT_A_TYPE_IDENTIFIER); exit_debug("get_type"); return(&dummy_type); } } default : { error(INVALID_TYPE); exit_debug("get_type"); return(&dummy_type); } } /* end switch */ } /* end get_type */ /***************************************************************************/ /***************************************************************************/ /* identifier_type(idp) Process an identifier type (the identifier at the */ /* LHS of an assignment). */ /* return pointer to the type structure. */ TYPE_STRUCT_PTR identifier_type(idp) SYMTAB_NODE_PTR idp; /* type id */ { TYPE_STRUCT_PTR tp = NULL; tp = idp->typep; /* get_token(); */ return(tp); } /* end identifier_type */ /***************************************************************************/ /***************************************************************************/ /* enumeration_type() Process an enumeration type. */ /* ( , , ... ) */ /* Make and return a type structure. */ /* at entry: token is opening ( */ /* at exit: token is after closing ) */ TYPE_STRUCT_PTR enumeration_type() { SYMTAB_NODE_PTR const_idp; /* constant id */ SYMTAB_NODE_PTR last_idp = NULL; /* last constant id */ TYPE_STRUCT_PTR tp = alloc_struct(TYPE_STRUCT); int const_value = -1; /* constant value */ tp->form = ENUM_FORM; tp->size = sizeof(int); tp->type_idp = NULL; get_token(); /* loop to process ids */ while (token == IDENTIFIER) { search_and_enter_local_symtab(const_idp); const_idp->defn.key = CONST_DEFN; const_idp->defn.info.constant.value.integer = ++const_value; const_idp->typep = tp; /* link ids into list */ if (last_idp == NULL) tp->info.enumeration.const_idp = last_idp = const_idp; else { last_idp->next = const_idp; last_idp = const_idp; } get_token(); if_token_get(COMMA); } /* end while */ if_token_get_else_error(RPAREN, MISSING_RPAREN); tp->info.enumeration.max = const_value; return(tp); } /* end enumeration_type */ /***************************************************************************/ /***************************************************************************/ /* make_string_typep(length) Make a type structure for a string of the */ /* given length. */ /* return a pointer to it. */ /* rewritten for new structure */ TYPE_STRUCT_PTR make_string_typep(length) int length; /* string length */ { TYPE_STRUCT_PTR string_tp = alloc_struct(TYPE_STRUCT); entry_debug("make_string_type"); if (length > MAX_EXPRESS_STRING) { error(STRING_TOO_LONG); } string_tp->form = STRING_FORM; string_tp->size = sizeof(STRING); string_tp->type_idp = string_idp; /* string_tp->type_idp = NULL; */ string_tp->info.string.max_length = MAX_EXPRESS_STRING; string_tp->info.string.length = length; exit_debug("make_string_type"); return(string_tp); } /* end make_string_typep */ /***************************************************************************/ /***************************************************************************/ /* calculate_array_size(tp) Return the size in bytes of an EXPRESS */ /* array by recursively */ /* calculating the size of each dimension. */ int calculate_array_size(tp) TYPE_STRUCT_PTR tp; /* ptr to array type structure */ { if (tp->info.array.elmt_typep->size == 0) { tp->info.array.elmt_typep->size = calculate_array_size(tp->info.array.elmt_typep); } tp->size = tp->info.array.elmt_count * tp->info.array.elmt_typep->size; return(tp->size); } /* end array_size */ /***************************************************************************/ /* VARIABLES */ /***************************************************************************/ /* attribute_declarations(rtn_idp, entity_tp, offset) */ /* Process entity attribute definitions. All ids declared */ /* with the same type are linked into a sublist, and all the */ /* sublists are then liked together. */ attribute_declarations(rtn_idp, entity_tp, offset) SYMTAB_NODE_PTR rtn_idp; TYPE_STRUCT_PTR entity_tp; int offset; { SYMTAB_NODE_PTR idp, first_idp, last_idp; /* variable or field ids */ SYMTAB_NODE_PTR prev_last_idp = NULL; /* last id of a list */ TYPE_STRUCT_PTR tp; /* type */ int size; int total_size = 0; entry_debug("attribute_declarations (l2xidecl.c)"); /* loop to process sublist, each of a single type */ while (!token_in(follow_attributes_list)) { first_idp = NULL; /* loop to process each attribute in a list */ while (token == IDENTIFIER) { search_and_enter_this_symtab(idp, entity_tp->info.entity.attribute_symtab); idp->defn.key = ATTRIBUTE_DEFN; idp->label_index = 0; /* link ids into a sublist */ if (first_idp == NULL) { first_idp = last_idp = idp; } else { last_idp->next = idp; last_idp = idp; } get_token(); if_token_get(COMMA); } /* end while */ /* Process the sublist's type */ if_token_get_else_error(COLON, MISSING_COLON); tp = get_type(); size = tp->size; /* Assign the offset and the type to all ids in the list */ for (idp = first_idp; idp != NULL; idp = idp->next) { idp->typep = tp; idp->defn.info.data.offset = offset; offset += size; } /* end for */ /* link this sublist to previous sublist */ if (prev_last_idp != NULL) prev_last_idp->next = first_idp; prev_last_idp = last_idp; get_token(); /* move on from type processing */ if_token_get_else_error(SEMICOLON, MISSING_SEMICOLON); } /* end while */ entity_tp->size = offset; exit_debug("attribute_declarations"); return; } /* end ATTRIBUTE_DECLARATIONS */ /***************************************************************************/ /***************************************************************************/ /* get_array_type() Process an array type */ /* ARRAY OF */ /* Make a structure and return pointer. */ /* at entry: token is ARRAY */ /* at exit: token is */ TYPE_STRUCT_PTR get_array_type() { TYPE_STRUCT_PTR tp = alloc_struct(TYPE_STRUCT); TYPE_STRUCT_PTR index_tp; /* index type */ TYPE_STRUCT_PTR elmt_tp = tp; /* element type */ TYPE_STRUCT_PTR bound_tp; /* bound type */ int min, max, count; int calculate_array_size(); entry_debug("get_array_type (l2xidecl.c)"); get_token(); elmt_tp->form = ARRAY_FORM; elmt_tp->size = 0; elmt_tp->type_idp = NULL; elmt_tp->info.array.index_typep = integer_typep; if (token != LBRACKET) error(MISSING_LBRACKET); bound_tp = get_bound_spec_type(); min = bound_tp->info.bound.min; max = bound_tp->info.bound.max; if (min == QUERY_CHAR || max == QUERY_CHAR) { error(INVALID_INDEX_TYPE); count = 0; } else if (min > max) { error(MIN_GT_MAX); count = 0; } else { elmt_tp->info.array.min_index = min; elmt_tp->info.array.max_index = max; count = (max - min) + 1; } elmt_tp->info.array.elmt_count = count; /* sync. Should be OF */ synchronize(follow_indexes_list, declaration_start_list, statement_start_list); if_token_get_else_error(OF, MISSING_OF); /* element type */ elmt_tp->info.array.elmt_typep = get_type(); tp->size = calculate_array_size(tp); /* was array_size(tp); */ exit_debug("get_array_type"); return(tp); } /* end GET_ARRAY_TYPE */ /***************************************************************************/ /***************************************************************************/ /* get_bls_type() Process a BAG, etc type */ /* BAG [ ] OF */ /* Make a structure and return pointer. */ /* at entry: token is BAG */ /* at exit: token is */ TYPE_STRUCT_PTR get_bls_type() { TYPE_STRUCT_PTR tp = alloc_struct(TYPE_STRUCT); TYPE_STRUCT_PTR index_tp; /* index type */ TYPE_STRUCT_PTR elmt_tp = tp; /* element type */ TYPE_STRUCT_PTR bound_tp; /* bound type */ int min, max, count, size; entry_debug("get_bls_type (l2xidecl.c)"); count = 0; if (token == XBAG) { elmt_tp->form = BAG_FORM; } else if (token == XLIST) { elmt_tp->form = LIST_FORM; } else if (token == SET) { elmt_tp->form = SET_FORM; } elmt_tp->size = 0; elmt_tp->type_idp = NULL; elmt_tp->info.dynagg.index_typep = integer_typep; get_token(); if (token == LBRACKET) { /* a bound spec */ bound_tp = get_bound_spec_type(); min = bound_tp->info.bound.min; max = bound_tp->info.bound.max; if (min == QUERY_CHAR) { error(INVALID_INDEX_TYPE); min = 0; count = 0; } else if (min < 0) { error(INVALID_INDEX_TYPE); min = 0; count = 0; } else if (max != QUERY_CHAR) { if (min > max) { error(MIN_GT_MAX); max = min; count = 0; } } else { /* count = (max - min) + 1; */ count = 0; } } else { /* default [0:?] bound spec */ min = 0; max = QUERY_CHAR; count = 0; } /* sync. Should be OF */ synchronize(follow_indexes_list, declaration_start_list, statement_start_list); if_token_get_else_error(OF, MISSING_OF); if (max == QUERY_CHAR) { max = MAX_AGG_SIZE; } elmt_tp->info.dynagg.min_index = min; elmt_tp->info.dynagg.max_index = max; elmt_tp->info.dynagg.elmt_count = count; elmt_tp->info.dynagg.elmt_typep = get_type(); tp->size = sizeof(LBS_PTR); exit_debug("get_bls_type"); return(tp); } /* end GET_BLS_TYPE */ /***************************************************************************/ /***************************************************************************/ /* get_bound_spec_type() Process a bound spec */ /* [ : ] */ /* make a type structure and return a pointer to it */ /* at entry: token is opening [ */ /* at exit: token is after closing ] */ TYPE_STRUCT_PTR get_bound_spec_type() { TYPE_STRUCT_PTR tp; entry_debug("get_bound_spec_type (l2xidecl.c)"); tp = alloc_struct(TYPE_STRUCT); tp->form = BOUND_FORM; tp->type_idp = NULL; tp->size = sizeof(int); tp->info.bound.bound_typep = integer_typep; /* lower bound */ get_token(); tp->info.bound.min = get_bound_limit(); /* sync. should be a : */ synchronize(follow_min_bound_list, NULL, NULL); if_token_get(COLON); else if (token_in(follow_min_bound_list) || token_in(declaration_start_list) || token_in(statement_start_list)) error(MISSING_COLON); /* upper bound */ tp->info.bound.max = get_bound_limit(); if_token_get_else_error(RBRACKET, MISSING_RBRACKET); exit_debug("get_bound_spec_type"); return(tp); } /* end GET_BOUND_SPEC_TYPE */ /***************************************************************************/ /***************************************************************************/ /* get_bound_limit(minmax_idp, minmaxp, typepp) Process the min or */ /* max limits of a bound spec */ /* [ + | - ] INTEGER_LITERAL */ /* at entry: token is the limit (value) */ /* at exit: token is after the limit */ int get_bound_limit() { TOKEN_CODE sign = PLUS; /* unary + or - sign */ int result = QUERY_CHAR; /* undef result */ /* unary + or - sign */ if ((token == PLUS) || (token == MINUS)) { sign = token; get_token(); } /* numeric limit --- integer only */ if (token == NUMBER_LITERAL) { if (literal.type == INTEGER_LIT) { result = (sign == PLUS) ? literal.value.integer : -literal.value.integer; } else error(INVALID_BOUND_TYPE); } else if (token == QUERY_CHAR) { result = QUERY_CHAR; } else { error(INVALID_BOUND_TYPE); } get_token(); return(result); } /* end GET_BOUND_LIMIT */ /***************************************************************************/