/* Main include file for Ksi.
   Copyright (C) 2001, 2002 Michal Moskal (malekith@pld-linux.org)

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to
the Free Software Foundation, 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */


#include "config.h"
#include "ksi-config.h"
#include "system.h"
#include "tree.h"
#include "flags.h"
#include "toplev.h"

/* I don't know if they work correctly... :<, #undef to disable */
#define LABELS

/* internal compiler error */
#define ice() abort()

#include "keyword.h"	/* keyword_t */

/* for ALLOWED argument for get*arg*() functions */
enum {
	arg_int		= 0x0001,
	arg_uint	= 0x0002,
	arg_float	= 0x0004,
	arg_string	= 0x0008,
	arg_id		= 0x0010,
	arg_kw		= 0x0020,
	arg_list_beg	= 0x0040,
	arg_list_end	= 0x0080,
};

struct arg {
	int sel;
	union {
		struct {
			HOST_WIDE_INT low;
			HOST_WIDE_INT high;
		} val_int;
		struct {
			unsigned HOST_WIDE_INT low;
			unsigned HOST_WIDE_INT high;
		} val_uint;
		/* unfortunetly, there is no better way, then ASCII */
		/* representation. */
		const char *val_float;
		struct {
			const char *data;
			int len;
		} val_string;
		const char *val_id;
		keyword_t val_kw;
	} u;
};

/* should be abstract */
struct term_state {
	keyword_t kw;
	int arg_no, next_sep;
};

/* should be abstract */
struct list_state {
	int arg_no;
	int eol;
};

extern tree bool_type_node;
extern tree poly_type_node;
extern int flag_just_preprocess;
extern int flag_yydebug;

/* keyword.c */
const char *keyword_name(keyword_t kw);
keyword_t lookup_keyword(const char *ptr, int len);

/* go up in scopes, looking for name */
tree lookup_id(const char *text, enum tree_code type);
/* look for TYPE_DECL, declaring type of TREE_CODE TYPE */
tree lookup_type(tree id, enum tree_code type);
tree get_vars(void);

/* expr.c */
tree compile_unary(keyword_t op, enum tree_code code, tree *type);
tree compile_bin(keyword_t op, enum tree_code code, tree *type);
tree compile_const(tree *type);
tree compile_enumref(tree *type);
tree compile_compound(tree *type);
tree compile_cond(tree *type);
tree compile_indirect(tree *type);
tree compile_modify(tree *type);
tree compile_nop(tree *type);
tree compile_result(tree *type);
tree compile_ref(tree *type);
tree compile_func_ref(tree *type);
tree compile_var(tree *type, int static_p);
tree compile_convert(tree *type);
tree compile_float(tree *type);
tree compile_fix(tree *type, enum tree_code fixmode);
tree compile(keyword_t kw, tree *type);
tree compile_no_kw(tree *type);
tree compile_component(tree *type);
tree compile_size_of(tree *type);
tree compile_prepost(keyword_t kw, enum tree_code code, tree *type);

/* lex.c */
/* low-level token fetching routines */
int get_separator(void);
struct arg *get_arg(int allowed, struct arg *ret);
void kpp_init(void);
void kpp_define_opt(const char *p);

const char *arg_name(int arg);

/* simple term handling */
void init_term(struct term_state *ctx, keyword_t kw);
void fini_term(struct term_state *ctx);
void arg0_term(keyword_t kw);
void get_term_arg(struct term_state *ctx, int allowed, struct arg *a);
tree get_id(struct term_state *ctx);
int optional_term_arg_present(struct term_state *ctx);
keyword_t get_keyword(struct term_state *ctx);
void expect_keyword(struct term_state *ctx, keyword_t exp);

/* list term handling */
void init_list(struct list_state *ctx);
void expect_list(struct list_state *ctx);
int get_list_arg(struct list_state *ctx, int allowed, struct arg *a);
keyword_t get_keyword_from_list(struct list_state *ctx);
void expect_keyword_in_list(struct list_state *ctx, keyword_t exp);

