/* * 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/rewrite.c,v 1.5 2004/08/14 15:15:36 bp Exp $ */ #include "config.h" #include "producer.h" #include "c_types.h" #include "ctype_ops.h" #include "exp_ops.h" #include "id_ops.h" #include "nspace_ops.h" #include "tok_ops.h" #include "type_ops.h" #include "error.h" #include "catalog.h" #include "access.h" #include "basetype.h" #include "class.h" #include "declare.h" #include "file.h" #include "function.h" #include "initialise.h" #include "macro.h" #include "namespace.h" #include "parse.h" #include "predict.h" #include "rewrite.h" #include "statement.h" #include "syntax.h" /* * COUNT OF NUMBER OF SKIPPED FUNCTIONS * * This value is used to keep track of the number of functions skipped * and subsequently compiled. */ static int functions_pending = 0; /* * SKIP A FUNCTION DEFINITION * * This routine skips the function definition for the function id given by * the current sequence of lexical tokens. Note that last_lex_token is * set to lex_func_Hop to indicate that a function definition has been * skipped. */ void skip_function(IDENTIFIER id) { EXP e; LOCATION loc; int t = crt_lex_token; PPTOKEN *p = crt_token; PPTOKEN *q = p; int brackets = 0; int try_block = 0; /* Check for previous definition */ if (!IS_NULL_id (id)) { PTR (LOCATION) ploc = id_loc (id); COPY_loc (ploc, decl_loc); e = DEREF_exp (id_function_etc_defn (id)); if (!IS_NULL_exp (e)) { /* Function already defined */ report (crt_loc, ERR_basic_odr_def_func (id, ploc)); } } /* Skip definition */ loc = crt_loc; if (t == lex_try) try_block = 1; for (;;) { if (t == lex_open_Hbrace_H1 || t == lex_open_Hbrace_H2) { /* Start of block */ brackets++; } else if (t == lex_close_Hbrace_H1 || t == lex_close_Hbrace_H2) { /* End of block */ brackets--; if (brackets <= 0) { q = crt_token; t = expand_preproc (EXPAND_AHEAD); if (t != lex_catch || !try_block) { /* End of function */ break; } } } else if (t == lex_semicolon && brackets == 0) { /* Premature end of function */ break; } else if (t == lex_eof) { /* Premature end of file */ report (loc, ERR_class_mfct_eof (id)); crt_lex_token = t; return; } q = crt_token; t = expand_preproc (EXPAND_AHEAD); } last_lex_token = lex_func_Hop; crt_lex_token = t; snip_tokens (p, q); /* Create the definition */ MAKE_exp_uncompiled (type_void, loc, p, e); if (!IS_NULL_id (id)) { COPY_exp (id_function_etc_defn (id), e); functions_pending++; } return; } /* * SKIP A DEFAULT ARGUMENT VALUE * * This routine skips the default argument value for the function parameter * id given by the current sequence of lexical tokens. It returns an * expression giving the skipped value which is associated with id by * init_param. */ EXP skip_default_arg(IDENTIFIER id) { EXP e; LOCATION loc; int brackets = 0; int t = crt_lex_token; PPTOKEN *p = crt_token; PPTOKEN *q = p; /* Skip definition */ loc = crt_loc; for (;;) { if (t == lex_open_Hround || t == lex_open_Htemplate) { brackets++; } else if (t == lex_close_Hround || t == lex_close_Htemplate) { if (brackets == 0) break; brackets--; } else if (t == lex_comma) { if (brackets == 0) break; } else if (t == lex_eof) { /* Premature end of file */ report (loc, ERR_class_mfct_eof (id)); crt_lex_token = t; return (NULL_exp); } q = crt_token; t = expand_preproc (EXPAND_AHEAD); } crt_lex_token = t; snip_tokens (p, q); /* Create the definition */ MAKE_exp_uncompiled (type_error, loc, p, e); functions_pending++; return (e); } /* * BRING A SET OF TEMPLATE ARGUMENTS INTO SCOPE * * When rescanning a template member function it is necessary to bring * the template parameters back into scope. This routine performs this * operation for the template type t. It returns the non-template * component of t. */ TYPE begin_templ_scope(TYPE t) { if (!IS_NULL_type (t) && IS_type_templ (t)) { TYPE s = DEREF_type (type_templ_defn (t)); TOKEN sort = DEREF_tok (type_templ_sort (t)); NAMESPACE ns = DEREF_nspace (tok_templ_pars (sort)); if (!IS_NULL_nspace (ns)) { record_location++; in_template_decl++; add_namespace (ns); } t = begin_templ_scope (s); } return (t); } /* * TAKE A SET OF TEMPLATE ARGUMENTS OUT OF SCOPE * * This routine removes any template parameters brought into scope by * begin_templ_scope. */ void end_templ_scope(TYPE t) { if (!IS_NULL_type (t) && IS_type_templ (t)) { TYPE s = DEREF_type (type_templ_defn (t)); TOKEN sort = DEREF_tok (type_templ_sort (t)); NAMESPACE ns = DEREF_nspace (tok_templ_pars (sort)); end_templ_scope (s); if (!IS_NULL_nspace (ns)) { remove_namespace (); in_template_decl--; record_location--; } } return; } /* * COMPILE A FUNCTION DEFINITION * * This routine compiles any previously skipped definition for the * function id. */ static void rescan_function(IDENTIFIER id) { EXP e = DEREF_exp (id_function_etc_defn (id)); if (!IS_NULL_exp (e) && IS_exp_uncompiled (e)) { PPTOKEN *p; PARSE_STATE s; TYPE fn = DEREF_type (id_function_etc_type (id)); /* Mark function as inline */ DECL_SPEC ds = DEREF_dspec (id_storage (id)); ds |= dspec_inline; COPY_dspec (id_storage (id), ds); /* Save current compiler state */ save_state (&s, 1); /* Set parser to stored definition */ DEREF_loc (exp_uncompiled_start (e), crt_loc); crt_line_changed = 1; crt_file_changed = 1; p = DEREF_pptok (exp_uncompiled_defn (e)); init_parser (p); /* Start function definition */ in_class_defn = 0; in_function_defn++; really_in_function_defn++; COPY_exp (id_function_etc_defn (id), NULL_exp); DEREF_loc (id_loc (id), decl_loc); IGNORE begin_templ_scope (fn); begin_function (id); /* Parse the stored function definition */ ADVANCE_LEXER; parse_func (&e); if (crt_lex_token != lex_eof && !have_syntax_error) { ERROR err = ERR_lex_parse (crt_token); report (crt_loc, err); unreached_code = 1; } /* End the function definition */ IGNORE end_function (id, e); end_templ_scope (fn); /* Reset the parser */ restore_state (&s); p = restore_parser (); free_tok_list (p); functions_pending--; } return; } /* * COMPILE A DEFAULT ARGUMENT VALUE * * This routine compiles any previously skipped default argument value * for the parameter id. */ void rescan_param(IDENTIFIER id, int rescan) { EXP e = DEREF_exp (id_parameter_init (id)); if (!IS_NULL_exp (e) && IS_exp_uncompiled (e)) { PPTOKEN *p; PARSE_STATE s; TYPE fn = NULL_type; NAMESPACE ns = DEREF_nspace (id_parent (id)); IDENTIFIER pid = DEREF_id (nspace_name (ns)); if (!IS_NULL_id (pid) && IS_id_function_etc (pid)) { fn = DEREF_type (id_function_etc_type (pid)); } else { CLASS_TYPE ct = crt_class; if (!IS_NULL_ctype (ct)) { pid = DEREF_id (ctype_name (ct)); } else { pid = NULL_id; } } /* Save current compiler state */ save_state (&s, 1); /* Set parser to stored definition */ DEREF_loc (exp_uncompiled_start (e), crt_loc); crt_line_changed = 1; crt_file_changed = 1; p = DEREF_pptok (exp_uncompiled_defn (e)); init_parser (p); /* Start dafault argument value */ in_class_defn = 0; COPY_exp (id_parameter_init (id), NULL_exp); if (rescan) { IGNORE begin_templ_scope (fn); push_namespace (ns); } /* Parse the stored expression */ ADVANCE_LEXER; in_default_arg++; parse_exp (&e); in_default_arg--; if (crt_lex_token != lex_eof && !have_syntax_error) { ERROR err = ERR_lex_parse (crt_token); report (crt_loc, err); } /* End the default argument value */ init_param (id, e); if (rescan) { IGNORE pop_namespace (); end_templ_scope (fn); } /* Reset the parser */ if (crt_access_list.pending) { IGNORE report_access (pid); } restore_state (&s); p = restore_parser (); free_tok_list (p); functions_pending--; } return; } /* * COMPILE ALL FUNCTIONS IN A NAMESPACE * * This routine scans through the current class and any nested classes * compiling any function definitions which remain uncompiled. */ void rescan_functions() { CLASS_TYPE ct = crt_class; LIST (IDENTIFIER) ft = DEREF_list (ctype_nest (ct)); while (!IS_NULL_list (ft)) { IDENTIFIER id = DEREF_id (HEAD_list (ft)); switch (TAG_id (id)) { case id_class_name_tag : { /* Deal with nested classes */ CLASS_TYPE cs; CLASS_INFO ci; NAMESPACE cns; TYPE t = DEREF_type (id_class_name_defn (id)); TYPE s = begin_templ_scope (t); cs = DEREF_ctype (type_compound_defn (s)); ci = DEREF_cinfo (ctype_info (cs)); if (ci & cinfo_complete) { cns = DEREF_nspace (ctype_member (cs)); push_class (cs); push_namespace (cns); rescan_functions (); IGNORE pop_namespace (); pop_class (); } end_templ_scope (t); break; } case id_function_tag : case id_mem_func_tag : case id_stat_mem_func_tag : { /* Deal with inline functions (including friends) */ rescan_function (id); break; } case id_parameter_tag : { /* Deal with default arguments */ rescan_param (id, 1); break; } } ft = TAIL_list (ft); } return; }