/* l2xiexpr.c LTX2X interpreter parsing routines for expressions */ /* 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" /* extern token code lists */ #endif /* EXTERNALS */ extern TOKEN_CODE token; extern char token_string[]; extern char word_string[]; extern LITERAL literal; extern SYMTAB_NODE_PTR symtab_display[]; extern int level; /* built-in constants */ extern SYMTAB_NODE_PTR false_idp, true_idp, unknown_idp; extern SYMTAB_NODE_PTR conste_idp, pi_idp, undef_idp; extern SYMTAB_NODE_PTR day_idp, month_idp, year_idp; /* FORWARDS */ TYPE_STRUCT_PTR expression(), simple_expression(), term(), factor(), function_call(); TYPE_STRUCT_PTR simple_factor(); TYPE_STRUCT_PTR index_list(); /* MACROS */ /* integer_operands(tp1, tp2) TRUE if both are integer, else FALSE */ #define integer_operands(tp1, tp2) ((tp1 == integer_typep) && \ (tp2 == integer_typep)) /* real_operands(tp1, tp2) TRUE if one or both operands are real, and */ /* the other is integer, else FALSE */ #define real_operands(tp1, tp2) (((tp1 == real_typep) && \ ((tp2 == real_typep) || \ (tp2 == integer_typep))) \ || \ ((tp2 == real_typep) && \ ((tp1 == real_typep) || \ (tp1 == integer_typep)))) /* boolean_operands(tp1, tp2) TRUE if both are boolean, else FALSE */ #define boolean_operands(tp1, tp2) ((tp1 == boolean_typep) && \ (tp2 == boolean_typep)) /* logical_operands(tp1, tp2) TRUE if both are logical/boolean, else FALSE */ #define logical_operands(tp1, tp2) ((tp1 == boolean_typep || tp1 == logical_typep) && \ (tp2 == boolean_typep || tp2 == logical_typep)) /* string_operands(tp1, tp2) TRUE iff both are string */ #define string_operands(tp1, tp2) ((tp1 == string_typep || \ tp1->form == STRING_FORM) && \ (tp2 == string_typep || \ tp2->form == STRING_FORM)) /* NEW undef_types(tp1, tp2) TRUE if either is undefined, else FALSE */ #define undef_types(tp1, tp2) ((tp1 == any_typep) || \ (tp2 == any_typep)) /* NEW is_undef(tp1) TRUE if undefined, else FALSE */ #define is_undef(tp1) (tp1 == any_typep) /* NEW set_undef(tp1) sets tp1 to be an undef */ #define set_undef(tp1) tp1 = any_typep /***************************************************************************/ /* expression() Process an expression consisting of a simple expression, */ /* optionally followed by a relational operator and a */ /* second simple expression. */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR expression() { TYPE_STRUCT_PTR result_tp, tp2; entry_debug("expression"); /* first simple expression */ result_tp = simple_expression(); /* if operator, process following expression */ if (token_in(rel_op_list)) { result_tp = base_type(result_tp); /* second expression */ get_token(); tp2 = base_type(simple_expression()); check_rel_op_types(result_tp, tp2); result_tp = logical_typep; } exit_debug("expression"); return(result_tp); } /* end expression */ /***************************************************************************/ /***************************************************************************/ /* simple_expression() Process a simple expression */ /* consisting of terms seperated by +, -, OR, XXOR */ /* operators. There may be an initial unary operator */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR simple_expression() { TOKEN_CODE op; /* operator token */ TYPE_STRUCT_PTR result_tp, tp2; BOOLEAN saw_unary_op = FALSE; entry_debug("simple_expression"); /* remember intial unary op */ if ((token == PLUS) || (token == MINUS)) { saw_unary_op = TRUE; get_token(); } /* first term */ result_tp = term(); /* if there was a unary operator, check its type for integer or real. */ if (saw_unary_op && (base_type(result_tp) != integer_typep) && (result_tp != real_typep)) error(INCOMPATIBLE_TYPES); /* loop to process subsequent terms seperated by operators */ while (token_in(add_op_list)) { op = token; result_tp = base_type(result_tp); get_token(); tp2 = base_type(term()); /* next term */ if (undef_types(result_tp, tp2)) { set_undef(result_tp); } else { switch (op) { case PLUS: { /* integer op integer -> integer */ if (integer_operands(result_tp, tp2)) result_tp = integer_typep; /* numbers -> real, */ else if (real_operands(result_tp, tp2)) result_tp = real_typep; /* string concatenation */ else if (string_operands(result_tp, tp2)) result_tp = string_typep; else { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; } break; } case MINUS: { /* integer op integer -> integer */ if (integer_operands(result_tp, tp2)) result_tp = integer_typep; /* otherwise numbers -> real, else error */ else if (real_operands(result_tp, tp2)) result_tp = real_typep; else { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; } break; } case OR: case XXOR: { /* boolean OR boolean -> boolean */ if (!logical_operands(result_tp, tp2)) { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; break; } result_tp = logical_typep; break; } case XLIKE: { /* string LIKE string -> boolean */ if (!string_operands(result_tp, tp2)) { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; break; } result_tp = logical_typep; break; } } /* end switch */ } } /* end while */ exit_debug("simple_expression"); return(result_tp); } /* end simple_expression */ /***************************************************************************/ /***************************************************************************/ /* term() Process a term */ /* consisting of factors seperated by */ /* *, /, DIV, MOD, or AND */ /* operators. */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR term() { TOKEN_CODE op; /* operator token */ TYPE_STRUCT_PTR result_tp, tp2; entry_debug("term"); /* first factor */ result_tp = factor(); /* loop to process subsequent factors seperated by operators */ while (token_in(mult_op_list)) { op = token; result_tp = base_type(result_tp); get_token(); tp2 = base_type(factor()); /* next factor */ if (undef_types(result_tp, tp2)) { set_undef(result_tp); } else { switch (op) { case STAR: { /* integer op integer -> integer */ if (integer_operands(result_tp, tp2)) result_tp = integer_typep; /* otherwise numbers -> real, else error */ else if (real_operands(result_tp, tp2)) result_tp = real_typep; else { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; } break; } case SLASH: { /* number op number -> real */ if ((!real_operands(result_tp, tp2)) && (!integer_operands(result_tp, tp2))) { error(INCOMPATIBLE_TYPES); } result_tp = real_typep; break; } case DIV: case MOD: { /* integer op integer -> integer */ if (!integer_operands(result_tp, tp2)) error(INCOMPATIBLE_TYPES); result_tp = integer_typep; break; } case AND: { /* boolean op boolean -> boolean */ if (!logical_operands(result_tp, tp2)) { error(INCOMPATIBLE_TYPES); result_tp = logical_typep; break; } } } /* end switch */ } } /* end while */ exit_debug("term"); return(result_tp); } /* end term */ /***************************************************************************/ /***************************************************************************/ /* factor() Process an EXPRESS factor */ /* simple_factor [ ** simple_factor ] */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR factor() { TOKEN_CODE op; /* operator token */ TYPE_STRUCT_PTR result_tp, tp2; entry_debug("factor"); /* first factor */ result_tp = simple_factor(); op = token; if (op == STARSTAR) { result_tp = base_type(result_tp); get_token(); tp2 = base_type(simple_factor()); if (undef_types(result_tp, tp2)) { set_undef(result_tp); } else if (integer_operands(result_tp, tp2)) result_tp = integer_typep; else if (real_operands(result_tp, tp2)) result_tp = real_typep; else { error(INCOMPATIBLE_TYPES); result_tp = &dummy_type; } } exit_debug("factor"); return(result_tp); } /* end FACTOR */ /***************************************************************************/ /***************************************************************************/ /* simple_factor() Process a simple factor */ /* a variable, a number, NOT factor, a */ /* parenthesized expression, or an interval expression */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR simple_factor() { TYPE_STRUCT_PTR tp; TYPE_STRUCT_PTR tp1, tp2; TOKEN_CODE op; entry_debug("simple_factor"); if (token_in(constant_list)) { /* language defined constant */ switch (token) { case XFALSE : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(false_idp); tp = logical_typep; break; } case XTRUE : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(true_idp); tp = logical_typep; break; } case XUNKNOWN : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(unknown_idp); tp = logical_typep; break; } case XCONST_E : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(conste_idp); tp = real_typep; break; } case XPI : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(pi_idp); tp = real_typep; break; } case QUERY_CHAR : { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(undef_idp); set_undef(tp); break; } case THE_DAY: { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(day_idp); tp = integer_typep; break; } case THE_MONTH: { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(month_idp); tp = integer_typep; break; } case THE_YEAR: { change_crunched_token(IDENTIFIER); crunch_symtab_node_ptr(year_idp); tp = integer_typep; break; } default : { error(UNIMPLEMENTED_CONSTANT); tp = &dummy_type; break; } } /* end switch */ get_token(); exit_debug("factor at defined constants"); return(tp); } /* end of language defined constants */ switch (token) { case IDENTIFIER: { SYMTAB_NODE_PTR idp; search_and_find_all_symtab(idp); switch (idp->defn.key) { case FUNC_DEFN: { crunch_symtab_node_ptr(idp); get_token(); tp = routine_call(idp,TRUE); break; } case PROC_DEFN: { error(INVALID_IDENTIFIER_USAGE); get_token(); actual_parm_list(idp,FALSE); tp = &dummy_type; break; } case CONST_DEFN: { crunch_symtab_node_ptr(idp); get_token(); tp = idp->typep; break; } default: { tp = variable(idp, EXPR_USE); break; } } /* end switch */ break; } case NUMBER_LITERAL: { SYMTAB_NODE_PTR np; np = search_symtab(token_string, symtab_display[1]); if (np == NULL) np = enter_symtab(token_string, symtab_display[1]); if (literal.type == INTEGER_LIT ) { tp = np->typep = integer_typep; np->defn.info.constant.value.integer = literal.value.integer; } else { /* a real literal */ tp = np->typep = real_typep; np->defn.info.constant.value.real = literal.value.real; } crunch_symtab_node_ptr(np); get_token(); break; } case STRING_LITERAL: { SYMTAB_NODE_PTR np; int length = strlen(literal.value.string); np = search_symtab(token_string, symtab_display[1]); if (np == NULL) np = enter_symtab(token_string, symtab_display[1]); np->typep = tp = make_string_typep(length); np->info = alloc_bytes(length + 1); strcpy(np->info, literal.value.string); crunch_symtab_node_ptr(np); get_token(); break; } case NOT: { get_token(); tp = simple_factor(); break; } case LPAREN: { get_token(); tp = expression(); if_token_get_else_error(RPAREN, MISSING_RPAREN); break; } case LBRACE: { /* interval expression {expr op var op expr} */ get_token(); tp1 = simple_expression(); op = token; if (op != LT && op != LE) { error(EXPECTED_INTERVAL_OP); } get_token(); tp = simple_expression(); check_rel_op_types(tp1, tp); op = token; if (op != LT && op != LE) { error(EXPECTED_INTERVAL_OP); } get_token(); tp2 = simple_expression(); check_rel_op_types(tp, tp2); if_token_get_else_error(RBRACE, MISSING_RBRACE); tp = logical_typep; break; } default: { error(INVALID_EXPRESSION); tp = &dummy_type; break; } } /* end switch */ exit_debug("simple_factor"); return(tp); } /* end SIMPLE_FACTOR */ /***************************************************************************/ /***************************************************************************/ /* variable(var_idp, use) Process a variable */ /* consisting of */ /* a simple id, an array id with subscripts, */ /* or an entity id with attributes */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR variable(var_idp, use) SYMTAB_NODE_PTR var_idp; /* var id */ USE use; /* how variable is used */ { TYPE_STRUCT_PTR tp = var_idp->typep; DEFN_KEY defn_key = var_idp->defn.key; TYPE_STRUCT_PTR array_subscript_list(); TYPE_STRUCT_PTR entity_attr(); entry_debug("variable"); crunch_symtab_node_ptr(var_idp); /* check the definition of the variable */ switch (defn_key) { case VAR_DEFN: case VALPARM_DEFN: case VARPARM_DEFN: case FUNC_DEFN: case UNDEFINED: { break; } default: { tp = &dummy_type; error(INVALID_IDENTIFIER_USAGE); break; } } /* end switch */ get_token(); /* there must not be a parameter list, but parse for one anyway */ if (token == LPAREN) { error(UNEXPECTED_TOKEN); actual_parm_list(var_idp, FALSE); exit_debug("variable (unexpected parm list)"); return(tp); } /* subscripts or fields? */ while ((token == LBRACKET) || (token == PERIOD)) { if (token == PERIOD) { tp = entity_attr(tp); } else { if (var_idp->typep == string_typep || var_idp->typep->form == STRING_FORM) { /* substring op */ tp = index_list(tp); } else { /* aggregate index */ tp = array_subscript_list(tp); } } } exit_debug("variable"); return(tp); } /* end variable */ /***************************************************************************/ /***************************************************************************/ /* index_list(tp) Process a (pair of) subscript v */ /* '[' [ ':' ] ']' */ /* return a pointer to the type structure */ /* at entry: token is opening [ */ /* at exit: token is after closing ] */ TYPE_STRUCT_PTR index_list(tp) TYPE_STRUCT_PTR tp; /* type of var just before opening [ */ { TYPE_STRUCT_PTR ss1_tp, ss2_tp; entry_debug("index_list (l2xiexpr.c)"); /* check on var type */ if (tp == string_typep || tp->form == STRING_FORM) { /* OK */ ; } else { error(UNEXPECTED_TOKEN); } /* do first expression */ get_token(); ss1_tp = expression(); if (ss1_tp != integer_typep) error(INCOMPATIBLE_TYPES); if (token == COLON) { /* do second expression */ get_token(); ss2_tp = expression(); if (ss2_tp != integer_typep) error(INCOMPATIBLE_TYPES); } if_token_get_else_error(RBRACKET, MISSING_RBRACKET); exit_debug("index_list"); return(tp); } /* end INDEX_LIST */ /***************************************************************************/ /***************************************************************************/ /* array_subscript_list(tp) Process a list of subscripts */ /* [ , , ... ] */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR array_subscript_list(tp) TYPE_STRUCT_PTR tp; { TYPE_STRUCT_PTR index_tp, elmt_tp, ss_tp; /* loop to process the list */ do { if (tp->form == ARRAY_FORM) { index_tp = tp->info.array.index_typep; elmt_tp = tp->info.array.elmt_typep; get_token(); ss_tp = expression(); /* check assignment compatibility */ if (!is_assign_type_compatible(index_tp, ss_tp)) error(INCOMPATIBLE_TYPES); tp = elmt_tp; } else if (tp->form == BAG_FORM || tp->form == LIST_FORM || tp->form == SET_FORM) { index_tp = tp->info.dynagg.index_typep; elmt_tp = tp->info.dynagg.elmt_typep; get_token(); ss_tp = expression(); /* check assignment compatibility */ if (!is_assign_type_compatible(index_tp, ss_tp)) error(INCOMPATIBLE_TYPES); tp = elmt_tp; } else { error(TOO_MANY_SUBSCRIPTS); while ((token != RBRACKET) && (!token_in(statement_end_list))) { get_token(); } } } while (token == COMMA); /* end do */ if_token_get_else_error(RBRACKET, MISSING_RBRACKET); return(tp); } /* end array_subscript_list */ /***************************************************************************/ /***************************************************************************/ /* entity_attr(tp) Process an entity attribute */ /* . */ /* return a pointer to the type structure */ TYPE_STRUCT_PTR entity_attr(tp) TYPE_STRUCT_PTR tp; { SYMTAB_NODE_PTR attr_idp; get_token(); if ((token == IDENTIFIER) && (tp->form == ENTITY_FORM)) { search_this_symtab(attr_idp, tp->info.entity.attribute_symtab); crunch_symtab_node_ptr(attr_idp); get_token(); if (attr_idp != NULL) return(attr_idp->typep); else { error(INVALID_ATTRIBUTE); return(&dummy_type); } } else { get_token(); error(INVALID_ATTRIBUTE); return(&dummy_type); } } /* end entity_attr */ /***************************************************************************/ /* TYPE COMPATIBILITY */ /***************************************************************************/ /* check_rel_op_types(tp1, tp2) Check operand types of a relational */ /* operator */ check_rel_op_types(tp1, tp2) TYPE_STRUCT_PTR tp1; TYPE_STRUCT_PTR tp2; { /* identical scalar or enumeration types */ if ((tp1 == tp2) && ((tp1->form == SCALAR_FORM) || (tp1->form == ENUM_FORM))) { return; } /* one integer and one real */ if (((tp1 == integer_typep) && (tp2 == real_typep)) || ((tp2 == integer_typep) && (tp1 == real_typep))) { return; } /* two arbitrary strings */ if (string_operands(tp1, tp2)) { return; } /* for the IN operator */ /* tp2 is a dynamic aggregate, tp1 is the elmt type */ if (is_dynagg(tp2)) { if (tp1 == tp2->info.dynagg.elmt_typep) { return; } } error(INCOMPATIBLE_TYPES); } /* end check_rel_op_types */ /***************************************************************************/ /***************************************************************************/ /* is_assign_type_compatible(tp1, tp2) Check if a value of type tp2 */ /* can be assigned to a variable of type tp1 */ /* (i.e. tp1 := tp2) */ /* return TRUE if types assignment compatible, else FALSE */ BOOLEAN is_assign_type_compatible(tp1, tp2) TYPE_STRUCT_PTR tp1; TYPE_STRUCT_PTR tp2; { tp1 = base_type(tp1); tp2 = base_type(tp2); if (tp1 == tp2) return(TRUE); if (is_undef(tp2)) { compile_warning(ASSIGN_TO_UNDEF); return(TRUE); } /* real := integer */ if ((tp1 == real_typep) && (tp2 == integer_typep)) return(TRUE); if (string_operands(tp1, tp2)) return(TRUE); /* incompatible */ return(FALSE); } /* end is_assign_type_compatible */ /***************************************************************************/ /***************************************************************************/ /* base_type(tp) Return the range type of a subrange type */ TYPE_STRUCT_PTR base_type(tp) TYPE_STRUCT_PTR tp; { return((tp->form == SUBRANGE_FORM) ? tp->info.subrange.range_typep : tp); } /* end base_type */ /***************************************************************************/