/* stmts.c */
tree compile_bind(tree *type);
tree compile_return(tree *type);
tree compile_loop(tree *type);
tree compile_exit_loop(tree *type);
tree compile_block(tree *type);
tree compile_exit(tree *type);
#ifdef LABELS
tree compile_label(tree *type);
tree compile_goto(tree *type);
#endif
void fini_labels(void);
tree compile_wfl(tree *type);
void parse_input_file(void);
void init_builtins(void);
tree compile_builtin(tree *type, int side);
tree compile_call(tree *type, int side);
tree compile_ptr_call(tree *type, int side);
tree compile_try_finally(tree *type);

/* types.c */
void parse_tyalias(void);
void parse_abstract_type(void);
void parse_enumdef(void);
void same_types(keyword_t kw, tree t1, tree t2);
void same_types_ex(keyword_t kw, tree t1, tree t2, int allow_poly);
int type_keyword(keyword_t kw);
tree parse_type(keyword_t kw);

/* unit.c */
void parse_func(void);
void parse_global(void);
void parse_unit(void);
void parse_structdef(int uniondef);
void parse_var(tree *type, tree *name);
void parse_alias_subset(void);
HOST_WIDE_INT get_id_alias_set(tree id);


struct lang_identifier {
	struct tree_identifier ignore;
	const char *system_macro;
	const char *user_macro;
	HOST_WIDE_INT alias_set;
	tree enum_value;
};

struct lang_type {
	HOST_WIDE_INT abstract_type;
};

struct lang_decl {
	tree ksi_name;
};

/* User/system macros for kpp */
#define IDENTIFIER_SYSTEM_MACRO(NODE)	\
  (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(NODE))->system_macro)
#define IDENTIFIER_USER_MACRO(NODE)	\
  (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(NODE))->user_macro)

#define IDENTIFIER_ENUM_VALUE(NODE)	\
  (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(NODE))->enum_value)

/* We allow giving names to alias sets. However it is going to be 
 * thousands of them so we put it into lang_identifier structure. */
#define IDENTIFIER_ALIAS_SET(NODE)	\
  (((struct lang_identifier *) IDENTIFIER_NODE_CHECK(NODE))->alias_set)

#define TYPE_POLYMORPHIC(NODE) 		\
  TYPE_LANG_FLAG_0(NODE)

#define TYPE_ABSTRACT_TYPE(NODE)		\
  (TYPE_LANG_SPECIFIC(NODE) ? 			\
    TYPE_LANG_SPECIFIC(NODE)->abstract_type : 0)

#define TYPE_ABSTRACT_P(NODE)			\
  (TYPE_POLYMORPHIC(NODE) || TYPE_ABSTRACT_TYPE(NODE) != 0)

#define DECL_KSI_NAME(NODE)			\
  (DECL_LANG_SPECIFIC(NODE)->ksi_name)

#define DECL_TAGGED_TYPE(NODE)			\
  DECL_LANG_FLAG_0(NODE)
  
enum attr_kind {
	ak_function		= 0x0001,
	ak_type			= 0x0002,
	ak_local_variable	= 0x0004,
	ak_global_variable	= 0x0008,
	ak_variable		= ak_local_variable|ak_global_variable,
	ak_toplev_data		= ak_function|ak_global_variable,
	ak_whatever		= ak_variable|ak_function|ak_type
};

/* Attributes stuff. */
struct attr_info {
	tree section_name;
	int align;
	HOST_WIDE_INT alias_set;
	tree export_name;

	/* flags */
	int packed : 1;
	int pure_func : 1;
	int const_func : 1;
	int suppress_debug : 1;
	int static_ctor : 1;
	int static_dtor : 1;
	int malloc_like : 1;
	int no_check_memory_usage : 1;
	int artificial : 1;
	int weak : 1;
	int one_only : 1;
	int comdat : 1;
	int no_limit_stack : 1;
	int no_return : 1;
	int public : 1;
	int external : 1;
};

void parse_attr(struct attr_info *ret, enum attr_kind ak);
void set_align(tree decl, struct attr_info *attr);
tree make_string(int len, const char *data);
void maybe_attr(struct term_state *ctx, struct attr_info *ret, 
		enum attr_kind ak, int allowed, struct arg *a);
keyword_t maybe_attr_then_keyword(struct term_state *ctx, 
				  struct attr_info *ret, 
	        	     	  enum attr_kind ak, 
				  keyword_t expected);
		     

/* glue.c */
void init_types(void);
void fini_types(void);

/* lex.c */
const char *ksi_init_parse(const char *filename);
