/*
* Copyright (c) 2002, The Tendra Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice unmodified, this list of conditions, and the following
* disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Crown Copyright (c) 1997
*
* This TenDRA(r) Computer Program is subject to Copyright
* owned by the United Kingdom Secretary of State for Defence
* acting through the Defence Evaluation and Research Agency
* (DERA). It is made available to Recipients with a
* royalty-free licence for its use, reproduction, transfer
* to other parties and amendment for any purpose not excluding
* product development provided that any such use et cetera
* shall be deemed to be acceptance of the following conditions:-
*
* (1) Its Recipients shall ensure that this Notice is
* reproduced upon any copies or amended versions of it;
*
* (2) Any amended version of it shall be clearly marked to
* show both the nature of and the organisation responsible
* for the relevant amendment or amendments;
*
* (3) Its onward transfer from a recipient to another
* party shall be deemed to be that party's acceptance of
* these conditions;
*
* (4) DERA gives no warranty or assurance as to its
* quality or suitability for any purpose and DERA accepts
* no liability whatsoever in relation to any use to which
* it may be put.
*
* $TenDRA: tendra/src/producers/common/construct/token.c,v 1.8 2004/08/15 11:13:36 bp Exp $
*/
#include "config.h"
#include "producer.h"
#include
#include "msgcat.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "etype_ops.h"
#include "exp_ops.h"
#include "ftype_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "itype_ops.h"
#include "nat_ops.h"
#include "nspace_ops.h"
#include "member_ops.h"
#include "off_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "catalog.h"
#include "option.h"
#include "access.h"
#include "basetype.h"
#include "check.h"
#include "chktype.h"
#include "class.h"
#include "constant.h"
#include "convert.h"
#include "copy.h"
#include "declare.h"
#include "dump.h"
#include "exception.h"
#include "expression.h"
#include "function.h"
#include "hash.h"
#include "identifier.h"
#include "initialise.h"
#include "instance.h"
#include "inttype.h"
#include "lex.h"
#include "macro.h"
#include "namespace.h"
#include "parse.h"
#include "predict.h"
#include "preproc.h"
#include "redeclare.h"
#include "statement.h"
#include "syntax.h"
#include "template.h"
#include "tok.h"
#include "tokdef.h"
#include "token.h"
/*
* FIND A TYPE TOKEN KEY
*
* This routine returns the keyword associated with a type token of
* kind bt.
*/
int
type_token_key(BASE_TYPE bt)
{
int key = lex_type_Hcap;
if (bt & btype_float) {
if (bt & btype_star) {
key = lex_scalar_Hcap;
} else if (bt & btype_int) {
key = lex_arith_Hcap;
} else {
key = lex_float_Hcap;
}
} else if (bt & btype_int) {
if (bt & btype_signed) {
key = lex_signed;
} else if (bt & btype_unsigned) {
key = lex_unsigned;
} else {
key = lex_variety_Hcap;
}
} else if (bt == btype_class) {
key = lex_class_Hcap;
} else if (bt == btype_struct) {
key = lex_struct_Hcap;
} else if (bt == btype_union) {
key = lex_union_Hcap;
}
return (key);
}
/*
* CREATE A TYPE TOKEN
*
* This routine creates a type token of kind bt.
*/
TOKEN
make_type_token(BASE_TYPE bt)
{
TOKEN tok;
MAKE_tok_type (bt, NULL_type, tok);
return (tok);
}
/*
* CREATE AN EXPRESSION TOKEN
*
* This routine creates an expression token of type t.
*/
TOKEN
make_exp_token(TYPE t, int lv, int c)
{
TOKEN tok;
if (lv) {
t = lvalue_type (t);
} else {
t = rvalue_type (t);
}
object_type (t, id_token_tag);
MAKE_tok_exp (t, c, NULL_exp, tok);
return (tok);
}
/*
* CREATE A FUNCTION TOKEN
*
* This routine creates a function token of type t.
*/
TOKEN
make_func_token(TYPE t)
{
int ell;
TOKEN tok;
if (!IS_type_func (t)) {
report (preproc_loc, ERR_token_func (t));
tok = make_exp_token (t, 0, 0);
return (tok);
}
ell = DEREF_int (type_func_ellipsis (t));
if (ell & FUNC_NO_PARAMS) {
/* Map 't ()' to 't (void)' */
COPY_int (type_func_ellipsis (t), FUNC_NONE);
}
MAKE_tok_func (t, tok);
return (tok);
}
/*
* CREATE A MEMBER SELECTOR TOKEN
*
* This routine creates a member selector token for a member of s of
* type t. acc gives the member access.
*/
TOKEN
make_member_token(TYPE t, TYPE s, DECL_SPEC acc)
{
TOKEN tok;
if (!IS_type_compound (s)) {
report (preproc_loc, ERR_token_mem (s));
tok = make_exp_token (t, 0, 0);
return (tok);
}
#if LANGUAGE_CPP
crt_access = acc;
#else
UNUSED (acc);
#endif
MAKE_tok_member (s, t, NULL_off, tok);
return (tok);
}
/*
* CHECK A TOKEN PARAMETER OR RESULT SORT
*
* Procedure tokens which take or return other procedure tokens are not
* allowed. This routine checks the parameter token sort tok.
*/
static TOKEN
check_param_sort(TOKEN tok)
{
if (!IS_NULL_tok (tok)) {
if (IS_tok_func (tok)) {
tok = func_proc_token (tok);
}
if (IS_tok_proc (tok)) {
report (preproc_loc, ERR_token_proc_high ());
tok = DEREF_tok (tok_proc_res (tok));
}
}
return (tok);
}
/*
* BEGIN THE DEFINITION OF A PROCEDURE TOKEN
*
* This routine begins the construction of a procedure token.
*/
TOKEN
begin_proc_token()
{
TOKEN tok;
begin_param (NULL_id);
MAKE_tok_proc (NULL_tok, crt_namespace, lex_identifier, tok);
return (tok);
}
/*
* SET THE PARAMETER NUMBERS FOR A PROCEDURE TOKEN
*
* This routine sets the token numbers for the list of procedure token
* parameters p.
*/
void
set_proc_token(LIST (IDENTIFIER) p)
{
ulong n = 0;
while (!IS_NULL_list (p)) {
IDENTIFIER pid = DEREF_id (HEAD_list (p));
if (!IS_NULL_id (pid)) {
COPY_ulong (id_no (pid), n);
}
n++;
p = TAIL_list (p);
}
return;
}
/*
* CONTINUE THE DEFINITION OF A PROCEDURE TOKEN
*
* This routine continues the definition of the procedure token prev
* by adding the lists of bound and program parameters, p and q.
*/
TOKEN
cont_proc_token(TOKEN prev, LIST (IDENTIFIER) p, LIST (IDENTIFIER) q)
{
if (!IS_NULL_tok (prev)) {
unsigned n;
if (!EQ_list (p, q)) {
int eq = 1;
LIST (IDENTIFIER) ps = p;
LIST (IDENTIFIER) qs = q;
while (!IS_NULL_list (ps) && !IS_NULL_list (qs)) {
IDENTIFIER ip = DEREF_id (HEAD_list (ps));
IDENTIFIER iq = DEREF_id (HEAD_list (qs));
if (!EQ_id (ip, iq)) {
eq = 0;
break;
}
ps = TAIL_list (ps);
qs = TAIL_list (qs);
}
if (eq && EQ_list (ps, qs)) {
/* Parameter lists match */
DESTROY_list (q, SIZE_id);
q = p;
} else {
set_proc_token (q);
}
}
set_proc_token (p);
COPY_list (tok_proc_bids (prev), p);
COPY_list (tok_proc_pids (prev), q);
n = LENGTH_list (q);
IGNORE check_value (OPT_VAL_macro_pars, (ulong) n);
}
return (prev);
}
/*
* COMPLETE THE DEFINITION OF A PROCEDURE TOKEN
*
* This routine completes the definition of the procedure token prev by
* filling in the token result sort res.
*/
TOKEN
end_proc_token(TOKEN prev, TOKEN res)
{
res = check_param_sort (res);
if (!IS_NULL_tok (prev)) {
COPY_tok (tok_proc_res (prev), res);
}
end_param ();
return (prev);
}
/*
* CREATE A TOKEN PARAMETER
*
* This routine declares a token bound parameter of sort tok with name
* id, which belongs to the tag namespace if tag is true.
*/
IDENTIFIER
make_tok_param(TOKEN tok, int tag, IDENTIFIER id)
{
if (IS_NULL_id (id)) {
HASHID nm = lookup_anon ();
id = DEREF_id (hashid_id (nm));
}
tok = check_param_sort (tok);
id = make_token_decl (tok, tag, id, NULL_id);
if (do_dump) dump_token_param (id);
return (id);
}
/*
* FIND A TOKEN MEMBER
*
* This routine looks up a member id of the class type t. If the member
* is not found or t is not a class type then an error message is printed
* and the null identifier is returned.
*/
IDENTIFIER
tok_member(IDENTIFIER id, TYPE t, int force)
{
if (IS_type_compound (t)) {
HASHID nm = DEREF_hashid (id_name (id));
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
NAMESPACE ns = DEREF_nspace (ctype_member (ct));
IDENTIFIER fid = search_id (ns, nm, 0, 0);
if (IS_NULL_id (fid)) {
/* Member not declared */
if (force) {
/* Report error */
report (preproc_loc, ERR_lookup_qual_bad (id, ns));
} else {
/* Create token member */
TOKEN tok;
HASHID fnm = lookup_anon ();
fid = DEREF_id (hashid_id (fnm));
MAKE_tok_member (t, type_error, NULL_off, tok);
fid = make_token_decl (tok, 0, id, fid);
fid = DEREF_id (id_token_alt (fid));
}
}
return (fid);
}
report (preproc_loc, ERR_token_mem (t));
return (NULL_id);
}
/*
* CREATE A TOKEN PROGRAM PARAMETER
*
* This routine declares a token program parameter named id. tt gives
* the associated token sort, while t gives the structure type if this
* denotes a member token or the parameter type if this denotes a type
* token.
*/
IDENTIFIER
prog_tok_param(IDENTIFIER id, TYPE t, unsigned tt, LIST (IDENTIFIER) p)
{
/* Look up member identifier */
IDENTIFIER tid = id;
if (tt == tok_member_tag) {
tid = tok_member (tid, t, 1);
if (IS_NULL_id (tid)) return (NULL_id);
}
/* Check through tokens */
while (!IS_NULL_list (p)) {
IDENTIFIER pid = DEREF_id (HEAD_list (p));
if (!IS_NULL_id (pid) && IS_id_token (pid)) {
IDENTIFIER qid = DEREF_id (id_token_alt (pid));
if (EQ_id (qid, tid)) {
/* Matching token found */
TOKEN tok = DEREF_tok (id_token_sort (pid));
unsigned pt = TAG_tok (tok);
switch (pt) {
case tok_nat_tag :
case tok_snat_tag : {
pt = tok_exp_tag;
break;
}
case tok_templ_tag :
case tok_func_tag : {
pt = tok_proc_tag;
break;
}
}
if (pt != tt) {
/* Wrong sort given for token parameter */
report (preproc_loc, ERR_token_arg_sort (pid));
}
return (pid);
}
}
p = TAIL_list (p);
}
/* Allow for complex type parameters */
if (tt == tok_type_tag) {
HASHID nm = lookup_anon ();
int tq = crt_templ_qualifier;
QUALIFIER cq = crt_id_qualifier;
crt_id_qualifier = qual_none;
crt_templ_qualifier = 0;
tid = DEREF_id (hashid_id (nm));
tid = make_object_decl (dspec_typedef, t, tid, 0);
crt_templ_qualifier = tq;
crt_id_qualifier = cq;
return (tid);
}
report (preproc_loc, ERR_token_arg_bad (tid));
return (NULL_id);
}
/*
* FIND AN UNDERLYING PROCEDURE TOKEN
*
* This routine returns the procedure token underlying the function
* token tok, creating this if necessary.
*/
TOKEN
func_proc_token(TOKEN tok)
{
TOKEN res;
if (!IS_tok_func (tok)) return (tok);
res = DEREF_tok (tok_func_proc (tok));
if (IS_NULL_tok (res)) {
TYPE t = DEREF_type (tok_func_type (tok));
int ell = DEREF_int (type_func_ellipsis (t));
if (ell & FUNC_ELLIPSIS) {
res = tok;
} else {
TOKEN rtok;
IDENTIFIER pid;
EXP e = NULL_exp;
LIST (IDENTIFIER) qids;
IDENTIFIER fn = DEREF_id (tok_func_defn (tok));
TYPE r = DEREF_type (type_func_ret (t));
LIST (TYPE) p = DEREF_list (type_func_mtypes (t));
LIST (IDENTIFIER) pids = NULL_list (IDENTIFIER);
res = begin_proc_token ();
while (!IS_NULL_list (p)) {
/* Normal function parameters */
TYPE s = DEREF_type (HEAD_list (p));
if (pass_complex_type (s)) {
MAKE_type_ptr (cv_none, s, s);
}
MAKE_tok_exp (s, 0, NULL_exp, rtok);
pid = make_tok_param (rtok, 0, NULL_id);
CONS_id (pid, pids, pids);
p = TAIL_list (p);
}
/* Extra constructor parameters ... */
pids = REVERSE_list (pids);
qids = pids;
if (pass_complex_type (r)) {
/* Complex function return */
TYPE s;
MAKE_type_ptr (cv_none, r, s);
MAKE_tok_exp (s, 0, NULL_exp, rtok);
pid = make_tok_param (rtok, 0, NULL_id);
CONS_id (pid, pids, pids);
r = type_void;
}
res = cont_proc_token (res, pids, qids);
if (!IS_NULL_id (fn)) {
/* Token already defined */
MAKE_exp_value (t, e);
}
MAKE_tok_exp (r, 0, e, rtok);
res = end_proc_token (res, rtok);
}
COPY_tok (tok_func_proc (tok), res);
}
return (res);
}
/*
* EXPAND A TOKEN VALUE
*
* This routine expands the token value tok. If force is true then a copy
* is always made.
*/
TOKEN
expand_sort(TOKEN tok, int rec, int force)
{
if (!IS_NULL_tok (tok)) {
unsigned tag = TAG_tok (tok);
switch (tag) {
case tok_exp_tag : {
/* Expression tokens */
EXP a1 = DEREF_exp (tok_exp_value (tok));
EXP a2 = expand_exp (a1, rec, 0);
if (force || !eq_exp_exact (a1, a2)) {
int c = DEREF_int (tok_exp_constant (tok));
TYPE t = DEREF_type (tok_exp_type (tok));
t = expand_type (t, rec);
MAKE_tok_exp (t, c, a2, tok);
}
break;
}
case tok_nat_tag :
case tok_snat_tag : {
/* Integral constant tokens */
ERROR err = NULL_err;
NAT n1 = DEREF_nat (tok_nat_etc_value (tok));
NAT n2 = expand_nat (n1, rec, 0, &err);
if (!IS_NULL_err (err)) report (crt_loc, err);
if (force || !EQ_nat (n1, n2)) {
MAKE_tok_nat_etc (tag, n2, tok);
}
break;
}
case tok_stmt_tag : {
/* Statement tokens */
EXP a1 = DEREF_exp (tok_stmt_value (tok));
EXP a2 = expand_exp (a1, rec, 1);
if (force || !eq_exp_exact (a1, a2)) {
EXP b = get_parent_stmt (a1);
set_parent_stmt (a2, b);
MAKE_tok_stmt (a2, tok);
}
break;
}
case tok_member_tag : {
/* Member tokens */
OFFSET a1 = DEREF_off (tok_member_value (tok));
OFFSET a2 = expand_offset (a1, rec);
if (force || !EQ_off (a1, a2)) {
TYPE s = DEREF_type (tok_member_of (tok));
TYPE t = DEREF_type (tok_member_type (tok));
s = expand_type (s, rec);
t = expand_type (t, rec);
MAKE_tok_member (s, t, a2, tok);
}
break;
}
case tok_type_tag : {
/* Type tokens */
TYPE t1 = DEREF_type (tok_type_value (tok));
TYPE t2 = expand_type (t1, rec);
if (force || !EQ_type (t1, t2)) {
BASE_TYPE bs = DEREF_btype (tok_type_kind (tok));
MAKE_tok_type (bs, t2, tok);
}
break;
}
case tok_class_tag : {
/* Template class tokens */
IDENTIFIER cid = DEREF_id (tok_class_value (tok));
/* NOT YET IMPLEMENTED */
if (force) {
TYPE s = DEREF_type (tok_class_type (tok));
TYPE t = DEREF_type (tok_class_alt (tok));
MAKE_tok_class (s, cid, tok);
COPY_type (tok_class_alt (tok), t);
}
break;
}
case tok_templ_tag : {
/* Template tokens */
if (force) {
int d;
LIST (IDENTIFIER) pids;
LIST (IDENTIFIER) rids;
LIST (IDENTIFIER) qids = NULL_list (IDENTIFIER);
DECL_SPEC ds = DEREF_dspec (tok_templ_usage (tok));
NAMESPACE ns = DEREF_nspace (tok_templ_pars (tok));
pids = DEREF_list (tok_templ_pids (tok));
rids = pids;
d = save_token_args (rids, NULL_list (TOKEN));
while (!IS_NULL_list (pids)) {
/* Copy template parameters */
TOKEN arg;
IDENTIFIER qid2;
IDENTIFIER pid = DEREF_id (HEAD_list (pids));
IDENTIFIER pid2 = DEREF_id (id_token_alt (pid));
IDENTIFIER qid = copy_id (pid, 2);
DECL_SPEC qds = DEREF_dspec (id_storage (qid));
qds |= dspec_pure;
COPY_dspec (id_storage (qid), qds);
arg = apply_token (qid, NULL_list (TOKEN));
assign_token (pid, arg);
qid2 = copy_id (pid2, 2);
COPY_id (id_token_alt (qid), qid2);
CONS_id (qid, qids, qids);
pids = TAIL_list (pids);
}
restore_token_args (rids, d);
MAKE_tok_templ (ds, ns, tok);
qids = REVERSE_list (qids);
COPY_list (tok_templ_pids (tok), qids);
set_proc_token (qids);
}
break;
}
}
}
return (tok);
}
/*
* EXPAND A LIST OF TOKEN ARGUMENTS
*
* This routine expands the list of token arguments p passing the parameter
* rec to the individual expansion routines. The null list is returned to
* indicate that the expansion has no effect.
*/
LIST (TOKEN)
expand_args(LIST (TOKEN) p, int rec, int force)
{
int changed = 0;
LIST (TOKEN) q = NULL_list (TOKEN);
while (!IS_NULL_list (p)) {
TOKEN a = DEREF_tok (HEAD_list (p));
TOKEN b = expand_sort (a, rec, force);
if (!EQ_tok (a, b)) changed = 1;
CONS_tok (b, q, q);
p = TAIL_list (p);
}
if (!changed) {
/* No effect */
DESTROY_list (q, SIZE_tok);
return (NULL_list (TOKEN));
}
q = REVERSE_list (q);
return (q);
}
/*
* EXPAND A TEMPLATE SORT
*
* This routine copies the given template sort producing a new sort
* comprising only those parameters which are unbound. If all the
* parameters are bound then the null sort is returned.
*/
TOKEN
expand_templ_sort(TOKEN sort, int rec)
{
NAMESPACE ns;
int changed = 0;
int all_unbound = 1;
LIST (TOKEN) dargs = NULL_list (TOKEN);
DECL_SPEC ex = DEREF_dspec (tok_templ_usage (sort));
LIST (IDENTIFIER) p = DEREF_list (tok_templ_pids (sort));
LIST (IDENTIFIER) q = NULL_list (IDENTIFIER);
LIST (IDENTIFIER) p0 = p;
while (!IS_NULL_list (p)) {
IDENTIFIER pid = DEREF_id (HEAD_list (p));
if (!IS_NULL_id (pid) && IS_id_token (pid)) {
TOKEN tok = DEREF_tok (id_token_sort (pid));
if (is_bound_tok (tok, 0)) {
/* Have bound parameter */
all_unbound = 0;
changed = 1;
} else {
/* Add unbound parameter to list */
/* NOT YET IMPLEMENTED */
CONS_id (pid, q, q);
}
}
p = TAIL_list (p);
}
if (IS_NULL_list (q)) {
/* All parameters are bound */
return (NULL_tok);
}
if (changed) {
/* Get unbound parameters into order */
q = REVERSE_list (q);
} else {
/* Use existing list */
DESTROY_list (q, SIZE_id);
q = p0;
}
if (all_unbound) {
/* Preserve instances and default arguments */
LIST (TOKEN) d;
dargs = DEREF_list (tok_templ_dargs (sort));
d = expand_args (dargs, rec, 0);
if (!IS_NULL_list (d)) dargs = d;
}
ns = DEREF_nspace (tok_templ_pars (sort));
MAKE_tok_templ (ex, ns, sort);
COPY_list (tok_templ_pids (sort), q);
COPY_list (tok_templ_dargs (sort), dargs);
return (sort);
}
/*
* RESTORE A TEMPLATE SORT
*
* This routine is called at the end of the expansion of a template
* type to restore the sort produced by expand_templ_sort.
*/
void
reset_templ_sort(TOKEN sort)
{
UNUSED (sort);
return;
}
/*
* EXPAND AN EXPRESSION TOKEN
*
* This routine expands any token definitions in the expression e.
* rec gives the level of expansion, 0 for just the top level, 1 for a
* complete recursive expansion, and 2 for a recursive expansion of
* token parameters only. Negative values just return e.
*/
EXP
expand_exp(EXP e, int rec, int stmt)
{
unsigned etag;
if (rec < 0) return (e);
if (IS_NULL_exp (e)) return (NULL_exp);
etag = TAG_exp (e);
if (etag == exp_token_tag) {
/* Tokenised values */
TOKEN tok;
DECL_SPEC ds;
unsigned tag;
IDENTIFIER id = DEREF_id (exp_token_tok (e));
IDENTIFIER aid = DEREF_id (id_alias (id));
LIST (TOKEN) p = DEREF_list (exp_token_args (e));
if (!EQ_id (id, aid)) {
/* Replace token by its alias */
e = apply_exp_token (aid, p, 1);
id = aid;
}
ds = DEREF_dspec (id_storage (id));
tok = DEREF_tok (id_token_sort (id));
tag = TAG_tok (tok);
if (tag == tok_proc_tag) {
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
if (rec) {
/* Expand token arguments */
p = expand_args (p, rec, 1);
e = apply_exp_token (id, p, rec);
}
/* if (rec == 2 && !(ds & dspec_auto)) break ; */
if (ds & dspec_temp) {
/* Check for recursive token expansions */
report (crt_loc, ERR_token_recursive (id));
return (make_error_exp (0));
}
COPY_dspec (id_storage (id), (ds | dspec_temp));
if (tag == tok_exp_tag) {
EXP a = DEREF_exp (tok_exp_value (tok));
if (!IS_NULL_exp (a)) {
/* Expand token definition */
e = expand_exp (a, rec, 0);
if (ds & dspec_auto) {
COPY_exp (tok_exp_value (tok), e);
}
}
} else if (tag == tok_stmt_tag) {
EXP a = DEREF_exp (tok_stmt_value (tok));
if (!IS_NULL_exp (a)) {
/* Expand token definition */
EXP b = get_parent_stmt (a);
e = expand_exp (a, rec, 1);
set_parent_stmt (e, b);
if (ds & dspec_auto) {
COPY_exp (tok_stmt_value (tok), e);
}
}
}
COPY_dspec (id_storage (id), ds);
} else if (etag == exp_int_lit_tag) {
/* Integer constants */
ERROR err = NULL_err;
NAT n1 = DEREF_nat (exp_int_lit_nat (e));
NAT n2 = expand_nat (n1, rec, 0, &err);
if (rec || !EQ_nat (n1, n2)) {
TYPE t = DEREF_type (exp_type (e));
unsigned tag = DEREF_unsigned (exp_int_lit_etag (e));
MAKE_exp_int_lit (t, n2, tag, e);
if (!IS_NULL_err (err)) report (crt_loc, err);
}
} else {
/* Other cases */
if (rec && !stmt) e = copy_exp (e, NULL_type, NULL_type);
}
return (e);
}
/*
* EXPAND AN INTEGER CONSTANT TOKEN
*
* This routine expands any token definitions in the integer constant
* expression n. rec is as above, ch is as in eval_exp.
*/
NAT
expand_nat(NAT n, int rec, int ch, ERROR *err)
{
if (rec < 0) return (n);
if (IS_NULL_nat (n)) return (NULL_nat);
switch (TAG_nat (n)) {
case nat_calc_tag : {
/* Calculated values */
EXP e2;
EXP e1 = DEREF_exp (nat_calc_value (n));
ulong tok = DEREF_ulong (nat_calc_tok (n));
if (rec) {
e2 = eval_exp (e1, ch);
} else {
e2 = expand_exp (e1, 0, 0);
}
e2 = convert_reference (e2, REF_NORMAL);
e2 = convert_lvalue (e2);
if (!EQ_exp (e1, e2) && !eq_exp_exact (e1, e2)) {
n = make_nat_exp (e2, err);
if (IS_nat_calc (n)) {
COPY_ulong (nat_calc_tok (n), tok);
}
}
break;
}
case nat_token_tag : {
/* Tokenised values */
TOKEN tok;
DECL_SPEC ds;
unsigned tag;
IDENTIFIER id = DEREF_id (nat_token_tok (n));
IDENTIFIER aid = DEREF_id (id_alias (id));
LIST (TOKEN) p = DEREF_list (nat_token_args (n));
if (!EQ_id (id, aid)) {
/* Replace token by its alias */
n = apply_nat_token (aid, p);
id = aid;
}
ds = DEREF_dspec (id_storage (id));
tok = DEREF_tok (id_token_sort (id));
tag = TAG_tok (tok);
if (tag == tok_proc_tag) {
if (rec) {
/* Expand token arguments */
p = expand_args (p, rec, 0);
if (!IS_NULL_list (p)) {
n = apply_nat_token (id, p);
}
}
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
/* if (rec == 2 && !(ds & dspec_auto)) break ; */
if (ds & dspec_temp) {
/* Check for recursive token expansions */
report (crt_loc, ERR_token_recursive (id));
return (small_nat [1]);
}
COPY_dspec (id_storage (id), (ds | dspec_temp));
if (tag == tok_nat_tag || tag == tok_snat_tag) {
NAT m = DEREF_nat (tok_nat_etc_value (tok));
if (!IS_NULL_nat (m)) {
/* Expand token definition */
n = expand_nat (m, rec, ch, err);
if (ds & dspec_auto) {
COPY_nat (tok_nat_etc_value (tok), n);
}
}
}
COPY_dspec (id_storage (id), ds);
break;
}
}
return (n);
}
/*
* EXPAND A MEMBER TOKEN
*
* This routine expands any token definitions in the offset off. rec
* is as above.
*/
OFFSET
expand_offset(OFFSET off, int rec)
{
if (rec > 0) off = copy_offset (off, lex_plus);
return (off);
}
/*
* EXPAND A TEMPLATE TYPE
*
* This routine is a special case of expand_type which deals with
* template types.
*/
static TYPE
expand_templ_type(TYPE t, int rec)
{
CV_SPEC cv = DEREF_cv (type_qual (t));
TYPE s = DEREF_type (type_templ_defn (t));
TOKEN sort = DEREF_tok (type_templ_sort (t));
sort = expand_templ_sort (sort, rec);
if (IS_type_compound (s)) {
/* Template classes */
s = copy_class (s, dspec_instance);
} else {
/* Other template types */
s = expand_type (s, rec);
}
if (IS_NULL_tok (sort)) {
/* No unbound parameters */
t = qualify_type (s, cv, 0);
} else {
/* Unbound parameters - result is a specialisation */
MAKE_type_templ (cv, sort, s, 1, t);
}
reset_templ_sort (sort);
return (t);
}
/*
* EXPAND A LIST OF EXCEPTION TYPES
*
* This routine expands the list of exception types p, setting changed to
* true if any changes.
*/
LIST (TYPE)
expand_exceptions(LIST (TYPE) p, int rec, int *changed)
{
LIST (TYPE) q = NULL_list (TYPE);
if (EQ_list (p, univ_type_set)) {
q = p;
} else if (EQ_list (p, empty_type_set)) {
q = p;
} else {
while (!IS_NULL_list (p)) {
TYPE s1 = DEREF_type (HEAD_list (p));
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (s1, s2)) {
s2 = check_except_type (s2, 0);
*changed = 1;
}
CONS_type (s2, q, q);
p = TAIL_list (p);
}
q = REVERSE_list (q);
}
return (q);
}
/*
* EXPAND A FUNCTION TYPE
*
* This routine is a special case of expand_type which deals with
* function types. rec will not be zero.
*/
static TYPE
expand_func_type(TYPE t, int rec)
{
int mf = 0;
int expanded = 0;
TYPE r1 = DEREF_type (type_func_ret (t));
TYPE r2;
LIST (TYPE) p1 = DEREF_list (type_func_ptypes (t));
LIST (TYPE) p2;
LIST (TYPE) m1 = DEREF_list (type_func_mtypes (t));
LIST (TYPE) m2 = NULL_list (TYPE);
LIST (TYPE) e1 = DEREF_list (type_func_except (t));
LIST (TYPE) e2;
if (!EQ_list (p1, m1)) {
if (!IS_NULL_list (m1) && EQ_list (p1, TAIL_list (m1))) {
/* Normal member function type */
mf = 1;
} else {
/* Swapped member function type */
mf = -1;
m1 = p1;
}
}
/* Copy return type */
r2 = expand_type (r1, rec);
if (!EQ_type (r1, r2)) expanded = 1;
/* Copy parameter types */
while (!IS_NULL_list (m1)) {
TYPE s1 = DEREF_type (HEAD_list (m1));
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (s1, s2)) expanded = 1;
CONS_type (s2, m2, m2);
m1 = TAIL_list (m1);
}
m2 = REVERSE_list (m2);
/* Copy exception types */
e2 = expand_exceptions (e1, rec, &expanded);
/* Check for default arguments */
if (!expanded) {
LIST (IDENTIFIER) pids = DEREF_list (type_func_pids (t));
while (!IS_NULL_list (pids)) {
IDENTIFIER id = DEREF_id (HEAD_list (pids));
EXP e = DEREF_exp (id_parameter_init (id));
if (!IS_NULL_exp (e)) {
if (depends_on_exp (e, any_token_param, 0)) {
/* Needs expansion */
expanded = 1;
break;
}
}
pids = TAIL_list (pids);
}
}
/* Expand remaining items */
if (expanded) {
CV_SPEC cv = DEREF_cv (type_qual (t));
CV_SPEC mq = DEREF_cv (type_func_mqual (t));
int ell = DEREF_int (type_func_ellipsis (t));
NAMESPACE pars = DEREF_nspace (type_func_pars (t));
LIST (IDENTIFIER) pids = DEREF_list (type_func_pids (t));
LIST (IDENTIFIER) qids = NULL_list (IDENTIFIER);
/* Copy parameters */
while (!IS_NULL_list (pids)) {
TYPE s;
IDENTIFIER id = DEREF_id (HEAD_list (pids));
IDENTIFIER lid = chase_alias (id);
EXP e = DEREF_exp (id_parameter_init (id));
id = copy_id (id, 2);
COPY_id (id_alias (id), lid);
s = DEREF_type (id_parameter_type (id));
check_par_decl (s, id, CONTEXT_WEAK_PARAM);
if (!IS_NULL_exp (e)) {
/* Copy default argument */
EXP d;
e = expand_exp (e, rec, 0);
e = init_general (s, e, id, 0);
d = destroy_general (s, id);
COPY_exp (id_parameter_term (id), d);
COPY_exp (id_parameter_init (id), e);
}
CONS_id (id, qids, qids);
pids = TAIL_list (pids);
}
qids = REVERSE_list (qids);
/* Form function type */
if (mf == 0) {
p2 = m2;
} else if (mf == 1) {
p2 = TAIL_list (m2);
} else {
p2 = m2;
m2 = TAIL_list (p2);
}
MAKE_type_func (cv, NULL_type, p2, ell, mq, m2, pars, qids, e2, t);
t = inject_pre_type (t, r2, 0);
} else {
/* Free unused type lists */
if (!EQ_list (m2, m1)) DESTROY_list (m2, SIZE_type);
if (!EQ_list (e2, e1)) DESTROY_list (e2, SIZE_type);
}
return (t);
}
/*
* RESCAN A CLASS NAME
*
* This routine expands the class type ct by rescanning its name in the
* current context. It returns the null type if the result is not a
* type name.
*/
static TYPE
rescan_class(CLASS_TYPE ct)
{
IDENTIFIER cid = DEREF_id (ctype_name (ct));
TYPE t = find_typename (cid, NULL_list (TOKEN), btype_none, 1);
return (t);
}
/*
* RESCAN AN ENUMERATION NAME
*
* This routine expands the enumeration type et by rescanning its name
* in the current context. It returns the null type if the result is
* not a type name.
*/
static TYPE
rescan_enum(ENUM_TYPE et)
{
IDENTIFIER eid = DEREF_id (etype_name (et));
TYPE t = find_typename (eid, NULL_list (TOKEN), btype_none, 1);
return (t);
}
/*
* EXPAND A CLASS TYPE
*
* This routine expands any token definitions in the class type ct.
* rec is as above. The null class is returned if the result is not
* a class type with the actual type being assigned to pt.
*/
CLASS_TYPE
expand_ctype(CLASS_TYPE ct, int rec, TYPE *pt)
{
if (rec >= 0) {
TYPE s = NULL_type;
TYPE t = DEREF_type (ctype_form (ct));
if (!IS_NULL_type (t)) {
if (IS_type_token (t)) {
IDENTIFIER id = DEREF_id (type_token_tok (t));
LIST (TOKEN) p = DEREF_list (type_token_args (t));
if (IS_id_token (id)) {
/* Tokenised classes */
s = expand_type (t, rec);
} else if (rec) {
/* Template classes */
p = expand_args (p, rec, 0);
if (!IS_NULL_list (p)) {
/* Template class instance */
id = instance_type (id, p, 0, 1);
s = DEREF_type (id_class_name_defn (id));
while (IS_type_templ (s)) {
s = DEREF_type (type_templ_defn (s));
}
}
}
if (EQ_type (s, t)) {
/* No expansion possible */
return (ct);
}
} else if (IS_type_instance (t)) {
s = rescan_class (ct);
if (EQ_type (s, t)) {
/* No expansion possible */
return (ct);
}
} else {
/* Recursive template classes */
s = expand_type (t, rec);
}
} else {
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
if (ci & cinfo_rescan) s = rescan_class (ct);
}
if (!IS_NULL_type (s)) {
if (IS_type_compound (s)) {
ct = DEREF_ctype (type_compound_defn (s));
} else {
*pt = s;
if (is_templ_type (s)) {
IDENTIFIER id = DEREF_id (type_token_tok (s));
ct = find_class (id);
} else {
ct = NULL_ctype;
}
}
}
}
return (ct);
}
/*
* BITFIELD EXPANSION FLAG
*
* This flag may be set to true to allow for zero sized bitfields in
* expand_type. The only way this can occur is in the expansion
* of an anonymous member type.
*/
int expand_anon_bitfield = 0;
/*
* EXPAND A TYPE TOKEN
*
* This routine expands any token definitions in the type t. rec is
* as above.
*/
TYPE
expand_type(TYPE t, int rec)
{
CV_SPEC cv;
int prom = 0;
IDENTIFIER id;
LIST (TOKEN) p;
if (rec < 0) return (t);
if (IS_NULL_type (t)) return (NULL_type);
cv = DEREF_cv (type_qual (t));
ASSERT (ORDER_type == 18);
switch (TAG_type (t)) {
case type_integer_tag : {
/* Integral types */
INT_TYPE it = DEREF_itype (type_integer_rep (t));
unsigned tag = TAG_itype (it);
if (tag == itype_arith_tag) {
/* Expand arithmetic types */
INT_TYPE ir = DEREF_itype (itype_arith_arg1 (it));
INT_TYPE is = DEREF_itype (itype_arith_arg2 (it));
TYPE r1 = DEREF_type (itype_prom (ir));
TYPE r2 = expand_type (r1, rec);
TYPE s1 = DEREF_type (itype_prom (is));
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (r1, r2) || !EQ_type (s1, s2)) {
t = arith_type (r2, s2, NULL_exp, NULL_exp);
if (cv) t = qualify_type (t, cv, 0);
}
} else {
/* Expand other integral types */
if (tag == itype_promote_tag) {
it = DEREF_itype (itype_promote_arg (it));
tag = TAG_itype (it);
prom = 1;
}
if (tag == itype_token_tag) {
id = DEREF_id (itype_token_tok (it));
p = DEREF_list (itype_token_args (it));
goto expand_label;
}
if (tag == itype_basic_tag) {
/* Allow for special tokens */
BUILTIN_TYPE n = DEREF_ntype (itype_basic_no (it));
id = get_special (base_token [n].tok, 0);
if (!IS_NULL_id (id)) {
p = NULL_list (TOKEN);
goto expand_label;
}
}
}
break;
}
case type_floating_tag : {
/* Floating point types */
FLOAT_TYPE ft = DEREF_ftype (type_floating_rep (t));
unsigned tag = TAG_ftype (ft);
if (tag == ftype_arith_tag) {
/* Expand arithmetic types */
FLOAT_TYPE fr = DEREF_ftype (ftype_arith_arg1 (ft));
FLOAT_TYPE fs = DEREF_ftype (ftype_arith_arg2 (ft));
TYPE r1 = make_ftype (fr, NULL_ftype);
TYPE r2 = expand_type (r1, rec);
TYPE s1 = make_ftype (fs, NULL_ftype);
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (r1, r2) || !EQ_type (s1, s2)) {
t = arith_type (r2, s2, NULL_exp, NULL_exp);
if (cv) t = qualify_type (t, cv, 0);
}
} else {
/* Expand other floating point types */
if (tag == ftype_arg_promote_tag) {
ft = DEREF_ftype (ftype_arg_promote_arg (ft));
tag = TAG_ftype (ft);
prom = 2;
}
if (tag == ftype_token_tag) {
id = DEREF_id (ftype_token_tok (ft));
p = DEREF_list (ftype_token_args (ft));
goto expand_label;
}
}
break;
}
case type_ptr_tag : {
/* Pointer types */
if (rec) {
TYPE s1 = DEREF_type (type_ptr_sub (t));
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (s1, s2)) {
if (TAG_type (s1) == TAG_type (s2)) {
/* Don't check in this case */
MAKE_type_ptr (cv, s2, t);
} else {
MAKE_type_ptr (cv, NULL_type, t);
t = inject_pre_type (t, s2, 0);
}
}
}
break;
}
case type_ref_tag : {
/* Reference types */
if (rec) {
TYPE s1 = DEREF_type (type_ref_sub (t));
TYPE s2 = expand_type (s1, rec);
if (!EQ_type (s1, s2)) {
MAKE_type_ref (cv, NULL_type, t);
t = inject_pre_type (t, s2, 0);
}
}
break;
}
case type_ptr_mem_tag : {
/* Pointer to member types */
if (rec) {
TYPE r2 = NULL_type;
CLASS_TYPE c1 = DEREF_ctype (type_ptr_mem_of (t));
CLASS_TYPE c2 = expand_ctype (c1, rec, &r2);
TYPE s1 = DEREF_type (type_ptr_mem_sub (t));
TYPE s2 = expand_type (s1, rec);
if (!EQ_ctype (c1, c2)) {
if (IS_NULL_ctype (c2)) {
/* Illegal class type expansion */
report (crt_loc, ERR_dcl_mptr_class (r2));
MAKE_type_ptr (cv, NULL_type, t);
} else {
MAKE_type_ptr_mem (cv, c2, NULL_type, t);
}
t = inject_pre_type (t, s2, 0);
} else if (!EQ_type (s1, s2)) {
MAKE_type_ptr_mem (cv, c1, NULL_type, t);
t = inject_pre_type (t, s2, 0);
}
}
break;
}
case type_func_tag : {
/* Function types */
if (rec) t = expand_func_type (t, rec);
break;
}
case type_array_tag : {
/* Array types */
if (rec) {
ERROR err = NULL_err;
TYPE s1 = DEREF_type (type_array_sub (t));
TYPE s2 = expand_type (s1, rec);
NAT n1 = DEREF_nat (type_array_size (t));
NAT n2 = expand_nat (n1, rec, 0, &err);
if (!EQ_nat (n1, n2)) {
if (!IS_NULL_err (err)) {
ERROR err2 = ERR_dcl_array_dim_const ();
err = concat_error (err, err2);
report (crt_loc, err);
}
n2 = check_array_dim (n2);
MAKE_type_array (cv, NULL_type, n2, t);
t = inject_pre_type (t, s2, 0);
} else if (!EQ_type (s1, s2)) {
MAKE_type_array (cv, NULL_type, n2, t);
t = inject_pre_type (t, s2, 0);
}
}
break;
}
case type_bitfield_tag : {
/* Bitfield types */
if (rec) {
ERROR err = NULL_err;
INT_TYPE it = DEREF_itype (type_bitfield_defn (t));
TYPE s1 = DEREF_type (itype_bitfield_sub (it));
NAT n1 = DEREF_nat (itype_bitfield_size (it));
TYPE s2 = expand_type (s1, rec);
NAT n2 = expand_nat (n1, rec, 0, &err);
if (!EQ_type (s1, s2) || !EQ_nat (n1, n2)) {
BASE_TYPE rep;
int anon = expand_anon_bitfield;
rep = DEREF_btype (itype_bitfield_rep (it));
if (!IS_NULL_err (err)) {
ERROR err2 = ERR_class_bit_dim_const ();
err = concat_error (err, err2);
report (crt_loc, err);
}
rep = get_bitfield_rep (s2, rep);
t = check_bitfield_type (cv, s2, rep, n2, anon);
}
}
break;
}
case type_compound_tag : {
/* Class types */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
TYPE s = DEREF_type (ctype_form (ct));
if (!IS_NULL_type (s)) {
if (IS_type_token (s)) {
/* Tokenised and template classes */
id = DEREF_id (type_token_tok (s));
p = DEREF_list (type_token_args (s));
if (IS_id_token (id)) goto expand_label;
if (rec) {
p = expand_args (p, rec, 0);
if (!IS_NULL_list (p)) {
/* Template class instance */
id = instance_type (id, p, 0, 1);
t = DEREF_type (id_class_name_defn (id));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
if (cv) t = qualify_type (t, cv, 0);
}
}
} else if (IS_type_instance (s)) {
s = rescan_class (ct);
if (!IS_NULL_type (s)) {
t = s;
if (cv) t = qualify_type (t, cv, 0);
}
} else {
/* Recursive template classes */
t = expand_type (s, rec);
if (cv) t = qualify_type (t, cv, 0);
}
} else {
CLASS_INFO ci = DEREF_cinfo (ctype_info (ct));
if (ci & cinfo_rescan) {
/* Force rescan */
s = rescan_class (ct);
if (!IS_NULL_type (s)) {
t = s;
if (cv) t = qualify_type (t, cv, 0);
}
}
}
break;
}
case type_enumerate_tag : {
/* Enumeration types */
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
CLASS_INFO ei = DEREF_cinfo (etype_info (et));
if (ei & cinfo_rescan) {
/* Force rescan */
TYPE s = rescan_enum (et);
if (!IS_NULL_type (s)) {
t = s;
if (cv) t = qualify_type (t, cv, 0);
}
}
break;
}
case type_token_tag : {
/* Tokenised types */
id = DEREF_id (type_token_tok (t));
p = DEREF_list (type_token_args (t));
expand_label : {
TOKEN tok;
unsigned tag;
DECL_SPEC ds;
IDENTIFIER aid;
int changed = 0;
if (!IS_id_token (id)) break;
aid = DEREF_id (id_alias (id));
if (!EQ_id (id, aid)) {
/* Replace token by its alias */
t = apply_type_token (aid, p, NULL_id);
changed = 1;
id = aid;
}
ds = DEREF_dspec (id_storage (id));
tok = DEREF_tok (id_token_sort (id));
tag = TAG_tok (tok);
if (tag == tok_proc_tag) {
if (rec) {
/* Expand token arguments */
p = expand_args (p, rec, 0);
if (!IS_NULL_list (p)) {
t = apply_type_token (id, p, NULL_id);
changed = 1;
}
}
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
/* if (rec == 2 && !(ds & dspec_auto)) break ; */
if (ds & dspec_temp) {
/* Check for recursive token expansions */
report (crt_loc, ERR_token_recursive (id));
return (type_error);
}
COPY_dspec (id_storage (id), (ds | dspec_temp));
if (tag == tok_type_tag) {
/* Tokenised type */
TYPE s = DEREF_type (tok_type_value (tok));
if (!IS_NULL_type (s)) {
/* Expand token definition */
t = expand_type (s, rec);
if (ds & dspec_auto) {
COPY_type (tok_type_value (tok), t);
}
changed = 1;
} else {
BASE_TYPE bt;
bt = DEREF_btype (tok_type_kind (tok));
if (bt & btype_typename) {
/* Allow for typename */
s = find_typename (id, p, bt, 0);
if (!IS_NULL_type (s)) {
t = expand_type (s, rec);
changed = 1;
}
}
}
} else if (tag == tok_class_tag) {
/* Template template parameter */
aid = DEREF_id (tok_class_value (tok));
if (!IS_NULL_id (aid) && rec) {
p = expand_args (p, rec, 1);
aid = apply_template (aid, p, 0, 0);
if (IS_id_class_name_etc (aid)) {
t = DEREF_type (id_class_name_etc_defn (aid));
changed = 1;
}
}
}
if (changed) {
/* Qualify modified type */
if (prom == 1) {
t = promote_type (t);
} else if (prom == 2) {
t = arg_promote_type (t, KILL_err);
}
if (cv) {
CV_SPEC qual = DEREF_cv (type_qual (t));
t = qualify_type (t, (qual | cv), 0);
}
}
COPY_dspec (id_storage (id), ds);
}
break;
}
case type_templ_tag : {
/* Template types */
t = expand_templ_type (t, rec);
break;
}
}
return (t);
}
/*
* APPLY AN EXPRESSION TOKEN
*
* This routine applies the expression, statement or integer constant
* token id to the arguments args. If rec is true then the result
* type is expanded.
*/
EXP
apply_exp_token(IDENTIFIER id, LIST (TOKEN) args, int rec)
{
EXP e;
int is_proc = 0;
TOKEN tok = DEREF_tok (id_token_sort (id));
unsigned tag = TAG_tok (tok);
if (tag == tok_func_tag) {
tok = func_proc_token (tok);
tag = TAG_tok (tok);
}
if (tag == tok_proc_tag) {
is_proc = 1;
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
switch (tag) {
case tok_exp_tag : {
/* Expression tokens */
int pt = in_proc_token;
TYPE t = DEREF_type (tok_exp_type (tok));
int c = DEREF_int (tok_exp_constant (tok));
if (rec > 0) {
t = expand_type (t, rec);
} else if (pt) {
in_proc_token = 0;
t = expand_type (t, 2);
in_proc_token = pt;
}
t = convert_qual_type (t);
MAKE_exp_token (t, id, args, e);
if (c) {
/* Check for integer constant tokens */
unsigned tt = TAG_type (t);
if (tt == type_integer_tag || tt == type_enumerate_tag) {
NAT n;
MAKE_nat_calc (e, n);
MAKE_exp_int_lit (t, n, exp_token_tag, e);
}
} else {
/* Allow for exceptions */
if (is_proc) {
IGNORE check_throw (NULL_type, 0);
}
}
break;
}
case tok_stmt_tag : {
/* Statement tokens */
MAKE_exp_token (type_void, id, args, e);
while (!IS_NULL_list (args)) {
TOKEN arg = DEREF_tok (HEAD_list (args));
if (IS_tok_stmt (arg)) {
/* Set parent statement for arguments */
EXP a = DEREF_exp (tok_stmt_value (arg));
set_parent_stmt (a, e);
}
args = TAIL_list (args);
}
IGNORE check_throw (NULL_type, 0);
break;
}
case tok_nat_tag :
case tok_snat_tag : {
/* Integer constant tokens */
NAT n;
MAKE_nat_token (id, args, n);
MAKE_exp_int_lit (type_sint, n, exp_token_tag, e);
break;
}
default : {
/* Other tokens */
e = NULL_exp;
break;
}
}
return (e);
}
/*
* APPLY AN INTEGER CONSTANT TOKEN
*
* This routine applies the integer constant token id to the arguments args.
*/
NAT
apply_nat_token(IDENTIFIER id, LIST (TOKEN) args)
{
NAT n;
TOKEN tok = DEREF_tok (id_token_sort (id));
unsigned tag = TAG_tok (tok);
if (tag == tok_proc_tag) {
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
if (tag == tok_nat_tag || tag == tok_snat_tag) {
MAKE_nat_token (id, args, n);
} else {
n = NULL_nat;
}
return (n);
}
/*
* APPLY A BUILT-IN TYPE TOKEN
*
* Certain language extensions are implemented as built-in tokens (see
* define_keyword). This routine applies such a token, given by the
* keyword lex, to the arguments args.
*/
static TYPE
key_type_token(int lex, LIST (TOKEN) args)
{
TYPE t = NULL_type;
switch (lex) {
case lex_representation : {
TOKEN arg = DEREF_tok (HEAD_list (args));
t = DEREF_type (tok_type_value (arg));
if (!IS_NULL_type (t) && IS_type_integer (t)) {
TYPE s;
args = TAIL_list (args);
arg = DEREF_tok (HEAD_list (args));
s = DEREF_type (tok_type_value (arg));
if (!IS_NULL_type (s) && IS_type_integer (s)) {
INT_TYPE it = DEREF_itype (type_integer_rep (t));
INT_TYPE is = DEREF_itype (type_integer_rep (s));
t = make_itype (it, is);
}
}
break;
}
case lex_typeof : {
TOKEN arg = DEREF_tok (HEAD_list (args));
EXP e = DEREF_exp (tok_exp_value (arg));
if (!IS_NULL_exp (e)) {
t = DEREF_type (exp_type (e));
if (IS_type_bitfield (t)) {
t = promote_type (t);
}
}
break;
}
}
return (t);
}
/*
* APPLY A TYPE TOKEN
*
* This routine applies the type token id to the arguments args. tid
* gives the name, if any, to be given to any class created.
*/
TYPE
apply_type_token(IDENTIFIER id, LIST (TOKEN) args, IDENTIFIER tid)
{
TYPE t;
int pt = in_proc_token;
TOKEN tok = DEREF_tok (id_token_sort (id));
unsigned tag = TAG_tok (tok);
if (tag == tok_proc_tag) {
int lex = DEREF_int (tok_proc_key (tok));
if (lex != lex_identifier) {
t = key_type_token (lex, args);
if (!IS_NULL_type (t)) return (t);
}
tok = DEREF_tok (tok_proc_res (tok));
tag = TAG_tok (tok);
}
if (tag == tok_type_tag) {
BASE_TYPE bt = DEREF_btype (tok_type_kind (tok));
if (bt & btype_scalar) {
/* Scalar types */
t = apply_itype_token (id, args);
} else if (bt & btype_named) {
/* Structure and union types */
TYPE s;
CLASS_TYPE ct;
CLASS_INFO ci;
int tq = crt_templ_qualifier;
QUALIFIER cq = crt_id_qualifier;
int td = have_type_declaration;
if (IS_NULL_id (tid)) {
/* Make up class name if necessary */
HASHID tnm = lookup_anon ();
tid = DEREF_id (hashid_id (tnm));
}
/* Define the class */
crt_id_qualifier = qual_none;
crt_templ_qualifier = 0;
tid = begin_class_defn (tid, bt, cinfo_token, NULL_type);
if (IS_NULL_list (args)) {
COPY_id (id_token_alt (id), tid);
}
t = DEREF_type (id_class_name_etc_defn (tid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
ct = DEREF_ctype (type_compound_defn (t));
ci = DEREF_cinfo (ctype_info (ct));
ci &= ~cinfo_empty;
COPY_cinfo (ctype_info (ct), ci);
MAKE_type_token (cv_none, id, args, s);
COPY_type (ctype_form (ct), s);
in_class_defn++;
really_in_class_defn++;
IGNORE end_class_defn (tid);
really_in_class_defn--;
in_class_defn--;
have_type_declaration = td;
crt_templ_qualifier = tq;
crt_id_qualifier = cq;
} else {
/* Generic types */
MAKE_type_token (cv_none, id, args, t);
}
} else {
/* Shouldn't occur */
t = type_error;
}
if (pt) {
/* Expand token arguments */
in_proc_token = 0;
t = expand_type (t, 2);
in_proc_token = pt;
}
return (t);
}
/*
* APPLY A MEMBER TOKEN
*
* This routine applies the member token id to the arguments args.
*/
OFFSET
apply_mem_token(IDENTIFIER id, LIST (TOKEN) args)
{
OFFSET off;
MAKE_off_token (id, args, off);
return (off);
}
/*
* APPLY A TOKEN
*
* This routine applies the token id to the arguments args.
*/
TOKEN
apply_token(IDENTIFIER id, LIST (TOKEN) args)
{
TOKEN tok = NULL_tok;
TOKEN sort = DEREF_tok (id_token_sort (id));
unsigned tag = TAG_tok (sort);
if (tag == tok_proc_tag) {
sort = DEREF_tok (tok_proc_res (sort));
tag = TAG_tok (sort);
}
switch (tag) {
case tok_exp_tag : {
EXP e = apply_exp_token (id, args, 0);
TYPE t = DEREF_type (exp_type (e));
int c = DEREF_int (tok_exp_constant (sort));
MAKE_tok_exp (t, c, e, tok);
break;
}
case tok_nat_tag :
case tok_snat_tag : {
NAT n = apply_nat_token (id, args);
MAKE_tok_nat_etc (tag, n, tok);
break;
}
case tok_stmt_tag : {
EXP e = apply_exp_token (id, args, 0);
MAKE_tok_stmt (e, tok);
break;
}
case tok_type_tag : {
TYPE t;
BASE_TYPE bt = DEREF_btype (tok_type_kind (sort));
t = apply_type_token (id, args, NULL_id);
MAKE_tok_type (bt, t, tok);
break;
}
case tok_member_tag : {
TYPE s = DEREF_type (tok_member_of (sort));
TYPE t = DEREF_type (tok_member_type (sort));
OFFSET off = apply_mem_token (id, args);
MAKE_tok_member (s, t, off, tok);
break;
}
case tok_class_tag : {
TYPE t = DEREF_type (tok_class_type (sort));
MAKE_tok_class (t, id, tok);
break;
}
}
return (tok);
}
/*
* COMPARE TWO TOKENS
*
* This routine compares the token sorts a and b.
*/
static int
eq_tok(TOKEN a, TOKEN b)
{
/* Check for obvious equality */
unsigned na, nb;
if (EQ_tok (a, b)) return (1);
if (IS_NULL_tok (a)) return (0);
if (IS_NULL_tok (b)) return (0);
/* Compare tags */
na = TAG_tok (a);
nb = TAG_tok (b);
if (na != nb) return (0);
/* Compare token components */
ASSERT (ORDER_tok == 10);
switch (na) {
case tok_exp_tag : {
/* Expression tokens */
TYPE ta = DEREF_type (tok_exp_type (a));
TYPE tb = DEREF_type (tok_exp_type (b));
CV_SPEC qa = DEREF_cv (type_qual (ta));
CV_SPEC qb = DEREF_cv (type_qual (tb));
int ca = DEREF_int (tok_exp_constant (a));
int cb = DEREF_int (tok_exp_constant (b));
return (ca == cb && qa == qb && eq_type (ta, tb));
}
case tok_nat_tag :
case tok_snat_tag :
case tok_stmt_tag : {
/* Trivial cases */
break;
}
case tok_func_tag : {
/* Function tokens */
TYPE ta = DEREF_type (tok_func_type (a));
TYPE tb = DEREF_type (tok_func_type (b));
return (eq_type (ta, tb));
}
case tok_member_tag : {
/* Member tokens */
TYPE sa = DEREF_type (tok_member_of (a));
TYPE sb = DEREF_type (tok_member_of (b));
TYPE ta = DEREF_type (tok_member_type (a));
TYPE tb = DEREF_type (tok_member_type (b));
return (eq_type (sa, sb) && eq_type (ta, tb));
}
case tok_proc_tag : {
/* Procedure tokens */
LIST (IDENTIFIER) pa, pb;
TOKEN ra = DEREF_tok (tok_proc_res (a));
TOKEN rb = DEREF_tok (tok_proc_res (b));
if (!eq_tok (ra, rb)) return (0);
/* Compare program parameters */
pa = DEREF_list (tok_proc_pids (a));
pb = DEREF_list (tok_proc_pids (b));
if (LENGTH_list (pa) != LENGTH_list (pb)) return (0);
while (!IS_NULL_list (pa) && !IS_NULL_list (pb)) {
IDENTIFIER u = DEREF_id (HEAD_list (pa));
IDENTIFIER v = DEREF_id (HEAD_list (pb));
if (IS_NULL_id (u) || !IS_id_token (u)) return (0);
if (IS_NULL_id (v) || !IS_id_token (v)) return (0);
ra = DEREF_tok (id_token_sort (u));
rb = DEREF_tok (id_token_sort (v));
if (!eq_tok (ra, rb)) return (0);
pa = TAIL_list (pa);
pb = TAIL_list (pb);
}
/* Compare bound parameters */
pa = DEREF_list (tok_proc_bids (a));
pb = DEREF_list (tok_proc_bids (b));
if (LENGTH_list (pa) != LENGTH_list (pb)) return (0);
while (!IS_NULL_list (pa) && !IS_NULL_list (pb)) {
IDENTIFIER u = DEREF_id (HEAD_list (pa));
IDENTIFIER v = DEREF_id (HEAD_list (pb));
if (IS_NULL_id (u) || !IS_id_token (u)) return (0);
if (IS_NULL_id (v) || !IS_id_token (v)) return (0);
ra = DEREF_tok (id_token_sort (u));
rb = DEREF_tok (id_token_sort (v));
if (!eq_tok (ra, rb)) return (0);
pa = TAIL_list (pa);
pb = TAIL_list (pb);
}
break;
}
case tok_type_tag : {
/* Type tokens */
BASE_TYPE ta = DEREF_btype (tok_type_kind (a));
BASE_TYPE tb = DEREF_btype (tok_type_kind (b));
if (ta != tb) return (0);
break;
}
case tok_class_tag : {
/* Template class tokens */
TYPE ta = DEREF_type (tok_class_type (a));
TYPE tb = DEREF_type (tok_class_type (b));
if (eq_type (ta, tb) == 1) return (1);
return (0);
}
case tok_templ_tag : {
/* Templates */
/* NOT YET IMPLEMENTED */
return (0);
}
}
return (1);
}
/*
* DECLARE A TOKEN IDENTIFIER
*
* This routine declares a token identifier id with sort tok and external
* name ext in the namespace ns.
*/
static IDENTIFIER
declare_token(IDENTIFIER id, TOKEN tok, NAMESPACE ns, IDENTIFIER ext)
{
HASHID nm = DEREF_hashid (id_name (id));
MEMBER mem = search_member (ns, nm, 1);
/* Check identifier name */
ERROR err = check_id_name (id, CONTEXT_OBJECT);
if (!IS_NULL_err (err)) report (crt_loc, err);
/* Check for previous definition */
id = DEREF_id (member_id (mem));
if (!IS_NULL_id (id)) {
id = redecl_inherit (id, qual_none, 0, 0);
if (!IS_NULL_id (id)) {
if (IS_id_token (id)) {
/* Allow for redeclarations */
IDENTIFIER tid = DEREF_id (id_token_alt (id));
if (EQ_id (tid, ext)) return (id);
}
if (IS_id_function (id) && IS_tok_proc (tok)) {
IDENTIFIER pid = id;
while (!IS_NULL_id (pid)) {
TYPE t = DEREF_type (id_function_type (pid));
if (IS_type_func (t)) {
TOKEN ptok;
MAKE_tok_func (t, ptok);
ptok = func_proc_token (ptok);
if (eq_tok (ptok, tok)) {
/* Procedure token matches function */
return (pid);
}
}
pid = DEREF_id (id_function_over (pid));
}
}
}
}
/* Declare the token */
MAKE_id_token (nm, dspec_token, ns, preproc_loc, tok, ext, id);
set_member (mem, id);
return (id);
}
/*
* DECLARE AN EXTERNAL TOKEN
*
* This routine declares a token of sort tok with internal name id,
* which belongs to the tag namespace if tag is true, and external name
* ext. It returns the external token identifier.
*/
IDENTIFIER
make_token_decl(TOKEN tok, int tag, IDENTIFIER id, IDENTIFIER ext)
{
int tq;
HASHID nm;
MEMBER mem;
unsigned tt;
QUALIFIER cq;
NAMESPACE ns;
NAMESPACE gns;
int macro = 0;
int pushed = 0;
int done_dump = 0;
IDENTIFIER tid = NULL_id;
DECL_SPEC ds = dspec_token;
DECL_SPEC mark = dspec_token;
/* Ignore illegal tokens */
if (IS_NULL_tok (tok)) return (NULL_id);
/* Find token name */
if (!IS_NULL_id (ext)) {
/* Externally named token */
ns = token_namespace;
/* gns = global_namespace ; */
gns = nonblock_namespace;
nm = DEREF_hashid (id_name (ext));
mem = search_member (ns, nm, 1);
ext = DEREF_id (member_id (mem));
if (!IS_NULL_id (ext)) {
TOKEN tok2 = DEREF_tok (id_token_sort (ext));
force_tokdef++;
if (!eq_tok (tok, tok2)) {
ERROR err = ERR_token_redecl (ext, id_loc (ext));
report (preproc_loc, err);
ext = NULL_id;
}
force_tokdef--;
}
if (IS_hashid_anon (nm)) {
ds |= dspec_static;
} else {
ds |= dspec_extern;
}
} else {
/* Token parameter */
ns = crt_namespace;
gns = ns;
nm = DEREF_hashid (id_name (id));
mem = NULL_member;
ds |= (dspec_auto | dspec_pure);
}
/* Create the token */
if (IS_NULL_id (ext)) {
IDENTIFIER uid = underlying_id (id);
MAKE_id_token (nm, ds, ns, preproc_loc, tok, uid, ext);
if (!IS_NULL_member (mem)) {
COPY_id (member_id (mem), ext);
}
}
/* Declare the corresponding identifier */
cq = crt_id_qualifier;
tq = crt_templ_qualifier;
crt_id_qualifier = qual_none;
crt_templ_qualifier = 0;
if (!EQ_nspace (gns, crt_namespace)) {
push_namespace (gns);
pushed = 1;
}
tt = TAG_tok (tok);
if (tt == tok_type_tag) {
BASE_TYPE bt = DEREF_btype (tok_type_kind (tok));
if (bt & btype_named) {
/* Allow structure and union tags */
if (tag) tid = id;
} else {
tag = 0;
}
} else {
/* Other tags are not allowed */
tag = 0;
}
switch (tt) {
case tok_type_tag : {
/* Simple type tokens */
TYPE t = apply_type_token (ext, NULL_list (TOKEN), tid);
if (tag) {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
id = DEREF_id (ctype_name (ct));
done_dump = 1;
} else {
id = make_object_decl (dspec_typedef, t, id, 0);
if (!(ds & dspec_auto)) macro = 2;
}
break;
}
case tok_func_tag : {
/* Function tokens (C linkage by default) */
TYPE t = DEREF_type (tok_func_type (tok));
int ell = DEREF_int (type_func_ellipsis (t));
DECL_SPEC ln = crt_linkage;
if (ln == dspec_none) crt_linkage = dspec_c;
id = make_func_decl (dspec_extern, t, id, 0);
IGNORE init_object (id, NULL_exp);
if (IS_id_function_etc (id) && ell == FUNC_NONE) {
TYPE form;
MAKE_type_token (cv_none, ext, NULL_list (TOKEN), form);
COPY_type (id_function_etc_form (id), form);
if (!(ds & dspec_auto)) macro = 1;
if (is_redeclared) {
/* Mark functions which have already been declared */
ds |= dspec_explicit;
COPY_dspec (id_storage (ext), ds);
}
} else {
/* Ellipsis functions are not really tokenised */
mark = dspec_none;
}
crt_linkage = ln;
break;
}
case tok_member_tag : {
/* Member tokens */
int pt = in_proc_token;
CLASS_TYPE cs = crt_class;
TYPE t = DEREF_type (tok_member_of (tok));
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
NAMESPACE cns = DEREF_nspace (ctype_member (ct));
crt_class = ct;
in_class_defn++;
really_in_class_defn++;
push_namespace (cns);
t = DEREF_type (tok_member_type (tok));
if (pt) {
in_proc_token = 0;
t = expand_type (t, 2);
in_proc_token = pt;
}
id = make_member_decl (dspec_token, t, id, 0);
if (IS_id_member (id)) {
OFFSET off = DEREF_off (id_member_off (id));
if (!IS_NULL_off (off)) {
t = DEREF_type (id_member_type (id));
IGNORE define_mem_token (ext, off, t, 1);
if (!IS_NULL_member (mem)) {
if (IS_off_member (off)) {
/* Record old member name */
IDENTIFIER pid;
pid = DEREF_id (off_member_id (off));
COPY_id (member_alt (mem), pid);
}
}
}
off = apply_mem_token (ext, NULL_list (TOKEN));
COPY_off (id_member_off (id), off);
if (!(ds & dspec_auto)) macro = 2;
}
IGNORE pop_namespace ();
really_in_class_defn--;
in_class_defn--;
crt_class = cs;
break;
}
case tok_class_tag : {
/* Template template parameters */
TYPE t;
TYPE q = DEREF_type (tok_class_type (tok));
MAKE_type_token (cv_none, ext, NULL_list (TOKEN), t);
id = make_object_decl (dspec_typedef, t, id, 0);
t = inject_pre_type (q, t, 0);
COPY_type (id_class_name_etc_defn (id), t);
COPY_type (tok_class_type (tok), t);
mark |= dspec_template;
break;
}
default : {
/* Other tokens */
decl_loc = preproc_loc;
id = declare_token (id, tok, gns, ext);
if (IS_id_function (id)) {
TYPE form;
MAKE_type_token (cv_none, ext, NULL_list (TOKEN), form);
COPY_type (id_function_form (id), form);
}
if (!(ds & dspec_auto)) macro = 1;
break;
}
}
if (mark) {
/* Mark object as a token */
ds = DEREF_dspec (id_storage (id));
ds |= mark;
COPY_dspec (id_storage (id), ds);
}
COPY_id (id_token_alt (ext), id);
if (!IS_NULL_member (mem)) {
IDENTIFIER pid = DEREF_id (member_alt (mem));
if (IS_NULL_id (pid)) COPY_id (member_alt (mem), id);
if (do_dump) {
if (!done_dump) dump_declare (id, &preproc_loc, 0);
dump_token (id, ext);
}
}
if (pushed) {
IGNORE pop_namespace ();
}
crt_templ_qualifier = tq;
crt_id_qualifier = cq;
/* Check for previous macro definition */
if (macro) {
IDENTIFIER mid;
nm = DEREF_hashid (id_name (id));
mid = DEREF_id (hashid_id (nm));
switch (TAG_id (mid)) {
case id_obj_macro_tag :
case id_func_macro_tag : {
LOCATION loc;
loc = preproc_loc;
DEREF_loc (id_loc (mid), preproc_loc);
ds = DEREF_dspec (id_storage (mid));
COPY_dspec (id_storage (mid), (ds | dspec_temp));
if (define_token_macro (id, mid)) {
ds |= dspec_used;
if (do_macro && do_usage) {
dump_use (mid, &loc, 1);
}
COPY_loc (id_loc (ext), preproc_loc);
no_declarations++;
}
COPY_dspec (id_storage (mid), ds);
preproc_loc = loc;
break;
}
}
}
return (ext);
}
/*
* FIND A TOKEN IDENTIFIER
*
* This routine finds the token identifier associated with the identifier
* id.
*/
static IDENTIFIER
find_token_aux(IDENTIFIER id)
{
switch (TAG_id (id)) {
case id_class_name_tag :
case id_class_alias_tag : {
/* Classes */
TYPE t = DEREF_type (id_class_name_etc_defn (id));
if (IS_type_compound (t)) {
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
t = DEREF_type (ctype_form (ct));
if (!IS_NULL_type (t) && IS_type_token (t)) {
id = DEREF_id (type_token_tok (t));
return (id);
}
}
break;
}
case id_type_alias_tag : {
/* Types */
TYPE t = DEREF_type (id_type_alias_defn (id));
if (IS_type_token (t)) {
id = DEREF_id (type_token_tok (t));
return (id);
}
break;
}
case id_function_tag :
case id_mem_func_tag :
case id_stat_mem_func_tag : {
/* Functions */
TYPE form = DEREF_type (id_function_etc_form (id));
if (!IS_NULL_type (form) && IS_type_token (form)) {
IDENTIFIER ext = DEREF_id (type_token_tok (form));
if (!IS_NULL_id (ext)) return (ext);
}
return (id);
}
case id_member_tag : {
/* Members */
OFFSET off = DEREF_off (id_member_off (id));
if (IS_off_token (off)) {
id = DEREF_id (off_token_tok (off));
return (id);
}
break;
}
case id_token_tag : {
/* Tokens */
IDENTIFIER alt = DEREF_id (id_token_alt (id));
if (IS_id_token (alt)) return (alt);
return (id);
}
}
return (id);
}
/*
* FIND AN EXTERNAL TOKEN IDENTIFIER
*
* This routine finds the external token corresponding to the identifier id.
* For functions this refers only to the function id itself and not to
* any overloading functions.
*/
IDENTIFIER
find_token(IDENTIFIER id)
{
MEMBER mem;
DECL_SPEC ds;
IDENTIFIER tid;
HASHID nm = DEREF_hashid (id_name (id));
if (IS_id_keyword_etc (id)) {
/* Rescan keywords */
id = find_id (nm);
}
ds = DEREF_dspec (id_storage (id));
if (ds & dspec_token) {
/* Deal with simple tokens */
tid = find_token_aux (id);
if (IS_id_token (tid)) {
ds = DEREF_dspec (id_storage (tid));
if (!(ds & dspec_auto)) return (tid);
}
}
/* Complex cases - check through token namespace */
id = DEREF_id (id_alias (id));
mem = DEREF_member (nspace_global_first (token_namespace));
while (!IS_NULL_member (mem)) {
tid = DEREF_id (member_alt (mem));
if (EQ_id (tid, id)) {
tid = DEREF_id (member_id (mem));
return (tid);
}
mem = DEREF_member (member_next (mem));
}
return (id);
}
/*
* FIND A TAG TOKEN IDENTIFIER
*
* This routine finds the token corresponding to the tag identifier id.
*/
IDENTIFIER
find_tag_token(IDENTIFIER id)
{
id = find_elaborate_type (id, btype_any, NULL_type, dspec_used);
return (id);
}
/*
* FIND A MEMBER TOKEN IDENTIFIER
*
* This routine finds the token corresponding to the member mid of cid.
*/
IDENTIFIER
find_mem_token(IDENTIFIER cid, IDENTIFIER mid)
{
if (IS_id_class_name_etc (cid)) {
TYPE t = DEREF_type (id_class_name_etc_defn (cid));
IDENTIFIER fid = tok_member (mid, t, 1);
if (!IS_NULL_id (fid)) return (fid);
return (mid);
}
report (preproc_loc, ERR_dcl_type_simple_undef (cid));
return (mid);
}
/*
* FIND AN EXTERNAL TOKEN IDENTIFIER
*
* This routine finds the token with external name given by id.
*/
IDENTIFIER
find_ext_token(IDENTIFIER id)
{
HASHID nm = DEREF_hashid (id_name (id));
id = search_id (token_namespace, nm, 0, 0);
if (IS_NULL_id (id)) id = DEREF_id (hashid_id (nm));
return (id);
}
/*
* FIND A FUNCTION TOKEN IDENTIFIER
*
* This routine is identical to find_token except that it does a primitive
* form of overload resolution on function tokens based on the number of
* arguments n. A value of UINT_MAX indicates that any number of
* parameters is allowed.
*/
IDENTIFIER
find_func_token(IDENTIFIER id, unsigned n)
{
if (IS_id_function_etc (id)) {
int no = 0;
IDENTIFIER tid = NULL_id;
IDENTIFIER fid = id;
while (!IS_NULL_id (fid)) {
TYPE form = DEREF_type (id_function_etc_form (fid));
if (!IS_NULL_type (form) && IS_type_token (form)) {
IDENTIFIER ext = DEREF_id (type_token_tok (form));
if (!IS_NULL_id (ext) && IS_id_token (ext)) {
if (n == (unsigned) UINT_MAX) {
tid = ext;
no++;
} else {
TYPE t;
int ell;
LIST (TYPE) p;
t = DEREF_type (id_function_etc_type (fid));
while (IS_type_templ (t)) {
t = DEREF_type (type_templ_defn (t));
}
p = DEREF_list (type_func_ptypes (t));
ell = DEREF_int (type_func_ellipsis (t));
if (LENGTH_list (p) == n) {
if (!(ell & FUNC_ELLIPSIS)) {
tid = ext;
no++;
}
}
}
}
}
fid = DEREF_id (id_function_etc_over (fid));
}
if (no > 1) report (preproc_loc, ERR_token_def_ambig (id));
return (tid);
}
return (find_token (id));
}
/*
* CURRENT INTERFACE METHOD
*
* This flag is used to record the current interface method. It gives the
* mapping of any '#pragma interface' to one of '#pragma define', '#pragma
* no_def' or '#pragma ignore'.
*/
int crt_interface = lex_no_Hdef;
/*
* PERFORM A TOKEN INTERFACE OPERATION
*
* This routine performs the token interface operation indicated by i
* (which will be lex_define, lex_no_Hdef, lex_ignore) on the token tid.
*/
static void
mark_interface(IDENTIFIER tid, int i)
{
DECL_SPEC ds = DEREF_dspec (id_storage (tid));
if (i == lex_define) {
/* Token must be defined */
ds |= dspec_static;
ds &= ~dspec_pure;
} else if (i == lex_no_Hdef) {
/* Token must not be defined */
ds |= dspec_pure;
if (ds & dspec_defn) {
/* Token already defined */
PTR (LOCATION) loc = id_loc (tid);
report (preproc_loc, ERR_token_no_def (tid, loc));
}
} else {
/* Ignore token definitions */
ds |= dspec_done;
ds &= ~dspec_pure;
}
COPY_dspec (id_storage (tid), ds);
return;
}
/*
* PERFORM A TOKEN INTERFACE OPERATION
*
* This routine looks up the token id and performs the token operation
* i on it. In addition to the values above i can be lex_undef indicating
* that the token should be undefined.
*/
void
token_interface(IDENTIFIER id, int i)
{
int ok = 0;
IDENTIFIER pid = id;
while (!IS_NULL_id (pid)) {
IDENTIFIER tid = find_token (pid);
if (IS_id_token (tid)) {
/* Token found */
if (i == lex_undef) {
if (do_dump) dump_undefine (pid, &preproc_loc, 1);
remove_id (pid);
} else {
mark_interface (tid, i);
}
ok = 1;
}
if (!IS_id_function_etc (pid)) break;
pid = DEREF_id (id_function_etc_over (pid));
}
if (!ok) {
/* Token not found */
report (preproc_loc, ERR_token_undecl (id));
}
return;
}