/*
* Copyright (c) 2002, The Tendra Project <http://www.ten15.org/>
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1