/* Implement I/O-related actions for CHILL. Copyright (C) 1992, 1993, 1994, 1998, 1999, 2000 Free Software Foundation, Inc. This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. GNU CC is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "config.h" #include "system.h" #include "tree.h" #include "ch-tree.h" #include "rtl.h" #include "lex.h" #include "flags.h" #include "input.h" #include "assert.h" #include "toplev.h" /* set non-zero if input text is forced to lowercase */ extern int ignore_case; /* set non-zero if special words are to be entered in uppercase */ extern int special_UC; static int intsize_of_charsexpr PARAMS ((tree)); static tree add_enum_to_list PARAMS ((tree, tree)); static void build_chill_io_list_type PARAMS ((void)); static void build_io_types PARAMS ((void)); static void declare_predefined_file PARAMS ((const char *, const char *)); static tree build_access_part PARAMS ((void)); static tree textlocation_mode PARAMS ((tree)); static int check_assoc PARAMS ((tree, int, const char *)); static tree assoc_call PARAMS ((tree, tree, const char *)); static int check_transfer PARAMS ((tree, int, const char *)); static int connect_process_optionals PARAMS ((tree, tree *, tree *, tree)); static tree connect_text PARAMS ((tree, tree, tree, tree)); static tree connect_access PARAMS ((tree, tree, tree, tree)); static int check_access PARAMS ((tree, int, const char *)); static int check_text PARAMS ((tree, int, const char *)); static tree get_final_type_and_range PARAMS ((tree, tree *, tree *)); static void process_io_list PARAMS ((tree, tree *, tree *, rtx *, int, int)); static void check_format_string PARAMS ((tree, tree, int)); static int get_max_size PARAMS ((tree)); /* association mode */ tree association_type_node; /* initialzier for association mode */ tree association_init_value; /* NOTE: should be same as in runtime/chillrt0.c */ #define STDIO_TEXT_LENGTH 1024 /* mode of stdout, stdin, stderr*/ static tree stdio_type_node; /* usage- and where modes */ tree usage_type_node; tree where_type_node; /* we have to distinguish between io-list-type for WRITETEXT and for READTEXT. WRITETEXT does not process ranges and READTEXT must get pointers to the variables. */ /* variable to hold the type of the io_list */ static tree chill_io_list_type = NULL_TREE; /* the type for the enum tables */ static tree enum_table_type = NULL_TREE; /* structure to save enums for later use in compilation */ typedef struct save_enum_names { struct save_enum_names *forward; tree name; tree decl; } SAVE_ENUM_NAMES; static SAVE_ENUM_NAMES *used_enum_names = (SAVE_ENUM_NAMES *)0; typedef struct save_enum_values { long val; struct save_enum_names *name; } SAVE_ENUM_VALUES; typedef struct save_enums { struct save_enums *forward; tree context; tree type; tree ptrdecl; long num_vals; struct save_enum_values *vals; } SAVE_ENUMS; static SAVE_ENUMS *used_enums = (SAVE_ENUMS *)0; /* Function collects all enums are necessary to collect, makes a copy of the value and returns a VAR_DECL external to current function describing the pointer to a name table, which will be generated at the end of compilation */ static tree add_enum_to_list (type, context) tree type; tree context; { tree tmp; SAVE_ENUMS *wrk = used_enums; SAVE_ENUM_VALUES *vals; SAVE_ENUM_NAMES *names; while (wrk != (SAVE_ENUMS *)0) { /* search for this enum already in use */ if (wrk->context == context && wrk->type == type) { /* yes, found. look if the ptrdecl is valid in this scope */ tree var = DECL_NAME (wrk->ptrdecl); tree decl = lookup_name (var); if (decl == NULL_TREE) { /* no, not valid in this context, declare it */ decl = decl_temp1 (var, build_pointer_type (TREE_TYPE (enum_table_type)), 0, NULL_TREE, 1, 0); } return decl; } /* next one */ wrk = wrk->forward; } /* not yet found -- generate an entry */ wrk = (SAVE_ENUMS *)xmalloc (sizeof (SAVE_ENUMS)); wrk->forward = used_enums; used_enums = wrk; /* generate the pointer decl */ wrk->ptrdecl = get_unique_identifier ("ENUMTABPTR"); wrk->ptrdecl = decl_temp1 (wrk->ptrdecl, build_pointer_type (TREE_TYPE (enum_table_type)), 0, NULL_TREE, 1, 0); /* save information for later use */ wrk->context = context; wrk->type = type; /* insert the names and values */ tmp = TYPE_FIELDS (type); wrk->num_vals = list_length (tmp); vals = (SAVE_ENUM_VALUES *)xmalloc (sizeof (SAVE_ENUM_VALUES) * wrk->num_vals); wrk->vals = vals; while (tmp != NULL_TREE) { /* search if name is already in use */ names = used_enum_names; while (names != (SAVE_ENUM_NAMES *)0) { if (names->name == TREE_PURPOSE (tmp)) break; names = names->forward; } if (names == (SAVE_ENUM_NAMES *)0) { /* we have to insert one */ names = (SAVE_ENUM_NAMES *)xmalloc (sizeof (SAVE_ENUM_NAMES)); names->forward = used_enum_names; used_enum_names = names; names->decl = NULL_TREE; names->name = TREE_PURPOSE (tmp); } vals->name = names; vals->val = TREE_INT_CST_LOW (TREE_VALUE (tmp)); /* next entry in enum */ vals++; tmp = TREE_CHAIN (tmp); } /* return the generated decl */ return wrk->ptrdecl; } static void build_chill_io_list_type () { tree list = NULL_TREE; tree result, enum1, listbase; tree io_descriptor; tree decl1, decl2; tree forcharstring, forset_W, forset_R, forboolrange; tree forintrange, intunion, forsetrange, forcharrange; tree long_type, ulong_type, union_type; long_type = long_integer_type_node; ulong_type = long_unsigned_type_node; if (chill_io_list_type != NULL_TREE) /* already done */ return; /* first build the enum for the desriptor */ enum1 = start_enum (NULL_TREE); result = build_enumerator (get_identifier ("__IO_UNUSED"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ByteVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UByteVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_IntVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UIntVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_LongVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ULongVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ByteLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UByteLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_IntLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UIntLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_LongLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ULongLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ByteRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UByteRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_IntRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_UIntRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_LongRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_ULongRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_BoolVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_BoolLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_BoolRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_SetVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_SetLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_SetRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_CharVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_CharLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_CharRangeLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_CharStrLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_CharVaryingLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_BitStrLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_RealVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_RealLoc"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_LongRealVal"), NULL_TREE); list = chainon (result, list); result = build_enumerator (get_identifier ("__IO_LongRealLoc"), NULL_TREE); list = chainon (result, list); #if 0 result = build_enumerator (get_identifier ("_IO_Pointer"), NULL_TREE); list = chainon (result, list); #endif result = finish_enum (enum1, list); pushdecl (io_descriptor = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_enum"), result)); /* prevent seizing/granting of the decl */ DECL_SOURCE_LINE (io_descriptor) = 0; satisfy_decl (io_descriptor, 0); /* build type for enum_tables */ decl1 = build_decl (FIELD_DECL, get_identifier ("value"), long_type); DECL_INITIAL (decl1) = NULL_TREE; decl2 = build_decl (FIELD_DECL, get_identifier ("name"), build_pointer_type (char_type_node)); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (decl1); pushdecl (enum_table_type = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_enum_table_type"), result)); DECL_SOURCE_LINE (enum_table_type) = 0; satisfy_decl (enum_table_type, 0); /* build type for writing a set mode */ decl1 = build_decl (FIELD_DECL, get_identifier ("value"), long_type); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("name_table"), build_pointer_type (TREE_TYPE (enum_table_type))); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forset_W = build_decl (TYPE_DECL, get_identifier ("__tmp_WIO_set"), result)); DECL_SOURCE_LINE (forset_W) = 0; satisfy_decl (forset_W, 0); /* build type for charrange */ decl1 = build_decl (FIELD_DECL, get_identifier ("ptr"), build_pointer_type (char_type_node)); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("lower"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("upper"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forcharrange = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_charrange"), result)); DECL_SOURCE_LINE (forcharrange) = 0; satisfy_decl (forcharrange, 0); /* type for integer range */ decl1 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("_slong"), long_type)); listbase = decl1; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("_ulong"), ulong_type)); TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; decl1 = grok_chill_variantdefs (NULL_TREE, listbase, NULL_TREE); TREE_CHAIN (decl1) = NULL_TREE; result = build_chill_struct_type (decl1); pushdecl (intunion = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_long"), result)); DECL_SOURCE_LINE (intunion) = 0; satisfy_decl (intunion, 0); decl1 = build_decl (FIELD_DECL, get_identifier ("ptr"), ptr_type_node); listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("lower"), TREE_TYPE (intunion)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("upper"), TREE_TYPE (intunion)); TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forintrange = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_intrange"), result)); DECL_SOURCE_LINE (forintrange) = 0; satisfy_decl (forintrange, 0); /* build structure for bool range */ decl1 = build_decl (FIELD_DECL, get_identifier ("ptr"), ptr_type_node); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("lower"), ulong_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("upper"), ulong_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forboolrange = build_decl (TYPE_DECL, get_identifier ("__tmp_RIO_boolrange"), result)); DECL_SOURCE_LINE (forboolrange) = 0; satisfy_decl (forboolrange, 0); /* build type for reading a set */ decl1 = build_decl (FIELD_DECL, get_identifier ("ptr"), ptr_type_node); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("length"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("name_table"), build_pointer_type (TREE_TYPE (enum_table_type))); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forset_R = build_decl (TYPE_DECL, get_identifier ("__tmp_RIO_set"), result)); DECL_SOURCE_LINE (forset_R) = 0; satisfy_decl (forset_R, 0); /* build type for setrange */ decl1 = build_decl (FIELD_DECL, get_identifier ("ptr"), ptr_type_node); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("length"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("name_table"), build_pointer_type (TREE_TYPE (enum_table_type))); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("lower"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("upper"), long_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forsetrange = build_decl (TYPE_DECL, get_identifier ("__tmp_RIO_setrange"), result)); DECL_SOURCE_LINE (forsetrange) = 0; satisfy_decl (forsetrange, 0); /* build structure for character string */ decl1 = build_decl (FIELD_DECL, get_identifier ("string"), build_pointer_type (char_type_node)); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("string_length"), ulong_type); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (forcharstring = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_forcharstring"), result)); DECL_SOURCE_LINE (forcharstring) = 0; satisfy_decl (forcharstring, 0); /* build the union */ decl1 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valbyte"), signed_char_type_node)); listbase = decl1; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valubyte"), unsigned_char_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valint"), chill_integer_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valuint"), chill_unsigned_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__vallong"), long_type)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valulong"), ulong_type)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locint"), ptr_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locintrange"), TREE_TYPE (forintrange))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valbool"), boolean_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locbool"), build_pointer_type (boolean_type_node))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locboolrange"), TREE_TYPE (forboolrange))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valset"), TREE_TYPE (forset_W))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locset"), TREE_TYPE (forset_R))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locsetrange"), TREE_TYPE (forsetrange))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valchar"), char_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locchar"), build_pointer_type (char_type_node))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__loccharrange"), TREE_TYPE (forcharrange))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__loccharstring"), TREE_TYPE (forcharstring))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__valreal"), float_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__locreal"), build_pointer_type (float_type_node))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__vallongreal"), double_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__loclongreal"), build_pointer_type (double_type_node))); TREE_CHAIN (decl1) = decl2; decl1 = decl2; #if 0 decl2 = build_tree_list (NULL_TREE, build_decl (FIELD_DECL, get_identifier ("__forpointer"), ptr_type_node)); TREE_CHAIN (decl1) = decl2; decl1 = decl2; #endif TREE_CHAIN (decl2) = NULL_TREE; decl1 = grok_chill_variantdefs (NULL_TREE, listbase, NULL_TREE); TREE_CHAIN (decl1) = NULL_TREE; result = build_chill_struct_type (decl1); pushdecl (union_type = build_decl (TYPE_DECL, get_identifier ("__tmp_WIO_union"), result)); DECL_SOURCE_LINE (union_type) = 0; satisfy_decl (union_type, 0); /* now build the final structure */ decl1 = build_decl (FIELD_DECL, get_identifier ("__t"), TREE_TYPE (union_type)); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("__descr"), long_type); TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (chill_io_list_type = build_decl (TYPE_DECL, get_identifier ("__tmp_IO_list"), result)); DECL_SOURCE_LINE (chill_io_list_type) = 0; satisfy_decl (chill_io_list_type, 0); } /* build the ASSOCIATION, ACCESS and TEXT mode types */ static void build_io_types () { tree listbase, decl1, decl2, result, association; tree acc, txt, tloc; tree enum1, tmp; /* the association mode */ listbase = build_decl (FIELD_DECL, get_identifier ("flags"), long_unsigned_type_node); DECL_INITIAL (listbase) = NULL_TREE; decl1 = listbase; decl2 = build_decl (FIELD_DECL, get_identifier ("pathname"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("access"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("handle"), integer_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("bufptr"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("syserrno"), long_integer_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("usage"), char_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("ctl_pre"), char_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("ctl_post"), char_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (association = build_decl (TYPE_DECL, ridpointers[(int)RID_ASSOCIATION], result)); DECL_SOURCE_LINE (association) = 0; satisfy_decl (association, 0); association_type_node = TREE_TYPE (association); TYPE_NAME (association_type_node) = association; CH_NOVELTY (association_type_node) = association; CH_TYPE_NONVALUE_P(association_type_node) = 1; CH_TYPE_NONVALUE_P(association) = 1; /* initialiser for association type */ tmp = convert (char_type_node, integer_zero_node); association_init_value = build_nt (CONSTRUCTOR, NULL_TREE, tree_cons (NULL_TREE, integer_zero_node, /* flags */ tree_cons (NULL_TREE, null_pointer_node, /* pathname */ tree_cons (NULL_TREE, null_pointer_node, /* access */ tree_cons (NULL_TREE, integer_minus_one_node, /* handle */ tree_cons (NULL_TREE, null_pointer_node, /* bufptr */ tree_cons (NULL_TREE, integer_zero_node, /* syserrno */ tree_cons (NULL_TREE, tmp, /* usage */ tree_cons (NULL_TREE, tmp, /* ctl_pre */ tree_cons (NULL_TREE, tmp, /* ctl_post */ NULL_TREE)))))))))); /* the type for stdin, stdout, stderr */ /* text part */ decl1 = build_decl (FIELD_DECL, get_identifier ("flags"), long_unsigned_type_node); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("text_record"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("access_sub"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("actual_index"), long_unsigned_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; txt = build_chill_struct_type (listbase); /* access part */ decl1 = build_decl (FIELD_DECL, get_identifier ("flags"), long_unsigned_type_node); DECL_INITIAL (decl1) = NULL_TREE; listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("reclength"), long_unsigned_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("lowindex"), long_integer_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("highindex"), long_integer_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl2 = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("association"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("base"), long_unsigned_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("storelocptr"), ptr_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("rectype"), long_integer_type_node); DECL_INITIAL (decl2) = NULL_TREE; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; acc = build_chill_struct_type (listbase); /* the location */ tmp = build_string_type (char_type_node, build_int_2 (STDIO_TEXT_LENGTH, 0)); tloc = build_varying_struct (tmp); /* now the final mode */ decl1 = build_decl (FIELD_DECL, get_identifier ("txt"), txt); listbase = decl1; decl2 = build_decl (FIELD_DECL, get_identifier ("acc"), acc); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (FIELD_DECL, get_identifier ("tloc"), tloc); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_lang_decl (TYPE_DECL, get_identifier ("__indexmode"), void_type_node); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (CONST_DECL, get_identifier ("__textlength"), integer_type_node); DECL_INITIAL (decl2) = build_int_2 (STDIO_TEXT_LENGTH, 0); TREE_CHAIN (decl1) = decl2; decl1 = decl2; decl2 = build_decl (CONST_DECL, get_identifier ("__dynamic"), integer_type_node); DECL_INITIAL (decl2) = integer_zero_node; TREE_CHAIN (decl1) = decl2; TREE_CHAIN (decl2) = NULL_TREE; result = build_chill_struct_type (listbase); pushdecl (tmp = build_decl (TYPE_DECL, get_identifier ("__stdio_text"), result)); DECL_SOURCE_LINE (tmp) = 0; satisfy_decl (tmp, 0); stdio_type_node = TREE_TYPE (tmp); CH_IS_TEXT_MODE (stdio_type_node) = 1; /* predefined usage mode */ enum1 = start_enum (NULL_TREE); listbase = NULL_TREE; result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "readonly" : "READONLY"), NULL_TREE); listbase = chainon (result, listbase); result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "writeonly" : "WRITEONLY"), NULL_TREE); listbase = chainon (result, listbase); result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "readwrite" : "READWRITE"), NULL_TREE); listbase = chainon (result, listbase); result = finish_enum (enum1, listbase); pushdecl (tmp = build_decl (TYPE_DECL, get_identifier ((ignore_case || ! special_UC) ? "usage" : "USAGE"), result)); DECL_SOURCE_LINE (tmp) = 0; satisfy_decl (tmp, 0); usage_type_node = TREE_TYPE (tmp); TYPE_NAME (usage_type_node) = tmp; CH_NOVELTY (usage_type_node) = tmp; /* predefined where mode */ enum1 = start_enum (NULL_TREE); listbase = NULL_TREE; result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "first" : "FIRST"), NULL_TREE); listbase = chainon (result, listbase); result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "same" : "SAME"), NULL_TREE); listbase = chainon (result, listbase); result = build_enumerator ( get_identifier ((ignore_case || ! special_UC) ? "last" : "LAST"), NULL_TREE); listbase = chainon (result, listbase); result = finish_enum (enum1, listbase); pushdecl (tmp = build_decl (TYPE_DECL, get_identifier ((ignore_case || ! special_UC) ? "where" : "WHERE"), result)); DECL_SOURCE_LINE (tmp) = 0; satisfy_decl (tmp, 0); where_type_node = TREE_TYPE (tmp); TYPE_NAME (where_type_node) = tmp; CH_NOVELTY (where_type_node) = tmp; } static void declare_predefined_file (name, assembler_name) const char *name; const char *assembler_name; { tree decl = build_lang_decl (VAR_DECL, get_identifier (name), stdio_type_node); DECL_ASSEMBLER_NAME (decl) = get_identifier(assembler_name); TREE_STATIC (decl) = 1; TREE_PUBLIC (decl) = 1; DECL_EXTERNAL (decl) = 1; DECL_IN_SYSTEM_HEADER (decl) = 1; make_decl_rtl (decl, 0, 1); pushdecl (decl); } /* initialisation of all IO/related functions, types, etc. */ void inout_init () { /* We temporarily reset the maximum_field_alignment to zero so the compiler's init data structures can be compatible with the run-time system, even when we're compiling with -fpack. */ unsigned int save_maximum_field_alignment = maximum_field_alignment; extern tree chill_predefined_function_type; tree endlink = void_list_node; tree bool_ftype_ptr_ptr_int; tree ptr_ftype_ptr_ptr_int; tree luns_ftype_ptr_ptr_int; tree int_ftype_ptr_ptr_int; tree ptr_ftype_ptr_ptr_int_ptr_int_ptr_int; tree void_ftype_ptr_ptr_int_ptr_int_ptr_int; tree void_ftype_ptr_ptr_int; tree void_ftype_ptr_ptr_int_int_int_long_ptr_int; tree ptr_ftype_ptr_int_ptr_ptr_int; tree void_ftype_ptr_int_ptr_luns_ptr_int; tree void_ftype_ptr_ptr_ptr_int; tree void_ftype_ptr_int_ptr_int; tree void_ftype_ptr_int_ptr_int_ptr_int_ptr_int; maximum_field_alignment = 0; builtin_function ((ignore_case || ! special_UC) ? "associate" : "ASSOCIATE", chill_predefined_function_type, BUILT_IN_ASSOCIATE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "connect" : "CONNECT", chill_predefined_function_type, BUILT_IN_CONNECT, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "create" : "CREATE", chill_predefined_function_type, BUILT_IN_CREATE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "delete" : "DELETE", chill_predefined_function_type, BUILT_IN_CH_DELETE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "disconnect" : "DISCONNECT", chill_predefined_function_type, BUILT_IN_DISCONNECT, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "dissociate" : "DISSOCIATE", chill_predefined_function_type, BUILT_IN_DISSOCIATE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "eoln" : "EOLN", chill_predefined_function_type, BUILT_IN_EOLN, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "existing" : "EXISTING", chill_predefined_function_type, BUILT_IN_EXISTING, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "getassociation" : "GETASSOCIATION", chill_predefined_function_type, BUILT_IN_GETASSOCIATION, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "gettextaccess" : "GETTEXTASSCESS", chill_predefined_function_type, BUILT_IN_GETTEXTACCESS, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "gettextindex" : "GETTEXTINDEX", chill_predefined_function_type, BUILT_IN_GETTEXTINDEX, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "gettextrecord" : "GETTEXTRECORD", chill_predefined_function_type, BUILT_IN_GETTEXTRECORD, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "getusage" : "GETUSAGE", chill_predefined_function_type, BUILT_IN_GETUSAGE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "indexable" : "INDEXABLE", chill_predefined_function_type, BUILT_IN_INDEXABLE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "isassociated" : "ISASSOCIATED", chill_predefined_function_type, BUILT_IN_ISASSOCIATED, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "modify" : "MODIFY", chill_predefined_function_type, BUILT_IN_MODIFY, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "outoffile" : "OUTOFFILE", chill_predefined_function_type, BUILT_IN_OUTOFFILE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "readable" : "READABLE", chill_predefined_function_type, BUILT_IN_READABLE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "readrecord" : "READRECORD", chill_predefined_function_type, BUILT_IN_READRECORD, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "readtext" : "READTEXT", chill_predefined_function_type, BUILT_IN_READTEXT, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "sequencible" : "SEQUENCIBLE", chill_predefined_function_type, BUILT_IN_SEQUENCIBLE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "settextaccess" : "SETTEXTACCESS", chill_predefined_function_type, BUILT_IN_SETTEXTACCESS, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "settextindex" : "SETTEXTINDEX", chill_predefined_function_type, BUILT_IN_SETTEXTINDEX, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "settextrecord" : "SETTEXTRECORD", chill_predefined_function_type, BUILT_IN_SETTEXTRECORD, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "variable" : "VARIABLE", chill_predefined_function_type, BUILT_IN_VARIABLE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "writeable" : "WRITEABLE", chill_predefined_function_type, BUILT_IN_WRITEABLE, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "writerecord" : "WRITERECORD", chill_predefined_function_type, BUILT_IN_WRITERECORD, BUILT_IN_NORMAL, NULL_PTR); builtin_function ((ignore_case || ! special_UC) ? "writetext" : "WRITETEXT", chill_predefined_function_type, BUILT_IN_WRITETEXT, BUILT_IN_NORMAL, NULL_PTR); /* build function prototypes */ bool_ftype_ptr_ptr_int = build_function_type (boolean_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))); ptr_ftype_ptr_ptr_int_ptr_int_ptr_int = build_function_type (ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))))))); void_ftype_ptr_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))); void_ftype_ptr_ptr_int_ptr_int_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))))))); void_ftype_ptr_ptr_int_int_int_long_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, long_integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink))))))))); ptr_ftype_ptr_ptr_int = build_function_type (ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))); int_ftype_ptr_ptr_int = build_function_type (integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))); ptr_ftype_ptr_int_ptr_ptr_int = build_function_type (ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))))); void_ftype_ptr_int_ptr_luns_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, long_unsigned_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink))))))); luns_ftype_ptr_ptr_int = build_function_type (long_unsigned_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink)))); void_ftype_ptr_ptr_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink))))); void_ftype_ptr_int_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink))))); void_ftype_ptr_int_ptr_int_ptr_int_ptr_int = build_function_type (void_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, tree_cons (NULL_TREE, ptr_type_node, tree_cons (NULL_TREE, integer_type_node, endlink))))))))); builtin_function ("__associate", ptr_ftype_ptr_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__connect", void_ftype_ptr_ptr_int_int_int_long_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__create", void_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__delete", void_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__disconnect", void_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__dissociate", void_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__eoln", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__existing", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__getassociation", ptr_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__gettextaccess", ptr_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__gettextindex", luns_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__gettextrecord", ptr_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__getusage", int_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__indexable", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__isassociated", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__modify", void_ftype_ptr_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__outoffile", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__readable", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__readrecord", ptr_ftype_ptr_int_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__readtext_f", void_ftype_ptr_int_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__readtext_s", void_ftype_ptr_int_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__sequencible", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__settextaccess", void_ftype_ptr_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__settextindex", void_ftype_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__settextrecord", void_ftype_ptr_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__variable", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__writeable", bool_ftype_ptr_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__writerecord", void_ftype_ptr_int_ptr_luns_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__writetext_f", void_ftype_ptr_int_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); builtin_function ("__writetext_s", void_ftype_ptr_int_ptr_int_ptr_int_ptr_int, 0, NOT_BUILT_IN, NULL_PTR); /* declare ASSOCIATION, ACCESS, and TEXT modes */ build_io_types (); /* declare the predefined text locations */ declare_predefined_file ((ignore_case || ! special_UC) ? "stdin" : "STDIN", "chill_stdin"); declare_predefined_file ((ignore_case || ! special_UC) ? "stdout" : "STDOUT", "chill_stdout"); declare_predefined_file ((ignore_case || ! special_UC) ? "stderr" : "STDERR", "chill_stderr"); /* last, but not least, build the chill IO-list type */ build_chill_io_list_type (); maximum_field_alignment = save_maximum_field_alignment; } /* function returns the recordmode of an ACCESS */ tree access_recordmode (access) tree access; { tree field; if (access == NULL_TREE || TREE_CODE (access) == ERROR_MARK) return NULL_TREE; if (! CH_IS_ACCESS_MODE (access)) return NULL_TREE; field = TYPE_FIELDS (access); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == TYPE_DECL && DECL_NAME (field) == get_identifier ("__recordmode")) return TREE_TYPE (field); } return void_type_node; } /* function invalidates the recordmode of an ACCESS */ void invalidate_access_recordmode (access) tree access; { tree field; if (access == NULL_TREE || TREE_CODE (access) == ERROR_MARK) return; if (! CH_IS_ACCESS_MODE (access)) return; field = TYPE_FIELDS (access); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == TYPE_DECL && DECL_NAME (field) == get_identifier ("__recordmode")) { TREE_TYPE (field) = error_mark_node; return; } } } /* function returns the index mode of an ACCESS if there is one, otherwise NULL_TREE */ tree access_indexmode (access) tree access; { tree field; if (access == NULL_TREE || TREE_CODE (access) == ERROR_MARK) return NULL_TREE; if (! CH_IS_ACCESS_MODE (access)) return NULL_TREE; field = TYPE_FIELDS (access); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == TYPE_DECL && DECL_NAME (field) == get_identifier ("__indexmode")) return TREE_TYPE (field); } return void_type_node; } /* function returns one if an ACCESS was specified DYNAMIC, otherwise zero */ tree access_dynamic (access) tree access; { tree field; if (access == NULL_TREE || TREE_CODE (access) == ERROR_MARK) return NULL_TREE; if (! CH_IS_ACCESS_MODE (access)) return NULL_TREE; field = TYPE_FIELDS (access); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == CONST_DECL) return DECL_INITIAL (field); } return integer_zero_node; } #if 0 returns a structure like STRUCT (data STRUCT (flags ULONG, reclength ULONG, lowindex LONG, highindex LONG, association PTR, base ULONG, store_loc PTR, rectype LONG), this is followed by a TYPE_DECL __recordmode recordmode ? recordmode : void_type_node TYPE_DECL __indexmode indexmode ? indexmode : void_type_node CONST_DECL __dynamic dynamic ? integer_one_node : integer_zero_node #endif static tree build_access_part () { tree listbase, decl; listbase = build_decl (FIELD_DECL, get_identifier ("flags"), long_unsigned_type_node); decl = build_decl (FIELD_DECL, get_identifier ("reclength"), long_unsigned_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("lowindex"), long_unsigned_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("highindex"), long_integer_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("association"), ptr_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("base"), long_unsigned_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("storelocptr"), ptr_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("rectype"), long_integer_type_node); listbase = chainon (listbase, decl); return build_chill_struct_type (listbase); } tree build_access_mode (indexmode, recordmode, dynamic) tree indexmode; tree recordmode; int dynamic; { tree type, listbase, decl, datamode; if (indexmode != NULL_TREE && TREE_CODE (indexmode) == ERROR_MARK) return error_mark_node; if (recordmode != NULL_TREE && TREE_CODE (recordmode) == ERROR_MARK) return error_mark_node; datamode = build_access_part (); type = make_node (RECORD_TYPE); listbase = build_decl (FIELD_DECL, get_identifier ("data"), datamode); TYPE_FIELDS (type) = listbase; decl = build_lang_decl (TYPE_DECL, get_identifier ("__recordmode"), recordmode == NULL_TREE ? void_type_node : recordmode); chainon (listbase, decl); decl = build_lang_decl (TYPE_DECL, get_identifier ("__indexmode"), indexmode == NULL_TREE ? void_type_node : indexmode); chainon (listbase, decl); decl = build_decl (CONST_DECL, get_identifier ("__dynamic"), integer_type_node); DECL_INITIAL (decl) = dynamic ? integer_one_node : integer_zero_node; chainon (listbase, decl); CH_IS_ACCESS_MODE (type) = 1; CH_TYPE_NONVALUE_P (type) = 1; return type; } #if 0 returns a structure like: STRUCT (txt STRUCT (flags ULONG, text_record PTR, access_sub PTR, actual_index LONG), acc STRUCT (flags ULONG, reclength ULONG, lowindex LONG, highindex LONG, association PTR, base ULONG, store_loc PTR, rectype LONG), tloc CHARS(textlength) VARYING; ) followed by TYPE_DECL __indexmode indexmode ? indexmode : void_type_node CONST_DECL __text_length CONST_DECL __dynamic dynamic ? integer_one_node : integer_zero_node #endif tree build_text_mode (textlength, indexmode, dynamic) tree textlength; tree indexmode; int dynamic; { tree txt, acc, listbase, decl, type, tltype; tree savedlength = textlength; if (indexmode != NULL_TREE && TREE_CODE (indexmode) == ERROR_MARK) return error_mark_node; if (textlength == NULL_TREE || TREE_CODE (textlength) == ERROR_MARK) return error_mark_node; /* build the structure */ listbase = build_decl (FIELD_DECL, get_identifier ("flags"), long_unsigned_type_node); decl = build_decl (FIELD_DECL, get_identifier ("text_record"), ptr_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("access_sub"), ptr_type_node); listbase = chainon (listbase, decl); decl = build_decl (FIELD_DECL, get_identifier ("actual_index"), long_integer_type_node); listbase = chainon (listbase, decl); txt = build_chill_struct_type (listbase); acc = build_access_part (); type = make_node (RECORD_TYPE); listbase = build_decl (FIELD_DECL, get_identifier ("txt"), txt); TYPE_FIELDS (type) = listbase; decl = build_decl (FIELD_DECL, get_identifier ("acc"), acc); chainon (listbase, decl); /* the text location */ tltype = build_string_type (char_type_node, textlength); tltype = build_varying_struct (tltype); decl = build_decl (FIELD_DECL, get_identifier ("tloc"), tltype); chainon (listbase, decl); /* the index mode */ decl = build_lang_decl (TYPE_DECL, get_identifier ("__indexmode"), indexmode == NULL_TREE ? void_type_node : indexmode); chainon (listbase, decl); /* save dynamic */ decl = build_decl (CONST_DECL, get_identifier ("__textlength"), integer_type_node); if (TREE_CODE (textlength) == COMPONENT_REF) /* FIXME: we cannot use one and the same COMPONENT_REF twice, so build another one */ savedlength = build_component_ref (TREE_OPERAND (textlength, 0), TREE_OPERAND (textlength, 1)); DECL_INITIAL (decl) = savedlength; chainon (listbase, decl); /* save dynamic */ decl = build_decl (CONST_DECL, get_identifier ("__dynamic"), integer_type_node); DECL_INITIAL (decl) = dynamic ? integer_one_node : integer_zero_node; chainon (listbase, decl); CH_IS_TEXT_MODE (type) = 1; CH_TYPE_NONVALUE_P (type) = 1; return type; } tree check_text_length (length) tree length; { if (length == NULL_TREE || TREE_CODE (length) == ERROR_MARK) return length; if (TREE_TYPE (length) == NULL_TREE || !CH_SIMILAR (TREE_TYPE (length), integer_type_node)) { error ("non-integral text length"); return integer_one_node; } if (TREE_CODE (length) != INTEGER_CST) { error ("non-constant text length"); return integer_one_node; } if (compare_int_csts (LE_EXPR, length, integer_zero_node)) { error ("text length must be greater then 0"); return integer_one_node; } return length; } tree text_indexmode (text) tree text; { tree field; if (text == NULL_TREE || TREE_CODE (text) == ERROR_MARK) return NULL_TREE; if (! CH_IS_TEXT_MODE (text)) return NULL_TREE; field = TYPE_FIELDS (text); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == TYPE_DECL) return TREE_TYPE (field); } return void_type_node; } tree text_dynamic (text) tree text; { tree field; if (text == NULL_TREE || TREE_CODE (text) == ERROR_MARK) return NULL_TREE; if (! CH_IS_TEXT_MODE (text)) return NULL_TREE; field = TYPE_FIELDS (text); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == CONST_DECL && DECL_NAME (field) == get_identifier ("__dynamic")) return DECL_INITIAL (field); } return integer_zero_node; } tree text_length (text) tree text; { tree field; if (text == NULL_TREE || TREE_CODE (text) == ERROR_MARK) return NULL_TREE; if (! CH_IS_TEXT_MODE (text)) return NULL_TREE; field = TYPE_FIELDS (text); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == CONST_DECL && DECL_NAME (field) == get_identifier ("__textlength")) return DECL_INITIAL (field); } return integer_zero_node; } static tree textlocation_mode (text) tree text; { tree field; if (text == NULL_TREE || TREE_CODE (text) == ERROR_MARK) return NULL_TREE; if (! CH_IS_TEXT_MODE (text)) return NULL_TREE; field = TYPE_FIELDS (text); for ( ; field != NULL_TREE; field = TREE_CHAIN (field)) { if (TREE_CODE (field) == FIELD_DECL && DECL_NAME (field) == get_identifier ("tloc")) return TREE_TYPE (field); } return NULL_TREE; } static int check_assoc (assoc, argnum, errmsg) tree assoc; int argnum; const char *errmsg; { if (assoc == NULL_TREE || TREE_CODE (assoc) == ERROR_MARK) return 0; if (! CH_IS_ASSOCIATION_MODE (TREE_TYPE (assoc))) { error ("argument %d of %s must be of mode ASSOCIATION", argnum, errmsg); return 0; } if (! CH_LOCATION_P (assoc)) { error ("argument %d of %s must be a location", argnum, errmsg); return 0; } return 1; } tree build_chill_associate (assoc, fname, attr) tree assoc; tree fname; tree attr; { tree arg1 = NULL_TREE, arg2 = NULL_TREE, arg3 = NULL_TREE, arg4 = NULL_TREE, arg5 = NULL_TREE, arg6, arg7; int had_errors = 0; tree result; /* make some checks */ if (fname == NULL_TREE || TREE_CODE (fname) == ERROR_MARK) return error_mark_node; /* check the association */ if (! check_assoc (assoc, 1, "ASSOCIATION")) had_errors = 1; else /* build a pointer to the association */ arg1 = force_addr_of (assoc); /* check the filename, must be a string */ if (CH_CHARS_TYPE_P (TREE_TYPE (fname)) || (flag_old_strings && TREE_CODE (fname) == INTEGER_CST && TREE_CODE (TREE_TYPE (fname)) == CHAR_TYPE)) { if (int_size_in_bytes (TREE_TYPE (fname)) == 0) { error ("argument 2 of ASSOCIATE must not be an empty string"); had_errors = 1; } else { arg2 = force_addr_of (fname); arg3 = size_in_bytes (TREE_TYPE (fname)); } } else if (chill_varying_string_type_p (TREE_TYPE (fname))) { arg2 = force_addr_of (build_component_ref (fname, var_data_id)); arg3 = build_component_ref (fname, var_length_id); } else { error ("argument 2 to ASSOCIATE must be a string"); had_errors = 1; } /* check attr argument, must be a string too */ if (attr == NULL_TREE) { arg4 = null_pointer_node; arg5 = integer_zero_node; } else { attr = TREE_VALUE (attr); if (attr == NULL_TREE || TREE_CODE (attr) == ERROR_MARK) had_errors = 1; else { if (CH_CHARS_TYPE_P (TREE_TYPE (attr)) || (flag_old_strings && TREE_CODE (attr) == INTEGER_CST && TREE_CODE (TREE_TYPE (attr)) == CHAR_TYPE)) { if (int_size_in_bytes (TREE_TYPE (attr)) == 0) { arg4 = null_pointer_node; arg5 = integer_zero_node; } else { arg4 = force_addr_of (attr); arg5 = size_in_bytes (TREE_TYPE (attr)); } } else if (chill_varying_string_type_p (TREE_TYPE (attr))) { arg4 = force_addr_of (build_component_ref (attr, var_data_id)); arg5 = build_component_ref (attr, var_length_id); } else { error ("argument 3 to ASSOCIATE must be a string"); had_errors = 1; } } } if (had_errors) return error_mark_node; /* other arguments */ arg6 = force_addr_of (get_chill_filename ()); arg7 = get_chill_linenumber (); result = build_chill_function_call ( lookup_name (get_identifier ("__associate")), tree_cons (NULL_TREE, arg1, tree_cons (NULL_TREE, arg2, tree_cons (NULL_TREE, arg3, tree_cons (NULL_TREE, arg4, tree_cons (NULL_TREE, arg5, tree_cons (NULL_TREE, arg6, tree_cons (NULL_TREE, arg7, NULL_TREE)))))))); TREE_TYPE (result) = build_chill_pointer_type (TREE_TYPE (assoc)); return result; } static tree assoc_call (assoc, func, name) tree assoc; tree func; const char *name; { tree arg1, arg2, arg3; tree result; if (! check_assoc (assoc, 1, name)) return error_mark_node; arg1 = force_addr_of (assoc); arg2 = force_addr_of (get_chill_filename ()); arg3 = get_chill_linenumber (); result = build_chill_function_call (func, tree_cons (NULL_TREE, arg1, tree_cons (NULL_TREE, arg2, tree_cons (NULL_TREE, arg3, NULL_TREE)))); return result; } tree build_chill_isassociated (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__isassociated")), "ISASSOCIATED"); return result; } tree build_chill_existing (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__existing")), "EXISTING"); return result; } tree build_chill_readable (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__readable")), "READABLE"); return result; } tree build_chill_writeable (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__writeable")), "WRITEABLE"); return result; } tree build_chill_sequencible (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__sequencible")), "SEQUENCIBLE"); return result; } tree build_chill_variable (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__variable")), "VARIABLE"); return result; } tree build_chill_indexable (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__indexable")), "INDEXABLE"); return result; } tree build_chill_dissociate (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__dissociate")), "DISSOCIATE"); return result; } tree build_chill_create (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__create")), "CREATE"); return result; } tree build_chill_delete (assoc) tree assoc; { tree result = assoc_call (assoc, lookup_name (get_identifier ("__delete")), "DELETE"); return result; } tree build_chill_modify (assoc, list) tree assoc; tree list; { tree arg1 = NULL_TREE, arg2 = NULL_TREE, arg3 = NULL_TREE, arg4 = NULL_TREE, arg5 = NULL_TREE, arg6, arg7; int had_errors = 0, numargs; tree fname = NULL_TREE, attr = NULL_TREE; tree result; /* check the association */ if (! check_assoc (assoc, 1, "MODIFY")) had_errors = 1; else arg1 = force_addr_of (assoc); /* look how much arguments we have got */ numargs = list_length (list); switch (numargs) { case 0: break; case 1: fname = TREE_VALUE (list); break; case 2: fname = TREE_VALUE (list); attr = TREE_VALUE (TREE_CHAIN (list)); break; default: error ("Too many arguments in call to MODIFY"); had_errors = 1; break; } if (fname != NULL_TREE && fname != null_pointer_node) { if (CH_CHARS_TYPE_P (TREE_TYPE (fname)) || (flag_old_strings && TREE_CODE (fname) == INTEGER_CST && TREE_CODE (TREE_TYPE (fname)) == CHAR_TYPE)) { if (int_size_in_bytes (TREE_TYPE (fname)) == 0) { error ("argument 2 of MODIFY must not be an empty string"); had_errors = 1; } else { arg2 = force_addr_of (fname); arg3 = size_in_bytes (TREE_TYPE (fname)); } } else if (chill_varying_string_type_p (TREE_TYPE (fname))) { arg2 = force_addr_of (build_component_ref (fname, var_data_id)); arg3 = build_component_ref (fname, var_length_id); } else { error ("argument 2 to MODIFY must be a string"); had_errors = 1; } } else { arg2 = null_pointer_node; arg3 = integer_zero_node; } if (attr != NULL_TREE && attr != null_pointer_node) { if (CH_CHARS_TYPE_P (TREE_TYPE (attr)) || (flag_old_strings && TREE_CODE (attr) == INTEGER_CST && TREE_CODE (TREE_TYPE (attr)) == CHAR_TYPE)) { if (int_size_in_bytes (TREE_TYPE (attr)) == 0) { arg4 = null_pointer_node; arg5 = integer_zero_node; } else { arg4 = force_addr_of (attr); arg5 = size_in_bytes (TREE_TYPE (attr)); } } else if (chill_varying_string_type_p (TREE_TYPE (attr))) { arg4 = force_addr_of (build_component_ref (attr, var_data_id)); arg5 = build_component_ref (attr, var_length_id); } else { error ("argument 3 to MODIFY must be a string"); had_errors = 1; } } else { arg4 = null_pointer_node; arg5 = integer_zero_node; } if (had_errors) return error_mark_node; /* other arguments */ arg6 = force_addr_of (get_chill_filename ()); arg7 = get_chill_linenumber (); result = build_chill_function_call ( lookup_name (get_identifier ("__modify")), tree_cons (NULL_TREE, arg1, tree_cons (NULL_TREE, arg2, tree_cons (NULL_TREE, arg3, tree_cons (NULL_TREE, arg4, tree_cons (NULL_TREE, arg5, tree_cons (NULL_TREE, arg6, tree_cons (NULL_TREE, arg7, NULL_TREE)))))))); return result; } static int check_transfer (transfer, argnum, errmsg) tree transfer; int argnum; const char *errmsg; { int result = 0; if (transfer == NULL_TREE || TREE_CODE (transfer) == ERROR_MARK) return 0; if (CH_IS_ACCESS_MODE (TREE_TYPE (transfer))) result = 1; else if (CH_IS_TEXT_MODE (TREE_TYPE (transfer))) result = 2; else { error ("argument %d of %s must be an ACCESS or TEXT mode", argnum, errmsg); return 0; } if (! CH_LOCATION_P (transfer)) { error ("argument %d of %s must be a location", argnum, errmsg); return 0; } return result; } /* define bits in an access/text flag word. NOTE: this must be consistent with runtime/iomodes.h */ #define IO_TEXTLOCATION 0x80000000 #define IO_INDEXED 0x00000001 #define IO_TEXTIO 0x00000002 #define IO_OUTOFFILE 0x00010000 /* generated initialisation code for ACCESS and TEXT. functions gets called from do_decl. */ void init_access_location (decl, type) tree decl; tree type; { tree recordmode = access_recordmode (type); tree indexmode = access_indexmode (type); int flags_init = 0; tree data = build_component_ref (decl, get_identifier ("data")); tree lowindex = integer_zero_node; tree highindex = integer_zero_node; tree rectype, reclen; /* flag word */ if (indexmode != NULL_TREE && indexmode != void_type_node) { flags_init |= IO_INDEXED; lowindex = convert (integer_type_node, TYPE_MIN_VALUE (indexmode)); highindex = convert (integer_type_node, TYPE_MAX_VALUE (indexmode)); } expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("flags")), build_int_2 (flags_init, 0))); /* record length */ if (recordmode == NULL_TREE || recordmode == void_type_node) { reclen = integer_zero_node; rectype = integer_zero_node; } else if (chill_varying_string_type_p (recordmode)) { tree fields = TYPE_FIELDS (recordmode); tree len1, len2; /* don't count any padding bytes at end of varying */ len1 = size_in_bytes (TREE_TYPE (fields)); fields = TREE_CHAIN (fields); len2 = size_in_bytes (TREE_TYPE (fields)); reclen = fold (build (PLUS_EXPR, long_integer_type_node, len1, len2)); rectype = build_int_2 (2, 0); } else { reclen = size_in_bytes (recordmode); rectype = integer_one_node; } expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("reclength")), reclen)); /* record type */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("rectype")), rectype)); /* the index */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("lowindex")), lowindex)); expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("highindex")), highindex)); /* association */ expand_expr_stmt ( build_chill_modify_expr ( build_chill_component_ref (data, get_identifier ("association")), null_pointer_node)); /* storelocptr */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("storelocptr")), null_pointer_node)); } void init_text_location (decl, type) tree decl; tree type; { tree indexmode = text_indexmode (type); unsigned long accessflags = 0; unsigned long textflags = IO_TEXTLOCATION; tree lowindex = integer_zero_node; tree highindex = integer_zero_node; tree data, tloc, tlocfields, len1, len2, reclen; if (indexmode != NULL_TREE && indexmode != void_type_node) { accessflags |= IO_INDEXED; lowindex = convert (integer_type_node, TYPE_MIN_VALUE (indexmode)); highindex = convert (integer_type_node, TYPE_MAX_VALUE (indexmode)); } tloc = build_component_ref (decl, get_identifier ("tloc")); /* fill access part of text location */ data = build_component_ref (decl, get_identifier ("acc")); /* flag word */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("flags")), build_int_2 (accessflags, 0))); /* record length, don't count any padding bytes at end of varying */ tlocfields = TYPE_FIELDS (TREE_TYPE (tloc)); len1 = size_in_bytes (TREE_TYPE (tlocfields)); tlocfields = TREE_CHAIN (tlocfields); len2 = size_in_bytes (TREE_TYPE (tlocfields)); reclen = fold (build (PLUS_EXPR, long_integer_type_node, len1, len2)); expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("reclength")), reclen)); /* the index */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("lowindex")), lowindex)); expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("highindex")), highindex)); /* association */ expand_expr_stmt ( build_chill_modify_expr ( build_chill_component_ref (data, get_identifier ("association")), null_pointer_node)); /* storelocptr */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("storelocptr")), null_pointer_node)); /* record type */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("rectype")), build_int_2 (2, 0))); /* VaryingChars */ /* fill text part */ data = build_component_ref (decl, get_identifier ("txt")); /* flag word */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("flags")), build_int_2 (textflags, 0))); /* pointer to text record */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("text_record")), force_addr_of (tloc))); /* pointer to the access */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("access_sub")), force_addr_of (build_component_ref (decl, get_identifier ("acc"))))); /* actual length */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (data, get_identifier ("actual_index")), integer_zero_node)); /* length of text record */ expand_expr_stmt ( build_chill_modify_expr ( build_component_ref (tloc, get_identifier (VAR_LENGTH)), integer_zero_node)); } static int connect_process_optionals (optionals, whereptr, indexptr, indexmode) tree optionals; tree *whereptr; tree *indexptr; tree indexmode; { tree where = NULL_TREE, theindex = NULL_TREE; int had_errors = 0; if (optionals != NULL_TREE) { /* get the where expression */ where = TREE_VALUE (optionals); if (where == NULL_TREE || TREE_CODE (where) == ERROR_MARK) had_errors = 1; else { if (! CH_IS_WHERE_MODE (TREE_TYPE (where))) { error ("argument 4 of CONNECT must be of mode WHERE"); had_errors = 1; } where = convert (integer_type_node, where); } optionals = TREE_CHAIN (optionals); } if (optionals != NULL_TREE) { theindex = TREE_VALUE (optionals); if (theindex == NULL_TREE || TREE_CODE (theindex) == ERROR_MARK) had_errors = 1; else { if (indexmode == void_type_node) { error ("index expression for ACCESS without index"); had_errors = 1; } else if (! CH_COMPATIBLE (theindex, indexmode)) { error ("incompatible index mode"); had_errors = 1; } } } if (had_errors) return 0; *whereptr = where; *indexptr = theindex; return 1; } static tree connect_text (assoc, text, usage, optionals) tree assoc; tree text; tree usage; tree optionals; { tree where = NULL_TREE, theindex = NULL_TREE; tree indexmode = text_indexmode (TREE_TYPE (text)); tree result, what_where, have_index, what_index; /* process optionals */ if (!connect_process_optionals (optionals, &where, &theindex, indexmode)) return error_mark_node; what_where = where == NULL_TREE ? integer_zero_node : where; have_index = theindex == NULL_TREE ? integer_zero_node : integer_one_node; what_index = theindex == NULL_TREE ? integer_zero_node : convert (integer_type_node, theindex); result = build_chill_function_call ( lookup_name (get_identifier ("__connect")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (assoc), tree_cons (NULL_TREE, convert (integer_type_node, usage), tree_cons (NULL_TREE, what_where, tree_cons (NULL_TREE, have_index, tree_cons (NULL_TREE, what_index, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))))))); return result; } static tree connect_access (assoc, transfer, usage, optionals) tree assoc; tree transfer; tree usage; tree optionals; { tree where = NULL_TREE, theindex = NULL_TREE; tree indexmode = access_indexmode (TREE_TYPE (transfer)); tree result, what_where, have_index, what_index; /* process the optionals */ if (! connect_process_optionals (optionals, &where, &theindex, indexmode)) return error_mark_node; /* now the call */ what_where = where == NULL_TREE ? integer_zero_node : where; have_index = theindex == NULL_TREE ? integer_zero_node : integer_one_node; what_index = theindex == NULL_TREE ? integer_zero_node : convert (integer_type_node, theindex); result = build_chill_function_call ( lookup_name (get_identifier ("__connect")), tree_cons (NULL_TREE, force_addr_of (transfer), tree_cons (NULL_TREE, force_addr_of (assoc), tree_cons (NULL_TREE, convert (integer_type_node, usage), tree_cons (NULL_TREE, what_where, tree_cons (NULL_TREE, have_index, tree_cons (NULL_TREE, what_index, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))))))); return result; } tree build_chill_connect (transfer, assoc, usage, optionals) tree transfer; tree assoc; tree usage; tree optionals; { int had_errors = 0; int what = 0; tree result = error_mark_node; if (! check_assoc (assoc, 2, "CONNECT")) had_errors = 1; /* check usage */ if (usage == NULL_TREE || TREE_CODE (usage) == ERROR_MARK) return error_mark_node; if (! CH_IS_USAGE_MODE (TREE_TYPE (usage))) { error ("argument 3 to CONNECT must be of mode USAGE"); had_errors = 1; } if (had_errors) return error_mark_node; /* look what we have got */ what = check_transfer (transfer, 1, "CONNECT"); switch (what) { case 1: /* we have an ACCESS */ result = connect_access (assoc, transfer, usage, optionals); break; case 2: /* we have a TEXT */ result = connect_text (assoc, transfer, usage, optionals); break; default: result = error_mark_node; } return result; } static int check_access (access, argnum, errmsg) tree access; int argnum; const char *errmsg; { if (access == NULL_TREE || TREE_CODE (access) == ERROR_MARK) return 1; if (! CH_IS_ACCESS_MODE (TREE_TYPE (access))) { error ("argument %d of %s must be of mode ACCESS", argnum, errmsg); return 0; } if (! CH_LOCATION_P (access)) { error ("argument %d of %s must be a location", argnum, errmsg); return 0; } return 1; } tree build_chill_readrecord (access, optionals) tree access; tree optionals; { int len; tree recordmode, indexmode, dynamic, result; tree index = NULL_TREE, location = NULL_TREE; if (! check_access (access, 1, "READRECORD")) return error_mark_node; recordmode = access_recordmode (TREE_TYPE (access)); indexmode = access_indexmode (TREE_TYPE (access)); dynamic = access_dynamic (TREE_TYPE (access)); /* process the optionals */ len = list_length (optionals); if (indexmode != void_type_node) { /* we must have an index */ if (!len) { error ("Too few arguments in call to `readrecord'"); return error_mark_node; } index = TREE_VALUE (optionals); if (index == NULL_TREE || TREE_CODE (index) == ERROR_MARK) return error_mark_node; optionals = TREE_CHAIN (optionals); if (! CH_COMPATIBLE (index, indexmode)) { error ("incompatible index mode"); return error_mark_node; } } /* check the record mode, if one */ if (optionals != NULL_TREE) { location = TREE_VALUE (optionals); if (location == NULL_TREE || TREE_CODE (location) == ERROR_MARK) return error_mark_node; if (recordmode != void_type_node && ! CH_COMPATIBLE (location, recordmode)) { error ("incompatible record mode"); return error_mark_node; } if (TYPE_READONLY_PROPERTY (TREE_TYPE (location))) { error ("store location must not be READonly"); return error_mark_node; } location = force_addr_of (location); } else location = null_pointer_node; index = index == NULL_TREE ? integer_zero_node : convert (integer_type_node, index); result = build_chill_function_call ( lookup_name (get_identifier ("__readrecord")), tree_cons (NULL_TREE, force_addr_of (access), tree_cons (NULL_TREE, index, tree_cons (NULL_TREE, location, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))))); TREE_TYPE (result) = build_chill_pointer_type (recordmode); return result; } tree build_chill_writerecord (access, optionals) tree access; tree optionals; { int had_errors = 0, len; tree recordmode, indexmode, dynamic; tree index = NULL_TREE, location = NULL_TREE; tree result; if (! check_access (access, 1, "WRITERECORD")) return error_mark_node; recordmode = access_recordmode (TREE_TYPE (access)); indexmode = access_indexmode (TREE_TYPE (access)); dynamic = access_dynamic (TREE_TYPE (access)); /* process the optionals */ len = list_length (optionals); if (indexmode != void_type_node && len != 2) { error ("Too few arguments in call to `writerecord'"); return error_mark_node; } if (indexmode != void_type_node) { index = TREE_VALUE (optionals); if (index == NULL_TREE || TREE_CODE (index) == ERROR_MARK) return error_mark_node; location = TREE_VALUE (TREE_CHAIN (optionals)); if (location == NULL_TREE || TREE_CODE (location) == ERROR_MARK) return error_mark_node; } else location = TREE_VALUE (optionals); /* check the index */ if (indexmode != void_type_node) { if (! CH_COMPATIBLE (index, indexmode)) { error ("incompatible index mode"); had_errors = 1; } } /* check the record mode */ if (recordmode == void_type_node) { error ("transfer to ACCESS without record mode"); had_errors = 1; } else if (! CH_COMPATIBLE (location, recordmode)) { error ("incompatible record mode"); had_errors = 1; } if (had_errors) return error_mark_node; index = index == NULL_TREE ? integer_zero_node : convert (integer_type_node, index); result = build_chill_function_call ( lookup_name (get_identifier ("__writerecord")), tree_cons (NULL_TREE, force_addr_of (access), tree_cons (NULL_TREE, index, tree_cons (NULL_TREE, force_addr_of (location), tree_cons (NULL_TREE, size_in_bytes (TREE_TYPE (location)), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))))); return result; } tree build_chill_disconnect (transfer) tree transfer; { tree result; if (! check_transfer (transfer, 1, "DISCONNECT")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__disconnect")), tree_cons (NULL_TREE, force_addr_of (transfer), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); return result; } tree build_chill_getassociation (transfer) tree transfer; { tree result; if (! check_transfer (transfer, 1, "GETASSOCIATION")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__getassociation")), tree_cons (NULL_TREE, force_addr_of (transfer), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); TREE_TYPE (result) = build_chill_pointer_type (association_type_node); return result; } tree build_chill_getusage (transfer) tree transfer; { tree result; if (! check_transfer (transfer, 1, "GETUSAGE")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__getusage")), tree_cons (NULL_TREE, force_addr_of (transfer), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); TREE_TYPE (result) = usage_type_node; return result; } tree build_chill_outoffile (transfer) tree transfer; { tree result; if (! check_transfer (transfer, 1, "OUTOFFILE")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__outoffile")), tree_cons (NULL_TREE, force_addr_of (transfer), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); return result; } static int check_text (text, argnum, errmsg) tree text; int argnum; const char *errmsg; { if (text == NULL_TREE || TREE_CODE (text) == ERROR_MARK) return 0; if (! CH_IS_TEXT_MODE (TREE_TYPE (text))) { error ("argument %d of %s must be of mode TEXT", argnum, errmsg); return 0; } if (! CH_LOCATION_P (text)) { error ("argument %d of %s must be a location", argnum, errmsg); return 0; } return 1; } tree build_chill_eoln (text) tree text; { tree result; if (! check_text (text, 1, "EOLN")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__eoln")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); return result; } tree build_chill_gettextindex (text) tree text; { tree result; if (! check_text (text, 1, "GETTEXTINDEX")) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__gettextindex")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); return result; } tree build_chill_gettextrecord (text) tree text; { tree textmode, result; if (! check_text (text, 1, "GETTEXTRECORD")) return error_mark_node; textmode = textlocation_mode (TREE_TYPE (text)); if (textmode == NULL_TREE) { error ("TEXT doesn't have a location"); /* FIXME */ return error_mark_node; } result = build_chill_function_call ( lookup_name (get_identifier ("__gettextrecord")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); TREE_TYPE (result) = build_chill_pointer_type (textmode); CH_DERIVED_FLAG (result) = 1; return result; } tree build_chill_gettextaccess (text) tree text; { tree access, refaccess, acc, decl, listbase; tree tlocmode, indexmode, dynamic; tree result; unsigned int save_maximum_field_alignment = maximum_field_alignment; if (! check_text (text, 1, "GETTEXTACCESS")) return error_mark_node; tlocmode = textlocation_mode (TREE_TYPE (text)); indexmode = text_indexmode (TREE_TYPE (text)); dynamic = text_dynamic (TREE_TYPE (text)); /* we have to build a type for the access */ acc = build_access_part (); access = make_node (RECORD_TYPE); listbase = build_decl (FIELD_DECL, get_identifier ("data"), acc); TYPE_FIELDS (access) = listbase; decl = build_lang_decl (TYPE_DECL, get_identifier ("__recordmode"), tlocmode); chainon (listbase, decl); decl = build_lang_decl (TYPE_DECL, get_identifier ("__indexmode"), indexmode); chainon (listbase, decl); decl = build_decl (CONST_DECL, get_identifier ("__dynamic"), integer_type_node); DECL_INITIAL (decl) = dynamic; chainon (listbase, decl); maximum_field_alignment = 0; layout_chill_struct_type (access); maximum_field_alignment = save_maximum_field_alignment; CH_IS_ACCESS_MODE (access) = 1; CH_TYPE_NONVALUE_P (access) = 1; refaccess = build_chill_pointer_type (access); result = build_chill_function_call ( lookup_name (get_identifier ("__gettextaccess")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE)))); TREE_TYPE (result) = refaccess; CH_DERIVED_FLAG (result) = 1; return result; } tree build_chill_settextindex (text, expr) tree text; tree expr; { tree result; if (! check_text (text, 1, "SETTEXTINDEX")) return error_mark_node; if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return error_mark_node; result = build_chill_function_call ( lookup_name (get_identifier ("__settextindex")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, expr, tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))); return result; } tree build_chill_settextaccess (text, access) tree text; tree access; { tree result; tree textindexmode, accessindexmode; tree textrecordmode, accessrecordmode; if (! check_text (text, 1, "SETTEXTACCESS")) return error_mark_node; if (! check_access (access, 2, "SETTEXTACCESS")) return error_mark_node; textindexmode = text_indexmode (TREE_TYPE (text)); accessindexmode = access_indexmode (TREE_TYPE (access)); if (textindexmode != accessindexmode) { if (! chill_read_compatible (textindexmode, accessindexmode)) { error ("incompatible index mode for SETETEXTACCESS"); return error_mark_node; } } textrecordmode = textlocation_mode (TREE_TYPE (text)); accessrecordmode = access_recordmode (TREE_TYPE (access)); if (textrecordmode != accessrecordmode) { if (! chill_read_compatible (textrecordmode, accessrecordmode)) { error ("incompatible record mode for SETTEXTACCESS"); return error_mark_node; } } result = build_chill_function_call ( lookup_name (get_identifier ("__settextaccess")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (access), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))); return result; } tree build_chill_settextrecord (text, charloc) tree text; tree charloc; { tree result; int had_errors = 0; tree tlocmode; if (! check_text (text, 1, "SETTEXTRECORD")) return error_mark_node; if (charloc == NULL_TREE || TREE_CODE (charloc) == ERROR_MARK) return error_mark_node; /* check the location */ if (! CH_LOCATION_P (charloc)) { error ("parameter 2 must be a location"); return error_mark_node; } tlocmode = textlocation_mode (TREE_TYPE (text)); if (! chill_varying_string_type_p (TREE_TYPE (charloc))) had_errors = 1; else if (int_size_in_bytes (tlocmode) != int_size_in_bytes (TREE_TYPE (charloc))) had_errors = 1; if (had_errors) { error ("incompatible modes in parameter 2"); return error_mark_node; } result = build_chill_function_call ( lookup_name (get_identifier ("__settextrecord")), tree_cons (NULL_TREE, force_addr_of (text), tree_cons (NULL_TREE, force_addr_of (charloc), tree_cons (NULL_TREE, force_addr_of (get_chill_filename ()), tree_cons (NULL_TREE, get_chill_linenumber (), NULL_TREE))))); return result; } /* process iolist for READ- and WRITETEXT */ /* function walks through types as long as they are ranges, returns the type and min- and max-value form starting type. */ static tree get_final_type_and_range (item, low, high) tree item; tree *low; tree *high; { tree wrk = item; *low = TYPE_MIN_VALUE (wrk); *high = TYPE_MAX_VALUE (wrk); while (TREE_CODE (wrk) == INTEGER_TYPE && TREE_TYPE (wrk) != NULL_TREE && TREE_CODE (TREE_TYPE (wrk)) == INTEGER_TYPE && TREE_TYPE (TREE_TYPE (wrk)) != NULL_TREE) wrk = TREE_TYPE (wrk); return (TREE_TYPE (wrk)); } static void process_io_list (exprlist, iolist_addr, iolist_length, iolist_rtx, do_read, argoffset) tree exprlist; tree *iolist_addr; tree *iolist_length; rtx *iolist_rtx; int do_read; int argoffset; { tree idxlist; int idxcnt; int iolen; tree iolisttype, iolist; if (exprlist == NULL_TREE) return; iolen = list_length (exprlist); /* build indexlist for the io list */ idxlist = build_tree_list (NULL_TREE, build_chill_range_type (NULL_TREE, integer_one_node, build_int_2 (iolen, 0))); /* build the io-list type */ iolisttype = build_chill_array_type (TREE_TYPE (chill_io_list_type), idxlist, 0, NULL_TREE); /* declare the iolist */ iolist = build_decl (VAR_DECL, get_unique_identifier (do_read ? "RDTEXT" : "WRTEXT"), iolisttype); /* we want to get a variable which gets marked unused after the function call, This is a little bit tricky cause the address of this variable will be taken and therefor the variable gets moved out one level. However, we REALLY don't need this variable again. Solution: push 2 levels and do pop and free twice at the end. */ push_temp_slots (); push_temp_slots (); *iolist_rtx = assign_temp (TREE_TYPE (iolist), 0, 1, 0); DECL_RTL (iolist) = *iolist_rtx; /* process the exprlist */ idxcnt = 1; while (exprlist != NULL_TREE) { tree item = TREE_VALUE (exprlist); tree idx = build_int_2 (idxcnt++, 0); const char *fieldname = 0; const char *enumname = 0; tree array_ref = build_chill_array_ref_1 (iolist, idx); tree item_type; tree range_low = NULL_TREE, range_high = NULL_TREE; int have_range = 0; tree item_addr = null_pointer_node; int referable = 0; int readonly = 0; /* next value in exprlist */ exprlist = TREE_CHAIN (exprlist); if (item == NULL_TREE || TREE_CODE (item) == ERROR_MARK) continue; item_type = TREE_TYPE (item); if (item_type == NULL_TREE) { if (TREE_CODE (item) == COND_EXPR || TREE_CODE (item) == CASE_EXPR) error ("conditional expression not allowed in this context"); else error ("untyped expression as argument %d", idxcnt + 1 + argoffset); continue; } else if (TREE_CODE (item_type) == ERROR_MARK) continue; if (TREE_CODE (item_type) == REFERENCE_TYPE) { item_type = TREE_TYPE (item_type); item = convert (item_type, item); } /* check for a range */ if (TREE_CODE (item_type) == INTEGER_TYPE && TREE_TYPE (item_type) != NULL_TREE) { /* we have a range. NOTE, however, on writetext we don't process ranges */ item_type = get_final_type_and_range (item_type, &range_low, &range_high); have_range = 1; } readonly = TYPE_READONLY_PROPERTY (item_type); referable = CH_REFERABLE (item); if (referable) item_addr = force_addr_of (item); /* if we are in read and have readonly we can't do this */ if (readonly && do_read) { item_addr = null_pointer_node; referable = 0; } /* process different types */ if (TREE_CODE (item_type) == INTEGER_TYPE) { int type_size = TREE_INT_CST_LOW (TYPE_SIZE (item_type)); tree to_assign = NULL_TREE; if (do_read && referable) { /* process an integer in case of READTEXT and expression is referable and not READONLY */ to_assign = item_addr; if (have_range) { /* do it for a range */ tree t, __forxx, __ptr, __low, __high; tree what_upper, what_lower; /* determine the name in the union of lower and upper */ if (TREE_UNSIGNED (item_type)) fieldname = "_ulong"; else fieldname = "_slong"; switch (type_size) { case 8: if (TREE_UNSIGNED (item_type)) enumname = "__IO_UByteRangeLoc"; else enumname = "__IO_ByteRangeLoc"; break; case 16: if (TREE_UNSIGNED (item_type)) enumname = "__IO_UIntRangeLoc"; else enumname = "__IO_IntRangeLoc"; break; case 32: if (TREE_UNSIGNED (item_type)) enumname = "__IO_ULongRangeLoc"; else enumname = "__IO_LongRangeLoc"; break; default: error ("Cannot process %d bits integer for READTEXT argument %d.", type_size, idxcnt + 1 + argoffset); continue; } /* set up access to structure */ t = build_component_ref (array_ref, get_identifier ("__t")); __forxx = build_component_ref (t, get_identifier ("__locintrange")); __ptr = build_component_ref (__forxx, get_identifier ("ptr")); __low = build_component_ref (__forxx, get_identifier ("lower")); what_lower = build_component_ref (__low, get_identifier (fieldname)); __high = build_component_ref (__forxx, get_identifier ("upper")); what_upper = build_component_ref (__high, get_identifier (fieldname)); /* do the assignments */ expand_assignment (__ptr, item_addr, 0, 0); expand_assignment (what_lower, range_low, 0, 0); expand_assignment (what_upper, range_high, 0, 0); fieldname = 0; } else { /* no range */ fieldname = "__locint"; switch (type_size) { case 8: if (TREE_UNSIGNED (item_type)) enumname = "__IO_UByteLoc"; else enumname = "__IO_ByteLoc"; break; case 16: if (TREE_UNSIGNED (item_type)) enumname = "__IO_UIntLoc"; else enumname = "__IO_IntLoc"; break; case 32: if (TREE_UNSIGNED (item_type)) enumname = "__IO_ULongLoc"; else enumname = "__IO_LongLoc"; break; default: error ("Cannot process %d bits integer for READTEXT argument %d.", type_size, idxcnt + 1 + argoffset); continue; } } } else { /* process an integer in case of WRITETEXT */ to_assign = item; switch (type_size) { case 8: if (TREE_UNSIGNED (item_type)) { enumname = "__IO_UByteVal"; fieldname = "__valubyte"; } else { enumname = "__IO_ByteVal"; fieldname = "__valbyte"; } break; case 16: if (TREE_UNSIGNED (item_type)) { enumname = "__IO_UIntVal"; fieldname = "__valuint"; } else { enumname = "__IO_IntVal"; fieldname = "__valint"; } break; case 32: try_long: if (TREE_UNSIGNED (item_type)) { enumname = "__IO_ULongVal"; fieldname = "__valulong"; } else { enumname = "__IO_LongVal"; fieldname = "__vallong"; } break; case 64: /* convert it back to {unsigned}long. */ if (TREE_UNSIGNED (item_type)) item_type = long_unsigned_type_node; else item_type = long_integer_type_node; item = convert (item_type, item); goto try_long; default: /* This kludge is because the lexer gives literals the type long_long_{integer,unsigned}_type_node. */ if (TREE_CODE (item) == INTEGER_CST) { if (int_fits_type_p (item, long_integer_type_node)) { item_type = long_integer_type_node; item = convert (item_type, item); goto try_long; } if (int_fits_type_p (item, long_unsigned_type_node)) { item_type = long_unsigned_type_node; item = convert (item_type, item); goto try_long; } } error ("Cannot process %d bits integer WRITETEXT argument %d.", type_size, idxcnt + 1 + argoffset); continue; } } if (fieldname) { tree t, __forxx; t = build_component_ref (array_ref, get_identifier ("__t")); __forxx = build_component_ref (t, get_identifier (fieldname)); expand_assignment (__forxx, to_assign, 0, 0); } } else if (TREE_CODE (item_type) == CHAR_TYPE) { tree to_assign = NULL_TREE; if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { if (! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } if (have_range) { tree t, forxx, ptr, lower, upper; t = build_component_ref (array_ref, get_identifier ("__t")); forxx = build_component_ref (t, get_identifier ("__loccharrange")); ptr = build_component_ref (forxx, get_identifier ("ptr")); lower = build_component_ref (forxx, get_identifier ("lower")); upper = build_component_ref (forxx, get_identifier ("upper")); expand_assignment (ptr, item_addr, 0, 0); expand_assignment (lower, range_low, 0, 0); expand_assignment (upper, range_high, 0, 0); fieldname = 0; enumname = "__IO_CharRangeLoc"; } else { to_assign = item_addr; fieldname = "__locchar"; enumname = "__IO_CharLoc"; } } else { to_assign = item; enumname = "__IO_CharVal"; fieldname = "__valchar"; } if (fieldname) { tree t, forxx; t = build_component_ref (array_ref, get_identifier ("__t")); forxx = build_component_ref (t, get_identifier (fieldname)); expand_assignment (forxx, to_assign, 0, 0); } } else if (TREE_CODE (item_type) == BOOLEAN_TYPE) { tree to_assign = NULL_TREE; if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { if (! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } if (have_range) { tree t, forxx, ptr, lower, upper; t = build_component_ref (array_ref, get_identifier ("__t")); forxx = build_component_ref (t, get_identifier ("__locboolrange")); ptr = build_component_ref (forxx, get_identifier ("ptr")); lower = build_component_ref (forxx, get_identifier ("lower")); upper = build_component_ref (forxx, get_identifier ("upper")); expand_assignment (ptr, item_addr, 0, 0); expand_assignment (lower, range_low, 0, 0); expand_assignment (upper, range_high, 0, 0); fieldname = 0; enumname = "__IO_BoolRangeLoc"; } else { to_assign = item_addr; fieldname = "__locbool"; enumname = "__IO_BoolLoc"; } } else { to_assign = item; enumname = "__IO_BoolVal"; fieldname = "__valbool"; } if (fieldname) { tree t, forxx; t = build_component_ref (array_ref, get_identifier ("__t")); forxx = build_component_ref (t, get_identifier (fieldname)); expand_assignment (forxx, to_assign, 0, 0); } } else if (TREE_CODE (item_type) == ENUMERAL_TYPE) { /* process an enum */ tree table_name; tree context_of_type; tree t; /* determine the context of the type. if TYPE_NAME (item_type) == NULL_TREE if TREE_CODE (item) == INTEGER_CST context = NULL_TREE -- this is wrong but should work for now else context = DECL_CONTEXT (item) else context = DECL_CONTEXT (TYPE_NAME (item_type)) */ if (TYPE_NAME (item_type) == NULL_TREE) { if (TREE_CODE (item) == INTEGER_CST) context_of_type = NULL_TREE; else context_of_type = DECL_CONTEXT (item); } else context_of_type = DECL_CONTEXT (TYPE_NAME (item_type)); table_name = add_enum_to_list (item_type, context_of_type); t = build_component_ref (array_ref, get_identifier ("__t")); if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { if (! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } if (have_range) { tree forxx, ptr, len, nametable, lower, upper; forxx = build_component_ref (t, get_identifier ("__locsetrange")); ptr = build_component_ref (forxx, get_identifier ("ptr")); len = build_component_ref (forxx, get_identifier ("length")); nametable = build_component_ref (forxx, get_identifier ("name_table")); lower = build_component_ref (forxx, get_identifier ("lower")); upper = build_component_ref (forxx, get_identifier ("upper")); expand_assignment (ptr, item_addr, 0, 0); expand_assignment (len, size_in_bytes (item_type), 0, 0); expand_assignment (nametable, table_name, 0, 0); expand_assignment (lower, range_low, 0, 0); expand_assignment (upper, range_high, 0, 0); enumname = "__IO_SetRangeLoc"; } else { tree forxx, ptr, len, nametable; forxx = build_component_ref (t, get_identifier ("__locset")); ptr = build_component_ref (forxx, get_identifier ("ptr")); len = build_component_ref (forxx, get_identifier ("length")); nametable = build_component_ref (forxx, get_identifier ("name_table")); expand_assignment (ptr, item_addr, 0, 0); expand_assignment (len, size_in_bytes (item_type), 0, 0); expand_assignment (nametable, table_name, 0, 0); enumname = "__IO_SetLoc"; } } else { tree forxx, value, nametable; forxx = build_component_ref (t, get_identifier ("__valset")); value = build_component_ref (forxx, get_identifier ("value")); nametable = build_component_ref (forxx, get_identifier ("name_table")); expand_assignment (value, item, 0, 0); expand_assignment (nametable, table_name, 0, 0); enumname = "__IO_SetVal"; } } else if (chill_varying_string_type_p (item_type)) { /* varying char string */ tree t = build_component_ref (array_ref, get_identifier ("__t")); tree forxx = build_component_ref (t, get_identifier ("__loccharstring")); tree string = build_component_ref (forxx, get_identifier ("string")); tree length = build_component_ref (forxx, get_identifier ("string_length")); if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { /* in this read case the argument must be referable */ if (! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } } else if (! referable) { /* in the write case we create a temporary if not referable */ rtx t; tree loc = build_decl (VAR_DECL, get_unique_identifier ("WRTEXTVS"), item_type); t = assign_temp (item_type, 0, 1, 0); DECL_RTL (loc) = t; expand_assignment (loc, item, 0, 0); item_addr = force_addr_of (loc); item = loc; } expand_assignment (string, item_addr, 0, 0); if (do_read) /* we must pass the maximum length of the varying */ expand_assignment (length, size_in_bytes (TREE_TYPE (TREE_CHAIN (TYPE_FIELDS (item_type)))), 0, 0); else /* we pass the actual length of the string */ expand_assignment (length, build_component_ref (item, var_length_id), 0, 0); enumname = "__IO_CharVaryingLoc"; } else if (CH_CHARS_TYPE_P (item_type)) { /* fixed character string */ tree the_size; tree t = build_component_ref (array_ref, get_identifier ("__t")); tree forxx = build_component_ref (t, get_identifier ("__loccharstring")); tree string = build_component_ref (forxx, get_identifier ("string")); tree length = build_component_ref (forxx, get_identifier ("string_length")); if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { /* in this read case the argument must be referable */ if (! CH_REFERABLE (item)) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } else item_addr = force_addr_of (item); the_size = size_in_bytes (item_type); enumname = "__IO_CharStrLoc"; } else { if (! CH_REFERABLE (item)) { /* in the write case we create a temporary if not referable */ rtx t; int howmuchbytes; howmuchbytes = int_size_in_bytes (item_type); if (howmuchbytes != -1) { /* fixed size */ tree loc = build_decl (VAR_DECL, get_unique_identifier ("WRTEXTVS"), item_type); t = assign_temp (item_type, 0, 1, 0); DECL_RTL (loc) = t; expand_assignment (loc, item, 0, 0); item_addr = force_addr_of (loc); the_size = size_in_bytes (item_type); enumname = "__IO_CharStrLoc"; } else { tree type, string, exp, loc; if ((howmuchbytes = intsize_of_charsexpr (item)) == -1) { error ("cannot process argument %d of WRITETEXT, unknown size", idxcnt + 1 + argoffset); continue; } string = build_string_type (char_type_node, build_int_2 (howmuchbytes, 0)); type = build_varying_struct (string); loc = build_decl (VAR_DECL, get_unique_identifier ("WRTEXTCS"), type); t = assign_temp (type, 0, 1, 0); DECL_RTL (loc) = t; exp = chill_convert_for_assignment (type, item, 0); expand_assignment (loc, exp, 0, 0); item_addr = force_addr_of (loc); the_size = integer_zero_node; enumname = "__IO_CharVaryingLoc"; } } else { item_addr = force_addr_of (item); the_size = size_in_bytes (item_type); enumname = "__IO_CharStrLoc"; } } expand_assignment (string, item_addr, 0, 0); expand_assignment (length, size_in_bytes (item_type), 0, 0); } else if (CH_BOOLS_TYPE_P (item_type)) { /* we have a bitstring */ tree t = build_component_ref (array_ref, get_identifier ("__t")); tree forxx = build_component_ref (t, get_identifier ("__loccharstring")); tree string = build_component_ref (forxx, get_identifier ("string")); tree length = build_component_ref (forxx, get_identifier ("string_length")); if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read) { /* in this read case the argument must be referable */ if (! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } } else if (! referable) { /* in the write case we create a temporary if not referable */ tree loc = build_decl (VAR_DECL, get_unique_identifier ("WRTEXTVS"), item_type); DECL_RTL (loc) = assign_temp (item_type, 0, 1, 0); expand_assignment (loc, item, 0, 0); item_addr = force_addr_of (loc); } expand_assignment (string, item_addr, 0, 0); expand_assignment (length, build_chill_length (item), 0, 0); enumname = "__IO_BitStrLoc"; } else if (TREE_CODE (item_type) == REAL_TYPE) { /* process a (long_)real */ tree t, forxx, to_assign; if (do_read && readonly) { error ("argument %d is READonly", idxcnt + 1 + argoffset); continue; } if (do_read && ! referable) { error ("argument %d must be referable", idxcnt + 1 + argoffset); continue; } if (lookup_name (ridpointers[RID_FLOAT]) == TYPE_NAME (item_type)) { /* we have a real */ if (do_read) { enumname = "__IO_RealLoc"; fieldname = "__locreal"; to_assign = item_addr; } else { enumname = "__IO_RealVal"; fieldname = "__valreal"; to_assign = item; } } else { /* we have a long_real */ if (do_read) { enumname = "__IO_LongRealLoc"; fieldname = "__loclongreal"; to_assign = item_addr; } else { enumname = "__IO_LongRealVal"; fieldname = "__vallongreal"; to_assign = item; } } t = build_component_ref (array_ref, get_identifier ("__t")); forxx = build_component_ref (t, get_identifier (fieldname)); expand_assignment (forxx, to_assign, 0, 0); } #if 0 /* don't process them for now */ else if (TREE_CODE (item_type) == POINTER_TYPE) { /* we have a pointer */ tree __t, __forxx; __t = build_component_ref (array_ref, get_identifier ("__t")); __forxx = build_component_ref (__t, get_identifier ("__forpointer")); expand_assignment (__forxx, item, 0, 0); enumname = "_IO_Pointer"; } else if (item_type == instance_type_node) { /* we have an INSTANCE */ tree __t, __forxx; __t = build_component_ref (array_ref, get_identifier ("__t")); __forxx = build_component_ref (__t, get_identifier ("__forinstance")); expand_assignment (__forxx, item, 0, 0); enumname = "_IO_Instance"; } #endif else { /* datatype is not yet implemented, issue a warning */ error ("cannot process mode of argument %d for %sTEXT.", idxcnt + 1 + argoffset, do_read ? "READ" : "WRITE"); enumname = "__IO_UNUSED"; } /* do assignment of the enum */ if (enumname) { tree descr = build_component_ref (array_ref, get_identifier ("__descr")); expand_assignment (descr, lookup_name (get_identifier (enumname)), 0, 0); } } /* set up address and length of iolist */ *iolist_addr = build_chill_addr_expr (iolist, (char *)0); *iolist_length = build_int_2 (iolen, 0); } /* check the format string */ #define LET 0x0001 #define BIN 0x0002 #define DEC 0x0004 #define OCT 0x0008 #define HEX 0x0010 #define USC 0x0020 #define BIL 0x0040 #define SPC 0x0080 #define SCS 0x0100 #define IOC 0x0200 #define EDC 0x0400 #define CVC 0x0800 #define isDEC(c) ( chartab[(c)] & DEC ) #define isCVC(c) ( chartab[(c)] & CVC ) #define isEDC(c) ( chartab[(c)] & EDC ) #define isIOC(c) ( chartab[(c)] & IOC ) #define isUSC(c) #define isXXX(c,XXX) ( chartab[(c)] & XXX ) static short int chartab[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, SPC, SPC, SPC, SPC, SPC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, SPC, IOC, 0, 0, 0, 0, 0, 0, SCS, SCS, SCS, SCS+IOC, SCS, SCS+IOC, SCS, SCS+IOC, BIN+OCT+DEC+HEX, BIN+OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, OCT+DEC+HEX, DEC+HEX, DEC+HEX, SCS, SCS, SCS+EDC, SCS+IOC, SCS+EDC, IOC, 0, LET+HEX+BIL, LET+HEX+BIL+CVC, LET+HEX+BIL+CVC, LET+HEX+BIL, LET+HEX, LET+HEX+CVC, LET, LET+BIL+CVC, LET, LET, LET, LET, LET, LET, LET+CVC, LET, LET, LET, LET, LET+EDC, LET, LET, LET, LET+EDC, LET, LET, SCS, 0, SCS, 0, USC, 0, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET+HEX, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, LET, 0, 0, 0, 0, 0 }; typedef enum { FormatText, FirstPercent, RepFact, ConvClause, EditClause, ClauseEnd, AfterWidth, FractWidth, FractWidthCont, ExpoWidth, ExpoWidthCont, ClauseWidth, CatchPadding, LastPercent } fcsstate_t; #define CONVERSIONCODES "CHOBF" typedef enum { DefaultConv, HexConv, OctalConv, BinaryConv, ScientConv } convcode_t; static convcode_t convcode; static tree check_exprlist PARAMS ((convcode_t, tree, int, unsigned long)); typedef enum { False, True, } Boolean; static unsigned long fractionwidth; #define IOCODES "/+-?!=" typedef enum { NextRecord, NextPage, CurrentLine, Prompt, Emit, EndPage } iocode_t; static iocode_t iocode; #define EDITCODES "X<>T" typedef enum { SpaceSkip, SkipLeft, SkipRight, Tabulation } editcode_t; static editcode_t editcode; static unsigned long clausewidth; static Boolean leftadjust; static Boolean overflowev; static Boolean dynamicwid; static Boolean paddingdef; static char paddingchar; static Boolean fractiondef; static Boolean exponentdef; static unsigned long exponentwidth; static unsigned long repetition; typedef enum { NormalEnd, EndAtParen, TextFailEnd } formatexit_t; static formatexit_t scanformcont PARAMS ((char *, int, char **, int *, tree, tree *, int, int *)); /* NOTE: varibale have to be set to False before calling check_format_string */ static Boolean empty_printed; static int formstroffset; static tree check_exprlist (code, exprlist, argnum, repetition) convcode_t code; tree exprlist; int argnum; unsigned long repetition; { tree expr, type, result = NULL_TREE; while (repetition--) { if (exprlist == NULL_TREE) { if (empty_printed == False) { warning ("too few arguments for this format string"); empty_printed = True; } return NULL_TREE; } expr = TREE_VALUE (exprlist); result = exprlist = TREE_CHAIN (exprlist); if (expr == NULL_TREE || TREE_CODE (expr) == ERROR_MARK) return result; type = TREE_TYPE (expr); if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) return result; if (TREE_CODE (type) == REFERENCE_TYPE) type = TREE_TYPE (type); if (type == NULL_TREE || TREE_CODE (type) == ERROR_MARK) return result; switch (code) { case DefaultConv: /* %C, everything is allowed. Not know types are flaged later. */ break; case ScientConv: /* %F, must be a REAL */ if (TREE_CODE (type) != REAL_TYPE) warning ("type of argument %d invalid for conversion code at offset %d", argnum, formstroffset); break; case HexConv: case OctalConv: case BinaryConv: case -1: /* %H, %O, %B, and V as clause width */ if (TREE_CODE (type) != INTEGER_TYPE) warning ("type of argument %d invalid for conversion code at offset %d", argnum, formstroffset); break; default: /* there is an invalid conversion code */ break; } } return result; } static formatexit_t scanformcont (fcs, len, fcsptr, lenptr, exprlist, exprptr, firstargnum, nextargnum) char *fcs; int len; char **fcsptr; int *lenptr; tree exprlist; tree *exprptr; int firstargnum; int *nextargnum; { fcsstate_t state = FormatText; unsigned char curr; int dig; while (len--) { curr = *fcs++; formstroffset++; switch (state) { case FormatText: if (curr == '%') state = FirstPercent; break; after_first_percent: ; case FirstPercent: if (curr == '%') { state = FormatText; break; } if (curr == ')') { *lenptr = len; *fcsptr = fcs; *exprptr = exprlist; *nextargnum = firstargnum; return EndAtParen; } if (isDEC (curr)) { state = RepFact; repetition = curr - '0'; break; } repetition = 1; test_for_control_codes: ; if (isCVC (curr)) { state = ConvClause; convcode = strchr (CONVERSIONCODES, curr) - CONVERSIONCODES; leftadjust = False; overflowev = False; dynamicwid = False; paddingdef = False; paddingchar = ' '; fractiondef = False; /* fractionwidth = 0; default depends on mode ! */ exponentdef = False; exponentwidth = 3; clausewidth = 0; /* check the argument */ exprlist = check_exprlist (convcode, exprlist, firstargnum, repetition); firstargnum++; break; } if (isEDC (curr)) { state = EditClause; editcode = strchr (EDITCODES, curr) - EDITCODES; dynamicwid = False; clausewidth = editcode == Tabulation ? 0 : 1; break; } if (isIOC (curr)) { state = ClauseEnd; iocode = strchr (IOCODES, curr) - IOCODES; break; } if (curr == '(') { unsigned long times = repetition; int cntlen; char* cntfcs; tree cntexprlist; int nextarg; while (times--) { if (scanformcont (fcs, len, &cntfcs, &cntlen, exprlist, &cntexprlist, firstargnum, &nextarg) != EndAtParen ) { warning ("unmatched open paren"); break; } exprlist = cntexprlist; } fcs = cntfcs; len = cntlen; if (len < 0) len = 0; exprlist = cntexprlist; firstargnum = nextarg; state = FormatText; break; } warning ("bad format specification character (offset %d)", formstroffset); state = FormatText; /* skip one argument */ if (exprlist != NULL_TREE) exprlist = TREE_CHAIN (exprlist); break; case RepFact: if (isDEC (curr)) { dig = curr - '0'; if (repetition > (ULONG_MAX - dig)/10) { warning ("repetition factor overflow (offset %d)", formstroffset); return TextFailEnd; } repetition = repetition*10 + dig; break; } goto test_for_control_codes; case ConvClause: if (isDEC (curr)) { state = ClauseWidth; clausewidth = curr - '0'; break; } if (curr == 'L') { if (leftadjust) warning ("duplicate qualifier (offset %d)", formstroffset); leftadjust = True; break; } if (curr == 'E') { if (overflowev) warning ("duplicate qualifier (offset %d)", formstroffset); overflowev = True; break; } if (curr == 'P') { if (paddingdef) warning ("duplicate qualifier (offset %d)", formstroffset); paddingdef = True; state = CatchPadding; break; } test_for_variable_width: ; if (curr == 'V') { dynamicwid = True; state = AfterWidth; exprlist = check_exprlist (-1, exprlist, firstargnum, 1); firstargnum++; break; } goto test_for_fraction_width; case ClauseWidth: if (isDEC (curr)) { dig = curr - '0'; if (clausewidth > (ULONG_MAX - dig)/10) warning ("clause width overflow (offset %d)", formstroffset); else clausewidth = clausewidth*10 + dig; break; } /* fall through */ test_for_fraction_width: ; case AfterWidth: if (curr == '.') { if (convcode != DefaultConv && convcode != ScientConv) { warning ("no fraction (offset %d)", formstroffset); state = FormatText; break; } fractiondef = True; state = FractWidth; break; } goto test_for_exponent_width; case FractWidth: if (isDEC (curr)) { state = FractWidthCont; fractionwidth = curr - '0'; break; } else warning ("no fraction width (offset %d)", formstroffset); case FractWidthCont: if (isDEC (curr)) { dig = curr - '0'; if (fractionwidth > (ULONG_MAX - dig)/10) warning ("fraction width overflow (offset %d)", formstroffset); else fractionwidth = fractionwidth*10 + dig; break; } test_for_exponent_width: ; if (curr == ':') { if (convcode != ScientConv) { warning ("no exponent (offset %d)", formstroffset); state = FormatText; break; } exponentdef = True; state = ExpoWidth; break; } goto test_for_final_percent; case ExpoWidth: if (isDEC (curr)) { state = ExpoWidthCont; exponentwidth = curr - '0'; break; } else warning ("no exponent width (offset %d)", formstroffset); case ExpoWidthCont: if (isDEC (curr)) { dig = curr - '0'; if (exponentwidth > (ULONG_MAX - dig)/10) warning ("exponent width overflow (offset %d)", formstroffset); else exponentwidth = exponentwidth*10 + dig; break; } /* fall through */ test_for_final_percent: ; case ClauseEnd: if (curr == '%') { state = LastPercent; break; } state = FormatText; break; case CatchPadding: paddingchar = curr; state = ConvClause; break; case EditClause: if (isDEC (curr)) { state = ClauseWidth; clausewidth = curr - '0'; break; } goto test_for_variable_width; case LastPercent: if (curr == '.') { state = FormatText; break; } goto after_first_percent; default: error ("internal error in check_format_string"); } } switch (state) { case FormatText: break; case FirstPercent: case LastPercent: case RepFact: case FractWidth: case ExpoWidth: warning ("bad format specification character (offset %d)", formstroffset); break; case CatchPadding: warning ("no padding character (offset %d)", formstroffset); break; default: break; } *fcsptr = fcs; *lenptr = len; *exprptr = exprlist; *nextargnum = firstargnum; return NormalEnd; } static void check_format_string (format_str, exprlist, firstargnum) tree format_str; tree exprlist; int firstargnum; { char *x; int y, yy; tree z = NULL_TREE; if (TREE_CODE (format_str) != STRING_CST) /* do nothing if we don't have a string constant */ return; formstroffset = -1; scanformcont (TREE_STRING_POINTER (format_str), TREE_STRING_LENGTH (format_str), &x, &y, exprlist, &z, firstargnum, &yy); if (z != NULL_TREE) /* too may arguments for format string */ warning ("too many arguments for this format string"); } static int get_max_size (expr) tree expr; { if (TREE_CODE (expr) == INDIRECT_REF) { tree x = TREE_OPERAND (expr, 0); tree y = TREE_OPERAND (x, 0); return int_size_in_bytes (TREE_TYPE (y)); } else if (TREE_CODE (expr) == CONCAT_EXPR) return intsize_of_charsexpr (expr); else return int_size_in_bytes (TREE_TYPE (expr)); } static int intsize_of_charsexpr (expr) tree expr; { int op0size, op1size; if (TREE_CODE (expr) != CONCAT_EXPR) return -1; /* find maximum length of CONCAT_EXPR, this is the worst case */ op0size = get_max_size (TREE_OPERAND (expr, 0)); op1size = get_max_size (TREE_OPERAND (expr, 1)); if (op0size == -1 || op1size == -1) return -1; return op0size + op1size; } tree build_chill_writetext (text_arg, exprlist) tree text_arg, exprlist; { tree iolist_addr = null_pointer_node; tree iolist_length = integer_zero_node; tree fstr_addr; tree fstr_length; tree outstr_addr; tree outstr_length; tree fstrtype; tree outfunction; tree filename, linenumber; tree format_str = NULL_TREE, indexexpr = NULL_TREE; rtx iolist_rtx = NULL_RTX; int argoffset = 0; /* make some checks */ if (text_arg == NULL_TREE || TREE_CODE (text_arg) == ERROR_MARK) return error_mark_node; if (exprlist != NULL_TREE) { if (TREE_CODE (exprlist) != TREE_LIST) return error_mark_node; } /* check the text argument */ if (chill_varying_string_type_p (TREE_TYPE (text_arg))) { /* build outstr-addr and outstr-length assuming that this is a CHAR (n) VARYING */ outstr_addr = force_addr_of (text_arg); outstr_length = size_in_bytes (CH_VARYING_ARRAY_TYPE (TREE_TYPE (text_arg))); outfunction = lookup_name (get_identifier ("__writetext_s")); format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); } else if (CH_IS_TEXT_MODE (TREE_TYPE (text_arg))) { /* we have a text mode */ tree indexmode; if (! check_text (text_arg, 1, "WRITETEXT")) return error_mark_node; indexmode = text_indexmode (TREE_TYPE (text_arg)); if (indexmode == void_type_node) { /* no index */ format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); } else { /* we have an index. there must be an index argument before format string */ indexexpr = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); if (! CH_COMPATIBLE (indexexpr, indexmode)) { if (chill_varying_string_type_p (TREE_TYPE (indexexpr)) || (CH_CHARS_TYPE_P (TREE_TYPE (indexexpr)) || (flag_old_strings && TREE_CODE (indexexpr) == INTEGER_CST && TREE_CODE (TREE_TYPE (indexexpr)) == CHAR_TYPE))) error ("missing index expression"); else error ("incompatible index mode"); return error_mark_node; } if (exprlist == NULL_TREE) { error ("Too few arguments in call to `writetext'"); return error_mark_node; } format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); argoffset = 1; } outstr_addr = force_addr_of (text_arg); outstr_length = convert (integer_type_node, indexexpr); outfunction = lookup_name (get_identifier ("__writetext_f")); } else { error ("argument 1 for WRITETEXT must be a TEXT or CHARS(n) VARYING location"); return error_mark_node; } /* check the format string */ fstrtype = TREE_TYPE (format_str); if (CH_CHARS_TYPE_P (fstrtype) || (flag_old_strings && TREE_CODE (format_str) == INTEGER_CST && TREE_CODE (fstrtype) == CHAR_TYPE)) { /* we have a character string */ fstr_addr = force_addr_of (format_str); fstr_length = size_in_bytes (fstrtype); } else if (chill_varying_string_type_p (TREE_TYPE (format_str))) { /* we have a varying char string */ fstr_addr = force_addr_of (build_component_ref (format_str, var_data_id)); fstr_length = build_component_ref (format_str, var_length_id); } else { error ("`format string' for WRITETEXT must be a CHARACTER string"); return error_mark_node; } empty_printed = False; check_format_string (format_str, exprlist, argoffset + 3); process_io_list (exprlist, &iolist_addr, &iolist_length, &iolist_rtx, 0, argoffset); /* tree to call the function */ filename = force_addr_of (get_chill_filename ()); linenumber = get_chill_linenumber (); expand_expr_stmt ( build_chill_function_call (outfunction, tree_cons (NULL_TREE, outstr_addr, tree_cons (NULL_TREE, outstr_length, tree_cons (NULL_TREE, fstr_addr, tree_cons (NULL_TREE, fstr_length, tree_cons (NULL_TREE, iolist_addr, tree_cons (NULL_TREE, iolist_length, tree_cons (NULL_TREE, filename, tree_cons (NULL_TREE, linenumber, NULL_TREE)))))))))); /* get rid of the iolist variable, if we have one */ if (iolist_rtx != NULL_RTX) { free_temp_slots (); pop_temp_slots (); free_temp_slots (); pop_temp_slots (); } /* return something the rest of the machinery can work with, i.e. (void)0 */ return build1 (CONVERT_EXPR, void_type_node, integer_zero_node); } tree build_chill_readtext (text_arg, exprlist) tree text_arg, exprlist; { tree instr_addr, instr_length, infunction; tree fstr_addr, fstr_length, fstrtype; tree iolist_addr = null_pointer_node; tree iolist_length = integer_zero_node; tree filename, linenumber; tree format_str = NULL_TREE, indexexpr = NULL_TREE; rtx iolist_rtx = NULL_RTX; int argoffset = 0; /* make some checks */ if (text_arg == NULL_TREE || TREE_CODE (text_arg) == ERROR_MARK) return error_mark_node; if (exprlist != NULL_TREE) { if (TREE_CODE (exprlist) != TREE_LIST) return error_mark_node; } /* check the text argument */ if (CH_CHARS_TYPE_P (TREE_TYPE (text_arg))) { instr_addr = force_addr_of (text_arg); instr_length = size_in_bytes (TREE_TYPE (text_arg)); infunction = lookup_name (get_identifier ("__readtext_s")); format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); } else if (chill_varying_string_type_p (TREE_TYPE (text_arg))) { instr_addr = force_addr_of (build_component_ref (text_arg, var_data_id)); instr_length = build_component_ref (text_arg, var_length_id); infunction = lookup_name (get_identifier ("__readtext_s")); format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); } else if (CH_IS_TEXT_MODE (TREE_TYPE (text_arg))) { /* we have a text mode */ tree indexmode; if (! check_text (text_arg, 1, "READTEXT")) return error_mark_node; indexmode = text_indexmode (TREE_TYPE (text_arg)); if (indexmode == void_type_node) { /* no index */ format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); } else { /* we have an index. there must be an index argument before format string */ indexexpr = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); if (! CH_COMPATIBLE (indexexpr, indexmode)) { if (chill_varying_string_type_p (TREE_TYPE (indexexpr)) || (CH_CHARS_TYPE_P (TREE_TYPE (indexexpr)) || (flag_old_strings && TREE_CODE (indexexpr) == INTEGER_CST && TREE_CODE (TREE_TYPE (indexexpr)) == CHAR_TYPE))) error ("missing index expression"); else error ("incompatible index mode"); return error_mark_node; } if (exprlist == NULL_TREE) { error ("Too few arguments in call to `readtext'"); return error_mark_node; } format_str = TREE_VALUE (exprlist); exprlist = TREE_CHAIN (exprlist); argoffset = 1; } instr_addr = force_addr_of (text_arg); instr_length = convert (integer_type_node, indexexpr); infunction = lookup_name (get_identifier ("__readtext_f")); } else { error ("argument 1 for READTEXT must be a TEXT location or CHARS(n) [ VARYING ] expression"); return error_mark_node; } /* check the format string */ fstrtype = TREE_TYPE (format_str); if (CH_CHARS_TYPE_P (fstrtype)) { /* we have a character string */ fstr_addr = force_addr_of (format_str); fstr_length = size_in_bytes (fstrtype); } else if (chill_varying_string_type_p (fstrtype)) { /* we have a CHARS(n) VARYING */ fstr_addr = force_addr_of (build_component_ref (format_str, var_data_id)); fstr_length = build_component_ref (format_str, var_length_id); } else { error ("`format string' for READTEXT must be a CHARACTER string"); return error_mark_node; } empty_printed = False; check_format_string (format_str, exprlist, argoffset + 3); process_io_list (exprlist, &iolist_addr, &iolist_length, &iolist_rtx, 1, argoffset); /* build the function call */ filename = force_addr_of (get_chill_filename ()); linenumber = get_chill_linenumber (); expand_expr_stmt ( build_chill_function_call (infunction, tree_cons (NULL_TREE, instr_addr, tree_cons (NULL_TREE, instr_length, tree_cons (NULL_TREE, fstr_addr, tree_cons (NULL_TREE, fstr_length, tree_cons (NULL_TREE, iolist_addr, tree_cons (NULL_TREE, iolist_length, tree_cons (NULL_TREE, filename, tree_cons (NULL_TREE, linenumber, NULL_TREE)))))))))); /* get rid of the iolist variable, if we have one */ if (iolist_rtx != NULL_RTX) { free_temp_slots (); pop_temp_slots (); free_temp_slots (); pop_temp_slots (); } /* return something the rest of the machinery can work with, i.e. (void)0 */ return build1 (CONVERT_EXPR, void_type_node, integer_zero_node); } /* this function build all neccesary enum-tables used for WRITETEXT or READTEXT of an enum */ void build_enum_tables () { SAVE_ENUM_NAMES *names; SAVE_ENUMS *wrk; void *saveptr; /* We temporarily reset the maximum_field_alignment to zero so the compiler's init data structures can be compatible with the run-time system, even when we're compiling with -fpack. */ unsigned int save_maximum_field_alignment; if (pass == 1) return; save_maximum_field_alignment = maximum_field_alignment; maximum_field_alignment = 0; /* output all names */ names = used_enum_names; while (names != (SAVE_ENUM_NAMES *)0) { tree var = get_unique_identifier ("ENUMNAME"); tree type; type = build_string_type (char_type_node, build_int_2 (IDENTIFIER_LENGTH (names->name) + 1, 0)); names->decl = decl_temp1 (var, type, 1, build_chill_string (IDENTIFIER_LENGTH (names->name) + 1, IDENTIFIER_POINTER (names->name)), 0, 0); names = names->forward; } /* output the tables and pointers to tables */ wrk = used_enums; while (wrk != (SAVE_ENUMS *)0) { tree varptr = wrk->ptrdecl; tree table_addr = null_pointer_node; tree init = NULL_TREE, one_entry; tree table, idxlist, tabletype, addr; SAVE_ENUM_VALUES *vals; int i; vals = wrk->vals; for (i = 0; i < wrk->num_vals; i++) { tree decl = vals->name->decl; addr = build1 (ADDR_EXPR, build_pointer_type (char_type_node), decl); TREE_CONSTANT (addr) = 1; one_entry = tree_cons (NULL_TREE, build_int_2 (vals->val, 0), tree_cons (NULL_TREE, addr, NULL_TREE)); one_entry = build_nt (CONSTRUCTOR, NULL_TREE, one_entry); init = tree_cons (NULL_TREE, one_entry, init); vals++; } /* add the terminator (name = null_pointer_node) to constructor */ one_entry = tree_cons (NULL_TREE, integer_zero_node, tree_cons (NULL_TREE, null_pointer_node, NULL_TREE)); one_entry = build_nt (CONSTRUCTOR, NULL_TREE, one_entry); init = tree_cons (NULL_TREE, one_entry, init); init = nreverse (init); init = build_nt (CONSTRUCTOR, NULL_TREE, init); TREE_CONSTANT (init) = 1; /* generate table */ idxlist = build_tree_list (NULL_TREE, build_chill_range_type (NULL_TREE, integer_zero_node, build_int_2 (wrk->num_vals, 0))); tabletype = build_chill_array_type (TREE_TYPE (enum_table_type), idxlist, 0, NULL_TREE); table = decl_temp1 (get_unique_identifier ("ENUMTAB"), tabletype, 1, init, 0, 0); table_addr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (enum_table_type)), table); TREE_CONSTANT (table_addr) = 1; /* generate pointer to table */ decl_temp1 (DECL_NAME (varptr), TREE_TYPE (table_addr), 1, table_addr, 0, 0); /* free that stuff */ saveptr = wrk->forward; free (wrk->vals); free (wrk); /* next enum */ wrk = saveptr; } /* free all the names */ names = used_enum_names; while (names != (SAVE_ENUM_NAMES *)0) { saveptr = names->forward; free (names); names = saveptr; } used_enums = (SAVE_ENUMS *)0; used_enum_names = (SAVE_ENUM_NAMES *)0; maximum_field_alignment = save_maximum_field_alignment; }