/* l2xidecl.c LTX2X interpreter parsing routines for declarations */
/* Written by: Peter Wilson, CUA
[email protected] */
/* This code is partly based on algorithms presented by Ronald Mak in */
/* "Writing Compilers & Interpreters", John Wiley & Sons, 1991 */
#include <stdio.h>
#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 { <constant_definition> } 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 */
/* <constant_id> : <type> := <expression> ; */
/* at entry, current token is <constant_id> */
/* 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 { <local_definition> } 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 <var_id> */
/* 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 <entity_body> 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 <type_body> 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 <rule_body> 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. */
/* ( <id>, <id>, ... ) */
/* 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 <bound_spec> OF <elmt-type> */
/* 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 [ <bound_spec> ] OF <elmt-type> */
/* 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 */
/* [ <int_expr> : <int_expr> ] */
/* 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 */
/***************************************************************************/