blob: 6049ff45927296b5164429bfed3c905ee3a7a82d [file] [log] [blame]
/* 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;
}