/*
 * (c) Thomas Pornin 1999 - 2002
 *
 * 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, 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.
 * 4. The name of the authors may not be used to endorse or promote
 *    products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT 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 AUTHORS OR CONTRIBUTORS 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.
 *
 */

#ifndef UCPP__CPP__
#define UCPP__CPP__

#ifdef __cplusplus
extern "C"
{
#endif

/*
 * Uncomment the following if you want ucpp to use externally provided
 * error-reporting functions (ucpp_warning(), ucpp_error() and ucpp_ouch())
 */
/* #define NO_UCPP_ERROR_FUNCTIONS */

/*
 * Tokens (do not change the order unless checking operators_name[] in cpp.c)
 *
 * It is important that the token NONE is 0
 * Check the STRING_TOKEN macro
 */
#define CPPERR	512
enum {
	NONE,		/* whitespace */
	NEWLINE,	/* newline */
	COMMENT,	/* comment */
	NUMBER,		/* number constant */
	NAME,		/* identifier */
	BUNCH,		/* non-C characters */
	PRAGMA,		/* a #pragma directive */
	CONTEXT,	/* new file or #line */
	STRING,		/* constant "xxx" */
	CHAR,		/* constant 'xxx' */
	SLASH,		/*	/	*/
	ASSLASH,	/*	/=	*/
	MINUS,		/*	-	*/
	MMINUS,		/*	--	*/
	ASMINUS,	/*	-=	*/
	ARROW,		/*	->	*/
	PLUS,		/*	+	*/
	PPLUS,		/*	++	*/
	ASPLUS,		/*	+=	*/
	LT,		/*	<	*/
	LEQ,		/*	<=	*/
	LSH,		/*	<<	*/
	ASLSH,		/*	<<=	*/
	GT,		/*	>	*/
	GEQ,		/*	>=	*/
	RSH,		/*	>>	*/
	ASRSH,		/*	>>=	*/
	ASGN,		/*	=	*/
	SAME,		/*	==	*/
#ifdef CAST_OP
	CAST,		/*	=>	*/
#endif
	NOT,		/*	~	*/
	NEQ,		/*	!=	*/
	AND,		/*	&	*/
	LAND,		/*	&&	*/
	ASAND,		/*	&=	*/
	OR,		/*	|	*/
	LOR,		/*	||	*/
	ASOR,		/*	|=	*/
	PCT,		/*	%	*/
	ASPCT,		/*	%=	*/
	STAR,		/*	*	*/
	ASSTAR,		/*	*=	*/
	CIRC,		/*	^	*/
	ASCIRC,		/*	^=	*/
	LNOT,		/*	!	*/
	LBRA,		/*	{	*/
	RBRA,		/*	}	*/
	LBRK,		/*	[	*/
	RBRK,		/*	]	*/
	LPAR,		/*	(	*/
	RPAR,		/*	)	*/
	COMMA,		/*	,	*/
	QUEST,		/*	?	*/
	SEMIC,		/*	;	*/
	COLON,		/*	:	*/
	DOT,		/*	.	*/
	MDOTS,		/*	...	*/
	SHARP,		/*	#	*/
	DSHARP,		/*	##	*/

	OPT_NONE,	/* optional space to separate tokens in text output */

	DIGRAPH_TOKENS,			/* there begin digraph tokens */

	/* for DIG_*, do not change order, unless checking undig() in cpp.c */
	DIG_LBRK,	/*	<:	*/
	DIG_RBRK,	/*	:>	*/
	DIG_LBRA,	/*	<%	*/
	DIG_RBRA,	/*	%>	*/
	DIG_SHARP,	/*	%:	*/
	DIG_DSHARP,	/*	%:%:	*/

	DIGRAPH_TOKENS_END,		/* digraph tokens end here */

	LAST_MEANINGFUL_TOKEN,		/* reserved words will go there */

	MACROARG,	/* special token for representing macro arguments */

	UPLUS = CPPERR,	/* unary + */
	UMINUS		/* unary - */
};

#include "tune.h"
#include <stdio.h>
#include <setjmp.h>

struct token {
	int type;
	long line;
	char *name;
};

struct token_fifo {
	struct token *t;
	size_t nt, art;
};

struct lexer_state {
	/* input control */
	FILE *input;
#ifndef NO_UCPP_BUF
	unsigned char *input_buf;
#ifdef UCPP_MMAP
	int from_mmap;
	unsigned char *input_buf_sav;
#endif
#endif
	unsigned char *input_string;
	size_t ebuf;
	size_t pbuf;
	int lka[2];
	int nlka;
	int macfile;
	int last;
	int discard;
	unsigned long utf8;
	unsigned char copy_line[COPY_LINE_LENGTH];
	int cli;

	/* output control */
	FILE *output;
	struct token_fifo *output_fifo, *toplevel_of;
#ifndef NO_UCPP_BUF
	unsigned char *output_buf;
#endif
	size_t sbuf;

	/* token control */
	struct token *ctok;
	struct token *save_ctok;
	size_t tknl;
	int ltwnl;
	int pending_token;
#ifdef INMACRO_FLAG
	int inmacro;
	long macro_count;
#endif

	/* lexer options */
	long line;
	long oline;
	unsigned long flags;
	long count_trigraphs;
	struct garbage_fifo *gf;
	int ifnest;
	int condnest;
	int condcomp;
	int condmet;
	unsigned long condf[2];
};

/*
 * Flags for struct lexer_state
 */
/* warning flags */
#define WARN_STANDARD	     0x000001UL	/* emit standard warnings */
#define WARN_ANNOYING	     0x000002UL	/* emit annoying warnings */
#define WARN_TRIGRAPHS	     0x000004UL	/* warn when trigraphs are used */
#define WARN_TRIGRAPHS_MORE  0x000008UL	/* extra-warn for trigraphs */
#define WARN_PRAGMA	     0x000010UL	/* warn for pragmas in non-lexer mode */

/* error flags */
#define FAIL_SHARP	     0x000020UL	/* emit errors on rogue '#' */
#define CCHARSET	     0x000040UL	/* emit errors on non-C characters */

/* emission flags */
#define DISCARD_COMMENTS     0x000080UL	/* discard comments from text output */
#define CPLUSPLUS_COMMENTS   0x000100UL	/* understand C++-like comments */
#define LINE_NUM	     0x000200UL	/* emit #line directives in output */
#define GCC_LINE_NUM	     0x000400UL	/* same as #line, with gcc-syntax */

/* language flags */
#define HANDLE_ASSERTIONS    0x000800UL	/* understand assertions */
#define HANDLE_PRAGMA	     0x001000UL	/* emit PRAGMA tokens in lexer mode */
#define MACRO_VAARG	     0x002000UL	/* understand macros with '...' */
#define UTF8_SOURCE	     0x004000UL	/* identifiers are in UTF8 encoding */
#define HANDLE_TRIGRAPHS     0x008000UL	/* handle trigraphs */

/* global ucpp behaviour */
#define LEXER		     0x010000UL	/* behave as a lexer */
#define KEEP_OUTPUT	     0x020000UL	/* emit the result of preprocessing */
#define COPY_LINE	     0x040000UL /* make a copy of the parsed line */

/* internal flags */
#define READ_AGAIN	     0x080000UL	/* emit again the last token */
#define TEXT_OUTPUT	     0x100000UL	/* output text */

/*
 * Public function prototypes
 */

#ifndef NO_UCPP_BUF
void flush_output(struct lexer_state *);
#endif

void init_assertions(void);
int make_assertion(char *);
int destroy_assertion(char *);
void print_assertions(void);

void init_macros(void);
int define_macro(struct lexer_state *, char *);
int undef_macro(struct lexer_state *, char *);
void print_defines(void);

void set_init_filename(const char *, int);
void init_cpp(void);
void init_include_path(char *[]);
void init_lexer_state(struct lexer_state *);
void init_lexer_mode(struct lexer_state *);
void free_lexer_state(struct lexer_state *);
void wipeout(void);
int lex(struct lexer_state *);
int check_cpp_errors(struct lexer_state *);
void add_incpath(char *);
void init_tables(int);
int enter_file(struct lexer_state *, unsigned long);
int cpp(struct lexer_state *);
void set_identifier_char(int c);
void unset_identifier_char(int c);

#ifdef UCPP_MMAP
FILE *fopen_mmap_file(char *);
void set_input_file(struct lexer_state *, FILE *);
#endif

struct stack_context {
	char *long_name, *name;
	long line;
};
struct stack_context *report_context(void);

extern int no_special_macros, system_macros,
	emit_dependencies, emit_defines, emit_assertions;
extern int c99_compliant, c99_hosted;
extern FILE *emit_output;
extern char *current_filename, *current_long_filename;
extern char *operators_name[];
extern struct protect {
	char *macro;
	int state;
	struct found_file *ff;
} protect_detect;

void ucpp_ouch(char *, ...);
void ucpp_error(long, char *, ...);
void ucpp_warning(long, char *, ...);

extern int *transient_characters;

/*
 * Errors from CPPERR_EOF and above are not real erros, only show-stoppers.
 * Errors below CPPERR_EOF are real ones.
 */
#define CPPERR_NEST	 900
#define CPPERR_EOF	1000

/*
 * This macro tells whether the name field of a given token type is
 * relevant, or not. Irrelevant name field means that it might point
 * to outerspace.
 */
#ifdef SEMPER_FIDELIS
#define STRING_TOKEN(x)    ((x) == NONE || ((x) >= COMMENT && (x) <= CHAR))
#else
#define STRING_TOKEN(x)    ((x) >= NUMBER && (x) <= CHAR)
#endif

#ifdef __cplusplus
} // End of extern "C"
#endif

#endif
