/*
* 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/utility/print.c,v 1.14 2005/10/18 08:33:44 stefanf Exp $
*/
#include "config.h"
#include "producer.h"
#include
#include "msgcat.h"
#include "system.h"
#include "c_types.h"
#include "ctype_ops.h"
#include "etype_ops.h"
#include "exp_ops.h"
#include "flt_ops.h"
#include "ftype_ops.h"
#include "graph_ops.h"
#include "hashid_ops.h"
#include "id_ops.h"
#include "itype_ops.h"
#include "member_ops.h"
#include "nat_ops.h"
#include "nspace_ops.h"
#include "off_ops.h"
#include "str_ops.h"
#include "tok_ops.h"
#include "type_ops.h"
#include "error.h"
#include "basetype.h"
#include "buffer.h"
#include "char.h"
#include "class.h"
#include "constant.h"
#include "convert.h"
#include "debug.h"
#include "exception.h"
#include "file.h"
#include "function.h"
#include "hash.h"
#include "label.h"
#include "lex.h"
#include "literal.h"
#include "print.h"
#include "redeclare.h"
#include "symbols.h"
#include "syntax.h"
#include "tok.h"
#include "token.h"
#include "ustring.h"
/*
* PRINT BUFFER
*
* This buffer is used for the error output.
*/
BUFFER print_buff = NULL_buff;
/*
* FUNCTION DECLARATIONS
*
* A couple of forward function declarations are necessary.
*/
static int print_head(TYPE, int, BUFFER *, int);
static int print_tail(TYPE, BUFFER *, int);
/*
* PRINT FLAGS
*
* These flags are used to control the form of the output.
*/
static int print_default_args = 0;
static int print_member_type = 0;
static int print_return_type = 1;
static int print_func_params = 0;
static int print_except = 0;
static int print_func_linkage = 0;
static int print_parent_namespace = 1;
static int print_bitfield_sep = ':';
int print_c_style = LANGUAGE_C;
int print_type_alias = 0;
int print_uniq_anon = 0;
int print_id_desc = 0;
/*
* PRINT A LEXICAL TOKEN NAME
*
* This routine prints the name of the lexical token t to the buffer bf.
* With all the routines in this file the sp argument is true if a space
* should be printed before the actual text, and the return value is true
* if a space should be printed after it.
*/
int
print_lex(int t, BUFFER *bf, int sp)
{
string s = token_name (t);
if (s == NULL) return (sp);
if (sp) bfputc (bf, ' ');
bfputs (bf, s);
return (1);
}
/*
* PRINT AN ACCESS SPECIFIER
*
* This routine prints the access specifier n to the buffer bf.
*/
int
print_access(DECL_SPEC n, BUFFER *bf, int sp)
{
int t;
DECL_SPEC a = (n & dspec_access);
if (a == dspec_private) {
t = lex_private;
} else if (a == dspec_protected) {
t = lex_protected;
} else {
t = lex_public;
}
sp = print_lex (t, bf, sp);
return (sp);
}
/*
* BUILT-IN TYPE NAMES
*
* This table gives the names of the built-in types.
*/
const char *ntype_name [ ORDER_ntype ] = {
"", /* ntype_none */
"char", /* ntype_char */
"signed char", /* ntype_schar */
"unsigned char", /* ntype_uchar */
"short", /* ntype_sshort */
"unsigned short", /* ntype_ushort */
"int", /* ntype_sint */
"unsigned int", /* ntype_uint */
"long", /* ntype_slong */
"unsigned long", /* ntype_ulong */
"long long", /* ntype_sllong */
"unsigned long long", /* ntype_ullong */
"float", /* ntype_float */
"double", /* ntype_double */
"long double", /* ntype_ldouble */
"void", /* ntype_void */
"", /* ntype_bottom */
#if LANGUAGE_CPP
"bool", /* ntype_bool */
#else
"_Bool", /* ntype_bool */
#endif
"ptrdiff_t", /* ntype_ptrdiff_t */
"size_t", /* ntype_size_t */
"wchar_t", /* ntype_wchar_t */
"..." /* ntype_ellipsis */
};
/*
* PRINT A BUILT-IN TYPE
*
* This routine prints the built-in type n to the buffer bf.
*/
int
print_ntype(BUILTIN_TYPE n, BUFFER *bf, int sp)
{
if (sp) bfputc (bf, ' ');
bfputs (bf, ustrlit (ntype_name [n]));
return (1);
}
/*
* PRINT A BASE TYPE
*
* This routine prints the base type n to the buffer bf.
*/
int
print_btype(BASE_TYPE n, BUFFER *bf, int sp)
{
BASE_TYPE key = (n & btype_named);
if (key) {
switch (key) {
case btype_class : sp = print_lex (lex_class, bf, sp); break;
case btype_struct : sp = print_lex (lex_struct, bf, sp); break;
case btype_union : sp = print_lex (lex_union, bf, sp); break;
case btype_enum : sp = print_lex (lex_enum, bf, sp); break;
case btype_any : sp = print_lex (lex_tag_Hcap, bf, sp); break;
}
} else {
if (n & btype_signed) sp = print_lex (lex_signed, bf, sp);
if (n & btype_unsigned) sp = print_lex (lex_unsigned, bf, sp);
if (n & btype_short) sp = print_lex (lex_short, bf, sp);
if (n & btype_long) sp = print_lex (lex_long, bf, sp);
if (n & btype_long2) sp = print_lex (lex_long, bf, sp);
if (n & btype_char) sp = print_lex (lex_char, bf, sp);
if (n & btype_int) sp = print_lex (lex_int, bf, sp);
if (n & btype_float) sp = print_lex (lex_float, bf, sp);
if (n & btype_double) sp = print_lex (lex_double, bf, sp);
if (n & btype_void) sp = print_lex (lex_void, bf, sp);
if (n & btype_bottom) sp = print_lex (lex_bottom, bf, sp);
if (n & btype_bool) sp = print_lex (lex_bool, bf, sp);
if (n & btype_ptrdiff_t) sp = print_lex (lex_ptrdiff_Ht, bf, sp);
if (n & btype_size_t) sp = print_lex (lex_size_Ht, bf, sp);
if (n & btype_wchar_t) sp = print_lex (lex_wchar_Ht, bf, sp);
if (n & btype_ellipsis) sp = print_lex (lex_ellipsis, bf, sp);
if (n & btype_star) sp = print_lex (lex_star, bf, sp);
}
return (sp);
}
/*
* PRINT A CONST-VOLATILE QUALIFIER
*
* This routine prints the const-volatile qualifier n to the buffer bf.
*/
int
print_cv(CV_SPEC n, BUFFER *bf, int sp)
{
if (n) {
if (n & cv_const) sp = print_lex (lex_const, bf, sp);
if (n & cv_restrict) sp = print_lex (lex_restrict, bf, sp);
if (n & cv_volatile) sp = print_lex (lex_volatile, bf, sp);
}
return (sp);
}
/*
* PRINT A DECLARATION SPECIFIER
*
* This routine prints the declaration specifier n to the buffer bf. The
* C and C++ linkage specifiers are not included.
*/
int
print_dspec(DECL_SPEC n, BUFFER *bf, int sp)
{
if (n & dspec_typedef) sp = print_lex (lex_typedef, bf, sp);
if (n & dspec_storage) {
if (n & dspec_extern) sp = print_lex (lex_extern, bf, sp);
if (n & dspec_static) sp = print_lex (lex_static, bf, sp);
if (n & dspec_register) sp = print_lex (lex_register, bf, sp);
if (n & dspec_auto) sp = print_lex (lex_auto, bf, sp);
if (n & dspec_mutable) sp = print_lex (lex_mutable, bf, sp);
}
if (n & dspec_function) {
if (n & dspec_explicit) sp = print_lex (lex_explicit, bf, sp);
if (n & dspec_friend) sp = print_lex (lex_friend, bf, sp);
if (n & dspec_inline) sp = print_lex (lex_inline, bf, sp);
if (n & dspec_virtual) sp = print_lex (lex_virtual, bf, sp);
}
return (sp);
}
/*
* PRINT A LINKAGE SPECIFIER
*
* This routine prints the linkage specifier n to the buffer bf.
*/
static int
print_linkage(CV_SPEC n, BUFFER *bf, int sp)
{
CV_SPEC m = (n & cv_language);
if (m) {
if (m != cv_cpp && !print_c_style) {
string s = linkage_string (dspec_none, m);
if (sp) bfputc (bf, ' ');
bfprintf (bf, "extern \"%s\"", s);
sp = 1;
}
}
return (sp);
}
/*
* PRINT A BUFFER LOCATION
*
* This routine prints the file location p to the buffer bf. q gives
* the main location. If the file names from p and q match then only
* the line number is printed.
*/
int
print_loc(LOCATION *p, LOCATION *q, BUFFER *bf, int sp)
{
string fn;
unsigned long ln;
if (sp) bfputc (bf, ' ');
if (p == NULL) {
fn = ustrlit ("");
ln = 0;
} else {
PTR (POSITION) pa = p->posn;
if (IS_NULL_ptr (pa)) {
fn = ustrlit ("");
} else {
fn = DEREF_string (posn_file (pa));
if (q) {
/* Check previous location */
PTR (POSITION) qa = q->posn;
if (EQ_ptr (qa, pa)) {
fn = NULL;
} else if (!IS_NULL_ptr (qa)) {
string gn = DEREF_string (posn_file (qa));
if (ustreq (gn, fn)) fn = NULL;
}
}
}
ln = p->line;
}
if (fn) {
bfprintf (bf, "\"%s\"", fn);
if (ln) bfprintf (bf, ", line %lu", ln);
} else {
bfprintf (bf, "line %lu", ln);
}
return (1);
}
/*
* PRINT A HASH TABLE ENTRY
*
* This routine prints the identifier name corresponding to the hash
* table entry p to the buffer bf.
*/
int
print_hashid(HASHID p, int sep, int anon, BUFFER *bf, int sp)
{
unsigned tag;
if (IS_NULL_hashid (p)) return (sp);
tag = TAG_hashid (p);
ASSERT (ORDER_hashid == 7);
switch (tag) {
case hashid_name_tag :
case hashid_ename_tag : {
/* Simple name */
string s = DEREF_string (hashid_name_etc_text (p));
if (sp) bfputc (bf, ' ');
bfputs (bf, s);
sp = 1;
break;
}
case hashid_constr_tag :
case hashid_destr_tag : {
/* Class destructor name */
IDENTIFIER tid = DEREF_id (hashid_constr_etc_tid (p));
if (IS_NULL_id (tid)) {
/* Unnamed constructor or destructor */
TYPE t = DEREF_type (hashid_constr_etc_type (p));
if (sep) {
IGNORE print_type (t, bf, sp);
bfprintf (bf, "::");
} else {
if (sp) bfputc (bf, ' ');
}
if (tag == hashid_destr_tag) bfputc (bf, '~');
sp = print_type (t, bf, 0);
} else {
/* Named constructor or destructor */
static HASHID lastp = NULL_hashid;
if (sep && !EQ_hashid (p, lastp)) {
lastp = p;
tid = DEREF_id (hashid_id (p));
sp = print_id_short (tid, qual_none, bf, sp);
lastp = NULL_hashid;
break;
}
p = DEREF_hashid (id_name (tid));
if (sp) bfputc (bf, ' ');
if (sep) {
IGNORE print_hashid (p, 0, 1, bf, 0);
bfprintf (bf, "::");
}
if (tag == hashid_destr_tag) bfputc (bf, '~');
sp = print_hashid (p, 0, 1, bf, 0);
}
break;
}
case hashid_conv_tag : {
/* Overloaded conversion name */
int prt = print_return_type;
TYPE t = DEREF_type (hashid_conv_type (p));
sp = print_lex (lex_operator, bf, sp);
print_return_type = 1;
sp = print_type (t, bf, sp);
print_return_type = prt;
break;
}
case hashid_op_tag : {
/* Overloaded operator name */
int op = DEREF_int (hashid_op_lex (p));
string s = token_name (op);
sp = print_lex (lex_operator, bf, sp);
if (s) {
int c = (int) *s;
if (isalpha (c)) bfputc (bf, ' ');
bfputs (bf, s);
}
break;
}
case hashid_anon_tag : {
/* Anonymous identifier */
if (anon) {
unsigned long u = DEREF_ulong (hashid_anon_uniq (p));
if (sp) bfputc (bf, ' ');
if (print_uniq_anon) {
bfprintf (bf, "", uniq_string, u);
} else {
bfprintf (bf, "", u);
}
sp = 1;
}
break;
}
}
return (sp);
}
/*
* PRINT AN IDENTIFIER (SHORT FORM)
*
* This routines prints the short form of the identifier id to the buffer bf.
*/
int
print_id_short(IDENTIFIER id, QUALIFIER qual, BUFFER *bf, int sp)
{
if (!IS_NULL_id (id)) {
int sep = 0;
HASHID p = DEREF_hashid (id_name (id));
/* Print enclosing namespace name */
NAMESPACE ns = DEREF_nspace (id_parent (id));
if (sp) bfputc (bf, ' ');
if (print_parent_namespace && !print_c_style) {
if (IS_NULL_nspace (ns)) {
if (qual == qual_full || qual == qual_top) {
bfprintf (bf, "::");
}
sep = 1;
} else {
IGNORE print_nspace (ns, qual, 1, bf, 0);
}
}
/* Print identifier name */
if (IS_hashid_anon (p)) {
/* Print anonymous identifier names */
IDENTIFIER alt = id;
unsigned tag = TAG_id (id);
if (tag == id_token_tag) {
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_auto) {
alt = DEREF_id (id_token_alt (id));
tag = id_parameter_tag;
}
}
if (tag == id_parameter_tag) {
/* Parameter names */
unsigned long n = 0;
MEMBER mem = DEREF_member (nspace_last (ns));
id = DEREF_id (id_alias (id));
alt = DEREF_id (id_alias (alt));
while (!IS_NULL_member (mem)) {
IDENTIFIER mid = DEREF_id (member_id (mem));
if (!IS_NULL_id (mid)) {
if (EQ_id (mid, id)) n = 0;
if (EQ_id (mid, alt)) n = 0;
n++;
}
mem = DEREF_member (member_next (mem));
}
bfprintf (bf, "", n);
} else {
/* Other identifiers */
LOCATION loc;
string fn, fs;
DEREF_loc (id_loc (id), loc);
fs = DEREF_string (posn_file (loc.posn));
fn = ustrrchr (fs, '/');
fn = (fn ? fn + 1 : fs);
bfprintf (bf, "(\"%s\":%lu)", fn, loc.line);
}
} else {
/* Print other identifier names */
IGNORE print_hashid (p, sep, 0, bf, 0);
}
sp = 1;
}
return (sp);
}
/*
* PRINT AN IDENTIFIER (LONG FORM)
*
* This routines prints the long form of the identifier id to the buffer bf.
*/
int
print_id_long(IDENTIFIER id, QUALIFIER qual, BUFFER *bf, int sp)
{
if (!IS_NULL_id (id)) {
int prt = 1;
int key = 0;
TYPE t = NULL_type;
TYPE f = NULL_type;
TOKEN tok = NULL_tok;
GRAPH gr = NULL_graph;
const char *desc = NULL;
int full = print_id_desc;
NAMESPACE pns = NULL_nspace;
LIST (TYPE) p = NULL_list (TYPE);
switch (TAG_id (id)) {
case id_keyword_tag :
case id_iso_keyword_tag : {
/* Keywords */
if (full) desc = "keyword";
break;
}
case id_builtin_tag : {
/* Built-in operators */
t = DEREF_type (id_builtin_ret (id));
p = DEREF_list (id_builtin_ptypes (id));
if (full) desc = "built-in";
break;
}
case id_obj_macro_tag :
case id_func_macro_tag : {
/* Macros */
if (full) desc = "macro";
break;
}
case id_predicate_tag : {
/* Predicates */
if (full) desc = "predicate";
break;
}
case id_class_name_tag :
case id_enum_name_tag : {
/* Class and enumeration names */
f = DEREF_type (id_class_name_etc_defn (id));
key = (full || print_c_style);
break;
}
case id_class_alias_tag :
case id_enum_alias_tag :
case id_type_alias_tag : {
/* Typedef names */
if (full) {
t = DEREF_type (id_class_name_etc_defn (id));
desc = "typedef";
}
break;
}
case id_nspace_name_tag : {
/* Namespace names */
if (full) desc = "namespace";
break;
}
case id_nspace_alias_tag : {
/* Namespace aliases */
if (full) {
desc = "namespace";
pns = DEREF_nspace (id_nspace_alias_defn (id));
}
break;
}
case id_variable_tag :
case id_parameter_tag : {
/* Object names */
if (full) {
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_auto) desc = "auto";
t = DEREF_type (id_variable_etc_type (id));
}
break;
}
case id_stat_member_tag : {
/* Static members */
if (full) {
t = DEREF_type (id_stat_member_type (id));
desc = "static";
}
break;
}
case id_weak_param_tag : {
if (full) {
desc = "auto";
t = type_sint;
}
break;
}
case id_function_tag :
case id_mem_func_tag : {
/* Function names */
HASHID nm = DEREF_hashid (id_name (id));
switch (TAG_hashid (nm)) {
case hashid_constr_tag :
case hashid_destr_tag :
case hashid_conv_tag : {
/* Inhibit return type */
prt = 0;
break;
}
}
t = DEREF_type (id_function_etc_type (id));
f = DEREF_type (id_function_etc_form (id));
if (!IS_NULL_type (f) && !IS_type_token (f)) {
f = NULL_type;
}
if (full) {
DECL_SPEC ds = DEREF_dspec (id_storage (id));
if (ds & dspec_implicit) desc = "implicit";
} else {
if (print_c_style) t = NULL_type;
}
break;
}
case id_stat_mem_func_tag : {
/* Static function member names */
t = DEREF_type (id_stat_mem_func_type (id));
f = DEREF_type (id_stat_mem_func_form (id));
if (!IS_NULL_type (f) && !IS_type_token (f)) {
f = NULL_type;
}
if (full) {
desc = "static";
} else {
if (print_c_style) t = NULL_type;
}
break;
}
case id_member_tag : {
/* Member names */
gr = DEREF_graph (id_member_base (id));
if (full) t = DEREF_type (id_member_type (id));
break;
}
case id_enumerator_tag : {
/* Enumerator names */
if (full) desc = "enumerator";
break;
}
case id_label_tag : {
/* Label names */
if (full) {
int op = DEREF_int (id_label_op (id));
if (op != lex_identifier) {
/* Print kind of label */
sp = print_lex (op, bf, sp);
if (op == lex_case) {
NAT n = find_case_nat (id);
sp = print_nat (n, 0, bf, sp);
}
return (sp);
}
desc = "label";
}
break;
}
case id_token_tag : {
/* Token names */
if (full) {
tok = DEREF_tok (id_token_sort (id));
desc = "token";
}
break;
}
}
if (desc) {
/* Print description */
if (sp) bfputc (bf, ' ');
bfprintf (bf, desc);
sp = 1;
}
if (!IS_NULL_tok (tok)) {
/* Print token sort */
sp = print_sort (tok, 0, bf, sp);
}
if (!IS_NULL_type (t)) {
/* Print start of identifier type */
print_return_type = prt;
sp = print_head (t, key, bf, sp);
print_return_type = 1;
}
if (IS_NULL_type (f)) {
if (!IS_NULL_graph (gr)) {
sp = print_graph (gr, 1, bf, sp);
print_parent_namespace = 0;
}
sp = print_id_short (id, qual, bf, sp);
print_parent_namespace = 1;
} else {
sp = print_head (f, key, bf, sp);
sp = print_tail (f, bf, sp);
}
if (!IS_NULL_type (t)) {
/* Print end of identifier type */
print_default_args = 1;
sp = print_tail (t, bf, sp);
print_default_args = 0;
}
if (!IS_NULL_list (p)) {
/* Print parameter types */
sp = print_type_list (p, bf, 1);
}
if (!IS_NULL_nspace (pns)) {
/* Print namespace alias definition */
sp = print_lex (lex_assign, bf, sp);
sp = print_nspace (pns, qual_none, 0, bf, sp);
}
}
return (sp);
}
/*
* PRINT A NAMESPACE
*
* This routines prints the namespace ns to the buffer bf. The argument
* pre is true if this a prefix to an identifier and false if the namespace
* itself is what is required.
*/
int
print_nspace(NAMESPACE ns, QUALIFIER qual, int pre, BUFFER *bf, int sp)
{
if (!IS_NULL_nspace (ns)) {
IDENTIFIER id = DEREF_id (nspace_name (ns));
switch (TAG_nspace (ns)) {
case nspace_named_tag :
case nspace_ctype_tag : {
/* Named and class namespaces */
if (sp) bfputc (bf, ' ');
if (IS_id_class_name (id)) {
TYPE t = DEREF_type (id_class_name_defn (id));
if (IS_type_compound (t)) {
int key = 0;
CLASS_TYPE ct;
if (!pre) key = print_c_style;
ct = DEREF_ctype (type_compound_defn (t));
IGNORE print_ctype (ct, qual, key, bf, 0);
} else {
IGNORE print_id_short (id, qual, bf, 0);
}
} else {
IGNORE print_id_short (id, qual, bf, 0);
}
if (pre) bfprintf (bf, "::");
sp = 1;
break;
}
case nspace_unnamed_tag : {
/* Unnamed namespaces */
if (sp) bfputc (bf, ' ');
ns = DEREF_nspace (id_parent (id));
IGNORE print_nspace (ns, qual, 1, bf, 0);
if (print_uniq_anon) {
bfprintf (bf, "", uniq_string);
} else {
bfprintf (bf, "");
}
if (pre) bfprintf (bf, "::");
sp = 1;
break;
}
case nspace_global_tag : {
/* The global namespace */
if (!pre || qual == qual_full || qual == qual_top) {
if (sp) bfputc (bf, ' ');
bfprintf (bf, "::");
sp = 1;
}
break;
}
default : {
/* Other namespaces */
if (!pre) sp = print_id_short (id, qual, bf, sp);
break;
}
}
}
return (sp);
}
/*
* PRINT A GRAPH
*
* This routines prints the graph gr to the buffer bf. The argument sep is
* true to indicate that a terminal '::' should be included.
*/
int
print_graph(GRAPH gr, int sep, BUFFER *bf, int sp)
{
if (!IS_NULL_graph (gr)) {
CLASS_TYPE ct = DEREF_ctype (graph_head (gr));
GRAPH gs = DEREF_graph (graph_up (gr));
if (sp) {
bfputc (bf, ' ');
sp = 0;
}
if (!IS_NULL_graph (gs)) {
IGNORE print_graph (gs, 1, bf, 0);
print_parent_namespace = 0;
}
IGNORE print_ctype (ct, qual_none, 0, bf, 0);
print_parent_namespace = 1;
if (sep) bfprintf (bf, "::");
}
return (sp);
}
/*
* PRINT A PREPROCESSING TOKEN
*
* This routine prints the preprocessing token p to the buffer bf. It
* is used not only in the error reporting routines, but also in the
* preprocessing action.
*/
int
print_pptok(PPTOKEN *p, BUFFER *bf, int sp)
{
int q;
int t = p->tok;
if (sp) bfputc (bf, ' ');
switch (t) {
case lex_identifier :
case lex_type_Hname :
case lex_namespace_Hname :
case lex_statement_Hname :
identifier_label : {
/* Identifiers */
HASHID nm = p->pp_data.id.hash;
string s = DEREF_string (hashid_name_etc_text (nm));
bfputs (bf, s);
break;
}
case lex_destructor_Hname : {
/* Destructor names */
bfputc (bf, '~');
goto identifier_label;
}
case lex_template_Hid :
case lex_template_Htype : {
/* Template names */
IDENTIFIER id = p->pp_data.tok.id;
IGNORE print_id_short (id, qual_none, bf, 0);
break;
}
case lex_integer_Hlit : {
/* Integer and floating point literals */
string s = p->pp_data.text;
bfputs (bf, s);
break;
}
case lex_char_Hlit : {
/* Character literals */
q = '\'';
string_label : {
string s = p->pp_data.str.start;
string e = p->pp_data.str.end;
bfputc (bf, q);
while (s != e) {
bfputc (bf, (int) *s);
s++;
}
bfputc (bf, q);
}
break;
}
case lex_wchar_Hlit : {
/* Wide character literals */
bfputc (bf, 'L');
q = '\'';
goto string_label;
}
case lex_string_Hlit : {
/* String literals */
q = '"';
goto string_label;
}
case lex_wstring_Hlit : {
/* Wide string literals */
bfputc (bf, 'L');
q = '"';
goto string_label;
}
case lex_integer_Hexp :
case lex_floating_Hexp :
case lex_char_Hexp :
case lex_wchar_Hexp :
case lex_string_Hexp :
case lex_wstring_Hexp : {
/* Literal expressions */
IGNORE print_exp (p->pp_data.exp, 0, bf, 0);
break;
}
case lex_unknown : {
/* Unknown characters */
unsigned long u;
int ch = CHAR_SIMPLE;
u = get_multi_char (p->pp_data.buff, &ch);
if (ch == CHAR_SIMPLE) {
bfputc (bf, (int) u);
} else {
print_char (u, ch, 0, bf);
}
break;
}
case lex_nested_Hname : {
/* Nested name qualifier */
NAMESPACE ns = p->pp_data.ns;
IGNORE print_nspace (ns, qual_nested, 1, bf, 0);
break;
}
case lex_full_Hname : {
/* Nested name qualifier */
NAMESPACE ns = p->pp_data.ns;
IGNORE print_nspace (ns, qual_full, 1, bf, 0);
break;
}
case lex_nested_Hname_Hstar : {
/* Nested member qualifier */
IDENTIFIER id = p->pp_data.id.use;
IGNORE print_id_short (id, qual_nested, bf, 0);
bfprintf (bf, "::*");
break;
}
case lex_full_Hname_Hstar : {
/* Nested member qualifier */
IDENTIFIER id = p->pp_data.id.use;
IGNORE print_id_short (id, qual_full, bf, 0);
bfprintf (bf, "::*");
break;
}
case lex_complex_Hexp :
case lex_complex_Htype : {
/* Token applications etc. */
IDENTIFIER id = p->pp_data.tok.id;
IGNORE print_id_short (id, qual_none, bf, 0);
break;
}
case lex_macro_Harg : {
/* Macro parameters */
HASHID nm = p->pp_data.par.hash;
string s = DEREF_string (hashid_name_etc_text (nm));
bfputs (bf, s);
break;
}
default : {
/* Simple token */
if (t >= 0) {
string s = token_name (t);
bfputs (bf, s);
} else {
bfprintf (bf, "");
}
break;
}
}
return (1);
}
/*
* INTEGER LITERAL PRINTING
*
* This prints an integer literal to the buffer bf. The only difficult case
* is when a large literal will not fit into an unsigned long. The digits
* need to be printed in reverse order, and it is again quickest to reverse
* the order of the list twice.
*/
int
print_nat(NAT n, int paren, BUFFER *bf, int sp)
{
if (!IS_NULL_nat (n)) {
ASSERT (ORDER_nat == 5);
switch (TAG_nat (n)) {
case nat_small_tag : {
/* Small values */
unsigned v = DEREF_unsigned (nat_small_value (n));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%u", v);
sp = 1;
break;
}
case nat_large_tag : {
/* Large values */
LIST (unsigned) p;
p = DEREF_list (nat_large_values (n));
if (sp) bfputc (bf, ' ');
if (LENGTH_list (p) <= 2) {
/* Two digit literals will fit into a unsigned long */
unsigned long v = get_nat_value (n);
bfprintf (bf, "%lu", v);
} else {
/* Print large literals by scanning through digits */
char buff [50];
const char *fmt = "0x%x";
LIST (unsigned) q;
p = REVERSE_list (p);
q = p;
while (!IS_NULL_list (q)) {
unsigned v = DEREF_unsigned (HEAD_list (q));
sprintf_v (buff, fmt, v);
bfputs (bf, ustrlit (buff));
fmt = "%04x";
q = TAIL_list (q);
}
IGNORE REVERSE_list (p);
}
sp = 1;
break;
}
case nat_calc_tag : {
/* Calculated values */
EXP e = DEREF_exp (nat_calc_value (n));
while (!IS_NULL_exp (e) && IS_exp_cast (e)) {
e = DEREF_exp (exp_cast_arg (e));
}
sp = print_exp (e, paren, bf, sp);
break;
}
case nat_neg_tag : {
/* Negative values */
NAT m = DEREF_nat (nat_neg_arg (n));
if (sp) bfputc (bf, ' ');
bfputc (bf, '-');
IGNORE print_nat (m, 1, bf, 0);
break;
}
case nat_token_tag : {
IDENTIFIER id = DEREF_id (nat_token_tok (n));
LIST (TOKEN) args = DEREF_list (nat_token_args (n));
sp = print_token (id, qual_none, args, bf, sp);
break;
}
}
}
return (sp);
}
/*
* FLOATING-POINT LITERAL PRINTING
*
* This routine prints a floating-point literal to the buffer bf.
*/
int
print_flt(FLOAT n, BUFFER *bf, int sp)
{
if (!IS_NULL_flt (n)) {
string i = DEREF_string (flt_simple_int_part (n));
string d = DEREF_string (flt_simple_frac_part (n));
NAT e = DEREF_nat (flt_simple_exponent (n));
unsigned b = DEREF_unsigned (flt_simple_base (n));
if (sp) bfputc (bf, ' ');
if (b == 16) bfprintf (bf, "0x");
bfprintf (bf, "%s.%s", i, d);
if (!is_zero_nat (e) || b == 16) {
bfputc (bf, b == 16 ? 'p' : 'e');
IGNORE print_nat (e, 0, bf, 0);
}
sp = 1;
}
return (sp);
}
/*
* CHARACTER PRINTING
*
* This routine prints the character c to the buffer bf as a string
* character of type ch enclosed by the quote character q.
*/
void
print_char(unsigned long c, int ch, int q, BUFFER *bf)
{
char buff [20];
if (ch == CHAR_SIMPLE) {
switch (c) {
case char_alert : bfprintf (bf, "\\a"); break;
case char_backspace : bfprintf (bf, "\\b"); break;
case char_form_feed : bfprintf (bf, "\\f"); break;
case char_newline : bfprintf (bf, "\\n"); break;
case char_return : bfprintf (bf, "\\r"); break;
case char_tab : bfprintf (bf, "\\t"); break;
case char_vert_tab : bfprintf (bf, "\\v"); break;
case char_backslash :
case char_question : {
if (q) bfputc (bf, '\\');
bfputc (bf, (int) c);
break;
}
case char_quote :
case char_single_quote : {
int a = (int) c;
if (a == q) bfputc (bf, '\\');
bfputc (bf, a);
break;
}
default : {
int a = (int) c;
if (isprint (a)) {
bfputc (bf, a);
} else {
sprintf_v (buff, "\\%03lo", c);
bfputs (bf, ustrlit (buff));
}
break;
}
}
} else {
const char *fmt;
switch (ch) {
case CHAR_OCTAL : fmt = "\\%03lo"; break;
case CHAR_UNI4 : fmt = "\\u%04lx"; break;
case CHAR_UNI8 : fmt = "\\U%08lx"; break;
default : fmt = "\\x%lx"; break;
}
sprintf_v (buff, fmt, c);
bfputs (bf, ustrlit (buff));
}
return;
}
/*
* STRING LITERAL PRINTING
*
* This routine prints a string or character literal to the buffer bf.
*/
int
print_str(STRING s, BUFFER *bf, int sp)
{
string text;
int q = '"';
unsigned kind;
unsigned long i, len;
if (IS_NULL_str (s)) return (sp);
/* Print the opening quote */
if (sp) bfputc (bf, ' ');
kind = DEREF_unsigned (str_simple_kind (s));
if (kind & STRING_CHAR) q = '\'';
if (kind & STRING_WIDE) bfputc (bf, 'L');
/* Print the string text */
text = DEREF_string (str_simple_text (s));
len = DEREF_ulong (str_simple_len (s));
bfputc (bf, q);
if (kind & STRING_MULTI) {
/* Multi-byte strings */
for (i = 0; i < len; i++) {
int ch = CHAR_SIMPLE;
unsigned long c = get_multi_char (text, &ch);
print_char (c, ch, q, bf);
text += MULTI_WIDTH;
}
} else {
/* Simple strings */
for (i = 0; i < len; i++) {
unsigned long c = (unsigned long) text [i];
print_char (c, CHAR_SIMPLE, q, bf);
}
}
bfputc (bf, q);
return (1);
}
/*
* EXPRESSION PRINTING
*
* This routine prints an expression to the buffer bf.
*/
int
print_exp(EXP e, int paren, BUFFER *bf, int sp)
{
if (!IS_NULL_exp (e)) {
switch (TAG_exp (e)) {
case exp_identifier_tag :
case exp_member_tag :
case exp_ambiguous_tag :
case exp_undeclared_tag : {
IDENTIFIER id = DEREF_id (exp_identifier_etc_id (e));
QUALIFIER q = DEREF_qual (exp_identifier_etc_qual (e));
q &= qual_explicit;
sp = print_id_short (id, q, bf, sp);
break;
}
case exp_int_lit_tag : {
NAT n = DEREF_nat (exp_int_lit_nat (e));
sp = print_nat (n, paren, bf, sp);
break;
}
case exp_float_lit_tag : {
FLOAT flt = DEREF_flt (exp_float_lit_flt (e));
sp = print_flt (flt, bf, sp);
break;
}
case exp_char_lit_tag : {
STRING s = DEREF_str (exp_char_lit_str (e));
sp = print_str (s, bf, sp);
break;
}
case exp_string_lit_tag : {
STRING s = DEREF_str (exp_string_lit_str (e));
sp = print_str (s, bf, sp);
break;
}
case exp_null_tag :
case exp_zero_tag :
case exp_value_tag : {
if (sp) bfputc (bf, ' ');
bfputc (bf, '0');
break;
}
case exp_contents_tag : {
EXP a = DEREF_exp (exp_contents_ptr (e));
sp = print_exp (a, 0, bf, sp);
break;
}
case exp_token_tag : {
IDENTIFIER id = DEREF_id (exp_token_tok (e));
LIST (TOKEN) args = DEREF_list (exp_token_args (e));
sp = print_token (id, qual_none, args, bf, sp);
break;
}
default : {
static unsigned long exp_no = 0;
#ifdef RUNTIME
if (debugging) {
/* Debug expression printing routine */
sp = print_exp_aux (e, paren, bf, sp);
break;
}
#endif
if (sp) bfputc (bf, ' ');
bfprintf (bf, "", ++exp_no);
sp = 1;
break;
}
}
}
return (sp);
}
/*
* TOKEN VALUE PRINTING
*
* This routine prints the value of the token tok to the buffer bf.
*/
int
print_tok_value(TOKEN tok, BUFFER *bf, int sp)
{
if (!IS_NULL_tok (tok)) {
ASSERT (ORDER_tok == 10);
switch (TAG_tok (tok)) {
case tok_exp_tag : {
EXP e = DEREF_exp (tok_exp_value (tok));
sp = print_exp (e, 0, bf, sp);
break;
}
case tok_stmt_tag : {
EXP e = DEREF_exp (tok_stmt_value (tok));
sp = print_exp (e, 0, bf, sp);
break;
}
case tok_nat_tag :
case tok_snat_tag : {
NAT n = DEREF_nat (tok_nat_etc_value (tok));
sp = print_nat (n, 0, bf, sp);
break;
}
case tok_type_tag : {
TYPE t = DEREF_type (tok_type_value (tok));
sp = print_type (t, bf, sp);
break;
}
case tok_member_tag : {
OFFSET off = DEREF_off (tok_member_value (tok));
sp = print_offset (off, bf, sp);
break;
}
case tok_class_tag : {
IDENTIFIER cid = DEREF_id (tok_class_value (tok));
sp = print_id_short (cid, qual_none, bf, sp);
break;
}
default : {
if (sp) bfputc (bf, ' ');
bfprintf (bf, "");
sp = 1;
break;
}
}
}
return (sp);
}
/*
* TOKEN APPLICATION PRINTING
*
* This routine prints the token application 'id (args)' or the template
* application 'id < args >' to the buffer bf.
*/
int
print_token(IDENTIFIER id, QUALIFIER qual, LIST (TOKEN) args, BUFFER *bf,
int sp)
{
int open_bracket = 0;
int close_bracket = 0;
if (IS_id_token (id)) {
/* Token application */
TOKEN tok = DEREF_tok (id_token_sort (id));
unsigned tag = TAG_tok (tok);
IDENTIFIER alt = DEREF_id (id_token_alt (id));
if (!IS_NULL_id (alt)) id = alt;
if (tag == tok_proc_tag || !IS_NULL_list (args)) {
open_bracket = '(';
close_bracket = ')';
} else if (tag == tok_class_tag) {
open_bracket = '<';
close_bracket = '>';
}
} else {
/* Template application */
open_bracket = '<';
close_bracket = '>';
}
sp = print_id_short (id, qual, bf, sp);
if (open_bracket) {
int first = 1;
bfputc (bf, ' ');
bfputc (bf, open_bracket);
while (!IS_NULL_list (args)) {
TOKEN ptok = DEREF_tok (HEAD_list (args));
if (!IS_NULL_tok (ptok)) {
if (!first) bfputc (bf, ',');
IGNORE print_tok_value (ptok, bf, 1);
first = 0;
}
args = TAIL_list (args);
}
if (!first) bfputc (bf, ' ');
bfputc (bf, close_bracket);
sp = 1;
}
return (sp);
}
/*
* TOKEN SORT PRINTING
*
* This routine prints the token sort tok to the buffer bf.
*/
int
print_sort(TOKEN tok, int arg, BUFFER *bf, int sp)
{
unsigned tag;
if (IS_NULL_tok (tok)) return (sp);
tag = TAG_tok (tok);
ASSERT (ORDER_tok == 10);
switch (tag) {
case tok_exp_tag : {
/* Expression tokens */
sp = print_lex (lex_exp_Hcap, bf, sp);
if (!arg) {
TYPE t = DEREF_type (tok_exp_type (tok));
CV_SPEC cv = DEREF_cv (type_qual (t));
if (cv & cv_lvalue) {
IGNORE print_lex (lex_lvalue, bf, sp);
} else {
int c = DEREF_int (tok_exp_constant (tok));
if (c) IGNORE print_lex (lex_const, bf, sp);
}
bfprintf (bf, " :");
IGNORE print_type (t, bf, 1);
bfprintf (bf, " :");
sp = 1;
}
break;
}
case tok_nat_tag : {
/* Integer constant tokens */
if (arg) {
sp = print_lex (lex_exp_Hcap, bf, sp);
} else {
sp = print_lex (lex_nat_Hcap, bf, sp);
}
break;
}
case tok_snat_tag : {
/* Integer constant tokens */
if (arg) {
sp = print_lex (lex_exp_Hcap, bf, sp);
} else {
sp = print_lex (lex_int_Hcap, bf, sp);
}
break;
}
case tok_stmt_tag : {
/* Statement tokens */
sp = print_lex (lex_stmt_Hcap, bf, sp);
break;
}
case tok_type_tag : {
/* Type tokens */
if (arg) {
sp = print_lex (lex_type_Hcap, bf, sp);
} else {
BASE_TYPE bt = DEREF_btype (tok_type_kind (tok));
int key = type_token_key (bt);
if (key == lex_signed || key == lex_unsigned) {
sp = print_lex (lex_variety_Hcap, bf, sp);
}
sp = print_lex (key, bf, sp);
}
break;
}
case tok_func_tag : {
/* Function tokens */
if (arg) {
sp = print_lex (lex_proc_Hcap, bf, sp);
} else {
TYPE t = DEREF_type (tok_func_type (tok));
IGNORE print_lex (lex_func_Hcap, bf, sp);
IGNORE print_type (t, bf, 1);
bfprintf (bf, " :");
sp = 1;
}
break;
}
case tok_member_tag : {
/* Member tokens */
TYPE s = DEREF_type (tok_member_of (tok));
IGNORE print_lex (lex_member_Hcap, bf, sp);
if (!arg) {
TYPE t = DEREF_type (tok_member_type (tok));
print_bitfield_sep = '%';
IGNORE print_type (t, bf, 1);
print_bitfield_sep = ':';
bfprintf (bf, " :");
}
IGNORE print_type (s, bf, 1);
bfprintf (bf, " :");
sp = 1;
break;
}
case tok_class_tag : {
/* Template class tokens */
TYPE t = DEREF_type (tok_class_type (tok));
while (!IS_NULL_type (t) && IS_type_templ (t)) {
TOKEN sort = DEREF_tok (type_templ_sort (t));
sp = print_sort (sort, 0, bf, sp);
t = DEREF_type (type_templ_defn (t));
}
sp = print_lex (lex_class, bf, sp);
break;
}
case tok_proc_tag : {
/* Procedure tokens */
TOKEN res;
int simple = 0;
LIST (IDENTIFIER) p, q;
sp = print_lex (lex_proc_Hcap, bf, sp);
if (arg) break;
res = DEREF_tok (tok_proc_res (tok));
p = DEREF_list (tok_proc_pids (tok));
q = DEREF_list (tok_proc_bids (tok));
if (EQ_list (p, q)) simple = 1;
if (simple) {
bfprintf (bf, " (");
} else {
bfprintf (bf, " {");
}
sp = 0;
while (!IS_NULL_list (q)) {
IDENTIFIER id = DEREF_id (HEAD_list (q));
if (!IS_NULL_id (id)) {
TOKEN par = DEREF_tok (id_token_sort (id));
if (sp) bfputc (bf, ',');
IGNORE print_sort (par, 0, bf, 1);
if (!simple) {
HASHID nm = DEREF_hashid (id_name (id));
IGNORE print_hashid (nm, 0, 0, bf, 1);
}
sp = 1;
}
q = TAIL_list (q);
}
if (simple) {
if (sp) bfputc (bf, ' ');
bfputc (bf, ')');
} else {
bfprintf (bf, " |");
sp = 0;
while (!IS_NULL_list (p)) {
IDENTIFIER id = DEREF_id (HEAD_list (p));
if (!IS_NULL_id (id)) {
if (sp) bfputc (bf, ',');
if (IS_id_token (id)) {
/* Simple token parameter */
HASHID nm = DEREF_hashid (id_name (id));
TOKEN par = DEREF_tok (id_token_sort (id));
IGNORE print_sort (par, 1, bf, 1);
IGNORE print_hashid (nm, 0, 0, bf, 1);
} else {
/* Complex type parameter */
TYPE r;
r = DEREF_type (id_class_name_etc_defn (id));
IGNORE print_lex (lex_type_Hcap, bf, 1);
IGNORE print_type (r, bf, 1);
}
sp = 1;
}
p = TAIL_list (p);
}
bfprintf (bf, " }");
}
sp = print_sort (res, 0, bf, 1);
break;
}
case tok_templ_tag : {
/* Template tokens */
LIST (TOKEN) q;
LIST (IDENTIFIER) p;
DECL_SPEC ex = DEREF_dspec (tok_templ_usage (tok));
NAMESPACE ns = DEREF_nspace (tok_templ_pars (tok));
if (ex & dspec_extern) {
/* Exported templates */
sp = print_lex (lex_export, bf, sp);
}
IGNORE print_lex (lex_template, bf, sp);
if (IS_NULL_nspace (ns)) {
sp = 1;
break;
}
p = DEREF_list (tok_templ_pids (tok));
q = DEREF_list (tok_templ_dargs (tok));
bfprintf (bf, " <");
sp = 0;
while (!IS_NULL_list (p)) {
TOKEN val = NULL_tok;
IDENTIFIER id = DEREF_id (HEAD_list (p));
HASHID nm = DEREF_hashid (id_name (id));
if (!IS_NULL_list (q)) {
val = DEREF_tok (HEAD_list (q));
q = TAIL_list (q);
}
tok = DEREF_tok (id_token_sort (id));
tag = TAG_tok (tok);
if (tag == tok_exp_tag) {
TYPE t = DEREF_type (tok_exp_type (tok));
int sp2 = print_head (t, 0, bf, 1);
sp2 = print_hashid (nm, 0, 0, bf, sp2);
IGNORE print_tail (t, bf, sp2);
} else if (tag == tok_type_tag) {
IGNORE print_lex (lex_class, bf, 1);
IGNORE print_hashid (nm, 0, 0, bf, 1);
} else {
IGNORE print_sort (tok, 0, bf, 1);
IGNORE print_hashid (nm, 0, 0, bf, 1);
}
if (!IS_NULL_tok (val)) {
bfprintf (bf, " =");
IGNORE print_tok_value (val, bf, 1);
}
p = TAIL_list (p);
if (!IS_NULL_list (p)) bfputc (bf, ',');
sp = 1;
}
if (sp) bfputc (bf, ' ');
bfputc (bf, '>');
sp = 1;
break;
}
}
return (sp);
}
/*
* INTEGRAL TYPE PRINTING
*
* This routine prints an integral type to the buffer bf. Note that the
* standard full forms, such as 'signed short int', are translated into
* shorter forms, such as 'short'.
*/
int
print_itype(INT_TYPE t, BUFFER *bf, int sp)
{
if (!IS_NULL_itype (t)) {
ASSERT (ORDER_itype == 6);
switch (TAG_itype (t)) {
case itype_basic_tag : {
BUILTIN_TYPE n = DEREF_ntype (itype_basic_no (t));
sp = print_ntype (n, bf, sp);
break;
}
case itype_bitfield_tag : {
BASE_TYPE bt = DEREF_btype (itype_bitfield_rep (t));
if (bt & btype_named) {
TYPE s = DEREF_type (itype_bitfield_sub (t));
sp = print_type (s, bf, sp);
} else {
sp = print_btype (bt, bf, sp);
}
break;
}
case itype_promote_tag : {
INT_TYPE s = DEREF_itype (itype_promote_arg (t));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (TOK_promote));
IGNORE print_itype (s, bf, 0);
bfprintf (bf, ")");
sp = 1;
break;
}
case itype_arith_tag : {
INT_TYPE s1 = DEREF_itype (itype_arith_arg1 (t));
INT_TYPE s2 = DEREF_itype (itype_arith_arg2 (t));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (TOK_arith_type));
IGNORE print_itype (s1, bf, 0);
bfprintf (bf, ", ");
IGNORE print_itype (s2, bf, 0);
bfprintf (bf, ")");
sp = 1;
break;
}
case itype_literal_tag : {
NAT n = DEREF_nat (itype_literal_nat (t));
int tok = DEREF_int (itype_literal_spec (t));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (tok));
IGNORE print_nat (n, 0, bf, 0);
bfprintf (bf, ")");
sp = 1;
break;
}
case itype_token_tag : {
BUILTIN_TYPE n = DEREF_ntype (itype_unprom (t));
if (n == ntype_none || n == ntype_ellipsis) {
IDENTIFIER id;
LIST (TOKEN) args;
id = DEREF_id (itype_token_tok (t));
args = DEREF_list (itype_token_args (t));
sp = print_token (id, qual_none, args, bf, sp);
} else {
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (TOK_promote));
IGNORE print_ntype (n, bf, 0);
bfprintf (bf, ")");
sp = 1;
}
break;
}
}
}
return (sp);
}
/*
* FLOATING-POINT TYPE PRINTING
*
* This routine prints a floating-point type to the buffer bf.
*/
int
print_ftype(FLOAT_TYPE t, BUFFER *bf, int sp)
{
if (!IS_NULL_ftype (t)) {
ASSERT (ORDER_ftype == 4);
switch (TAG_ftype (t)) {
case ftype_basic_tag : {
BUILTIN_TYPE n = DEREF_ntype (ftype_basic_no (t));
sp = print_ntype (n, bf, sp);
break;
}
case ftype_arg_promote_tag : {
FLOAT_TYPE s = DEREF_ftype (ftype_arg_promote_arg (t));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (TOK_promote));
IGNORE print_ftype (s, bf, 0);
bfprintf (bf, ")");
sp = 1;
break;
}
case ftype_arith_tag : {
FLOAT_TYPE s1 = DEREF_ftype (ftype_arith_arg1 (t));
FLOAT_TYPE s2 = DEREF_ftype (ftype_arith_arg2 (t));
if (sp) bfputc (bf, ' ');
bfprintf (bf, "%s (", special_name (TOK_arith_type));
IGNORE print_ftype (s1, bf, 0);
bfprintf (bf, ", ");
IGNORE print_ftype (s2, bf, 0);
bfprintf (bf, ")");
sp = 1;
break;
}
case ftype_token_tag : {
IDENTIFIER id = DEREF_id (ftype_token_tok (t));
LIST (TOKEN) args = DEREF_list (ftype_token_args (t));
sp = print_token (id, qual_none, args, bf, sp);
break;
}
}
}
return (sp);
}
/*
* CLASS TYPE PRINTING
*
* This routines prints the class type ct to the buffer bf.
*/
int
print_ctype(CLASS_TYPE ct, QUALIFIER qual, int key, BUFFER *bf, int sp)
{
if (!IS_NULL_ctype (ct)) {
TYPE t = DEREF_type (ctype_form (ct));
IDENTIFIER id = DEREF_id (ctype_name (ct));
if (key && IS_id_class_name (id)) {
BASE_TYPE bt = find_class_key (ct);
sp = print_btype (bt, bf, sp);
}
if (!IS_NULL_type (t) && IS_type_token (t)) {
IDENTIFIER tid = DEREF_id (type_token_tok (t));
LIST (TOKEN) args = DEREF_list (type_token_args (t));
sp = print_token (tid, qual, args, bf, sp);
} else {
sp = print_id_short (id, qual, bf, sp);
}
}
return (sp);
}
/*
* ENUMERATION TYPE PRINTING
*
* This routines prints the enumeration type et to the buffer bf.
*/
int
print_etype(ENUM_TYPE et, int key, BUFFER *bf, int sp)
{
if (!IS_NULL_etype (et)) {
IDENTIFIER id = DEREF_id (etype_name (et));
if (key && IS_id_enum_name (id)) {
sp = print_lex (lex_enum, bf, sp);
}
sp = print_id_short (id, qual_none, bf, sp);
}
return (sp);
}
/*
* CHECK FOR TAILED TYPES
*
* This routine tested whether the type t is a tailed type, that is an
* array, bitfield, or function type.
*/
static int
is_tailed_type(TYPE t)
{
if (!IS_NULL_type (t)) {
IDENTIFIER tid = DEREF_id (type_name (t));
if (IS_NULL_id (tid) || !print_type_alias) {
switch (TAG_type (t)) {
case type_func_tag :
case type_array_tag :
case type_bitfield_tag : {
return (1);
}
case type_templ_tag : {
TYPE s = DEREF_type (type_templ_defn (t));
return (is_tailed_type (s));
}
}
}
}
return (0);
}
/*
* TYPE HEAD PRINTING
*
* This routine prints the head of a type (i.e. the main part and any
* pointer or reference components) to the buffer bf.
*/
static int
print_head(TYPE t, int key, BUFFER *bf, int sp)
{
if (IS_NULL_type (t)) {
static unsigned long type_no = 0;
if (sp) bfputc (bf, ' ');
bfprintf (bf, "", ++type_no);
sp = 1;
} else {
CV_SPEC qual = DEREF_cv (type_qual (t));
IDENTIFIER tid = DEREF_id (type_name (t));
qual &= cv_qual;
if (!IS_NULL_id (tid) && print_type_alias) {
switch (TAG_id (tid)) {
case id_class_alias_tag :
case id_enum_alias_tag :
case id_type_alias_tag : {
/* Print type aliases */
if (!IS_type_pre (t)) {
sp = print_cv (qual, bf, sp);
sp = print_id_short (tid, qual_none, bf, sp);
return (sp);
}
break;
}
}
}
ASSERT (ORDER_type == 18);
switch (TAG_type (t)) {
case type_pre_tag : {
/* Pre-types */
BASE_TYPE bt = DEREF_btype (type_pre_rep (t));
BASE_TYPE kt = (bt & btype_named);
sp = print_cv (qual, bf, sp);
if (kt) {
if (kt == btype_alias) {
sp = print_id_short (tid, qual_none, bf, sp);
} else {
HASHID nm = DEREF_hashid (id_name (tid));
sp = print_btype (kt, bf, sp);
sp = print_hashid (nm, 0, 0, bf, sp);
}
} else {
sp = print_btype (bt, bf, sp);
}
break;
}
case type_integer_tag : {
/* Integral types */
INT_TYPE it = DEREF_itype (type_integer_rep (t));
sp = print_cv (qual, bf, sp);
sp = print_itype (it, bf, sp);
break;
}
case type_floating_tag : {
/* Floating-point types */
FLOAT_TYPE ft = DEREF_ftype (type_floating_rep (t));
sp = print_cv (qual, bf, sp);
sp = print_ftype (ft, bf, sp);
break;
}
case type_top_tag : {
/* Top type */
sp = print_cv (qual, bf, sp);
sp = print_ntype (ntype_void, bf, sp);
break;
}
case type_bottom_tag : {
/* Bottom type */
sp = print_cv (qual, bf, sp);
sp = print_ntype (ntype_bottom, bf, sp);
break;
}
case type_ptr_tag : {
/* Pointer type */
TYPE s = DEREF_type (type_ptr_sub (t));
sp = print_head (s, key, bf, sp);
if (is_tailed_type (s)) {
bfprintf (bf, " (*");
} else {
if (sp) bfputc (bf, ' ');
bfputc (bf, '*');
}
sp = (qual ? print_cv (qual, bf, 1) : 0);
break;
}
case type_ref_tag : {
/* Reference type */
TYPE s = DEREF_type (type_ref_sub (t));
sp = print_head (s, key, bf, sp);
if (is_tailed_type (s)) {
bfprintf (bf, " (&");
} else {
if (sp) bfputc (bf, ' ');
bfputc (bf, '&');
}
sp = (qual ? print_cv (qual, bf, 1) : 0);
break;
}
case type_ptr_mem_tag : {
/* Pointer to member type */
TYPE s = DEREF_type (type_ptr_mem_sub (t));
CLASS_TYPE ct = DEREF_ctype (type_ptr_mem_of (t));
sp = print_head (s, key, bf, sp);
if (is_tailed_type (s)) {
bfprintf (bf, " (");
sp = 0;
}
IGNORE print_ctype (ct, qual_none, 0, bf, sp);
bfprintf (bf, "::*");
sp = (qual ? print_cv (qual, bf, 1) : 0);
break;
}
case type_func_tag : {
/* Function type */
qual = DEREF_cv (type_func_mqual (t));
if (qual && print_func_linkage) {
sp = print_linkage (qual, bf, sp);
}
if (print_return_type) {
TYPE r = DEREF_type (type_func_ret (t));
if (!IS_NULL_type (r)) {
sp = print_head (r, 0, bf, sp);
}
}
break;
}
case type_array_tag : {
/* Array type */
TYPE s = DEREF_type (type_array_sub (t));
sp = print_head (s, key, bf, sp);
break;
}
case type_bitfield_tag : {
/* Bitfield type */
INT_TYPE it = DEREF_itype (type_bitfield_defn (t));
sp = print_cv (qual, bf, sp);
sp = print_itype (it, bf, sp);
break;
}
case type_compound_tag : {
/* Class type */
CLASS_TYPE ct = DEREF_ctype (type_compound_defn (t));
sp = print_cv (qual, bf, sp);
sp = print_ctype (ct, qual_none, key, bf, sp);
break;
}
case type_enumerate_tag : {
/* Enumeration type */
ENUM_TYPE et = DEREF_etype (type_enumerate_defn (t));
sp = print_cv (qual, bf, sp);
sp = print_etype (et, key, bf, sp);
break;
}
case type_token_tag : {
/* Tokenised type */
IDENTIFIER id = DEREF_id (type_token_tok (t));
LIST (TOKEN) args = DEREF_list (type_token_args (t));
sp = print_cv (qual, bf, sp);
sp = print_token (id, qual_none, args, bf, sp);
break;
}
case type_templ_tag : {
/* Template type */
TYPE s = DEREF_type (type_templ_defn (t));
TOKEN tok = DEREF_tok (type_templ_sort (t));
sp = print_sort (tok, 0, bf, sp);
sp = print_cv (qual, bf, sp);
sp = print_head (s, 1, bf, sp);
break;
}
case type_instance_tag : {
/* Instance type */
IDENTIFIER id = DEREF_id (type_name (t));
sp = print_id_short (id, qual_none, bf, sp);
break;
}
default : {
/* Error type */
sp = print_cv (qual, bf, sp);
if (sp) bfputc (bf, ' ');
bfprintf (bf, "");
sp = 1;
break;
}
}
}
return (sp);
}
/*
* TYPE TAIL PRINTING
*
* This routine prints the tail of a type (i.e. any array, bitfield or
* function components) to the buffer bf.
*/
static int
print_tail(TYPE t, BUFFER *bf, int sp)
{
if (!IS_NULL_type (t)) {
IDENTIFIER tid = DEREF_id (type_name (t));
if (!IS_NULL_id (tid) && print_type_alias) {
return (sp);
}
switch (TAG_type (t)) {
case type_ptr_tag :
case type_ref_tag : {
/* Pointer and reference types */
TYPE s = DEREF_type (type_ptr_etc_sub (t));
if (is_tailed_type (s)) bfprintf (bf, ")");
sp = print_tail (s, bf, sp);
break;
}
case type_ptr_mem_tag : {
/* Pointer to member type */
TYPE s = DEREF_type (type_ptr_mem_sub (t));
if (is_tailed_type (s)) bfprintf (bf, ")");
sp = print_tail (s, bf, sp);
break;
}
case type_func_tag : {
/* Function type */
int prt = print_return_type;
int ell = DEREF_int (type_func_ellipsis (t));
CV_SPEC qual = DEREF_cv (type_func_mqual (t));
LIST (TYPE) p = DEREF_list (type_func_ptypes (t));
LIST (IDENTIFIER) q = DEREF_list (type_func_pids (t));
LIST (TYPE) ex = DEREF_list (type_func_except (t));
sp = 0;
if (print_member_type) {
/* Print member parameter types */
p = DEREF_list (type_func_mtypes (t));
}
if (ell & FUNC_WEAK) {
/* Weak function prototype */
bfprintf (bf, " WEAK");
}
bfprintf (bf, "(");
if (IS_NULL_list (p) && !(ell & FUNC_ELLIPSIS)) {
/* There are no parameters */
if (!(ell & FUNC_NO_PARAMS) && print_c_style) {
bfprintf (bf, "void");
sp = 1;
}
} else {
/* Print parameters */
int pars = print_func_params;
int dargs = print_default_args;
if (LENGTH_list (p) != LENGTH_list (q)) dargs = 0;
print_return_type = 1;
while (!IS_NULL_list (p)) {
TYPE s = DEREF_type (HEAD_list (p));
if (ell & FUNC_PARAMS) s = unpromote_type (s);
IGNORE print_type (s, bf, 0);
if (dargs) {
/* Print default argument */
IDENTIFIER id = DEREF_id (HEAD_list (q));
EXP e = DEREF_exp (id_parameter_init (id));
if (pars) {
HASHID nm = DEREF_hashid (id_name (id));
IGNORE print_hashid (nm, 0, 0, bf, 1);
}
if (!IS_NULL_exp (e)) {
bfprintf (bf, " = ");
IGNORE print_exp (e, 0, bf, 0);
}
q = TAIL_list (q);
}
p = TAIL_list (p);
if (!IS_NULL_list (p)) {
bfprintf (bf, ", ");
} else if (ell & FUNC_ELLIPSIS) {
bfprintf (bf, ", ");
}
}
if (ell & FUNC_ELLIPSIS) {
bfprintf (bf, "...");
}
print_return_type = prt;
}
bfputc (bf, ')');
sp = print_cv (qual, bf, 1);
if (prt) {
TYPE r = DEREF_type (type_func_ret (t));
if (!IS_NULL_type (r)) {
sp = print_tail (r, bf, sp);
}
}
if (!EQ_list (ex, univ_type_set) && print_except) {
/* Print exception specifier */
sp = print_lex (lex_throw, bf, sp);
sp = print_type_list (ex, bf, sp);
}
break;
}
case type_array_tag : {
/* Array type */
TYPE s = DEREF_type (type_array_sub (t));
NAT n = DEREF_nat (type_array_size (t));
bfprintf (bf, "[");
IGNORE print_nat (n, 0, bf, 0);
bfprintf (bf, "]");
sp = print_tail (s, bf, 1);
break;
}
case type_bitfield_tag : {
/* Bitfield type */
INT_TYPE it = DEREF_itype (type_bitfield_defn (t));
NAT n = DEREF_nat (itype_bitfield_size (it));
bfputc (bf, ' ');
bfputc (bf, print_bitfield_sep);
IGNORE print_nat (n, 0, bf, 1);
break;
}
case type_templ_tag : {
/* Template type */
TYPE s = DEREF_type (type_templ_defn (t));
sp = print_tail (s, bf, sp);
break;
}
}
}
return (sp);
}
/*
* PRINT A TYPE
*
* This routine prints the type t to the buffer bf. Note that this is in
* two passes - the first prints the head of the type, comprising the
* base type and any pointer or reference qualifiers, while the second
* prints the tail of the type, comprising any array or function qualifiers.
*/
int
print_type(TYPE t, BUFFER *bf, int sp)
{
sp = print_head (t, print_c_style, bf, sp);
sp = print_tail (t, bf, sp);
return (sp);
}
/*
* PRINT A LIST OF TYPES
*
* This routine prints the list of types p, enclosed in brackets, to the
* buffer bf.
*/
int
print_type_list(LIST (TYPE) p, BUFFER *bf, int sp)
{
if (sp) bfputc (bf, ' ');
bfputc (bf, '(');
if (!IS_NULL_list (p)) {
for (; ;) {
TYPE t = DEREF_type (HEAD_list (p));
IGNORE print_type (t, bf, 1);
p = TAIL_list (p);
if (IS_NULL_list (p)) break;
bfputc (bf, ',');
}
bfputc (bf, ' ');
}
bfputc (bf, ')');
return (1);
}
/*
* OFFSET PRINTING
*
* This routine prints an offset to the buffer bf.
*/
int
print_offset(OFFSET off, BUFFER *bf, int sp)
{
if (!IS_NULL_off (off)) {
switch (TAG_off (off)) {
case off_base_tag : {
GRAPH gr = DEREF_graph (off_base_graph (off));
sp = print_graph (gr, 0, bf, sp);
break;
}
case off_deriv_tag : {
GRAPH gr = DEREF_graph (off_deriv_graph (off));
sp = print_graph (gr, 0, bf, sp);
break;
}
case off_member_tag : {
IDENTIFIER id = DEREF_id (off_member_id (off));
sp = print_id_short (id, qual_none, bf, sp);
break;
}
case off_token_tag : {
IDENTIFIER id = DEREF_id (off_token_tok (off));
LIST (TOKEN) args = DEREF_list (off_token_args (off));
sp = print_token (id, qual_none, args, bf, sp);
break;
}
default : {
static unsigned long off_no = 0;
#ifdef RUNTIME
if (debugging) {
/* Debug offset printing routine */
sp = print_offset_aux (off, bf, sp);
break;
}
#endif
if (sp) bfputc (bf, ' ');
bfprintf (bf, "", ++off_no);
sp = 1;
break;
}
}
}
return (sp);
}
/*
* FIND A LINE WITHIN THE CURRENT FILE BUFFER
*
* This routine checks whether the start of line n lies within the
* current file buffer. If so it returns a pointer to the start of
* the line. m gives the line number of the current position.
*/
static string
find_buffer_line(unsigned long n, unsigned long m)
{
string p = input_posn - 1;
if (n <= m) {
/* Scan backwards */
while (p >= input_start) {
character c = *(p--);
if (c == char_newline) {
if (n == m) return (p + 2);
m--;
}
}
if (m == 1) {
/* Allow falling off start */
return (input_start);
}
} else {
while (p < input_end) {
character c = *(p++);
if (c == char_newline) {
if (n == m) return (p);
m++;
}
}
if (p == input_eof) {
/* Allow falling off end */
return (p);
}
}
return (NULL);
}
/*
* FIND A LOCATION WITHIN THE CURRENT FILE BUFFER
*
* This routine checks whether the n lines following line ln of file fn
* lie within the input buffer. If so it returns the position of the
* first line within the buffer.
*/
static string
find_buffer_loc(string fn, unsigned long ln, unsigned long n)
{
if (input_start && !bad_crt_loc) {
PTR (POSITION) pm = crt_loc.posn;
if (!IS_NULL_ptr (pm)) {
string fm = DEREF_string (posn_input (pm));
if (ustreq (fn, fm)) {
unsigned long om = DEREF_ulong (posn_offset (pm));
unsigned long lm = crt_loc.line - om;
string p = find_buffer_line (ln, lm);
if (p) {
string q = find_buffer_line (ln + n, lm);
if (q) return (p);
}
}
}
}
return (NULL);
}
/*
* PRINT SOURCE LINES
*
* This routine prints a number of lines from the input buffer centred
* on the location loc to the file f. If loc does not correspond to a
* position within the current buffer then no text is output.
*/
void
print_source(LOCATION *loc, int lines, int full, const char *pre, FILE *f)
{
PTR (POSITION) pn = loc->posn;
if (lines > 0 && !IS_NULL_ptr (pn)) {
string p;
int nl = 0;
FILE *g = NULL;
const char *mark = "!!!!";
unsigned long n = (unsigned long) lines;
unsigned long b = n / 2;
string fn = DEREF_string (posn_input (pn));
unsigned long on = DEREF_ulong (posn_offset (pn));
unsigned long ln = loc->line - on;
unsigned long cn = loc->column;
unsigned long lc = ln;
unsigned long cc = 0;
if (ln <= b) {
ln = 1;
} else {
ln -= b;
}
/* Find start of source */
p = find_buffer_loc (fn, ln, n);
if (p == NULL) {
g = fopen (strlit (fn), "r");
if (g) {
/* Skip to correct line in file */
unsigned long lm = 1;
while (lm != ln) {
int c = fgetc (g);
if (c == EOF) {
fclose_v (g);
g = NULL;
break;
}
if (c == '\n') lm++;
}
}
}
/* Print source */
if (full) {
if (pre) fputs_v (pre, f);
fn = DEREF_string (posn_file (pn));
fprintf_v (f, "FILE: %s\n", strlit (fn));
}
while (n) {
int c;
if (nl == 0) {
if (pre) fputs_v (pre, f);
if (full) fprintf_v (f, "%lu:\t", ln + on);
nl = 1;
}
if (ln == lc && cn == cc) {
fputs_v (mark, f);
mark = NULL;
}
if (p) {
/* Read from buffer */
if (p >= input_end) break;
c = (int) *(p++);
} else if (g) {
/* Read from file */
c = fgetc (g);
if (c == EOF) break;
} else {
break;
}
if (c == char_newline) {
/* Newline characters */
if (ln == lc && mark) {
fputs_v (mark, f);
mark = NULL;
}
if (--n == 0) break;
nl = 0;
ln++;
cc = 0;
} else {
cc++;
}
fputc_v ((int) c, f);
}
if (mark) {
fputs_v (mark, f);
nl = 1;
}
if (nl) fputc_v ('\n', f);
if (g) fclose_v (g);
}
return;
}