| /* 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; |
| } |
| |
| /* |
| 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 |
| */ |
| |
| 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; |
| } |
| |
| /* |
| 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 |
| */ |
| 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 than 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 necessary 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; |
| } |