-/*
-See
-http://src.openresources.com/debian/src/devel/HTML/S/altgcc_2.7.2.2.orig%20altgcc-2.7.2.2.orig%20protoize.c.html
-static char *
-abspath (cwd, rel_filename)
-
-*/
-
-/*!!!!
-*** cpplib.c.old Tue Nov 28 2000 09:04:09 AM
---- cpplib.c Tue Nov 28 2000 08:55:18 AM
-***************
-*** 5715,5722 ****
- c2 = cppReader_peekC (pfile)
- if (c2 != '\n'
- goto randomchar
-! token = CPP_HSPACE
-! goto op2any
---- 5714,5723 ----
- case '\\'
- c2 = cppReader_peekC (pfile)
- if (c2 != '\n'
- goto randomchar
-! cppReader_forward (pfile, 1)
-! pfile->lineno++
-! return CPP_HSPACE
-
-
- case '\n'
- cppReader_putChar (pfile, c)
-
-
-Carl J. Appellof ( mailto:cappello@legato.com <mailto:cappello@legato.com> )
-*/ /*@i8@*/
-
-/*
-** LCLint - annotation-assisted static program checker
-** Copyright (C) 1994-2001 University of Virginia,
-** Massachusetts Institute of Technology
-**
-** This program 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 of the License, or (at your
-** option) any later version.
-**
-** This program 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.
-**
-** The GNU General Public License is available from http://www.gnu.org/ or
-** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
-** MA 02111-1307, USA.
-**
-** For information on lclint: lclint-request@cs.virginia.edu
-** To report a bug: lclint-bug@cs.virginia.edu
-** For more information: http://lclint.cs.virginia.edu
-*/
-/*
-** cpplib.c
-*/
-/*
- Copyright (C) 1986, 87, 89, 92-6, 1997 Free Software Foundation, Inc.
- Contributed by Per Bothner, 1994-95.
- Based on CCCP program by Paul Rubin, June 1986
- Adapted to ANSI C, Richard Stallman, Jan 1987
-
-This program 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.
-
-This program 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 this program; if not, write to the Free Software
-Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
-
- In other words, you are welcome to use, share and improve this program.
- You are forbidden to forbid anyone else to use, share and improve
- what you give them. Help stamp out software-hoarding! */
-
-/*
- * Herbert 06/12/2000:
- * - OS2 drive specs like WIN32
- * - Includes for IBMs OS/2 compiler
- */
-
-# include <ctype.h>
-# include <stdio.h>
-# include <signal.h>
-# ifdef __STDC__
-# include <stdlib.h>
-# endif
-
-# include <string.h>
-
-# if !(defined (WIN32) || defined (OS2) && defined (__IBMC__))
-# include <unistd.h>
-# endif
-
-# include <sys/types.h>
-# include <sys/stat.h>
-# include <fcntl.h>
-
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
-# include <io.h>
-# include <sys/utime.h> /* for __DATE__ and __TIME__ */
-# include <time.h>
-# else
-# ifndef VMS
-# ifndef USG
-# include <time.h> /* Reported by Paul Smith */
-# include <sys/time.h>
-# include <sys/resource.h>
-# else
-# include <sys/times.h>
-# include <time.h>
-# include <fcntl.h>
-# endif /* USG */
-# endif /* not VMS */
-# endif /* not WIN32 */
-
-/* This defines "errno" properly for VMS, and gives us EACCES. */
-# include <errno.h>
-
-# include "lclintMacros.nf"
-# include "llbasic.h"
-# include "lcllib.h"
-# include "cpplib.h"
-# include "cpperror.h"
-# include "cpphash.h"
-# include "cppexp.h"
-# include "version.h"
-# include "portab.h"
-# include "osd.h"
-
-/*
-** This is really kludgey code...
-*/
-
-/*@+boolint@*/
-/*@+charint@*/
-
-#define NO_SHORTNAMES
-
-# ifdef open
-# undef open
-# undef read
-# undef write
-# endif /* open */
-
-/*@constant int IMPORT_FOUND@*/
-# define IMPORT_FOUND -2
-
-/*@constant int SKIP_INCLUDE@*/
-# define SKIP_INCLUDE IMPORT_FOUND
-
-/*@constant unused int IMPORT_NOT_FOUND@*/
-# define IMPORT_NOT_FOUND -1
-
-#ifndef STDC_VALUE
-/*@constant unused int STDC_VALUE@*/
-#define STDC_VALUE 1
-#endif
-
-/* By default, colon separates directories in a path. */
-#ifndef PATH_SEPARATOR
-/*@constant char PATH_SEPARATOR@*/
-#define PATH_SEPARATOR ':'
-#endif
-
-static void parse_name (cppReader *, int);
-
-static int cpp_openIncludeFile (char *p_filename)
- /*@modifies fileSystem @*/ ;
-
-static void cpp_setLocation (cppReader *p_pfile)
- /*@modifies g_currentloc@*/ ;
-
-static enum cpp_token cpp_handleComment (cppReader *p_pfile,
- struct parse_marker *p_smark)
- /*@modifies p_pfile, p_smark@*/;
-
-static bool cpp_shouldCheckMacro (cppReader *p_pfile, char *p_p) /*@*/ ;
-
-static bool cpp_skipIncludeFile (cstring p_fname) /*@*/ ;
-
-#ifndef O_RDONLY
-#define O_RDONLY 0
-#endif
-
-/* Symbols to predefine. */
-
-#ifdef CPP_PREDEFINES
-static /*@observer@*/ char *predefs = CPP_PREDEFINES;
-#else
-static /*@observer@*/ char *predefs = "";
-#endif
-
-/* We let tm.h override the types used here, to handle trivial differences
- such as the choice of unsigned int or long unsigned int for size_t.
- When machines start needing nontrivial differences in the size type,
- it would be best to do something here to figure out automatically
- from other information what type to use. */
-
-/* The string value for __SIZE_TYPE__. */
-
-#ifndef SIZE_TYPE
-/*@constant observer char *SIZE_TYPE@*/
-#define SIZE_TYPE "long unsigned int"
-#endif
-
-/* The string value for __PTRDIFF_TYPE__. */
-
-#ifndef PTRDIFF_TYPE
-/*@constant observer char *PTRDIFF_TYPE@*/
-#define PTRDIFF_TYPE "long int"
-#endif
-
-/* The string value for __WCHAR_TYPE__. */
-
-#ifndef WCHAR_TYPE
-/*@constant observer char *WCHAR_TYPE@*/
-#define WCHAR_TYPE "int"
-#endif
-
-/* The string value for __USER_LABEL_PREFIX__ */
-
-#ifndef USER_LABEL_PREFIX
-/*@constant observer char *USER_LABEL_PREFIX@*/
-#define USER_LABEL_PREFIX ""
-#endif
-
-/* The string value for __REGISTER_PREFIX__ */
-
-#ifndef REGISTER_PREFIX
-/*@constant observer char *REGISTER_PREFIX@*/
-#define REGISTER_PREFIX ""
-#endif
-
-/* table to tell if char can be part of a C identifier. */
-static bool is_idchar[256];
-/* table to tell if char can be first char of a c identifier. */
-static bool is_idstart[256];
-/* table to tell if c is horizontal space. */
-static bool is_hor_space[256];
-/* table to tell if c is horizontal or vertical space. */
-static bool is_space[256];
-
-static /*@exposed@*/ /*@null@*/ cppBuffer *
-cppReader_getBuffer (/*@special@*/ cppReader *p_pfile)
- /*@uses p_pfile->buffer@*/
- /*@modifies nothing@*/ ;
-
-/*@notfunction@*/
-# define SKIP_WHITE_SPACE(p) do { /*@access cstring@*/ while (is_hor_space[(int) *(p)]) { (p)++; } } /*@noaccess cstring@*/ while (0)
-
-/*@notfunction@*/
-# define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*(p)]) { (p)++; } } while (0)
-
-static int cpp_peekN (cppReader *p_pfile, int p_n) /*@*/ ;
-
-/*@function static int cppBuffer_get (sef cppBuffer *p_b) modifies *p_b ; @*/
-# define cppBuffer_get(BUFFER) \
- ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF)
-
-/* Append string STR (of length N) to PFILE's output buffer. Make space. */
-/*@function static void cppReader_puts (sef cppReader *p_file, char *p_str, sef size_t p_n)
- modifies *p_file; @*/
-# define cppReader_puts(PFILE, STR, N) \
- cppReader_reserve(PFILE, N), cppReader_putStrN (PFILE, STR,N)
-
-/* Append character CH to PFILE's output buffer. Assume sufficient space. */
-
-/*@function static void cppReader_putCharQ (cppReader *p_file, char p_ch)
- modifies *p_file; @*/
-# define cppReader_putCharQ(PFILE, CH) (*(PFILE)->limit++ = (CH))
-
-/* Append character CH to PFILE's output buffer. Make space if need be. */
-
-/*@function static void cppReader_putChar (sef cppReader *p_file, char p_ch)
- modifies *p_file; @*/
-#define cppReader_putChar(PFILE, CH) (cppReader_reserve (PFILE, (size_t) 1), cppReader_putCharQ (PFILE, CH))
-
-/* Make sure PFILE->limit is followed by '\0'. */
-/*@function static void cppReader_nullTerminateQ (cppReader *p_file)
- modifies *p_file; @*/
-
-#define cppReader_nullTerminateQ(PFILE) (*(PFILE)->limit = 0)
-
-/*@function static void cppReader_nullTerminate (sef cppReader *p_file)
- modifies *p_file; @*/
-# define cppReader_nullTerminate(PFILE) \
- (cppReader_reserve (PFILE, (size_t) 1), *(PFILE)->limit = 0)
-
-/*@function static void cppReader_adjustWritten (cppReader *p_file, size_t)
- modifies *p_file; @*/
-#define cppReader_adjustWritten(PFILE,DELTA) ((PFILE)->limit += (DELTA))
-
-/*@function static bool cppReader_isC89 (cppReader *) modifies nothing; @*/
-#define cppReader_isC89(PFILE) (CPPOPTIONS(PFILE)->c89)
-
-/*@function static observer char *cppReader_wcharType (cppReader *)
- modifies nothing; @*/
-
-# define cppReader_wcharType(PFILE) \
- (CPPOPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE)
-
-static void cppBuffer_forward (cppBuffer *p_buf, int p_n) /*@modifies *p_buf@*/ ;
-
-/*@function static void cppReader_forward (cppReader *p_pfile, int) modifies *p_pfile; @*/
-# define cppReader_forward(pfile, N) \
- (cppBuffer_forward (cppReader_getBufferSafe (pfile), (N)))
-
-/*@function static int cppReader_getC (cppReader *p_pfile) modifies *p_pfile; @*/
-# define cppReader_getC(pfile) (cppBuffer_get (cppReader_getBufferSafe (pfile)))
-
-/*@function static int cppReader_peekC (cppReader *) modifies nothing;@*/
-# define cppReader_peekC(pfile) (cppBufPeek (cppReader_getBufferSafe (pfile)))
-
-/* Move all backslash-newline pairs out of embarrassing places.
- Exchange all such pairs following BP
- with any potentially-embarrassing characters that follow them.
- Potentially-embarrassing characters are / and *
- (because a backslash-newline inside a comment delimiter
- would cause it not to be recognized). */
-
-/*@notfunction@*/
-# define NEWLINE_FIX \
- do { while (cppReader_peekC (pfile) == '\\' && cpp_peekN (pfile, 1) == '\n') { cppReader_forward (pfile, 2); } } while(FALSE)
-
- /* Same, but assume we've already read the potential '\\' into C. */
-/*@notfunction@*/
-# define NEWLINE_FIX1(C) do { \
- while ((C) == '\\' && cppReader_peekC (pfile) == '\n') { cppReader_forward (pfile, 1); (C) = cppReader_getC (pfile); }\
- } while(0)
-
-static void parseSetMark (/*@out@*/ struct parse_marker *,
- cppReader *);
-static void parseClearMark (struct parse_marker *);
-static void parseGotoMark (struct parse_marker *, cppReader *);
-static void parseMoveMark (struct parse_marker *, cppReader *);
-
-/* If we have a huge buffer, may need to cache more recent counts */
-static /*@exposed@*/ char *cppLineBase (/*@sef@*/ cppBuffer *);
-
-static /*@exposed@*/ /*@null@*/ cppBuffer *
- cppReader_pushBuffer (cppReader *p_pfile,
- /*@owned@*/ /*@null@*/ char *, size_t)
- /*@modifies p_pfile@*/ ;
-
-static void cppReader_appendIncludeChain
-(cppReader *p_pfile,
- /*@keep@*/ struct file_name_list *p_first,
- /*@dependent@*/ struct file_name_list *p_last);
-
-static void cppReader_macroCleanup (cppBuffer *p_pbuf, cppReader *p_pfile);
-static enum cpp_token cppReader_nullUnderflow (/*@unused@*/ cppReader *p_pfile);
-
-static void cppReader_nullCleanup (/*@unused@*/ cppBuffer *p_pbuf,
- /*@unused@*/ cppReader *p_pfile);
-
-static void cppReader_fileCleanup (cppBuffer *p_pbuf,
- /*@unused@*/ cppReader *p_pfile);
-
-static int cppReader_handleDirective (cppReader *p_pfile);
-
-static void cppReader_scanBuffer (cppReader *p_pfile);
-
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
-
-/*
-** WIN32 (at least the VC++ include files) does not define mode_t.
-*/
-
-/*@-incondefs@*/ /*@-czechtypes@*/
-typedef unsigned int mode_t;
-/*@=incondefs@*/ /*@=czechtypes@*/
-
-# endif
-
-static int file_size_and_mode (int p_fd, /*@out@*/ mode_t *p_mode_pointer,
- /*@out@*/ size_t *p_size_pointer);
-static int safe_read (int p_desc, /*@out@*/ char *p_ptr, int p_len);
-
-
-/*
-** cppBuffer_isMacro is true if the buffer contains macro expansion.
-** (Note that it is false while we're expanding marco *arguments*.)
-*/
-
-static bool cppBuffer_isMacro (/*@null@*/ cppBuffer *) /*@*/ ;
-
-static void path_include (cppReader *p_pfile, char *p_path)
- /*@modifies p_pfile@*/ ;
-
-static void initialize_builtins (cppReader *p_pfile)
- /*@modifies p_pfile@*/ ;
-
-static void initialize_char_syntax (struct cppOptions *p_opts) ;
-
-static int /*@alt void@*/ finclude (cppReader *p_pfile, int p_f,
- cstring p_fname,
- bool p_system_header_p,
- /*@dependent@*/ /*@null@*/ struct file_name_list *p_dirptr);
-
-static void validate_else (cppReader *p_pfile, cstring p_directive);
-
-static void conditional_skip (cppReader *p_pfile, int p_skip,
- enum node_type p_type,
- /*@dependent@*/ /*@null@*/ char *p_control_macro);
-
-static HOST_WIDE_INT eval_if_expression (cppReader *p_pfile,
- char *p_buf,
- int p_length);
-
-static void skip_if_group (cppReader *p_pfile, int p_any);
-
-static bool comp_def_part (bool p_first, char *p_beg1, int p_len1,
- char *p_beg2, int p_len2, bool p_last);
-
-#ifdef abort
-extern void fancy_abort ();
-#endif
-
-static bool redundant_include_p (cppReader *p_pfile, /*@null@*/ cstring p_name);
-static bool is_system_include (cppReader *p_pfile, cstring p_filename);
-
-static /*@observer@*/ /*@null@*/ struct file_name_map *
-read_name_map (cppReader *p_pfile, cstring p_dirname);
-
-static cstring read_filename_string (int p_ch, /*:open:*/ FILE *p_f);
-
-static int open_include_file (cppReader *p_pfile,
- /*@owned@*/ cstring p_fname,
- /*@null@*/ struct file_name_list *p_searchptr);
-
-static void push_macro_expansion (cppReader *,
- /*@owned@*/ char *, size_t,
- /*@dependent@*/ hashNode);
-
-/* Last arg to output_line_command. */
-enum file_change_code {
- same_file, enter_file, leave_file
-};
-
-/* `struct directive' defines one #-directive, including how to handle it. */
-
-struct directive {
- int length; /* Length of name */
- /*@null@*/ int (*func)(); /* Function to handle directive */
- /*@observer@*/ cstring name; /* Name of directive */
- enum node_type type; /* Code which describes which directive. */
- bool command_reads_line; /* One if rest of line is read by func. */
- bool traditional_comments; /* Nonzero: keep comments if -traditional. */
- bool pass_thru; /* Copy preprocessed directive to output file.*/
-};
-
-/* These functions are declared to return int instead of void since they
- are going to be placed in a table and some old compilers have trouble with
- pointers to functions returning void. */
-
-static int do_define (cppReader *, /*@null@*/ struct directive *,
- char *, char *);
-static int do_defineAux (cppReader *, /*@null@*/ struct directive *,
- char *, char *, bool);
-
-static int do_line (cppReader *, /*@null@*/ struct directive *);
-static int do_include (cppReader *, struct directive *, char *, char *);
-static int do_undef (cppReader *, struct directive *, char *, char *);
-static int do_error (cppReader *, struct directive *, char *, char *);
-static int do_pragma (cppReader *, struct directive *, char *, char *);
-static int do_ident (cppReader *, struct directive *, char *, char *);
-static int do_if (cppReader *, struct directive *, char *, char *);
-static int do_xifdef (cppReader *, struct directive *, char *, char *);
-static int do_else (cppReader *, struct directive *, char *, char *);
-static int do_elif (cppReader *, struct directive *, char *, char *);
-static int do_endif (cppReader *, struct directive *, char *, char *);
-static int do_warning (cppReader *, struct directive *, char *, char *);
-
-/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found
- via the same directory as the file that #included it. */
-
-/*@constant observer struct file_name_list *SELF_DIR_DUMMY@*/
-#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))
-
-/* #include "file" looks in source file dir, then stack. */
-/* #include <file> just looks in the stack. */
-/* -I directories are added to the end, then the defaults are added. */
-
-/*@access cstring@*/
-
-static struct default_include {
- /*@dependent@*/ /*@observer@*/ cstring fname; /* The name of the directory. */
- int cplusplus; /* Only look here if we're compiling C++. */
- int cxx_aware; /* Includes in this directory don't need to
- be wrapped in extern "C" when compiling
- C++. */
-} include_defaults_array[]
-= {
- /* This is the dir for fixincludes. Put it just before
- the files that we fix. */
- { GCC_INCLUDE_DIR, 0, 0 },
- { GCC_INCLUDE_DIR2, 0, 0 },
- { cstring_undefined, 0, 0 }
-};
-
-/*@noaccess cstring@*/
-
-/* Here is the actual list of #-directives, most-often-used first.
- The initialize_builtins function assumes #define is the very first. */
-
-/*@access cstring@*/
-
-static struct directive directive_table[] = {
- { 6, do_define, "define", T_DEFINE, FALSE, TRUE, FALSE },
- { 5, do_xifdef, "ifdef", T_IFDEF, TRUE, FALSE, FALSE },
- { 6, do_xifdef, "ifndef", T_IFNDEF, TRUE, FALSE, FALSE },
- { 7, do_include, "include", T_INCLUDE, TRUE, FALSE, FALSE },
- { 5, do_endif, "endif", T_ENDIF, TRUE, FALSE, FALSE },
- { 4, do_else, "else", T_ELSE, TRUE, FALSE, FALSE },
- { 2, do_if, "if", T_IF, TRUE, FALSE, FALSE },
- { 4, do_elif, "elif", T_ELIF, TRUE, FALSE, FALSE },
- { 5, do_undef, "undef", T_UNDEF, FALSE, FALSE, FALSE },
- { 5, do_error, "error", T_ERROR, FALSE, FALSE, FALSE },
- { 7, do_warning, "warning", T_WARNING, FALSE, FALSE, FALSE },
- { 6, do_pragma, "pragma", T_PRAGMA, FALSE, FALSE, TRUE},
- { 4, do_line, "line", T_LINE, TRUE, FALSE, FALSE },
- { 5, do_ident, "ident", T_IDENT, TRUE, FALSE, TRUE },
- /* { 8, do_unassert, "unassert", T_UNASSERT, TRUE, FALSE, FALSE }, */
- { -1, 0, "", T_UNUSED, FALSE, FALSE, FALSE },
-};
-/*@noaccess cstring@*/
-
-static cstring searchPath_unparse (struct file_name_list *search_start)
-{
- cstring res = cstring_newEmpty ();
- struct file_name_list *searchptr = NULL;
-
- for (searchptr = search_start; searchptr != NULL;
- searchptr = searchptr->next)
- {
- if (!cstring_isEmpty (searchptr->fname)) {
- res = cstring_concatFree1 (res, searchptr->fname);
- if (searchptr->next != NULL) {
- res = cstring_appendChar (res, ';');
- }
- }
- }
-
- return res;
-}
-
-/*@+charint@*/
-static void
-initialize_char_syntax (struct cppOptions *opts)
-{
- char i;
-
- /*
- * Set up is_idchar and is_idstart tables. These should be
- * faster than saying (is_alpha (c) || c == '_'), etc.
- * Set up these things before calling any routines tthat
- * refer to them.
- */
-
- for (i = 'a'; i <= 'z'; i++) {
- is_idchar[i - 'a' + 'A'] = TRUE;
- is_idchar[(int) i] = TRUE;
- is_idstart[i - 'a' + 'A'] = TRUE;
- is_idstart[(int) i] = TRUE;
- }
-
- for (i = '0'; i <= '9'; i++)
- {
- is_idchar[(int) i] = TRUE;
- }
-
- is_idchar['_'] = TRUE;
- is_idstart['_'] = TRUE;
- is_idchar['$'] = opts->dollars_in_ident;
- is_idstart['$'] = opts->dollars_in_ident;
-
- /* horizontal space table */
- is_hor_space[' '] = TRUE;
- is_hor_space['\t'] = TRUE;
- is_hor_space['\v'] = TRUE;
- is_hor_space['\f'] = TRUE;
- is_hor_space['\r'] = TRUE;
-
- is_space[' '] = TRUE;
- is_space['\t'] = TRUE;
- is_space['\v'] = TRUE;
- is_space['\f'] = TRUE;
- is_space['\n'] = TRUE;
- is_space['\r'] = TRUE;
-}
-
-bool isIdentifierChar (char c)
-{
- return is_idchar[(int) c];
-}
-
-/* Place into P_PFILE a quoted string representing the string SRC.
- Caller must reserve enough space in pfile->token_buffer. */
-
-static void
-quote_string (cppReader *pfile, char *src)
-{
- char c;
-
- cppReader_putCharQ (pfile, '\"');
- for (;;)
- {
- switch ((c = *src++))
- {
- default:
- if (isprint (c))
- cppReader_putCharQ (pfile, c);
- else
- {
- sprintf (cppReader_getPWritten (pfile), "\\%03o",
- (unsigned int) c);
- cppReader_adjustWritten (pfile, (size_t) 4);
- }
- /*@switchbreak@*/ break;
-
- case '\"':
- case '\\':
- cppReader_putCharQ (pfile, '\\');
- cppReader_putCharQ (pfile, c);
- /*@switchbreak@*/ break;
-
- case '\0':
- cppReader_putCharQ (pfile, '\"');
- cppReader_nullTerminateQ (pfile);
- return;
- }
- }
-}
-
-/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */
-
-void
-cppReader_growBuffer (cppReader *pfile, size_t n)
-{
- size_t old_written = cppReader_getWritten (pfile);
- pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;
- pfile->token_buffer = (char *)
- drealloc (pfile->token_buffer, pfile->token_buffer_size);
- cppReader_setWritten (pfile, old_written);
-}
-
-/*
- * process a given definition string, for initialization
- * If STR is just an identifier, define it with value 1.
- * If STR has anything after the identifier, then it should
- * be identifier=definition.
- */
-
-void
-cppReader_define (cppReader *pfile, char *str)
-{
- char *buf = NULL;
- char *p = str;
-
- DPRINTF (("Cpp reader define: %s", str));
-
- if (!is_idstart[(int) *p])
- {
- DPRINTF (("ERROR 1"));
- cppReader_error (pfile,
- message ("Malformed option `-D%s'",
- cstring_fromChars (str)));
-
- return;
- }
-
- p++;
-
- DPRINTF (("Here 2"));
-
- while (is_idchar[(int) *p])
- {
- p++;
- }
-
- if (*p == '(') {
- p++;
- while (*p != ')' && *p != '\0') {
- p++;
- }
-
- if (*p == ')') {
- p++;
- } else {
- cppReader_error
- (pfile,
- message ("Malformed option: -D%s (no closing parenthesis)",
- cstring_fromChars (str)));
- }
- }
-
- DPRINTF (("Here 2"));
-
- if (*p == '\0')
- {
- buf = (char *) dmalloc (size_fromInt (p - str + 4));
- strcpy ((char *) buf, str);
- strcat ((char *) buf, " 1");
- }
- else if (*p != '=')
- {
- DPRINTF (("ERROR 2"));
- cppReader_error (pfile,
- message ("Malformed option: -D%s (expected '=', found '%c')",
- cstring_fromChars (str),
- *p));
- return;
- }
- else
- {
- char *q;
- /* Copy the entire option so we can modify it. */
- DPRINTF (("Copying..."));
- buf = (char *) dmalloc (2 * strlen (str) + 1);
- strncpy (buf, str, size_fromInt (p - str));
-
- /* Change the = to a space. */
- buf[p - str] = ' ';
- /* Scan for any backslash-newline and remove it. */
- p++;
- q = &buf[p - str];
-
- while (*p != '\0')
- {
- if (*p == '\\' && p[1] == '\n')
- p += 2;
- else
- *q++ = *p++;
- }
-
- DPRINTF (("Here we are..."));
- *q = '\0';
- }
-
- llassert (buf != NULL);
- DPRINTF (("Do define: %s / %ld", buf, size_toLong (strlen (buf))));
- (void) do_define (pfile, NULL, buf, buf + strlen (buf));
- sfree (buf);
-}
-
-/* Append a chain of `struct file_name_list's
- to the end of the main include chain.
- FIRST is gthe beginning of the chain to append, and LAST is the end. */
-
-void
-cppReader_appendIncludeChain (cppReader *pfile,
- struct file_name_list *first,
- struct file_name_list *last)
-{
- struct cppOptions *opts = CPPOPTIONS (pfile);
- struct file_name_list *dir;
-
- if (first == NULL || last == NULL)
- {
- return;
- }
-
- if (opts->include == 0)
- {
- opts->include = first;
- }
- else
- {
- llassert (opts->last_include->next == NULL);
- opts->last_include->next = first;
- }
-
- if (opts->first_bracket_include == 0)
- {
- opts->first_bracket_include = first;
-
- for (dir = first; ; dir = dir->next) {
- int len = cstring_length (dir->fname) + INCLUDE_LEN_FUDGE;
- if (len > pfile->max_include_len)
- pfile->max_include_len = len;
- if (dir == last)
- break;
- }
- }
-
- llassert (last->next == NULL);
- /* last->next = NULL; */
- opts->last_include = last;
-}
-
-# if 0
-static /*@unused@*/ void
-cppReader_showIncludeChain (cppReader *pfile)
-{
- struct file_name_list *dirs = CPPOPTIONS (pfile)->include;
-
- if (dirs != NULL)
- {
- while (dirs != NULL)
- {
- fprintf (stderr, "*%s*:", cstring_toCharsSafe (dirs->fname));
- dirs = dirs->next;
- }
-
- fprintf (stderr, "\n");
- }
- else
- {
- fprintf (stderr, "No includes\n");
- }
-}
-# endif
-
-cstring
-cppReader_getIncludePath ()
-{
- cppReader *pfile = &g_cppState;
- struct file_name_list *dirs = CPPOPTIONS (pfile)->include;
- cstring res = cstring_undefined;
-
- if (dirs != NULL)
- {
- while (dirs != NULL)
- {
- res = message ("%q%c%s", res, PATH_SEPARATOR, dirs->fname);
- dirs = dirs->next;
- }
- }
- else
- {
- res = cstring_makeLiteral ("<no include path>");
- }
-
- return res;
-}
-
-void
-cppReader_addIncludeChain (cppReader *pfile, struct file_name_list *dir)
-{
- struct cppOptions *opts = CPPOPTIONS (pfile);
-
- if (dir == 0)
- {
- return;
- }
-
- if (opts->include == 0)
- {
- opts->include = dir;
- }
- else
- {
- llassert (opts->last_include->next == NULL);
- opts->last_include->next = dir;
- }
-
- if (opts->first_bracket_include == 0)
- {
- int len = cstring_length (dir->fname) + INCLUDE_LEN_FUDGE;
- opts->first_bracket_include = dir;
- if (len > pfile->max_include_len)
- {
- pfile->max_include_len = len;
- }
- }
-
- dir->next = NULL;
- opts->last_include = dir;
- /* cppReader_showIncludeChain (pfile); */
-}
-
-/* Given a colon-separated list of file names PATH,
- add all the names to the search path for include files. */
-
-static void
-path_include (cppReader *pfile, char *path)
-{
- char *p;
-
-#ifdef __CYGWIN32__
- char *win32temp;
-
- /* if we have a posix path list, convert to win32 path list */
- win32temp = (char *) dmalloc /*@i4@*/
- (cygwin32_posix_to_win32_path_list_buf_size (path));
- cygwin32_posix_to_win32_path_list (path, win32temp);
- path = win32temp;
-#endif
-
- p = path;
-
- if (*p != '\0')
- while (1) {
- char *q = p;
- char *name;
- struct file_name_list *dirtmp;
-
- /* Find the end of this name. */
- while (*q != '\0' && *q != PATH_SEPARATOR)
- {
- q++;
- }
-
- if (p == q)
- {
- /* An empty name in the path stands for the current directory. */
- name = (char *) dmalloc ((size_t) 2);
- name[0] = '.';
- name[1] = '\0';
- }
- else
- {
- /* Otherwise use the directory that is named. */
- name = (char *) dmalloc (size_fromInt (q - p + 1));
- memcpy (name, p, size_fromInt (q - p));
- name[q - p] = '\0';
- }
-
- dirtmp = (struct file_name_list *) dmalloc (sizeof (*dirtmp));
- dirtmp->next = 0; /* New one goes on the end */
- dirtmp->control_macro = 0;
- dirtmp->c_system_include_path = 0;
- dirtmp->fname = cstring_fromChars (name);
- dirtmp->got_name_map = 0;
- cppReader_addIncludeChain (pfile, dirtmp);
-
- /* Advance past this name. */
- p = q;
- if (*p == '\0')
- break;
- /* Skip the colon. */
- p++;
- }
-}
-
-void
-cppOptions_init (cppOptions *opts)
-{
- memset ((char *) opts, 0, sizeof *opts);
- assertSet (opts);
-
- opts->in_fname = NULL;
- opts->out_fname = NULL;
-
- /* Initialize is_idchar to allow $. */
- opts->dollars_in_ident = TRUE;
-
- opts->no_line_commands = 0;
- opts->no_trigraphs = TRUE;
- opts->put_out_comments = 1;
- opts->print_include_names = 0;
- opts->dump_macros = DUMP_DEFINITIONS; /* DUMP_NONE; */
- opts->no_output = 0;
- opts->cplusplus = 0;
-
- opts->cplusplus_comments = 1;
- opts->verbose = 0;
- opts->lang_asm = 0;
- opts->for_lint = 0;
- opts->chill = 0;
- opts->pedantic_errors = 0;
- opts->warn_comments = 0;
- opts->warnings_are_errors = 0;
-
- initialize_char_syntax (opts);
-}
-
-enum cpp_token
-cppReader_nullUnderflow (/*@unused@*/ cppReader *pfile)
-{
- return CPP_EOF;
-}
-
-void
-cppReader_nullCleanup (/*@unused@*/ cppBuffer *pbuf,
- /*@unused@*/ cppReader *pfile)
-{
- ;
-}
-
-void
-cppReader_macroCleanup (cppBuffer *pbuf, /*@unused@*/ cppReader *pfile)
-{
- hashNode macro = pbuf->hnode;
-
- if (macro->type == T_DISABLED)
- {
- macro->type = T_MACRO;
- }
-
- if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)
- {
- sfree (pbuf->buf);
- pbuf->buf = NULL;
- }
-}
-
-void
-cppReader_fileCleanup (cppBuffer *pbuf, /*@unused@*/ cppReader *pfile)
-{
- if (pbuf->buf != NULL)
- {
- sfree (pbuf->buf);
- pbuf->buf = NULL;
- }
-}
-
-/* Assuming we have read '/'.
- If this is the start of a comment (followed by '*' or '/'),
- skip to the end of the comment, and return ' '.
- Return EOF if we reached the end of file before the end of the comment.
- If not the start of a comment, return '/'. */
-
-static int
-skip_comment (cppReader *pfile, /*@null@*/ long *linep)
-{
- int c = 0;
-
- llassert (pfile->buffer != NULL);
- llassert (pfile->buffer->cur != NULL);
-
- while (cppReader_peekC (pfile) == '\\' && cpp_peekN (pfile, 1) == '\n')
- {
- if (linep != NULL)
- {
- (*linep)++;
- }
-
- cppReader_forward (pfile, 2);
- }
-
- if (cppReader_peekC (pfile) == '*')
- {
- cppReader_forward (pfile, 1);
-
- for (;;)
- {
- int prev_c = c;
- c = cppReader_getC (pfile);
-
- if (c == EOF)
- {
- return EOF;
- }
-
- while (c == (int) '\\' && cppReader_peekC (pfile) == (int) '\n')
- {
- if (linep != NULL )
- {
- (*linep)++;
- }
-
- cppReader_forward (pfile, 1), c = cppReader_getC (pfile);
- }
-
- if (prev_c == (int) '*' && c == (int) '/')
- {
- return (int) ' ';
- }
-
- if (c == (int) '\n' && (linep != NULL))
- {
- (*linep)++;
- }
- }
- }
- else if (cppReader_peekC (pfile) == '/'
- && CPPOPTIONS (pfile)->cplusplus_comments)
- {
- cppReader_forward (pfile, 1);
-
- for (;;)
- {
- c = cppReader_getC (pfile);
-
- if (c == EOF)
- {
- /* Allow hash comment to be terminated by EOF. */
- return (int) ' ';
- }
-
- while (c == (int) '\\' && cppReader_peekC (pfile) == '\n')
- {
- cppReader_forward (pfile, 1);
- c = cppReader_getC (pfile);
-
- if (linep != NULL)
- {
- (*linep)++;
- }
- }
-
- if (c == (int) '\n')
- {
- /* Don't consider final '\n' to be part of comment. */
- cppReader_forward (pfile, -1);
- return (int) ' ';
- }
- }
- }
- else
- {
- return (int) '/';
- }
-}
-
-/* Skip whitespace \-newline and comments. Does not macro-expand. */
-int /*@alt void@*/
-cppSkipHspace (cppReader *pfile)
-{
- int nspaces = 0;
-
- while (TRUE)
- {
- int c;
-
- llassert (pfile->buffer != NULL);
-
- c = cppReader_peekC (pfile);
-
- if (c == EOF)
- {
- return 0; /* FIXME */
- }
-
- if (is_hor_space[c])
- {
- if ((c == '\f' || c == '\v') && cppReader_isPedantic (pfile))
- cppReader_pedwarn (pfile,
- message ("%s in preprocessing directive",
- c == '\f'
- ? cstring_makeLiteralTemp ("formfeed")
- : cstring_makeLiteralTemp ("vertical tab")));
-
- nspaces++;
- cppReader_forward (pfile, 1);
- }
- else if (c == '/')
- {
- cppReader_forward (pfile, 1);
- c = skip_comment (pfile, NULL);
-
- if (c == '/')
- {
- cppReader_forward (pfile, -1);
- }
-
- if (c == EOF || c == '/')
- {
- return nspaces;
- }
- }
- else if (c == '\\' && cpp_peekN (pfile, 1) == '\n')
- {
- cppReader_forward (pfile, 2);
- }
- else if (c == '@' && CPPBUFFER (pfile)->has_escapes
- && is_hor_space [cpp_peekN (pfile, 1)])
- {
- cppReader_forward (pfile, 2);
- }
- else
- {
- return nspaces;
- }
- }
-}
-
-/* Read the rest of the current line.
- The line is appended to PFILE's output buffer. */
-
-static void
-copy_rest_of_line (cppReader *pfile)
-{
- struct cppOptions *opts = CPPOPTIONS (pfile);
-
- for (;;)
- {
- int c;
- int nextc;
-
- llassert (pfile->buffer != NULL);
-
- c = cppReader_getC (pfile);
- switch (c)
- {
- case EOF:
- goto end_directive;
- case '\\':
- if (cppReader_peekC (pfile) == '\n')
- {
- cppReader_forward (pfile, 1);
- continue;
- }
-
- /*@fallthrough@*/ case '\'': case '\"':
- goto scan_directive_token;
-
- case '/':
- nextc = cppReader_peekC (pfile);
-
- /*
- ** was (opts->cplusplus_comments && nextc == '*')
- ** yoikes!
- */
-
- if (nextc == '*'
- || (opts->cplusplus_comments && nextc == '/'))
- {
- goto scan_directive_token;
- }
- /*@switchbreak@*/ break;
- case '\f':
- case '\v':
- if (cppReader_isPedantic (pfile))
- cppReader_pedwarn (pfile,
- message ("%s in preprocessing directive",
- c == '\f'
- ? cstring_makeLiteralTemp ("formfeed")
- : cstring_makeLiteralTemp ("vertical tab")));
- /*@switchbreak@*/ break;
-
- case '\n':
- cppReader_forward (pfile, -1);
- goto end_directive;
- scan_directive_token:
- cppReader_forward (pfile, -1);
- (void) cppGetToken (pfile);
- continue;
- }
- cppReader_putChar (pfile, c);
- }
-end_directive: ;
- cppReader_nullTerminate (pfile);
-}
-
-void
-cppReader_skipRestOfLine (cppReader *pfile)
-{
- size_t old = cppReader_getWritten (pfile);
- copy_rest_of_line (pfile);
- cppReader_setWritten (pfile, old);
-}
-
-/* Handle a possible # directive.
- '#' has already been read. */
-
-int
-cppReader_handleDirective (cppReader *pfile)
-{
- int c;
- struct directive *kt = NULL;
- int ident_length;
- size_t after_ident = 0;
- char *ident = NULL;
- char *line_end = NULL;
- size_t old_written = cppReader_getWritten (pfile);
- int nspaces = cppSkipHspace (pfile);
-
- c = cppReader_peekC (pfile);
-
- if (c >= '0' && c <= '9')
- {
- /* Handle # followed by a line number. */
- if (cppReader_isPedantic (pfile))
- {
- cppReader_pedwarnLit
- (pfile,
- cstring_makeLiteralTemp ("`#' followed by integer"));
- }
-
- (void) do_line (pfile, NULL);
- goto done_a_directive;
- }
-
-
- /* Now find the directive name. */
-
- cppReader_putChar (pfile, '#');
-
- parse_name (pfile, cppReader_getC (pfile));
-
- llassert (pfile->token_buffer != NULL);
- ident = pfile->token_buffer + old_written + 1;
-
- ident_length = cppReader_getPWritten (pfile) - ident;
-
- if (ident_length == 0 && cppReader_peekC (pfile) == '\n')
- {
- /* A line of just `#' becomes blank. */
- return 1;
- }
-
- for (kt = directive_table; ; kt++)
- {
- if (kt->length <= 0)
- {
- return 0; /* goto not_a_directive; */
- }
-
- if (kt->length == ident_length
- && (cstring_equalPrefix (kt->name, cstring_fromChars (ident))))
- {
- break;
- }
- }
-
- if (kt->command_reads_line)
- {
- after_ident = 0;
- }
- else
- {
- /* Nonzero means do not delete comments within the directive.
- #define needs this when -traditional. */
- bool comments = 1; /*cppReader_isTraditional (pfile) && kt->traditional_comments; */
- int save_put_out_comments = CPPOPTIONS (pfile)->put_out_comments;
- CPPOPTIONS (pfile)->put_out_comments = comments;
- after_ident = cppReader_getWritten (pfile);
- copy_rest_of_line (pfile);
- CPPOPTIONS (pfile)->put_out_comments = save_put_out_comments;
- }
-
-
- /* For #pragma and #define, we may want to pass through the directive.
- Other directives may create output, but we don't want the directive
- itself out, so we pop it now. For example #include may write a #line
- command (see comment in do_include), and conditionals may emit
- #failed ... #endfailed stuff. But note that popping the buffer
- means the parameters to kt->func may point after pfile->limit
- so these parameters are invalid as soon as something gets appended
- to the token_buffer. */
-
- line_end = cppReader_getPWritten (pfile);
-
-
- if (!kt->pass_thru && kt->type != T_DEFINE)
- {
- cppReader_setWritten (pfile, old_written);
- }
-
- llassert (pfile->token_buffer != NULL);
-
- /* was kt->pass_thru || */
-
- if (kt->type == T_DEFINE
- && cpp_shouldCheckMacro (pfile, pfile->token_buffer + old_written))
- {
- char *p = pfile->token_buffer + old_written;
-
- /*
- ** Still need to record value for preprocessing, so
- ** #ifdef's, etc. using the value behave correctly.
- */
-
- (void) do_defineAux (pfile, kt,
- pfile->token_buffer + after_ident,
- line_end,
- TRUE);
-
- if (*p == '#')
- {
- *p = ' ';
- }
-
- SKIP_WHITE_SPACE (p);
-
- llassert (*p == 'd');
- *p++ = LLMRCODE[0];
-
- llassert (*p == 'e');
- *p++ = LLMRCODE[1];
-
- llassert (*p == 'f');
- *p++ = LLMRCODE[2];
-
- llassert (*p == 'i');
- *p++ = LLMRCODE[3];
-
- llassert (*p == 'n');
- *p++ = LLMRCODE[4];
-
- llassert (*p == 'e');
-
- /*
- ** This is way-bogus. We use the last char to record the number of
- ** spaces. Its too hard to get them back into the input stream.
- */
-
- if (nspaces > 9) nspaces = 9;
-
- *p++ = '0' + nspaces;
-
- return 0; /* not_a_directive */
- }
- else if (kt->pass_thru)
- {
- /* Just leave the entire #define in the output stack. */
- return 0; /* not_a_directive */
-
- }
- else if (kt->type == T_DEFINE
- && CPPOPTIONS (pfile)->dump_macros == DUMP_NAMES)
- {
- char *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */
- SKIP_WHITE_SPACE (p);
-
- while (is_idchar[(int) *p])
- {
- p++;
- }
-
- pfile->limit = p;
- cppReader_putChar (pfile, '\n');
- }
- else if (kt->type == T_DEFINE)
- {
- cppReader_setWritten (pfile, old_written);
- }
- else
- {
- ;
- }
-
-done_a_directive:
- if (kt == NULL) {
- return 1;
- } else {
- llassert (kt->func != NULL);
- (void) (kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end);
- return 1;
- }
-}
-
-/* Pass a directive through to the output file.
- BUF points to the contents of the directive, as a contiguous string.
- LIMIT points to the first character past the end of the directive.
- KEYWORD is the keyword-table entry for the directive. */
-
-static void
-pass_thru_directive (char *buf, char *limit,
- cppReader *pfile,
- struct directive *keyword)
-{
- int keyword_length = keyword->length;
-
- cppReader_reserve (pfile,
- size_fromInt (2 + keyword_length + (limit - buf)));
- cppReader_putCharQ (pfile, '#');
- /*@-observertrans@*/
- cppReader_putStrN (pfile, cstring_toCharsSafe (keyword->name),
- size_fromInt (keyword_length));
- /*:=observertrans@*/
-
- if (limit != buf && buf[0] != ' ')
- {
- /* Was a bug, since reserve only used 1 + ... */
- cppReader_putCharQ (pfile, ' ');
- }
-
- cppReader_putStrN (pfile, buf, size_fromInt (limit - buf));
-}
-
-/* Read a replacement list for a macro with parameters.
- Build the DEFINITION structure.
- Reads characters of text starting at BUF until END.
- ARGLIST specifies the formal parameters to look for
- in the text of the definition; NARGS is the number of args
- in that list, or -1 for a macro name that wants no argument list.
- MACRONAME is the macro name itself (so we can avoid recursive expansion)
- and NAMELEN is its length in characters.
-
- Note that comments, backslash-newlines, and leading white space
- have already been deleted from the argument. */
-
-static DEFINITION *
-collect_expansion (cppReader *pfile, char *buf, char *limit,
- int nargs, /*@null@*/ struct arglist *arglist)
-{
- DEFINITION *defn;
- char *p, *lastp, *exp_p;
- struct reflist *endpat = NULL;
- /* Pointer to first nonspace after last ## seen. */
- char *concat = 0;
- /* Pointer to first nonspace after last single-# seen. */
- char *stringify = 0;
- size_t maxsize;
- char expected_delimiter = '\0';
-
-
- /* Scan thru the replacement list, ignoring comments and quoted
- strings, picking up on the macro calls. It does a linear search
- thru the arg list on every potential symbol. Profiling might say
- that something smarter should happen. */
-
- if (limit < buf)
- abort ();
-
- /* Find the beginning of the trailing whitespace. */
- p = buf;
-
- while (p < limit && is_space[(int) limit[-1]])
- {
- limit--;
- }
-
- /* Allocate space for the text in the macro definition.
- Leading and trailing whitespace chars need 2 bytes each.
- Each other input char may or may not need 1 byte,
- so this is an upper bound. The extra 5 are for invented
- leading and trailing newline-marker and final null. */
- maxsize = (sizeof (*defn) + (limit - p) + 5);
-
- /* Occurrences of '@' get doubled, so allocate extra space for them. */
- while (p < limit)
- {
- if (*p++ == '@')
- {
- maxsize++;
- }
- }
-
- defn = (DEFINITION *) dmalloc (maxsize);
- defn->noExpand = FALSE;
- defn->file = NULL;
- defn->pattern = NULL;
- defn->nargs = nargs;
- defn->predefined = NULL;
-
- exp_p = defn->expansion = (char *) defn + sizeof (*defn);
-
- defn->line = 0;
- defn->rest_args = NULL;
- defn->args.argnames = NULL;
-
- lastp = exp_p;
-
- p = buf;
-
- /* Add one initial space escape-marker to prevent accidental
- token-pasting (often removed by macroexpand). */
- *exp_p++ = '@';
- *exp_p++ = ' ';
-
- if (limit - p >= 2 && p[0] == '#' && p[1] == '#') {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`##' at start of macro definition"));
- p += 2;
- }
-
- /* Process the main body of the definition. */
- while (p < limit) {
- int skipped_arg = 0;
- register char c = *p++;
-
- *exp_p++ = c;
-
- if (!cppReader_isTraditional (pfile)) {
- switch (c) {
- case '\'':
- case '\"':
- if (expected_delimiter != '\0')
- {
- if (c == expected_delimiter)
- expected_delimiter = '\0';
- }
- else
- {
- expected_delimiter = c;
- }
- /*@switchbreak@*/ break;
-
- case '\\':
- if (p < limit && (expected_delimiter != '\0'))
- {
- /* In a string, backslash goes through
- and makes next char ordinary. */
- *exp_p++ = *p++;
- }
- /*@switchbreak@*/ break;
-
- case '@':
- /* An '@' in a string or character constant stands for itself,
- and does not need to be escaped. */
- if (expected_delimiter == '\0')
- {
- *exp_p++ = c;
- }
-
- /*@switchbreak@*/ break;
-
- case '#':
- /* # is ordinary inside a string. */
- if (expected_delimiter != '\0')
- {
- /*@switchbreak@*/ break;
- }
-
- if (p < limit && *p == '#') {
- /* ##: concatenate preceding and following tokens. */
- /* Take out the first #, discard preceding whitespace. */
- exp_p--;
-
- /*@-usedef@*/
- while (exp_p > lastp && is_hor_space[(int) exp_p[-1]])
- {
- --exp_p;
- }
- /*@=usedef@*/
-
- /* Skip the second #. */
- p++;
- /* Discard following whitespace. */
- SKIP_WHITE_SPACE (p);
- concat = p;
- if (p == limit)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`##' at end of macro definition"));
- }
- } else if (nargs >= 0) {
- /* Single #: stringify following argument ref.
- Don't leave the # in the expansion. */
- exp_p--;
- SKIP_WHITE_SPACE (p);
- if (p == limit || ! is_idstart[(int) *p]
- || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"')))
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`#' operator is not followed by a macro argument name"));
- else
- stringify = p;
- } else {
- ; /* BADBRANCH; */
- }
-
- /*@switchbreak@*/ break;
- }
- } else {
- /* In -traditional mode, recognize arguments inside strings and
- and character constants, and ignore special properties of #.
- Arguments inside strings are considered "stringified", but no
- extra quote marks are supplied. */
- switch (c) {
- case '\'':
- case '\"':
- if (expected_delimiter != '\0') {
- if (c == expected_delimiter)
- expected_delimiter = '\0';
- } else
- expected_delimiter = c;
- /*@switchbreak@*/ break;
-
- case '\\':
- /* Backslash quotes delimiters and itself, but not macro args. */
- if (expected_delimiter != '\0' && p < limit
- && (*p == expected_delimiter || *p == '\\')) {
- *exp_p++ = *p++;
- continue;
- }
- /*@switchbreak@*/ break;
-
- case '/':
- if (expected_delimiter != '\0') /* No comments inside strings. */
- /*@switchbreak@*/ break;
- if (*p == '*') {
- /* If we find a comment that wasn't removed by cppReader_handleDirective,
- this must be -traditional. So replace the comment with
- nothing at all. */
- exp_p--;
- p += 1;
- while (p < limit && !(p[-2] == '*' && p[-1] == '/'))
- {
- p++;
- }
- }
- /*@switchbreak@*/ break;
- }
- }
-
- /* Handle the start of a symbol. */
- if (is_idchar[(int) c] && nargs > 0) {
- char *id_beg = p - 1;
- int id_len;
-
- --exp_p;
- while (p != limit && is_idchar[(int) *p])
- {
- p++;
- }
-
- id_len = p - id_beg;
-
- if (is_idstart[(int) c]
- && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) {
- register struct arglist *arg;
-
- for (arg = arglist; arg != NULL; arg = arg->next) {
- struct reflist *tpat;
-
- if (arg->name[0] == c
- && arg->length == id_len
- && strncmp (arg->name, id_beg, size_fromInt (id_len)) == 0) {
- char *p1;
-
- if (expected_delimiter && CPPOPTIONS (pfile)->warn_stringify) {
- if (cppReader_isTraditional (pfile)) {
- cppReader_warning (pfile,
- message ("macro argument `%x' is stringified.",
- cstring_prefix (cstring_fromChars (arg->name), id_len)));
- } else {
- cppReader_warning (pfile,
- message ("macro arg `%x' would be stringified with -traditional.",
- cstring_prefix (cstring_fromChars (arg->name), id_len)));
- }
- }
- /* If ANSI, don't actually substitute inside a string. */
- if (!cppReader_isTraditional (pfile) && expected_delimiter)
- /*@innerbreak@*/ break;
- /* make a pat node for this arg and append it to the end of
- the pat list */
- tpat = (struct reflist *) dmalloc (sizeof (*tpat));
- tpat->next = NULL;
- tpat->raw_before = (concat == id_beg);
- tpat->raw_after = 0;
- tpat->rest_args = arg->rest_args;
- tpat->stringify = (cppReader_isTraditional (pfile)
- ? expected_delimiter != '\0'
- : stringify == id_beg);
-
- if (endpat == NULL)
- {
- defn->pattern = tpat;
- }
- else
- {
- endpat->next = tpat;
- /*@-branchstate@*/
- } /*@=branchstate@*/ /* evs 2000 was =branchstate */
-
- endpat = tpat;
-
- tpat->argno = arg->argno;
- tpat->nchars = exp_p - lastp;
-
- p1 = p;
-
- SKIP_WHITE_SPACE (p1);
-
- if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')
- {
- tpat->raw_after = 1;
- }
-
- lastp = exp_p; /* place to start copying from next time */
- skipped_arg = 1;
-
- /*@innerbreak@*/ break;
- }
- }
- }
-
- /* If this was not a macro arg, copy it into the expansion. */
- if (skipped_arg == 0) {
- register char *lim1 = p;
- p = id_beg;
-
- while (p != lim1)
- {
- *exp_p++ = *p++;
- }
-
- if (stringify == id_beg)
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`#' operator should be followed by a macro argument name"));
- }
- }
- }
-
- if (!cppReader_isTraditional (pfile) && expected_delimiter == '\0')
- {
- /* If ANSI, put in a "@ " marker to prevent token pasting.
- But not if "inside a string" (which in ANSI mode
- happens only for -D option). */
- *exp_p++ = '@';
- *exp_p++ = ' ';
- }
-
- *exp_p = '\0';
-
- defn->length = size_fromInt (exp_p - defn->expansion);
-
- /* Crash now if we overrun the allocated size. */
- if (defn->length + 1 > maxsize)
- {
- llfatalbug (cstring_makeLiteral ("Maximum definition size exceeded."));
- }
-
- return defn;
-}
-
-/*
- * special extension string that can be added to the last macro argument to
- * allow it to absorb the "rest" of the arguments when expanded. Ex:
- * #define wow(a, b...) process (b, a, b)
- * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); }
- * { wow (one, two); } -> { process (two, one, two); }
- * if this "rest_arg" is used with the concat token '##' and if it is not
- * supplied then the token attached to with ## will not be outputted. Ex:
- * #define wow (a, b...) process (b ## , a, ## b)
- * { wow (1, 2); } -> { process (2, 1, 2); }
- * { wow (one); } -> { process (one); {
- */
-
-/*@-readonlytrans@*/
-static char rest_extension[] = "...";
-/*:=readonlytrans@*/
-
-/*@notfunction@*/
-#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)
-
-/* Create a DEFINITION node from a #define directive. Arguments are
- as for do_define. */
-
-static /*@null@*/ MACRODEF
-create_definition (char *buf, char *limit,
- cppReader *pfile, bool predefinition,
- bool noExpand)
-{
- char *bp; /* temp ptr into input buffer */
- char *symname; /* remember where symbol name starts */
- int sym_length; /* and how long it is */
- int rest_args = 0; /* really int! */
- int line;
- int col;
- cstring file = (CPPBUFFER (pfile) != NULL)
- ? CPPBUFFER (pfile)->nominal_fname : cstring_makeLiteralTemp ("");
- DEFINITION *defn;
- int arglengths = 0; /* Accumulate lengths of arg names
- plus number of args. */
- MACRODEF mdef;
-
- cppBuffer_lineAndColumn (CPPBUFFER (pfile), &line, &col);
-
- bp = buf;
-
- while (is_hor_space[(int) *bp])
- {
- bp++;
- }
-
- symname = bp; /* remember where it starts */
-
- sym_length = cppReader_checkMacroName (pfile, bp, cstring_makeLiteralTemp ("macro"));
-
- bp += sym_length;
-
- /* Lossage will occur if identifiers or control keywords are broken
- across lines using backslash. This is not the right place to take
- care of that. */
-
- if (*bp == '(') {
- struct arglist *arg_ptrs = NULL;
- int argno = 0;
-
- bp++; /* skip '(' */
- SKIP_WHITE_SPACE (bp);
-
- /* Loop over macro argument names. */
- while (*bp != ')')
- {
- struct arglist *temp = (struct arglist *) dmalloc (sizeof (*temp));
- temp->name = bp;
- temp->next = arg_ptrs;
- temp->argno = argno++;
- temp->rest_args = 0;
-
- arg_ptrs = temp;
-
- if (rest_args != 0)
- {
- cppReader_pedwarn (pfile,
- message ("another parameter follows `%s'",
- cstring_fromChars (rest_extension)));
- }
-
- if (!is_idstart[(int) *bp])
- {
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("invalid character in macro parameter name"));
- }
-
- /* Find the end of the arg name. */
- while (is_idchar[(int) *bp])
- {
- bp++;
- /* do we have a "special" rest-args extension here? */
- if (limit - bp > size_toInt (REST_EXTENSION_LENGTH)
- && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)
- {
- rest_args = 1;
- temp->rest_args = 1;
- /*@innerbreak@*/ break;
- }
- }
-
- temp->length = bp - temp->name;
-
- if (rest_args != 0)
- {
- bp += REST_EXTENSION_LENGTH;
- }
-
- arglengths += temp->length + 2;
- SKIP_WHITE_SPACE (bp);
-
- if (temp->length == 0 || (*bp != ',' && *bp != ')')) {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("Parameter list for #define is not parseable"));
- goto nope;
- }
-
- if (*bp == ',') {
- bp++;
- SKIP_WHITE_SPACE (bp);
- }
- if (bp >= limit) {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("unterminated parameter list in `#define'"));
- goto nope;
- }
- {
- struct arglist *otemp;
-
- for (otemp = temp->next; otemp != NULL; otemp = otemp->next)
- {
- if (temp->length == otemp->length &&
- strncmp (temp->name, otemp->name, size_fromInt (temp->length)) == 0) {
- cstring name = cstring_copyLength (temp->name, temp->length);
- cppReader_error (pfile,
- message ("duplicate argument name `%x' in `#define'", name));
- goto nope;
- }
- }
- }
- }
-
- ++bp; /* skip paren */
- SKIP_WHITE_SPACE (bp);
- /* now everything from bp before limit is the definition. */
- defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);
- defn->rest_args = rest_args;
-
- /* Now set defn->args.argnames to the result of concatenating
- the argument names in reverse order
- with comma-space between them. */
- defn->args.argnames = (char *) dmalloc (size_fromInt (arglengths + 1));
-
- {
- struct arglist *temp;
- int i = 0;
- for (temp = arg_ptrs; temp != NULL; temp = temp->next) {
- memcpy (&defn->args.argnames[i], temp->name, size_fromInt (temp->length));
- i += temp->length;
- if (temp->next != 0) {
- defn->args.argnames[i++] = ',';
- defn->args.argnames[i++] = ' ';
- }
- }
-
- defn->args.argnames[i] = '\0';
- }
-
- sfree (arg_ptrs);
- } else {
- /* Simple expansion or empty definition. */
-
- if (bp < limit)
- {
- if (is_hor_space[(int) *bp]) {
- bp++;
- SKIP_WHITE_SPACE (bp);
- } else {
- switch (*bp) {
- case '!': case '"': case '#': case '%': case '&': case '\'':
- case ')': case '*': case '+': case ',': case '-': case '.':
- case '/': case ':': case ';': case '<': case '=': case '>':
- case '?': case '[': case '\\': case ']': case '^': case '{':
- case '|': case '}': case '~':
- cppReader_warning (pfile,
- message ("Missing white space after #define %x",
- cstring_prefix (cstring_fromChars (symname),
- sym_length)));
- break;
-
- default:
- cppReader_pedwarn (pfile,
- message ("Missing white space after #define %x",
- cstring_prefix (cstring_fromChars (symname),
- sym_length)));
- break;
- }
- }
- }
- /* now everything from bp before limit is the definition. */
- defn = collect_expansion (pfile, bp, limit, -1, NULL);
- defn->args.argnames = mstring_createEmpty ();
- }
-
- defn->noExpand = noExpand;
- DPRINTF (("No expand: %d", noExpand));
-
- defn->line = line;
-
- /* not: llassert (cstring_isUndefined (defn->file)); */
- defn->file = file;
-
- /* OP is null if this is a predefinition */
- defn->predefined = predefinition;
- mdef.defn = defn;
- mdef.symnam = symname;
- mdef.symlen = sym_length;
-
- return mdef;
-
-nope:
- mdef.defn = NULL;
- mdef.symnam = NULL;
- return mdef;
-}
-
-/* Check a purported macro name SYMNAME, and yield its length.
- USAGE is the kind of name this is intended for. */
-
-int cppReader_checkMacroName (cppReader *pfile,
- char *symname,
- cstring usage)
-{
- char *p;
- size_t sym_length;
-
- for (p = symname; is_idchar[(int) *p]; p++)
- {
- ;
- }
-
- sym_length = size_fromInt (p - symname);
-
- if (sym_length == 0
- || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))
- cppReader_error (pfile, message ("invalid %s name", usage));
- else if (!is_idstart[(int) *symname])
- {
- char *msg = (char *) dmalloc (sym_length + 1);
- memcpy (msg, symname, sym_length);
- msg[sym_length] = '\0';
- cppReader_error (pfile, message ("invalid %s name `%s'", usage,
- cstring_fromChars (msg)));
- sfree (msg);
- }
- else
- {
- if ((strncmp (symname, "defined", 7) == 0) && sym_length == 7)
- {
- cppReader_error (pfile, message ("invalid %s name `defined'", usage));
- }
- }
-
- return size_toInt (sym_length);
-}
-
-/* Return zero if two DEFINITIONs are isomorphic. */
-
-static bool
-compare_defs (DEFINITION *d1, DEFINITION *d2)
-{
- register struct reflist *a1, *a2;
- register char *p1 = d1->expansion;
- register char *p2 = d2->expansion;
- bool first = TRUE;
-
- if (d1->nargs != d2->nargs)
- {
- return TRUE;
- }
-
- llassert (d1->args.argnames != NULL);
- llassert (d2->args.argnames != NULL);
-
- if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames) != 0)
- {
- return TRUE;
- }
-
- for (a1 = d1->pattern, a2 = d2->pattern;
- (a1 != NULL) && (a2 != NULL);
- a1 = a1->next, a2 = a2->next) {
- if (!((a1->nchars == a2->nchars
- && (strncmp (p1, p2, size_fromInt (a1->nchars)) == 0))
- || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))
- || a1->argno != a2->argno
- || a1->stringify != a2->stringify
- || a1->raw_before != a2->raw_before
- || a1->raw_after != a2->raw_after)
- return TRUE;
- first = 0;
- p1 += a1->nchars;
- p2 += a2->nchars;
- }
- if (a1 != a2)
- return TRUE;
-
- if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),
- p2, d2->length - (p2 - d2->expansion), 1))
- return TRUE;
-
- return FALSE;
-}
-
-/* Return TRUE if two parts of two macro definitions are effectively different.
- One of the parts starts at BEG1 and has LEN1 chars;
- the other has LEN2 chars at BEG2.
- Any sequence of whitespace matches any other sequence of whitespace.
- FIRST means these parts are the first of a macro definition;
- so ignore leading whitespace entirely.
- LAST means these parts are the last of a macro definition;
- so ignore trailing whitespace entirely. */
-
-static bool
-comp_def_part (bool first, char *beg1, int len1, char *beg2, int len2, bool last)
-{
- char *end1 = beg1 + len1;
- char *end2 = beg2 + len2;
-
- if (first) {
- while (beg1 != end1 && is_space[(int) *beg1]) { beg1++; }
- while (beg2 != end2 && is_space[(int) *beg2]) { beg2++; }
- }
- if (last) {
- while (beg1 != end1 && is_space[(int) end1[-1]]) { end1--; }
- while (beg2 != end2 && is_space[(int) end2[-1]]) { end2--; }
- }
- while (beg1 != end1 && beg2 != end2) {
- if (is_space[(int) *beg1] && is_space[(int) *beg2]) {
- while (beg1 != end1 && is_space[(int) *beg1]) { beg1++; }
- while (beg2 != end2 && is_space[(int) *beg2]) { beg2++; }
- } else if (*beg1 == *beg2) {
- beg1++; beg2++;
- } else break;
- }
- return (beg1 != end1) || (beg2 != end2);
-}
-
-/* Process a #define command.
- BUF points to the contents of the #define command, as a contiguous string.
- LIMIT points to the first character past the end of the definition.
- KEYWORD is the keyword-table entry for #define,
- or NULL for a "predefined" macro. */
-
-static int
-do_defineAux (cppReader *pfile, struct directive *keyword,
- char *buf, char *limit, bool noExpand)
-{
- int hashcode;
- MACRODEF mdef;
- hashNode hp;
-
- DPRINTF (("Define aux: %d", noExpand));
-
- mdef = create_definition (buf, limit, pfile, keyword == NULL, noExpand);
-
- if (mdef.defn == 0)
- goto nope;
-
- hashcode = hashf (mdef.symnam, mdef.symlen, CPP_HASHSIZE);
-
- DPRINTF (("Macro: %s / %s",
- cstring_copyLength (mdef.symnam, mdef.symlen),
- bool_unparse (noExpand)));
-
- if ((hp = cppReader_lookup (mdef.symnam, mdef.symlen, hashcode)) != NULL)
- {
- bool ok = FALSE;
-
- /* Redefining a precompiled key is ok. */
- if (hp->type == T_PCSTRING)
- ok = TRUE;
- /* Redefining a macro is ok if the definitions are the same. */
- else if (hp->type == T_MACRO)
- ok = !compare_defs (mdef.defn, hp->value.defn);
- /* Redefining a constant is ok with -D. */
- else if (hp->type == T_CONST)
- ok = !CPPOPTIONS (pfile)->done_initializing;
- else {
- BADBRANCH;
- }
-
- /* Print the warning if it's not ok. */
- if (!ok)
- {
- /*
- ** If we are passing through #define and #undef directives, do
- ** that for this re-definition now.
- */
-
- if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))
- {
- /* llassert (keyword != NULL); */
- pass_thru_directive (buf, limit, pfile, keyword);
- }
-
- cpp_setLocation (pfile);
-
- if (hp->type == T_MACRO)
- {
- if (hp->value.defn->noExpand)
- {
- ; /* error will be reported checking macros */
- }
- else
- {
- genppllerrorhint
- (FLG_MACROREDEF,
- message ("Macro %q already defined",
- cstring_copyLength (mdef.symnam, mdef.symlen)),
- message ("%q: Previous definition of %q",
- fileloc_unparseRaw (hp->value.defn->file,
- (int) hp->value.defn->line),
- cstring_copyLength (mdef.symnam, mdef.symlen)));
- }
- }
- else
- {
- genppllerror (FLG_MACROREDEF,
- message ("Macro %q already defined",
- cstring_copyLength (mdef.symnam,
- mdef.symlen)));
-
- }
- }
-
- /* Replace the old definition. */
- hp->type = T_MACRO;
- hp->value.defn = mdef.defn;
- }
- else
- {
- /*
- ** If we are passing through #define and #undef directives, do
- ** that for this new definition now.
- */
-
- hashNode hn;
-
- if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))
- {
- pass_thru_directive (buf, limit, pfile, keyword);
- }
-
- DPRINTF (("Define macro: %s / %d",
- mdef.symnam, mdef.defn->noExpand));
-
- hn = cppReader_installMacro (mdef.symnam, mdef.symlen, mdef.defn, hashcode);
- /*@-branchstate@*/
- } /*@=branchstate@*/
-
- return 0;
-
-nope:
-
- return 1;
-}
-
-static int
-do_define (cppReader *pfile, struct directive *keyword,
- char *buf, char *limit)
-{
- DPRINTF (("Regular do define"));
- return do_defineAux (pfile, keyword, buf, limit, FALSE);
-}
-
-/* This structure represents one parsed argument in a macro call.
- `raw' points to the argument text as written (`raw_length' is its length).
- `expanded' points to the argument's macro-expansion
- (its length is `expand_length').
- `stringified_length' is the length the argument would have
- if stringified.
- `use_count' is the number of times this macro arg is substituted
- into the macro. If the actual use count exceeds 10,
- the value stored is 10. */
-
-/* raw and expanded are relative to ARG_BASE */
-/*@notfunction@*/
-#define ARG_BASE ((pfile)->token_buffer)
-
-struct argdata {
- /* Strings relative to pfile->token_buffer */
- long raw;
- size_t expanded;
- size_t stringified;
- int raw_length;
- int expand_length;
- int stringified_length;
- bool newlines;
- int use_count;
-};
-
-/* Allocate a new cppBuffer for PFILE, and push it on the input buffer stack.
- If BUFFER != NULL, then use the LENGTH characters in BUFFER
- as the new input buffer.
- Return the new buffer, or NULL on failure. */
-
-/*@null@*/ /*@exposed@*/ cppBuffer *
-cppReader_pushBuffer (cppReader *pfile, char *buffer, size_t length)
-{
- cppBuffer *buf = cppReader_getBuffer (pfile);
-
- if (buf == pfile->buffer_stack)
- {
- cppReader_fatalError
- (pfile,
- message ("%s: macro or `#include' recursion too deep",
- (buf->fname != NULL)
- ? buf->fname
- : cstring_makeLiteral ("<no name>")));
- sfreeEventually (buffer);
- return NULL;
- }
-
- llassert (buf != NULL);
-
- buf--;
- memset ((char *) buf, 0, sizeof (*buf));
- CPPBUFFER (pfile) = buf;
-
- buf->if_stack = pfile->if_stack;
- buf->cleanup = cppReader_nullCleanup;
- buf->underflow = cppReader_nullUnderflow;
- buf->buf = buffer;
- buf->cur = buf->buf;
-
- if (buffer != NULL)
- {
- buf->alimit = buf->rlimit = buffer + length;
- }
- else
- {
- buf->alimit = buf->rlimit = NULL;
- }
-
- return buf;
-}
-
-cppBuffer *
-cppReader_popBuffer (cppReader *pfile)
-{
- cppBuffer *buf = CPPBUFFER (pfile);
-
- llassert (buf != NULL);
-
- (void) (*buf->cleanup) (buf, pfile);
- return ++CPPBUFFER (pfile);
-}
-
-/* Scan until CPPBUFFER (PFILE) is exhausted into PFILE->token_buffer.
- Pop the buffer when done. */
-
-void
-cppReader_scanBuffer (cppReader *pfile)
-{
- cppBuffer *buffer = CPPBUFFER (pfile);
- for (;;)
- {
- enum cpp_token token;
-
- token = cppGetToken (pfile);
-
- if (token == CPP_EOF) /* Should not happen ... */
- {
- break;
- }
-
- if (token == CPP_POP && CPPBUFFER (pfile) == buffer)
- {
- (void) cppReader_popBuffer (pfile);
- break;
- }
- }
-}
-
-/*
- * Rescan a string (which may have escape marks) into pfile's buffer.
- * Place the result in pfile->token_buffer.
- *
- * The input is copied before it is scanned, so it is safe to pass
- * it something from the token_buffer that will get overwritten
- * (because it follows cppReader_getWritten). This is used by do_include.
- */
-
-static void
-cpp_expand_to_buffer (cppReader *pfile, char *buf, size_t length)
-{
- register cppBuffer *ip;
- char *limit = buf + length;
- char *buf1, *p1, *p2;
-
- /* evans - 2001-08-26
- ** length is unsigned - this doesn't make sense
- if (length < 0)
- abort ();
- **
- */
-
- /* Set up the input on the input stack. */
-
- buf1 = (char *) dmalloc (length + 1);
-
- p1 = buf;
- p2 = buf1;
-
- while (p1 != limit)
- {
- *p2++ = *p1++;
- }
-
- buf1[length] = '\0';
-
- ip = cppReader_pushBuffer (pfile, buf1, length);
-
- if (ip == NULL)
- return;
-
- ip->has_escapes = TRUE;
-
- /* Scan the input, create the output. */
- cppReader_scanBuffer (pfile);
-
- cppReader_nullTerminate (pfile);
-}
-
-static void
-adjust_position (char *buf, char *limit, int *linep, int *colp)
-{
- while (buf < limit)
- {
- char ch = *buf++;
- if (ch == '\n')
- (*linep)++, (*colp) = 1;
- else
- (*colp)++;
- }
-}
-
-/* Move line_base forward, updating lineno and colno. */
-
-static void
-update_position (cppBuffer *pbuf)
-{
- char *old_pos;
- char *new_pos = pbuf->cur;
- register struct parse_marker *mark;
-
- llassert (pbuf->buf != NULL);
- old_pos = pbuf->buf + pbuf->line_base;
-
- for (mark = pbuf->marks; mark != NULL; mark = mark->next)
- {
- if (pbuf->buf + mark->position < new_pos)
- new_pos = pbuf->buf + mark->position;
- }
- pbuf->line_base += new_pos - old_pos;
-
- llassert (old_pos != NULL);
- llassert (new_pos != NULL);
-
- adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno);
-}
-
-void
-cppBuffer_lineAndColumn (/*@null@*/ cppBuffer *pbuf, /*@out@*/ int *linep,
- /*@null@*/ /*@out@*/ int *colp)
-{
- int dummy;
-
- if (colp == NULL)
- {
- colp = &dummy;
- /*@-branchstate@*/
- } /*@=branchstate@*/
-
- if (pbuf != NULL)
- {
- *linep = pbuf->lineno;
- *colp = pbuf->colno;
-
- llassert (pbuf->buf != NULL);
- llassert (pbuf->cur != NULL);
-
- adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp);
- }
- else
- {
- *linep = 0;
- *colp = 0;
- }
-}
-
-/* Return the cppBuffer that corresponds to a file (not a macro). */
-
-/*@exposed@*/ /*@null@*/ cppBuffer *cppReader_fileBuffer (cppReader *pfile)
-{
- cppBuffer *ip = cppReader_getBuffer (pfile);
-
- for ( ;
- ip != NULL && ip != cppReader_nullBuffer (pfile);
- ip = cppBuffer_prevBuffer (ip))
- {
- if (ip->fname != NULL)
- {
- return ip;
- }
- }
-
- return NULL;
-}
-
-static long
-count_newlines (char *buf, char *limit)
-{
- register long count = 0;
-
- while (buf < limit)
- {
- char ch = *buf++;
- if (ch == '\n')
- count++;
- }
- return count;
-}
-
-/*
- * write out a #line command, for instance, after an #include file.
- * If CONDITIONAL is nonzero, we can omit the #line if it would
- * appear to be a no-op, and we can output a few newlines instead
- * if we want to increase the line number by a small amount.
- * FILE_CHANGE says whether we are entering a file, leaving, or neither.
- */
-
-static void
-output_line_command (cppReader *pfile, bool conditional,
- enum file_change_code file_change)
-{
- int line, col;
- cppBuffer *ip = CPPBUFFER (pfile);
- cppBuffer *buf;
-
- llassert (ip != NULL);
-
- if (ip->fname == NULL)
- return;
-
- update_position (ip);
-
- if (CPPOPTIONS (pfile)->no_line_commands
- || CPPOPTIONS (pfile)->no_output)
- return;
-
- buf = CPPBUFFER (pfile);
-
- llassert (buf != NULL);
-
- line = buf->lineno;
- col = buf->colno;
-
- llassert (ip->cur != NULL);
-
- adjust_position (cppLineBase (ip), ip->cur, &line, &col);
-
- if (CPPOPTIONS (pfile)->no_line_commands)
- return;
-
- if (conditional) {
- if (line == pfile->lineno)
- return;
-
- /* If the inherited line number is a little too small,
- output some newlines instead of a #line command. */
-
- if (line > pfile->lineno && line < pfile->lineno + 8)
- {
- cppReader_reserve (pfile, 20);
- while (line > pfile->lineno)
- {
- cppReader_putCharQ (pfile, '\n');
- pfile->lineno++;
- }
-
- return;
- }
- }
-
- cppReader_reserve (pfile,
- size_fromInt (4 * cstring_length (ip->nominal_fname) + 50));
-
- {
-#ifdef OUTPUT_LINE_COMMANDS
- static char sharp_line[] = "#line ";
-#else
- static char sharp_line[] = "# ";
-#endif
- cppReader_putStrN (pfile, sharp_line, sizeof(sharp_line)-1);
- }
-
- sprintf (cppReader_getPWritten (pfile), "%d ", line);
- cppReader_adjustWritten (pfile, strlen (cppReader_getPWritten (pfile)));
-
- quote_string (pfile, cstring_toCharsSafe (ip->nominal_fname));
-
- if (file_change != same_file) {
- cppReader_putCharQ (pfile, ' ');
- cppReader_putCharQ (pfile, file_change == enter_file ? '1' : '2');
- }
- /* Tell cc1 if following text comes from a system header file. */
- if (ip->system_header_p != '\0') {
- cppReader_putCharQ (pfile, ' ');
- cppReader_putCharQ (pfile, '3');
- }
-#ifndef NO_IMPLICIT_EXTERN_C
- /* Tell cc1plus if following text should be treated as C. */
- if (ip->system_header_p == (char) 2 && CPPOPTIONS (pfile)->cplusplus) {
- cppReader_putCharQ (pfile, ' ');
- cppReader_putCharQ (pfile, '4');
- }
-#endif
- cppReader_putCharQ (pfile, '\n');
- pfile->lineno = line;
-}
-
-
-/*
- * Parse a macro argument and append the info on PFILE's token_buffer.
- * REST_ARGS means to absorb the rest of the args.
- * Return nonzero to indicate a syntax error.
- */
-
-static enum cpp_token
-macarg (cppReader *pfile, int rest_args)
-{
- int paren = 0;
- enum cpp_token token;
- char save_put_out_comments = CPPOPTIONS (pfile)->put_out_comments;
- bool oldexpand = pfile->no_macro_expand;
- CPPOPTIONS (pfile)->put_out_comments = 1;
-
- /* Try to parse as much of the argument as exists at this
- input stack level. */
-
- pfile->no_macro_expand = TRUE;
-
- for (;;)
- {
- token = cppGetToken (pfile);
-
- switch (token)
- {
- case CPP_EOF:
- goto done;
- case CPP_POP:
- /* If we've hit end of file, it's an error (reported by caller).
- Ditto if it's the end of cpp_expand_to_buffer text.
- If we've hit end of macro, just continue. */
- if (!cppBuffer_isMacro (CPPBUFFER (pfile)))
- goto done;
- /*@switchbreak@*/ break;
- case CPP_LPAREN:
- paren++;
- /*@switchbreak@*/ break;
- case CPP_RPAREN:
- if (--paren < 0)
- goto found;
- /*@switchbreak@*/ break;
- case CPP_COMMA:
- /* if we've returned to lowest level and
- we aren't absorbing all args */
- if (paren == 0 && rest_args == 0)
- goto found;
- /*@switchbreak@*/ break;
- found:
- /* Remove ',' or ')' from argument buffer. */
- cppReader_adjustWritten (pfile, -1);
- goto done;
- default:
- ;
- }
- }
-
-done:
- CPPOPTIONS (pfile)->put_out_comments = save_put_out_comments;
- pfile->no_macro_expand = oldexpand;
-
- return token;
-}
-
-
-/* Turn newlines to spaces in the string of length LENGTH at START,
- except inside of string constants.
- The string is copied into itself with its beginning staying fixed. */
-
-static int
-change_newlines (char *start, int length)
-{
- register char *ibp;
- register char *obp;
- register char *limit;
- char c;
-
- ibp = start;
- limit = start + length;
- obp = start;
-
- while (ibp < limit) {
- *obp++ = c = *ibp++;
- switch (c) {
-
- case '\'':
- case '\"':
- /* Notice and skip strings, so that we don't delete newlines in them. */
- {
- char quotec = c;
- while (ibp < limit) {
- *obp++ = c = *ibp++;
- if (c == quotec)
- /*@innerbreak@*/ break;
- if (c == '\n' && quotec == '\'')
- /*@innerbreak@*/ break;
- }
- }
- /*@switchbreak@*/ break;
- }
- }
-
- return obp - start;
-}
-
-static /*@observer@*/ struct tm *
-timestamp (/*@returned@*/ cppReader *pfile)
-{
- if (pfile->timebuf == NULL)
- {
- time_t t = time ((time_t *) 0);
- pfile->timebuf = localtime (&t);
- }
-
- llassert (pfile->timebuf != NULL);
-
- return pfile->timebuf;
-}
-
-static ob_mstring monthnames[] = {
- "Jan", "Feb", "Mar", "Apr", "May", "Jun",
- "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
-} ;
-
-/*
- * expand things like __FILE__. Place the expansion into the output
- * buffer *without* rescanning.
- */
-
-static void
-special_symbol (hashNode hp, cppReader *pfile)
-{
- cstring buf = cstring_undefined;
- size_t len;
- int true_indepth;
- cppBuffer *ip;
- struct tm *timebuf;
-
- int paren = 0; /* For special `defined' keyword */
-
- for (ip = cppReader_getBuffer (pfile); ip != NULL; ip = cppBuffer_prevBuffer (ip))
- {
- if (ip == cppReader_nullBuffer (pfile))
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("cccp error: not in any file?!"));
- return; /* the show must go on */
- }
-
- if (ip != NULL && ip->fname != NULL)
- {
- break;
- }
- }
-
- switch (hp->type)
- {
- case T_FILE:
- case T_BASE_FILE:
- {
- char *string;
- if (hp->type == T_BASE_FILE)
- {
- while (cppBuffer_prevBuffer (ip) != cppReader_nullBuffer (pfile))
- {
- ip = cppBuffer_prevBuffer (ip);
- }
- }
-
- llassert (ip != NULL);
- string = cstring_toCharsSafe (ip->nominal_fname);
-
- if (string == NULL)
- {
- string = "";
- }
-
- cppReader_reserve (pfile, 3 + 4 * strlen (string));
- quote_string (pfile, string);
- return;
- }
-
- case T_INCLUDE_LEVEL:
- true_indepth = 0;
- ip = cppReader_getBuffer (pfile);
-
- for (; ip != cppReader_nullBuffer (pfile) && ip != NULL;
- ip = cppBuffer_prevBuffer (ip))
- {
- if (ip != NULL && ip->fname != NULL)
- {
- true_indepth++;
- }
- }
-
- buf = message ("%d", true_indepth - 1);
- break;
-
- case T_VERSION:
- buf = message ("\"%s\"", cstring_makeLiteralTemp (CPP_VERSION));
- break;
-
-#ifndef NO_BUILTIN_SIZE_TYPE
- case T_SIZE_TYPE:
- buf = cstring_makeLiteral (SIZE_TYPE);
- break;
-#endif
-
-#ifndef NO_BUILTIN_PTRDIFF_TYPE
- case T_PTRDIFF_TYPE:
- buf = cstring_makeLiteral (PTRDIFF_TYPE);
- break;
-#endif
-
- case T_WCHAR_TYPE:
- buf = cstring_makeLiteral (cppReader_wcharType (pfile));
- break;
-
- case T_USER_LABEL_PREFIX_TYPE:
- buf = cstring_makeLiteral (USER_LABEL_PREFIX);
- break;
-
- case T_REGISTER_PREFIX_TYPE:
- buf = cstring_makeLiteral (REGISTER_PREFIX);
- break;
-
- case T_CONST:
- buf = message ("%d", hp->value.ival);
- break;
-
- case T_SPECLINE:
- {
- if (ip != NULL)
- {
- int line = ip->lineno;
- int col = ip->colno;
-
- llassert (ip->cur != NULL);
- adjust_position (cppLineBase (ip), ip->cur, &line, &col);
-
- buf = message ("%d", (int) line);
- }
- else
- {
- BADBRANCH;
- }
- }
- break;
-
- case T_DATE:
- case T_TIME:
- {
- char *sbuf = (char *) dmalloc (20);
- timebuf = timestamp (pfile);
- if (hp->type == T_DATE)
- {
- sprintf (sbuf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],
- timebuf->tm_mday, timebuf->tm_year + 1900);
- }
- else
- {
- sprintf (sbuf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,
- timebuf->tm_sec);
- }
-
- buf = cstring_fromCharsNew (sbuf);
- sfree (sbuf);
- break;
- }
-
- case T_SPEC_DEFINED:
- buf = cstring_makeLiteral (" 0 "); /* Assume symbol is not defined */
- ip = cppReader_getBuffer (pfile);
-
- llassert (ip->cur != NULL);
- SKIP_WHITE_SPACE (ip->cur);
-
- if (*ip->cur == '(')
- {
- paren++;
- ip->cur++; /* Skip over the paren */
- SKIP_WHITE_SPACE (ip->cur);
- }
-
- if (!is_idstart[(int) *ip->cur])
- goto oops;
- if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"'))
- goto oops;
-
- if ((hp = cppReader_lookup (ip->cur, -1, -1)) != 0)
- {
- cstring_free (buf);
- buf = cstring_makeLiteral (" 1 ");
- }
-
- while (is_idchar[(int) *ip->cur])
- {
- ++ip->cur;
- }
-
- SKIP_WHITE_SPACE (ip->cur);
-
- if (paren != 0)
- {
- if (*ip->cur != ')')
- goto oops;
- ++ip->cur;
- }
- break;
-
- oops:
-
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`defined' without an identifier"));
- break;
-
- default:
- cpp_setLocation (pfile);
- llfatalerror (message ("Pre-processing error: invalid special hash type"));
- }
-
- len = size_fromInt (cstring_length (buf));
-
- cppReader_reserve (pfile, len + 1);
- cppReader_putStrN (pfile, cstring_toCharsSafe (buf), len);
- cppReader_nullTerminateQ (pfile);
-
- cstring_free (buf);
- return;
-}
-
-/* Write out a #define command for the special named MACRO_NAME
- to PFILE's token_buffer. */
-
-static void
-dump_special_to_buffer (cppReader *pfile, char *macro_name)
-{
- static char define_directive[] = "#define ";
- size_t macro_name_length = strlen (macro_name);
- output_line_command (pfile, 0, same_file);
- cppReader_reserve (pfile, sizeof(define_directive) + macro_name_length);
- cppReader_putStrN (pfile, define_directive, sizeof(define_directive)-1);
- cppReader_putStrN (pfile, macro_name, macro_name_length);
- cppReader_putCharQ (pfile, ' ');
- cpp_expand_to_buffer (pfile, macro_name, macro_name_length);
- cppReader_putChar (pfile, '\n');
-}
-
-/* Initialize the built-in macros. */
-
-static void
-cppReader_installBuiltin (/*@observer@*/ char *name, ctype ctyp,
- int len, enum node_type type,
- int ivalue, /*@null@*/ /*@only@*/ char *value,
- int hash)
-{
- cstring sname = cstring_fromCharsNew (name);
-
- llassert (usymtab_inGlobalScope ());
-
- /*
- ** Be careful here: this is done before the ctype table has
- ** been initialized.
- */
-
- if (!usymtab_exists (sname))
- {
- uentry ue = uentry_makeConstant (sname, ctyp, fileloc_createBuiltin ());
-
- if (ctype_equal (ctyp, ctype_string))
- {
- qualList ql = qualList_new ();
- ql = qualList_add (ql, qual_createObserver ());
- uentry_reflectQualifiers (ue, ql);
- qualList_free (ql);
- }
-
- usymtab_addGlobalEntry (ue);
- }
- else
- {
- ;
- }
-
- (void) cppReader_install (name, len, type, ivalue, value, hash);
- cstring_free (sname);
-}
-
-static void
-cppReader_installBuiltinType (/*@observer@*/ char *name, ctype ctyp,
- int len, enum node_type type,
- int ivalue,
- /*@only@*/ /*@null@*/ char *value, int hash)
-{
- cstring sname = cstring_fromChars (name);
- /* evs 2000 07 10 - removed a memory leak, detected by lclint */
-
- llassert (usymtab_inGlobalScope ());
-
- if (!usymtab_existsTypeEither (sname))
- {
- uentry ue = uentry_makeDatatype (sname, ctyp,
- NO, NO,
- fileloc_createBuiltin ());
- llassert (!usymtab_existsEither (sname));
- usymtab_addGlobalEntry (ue);
- }
-
- (void) cppReader_install (name, len, type, ivalue, value, hash);
-}
-
-static void
-initialize_builtins (cppReader *pfile)
-{
- cppReader_installBuiltin ("__LINE__", ctype_int, -1, T_SPECLINE, 0, NULL, -1);
- cppReader_installBuiltin ("__DATE__", ctype_string, -1, T_DATE, 0, NULL, -1);
- cppReader_installBuiltin ("__FILE__", ctype_string, -1, T_FILE, 0, NULL, -1);
- cppReader_installBuiltin ("__BASE_FILE__", ctype_string, -1, T_BASE_FILE, 0, NULL, -1);
- cppReader_installBuiltin ("__INCLUDE_LEVEL__", ctype_int, -1, T_INCLUDE_LEVEL, 0, NULL, -1);
- cppReader_installBuiltin ("__VERSION__", ctype_string, -1, T_VERSION, 0, NULL, -1);
-#ifndef NO_BUILTIN_SIZE_TYPE
- cppReader_installBuiltinType ("__SIZE_TYPE__", ctype_anyintegral, -1, T_SIZE_TYPE, 0, NULL, -1);
-#endif
-#ifndef NO_BUILTIN_PTRDIFF_TYPE
- cppReader_installBuiltinType ("__PTRDIFF_TYPE__", ctype_anyintegral, -1, T_PTRDIFF_TYPE, 0, NULL, -1);
-#endif
- cppReader_installBuiltinType ("__WCHAR_TYPE__", ctype_anyintegral, -1, T_WCHAR_TYPE, 0, NULL, -1);
- cppReader_installBuiltin ("__USER_LABEL_PREFIX__", ctype_string, -1, T_USER_LABEL_PREFIX_TYPE, 0, NULL, -1);
- cppReader_installBuiltin ("__REGISTER_PREFIX__", ctype_string, -1, T_REGISTER_PREFIX_TYPE, 0, NULL, -1);
- cppReader_installBuiltin ("__TIME__", ctype_string, -1, T_TIME, 0, NULL, -1);
-
- /*
- ** No, don't define __STDC__
- **
-
- if (!cppReader_isTraditional (pfile))
- {
- cppReader_installBuiltin ("__STDC__", ctype_int, -1, T_CONST, STDC_VALUE, NULL, -1);
- }
-
- **
- */
-
-# ifdef WIN32
- cppReader_installBuiltin ("_WIN32", ctype_int, -1, T_CONST, STDC_VALUE, NULL, -1);
-# endif
-
- /*
- ** This is supplied using a -D by the compiler driver
- ** so that it is present only when truly compiling with GNU C.
- */
-
- /* cppReader_install ("__GNUC__", -1, T_CONST, 2, 0, -1); */
-
- cppReader_installBuiltin ("__LCLINT__", ctype_int, -1, T_CONST, 2, NULL, -1);
-
- if (CPPOPTIONS (pfile)->debug_output)
- {
- dump_special_to_buffer (pfile, "__BASE_FILE__");
- dump_special_to_buffer (pfile, "__VERSION__");
-#ifndef NO_BUILTIN_SIZE_TYPE
- dump_special_to_buffer (pfile, "__SIZE_TYPE__");
-#endif
-#ifndef NO_BUILTIN_PTRDIFF_TYPE
- dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__");
-#endif
- dump_special_to_buffer (pfile, "__WCHAR_TYPE__");
- dump_special_to_buffer (pfile, "__DATE__");
- dump_special_to_buffer (pfile, "__TIME__");
- if (!cppReader_isTraditional (pfile))
- dump_special_to_buffer (pfile, "__STDC__");
- }
-}
-
-
-/* Return 1 iff a token ending in C1 followed directly by a token C2
- could cause mis-tokenization. */
-
-static bool
-unsafe_chars (char c1, char c2)
-{
- switch (c1)
- {
- case '+': case '-':
- if (c2 == c1 || c2 == '=')
- return 1;
- goto letter;
- case '.':
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- case 'e': case 'E': case 'p': case 'P':
- if (c2 == '-' || c2 == '+')
- return 1; /* could extend a pre-processing number */
- goto letter;
- case 'L':
- if (c2 == '\'' || c2 == '\"')
- return 1; /* Could turn into L"xxx" or L'xxx'. */
- goto letter;
- letter:
- case '_':
- case 'a': case 'b': case 'c': case 'd': case 'f':
- case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
- case 'm': case 'n': case 'o': case 'q': case 'r':
- case 's': case 't': case 'u': case 'v': case 'w': case 'x':
- case 'y': case 'z':
- case 'A': case 'B': case 'C': case 'D': case 'F':
- case 'G': case 'H': case 'I': case 'J': case 'K':
- case 'M': case 'N': case 'O': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- /* We're in the middle of either a name or a pre-processing number. */
- return (is_idchar[(int) c2] || c2 == '.');
- case '<': case '>': case '!': case '%': case '#': case ':':
- case '^': case '&': case '|': case '*': case '/': case '=':
- return (c2 == c1 || c2 == '=');
- }
- return 0;
-}
-
-/* Expand a macro call.
- HP points to the symbol that is the macro being called.
- Put the result of expansion onto the input stack
- so that subsequent input by our caller will use it.
-
- If macro wants arguments, caller has already verified that
- an argument list follows; arguments come from the input stack. */
-
-static void
-macroexpand (cppReader *pfile, /*@dependent@*/ hashNode hp)
-{
- int nargs;
- DEFINITION *defn = hp->value.defn;
- char *xbuf;
- char *oxbuf = NULL;
- int start_line;
- int start_column;
- size_t xbuf_len;
- size_t old_written = cppReader_getWritten (pfile);
- int rest_args;
- int rest_zero = 0;
- int i;
- struct argdata *args = NULL;
-
- pfile->output_escapes++;
-
- cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile), &start_line, &start_column);
-
- nargs = defn->nargs;
-
- if (nargs >= 0)
- {
- enum cpp_token token = CPP_EOF;
-
- args = (struct argdata *) dmalloc ((nargs + 1) * sizeof (*args));
-
- for (i = 0; i < nargs; i++)
- {
- args[i].expanded = 0;
- args[i].raw = 0;
- args[i].raw_length = 0;
- args[i].expand_length = args[i].stringified_length = -1;
- args[i].use_count = 0;
- }
-
- /*
- ** Parse all the macro args that are supplied. I counts them.
- ** The first NARGS args are stored in ARGS.
- ** The rest are discarded. If rest_args is set then we assume
- ** macarg absorbed the rest of the args.
- */
-
- i = 0;
- rest_args = 0;
-
- cppReader_forward (pfile, 1); /* Discard the open-parenthesis before the first arg. */
- do
- {
- if (rest_args != 0)
- {
- continue;
- }
-
- if (i < nargs || (nargs == 0 && i == 0))
- {
- /* if we are working on last arg which absorbs rest of args... */
- if (i == nargs - 1 && defn->rest_args)
- {
- rest_args = 1;
- }
-
- args[i].raw = size_toLong (cppReader_getWritten (pfile));
- token = macarg (pfile, rest_args);
- args[i].raw_length = cppReader_getWritten (pfile) - args[i].raw;
- args[i].newlines = FALSE; /* FIXME */
- }
- else
- {
- token = macarg (pfile, 0);
- }
-
- if (token == CPP_EOF || token == CPP_POP)
- {
- cppReader_errorWithLine (pfile, start_line, start_column,
- cstring_fromCharsNew ("unterminated macro call"));
- sfree (args);
- return;
- }
- i++;
- } while (token == CPP_COMMA);
-
- /* If we got one arg but it was just whitespace, call that 0 args. */
- if (i == 1)
- {
- char *bp;
- char *lim;
-
- assertSet (args);
-
- bp = ARG_BASE + args[0].raw;
- lim = bp + args[0].raw_length;
-
- /* cpp.texi says for foo ( ) we provide one argument.
- However, if foo wants just 0 arguments, treat this as 0. */
-
- if (nargs == 0)
- {
- while (bp != lim && is_space[(int) *bp])
- {
- bp++;
- }
- }
-
- if (bp == lim)
- i = 0;
- }
-
- /* Don't output an error message if we have already output one for
- a parse error above. */
- rest_zero = 0;
-
- if (nargs == 0 && i > 0)
- {
- cppReader_error (pfile,
- message ("arguments given to macro `%s'", hp->name));
- }
- else if (i < nargs)
- {
- /* traditional C allows foo() if foo wants one argument. */
- if (nargs == 1 && i == 0 && cppReader_isTraditional (pfile))
- {
- ;
- }
- /* the rest args token is allowed to absorb 0 tokens */
- else if (i == nargs - 1 && defn->rest_args)
- rest_zero = 1;
- else if (i == 0)
- cppReader_error (pfile,
- message ("macro `%s' used without args", hp->name));
- else if (i == 1)
- cppReader_error (pfile,
- message ("macro `%s' used with just one arg", hp->name));
- else
- {
- cppReader_error (pfile,
- message ("macro `%s' used with only %d args",
- hp->name, i));
- }
- }
- else if (i > nargs)
- {
- cppReader_error (pfile,
- message ("macro `%s' used with too many (%d) args", hp->name, i));
- }
- else
- {
- ;
- }
- }
-
- /* If macro wants zero args, we parsed the arglist for checking only.
- Read directly from the macro definition. */
-
- if (nargs <= 0)
- {
- xbuf = defn->expansion;
- xbuf_len = defn->length;
- }
- else
- {
- char *exp = defn->expansion;
- int offset; /* offset in expansion,
- copied a piece at a time */
- size_t totlen; /* total amount of exp buffer filled so far */
-
- register struct reflist *ap, *last_ap;
-
- assertSet (args); /* args is defined since the nargs > 0 path was taken */
-
- /* Macro really takes args. Compute the expansion of this call. */
-
- /* Compute length in characters of the macro's expansion.
- Also count number of times each arg is used. */
- xbuf_len = defn->length;
-
- llassert (args != NULL);
-
- for (ap = defn->pattern; ap != NULL; ap = ap->next)
- {
- if (ap->stringify)
- {
- struct argdata *arg = &args[ap->argno];
-
- /* Stringify it it hasn't already been */
- assertSet (arg);
-
- if (arg->stringified_length < 0)
- {
- int arglen = arg->raw_length;
- bool escaped = FALSE;
- char in_string = '\0';
- char c;
-
- /* Initially need_space is -1. Otherwise, 1 means the
- previous character was a space, but we suppressed it;
- 0 means the previous character was a non-space. */
- int need_space = -1;
-
- i = 0;
- arg->stringified = cppReader_getWritten (pfile);
- if (!cppReader_isTraditional (pfile))
- cppReader_putChar (pfile, '\"'); /* insert beginning quote */
- for (; i < arglen; i++)
- {
- c = (ARG_BASE + arg->raw)[i];
-
- if (in_string == '\0')
- {
- /* Internal sequences of whitespace are replaced by
- one space except within an string or char token.*/
- if (is_space[(int) c])
- {
- if (cppReader_getWritten (pfile) > arg->stringified
- && (cppReader_getPWritten (pfile))[-1] == '@')
- {
- /* "@ " escape markers are removed */
- cppReader_adjustWritten (pfile, -1);
- /*@innercontinue@*/ continue;
- }
- if (need_space == 0)
- need_space = 1;
- /*@innercontinue@*/ continue;
- }
- else if (need_space > 0)
- cppReader_putChar (pfile, ' ');
- else
- {
- ;
- }
-
- need_space = 0;
- }
-
- if (escaped)
- escaped = 0;
- else
- {
- if (c == '\\')
- escaped = 1;
-
- if (in_string != '\0')
- {
- if (c == in_string)
- in_string = '\0';
- }
- else if (c == '\"' || c == '\'')
- {
- in_string = c;
- }
- else
- {
- ;
- }
- }
-
- /* Escape these chars */
- if (c == '\"' || (in_string != '\0' && c == '\\'))
- cppReader_putChar (pfile, '\\');
- if (isprint (c))
- cppReader_putChar (pfile, c);
- else
- {
- cppReader_reserve (pfile, 4);
- sprintf (cppReader_getPWritten (pfile), "\\%03o",
- (unsigned int) c);
- cppReader_adjustWritten (pfile, 4);
- }
- }
- if (!cppReader_isTraditional (pfile))
- cppReader_putChar (pfile, '\"'); /* insert ending quote */
- arg->stringified_length
- = size_toInt (cppReader_getWritten (pfile) - arg->stringified);
- }
-
- xbuf_len += args[ap->argno].stringified_length;
- }
- else if (ap->raw_before || ap->raw_after || cppReader_isTraditional (pfile))
- {
- /* Add 4 for two newline-space markers to prevent
- token concatenation. */
- assertSet (args); /*@i534 shouldn't need this */
- xbuf_len += args[ap->argno].raw_length + 4;
- }
- else
- {
- /* We have an ordinary (expanded) occurrence of the arg.
- So compute its expansion, if we have not already. */
-
- assertSet (args); /*@i534 shouldn't need this */
-
- if (args[ap->argno].expand_length < 0)
- {
- args[ap->argno].expanded = cppReader_getWritten (pfile);
- cpp_expand_to_buffer (pfile,
- ARG_BASE + args[ap->argno].raw,
- size_fromInt (args[ap->argno].raw_length));
-
- args[ap->argno].expand_length
- = size_toInt (cppReader_getWritten (pfile) - args[ap->argno].expanded);
- }
-
- /* Add 4 for two newline-space markers to prevent
- token concatenation. */
- xbuf_len += args[ap->argno].expand_length + 4;
- }
- if (args[ap->argno].use_count < 10)
- args[ap->argno].use_count++;
- }
-
- xbuf = (char *) dmalloc (xbuf_len + 1);
- oxbuf = xbuf;
-
- /*
- ** Generate in XBUF the complete expansion
- ** with arguments substituted in.
- ** TOTLEN is the total size generated so far.
- ** OFFSET is the index in the definition
- ** of where we are copying from.
- */
-
- offset = 0;
- totlen = 0;
-
- for (last_ap = NULL, ap = defn->pattern; ap != NULL;
- last_ap = ap, ap = ap->next)
- {
- register struct argdata *arg = &args[ap->argno];
- size_t count_before = totlen;
-
- /* Add chars to XBUF. */
- for (i = 0; i < ap->nchars; i++, offset++)
- {
- xbuf[totlen++] = exp[offset];
- }
-
- /* If followed by an empty rest arg with concatenation,
- delete the last run of nonwhite chars. */
- if (rest_zero && totlen > count_before
- && ((ap->rest_args && ap->raw_before)
- || (last_ap != NULL && last_ap->rest_args
- && last_ap->raw_after)))
- {
- /* Delete final whitespace. */
- while (totlen > count_before && is_space[(int) xbuf[totlen - 1]])
- {
- totlen--;
- }
-
- /* Delete the nonwhites before them. */
- while (totlen > count_before && ! is_space[(int) xbuf[totlen - 1]])
- {
- totlen--;
- }
- }
-
- if (ap->stringify != 0)
- {
- assertSet(arg);
- memcpy (xbuf + totlen,
- ARG_BASE + arg->stringified,
- size_fromInt (arg->stringified_length));
- totlen += arg->stringified_length;
- }
- else if (ap->raw_before || ap->raw_after || cppReader_isTraditional (pfile))
- {
- char *p1;
- char *l1;
-
- assertSet (arg);
-
- p1 = ARG_BASE + arg->raw;
- l1 = p1 + arg->raw_length;
-
- if (ap->raw_before)
- {
- while (p1 != l1 && is_space[(int) *p1])
- {
- p1++;
- }
-
- while (p1 != l1 && is_idchar[(int) *p1])
- {
- xbuf[totlen++] = *p1++;
- }
-
- /* Delete any no-reexpansion marker that follows
- an identifier at the beginning of the argument
- if the argument is concatenated with what precedes it. */
- if (p1[0] == '@' && p1[1] == '-')
- p1 += 2;
- }
- if (ap->raw_after)
- {
- /* Arg is concatenated after: delete trailing whitespace,
- whitespace markers, and no-reexpansion markers. */
- while (p1 != l1)
- {
- if (is_space[(int) l1[-1]]) l1--;
- else if (l1[-1] == '-')
- {
- char *p2 = l1 - 1;
- /* If a `-' is preceded by an odd number of newlines then it
- and the last newline are a no-reexpansion marker. */
- while (p2 != p1 && p2[-1] == '\n')
- {
- p2--;
- }
-
- if (((l1 - 1 - p2) & 1) != 0)
- {
- l1 -= 2;
- }
- else
- {
- /*@innerbreak@*/ break;
- }
- }
- else
- {
- /*@innerbreak@*/ break;
- }
- }
- }
-
- memcpy (xbuf + totlen, p1, size_fromInt (l1 - p1));
- totlen += l1 - p1;
- }
- else
- {
- char *expanded;
-
- assertSet (arg);
- expanded = ARG_BASE + arg->expanded;
-
- if (!ap->raw_before && totlen > 0
- && (arg->expand_length != 0)
- && !cppReader_isTraditional(pfile)
- && unsafe_chars (xbuf[totlen-1], expanded[0]))
- {
- xbuf[totlen++] = '@';
- xbuf[totlen++] = ' ';
- }
-
- memcpy (xbuf + totlen, expanded,
- size_fromInt (arg->expand_length));
- totlen += arg->expand_length;
-
- if (!ap->raw_after && totlen > 0
- && offset < size_toInt (defn->length)
- && !cppReader_isTraditional(pfile)
- && unsafe_chars (xbuf[totlen-1], exp[offset]))
- {
- xbuf[totlen++] = '@';
- xbuf[totlen++] = ' ';
- }
-
- /* If a macro argument with newlines is used multiple times,
- then only expand the newlines once. This avoids creating
- output lines which don't correspond to any input line,
- which confuses gdb and gcov. */
- if (arg->use_count > 1 && arg->newlines > 0)
- {
- /* Don't bother doing change_newlines for subsequent
- uses of arg. */
- arg->use_count = 1;
- arg->expand_length
- = change_newlines (expanded, arg->expand_length);
- }
- }
-
- if (totlen > xbuf_len)
- abort ();
- }
-
- /* if there is anything left of the definition
- after handling the arg list, copy that in too. */
-
- for (i = offset; i < size_toInt (defn->length); i++)
- {
- /* if we've reached the end of the macro */
- if (exp[i] == ')')
- rest_zero = 0;
- if (! (rest_zero && last_ap != NULL && last_ap->rest_args
- && last_ap->raw_after))
- xbuf[totlen++] = exp[i];
- }
-
- xbuf[totlen] = '\0';
- xbuf_len = totlen;
- }
-
- pfile->output_escapes--;
-
- /* Now put the expansion on the input stack
- so our caller will commence reading from it. */
- push_macro_expansion (pfile, xbuf, xbuf_len, hp);
- cppReader_getBuffer (pfile)->has_escapes = 1;
-
- /* Pop the space we've used in the token_buffer for argument expansion. */
- cppReader_setWritten (pfile, old_written);
-
- /* Recursive macro use sometimes works traditionally.
- #define foo(x,y) bar (x (y,0), y)
- foo (foo, baz) */
-
- if (!cppReader_isTraditional (pfile))
- hp->type = T_DISABLED;
-
- sfree (args);
-}
-
-static void
-push_macro_expansion (cppReader *pfile, char *xbuf, size_t xbuf_len,
- /*@dependent@*/ hashNode hp)
-{
- cppBuffer *mbuf = cppReader_pushBuffer (pfile, xbuf, xbuf_len);
-
- if (mbuf == NULL)
- {
- return;
- }
-
- mbuf->cleanup = cppReader_macroCleanup;
-
- llassert (mbuf->hnode == NULL);
- mbuf->hnode = hp;
-
- /* The first chars of the expansion should be a "@ " added by
- collect_expansion. This is to prevent accidental token-pasting
- between the text preceding the macro invocation, and the macro
- expansion text.
-
- We would like to avoid adding unneeded spaces (for the sake of
- tools that use cpp, such as imake). In some common cases we can
- tell that it is safe to omit the space.
-
- The character before the macro invocation cannot have been an
- idchar (or else it would have been pasted with the idchars of
- the macro name). Therefore, if the first non-space character
- of the expansion is an idchar, we do not need the extra space
- to prevent token pasting.
-
- Also, we don't need the extra space if the first char is '(',
- or some other (less common) characters. */
-
- if (xbuf[0] == '@' && xbuf[1] == ' '
- && (is_idchar[(int) xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\''
- || xbuf[2] == '\"'))
- {
- llassert (mbuf->cur != NULL);
- mbuf->cur += 2;
- }
-}
-
-
-/* Like cppGetToken, except that it does not read past end-of-line.
- Also, horizontal space is skipped, and macros are popped. */
-
-static enum cpp_token
-get_directive_token (cppReader *pfile)
-{
- for (;;)
- {
- size_t old_written = cppReader_getWritten (pfile);
- enum cpp_token token;
- cppSkipHspace (pfile);
- if (cppReader_peekC (pfile) == '\n')
- {
- return CPP_VSPACE;
- }
-
- token = cppGetToken (pfile);
-
- switch (token)
- {
- case CPP_POP:
- if (!cppBuffer_isMacro (cppReader_getBuffer (pfile)))
- return token;
- /*@fallthrough@*/
- case CPP_HSPACE:
- case CPP_COMMENT:
- cppReader_setWritten (pfile, old_written);
- /*@switchbreak@*/ break;
- default:
- return token;
- }
- }
-}
-
-
-/* Handle #include and #import.
- This function expects to see "fname" or <fname> on the input.
-
- The input is normally in part of the output_buffer following
- cppReader_getWritten, and will get overwritten by output_line_command.
- I.e. in input file specification has been popped by cppReader_handleDirective.
- This is safe. */
-
-static int
-do_include (cppReader *pfile, struct directive *keyword,
- /*@unused@*/ char *unused1, /*@unused@*/ char *unused2)
-{
- bool skip_dirs = (keyword->type == T_INCLUDE_NEXT);
- cstring fname;
- char *fbeg, *fend; /* Beginning and end of fname */
- enum cpp_token token;
-
- /* Chain of dirs to search */
- struct file_name_list *search_start = CPPOPTIONS (pfile)->include;
- struct file_name_list dsp[1]; /* First in chain, if #include "..." */
- struct file_name_list *searchptr = NULL;
- size_t old_written = cppReader_getWritten (pfile);
-
- int flen;
-
- int f; /* file number */
- int angle_brackets = 0; /* 0 for "...", 1 for <...> */
- f= -1; /* JF we iz paranoid! */
-
- pfile->parsing_include_directive++;
- token = get_directive_token (pfile);
- pfile->parsing_include_directive--;
-
- if (token == CPP_STRING)
- {
- /* FIXME - check no trailing garbage */
- fbeg = pfile->token_buffer + old_written + 1;
- fend = cppReader_getPWritten (pfile) - 1;
- if (fbeg[-1] == '<')
- {
- angle_brackets = 1;
- /* If -I-, start with the first -I dir after the -I-. */
- if (CPPOPTIONS (pfile)->first_bracket_include != NULL)
- search_start = CPPOPTIONS (pfile)->first_bracket_include;
- }
- /* If -I- was specified, don't search current dir, only spec'd ones. */
- else if (!CPPOPTIONS (pfile)->ignore_srcdir)
- {
- cppBuffer *fp = CPPBUFFER (pfile);
- /* We have "filename". Figure out directory this source
- file is coming from and put it on the front of the list. */
-
- for ( ; fp != cppReader_nullBuffer (pfile); fp = cppBuffer_prevBuffer (fp))
- {
- int n;
- char *ep,*nam;
-
- llassert (fp != NULL);
-
- nam = NULL;
-
- if (cstring_isDefined (fp->nominal_fname))
- {
- nam = cstring_toCharsSafe (fp->nominal_fname);
-
- /* Found a named file. Figure out dir of the file,
- and put it in front of the search list. */
- dsp[0].next = search_start;
- search_start = dsp;
-
-#ifndef VMS
- ep = strrchr (nam, CONNECTCHAR);
-#else /* VMS */
- ep = strrchr (nam, ']');
- if (ep == NULL) ep = strrchr (nam, '>');
- if (ep == NULL) ep = strrchr (nam, ':');
- if (ep != NULL) ep++;
-#endif /* VMS */
- if (ep != NULL)
- {
- char save;
-
- n = ep - nam;
- save = nam[n];
- nam[n] = '\0';
-
- /*@-onlytrans@*/ /* This looks like a memory leak... */
- dsp[0].fname = cstring_fromCharsNew (nam); /* evs 2000-07-20: was fromChars */
- /*@=onlytrans@*/
- nam[n] = save;
-
- if (n + INCLUDE_LEN_FUDGE > pfile->max_include_len)
- pfile->max_include_len = n + INCLUDE_LEN_FUDGE;
- }
- else
- {
- dsp[0].fname = cstring_undefined; /* Current directory */
- }
-
- dsp[0].got_name_map = 0;
- break;
- }
- }
- }
- else
- {
- ;
- }
- }
-#ifdef VMS
- else if (token == CPP_NAME)
- {
- /*
- * Support '#include xyz' like VAX-C to allow for easy use of all the
- * decwindow include files. It defaults to '#include <xyz.h>' (so the
- * code from case '<' is repeated here) and generates a warning.
- */
- cppReader_warning (pfile,
- "VAX-C-style include specification found, use '#include <filename.h>' !");
- angle_brackets = 1;
- /* If -I-, start with the first -I dir after the -I-. */
- if (CPPOPTIONS (pfile)->first_bracket_include)
- search_start = CPPOPTIONS (pfile)->first_bracket_include;
- fbeg = pfile->token_buffer + old_written;
- fend = cppReader_getPWritten (pfile);
- }
-#endif
- else
- {
- cppReader_error (pfile,
- message ("Preprocessor command #%s expects \"FILENAME\" or <FILENAME>",
- keyword->name));
-
- cppReader_setWritten (pfile, old_written);
- cppReader_skipRestOfLine (pfile);
- return 0;
- }
-
- *fend = 0;
-
- token = get_directive_token (pfile);
- if (token != CPP_VSPACE)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("Junk at end of #include"));
-
- while (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)
- {
- token = get_directive_token (pfile);
- }
- }
-
- /*
- ** For #include_next, skip in the search path
- ** past the dir in which the containing file was found.
- */
-
- if (skip_dirs)
- {
- cppBuffer *fp = CPPBUFFER (pfile);
-
- for (; fp != cppReader_nullBuffer (pfile); fp = cppBuffer_prevBuffer (fp))
- {
- llassert (fp != NULL);
-
- if (fp->fname != NULL)
- {
- /* fp->dir is null if the containing file was specified with
- an absolute file name. In that case, don't skip anything. */
- if (fp->dir == SELF_DIR_DUMMY)
- {
- search_start = CPPOPTIONS (pfile)->include;
- }
- else if (fp->dir != NULL)
- {
- search_start = fp->dir->next;
- }
- else
- {
- ;
- }
-
- break;
- }
- }
- }
-
- cppReader_setWritten (pfile, old_written);
-
- flen = fend - fbeg;
-
- DPRINTF (("fbeg: %s", fbeg));
-
- if (flen == 0)
- {
- cppReader_error (pfile,
- message ("Empty file name in #%s", keyword->name));
- return 0;
- }
-
- /*
- ** Allocate this permanently, because it gets stored in the definitions
- ** of macros.
- */
-
- fname = cstring_undefined;
-
- /* + 2 above for slash and terminating null. */
- /* + 2 added for '.h' on VMS (to support '#include filename') */
-
- /* If specified file name is absolute, just open it. */
-
- if (osd_isConnectChar (*fbeg)
-# if defined (WIN32) || defined (OS2)
- || (*(fbeg + 1) == ':')
-# endif
- )
- {
- fname = cstring_copyLength (fbeg, flen);
-
- if (redundant_include_p (pfile, fname))
- {
- cstring_free (fname);
- return 0;
- }
-
- f = open_include_file (pfile, fname, NULL);
-
- if (f == IMPORT_FOUND)
- {
- return 0; /* Already included this file */
- }
- }
- else
- {
- /* Search directory path, trying to open the file.
- Copy each filename tried into FNAME. */
-
- for (searchptr = search_start; searchptr != NULL;
- searchptr = searchptr->next)
- {
- if (!cstring_isEmpty (searchptr->fname))
- {
- /* The empty string in a search path is ignored.
- This makes it possible to turn off entirely
- a standard piece of the list. */
- if (cstring_isEmpty (searchptr->fname))
- continue;
-
- fname = cstring_copy (searchptr->fname);
- fname = cstring_appendChar (fname, CONNECTCHAR);
- DPRINTF (("Here: %s", fname));
- }
- else
- {
- ;
- }
-
- fname = cstring_concatLength (fname, fbeg, flen);
-
- DPRINTF (("fname: %s", fname));
-
- /* Win32 directory fix from Kay Buschner. */
-#if defined (WIN32) || defined (OS2)
- /* Fix all unixdir slashes to win dir slashes */
- if (searchptr->fname && (searchptr->fname[0] != 0))
- {
- cstring_replaceAll (fname, '/', '\\');
- }
-#endif /* WIN32 */
-
-#ifdef VMS
- /* Change this 1/2 Unix 1/2 VMS file specification into a
- full VMS file specification */
- if (searchptr->fname && (searchptr->fname[0] != 0)) {
- /* Fix up the filename */
- hack_vms_include_specification (fname);
- } else {
- /* This is a normal VMS filespec, so use it unchanged. */
- strncpy (fname, fbeg, flen);
- fname[flen] = 0;
- /* if it's '#include filename', add the missing .h */
- if (strchr (fname,'.') == NULL) {
- strcat (fname, ".h");
- }
- }
-#endif /* VMS */
- /* ??? There are currently 3 separate mechanisms for avoiding processing
- of redundant include files: #import, #pragma once, and
- redundant_include_p. It would be nice if they were unified. */
-
- if (redundant_include_p (pfile, fname))
- {
- cstring_free (fname);
- return 0;
- }
-
- DPRINTF (("Trying: %s", fname));
-
- f = open_include_file (pfile, fname, searchptr);
-
- if (f == IMPORT_FOUND)
- {
- return 0; /* Already included this file */
- }
-#ifdef EACCES
- else if (f == IMPORT_NOT_FOUND && errno == EACCES)
- {
- cppReader_warning (pfile,
- message ("Header file %s exists, but is not readable", fname));
- }
-#endif
-
- if (f >= 0)
- {
- break;
- }
- }
- }
-
- if (f < 0)
- {
- /* A file that was not found. */
- fname = cstring_copyLength (fbeg, flen);
-
- if (search_start != NULL)
- {
- cppReader_error (pfile,
- message ("Cannot find include file %s on search path: %x",
- fname,
- searchPath_unparse (search_start)));
- }
- else
- {
- cppReader_error (pfile,
- message ("No include path in which to find %s", fname));
- }
- }
- else {
- /*
- ** Check to see if this include file is a once-only include file.
- ** If so, give up.
- */
-
- struct file_name_list *ptr;
-
- for (ptr = pfile->all_include_files; ptr != NULL; ptr = ptr->next)
- {
- if (cstring_equal (ptr->fname, fname))
- {
- /* This file was included before. */
- break;
- }
- }
-
- if (ptr == NULL)
- {
- /* This is the first time for this file. */
- /* Add it to list of files included. */
-
- ptr = (struct file_name_list *) dmalloc (sizeof (*ptr));
- ptr->control_macro = NULL;
- ptr->c_system_include_path = NULL;
- ptr->next = pfile->all_include_files;
- ptr->fname = fname;
- ptr->got_name_map = NULL;
-
- DPRINTF (("Including file: %s", fname));
- pfile->all_include_files = ptr;
- assertSet (pfile->all_include_files);
- }
-
- if (angle_brackets != 0)
- {
- pfile->system_include_depth++;
- }
-
- /* Actually process the file */
- if (cppReader_pushBuffer (pfile, NULL, 0) == NULL)
- {
- cstring_free (fname);
- return 0;
- }
-
- if (finclude (pfile, f, fname, is_system_include (pfile, fname),
- searchptr != dsp ? searchptr : SELF_DIR_DUMMY))
- {
- output_line_command (pfile, 0, enter_file);
- pfile->only_seen_white = 2;
- }
-
- if (angle_brackets)
- {
- pfile->system_include_depth--;
- }
- /*@-branchstate@*/
- } /*@=branchstate@*/
-
- return 0;
-}
-
-/* Return nonzero if there is no need to include file NAME
- because it has already been included and it contains a conditional
- to make a repeated include do nothing. */
-
-static bool
-redundant_include_p (cppReader *pfile, cstring name)
-{
- struct file_name_list *l = pfile->all_include_files;
-
- for (; l != NULL; l = l->next)
- {
- if (cstring_equal (name, l->fname)
- && (l->control_macro != NULL)
- && (cppReader_lookup (l->control_macro, -1, -1) != NULL))
- {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/* Return nonzero if the given FILENAME is an absolute pathname which
- designates a file within one of the known "system" include file
- directories. We assume here that if the given FILENAME looks like
- it is the name of a file which resides either directly in a "system"
- include file directory, or within any subdirectory thereof, then the
- given file must be a "system" include file. This function tells us
- if we should suppress pedantic errors/warnings for the given FILENAME.
-
- The value is 2 if the file is a C-language system header file
- for which C++ should (on most systems) assume `extern "C"'. */
-
-static bool
-is_system_include (cppReader *pfile, cstring filename)
-{
- struct file_name_list *searchptr;
-
- for (searchptr = CPPOPTIONS (pfile)->first_system_include;
- searchptr != NULL;
- searchptr = searchptr->next)
- {
- if (!cstring_isEmpty (searchptr->fname)) {
- cstring sys_dir = searchptr->fname;
- int length = cstring_length (sys_dir);
-
- if (cstring_equalLen (sys_dir, filename, length)
- && osd_isConnectChar (cstring_getChar (filename, length)))
- {
- if (searchptr->c_system_include_path)
- return 2;
- else
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-/* Convert a character string literal into a nul-terminated string.
- The input string is [IN ... LIMIT).
- The result is placed in RESULT. RESULT can be the same as IN.
- The value returned in the end of the string written to RESULT,
- or NULL on error. */
-
-static /*@null@*/ char *
-convert_string (cppReader *pfile, /*@returned@*/ char *result,
- char *in, char *limit, int handle_escapes)
-{
- char c;
- c = *in++;
-
- if (c != '\"')
- {
- return NULL;
- }
-
- while (in < limit)
- {
- c = *in++;
-
- switch (c)
- {
- case '\0':
- return NULL;
- case '\"':
- limit = in;
- /*@switchbreak@*/ break;
- case '\\':
- if (handle_escapes)
- {
- char *bpc = (char *) in;
- int i = (char) cppReader_parseEscape (pfile, &bpc);
- in = (char *) bpc;
- if (i >= 0)
- *result++ = (char) c;
- /*@switchbreak@*/ break;
- }
-
- /*@fallthrough@*/
- default:
- *result++ = c;
- }
- }
-
- *result = 0;
- return result;
-}
-
-/*
- * interpret #line command. Remembers previously seen fnames
- * in its very own hash table.
- */
-
-/*@constant int FNAME_HASHSIZE@*/
-#define FNAME_HASHSIZE 37
-
-static int
-do_line (cppReader *pfile, /*@unused@*/ struct directive *keyword)
-{
- cppBuffer *ip = cppReader_getBuffer (pfile);
- int new_lineno;
- size_t old_written = cppReader_getWritten (pfile);
- enum file_change_code file_change = same_file;
- enum cpp_token token;
-
- token = get_directive_token (pfile);
-
- if (token != CPP_NUMBER
- || !isdigit(pfile->token_buffer[old_written]))
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("invalid format `#line' command"));
-
- goto bad_line_directive;
- }
-
- /* The Newline at the end of this line remains to be processed.
- To put the next line at the specified line number,
- we must store a line number now that is one less. */
- new_lineno = atoi (pfile->token_buffer + old_written) - 1;
- cppReader_setWritten (pfile, old_written);
-
- /* NEW_LINENO is one less than the actual line number here. */
- if (cppReader_isPedantic (pfile) && new_lineno < 0)
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("line number out of range in `#line' command"));
-
- token = get_directive_token (pfile);
-
- if (token == CPP_STRING) {
- char *fname = pfile->token_buffer + old_written;
- char *end_name;
- static hashNode fname_table[FNAME_HASHSIZE];
- hashNode hp;
- hashNode *hash_bucket;
- char *p;
- size_t num_start;
- int fname_length;
-
- /* Turn the file name, which is a character string literal,
- into a null-terminated string. Do this in place. */
- end_name = convert_string (pfile, fname, fname, cppReader_getPWritten (pfile), 1);
- if (end_name == NULL)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("invalid format `#line' command"));
- goto bad_line_directive;
- }
-
- fname_length = end_name - fname;
- num_start = cppReader_getWritten (pfile);
-
- token = get_directive_token (pfile);
- if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP) {
- p = pfile->token_buffer + num_start;
- if (cppReader_isPedantic (pfile))
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("garbage at end of `#line' command"));
-
- if (token != CPP_NUMBER || *p < '0' || *p > '4' || p[1] != '\0')
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("invalid format `#line' command"));
- goto bad_line_directive;
- }
- if (*p == '1')
- file_change = enter_file;
- else if (*p == 2)
- file_change = leave_file;
- else if (*p == 3)
- ip->system_header_p = 1;
- else /* if (*p == 4) */
- ip->system_header_p = 2;
-
- cppReader_setWritten (pfile, num_start);
- token = get_directive_token (pfile);
- p = pfile->token_buffer + num_start;
- if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4')) {
- ip->system_header_p = *p == 3 ? 1 : 2;
- token = get_directive_token (pfile);
- }
- if (token != CPP_VSPACE) {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("invalid format `#line' command"));
-
- goto bad_line_directive;
- }
- }
-
- hash_bucket =
- &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];
- for (hp = *hash_bucket; hp != NULL; hp = hp->next)
- {
- if (hp->length == fname_length &&
- strncmp (hp->value.cpval, fname, size_fromInt (fname_length)) == 0) {
- ip->nominal_fname = cstring_fromChars (hp->value.cpval);
- break;
- }
- }
-
- if (hp == 0) {
- /* Didn't find it; cons up a new one. */
- hp = (hashNode) dmalloc (sizeof (*hp));
-
- hp->prev = NULL;
- hp->bucket_hdr = NULL;
- hp->type = T_NONE;
- hp->name = cstring_undefined;
- hp->next = *hash_bucket;
-
- *hash_bucket = hp;
-
- hp->length = fname_length;
- hp->value.cpval = dmalloc (sizeof (*hp->value.cpval) * (fname_length + 1));
- memcpy (hp->value.cpval, fname, size_fromInt (fname_length));
- hp->value.cpval[fname_length] = '\0';
- ip->nominal_fname = cstring_fromChars (hp->value.cpval);
- }
- }
- else if (token != CPP_VSPACE && token != CPP_EOF)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("invalid format `#line' command"));
- goto bad_line_directive;
- }
- else
- {
- ;
- }
-
- ip->lineno = new_lineno;
-bad_line_directive:
- cppReader_skipRestOfLine (pfile);
- cppReader_setWritten (pfile, old_written);
- output_line_command (pfile, 0, file_change);
- return 0;
-}
-
-/*
- * remove the definition of a symbol from the symbol table.
- * according to un*x /lib/cpp, it is not an error to undef
- * something that has no definitions, so it isn't one here either.
- */
-
-static int
-do_undef (cppReader *pfile, struct directive *keyword, char *buf, char *limit)
-{
-
- int sym_length;
- hashNode hp;
- char *orig_buf = buf;
-
- SKIP_WHITE_SPACE (buf);
-
- sym_length = cppReader_checkMacroName (pfile, buf, cstring_makeLiteralTemp ("macro"));
-
- while ((hp = cppReader_lookup (buf, sym_length, -1)) != NULL)
- {
- /* If we are generating additional info for debugging (with -g) we
- need to pass through all effective #undef commands. */
- if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))
- {
- pass_thru_directive (orig_buf, limit, pfile, keyword);
- }
-
- if (hp->type != T_MACRO)
- {
- cppReader_warning (pfile,
- message ("Undefining preprocessor builtin: %s",
- hp->name));
- }
-
- cppReader_deleteMacro (hp);
- }
-
- if (cppReader_isPedantic (pfile)) {
- buf += sym_length;
- SKIP_WHITE_SPACE (buf);
- if (buf != limit)
- {
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("garbage after `#undef' directive"));
- }
- }
-
- return 0;
-}
-
-
-/*
- * Report an error detected by the program we are processing.
- * Use the text of the line in the error message.
- * (We use error because it prints the filename & line#.)
- */
-
-static int
-do_error (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- char *buf, char *limit)
-{
- int length = limit - buf;
- cstring copy = cstring_copyLength (buf, length);
- cstring adv = cstring_advanceWhiteSpace (copy);
-
- cppReader_error (pfile, message ("#error %s", adv));
- cstring_free (copy);
- return 0;
-}
-
-/*
- * Report a warning detected by the program we are processing.
- * Use the text of the line in the warning message, then continue.
- * (We use error because it prints the filename & line#.)
- */
-
-static int
-do_warning (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- char *buf, char *limit)
-{
- int length = limit - buf;
- cstring copy = cstring_copyLength (buf, length);
- cstring adv = cstring_advanceWhiteSpace (copy);
- cppReader_warning (pfile, message ("#warning %s", adv));
- cstring_free (copy);
- return 0;
-}
-
-
-/* #ident has already been copied to the output file, so just ignore it. */
-
-static int
-do_ident (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- /*@unused@*/ char *buf, /*@unused@*/ char *limit)
-{
- /* Allow #ident in system headers, since that's not user's fault. */
- if (cppReader_isPedantic (pfile) && !cppReader_getBuffer (pfile)->system_header_p)
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("ANSI C does not allow `#ident'"));
-
- /* Leave rest of line to be read by later calls to cppGetToken. */
-
- return 0;
-}
-
-/* #pragma and its argument line have already been copied to the output file.
- Just check for some recognized pragmas that need validation here. */
-
-static int
-do_pragma (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- /*@unused@*/ char *buf, /*@unused@*/ char *limit)
-{
- while (*buf == ' ' || *buf == '\t')
- {
- buf++;
- }
-
- if (!strncmp (buf, "implementation", 14)) {
- /* Be quiet about `#pragma implementation' for a file only if it hasn't
- been included yet. */
- struct file_name_list *ptr;
- char *p = buf + 14, *fname, *inc_fname;
- int fname_len;
- SKIP_WHITE_SPACE (p);
- if (*p == '\n' || *p != '\"')
- return 0;
-
- fname = p + 1;
- p = (char *) strchr (fname, '\"');
- fname_len = p != NULL ? p - fname : mstring_length (fname);
-
- for (ptr = pfile->all_include_files; ptr != NULL; ptr = ptr->next)
- {
- inc_fname = (char *) strrchr (cstring_toCharsSafe (ptr->fname), CONNECTCHAR);
- inc_fname = (inc_fname != NULL)
- ? inc_fname + 1 : cstring_toCharsSafe (ptr->fname);
-
- if ((inc_fname != NULL)
- && (strncmp (inc_fname, fname, size_fromInt (fname_len)) == 0))
- {
- cpp_setLocation (pfile);
-
- ppllerror (message ("`#pragma implementation' for `%s' appears "
- "after file is included",
- cstring_fromChars (fname)));
- }
- }
- }
-
- return 0;
-}
-
-/*
- * handle #if command by
- * 1) inserting special `defined' keyword into the hash table
- * that gets turned into 0 or 1 by special_symbol (thus,
- * if the luser has a symbol called `defined' already, it won't
- * work inside the #if command)
- * 2) rescan the input into a temporary output buffer
- * 3) pass the output buffer to the yacc parser and collect a value
- * 4) clean up the mess left from steps 1 and 2.
- * 5) call conditional_skip to skip til the next #endif (etc.),
- * or not, depending on the value from step 3.
- */
-
-static int
-do_if (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- char *buf, char *limit)
-{
- HOST_WIDE_INT value = eval_if_expression (pfile, buf, limit - buf);
- conditional_skip (pfile, value == 0, T_IF, NULL);
- return 0;
-}
-
-/*
- * handle a #elif directive by not changing if_stack either.
- * see the comment above do_else.
- */
-
-static int do_elif (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- char *buf, char *limit)
-{
- if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("Preprocessor command #elif is not within a conditional"));
- return 0;
- }
- else
- {
- llassert (pfile->if_stack != NULL);
-
- if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`#elif' after `#else'"));
-
- if (pfile->if_stack->fname != NULL
- && cppReader_getBuffer (pfile)->fname != NULL
- && !cstring_equal (pfile->if_stack->fname,
- cppReader_getBuffer (pfile)->nominal_fname))
- fprintf (stderr, ", file %s", cstring_toCharsSafe (pfile->if_stack->fname));
- fprintf (stderr, ")\n");
- }
- pfile->if_stack->type = T_ELIF;
- }
-
- if (pfile->if_stack->if_succeeded)
- {
- skip_if_group (pfile, 0);
- }
- else
- {
- HOST_WIDE_INT value = eval_if_expression (pfile, buf, limit - buf);
- if (value == 0)
- skip_if_group (pfile, 0);
- else
- {
- ++pfile->if_stack->if_succeeded; /* continue processing input */
- output_line_command (pfile, 1, same_file);
- }
- }
-
- return 0;
-}
-
-/*
- * evaluate a #if expression in BUF, of length LENGTH,
- * then parse the result as a C expression and return the value as an int.
- */
-
-static HOST_WIDE_INT
-eval_if_expression (cppReader *pfile,
- /*@unused@*/ char *buf,
- /*@unused@*/ int length)
-{
- hashNode save_defined;
- HOST_WIDE_INT value;
- size_t old_written = cppReader_getWritten (pfile);
-
- save_defined = cppReader_install ("defined", -1, T_SPEC_DEFINED, 0, 0, -1);
- pfile->pcp_inside_if = 1;
-
- value = cppReader_parseExpression (pfile);
- pfile->pcp_inside_if = 0;
-
- /* Clean up special symbol */
- cppReader_deleteMacro (save_defined);
-
- cppReader_setWritten (pfile, old_written); /* Pop */
-
- return value;
-}
-
-/*
- * routine to handle ifdef/ifndef. Try to look up the symbol,
- * then do or don't skip to the #endif/#else/#elif depending
- * on what directive is actually being processed.
- */
-
-static int
-do_xifdef (cppReader *pfile, struct directive *keyword,
- /*@unused@*/ char *unused1, /*@unused@*/ char *unused2)
-{
- int skip;
- cppBuffer *ip = cppReader_getBuffer (pfile);
- char *ident;
- int ident_length;
- enum cpp_token token;
- int start_of_file = 0;
- char *control_macro = 0;
- size_t old_written = cppReader_getWritten (pfile);
-
- DPRINTF (("do xifdef: %d",
- keyword->type == T_IFNDEF));
-
- /* Detect a #ifndef at start of file (not counting comments). */
- if (cstring_isDefined (ip->fname) && keyword->type == T_IFNDEF)
- {
- start_of_file = pfile->only_seen_white == 2;
- }
-
- pfile->no_macro_expand++;
- token = get_directive_token (pfile);
- pfile->no_macro_expand--;
-
- ident = pfile->token_buffer + old_written;
- ident_length = size_toInt (cppReader_getWritten (pfile) - old_written);
- cppReader_setWritten (pfile, old_written); /* Pop */
-
- if (token == CPP_VSPACE || token == CPP_POP || token == CPP_EOF)
- {
- skip = (keyword->type == T_IFDEF);
- if (! cppReader_isTraditional (pfile))
- {
- cppReader_pedwarn (pfile,
- message ("`#%s' with no argument", keyword->name));
- }
- }
- else if (token == CPP_NAME)
- {
- hashNode hp = cppReader_lookup (ident, ident_length, -1);
- skip = (keyword->type == T_IFDEF)
- ? (hp == NULL) : (hp != NULL);
-
- DPRINTF (("hp null: %d / %d / %d",
- (hp == NULL),
- (keyword->type == T_IFNDEF),
- skip));
-
- if (start_of_file && !skip)
- {
- DPRINTF (("Not skipping!"));
- control_macro = (char *) dmalloc (size_fromInt (ident_length + 1));
- memcpy (control_macro, ident, size_fromInt (ident_length + 1));
- }
- }
- else
- {
- skip = (keyword->type == T_IFDEF);
- if (! cppReader_isTraditional (pfile))
- {
- cppReader_error (pfile,
- message ("`#%s' with invalid argument", keyword->name));
- }
- }
-
- if (!cppReader_isTraditional (pfile))
- {
- int c;
- cppSkipHspace (pfile);
- c = cppReader_peekC (pfile);
- if (c != EOF && c != '\n')
- {
- cppReader_pedwarn (pfile,
- message ("garbage at end of `#%s' argument", keyword->name));
- }
- }
-
- cppReader_skipRestOfLine (pfile);
-
- DPRINTF (("Conditional skip: %d", skip));
- conditional_skip (pfile, skip, T_IF, control_macro);
- return 0;
-}
-
-/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead.
- If this is a #ifndef starting at the beginning of a file,
- CONTROL_MACRO is the macro name tested by the #ifndef.
- Otherwise, CONTROL_MACRO is 0. */
-
-static void
-conditional_skip (cppReader *pfile, int skip,
- enum node_type type,
- /*@dependent@*/ char *control_macro)
-{
- cppIfStackFrame *temp = (cppIfStackFrame *) dmalloc (sizeof (*temp));
-
- temp->fname = cppReader_getBuffer (pfile)->nominal_fname;
- temp->next = pfile->if_stack;
- temp->control_macro = control_macro;
- temp->lineno = 0;
- temp->if_succeeded = 0;
-
- pfile->if_stack = temp;
- pfile->if_stack->type = type;
-
- if (skip != 0)
- {
- skip_if_group (pfile, 0);
- return;
- }
- else
- {
- ++pfile->if_stack->if_succeeded;
- output_line_command (pfile, 1, same_file);
- }
-}
-
-/*
- * skip to #endif, #else, or #elif. adjust line numbers, etc.
- * leaves input ptr at the sharp sign found.
- * If ANY is nonzero, return at next directive of any sort.
- */
-
-static void
-skip_if_group (cppReader *pfile, int any)
-{
- int c;
- struct directive *kt;
- cppIfStackFrame *save_if_stack = pfile->if_stack; /* don't pop past here */
- register int ident_length;
- char *ident;
- struct parse_marker line_start_mark;
-
- parseSetMark (&line_start_mark, pfile);
-
- if (CPPOPTIONS (pfile)->output_conditionals) {
- static char failed[] = "#failed\n";
- cppReader_puts (pfile, failed, sizeof(failed)-1);
- pfile->lineno++;
- output_line_command (pfile, 1, same_file);
- }
-
-beg_of_line:
- if (CPPOPTIONS (pfile)->output_conditionals)
- {
- cppBuffer *pbuf = cppReader_getBuffer (pfile);
- char *start_line;
-
- llassert (pbuf->buf != NULL);
-
- start_line = pbuf->buf + line_start_mark.position;
- cppReader_puts (pfile, start_line, size_fromInt (pbuf->cur - start_line));
- }
-
- parseMoveMark (&line_start_mark, pfile);
-
- if (!cppReader_isTraditional (pfile))
- {
- cppSkipHspace (pfile);
- }
-
- c = cppReader_getC (pfile);
- if (c == '#')
- {
- size_t old_written = cppReader_getWritten (pfile);
- cppSkipHspace (pfile);
-
- parse_name (pfile, cppReader_getC (pfile));
- ident_length = size_toInt (cppReader_getWritten (pfile) - old_written);
- ident = pfile->token_buffer + old_written;
- pfile->limit = ident;
-
- for (kt = directive_table; kt->length >= 0; kt++)
- {
- cppIfStackFrame *temp;
- if (ident_length == kt->length
- && cstring_equalPrefix (kt->name, cstring_fromChars (ident)))
- {
- /* If we are asked to return on next directive, do so now. */
- if (any)
- {
- goto done;
- }
-
- switch (kt->type)
- {
- case T_IF:
- case T_IFDEF:
- case T_IFNDEF:
- temp = (cppIfStackFrame *) dmalloc (sizeof (*temp));
- temp->next = pfile->if_stack;
- temp->fname = cppReader_getBuffer (pfile)->nominal_fname;
- temp->type = kt->type;
- temp->lineno = 0;
- temp->if_succeeded = 0;
- temp->control_macro = NULL;
-
- pfile->if_stack = temp;
- /*@switchbreak@*/ break;
- case T_ELSE:
- case T_ENDIF:
- if (cppReader_isPedantic (pfile) && pfile->if_stack != save_if_stack)
- validate_else (pfile,
- cstring_makeLiteralTemp (kt->type == T_ELSE ? "#else" : "#endif"));
- /*@fallthrough@*/
- case T_ELIF:
- if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)
- {
- cppReader_error (pfile,
- message ("Preprocessor command #%s is not within a conditional", kt->name));
- /*@switchbreak@*/ break;
- }
- else if (pfile->if_stack == save_if_stack)
- {
- goto done; /* found what we came for */
- }
- else
- {
- ;
- }
-
- if (kt->type != T_ENDIF)
- {
- llassert (pfile->if_stack != NULL);
-
- if (pfile->if_stack->type == T_ELSE)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("`#else' or `#elif' after `#else'"));
- }
-
- pfile->if_stack->type = kt->type;
- /*@switchbreak@*/ break;
- }
-
- temp = pfile->if_stack;
- llassert (temp != NULL);
- pfile->if_stack = temp->next;
- sfree (temp);
- /*@switchbreak@*/ break;
- default: ;
- /*@-branchstate@*/
- }
- /*@=branchstate@*/
- break;
- }
-
- /* Don't let erroneous code go by. */
-
- if (kt->length < 0 && !CPPOPTIONS (pfile)->lang_asm
- && cppReader_isPedantic (pfile))
- {
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("Invalid preprocessor directive name"));
- }
- }
-
- c = cppReader_getC (pfile);
- }
- /* We're in the middle of a line. Skip the rest of it. */
- for (;;) {
- size_t old;
-
- switch (c)
- {
- case EOF:
- goto done;
- case '/': /* possible comment */
- c = skip_comment (pfile, NULL);
- if (c == EOF)
- goto done;
- /*@switchbreak@*/ break;
- case '\"':
- case '\'':
- cppReader_forward (pfile, -1);
- old = cppReader_getWritten (pfile);
- (void) cppGetToken (pfile);
- cppReader_setWritten (pfile, old);
- /*@switchbreak@*/ break;
- case '\\':
- /* Char after backslash loses its special meaning. */
- if (cppReader_peekC (pfile) == '\n')
- {
- cppReader_forward (pfile, 1);
- }
-
- /*@switchbreak@*/ break;
- case '\n':
- goto beg_of_line;
- }
- c = cppReader_getC (pfile);
- }
-done:
- if (CPPOPTIONS (pfile)->output_conditionals) {
- static char end_failed[] = "#endfailed\n";
- cppReader_puts (pfile, end_failed, sizeof(end_failed)-1);
- pfile->lineno++;
- }
- pfile->only_seen_white = 1;
-
- parseGotoMark (&line_start_mark, pfile);
- parseClearMark (&line_start_mark);
-}
-
-/*
- * handle a #else directive. Do this by just continuing processing
- * without changing if_stack ; this is so that the error message
- * for missing #endif's etc. will point to the original #if. It
- * is possible that something different would be better.
- */
-
-static int
-do_else (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- /*@unused@*/ char *buf, /*@unused@*/ char *limit)
-{
- if (cppReader_isPedantic (pfile))
- {
- validate_else (pfile, cstring_makeLiteralTemp ("#else"));
- }
-
- cppReader_skipRestOfLine (pfile);
-
- if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack) {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("Preprocessor command #else is not within a conditional"));
- return 0;
- } else {
- /* #ifndef can't have its special treatment for containing the whole file
- if it has a #else clause. */
-
- llassert (pfile->if_stack != NULL);
-
- pfile->if_stack->control_macro = 0;
-
- if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF)
- {
- cpp_setLocation (pfile);
- genppllerrorhint (FLG_PREPROC,
- message ("Pre-processor directive #else after #else"),
- message ("%q: Location of match",
- fileloc_unparseRaw (pfile->if_stack->fname,
- pfile->if_stack->lineno)));
- }
-
- pfile->if_stack->type = T_ELSE;
- }
-
- if (pfile->if_stack->if_succeeded)
- skip_if_group (pfile, 0);
- else {
- ++pfile->if_stack->if_succeeded; /* continue processing input */
- output_line_command (pfile, 1, same_file);
- }
-
- return 0;
-}
-
-/*
- * unstack after #endif command
- */
-
-static int
-do_endif (cppReader *pfile, /*@unused@*/ struct directive *keyword,
- /*@unused@*/ char *buf, /*@unused@*/ char *limit)
-{
- if (cppReader_isPedantic (pfile))
- {
- validate_else (pfile, cstring_makeLiteralTemp ("#endif"));
- }
-
- cppReader_skipRestOfLine (pfile);
-
- if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)
- {
- cppReader_errorLit (pfile, cstring_makeLiteralTemp ("Unbalanced #endif"));
- }
- else
- {
- cppIfStackFrame *temp = pfile->if_stack;
-
- llassert (temp != NULL);
-
- pfile->if_stack = temp->next;
- if (temp->control_macro != 0)
- {
- /* This #endif matched a #ifndef at the start of the file.
- See if it is at the end of the file. */
- struct parse_marker start_mark;
- int c;
-
- parseSetMark (&start_mark, pfile);
-
- for (;;)
- {
- cppSkipHspace (pfile);
- c = cppReader_getC (pfile);
-
- if (c != '\n')
- break;
- }
-
- parseGotoMark (&start_mark, pfile);
- parseClearMark (&start_mark);
-
- if (c == EOF)
- {
- /* If we get here, this #endif ends a #ifndef
- that contains all of the file (aside from whitespace).
- Arrange not to include the file again
- if the macro that was tested is defined.
-
- Do not do this for the top-level file in a -include or any
- file in a -imacros. */
- struct file_name_list *ifile = pfile->all_include_files;
-
- for ( ; ifile != NULL; ifile = ifile->next)
- {
- if (cstring_equal (ifile->fname, cppReader_getBuffer (pfile)->fname))
- {
- ifile->control_macro = temp->control_macro;
- break;
- }
- }
- }
- }
-
- sfree (temp);
- output_line_command (pfile, 1, same_file);
- }
- return 0;
-}
-
-/* When an #else or #endif is found while skipping failed conditional,
- if -pedantic was specified, this is called to warn about text after
- the command name. P points to the first char after the command name. */
-
-static void
-validate_else (cppReader *pfile, cstring directive)
-{
- int c;
- cppSkipHspace (pfile);
- c = cppReader_peekC (pfile);
- if (c != EOF && c != '\n')
- {
- cppReader_pedwarn (pfile,
- message ("text following `%s' violates ANSI standard", directive));
- }
-}
-
-/*
-** Get the next token, and add it to the text in pfile->token_buffer.
-** Return the kind of token we got.
-*/
-
-enum cpp_token
-cppGetToken (cppReader *pfile)
-{
- int c, c2, c3;
- size_t old_written = 0;
- int start_line, start_column;
- enum cpp_token token;
- struct cppOptions *opts = CPPOPTIONS (pfile);
- cppReader_getBuffer (pfile)->prev = cppReader_getBuffer (pfile)->cur;
-
-get_next:
- c = cppReader_getC (pfile);
-
- if (c == EOF)
- {
- handle_eof:
- if (cppReader_getBuffer (pfile)->seen_eof)
- {
- cppBuffer *buf = cppReader_popBuffer (pfile);
-
- if (buf != cppReader_nullBuffer (pfile))
- {
- goto get_next;
- }
- else
- {
- return CPP_EOF;
- }
- }
- else
- {
- cppBuffer *next_buf = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));
- cppReader_getBuffer (pfile)->seen_eof = 1;
-
- if (cstring_isDefined (cppReader_getBuffer (pfile)->nominal_fname)
- && next_buf != cppReader_nullBuffer (pfile))
- {
- /* We're about to return from an #include file.
- Emit #line information now (as part of the CPP_POP) result.
- But the #line refers to the file we will pop to. */
- cppBuffer *cur_buffer = CPPBUFFER (pfile);
- CPPBUFFER (pfile) = next_buf;
- pfile->input_stack_listing_current = 0;
- output_line_command (pfile, 0, leave_file);
- CPPBUFFER (pfile) = cur_buffer;
- }
- return CPP_POP;
- }
- }
- else
- {
- long newlines;
- struct parse_marker start_mark;
-
- switch (c)
- {
- case '/':
- if (cppReader_peekC (pfile) == '=')
- {
- goto op2;
- }
-
- if (opts->put_out_comments)
- {
- parseSetMark (&start_mark, pfile);
- }
-
- newlines = 0;
- cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile),
- &start_line, &start_column);
- c = skip_comment (pfile, &newlines);
-
- if (opts->put_out_comments && (c == '/' || c == EOF))
- {
- assertSet (&start_mark);
- parseClearMark (&start_mark);
- }
-
- if (c == '/')
- goto randomchar;
- if (c == EOF)
- {
- cppReader_errorWithLine (pfile, start_line, start_column,
- cstring_makeLiteral ("Unterminated comment"));
- goto handle_eof;
- }
- c = '/'; /* Initial letter of comment. */
- return_comment:
- /* Comments are equivalent to spaces.
- For -traditional, a comment is equivalent to nothing. */
-
- if (opts->put_out_comments)
- {
- enum cpp_token res;
-
- assertSet (&start_mark);
- res = cpp_handleComment (pfile, &start_mark);
- pfile->lineno += newlines;
- return res;
- }
- else if (cppReader_isTraditional (pfile))
- {
- return CPP_COMMENT;
- }
- else
- {
- cppReader_reserve(pfile, 1);
- cppReader_putCharQ (pfile, ' ');
- return CPP_HSPACE;
- }
-
- case '#':
- if (!pfile->only_seen_white)
- {
- goto randomchar;
- }
-
- if (cppReader_handleDirective (pfile))
- {
- return CPP_DIRECTIVE;
- }
-
- pfile->only_seen_white = 0;
- return CPP_OTHER;
-
- case '\"':
- case '\'':
- /* A single quoted string is treated like a double -- some
- programs (e.g., troff) are perverse this way */
- cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile),
- &start_line, &start_column);
- old_written = cppReader_getWritten (pfile);
- string:
- cppReader_putChar (pfile, c);
- while (TRUE)
- {
- int cc = cppReader_getC (pfile);
- if (cc == EOF)
- {
- if (cppBuffer_isMacro (CPPBUFFER (pfile)))
- {
- /* try harder: this string crosses a macro expansion
- boundary. This can happen naturally if -traditional.
- Otherwise, only -D can make a macro with an unmatched
- quote. */
- cppBuffer *next_buf
- = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));
- (*cppReader_getBuffer (pfile)->cleanup)
- (cppReader_getBuffer (pfile), pfile);
- CPPBUFFER (pfile) = next_buf;
- continue;
- }
- if (!cppReader_isTraditional (pfile))
- {
- cpp_setLocation (pfile);
-
- setLine (long_toInt (start_line));
- setColumn (long_toInt (start_column));
-
- if (pfile->multiline_string_line != long_toInt (start_line)
- && pfile->multiline_string_line != 0)
- {
- genppllerrorhint
- (FLG_PREPROC,
- message ("Unterminated string or character constant"),
- message ("%q: Possible real start of unterminated constant",
- fileloc_unparseRaw
- (fileloc_filename (g_currentloc),
- pfile->multiline_string_line)));
- pfile->multiline_string_line = 0;
- }
- else
- {
- genppllerror
- (FLG_PREPROC,
- message ("Unterminated string or character constant"));
- }
- }
- /*@loopbreak@*/ break;
- }
- cppReader_putChar (pfile, cc);
- switch (cc)
- {
- case '\n':
- /* Traditionally, end of line ends a string constant with
- no error. So exit the loop and record the new line. */
- if (cppReader_isTraditional (pfile))
- goto while2end;
- if (c == '\'')
- {
- goto while2end;
- }
- if (cppReader_isPedantic (pfile)
- && pfile->multiline_string_line == 0)
- {
- cppReader_pedwarnWithLine
- (pfile, long_toInt (start_line),
- long_toInt (start_column),
- cstring_makeLiteral ("String constant runs past end of line"));
- }
- if (pfile->multiline_string_line == 0)
- {
- pfile->multiline_string_line = start_line;
- }
-
- /*@switchbreak@*/ break;
-
- case '\\':
- cc = cppReader_getC (pfile);
- if (cc == '\n')
- {
- /* Backslash newline is replaced by nothing at all. */
- cppReader_adjustWritten (pfile, -1);
- pfile->lineno++;
- }
- else
- {
- /* ANSI stupidly requires that in \\ the second \
- is *not* prevented from combining with a newline. */
- NEWLINE_FIX1(cc);
- if (cc != EOF)
- cppReader_putChar (pfile, cc);
- }
- /*@switchbreak@*/ break;
-
- case '\"':
- case '\'':
- if (cc == c)
- goto while2end;
- /*@switchbreak@*/ break;
- }
- }
- while2end:
- pfile->lineno += count_newlines (pfile->token_buffer + old_written,
- cppReader_getPWritten (pfile));
- pfile->only_seen_white = 0;
- return c == '\'' ? CPP_CHAR : CPP_STRING;
-
- case '$':
- if (!opts->dollars_in_ident)
- goto randomchar;
- goto letter;
-
- case ':':
- if (opts->cplusplus && cppReader_peekC (pfile) == ':')
- goto op2;
- goto randomchar;
-
- case '&':
- case '+':
- case '|':
- NEWLINE_FIX;
- c2 = cppReader_peekC (pfile);
- if (c2 == c || c2 == '=')
- goto op2;
- goto randomchar;
-
- case '*':
- case '!':
- case '%':
- case '=':
- case '^':
- NEWLINE_FIX;
- if (cppReader_peekC (pfile) == '=')
- goto op2;
- goto randomchar;
-
- case '-':
- NEWLINE_FIX;
- c2 = cppReader_peekC (pfile);
- if (c2 == '-' && opts->chill)
- {
- /* Chill style comment */
- if (opts->put_out_comments)
- {
- parseSetMark (&start_mark, pfile);
- }
-
- cppReader_forward (pfile, 1); /* Skip second '-'. */
-
- for (;;)
- {
- c = cppReader_getC (pfile);
- if (c == EOF)
- /*@loopbreak@*/ break;
- if (c == '\n')
- {
- /* Don't consider final '\n' to be part of comment. */
- cppReader_forward (pfile, -1);
- /*@loopbreak@*/ break;
- }
- }
- c = '-';
- goto return_comment;
- }
- if (c2 == '-' || c2 == '=' || c2 == '>')
- goto op2;
- goto randomchar;
-
- case '<':
- if (pfile->parsing_include_directive)
- {
- for (;;)
- {
- cppReader_putChar (pfile, c);
- if (c == '>')
- /*@loopbreak@*/ break;
- c = cppReader_getC (pfile);
- NEWLINE_FIX1 (c);
- if (c == '\n' || c == EOF)
- {
- cppReader_errorLit (pfile,
- cstring_makeLiteralTemp ("Missing '>' in \"#include <FILENAME>\""));
- /*@loopbreak@*/ break;
- }
- }
- return CPP_STRING;
- }
- /*@fallthrough@*/
- case '>':
- NEWLINE_FIX;
- c2 = cppReader_peekC (pfile);
- if (c2 == '=')
- goto op2;
- if (c2 != c)
- goto randomchar;
- cppReader_forward (pfile, 1);
- cppReader_reserve (pfile, 4);
- cppReader_putChar (pfile, c);
- cppReader_putChar (pfile, c2);
- NEWLINE_FIX;
- c3 = cppReader_peekC (pfile);
- if (c3 == '=')
- cppReader_putCharQ (pfile, cppReader_getC (pfile));
- cppReader_nullTerminateQ (pfile);
- pfile->only_seen_white = 0;
- return CPP_OTHER;
-
- case '@':
- if (cppReader_getBuffer (pfile)->has_escapes)
- {
- c = cppReader_getC (pfile);
- if (c == '-')
- {
- if (pfile->output_escapes)
- cppReader_puts (pfile, "@-", 2);
- parse_name (pfile, cppReader_getC (pfile));
- return CPP_NAME;
- }
- else if (is_space [c])
- {
- cppReader_reserve (pfile, 2);
- if (pfile->output_escapes)
- cppReader_putCharQ (pfile, '@');
- cppReader_putCharQ (pfile, c);
- return CPP_HSPACE;
- }
- else
- {
- ;
- }
- }
- if (pfile->output_escapes)
- {
- cppReader_puts (pfile, "@@", 2);
- return CPP_OTHER;
- }
- goto randomchar;
- case '.':
- NEWLINE_FIX;
- c2 = cppReader_peekC (pfile);
- if (isdigit(c2))
- {
- cppReader_reserve(pfile, 2);
- cppReader_putCharQ (pfile, '.');
- c = cppReader_getC (pfile);
- goto number;
- }
-
- /* FIXME - misses the case "..\\\n." */
- if (c2 == '.' && cpp_peekN (pfile, 1) == '.')
- {
- cppReader_reserve(pfile, 4);
- cppReader_putCharQ (pfile, '.');
- cppReader_putCharQ (pfile, '.');
- cppReader_putCharQ (pfile, '.');
- cppReader_forward (pfile, 2);
- cppReader_nullTerminateQ (pfile);
- pfile->only_seen_white = 0;
- return CPP_3DOTS;
- }
- goto randomchar;
- op2:
- token = CPP_OTHER;
- pfile->only_seen_white = 0;
- op2any:
- cppReader_reserve(pfile, 3);
- cppReader_putCharQ (pfile, c);
- cppReader_putCharQ (pfile, cppReader_getC (pfile));
- cppReader_nullTerminateQ (pfile);
- return token;
-
- case 'L':
- NEWLINE_FIX;
- c2 = cppReader_peekC (pfile);
- if ((c2 == '\'' || c2 == '\"') && !cppReader_isTraditional (pfile))
- {
- cppReader_putChar (pfile, c);
- c = cppReader_getC (pfile);
- goto string;
- }
- goto letter;
-
- case '0': case '1': case '2': case '3': case '4':
- case '5': case '6': case '7': case '8': case '9':
- number:
- c2 = '.';
- for (;;)
- {
- cppReader_reserve (pfile, 2);
- cppReader_putCharQ (pfile, c);
- NEWLINE_FIX;
- c = cppReader_peekC (pfile);
- if (c == EOF)
- /*@loopbreak@*/ break;
- if (!is_idchar[c] && c != '.'
- && ((c2 != 'e' && c2 != 'E'
- && ((c2 != 'p' && c2 != 'P') || cppReader_isC89 (pfile)))
- || (c != '+' && c != '-')))
- /*@loopbreak@*/ break;
- cppReader_forward (pfile, 1);
- c2= c;
- }
-
- cppReader_nullTerminateQ (pfile);
- pfile->only_seen_white = 0;
- return CPP_NUMBER;
-
- case 'b': case 'c': case 'd': case 'h': case 'o':
- case 'B': case 'C': case 'D': case 'H': case 'O':
- if (opts->chill && cppReader_peekC (pfile) == '\'')
- {
- pfile->only_seen_white = 0;
- cppReader_reserve (pfile, 2);
- cppReader_putCharQ (pfile, c);
- cppReader_putCharQ (pfile, '\'');
- cppReader_forward (pfile, 1);
- for (;;)
- {
- c = cppReader_getC (pfile);
- if (c == EOF)
- goto chill_number_eof;
- if (!is_idchar[c])
- {
- if (c == '\\' && cppReader_peekC (pfile) == '\n')
- {
- cppReader_forward (pfile, 2);
- continue;
- }
- /*@loopbreak@*/ break;
- }
- cppReader_putChar (pfile, c);
- }
- if (c == '\'')
- {
- cppReader_reserve (pfile, 2);
- cppReader_putCharQ (pfile, c);
- cppReader_nullTerminateQ (pfile);
- return CPP_STRING;
- }
- else
- {
- cppReader_forward (pfile, -1);
- chill_number_eof:
- cppReader_nullTerminate (pfile);
- return CPP_NUMBER;
- }
- }
- else
- goto letter;
- case '_':
- case 'a': case 'e': case 'f': case 'g': case 'i': case 'j':
- case 'k': case 'l': case 'm': case 'n': case 'p': case 'q':
- case 'r': case 's': case 't': case 'u': case 'v': case 'w':
- case 'x': case 'y': case 'z':
- case 'A': case 'E': case 'F': case 'G': case 'I': case 'J':
- case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R':
- case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
- case 'Y': case 'Z':
- letter:
- {
- hashNode hp;
- char *ident;
- size_t before_name_written = cppReader_getWritten (pfile);
- int ident_len;
- parse_name (pfile, c);
- pfile->only_seen_white = 0;
- if (pfile->no_macro_expand)
- {
- return CPP_NAME;
- }
-
- ident = pfile->token_buffer + before_name_written;
- ident_len = (cppReader_getPWritten (pfile)) - ident;
-
- hp = cppReader_lookupExpand (ident, ident_len, -1);
-
- if (hp == NULL)
- {
- return CPP_NAME;
- }
-
- if (hp->type == T_DISABLED)
- {
- if (pfile->output_escapes)
- { /* Return "@-IDENT", followed by '\0'. */
- int i;
- cppReader_reserve (pfile, 3);
- ident = pfile->token_buffer + before_name_written;
- cppReader_adjustWritten (pfile, 2);
-
- for (i = ident_len; i >= 0; i--)
- {
- ident[i+2] = ident[i];
- }
-
- ident[0] = '@';
- ident[1] = '-';
- }
- return CPP_NAME;
- }
-
- /* If macro wants an arglist, verify that a '(' follows.
- first skip all whitespace, copying it to the output
- after the macro name. Then, if there is no '(',
- decide this is not a macro call and leave things that way. */
-
- if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)
- {
- struct parse_marker macro_mark;
- int is_macro_call;
-
- while (cppBuffer_isMacro (CPPBUFFER (pfile)))
- {
- cppBuffer *next_buf;
- cppSkipHspace (pfile);
- if (cppReader_peekC (pfile) != EOF)
- {
- /*@loopbreak@*/ break;
- }
-
- next_buf = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));
- (*cppReader_getBuffer (pfile)->cleanup) (cppReader_getBuffer (pfile), pfile);
- CPPBUFFER (pfile) = next_buf;
- }
-
- parseSetMark (¯o_mark, pfile);
-
- for (;;)
- {
- cppSkipHspace (pfile);
- c = cppReader_peekC (pfile);
- is_macro_call = c == '(';
- if (c != '\n')
- /*@loopbreak@*/ break;
- cppReader_forward (pfile, 1);
- }
-
- if (!is_macro_call)
- {
- parseGotoMark (¯o_mark, pfile);
- }
-
- parseClearMark (¯o_mark);
-
- if (!is_macro_call)
- {
- return CPP_NAME;
- }
- }
- /* This is now known to be a macro call. */
-
- /* it might not actually be a macro. */
- if (hp->type != T_MACRO)
- {
- size_t xbuf_len;
- char *xbuf;
-
- cppReader_setWritten (pfile, before_name_written);
- special_symbol (hp, pfile);
- xbuf_len = cppReader_getWritten (pfile) - before_name_written;
- xbuf = (char *) dmalloc (xbuf_len + 1);
- cppReader_setWritten (pfile, before_name_written);
- memcpy (xbuf, cppReader_getPWritten (pfile), xbuf_len + 1);
- push_macro_expansion (pfile, xbuf, xbuf_len, hp);
- }
- else
- {
- /* Expand the macro, reading arguments as needed,
- and push the expansion on the input stack. */
- macroexpand (pfile, hp);
- cppReader_setWritten (pfile, before_name_written);
- }
-
- /* An extra "@ " is added to the end of a macro expansion
- to prevent accidental token pasting. We prefer to avoid
- unneeded extra spaces (for the sake of cpp-using tools like
- imake). Here we remove the space if it is safe to do so. */
-
- llassert (pfile->buffer->rlimit != NULL);
-
- if (pfile->buffer->rlimit - pfile->buffer->cur >= 3
- && pfile->buffer->rlimit[-2] == '@'
- && pfile->buffer->rlimit[-1] == ' ')
- {
- int c1 = pfile->buffer->rlimit[-3];
- int cl2 = cppBufPeek (cppBuffer_prevBuffer (CPPBUFFER (pfile)));
-
- if (cl2 == EOF || !unsafe_chars ((char) c1, (char) cl2))
- pfile->buffer->rlimit -= 2;
- }
- }
- goto get_next;
-
-
- case ' ': case '\t': case '\v': case '\r':
- for (;;)
- {
- cppReader_putChar (pfile, c);
- c = cppReader_peekC (pfile);
- if (c == EOF || !is_hor_space[c])
- /*@loopbreak@*/ break;
- cppReader_forward (pfile, 1);
- }
- return CPP_HSPACE;
-
- case '\\':
- c2 = cppReader_peekC (pfile);
- if (c2 != '\n')
- goto randomchar;
- token = CPP_HSPACE;
- goto op2any;
-
- case '\n':
- cppReader_putChar (pfile, c);
- if (pfile->only_seen_white == 0)
- pfile->only_seen_white = 1;
- pfile->lineno++;
- output_line_command (pfile, 1, same_file);
- return CPP_VSPACE;
-
- case '(': token = CPP_LPAREN; goto char1;
- case ')': token = CPP_RPAREN; goto char1;
- case '{': token = CPP_LBRACE; goto char1;
- case '}': token = CPP_RBRACE; goto char1;
- case ',': token = CPP_COMMA; goto char1;
- case ';': token = CPP_SEMICOLON; goto char1;
-
- randomchar:
- default:
- token = CPP_OTHER;
- char1:
- pfile->only_seen_white = 0;
- cppReader_putChar (pfile, c);
- return token;
- }
- }
-
- BADBRANCH;
- /*@notreached@*/
-}
-
-/* Parse an identifier starting with C. */
-
-void
-parse_name (cppReader *pfile, int c)
-{
- for (;;)
- {
- if (!is_idchar[c])
- {
- if (c == '\\' && cppReader_peekC (pfile) == '\n')
- {
- cppReader_forward (pfile, 2);
- continue;
- }
-
- cppReader_forward (pfile, -1);
- break;
- }
-
- if (c == '$' && cppReader_isPedantic (pfile))
- {
- cppReader_pedwarnLit (pfile,
- cstring_makeLiteralTemp ("`$' in identifier"));
- }
-
- cppReader_reserve(pfile, 2); /* One more for final NUL. */
- cppReader_putCharQ (pfile, c);
- c = cppReader_getC (pfile);
-
- if (c == EOF)
- break;
- }
-
- cppReader_nullTerminateQ (pfile);
-}
-
-/* The file_name_map structure holds a mapping of file names for a
- particular directory. This mapping is read from the file named
- FILE_NAME_MAP_FILE in that directory. Such a file can be used to
- map filenames on a file system with severe filename restrictions,
- such as DOS. The format of the file name map file is just a series
- of lines with two tokens on each line. The first token is the name
- to map, and the second token is the actual name to use. */
-
-struct file_name_map
-{
- struct file_name_map *map_next;
- cstring map_from;
- cstring map_to;
-};
-
-/*@constant observer char *FILE_NAME_MAP_FILE*/
-#define FILE_NAME_MAP_FILE "header.gcc"
-
-/* Read a space delimited string of unlimited length from a stdio
- file. */
-
-static cstring read_filename_string (int ch, /*:open:*/ FILE *f)
-{
- char *alloc, *set;
- size_t len;
-
- len = 20;
- set = alloc = dmalloc (len + 1);
-
- if (!is_space[ch])
- {
- *set++ = ch;
- while ((ch = getc (f)) != EOF && ! is_space[ch])
- {
- if (set - alloc == size_toInt (len))
- {
- len *= 2;
- alloc = drealloc (alloc, len + 1);
- set = alloc + len / 2;
- /*@-branchstate@*/ }
-
- *set++ = ch;
- } /*@=branchstate@*/
- }
- *set = '\0';
- check (ungetc (ch, f) != EOF);
-
- return cstring_fromChars (alloc);
-}
-
-/* This structure holds a linked list of file name maps, one per directory. */
-
-struct file_name_map_list
-{
- struct file_name_map_list *map_list_next;
- cstring map_list_name;
- struct file_name_map *map_list_map;
-};
-
-/* Read the file name map file for DIRNAME. */
-
-static struct file_name_map *
-read_name_map (cppReader *pfile, cstring dirname)
-{
- struct file_name_map_list *map_list_ptr;
- cstring name;
- FILE *f;
-
- for (map_list_ptr = CPPOPTIONS (pfile)->map_list;
- map_list_ptr != NULL;
- map_list_ptr = map_list_ptr->map_list_next)
- {
- if (cstring_equal (map_list_ptr->map_list_name, dirname))
- {
- return map_list_ptr->map_list_map;
- }
- }
-
- map_list_ptr = (struct file_name_map_list *) dmalloc (sizeof (*map_list_ptr));
- map_list_ptr->map_list_name = cstring_copy (dirname);
- map_list_ptr->map_list_map = NULL;
-
- name = cstring_copy (dirname);
-
- if (cstring_length (dirname) > 0)
- {
- name = cstring_appendChar (name, CONNECTCHAR);
- }
-
- name = cstring_concatFree1 (name, cstring_makeLiteralTemp (FILE_NAME_MAP_FILE));
-
- f = fileTable_openFile (context_fileTable (), name, "r");
- cstring_free (name);
-
- if (f == NULL)
- {
- map_list_ptr->map_list_map = NULL;
- }
- else
- {
- int ch;
-
- while ((ch = getc (f)) != EOF)
- {
- cstring from, to;
- struct file_name_map *ptr;
-
- if (is_space[ch])
- {
- continue;
- }
-
- from = read_filename_string (ch, f);
- while ((ch = getc (f)) != EOF && is_hor_space[ch])
- {
- ;
- }
-
- to = read_filename_string (ch, f);
-
- ptr = (struct file_name_map *) dmalloc (sizeof (*ptr));
- ptr->map_from = from;
-
- /* Make the real filename absolute. */
- if (cstring_length (to) > 1
- && osd_isConnectChar (cstring_firstChar (to)))
- {
- ptr->map_to = to;
- }
- else
- {
- ptr->map_to = cstring_copy (dirname);
- ptr->map_to = cstring_appendChar (ptr->map_to, CONNECTCHAR);
- ptr->map_to = cstring_concatFree (ptr->map_to, to);
- }
-
- ptr->map_next = map_list_ptr->map_list_map;
- map_list_ptr->map_list_map = ptr;
-
- while ((ch = getc (f)) != '\n')
- {
- if (ch == EOF)
- {
- /*@innerbreak@*/ break;
- }
- }
- }
-
- assertSet (map_list_ptr->map_list_map);
- check (fileTable_closeFile (context_fileTable (),f) == 0);
- }
-
- map_list_ptr->map_list_next = pfile->opts->map_list;
- pfile->opts->map_list = map_list_ptr;
-
- return map_list_ptr->map_list_map;
-}
-
-/* Try to open include file FILENAME. SEARCHPTR is the directory
- being tried from the include file search path. This function maps
- filenames on file systems based on information read by
- read_name_map. */
-
-static int
-open_include_file (cppReader *pfile,
- cstring fname,
- struct file_name_list *searchptr)
-{
- char *filename = cstring_toCharsSafe (fname);
- struct file_name_map *map;
- char *from;
- char *p, *dir;
-
- cstring_markOwned (fname);
-
- cpp_setLocation (pfile);
-
- if (context_getFlag (FLG_NEVERINCLUDE))
- {
- if (isHeaderFile (fname))
- {
- return SKIP_INCLUDE;
- }
- }
-
- if ((searchptr != NULL) && ! searchptr->got_name_map)
- {
- searchptr->name_map = read_name_map (pfile,
- !cstring_isEmpty (searchptr->fname)
- ? searchptr->fname :
- cstring_makeLiteralTemp ("."));
- searchptr->got_name_map = 1;
- }
-
- /* First check the mapping for the directory we are using. */
-
- if ((searchptr != NULL)
- && (searchptr->name_map != NULL))
- {
- from = filename;
-
- if (!cstring_isEmpty (searchptr->fname))
- {
- from += cstring_length (searchptr->fname) + 1;
- }
-
- for (map = searchptr->name_map;
- map != NULL;
- map = map->map_next)
- {
- if (cstring_equal (map->map_from, cstring_fromChars (from)))
- {
- /*
- ** Found a match. Check if the file should be skipped
- */
-
- if (cpp_skipIncludeFile (map->map_to))
- {
- return SKIP_INCLUDE;
- }
- else
- {
- return cpp_openIncludeFile (cstring_toCharsSafe (map->map_to));
- }
- }
- }
- }
-
- /*
- ** Try to find a mapping file for the particular directory we are
- ** looking in. Thus #include <sys/types.h> will look up sys/types.h
- ** in /usr/include/header.gcc and look up types.h in
- ** /usr/include/sys/header.gcc.
- */
-
- p = strrchr (filename, CONNECTCHAR);
-
- if (p == NULL)
- {
- p = filename;
- }
-
- if ((searchptr != NULL)
- && (cstring_isDefined (searchptr->fname))
- && (cstring_length (searchptr->fname) == p - filename)
- && !strncmp (cstring_toCharsSafe (searchptr->fname),
- filename,
- size_fromInt (p - filename)))
- {
- /* filename is in SEARCHPTR, which we've already checked. */
-
- if (cpp_skipIncludeFile (cstring_fromChars (filename)))
- {
- return SKIP_INCLUDE;
- }
- else
- {
- return cpp_openIncludeFile (filename);
- }
- }
-
- if (p == filename)
- {
- dir = mstring_copy (".");
- from = filename;
- }
- else
- {
- dir = (char *) dmalloc (size_fromInt (p - filename + 1));
- memcpy (dir, filename, size_fromInt (p - filename));
- dir[p - filename] = '\0';
- from = p + 1;
- }
-
- for (map = read_name_map (pfile, cstring_fromChars (dir));
- map != NULL;
- map = map->map_next)
- {
- if (cstring_equal (map->map_from, cstring_fromChars (from)))
- {
- sfree (dir);
-
- if (cpp_skipIncludeFile (map->map_to))
- {
- return SKIP_INCLUDE;
- }
- else
- {
- return cpp_openIncludeFile (cstring_toCharsSafe (map->map_to));
- }
- }
- }
-
- sfree (dir);
-
- if (cpp_skipIncludeFile (cstring_fromChars (filename)))
- {
- return SKIP_INCLUDE;
- }
- else
- {
- return cpp_openIncludeFile (filename);
- }
-}
-
-/* Process the contents of include file FNAME, already open on descriptor F,
- with output to OP.
- SYSTEM_HEADER_P is 1 if this file resides in any one of the known
- "system" include directories (as decided by the `is_system_include'
- function above).
- DIRPTR is the link in the dir path through which this file was found,
- or 0 if the file name was absolute or via the current directory.
- Return 1 on success, 0 on failure.
-
- The caller is responsible for the cppReader_pushBuffer. */
-
-static int
-finclude (cppReader *pfile, int f,
- cstring fname,
- bool system_header_p,
- /*@dependent@*/ struct file_name_list *dirptr)
-{
- mode_t st_mode;
- size_t st_size;
- long i;
- int length = 0;
- cppBuffer *fp; /* For input stack frame */
-
- if (file_size_and_mode (f, &st_mode, &st_size) < 0)
- {
- cppReader_perrorWithName (pfile, fname);
- check (close (f) == 0);
- (void) cppReader_popBuffer (pfile);
- /*@-mustfree@*/
- return 0;
- /*@=mustfree@*/
- }
-
- fp = cppReader_getBuffer (pfile);
-
- /*@-temptrans@*/ /* fname shouldn't really be temp */
- fp->nominal_fname = fp->fname = fname;
- /*@=temptrans@*/
-
- fp->dir = dirptr;
- fp->system_header_p = system_header_p;
- fp->lineno = 1;
- fp->colno = 1;
- fp->cleanup = cppReader_fileCleanup;
-
- if (S_ISREG (st_mode))
- {
- sfree (fp->buf);
- fp->buf = (char *) dmalloc (st_size + 2);
- fp->alimit = fp->buf + st_size + 2;
- fp->cur = fp->buf;
-
- /* Read the file contents, knowing that st_size is an upper bound
- on the number of bytes we can read. */
- length = safe_read (f, fp->buf, size_toInt (st_size));
- fp->rlimit = fp->buf + length;
- if (length < 0) goto nope;
- }
- else if (S_ISDIR (st_mode))
- {
- cppReader_error (pfile,
- message ("Directory specified in #include: %s", fname));
- check (close (f) == 0);
- return 0;
- }
- else
- {
- /*
- ** Cannot count its file size before reading.
- ** First read the entire file into heap and
- ** copy them into buffer on stack.
- */
-
- size_t bsize = 2000;
-
- st_size = 0;
-
- sfree (fp->buf);
- fp->buf = (char *) dmalloc (bsize + 2);
-
- for (;;) {
- i = safe_read (f, fp->buf + st_size, size_toInt (bsize - st_size));
-
- if (i < 0)
- goto nope; /* error! */
- st_size += i;
-
- if (st_size != bsize)
- {
- break; /* End of file */
- }
-
- bsize *= 2;
- fp->buf = (char *) drealloc (fp->buf, bsize + 2);
- }
-
- fp->cur = fp->buf;
- length = size_toInt (st_size);
- }
-
- if ((length > 0 && fp->buf[length - 1] != '\n')
- /* Backslash-newline at end is not good enough. */
- || (length > 1 && fp->buf[length - 2] == '\\')) {
- fp->buf[length++] = '\n';
- }
-
- fp->buf[length] = '\0';
- fp->rlimit = fp->buf + length;
-
- /* Close descriptor now, so nesting does not use lots of descriptors. */
- check (close (f) == 0);
-
- /* Must do this before calling trigraph_pcp, so that the correct file name
- will be printed in warning messages. */
-
- pfile->input_stack_listing_current = 0;
- return 1;
-
- nope:
-
- cppReader_perrorWithName (pfile, fname);
- check (close (f) == 0);
- sfree (fp->buf);
- return 1;
-}
-
-void
-cppReader_init (cppReader *pfile)
-{
- memset ((char *) pfile, 0, sizeof (*pfile));
-
- pfile->get_token = cppGetToken;
- pfile->token_buffer_size = 200;
- pfile->token_buffer = (char *) dmalloc (pfile->token_buffer_size);
- pfile->all_include_files = NULL;
-
- assertSet (pfile);
-
- cppReader_setWritten (pfile, 0);
-
- pfile->system_include_depth = 0;
- pfile->max_include_len = 0;
- pfile->timebuf = NULL;
- pfile->only_seen_white = 1;
-
- pfile->buffer = cppReader_nullBuffer (pfile);
-}
-
-void
-cppReader_finish (/*@unused@*/ cppReader *pfile)
-{
- ;
-}
-
-/* Free resources used by PFILE.
- This is the cppReader 'finalizer' or 'destructor' (in C++ terminology). */
-
-void
-cppCleanup (cppReader *pfile)
-{
- while (CPPBUFFER (pfile) != cppReader_nullBuffer (pfile))
- {
- (void) cppReader_popBuffer (pfile);
- }
-
- if (pfile->token_buffer != NULL)
- {
- sfree (pfile->token_buffer);
- pfile->token_buffer = NULL;
- }
-
- while (pfile->if_stack != NULL)
- {
- cppIfStackFrame *temp = pfile->if_stack;
- pfile->if_stack = temp->next;
- sfree (temp);
- }
-
- while (pfile->all_include_files != NULL)
- {
- struct file_name_list *temp = pfile->all_include_files;
- pfile->all_include_files = temp->next;
- /*@-dependenttrans@*/
- cstring_free (temp->fname);
- /*@=dependenttrans@*/
- sfree (temp);
- }
-
- cppReader_hashCleanup ();
-}
-
-/*
-** Get the file-mode and data size of the file open on FD
-** and store them in *MODE_POINTER and *SIZE_POINTER.
-*/
-
-static int
-file_size_and_mode (int fd, mode_t *mode_pointer, size_t *size_pointer)
-{
- struct stat sbuf;
-
- if (fstat (fd, &sbuf) < 0) {
- return (-1);
- }
-
- if (mode_pointer != NULL)
- {
- *mode_pointer = sbuf.st_mode;
- }
-
- if (size_pointer != NULL)
- {
- *size_pointer = (size_t) sbuf.st_size;
- }
-
- return 0;
-}
-
-/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,
- retrying if necessary. Return a negative value if an error occurs,
- otherwise return the actual number of bytes read,
- which must be LEN unless end-of-file was reached. */
-
-static int safe_read (int desc, char *ptr, int len)
-{
- int left = len;
-
- while (left > 0)
- {
-# if defined (WIN32) || defined (OS2) && defined (__IBMC__)
- /*@-compdef@*/ /* ptr is an out parameter */
- int nchars = _read (desc, ptr, (unsigned) left);
- /*@=compdef@*/
-# else
- ssize_t nchars = read (desc, ptr, size_fromInt (left));
-# endif
-
- if (nchars < 0)
- {
-#ifdef EINTR
- if (errno == EINTR)
- continue;
-#endif
- return (int) nchars;
- }
-
- if (nchars == 0) {
- break;
- }
-
- ptr += nchars;
- left -= nchars;
- }
-
- return len - left;
-}
-
-/* Initialize PMARK to remember the current position of PFILE. */
-
-void
-parseSetMark (struct parse_marker *pmark, cppReader *pfile)
-{
- cppBuffer *pbuf = cppReader_getBuffer (pfile);
-
- pmark->next = pbuf->marks;
- /*@-temptrans@*/
- pbuf->marks = pmark;
- /*@=temptrans@*/
-
- pmark->buf = pbuf;
- pmark->position = pbuf->cur - pbuf->buf;
-}
-
-/* Cleanup PMARK - we no longer need it. */
-
-void parseClearMark (struct parse_marker *pmark)
-{
- struct parse_marker **pp = &pmark->buf->marks;
-
- for (; ; pp = &(*pp)->next)
- {
- llassert (*pp != NULL);
- if (*pp == pmark) break;
- }
-
- *pp = pmark->next;
-}
-
-/* Backup the current position of PFILE to that saved in PMARK. */
-
-void
-parseGotoMark (struct parse_marker *pmark, cppReader *pfile)
-{
- cppBuffer *pbuf = cppReader_getBuffer (pfile);
-
- if (pbuf != pmark->buf)
- {
- cpp_setLocation (pfile);
- llfatalbug (cstring_makeLiteral ("Internal error parseGotoMark"));
- }
-
- llassert (pbuf->buf != NULL);
- pbuf->cur = pbuf->buf + pmark->position;
-}
-
-/* Reset PMARK to point to the current position of PFILE. (Same
- as parseClearMark (PMARK), parseSetMark (PMARK, PFILE) but faster. */
-
-void
-parseMoveMark (struct parse_marker *pmark, cppReader *pfile)
-{
- cppBuffer *pbuf = cppReader_getBuffer (pfile);
-
- if (pbuf != pmark->buf)
- {
- cpp_setLocation (pfile);
- llfatalerror (cstring_makeLiteral ("Internal error parseMoveMark"));
- }
-
- pmark->position = pbuf->cur - pbuf->buf;
-}
-
-void cppReader_initializeReader (cppReader *pfile) /* Must be done after library is loaded. */
-{
- struct cppOptions *opts = CPPOPTIONS (pfile);
- cstring xp;
-
- /* The code looks at the defaults through this pointer, rather than through
- the constant structure above. This pointer gets changed if an environment
- variable specifies other defaults. */
-
- struct default_include *include_defaults = include_defaults_array;
-
- /* Add dirs from INCLUDEPATH_VAR after dirs from -I. */
- /* There seems to be confusion about what CPATH should do,
- so for the moment it is not documented. */
- /* Some people say that CPATH should replace the standard include dirs,
- but that seems pointless: it comes before them, so it overrides them
- anyway. */
-
- xp = osd_getEnvironmentVariable (INCLUDEPATH_VAR);
-
- if (cstring_isDefined (xp) && !opts->no_standard_includes)
- {
- path_include (pfile, cstring_toCharsSafe (xp));
- }
-
- /* Now that dollars_in_ident is known, initialize is_idchar. */
- initialize_char_syntax (opts);
-
- /* CppReader_Install __LINE__, etc. Must follow initialize_char_syntax
- and option processing. */
-
- initialize_builtins (pfile);
-
- /* Do standard #defines and assertions
- that identify system and machine type. */
-
- if (!opts->inhibit_predefs) {
- char *p = (char *) dmalloc (strlen (predefs) + 1);
- strcpy (p, predefs);
-
- while (*p)
- {
- char *q;
-
- while (*p == ' ' || *p == '\t')
- {
- p++;
- }
-
- /* Handle -D options. */
- if (p[0] == '-' && p[1] == 'D')
- {
- q = &p[2];
-
- while (*p && *p != ' ' && *p != '\t')
- {
- p++;
- }
-
- if (*p != 0)
- {
- *p++= 0;
- }
-
- if (opts->debug_output)
- {
- output_line_command (pfile, 0, same_file);
- }
-
- cppReader_define (pfile, q);
-
- while (*p == ' ' || *p == '\t')
- {
- p++;
- }
- }
- else
- {
- abort ();
- }
- }
-
- sfree (p);
- }
-
- opts->done_initializing = 1;
-
- { /* Read the appropriate environment variable and if it exists
- replace include_defaults with the listed path. */
- char *epath = 0;
-#ifdef __CYGWIN32__
- char *win32epath;
- int win32_buf_size = 0; /* memory we need to allocate */
-#endif
-
- if (opts->cplusplus)
- {
- epath = getenv ("CPLUS_INCLUDE_PATH");
- }
- else
- {
- epath = getenv ("C_INCLUDE_PATH");
- }
-
- /*
- ** If the environment var for this language is set,
- ** add to the default list of include directories.
- */
-
- if (epath != NULL) {
- char *nstore = (char *) dmalloc (strlen (epath) + 2);
- int num_dirs;
- char *startp, *endp;
-
-#ifdef __CYGWIN32__
- /* if we have a posix path list, convert to win32 path list */
- if (cygwin32_posix_path_list_p (epath))
- {
- win32_buf_size = cygwin32_posix_to_win32_path_list_buf_size (epath);
- win32epath = (char *) dmalloc /*@i4@*/ (win32_buf_size);
- cygwin32_posix_to_win32_path_list (epath, win32epath);
- epath = win32epath;
- }
-#endif
- for (num_dirs = 1, startp = epath; *startp; startp++)
- {
- if (*startp == PATH_SEPARATOR)
- num_dirs++;
- }
-
- /*@-sizeoftype@*/
- include_defaults
- = (struct default_include *) dmalloc ((num_dirs
- * sizeof (struct default_include))
- + sizeof (include_defaults_array));
- /*@=sizeoftype@*/
-
- startp = endp = epath;
- num_dirs = 0;
- while (1) {
- /* Handle cases like c:/usr/lib:d:/gcc/lib */
- if ((*endp == PATH_SEPARATOR) || *endp == 0)
- {
- strncpy (nstore, startp, size_fromInt (endp - startp));
- if (endp == startp)
- {
- strcpy (nstore, ".");
- }
- else
- {
- nstore[endp-startp] = '\0';
- }
-
- include_defaults[num_dirs].fname = cstring_fromCharsNew (nstore);
- include_defaults[num_dirs].cplusplus = opts->cplusplus;
- include_defaults[num_dirs].cxx_aware = 1;
- num_dirs++;
-
- if (*endp == '\0')
- {
- break;
- }
- endp = startp = endp + 1;
- }
- else
- {
- endp++;
- }
- }
- /* Put the usual defaults back in at the end. */
- memcpy ((char *) &include_defaults[num_dirs],
- (char *) include_defaults_array,
- sizeof (include_defaults_array));
-
- sfree (nstore);
- /*@-branchstate@*/ } /*@=branchstate@*/
- }
-
- cppReader_appendIncludeChain (pfile, opts->before_system,
- opts->last_before_system);
- opts->first_system_include = opts->before_system;
-
- /* Unless -fnostdinc,
- tack on the standard include file dirs to the specified list */
- if (!opts->no_standard_includes) {
- struct default_include *p = include_defaults;
- char *specd_prefix = opts->include_prefix;
- char *default_prefix = mstring_copy (GCC_INCLUDE_DIR);
- int default_len = 0;
-
- /* Remove the `include' from /usr/local/lib/gcc.../include. */
- if (default_prefix != NULL) {
- if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) {
- default_len = strlen (default_prefix) - 7;
- default_prefix[default_len] = 0;
- }
- }
-
- /* Search "translated" versions of GNU directories.
- These have /usr/local/lib/gcc... replaced by specd_prefix. */
- if (specd_prefix != 0 && default_len != 0)
- for (p = include_defaults; p->fname != NULL; p++) {
- /* Some standard dirs are only for C++. */
- if (!p->cplusplus
- || (opts->cplusplus && !opts->no_standard_cplusplus_includes)) {
- /* Does this dir start with the prefix? */
- if (!strncmp (cstring_toCharsSafe (p->fname), default_prefix,
- size_fromInt (default_len)))
- {
- /* Yes; change prefix and add to search list. */
- struct file_name_list *nlist
- = (struct file_name_list *) dmalloc (sizeof (*nlist));
- size_t this_len = strlen (specd_prefix) + cstring_length (p->fname) - default_len;
- char *str = (char *) dmalloc (this_len + 1);
- strcpy (str, specd_prefix);
- strcat (str, cstring_toCharsSafe (p->fname) + default_len);
-
- nlist->next = NULL;
- nlist->fname = cstring_fromChars (str);
- nlist->control_macro = 0;
- nlist->c_system_include_path = !p->cxx_aware;
- nlist->got_name_map = 0;
-
- cppReader_addIncludeChain (pfile, nlist);
- if (opts->first_system_include == 0)
- {
- opts->first_system_include = nlist;
- }
- }
- }
- }
-
- /* Search ordinary names for GNU include directories. */
-
- for (p = include_defaults; p->fname != NULL; p++)
- {
- /* Some standard dirs are only for C++. */
- if (!p->cplusplus
- || (opts->cplusplus && !opts->no_standard_cplusplus_includes))
- {
- struct file_name_list *nlist
- = (struct file_name_list *) dmalloc (sizeof (*nlist));
- nlist->control_macro = 0;
- nlist->c_system_include_path = !p->cxx_aware;
- nlist->fname = p->fname;
- nlist->got_name_map = 0;
- nlist->next = NULL;
-
- cppReader_addIncludeChain (pfile, nlist);
-
- if (opts->first_system_include == 0)
- {
- opts->first_system_include = nlist;
- }
- }
- }
- sfree (default_prefix);
- }
-
- /* Tack the after_include chain at the end of the include chain. */
- cppReader_appendIncludeChain (pfile, opts->after_include,
- opts->last_after_include);
-
- if (opts->first_system_include == 0)
- {
- opts->first_system_include = opts->after_include;
- }
-
- /* With -v, print the list of dirs to search. */
- if (opts->verbose) {
- struct file_name_list *p;
- fprintf (stderr, "#include \"...\" search starts here:\n");
-
- for (p = opts->include; p != NULL; p = p->next) {
- if (p == opts->first_bracket_include)
- fprintf (stderr, "#include <...> search starts here:\n");
-
- fprintf (stderr, " %s\n", cstring_toCharsSafe (p->fname));
- }
- fprintf (stderr, "End of search list.\n");
- }
-}
-
-int cppReader_startProcess (cppReader *pfile, cstring fname)
-{
- cppBuffer *fp;
- int f;
- struct cppOptions *opts = CPPOPTIONS (pfile);
-
- fp = cppReader_pushBuffer (pfile, NULL, 0);
-
- if (fp == NULL)
- {
- return 0;
- }
-
- if (opts->in_fname == NULL)
- {
- opts->in_fname = cstring_makeLiteralTemp ("");
- }
-
- fp->fname = opts->in_fname;
- fp->nominal_fname = fp->fname;
- fp->lineno = 0;
-
- /* Copy the entire contents of the main input file into
- the stacked input buffer previously allocated for it. */
-
- if (cstring_isEmpty (fname))
- {
- fname = cstring_makeLiteralTemp ("");
- f = 0;
- }
- else if ((f = open (cstring_toCharsSafe (fname), O_RDONLY, 0666)) < 0)
- {
- cppReader_error (pfile,
- message ("Error opening %s for reading: %s",
- fname, lldecodeerror (errno)));
-
- return 0;
- }
- else
- {
- ;
- }
-
- if (finclude (pfile, f, fname, 0, NULL))
- {
- output_line_command (pfile, 0, same_file);
- }
-
- return 1;
-}
-
-static /*@exposed@*/ /*@null@*/ cppBuffer *cppReader_getBuffer (cppReader *pfile)
-{
- return pfile->buffer;
-}
-
-/*@exposed@*/ cppBuffer *cppReader_getBufferSafe (cppReader *pfile)
-{
- llassert (pfile->buffer != NULL);
- return pfile->buffer;
-}
-
-/*@exposed@*/ char *cppLineBase (cppBuffer *buf)
-{
- llassert (buf->buf != NULL);
- return (buf->buf + buf->line_base);
-}
-
-int cppBufPeek (cppBuffer *buf)
-{
- if (buf->cur == NULL || buf->rlimit == NULL) {
- return EOF;
- }
-
- if (buf->cur < buf->rlimit) {
- return *(buf->cur);
- }
-
- return EOF;
-}
-
-bool cppBuffer_isMacro (cppBuffer *buf)
-{
- if (buf != NULL)
- {
- return (buf->cleanup == cppReader_macroCleanup);
- }
-
- return FALSE;
-}
-
-/*
-** Returns true if the macro should be checked, false
-** if it should be expanded normally.
-*/
-
-static bool notparseable = FALSE; /* preceeded by @notparseable@ */
-static bool notfunction = FALSE; /* preceeded by @notfunction@ */
-static bool expectiter = FALSE; /* preceeded by @iter@ */
-static bool expectenditer = FALSE; /* second after @iter@ */
-static bool expectfunction = FALSE; /* preceeded by @function@ */
-static bool expectconstant = FALSE; /* preceeded by @constant@ */
-static bool expectmacro = FALSE; /* preceeded by notfunction or notparseable */
-
-static void cpp_setLocation (cppReader *pfile)
-{
- fileId fid;
- int line;
-
- if (pfile->buffer != NULL)
- {
- if (cstring_isDefined (cppReader_getBuffer (pfile)->nominal_fname))
- {
- cstring fname = cppReader_getBuffer (pfile)->nominal_fname;
-
- DPRINTF (("Looking up: %s", fname));
-
- if (fileTable_exists (context_fileTable (), fname))
- {
- fid = fileTable_lookup (context_fileTable (), fname);
- }
- else
- {
- DPRINTF (("Trying %s", cppReader_getBuffer (pfile)->fname));
-
- fid = fileTable_lookup (context_fileTable (),
- cppReader_getBuffer (pfile)->fname);
- }
- }
- else
- {
- fid = fileTable_lookup (context_fileTable (),
- cppReader_getBuffer (pfile)->fname);
- }
-
- line = cppReader_getBuffer (pfile)->lineno;
- fileloc_free (g_currentloc);
-
- if (fileId_isValid (fid))
- {
- g_currentloc = fileloc_create (fid, line, 1);
- }
- else
- {
- g_currentloc = fileloc_createBuiltin ();
- }
- }
- else
- {
- fileloc_free (g_currentloc);
- g_currentloc = fileloc_createBuiltin ();
- }
-}
-
-static bool cpp_shouldCheckMacro (cppReader *pfile, char *p) /*@*/
-{
- bool checkmacro = FALSE;
- bool hasParams = FALSE;
- bool noexpand = FALSE;
- cstring sname;
- char c;
-
- cpp_setLocation (pfile);
-
- DPRINTF (("Should check macro? %s", p));
-
- if (expectiter || expectconstant || expectenditer)
- {
- if (expectiter)
- {
- expectiter = FALSE;
- expectenditer = TRUE;
- }
- else
- {
- expectiter = FALSE;
- expectconstant = FALSE;
- expectenditer = FALSE;
- }
-
- if (notfunction || notparseable)
- {
- notfunction = FALSE;
- notparseable = FALSE;
- return FALSE;
- }
- else
- {
- return TRUE;
- }
- }
-
- llassert (*p == '#');
- p++;
-
- while (*p == ' ' || *p == '\t')
- {
- p++;
- }
-
- llassert (*p == 'd'); /* define starts */
-
- p += 6;
-
- while (*p == ' ' || *p == '\t')
- {
- p++;
- }
-
- sname = cstring_fromChars (p);
- DPRINTF (("Check macro: %s", sname));
-
- while (((c = *p) != ' ')
- && c != '\0' && c != '('
- && c != '\t' && c != '\\' && c != '\n'
- && !iscntrl (c))
- {
- p++;
- }
-
- hasParams = (c == '(');
- *p = '\0';
-
-
- if (notparseable)
- {
- notparseable = FALSE;
- }
- else if (notfunction || fileloc_isStandardLib (g_currentloc))
- {
- DPRINTF (("Clear notfunction"));
- notfunction = FALSE;
- }
- else
- {
- if (noexpand)
- {
- checkmacro = TRUE;
-
- if (!expectenditer)
- {
- noexpand = FALSE;
- }
- }
- else
- {
- if (usymtab_existsReal (sname))
- {
- uentry ue = usymtab_lookup (sname);
-
- DPRINTF (("Lookup macro: %s", uentry_unparse (ue)));
-
- if (fileloc_isPreproc (uentry_whereLast (ue)))
- {
- goto macroDne;
- }
- else
- {
- if (uentry_isSpecified (ue))
- {
- checkmacro = context_getFlag (FLG_SPECMACROS);
- }
- else
- {
- if (hasParams)
- {
- checkmacro = context_getFlag (FLG_LIBMACROS)
- || context_getFlag (FLG_FCNMACROS);
- }
- }
- }
- }
- else
- {
- macroDne:
- DPRINTF (("Macro doesn't exist: %s", bool_unparse (checkmacro)));
-
- if (fileloc_isSystemFile (g_currentloc)
- && context_getFlag (FLG_SYSTEMDIREXPAND))
- {
- ; /* don't check this macro */
- DPRINTF (("Don't check 1"));
- }
- else
- {
- uentry le;
-
- if (hasParams)
- {
- DPRINTF (("Has params..."));
-
- if (context_getFlag (FLG_FCNMACROS))
- {
- if (usymtab_exists (sname))
- {
- /*
- ** only get here is macro is redefined
- ** error reported elsewhere
- */
-
- DPRINTF (("It exists!"));
- }
- else
- {
- /*
- ** We make it a forward function, since it might be declared elsewhere.
- ** After all headers have been processed, we should check the forward
- ** functions.
- */
-
- fileloc loc = fileloc_makePreproc (g_currentloc);
-
- /* the line is off-by-one, since the newline was already read */
- decLine ();
-
- if (expectfunction)
- {
- expectfunction = FALSE;
- }
-
- le = uentry_makeForwardFunction (sname,
- typeId_invalid, loc);
-
- fileloc_free (loc);
-
- incLine ();
-
- /* Do not define here! */
-
- (void) usymtab_addEntry (le);
- }
-
- checkmacro = TRUE;
- DPRINTF (("Check: TRUE"));
- }
- else
- {
- DPRINTF (("Flag FCN_MACROS not set!"));
- }
- }
- else
- {
- DPRINTF (("No params"));
-
- if (context_getFlag (FLG_CONSTMACROS))
- {
- bool nocontent = FALSE;
-
- if (c == '\0')
- {
- nocontent = TRUE;
- }
- else
- {
- if (isspace (c))
- {
- char *rest = p + 1;
-
- /*
- ** Check if there is nothing after the define.
- */
-
- while ((*rest) != '\0' && isspace (*rest))
- {
- rest++;
- }
-
- if (*rest == '\0')
- {
- nocontent = TRUE; /* empty macro, don't check */
- }
- }
- }
-
- if (usymtab_exists (sname))
- {
- ;
- }
- else
- {
- fileloc loc = fileloc_makePreproc (g_currentloc);
- DPRINTF (("Make constant: %s", sname));
- le = uentry_makeConstant (sname,
- ctype_unknown, loc);
- (void) usymtab_addEntry (le);
- }
-
- checkmacro = !nocontent;
- }
- }
- }
-
- if (checkmacro && usymtab_existsType (sname))
- {
- DPRINTF (("Making false..."));
- decLine ();
- ppllerror (message ("Specified type implemented as macro: %s", sname));
- checkmacro = FALSE;
- incLine ();
- }
- }
- }
- }
-
- if (!checkmacro)
- {
- if (usymtab_exists (sname))
- {
- uentry ue = usymtab_lookupExpose (sname);
- fileloc tloc = fileloc_makePreproc (g_currentloc);
-
- uentry_setDefined (ue, tloc);
- fileloc_free (tloc);
- uentry_setUsed (ue, fileloc_undefined);
- }
- else
- {
- fileloc tloc = fileloc_makePreproc (g_currentloc);
- uentry ue = uentry_makeExpandedMacro (sname, tloc);
- DPRINTF (("Make expanded macro: %s", sname));
- DPRINTF (("Not in symbol table: %s", sname));
-
- (void) usymtab_addGlobalEntry (ue);
- fileloc_free (tloc);
- }
- }
-
- *p = c;
- DPRINTF (("Returning: %s", bool_unparse (checkmacro)));
- return checkmacro;
-}
-
-static enum cpp_token
-cpp_handleComment (cppReader *pfile, struct parse_marker *smark)
-{
- cppBuffer *pbuf = cppReader_getBuffer (pfile);
- char *start;
- int len;
- bool eliminateComment = FALSE;
-
- llassert (pbuf->buf != NULL);
-
- start = pbuf->buf + smark->position;
-
- llassert (pbuf->cur != NULL);
- len = pbuf->cur - start;
-
- if (start[0] == '*'
- && start[1] == context_getCommentMarkerChar ())
- {
- int i;
- char c = ' ';
- char *scomment = start + 2;
- char savec = start[len];
-
- start[0] = BEFORE_COMMENT_MARKER[0];
- start[1] = BEFORE_COMMENT_MARKER[1];
-
- llassert (start[len - 2] == '*');
- start[len - 2] = AFTER_COMMENT_MARKER[0];
-
- llassert (start[len - 1] == '/');
- start[len - 1] = AFTER_COMMENT_MARKER[1];
-
- cppReader_reserve(pfile, size_fromInt (1 + len));
- cppReader_putCharQ (pfile, c);
-
- cpp_setLocation (pfile);
-
- start[len] = '\0';
-
- if (mstring_containsString (scomment, "/*"))
- {
- (void) cppoptgenerror
- (FLG_NESTCOMMENT,
- message ("Comment starts inside syntactic comment: %s",
- cstring_fromChars (scomment)),
- pfile);
- }
-
- start[len] = savec;
-
- if (mstring_equalPrefix (scomment, "ignore"))
- {
- if (!context_getFlag (FLG_NOCOMMENTS))
- {
- context_enterSuppressRegion ();
- }
- }
- else if (mstring_equalPrefix (scomment, "end"))
- {
- if (!context_getFlag (FLG_NOCOMMENTS))
- {
- context_exitSuppressRegion ();
- }
- }
- else if (mstring_equalPrefix (scomment, "notparseable"))
- {
- notparseable = TRUE;
- expectmacro = TRUE;
- eliminateComment = TRUE;
- }
- else if (mstring_equalPrefix (scomment, "notfunction"))
- {
- notfunction = TRUE;
- expectmacro = TRUE;
- eliminateComment = TRUE;
- }
- else if (mstring_equalPrefix (scomment, "iter"))
- {
- expectiter = TRUE;
- }
- else if (mstring_equalPrefix (scomment, "function"))
- {
- expectfunction = TRUE;
- }
- else if (mstring_equalPrefix (scomment, "constant"))
- {
- expectconstant = TRUE;
- }
- else
- {
- char sChar = *scomment;
-
- if (sChar == '='
- || sChar == '-'
- || sChar == '+')
- {
- char *rest = scomment + 1;
-
- if (mstring_equalPrefix (rest, "commentchar"))
- {
- eliminateComment = TRUE;
-
- if (sChar == '=')
- {
- ppllerror (cstring_makeLiteral
- ("Cannot restore commentchar"));
- }
- else
- {
- char *next = scomment + 12; /* strlen commentchar = 12 */
-
- if (*next != ' ' && *next != '\t' && *next != '\n')
- {
- ppllerror
- (message
- ("Syntactic commentchar comment is not followed by a "
- "whitespace character: %c",
- *next));
- }
- else
- {
- char cchar = *(next + 1);
-
- if (cchar == '\0')
- {
- ppllerror
- (cstring_makeLiteral
- ("Cannot set commentchar to NUL"));
- }
- else
- {
- context_setCommentMarkerChar (cchar);
- /* setComment = TRUE; */
- }
- }
- }
- }
- else if (mstring_equalPrefix (scomment, "nestcomment"))
- {
- /* fix from Mike Miller <MikeM@xata.com> */
- context_fileSetFlag (FLG_NESTCOMMENT,
- ynm_fromCodeChar (sChar));
- }
- else if (mstring_equalPrefix (rest, "namechecks"))
- {
- context_fileSetFlag (FLG_NAMECHECKS,
- ynm_fromCodeChar (sChar));
- }
- else if (mstring_equalPrefix (rest, "macroredef"))
- {
- context_fileSetFlag (FLG_MACROREDEF,
- ynm_fromCodeChar (sChar));
- }
- else if (mstring_equalPrefix (rest, "usevarargs"))
- {
- context_fileSetFlag (FLG_USEVARARGS,
- ynm_fromCodeChar (sChar));
- }
- else if (mstring_equalPrefix (rest, "nextlinemacros"))
- {
- context_fileSetFlag (FLG_MACRONEXTLINE,
- ynm_fromCodeChar (sChar));
- }
- else if (mstring_equalPrefix (rest, "allmacros")
- || mstring_equalPrefix (rest, "fcnmacros")
- || mstring_equalPrefix (rest, "constmacros"))
- {
- flagcode fl;
-
- if (mstring_equalPrefix (rest, "allmacros"))
- {
- fl = FLG_ALLMACROS;
- }
- else if (mstring_equalPrefix (rest, "fcnmacros"))
- {
- fl = FLG_FCNMACROS;
- }
- else
- {
- llassert (mstring_equalPrefix (rest, "constmacros"));
- fl = FLG_CONSTMACROS;
- }
-
-
- context_fileSetFlag (fl, ynm_fromCodeChar (sChar));
- notfunction = FALSE;
- }
- else
- {
- ;
- }
- }
- else
- {
- ;
- }
- }
-
- if (eliminateComment)
- {
- goto removeComment;
- }
-
- /* Replaces comment char's in start with spaces */
-
- for (i = 2; i < len - 2; i++)
- {
- if (start[i] == BEFORE_COMMENT_MARKER[0]
- || start[i] == BEFORE_COMMENT_MARKER[1]
- || start[i] == context_getCommentMarkerChar ())
- {
- start[i] = ' ';
- }
- }
-
- cppReader_putStrN (pfile, start, size_fromInt (len));
- parseClearMark (smark);
- return CPP_COMMENT;
- }
- else
- {
- removeComment:
- {
- int i;
-
- /*
- ** Output the comment as all spaces so line/column
- ** in output file is still correct.
- */
-
- char c = ' ';
- cstring lintcomment = cstring_undefined;
-
- if (context_getFlag (FLG_LINTCOMMENTS))
- {
- if (mstring_equalPrefix (start, "*NOTREACHED*/"))
- {
- lintcomment = cstring_makeLiteralTemp ("l_notreach");
- }
- else if (mstring_equalPrefix (start, "*PRINTFLIKE*/"))
- {
- lintcomment = cstring_makeLiteralTemp ("l_printfli");
- }
- else if (mstring_equalPrefix (start, "*FALLTHROUGH*/"))
- {
- lintcomment = cstring_makeLiteralTemp ("l_fallthrou");
- }
- else if (mstring_equalPrefix (start, "*ARGSUSED*/"))
- {
- lintcomment = cstring_makeLiteralTemp ("l_argsus");
- }
- else if (mstring_equalPrefix (start, "*FALLTHRU*/"))
- {
- lintcomment = cstring_makeLiteralTemp ("l_fallth");
- }
- else
- {
- lintcomment = cstring_undefined;
- }
- }
- else
- {
- lintcomment = cstring_undefined;
- }
-
- if (cstring_isDefined (lintcomment))
- {
- c = BEFORE_COMMENT_MARKER[0];
- start[0] = BEFORE_COMMENT_MARKER[1];
-
- llassert (cstring_length (lintcomment) == len - 3);
-
- for (i = 1; i < len - 2; i++)
- {
- start[i] = cstring_getChar (lintcomment, i);
- }
-
- start[len - 2] = AFTER_COMMENT_MARKER[0];
- start[len - 1] = AFTER_COMMENT_MARKER[1];
- }
- else
- {
- /* Replaces char's in start with spaces */
- for (i = 0; i < len; i++)
- {
- if (start[i] == '/'
- && i < len - 1
- && start[i + 1] == '*') {
- (void) cppoptgenerror (FLG_NESTCOMMENT,
- message ("Comment starts inside comment"),
- pfile);
- }
-
- if (start[i] != '\n')
- {
- start[i] = ' ';
- }
- }
- }
-
- cppReader_reserve (pfile, size_fromInt (1 + len));
- cppReader_putCharQ (pfile, c);
- cppReader_putStrN (pfile, start, size_fromInt (len));
- parseClearMark (smark);
- return CPP_COMMENT;
- }
- }
-}
-
-static int cpp_openIncludeFile (char *filename)
-{
- int res = open (filename, O_RDONLY, 0666);
-
- /* evans 2001-08-23: was (res) - open returns -1 on error! reported by Robin Watts */
- if (res >= 0)
- {
- if (!fileTable_exists (context_fileTable (),
- cstring_fromChars (filename)))
- {
- (void) fileTable_addHeaderFile (context_fileTable (),
- cstring_fromChars (filename));
- }
- else
- {
- DPRINTF (("File already exists: %s", filename));
- }
- }
-
- return res;
-}
-
-static bool cpp_skipIncludeFile (cstring fname)
-{
- if (context_isSystemDir (fname))
- {
- DPRINTF (("System dir: %s", fname));
-
- if (lcllib_isSkipHeader (fname))
- {
- DPRINTF (("Skip include TRUE: %s", fname));
- return TRUE;
- }
-
- if (context_getFlag (FLG_SKIPSYSHEADERS))
- {
- DPRINTF (("Skip include TRUE: %s", fname));
- return TRUE;
- }
- }
-
- if (context_getFlag (FLG_SINGLEINCLUDE))
- {
- fname = removePreDirs (fname);
-
-# if defined (WIN32) || defined (OS2)
- cstring_replaceAll (fname, '/', '\\');
-# endif
-
- if (fileTable_exists (context_fileTable (), fname))
- {
- DPRINTF (("Skip include TRUE: %s", fname));
- return TRUE;
- }
- }
-
- DPRINTF (("Skip include FALSE: %s", fname));
- return FALSE;
-}
-
-static int cpp_peekN (cppReader *pfile, int n)
-{
- cppBuffer *buf = cppReader_getBuffer (pfile);
-
- llassert (buf->cur != NULL);
-
- return (buf->rlimit - buf->cur >= (n)
- ? buf->cur[n]
- : EOF);
-}
-
-cppBuffer *cppBuffer_prevBuffer (cppBuffer *buf)
-{
- return buf + 1;
-}
-
-void cppBuffer_forward (cppBuffer *buf, int n)
-{
- llassert (buf->cur != NULL);
- buf->cur += n;
-}
+/*\r
+See\r
+http://src.openresources.com/debian/src/devel/HTML/S/altgcc_2.7.2.2.orig%20altgcc-2.7.2.2.orig%20protoize.c.html\r
+static char *\r
+abspath (cwd, rel_filename)\r
+\r
+*/\r
+\r
+/*!!!!\r
+*** cpplib.c.old Tue Nov 28 2000 09:04:09 AM\r
+--- cpplib.c Tue Nov 28 2000 08:55:18 AM\r
+***************\r
+*** 5715,5722 ****\r
+ c2 = cppReader_peekC (pfile)\r
+ if (c2 != '\n'\r
+ goto randomchar\r
+! token = CPP_HSPACE\r
+! goto op2any\r
+--- 5714,5723 ----\r
+ case '\\'\r
+ c2 = cppReader_peekC (pfile)\r
+ if (c2 != '\n'\r
+ goto randomchar\r
+! cppReader_forward (pfile, 1)\r
+! pfile->lineno++\r
+! return CPP_HSPACE\r
+ \r
+ \r
+ case '\n'\r
+ cppReader_putChar (pfile, c)\r
+\r
+\r
+Carl J. Appellof ( mailto:cappello@legato.com <mailto:cappello@legato.com> )\r
+*/ /*@i8@*/\r
+\r
+/*\r
+** LCLint - annotation-assisted static program checker\r
+** Copyright (C) 1994-2001 University of Virginia,\r
+** Massachusetts Institute of Technology\r
+**\r
+** This program is free software; you can redistribute it and/or modify it\r
+** under the terms of the GNU General Public License as published by the\r
+** Free Software Foundation; either version 2 of the License, or (at your\r
+** option) any later version.\r
+** \r
+** This program is distributed in the hope that it will be useful, but\r
+** WITHOUT ANY WARRANTY; without even the implied warranty of\r
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+** General Public License for more details.\r
+** \r
+** The GNU General Public License is available from http://www.gnu.org/ or\r
+** the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,\r
+** MA 02111-1307, USA.\r
+**\r
+** For information on lclint: lclint-request@cs.virginia.edu\r
+** To report a bug: lclint-bug@cs.virginia.edu\r
+** For more information: http://lclint.cs.virginia.edu\r
+*/\r
+/*\r
+** cpplib.c\r
+*/\r
+/*\r
+ Copyright (C) 1986, 87, 89, 92-6, 1997 Free Software Foundation, Inc.\r
+ Contributed by Per Bothner, 1994-95.\r
+ Based on CCCP program by Paul Rubin, June 1986\r
+ Adapted to ANSI C, Richard Stallman, Jan 1987\r
+\r
+This program is free software; you can redistribute it and/or modify it\r
+under the terms of the GNU General Public License as published by the\r
+Free Software Foundation; either version 2, or (at your option) any\r
+later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY; without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program; if not, write to the Free Software\r
+Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.\r
+\r
+ In other words, you are welcome to use, share and improve this program.\r
+ You are forbidden to forbid anyone else to use, share and improve\r
+ what you give them. Help stamp out software-hoarding! */\r
+\r
+/*\r
+ * Herbert 06/12/2000:\r
+ * - OS2 drive specs like WIN32\r
+ * - Includes for IBMs OS/2 compiler\r
+ */\r
+\r
+# include <ctype.h>\r
+# include <stdio.h>\r
+# include <signal.h>\r
+# ifdef __STDC__\r
+# include <stdlib.h>\r
+# endif\r
+\r
+# include <string.h>\r
+\r
+# if !(defined (WIN32) || defined (OS2) && defined (__IBMC__))\r
+# include <unistd.h>\r
+# endif\r
+\r
+# include <sys/types.h>\r
+# include <sys/stat.h>\r
+# include <fcntl.h>\r
+\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+# include <io.h>\r
+# include <sys/utime.h> /* for __DATE__ and __TIME__ */\r
+# include <time.h>\r
+# else\r
+# ifndef VMS\r
+# ifndef USG\r
+# include <time.h> /* Reported by Paul Smith */\r
+# include <sys/time.h>\r
+# include <sys/resource.h>\r
+# else\r
+# include <sys/times.h>\r
+# include <time.h>\r
+# include <fcntl.h>\r
+# endif /* USG */\r
+# endif /* not VMS */\r
+# endif /* not WIN32 */\r
+\r
+/* This defines "errno" properly for VMS, and gives us EACCES. */\r
+# include <errno.h>\r
+\r
+# include "lclintMacros.nf"\r
+# include "llbasic.h"\r
+# include "lcllib.h"\r
+# include "cpplib.h"\r
+# include "cpperror.h"\r
+# include "cpphash.h"\r
+# include "cppexp.h"\r
+# include "version.h"\r
+# include "portab.h"\r
+# include "osd.h"\r
+\r
+/*\r
+** This is really kludgey code...\r
+*/\r
+\r
+/*@+boolint@*/\r
+/*@+charint@*/\r
+\r
+#define NO_SHORTNAMES\r
+\r
+# ifdef open\r
+# undef open\r
+# undef read\r
+# undef write\r
+# endif /* open */\r
+\r
+/*@constant int IMPORT_FOUND@*/\r
+# define IMPORT_FOUND -2\r
+\r
+/*@constant int SKIP_INCLUDE@*/\r
+# define SKIP_INCLUDE IMPORT_FOUND\r
+\r
+/*@constant unused int IMPORT_NOT_FOUND@*/\r
+# define IMPORT_NOT_FOUND -1\r
+\r
+#ifndef STDC_VALUE\r
+/*@constant unused int STDC_VALUE@*/\r
+#define STDC_VALUE 1\r
+#endif\r
+\r
+/* By default, colon separates directories in a path. */\r
+#ifndef PATH_SEPARATOR\r
+/*@constant char PATH_SEPARATOR@*/\r
+#define PATH_SEPARATOR ':'\r
+#endif\r
+\r
+static void parse_name (cppReader *, int);\r
+\r
+static int cpp_openIncludeFile (char *p_filename)\r
+ /*@modifies fileSystem @*/ ;\r
+\r
+static void cpp_setLocation (cppReader *p_pfile)\r
+ /*@modifies g_currentloc@*/ ;\r
+\r
+static enum cpp_token cpp_handleComment (cppReader *p_pfile,\r
+ struct parse_marker *p_smark)\r
+ /*@modifies p_pfile, p_smark@*/;\r
+\r
+static bool cpp_shouldCheckMacro (cppReader *p_pfile, char *p_p) /*@*/ ;\r
+\r
+static bool cpp_skipIncludeFile (cstring p_fname) /*@*/ ;\r
+\r
+#ifndef O_RDONLY\r
+#define O_RDONLY 0\r
+#endif\r
+\r
+/* Symbols to predefine. */\r
+\r
+#ifdef CPP_PREDEFINES\r
+static /*@observer@*/ char *predefs = CPP_PREDEFINES;\r
+#else\r
+static /*@observer@*/ char *predefs = "";\r
+#endif\r
+\r
+/* We let tm.h override the types used here, to handle trivial differences\r
+ such as the choice of unsigned int or long unsigned int for size_t.\r
+ When machines start needing nontrivial differences in the size type,\r
+ it would be best to do something here to figure out automatically\r
+ from other information what type to use. */\r
+\r
+/* The string value for __SIZE_TYPE__. */\r
+\r
+#ifndef SIZE_TYPE\r
+/*@constant observer char *SIZE_TYPE@*/\r
+#define SIZE_TYPE "long unsigned int"\r
+#endif\r
+\r
+/* The string value for __PTRDIFF_TYPE__. */\r
+\r
+#ifndef PTRDIFF_TYPE\r
+/*@constant observer char *PTRDIFF_TYPE@*/\r
+#define PTRDIFF_TYPE "long int"\r
+#endif\r
+\r
+/* The string value for __WCHAR_TYPE__. */\r
+\r
+#ifndef WCHAR_TYPE\r
+/*@constant observer char *WCHAR_TYPE@*/\r
+#define WCHAR_TYPE "int"\r
+#endif\r
+\r
+/* The string value for __USER_LABEL_PREFIX__ */\r
+\r
+#ifndef USER_LABEL_PREFIX\r
+/*@constant observer char *USER_LABEL_PREFIX@*/\r
+#define USER_LABEL_PREFIX ""\r
+#endif\r
+\r
+/* The string value for __REGISTER_PREFIX__ */\r
+\r
+#ifndef REGISTER_PREFIX\r
+/*@constant observer char *REGISTER_PREFIX@*/\r
+#define REGISTER_PREFIX ""\r
+#endif\r
+\r
+/* table to tell if char can be part of a C identifier. */\r
+static bool is_idchar[256];\r
+/* table to tell if char can be first char of a c identifier. */\r
+static bool is_idstart[256];\r
+/* table to tell if c is horizontal space. */\r
+static bool is_hor_space[256];\r
+/* table to tell if c is horizontal or vertical space. */\r
+static bool is_space[256];\r
+\r
+static /*@exposed@*/ /*@null@*/ cppBuffer *\r
+cppReader_getBuffer (/*@special@*/ cppReader *p_pfile)\r
+ /*@uses p_pfile->buffer@*/\r
+ /*@modifies nothing@*/ ;\r
+\r
+/*@notfunction@*/\r
+# define SKIP_WHITE_SPACE(p) do { /*@access cstring@*/ while (is_hor_space[(int) *(p)]) { (p)++; } } /*@noaccess cstring@*/ while (0)\r
+\r
+/*@notfunction@*/\r
+# define SKIP_ALL_WHITE_SPACE(p) do { while (is_space[*(p)]) { (p)++; } } while (0)\r
+\r
+static int cpp_peekN (cppReader *p_pfile, int p_n) /*@*/ ;\r
+\r
+/*@function static int cppBuffer_get (sef cppBuffer *p_b) modifies *p_b ; @*/\r
+# define cppBuffer_get(BUFFER) \\r
+ ((BUFFER)->cur < (BUFFER)->rlimit ? *(BUFFER)->cur++ : EOF)\r
+\r
+/* Append string STR (of length N) to PFILE's output buffer. Make space. */\r
+/*@function static void cppReader_puts (sef cppReader *p_file, char *p_str, sef size_t p_n)\r
+ modifies *p_file; @*/\r
+# define cppReader_puts(PFILE, STR, N) \\r
+ cppReader_reserve(PFILE, N), cppReader_putStrN (PFILE, STR,N)\r
+\r
+/* Append character CH to PFILE's output buffer. Assume sufficient space. */\r
+\r
+/*@function static void cppReader_putCharQ (cppReader *p_file, char p_ch)\r
+ modifies *p_file; @*/\r
+# define cppReader_putCharQ(PFILE, CH) (*(PFILE)->limit++ = (CH))\r
+\r
+/* Append character CH to PFILE's output buffer. Make space if need be. */\r
+\r
+/*@function static void cppReader_putChar (sef cppReader *p_file, char p_ch)\r
+ modifies *p_file; @*/\r
+#define cppReader_putChar(PFILE, CH) (cppReader_reserve (PFILE, (size_t) 1), cppReader_putCharQ (PFILE, CH))\r
+\r
+/* Make sure PFILE->limit is followed by '\0'. */\r
+/*@function static void cppReader_nullTerminateQ (cppReader *p_file)\r
+ modifies *p_file; @*/\r
+\r
+#define cppReader_nullTerminateQ(PFILE) (*(PFILE)->limit = 0)\r
+\r
+/*@function static void cppReader_nullTerminate (sef cppReader *p_file)\r
+ modifies *p_file; @*/\r
+# define cppReader_nullTerminate(PFILE) \\r
+ (cppReader_reserve (PFILE, (size_t) 1), *(PFILE)->limit = 0)\r
+\r
+/*@function static void cppReader_adjustWritten (cppReader *p_file, size_t)\r
+ modifies *p_file; @*/\r
+#define cppReader_adjustWritten(PFILE,DELTA) ((PFILE)->limit += (DELTA))\r
+\r
+/*@function static bool cppReader_isC89 (cppReader *) modifies nothing; @*/\r
+#define cppReader_isC89(PFILE) (CPPOPTIONS(PFILE)->c89)\r
+\r
+/*@function static observer char *cppReader_wcharType (cppReader *)\r
+ modifies nothing; @*/\r
+\r
+# define cppReader_wcharType(PFILE) \\r
+ (CPPOPTIONS (PFILE)->cplusplus ? "__wchar_t" : WCHAR_TYPE)\r
+\r
+static void cppBuffer_forward (cppBuffer *p_buf, int p_n) /*@modifies *p_buf@*/ ;\r
+\r
+/*@function static void cppReader_forward (cppReader *p_pfile, int) modifies *p_pfile; @*/\r
+# define cppReader_forward(pfile, N) \\r
+ (cppBuffer_forward (cppReader_getBufferSafe (pfile), (N)))\r
+\r
+/*@function static int cppReader_getC (cppReader *p_pfile) modifies *p_pfile; @*/\r
+# define cppReader_getC(pfile) (cppBuffer_get (cppReader_getBufferSafe (pfile)))\r
+\r
+/*@function static int cppReader_peekC (cppReader *) modifies nothing;@*/\r
+# define cppReader_peekC(pfile) (cppBufPeek (cppReader_getBufferSafe (pfile)))\r
+\r
+/* Move all backslash-newline pairs out of embarrassing places.\r
+ Exchange all such pairs following BP\r
+ with any potentially-embarrassing characters that follow them.\r
+ Potentially-embarrassing characters are / and *\r
+ (because a backslash-newline inside a comment delimiter\r
+ would cause it not to be recognized). */\r
+\r
+/*@notfunction@*/\r
+# define NEWLINE_FIX \\r
+ do { while (cppReader_peekC (pfile) == '\\' && cpp_peekN (pfile, 1) == '\n') { cppReader_forward (pfile, 2); } } while(FALSE)\r
+\r
+ /* Same, but assume we've already read the potential '\\' into C. */\r
+/*@notfunction@*/\r
+# define NEWLINE_FIX1(C) do { \\r
+ while ((C) == '\\' && cppReader_peekC (pfile) == '\n') { cppReader_forward (pfile, 1); (C) = cppReader_getC (pfile); }\\r
+ } while(0)\r
+\r
+static void parseSetMark (/*@out@*/ struct parse_marker *,\r
+ cppReader *);\r
+static void parseClearMark (struct parse_marker *);\r
+static void parseGotoMark (struct parse_marker *, cppReader *);\r
+static void parseMoveMark (struct parse_marker *, cppReader *);\r
+\r
+/* If we have a huge buffer, may need to cache more recent counts */\r
+static /*@exposed@*/ char *cppLineBase (/*@sef@*/ cppBuffer *);\r
+\r
+static /*@exposed@*/ /*@null@*/ cppBuffer *\r
+ cppReader_pushBuffer (cppReader *p_pfile,\r
+ /*@owned@*/ /*@null@*/ char *, size_t)\r
+ /*@modifies p_pfile@*/ ;\r
+\r
+static void cppReader_appendIncludeChain\r
+(cppReader *p_pfile,\r
+ /*@keep@*/ struct file_name_list *p_first,\r
+ /*@dependent@*/ struct file_name_list *p_last);\r
+\r
+static void cppReader_macroCleanup (cppBuffer *p_pbuf, cppReader *p_pfile);\r
+static enum cpp_token cppReader_nullUnderflow (/*@unused@*/ cppReader *p_pfile);\r
+\r
+static void cppReader_nullCleanup (/*@unused@*/ cppBuffer *p_pbuf,\r
+ /*@unused@*/ cppReader *p_pfile);\r
+\r
+static void cppReader_fileCleanup (cppBuffer *p_pbuf,\r
+ /*@unused@*/ cppReader *p_pfile);\r
+\r
+static int cppReader_handleDirective (cppReader *p_pfile);\r
+\r
+static void cppReader_scanBuffer (cppReader *p_pfile);\r
+\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+\r
+/*\r
+** WIN32 (at least the VC++ include files) does not define mode_t.\r
+*/\r
+\r
+/*@-incondefs@*/ /*@-czechtypes@*/\r
+typedef unsigned int mode_t;\r
+/*@=incondefs@*/ /*@=czechtypes@*/\r
+\r
+# endif\r
+\r
+static int file_size_and_mode (int p_fd, /*@out@*/ mode_t *p_mode_pointer,\r
+ /*@out@*/ size_t *p_size_pointer);\r
+static int safe_read (int p_desc, /*@out@*/ char *p_ptr, int p_len);\r
+\r
+\r
+/*\r
+** cppBuffer_isMacro is true if the buffer contains macro expansion.\r
+** (Note that it is false while we're expanding marco *arguments*.)\r
+*/\r
+\r
+static bool cppBuffer_isMacro (/*@null@*/ cppBuffer *) /*@*/ ;\r
+\r
+static void path_include (cppReader *p_pfile, char *p_path)\r
+ /*@modifies p_pfile@*/ ;\r
+\r
+static void initialize_builtins (cppReader *p_pfile)\r
+ /*@modifies p_pfile@*/ ;\r
+\r
+static void initialize_char_syntax (struct cppOptions *p_opts) ;\r
+\r
+static int /*@alt void@*/ finclude (cppReader *p_pfile, int p_f,\r
+ cstring p_fname,\r
+ bool p_system_header_p,\r
+ /*@dependent@*/ /*@null@*/ struct file_name_list *p_dirptr);\r
+\r
+static void validate_else (cppReader *p_pfile, cstring p_directive);\r
+\r
+static void conditional_skip (cppReader *p_pfile, int p_skip,\r
+ enum node_type p_type,\r
+ /*@dependent@*/ /*@null@*/ char *p_control_macro);\r
+\r
+static HOST_WIDE_INT eval_if_expression (cppReader *p_pfile,\r
+ char *p_buf,\r
+ int p_length);\r
+\r
+static void skip_if_group (cppReader *p_pfile, int p_any);\r
+\r
+static bool comp_def_part (bool p_first, char *p_beg1, int p_len1,\r
+ char *p_beg2, int p_len2, bool p_last);\r
+\r
+#ifdef abort\r
+extern void fancy_abort ();\r
+#endif\r
+\r
+static bool redundant_include_p (cppReader *p_pfile, /*@null@*/ cstring p_name);\r
+static bool is_system_include (cppReader *p_pfile, cstring p_filename);\r
+\r
+static /*@observer@*/ /*@null@*/ struct file_name_map *\r
+read_name_map (cppReader *p_pfile, cstring p_dirname);\r
+\r
+static cstring read_filename_string (int p_ch, /*:open:*/ FILE *p_f);\r
+\r
+static int open_include_file (cppReader *p_pfile,\r
+ /*@owned@*/ cstring p_fname,\r
+ /*@null@*/ struct file_name_list *p_searchptr);\r
+\r
+static void push_macro_expansion (cppReader *,\r
+ /*@owned@*/ char *, size_t,\r
+ /*@dependent@*/ hashNode);\r
+\r
+/* Last arg to output_line_command. */\r
+enum file_change_code {\r
+ same_file, enter_file, leave_file\r
+};\r
+\r
+/* `struct directive' defines one #-directive, including how to handle it. */\r
+\r
+struct directive {\r
+ int length; /* Length of name */\r
+ /*@null@*/ int (*func)(); /* Function to handle directive */\r
+ /*@observer@*/ cstring name; /* Name of directive */\r
+ enum node_type type; /* Code which describes which directive. */\r
+ bool command_reads_line; /* One if rest of line is read by func. */\r
+ bool traditional_comments; /* Nonzero: keep comments if -traditional. */\r
+ bool pass_thru; /* Copy preprocessed directive to output file.*/\r
+};\r
+\r
+/* These functions are declared to return int instead of void since they\r
+ are going to be placed in a table and some old compilers have trouble with\r
+ pointers to functions returning void. */\r
+\r
+static int do_define (cppReader *, /*@null@*/ struct directive *, \r
+ char *, char *);\r
+static int do_defineAux (cppReader *, /*@null@*/ struct directive *,\r
+ char *, char *, bool);\r
+ \r
+static int do_line (cppReader *, /*@null@*/ struct directive *);\r
+static int do_include (cppReader *, struct directive *, char *, char *);\r
+static int do_undef (cppReader *, struct directive *, char *, char *);\r
+static int do_error (cppReader *, struct directive *, char *, char *);\r
+static int do_pragma (cppReader *, struct directive *, char *, char *);\r
+static int do_ident (cppReader *, struct directive *, char *, char *);\r
+static int do_if (cppReader *, struct directive *, char *, char *);\r
+static int do_xifdef (cppReader *, struct directive *, char *, char *);\r
+static int do_else (cppReader *, struct directive *, char *, char *);\r
+static int do_elif (cppReader *, struct directive *, char *, char *);\r
+static int do_endif (cppReader *, struct directive *, char *, char *);\r
+static int do_warning (cppReader *, struct directive *, char *, char *);\r
+\r
+/* If a buffer's dir field is SELF_DIR_DUMMY, it means the file was found\r
+ via the same directory as the file that #included it. */\r
+\r
+/*@constant observer struct file_name_list *SELF_DIR_DUMMY@*/\r
+#define SELF_DIR_DUMMY ((struct file_name_list *) (~0))\r
+\r
+/* #include "file" looks in source file dir, then stack. */\r
+/* #include <file> just looks in the stack. */\r
+/* -I directories are added to the end, then the defaults are added. */\r
+\r
+/*@access cstring@*/\r
+\r
+static struct default_include {\r
+ /*@dependent@*/ /*@observer@*/ cstring fname; /* The name of the directory. */\r
+ int cplusplus; /* Only look here if we're compiling C++. */\r
+ int cxx_aware; /* Includes in this directory don't need to\r
+ be wrapped in extern "C" when compiling\r
+ C++. */\r
+} include_defaults_array[]\r
+= {\r
+ /* This is the dir for fixincludes. Put it just before\r
+ the files that we fix. */\r
+ { GCC_INCLUDE_DIR, 0, 0 },\r
+ { GCC_INCLUDE_DIR2, 0, 0 },\r
+ { cstring_undefined, 0, 0 }\r
+};\r
+\r
+/*@noaccess cstring@*/\r
+\r
+/* Here is the actual list of #-directives, most-often-used first.\r
+ The initialize_builtins function assumes #define is the very first. */\r
+\r
+/*@access cstring@*/\r
+\r
+static struct directive directive_table[] = {\r
+ { 6, do_define, "define", T_DEFINE, FALSE, TRUE, FALSE },\r
+ { 5, do_xifdef, "ifdef", T_IFDEF, TRUE, FALSE, FALSE },\r
+ { 6, do_xifdef, "ifndef", T_IFNDEF, TRUE, FALSE, FALSE },\r
+ { 7, do_include, "include", T_INCLUDE, TRUE, FALSE, FALSE },\r
+ { 5, do_endif, "endif", T_ENDIF, TRUE, FALSE, FALSE },\r
+ { 4, do_else, "else", T_ELSE, TRUE, FALSE, FALSE },\r
+ { 2, do_if, "if", T_IF, TRUE, FALSE, FALSE },\r
+ { 4, do_elif, "elif", T_ELIF, TRUE, FALSE, FALSE },\r
+ { 5, do_undef, "undef", T_UNDEF, FALSE, FALSE, FALSE },\r
+ { 5, do_error, "error", T_ERROR, FALSE, FALSE, FALSE },\r
+ { 7, do_warning, "warning", T_WARNING, FALSE, FALSE, FALSE },\r
+ { 6, do_pragma, "pragma", T_PRAGMA, FALSE, FALSE, TRUE},\r
+ { 4, do_line, "line", T_LINE, TRUE, FALSE, FALSE },\r
+ { 5, do_ident, "ident", T_IDENT, TRUE, FALSE, TRUE },\r
+ /* { 8, do_unassert, "unassert", T_UNASSERT, TRUE, FALSE, FALSE }, */\r
+ { -1, 0, "", T_UNUSED, FALSE, FALSE, FALSE },\r
+};\r
+/*@noaccess cstring@*/\r
+\r
+static cstring searchPath_unparse (struct file_name_list *search_start) \r
+{\r
+ cstring res = cstring_newEmpty ();\r
+ struct file_name_list *searchptr = NULL;\r
+\r
+ for (searchptr = search_start; searchptr != NULL;\r
+ searchptr = searchptr->next)\r
+ {\r
+ if (!cstring_isEmpty (searchptr->fname)) {\r
+ res = cstring_concatFree1 (res, searchptr->fname);\r
+ if (searchptr->next != NULL) {\r
+ res = cstring_appendChar (res, ';');\r
+ }\r
+ }\r
+ }\r
+\r
+ return res;\r
+}\r
+\r
+/*@+charint@*/\r
+static void\r
+initialize_char_syntax (struct cppOptions *opts)\r
+{\r
+ char i;\r
+\r
+ /*\r
+ * Set up is_idchar and is_idstart tables. These should be\r
+ * faster than saying (is_alpha (c) || c == '_'), etc.\r
+ * Set up these things before calling any routines tthat\r
+ * refer to them.\r
+ */\r
+\r
+ for (i = 'a'; i <= 'z'; i++) {\r
+ is_idchar[i - 'a' + 'A'] = TRUE;\r
+ is_idchar[(int) i] = TRUE;\r
+ is_idstart[i - 'a' + 'A'] = TRUE;\r
+ is_idstart[(int) i] = TRUE;\r
+ }\r
+\r
+ for (i = '0'; i <= '9'; i++)\r
+ {\r
+ is_idchar[(int) i] = TRUE;\r
+ }\r
+\r
+ is_idchar['_'] = TRUE;\r
+ is_idstart['_'] = TRUE;\r
+ is_idchar['$'] = opts->dollars_in_ident;\r
+ is_idstart['$'] = opts->dollars_in_ident;\r
+\r
+ /* horizontal space table */\r
+ is_hor_space[' '] = TRUE;\r
+ is_hor_space['\t'] = TRUE;\r
+ is_hor_space['\v'] = TRUE;\r
+ is_hor_space['\f'] = TRUE;\r
+ is_hor_space['\r'] = TRUE;\r
+\r
+ is_space[' '] = TRUE;\r
+ is_space['\t'] = TRUE;\r
+ is_space['\v'] = TRUE;\r
+ is_space['\f'] = TRUE;\r
+ is_space['\n'] = TRUE;\r
+ is_space['\r'] = TRUE;\r
+}\r
+\r
+bool isIdentifierChar (char c)\r
+{\r
+ return is_idchar[(int) c];\r
+}\r
+\r
+/* Place into P_PFILE a quoted string representing the string SRC.\r
+ Caller must reserve enough space in pfile->token_buffer. */\r
+\r
+static void\r
+quote_string (cppReader *pfile, char *src)\r
+{\r
+ char c;\r
+\r
+ cppReader_putCharQ (pfile, '\"');\r
+ for (;;)\r
+ {\r
+ switch ((c = *src++))\r
+ {\r
+ default:\r
+ if (isprint (c))\r
+ cppReader_putCharQ (pfile, c);\r
+ else\r
+ {\r
+ sprintf (cppReader_getPWritten (pfile), "\\%03o",\r
+ (unsigned int) c);\r
+ cppReader_adjustWritten (pfile, (size_t) 4);\r
+ }\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\"':\r
+ case '\\':\r
+ cppReader_putCharQ (pfile, '\\');\r
+ cppReader_putCharQ (pfile, c);\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\0':\r
+ cppReader_putCharQ (pfile, '\"');\r
+ cppReader_nullTerminateQ (pfile);\r
+ return;\r
+ }\r
+ }\r
+}\r
+\r
+/* Re-allocates PFILE->token_buffer so it will hold at least N more chars. */\r
+\r
+void\r
+cppReader_growBuffer (cppReader *pfile, size_t n)\r
+{\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ pfile->token_buffer_size = n + 2 * pfile->token_buffer_size;\r
+ pfile->token_buffer = (char *)\r
+ drealloc (pfile->token_buffer, pfile->token_buffer_size);\r
+ cppReader_setWritten (pfile, old_written);\r
+}\r
+\r
+/*\r
+ * process a given definition string, for initialization\r
+ * If STR is just an identifier, define it with value 1.\r
+ * If STR has anything after the identifier, then it should\r
+ * be identifier=definition.\r
+ */\r
+\r
+void\r
+cppReader_define (cppReader *pfile, char *str)\r
+{\r
+ char *buf = NULL;\r
+ char *p = str;\r
+\r
+ DPRINTF (("Cpp reader define: %s", str));\r
+\r
+ if (!is_idstart[(int) *p])\r
+ {\r
+ DPRINTF (("ERROR 1"));\r
+ cppReader_error (pfile,\r
+ message ("Malformed option `-D%s'",\r
+ cstring_fromChars (str)));\r
+ \r
+ return;\r
+ }\r
+\r
+ p++;\r
+\r
+ DPRINTF (("Here 2"));\r
+\r
+ while (is_idchar[(int) *p])\r
+ {\r
+ p++;\r
+ }\r
+\r
+ if (*p == '(') {\r
+ p++;\r
+ while (*p != ')' && *p != '\0') {\r
+ p++;\r
+ }\r
+\r
+ if (*p == ')') {\r
+ p++;\r
+ } else {\r
+ cppReader_error \r
+ (pfile,\r
+ message ("Malformed option: -D%s (no closing parenthesis)", \r
+ cstring_fromChars (str)));\r
+ }\r
+ }\r
+\r
+ DPRINTF (("Here 2"));\r
+\r
+ if (*p == '\0')\r
+ {\r
+ buf = (char *) dmalloc (size_fromInt (p - str + 4));\r
+ strcpy ((char *) buf, str);\r
+ strcat ((char *) buf, " 1");\r
+ }\r
+ else if (*p != '=')\r
+ {\r
+ DPRINTF (("ERROR 2"));\r
+ cppReader_error (pfile,\r
+ message ("Malformed option: -D%s (expected '=', found '%c')",\r
+ cstring_fromChars (str),\r
+ *p));\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ char *q;\r
+ /* Copy the entire option so we can modify it. */\r
+ DPRINTF (("Copying..."));\r
+ buf = (char *) dmalloc (2 * strlen (str) + 1);\r
+ strncpy (buf, str, size_fromInt (p - str));\r
+\r
+ /* Change the = to a space. */\r
+ buf[p - str] = ' ';\r
+ /* Scan for any backslash-newline and remove it. */\r
+ p++;\r
+ q = &buf[p - str];\r
+\r
+ while (*p != '\0')\r
+ {\r
+ if (*p == '\\' && p[1] == '\n')\r
+ p += 2;\r
+ else\r
+ *q++ = *p++;\r
+ }\r
+\r
+ DPRINTF (("Here we are..."));\r
+ *q = '\0';\r
+ }\r
+\r
+ llassert (buf != NULL);\r
+ DPRINTF (("Do define: %s / %ld", buf, size_toLong (strlen (buf))));\r
+ (void) do_define (pfile, NULL, buf, buf + strlen (buf));\r
+ sfree (buf);\r
+}\r
+\r
+/* Append a chain of `struct file_name_list's\r
+ to the end of the main include chain.\r
+ FIRST is gthe beginning of the chain to append, and LAST is the end. */\r
+\r
+void\r
+cppReader_appendIncludeChain (cppReader *pfile,\r
+ struct file_name_list *first,\r
+ struct file_name_list *last)\r
+{\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+ struct file_name_list *dir;\r
+\r
+ if (first == NULL || last == NULL)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (opts->include == 0)\r
+ {\r
+ opts->include = first;\r
+ }\r
+ else\r
+ {\r
+ llassert (opts->last_include->next == NULL);\r
+ opts->last_include->next = first;\r
+ }\r
+\r
+ if (opts->first_bracket_include == 0)\r
+ {\r
+ opts->first_bracket_include = first;\r
+\r
+ for (dir = first; ; dir = dir->next) {\r
+ int len = cstring_length (dir->fname) + INCLUDE_LEN_FUDGE;\r
+ if (len > pfile->max_include_len)\r
+ pfile->max_include_len = len;\r
+ if (dir == last)\r
+ break;\r
+ }\r
+ }\r
+\r
+ llassert (last->next == NULL);\r
+ /* last->next = NULL; */\r
+ opts->last_include = last;\r
+}\r
+\r
+# if 0\r
+static /*@unused@*/ void \r
+cppReader_showIncludeChain (cppReader *pfile)\r
+{\r
+ struct file_name_list *dirs = CPPOPTIONS (pfile)->include;\r
+\r
+ if (dirs != NULL)\r
+ {\r
+ while (dirs != NULL)\r
+ {\r
+ fprintf (stderr, "*%s*:", cstring_toCharsSafe (dirs->fname));\r
+ dirs = dirs->next;\r
+ }\r
+\r
+ fprintf (stderr, "\n");\r
+ }\r
+ else\r
+ {\r
+ fprintf (stderr, "No includes\n");\r
+ }\r
+}\r
+# endif\r
+\r
+cstring \r
+cppReader_getIncludePath ()\r
+{\r
+ cppReader *pfile = &g_cppState;\r
+ struct file_name_list *dirs = CPPOPTIONS (pfile)->include;\r
+ cstring res = cstring_undefined;\r
+\r
+ if (dirs != NULL)\r
+ {\r
+ while (dirs != NULL)\r
+ {\r
+ res = message ("%q%c%s", res, PATH_SEPARATOR, dirs->fname);\r
+ dirs = dirs->next;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ res = cstring_makeLiteral ("<no include path>");\r
+ }\r
+\r
+ return res;\r
+}\r
+\r
+void\r
+cppReader_addIncludeChain (cppReader *pfile, struct file_name_list *dir)\r
+{\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+\r
+ if (dir == 0)\r
+ {\r
+ return;\r
+ }\r
+\r
+ if (opts->include == 0)\r
+ {\r
+ opts->include = dir;\r
+ }\r
+ else\r
+ {\r
+ llassert (opts->last_include->next == NULL);\r
+ opts->last_include->next = dir;\r
+ }\r
+\r
+ if (opts->first_bracket_include == 0)\r
+ {\r
+ int len = cstring_length (dir->fname) + INCLUDE_LEN_FUDGE;\r
+ opts->first_bracket_include = dir;\r
+ if (len > pfile->max_include_len)\r
+ {\r
+ pfile->max_include_len = len;\r
+ }\r
+ }\r
+\r
+ dir->next = NULL;\r
+ opts->last_include = dir;\r
+ /* cppReader_showIncludeChain (pfile); */\r
+}\r
+\r
+/* Given a colon-separated list of file names PATH,\r
+ add all the names to the search path for include files. */\r
+\r
+static void\r
+path_include (cppReader *pfile, char *path)\r
+{\r
+ char *p;\r
+\r
+#ifdef __CYGWIN32__\r
+ char *win32temp;\r
+\r
+ /* if we have a posix path list, convert to win32 path list */\r
+ win32temp = (char *) dmalloc /*@i4@*/\r
+ (cygwin32_posix_to_win32_path_list_buf_size (path));\r
+ cygwin32_posix_to_win32_path_list (path, win32temp);\r
+ path = win32temp;\r
+#endif\r
+\r
+ p = path;\r
+\r
+ if (*p != '\0')\r
+ while (1) {\r
+ char *q = p;\r
+ char *name;\r
+ struct file_name_list *dirtmp;\r
+\r
+ /* Find the end of this name. */\r
+ while (*q != '\0' && *q != PATH_SEPARATOR)\r
+ {\r
+ q++;\r
+ }\r
+\r
+ if (p == q)\r
+ {\r
+ /* An empty name in the path stands for the current directory. */\r
+ name = (char *) dmalloc ((size_t) 2);\r
+ name[0] = '.';\r
+ name[1] = '\0';\r
+ }\r
+ else\r
+ {\r
+ /* Otherwise use the directory that is named. */\r
+ name = (char *) dmalloc (size_fromInt (q - p + 1));\r
+ memcpy (name, p, size_fromInt (q - p));\r
+ name[q - p] = '\0';\r
+ }\r
+\r
+ dirtmp = (struct file_name_list *) dmalloc (sizeof (*dirtmp));\r
+ dirtmp->next = 0; /* New one goes on the end */\r
+ dirtmp->control_macro = 0;\r
+ dirtmp->c_system_include_path = 0;\r
+ dirtmp->fname = cstring_fromChars (name);\r
+ dirtmp->got_name_map = 0;\r
+ cppReader_addIncludeChain (pfile, dirtmp);\r
+\r
+ /* Advance past this name. */\r
+ p = q;\r
+ if (*p == '\0')\r
+ break;\r
+ /* Skip the colon. */\r
+ p++;\r
+ }\r
+}\r
+\r
+void\r
+cppOptions_init (cppOptions *opts)\r
+{\r
+ memset ((char *) opts, 0, sizeof *opts);\r
+ assertSet (opts);\r
+\r
+ opts->in_fname = NULL;\r
+ opts->out_fname = NULL;\r
+\r
+ /* Initialize is_idchar to allow $. */\r
+ opts->dollars_in_ident = TRUE;\r
+\r
+ opts->no_line_commands = 0;\r
+ opts->no_trigraphs = TRUE;\r
+ opts->put_out_comments = 1;\r
+ opts->print_include_names = 0;\r
+ opts->dump_macros = DUMP_DEFINITIONS; /* DUMP_NONE; */\r
+ opts->no_output = 0;\r
+ opts->cplusplus = 0;\r
+\r
+ opts->cplusplus_comments = 1;\r
+ opts->verbose = 0;\r
+ opts->lang_asm = 0;\r
+ opts->for_lint = 0;\r
+ opts->chill = 0;\r
+ opts->pedantic_errors = 0;\r
+ opts->warn_comments = 0;\r
+ opts->warnings_are_errors = 0;\r
+\r
+ initialize_char_syntax (opts);\r
+}\r
+\r
+enum cpp_token\r
+cppReader_nullUnderflow (/*@unused@*/ cppReader *pfile)\r
+{\r
+ return CPP_EOF;\r
+}\r
+\r
+void\r
+cppReader_nullCleanup (/*@unused@*/ cppBuffer *pbuf,\r
+ /*@unused@*/ cppReader *pfile)\r
+{\r
+ ;\r
+}\r
+\r
+void\r
+cppReader_macroCleanup (cppBuffer *pbuf, /*@unused@*/ cppReader *pfile)\r
+{\r
+ hashNode macro = pbuf->hnode;\r
+\r
+ if (macro->type == T_DISABLED)\r
+ {\r
+ macro->type = T_MACRO;\r
+ }\r
+\r
+ if (macro->type != T_MACRO || pbuf->buf != macro->value.defn->expansion)\r
+ {\r
+ sfree (pbuf->buf);\r
+ pbuf->buf = NULL;\r
+ }\r
+}\r
+\r
+void\r
+cppReader_fileCleanup (cppBuffer *pbuf, /*@unused@*/ cppReader *pfile)\r
+{\r
+ if (pbuf->buf != NULL)\r
+ {\r
+ sfree (pbuf->buf);\r
+ pbuf->buf = NULL;\r
+ }\r
+}\r
+\r
+/* Assuming we have read '/'.\r
+ If this is the start of a comment (followed by '*' or '/'),\r
+ skip to the end of the comment, and return ' '.\r
+ Return EOF if we reached the end of file before the end of the comment.\r
+ If not the start of a comment, return '/'. */\r
+\r
+static int\r
+skip_comment (cppReader *pfile, /*@null@*/ long *linep)\r
+{\r
+ int c = 0;\r
+\r
+ llassert (pfile->buffer != NULL);\r
+ llassert (pfile->buffer->cur != NULL);\r
+\r
+ while (cppReader_peekC (pfile) == '\\' && cpp_peekN (pfile, 1) == '\n')\r
+ {\r
+ if (linep != NULL)\r
+ {\r
+ (*linep)++;\r
+ }\r
+\r
+ cppReader_forward (pfile, 2);\r
+ }\r
+\r
+ if (cppReader_peekC (pfile) == '*')\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+\r
+ for (;;)\r
+ {\r
+ int prev_c = c;\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (c == EOF)\r
+ {\r
+ return EOF;\r
+ }\r
+\r
+ while (c == (int) '\\' && cppReader_peekC (pfile) == (int) '\n')\r
+ {\r
+ if (linep != NULL )\r
+ {\r
+ (*linep)++;\r
+ }\r
+\r
+ cppReader_forward (pfile, 1), c = cppReader_getC (pfile);\r
+ }\r
+\r
+ if (prev_c == (int) '*' && c == (int) '/')\r
+ {\r
+ return (int) ' ';\r
+ }\r
+\r
+ if (c == (int) '\n' && (linep != NULL))\r
+ {\r
+ (*linep)++;\r
+ }\r
+ }\r
+ }\r
+ else if (cppReader_peekC (pfile) == '/' \r
+ && CPPOPTIONS (pfile)->cplusplus_comments)\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+\r
+ for (;;)\r
+ {\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (c == EOF)\r
+ {\r
+ /* Allow hash comment to be terminated by EOF. */\r
+ return (int) ' '; \r
+ }\r
+\r
+ while (c == (int) '\\' && cppReader_peekC (pfile) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (linep != NULL)\r
+ {\r
+ (*linep)++;\r
+ }\r
+ }\r
+\r
+ if (c == (int) '\n')\r
+ {\r
+ /* Don't consider final '\n' to be part of comment. */\r
+ cppReader_forward (pfile, -1);\r
+ return (int) ' ';\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ return (int) '/';\r
+ }\r
+}\r
+\r
+/* Skip whitespace \-newline and comments. Does not macro-expand. */\r
+int /*@alt void@*/\r
+cppSkipHspace (cppReader *pfile)\r
+{\r
+ int nspaces = 0;\r
+\r
+ while (TRUE)\r
+ {\r
+ int c;\r
+\r
+ llassert (pfile->buffer != NULL);\r
+\r
+ c = cppReader_peekC (pfile);\r
+\r
+ if (c == EOF)\r
+ {\r
+ return 0; /* FIXME */\r
+ }\r
+\r
+ if (is_hor_space[c])\r
+ {\r
+ if ((c == '\f' || c == '\v') && cppReader_isPedantic (pfile))\r
+ cppReader_pedwarn (pfile,\r
+ message ("%s in preprocessing directive",\r
+ c == '\f'\r
+ ? cstring_makeLiteralTemp ("formfeed")\r
+ : cstring_makeLiteralTemp ("vertical tab")));\r
+\r
+ nspaces++;\r
+ cppReader_forward (pfile, 1);\r
+ }\r
+ else if (c == '/')\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+ c = skip_comment (pfile, NULL);\r
+\r
+ if (c == '/')\r
+ {\r
+ cppReader_forward (pfile, -1);\r
+ }\r
+\r
+ if (c == EOF || c == '/')\r
+ {\r
+ return nspaces;\r
+ }\r
+ }\r
+ else if (c == '\\' && cpp_peekN (pfile, 1) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 2);\r
+ }\r
+ else if (c == '@' && CPPBUFFER (pfile)->has_escapes\r
+ && is_hor_space [cpp_peekN (pfile, 1)])\r
+ {\r
+ cppReader_forward (pfile, 2);\r
+ }\r
+ else\r
+ {\r
+ return nspaces;\r
+ }\r
+ }\r
+}\r
+\r
+/* Read the rest of the current line.\r
+ The line is appended to PFILE's output buffer. */\r
+\r
+static void\r
+copy_rest_of_line (cppReader *pfile)\r
+{\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+\r
+ for (;;)\r
+ {\r
+ int c;\r
+ int nextc;\r
+\r
+ llassert (pfile->buffer != NULL);\r
+\r
+ c = cppReader_getC (pfile);\r
+ switch (c)\r
+ {\r
+ case EOF:\r
+ goto end_directive;\r
+ case '\\':\r
+ if (cppReader_peekC (pfile) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+ continue;\r
+ }\r
+\r
+ /*@fallthrough@*/ case '\'': case '\"':\r
+ goto scan_directive_token;\r
+\r
+ case '/':\r
+ nextc = cppReader_peekC (pfile);\r
+\r
+ /*\r
+ ** was (opts->cplusplus_comments && nextc == '*')\r
+ ** yoikes!\r
+ */\r
+\r
+ if (nextc == '*'\r
+ || (opts->cplusplus_comments && nextc == '/'))\r
+ {\r
+ goto scan_directive_token;\r
+ }\r
+ /*@switchbreak@*/ break;\r
+ case '\f':\r
+ case '\v':\r
+ if (cppReader_isPedantic (pfile))\r
+ cppReader_pedwarn (pfile,\r
+ message ("%s in preprocessing directive",\r
+ c == '\f'\r
+ ? cstring_makeLiteralTemp ("formfeed")\r
+ : cstring_makeLiteralTemp ("vertical tab")));\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\n':\r
+ cppReader_forward (pfile, -1);\r
+ goto end_directive;\r
+ scan_directive_token:\r
+ cppReader_forward (pfile, -1);\r
+ (void) cppGetToken (pfile);\r
+ continue;\r
+ }\r
+ cppReader_putChar (pfile, c);\r
+ }\r
+end_directive: ;\r
+ cppReader_nullTerminate (pfile);\r
+}\r
+\r
+void\r
+cppReader_skipRestOfLine (cppReader *pfile)\r
+{\r
+ size_t old = cppReader_getWritten (pfile);\r
+ copy_rest_of_line (pfile);\r
+ cppReader_setWritten (pfile, old);\r
+}\r
+\r
+/* Handle a possible # directive.\r
+ '#' has already been read. */\r
+\r
+int\r
+cppReader_handleDirective (cppReader *pfile)\r
+{\r
+ int c;\r
+ struct directive *kt = NULL;\r
+ int ident_length;\r
+ size_t after_ident = 0;\r
+ char *ident = NULL;\r
+ char *line_end = NULL;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ int nspaces = cppSkipHspace (pfile);\r
+\r
+ c = cppReader_peekC (pfile);\r
+\r
+ if (c >= '0' && c <= '9')\r
+ {\r
+ /* Handle # followed by a line number. */\r
+ if (cppReader_isPedantic (pfile))\r
+ {\r
+ cppReader_pedwarnLit\r
+ (pfile,\r
+ cstring_makeLiteralTemp ("`#' followed by integer"));\r
+ }\r
+\r
+ (void) do_line (pfile, NULL);\r
+ goto done_a_directive;\r
+ }\r
+\r
+\r
+ /* Now find the directive name. */\r
+\r
+ cppReader_putChar (pfile, '#');\r
+\r
+ parse_name (pfile, cppReader_getC (pfile));\r
+\r
+ llassert (pfile->token_buffer != NULL);\r
+ ident = pfile->token_buffer + old_written + 1;\r
+\r
+ ident_length = cppReader_getPWritten (pfile) - ident;\r
+\r
+ if (ident_length == 0 && cppReader_peekC (pfile) == '\n')\r
+ {\r
+ /* A line of just `#' becomes blank. */\r
+ return 1; \r
+ }\r
+\r
+ for (kt = directive_table; ; kt++) \r
+ {\r
+ if (kt->length <= 0)\r
+ {\r
+ return 0; /* goto not_a_directive; */\r
+ }\r
+\r
+ if (kt->length == ident_length\r
+ && (cstring_equalPrefix (kt->name, cstring_fromChars (ident))))\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (kt->command_reads_line)\r
+ {\r
+ after_ident = 0;\r
+ }\r
+ else\r
+ {\r
+ /* Nonzero means do not delete comments within the directive.\r
+ #define needs this when -traditional. */\r
+ bool comments = 1; /*cppReader_isTraditional (pfile) && kt->traditional_comments; */\r
+ int save_put_out_comments = CPPOPTIONS (pfile)->put_out_comments;\r
+ CPPOPTIONS (pfile)->put_out_comments = comments;\r
+ after_ident = cppReader_getWritten (pfile);\r
+ copy_rest_of_line (pfile);\r
+ CPPOPTIONS (pfile)->put_out_comments = save_put_out_comments;\r
+ }\r
+\r
+\r
+ /* For #pragma and #define, we may want to pass through the directive.\r
+ Other directives may create output, but we don't want the directive\r
+ itself out, so we pop it now. For example #include may write a #line\r
+ command (see comment in do_include), and conditionals may emit\r
+ #failed ... #endfailed stuff. But note that popping the buffer\r
+ means the parameters to kt->func may point after pfile->limit\r
+ so these parameters are invalid as soon as something gets appended\r
+ to the token_buffer. */\r
+\r
+ line_end = cppReader_getPWritten (pfile);\r
+\r
+\r
+ if (!kt->pass_thru && kt->type != T_DEFINE)\r
+ {\r
+ cppReader_setWritten (pfile, old_written);\r
+ }\r
+\r
+ llassert (pfile->token_buffer != NULL);\r
+\r
+ /* was kt->pass_thru || */\r
+\r
+ if (kt->type == T_DEFINE\r
+ && cpp_shouldCheckMacro (pfile, pfile->token_buffer + old_written))\r
+ {\r
+ char *p = pfile->token_buffer + old_written;\r
+\r
+ /*\r
+ ** Still need to record value for preprocessing, so \r
+ ** #ifdef's, etc. using the value behave correctly.\r
+ */\r
+ \r
+ (void) do_defineAux (pfile, kt, \r
+ pfile->token_buffer + after_ident,\r
+ line_end,\r
+ TRUE);\r
+ \r
+ if (*p == '#')\r
+ {\r
+ *p = ' ';\r
+ }\r
+\r
+ SKIP_WHITE_SPACE (p);\r
+\r
+ llassert (*p == 'd');\r
+ *p++ = LLMRCODE[0];\r
+\r
+ llassert (*p == 'e');\r
+ *p++ = LLMRCODE[1];\r
+\r
+ llassert (*p == 'f');\r
+ *p++ = LLMRCODE[2];\r
+\r
+ llassert (*p == 'i');\r
+ *p++ = LLMRCODE[3];\r
+\r
+ llassert (*p == 'n');\r
+ *p++ = LLMRCODE[4];\r
+\r
+ llassert (*p == 'e');\r
+\r
+ /*\r
+ ** This is way-bogus. We use the last char to record the number of\r
+ ** spaces. Its too hard to get them back into the input stream.\r
+ */\r
+\r
+ if (nspaces > 9) nspaces = 9;\r
+\r
+ *p++ = '0' + nspaces;\r
+\r
+ return 0; /* not_a_directive */\r
+ }\r
+ else if (kt->pass_thru)\r
+ {\r
+ /* Just leave the entire #define in the output stack. */\r
+ return 0; /* not_a_directive */\r
+\r
+ }\r
+ else if (kt->type == T_DEFINE\r
+ && CPPOPTIONS (pfile)->dump_macros == DUMP_NAMES)\r
+ {\r
+ char *p = pfile->token_buffer + old_written + 7; /* Skip "#define". */\r
+ SKIP_WHITE_SPACE (p);\r
+\r
+ while (is_idchar[(int) *p])\r
+ {\r
+ p++;\r
+ }\r
+\r
+ pfile->limit = p;\r
+ cppReader_putChar (pfile, '\n');\r
+ }\r
+ else if (kt->type == T_DEFINE)\r
+ {\r
+ cppReader_setWritten (pfile, old_written);\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+done_a_directive:\r
+ if (kt == NULL) {\r
+ return 1;\r
+ } else {\r
+ llassert (kt->func != NULL);\r
+ (void) (kt->func) (pfile, kt, pfile->token_buffer + after_ident, line_end);\r
+ return 1;\r
+ }\r
+}\r
+\r
+/* Pass a directive through to the output file.\r
+ BUF points to the contents of the directive, as a contiguous string.\r
+ LIMIT points to the first character past the end of the directive.\r
+ KEYWORD is the keyword-table entry for the directive. */\r
+\r
+static void\r
+pass_thru_directive (char *buf, char *limit,\r
+ cppReader *pfile,\r
+ struct directive *keyword)\r
+{\r
+ int keyword_length = keyword->length;\r
+\r
+ cppReader_reserve (pfile,\r
+ size_fromInt (2 + keyword_length + (limit - buf)));\r
+ cppReader_putCharQ (pfile, '#');\r
+ /*@-observertrans@*/\r
+ cppReader_putStrN (pfile, cstring_toCharsSafe (keyword->name),\r
+ size_fromInt (keyword_length));\r
+ /*:=observertrans@*/\r
+\r
+ if (limit != buf && buf[0] != ' ')\r
+ {\r
+ /* Was a bug, since reserve only used 1 + ... */\r
+ cppReader_putCharQ (pfile, ' ');\r
+ }\r
+\r
+ cppReader_putStrN (pfile, buf, size_fromInt (limit - buf));\r
+}\r
+\r
+/* Read a replacement list for a macro with parameters.\r
+ Build the DEFINITION structure.\r
+ Reads characters of text starting at BUF until END.\r
+ ARGLIST specifies the formal parameters to look for\r
+ in the text of the definition; NARGS is the number of args\r
+ in that list, or -1 for a macro name that wants no argument list.\r
+ MACRONAME is the macro name itself (so we can avoid recursive expansion)\r
+ and NAMELEN is its length in characters.\r
+\r
+ Note that comments, backslash-newlines, and leading white space\r
+ have already been deleted from the argument. */\r
+\r
+static DEFINITION *\r
+collect_expansion (cppReader *pfile, char *buf, char *limit,\r
+ int nargs, /*@null@*/ struct arglist *arglist)\r
+{\r
+ DEFINITION *defn;\r
+ char *p, *lastp, *exp_p;\r
+ struct reflist *endpat = NULL;\r
+ /* Pointer to first nonspace after last ## seen. */\r
+ char *concat = 0;\r
+ /* Pointer to first nonspace after last single-# seen. */\r
+ char *stringify = 0;\r
+ size_t maxsize;\r
+ char expected_delimiter = '\0';\r
+\r
+\r
+ /* Scan thru the replacement list, ignoring comments and quoted\r
+ strings, picking up on the macro calls. It does a linear search\r
+ thru the arg list on every potential symbol. Profiling might say\r
+ that something smarter should happen. */\r
+\r
+ if (limit < buf)\r
+ abort ();\r
+\r
+ /* Find the beginning of the trailing whitespace. */\r
+ p = buf;\r
+\r
+ while (p < limit && is_space[(int) limit[-1]])\r
+ {\r
+ limit--;\r
+ }\r
+\r
+ /* Allocate space for the text in the macro definition.\r
+ Leading and trailing whitespace chars need 2 bytes each.\r
+ Each other input char may or may not need 1 byte,\r
+ so this is an upper bound. The extra 5 are for invented\r
+ leading and trailing newline-marker and final null. */\r
+ maxsize = (sizeof (*defn) + (limit - p) + 5);\r
+\r
+ /* Occurrences of '@' get doubled, so allocate extra space for them. */\r
+ while (p < limit)\r
+ {\r
+ if (*p++ == '@')\r
+ {\r
+ maxsize++;\r
+ }\r
+ }\r
+\r
+ defn = (DEFINITION *) dmalloc (maxsize);\r
+ defn->noExpand = FALSE;\r
+ defn->file = NULL;\r
+ defn->pattern = NULL;\r
+ defn->nargs = nargs;\r
+ defn->predefined = NULL;\r
+\r
+ exp_p = defn->expansion = (char *) defn + sizeof (*defn);\r
+\r
+ defn->line = 0;\r
+ defn->rest_args = NULL;\r
+ defn->args.argnames = NULL;\r
+\r
+ lastp = exp_p;\r
+\r
+ p = buf;\r
+\r
+ /* Add one initial space escape-marker to prevent accidental\r
+ token-pasting (often removed by macroexpand). */\r
+ *exp_p++ = '@';\r
+ *exp_p++ = ' ';\r
+\r
+ if (limit - p >= 2 && p[0] == '#' && p[1] == '#') {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`##' at start of macro definition"));\r
+ p += 2;\r
+ }\r
+\r
+ /* Process the main body of the definition. */\r
+ while (p < limit) {\r
+ int skipped_arg = 0;\r
+ register char c = *p++;\r
+\r
+ *exp_p++ = c;\r
+\r
+ if (!cppReader_isTraditional (pfile)) {\r
+ switch (c) {\r
+ case '\'':\r
+ case '\"':\r
+ if (expected_delimiter != '\0')\r
+ {\r
+ if (c == expected_delimiter)\r
+ expected_delimiter = '\0';\r
+ }\r
+ else\r
+ {\r
+ expected_delimiter = c;\r
+ }\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\\':\r
+ if (p < limit && (expected_delimiter != '\0'))\r
+ {\r
+ /* In a string, backslash goes through\r
+ and makes next char ordinary. */\r
+ *exp_p++ = *p++;\r
+ }\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '@':\r
+ /* An '@' in a string or character constant stands for itself,\r
+ and does not need to be escaped. */\r
+ if (expected_delimiter == '\0')\r
+ {\r
+ *exp_p++ = c;\r
+ }\r
+\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '#':\r
+ /* # is ordinary inside a string. */\r
+ if (expected_delimiter != '\0')\r
+ {\r
+ /*@switchbreak@*/ break;\r
+ }\r
+\r
+ if (p < limit && *p == '#') {\r
+ /* ##: concatenate preceding and following tokens. */\r
+ /* Take out the first #, discard preceding whitespace. */\r
+ exp_p--;\r
+\r
+ /*@-usedef@*/\r
+ while (exp_p > lastp && is_hor_space[(int) exp_p[-1]])\r
+ {\r
+ --exp_p;\r
+ }\r
+ /*@=usedef@*/\r
+\r
+ /* Skip the second #. */\r
+ p++;\r
+ /* Discard following whitespace. */\r
+ SKIP_WHITE_SPACE (p);\r
+ concat = p;\r
+ if (p == limit)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`##' at end of macro definition"));\r
+ }\r
+ } else if (nargs >= 0) {\r
+ /* Single #: stringify following argument ref.\r
+ Don't leave the # in the expansion. */\r
+ exp_p--;\r
+ SKIP_WHITE_SPACE (p);\r
+ if (p == limit || ! is_idstart[(int) *p]\r
+ || (*p == 'L' && p + 1 < limit && (p[1] == '\'' || p[1] == '"')))\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`#' operator is not followed by a macro argument name"));\r
+ else\r
+ stringify = p;\r
+ } else {\r
+ ; /* BADBRANCH; */\r
+ }\r
+\r
+ /*@switchbreak@*/ break;\r
+ }\r
+ } else {\r
+ /* In -traditional mode, recognize arguments inside strings and\r
+ and character constants, and ignore special properties of #.\r
+ Arguments inside strings are considered "stringified", but no\r
+ extra quote marks are supplied. */\r
+ switch (c) {\r
+ case '\'':\r
+ case '\"':\r
+ if (expected_delimiter != '\0') {\r
+ if (c == expected_delimiter)\r
+ expected_delimiter = '\0';\r
+ } else\r
+ expected_delimiter = c;\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\\':\r
+ /* Backslash quotes delimiters and itself, but not macro args. */\r
+ if (expected_delimiter != '\0' && p < limit\r
+ && (*p == expected_delimiter || *p == '\\')) {\r
+ *exp_p++ = *p++;\r
+ continue;\r
+ }\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '/':\r
+ if (expected_delimiter != '\0') /* No comments inside strings. */\r
+ /*@switchbreak@*/ break;\r
+ if (*p == '*') {\r
+ /* If we find a comment that wasn't removed by cppReader_handleDirective,\r
+ this must be -traditional. So replace the comment with\r
+ nothing at all. */\r
+ exp_p--;\r
+ p += 1;\r
+ while (p < limit && !(p[-2] == '*' && p[-1] == '/'))\r
+ {\r
+ p++;\r
+ }\r
+ }\r
+ /*@switchbreak@*/ break;\r
+ }\r
+ }\r
+\r
+ /* Handle the start of a symbol. */\r
+ if (is_idchar[(int) c] && nargs > 0) {\r
+ char *id_beg = p - 1;\r
+ int id_len;\r
+\r
+ --exp_p;\r
+ while (p != limit && is_idchar[(int) *p])\r
+ {\r
+ p++;\r
+ }\r
+\r
+ id_len = p - id_beg;\r
+\r
+ if (is_idstart[(int) c]\r
+ && ! (id_len == 1 && c == 'L' && (*p == '\'' || *p == '"'))) {\r
+ register struct arglist *arg;\r
+\r
+ for (arg = arglist; arg != NULL; arg = arg->next) {\r
+ struct reflist *tpat;\r
+\r
+ if (arg->name[0] == c\r
+ && arg->length == id_len\r
+ && strncmp (arg->name, id_beg, size_fromInt (id_len)) == 0) {\r
+ char *p1;\r
+\r
+ if (expected_delimiter && CPPOPTIONS (pfile)->warn_stringify) {\r
+ if (cppReader_isTraditional (pfile)) {\r
+ cppReader_warning (pfile,\r
+ message ("macro argument `%x' is stringified.",\r
+ cstring_prefix (cstring_fromChars (arg->name), id_len)));\r
+ } else {\r
+ cppReader_warning (pfile,\r
+ message ("macro arg `%x' would be stringified with -traditional.",\r
+ cstring_prefix (cstring_fromChars (arg->name), id_len)));\r
+ }\r
+ }\r
+ /* If ANSI, don't actually substitute inside a string. */\r
+ if (!cppReader_isTraditional (pfile) && expected_delimiter)\r
+ /*@innerbreak@*/ break;\r
+ /* make a pat node for this arg and append it to the end of\r
+ the pat list */\r
+ tpat = (struct reflist *) dmalloc (sizeof (*tpat));\r
+ tpat->next = NULL;\r
+ tpat->raw_before = (concat == id_beg);\r
+ tpat->raw_after = 0;\r
+ tpat->rest_args = arg->rest_args;\r
+ tpat->stringify = (cppReader_isTraditional (pfile)\r
+ ? expected_delimiter != '\0'\r
+ : stringify == id_beg);\r
+\r
+ if (endpat == NULL)\r
+ {\r
+ defn->pattern = tpat;\r
+ }\r
+ else\r
+ {\r
+ endpat->next = tpat;\r
+ /*@-branchstate@*/\r
+ } /*@=branchstate@*/ /* evs 2000 was =branchstate */\r
+\r
+ endpat = tpat;\r
+\r
+ tpat->argno = arg->argno;\r
+ tpat->nchars = exp_p - lastp;\r
+\r
+ p1 = p;\r
+\r
+ SKIP_WHITE_SPACE (p1);\r
+\r
+ if (p1 + 2 <= limit && p1[0] == '#' && p1[1] == '#')\r
+ {\r
+ tpat->raw_after = 1;\r
+ }\r
+\r
+ lastp = exp_p; /* place to start copying from next time */\r
+ skipped_arg = 1;\r
+\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ /* If this was not a macro arg, copy it into the expansion. */\r
+ if (skipped_arg == 0) {\r
+ register char *lim1 = p;\r
+ p = id_beg;\r
+\r
+ while (p != lim1)\r
+ {\r
+ *exp_p++ = *p++;\r
+ }\r
+\r
+ if (stringify == id_beg)\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`#' operator should be followed by a macro argument name"));\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!cppReader_isTraditional (pfile) && expected_delimiter == '\0')\r
+ {\r
+ /* If ANSI, put in a "@ " marker to prevent token pasting.\r
+ But not if "inside a string" (which in ANSI mode\r
+ happens only for -D option). */\r
+ *exp_p++ = '@';\r
+ *exp_p++ = ' ';\r
+ }\r
+\r
+ *exp_p = '\0';\r
+\r
+ defn->length = size_fromInt (exp_p - defn->expansion);\r
+\r
+ /* Crash now if we overrun the allocated size. */\r
+ if (defn->length + 1 > maxsize)\r
+ {\r
+ llfatalbug (cstring_makeLiteral ("Maximum definition size exceeded."));\r
+ }\r
+\r
+ return defn;\r
+}\r
+\r
+/*\r
+ * special extension string that can be added to the last macro argument to\r
+ * allow it to absorb the "rest" of the arguments when expanded. Ex:\r
+ * #define wow(a, b...) process (b, a, b)\r
+ * { wow (1, 2, 3); } -> { process (2, 3, 1, 2, 3); }\r
+ * { wow (one, two); } -> { process (two, one, two); }\r
+ * if this "rest_arg" is used with the concat token '##' and if it is not\r
+ * supplied then the token attached to with ## will not be outputted. Ex:\r
+ * #define wow (a, b...) process (b ## , a, ## b)\r
+ * { wow (1, 2); } -> { process (2, 1, 2); }\r
+ * { wow (one); } -> { process (one); {\r
+ */\r
+\r
+/*@-readonlytrans@*/\r
+static char rest_extension[] = "...";\r
+/*:=readonlytrans@*/\r
+\r
+/*@notfunction@*/\r
+#define REST_EXTENSION_LENGTH (sizeof (rest_extension) - 1)\r
+\r
+/* Create a DEFINITION node from a #define directive. Arguments are\r
+ as for do_define. */\r
+\r
+static /*@null@*/ MACRODEF\r
+create_definition (char *buf, char *limit,\r
+ cppReader *pfile, bool predefinition,\r
+ bool noExpand)\r
+{\r
+ char *bp; /* temp ptr into input buffer */\r
+ char *symname; /* remember where symbol name starts */\r
+ int sym_length; /* and how long it is */\r
+ int rest_args = 0; /* really int! */\r
+ int line;\r
+ int col;\r
+ cstring file = (CPPBUFFER (pfile) != NULL)\r
+ ? CPPBUFFER (pfile)->nominal_fname : cstring_makeLiteralTemp ("");\r
+ DEFINITION *defn;\r
+ int arglengths = 0; /* Accumulate lengths of arg names\r
+ plus number of args. */\r
+ MACRODEF mdef;\r
+\r
+ cppBuffer_lineAndColumn (CPPBUFFER (pfile), &line, &col);\r
+\r
+ bp = buf;\r
+\r
+ while (is_hor_space[(int) *bp])\r
+ {\r
+ bp++;\r
+ }\r
+\r
+ symname = bp; /* remember where it starts */\r
+\r
+ sym_length = cppReader_checkMacroName (pfile, bp, cstring_makeLiteralTemp ("macro"));\r
+\r
+ bp += sym_length;\r
+\r
+ /* Lossage will occur if identifiers or control keywords are broken\r
+ across lines using backslash. This is not the right place to take\r
+ care of that. */\r
+\r
+ if (*bp == '(') {\r
+ struct arglist *arg_ptrs = NULL;\r
+ int argno = 0;\r
+\r
+ bp++; /* skip '(' */\r
+ SKIP_WHITE_SPACE (bp);\r
+\r
+ /* Loop over macro argument names. */\r
+ while (*bp != ')')\r
+ {\r
+ struct arglist *temp = (struct arglist *) dmalloc (sizeof (*temp));\r
+ temp->name = bp;\r
+ temp->next = arg_ptrs;\r
+ temp->argno = argno++;\r
+ temp->rest_args = 0;\r
+\r
+ arg_ptrs = temp;\r
+\r
+ if (rest_args != 0)\r
+ {\r
+ cppReader_pedwarn (pfile,\r
+ message ("another parameter follows `%s'",\r
+ cstring_fromChars (rest_extension)));\r
+ }\r
+\r
+ if (!is_idstart[(int) *bp])\r
+ {\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid character in macro parameter name"));\r
+ }\r
+\r
+ /* Find the end of the arg name. */\r
+ while (is_idchar[(int) *bp])\r
+ {\r
+ bp++;\r
+ /* do we have a "special" rest-args extension here? */\r
+ if (limit - bp > size_toInt (REST_EXTENSION_LENGTH)\r
+ && strncmp (rest_extension, bp, REST_EXTENSION_LENGTH) == 0)\r
+ {\r
+ rest_args = 1;\r
+ temp->rest_args = 1;\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+\r
+ temp->length = bp - temp->name;\r
+\r
+ if (rest_args != 0)\r
+ {\r
+ bp += REST_EXTENSION_LENGTH;\r
+ }\r
+\r
+ arglengths += temp->length + 2;\r
+ SKIP_WHITE_SPACE (bp);\r
+\r
+ if (temp->length == 0 || (*bp != ',' && *bp != ')')) {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("Parameter list for #define is not parseable"));\r
+ goto nope;\r
+ }\r
+\r
+ if (*bp == ',') {\r
+ bp++;\r
+ SKIP_WHITE_SPACE (bp);\r
+ }\r
+ if (bp >= limit) {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("unterminated parameter list in `#define'"));\r
+ goto nope;\r
+ }\r
+ {\r
+ struct arglist *otemp;\r
+\r
+ for (otemp = temp->next; otemp != NULL; otemp = otemp->next)\r
+ {\r
+ if (temp->length == otemp->length &&\r
+ strncmp (temp->name, otemp->name, size_fromInt (temp->length)) == 0) {\r
+ cstring name = cstring_copyLength (temp->name, temp->length);\r
+ cppReader_error (pfile,\r
+ message ("duplicate argument name `%x' in `#define'", name));\r
+ goto nope;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ ++bp; /* skip paren */\r
+ SKIP_WHITE_SPACE (bp);\r
+ /* now everything from bp before limit is the definition. */\r
+ defn = collect_expansion (pfile, bp, limit, argno, arg_ptrs);\r
+ defn->rest_args = rest_args;\r
+ \r
+ /* Now set defn->args.argnames to the result of concatenating\r
+ the argument names in reverse order\r
+ with comma-space between them. */\r
+ defn->args.argnames = (char *) dmalloc (size_fromInt (arglengths + 1));\r
+\r
+ {\r
+ struct arglist *temp;\r
+ int i = 0;\r
+ for (temp = arg_ptrs; temp != NULL; temp = temp->next) {\r
+ memcpy (&defn->args.argnames[i], temp->name, size_fromInt (temp->length));\r
+ i += temp->length;\r
+ if (temp->next != 0) {\r
+ defn->args.argnames[i++] = ',';\r
+ defn->args.argnames[i++] = ' ';\r
+ }\r
+ }\r
+\r
+ defn->args.argnames[i] = '\0';\r
+ }\r
+\r
+ sfree (arg_ptrs);\r
+ } else {\r
+ /* Simple expansion or empty definition. */\r
+\r
+ if (bp < limit)\r
+ {\r
+ if (is_hor_space[(int) *bp]) {\r
+ bp++;\r
+ SKIP_WHITE_SPACE (bp);\r
+ } else {\r
+ switch (*bp) {\r
+ case '!': case '"': case '#': case '%': case '&': case '\'':\r
+ case ')': case '*': case '+': case ',': case '-': case '.':\r
+ case '/': case ':': case ';': case '<': case '=': case '>':\r
+ case '?': case '[': case '\\': case ']': case '^': case '{':\r
+ case '|': case '}': case '~':\r
+ cppReader_warning (pfile,\r
+ message ("Missing white space after #define %x",\r
+ cstring_prefix (cstring_fromChars (symname),\r
+ sym_length)));\r
+ break;\r
+\r
+ default:\r
+ cppReader_pedwarn (pfile,\r
+ message ("Missing white space after #define %x",\r
+ cstring_prefix (cstring_fromChars (symname),\r
+ sym_length)));\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ /* now everything from bp before limit is the definition. */\r
+ defn = collect_expansion (pfile, bp, limit, -1, NULL);\r
+ defn->args.argnames = mstring_createEmpty ();\r
+ }\r
+\r
+ defn->noExpand = noExpand;\r
+ DPRINTF (("No expand: %d", noExpand));\r
+\r
+ defn->line = line;\r
+\r
+ /* not: llassert (cstring_isUndefined (defn->file)); */\r
+ defn->file = file;\r
+\r
+ /* OP is null if this is a predefinition */\r
+ defn->predefined = predefinition;\r
+ mdef.defn = defn;\r
+ mdef.symnam = symname;\r
+ mdef.symlen = sym_length;\r
+\r
+ return mdef;\r
+\r
+nope:\r
+ mdef.defn = NULL;\r
+ mdef.symnam = NULL;\r
+ return mdef;\r
+}\r
+\r
+/* Check a purported macro name SYMNAME, and yield its length.\r
+ USAGE is the kind of name this is intended for. */\r
+\r
+int cppReader_checkMacroName (cppReader *pfile,\r
+ char *symname,\r
+ cstring usage)\r
+{\r
+ char *p;\r
+ size_t sym_length;\r
+\r
+ for (p = symname; is_idchar[(int) *p]; p++)\r
+ {\r
+ ;\r
+ }\r
+\r
+ sym_length = size_fromInt (p - symname);\r
+\r
+ if (sym_length == 0\r
+ || (sym_length == 1 && *symname == 'L' && (*p == '\'' || *p == '"')))\r
+ cppReader_error (pfile, message ("invalid %s name", usage));\r
+ else if (!is_idstart[(int) *symname])\r
+ {\r
+ char *msg = (char *) dmalloc (sym_length + 1);\r
+ memcpy (msg, symname, sym_length);\r
+ msg[sym_length] = '\0';\r
+ cppReader_error (pfile, message ("invalid %s name `%s'", usage,\r
+ cstring_fromChars (msg)));\r
+ sfree (msg);\r
+ }\r
+ else\r
+ {\r
+ if ((strncmp (symname, "defined", 7) == 0) && sym_length == 7)\r
+ {\r
+ cppReader_error (pfile, message ("invalid %s name `defined'", usage));\r
+ }\r
+ }\r
+\r
+ return size_toInt (sym_length);\r
+}\r
+\r
+/* Return zero if two DEFINITIONs are isomorphic. */\r
+\r
+static bool\r
+compare_defs (DEFINITION *d1, DEFINITION *d2)\r
+{\r
+ register struct reflist *a1, *a2;\r
+ register char *p1 = d1->expansion;\r
+ register char *p2 = d2->expansion;\r
+ bool first = TRUE;\r
+\r
+ if (d1->nargs != d2->nargs)\r
+ {\r
+ return TRUE;\r
+ }\r
+\r
+ llassert (d1->args.argnames != NULL);\r
+ llassert (d2->args.argnames != NULL);\r
+\r
+ if (strcmp ((char *)d1->args.argnames, (char *)d2->args.argnames) != 0)\r
+ {\r
+ return TRUE;\r
+ }\r
+\r
+ for (a1 = d1->pattern, a2 = d2->pattern;\r
+ (a1 != NULL) && (a2 != NULL);\r
+ a1 = a1->next, a2 = a2->next) {\r
+ if (!((a1->nchars == a2->nchars\r
+ && (strncmp (p1, p2, size_fromInt (a1->nchars)) == 0))\r
+ || ! comp_def_part (first, p1, a1->nchars, p2, a2->nchars, 0))\r
+ || a1->argno != a2->argno\r
+ || a1->stringify != a2->stringify\r
+ || a1->raw_before != a2->raw_before\r
+ || a1->raw_after != a2->raw_after)\r
+ return TRUE;\r
+ first = 0;\r
+ p1 += a1->nchars;\r
+ p2 += a2->nchars;\r
+ }\r
+ if (a1 != a2)\r
+ return TRUE;\r
+\r
+ if (comp_def_part (first, p1, d1->length - (p1 - d1->expansion),\r
+ p2, d2->length - (p2 - d2->expansion), 1))\r
+ return TRUE;\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* Return TRUE if two parts of two macro definitions are effectively different.\r
+ One of the parts starts at BEG1 and has LEN1 chars;\r
+ the other has LEN2 chars at BEG2.\r
+ Any sequence of whitespace matches any other sequence of whitespace.\r
+ FIRST means these parts are the first of a macro definition;\r
+ so ignore leading whitespace entirely.\r
+ LAST means these parts are the last of a macro definition;\r
+ so ignore trailing whitespace entirely. */\r
+\r
+static bool\r
+comp_def_part (bool first, char *beg1, int len1, char *beg2, int len2, bool last)\r
+{\r
+ char *end1 = beg1 + len1;\r
+ char *end2 = beg2 + len2;\r
+\r
+ if (first) {\r
+ while (beg1 != end1 && is_space[(int) *beg1]) { beg1++; }\r
+ while (beg2 != end2 && is_space[(int) *beg2]) { beg2++; }\r
+ }\r
+ if (last) {\r
+ while (beg1 != end1 && is_space[(int) end1[-1]]) { end1--; }\r
+ while (beg2 != end2 && is_space[(int) end2[-1]]) { end2--; }\r
+ }\r
+ while (beg1 != end1 && beg2 != end2) {\r
+ if (is_space[(int) *beg1] && is_space[(int) *beg2]) {\r
+ while (beg1 != end1 && is_space[(int) *beg1]) { beg1++; }\r
+ while (beg2 != end2 && is_space[(int) *beg2]) { beg2++; }\r
+ } else if (*beg1 == *beg2) {\r
+ beg1++; beg2++;\r
+ } else break;\r
+ }\r
+ return (beg1 != end1) || (beg2 != end2);\r
+}\r
+\r
+/* Process a #define command.\r
+ BUF points to the contents of the #define command, as a contiguous string.\r
+ LIMIT points to the first character past the end of the definition.\r
+ KEYWORD is the keyword-table entry for #define,\r
+ or NULL for a "predefined" macro. */\r
+\r
+static int\r
+do_defineAux (cppReader *pfile, struct directive *keyword,\r
+ char *buf, char *limit, bool noExpand)\r
+{\r
+ int hashcode;\r
+ MACRODEF mdef;\r
+ hashNode hp;\r
+ \r
+ DPRINTF (("Define aux: %d", noExpand));\r
+\r
+ mdef = create_definition (buf, limit, pfile, keyword == NULL, noExpand);\r
+\r
+ if (mdef.defn == 0)\r
+ goto nope;\r
+\r
+ hashcode = hashf (mdef.symnam, mdef.symlen, CPP_HASHSIZE);\r
+\r
+ DPRINTF (("Macro: %s / %s", \r
+ cstring_copyLength (mdef.symnam, mdef.symlen),\r
+ bool_unparse (noExpand)));\r
+\r
+ if ((hp = cppReader_lookup (mdef.symnam, mdef.symlen, hashcode)) != NULL)\r
+ {\r
+ bool ok = FALSE;\r
+\r
+ /* Redefining a precompiled key is ok. */\r
+ if (hp->type == T_PCSTRING)\r
+ ok = TRUE;\r
+ /* Redefining a macro is ok if the definitions are the same. */\r
+ else if (hp->type == T_MACRO)\r
+ ok = !compare_defs (mdef.defn, hp->value.defn);\r
+ /* Redefining a constant is ok with -D. */\r
+ else if (hp->type == T_CONST)\r
+ ok = !CPPOPTIONS (pfile)->done_initializing;\r
+ else {\r
+ BADBRANCH;\r
+ }\r
+\r
+ /* Print the warning if it's not ok. */\r
+ if (!ok)\r
+ {\r
+ /*\r
+ ** If we are passing through #define and #undef directives, do\r
+ ** that for this re-definition now.\r
+ */\r
+\r
+ if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))\r
+ {\r
+ /* llassert (keyword != NULL); */\r
+ pass_thru_directive (buf, limit, pfile, keyword);\r
+ }\r
+\r
+ cpp_setLocation (pfile);\r
+\r
+ if (hp->type == T_MACRO)\r
+ {\r
+ if (hp->value.defn->noExpand)\r
+ {\r
+ ; /* error will be reported checking macros */\r
+ }\r
+ else\r
+ {\r
+ genppllerrorhint\r
+ (FLG_MACROREDEF,\r
+ message ("Macro %q already defined",\r
+ cstring_copyLength (mdef.symnam, mdef.symlen)),\r
+ message ("%q: Previous definition of %q",\r
+ fileloc_unparseRaw (hp->value.defn->file,\r
+ (int) hp->value.defn->line),\r
+ cstring_copyLength (mdef.symnam, mdef.symlen)));\r
+ }\r
+ }\r
+ else\r
+ {\r
+ genppllerror (FLG_MACROREDEF,\r
+ message ("Macro %q already defined",\r
+ cstring_copyLength (mdef.symnam,\r
+ mdef.symlen)));\r
+\r
+ }\r
+ }\r
+\r
+ /* Replace the old definition. */\r
+ hp->type = T_MACRO;\r
+ hp->value.defn = mdef.defn;\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ ** If we are passing through #define and #undef directives, do\r
+ ** that for this new definition now.\r
+ */\r
+\r
+ hashNode hn;\r
+\r
+ if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))\r
+ {\r
+ pass_thru_directive (buf, limit, pfile, keyword);\r
+ }\r
+\r
+ DPRINTF (("Define macro: %s / %d", \r
+ mdef.symnam, mdef.defn->noExpand));\r
+ \r
+ hn = cppReader_installMacro (mdef.symnam, mdef.symlen, mdef.defn, hashcode);\r
+ /*@-branchstate@*/\r
+ } /*@=branchstate@*/\r
+\r
+ return 0;\r
+\r
+nope:\r
+\r
+ return 1;\r
+}\r
+\r
+static int\r
+do_define (cppReader *pfile, struct directive *keyword,\r
+ char *buf, char *limit)\r
+{\r
+ DPRINTF (("Regular do define"));\r
+ return do_defineAux (pfile, keyword, buf, limit, FALSE);\r
+}\r
+\r
+/* This structure represents one parsed argument in a macro call.\r
+ `raw' points to the argument text as written (`raw_length' is its length).\r
+ `expanded' points to the argument's macro-expansion\r
+ (its length is `expand_length').\r
+ `stringified_length' is the length the argument would have\r
+ if stringified.\r
+ `use_count' is the number of times this macro arg is substituted\r
+ into the macro. If the actual use count exceeds 10,\r
+ the value stored is 10. */\r
+\r
+/* raw and expanded are relative to ARG_BASE */\r
+/*@notfunction@*/\r
+#define ARG_BASE ((pfile)->token_buffer)\r
+\r
+struct argdata {\r
+ /* Strings relative to pfile->token_buffer */\r
+ long raw;\r
+ size_t expanded;\r
+ size_t stringified;\r
+ int raw_length;\r
+ int expand_length;\r
+ int stringified_length;\r
+ bool newlines;\r
+ int use_count;\r
+};\r
+\r
+/* Allocate a new cppBuffer for PFILE, and push it on the input buffer stack.\r
+ If BUFFER != NULL, then use the LENGTH characters in BUFFER\r
+ as the new input buffer.\r
+ Return the new buffer, or NULL on failure. */\r
+\r
+/*@null@*/ /*@exposed@*/ cppBuffer *\r
+cppReader_pushBuffer (cppReader *pfile, char *buffer, size_t length)\r
+{\r
+ cppBuffer *buf = cppReader_getBuffer (pfile);\r
+\r
+ if (buf == pfile->buffer_stack)\r
+ {\r
+ cppReader_fatalError\r
+ (pfile,\r
+ message ("%s: macro or `#include' recursion too deep",\r
+ (buf->fname != NULL)\r
+ ? buf->fname\r
+ : cstring_makeLiteral ("<no name>")));\r
+ sfreeEventually (buffer);\r
+ return NULL;\r
+ }\r
+\r
+ llassert (buf != NULL);\r
+\r
+ buf--;\r
+ memset ((char *) buf, 0, sizeof (*buf));\r
+ CPPBUFFER (pfile) = buf;\r
+\r
+ buf->if_stack = pfile->if_stack;\r
+ buf->cleanup = cppReader_nullCleanup;\r
+ buf->underflow = cppReader_nullUnderflow;\r
+ buf->buf = buffer;\r
+ buf->cur = buf->buf;\r
+\r
+ if (buffer != NULL)\r
+ {\r
+ buf->alimit = buf->rlimit = buffer + length;\r
+ }\r
+ else\r
+ {\r
+ buf->alimit = buf->rlimit = NULL;\r
+ }\r
+\r
+ return buf;\r
+}\r
+\r
+cppBuffer *\r
+cppReader_popBuffer (cppReader *pfile)\r
+{\r
+ cppBuffer *buf = CPPBUFFER (pfile);\r
+\r
+ llassert (buf != NULL);\r
+\r
+ (void) (*buf->cleanup) (buf, pfile);\r
+ return ++CPPBUFFER (pfile);\r
+}\r
+\r
+/* Scan until CPPBUFFER (PFILE) is exhausted into PFILE->token_buffer.\r
+ Pop the buffer when done. */\r
+\r
+void\r
+cppReader_scanBuffer (cppReader *pfile)\r
+{\r
+ cppBuffer *buffer = CPPBUFFER (pfile);\r
+ for (;;)\r
+ {\r
+ enum cpp_token token;\r
+ \r
+ token = cppGetToken (pfile);\r
+\r
+ if (token == CPP_EOF) /* Should not happen ... */\r
+ {\r
+ break;\r
+ }\r
+\r
+ if (token == CPP_POP && CPPBUFFER (pfile) == buffer)\r
+ {\r
+ (void) cppReader_popBuffer (pfile);\r
+ break;\r
+ }\r
+ }\r
+}\r
+\r
+/*\r
+ * Rescan a string (which may have escape marks) into pfile's buffer.\r
+ * Place the result in pfile->token_buffer.\r
+ *\r
+ * The input is copied before it is scanned, so it is safe to pass\r
+ * it something from the token_buffer that will get overwritten\r
+ * (because it follows cppReader_getWritten). This is used by do_include.\r
+ */\r
+\r
+static void\r
+cpp_expand_to_buffer (cppReader *pfile, char *buf, size_t length)\r
+{\r
+ register cppBuffer *ip;\r
+ char *limit = buf + length;\r
+ char *buf1, *p1, *p2;\r
+\r
+ /* evans - 2001-08-26\r
+ ** length is unsigned - this doesn't make sense\r
+ if (length < 0)\r
+ abort ();\r
+ **\r
+ */\r
+\r
+ /* Set up the input on the input stack. */\r
+\r
+ buf1 = (char *) dmalloc (length + 1);\r
+\r
+ p1 = buf;\r
+ p2 = buf1;\r
+\r
+ while (p1 != limit)\r
+ {\r
+ *p2++ = *p1++;\r
+ }\r
+\r
+ buf1[length] = '\0';\r
+\r
+ ip = cppReader_pushBuffer (pfile, buf1, length);\r
+\r
+ if (ip == NULL)\r
+ return;\r
+\r
+ ip->has_escapes = TRUE;\r
+\r
+ /* Scan the input, create the output. */\r
+ cppReader_scanBuffer (pfile);\r
+\r
+ cppReader_nullTerminate (pfile);\r
+}\r
+\r
+static void\r
+adjust_position (char *buf, char *limit, int *linep, int *colp)\r
+{\r
+ while (buf < limit)\r
+ {\r
+ char ch = *buf++;\r
+ if (ch == '\n')\r
+ (*linep)++, (*colp) = 1;\r
+ else\r
+ (*colp)++;\r
+ }\r
+}\r
+\r
+/* Move line_base forward, updating lineno and colno. */\r
+\r
+static void\r
+update_position (cppBuffer *pbuf)\r
+{\r
+ char *old_pos;\r
+ char *new_pos = pbuf->cur;\r
+ register struct parse_marker *mark;\r
+\r
+ llassert (pbuf->buf != NULL);\r
+ old_pos = pbuf->buf + pbuf->line_base;\r
+\r
+ for (mark = pbuf->marks; mark != NULL; mark = mark->next)\r
+ {\r
+ if (pbuf->buf + mark->position < new_pos)\r
+ new_pos = pbuf->buf + mark->position;\r
+ }\r
+ pbuf->line_base += new_pos - old_pos;\r
+\r
+ llassert (old_pos != NULL);\r
+ llassert (new_pos != NULL);\r
+\r
+ adjust_position (old_pos, new_pos, &pbuf->lineno, &pbuf->colno);\r
+}\r
+\r
+void\r
+cppBuffer_lineAndColumn (/*@null@*/ cppBuffer *pbuf, /*@out@*/ int *linep,\r
+ /*@null@*/ /*@out@*/ int *colp)\r
+{\r
+ int dummy;\r
+\r
+ if (colp == NULL)\r
+ {\r
+ colp = &dummy;\r
+ /*@-branchstate@*/\r
+ } /*@=branchstate@*/\r
+\r
+ if (pbuf != NULL)\r
+ {\r
+ *linep = pbuf->lineno;\r
+ *colp = pbuf->colno;\r
+\r
+ llassert (pbuf->buf != NULL);\r
+ llassert (pbuf->cur != NULL);\r
+\r
+ adjust_position (pbuf->buf + pbuf->line_base, pbuf->cur, linep, colp);\r
+ }\r
+ else\r
+ {\r
+ *linep = 0;\r
+ *colp = 0;\r
+ }\r
+}\r
+\r
+/* Return the cppBuffer that corresponds to a file (not a macro). */\r
+\r
+/*@exposed@*/ /*@null@*/ cppBuffer *cppReader_fileBuffer (cppReader *pfile)\r
+{\r
+ cppBuffer *ip = cppReader_getBuffer (pfile);\r
+\r
+ for ( ;\r
+ ip != NULL && ip != cppReader_nullBuffer (pfile); \r
+ ip = cppBuffer_prevBuffer (ip))\r
+ {\r
+ if (ip->fname != NULL)\r
+ {\r
+ return ip;\r
+ }\r
+ }\r
+ \r
+ return NULL;\r
+}\r
+\r
+static long\r
+count_newlines (char *buf, char *limit)\r
+{\r
+ register long count = 0;\r
+\r
+ while (buf < limit)\r
+ {\r
+ char ch = *buf++;\r
+ if (ch == '\n')\r
+ count++;\r
+ }\r
+ return count;\r
+}\r
+\r
+/*\r
+ * write out a #line command, for instance, after an #include file.\r
+ * If CONDITIONAL is nonzero, we can omit the #line if it would\r
+ * appear to be a no-op, and we can output a few newlines instead\r
+ * if we want to increase the line number by a small amount.\r
+ * FILE_CHANGE says whether we are entering a file, leaving, or neither.\r
+ */\r
+\r
+static void\r
+output_line_command (cppReader *pfile, bool conditional,\r
+ enum file_change_code file_change)\r
+{\r
+ int line, col;\r
+ cppBuffer *ip = CPPBUFFER (pfile);\r
+ cppBuffer *buf;\r
+\r
+ llassert (ip != NULL);\r
+\r
+ if (ip->fname == NULL)\r
+ return;\r
+\r
+ update_position (ip);\r
+\r
+ if (CPPOPTIONS (pfile)->no_line_commands\r
+ || CPPOPTIONS (pfile)->no_output)\r
+ return;\r
+\r
+ buf = CPPBUFFER (pfile);\r
+\r
+ llassert (buf != NULL);\r
+\r
+ line = buf->lineno;\r
+ col = buf->colno;\r
+\r
+ llassert (ip->cur != NULL);\r
+\r
+ adjust_position (cppLineBase (ip), ip->cur, &line, &col);\r
+\r
+ if (CPPOPTIONS (pfile)->no_line_commands)\r
+ return;\r
+\r
+ if (conditional) {\r
+ if (line == pfile->lineno)\r
+ return;\r
+\r
+ /* If the inherited line number is a little too small,\r
+ output some newlines instead of a #line command. */\r
+\r
+ if (line > pfile->lineno && line < pfile->lineno + 8)\r
+ {\r
+ cppReader_reserve (pfile, 20);\r
+ while (line > pfile->lineno)\r
+ {\r
+ cppReader_putCharQ (pfile, '\n');\r
+ pfile->lineno++;\r
+ }\r
+\r
+ return;\r
+ }\r
+ }\r
+\r
+ cppReader_reserve (pfile,\r
+ size_fromInt (4 * cstring_length (ip->nominal_fname) + 50));\r
+\r
+ {\r
+#ifdef OUTPUT_LINE_COMMANDS\r
+ static char sharp_line[] = "#line ";\r
+#else\r
+ static char sharp_line[] = "# ";\r
+#endif\r
+ cppReader_putStrN (pfile, sharp_line, sizeof(sharp_line)-1);\r
+ }\r
+\r
+ sprintf (cppReader_getPWritten (pfile), "%d ", line);\r
+ cppReader_adjustWritten (pfile, strlen (cppReader_getPWritten (pfile)));\r
+\r
+ quote_string (pfile, cstring_toCharsSafe (ip->nominal_fname));\r
+\r
+ if (file_change != same_file) {\r
+ cppReader_putCharQ (pfile, ' ');\r
+ cppReader_putCharQ (pfile, file_change == enter_file ? '1' : '2');\r
+ }\r
+ /* Tell cc1 if following text comes from a system header file. */\r
+ if (ip->system_header_p != '\0') {\r
+ cppReader_putCharQ (pfile, ' ');\r
+ cppReader_putCharQ (pfile, '3');\r
+ }\r
+#ifndef NO_IMPLICIT_EXTERN_C\r
+ /* Tell cc1plus if following text should be treated as C. */\r
+ if (ip->system_header_p == (char) 2 && CPPOPTIONS (pfile)->cplusplus) {\r
+ cppReader_putCharQ (pfile, ' ');\r
+ cppReader_putCharQ (pfile, '4');\r
+ }\r
+#endif\r
+ cppReader_putCharQ (pfile, '\n');\r
+ pfile->lineno = line;\r
+}\r
+\r
+\r
+/*\r
+ * Parse a macro argument and append the info on PFILE's token_buffer.\r
+ * REST_ARGS means to absorb the rest of the args.\r
+ * Return nonzero to indicate a syntax error.\r
+ */\r
+\r
+static enum cpp_token\r
+macarg (cppReader *pfile, int rest_args)\r
+{\r
+ int paren = 0;\r
+ enum cpp_token token;\r
+ char save_put_out_comments = CPPOPTIONS (pfile)->put_out_comments;\r
+ bool oldexpand = pfile->no_macro_expand;\r
+ CPPOPTIONS (pfile)->put_out_comments = 1;\r
+\r
+ /* Try to parse as much of the argument as exists at this\r
+ input stack level. */\r
+\r
+ pfile->no_macro_expand = TRUE;\r
+\r
+ for (;;)\r
+ {\r
+ token = cppGetToken (pfile);\r
+\r
+ switch (token)\r
+ {\r
+ case CPP_EOF:\r
+ goto done;\r
+ case CPP_POP:\r
+ /* If we've hit end of file, it's an error (reported by caller).\r
+ Ditto if it's the end of cpp_expand_to_buffer text.\r
+ If we've hit end of macro, just continue. */\r
+ if (!cppBuffer_isMacro (CPPBUFFER (pfile)))\r
+ goto done;\r
+ /*@switchbreak@*/ break;\r
+ case CPP_LPAREN:\r
+ paren++;\r
+ /*@switchbreak@*/ break;\r
+ case CPP_RPAREN:\r
+ if (--paren < 0)\r
+ goto found;\r
+ /*@switchbreak@*/ break;\r
+ case CPP_COMMA:\r
+ /* if we've returned to lowest level and\r
+ we aren't absorbing all args */\r
+ if (paren == 0 && rest_args == 0)\r
+ goto found;\r
+ /*@switchbreak@*/ break;\r
+ found:\r
+ /* Remove ',' or ')' from argument buffer. */\r
+ cppReader_adjustWritten (pfile, -1);\r
+ goto done;\r
+ default:\r
+ ;\r
+ }\r
+ }\r
+\r
+done:\r
+ CPPOPTIONS (pfile)->put_out_comments = save_put_out_comments;\r
+ pfile->no_macro_expand = oldexpand;\r
+\r
+ return token;\r
+}\r
+\r
+\r
+/* Turn newlines to spaces in the string of length LENGTH at START,\r
+ except inside of string constants.\r
+ The string is copied into itself with its beginning staying fixed. */\r
+\r
+static int\r
+change_newlines (char *start, int length)\r
+{\r
+ register char *ibp;\r
+ register char *obp;\r
+ register char *limit;\r
+ char c;\r
+\r
+ ibp = start;\r
+ limit = start + length;\r
+ obp = start;\r
+\r
+ while (ibp < limit) {\r
+ *obp++ = c = *ibp++;\r
+ switch (c) {\r
+\r
+ case '\'':\r
+ case '\"':\r
+ /* Notice and skip strings, so that we don't delete newlines in them. */\r
+ {\r
+ char quotec = c;\r
+ while (ibp < limit) {\r
+ *obp++ = c = *ibp++;\r
+ if (c == quotec)\r
+ /*@innerbreak@*/ break;\r
+ if (c == '\n' && quotec == '\'')\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+ /*@switchbreak@*/ break;\r
+ }\r
+ }\r
+\r
+ return obp - start;\r
+}\r
+\r
+static /*@observer@*/ struct tm *\r
+timestamp (/*@returned@*/ cppReader *pfile)\r
+{\r
+ if (pfile->timebuf == NULL)\r
+ {\r
+ time_t t = time ((time_t *) 0);\r
+ pfile->timebuf = localtime (&t);\r
+ }\r
+\r
+ llassert (pfile->timebuf != NULL);\r
+\r
+ return pfile->timebuf;\r
+}\r
+\r
+static ob_mstring monthnames[] = {\r
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",\r
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",\r
+} ;\r
+\r
+/*\r
+ * expand things like __FILE__. Place the expansion into the output\r
+ * buffer *without* rescanning.\r
+ */\r
+\r
+static void\r
+special_symbol (hashNode hp, cppReader *pfile)\r
+{\r
+ cstring buf = cstring_undefined;\r
+ size_t len;\r
+ int true_indepth;\r
+ cppBuffer *ip;\r
+ struct tm *timebuf;\r
+\r
+ int paren = 0; /* For special `defined' keyword */\r
+\r
+ for (ip = cppReader_getBuffer (pfile); ip != NULL; ip = cppBuffer_prevBuffer (ip))\r
+ {\r
+ if (ip == cppReader_nullBuffer (pfile))\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("cccp error: not in any file?!"));\r
+ return; /* the show must go on */\r
+ }\r
+\r
+ if (ip != NULL && ip->fname != NULL)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ switch (hp->type)\r
+ {\r
+ case T_FILE:\r
+ case T_BASE_FILE:\r
+ {\r
+ char *string;\r
+ if (hp->type == T_BASE_FILE)\r
+ {\r
+ while (cppBuffer_prevBuffer (ip) != cppReader_nullBuffer (pfile))\r
+ {\r
+ ip = cppBuffer_prevBuffer (ip);\r
+ }\r
+ }\r
+\r
+ llassert (ip != NULL);\r
+ string = cstring_toCharsSafe (ip->nominal_fname);\r
+\r
+ if (string == NULL)\r
+ {\r
+ string = "";\r
+ }\r
+\r
+ cppReader_reserve (pfile, 3 + 4 * strlen (string));\r
+ quote_string (pfile, string);\r
+ return;\r
+ }\r
+\r
+ case T_INCLUDE_LEVEL:\r
+ true_indepth = 0;\r
+ ip = cppReader_getBuffer (pfile);\r
+\r
+ for (; ip != cppReader_nullBuffer (pfile) && ip != NULL;\r
+ ip = cppBuffer_prevBuffer (ip))\r
+ {\r
+ if (ip != NULL && ip->fname != NULL)\r
+ {\r
+ true_indepth++;\r
+ }\r
+ }\r
+\r
+ buf = message ("%d", true_indepth - 1);\r
+ break;\r
+\r
+ case T_VERSION:\r
+ buf = message ("\"%s\"", cstring_makeLiteralTemp (CPP_VERSION));\r
+ break;\r
+\r
+#ifndef NO_BUILTIN_SIZE_TYPE\r
+ case T_SIZE_TYPE:\r
+ buf = cstring_makeLiteral (SIZE_TYPE);\r
+ break;\r
+#endif\r
+\r
+#ifndef NO_BUILTIN_PTRDIFF_TYPE\r
+ case T_PTRDIFF_TYPE:\r
+ buf = cstring_makeLiteral (PTRDIFF_TYPE);\r
+ break;\r
+#endif\r
+\r
+ case T_WCHAR_TYPE:\r
+ buf = cstring_makeLiteral (cppReader_wcharType (pfile));\r
+ break;\r
+\r
+ case T_USER_LABEL_PREFIX_TYPE:\r
+ buf = cstring_makeLiteral (USER_LABEL_PREFIX);\r
+ break;\r
+\r
+ case T_REGISTER_PREFIX_TYPE:\r
+ buf = cstring_makeLiteral (REGISTER_PREFIX);\r
+ break;\r
+\r
+ case T_CONST:\r
+ buf = message ("%d", hp->value.ival);\r
+ break;\r
+\r
+ case T_SPECLINE:\r
+ {\r
+ if (ip != NULL)\r
+ {\r
+ int line = ip->lineno;\r
+ int col = ip->colno;\r
+\r
+ llassert (ip->cur != NULL);\r
+ adjust_position (cppLineBase (ip), ip->cur, &line, &col);\r
+\r
+ buf = message ("%d", (int) line);\r
+ }\r
+ else\r
+ {\r
+ BADBRANCH;\r
+ }\r
+ }\r
+ break;\r
+\r
+ case T_DATE:\r
+ case T_TIME:\r
+ {\r
+ char *sbuf = (char *) dmalloc (20);\r
+ timebuf = timestamp (pfile);\r
+ if (hp->type == T_DATE)\r
+ {\r
+ sprintf (sbuf, "\"%s %2d %4d\"", monthnames[timebuf->tm_mon],\r
+ timebuf->tm_mday, timebuf->tm_year + 1900);\r
+ }\r
+ else\r
+ {\r
+ sprintf (sbuf, "\"%02d:%02d:%02d\"", timebuf->tm_hour, timebuf->tm_min,\r
+ timebuf->tm_sec);\r
+ }\r
+\r
+ buf = cstring_fromCharsNew (sbuf);\r
+ sfree (sbuf);\r
+ break;\r
+ }\r
+\r
+ case T_SPEC_DEFINED:\r
+ buf = cstring_makeLiteral (" 0 "); /* Assume symbol is not defined */\r
+ ip = cppReader_getBuffer (pfile);\r
+\r
+ llassert (ip->cur != NULL);\r
+ SKIP_WHITE_SPACE (ip->cur);\r
+\r
+ if (*ip->cur == '(')\r
+ {\r
+ paren++;\r
+ ip->cur++; /* Skip over the paren */\r
+ SKIP_WHITE_SPACE (ip->cur);\r
+ }\r
+\r
+ if (!is_idstart[(int) *ip->cur])\r
+ goto oops;\r
+ if (ip->cur[0] == 'L' && (ip->cur[1] == '\'' || ip->cur[1] == '"'))\r
+ goto oops;\r
+\r
+ if ((hp = cppReader_lookup (ip->cur, -1, -1)) != 0)\r
+ {\r
+ cstring_free (buf);\r
+ buf = cstring_makeLiteral (" 1 ");\r
+ }\r
+\r
+ while (is_idchar[(int) *ip->cur])\r
+ {\r
+ ++ip->cur;\r
+ }\r
+\r
+ SKIP_WHITE_SPACE (ip->cur);\r
+\r
+ if (paren != 0)\r
+ {\r
+ if (*ip->cur != ')')\r
+ goto oops;\r
+ ++ip->cur;\r
+ }\r
+ break;\r
+\r
+ oops:\r
+\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`defined' without an identifier"));\r
+ break;\r
+\r
+ default:\r
+ cpp_setLocation (pfile);\r
+ llfatalerror (message ("Pre-processing error: invalid special hash type"));\r
+ }\r
+\r
+ len = size_fromInt (cstring_length (buf));\r
+\r
+ cppReader_reserve (pfile, len + 1);\r
+ cppReader_putStrN (pfile, cstring_toCharsSafe (buf), len);\r
+ cppReader_nullTerminateQ (pfile);\r
+\r
+ cstring_free (buf);\r
+ return;\r
+}\r
+\r
+/* Write out a #define command for the special named MACRO_NAME\r
+ to PFILE's token_buffer. */\r
+\r
+static void\r
+dump_special_to_buffer (cppReader *pfile, char *macro_name)\r
+{\r
+ static char define_directive[] = "#define ";\r
+ size_t macro_name_length = strlen (macro_name);\r
+ output_line_command (pfile, 0, same_file);\r
+ cppReader_reserve (pfile, sizeof(define_directive) + macro_name_length);\r
+ cppReader_putStrN (pfile, define_directive, sizeof(define_directive)-1);\r
+ cppReader_putStrN (pfile, macro_name, macro_name_length);\r
+ cppReader_putCharQ (pfile, ' ');\r
+ cpp_expand_to_buffer (pfile, macro_name, macro_name_length);\r
+ cppReader_putChar (pfile, '\n');\r
+}\r
+\r
+/* Initialize the built-in macros. */\r
+\r
+static void\r
+cppReader_installBuiltin (/*@observer@*/ char *name, ctype ctyp,\r
+ int len, enum node_type type,\r
+ int ivalue, /*@null@*/ /*@only@*/ char *value,\r
+ int hash)\r
+{\r
+ cstring sname = cstring_fromCharsNew (name);\r
+\r
+ llassert (usymtab_inGlobalScope ());\r
+\r
+ /*\r
+ ** Be careful here: this is done before the ctype table has\r
+ ** been initialized.\r
+ */\r
+\r
+ if (!usymtab_exists (sname))\r
+ {\r
+ uentry ue = uentry_makeConstant (sname, ctyp, fileloc_createBuiltin ());\r
+\r
+ if (ctype_equal (ctyp, ctype_string))\r
+ {\r
+ qualList ql = qualList_new ();\r
+ ql = qualList_add (ql, qual_createObserver ());\r
+ uentry_reflectQualifiers (ue, ql);\r
+ qualList_free (ql);\r
+ }\r
+ \r
+ usymtab_addGlobalEntry (ue);\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ (void) cppReader_install (name, len, type, ivalue, value, hash);\r
+ cstring_free (sname);\r
+}\r
+\r
+static void\r
+cppReader_installBuiltinType (/*@observer@*/ char *name, ctype ctyp,\r
+ int len, enum node_type type,\r
+ int ivalue,\r
+ /*@only@*/ /*@null@*/ char *value, int hash)\r
+{\r
+ cstring sname = cstring_fromChars (name);\r
+ /* evs 2000 07 10 - removed a memory leak, detected by lclint */\r
+\r
+ llassert (usymtab_inGlobalScope ());\r
+\r
+ if (!usymtab_existsTypeEither (sname))\r
+ {\r
+ uentry ue = uentry_makeDatatype (sname, ctyp,\r
+ NO, NO,\r
+ fileloc_createBuiltin ());\r
+ llassert (!usymtab_existsEither (sname));\r
+ usymtab_addGlobalEntry (ue);\r
+ }\r
+\r
+ (void) cppReader_install (name, len, type, ivalue, value, hash);\r
+}\r
+\r
+static void\r
+initialize_builtins (cppReader *pfile)\r
+{\r
+ cppReader_installBuiltin ("__LINE__", ctype_int, -1, T_SPECLINE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__DATE__", ctype_string, -1, T_DATE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__FILE__", ctype_string, -1, T_FILE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__BASE_FILE__", ctype_string, -1, T_BASE_FILE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__INCLUDE_LEVEL__", ctype_int, -1, T_INCLUDE_LEVEL, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__VERSION__", ctype_string, -1, T_VERSION, 0, NULL, -1);\r
+#ifndef NO_BUILTIN_SIZE_TYPE\r
+ cppReader_installBuiltinType ("__SIZE_TYPE__", ctype_anyintegral, -1, T_SIZE_TYPE, 0, NULL, -1);\r
+#endif\r
+#ifndef NO_BUILTIN_PTRDIFF_TYPE\r
+ cppReader_installBuiltinType ("__PTRDIFF_TYPE__", ctype_anyintegral, -1, T_PTRDIFF_TYPE, 0, NULL, -1);\r
+#endif\r
+ cppReader_installBuiltinType ("__WCHAR_TYPE__", ctype_anyintegral, -1, T_WCHAR_TYPE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__USER_LABEL_PREFIX__", ctype_string, -1, T_USER_LABEL_PREFIX_TYPE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__REGISTER_PREFIX__", ctype_string, -1, T_REGISTER_PREFIX_TYPE, 0, NULL, -1);\r
+ cppReader_installBuiltin ("__TIME__", ctype_string, -1, T_TIME, 0, NULL, -1);\r
+\r
+ /*\r
+ ** No, don't define __STDC__\r
+ **\r
+\r
+ if (!cppReader_isTraditional (pfile))\r
+ {\r
+ cppReader_installBuiltin ("__STDC__", ctype_int, -1, T_CONST, STDC_VALUE, NULL, -1);\r
+ }\r
+\r
+ **\r
+ */\r
+\r
+# ifdef WIN32\r
+ cppReader_installBuiltin ("_WIN32", ctype_int, -1, T_CONST, STDC_VALUE, NULL, -1);\r
+# endif\r
+\r
+ /*\r
+ ** This is supplied using a -D by the compiler driver\r
+ ** so that it is present only when truly compiling with GNU C.\r
+ */\r
+\r
+ /* cppReader_install ("__GNUC__", -1, T_CONST, 2, 0, -1); */\r
+\r
+ cppReader_installBuiltin ("__LCLINT__", ctype_int, -1, T_CONST, 2, NULL, -1);\r
+\r
+ if (CPPOPTIONS (pfile)->debug_output)\r
+ {\r
+ dump_special_to_buffer (pfile, "__BASE_FILE__");\r
+ dump_special_to_buffer (pfile, "__VERSION__");\r
+#ifndef NO_BUILTIN_SIZE_TYPE\r
+ dump_special_to_buffer (pfile, "__SIZE_TYPE__");\r
+#endif\r
+#ifndef NO_BUILTIN_PTRDIFF_TYPE\r
+ dump_special_to_buffer (pfile, "__PTRDIFF_TYPE__");\r
+#endif\r
+ dump_special_to_buffer (pfile, "__WCHAR_TYPE__");\r
+ dump_special_to_buffer (pfile, "__DATE__");\r
+ dump_special_to_buffer (pfile, "__TIME__");\r
+ if (!cppReader_isTraditional (pfile))\r
+ dump_special_to_buffer (pfile, "__STDC__");\r
+ }\r
+}\r
+\r
+\r
+/* Return 1 iff a token ending in C1 followed directly by a token C2\r
+ could cause mis-tokenization. */\r
+\r
+static bool\r
+unsafe_chars (char c1, char c2)\r
+{\r
+ switch (c1)\r
+ {\r
+ case '+': case '-':\r
+ if (c2 == c1 || c2 == '=')\r
+ return 1;\r
+ goto letter;\r
+ case '.':\r
+ case '0': case '1': case '2': case '3': case '4':\r
+ case '5': case '6': case '7': case '8': case '9':\r
+ case 'e': case 'E': case 'p': case 'P':\r
+ if (c2 == '-' || c2 == '+')\r
+ return 1; /* could extend a pre-processing number */\r
+ goto letter;\r
+ case 'L':\r
+ if (c2 == '\'' || c2 == '\"')\r
+ return 1; /* Could turn into L"xxx" or L'xxx'. */\r
+ goto letter;\r
+ letter:\r
+ case '_':\r
+ case 'a': case 'b': case 'c': case 'd': case 'f':\r
+ case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':\r
+ case 'm': case 'n': case 'o': case 'q': case 'r':\r
+ case 's': case 't': case 'u': case 'v': case 'w': case 'x':\r
+ case 'y': case 'z':\r
+ case 'A': case 'B': case 'C': case 'D': case 'F':\r
+ case 'G': case 'H': case 'I': case 'J': case 'K':\r
+ case 'M': case 'N': case 'O': case 'Q': case 'R':\r
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':\r
+ case 'Y': case 'Z':\r
+ /* We're in the middle of either a name or a pre-processing number. */\r
+ return (is_idchar[(int) c2] || c2 == '.');\r
+ case '<': case '>': case '!': case '%': case '#': case ':':\r
+ case '^': case '&': case '|': case '*': case '/': case '=':\r
+ return (c2 == c1 || c2 == '=');\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* Expand a macro call.\r
+ HP points to the symbol that is the macro being called.\r
+ Put the result of expansion onto the input stack\r
+ so that subsequent input by our caller will use it.\r
+\r
+ If macro wants arguments, caller has already verified that\r
+ an argument list follows; arguments come from the input stack. */\r
+\r
+static void\r
+macroexpand (cppReader *pfile, /*@dependent@*/ hashNode hp)\r
+{\r
+ int nargs;\r
+ DEFINITION *defn = hp->value.defn;\r
+ char *xbuf;\r
+ char *oxbuf = NULL;\r
+ int start_line;\r
+ int start_column;\r
+ size_t xbuf_len;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ int rest_args;\r
+ int rest_zero = 0;\r
+ int i;\r
+ struct argdata *args = NULL;\r
+\r
+ pfile->output_escapes++;\r
+\r
+ cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile), &start_line, &start_column);\r
+\r
+ nargs = defn->nargs;\r
+\r
+ if (nargs >= 0)\r
+ {\r
+ enum cpp_token token = CPP_EOF;\r
+\r
+ args = (struct argdata *) dmalloc ((nargs + 1) * sizeof (*args));\r
+\r
+ for (i = 0; i < nargs; i++)\r
+ {\r
+ args[i].expanded = 0;\r
+ args[i].raw = 0;\r
+ args[i].raw_length = 0;\r
+ args[i].expand_length = args[i].stringified_length = -1;\r
+ args[i].use_count = 0;\r
+ }\r
+\r
+ /*\r
+ ** Parse all the macro args that are supplied. I counts them.\r
+ ** The first NARGS args are stored in ARGS.\r
+ ** The rest are discarded. If rest_args is set then we assume\r
+ ** macarg absorbed the rest of the args.\r
+ */\r
+\r
+ i = 0;\r
+ rest_args = 0;\r
+\r
+ cppReader_forward (pfile, 1); /* Discard the open-parenthesis before the first arg. */\r
+ do\r
+ {\r
+ if (rest_args != 0)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ if (i < nargs || (nargs == 0 && i == 0))\r
+ {\r
+ /* if we are working on last arg which absorbs rest of args... */\r
+ if (i == nargs - 1 && defn->rest_args)\r
+ {\r
+ rest_args = 1;\r
+ }\r
+\r
+ args[i].raw = size_toLong (cppReader_getWritten (pfile));\r
+ token = macarg (pfile, rest_args);\r
+ args[i].raw_length = cppReader_getWritten (pfile) - args[i].raw;\r
+ args[i].newlines = FALSE; /* FIXME */\r
+ }\r
+ else\r
+ {\r
+ token = macarg (pfile, 0);\r
+ }\r
+\r
+ if (token == CPP_EOF || token == CPP_POP)\r
+ {\r
+ cppReader_errorWithLine (pfile, start_line, start_column,\r
+ cstring_fromCharsNew ("unterminated macro call"));\r
+ sfree (args);\r
+ return;\r
+ }\r
+ i++;\r
+ } while (token == CPP_COMMA);\r
+\r
+ /* If we got one arg but it was just whitespace, call that 0 args. */\r
+ if (i == 1)\r
+ {\r
+ char *bp;\r
+ char *lim;\r
+\r
+ assertSet (args);\r
+\r
+ bp = ARG_BASE + args[0].raw;\r
+ lim = bp + args[0].raw_length;\r
+\r
+ /* cpp.texi says for foo ( ) we provide one argument.\r
+ However, if foo wants just 0 arguments, treat this as 0. */\r
+\r
+ if (nargs == 0)\r
+ {\r
+ while (bp != lim && is_space[(int) *bp])\r
+ {\r
+ bp++;\r
+ }\r
+ }\r
+\r
+ if (bp == lim)\r
+ i = 0;\r
+ }\r
+\r
+ /* Don't output an error message if we have already output one for\r
+ a parse error above. */\r
+ rest_zero = 0;\r
+\r
+ if (nargs == 0 && i > 0)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("arguments given to macro `%s'", hp->name));\r
+ }\r
+ else if (i < nargs)\r
+ {\r
+ /* traditional C allows foo() if foo wants one argument. */\r
+ if (nargs == 1 && i == 0 && cppReader_isTraditional (pfile))\r
+ {\r
+ ;\r
+ }\r
+ /* the rest args token is allowed to absorb 0 tokens */\r
+ else if (i == nargs - 1 && defn->rest_args)\r
+ rest_zero = 1;\r
+ else if (i == 0)\r
+ cppReader_error (pfile,\r
+ message ("macro `%s' used without args", hp->name));\r
+ else if (i == 1)\r
+ cppReader_error (pfile,\r
+ message ("macro `%s' used with just one arg", hp->name));\r
+ else\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("macro `%s' used with only %d args",\r
+ hp->name, i));\r
+ }\r
+ }\r
+ else if (i > nargs)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("macro `%s' used with too many (%d) args", hp->name, i));\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+\r
+ /* If macro wants zero args, we parsed the arglist for checking only.\r
+ Read directly from the macro definition. */\r
+\r
+ if (nargs <= 0)\r
+ {\r
+ xbuf = defn->expansion;\r
+ xbuf_len = defn->length;\r
+ }\r
+ else\r
+ {\r
+ char *exp = defn->expansion;\r
+ int offset; /* offset in expansion,\r
+ copied a piece at a time */\r
+ size_t totlen; /* total amount of exp buffer filled so far */\r
+\r
+ register struct reflist *ap, *last_ap;\r
+ \r
+ assertSet (args); /* args is defined since the nargs > 0 path was taken */\r
+\r
+ /* Macro really takes args. Compute the expansion of this call. */\r
+\r
+ /* Compute length in characters of the macro's expansion.\r
+ Also count number of times each arg is used. */\r
+ xbuf_len = defn->length;\r
+\r
+ llassert (args != NULL);\r
+\r
+ for (ap = defn->pattern; ap != NULL; ap = ap->next)\r
+ {\r
+ if (ap->stringify)\r
+ {\r
+ struct argdata *arg = &args[ap->argno];\r
+\r
+ /* Stringify it it hasn't already been */\r
+ assertSet (arg);\r
+\r
+ if (arg->stringified_length < 0)\r
+ {\r
+ int arglen = arg->raw_length;\r
+ bool escaped = FALSE;\r
+ char in_string = '\0';\r
+ char c;\r
+\r
+ /* Initially need_space is -1. Otherwise, 1 means the\r
+ previous character was a space, but we suppressed it;\r
+ 0 means the previous character was a non-space. */\r
+ int need_space = -1;\r
+\r
+ i = 0;\r
+ arg->stringified = cppReader_getWritten (pfile);\r
+ if (!cppReader_isTraditional (pfile))\r
+ cppReader_putChar (pfile, '\"'); /* insert beginning quote */\r
+ for (; i < arglen; i++)\r
+ {\r
+ c = (ARG_BASE + arg->raw)[i];\r
+\r
+ if (in_string == '\0')\r
+ {\r
+ /* Internal sequences of whitespace are replaced by\r
+ one space except within an string or char token.*/\r
+ if (is_space[(int) c])\r
+ {\r
+ if (cppReader_getWritten (pfile) > arg->stringified\r
+ && (cppReader_getPWritten (pfile))[-1] == '@')\r
+ {\r
+ /* "@ " escape markers are removed */\r
+ cppReader_adjustWritten (pfile, -1);\r
+ /*@innercontinue@*/ continue;\r
+ }\r
+ if (need_space == 0)\r
+ need_space = 1;\r
+ /*@innercontinue@*/ continue;\r
+ }\r
+ else if (need_space > 0)\r
+ cppReader_putChar (pfile, ' ');\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ need_space = 0;\r
+ }\r
+\r
+ if (escaped)\r
+ escaped = 0;\r
+ else\r
+ {\r
+ if (c == '\\')\r
+ escaped = 1;\r
+\r
+ if (in_string != '\0')\r
+ {\r
+ if (c == in_string)\r
+ in_string = '\0';\r
+ }\r
+ else if (c == '\"' || c == '\'')\r
+ {\r
+ in_string = c;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+\r
+ /* Escape these chars */\r
+ if (c == '\"' || (in_string != '\0' && c == '\\'))\r
+ cppReader_putChar (pfile, '\\');\r
+ if (isprint (c))\r
+ cppReader_putChar (pfile, c);\r
+ else\r
+ {\r
+ cppReader_reserve (pfile, 4);\r
+ sprintf (cppReader_getPWritten (pfile), "\\%03o",\r
+ (unsigned int) c);\r
+ cppReader_adjustWritten (pfile, 4);\r
+ }\r
+ }\r
+ if (!cppReader_isTraditional (pfile))\r
+ cppReader_putChar (pfile, '\"'); /* insert ending quote */\r
+ arg->stringified_length\r
+ = size_toInt (cppReader_getWritten (pfile) - arg->stringified);\r
+ }\r
+\r
+ xbuf_len += args[ap->argno].stringified_length;\r
+ }\r
+ else if (ap->raw_before || ap->raw_after || cppReader_isTraditional (pfile))\r
+ {\r
+ /* Add 4 for two newline-space markers to prevent\r
+ token concatenation. */\r
+ assertSet (args); /*@i534 shouldn't need this */\r
+ xbuf_len += args[ap->argno].raw_length + 4;\r
+ }\r
+ else\r
+ {\r
+ /* We have an ordinary (expanded) occurrence of the arg.\r
+ So compute its expansion, if we have not already. */\r
+\r
+ assertSet (args); /*@i534 shouldn't need this */\r
+\r
+ if (args[ap->argno].expand_length < 0)\r
+ {\r
+ args[ap->argno].expanded = cppReader_getWritten (pfile);\r
+ cpp_expand_to_buffer (pfile,\r
+ ARG_BASE + args[ap->argno].raw,\r
+ size_fromInt (args[ap->argno].raw_length));\r
+\r
+ args[ap->argno].expand_length\r
+ = size_toInt (cppReader_getWritten (pfile) - args[ap->argno].expanded);\r
+ }\r
+\r
+ /* Add 4 for two newline-space markers to prevent\r
+ token concatenation. */\r
+ xbuf_len += args[ap->argno].expand_length + 4;\r
+ }\r
+ if (args[ap->argno].use_count < 10)\r
+ args[ap->argno].use_count++;\r
+ }\r
+\r
+ xbuf = (char *) dmalloc (xbuf_len + 1);\r
+ oxbuf = xbuf;\r
+\r
+ /*\r
+ ** Generate in XBUF the complete expansion\r
+ ** with arguments substituted in.\r
+ ** TOTLEN is the total size generated so far.\r
+ ** OFFSET is the index in the definition\r
+ ** of where we are copying from.\r
+ */\r
+\r
+ offset = 0;\r
+ totlen = 0;\r
+\r
+ for (last_ap = NULL, ap = defn->pattern; ap != NULL;\r
+ last_ap = ap, ap = ap->next)\r
+ {\r
+ register struct argdata *arg = &args[ap->argno];\r
+ size_t count_before = totlen;\r
+\r
+ /* Add chars to XBUF. */\r
+ for (i = 0; i < ap->nchars; i++, offset++)\r
+ {\r
+ xbuf[totlen++] = exp[offset];\r
+ }\r
+\r
+ /* If followed by an empty rest arg with concatenation,\r
+ delete the last run of nonwhite chars. */\r
+ if (rest_zero && totlen > count_before\r
+ && ((ap->rest_args && ap->raw_before)\r
+ || (last_ap != NULL && last_ap->rest_args\r
+ && last_ap->raw_after)))\r
+ {\r
+ /* Delete final whitespace. */\r
+ while (totlen > count_before && is_space[(int) xbuf[totlen - 1]])\r
+ {\r
+ totlen--;\r
+ }\r
+\r
+ /* Delete the nonwhites before them. */\r
+ while (totlen > count_before && ! is_space[(int) xbuf[totlen - 1]])\r
+ {\r
+ totlen--;\r
+ }\r
+ }\r
+\r
+ if (ap->stringify != 0)\r
+ {\r
+ assertSet(arg);\r
+ memcpy (xbuf + totlen,\r
+ ARG_BASE + arg->stringified,\r
+ size_fromInt (arg->stringified_length));\r
+ totlen += arg->stringified_length;\r
+ }\r
+ else if (ap->raw_before || ap->raw_after || cppReader_isTraditional (pfile))\r
+ {\r
+ char *p1;\r
+ char *l1;\r
+\r
+ assertSet (arg);\r
+\r
+ p1 = ARG_BASE + arg->raw;\r
+ l1 = p1 + arg->raw_length;\r
+\r
+ if (ap->raw_before)\r
+ {\r
+ while (p1 != l1 && is_space[(int) *p1])\r
+ {\r
+ p1++;\r
+ }\r
+\r
+ while (p1 != l1 && is_idchar[(int) *p1])\r
+ {\r
+ xbuf[totlen++] = *p1++;\r
+ }\r
+\r
+ /* Delete any no-reexpansion marker that follows\r
+ an identifier at the beginning of the argument\r
+ if the argument is concatenated with what precedes it. */\r
+ if (p1[0] == '@' && p1[1] == '-')\r
+ p1 += 2;\r
+ }\r
+ if (ap->raw_after)\r
+ {\r
+ /* Arg is concatenated after: delete trailing whitespace,\r
+ whitespace markers, and no-reexpansion markers. */\r
+ while (p1 != l1)\r
+ {\r
+ if (is_space[(int) l1[-1]]) l1--;\r
+ else if (l1[-1] == '-')\r
+ {\r
+ char *p2 = l1 - 1;\r
+ /* If a `-' is preceded by an odd number of newlines then it\r
+ and the last newline are a no-reexpansion marker. */\r
+ while (p2 != p1 && p2[-1] == '\n')\r
+ {\r
+ p2--;\r
+ }\r
+\r
+ if (((l1 - 1 - p2) & 1) != 0)\r
+ {\r
+ l1 -= 2;\r
+ }\r
+ else\r
+ {\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ memcpy (xbuf + totlen, p1, size_fromInt (l1 - p1));\r
+ totlen += l1 - p1;\r
+ }\r
+ else\r
+ {\r
+ char *expanded;\r
+\r
+ assertSet (arg);\r
+ expanded = ARG_BASE + arg->expanded;\r
+\r
+ if (!ap->raw_before && totlen > 0\r
+ && (arg->expand_length != 0)\r
+ && !cppReader_isTraditional(pfile)\r
+ && unsafe_chars (xbuf[totlen-1], expanded[0]))\r
+ {\r
+ xbuf[totlen++] = '@';\r
+ xbuf[totlen++] = ' ';\r
+ }\r
+\r
+ memcpy (xbuf + totlen, expanded,\r
+ size_fromInt (arg->expand_length));\r
+ totlen += arg->expand_length;\r
+\r
+ if (!ap->raw_after && totlen > 0\r
+ && offset < size_toInt (defn->length)\r
+ && !cppReader_isTraditional(pfile)\r
+ && unsafe_chars (xbuf[totlen-1], exp[offset]))\r
+ {\r
+ xbuf[totlen++] = '@';\r
+ xbuf[totlen++] = ' ';\r
+ }\r
+\r
+ /* If a macro argument with newlines is used multiple times,\r
+ then only expand the newlines once. This avoids creating\r
+ output lines which don't correspond to any input line,\r
+ which confuses gdb and gcov. */\r
+ if (arg->use_count > 1 && arg->newlines > 0)\r
+ {\r
+ /* Don't bother doing change_newlines for subsequent\r
+ uses of arg. */\r
+ arg->use_count = 1;\r
+ arg->expand_length\r
+ = change_newlines (expanded, arg->expand_length);\r
+ }\r
+ }\r
+\r
+ if (totlen > xbuf_len)\r
+ abort ();\r
+ }\r
+\r
+ /* if there is anything left of the definition\r
+ after handling the arg list, copy that in too. */\r
+\r
+ for (i = offset; i < size_toInt (defn->length); i++)\r
+ {\r
+ /* if we've reached the end of the macro */\r
+ if (exp[i] == ')')\r
+ rest_zero = 0;\r
+ if (! (rest_zero && last_ap != NULL && last_ap->rest_args\r
+ && last_ap->raw_after))\r
+ xbuf[totlen++] = exp[i];\r
+ }\r
+\r
+ xbuf[totlen] = '\0';\r
+ xbuf_len = totlen;\r
+ }\r
+\r
+ pfile->output_escapes--;\r
+\r
+ /* Now put the expansion on the input stack\r
+ so our caller will commence reading from it. */\r
+ push_macro_expansion (pfile, xbuf, xbuf_len, hp);\r
+ cppReader_getBuffer (pfile)->has_escapes = 1;\r
+\r
+ /* Pop the space we've used in the token_buffer for argument expansion. */\r
+ cppReader_setWritten (pfile, old_written);\r
+\r
+ /* Recursive macro use sometimes works traditionally.\r
+ #define foo(x,y) bar (x (y,0), y)\r
+ foo (foo, baz) */\r
+\r
+ if (!cppReader_isTraditional (pfile))\r
+ hp->type = T_DISABLED;\r
+\r
+ sfree (args);\r
+}\r
+\r
+static void\r
+push_macro_expansion (cppReader *pfile, char *xbuf, size_t xbuf_len,\r
+ /*@dependent@*/ hashNode hp)\r
+{\r
+ cppBuffer *mbuf = cppReader_pushBuffer (pfile, xbuf, xbuf_len);\r
+\r
+ if (mbuf == NULL)\r
+ {\r
+ return;\r
+ }\r
+\r
+ mbuf->cleanup = cppReader_macroCleanup;\r
+\r
+ llassert (mbuf->hnode == NULL);\r
+ mbuf->hnode = hp;\r
+\r
+ /* The first chars of the expansion should be a "@ " added by\r
+ collect_expansion. This is to prevent accidental token-pasting\r
+ between the text preceding the macro invocation, and the macro\r
+ expansion text.\r
+\r
+ We would like to avoid adding unneeded spaces (for the sake of\r
+ tools that use cpp, such as imake). In some common cases we can\r
+ tell that it is safe to omit the space.\r
+\r
+ The character before the macro invocation cannot have been an\r
+ idchar (or else it would have been pasted with the idchars of\r
+ the macro name). Therefore, if the first non-space character\r
+ of the expansion is an idchar, we do not need the extra space\r
+ to prevent token pasting.\r
+\r
+ Also, we don't need the extra space if the first char is '(',\r
+ or some other (less common) characters. */\r
+\r
+ if (xbuf[0] == '@' && xbuf[1] == ' '\r
+ && (is_idchar[(int) xbuf[2]] || xbuf[2] == '(' || xbuf[2] == '\''\r
+ || xbuf[2] == '\"'))\r
+ {\r
+ llassert (mbuf->cur != NULL);\r
+ mbuf->cur += 2;\r
+ }\r
+}\r
+\r
+\r
+/* Like cppGetToken, except that it does not read past end-of-line.\r
+ Also, horizontal space is skipped, and macros are popped. */\r
+\r
+static enum cpp_token\r
+get_directive_token (cppReader *pfile)\r
+{\r
+ for (;;)\r
+ {\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ enum cpp_token token;\r
+ cppSkipHspace (pfile);\r
+ if (cppReader_peekC (pfile) == '\n')\r
+ {\r
+ return CPP_VSPACE;\r
+ }\r
+\r
+ token = cppGetToken (pfile);\r
+\r
+ switch (token)\r
+ {\r
+ case CPP_POP:\r
+ if (!cppBuffer_isMacro (cppReader_getBuffer (pfile)))\r
+ return token;\r
+ /*@fallthrough@*/\r
+ case CPP_HSPACE:\r
+ case CPP_COMMENT:\r
+ cppReader_setWritten (pfile, old_written);\r
+ /*@switchbreak@*/ break;\r
+ default:\r
+ return token;\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/* Handle #include and #import.\r
+ This function expects to see "fname" or <fname> on the input.\r
+\r
+ The input is normally in part of the output_buffer following\r
+ cppReader_getWritten, and will get overwritten by output_line_command.\r
+ I.e. in input file specification has been popped by cppReader_handleDirective.\r
+ This is safe. */\r
+\r
+static int\r
+do_include (cppReader *pfile, struct directive *keyword,\r
+ /*@unused@*/ char *unused1, /*@unused@*/ char *unused2)\r
+{\r
+ bool skip_dirs = (keyword->type == T_INCLUDE_NEXT);\r
+ cstring fname;\r
+ char *fbeg, *fend; /* Beginning and end of fname */\r
+ enum cpp_token token;\r
+\r
+ /* Chain of dirs to search */\r
+ struct file_name_list *search_start = CPPOPTIONS (pfile)->include;\r
+ struct file_name_list dsp[1]; /* First in chain, if #include "..." */\r
+ struct file_name_list *searchptr = NULL;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+\r
+ int flen;\r
+\r
+ int f; /* file number */\r
+ int angle_brackets = 0; /* 0 for "...", 1 for <...> */\r
+ f= -1; /* JF we iz paranoid! */\r
+\r
+ pfile->parsing_include_directive++;\r
+ token = get_directive_token (pfile);\r
+ pfile->parsing_include_directive--;\r
+\r
+ if (token == CPP_STRING)\r
+ {\r
+ /* FIXME - check no trailing garbage */\r
+ fbeg = pfile->token_buffer + old_written + 1;\r
+ fend = cppReader_getPWritten (pfile) - 1;\r
+ if (fbeg[-1] == '<')\r
+ {\r
+ angle_brackets = 1;\r
+ /* If -I-, start with the first -I dir after the -I-. */\r
+ if (CPPOPTIONS (pfile)->first_bracket_include != NULL)\r
+ search_start = CPPOPTIONS (pfile)->first_bracket_include;\r
+ }\r
+ /* If -I- was specified, don't search current dir, only spec'd ones. */\r
+ else if (!CPPOPTIONS (pfile)->ignore_srcdir)\r
+ {\r
+ cppBuffer *fp = CPPBUFFER (pfile);\r
+ /* We have "filename". Figure out directory this source\r
+ file is coming from and put it on the front of the list. */\r
+\r
+ for ( ; fp != cppReader_nullBuffer (pfile); fp = cppBuffer_prevBuffer (fp))\r
+ {\r
+ int n;\r
+ char *ep,*nam;\r
+\r
+ llassert (fp != NULL);\r
+\r
+ nam = NULL;\r
+\r
+ if (cstring_isDefined (fp->nominal_fname))\r
+ {\r
+ nam = cstring_toCharsSafe (fp->nominal_fname);\r
+\r
+ /* Found a named file. Figure out dir of the file,\r
+ and put it in front of the search list. */\r
+ dsp[0].next = search_start;\r
+ search_start = dsp;\r
+\r
+#ifndef VMS\r
+ ep = strrchr (nam, CONNECTCHAR);\r
+#else /* VMS */\r
+ ep = strrchr (nam, ']');\r
+ if (ep == NULL) ep = strrchr (nam, '>');\r
+ if (ep == NULL) ep = strrchr (nam, ':');\r
+ if (ep != NULL) ep++;\r
+#endif /* VMS */\r
+ if (ep != NULL)\r
+ {\r
+ char save;\r
+\r
+ n = ep - nam;\r
+ save = nam[n];\r
+ nam[n] = '\0';\r
+\r
+ /*@-onlytrans@*/ /* This looks like a memory leak... */ \r
+ dsp[0].fname = cstring_fromCharsNew (nam); /* evs 2000-07-20: was fromChars */\r
+ /*@=onlytrans@*/\r
+ nam[n] = save;\r
+\r
+ if (n + INCLUDE_LEN_FUDGE > pfile->max_include_len)\r
+ pfile->max_include_len = n + INCLUDE_LEN_FUDGE;\r
+ }\r
+ else\r
+ {\r
+ dsp[0].fname = cstring_undefined; /* Current directory */\r
+ }\r
+\r
+ dsp[0].got_name_map = 0;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+#ifdef VMS\r
+ else if (token == CPP_NAME)\r
+ {\r
+ /*\r
+ * Support '#include xyz' like VAX-C to allow for easy use of all the\r
+ * decwindow include files. It defaults to '#include <xyz.h>' (so the\r
+ * code from case '<' is repeated here) and generates a warning.\r
+ */\r
+ cppReader_warning (pfile,\r
+ "VAX-C-style include specification found, use '#include <filename.h>' !");\r
+ angle_brackets = 1;\r
+ /* If -I-, start with the first -I dir after the -I-. */\r
+ if (CPPOPTIONS (pfile)->first_bracket_include)\r
+ search_start = CPPOPTIONS (pfile)->first_bracket_include;\r
+ fbeg = pfile->token_buffer + old_written;\r
+ fend = cppReader_getPWritten (pfile);\r
+ }\r
+#endif\r
+ else\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Preprocessor command #%s expects \"FILENAME\" or <FILENAME>",\r
+ keyword->name));\r
+\r
+ cppReader_setWritten (pfile, old_written);\r
+ cppReader_skipRestOfLine (pfile);\r
+ return 0;\r
+ }\r
+\r
+ *fend = 0;\r
+\r
+ token = get_directive_token (pfile);\r
+ if (token != CPP_VSPACE)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("Junk at end of #include"));\r
+\r
+ while (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP)\r
+ {\r
+ token = get_directive_token (pfile);\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** For #include_next, skip in the search path\r
+ ** past the dir in which the containing file was found.\r
+ */\r
+\r
+ if (skip_dirs)\r
+ {\r
+ cppBuffer *fp = CPPBUFFER (pfile);\r
+\r
+ for (; fp != cppReader_nullBuffer (pfile); fp = cppBuffer_prevBuffer (fp))\r
+ {\r
+ llassert (fp != NULL);\r
+\r
+ if (fp->fname != NULL)\r
+ {\r
+ /* fp->dir is null if the containing file was specified with\r
+ an absolute file name. In that case, don't skip anything. */\r
+ if (fp->dir == SELF_DIR_DUMMY)\r
+ {\r
+ search_start = CPPOPTIONS (pfile)->include;\r
+ }\r
+ else if (fp->dir != NULL)\r
+ {\r
+ search_start = fp->dir->next;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ cppReader_setWritten (pfile, old_written);\r
+\r
+ flen = fend - fbeg;\r
+\r
+ DPRINTF (("fbeg: %s", fbeg));\r
+\r
+ if (flen == 0)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Empty file name in #%s", keyword->name));\r
+ return 0;\r
+ }\r
+\r
+ /*\r
+ ** Allocate this permanently, because it gets stored in the definitions\r
+ ** of macros.\r
+ */\r
+\r
+ fname = cstring_undefined;\r
+\r
+ /* + 2 above for slash and terminating null. */\r
+ /* + 2 added for '.h' on VMS (to support '#include filename') */\r
+\r
+ /* If specified file name is absolute, just open it. */\r
+\r
+ if (osd_isConnectChar (*fbeg)\r
+# if defined (WIN32) || defined (OS2)\r
+ || (*(fbeg + 1) == ':')\r
+# endif\r
+ )\r
+ {\r
+ fname = cstring_copyLength (fbeg, flen);\r
+ \r
+ if (redundant_include_p (pfile, fname))\r
+ {\r
+ cstring_free (fname);\r
+ return 0;\r
+ }\r
+ \r
+ f = open_include_file (pfile, fname, NULL);\r
+ \r
+ if (f == IMPORT_FOUND)\r
+ {\r
+ return 0; /* Already included this file */\r
+ }\r
+ } \r
+ else \r
+ {\r
+ /* Search directory path, trying to open the file.\r
+ Copy each filename tried into FNAME. */\r
+\r
+ for (searchptr = search_start; searchptr != NULL;\r
+ searchptr = searchptr->next)\r
+ {\r
+ if (!cstring_isEmpty (searchptr->fname))\r
+ {\r
+ /* The empty string in a search path is ignored.\r
+ This makes it possible to turn off entirely\r
+ a standard piece of the list. */\r
+ if (cstring_isEmpty (searchptr->fname))\r
+ continue;\r
+ \r
+ fname = cstring_copy (searchptr->fname);\r
+ fname = cstring_appendChar (fname, CONNECTCHAR);\r
+ DPRINTF (("Here: %s", fname));\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ \r
+ fname = cstring_concatLength (fname, fbeg, flen);\r
+\r
+ DPRINTF (("fname: %s", fname));\r
+ \r
+ /* Win32 directory fix from Kay Buschner. */\r
+#if defined (WIN32) || defined (OS2)\r
+ /* Fix all unixdir slashes to win dir slashes */\r
+ if (searchptr->fname && (searchptr->fname[0] != 0)) \r
+ {\r
+ cstring_replaceAll (fname, '/', '\\');\r
+ }\r
+#endif /* WIN32 */\r
+\r
+#ifdef VMS\r
+ /* Change this 1/2 Unix 1/2 VMS file specification into a\r
+ full VMS file specification */\r
+ if (searchptr->fname && (searchptr->fname[0] != 0)) {\r
+ /* Fix up the filename */\r
+ hack_vms_include_specification (fname);\r
+ } else {\r
+ /* This is a normal VMS filespec, so use it unchanged. */\r
+ strncpy (fname, fbeg, flen);\r
+ fname[flen] = 0;\r
+ /* if it's '#include filename', add the missing .h */\r
+ if (strchr (fname,'.') == NULL) {\r
+ strcat (fname, ".h");\r
+ }\r
+ }\r
+#endif /* VMS */\r
+ /* ??? There are currently 3 separate mechanisms for avoiding processing\r
+ of redundant include files: #import, #pragma once, and\r
+ redundant_include_p. It would be nice if they were unified. */\r
+ \r
+ if (redundant_include_p (pfile, fname))\r
+ {\r
+ cstring_free (fname);\r
+ return 0;\r
+ }\r
+\r
+ DPRINTF (("Trying: %s", fname));\r
+\r
+ f = open_include_file (pfile, fname, searchptr);\r
+ \r
+ if (f == IMPORT_FOUND)\r
+ {\r
+ return 0; /* Already included this file */\r
+ }\r
+#ifdef EACCES\r
+ else if (f == IMPORT_NOT_FOUND && errno == EACCES)\r
+ {\r
+ cppReader_warning (pfile,\r
+ message ("Header file %s exists, but is not readable", fname));\r
+ }\r
+#endif\r
+ \r
+ if (f >= 0)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (f < 0)\r
+ {\r
+ /* A file that was not found. */\r
+ fname = cstring_copyLength (fbeg, flen);\r
+\r
+ if (search_start != NULL)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Cannot find include file %s on search path: %x", \r
+ fname,\r
+ searchPath_unparse (search_start)));\r
+ }\r
+ else\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("No include path in which to find %s", fname));\r
+ }\r
+ }\r
+ else {\r
+ /*\r
+ ** Check to see if this include file is a once-only include file.\r
+ ** If so, give up.\r
+ */\r
+\r
+ struct file_name_list *ptr;\r
+\r
+ for (ptr = pfile->all_include_files; ptr != NULL; ptr = ptr->next)\r
+ {\r
+ if (cstring_equal (ptr->fname, fname))\r
+ {\r
+ /* This file was included before. */\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (ptr == NULL)\r
+ {\r
+ /* This is the first time for this file. */\r
+ /* Add it to list of files included. */\r
+\r
+ ptr = (struct file_name_list *) dmalloc (sizeof (*ptr));\r
+ ptr->control_macro = NULL;\r
+ ptr->c_system_include_path = NULL;\r
+ ptr->next = pfile->all_include_files;\r
+ ptr->fname = fname;\r
+ ptr->got_name_map = NULL;\r
+\r
+ DPRINTF (("Including file: %s", fname));\r
+ pfile->all_include_files = ptr;\r
+ assertSet (pfile->all_include_files);\r
+ }\r
+\r
+ if (angle_brackets != 0)\r
+ {\r
+ pfile->system_include_depth++;\r
+ }\r
+\r
+ /* Actually process the file */\r
+ if (cppReader_pushBuffer (pfile, NULL, 0) == NULL)\r
+ {\r
+ cstring_free (fname);\r
+ return 0;\r
+ }\r
+\r
+ if (finclude (pfile, f, fname, is_system_include (pfile, fname),\r
+ searchptr != dsp ? searchptr : SELF_DIR_DUMMY))\r
+ {\r
+ output_line_command (pfile, 0, enter_file);\r
+ pfile->only_seen_white = 2;\r
+ }\r
+\r
+ if (angle_brackets)\r
+ {\r
+ pfile->system_include_depth--;\r
+ }\r
+ /*@-branchstate@*/\r
+ } /*@=branchstate@*/ \r
+\r
+ return 0;\r
+}\r
+\r
+/* Return nonzero if there is no need to include file NAME\r
+ because it has already been included and it contains a conditional\r
+ to make a repeated include do nothing. */\r
+\r
+static bool\r
+redundant_include_p (cppReader *pfile, cstring name)\r
+{\r
+ struct file_name_list *l = pfile->all_include_files;\r
+\r
+ for (; l != NULL; l = l->next)\r
+ {\r
+ if (cstring_equal (name, l->fname)\r
+ && (l->control_macro != NULL)\r
+ && (cppReader_lookup (l->control_macro, -1, -1) != NULL))\r
+ {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/* Return nonzero if the given FILENAME is an absolute pathname which\r
+ designates a file within one of the known "system" include file\r
+ directories. We assume here that if the given FILENAME looks like\r
+ it is the name of a file which resides either directly in a "system"\r
+ include file directory, or within any subdirectory thereof, then the\r
+ given file must be a "system" include file. This function tells us\r
+ if we should suppress pedantic errors/warnings for the given FILENAME.\r
+\r
+ The value is 2 if the file is a C-language system header file\r
+ for which C++ should (on most systems) assume `extern "C"'. */\r
+\r
+static bool\r
+is_system_include (cppReader *pfile, cstring filename)\r
+{\r
+ struct file_name_list *searchptr;\r
+\r
+ for (searchptr = CPPOPTIONS (pfile)->first_system_include;\r
+ searchptr != NULL;\r
+ searchptr = searchptr->next)\r
+ {\r
+ if (!cstring_isEmpty (searchptr->fname)) {\r
+ cstring sys_dir = searchptr->fname;\r
+ int length = cstring_length (sys_dir);\r
+\r
+ if (cstring_equalLen (sys_dir, filename, length)\r
+ && osd_isConnectChar (cstring_getChar (filename, length)))\r
+ {\r
+ if (searchptr->c_system_include_path)\r
+ return 2;\r
+ else\r
+ return 1;\r
+ }\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/* Convert a character string literal into a nul-terminated string.\r
+ The input string is [IN ... LIMIT).\r
+ The result is placed in RESULT. RESULT can be the same as IN.\r
+ The value returned in the end of the string written to RESULT,\r
+ or NULL on error. */\r
+\r
+static /*@null@*/ char *\r
+convert_string (cppReader *pfile, /*@returned@*/ char *result,\r
+ char *in, char *limit, int handle_escapes)\r
+{\r
+ char c;\r
+ c = *in++;\r
+\r
+ if (c != '\"')\r
+ {\r
+ return NULL;\r
+ }\r
+\r
+ while (in < limit)\r
+ {\r
+ c = *in++;\r
+\r
+ switch (c)\r
+ {\r
+ case '\0':\r
+ return NULL;\r
+ case '\"':\r
+ limit = in;\r
+ /*@switchbreak@*/ break;\r
+ case '\\':\r
+ if (handle_escapes)\r
+ {\r
+ char *bpc = (char *) in;\r
+ int i = (char) cppReader_parseEscape (pfile, &bpc);\r
+ in = (char *) bpc;\r
+ if (i >= 0)\r
+ *result++ = (char) c;\r
+ /*@switchbreak@*/ break;\r
+ }\r
+\r
+ /*@fallthrough@*/\r
+ default:\r
+ *result++ = c;\r
+ }\r
+ }\r
+\r
+ *result = 0;\r
+ return result;\r
+}\r
+\r
+/*\r
+ * interpret #line command. Remembers previously seen fnames\r
+ * in its very own hash table.\r
+ */\r
+\r
+/*@constant int FNAME_HASHSIZE@*/\r
+#define FNAME_HASHSIZE 37\r
+\r
+static int\r
+do_line (cppReader *pfile, /*@unused@*/ struct directive *keyword)\r
+{\r
+ cppBuffer *ip = cppReader_getBuffer (pfile);\r
+ int new_lineno;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ enum file_change_code file_change = same_file;\r
+ enum cpp_token token;\r
+\r
+ token = get_directive_token (pfile);\r
+\r
+ if (token != CPP_NUMBER\r
+ || !isdigit(pfile->token_buffer[old_written]))\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid format `#line' command"));\r
+\r
+ goto bad_line_directive;\r
+ }\r
+\r
+ /* The Newline at the end of this line remains to be processed.\r
+ To put the next line at the specified line number,\r
+ we must store a line number now that is one less. */\r
+ new_lineno = atoi (pfile->token_buffer + old_written) - 1;\r
+ cppReader_setWritten (pfile, old_written);\r
+\r
+ /* NEW_LINENO is one less than the actual line number here. */\r
+ if (cppReader_isPedantic (pfile) && new_lineno < 0)\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("line number out of range in `#line' command"));\r
+\r
+ token = get_directive_token (pfile);\r
+\r
+ if (token == CPP_STRING) {\r
+ char *fname = pfile->token_buffer + old_written;\r
+ char *end_name;\r
+ static hashNode fname_table[FNAME_HASHSIZE];\r
+ hashNode hp; \r
+ hashNode *hash_bucket;\r
+ char *p;\r
+ size_t num_start;\r
+ int fname_length;\r
+\r
+ /* Turn the file name, which is a character string literal,\r
+ into a null-terminated string. Do this in place. */\r
+ end_name = convert_string (pfile, fname, fname, cppReader_getPWritten (pfile), 1);\r
+ if (end_name == NULL)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid format `#line' command"));\r
+ goto bad_line_directive;\r
+ }\r
+\r
+ fname_length = end_name - fname;\r
+ num_start = cppReader_getWritten (pfile);\r
+\r
+ token = get_directive_token (pfile);\r
+ if (token != CPP_VSPACE && token != CPP_EOF && token != CPP_POP) {\r
+ p = pfile->token_buffer + num_start;\r
+ if (cppReader_isPedantic (pfile))\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("garbage at end of `#line' command"));\r
+\r
+ if (token != CPP_NUMBER || *p < '0' || *p > '4' || p[1] != '\0')\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid format `#line' command"));\r
+ goto bad_line_directive;\r
+ }\r
+ if (*p == '1')\r
+ file_change = enter_file;\r
+ else if (*p == 2)\r
+ file_change = leave_file;\r
+ else if (*p == 3)\r
+ ip->system_header_p = 1;\r
+ else /* if (*p == 4) */\r
+ ip->system_header_p = 2;\r
+\r
+ cppReader_setWritten (pfile, num_start);\r
+ token = get_directive_token (pfile);\r
+ p = pfile->token_buffer + num_start;\r
+ if (token == CPP_NUMBER && p[1] == '\0' && (*p == '3' || *p== '4')) {\r
+ ip->system_header_p = *p == 3 ? 1 : 2;\r
+ token = get_directive_token (pfile);\r
+ }\r
+ if (token != CPP_VSPACE) {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid format `#line' command"));\r
+\r
+ goto bad_line_directive;\r
+ }\r
+ }\r
+\r
+ hash_bucket =\r
+ &fname_table[hashf (fname, fname_length, FNAME_HASHSIZE)];\r
+ for (hp = *hash_bucket; hp != NULL; hp = hp->next)\r
+ {\r
+ if (hp->length == fname_length &&\r
+ strncmp (hp->value.cpval, fname, size_fromInt (fname_length)) == 0) {\r
+ ip->nominal_fname = cstring_fromChars (hp->value.cpval);\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (hp == 0) {\r
+ /* Didn't find it; cons up a new one. */\r
+ hp = (hashNode) dmalloc (sizeof (*hp));\r
+\r
+ hp->prev = NULL;\r
+ hp->bucket_hdr = NULL;\r
+ hp->type = T_NONE;\r
+ hp->name = cstring_undefined;\r
+ hp->next = *hash_bucket;\r
+\r
+ *hash_bucket = hp;\r
+\r
+ hp->length = fname_length;\r
+ hp->value.cpval = dmalloc (sizeof (*hp->value.cpval) * (fname_length + 1));\r
+ memcpy (hp->value.cpval, fname, size_fromInt (fname_length));\r
+ hp->value.cpval[fname_length] = '\0';\r
+ ip->nominal_fname = cstring_fromChars (hp->value.cpval);\r
+ }\r
+ }\r
+ else if (token != CPP_VSPACE && token != CPP_EOF)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("invalid format `#line' command"));\r
+ goto bad_line_directive;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ ip->lineno = new_lineno;\r
+bad_line_directive:\r
+ cppReader_skipRestOfLine (pfile);\r
+ cppReader_setWritten (pfile, old_written);\r
+ output_line_command (pfile, 0, file_change);\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * remove the definition of a symbol from the symbol table.\r
+ * according to un*x /lib/cpp, it is not an error to undef\r
+ * something that has no definitions, so it isn't one here either.\r
+ */\r
+\r
+static int\r
+do_undef (cppReader *pfile, struct directive *keyword, char *buf, char *limit)\r
+{\r
+\r
+ int sym_length;\r
+ hashNode hp;\r
+ char *orig_buf = buf;\r
+\r
+ SKIP_WHITE_SPACE (buf);\r
+\r
+ sym_length = cppReader_checkMacroName (pfile, buf, cstring_makeLiteralTemp ("macro"));\r
+\r
+ while ((hp = cppReader_lookup (buf, sym_length, -1)) != NULL)\r
+ {\r
+ /* If we are generating additional info for debugging (with -g) we\r
+ need to pass through all effective #undef commands. */\r
+ if (CPPOPTIONS (pfile)->debug_output && (keyword != NULL))\r
+ {\r
+ pass_thru_directive (orig_buf, limit, pfile, keyword);\r
+ }\r
+\r
+ if (hp->type != T_MACRO)\r
+ {\r
+ cppReader_warning (pfile,\r
+ message ("Undefining preprocessor builtin: %s",\r
+ hp->name));\r
+ }\r
+\r
+ cppReader_deleteMacro (hp);\r
+ }\r
+\r
+ if (cppReader_isPedantic (pfile)) {\r
+ buf += sym_length;\r
+ SKIP_WHITE_SPACE (buf);\r
+ if (buf != limit)\r
+ {\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("garbage after `#undef' directive"));\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+/*\r
+ * Report an error detected by the program we are processing.\r
+ * Use the text of the line in the error message.\r
+ * (We use error because it prints the filename & line#.)\r
+ */\r
+\r
+static int\r
+do_error (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ char *buf, char *limit)\r
+{\r
+ int length = limit - buf;\r
+ cstring copy = cstring_copyLength (buf, length);\r
+ cstring adv = cstring_advanceWhiteSpace (copy);\r
+\r
+ cppReader_error (pfile, message ("#error %s", adv));\r
+ cstring_free (copy);\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * Report a warning detected by the program we are processing.\r
+ * Use the text of the line in the warning message, then continue.\r
+ * (We use error because it prints the filename & line#.)\r
+ */\r
+\r
+static int\r
+do_warning (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ char *buf, char *limit)\r
+{\r
+ int length = limit - buf;\r
+ cstring copy = cstring_copyLength (buf, length);\r
+ cstring adv = cstring_advanceWhiteSpace (copy);\r
+ cppReader_warning (pfile, message ("#warning %s", adv));\r
+ cstring_free (copy);\r
+ return 0;\r
+}\r
+\r
+\r
+/* #ident has already been copied to the output file, so just ignore it. */\r
+\r
+static int\r
+do_ident (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ /*@unused@*/ char *buf, /*@unused@*/ char *limit)\r
+{\r
+ /* Allow #ident in system headers, since that's not user's fault. */\r
+ if (cppReader_isPedantic (pfile) && !cppReader_getBuffer (pfile)->system_header_p)\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("ANSI C does not allow `#ident'"));\r
+\r
+ /* Leave rest of line to be read by later calls to cppGetToken. */\r
+\r
+ return 0;\r
+}\r
+\r
+/* #pragma and its argument line have already been copied to the output file.\r
+ Just check for some recognized pragmas that need validation here. */\r
+\r
+static int\r
+do_pragma (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ /*@unused@*/ char *buf, /*@unused@*/ char *limit)\r
+{\r
+ while (*buf == ' ' || *buf == '\t')\r
+ {\r
+ buf++;\r
+ }\r
+\r
+ if (!strncmp (buf, "implementation", 14)) {\r
+ /* Be quiet about `#pragma implementation' for a file only if it hasn't\r
+ been included yet. */\r
+ struct file_name_list *ptr;\r
+ char *p = buf + 14, *fname, *inc_fname;\r
+ int fname_len;\r
+ SKIP_WHITE_SPACE (p);\r
+ if (*p == '\n' || *p != '\"')\r
+ return 0;\r
+\r
+ fname = p + 1;\r
+ p = (char *) strchr (fname, '\"');\r
+ fname_len = p != NULL ? p - fname : mstring_length (fname);\r
+\r
+ for (ptr = pfile->all_include_files; ptr != NULL; ptr = ptr->next)\r
+ {\r
+ inc_fname = (char *) strrchr (cstring_toCharsSafe (ptr->fname), CONNECTCHAR);\r
+ inc_fname = (inc_fname != NULL)\r
+ ? inc_fname + 1 : cstring_toCharsSafe (ptr->fname);\r
+\r
+ if ((inc_fname != NULL)\r
+ && (strncmp (inc_fname, fname, size_fromInt (fname_len)) == 0))\r
+ {\r
+ cpp_setLocation (pfile);\r
+\r
+ ppllerror (message ("`#pragma implementation' for `%s' appears "\r
+ "after file is included",\r
+ cstring_fromChars (fname)));\r
+ }\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * handle #if command by\r
+ * 1) inserting special `defined' keyword into the hash table\r
+ * that gets turned into 0 or 1 by special_symbol (thus,\r
+ * if the luser has a symbol called `defined' already, it won't\r
+ * work inside the #if command)\r
+ * 2) rescan the input into a temporary output buffer\r
+ * 3) pass the output buffer to the yacc parser and collect a value\r
+ * 4) clean up the mess left from steps 1 and 2.\r
+ * 5) call conditional_skip to skip til the next #endif (etc.),\r
+ * or not, depending on the value from step 3.\r
+ */\r
+\r
+static int\r
+do_if (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ char *buf, char *limit)\r
+{\r
+ HOST_WIDE_INT value = eval_if_expression (pfile, buf, limit - buf);\r
+ conditional_skip (pfile, value == 0, T_IF, NULL);\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * handle a #elif directive by not changing if_stack either.\r
+ * see the comment above do_else.\r
+ */\r
+\r
+static int do_elif (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ char *buf, char *limit)\r
+{\r
+ if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("Preprocessor command #elif is not within a conditional"));\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ llassert (pfile->if_stack != NULL);\r
+\r
+ if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`#elif' after `#else'"));\r
+\r
+ if (pfile->if_stack->fname != NULL\r
+ && cppReader_getBuffer (pfile)->fname != NULL\r
+ && !cstring_equal (pfile->if_stack->fname,\r
+ cppReader_getBuffer (pfile)->nominal_fname))\r
+ fprintf (stderr, ", file %s", cstring_toCharsSafe (pfile->if_stack->fname));\r
+ fprintf (stderr, ")\n");\r
+ }\r
+ pfile->if_stack->type = T_ELIF;\r
+ }\r
+\r
+ if (pfile->if_stack->if_succeeded)\r
+ {\r
+ skip_if_group (pfile, 0);\r
+ }\r
+ else\r
+ {\r
+ HOST_WIDE_INT value = eval_if_expression (pfile, buf, limit - buf);\r
+ if (value == 0)\r
+ skip_if_group (pfile, 0);\r
+ else\r
+ {\r
+ ++pfile->if_stack->if_succeeded; /* continue processing input */\r
+ output_line_command (pfile, 1, same_file);\r
+ }\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * evaluate a #if expression in BUF, of length LENGTH,\r
+ * then parse the result as a C expression and return the value as an int.\r
+ */\r
+\r
+static HOST_WIDE_INT\r
+eval_if_expression (cppReader *pfile,\r
+ /*@unused@*/ char *buf,\r
+ /*@unused@*/ int length)\r
+{\r
+ hashNode save_defined;\r
+ HOST_WIDE_INT value;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+\r
+ save_defined = cppReader_install ("defined", -1, T_SPEC_DEFINED, 0, 0, -1);\r
+ pfile->pcp_inside_if = 1;\r
+\r
+ value = cppReader_parseExpression (pfile);\r
+ pfile->pcp_inside_if = 0;\r
+\r
+ /* Clean up special symbol */\r
+ cppReader_deleteMacro (save_defined);\r
+\r
+ cppReader_setWritten (pfile, old_written); /* Pop */\r
+\r
+ return value;\r
+}\r
+\r
+/*\r
+ * routine to handle ifdef/ifndef. Try to look up the symbol,\r
+ * then do or don't skip to the #endif/#else/#elif depending\r
+ * on what directive is actually being processed.\r
+ */\r
+\r
+static int\r
+do_xifdef (cppReader *pfile, struct directive *keyword,\r
+ /*@unused@*/ char *unused1, /*@unused@*/ char *unused2)\r
+{\r
+ int skip;\r
+ cppBuffer *ip = cppReader_getBuffer (pfile);\r
+ char *ident;\r
+ int ident_length;\r
+ enum cpp_token token;\r
+ int start_of_file = 0;\r
+ char *control_macro = 0;\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+\r
+ DPRINTF (("do xifdef: %d",\r
+ keyword->type == T_IFNDEF));\r
+\r
+ /* Detect a #ifndef at start of file (not counting comments). */\r
+ if (cstring_isDefined (ip->fname) && keyword->type == T_IFNDEF)\r
+ {\r
+ start_of_file = pfile->only_seen_white == 2;\r
+ }\r
+\r
+ pfile->no_macro_expand++;\r
+ token = get_directive_token (pfile);\r
+ pfile->no_macro_expand--;\r
+\r
+ ident = pfile->token_buffer + old_written;\r
+ ident_length = size_toInt (cppReader_getWritten (pfile) - old_written);\r
+ cppReader_setWritten (pfile, old_written); /* Pop */\r
+\r
+ if (token == CPP_VSPACE || token == CPP_POP || token == CPP_EOF)\r
+ {\r
+ skip = (keyword->type == T_IFDEF);\r
+ if (! cppReader_isTraditional (pfile))\r
+ {\r
+ cppReader_pedwarn (pfile,\r
+ message ("`#%s' with no argument", keyword->name));\r
+ }\r
+ }\r
+ else if (token == CPP_NAME)\r
+ {\r
+ hashNode hp = cppReader_lookup (ident, ident_length, -1);\r
+ skip = (keyword->type == T_IFDEF) \r
+ ? (hp == NULL) : (hp != NULL);\r
+\r
+ DPRINTF (("hp null: %d / %d / %d",\r
+ (hp == NULL),\r
+ (keyword->type == T_IFNDEF),\r
+ skip));\r
+ \r
+ if (start_of_file && !skip)\r
+ {\r
+ DPRINTF (("Not skipping!"));\r
+ control_macro = (char *) dmalloc (size_fromInt (ident_length + 1));\r
+ memcpy (control_macro, ident, size_fromInt (ident_length + 1));\r
+ }\r
+ }\r
+ else\r
+ {\r
+ skip = (keyword->type == T_IFDEF);\r
+ if (! cppReader_isTraditional (pfile))\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("`#%s' with invalid argument", keyword->name));\r
+ }\r
+ }\r
+\r
+ if (!cppReader_isTraditional (pfile))\r
+ {\r
+ int c;\r
+ cppSkipHspace (pfile);\r
+ c = cppReader_peekC (pfile);\r
+ if (c != EOF && c != '\n')\r
+ {\r
+ cppReader_pedwarn (pfile,\r
+ message ("garbage at end of `#%s' argument", keyword->name));\r
+ }\r
+ }\r
+\r
+ cppReader_skipRestOfLine (pfile);\r
+\r
+ DPRINTF (("Conditional skip: %d", skip));\r
+ conditional_skip (pfile, skip, T_IF, control_macro);\r
+ return 0;\r
+}\r
+\r
+/* Push TYPE on stack; then, if SKIP is nonzero, skip ahead.\r
+ If this is a #ifndef starting at the beginning of a file,\r
+ CONTROL_MACRO is the macro name tested by the #ifndef.\r
+ Otherwise, CONTROL_MACRO is 0. */\r
+\r
+static void\r
+conditional_skip (cppReader *pfile, int skip,\r
+ enum node_type type,\r
+ /*@dependent@*/ char *control_macro)\r
+{\r
+ cppIfStackFrame *temp = (cppIfStackFrame *) dmalloc (sizeof (*temp));\r
+\r
+ temp->fname = cppReader_getBuffer (pfile)->nominal_fname;\r
+ temp->next = pfile->if_stack;\r
+ temp->control_macro = control_macro;\r
+ temp->lineno = 0;\r
+ temp->if_succeeded = 0;\r
+\r
+ pfile->if_stack = temp;\r
+ pfile->if_stack->type = type;\r
+\r
+ if (skip != 0)\r
+ {\r
+ skip_if_group (pfile, 0);\r
+ return;\r
+ }\r
+ else\r
+ {\r
+ ++pfile->if_stack->if_succeeded;\r
+ output_line_command (pfile, 1, same_file);\r
+ }\r
+}\r
+\r
+/*\r
+ * skip to #endif, #else, or #elif. adjust line numbers, etc.\r
+ * leaves input ptr at the sharp sign found.\r
+ * If ANY is nonzero, return at next directive of any sort.\r
+ */\r
+\r
+static void\r
+skip_if_group (cppReader *pfile, int any)\r
+{\r
+ int c;\r
+ struct directive *kt;\r
+ cppIfStackFrame *save_if_stack = pfile->if_stack; /* don't pop past here */\r
+ register int ident_length;\r
+ char *ident;\r
+ struct parse_marker line_start_mark;\r
+\r
+ parseSetMark (&line_start_mark, pfile);\r
+\r
+ if (CPPOPTIONS (pfile)->output_conditionals) {\r
+ static char failed[] = "#failed\n";\r
+ cppReader_puts (pfile, failed, sizeof(failed)-1);\r
+ pfile->lineno++;\r
+ output_line_command (pfile, 1, same_file);\r
+ }\r
+\r
+beg_of_line:\r
+ if (CPPOPTIONS (pfile)->output_conditionals)\r
+ {\r
+ cppBuffer *pbuf = cppReader_getBuffer (pfile);\r
+ char *start_line;\r
+\r
+ llassert (pbuf->buf != NULL);\r
+\r
+ start_line = pbuf->buf + line_start_mark.position;\r
+ cppReader_puts (pfile, start_line, size_fromInt (pbuf->cur - start_line));\r
+ }\r
+\r
+ parseMoveMark (&line_start_mark, pfile);\r
+\r
+ if (!cppReader_isTraditional (pfile))\r
+ {\r
+ cppSkipHspace (pfile);\r
+ }\r
+\r
+ c = cppReader_getC (pfile);\r
+ if (c == '#')\r
+ {\r
+ size_t old_written = cppReader_getWritten (pfile);\r
+ cppSkipHspace (pfile);\r
+\r
+ parse_name (pfile, cppReader_getC (pfile));\r
+ ident_length = size_toInt (cppReader_getWritten (pfile) - old_written);\r
+ ident = pfile->token_buffer + old_written;\r
+ pfile->limit = ident;\r
+\r
+ for (kt = directive_table; kt->length >= 0; kt++)\r
+ {\r
+ cppIfStackFrame *temp;\r
+ if (ident_length == kt->length\r
+ && cstring_equalPrefix (kt->name, cstring_fromChars (ident)))\r
+ {\r
+ /* If we are asked to return on next directive, do so now. */\r
+ if (any)\r
+ {\r
+ goto done;\r
+ }\r
+\r
+ switch (kt->type)\r
+ {\r
+ case T_IF:\r
+ case T_IFDEF:\r
+ case T_IFNDEF:\r
+ temp = (cppIfStackFrame *) dmalloc (sizeof (*temp));\r
+ temp->next = pfile->if_stack;\r
+ temp->fname = cppReader_getBuffer (pfile)->nominal_fname;\r
+ temp->type = kt->type;\r
+ temp->lineno = 0;\r
+ temp->if_succeeded = 0;\r
+ temp->control_macro = NULL;\r
+\r
+ pfile->if_stack = temp;\r
+ /*@switchbreak@*/ break;\r
+ case T_ELSE:\r
+ case T_ENDIF:\r
+ if (cppReader_isPedantic (pfile) && pfile->if_stack != save_if_stack)\r
+ validate_else (pfile,\r
+ cstring_makeLiteralTemp (kt->type == T_ELSE ? "#else" : "#endif"));\r
+ /*@fallthrough@*/\r
+ case T_ELIF:\r
+ if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Preprocessor command #%s is not within a conditional", kt->name));\r
+ /*@switchbreak@*/ break;\r
+ }\r
+ else if (pfile->if_stack == save_if_stack)\r
+ {\r
+ goto done; /* found what we came for */\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ if (kt->type != T_ENDIF)\r
+ {\r
+ llassert (pfile->if_stack != NULL);\r
+\r
+ if (pfile->if_stack->type == T_ELSE)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("`#else' or `#elif' after `#else'"));\r
+ }\r
+\r
+ pfile->if_stack->type = kt->type;\r
+ /*@switchbreak@*/ break;\r
+ }\r
+\r
+ temp = pfile->if_stack;\r
+ llassert (temp != NULL);\r
+ pfile->if_stack = temp->next;\r
+ sfree (temp);\r
+ /*@switchbreak@*/ break;\r
+ default: ;\r
+ /*@-branchstate@*/ \r
+ }\r
+ /*@=branchstate@*/\r
+ break;\r
+ }\r
+ \r
+ /* Don't let erroneous code go by. */\r
+ \r
+ if (kt->length < 0 && !CPPOPTIONS (pfile)->lang_asm\r
+ && cppReader_isPedantic (pfile))\r
+ {\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("Invalid preprocessor directive name"));\r
+ }\r
+ }\r
+\r
+ c = cppReader_getC (pfile);\r
+ }\r
+ /* We're in the middle of a line. Skip the rest of it. */\r
+ for (;;) {\r
+ size_t old;\r
+\r
+ switch (c)\r
+ {\r
+ case EOF:\r
+ goto done;\r
+ case '/': /* possible comment */\r
+ c = skip_comment (pfile, NULL);\r
+ if (c == EOF)\r
+ goto done;\r
+ /*@switchbreak@*/ break;\r
+ case '\"':\r
+ case '\'':\r
+ cppReader_forward (pfile, -1);\r
+ old = cppReader_getWritten (pfile);\r
+ (void) cppGetToken (pfile);\r
+ cppReader_setWritten (pfile, old);\r
+ /*@switchbreak@*/ break;\r
+ case '\\':\r
+ /* Char after backslash loses its special meaning. */\r
+ if (cppReader_peekC (pfile) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 1);\r
+ }\r
+\r
+ /*@switchbreak@*/ break;\r
+ case '\n':\r
+ goto beg_of_line;\r
+ }\r
+ c = cppReader_getC (pfile);\r
+ }\r
+done:\r
+ if (CPPOPTIONS (pfile)->output_conditionals) {\r
+ static char end_failed[] = "#endfailed\n";\r
+ cppReader_puts (pfile, end_failed, sizeof(end_failed)-1);\r
+ pfile->lineno++;\r
+ }\r
+ pfile->only_seen_white = 1;\r
+\r
+ parseGotoMark (&line_start_mark, pfile);\r
+ parseClearMark (&line_start_mark);\r
+}\r
+\r
+/*\r
+ * handle a #else directive. Do this by just continuing processing\r
+ * without changing if_stack ; this is so that the error message\r
+ * for missing #endif's etc. will point to the original #if. It\r
+ * is possible that something different would be better.\r
+ */\r
+\r
+static int\r
+do_else (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ /*@unused@*/ char *buf, /*@unused@*/ char *limit)\r
+{\r
+ if (cppReader_isPedantic (pfile))\r
+ {\r
+ validate_else (pfile, cstring_makeLiteralTemp ("#else"));\r
+ }\r
+\r
+ cppReader_skipRestOfLine (pfile);\r
+\r
+ if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack) {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("Preprocessor command #else is not within a conditional"));\r
+ return 0;\r
+ } else {\r
+ /* #ifndef can't have its special treatment for containing the whole file\r
+ if it has a #else clause. */\r
+\r
+ llassert (pfile->if_stack != NULL);\r
+\r
+ pfile->if_stack->control_macro = 0;\r
+\r
+ if (pfile->if_stack->type != T_IF && pfile->if_stack->type != T_ELIF)\r
+ {\r
+ cpp_setLocation (pfile);\r
+ genppllerrorhint (FLG_PREPROC,\r
+ message ("Pre-processor directive #else after #else"),\r
+ message ("%q: Location of match",\r
+ fileloc_unparseRaw (pfile->if_stack->fname,\r
+ pfile->if_stack->lineno)));\r
+ }\r
+\r
+ pfile->if_stack->type = T_ELSE;\r
+ }\r
+\r
+ if (pfile->if_stack->if_succeeded)\r
+ skip_if_group (pfile, 0);\r
+ else {\r
+ ++pfile->if_stack->if_succeeded; /* continue processing input */\r
+ output_line_command (pfile, 1, same_file);\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/*\r
+ * unstack after #endif command\r
+ */\r
+\r
+static int\r
+do_endif (cppReader *pfile, /*@unused@*/ struct directive *keyword,\r
+ /*@unused@*/ char *buf, /*@unused@*/ char *limit)\r
+{\r
+ if (cppReader_isPedantic (pfile))\r
+ {\r
+ validate_else (pfile, cstring_makeLiteralTemp ("#endif"));\r
+ }\r
+\r
+ cppReader_skipRestOfLine (pfile);\r
+\r
+ if (pfile->if_stack == cppReader_getBuffer (pfile)->if_stack)\r
+ {\r
+ cppReader_errorLit (pfile, cstring_makeLiteralTemp ("Unbalanced #endif"));\r
+ }\r
+ else\r
+ {\r
+ cppIfStackFrame *temp = pfile->if_stack;\r
+\r
+ llassert (temp != NULL);\r
+\r
+ pfile->if_stack = temp->next;\r
+ if (temp->control_macro != 0)\r
+ {\r
+ /* This #endif matched a #ifndef at the start of the file.\r
+ See if it is at the end of the file. */\r
+ struct parse_marker start_mark;\r
+ int c;\r
+\r
+ parseSetMark (&start_mark, pfile);\r
+\r
+ for (;;)\r
+ {\r
+ cppSkipHspace (pfile);\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (c != '\n')\r
+ break;\r
+ }\r
+\r
+ parseGotoMark (&start_mark, pfile);\r
+ parseClearMark (&start_mark);\r
+\r
+ if (c == EOF)\r
+ {\r
+ /* If we get here, this #endif ends a #ifndef\r
+ that contains all of the file (aside from whitespace).\r
+ Arrange not to include the file again\r
+ if the macro that was tested is defined.\r
+\r
+ Do not do this for the top-level file in a -include or any\r
+ file in a -imacros. */\r
+ struct file_name_list *ifile = pfile->all_include_files;\r
+\r
+ for ( ; ifile != NULL; ifile = ifile->next)\r
+ {\r
+ if (cstring_equal (ifile->fname, cppReader_getBuffer (pfile)->fname))\r
+ {\r
+ ifile->control_macro = temp->control_macro;\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ sfree (temp);\r
+ output_line_command (pfile, 1, same_file);\r
+ }\r
+ return 0;\r
+}\r
+\r
+/* When an #else or #endif is found while skipping failed conditional,\r
+ if -pedantic was specified, this is called to warn about text after\r
+ the command name. P points to the first char after the command name. */\r
+\r
+static void\r
+validate_else (cppReader *pfile, cstring directive)\r
+{\r
+ int c;\r
+ cppSkipHspace (pfile);\r
+ c = cppReader_peekC (pfile);\r
+ if (c != EOF && c != '\n')\r
+ {\r
+ cppReader_pedwarn (pfile,\r
+ message ("text following `%s' violates ANSI standard", directive));\r
+ }\r
+}\r
+\r
+/*\r
+** Get the next token, and add it to the text in pfile->token_buffer.\r
+** Return the kind of token we got.\r
+*/\r
+\r
+enum cpp_token\r
+cppGetToken (cppReader *pfile)\r
+{\r
+ int c, c2, c3;\r
+ size_t old_written = 0;\r
+ int start_line, start_column;\r
+ enum cpp_token token;\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+ cppReader_getBuffer (pfile)->prev = cppReader_getBuffer (pfile)->cur;\r
+\r
+get_next:\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (c == EOF)\r
+ {\r
+ handle_eof:\r
+ if (cppReader_getBuffer (pfile)->seen_eof)\r
+ {\r
+ cppBuffer *buf = cppReader_popBuffer (pfile);\r
+\r
+ if (buf != cppReader_nullBuffer (pfile))\r
+ {\r
+ goto get_next;\r
+ }\r
+ else\r
+ {\r
+ return CPP_EOF;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ cppBuffer *next_buf = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));\r
+ cppReader_getBuffer (pfile)->seen_eof = 1;\r
+\r
+ if (cstring_isDefined (cppReader_getBuffer (pfile)->nominal_fname)\r
+ && next_buf != cppReader_nullBuffer (pfile))\r
+ {\r
+ /* We're about to return from an #include file.\r
+ Emit #line information now (as part of the CPP_POP) result.\r
+ But the #line refers to the file we will pop to. */\r
+ cppBuffer *cur_buffer = CPPBUFFER (pfile);\r
+ CPPBUFFER (pfile) = next_buf;\r
+ pfile->input_stack_listing_current = 0;\r
+ output_line_command (pfile, 0, leave_file);\r
+ CPPBUFFER (pfile) = cur_buffer;\r
+ }\r
+ return CPP_POP;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ long newlines;\r
+ struct parse_marker start_mark;\r
+\r
+ switch (c)\r
+ {\r
+ case '/':\r
+ if (cppReader_peekC (pfile) == '=')\r
+ {\r
+ goto op2;\r
+ }\r
+\r
+ if (opts->put_out_comments)\r
+ {\r
+ parseSetMark (&start_mark, pfile);\r
+ }\r
+\r
+ newlines = 0;\r
+ cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile),\r
+ &start_line, &start_column);\r
+ c = skip_comment (pfile, &newlines);\r
+\r
+ if (opts->put_out_comments && (c == '/' || c == EOF))\r
+ {\r
+ assertSet (&start_mark);\r
+ parseClearMark (&start_mark);\r
+ }\r
+\r
+ if (c == '/')\r
+ goto randomchar;\r
+ if (c == EOF)\r
+ {\r
+ cppReader_errorWithLine (pfile, start_line, start_column,\r
+ cstring_makeLiteral ("Unterminated comment"));\r
+ goto handle_eof;\r
+ }\r
+ c = '/'; /* Initial letter of comment. */\r
+ return_comment:\r
+ /* Comments are equivalent to spaces.\r
+ For -traditional, a comment is equivalent to nothing. */\r
+\r
+ if (opts->put_out_comments)\r
+ {\r
+ enum cpp_token res;\r
+\r
+ assertSet (&start_mark);\r
+ res = cpp_handleComment (pfile, &start_mark);\r
+ pfile->lineno += newlines;\r
+ return res;\r
+ }\r
+ else if (cppReader_isTraditional (pfile))\r
+ {\r
+ return CPP_COMMENT;\r
+ }\r
+ else\r
+ {\r
+ cppReader_reserve(pfile, 1);\r
+ cppReader_putCharQ (pfile, ' ');\r
+ return CPP_HSPACE;\r
+ }\r
+\r
+ case '#':\r
+ if (!pfile->only_seen_white)\r
+ {\r
+ goto randomchar;\r
+ }\r
+\r
+ if (cppReader_handleDirective (pfile))\r
+ {\r
+ return CPP_DIRECTIVE;\r
+ }\r
+\r
+ pfile->only_seen_white = 0;\r
+ return CPP_OTHER;\r
+\r
+ case '\"':\r
+ case '\'':\r
+ /* A single quoted string is treated like a double -- some\r
+ programs (e.g., troff) are perverse this way */\r
+ cppBuffer_lineAndColumn (cppReader_fileBuffer (pfile),\r
+ &start_line, &start_column);\r
+ old_written = cppReader_getWritten (pfile);\r
+ string:\r
+ cppReader_putChar (pfile, c);\r
+ while (TRUE)\r
+ {\r
+ int cc = cppReader_getC (pfile);\r
+ if (cc == EOF)\r
+ {\r
+ if (cppBuffer_isMacro (CPPBUFFER (pfile)))\r
+ {\r
+ /* try harder: this string crosses a macro expansion\r
+ boundary. This can happen naturally if -traditional.\r
+ Otherwise, only -D can make a macro with an unmatched\r
+ quote. */\r
+ cppBuffer *next_buf\r
+ = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));\r
+ (*cppReader_getBuffer (pfile)->cleanup)\r
+ (cppReader_getBuffer (pfile), pfile);\r
+ CPPBUFFER (pfile) = next_buf;\r
+ continue;\r
+ }\r
+ if (!cppReader_isTraditional (pfile))\r
+ {\r
+ cpp_setLocation (pfile);\r
+\r
+ setLine (long_toInt (start_line));\r
+ setColumn (long_toInt (start_column));\r
+\r
+ if (pfile->multiline_string_line != long_toInt (start_line)\r
+ && pfile->multiline_string_line != 0)\r
+ {\r
+ genppllerrorhint\r
+ (FLG_PREPROC,\r
+ message ("Unterminated string or character constant"),\r
+ message ("%q: Possible real start of unterminated constant",\r
+ fileloc_unparseRaw \r
+ (fileloc_filename (g_currentloc),\r
+ pfile->multiline_string_line)));\r
+ pfile->multiline_string_line = 0;\r
+ }\r
+ else\r
+ {\r
+ genppllerror\r
+ (FLG_PREPROC,\r
+ message ("Unterminated string or character constant"));\r
+ }\r
+ }\r
+ /*@loopbreak@*/ break;\r
+ }\r
+ cppReader_putChar (pfile, cc);\r
+ switch (cc)\r
+ {\r
+ case '\n':\r
+ /* Traditionally, end of line ends a string constant with\r
+ no error. So exit the loop and record the new line. */\r
+ if (cppReader_isTraditional (pfile))\r
+ goto while2end;\r
+ if (c == '\'')\r
+ {\r
+ goto while2end;\r
+ }\r
+ if (cppReader_isPedantic (pfile)\r
+ && pfile->multiline_string_line == 0)\r
+ {\r
+ cppReader_pedwarnWithLine\r
+ (pfile, long_toInt (start_line),\r
+ long_toInt (start_column),\r
+ cstring_makeLiteral ("String constant runs past end of line"));\r
+ }\r
+ if (pfile->multiline_string_line == 0)\r
+ {\r
+ pfile->multiline_string_line = start_line;\r
+ }\r
+\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\\':\r
+ cc = cppReader_getC (pfile);\r
+ if (cc == '\n')\r
+ {\r
+ /* Backslash newline is replaced by nothing at all. */\r
+ cppReader_adjustWritten (pfile, -1);\r
+ pfile->lineno++;\r
+ }\r
+ else\r
+ {\r
+ /* ANSI stupidly requires that in \\ the second \\r
+ is *not* prevented from combining with a newline. */\r
+ NEWLINE_FIX1(cc);\r
+ if (cc != EOF)\r
+ cppReader_putChar (pfile, cc);\r
+ }\r
+ /*@switchbreak@*/ break;\r
+\r
+ case '\"':\r
+ case '\'':\r
+ if (cc == c)\r
+ goto while2end;\r
+ /*@switchbreak@*/ break;\r
+ }\r
+ }\r
+ while2end:\r
+ pfile->lineno += count_newlines (pfile->token_buffer + old_written,\r
+ cppReader_getPWritten (pfile));\r
+ pfile->only_seen_white = 0;\r
+ return c == '\'' ? CPP_CHAR : CPP_STRING;\r
+\r
+ case '$':\r
+ if (!opts->dollars_in_ident)\r
+ goto randomchar;\r
+ goto letter;\r
+\r
+ case ':':\r
+ if (opts->cplusplus && cppReader_peekC (pfile) == ':')\r
+ goto op2;\r
+ goto randomchar;\r
+\r
+ case '&':\r
+ case '+':\r
+ case '|':\r
+ NEWLINE_FIX;\r
+ c2 = cppReader_peekC (pfile);\r
+ if (c2 == c || c2 == '=')\r
+ goto op2;\r
+ goto randomchar;\r
+\r
+ case '*':\r
+ case '!':\r
+ case '%':\r
+ case '=':\r
+ case '^':\r
+ NEWLINE_FIX;\r
+ if (cppReader_peekC (pfile) == '=')\r
+ goto op2;\r
+ goto randomchar;\r
+\r
+ case '-':\r
+ NEWLINE_FIX;\r
+ c2 = cppReader_peekC (pfile);\r
+ if (c2 == '-' && opts->chill)\r
+ {\r
+ /* Chill style comment */\r
+ if (opts->put_out_comments)\r
+ {\r
+ parseSetMark (&start_mark, pfile);\r
+ }\r
+\r
+ cppReader_forward (pfile, 1); /* Skip second '-'. */\r
+\r
+ for (;;)\r
+ {\r
+ c = cppReader_getC (pfile);\r
+ if (c == EOF)\r
+ /*@loopbreak@*/ break;\r
+ if (c == '\n')\r
+ {\r
+ /* Don't consider final '\n' to be part of comment. */\r
+ cppReader_forward (pfile, -1);\r
+ /*@loopbreak@*/ break;\r
+ }\r
+ }\r
+ c = '-';\r
+ goto return_comment;\r
+ }\r
+ if (c2 == '-' || c2 == '=' || c2 == '>')\r
+ goto op2;\r
+ goto randomchar;\r
+\r
+ case '<':\r
+ if (pfile->parsing_include_directive)\r
+ {\r
+ for (;;)\r
+ {\r
+ cppReader_putChar (pfile, c);\r
+ if (c == '>')\r
+ /*@loopbreak@*/ break;\r
+ c = cppReader_getC (pfile);\r
+ NEWLINE_FIX1 (c);\r
+ if (c == '\n' || c == EOF)\r
+ {\r
+ cppReader_errorLit (pfile,\r
+ cstring_makeLiteralTemp ("Missing '>' in \"#include <FILENAME>\""));\r
+ /*@loopbreak@*/ break;\r
+ }\r
+ }\r
+ return CPP_STRING;\r
+ }\r
+ /*@fallthrough@*/\r
+ case '>':\r
+ NEWLINE_FIX;\r
+ c2 = cppReader_peekC (pfile);\r
+ if (c2 == '=')\r
+ goto op2;\r
+ if (c2 != c)\r
+ goto randomchar;\r
+ cppReader_forward (pfile, 1);\r
+ cppReader_reserve (pfile, 4);\r
+ cppReader_putChar (pfile, c);\r
+ cppReader_putChar (pfile, c2);\r
+ NEWLINE_FIX;\r
+ c3 = cppReader_peekC (pfile);\r
+ if (c3 == '=')\r
+ cppReader_putCharQ (pfile, cppReader_getC (pfile));\r
+ cppReader_nullTerminateQ (pfile);\r
+ pfile->only_seen_white = 0;\r
+ return CPP_OTHER;\r
+\r
+ case '@':\r
+ if (cppReader_getBuffer (pfile)->has_escapes)\r
+ {\r
+ c = cppReader_getC (pfile);\r
+ if (c == '-')\r
+ {\r
+ if (pfile->output_escapes)\r
+ cppReader_puts (pfile, "@-", 2);\r
+ parse_name (pfile, cppReader_getC (pfile));\r
+ return CPP_NAME;\r
+ }\r
+ else if (is_space [c])\r
+ {\r
+ cppReader_reserve (pfile, 2);\r
+ if (pfile->output_escapes)\r
+ cppReader_putCharQ (pfile, '@');\r
+ cppReader_putCharQ (pfile, c);\r
+ return CPP_HSPACE;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+ if (pfile->output_escapes)\r
+ {\r
+ cppReader_puts (pfile, "@@", 2);\r
+ return CPP_OTHER;\r
+ }\r
+ goto randomchar;\r
+ case '.':\r
+ NEWLINE_FIX;\r
+ c2 = cppReader_peekC (pfile);\r
+ if (isdigit(c2))\r
+ {\r
+ cppReader_reserve(pfile, 2);\r
+ cppReader_putCharQ (pfile, '.');\r
+ c = cppReader_getC (pfile);\r
+ goto number;\r
+ }\r
+\r
+ /* FIXME - misses the case "..\\\n." */\r
+ if (c2 == '.' && cpp_peekN (pfile, 1) == '.')\r
+ {\r
+ cppReader_reserve(pfile, 4);\r
+ cppReader_putCharQ (pfile, '.');\r
+ cppReader_putCharQ (pfile, '.');\r
+ cppReader_putCharQ (pfile, '.');\r
+ cppReader_forward (pfile, 2);\r
+ cppReader_nullTerminateQ (pfile);\r
+ pfile->only_seen_white = 0;\r
+ return CPP_3DOTS;\r
+ }\r
+ goto randomchar;\r
+ op2:\r
+ token = CPP_OTHER;\r
+ pfile->only_seen_white = 0;\r
+ op2any:\r
+ cppReader_reserve(pfile, 3);\r
+ cppReader_putCharQ (pfile, c);\r
+ cppReader_putCharQ (pfile, cppReader_getC (pfile));\r
+ cppReader_nullTerminateQ (pfile);\r
+ return token;\r
+\r
+ case 'L':\r
+ NEWLINE_FIX;\r
+ c2 = cppReader_peekC (pfile);\r
+ if ((c2 == '\'' || c2 == '\"') && !cppReader_isTraditional (pfile))\r
+ {\r
+ cppReader_putChar (pfile, c);\r
+ c = cppReader_getC (pfile);\r
+ goto string;\r
+ }\r
+ goto letter;\r
+\r
+ case '0': case '1': case '2': case '3': case '4':\r
+ case '5': case '6': case '7': case '8': case '9':\r
+ number:\r
+ c2 = '.';\r
+ for (;;)\r
+ {\r
+ cppReader_reserve (pfile, 2);\r
+ cppReader_putCharQ (pfile, c);\r
+ NEWLINE_FIX;\r
+ c = cppReader_peekC (pfile);\r
+ if (c == EOF)\r
+ /*@loopbreak@*/ break;\r
+ if (!is_idchar[c] && c != '.'\r
+ && ((c2 != 'e' && c2 != 'E'\r
+ && ((c2 != 'p' && c2 != 'P') || cppReader_isC89 (pfile)))\r
+ || (c != '+' && c != '-')))\r
+ /*@loopbreak@*/ break;\r
+ cppReader_forward (pfile, 1);\r
+ c2= c;\r
+ }\r
+\r
+ cppReader_nullTerminateQ (pfile);\r
+ pfile->only_seen_white = 0;\r
+ return CPP_NUMBER;\r
+\r
+ case 'b': case 'c': case 'd': case 'h': case 'o':\r
+ case 'B': case 'C': case 'D': case 'H': case 'O':\r
+ if (opts->chill && cppReader_peekC (pfile) == '\'')\r
+ {\r
+ pfile->only_seen_white = 0;\r
+ cppReader_reserve (pfile, 2);\r
+ cppReader_putCharQ (pfile, c);\r
+ cppReader_putCharQ (pfile, '\'');\r
+ cppReader_forward (pfile, 1);\r
+ for (;;)\r
+ {\r
+ c = cppReader_getC (pfile);\r
+ if (c == EOF)\r
+ goto chill_number_eof;\r
+ if (!is_idchar[c])\r
+ {\r
+ if (c == '\\' && cppReader_peekC (pfile) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 2);\r
+ continue;\r
+ }\r
+ /*@loopbreak@*/ break;\r
+ }\r
+ cppReader_putChar (pfile, c);\r
+ }\r
+ if (c == '\'')\r
+ {\r
+ cppReader_reserve (pfile, 2);\r
+ cppReader_putCharQ (pfile, c);\r
+ cppReader_nullTerminateQ (pfile);\r
+ return CPP_STRING;\r
+ }\r
+ else\r
+ {\r
+ cppReader_forward (pfile, -1);\r
+ chill_number_eof:\r
+ cppReader_nullTerminate (pfile);\r
+ return CPP_NUMBER;\r
+ }\r
+ }\r
+ else\r
+ goto letter;\r
+ case '_':\r
+ case 'a': case 'e': case 'f': case 'g': case 'i': case 'j':\r
+ case 'k': case 'l': case 'm': case 'n': case 'p': case 'q':\r
+ case 'r': case 's': case 't': case 'u': case 'v': case 'w':\r
+ case 'x': case 'y': case 'z':\r
+ case 'A': case 'E': case 'F': case 'G': case 'I': case 'J':\r
+ case 'K': case 'M': case 'N': case 'P': case 'Q': case 'R':\r
+ case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':\r
+ case 'Y': case 'Z':\r
+ letter:\r
+ {\r
+ hashNode hp;\r
+ char *ident;\r
+ size_t before_name_written = cppReader_getWritten (pfile);\r
+ int ident_len;\r
+ parse_name (pfile, c);\r
+ pfile->only_seen_white = 0;\r
+ if (pfile->no_macro_expand)\r
+ {\r
+ return CPP_NAME;\r
+ }\r
+\r
+ ident = pfile->token_buffer + before_name_written;\r
+ ident_len = (cppReader_getPWritten (pfile)) - ident;\r
+\r
+ hp = cppReader_lookupExpand (ident, ident_len, -1);\r
+\r
+ if (hp == NULL)\r
+ {\r
+ return CPP_NAME;\r
+ }\r
+\r
+ if (hp->type == T_DISABLED)\r
+ {\r
+ if (pfile->output_escapes)\r
+ { /* Return "@-IDENT", followed by '\0'. */\r
+ int i;\r
+ cppReader_reserve (pfile, 3);\r
+ ident = pfile->token_buffer + before_name_written;\r
+ cppReader_adjustWritten (pfile, 2);\r
+\r
+ for (i = ident_len; i >= 0; i--)\r
+ {\r
+ ident[i+2] = ident[i];\r
+ }\r
+\r
+ ident[0] = '@';\r
+ ident[1] = '-';\r
+ }\r
+ return CPP_NAME;\r
+ }\r
+\r
+ /* If macro wants an arglist, verify that a '(' follows.\r
+ first skip all whitespace, copying it to the output\r
+ after the macro name. Then, if there is no '(',\r
+ decide this is not a macro call and leave things that way. */\r
+\r
+ if (hp->type == T_MACRO && hp->value.defn->nargs >= 0)\r
+ {\r
+ struct parse_marker macro_mark;\r
+ int is_macro_call;\r
+\r
+ while (cppBuffer_isMacro (CPPBUFFER (pfile)))\r
+ {\r
+ cppBuffer *next_buf;\r
+ cppSkipHspace (pfile);\r
+ if (cppReader_peekC (pfile) != EOF)\r
+ {\r
+ /*@loopbreak@*/ break;\r
+ }\r
+\r
+ next_buf = cppBuffer_prevBuffer (cppReader_getBuffer (pfile));\r
+ (*cppReader_getBuffer (pfile)->cleanup) (cppReader_getBuffer (pfile), pfile);\r
+ CPPBUFFER (pfile) = next_buf;\r
+ }\r
+\r
+ parseSetMark (¯o_mark, pfile);\r
+\r
+ for (;;)\r
+ {\r
+ cppSkipHspace (pfile);\r
+ c = cppReader_peekC (pfile);\r
+ is_macro_call = c == '(';\r
+ if (c != '\n')\r
+ /*@loopbreak@*/ break;\r
+ cppReader_forward (pfile, 1);\r
+ }\r
+\r
+ if (!is_macro_call)\r
+ {\r
+ parseGotoMark (¯o_mark, pfile);\r
+ }\r
+\r
+ parseClearMark (¯o_mark);\r
+\r
+ if (!is_macro_call)\r
+ {\r
+ return CPP_NAME;\r
+ }\r
+ }\r
+ /* This is now known to be a macro call. */\r
+\r
+ /* it might not actually be a macro. */\r
+ if (hp->type != T_MACRO)\r
+ {\r
+ size_t xbuf_len;\r
+ char *xbuf;\r
+\r
+ cppReader_setWritten (pfile, before_name_written);\r
+ special_symbol (hp, pfile);\r
+ xbuf_len = cppReader_getWritten (pfile) - before_name_written;\r
+ xbuf = (char *) dmalloc (xbuf_len + 1);\r
+ cppReader_setWritten (pfile, before_name_written);\r
+ memcpy (xbuf, cppReader_getPWritten (pfile), xbuf_len + 1);\r
+ push_macro_expansion (pfile, xbuf, xbuf_len, hp);\r
+ }\r
+ else\r
+ {\r
+ /* Expand the macro, reading arguments as needed,\r
+ and push the expansion on the input stack. */\r
+ macroexpand (pfile, hp);\r
+ cppReader_setWritten (pfile, before_name_written);\r
+ }\r
+\r
+ /* An extra "@ " is added to the end of a macro expansion\r
+ to prevent accidental token pasting. We prefer to avoid\r
+ unneeded extra spaces (for the sake of cpp-using tools like\r
+ imake). Here we remove the space if it is safe to do so. */\r
+\r
+ llassert (pfile->buffer->rlimit != NULL);\r
+\r
+ if (pfile->buffer->rlimit - pfile->buffer->cur >= 3\r
+ && pfile->buffer->rlimit[-2] == '@'\r
+ && pfile->buffer->rlimit[-1] == ' ')\r
+ {\r
+ int c1 = pfile->buffer->rlimit[-3];\r
+ int cl2 = cppBufPeek (cppBuffer_prevBuffer (CPPBUFFER (pfile)));\r
+\r
+ if (cl2 == EOF || !unsafe_chars ((char) c1, (char) cl2))\r
+ pfile->buffer->rlimit -= 2;\r
+ }\r
+ }\r
+ goto get_next;\r
+\r
+\r
+ case ' ': case '\t': case '\v': case '\r':\r
+ for (;;)\r
+ {\r
+ cppReader_putChar (pfile, c);\r
+ c = cppReader_peekC (pfile);\r
+ if (c == EOF || !is_hor_space[c])\r
+ /*@loopbreak@*/ break;\r
+ cppReader_forward (pfile, 1);\r
+ }\r
+ return CPP_HSPACE;\r
+\r
+ case '\\':\r
+ c2 = cppReader_peekC (pfile);\r
+ if (c2 != '\n')\r
+ goto randomchar;\r
+ token = CPP_HSPACE;\r
+ goto op2any;\r
+\r
+ case '\n':\r
+ cppReader_putChar (pfile, c);\r
+ if (pfile->only_seen_white == 0)\r
+ pfile->only_seen_white = 1;\r
+ pfile->lineno++;\r
+ output_line_command (pfile, 1, same_file);\r
+ return CPP_VSPACE;\r
+\r
+ case '(': token = CPP_LPAREN; goto char1;\r
+ case ')': token = CPP_RPAREN; goto char1;\r
+ case '{': token = CPP_LBRACE; goto char1;\r
+ case '}': token = CPP_RBRACE; goto char1;\r
+ case ',': token = CPP_COMMA; goto char1;\r
+ case ';': token = CPP_SEMICOLON; goto char1;\r
+\r
+ randomchar:\r
+ default:\r
+ token = CPP_OTHER;\r
+ char1:\r
+ pfile->only_seen_white = 0;\r
+ cppReader_putChar (pfile, c);\r
+ return token;\r
+ }\r
+ }\r
+\r
+ BADBRANCH;\r
+ /*@notreached@*/\r
+}\r
+\r
+/* Parse an identifier starting with C. */\r
+\r
+void\r
+parse_name (cppReader *pfile, int c)\r
+{\r
+ for (;;)\r
+ {\r
+ if (!is_idchar[c])\r
+ {\r
+ if (c == '\\' && cppReader_peekC (pfile) == '\n')\r
+ {\r
+ cppReader_forward (pfile, 2);\r
+ continue;\r
+ }\r
+\r
+ cppReader_forward (pfile, -1);\r
+ break;\r
+ }\r
+\r
+ if (c == '$' && cppReader_isPedantic (pfile))\r
+ {\r
+ cppReader_pedwarnLit (pfile,\r
+ cstring_makeLiteralTemp ("`$' in identifier"));\r
+ }\r
+\r
+ cppReader_reserve(pfile, 2); /* One more for final NUL. */\r
+ cppReader_putCharQ (pfile, c);\r
+ c = cppReader_getC (pfile);\r
+\r
+ if (c == EOF)\r
+ break;\r
+ }\r
+\r
+ cppReader_nullTerminateQ (pfile);\r
+}\r
+\r
+/* The file_name_map structure holds a mapping of file names for a\r
+ particular directory. This mapping is read from the file named\r
+ FILE_NAME_MAP_FILE in that directory. Such a file can be used to\r
+ map filenames on a file system with severe filename restrictions,\r
+ such as DOS. The format of the file name map file is just a series\r
+ of lines with two tokens on each line. The first token is the name\r
+ to map, and the second token is the actual name to use. */\r
+\r
+struct file_name_map\r
+{\r
+ struct file_name_map *map_next;\r
+ cstring map_from;\r
+ cstring map_to;\r
+};\r
+\r
+/*@constant observer char *FILE_NAME_MAP_FILE*/\r
+#define FILE_NAME_MAP_FILE "header.gcc"\r
+\r
+/* Read a space delimited string of unlimited length from a stdio\r
+ file. */\r
+\r
+static cstring read_filename_string (int ch, /*:open:*/ FILE *f)\r
+{\r
+ char *alloc, *set;\r
+ size_t len;\r
+\r
+ len = 20;\r
+ set = alloc = dmalloc (len + 1);\r
+\r
+ if (!is_space[ch])\r
+ {\r
+ *set++ = ch;\r
+ while ((ch = getc (f)) != EOF && ! is_space[ch])\r
+ {\r
+ if (set - alloc == size_toInt (len))\r
+ {\r
+ len *= 2;\r
+ alloc = drealloc (alloc, len + 1);\r
+ set = alloc + len / 2;\r
+ /*@-branchstate@*/ }\r
+\r
+ *set++ = ch;\r
+ } /*@=branchstate@*/\r
+ }\r
+ *set = '\0';\r
+ check (ungetc (ch, f) != EOF);\r
+\r
+ return cstring_fromChars (alloc);\r
+}\r
+\r
+/* This structure holds a linked list of file name maps, one per directory. */\r
+\r
+struct file_name_map_list\r
+{\r
+ struct file_name_map_list *map_list_next;\r
+ cstring map_list_name;\r
+ struct file_name_map *map_list_map;\r
+};\r
+\r
+/* Read the file name map file for DIRNAME. */\r
+\r
+static struct file_name_map *\r
+read_name_map (cppReader *pfile, cstring dirname)\r
+{\r
+ struct file_name_map_list *map_list_ptr;\r
+ cstring name;\r
+ FILE *f;\r
+\r
+ for (map_list_ptr = CPPOPTIONS (pfile)->map_list;\r
+ map_list_ptr != NULL;\r
+ map_list_ptr = map_list_ptr->map_list_next)\r
+ {\r
+ if (cstring_equal (map_list_ptr->map_list_name, dirname))\r
+ {\r
+ return map_list_ptr->map_list_map;\r
+ }\r
+ }\r
+\r
+ map_list_ptr = (struct file_name_map_list *) dmalloc (sizeof (*map_list_ptr));\r
+ map_list_ptr->map_list_name = cstring_copy (dirname);\r
+ map_list_ptr->map_list_map = NULL;\r
+\r
+ name = cstring_copy (dirname);\r
+\r
+ if (cstring_length (dirname) > 0)\r
+ {\r
+ name = cstring_appendChar (name, CONNECTCHAR);\r
+ }\r
+\r
+ name = cstring_concatFree1 (name, cstring_makeLiteralTemp (FILE_NAME_MAP_FILE));\r
+\r
+ f = fileTable_openFile (context_fileTable (), name, "r");\r
+ cstring_free (name);\r
+\r
+ if (f == NULL)\r
+ {\r
+ map_list_ptr->map_list_map = NULL;\r
+ }\r
+ else\r
+ {\r
+ int ch;\r
+\r
+ while ((ch = getc (f)) != EOF)\r
+ {\r
+ cstring from, to;\r
+ struct file_name_map *ptr;\r
+\r
+ if (is_space[ch])\r
+ {\r
+ continue;\r
+ }\r
+\r
+ from = read_filename_string (ch, f);\r
+ while ((ch = getc (f)) != EOF && is_hor_space[ch])\r
+ {\r
+ ;\r
+ }\r
+\r
+ to = read_filename_string (ch, f);\r
+\r
+ ptr = (struct file_name_map *) dmalloc (sizeof (*ptr));\r
+ ptr->map_from = from;\r
+\r
+ /* Make the real filename absolute. */\r
+ if (cstring_length (to) > 1 \r
+ && osd_isConnectChar (cstring_firstChar (to)))\r
+ {\r
+ ptr->map_to = to;\r
+ }\r
+ else\r
+ {\r
+ ptr->map_to = cstring_copy (dirname);\r
+ ptr->map_to = cstring_appendChar (ptr->map_to, CONNECTCHAR);\r
+ ptr->map_to = cstring_concatFree (ptr->map_to, to);\r
+ }\r
+\r
+ ptr->map_next = map_list_ptr->map_list_map;\r
+ map_list_ptr->map_list_map = ptr;\r
+\r
+ while ((ch = getc (f)) != '\n')\r
+ {\r
+ if (ch == EOF)\r
+ {\r
+ /*@innerbreak@*/ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ assertSet (map_list_ptr->map_list_map);\r
+ check (fileTable_closeFile (context_fileTable (),f) == 0);\r
+ }\r
+\r
+ map_list_ptr->map_list_next = pfile->opts->map_list;\r
+ pfile->opts->map_list = map_list_ptr;\r
+\r
+ return map_list_ptr->map_list_map;\r
+}\r
+\r
+/* Try to open include file FILENAME. SEARCHPTR is the directory\r
+ being tried from the include file search path. This function maps\r
+ filenames on file systems based on information read by\r
+ read_name_map. */\r
+\r
+static int\r
+open_include_file (cppReader *pfile,\r
+ cstring fname,\r
+ struct file_name_list *searchptr)\r
+{\r
+ char *filename = cstring_toCharsSafe (fname);\r
+ struct file_name_map *map;\r
+ char *from;\r
+ char *p, *dir;\r
+\r
+ cstring_markOwned (fname);\r
+\r
+ cpp_setLocation (pfile);\r
+\r
+ if (context_getFlag (FLG_NEVERINCLUDE))\r
+ {\r
+ if (isHeaderFile (fname))\r
+ {\r
+ return SKIP_INCLUDE;\r
+ }\r
+ }\r
+\r
+ if ((searchptr != NULL) && ! searchptr->got_name_map)\r
+ {\r
+ searchptr->name_map = read_name_map (pfile,\r
+ !cstring_isEmpty (searchptr->fname)\r
+ ? searchptr->fname :\r
+ cstring_makeLiteralTemp ("."));\r
+ searchptr->got_name_map = 1;\r
+ }\r
+\r
+ /* First check the mapping for the directory we are using. */\r
+\r
+ if ((searchptr != NULL)\r
+ && (searchptr->name_map != NULL))\r
+ {\r
+ from = filename;\r
+\r
+ if (!cstring_isEmpty (searchptr->fname))\r
+ {\r
+ from += cstring_length (searchptr->fname) + 1;\r
+ }\r
+\r
+ for (map = searchptr->name_map;\r
+ map != NULL;\r
+ map = map->map_next)\r
+ {\r
+ if (cstring_equal (map->map_from, cstring_fromChars (from)))\r
+ {\r
+ /*\r
+ ** Found a match. Check if the file should be skipped\r
+ */\r
+ \r
+ if (cpp_skipIncludeFile (map->map_to))\r
+ {\r
+ return SKIP_INCLUDE;\r
+ }\r
+ else\r
+ {\r
+ return cpp_openIncludeFile (cstring_toCharsSafe (map->map_to));\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /*\r
+ ** Try to find a mapping file for the particular directory we are\r
+ ** looking in. Thus #include <sys/types.h> will look up sys/types.h\r
+ ** in /usr/include/header.gcc and look up types.h in\r
+ ** /usr/include/sys/header.gcc.\r
+ */\r
+\r
+ p = strrchr (filename, CONNECTCHAR);\r
+\r
+ if (p == NULL)\r
+ {\r
+ p = filename;\r
+ }\r
+\r
+ if ((searchptr != NULL)\r
+ && (cstring_isDefined (searchptr->fname))\r
+ && (cstring_length (searchptr->fname) == p - filename)\r
+ && !strncmp (cstring_toCharsSafe (searchptr->fname),\r
+ filename,\r
+ size_fromInt (p - filename)))\r
+ {\r
+ /* filename is in SEARCHPTR, which we've already checked. */\r
+\r
+ if (cpp_skipIncludeFile (cstring_fromChars (filename)))\r
+ {\r
+ return SKIP_INCLUDE;\r
+ }\r
+ else\r
+ {\r
+ return cpp_openIncludeFile (filename);\r
+ }\r
+ }\r
+\r
+ if (p == filename)\r
+ {\r
+ dir = mstring_copy (".");\r
+ from = filename;\r
+ }\r
+ else\r
+ {\r
+ dir = (char *) dmalloc (size_fromInt (p - filename + 1));\r
+ memcpy (dir, filename, size_fromInt (p - filename));\r
+ dir[p - filename] = '\0';\r
+ from = p + 1;\r
+ }\r
+\r
+ for (map = read_name_map (pfile, cstring_fromChars (dir));\r
+ map != NULL;\r
+ map = map->map_next)\r
+ {\r
+ if (cstring_equal (map->map_from, cstring_fromChars (from)))\r
+ {\r
+ sfree (dir);\r
+\r
+ if (cpp_skipIncludeFile (map->map_to))\r
+ {\r
+ return SKIP_INCLUDE;\r
+ }\r
+ else\r
+ {\r
+ return cpp_openIncludeFile (cstring_toCharsSafe (map->map_to));\r
+ }\r
+ }\r
+ }\r
+\r
+ sfree (dir);\r
+\r
+ if (cpp_skipIncludeFile (cstring_fromChars (filename)))\r
+ {\r
+ return SKIP_INCLUDE;\r
+ }\r
+ else\r
+ {\r
+ return cpp_openIncludeFile (filename);\r
+ }\r
+}\r
+\r
+/* Process the contents of include file FNAME, already open on descriptor F,\r
+ with output to OP.\r
+ SYSTEM_HEADER_P is 1 if this file resides in any one of the known\r
+ "system" include directories (as decided by the `is_system_include'\r
+ function above).\r
+ DIRPTR is the link in the dir path through which this file was found,\r
+ or 0 if the file name was absolute or via the current directory.\r
+ Return 1 on success, 0 on failure.\r
+\r
+ The caller is responsible for the cppReader_pushBuffer. */\r
+\r
+static int\r
+finclude (cppReader *pfile, int f,\r
+ cstring fname,\r
+ bool system_header_p,\r
+ /*@dependent@*/ struct file_name_list *dirptr)\r
+{\r
+ mode_t st_mode;\r
+ size_t st_size;\r
+ long i;\r
+ int length = 0;\r
+ cppBuffer *fp; /* For input stack frame */\r
+\r
+ if (file_size_and_mode (f, &st_mode, &st_size) < 0)\r
+ {\r
+ cppReader_perrorWithName (pfile, fname);\r
+ check (close (f) == 0);\r
+ (void) cppReader_popBuffer (pfile);\r
+ /*@-mustfree@*/\r
+ return 0;\r
+ /*@=mustfree@*/\r
+ }\r
+\r
+ fp = cppReader_getBuffer (pfile);\r
+\r
+ /*@-temptrans@*/ /* fname shouldn't really be temp */\r
+ fp->nominal_fname = fp->fname = fname;\r
+ /*@=temptrans@*/\r
+\r
+ fp->dir = dirptr;\r
+ fp->system_header_p = system_header_p;\r
+ fp->lineno = 1;\r
+ fp->colno = 1;\r
+ fp->cleanup = cppReader_fileCleanup;\r
+\r
+ if (S_ISREG (st_mode))\r
+ {\r
+ sfree (fp->buf);\r
+ fp->buf = (char *) dmalloc (st_size + 2);\r
+ fp->alimit = fp->buf + st_size + 2;\r
+ fp->cur = fp->buf;\r
+\r
+ /* Read the file contents, knowing that st_size is an upper bound\r
+ on the number of bytes we can read. */\r
+ length = safe_read (f, fp->buf, size_toInt (st_size));\r
+ fp->rlimit = fp->buf + length;\r
+ if (length < 0) goto nope;\r
+ }\r
+ else if (S_ISDIR (st_mode))\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Directory specified in #include: %s", fname));\r
+ check (close (f) == 0);\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ ** Cannot count its file size before reading.\r
+ ** First read the entire file into heap and\r
+ ** copy them into buffer on stack.\r
+ */\r
+\r
+ size_t bsize = 2000;\r
+\r
+ st_size = 0;\r
+\r
+ sfree (fp->buf);\r
+ fp->buf = (char *) dmalloc (bsize + 2);\r
+\r
+ for (;;) {\r
+ i = safe_read (f, fp->buf + st_size, size_toInt (bsize - st_size));\r
+\r
+ if (i < 0)\r
+ goto nope; /* error! */\r
+ st_size += i;\r
+\r
+ if (st_size != bsize)\r
+ {\r
+ break; /* End of file */\r
+ }\r
+\r
+ bsize *= 2;\r
+ fp->buf = (char *) drealloc (fp->buf, bsize + 2);\r
+ }\r
+\r
+ fp->cur = fp->buf;\r
+ length = size_toInt (st_size);\r
+ }\r
+\r
+ if ((length > 0 && fp->buf[length - 1] != '\n')\r
+ /* Backslash-newline at end is not good enough. */\r
+ || (length > 1 && fp->buf[length - 2] == '\\')) {\r
+ fp->buf[length++] = '\n';\r
+ }\r
+\r
+ fp->buf[length] = '\0';\r
+ fp->rlimit = fp->buf + length;\r
+\r
+ /* Close descriptor now, so nesting does not use lots of descriptors. */\r
+ check (close (f) == 0);\r
+\r
+ /* Must do this before calling trigraph_pcp, so that the correct file name\r
+ will be printed in warning messages. */\r
+\r
+ pfile->input_stack_listing_current = 0;\r
+ return 1;\r
+\r
+ nope:\r
+\r
+ cppReader_perrorWithName (pfile, fname);\r
+ check (close (f) == 0);\r
+ sfree (fp->buf);\r
+ return 1;\r
+}\r
+\r
+void\r
+cppReader_init (cppReader *pfile)\r
+{\r
+ memset ((char *) pfile, 0, sizeof (*pfile));\r
+\r
+ pfile->get_token = cppGetToken;\r
+ pfile->token_buffer_size = 200;\r
+ pfile->token_buffer = (char *) dmalloc (pfile->token_buffer_size);\r
+ pfile->all_include_files = NULL;\r
+\r
+ assertSet (pfile);\r
+\r
+ cppReader_setWritten (pfile, 0);\r
+\r
+ pfile->system_include_depth = 0;\r
+ pfile->max_include_len = 0;\r
+ pfile->timebuf = NULL;\r
+ pfile->only_seen_white = 1;\r
+\r
+ pfile->buffer = cppReader_nullBuffer (pfile);\r
+}\r
+\r
+void\r
+cppReader_finish (/*@unused@*/ cppReader *pfile)\r
+{\r
+ ;\r
+}\r
+\r
+/* Free resources used by PFILE.\r
+ This is the cppReader 'finalizer' or 'destructor' (in C++ terminology). */\r
+\r
+void\r
+cppCleanup (cppReader *pfile)\r
+{\r
+ while (CPPBUFFER (pfile) != cppReader_nullBuffer (pfile))\r
+ {\r
+ (void) cppReader_popBuffer (pfile);\r
+ }\r
+\r
+ if (pfile->token_buffer != NULL)\r
+ {\r
+ sfree (pfile->token_buffer);\r
+ pfile->token_buffer = NULL;\r
+ }\r
+\r
+ while (pfile->if_stack != NULL)\r
+ {\r
+ cppIfStackFrame *temp = pfile->if_stack;\r
+ pfile->if_stack = temp->next;\r
+ sfree (temp);\r
+ }\r
+\r
+ while (pfile->all_include_files != NULL)\r
+ {\r
+ struct file_name_list *temp = pfile->all_include_files;\r
+ pfile->all_include_files = temp->next;\r
+ /*@-dependenttrans@*/\r
+ cstring_free (temp->fname);\r
+ /*@=dependenttrans@*/\r
+ sfree (temp);\r
+ }\r
+\r
+ cppReader_hashCleanup ();\r
+}\r
+\r
+/*\r
+** Get the file-mode and data size of the file open on FD\r
+** and store them in *MODE_POINTER and *SIZE_POINTER.\r
+*/\r
+\r
+static int\r
+file_size_and_mode (int fd, mode_t *mode_pointer, size_t *size_pointer)\r
+{\r
+ struct stat sbuf;\r
+\r
+ if (fstat (fd, &sbuf) < 0) {\r
+ return (-1);\r
+ }\r
+\r
+ if (mode_pointer != NULL)\r
+ {\r
+ *mode_pointer = sbuf.st_mode;\r
+ }\r
+\r
+ if (size_pointer != NULL)\r
+ {\r
+ *size_pointer = (size_t) sbuf.st_size;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
+/* Read LEN bytes at PTR from descriptor DESC, for file FILENAME,\r
+ retrying if necessary. Return a negative value if an error occurs,\r
+ otherwise return the actual number of bytes read,\r
+ which must be LEN unless end-of-file was reached. */\r
+\r
+static int safe_read (int desc, char *ptr, int len)\r
+{\r
+ int left = len;\r
+\r
+ while (left > 0)\r
+ {\r
+# if defined (WIN32) || defined (OS2) && defined (__IBMC__)\r
+ /*@-compdef@*/ /* ptr is an out parameter */\r
+ int nchars = _read (desc, ptr, (unsigned) left);\r
+ /*@=compdef@*/\r
+# else\r
+ ssize_t nchars = read (desc, ptr, size_fromInt (left));\r
+# endif\r
+\r
+ if (nchars < 0)\r
+ {\r
+#ifdef EINTR\r
+ if (errno == EINTR)\r
+ continue;\r
+#endif\r
+ return (int) nchars;\r
+ }\r
+\r
+ if (nchars == 0) {\r
+ break;\r
+ }\r
+\r
+ ptr += nchars;\r
+ left -= nchars;\r
+ }\r
+\r
+ return len - left;\r
+}\r
+\r
+/* Initialize PMARK to remember the current position of PFILE. */\r
+\r
+void\r
+parseSetMark (struct parse_marker *pmark, cppReader *pfile)\r
+{\r
+ cppBuffer *pbuf = cppReader_getBuffer (pfile);\r
+\r
+ pmark->next = pbuf->marks;\r
+ /*@-temptrans@*/\r
+ pbuf->marks = pmark;\r
+ /*@=temptrans@*/\r
+\r
+ pmark->buf = pbuf;\r
+ pmark->position = pbuf->cur - pbuf->buf;\r
+}\r
+\r
+/* Cleanup PMARK - we no longer need it. */\r
+\r
+void parseClearMark (struct parse_marker *pmark)\r
+{\r
+ struct parse_marker **pp = &pmark->buf->marks;\r
+\r
+ for (; ; pp = &(*pp)->next)\r
+ {\r
+ llassert (*pp != NULL);\r
+ if (*pp == pmark) break;\r
+ }\r
+\r
+ *pp = pmark->next;\r
+}\r
+\r
+/* Backup the current position of PFILE to that saved in PMARK. */\r
+\r
+void\r
+parseGotoMark (struct parse_marker *pmark, cppReader *pfile)\r
+{\r
+ cppBuffer *pbuf = cppReader_getBuffer (pfile);\r
+\r
+ if (pbuf != pmark->buf)\r
+ {\r
+ cpp_setLocation (pfile);\r
+ llfatalbug (cstring_makeLiteral ("Internal error parseGotoMark"));\r
+ }\r
+\r
+ llassert (pbuf->buf != NULL);\r
+ pbuf->cur = pbuf->buf + pmark->position;\r
+}\r
+\r
+/* Reset PMARK to point to the current position of PFILE. (Same\r
+ as parseClearMark (PMARK), parseSetMark (PMARK, PFILE) but faster. */\r
+\r
+void\r
+parseMoveMark (struct parse_marker *pmark, cppReader *pfile)\r
+{\r
+ cppBuffer *pbuf = cppReader_getBuffer (pfile);\r
+\r
+ if (pbuf != pmark->buf)\r
+ {\r
+ cpp_setLocation (pfile);\r
+ llfatalerror (cstring_makeLiteral ("Internal error parseMoveMark"));\r
+ }\r
+\r
+ pmark->position = pbuf->cur - pbuf->buf;\r
+}\r
+\r
+void cppReader_initializeReader (cppReader *pfile) /* Must be done after library is loaded. */\r
+{\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+ cstring xp;\r
+\r
+ /* The code looks at the defaults through this pointer, rather than through\r
+ the constant structure above. This pointer gets changed if an environment\r
+ variable specifies other defaults. */\r
+\r
+ struct default_include *include_defaults = include_defaults_array;\r
+\r
+ /* Add dirs from INCLUDEPATH_VAR after dirs from -I. */\r
+ /* There seems to be confusion about what CPATH should do,\r
+ so for the moment it is not documented. */\r
+ /* Some people say that CPATH should replace the standard include dirs,\r
+ but that seems pointless: it comes before them, so it overrides them\r
+ anyway. */\r
+\r
+ xp = osd_getEnvironmentVariable (INCLUDEPATH_VAR);\r
+\r
+ if (cstring_isDefined (xp) && !opts->no_standard_includes)\r
+ {\r
+ path_include (pfile, cstring_toCharsSafe (xp));\r
+ }\r
+\r
+ /* Now that dollars_in_ident is known, initialize is_idchar. */\r
+ initialize_char_syntax (opts);\r
+\r
+ /* CppReader_Install __LINE__, etc. Must follow initialize_char_syntax\r
+ and option processing. */\r
+\r
+ initialize_builtins (pfile);\r
+\r
+ /* Do standard #defines and assertions\r
+ that identify system and machine type. */\r
+\r
+ if (!opts->inhibit_predefs) {\r
+ char *p = (char *) dmalloc (strlen (predefs) + 1);\r
+ strcpy (p, predefs);\r
+\r
+ while (*p)\r
+ {\r
+ char *q;\r
+\r
+ while (*p == ' ' || *p == '\t')\r
+ {\r
+ p++;\r
+ }\r
+\r
+ /* Handle -D options. */\r
+ if (p[0] == '-' && p[1] == 'D')\r
+ {\r
+ q = &p[2];\r
+\r
+ while (*p && *p != ' ' && *p != '\t')\r
+ {\r
+ p++;\r
+ }\r
+\r
+ if (*p != 0)\r
+ {\r
+ *p++= 0;\r
+ }\r
+\r
+ if (opts->debug_output)\r
+ {\r
+ output_line_command (pfile, 0, same_file);\r
+ }\r
+\r
+ cppReader_define (pfile, q);\r
+\r
+ while (*p == ' ' || *p == '\t')\r
+ {\r
+ p++;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ abort ();\r
+ }\r
+ }\r
+\r
+ sfree (p);\r
+ }\r
+\r
+ opts->done_initializing = 1;\r
+\r
+ { /* Read the appropriate environment variable and if it exists\r
+ replace include_defaults with the listed path. */\r
+ char *epath = 0;\r
+#ifdef __CYGWIN32__\r
+ char *win32epath;\r
+ int win32_buf_size = 0; /* memory we need to allocate */\r
+#endif\r
+\r
+ if (opts->cplusplus)\r
+ {\r
+ epath = getenv ("CPLUS_INCLUDE_PATH");\r
+ }\r
+ else\r
+ {\r
+ epath = getenv ("C_INCLUDE_PATH");\r
+ }\r
+\r
+ /*\r
+ ** If the environment var for this language is set,\r
+ ** add to the default list of include directories.\r
+ */\r
+\r
+ if (epath != NULL) {\r
+ char *nstore = (char *) dmalloc (strlen (epath) + 2);\r
+ int num_dirs;\r
+ char *startp, *endp;\r
+\r
+#ifdef __CYGWIN32__\r
+ /* if we have a posix path list, convert to win32 path list */\r
+ if (cygwin32_posix_path_list_p (epath))\r
+ {\r
+ win32_buf_size = cygwin32_posix_to_win32_path_list_buf_size (epath);\r
+ win32epath = (char *) dmalloc /*@i4@*/ (win32_buf_size);\r
+ cygwin32_posix_to_win32_path_list (epath, win32epath);\r
+ epath = win32epath;\r
+ }\r
+#endif\r
+ for (num_dirs = 1, startp = epath; *startp; startp++)\r
+ {\r
+ if (*startp == PATH_SEPARATOR)\r
+ num_dirs++;\r
+ }\r
+\r
+ /*@-sizeoftype@*/\r
+ include_defaults\r
+ = (struct default_include *) dmalloc ((num_dirs\r
+ * sizeof (struct default_include))\r
+ + sizeof (include_defaults_array));\r
+ /*@=sizeoftype@*/\r
+\r
+ startp = endp = epath;\r
+ num_dirs = 0;\r
+ while (1) {\r
+ /* Handle cases like c:/usr/lib:d:/gcc/lib */\r
+ if ((*endp == PATH_SEPARATOR) || *endp == 0)\r
+ {\r
+ strncpy (nstore, startp, size_fromInt (endp - startp));\r
+ if (endp == startp)\r
+ {\r
+ strcpy (nstore, ".");\r
+ }\r
+ else\r
+ {\r
+ nstore[endp-startp] = '\0';\r
+ }\r
+\r
+ include_defaults[num_dirs].fname = cstring_fromCharsNew (nstore);\r
+ include_defaults[num_dirs].cplusplus = opts->cplusplus;\r
+ include_defaults[num_dirs].cxx_aware = 1;\r
+ num_dirs++;\r
+\r
+ if (*endp == '\0')\r
+ {\r
+ break;\r
+ }\r
+ endp = startp = endp + 1;\r
+ }\r
+ else\r
+ {\r
+ endp++;\r
+ }\r
+ }\r
+ /* Put the usual defaults back in at the end. */\r
+ memcpy ((char *) &include_defaults[num_dirs],\r
+ (char *) include_defaults_array,\r
+ sizeof (include_defaults_array));\r
+\r
+ sfree (nstore);\r
+ /*@-branchstate@*/ } /*@=branchstate@*/\r
+ }\r
+\r
+ cppReader_appendIncludeChain (pfile, opts->before_system,\r
+ opts->last_before_system);\r
+ opts->first_system_include = opts->before_system;\r
+\r
+ /* Unless -fnostdinc,\r
+ tack on the standard include file dirs to the specified list */\r
+ if (!opts->no_standard_includes) {\r
+ struct default_include *p = include_defaults;\r
+ char *specd_prefix = opts->include_prefix;\r
+ char *default_prefix = mstring_copy (GCC_INCLUDE_DIR);\r
+ int default_len = 0;\r
+\r
+ /* Remove the `include' from /usr/local/lib/gcc.../include. */\r
+ if (default_prefix != NULL) {\r
+ if (!strcmp (default_prefix + strlen (default_prefix) - 8, "/include")) {\r
+ default_len = strlen (default_prefix) - 7;\r
+ default_prefix[default_len] = 0;\r
+ }\r
+ }\r
+\r
+ /* Search "translated" versions of GNU directories.\r
+ These have /usr/local/lib/gcc... replaced by specd_prefix. */\r
+ if (specd_prefix != 0 && default_len != 0)\r
+ for (p = include_defaults; p->fname != NULL; p++) {\r
+ /* Some standard dirs are only for C++. */\r
+ if (!p->cplusplus\r
+ || (opts->cplusplus && !opts->no_standard_cplusplus_includes)) {\r
+ /* Does this dir start with the prefix? */\r
+ if (!strncmp (cstring_toCharsSafe (p->fname), default_prefix,\r
+ size_fromInt (default_len)))\r
+ {\r
+ /* Yes; change prefix and add to search list. */\r
+ struct file_name_list *nlist\r
+ = (struct file_name_list *) dmalloc (sizeof (*nlist));\r
+ size_t this_len = strlen (specd_prefix) + cstring_length (p->fname) - default_len;\r
+ char *str = (char *) dmalloc (this_len + 1);\r
+ strcpy (str, specd_prefix);\r
+ strcat (str, cstring_toCharsSafe (p->fname) + default_len);\r
+\r
+ nlist->next = NULL;\r
+ nlist->fname = cstring_fromChars (str);\r
+ nlist->control_macro = 0;\r
+ nlist->c_system_include_path = !p->cxx_aware;\r
+ nlist->got_name_map = 0;\r
+\r
+ cppReader_addIncludeChain (pfile, nlist);\r
+ if (opts->first_system_include == 0)\r
+ {\r
+ opts->first_system_include = nlist;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Search ordinary names for GNU include directories. */\r
+\r
+ for (p = include_defaults; p->fname != NULL; p++)\r
+ {\r
+ /* Some standard dirs are only for C++. */\r
+ if (!p->cplusplus\r
+ || (opts->cplusplus && !opts->no_standard_cplusplus_includes))\r
+ {\r
+ struct file_name_list *nlist\r
+ = (struct file_name_list *) dmalloc (sizeof (*nlist));\r
+ nlist->control_macro = 0;\r
+ nlist->c_system_include_path = !p->cxx_aware;\r
+ nlist->fname = p->fname;\r
+ nlist->got_name_map = 0;\r
+ nlist->next = NULL;\r
+\r
+ cppReader_addIncludeChain (pfile, nlist);\r
+\r
+ if (opts->first_system_include == 0)\r
+ {\r
+ opts->first_system_include = nlist;\r
+ }\r
+ }\r
+ }\r
+ sfree (default_prefix);\r
+ }\r
+\r
+ /* Tack the after_include chain at the end of the include chain. */\r
+ cppReader_appendIncludeChain (pfile, opts->after_include,\r
+ opts->last_after_include);\r
+\r
+ if (opts->first_system_include == 0)\r
+ {\r
+ opts->first_system_include = opts->after_include;\r
+ }\r
+\r
+ /* With -v, print the list of dirs to search. */\r
+ if (opts->verbose) {\r
+ struct file_name_list *p;\r
+ fprintf (stderr, "#include \"...\" search starts here:\n");\r
+\r
+ for (p = opts->include; p != NULL; p = p->next) {\r
+ if (p == opts->first_bracket_include)\r
+ fprintf (stderr, "#include <...> search starts here:\n");\r
+\r
+ fprintf (stderr, " %s\n", cstring_toCharsSafe (p->fname));\r
+ }\r
+ fprintf (stderr, "End of search list.\n");\r
+ }\r
+}\r
+\r
+int cppReader_startProcess (cppReader *pfile, cstring fname)\r
+{\r
+ cppBuffer *fp;\r
+ int f;\r
+ struct cppOptions *opts = CPPOPTIONS (pfile);\r
+\r
+ fp = cppReader_pushBuffer (pfile, NULL, 0);\r
+\r
+ if (fp == NULL)\r
+ {\r
+ return 0;\r
+ }\r
+\r
+ if (opts->in_fname == NULL)\r
+ {\r
+ opts->in_fname = cstring_makeLiteralTemp ("");\r
+ }\r
+\r
+ fp->fname = opts->in_fname;\r
+ fp->nominal_fname = fp->fname;\r
+ fp->lineno = 0;\r
+\r
+ /* Copy the entire contents of the main input file into\r
+ the stacked input buffer previously allocated for it. */\r
+\r
+ if (cstring_isEmpty (fname))\r
+ {\r
+ fname = cstring_makeLiteralTemp ("");\r
+ f = 0;\r
+ }\r
+ else if ((f = open (cstring_toCharsSafe (fname), O_RDONLY, 0666)) < 0)\r
+ {\r
+ cppReader_error (pfile,\r
+ message ("Error opening %s for reading: %s",\r
+ fname, lldecodeerror (errno)));\r
+\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ if (finclude (pfile, f, fname, 0, NULL))\r
+ {\r
+ output_line_command (pfile, 0, same_file);\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+static /*@exposed@*/ /*@null@*/ cppBuffer *cppReader_getBuffer (cppReader *pfile)\r
+{\r
+ return pfile->buffer;\r
+}\r
+\r
+/*@exposed@*/ cppBuffer *cppReader_getBufferSafe (cppReader *pfile)\r
+{\r
+ llassert (pfile->buffer != NULL);\r
+ return pfile->buffer;\r
+}\r
+\r
+/*@exposed@*/ char *cppLineBase (cppBuffer *buf)\r
+{\r
+ llassert (buf->buf != NULL);\r
+ return (buf->buf + buf->line_base);\r
+}\r
+\r
+int cppBufPeek (cppBuffer *buf)\r
+{\r
+ if (buf->cur == NULL || buf->rlimit == NULL) {\r
+ return EOF;\r
+ }\r
+\r
+ if (buf->cur < buf->rlimit) {\r
+ return *(buf->cur);\r
+ }\r
+\r
+ return EOF;\r
+}\r
+\r
+bool cppBuffer_isMacro (cppBuffer *buf)\r
+{\r
+ if (buf != NULL)\r
+ {\r
+ return (buf->cleanup == cppReader_macroCleanup);\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+/*\r
+** Returns true if the macro should be checked, false\r
+** if it should be expanded normally.\r
+*/\r
+\r
+static bool notparseable = FALSE; /* preceeded by @notparseable@ */\r
+static bool notfunction = FALSE; /* preceeded by @notfunction@ */\r
+static bool expectiter = FALSE; /* preceeded by @iter@ */\r
+static bool expectenditer = FALSE; /* second after @iter@ */\r
+static bool expectfunction = FALSE; /* preceeded by @function@ */\r
+static bool expectconstant = FALSE; /* preceeded by @constant@ */\r
+static bool expectmacro = FALSE; /* preceeded by notfunction or notparseable */\r
+\r
+static void cpp_setLocation (cppReader *pfile)\r
+{\r
+ fileId fid;\r
+ int line;\r
+\r
+ if (pfile->buffer != NULL)\r
+ {\r
+ if (cstring_isDefined (cppReader_getBuffer (pfile)->nominal_fname))\r
+ {\r
+ cstring fname = cppReader_getBuffer (pfile)->nominal_fname;\r
+ \r
+ DPRINTF (("Looking up: %s", fname));\r
+ \r
+ if (fileTable_exists (context_fileTable (), fname))\r
+ {\r
+ fid = fileTable_lookup (context_fileTable (), fname);\r
+ }\r
+ else\r
+ {\r
+ DPRINTF (("Trying %s", cppReader_getBuffer (pfile)->fname));\r
+\r
+ fid = fileTable_lookup (context_fileTable (),\r
+ cppReader_getBuffer (pfile)->fname);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ fid = fileTable_lookup (context_fileTable (),\r
+ cppReader_getBuffer (pfile)->fname);\r
+ }\r
+ \r
+ line = cppReader_getBuffer (pfile)->lineno;\r
+ fileloc_free (g_currentloc);\r
+\r
+ if (fileId_isValid (fid))\r
+ {\r
+ g_currentloc = fileloc_create (fid, line, 1);\r
+ }\r
+ else\r
+ {\r
+ g_currentloc = fileloc_createBuiltin ();\r
+ }\r
+ }\r
+ else\r
+ {\r
+ fileloc_free (g_currentloc);\r
+ g_currentloc = fileloc_createBuiltin ();\r
+ }\r
+}\r
+\r
+static bool cpp_shouldCheckMacro (cppReader *pfile, char *p) /*@*/\r
+{\r
+ bool checkmacro = FALSE;\r
+ bool hasParams = FALSE;\r
+ bool noexpand = FALSE;\r
+ cstring sname;\r
+ char c;\r
+\r
+ cpp_setLocation (pfile);\r
+\r
+ DPRINTF (("Should check macro? %s", p));\r
+\r
+ if (expectiter || expectconstant || expectenditer)\r
+ {\r
+ if (expectiter)\r
+ {\r
+ expectiter = FALSE;\r
+ expectenditer = TRUE;\r
+ }\r
+ else\r
+ {\r
+ expectiter = FALSE;\r
+ expectconstant = FALSE;\r
+ expectenditer = FALSE;\r
+ }\r
+\r
+ if (notfunction || notparseable)\r
+ {\r
+ notfunction = FALSE;\r
+ notparseable = FALSE;\r
+ return FALSE;\r
+ }\r
+ else\r
+ {\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ llassert (*p == '#');\r
+ p++;\r
+\r
+ while (*p == ' ' || *p == '\t')\r
+ {\r
+ p++;\r
+ }\r
+\r
+ llassert (*p == 'd'); /* define starts */\r
+\r
+ p += 6;\r
+\r
+ while (*p == ' ' || *p == '\t')\r
+ {\r
+ p++;\r
+ }\r
+\r
+ sname = cstring_fromChars (p);\r
+ DPRINTF (("Check macro: %s", sname));\r
+\r
+ while (((c = *p) != ' ')\r
+ && c != '\0' && c != '('\r
+ && c != '\t' && c != '\\' && c != '\n'\r
+ && !iscntrl (c))\r
+ {\r
+ p++;\r
+ }\r
+\r
+ hasParams = (c == '(');\r
+ *p = '\0';\r
+\r
+\r
+ if (notparseable)\r
+ {\r
+ notparseable = FALSE;\r
+ }\r
+ else if (notfunction || fileloc_isStandardLib (g_currentloc))\r
+ {\r
+ DPRINTF (("Clear notfunction"));\r
+ notfunction = FALSE;\r
+ }\r
+ else\r
+ {\r
+ if (noexpand)\r
+ {\r
+ checkmacro = TRUE;\r
+\r
+ if (!expectenditer)\r
+ {\r
+ noexpand = FALSE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (usymtab_existsReal (sname))\r
+ {\r
+ uentry ue = usymtab_lookup (sname);\r
+\r
+ DPRINTF (("Lookup macro: %s", uentry_unparse (ue)));\r
+\r
+ if (fileloc_isPreproc (uentry_whereLast (ue)))\r
+ {\r
+ goto macroDne;\r
+ }\r
+ else\r
+ {\r
+ if (uentry_isSpecified (ue))\r
+ {\r
+ checkmacro = context_getFlag (FLG_SPECMACROS);\r
+ }\r
+ else\r
+ {\r
+ if (hasParams)\r
+ {\r
+ checkmacro = context_getFlag (FLG_LIBMACROS)\r
+ || context_getFlag (FLG_FCNMACROS);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ macroDne:\r
+ DPRINTF (("Macro doesn't exist: %s", bool_unparse (checkmacro)));\r
+\r
+ if (fileloc_isSystemFile (g_currentloc)\r
+ && context_getFlag (FLG_SYSTEMDIREXPAND))\r
+ {\r
+ ; /* don't check this macro */\r
+ DPRINTF (("Don't check 1"));\r
+ }\r
+ else\r
+ {\r
+ uentry le;\r
+ \r
+ if (hasParams)\r
+ {\r
+ DPRINTF (("Has params..."));\r
+\r
+ if (context_getFlag (FLG_FCNMACROS))\r
+ {\r
+ if (usymtab_exists (sname))\r
+ {\r
+ /*\r
+ ** only get here is macro is redefined\r
+ ** error reported elsewhere\r
+ */\r
+\r
+ DPRINTF (("It exists!"));\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ ** We make it a forward function, since it might be declared elsewhere.\r
+ ** After all headers have been processed, we should check the forward\r
+ ** functions.\r
+ */\r
+\r
+ fileloc loc = fileloc_makePreproc (g_currentloc);\r
+\r
+ /* the line is off-by-one, since the newline was already read */\r
+ decLine ();\r
+\r
+ if (expectfunction)\r
+ {\r
+ expectfunction = FALSE;\r
+ }\r
+\r
+ le = uentry_makeForwardFunction (sname,\r
+ typeId_invalid, loc);\r
+\r
+ fileloc_free (loc);\r
+\r
+ incLine ();\r
+\r
+ /* Do not define here! */\r
+\r
+ (void) usymtab_addEntry (le);\r
+ }\r
+\r
+ checkmacro = TRUE;\r
+ DPRINTF (("Check: TRUE"));\r
+ }\r
+ else \r
+ {\r
+ DPRINTF (("Flag FCN_MACROS not set!"));\r
+ }\r
+ }\r
+ else\r
+ {\r
+ DPRINTF (("No params"));\r
+\r
+ if (context_getFlag (FLG_CONSTMACROS))\r
+ {\r
+ bool nocontent = FALSE;\r
+\r
+ if (c == '\0')\r
+ {\r
+ nocontent = TRUE;\r
+ }\r
+ else\r
+ {\r
+ if (isspace (c))\r
+ {\r
+ char *rest = p + 1;\r
+\r
+ /*\r
+ ** Check if there is nothing after the define.\r
+ */\r
+\r
+ while ((*rest) != '\0' && isspace (*rest))\r
+ {\r
+ rest++;\r
+ }\r
+\r
+ if (*rest == '\0')\r
+ {\r
+ nocontent = TRUE; /* empty macro, don't check */\r
+ }\r
+ }\r
+ }\r
+\r
+ if (usymtab_exists (sname))\r
+ {\r
+ ;\r
+ }\r
+ else\r
+ {\r
+ fileloc loc = fileloc_makePreproc (g_currentloc);\r
+ DPRINTF (("Make constant: %s", sname));\r
+ le = uentry_makeConstant (sname,\r
+ ctype_unknown, loc);\r
+ (void) usymtab_addEntry (le);\r
+ }\r
+\r
+ checkmacro = !nocontent;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (checkmacro && usymtab_existsType (sname))\r
+ {\r
+ DPRINTF (("Making false..."));\r
+ decLine ();\r
+ ppllerror (message ("Specified type implemented as macro: %s", sname));\r
+ checkmacro = FALSE;\r
+ incLine ();\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ if (!checkmacro)\r
+ {\r
+ if (usymtab_exists (sname))\r
+ {\r
+ uentry ue = usymtab_lookupExpose (sname);\r
+ fileloc tloc = fileloc_makePreproc (g_currentloc);\r
+\r
+ uentry_setDefined (ue, tloc);\r
+ fileloc_free (tloc);\r
+ uentry_setUsed (ue, fileloc_undefined);\r
+ }\r
+ else\r
+ {\r
+ fileloc tloc = fileloc_makePreproc (g_currentloc);\r
+ uentry ue = uentry_makeExpandedMacro (sname, tloc);\r
+ DPRINTF (("Make expanded macro: %s", sname));\r
+ DPRINTF (("Not in symbol table: %s", sname));\r
+ \r
+ (void) usymtab_addGlobalEntry (ue);\r
+ fileloc_free (tloc);\r
+ }\r
+ }\r
+\r
+ *p = c;\r
+ DPRINTF (("Returning: %s", bool_unparse (checkmacro)));\r
+ return checkmacro;\r
+}\r
+\r
+static enum cpp_token\r
+cpp_handleComment (cppReader *pfile, struct parse_marker *smark)\r
+{\r
+ cppBuffer *pbuf = cppReader_getBuffer (pfile);\r
+ char *start;\r
+ int len;\r
+ bool eliminateComment = FALSE;\r
+\r
+ llassert (pbuf->buf != NULL);\r
+\r
+ start = pbuf->buf + smark->position;\r
+\r
+ llassert (pbuf->cur != NULL);\r
+ len = pbuf->cur - start;\r
+\r
+ if (start[0] == '*'\r
+ && start[1] == context_getCommentMarkerChar ())\r
+ {\r
+ int i;\r
+ char c = ' ';\r
+ char *scomment = start + 2;\r
+ char savec = start[len];\r
+\r
+ start[0] = BEFORE_COMMENT_MARKER[0];\r
+ start[1] = BEFORE_COMMENT_MARKER[1];\r
+\r
+ llassert (start[len - 2] == '*');\r
+ start[len - 2] = AFTER_COMMENT_MARKER[0];\r
+\r
+ llassert (start[len - 1] == '/');\r
+ start[len - 1] = AFTER_COMMENT_MARKER[1];\r
+\r
+ cppReader_reserve(pfile, size_fromInt (1 + len));\r
+ cppReader_putCharQ (pfile, c);\r
+\r
+ cpp_setLocation (pfile);\r
+\r
+ start[len] = '\0';\r
+\r
+ if (mstring_containsString (scomment, "/*"))\r
+ {\r
+ (void) cppoptgenerror \r
+ (FLG_NESTCOMMENT,\r
+ message ("Comment starts inside syntactic comment: %s", \r
+ cstring_fromChars (scomment)),\r
+ pfile);\r
+ }\r
+\r
+ start[len] = savec;\r
+\r
+ if (mstring_equalPrefix (scomment, "ignore"))\r
+ {\r
+ if (!context_getFlag (FLG_NOCOMMENTS))\r
+ {\r
+ context_enterSuppressRegion ();\r
+ }\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "end"))\r
+ {\r
+ if (!context_getFlag (FLG_NOCOMMENTS))\r
+ {\r
+ context_exitSuppressRegion ();\r
+ }\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "notparseable"))\r
+ {\r
+ notparseable = TRUE;\r
+ expectmacro = TRUE;\r
+ eliminateComment = TRUE;\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "notfunction"))\r
+ {\r
+ notfunction = TRUE;\r
+ expectmacro = TRUE;\r
+ eliminateComment = TRUE;\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "iter"))\r
+ {\r
+ expectiter = TRUE;\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "function"))\r
+ {\r
+ expectfunction = TRUE;\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "constant"))\r
+ {\r
+ expectconstant = TRUE;\r
+ }\r
+ else\r
+ {\r
+ char sChar = *scomment;\r
+\r
+ if (sChar == '='\r
+ || sChar == '-'\r
+ || sChar == '+')\r
+ {\r
+ char *rest = scomment + 1;\r
+\r
+ if (mstring_equalPrefix (rest, "commentchar"))\r
+ {\r
+ eliminateComment = TRUE;\r
+\r
+ if (sChar == '=')\r
+ {\r
+ ppllerror (cstring_makeLiteral\r
+ ("Cannot restore commentchar"));\r
+ }\r
+ else\r
+ {\r
+ char *next = scomment + 12; /* strlen commentchar = 12 */\r
+\r
+ if (*next != ' ' && *next != '\t' && *next != '\n')\r
+ {\r
+ ppllerror\r
+ (message\r
+ ("Syntactic commentchar comment is not followed by a "\r
+ "whitespace character: %c",\r
+ *next));\r
+ }\r
+ else\r
+ {\r
+ char cchar = *(next + 1);\r
+\r
+ if (cchar == '\0')\r
+ {\r
+ ppllerror\r
+ (cstring_makeLiteral\r
+ ("Cannot set commentchar to NUL"));\r
+ }\r
+ else\r
+ {\r
+ context_setCommentMarkerChar (cchar);\r
+ /* setComment = TRUE; */\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else if (mstring_equalPrefix (scomment, "nestcomment"))\r
+ {\r
+ /* fix from Mike Miller <MikeM@xata.com> */\r
+ context_fileSetFlag (FLG_NESTCOMMENT,\r
+ ynm_fromCodeChar (sChar));\r
+ }\r
+ else if (mstring_equalPrefix (rest, "namechecks"))\r
+ {\r
+ context_fileSetFlag (FLG_NAMECHECKS,\r
+ ynm_fromCodeChar (sChar));\r
+ }\r
+ else if (mstring_equalPrefix (rest, "macroredef"))\r
+ {\r
+ context_fileSetFlag (FLG_MACROREDEF,\r
+ ynm_fromCodeChar (sChar));\r
+ }\r
+ else if (mstring_equalPrefix (rest, "usevarargs"))\r
+ {\r
+ context_fileSetFlag (FLG_USEVARARGS,\r
+ ynm_fromCodeChar (sChar));\r
+ }\r
+ else if (mstring_equalPrefix (rest, "nextlinemacros"))\r
+ {\r
+ context_fileSetFlag (FLG_MACRONEXTLINE,\r
+ ynm_fromCodeChar (sChar));\r
+ }\r
+ else if (mstring_equalPrefix (rest, "allmacros")\r
+ || mstring_equalPrefix (rest, "fcnmacros")\r
+ || mstring_equalPrefix (rest, "constmacros"))\r
+ {\r
+ flagcode fl;\r
+\r
+ if (mstring_equalPrefix (rest, "allmacros"))\r
+ {\r
+ fl = FLG_ALLMACROS;\r
+ }\r
+ else if (mstring_equalPrefix (rest, "fcnmacros"))\r
+ {\r
+ fl = FLG_FCNMACROS;\r
+ }\r
+ else\r
+ {\r
+ llassert (mstring_equalPrefix (rest, "constmacros"));\r
+ fl = FLG_CONSTMACROS;\r
+ }\r
+\r
+\r
+ context_fileSetFlag (fl, ynm_fromCodeChar (sChar));\r
+ notfunction = FALSE;\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+\r
+ if (eliminateComment)\r
+ {\r
+ goto removeComment;\r
+ }\r
+\r
+ /* Replaces comment char's in start with spaces */\r
+\r
+ for (i = 2; i < len - 2; i++)\r
+ {\r
+ if (start[i] == BEFORE_COMMENT_MARKER[0]\r
+ || start[i] == BEFORE_COMMENT_MARKER[1]\r
+ || start[i] == context_getCommentMarkerChar ())\r
+ {\r
+ start[i] = ' ';\r
+ }\r
+ }\r
+\r
+ cppReader_putStrN (pfile, start, size_fromInt (len));\r
+ parseClearMark (smark);\r
+ return CPP_COMMENT;\r
+ }\r
+ else\r
+ {\r
+ removeComment:\r
+ {\r
+ int i;\r
+\r
+ /*\r
+ ** Output the comment as all spaces so line/column\r
+ ** in output file is still correct.\r
+ */\r
+\r
+ char c = ' ';\r
+ cstring lintcomment = cstring_undefined;\r
+\r
+ if (context_getFlag (FLG_LINTCOMMENTS))\r
+ {\r
+ if (mstring_equalPrefix (start, "*NOTREACHED*/"))\r
+ {\r
+ lintcomment = cstring_makeLiteralTemp ("l_notreach");\r
+ }\r
+ else if (mstring_equalPrefix (start, "*PRINTFLIKE*/"))\r
+ {\r
+ lintcomment = cstring_makeLiteralTemp ("l_printfli");\r
+ }\r
+ else if (mstring_equalPrefix (start, "*FALLTHROUGH*/"))\r
+ {\r
+ lintcomment = cstring_makeLiteralTemp ("l_fallthrou");\r
+ }\r
+ else if (mstring_equalPrefix (start, "*ARGSUSED*/"))\r
+ {\r
+ lintcomment = cstring_makeLiteralTemp ("l_argsus");\r
+ }\r
+ else if (mstring_equalPrefix (start, "*FALLTHRU*/"))\r
+ {\r
+ lintcomment = cstring_makeLiteralTemp ("l_fallth");\r
+ }\r
+ else\r
+ {\r
+ lintcomment = cstring_undefined;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ lintcomment = cstring_undefined;\r
+ }\r
+\r
+ if (cstring_isDefined (lintcomment))\r
+ {\r
+ c = BEFORE_COMMENT_MARKER[0];\r
+ start[0] = BEFORE_COMMENT_MARKER[1];\r
+\r
+ llassert (cstring_length (lintcomment) == len - 3);\r
+\r
+ for (i = 1; i < len - 2; i++)\r
+ {\r
+ start[i] = cstring_getChar (lintcomment, i);\r
+ }\r
+ \r
+ start[len - 2] = AFTER_COMMENT_MARKER[0];\r
+ start[len - 1] = AFTER_COMMENT_MARKER[1];\r
+ }\r
+ else\r
+ {\r
+ /* Replaces char's in start with spaces */\r
+ for (i = 0; i < len; i++)\r
+ {\r
+ if (start[i] == '/'\r
+ && i < len - 1\r
+ && start[i + 1] == '*') {\r
+ (void) cppoptgenerror (FLG_NESTCOMMENT,\r
+ message ("Comment starts inside comment"),\r
+ pfile);\r
+ }\r
+ \r
+ if (start[i] != '\n')\r
+ {\r
+ start[i] = ' ';\r
+ }\r
+ }\r
+ }\r
+\r
+ cppReader_reserve (pfile, size_fromInt (1 + len));\r
+ cppReader_putCharQ (pfile, c);\r
+ cppReader_putStrN (pfile, start, size_fromInt (len));\r
+ parseClearMark (smark);\r
+ return CPP_COMMENT;\r
+ }\r
+ }\r
+}\r
+\r
+static int cpp_openIncludeFile (char *filename)\r
+{\r
+ int res = open (filename, O_RDONLY, 0666);\r
+\r
+ /* evans 2001-08-23: was (res) - open returns -1 on error! reported by Robin Watts */\r
+ if (res >= 0)\r
+ {\r
+ if (!fileTable_exists (context_fileTable (),\r
+ cstring_fromChars (filename)))\r
+ {\r
+ (void) fileTable_addHeaderFile (context_fileTable (),\r
+ cstring_fromChars (filename));\r
+ }\r
+ else\r
+ {\r
+ DPRINTF (("File already exists: %s", filename));\r
+ }\r
+ }\r
+\r
+ return res;\r
+}\r
+\r
+static bool cpp_skipIncludeFile (cstring fname)\r
+{\r
+ if (context_isSystemDir (fname))\r
+ {\r
+ DPRINTF (("System dir: %s", fname));\r
+\r
+ if (lcllib_isSkipHeader (fname))\r
+ {\r
+ DPRINTF (("Skip include TRUE: %s", fname));\r
+ return TRUE;\r
+ }\r
+ \r
+ if (context_getFlag (FLG_SKIPSYSHEADERS))\r
+ {\r
+ DPRINTF (("Skip include TRUE: %s", fname));\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ if (context_getFlag (FLG_SINGLEINCLUDE))\r
+ {\r
+ fname = removePreDirs (fname);\r
+\r
+# if defined (WIN32) || defined (OS2)\r
+ cstring_replaceAll (fname, '\\', '/');\r
+# endif\r
+\r
+ if (fileTable_exists (context_fileTable (), fname))\r
+ {\r
+ DPRINTF (("Skip include TRUE: %s", fname));\r
+ return TRUE;\r
+ }\r
+ }\r
+\r
+ DPRINTF (("Skip include FALSE: %s", fname));\r
+ return FALSE;\r
+}\r
+\r
+static int cpp_peekN (cppReader *pfile, int n)\r
+{\r
+ cppBuffer *buf = cppReader_getBuffer (pfile);\r
+\r
+ llassert (buf->cur != NULL);\r
+\r
+ return (buf->rlimit - buf->cur >= (n)\r
+ ? buf->cur[n]\r
+ : EOF);\r
+}\r
+\r
+cppBuffer *cppBuffer_prevBuffer (cppBuffer *buf)\r
+{\r
+ return buf + 1;\r
+}\r
+\r
+void cppBuffer_forward (cppBuffer *buf, int n)\r
+{\r
+ llassert (buf->cur != NULL);\r
+ buf->cur += n;\r
+}\r
-/*;-*-C-*-;
-** Copyright (c) Massachusetts Institute of Technology 1994-1998.
-** All Rights Reserved.
-** Unpublished rights reserved under the copyright laws of
-** the United States.
-**
-** THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
-** OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
-**
-** This code is distributed freely and may be used freely under the
-** following conditions:
-**
-** 1. This notice may not be removed or altered.
-**
-** 2. Works derived from this code are not distributed for
-** commercial gain without explicit permission from MIT
-** (for permission contact lclint-request@sds.lcs.mit.edu).
-*/
-/*
- * Modified by Herbert 08/19/97:
- * - added #include for IBM's OS/2 compiler.
- * - fixed weird bug with lookup of tmp files (OS/2 and MSDOS only).
- */
-
-/*
- * Modified by Mike Smith
- * Corrected missing 'line' in scanf() calls in handleSpecial().
- * Without this, I get an error when LCLint hits a '#line' directive
- * in the pre-pre-processed source files. For safety, I have made these
- * conditional on OS2 and MSDOS because I don't understand why noone else
- * has seen this problem.
- *
- * Modified by Mike Smith, 4th June 1997
- * Finally resolved the #line problem. The scanf() calls have been fixed to
- * allow the following #line forms:-
- *
- * #line 123 "filename"
- * #line 123
- * # 123 "filename"
- * # 123
- *
- * The last two are generated by the GNU pre-processor, apparently
- */
-
-Digit [0-9]
-Letter [a-zA-Z_$]
-H [a-fA-F0-9]
-E [Ee][+-]?{Digit}+
-U (u|U)
-L (l|L)
-FS (f|F|l|L)
-IS (u|U|l|L)*
-ULSuffix ({U}{L}|{L}{U})
-
-%{
-/*
-** based on original C lexer by Nate Osgood
-** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993
-**
-*/
-
-# include "lclintMacros.nf"
-# include <unistd.h>
-# include "basic.h"
-
-# include "cgrammar.h"
-# include "cgrammar_tokens.h"
-
-# include "fileIdList.h"
-# include "portab.h"
-
-# if defined(OS2) && defined(__IBMC__)
- /* needed for isatty()... */
-# include <io.h>
-# endif
-
-static bool lastWasString = FALSE;
-static char savechar = '\0';
-
-/*@notfunction@*/
-# define yyinput() (incColumn (), getc (yyin))
-
-static /*@owned@*/ cstring lastidprocessed = cstring_undefined;
-static int lminput (void);
-static int tokLength = 0;
-static bool inSpecPart = FALSE;
-static bool continueLine = FALSE;
-
-static int ninput (void);
-static char processChar (void);
-static double processFloat (void);
-static /*@only@*/ exprNode processString (void);
-static long processDec (void);
-static long processHex (void);
-static long processOctal (void);
-static int processIdentifier (/*@only@*/ cstring)
- /*@globals undef lastidprocessed@*/ ;
-static bool processHashIdentifier (/*@only@*/ cstring)
- /*@globals undef lastidprocessed@*/ ;
-
-static int processSpec (int);
-static bool handleSpecial (char *);
-static int handleLlSpecial (void);
-static void handleMacro (void);
-static bool processMacro (void);
-static /*@only@*/ cstring makeIdentifier (char *);
-
-/* yes, this is exported! */
-bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */
-
-static bool expectingMetaStateName = FALSE;
-
-static int returnInt (ctype, long);
-static int returnFloat (ctype, double);
-static int returnChar (char);
-static void setTokLength (int) /*@modifies g_currentloc@*/ ;
-static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;
-
-static void advanceLine (void)
-{
- tokLength = 0;
- beginLine ();
-}
-
-/*@-allmacros@*/
-# define RETURN_INT(c,i) \
- do { lastWasString = FALSE; \
- return (returnInt (c, i)); } while (FALSE)
-
-# define RETURN_FLOAT(c,f) \
- do { lastWasString = FALSE; \
- return (returnFloat (c, f)); \
- } while (FALSE)
-
-# define RETURN_CHAR(c) \
- do { lastWasString = FALSE; \
- return (returnChar (c)); \
- } while (FALSE)
-
-# define RETURN_TOK(t) \
- do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \
- tokLength = 0; \
- lastWasString = FALSE; \
- return (t); } while (FALSE)
-
-# define RETURN_TYPE(t, ct) \
- do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)
-
-/* don't fileloc_decColumn (g_currentloc, tokLength));
- the string could have \n's in it!
-*/
-
-# define RETURN_STRING(c) \
- do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \
- tokLength = 0; \
- lastWasString = TRUE; \
- return (CCONSTANT); } while (FALSE)
-
-# define RETURN_EXPR(e) \
- do { yylval.expr = e; \
- tokLength = 0; \
- lastWasString = TRUE; \
- return (CCONSTANT); } while (FALSE)
-
-/*@=allmacros@*/
-
-static void setTokLength (int len)
-{
- addColumn (len);
- tokLength = len;
- DPRINTF (("Set tok length: %d", len));
-}
-
-static void setTokLengthT (size_t len)
-{
- setTokLength (size_toInt (len));
-}
-
-# include "flex.head"
-
-/*@-unrecog@*/ /*@i5343@*/
-
-%}
-
-%%
-
-"/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }
-
-"#"{Letter}({Letter}|{Digit})* {
- context_saveLocation ();
- setTokLength (longUnsigned_toInt (mstring_length (yytext)));
-
- if (processHashIdentifier (makeIdentifier (yytext + 1)))
- {
- if (lastWasString)
- {
- /* was nothing! */ /*@i32@*/
- RETURN_STRING (cstring_makeLiteral ("\"\""));
- }
- else
- {
- RETURN_STRING (cstring_makeLiteral ("\"\""));
- }
- }
- else
- {
- if (handleSpecial (yytext))
- {
- setTokLength (1);
- RETURN_TOK (0);
- }
- }
- }
-"#" { if (handleSpecial (yytext))
- {
- setTokLength (1); RETURN_TOK (0);
- }
- }
-"..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }
-"break" { setTokLength (5); RETURN_TOK (BREAK); }
-"case" { setTokLength (4); RETURN_TOK (CASE); }
-"continue" { setTokLength (8); RETURN_TOK (CONTINUE); }
-"default" { setTokLength (7); RETURN_TOK (DEFAULT); }
-"do" { setTokLength (2); RETURN_TOK (DO); }
-"else" { setTokLength (4); RETURN_TOK (CELSE); }
-"for" { setTokLength (3); RETURN_TOK (CFOR); }
-"goto" { setTokLength (4); RETURN_TOK (GOTO); }
-"if" { setTokLength (2); RETURN_TOK (CIF); }
-"return" { setTokLength (6); RETURN_TOK (RETURN); }
-"sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }
-"offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }
-"switch" { setTokLength (6); RETURN_TOK (SWITCH); }
-"while" { setTokLength (5); RETURN_TOK (WHILE); }
-"va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); }
-"va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); }
-"inline" {
- /* gcc extension...this might not be appropriate */
- setTokLength (6); RETURN_TOK (QINLINE); }
-
-"struct" { setTokLength (6); RETURN_TOK (CSTRUCT); }
-"typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }
-
-"union" { setTokLength (5); RETURN_TOK (CUNION); }
-"enum" { setTokLength (4); RETURN_TOK (CENUM); }
-
-"void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }
-"int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }
-"double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }
-"char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }
-"float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }
-
-"long" { setTokLength (4); RETURN_TOK (QLONG); }
-"short" { setTokLength (5); RETURN_TOK (QSHORT); }
-"unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }
-"signed" { setTokLength (6); RETURN_TOK (QSIGNED); }
-
-"volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }
-"const" { setTokLength (5); RETURN_TOK (QCONST); }
-
- /* some systems expect this! [gack!] */
-"__const" { setTokLength (7); RETURN_TOK (QCONST); }
-
-"extern" { setTokLength (6); RETURN_TOK (QEXTERN); }
-"auto" { setTokLength (4); RETURN_TOK (QAUTO); }
-"register" { setTokLength (8); RETURN_TOK (QREGISTER); }
-"static" { setTokLength (6); RETURN_TOK (QSTATIC); }
-
-\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
-L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }
-"out" { return (processSpec (QOUT)); }
-"in" { return (processSpec (QIN)); }
-"partial" { return (processSpec (QPARTIAL)); }
-"special" { return (processSpec (QSPECIAL)); }
-"anytype" { return (processSpec (QANYTYPE)); }
-"integraltype" { return (processSpec (QINTEGRALTYPE)); }
-"unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }
-"signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }
-"keep" { return (processSpec (QKEEP)); }
-"null" { return (processSpec (QNULL)); }
-"notnull" { return (processSpec (QNOTNULL)); }
-"isnull" { return (processSpec (QISNULL)); }
-"truenull" { return (processSpec (QTRUENULL)); }
-"falsenull" { return (processSpec (QFALSENULL)); }
-"relnull" { return (processSpec (QRELNULL)); }
-"reldef" { return (processSpec (QRELDEF)); }
-"exposed" { return (processSpec (QEXPOSED)); }
-"newref" { return (processSpec (QNEWREF)); }
-"tempref" { return (processSpec (QTEMPREF)); }
-"killref" { return (processSpec (QKILLREF)); }
-"refcounted" { return (processSpec (QREFCOUNTED)); }
-"checked" { return (processSpec (QCHECKED)); }
-"checkmod" { return (processSpec (QCHECKMOD)); }
-"checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }
-"unchecked" { return (processSpec (QUNCHECKED)); }
-"only" { return (processSpec (QONLY)); }
-"owned" { return (processSpec (QOWNED)); }
-"observer" { return (processSpec (QOBSERVER)); }
-"dependent" { return (processSpec (QDEPENDENT)); }
-"unused" { return (processSpec (QUNUSED)); }
-"external" { return (processSpec (QEXTERNAL)); }
-"sef" { return (processSpec (QSEF)); }
-"shared" { return (processSpec (QSHARED)); }
-"yield" { return (processSpec (QYIELD)); }
-"undef" { return (processSpec (QUNDEF)); }
-"killed" { return (processSpec (QKILLED)); }
-"nullterminated" { return (processSpec (QNULLTERMINATED));}
-"MaxSet" { return (processSpec (QMAXSET));}
-"MaxRead" { return (processSpec (QMAXREAD));}
-"maxSet" { return (processSpec (QMAXSET));}
-"maxRead" { return (processSpec (QMAXREAD));}
-
-{Letter}({Letter}|{Digit})* { int tok;
- context_saveLocation ();
- setTokLength (longUnsigned_toInt (mstring_length (yytext)));
- tok = processIdentifier (makeIdentifier (yytext));
- if (tok != BADTOK)
- {
- return (tok);
- }
- }
-0[xX]{H}+ { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */
- }
-0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_lint, processHex ()); }
-0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_llint, processHex ()); }
-0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_uint, processHex ()); }
-0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ulint, processHex ()); }
-0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processHex ()); }
-0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processHex ()); }
-0{Digit}+ { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_int, processOctal ()); }
-0{Digit}+{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_uint, processOctal ()); }
-0{Digit}+{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_lint, processOctal ()); }
-0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_llint, processOctal ()); }
-0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ulint, processOctal ()); }
-0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processOctal ()); }
-0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processOctal ()); }
-{Digit}+ { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_int, processDec ()); }
-{Digit}+{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_uint, processDec ()); }
-{Digit}+{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_lint, processDec ()); }
-{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_llint, processDec ()); }
-{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ulint, processDec ()); }
-{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processDec ()); }
-{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext));
- RETURN_INT (ctype_ullint, processDec ()); }
-'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
- RETURN_CHAR (processChar ()); }
-L'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext));
- RETURN_CHAR (processChar ()); }
-{Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_float, processFloat ()); }
-{Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_ldouble, processFloat ()); }
-{Digit}+{E} { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_double, processFloat ()); }
-
-{Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_float, processFloat ()); }
-{Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_ldouble, processFloat ()); }
-{Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_double, processFloat ()); }
-
-{Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_float, processFloat ()); }
-{Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_ldouble, processFloat ()); }
-{Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext));
- RETURN_FLOAT (ctype_double, processFloat ()); }
-
-">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }
-"<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }
-"+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }
-"-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }
-"*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }
-"/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }
-"%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }
-"&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }
-"^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }
-"|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }
-">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }
-"<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }
-"++" { setTokLength (2); RETURN_TOK (INC_OP); }
-"--" { setTokLength (2); RETURN_TOK (DEC_OP); }
-"->" { setTokLength (2); RETURN_TOK (ARROW_OP); }
-"&&" { setTokLength (2); RETURN_TOK (AND_OP); }
-"||" { setTokLength (2); RETURN_TOK (OR_OP); }
-"<=" { setTokLength (2); RETURN_TOK (LE_OP); }
-">=" { setTokLength (2); RETURN_TOK (GE_OP); }
-"==" { setTokLength (2); RETURN_TOK (EQ_OP); }
-"!=" { setTokLength (2); RETURN_TOK (NE_OP); }
-";" { setTokLength (1); RETURN_TOK (TSEMI); }
-"{" { setTokLength (1); RETURN_TOK (TLBRACE); }
-"}" { setTokLength (1); RETURN_TOK (TRBRACE); }
-"," { setTokLength (1); RETURN_TOK (TCOMMA); }
-":" { setTokLength (1); RETURN_TOK (TCOLON); }
-"=" { setTokLength (1); RETURN_TOK (TASSIGN); }
-"(" { setTokLength (1); RETURN_TOK (TLPAREN); }
-")" { setTokLength (1); RETURN_TOK (TRPAREN); }
-"[" { setTokLength (1); RETURN_TOK (TLSQBR); }
-"]" { setTokLength (1); RETURN_TOK (TRSQBR); }
-"." { setTokLength (1); RETURN_TOK (TDOT); }
-"&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }
-"!" { setTokLength (1); RETURN_TOK (TEXCL); }
-
-
-"~" { setTokLength (1); RETURN_TOK (TTILDE); }
-"-" { setTokLength (1); RETURN_TOK (TMINUS); }
-"+" { setTokLength (1); RETURN_TOK (TPLUS); }
-"*" { setTokLength (1); RETURN_TOK (TMULT); }
-"/" { setTokLength (1); RETURN_TOK (TDIV); }
-"%" { setTokLength (1); RETURN_TOK (TPERCENT); }
-"<" { setTokLength (1); RETURN_TOK (TLT); }
-">" { setTokLength (1); RETURN_TOK (TGT); }
-"^" { setTokLength (1); RETURN_TOK (TCIRC); }
-"|" { setTokLength (1); RETURN_TOK (TBAR); }
-"?" { setTokLength (1); RETURN_TOK (TQUEST); }
-
-
-"/\\" { setTokLength (1); RETURN_TOK (TCAND); }
-
-
-[ \t\v\f] { incColumn (); }
-\n { context_incLineno ();
- if (tokLength != 0) {
- tokLength = 0;
- /* No error to report
- voptgenerror
- (FLG_SYNTAX,
- message ("Likely parse error: token spans multiple lines."),
- g_currentloc);
- */
- }
-
- if (continueLine)
- {
- continueLine = FALSE;
- }
- else
- {
- if (context_inMacro ())
- {
- /* Don't use RETURN_TOK */
- yylval.tok = lltok_create (TENDMACRO, g_currentloc);
- lastWasString = FALSE;
- return (TENDMACRO);
- }
- }
- }
-"@@MR@@" { setTokLength (6);
-
- if (processMacro ()) {
- if (context_inIterDef ())
- {
- RETURN_TOK (LLMACROITER);
- }
- if (context_inIterEnd ())
- {
- RETURN_TOK (LLMACROEND);
- }
- if (context_inMacro ())
- {
- RETURN_TOK (LLMACRO);
- }
- }
- }
-"@QLMR" { if (context_inHeader () || context_inFunction ())
- {
- handleMacro ();
- }
- else
- {
- int nspchar = ninput ();
- int nspaces;
-
- /*
- ** This is a hack to get the column number correct.
- */
-
- llassert (nspchar >= '0' && nspchar <= '9');
-
- nspaces = nspchar - '0';
-
- setTokLength (5 + nspaces);
-
- if (processMacro ())
- {
- if (context_inIterDef ())
- {
- RETURN_TOK (LLMACROITER);
- }
- if (context_inIterEnd ())
- {
- RETURN_TOK (LLMACROEND);
- }
- if (context_inMacro ())
- {
- RETURN_TOK (LLMACRO);
- }
- }
- }
- }
-"@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }
-"@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }
-"@.F" { setTokLength (3);
- lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));
- }
-"@.L" { setTokLength (3); usymtab_printLocal (); }
-"@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }
-"@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }
-"@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }
-"@.G" { setTokLength (3); usymtab_printGuards (); }
-"@.S" { setTokLength (3); usymtab_printOut (); }
-"@.X" { setTokLength (3); usymtab_printAll (); }
-"@.Z" { setTokLength (3); usymtab_printComplete (); }
-"@.T" { setTokLength (3); usymtab_printTypes (); }
-"@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }
-"@.M" { setTokLength (3);
- lldiagmsg (message ("Can modify: %q",
- sRefSet_unparse (context_modList ())));
- }
-"%{" { /* BEFORE_COMMENT_MARKER */
- int tok;
- incColumn (); incColumn ();
- tok = handleLlSpecial ();
-
- if (tok != BADTOK)
- {
- if (tok == CANNOTATION) {
- return (tok);
- } else {
- /* Beware - this bashes yylval! */
- RETURN_TOK (tok);
- }
- }
- }
-"%}" { /* AFTER_COMMENT_MARKER */
- setTokLength (2);
- inSpecPart = FALSE;
- RETURN_TOK (QENDMACRO); }
-"\\" { incColumn (); continueLine = TRUE; }
-. { incColumn ();
- if ((int) *yytext == 13 ) {
- ;
- } else {
- voptgenerror
- (FLG_SYNTAX,
- message ("Invalid character (ascii: %d), skipping character",
- (int)(*yytext)),
- g_currentloc);
- }
- }
-%%
-
-struct skeyword
-{
- /*@null@*/ /*@observer@*/ char *name;
- int token;
-} ;
-
-/*
-** These tokens are followed by syntax that is parsed by the
-** grammar proper.
-*/
-
-struct skeyword s_parsetable[] = {
- { "modifies", QMODIFIES } ,
- { "globals", QGLOBALS } ,
- { "alt", QALT } ,
- { "warn", QWARN } ,
- { "constant", QCONSTANT } ,
- { "function", QFUNCTION } ,
- { "iter", QITER } ,
- { "defines", QDEFINES } ,
- { "uses", QUSES } ,
- { "allocates", QALLOCATES } ,
- { "sets", QSETS } ,
- { "releases", QRELEASES } ,
- { "pre", QPRECLAUSE } ,
- { "post", QPOSTCLAUSE } ,
- { "setBufferSize", QSETBUFFERSIZE},
- { "setStringLength", QSETSTRINGLENGTH},
- { "testinRange", QTESTINRANGE},
- { "requires", QPRECLAUSE } ,
- { "ensures", QPOSTCLAUSE } ,
- { NULL, BADTOK }
-} ;
-
-/*
-** These tokens are either stand-alone tokens, or followed by
-** token-specific text.
-*/
-
-struct skeyword s_keytable[] = {
- { "anytype", QANYTYPE } ,
- { "integraltype", QINTEGRALTYPE } ,
- { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,
- { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,
- { "out", QOUT } ,
- { "in", QIN } ,
- { "only", QONLY } ,
- { "owned", QOWNED } ,
- { "dependent", QDEPENDENT } ,
- { "partial", QPARTIAL } ,
- { "special", QSPECIAL } ,
- { "truenull", QTRUENULL } ,
- { "falsenull", QFALSENULL } ,
- { "keep", QKEEP } ,
- { "kept", QKEPT } ,
- { "notnull", QNOTNULL } ,
- { "abstract", QABSTRACT } ,
- { "concrete", QCONCRETE } ,
- { "mutable", QMUTABLE } ,
- { "immutable", QIMMUTABLE } ,
- { "unused", QUNUSED } ,
- { "external", QEXTERNAL } ,
- { "sef", QSEF } ,
- { "unique", QUNIQUE } ,
- { "returned", QRETURNED } ,
- { "exposed", QEXPOSED } ,
- { "refcounted", QREFCOUNTED } ,
- { "refs", QREFS } ,
- { "newref", QNEWREF } ,
- { "tempref", QTEMPREF } ,
- { "killref", QKILLREF } ,
- { "null", QNULL } ,
- { "relnull", QRELNULL } ,
- { "nullterminated", QNULLTERMINATED },
- { "setBufferSize", QSETBUFFERSIZE },
- { "testInRange", QTESTINRANGE},
- { "MaxSet", QMAXSET},
- { "MaxRead", QMAXREAD},
- { "reldef", QRELDEF } ,
- { "observer", QOBSERVER } ,
- { "exits", QEXITS } ,
- { "mayexit", QMAYEXIT } ,
- { "trueexit", QTRUEEXIT } ,
- { "falseexit", QFALSEEXIT } ,
- { "neverexit", QNEVEREXIT } ,
- { "temp", QTEMP } ,
- { "shared", QSHARED } ,
- { "ref", QREF } ,
- { "unchecked", QUNCHECKED } ,
- { "checked", QCHECKED } ,
- { "checkmod", QCHECKMOD } ,
- { "checkedstrict", QCHECKEDSTRICT } ,
- { "innercontinue", QINNERCONTINUE } ,
- { "innerbreak", QINNERBREAK } ,
- { "loopbreak", QLOOPBREAK } ,
- { "switchbreak", QSWITCHBREAK } ,
- { "safebreak", QSAFEBREAK } ,
- { "fallthrough", QFALLTHROUGH } ,
- { "l_fallthrou", QLINTFALLTHROUGH } ,
- { "l_fallth", QLINTFALLTHRU } ,
- { "notreached", QNOTREACHED } ,
- { "l_notreach", QLINTNOTREACHED } ,
- { "printflike", QPRINTFLIKE } ,
- { "l_printfli", QLINTPRINTFLIKE } ,
- { "scanflike", QSCANFLIKE } ,
- { "messagelike", QMESSAGELIKE } ,
- { "l_argsus", QARGSUSED } ,
- { NULL, BADTOK }
-} ;
-
-/*
-** would be better if these weren't hard coded...
-*/
-
-static bool isArtificial (cstring s)
-{
- return (cstring_equalLit (s, "modifies")
- || cstring_equalLit (s, "globals")
- || cstring_equalLit (s, "warn")
- || cstring_equalLit (s, "alt"));
-}
-
-void swallowMacro (void)
-{
- int i;
- bool skipnext = FALSE;
-
- while ((i = lminput ()) != EOF)
- {
- char c = (char) i;
-
-
- if (c == '\\')
- {
- skipnext = TRUE;
- }
- else if (c == '\n')
- {
- if (skipnext)
- {
- skipnext = FALSE;
- }
- else
- {
- reader_checkUngetc (i, yyin);
- return;
- }
- }
- }
-
- if (i != EOF)
- {
- reader_checkUngetc (i, yyin);
- }
-}
-
-static int commentMarkerToken (cstring s)
-{
- int i = 0;
-
- while (s_parsetable[i].name != NULL)
- {
- DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));
-
- if (cstring_equalLit (s, s_parsetable[i].name))
- {
- return s_parsetable[i].token;
- }
-
- i++;
- }
-
- return BADTOK;
-}
-
-static int tokenMacroCode (cstring s)
-{
- int i = 0;
-
- while (s_keytable[i].name != NULL)
- {
- if (cstring_equalLit (s, s_keytable[i].name))
- {
- if (s_keytable[i].token == QLINTFALLTHROUGH)
- {
- voptgenerror
- (FLG_WARNLINTCOMMENTS,
- cstring_makeLiteral
- ("Traditional lint comment /*FALLTHROUGH*/ used. "
- "This is interpreted by "
- "LCLint in the same way as most Unix lints, but it is "
- "preferable to replace it with the /*@fallthrough@*/ "
- "semantic comment"),
- g_currentloc);
- return QFALLTHROUGH;
- }
- else if (s_keytable[i].token == QLINTFALLTHRU)
- {
- voptgenerror
- (FLG_WARNLINTCOMMENTS,
- cstring_makeLiteral
- ("Traditional lint comment /*FALLTHRU*/ used. "
- "This is interpreted by "
- "LCLint in the same way as most Unix lints, but it is "
- "preferable to replace it with the /*@fallthrough@*/ "
- "semantic comment"),
- g_currentloc);
- return QFALLTHROUGH;
- }
- else if (s_keytable[i].token == QLINTNOTREACHED)
- {
- voptgenerror
- (FLG_WARNLINTCOMMENTS,
- cstring_makeLiteral
- ("Traditional lint comment /*NOTREACHED*/ used. "
- "This is interpreted by "
- "LCLint in the same way as most Unix lints, but it is "
- "preferable to replace it with the /*@notreached@*/ "
- "semantic comment."),
- g_currentloc);
-
- return QNOTREACHED;
- }
- else if (s_keytable[i].token == QPRINTFLIKE)
- {
- setSpecialFunction (qual_createPrintfLike ());
- return SKIPTOK;
- }
- else if (s_keytable[i].token == QLINTPRINTFLIKE)
- {
- voptgenerror
- (FLG_WARNLINTCOMMENTS,
- cstring_makeLiteral
- ("Traditional lint comment /*PRINTFLIKE*/ used. "
- "This is interpreted by "
- "LCLint in the same way as most Unix lints, but it is "
- "preferable to replace it with either /*@printflike@*/, "
- "/*@scanflike@*/ or /*@messagelike@*/."),
- g_currentloc);
-
- setSpecialFunction (qual_createPrintfLike ());
- return SKIPTOK;
- }
- else if (s_keytable[i].token == QSCANFLIKE)
- {
- setSpecialFunction (qual_createScanfLike ());
- return SKIPTOK;
- }
- else if (s_keytable[i].token == QMESSAGELIKE)
- {
- setSpecialFunction (qual_createMessageLike ());
- return SKIPTOK;
- }
- else if (s_keytable[i].token == QARGSUSED)
- {
- voptgenerror
- (FLG_WARNLINTCOMMENTS,
- cstring_makeLiteral
- ("Traditional lint comment /*ARGSUSED*/ used. "
- "This is interpreted by "
- "LCLint in the same way as most Unix lints, but it is "
- "preferable to use /*@unused@*/ annotations on "
- "the unused parameters."),
- g_currentloc);
-
- setArgsUsed ();
- return SKIPTOK;
- }
-
- return s_keytable[i].token;
- }
-
- i++;
- }
-
- return BADTOK;
-}
-
-static int lminput ()
-{
- if (savechar == '\0')
- {
- incColumn ();
- return (input ());
- }
- else
- {
- int save = (int) savechar;
- savechar = '\0';
- return save;
- }
-}
-
-static void lmsavechar (char c)
-{
- if (savechar == '\0') savechar = c;
- else
- {
- llbuglit ("lmsavechar: override");
- }
-}
-
-static int returnFloat (ctype ct, double f)
-{
- yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext),
- fileloc_decColumn (g_currentloc, tokLength));
- tokLength = 0;
- return (CCONSTANT);
-}
-
-static int returnInt (ctype ct, long i)
-{
- ctype c = ct;
-
- if (ctype_equal (ct, ctype_int))
- {
- if (i == 0)
- {
- c = context_typeofZero ();
- }
- else if (i == 1)
- {
- c = context_typeofOne ();
- }
- }
-
- yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext),
- fileloc_decColumn (g_currentloc, tokLength), i);
- tokLength = 0;
- return (CCONSTANT);
-}
-
-static int returnChar (char c)
-{
- yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext),
- fileloc_decColumn (g_currentloc, tokLength));
- tokLength = 0;
- return (CCONSTANT);
-}
-
-static int ninput ()
-{
- int c = lminput ();
-
- if (c != EOF && ((char)c == '\n'))
- {
- context_incLineno ();
- }
-
- return c;
-}
-
-static char macro_nextChar ()
-{
- static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
- int ic;
- char c;
-
- ic = lminput ();
- c = char_fromInt (ic);
-
- if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))
- {
- if (c == '\\')
- {
- while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
- {
- ; /* skip to newline */
- }
-
- context_incLineno ();
-
- if (c != '\0')
- {
- return macro_nextChar ();
- }
- else
- {
- return c;
- }
- }
- else /* if (c == '@') */
- {
- llassert (FALSE); /*@i23@*/
- if (handleLlSpecial () != BADTOK)
- {
- llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");
- }
-
- return macro_nextChar ();
- }
- }
- else if (!in_escape && c == '\"')
- {
- in_quote = !in_quote;
- }
- else if (!in_escape && c == '\'')
- {
- in_char = !in_char;
- }
- else if ((in_quote || in_char) && c == '\\')
- {
- in_escape = !in_escape;
- }
- else if ((in_quote || in_char) && in_escape)
- {
- in_escape = FALSE;
- }
- else if (!in_quote && c == '/')
- {
- char c2;
-
- if ((c2 = char_fromInt (lminput ())) == '*')
- {
- while (c2 != '\0')
- {
- while ((c2 = char_fromInt (lminput ())) != '\0'
- && c2 != '\n' && c2 != '*')
- {
- ;
- }
-
- if (c2 == '*')
- {
- while ((c2 = char_fromInt (lminput ())) != '\0'
- && c2 == '*')
- {
- ;
- }
-
- if (c2 == '/')
- {
- goto outofcomment;
- }
- }
- else
- {
- llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
- }
- }
- outofcomment:
- return macro_nextChar ();
- }
- else
- {
- /*** putchar does not work! why? puts to stdio...??! ***/
- lmsavechar (c2);
- }
- }
- return c;
-}
-
-/*
-** keeps semantic comments
-*/
-
-static char macro_nextCharC ()
-{
- static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;
- char c;
-
- c = char_fromInt (lminput ());
-
- if (!in_quote && !in_char && c == '\\')
- {
- while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')
- {
- ; /* skip to newline */
- }
-
- context_incLineno ();
-
- if (c != '\0')
- {
- return macro_nextCharC ();
- }
- else
- {
- return c;
- }
- }
- else if (!in_escape && c == '\"')
- {
- in_quote = !in_quote;
- }
- else if (!in_escape && c == '\'')
- {
- in_char = !in_char;
- }
- else if ((in_quote || in_char) && c == '\\')
- {
- in_escape = !in_escape;
- }
- else if ((in_quote || in_char) && in_escape)
- {
- in_escape = FALSE;
- }
- else if (!in_quote && c == '/')
- {
- char c2;
-
- if ((c2 = char_fromInt (lminput ())) == '*')
- {
- while (c2 != '\0')
- {
- while ((c2 = char_fromInt (lminput ())) != '\0'
- && c2 != '\n' && c2 != '*')
- {
- ;
- }
-
- if (c2 == '*')
- {
- while ((c2 = char_fromInt (lminput ())) != '\0'
- && c2 == '*')
- {
- ;
- }
-
- if (c2 == '/')
- {
- goto outofcomment;
- }
- }
- else
- {
- llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));
- }
- }
- outofcomment:
- return macro_nextCharC ();
- }
- else
- {
- lmsavechar (c2);
- }
- }
- return c;
-}
-
-/*
-** skips whitespace (handles line continuations)
-** returns first non-whitespace character
-*/
-
-static char skip_whitespace ()
-{
- char c;
-
- while ((c = macro_nextChar ()) == ' ' || c == '\t')
- {
- ;
- }
-
- return c;
-}
-
-static void handleMacro ()
-{
- cstring mac = cstring_undefined;
- int macrocode;
- char c;
-
- while (currentColumn () > 2)
- {
- mac = cstring_appendChar (mac, ' ');
- setTokLength (-1);
- }
-
- c = macro_nextCharC ();
-
- if (c >= '0' && c <= '9')
- {
- int i;
-
- for (i = 0; i < ((c - '0') + 1); i++)
- {
- mac = cstring_appendChar (mac, ' ');
- }
- }
- else
- {
- BADBRANCH;
- }
-
- while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))
- {
- mac = cstring_appendChar (mac, c);
- }
-
-
- macrocode = tokenMacroCode (mac);
-
- if (macrocode == BADTOK && !isArtificial (mac))
- {
- context_addMacroCache (mac);
- }
- else
- {
- cstring_free (mac);
- }
-
- if (c == '\n')
- {
- context_incLineno ();
- }
-}
-
-static bool processMacro (void)
-{
- uentry e2;
- ctype ct;
- int noparams = 0;
- cstring fname = cstring_undefined;
- bool res = TRUE;
- bool isspecfcn = FALSE;
- bool isiter = FALSE;
- bool skipparam = FALSE;
- bool isenditer = FALSE;
- bool unknownm = FALSE;
- bool hasParams = FALSE;
- bool emptyMacro = FALSE;
- char c = skip_whitespace ();
- fileloc loc = fileloc_noColumn (g_currentloc);
-
- /* are both of these necessary? what do they mean? */
- uentryList specparams = uentryList_undefined;
- uentryList pn = uentryList_undefined;
-
- context_resetMacroMissingParams ();
-
- if (c == '\0' || c == '\n')
- {
- llcontbug (cstring_makeLiteral ("Bad macro"));
- fileloc_free (loc);
- return FALSE;
- }
-
- fname = cstring_appendChar (fname, c);
-
- while ((c = macro_nextChar ()) != '(' && c != '\0'
- && c != ' ' && c != '\t' && c != '\n')
- {
- fname = cstring_appendChar (fname, c);
- }
-
- if (c == ' ' || c == '\t' || c == '\n')
- {
- char oldc = c;
-
- if (c != '\n')
- {
- while (c == ' ' || c == '\t')
- {
- c = macro_nextChar ();
- }
- unput (c);
- }
-
- if (c == '\n')
- {
- emptyMacro = TRUE;
- unput (c);
- }
-
- c = oldc;
- }
-
- hasParams = (c == '(');
-
- if (usymtab_exists (fname))
- {
- e2 = usymtab_lookupExpose (fname);
- ct = uentry_getType (e2);
-
- if (uentry_isCodeDefined (e2)
- && fileloc_isUser (uentry_whereDefined (e2)))
- {
- if (optgenerror
- (FLG_MACROREDEF,
- message ("Macro %s already defined", fname),
- loc))
- {
- uentry_showWhereDefined (e2);
- uentry_clearDefined (e2);
- }
-
- if (uentry_isFunction (e2))
- {
- uentry_setType (e2, ctype_unknown);
- ct = ctype_unknown;
- unknownm = TRUE;
- context_enterUnknownMacro (e2);
- }
- else
- {
- context_enterConstantMacro (e2);
- }
- }
- else
- {
- if (uentry_isForward (e2) && uentry_isFunction (e2))
- {
- unknownm = TRUE;
-
- voptgenerror
- (FLG_MACROFCNDECL,
- message
- ("Parameterized macro has no prototype or specification: %s ",
- fname),
- loc);
-
- ct = ctype_unknown;
- uentry_setType (e2, ctype_unknown);
- uentry_setFunctionDefined (e2, loc);
- uentry_setUsed (e2, fileloc_undefined);
- context_enterUnknownMacro (e2);
- }
- else
- {
- if (uentry_isIter (e2))
- {
- isiter = TRUE;
- specparams = uentry_getParams (e2);
- noparams = uentryList_size (specparams);
- uentry_setDefined (e2, loc);
- context_enterIterDef (e2);
- }
- else if (uentry_isEndIter (e2))
- {
- isenditer = TRUE;
- uentry_setDefined (e2, loc);
- context_enterIterEnd (e2); /* don't care about it now */
- /* but should parse like an iter! */
- }
- else if (uentry_isConstant (e2))
- {
- if (hasParams)
- {
- voptgenerror
- (FLG_INCONDEFS,
- message ("Constant %s implemented as parameterized macro",
- fname),
- g_currentloc);
-
- uentry_showWhereSpecified (e2);
- uentry_setType (e2, ctype_unknown);
- uentry_makeConstantFunction (e2);
- uentry_setDefined (e2, g_currentloc);
- uentry_setFunctionDefined (e2, g_currentloc);
- context_enterUnknownMacro (e2);
- }
- else
- {
- if (!uentry_isSpecified (e2))
- {
- fileloc oloc = uentry_whereDeclared (e2);
-
- if (fileloc_isLib (oloc))
- {
- ;
- }
- else if (fileloc_isUndefined (oloc)
- || fileloc_isPreproc (oloc))
- {
- if (!emptyMacro)
- {
- voptgenerror
- (FLG_MACROCONSTDECL,
- message
- ("Macro constant %q not declared",
- uentry_getName (e2)),
- loc);
- }
- }
- else if (!fileloc_withinLines (oloc, loc, 2))
- { /* bogus! will give errors if there is too much whitespace */
- voptgenerror
- (FLG_SYNTAX,
- message
- ("Macro constant name %s does not match name in "
- "previous constant declaration. This constant "
- "is declared at %q", fname,
- fileloc_unparse (oloc)),
- loc);
- }
- }
-
- context_enterConstantMacro (e2);
- cstring_free (fname);
- fileloc_free (loc);
- return res;
- }
-
- }
- else if (ctype_isFunction (ct))
- {
- isspecfcn = TRUE;
- specparams = ctype_argsFunction (ct);
- noparams = uentryList_size (specparams);
-
- uentry_setFunctionDefined (e2, loc);
- context_enterMacro (e2);
- }
- else if (uentry_isVar (e2))
- {
- if (hasParams)
- {
- voptgenerror
- (FLG_INCONDEFS,
- message ("Variable %s implemented as parameterized macro",
- fname),
- loc);
-
- uentry_showWhereSpecified (e2);
- uentry_setType (e2, ctype_unknown);
- uentry_makeVarFunction (e2);
- uentry_setDefined (e2, g_currentloc);
- uentry_setFunctionDefined (e2, g_currentloc);
- context_enterUnknownMacro (e2);
- }
- else
- {
- uentry ucons = uentry_makeConstant (fname,
- ctype_unknown,
- loc);
- if (uentry_isExpandedMacro (e2))
- {
- ; /* okay */
- }
- else
- {
- if (optgenerror
- (FLG_INCONDEFS,
- message ("Variable %s implemented by a macro",
- fname),
- loc))
- {
- uentry_showWhereSpecified (e2);
- }
- }
-
- uentry_setDefined (e2, loc);
- uentry_setUsed (ucons, loc);
-
- context_enterConstantMacro (ucons);
- uentry_markOwned (ucons);
- cstring_free (fname);
- return res;
- }
- }
- else
- {
- if (uentry_isDatatype (e2))
- {
- vgenhinterror
- (FLG_SYNTAX,
- message ("Type implemented as macro: %x",
- uentry_getName (e2)),
- message ("A type is implemented using a macro definition. A "
- "typedef should be used instead."),
- g_currentloc);
-
- swallowMacro ();
- /* Must exit scope (not sure why a new scope was entered?) */
- usymtab_quietExitScope (g_currentloc);
- uentry_setDefined (e2, g_currentloc);
- res = FALSE;
- }
- else
- {
- llcontbug
- (message ("Unexpanded macro not function or constant: %q",
- uentry_unparse (e2)));
- uentry_setType (e2, ctype_unknown);
-
- if (hasParams)
- {
- uentry_makeVarFunction (e2);
- uentry_setDefined (e2, g_currentloc);
- uentry_setFunctionDefined (e2, g_currentloc);
- context_enterUnknownMacro (e2);
- }
- }
- }
- }
- }
- }
- else
- {
- uentry ce;
-
- /* evans 2001-09-09 - if it has params, assume a function */
- if (hasParams)
- {
- voptgenerror
- (FLG_MACROMATCHNAME,
- message ("Unexpanded macro %s does not match name of a declared "
- "function. The name used in the control "
- "comment on the previous line should match.",
- fname),
- loc);
-
- ce = uentry_makeFunction (fname, ctype_unknown,
- typeId_invalid,
- globSet_undefined,
- sRefSet_undefined,
- warnClause_undefined,
- fileloc_undefined);
- uentry_setUsed (ce, loc); /* perhaps bogus? */
- e2 = usymtab_supEntryReturn (ce);
- context_enterUnknownMacro (e2);
- }
- else
- {
- voptgenerror
- (FLG_MACROMATCHNAME,
- message ("Unexpanded macro %s does not match name of a constant "
- "or iter declaration. The name used in the control "
- "comment on the previous line should match. "
- "(Assuming macro defines a constant.)",
- fname),
- loc);
-
- ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined);
- uentry_setUsed (ce, loc); /* perhaps bogus? */
- e2 = usymtab_supEntryReturn (ce);
-
- context_enterConstantMacro (e2);
- cstring_free (fname);
- fileloc_free (loc);
- return res;
- }
- }
-
- /* in macros, ( must follow immediatetly after name */
-
- if (hasParams)
- {
- int paramno = 0;
-
- c = skip_whitespace ();
-
- while (c != ')' && c != '\0')
- {
- uentry param;
- bool suppress = context_inSuppressRegion ();
- cstring paramname = cstring_undefined;
-
- /*
- ** save the parameter location
- */
-
- decColumn ();
- context_saveLocation ();
- incColumn ();
-
- while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')
- {
- paramname = cstring_appendChar (paramname, c);
- c = macro_nextChar ();
- }
-
- if (c == ' ' || c == '\t') c = skip_whitespace ();
-
- if (c == ',')
- {
- c = macro_nextChar ();
- if (c == ' ' || c == '\t') c = skip_whitespace ();
- }
-
- if (c == '\0')
- {
- llfatalerror (cstring_makeLiteral
- ("Bad macro syntax: uentryList"));
- }
-
- if ((isspecfcn || isiter) && (paramno < noparams)
- && !uentry_isElipsisMarker (uentryList_getN
- (specparams, paramno)))
- {
- fileloc sloc = context_getSaveLocation ();
- uentry decl = uentryList_getN (specparams, paramno);
- sRef sr;
-
- param = uentry_nameCopy (paramname, decl);
-
- uentry_setParam (param);
- sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc));
-
- if (sRef_getNullState (sr) == NS_ABSNULL)
- {
- ctype pt = ctype_realType (uentry_getType (param));
-
- if (ctype_isUser (pt))
- {
- uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));
-
- if (uentry_isValid (te))
- {
- sRef_setStateFromUentry (sr, te);
- }
- }
- else
- {
- sRef_setNullState (sr, NS_UNKNOWN, sloc);
- }
- }
-
- uentry_setSref (param, sr);
- uentry_setDeclaredForceOnly (param, sloc);
-
- skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));
- }
- else
- {
- fileloc sloc = context_getSaveLocation ();
-
- param = uentry_makeVariableSrefParam
- (paramname, ctype_unknown, fileloc_copy (sloc),
- sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc)));
- DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));
- cstring_free (paramname);
-
- sRef_setPosNull (uentry_getSref (param), sloc);
- uentry_setDeclaredForce (param, sloc);
-
- skipparam = FALSE;
- fileloc_free (sloc);
- }
-
- if (!skipparam)
- {
- llassert (!uentry_isElipsisMarker (param));
-
- if (!suppress)
- {
- sRef_makeUnsafe (uentry_getSref (param));
- }
-
- pn = uentryList_add (pn, uentry_copy (param));
- usymtab_supEntry (param);
- }
- else
- {
- /* don't add param */
- uentry_free (param);
- }
-
- if (c == ',')
- {
- (void) macro_nextChar ();
- c = skip_whitespace ();
- }
-
- paramno++;
- }
-
- if (c == ')')
- {
- if (isspecfcn || isiter)
- {
- if (paramno != noparams && noparams >= 0)
- {
- advanceLine ();
-
- voptgenerror
- (FLG_INCONDEFS,
- message ("Macro %s specified with %d args, defined with %d",
- fname, noparams, paramno),
- g_currentloc);
-
- uentry_showWhereSpecified (e2);
- uentry_resetParams (e2, pn);
- }
- }
- else
- {
- uentry_resetParams (e2, pn);
- }
- }
- }
- else
- {
- /*
- ** the form should be:
- **
- ** # define newname oldname
- ** where oldname refers to a function matching the specification
- ** of newname.
- */
-
- if (unknownm)
- {
- sRef_setGlobalScope ();
- usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));
- sRef_clearGlobalScope ();
- }
- else
- {
- context_setMacroMissingParams ();
- }
- }
-
-
- /* context_setuentryList (pn); */
- usymtab_enterScope ();
-
- fileloc_free (loc);
- cstring_free (fname);
-
- return res;
-}
-
-static bool handleSpecial (char *yyt)
-{
- char *l = mstring_create (MAX_NAME_LENGTH);
- static bool reportcpp = FALSE;
- int lineno = 0;
- char c;
- char *ol;
- cstring olc;
-
- strcpy (l, yyt + 1);
-
- /* Need to safe original l for deallocating. */
- ol = l;
-
- l += strlen (yyt) - 1;
-
- while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')
- {
- *l++ = c;
- }
-
- *l = '\0';
- olc = cstring_fromChars (ol);
-
- if (cstring_equalPrefixLit (olc, "pragma"))
- {
- char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));
- char *opname = pname;
- char *ptr = ol + 6; /* pragma is six characters, plus space */
- int len = 0;
-
-
- /* skip whitespace */
- while (((c = *ptr) != '\0') && isspace (c))
- {
- ptr++;
- }
-
-
- while (((c = *ptr) != '\0') && !isspace (c))
- {
- len++;
-
- if (len > MAX_PRAGMA_LEN)
- {
- break;
- }
-
- ptr++;
- *pname++ = c;
- }
-
- *pname = '\0';
-
- if (len == PRAGMA_LEN_EXPAND
- && mstring_equal (opname, PRAGMA_EXPAND))
- {
- cstring exname = cstring_undefined;
- uentry ue;
-
- ptr++;
- while (((c = *ptr) != '\0') && !isspace (c))
- {
- exname = cstring_appendChar (exname, c);
- ptr++;
- }
-
-
- ue = usymtab_lookupExposeGlob (exname);
-
- if (uentry_isExpandedMacro (ue))
- {
- if (fileloc_isPreproc (uentry_whereDefined (ue)))
- {
- fileloc_setColumn (g_currentloc, 1);
- uentry_setDefined (ue, g_currentloc);
- }
- }
-
- cstring_free (exname);
- }
- }
- else if (cstring_equalPrefixLit (olc, "ident"))
- {
- /* Some pre-processors will leave these in the code. Ignore rest of line */
- }
- /*
- ** Yuk...Win32 filenames can have spaces in them...we need to read
- ** to the matching end quote.
- */
- else if ((sscanf (ol, "line %d \"", &lineno) == 1)
- || (sscanf (ol, " %d \"", &lineno) == 1))
- {
- char *tmp = ol;
- cstring fname;
- fileId fid;
-
- /*@access cstring@*/
- while (*tmp != '\"' && *tmp != '\0')
- {
- tmp++;
- }
-
- llassert (*tmp == '\"');
-
- tmp++;
-
- fname = tmp;
-
- while (*tmp != '\"' && *tmp != '\0')
- {
- tmp++;
- }
-
- llassert (*tmp == '\"');
-
- *tmp = '\0';
-
-# if defined(OS2) || defined(MSDOS) || defined(WIN32)
-
- /*
- ** DOS-like path delimiters get delivered in pairs, something like
- ** \"..\\\\file.h\", so we have to make it normal again. We do NOT
- ** remove the pre dirs yet as we usually specify tmp paths relative
- ** to the current directory, so tmp files would not get found in
- ** the hash table. If this method fails we try it again later.
- */
-
- {
- char *stmp = fname;
-
- /*
- ** Skip past the drive marker.
- */
-
- if (strchr (stmp, ':') != NULL)
- {
- stmp = strchr (stmp, ':') + 1;
- }
-
- while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )
- {
- if (*(stmp+1) == CONNECTCHAR)
- {
- memmove (stmp, stmp+1, strlen (stmp));
- }
-
- stmp++;
- }
-
- fid = fileTable_lookupBase (context_fileTable (), fname);
- if (!(fileId_isValid (fid)))
- {
- fname = removePreDirs (fname);
- fid = fileTable_lookupBase (context_fileTable (), fname);
- }
- }
-# else /* !defined(OS2) && !defined(MSDOS) */
- fname = removePreDirs (fname);
- fid = fileTable_lookupBase (context_fileTable (), fname);
-# endif /* !defined(OS2) && !defined(MSDOS) */
-
- if (!(fileId_isValid (fid)))
- {
- if (context_inXHFile ())
- {
- fid = fileTable_addXHFile (context_fileTable (), fname);
- }
- else if (isHeaderFile (fname))
- {
- fid = fileTable_addHeaderFile (context_fileTable (), fname);
- }
- else
- {
- fid = fileTable_addFile (context_fileTable (), fname);
- }
- }
-
- setFileLine (fid, lineno);
- /*@noaccess cstring@*/
- }
- else if ((sscanf (ol, "line %d", &lineno) == 1)
- || (sscanf (ol, " %d", &lineno) == 1))
- {
- setLine (lineno); /* next line is <cr> */
- }
- else
- {
- if (mstring_equal (ol, "")) {
- DPRINTF (("Empty pp command!"));
- /*
- ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.
- ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.
- */
- mstring_free (ol);
- return FALSE;
- } else {
- if (!reportcpp)
- {
-
- } else {
- llbug (message ("File contains preprocessor command: #%s",
- cstring_fromChars (ol)));
- reportcpp = TRUE;
- }
- }
-
- sfree (ol);
- return TRUE;
- }
-
- sfree (ol);
- return FALSE;
-}
-
-static int handleLlSpecial ()
-{
- bool hasnl = FALSE;
- int ic;
- char c;
- char *s = mstring_createEmpty ();
- char *os;
- int tok;
- int charsread = 0;
- fileloc loc;
-
- loc = fileloc_copy (g_currentloc);
- DPRINTF (("Handle special: %s", fileloc_unparse (loc)));
-
- while (((ic = ninput ()) != 0) && isalpha (ic))
- {
- c = (char) ic;
- s = mstring_append (s, c);
- charsread++;
- }
-
- DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
- os = s;
-
- if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])
- {
- ic = ninput ();
-
- llassert (ic == AFTER_COMMENT_MARKER[1]);
-
- if (*s == '\0')
- {
- sfree (os);
- fileloc_free (loc);
- return QNOMODS; /* special token no modifications token */
- }
- }
-
- DPRINTF (("Coment marker: %s", os));
- tok = commentMarkerToken (cstring_fromChars (os));
-
- if (tok != BADTOK)
- {
- tokLength = charsread;
- sfree (os);
- inSpecPart = TRUE;
- fileloc_free (loc);
- return tok;
- }
-
- DPRINTF (("Not a comment marker..."));
- /* Add rest of the comment */
-
- if (ic != 0 && ic != EOF)
- {
- c = (char) ic;
-
- s = mstring_append (s, c);
- charsread++;
-
- while (((ic = ninput ()) != 0) && (ic != EOF)
- && (ic != AFTER_COMMENT_MARKER[0]))
- {
- c = (char) ic;
-
- /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */
-
- if (c == '\n') {
- hasnl = TRUE; /* This prevents tokLength from being set later. */
- tokLength = 0;
-
- voptgenerror
- (FLG_SYNTAX,
- message ("Likely parse error: syntactic comment token spans multiple lines: %s",
- cstring_fromChars (s)),
- g_currentloc);
- }
-
- s = mstring_append (s, c);
- charsread++;
- }
- }
-
- DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));
-
- if (ic == AFTER_COMMENT_MARKER[0])
- {
- int nc = ninput ();
- llassert ((char) nc == AFTER_COMMENT_MARKER[1]);
- charsread++;
- }
-
- os = s;
-
- while (*s == ' ' || *s == '\t' || *s == '\n')
- {
- s++;
- }
-
- if (*s == '-' || *s == '+' || *s == '=') /* setting flags */
- {
- c = *s;
-
- while (c == '-' || c == '+' || c == '=')
- {
- ynm set = ynm_fromCodeChar (c);
- cstring thisflag;
-
- s++;
-
- thisflag = cstring_fromChars (s);
-
- while ((c = *s) != '\0' && (c != '-') && (c != '=')
- && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))
- {
- s++;
- }
-
- *s = '\0';
-
- if (!context_getFlag (FLG_NOCOMMENTS))
- {
- cstring flagname = thisflag;
- flagcode fflag = identifyFlag (flagname);
-
- if (flagcode_isSkip (fflag))
- {
- ;
- }
- else if (flagcode_isInvalid (fflag))
- {
- if (isMode (flagname))
- {
- if (ynm_isMaybe (set))
- {
- llerror
- (FLG_BADFLAG,
- message
- ("Semantic comment attempts to restore flag %s. "
- "A mode flag cannot be restored.",
- flagname));
- }
- else
- {
- context_setMode (flagname);
- }
- }
- else
- {
- voptgenerror
- (FLG_UNRECOGFLAGCOMMENTS,
- message ("Unrecognized option in semantic comment: %s",
- flagname),
- g_currentloc);
- }
- }
- else if (flagcode_isGlobalFlag (fflag))
- {
- voptgenerror
- (FLG_BADFLAG,
- message
- ("Semantic comment attempts to set global flag %s. "
- "A global flag cannot be set locally.",
- flagname),
- g_currentloc);
- }
- else
- {
- context_fileSetFlag (fflag, set);
-
- if (flagcode_hasArgument (fflag))
- {
- if (ynm_isMaybe (set))
- {
- voptgenerror
- (FLG_BADFLAG,
- message
- ("Semantic comment attempts to restore flag %s. "
- "A flag for setting a value cannot be restored.",
- flagname),
- g_currentloc);
- }
- else
- { /* cut-and-pastied from llmain...blecch */
- cstring extra = cstring_undefined;
- char *rest;
- char *orest;
- char rchar;
-
- *s = c;
- rest = mstring_copy (s);
- orest = rest;
- *s = '\0';
-
- while ((rchar = *rest) != '\0'
- && (isspace (rchar)))
- {
- rest++;
- s++;
- }
-
- while ((rchar = *rest) != '\0'
- && !isspace (rchar))
- {
- extra = cstring_appendChar (extra, rchar);
- rest++;
- s++;
- }
-
- sfree (orest);
-
- if (cstring_isUndefined (extra))
- {
- llerror
- (FLG_BADFLAG,
- message
- ("Flag %s (in semantic comment) must be followed by an argument",
- flagcode_unparse (fflag)));
- }
- else
- {
- s--;
-
- if (flagcode_hasValue (fflag))
- {
- setValueFlag (fflag, extra);
- }
- else if (flagcode_hasString (fflag))
- {
- setStringFlag (fflag, extra);
- }
- else
- {
- BADEXIT;
- }
- }
- }
- }
- }
- }
- else
- {
- ;
- }
-
- *s = c;
- while ((c == ' ') || (c == '\t') || (c == '\n'))
- {
- c = *(++s);
- }
- }
-
- if (context_inHeader () && !isArtificial (cstring_fromChars (os)))
- {
- DPRINTF (("Here adding comment: %s", os));
- context_addComment (cstring_fromCharsNew (os));
- }
- else
- {
- ;
- }
- }
- else
- {
- char *t = s;
- int macrocode;
- char tchar = '\0';
- annotationInfo ainfo;
-
- while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n')
- {
- s++;
- }
-
- if (*s != '\0')
- {
- tchar = *s;
- *s = '\0';
- s++;
- }
-
- t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));
- macrocode = tokenMacroCode (cstring_fromChars (t));
-
- if (macrocode != BADTOK)
- {
- tokLength = hasnl ? 0 : mstring_length (t);
-
- sfree (t);
- sfree (os);
- fileloc_free (loc);
-
- if (macrocode == SKIPTOK)
- {
- return BADTOK;
- }
-
- return macrocode;
- }
-
- ainfo = context_lookupAnnotation (cstring_fromChars (os));
-
- if (annotationInfo_isDefined (ainfo)) {
- DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
- /*@i324@*/ yylval.annotation = ainfo;
- tokLength = 0;
- sfree (os);
- sfree (t);
- fileloc_free (loc);
- return CANNOTATION;
- }
-
- if (context_inHeader ())
- {
- if (tchar != '\0')
- {
- *(s-1) = tchar;
- }
-
- if ((context_inMacro () || context_inGlobalContext ())
- && macrocode != SKIPTOK
- && !isArtificial (cstring_fromChars (os)))
- {
- DPRINTF (("Add comment: %s", os));
- context_addComment (cstring_fromCharsNew (os));
- }
- else
- {
- ;
- }
-
- if (tchar != '\0')
- {
- *(s-1) = '\0';
- }
- }
-
- if (mstring_equal (t, "ignore"))
- {
- if (!context_getFlag (FLG_NOCOMMENTS))
- {
- context_enterSuppressRegion ();
- }
- }
- else if ((*t == 'i' || *t == 't')
- && (*(t + 1) == '\0'))
- {
- if (!context_getFlag (FLG_NOCOMMENTS)
- && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))
- {
- context_enterSuppressLine (-1); /* infinite suppression */
- }
- }
- else if (((*t == 'i') || (*t == 't'))
- && ((*(t + 1) >= '0' && *(t + 1) <= '9')))
- {
- bool tmpcomment = (*t == 't');
- int val = -1;
- char *tt = t; /* don't mangle t, since it is free'd */
- char lc = *(++tt);
-
- if (lc >= '0' && lc <= '9')
- {
- val = (int)(lc - '0');
-
- lc = *(++tt);
- while (lc >= '0' && lc <= '9')
- {
- val *= 10;
- val += lc - '0';
- lc = *(++tt);
- }
- }
-
-
- if (!context_getFlag (FLG_NOCOMMENTS)
- && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))
- {
- context_enterSuppressLine (val);
- }
- }
- else if (mstring_equal (t, "end"))
- {
- if (!context_getFlag (FLG_NOCOMMENTS))
- {
- context_exitSuppressRegion ();
- }
- }
- else if (mstring_equal (t, "notfunction"))
- {
- ; /* handled by pcpp */
- }
- else if (mstring_equal (t, "access"))
- {
- cstring tname;
-
- while (TRUE)
- {
- while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))
- {
- s++;
- }
-
- if (c == '\0')
- {
- break;
- }
-
- tname = cstring_fromChars (s);
-
- while ((c = *s) != '\0' && c != ' '
- && c != '\t' && c != '\n' && c != ',')
- {
- s++;
- }
-
- *s = '\0';
-
- DPRINTF (("Access %s", tname));
-
- if (!context_getFlag (FLG_NOCOMMENTS)
- && !context_getFlag (FLG_NOACCESS))
- {
- if (usymtab_existsType (tname))
- {
- typeId uid = usymtab_getTypeId (tname);
- uentry ue = usymtab_getTypeEntry (uid);
-
- if (uentry_isAbstractDatatype (ue))
- {
- context_addFileAccessType (uid);
- DPRINTF (("Adding access to: %s / %d", tname, uid));
- }
- else
- {
- voptgenerror
- (FLG_COMMENTERROR,
- message
- ("Non-abstract type %s used in access comment",
- tname),
- g_currentloc);
- }
- }
- else
- {
- if (!(context_inSuppressRegion ()
- || context_inSuppressZone (g_currentloc)))
- {
- voptgenerror
- (FLG_COMMENTERROR,
- message
- ("Unrecognized type %s used in access comment",
- tname),
- g_currentloc);
- }
- }
- }
-
- if (c != '\0')
- {
- s++;
- }
-
- if (c != ',' && c != ' ')
- {
- break;
- }
- }
- }
- else if (mstring_equal (t, "noaccess"))
- {
- cstring tname;
- char lc;
-
- while (TRUE)
- {
- while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n'))
- {
- s++;
- }
-
- if (lc == '\0')
- {
- break;
- }
-
- tname = cstring_fromChars (s);
-
- while ((lc = *s) != '\0' && lc != ' ' && lc != '\t'
- && lc != '\n' && lc != ',')
- {
- s++;
- }
-
- *s = '\0';
-
- if (!context_getFlag (FLG_NOCOMMENTS)
- && !context_getFlag (FLG_NOACCESS))
- {
- if (usymtab_existsType (tname))
- {
- typeId tuid = usymtab_getTypeId (tname);
-
- if (context_couldHaveAccess (tuid))
- {
- DPRINTF (("Removing access: %s", tname));
- context_removeFileAccessType (tuid);
- }
- else
- {
- if (!(context_inSuppressRegion ()
- || context_inSuppressZone (g_currentloc)))
- {
- uentry ue = usymtab_getTypeEntry (tuid);
-
- if (uentry_isAbstractDatatype (ue))
- {
- voptgenerror
- (FLG_COMMENTERROR,
- message
- ("Non-accessible abstract type %s used in noaccess comment",
- tname),
- g_currentloc);
- }
- else
- {
- voptgenerror
- (FLG_COMMENTERROR,
- message
- ("Non-abstract type %s used in noaccess comment",
- tname),
- g_currentloc);
- }
- }
- }
- }
- else
- {
- if (!(context_inSuppressRegion ()
- || context_inSuppressZone (g_currentloc)))
- {
- voptgenerror
- (FLG_COMMENTERROR,
- message
- ("Unrecognized type %s used in noaccess comment",
- tname),
- g_currentloc);
- }
- }
- }
-
- if (lc != '\0')
- {
- s++;
- }
-
- if (lc != ',' && lc != ' ')
- {
- break;
- }
- }
- }
- else
- {
- voptgenerror (FLG_UNRECOGCOMMENTS,
- message ("Semantic comment unrecognized: %s",
- cstring_fromChars (os)), loc);
- }
-
- sfree (t);
- }
-
- sfree (os);
- fileloc_free (loc);
- return BADTOK;
-}
-
-static /*@only@*/ cstring makeIdentifier (char *s)
-{
- char *c = mstring_create (size_toInt (strlen (s)) + 1);
- cstring id = cstring_fromChars (c);
-
- while (isalnum (*s) || (*s == '_') || (*s == '$'))
- {
- *c++ = *s++;
- }
-
- *c = '\0';
- return (id);
-}
-
-/*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)
-{
- if (!(usymtab_exists (cn)))
- {
- fileloc loc = fileloc_createExternal ();
-
- /*
- ** We need to put this in a global scope, otherwise the sRef will be deallocated.
- */
-
- uentry ce = uentry_makeUnrecognized (cn, loc);
-
- if (!context_inIterEnd ())
- {
- voptgenerror
- (FLG_SYSTEMUNRECOG,
- message ("Unrecognized (possibly system) identifier: %q",
- uentry_getName (ce)),
- g_currentloc);
- }
-
- return ce;
- }
-
- return (usymtab_lookup (cn));
-}
-
-/*
-** like, coerceId, but doesn't supercede for iters
-*/
-
-/*@observer@*/ uentry coerceIterId (cstring cn)
-{
- if (!(usymtab_exists (cn)))
- {
- return uentry_undefined;
- }
-
- return (usymtab_lookup (cn));
-}
-
-/*@observer@*/ cstring LastIdentifier ()
-{
- return (lastidprocessed);
-}
-
-static int processIdentifier (cstring id)
-{
- uentry le;
-
- if (context_getFlag (FLG_GRAMMAR))
- {
- lldiagmsg (message ("Process identifier: %s", id));
- }
-
- context_clearJustPopped ();
- lastidprocessed = id;
-
- if (context_inFunctionHeader ())
- {
- int tok = commentMarkerToken (id);
- DPRINTF (("in function decl..."));
-
- if (tok != BADTOK)
- {
- return tok;
- }
- else
- {
- tok = tokenMacroCode (id);
-
- if (tok != BADTOK)
- {
- return tok;
- }
- else
- {
- annotationInfo ainfo;
-
- if (expectingMetaStateName)
- {
- metaStateInfo msinfo = context_lookupMetaStateInfo (id);
-
- if (metaStateInfo_isDefined (msinfo))
- {
- yylval.msinfo = msinfo;
- return METASTATE_NAME;
- }
- else
- {
- DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));
- }
- }
-
- ainfo = context_lookupAnnotation (id);
-
- if (annotationInfo_isDefined (ainfo))
- {
- DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));
- /*@i324@*/ yylval.annotation = ainfo;
- return CANNOTATION;
- }
- else
- {
- DPRINTF (("Not annotation: %s", id));
- }
- }
- }
- }
-
- /* Consider handling: Defined by C99 as static const char __func__[] */
-
- if (context_getFlag (FLG_GNUEXTENSIONS))
- {
- int tok = BADTOK;
-
- if (cstring_equalLit (id, "__stdcall")
- || cstring_equalLit (id, "__cdecl")
- || cstring_equalLit (id, "__extension__"))
- {
- return BADTOK;
- }
- else if (cstring_equalLit (id, "__volatile__"))
- {
- tok = QVOLATILE;
- }
- else if (cstring_equalLit (id, "__signed"))
- {
- tok = QSIGNED;
- }
- else if (cstring_equalLit (id, "__unsigned"))
- {
- tok = QUNSIGNED;
- }
- else if (cstring_equalLit (id, "__const__"))
- {
- tok = QCONST;
- }
- else if (cstring_equalLit (id, "__alignof__"))
- {
- tok = CALIGNOF; /* alignof is parsed like sizeof */
- }
- else if (cstring_equalLit (id, "__FUNCTION__")
- || cstring_equalLit (id, "__PRETTY_FUNCTION__"))
- {
- /* These tokens hold the name of the current function as strings */
- yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));
- tokLength = 0;
- lastWasString = TRUE;
- tok = CCONSTANT;
- return tok;
- }
- else if (cstring_equalLit (id, "__attribute__")
- || cstring_equalLit (id, "__asm__")
- || cstring_equalLit (id, "_asm")
- || cstring_equalLit (id, "__asm")
- || cstring_equalLit (id, "__declspec"))
- {
- int depth = 0;
- bool useparens = FALSE;
- bool usebraces = FALSE;
- bool inquote = FALSE;
- bool inescape = FALSE;
- int ic;
-
- while ((ic = input ()) != EOF)
- {
-
- if (inescape)
- {
- inescape = FALSE;
- }
- else if (ic == '\\')
- {
- inescape = TRUE;
- }
- else if (ic == '\"')
- {
- inquote = !inquote;
- }
- else if (!inquote)
- {
- if (ic == '(')
- {
- if (!useparens)
- {
- if (!usebraces)
- {
- useparens = TRUE;
- }
- }
-
- if (useparens)
- {
- depth++;
- }
- }
- else if (ic == '{')
- {
- if (!usebraces)
- {
- if (!useparens)
- {
- usebraces = TRUE;
- }
- }
-
- if (usebraces)
- {
- depth++;
- }
- }
- else if (ic == ')' && useparens)
- {
- depth--;
- if (depth == 0) break;
- }
- else if (ic == '}' && usebraces)
- {
- depth--;
- if (depth == 0) break;
- }
- else if (ic == '}'
- && !usebraces && !useparens
- && cstring_equalLit (id, "__asm"))
- {
- /*
- ** We need this because some MS VC++ include files
- ** have __asm mov ... }
- ** Its a kludge, but otherwise would need to parse
- ** the asm code!
- */
- return TRBRACE;
- }
- }
-
- if (ic == '\n')
- {
- context_incLineno ();
-
- if (cstring_equalLit (id, "__asm")
- && !useparens && !usebraces)
- {
- break;
- }
- }
- }
-
- llassert ((useparens && ic == ')')
- || (usebraces && ic == '}')
- || (!useparens && !usebraces));
-
- return BADTOK;
- }
- else if (cstring_equalLit (id, "inline")
- || cstring_equalLit (id, "__inline")
- || cstring_equalLit (id, "_inline")
- || cstring_equalLit (id, "__inline__"))
- {
- tok = QINLINE;
- }
-
- if (tok != BADTOK)
- {
- RETURN_TOK (tok);
- }
- }
-
- le = usymtab_lookupSafe (id);
-
- /*@-dependenttrans@*/
-
- if (uentry_isIter (le))
- {
- /*@i32@*/ yylval.entry = le;
- return (ITER_NAME);
- }
- else if (uentry_isEndIter (le))
- {
- /*@i32@*/ yylval.entry = le;
- return (ITER_ENDNAME);
- }
- else if (uentry_isUndefined (le))
- {
- yylval.cname = id;
-
- /* avoid parse errors for certain system built ins */
-
- if (g_expectingTypeName && (cstring_firstChar (id) == '_')
- && (cstring_secondChar (id) == '_'))
- {
- return (TYPE_NAME_OR_ID);
- }
-
- return (NEW_IDENTIFIER);
- }
- else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))
- {
- if (uentry_isDatatype (le))
- {
- yylval.cname = id;
- return (NEW_IDENTIFIER);
- }
- else
- {
- /*@i32@*/ yylval.entry = le;
- return (IDENTIFIER);
- }
- }
- else if (uentry_isDatatype (le))
- {
- if (!g_expectingTypeName)
- {
- yylval.cname = id;
-
- return (NEW_IDENTIFIER);
- }
- else
- {
- yylval.ctyp = uentry_getAbstractType (le);
-
- uentry_setUsed (le, g_currentloc);
- return (TYPE_NAME);
- }
- }
- else
- {
- /*@i32@*/ yylval.entry = le;
- return (IDENTIFIER);
- }
-
- /*@=dependenttrans@*/
-}
-
-static bool processHashIdentifier (/*@only@*/ cstring id)
-{
- if (context_inMacro () || context_inIterDef () ||
- context_inIterEnd ())
- {
- uentry le;
-
- context_clearJustPopped ();
-
- lastidprocessed = id;
- le = usymtab_lookupSafe (id);
-
- if (uentry_isParam (le) || uentry_isRefParam (le))
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- else
- {
- cstring_free (id);
- return FALSE;
- }
-}
-
-
-static /*@only@*/ exprNode processString ()
-{
- exprNode res;
- fileloc loc;
- char *nl = strchr (yytext, '\n');
- cstring ns = cstring_fromCharsNew (yytext);
-
- if (nl == NULL)
- {
- loc = fileloc_copy (g_currentloc);
- addColumn (cstring_length (ns));
- }
- else
- {
- char *lastnl = nl;
-
- loc = fileloc_copy (g_currentloc);
-
- context_incLineno ();
-
- while ((nl = strchr ((nl + 1), '\n')) != NULL)
- {
- context_incLineno ();
- lastnl = nl;
- }
- }
-
-
- res = exprNode_stringLiteral (ns, loc);
- return (res);
-}
-
-static
-char processChar ()
-{
- char fchar;
- char next;
-
- llassert (*yytext != '\0');
- fchar = *(yytext + 1);
- if (fchar != '\\') return fchar;
-
- next = *(yytext + 2);
-
- switch (next)
- {
- case 'n': return '\n';
- case 't': return '\t';
- case '\"': return '\"';
- case '\'': return '\'';
- case '\\': return '\\';
- default: return '\0';
- }
-}
-
-static
-double processFloat ()
-{
- double ret = atof (yytext);
-
- return (ret);
-}
-
-static
-long processHex ()
-{
- int index = 2;
- long val = 0;
-
- llassert (yytext[0] == '0'
- && (yytext[1] == 'X' || yytext[1] == 'x'));
-
- while (yytext[index] != '\0') {
- int tval;
- char c = yytext[index];
-
- if (c >= '0' && c <= '9') {
- tval = (int) c - (int) '0';
- } else if (c >= 'A' && c <= 'F') {
- tval = (int) c - (int) 'A' + 10;
- } else if (c >= 'a' && c <= 'f') {
- tval = (int) c - (int) 'a' + 10;
- } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
- index++;
- while (yytext[index] != '\0') {
- if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {
- ;
- } else {
- voptgenerror
- (FLG_SYNTAX,
- message ("Invalid character (%c) following specifier in hex constant: %s",
- c, cstring_fromChars (yytext)),
- g_currentloc);
- }
- index++;
- }
-
- break;
- } else {
- voptgenerror
- (FLG_SYNTAX,
- message ("Invalid character (%c) in hex constant: %s",
- c, cstring_fromChars (yytext)),
- g_currentloc);
- break;
- }
-
- val = (val * 16) + tval;
- index++;
- }
-
- DPRINTF (("Hex constant: %s = %ld", yytext, val));
- return val;
-}
-
-static
-long processOctal ()
-{
- int index = 1;
- long val = 0;
-
- llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');
-
- while (yytext[index] != '\0') {
- int tval;
- char c = yytext[index];
-
- if (c >= '0' && c <= '7') {
- tval = (int) c - (int) '0';
- } else {
- voptgenerror
- (FLG_SYNTAX,
- message ("Invalid character (%c) in octal constant: %s",
- c, cstring_fromChars (yytext)),
- g_currentloc);
- break;
- }
-
- val = (val * 8) + tval;
- index++;
- }
-
- DPRINTF (("Octal constant: %s = %ld", yytext, val));
- return val;
-}
-
-static
-long processDec ()
-{
- return (atol (yytext));
-}
-
-static int
-processSpec (int tok)
-{
- size_t length = strlen (yytext);
-
- if (inSpecPart)
- {
- setTokLengthT (length);
- RETURN_TOK (tok);
- }
- else
- {
-
- context_saveLocation ();
- setTokLengthT (length);
- return (processIdentifier (makeIdentifier (yytext)));
- }
-}
-
-void cscanner_expectingMetaStateName ()
-{
- llassert (!expectingMetaStateName);
- llassert (context_inFunctionHeader ());
- expectingMetaStateName = TRUE;
-}
-
-void cscanner_clearExpectingMetaStateName ()
-{
- llassert (expectingMetaStateName);
- expectingMetaStateName = FALSE;
-}
+/*;-*-C-*-; \r
+** Copyright (c) Massachusetts Institute of Technology 1994-1998.\r
+** All Rights Reserved.\r
+** Unpublished rights reserved under the copyright laws of\r
+** the United States.\r
+**\r
+** THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED\r
+** OR IMPLIED. ANY USE IS AT YOUR OWN RISK.\r
+**\r
+** This code is distributed freely and may be used freely under the \r
+** following conditions:\r
+**\r
+** 1. This notice may not be removed or altered.\r
+**\r
+** 2. Works derived from this code are not distributed for\r
+** commercial gain without explicit permission from MIT \r
+** (for permission contact lclint-request@sds.lcs.mit.edu).\r
+*/\r
+/*\r
+ * Modified by Herbert 08/19/97:\r
+ * - added #include for IBM's OS/2 compiler.\r
+ * - fixed weird bug with lookup of tmp files (OS/2 and MSDOS only).\r
+ */\r
+\r
+/*\r
+ * Modified by Mike Smith \r
+ * Corrected missing 'line' in scanf() calls in handleSpecial().\r
+ * Without this, I get an error when LCLint hits a '#line' directive\r
+ * in the pre-pre-processed source files. For safety, I have made these\r
+ * conditional on OS2 and MSDOS because I don't understand why noone else\r
+ * has seen this problem.\r
+ *\r
+ * Modified by Mike Smith, 4th June 1997\r
+ * Finally resolved the #line problem. The scanf() calls have been fixed to\r
+ * allow the following #line forms:-\r
+ *\r
+ * #line 123 "filename"\r
+ * #line 123\r
+ * # 123 "filename"\r
+ * # 123\r
+ *\r
+ * The last two are generated by the GNU pre-processor, apparently\r
+ */\r
+\r
+Digit [0-9]\r
+Letter [a-zA-Z_$]\r
+H [a-fA-F0-9]\r
+E [Ee][+-]?{Digit}+\r
+U (u|U)\r
+L (l|L)\r
+FS (f|F|l|L)\r
+IS (u|U|l|L)*\r
+ULSuffix ({U}{L}|{L}{U})\r
+\r
+%{\r
+/*\r
+** based on original C lexer by Nate Osgood\r
+** from hacrat@catfish.lcs.mit.edu Mon Jun 14 13:06:32 1993\r
+**\r
+*/\r
+\r
+# include "lclintMacros.nf"\r
+# if defined(OS2) && defined(__IBMC__)\r
+ /* needed for isatty()... */\r
+# include <io.h>\r
+# else\r
+# include <unistd.h>\r
+# endif\r
+\r
+# include "basic.h"\r
+\r
+# include "cgrammar.h"\r
+# include "cgrammar_tokens.h"\r
+\r
+# include "fileIdList.h"\r
+# include "portab.h"\r
+\r
+static bool lastWasString = FALSE;\r
+static char savechar = '\0';\r
+\r
+/*@notfunction@*/\r
+# define yyinput() (incColumn (), getc (yyin))\r
+\r
+static /*@owned@*/ cstring lastidprocessed = cstring_undefined;\r
+static int lminput (void);\r
+static int tokLength = 0;\r
+static bool inSpecPart = FALSE;\r
+static bool continueLine = FALSE;\r
+\r
+static int ninput (void);\r
+static char processChar (void);\r
+static double processFloat (void);\r
+static /*@only@*/ exprNode processString (void);\r
+static long processDec (void);\r
+static long processHex (void);\r
+static long processOctal (void);\r
+static int processIdentifier (/*@only@*/ cstring)\r
+ /*@globals undef lastidprocessed@*/ ;\r
+static bool processHashIdentifier (/*@only@*/ cstring)\r
+ /*@globals undef lastidprocessed@*/ ;\r
+\r
+static int processSpec (int);\r
+static bool handleSpecial (char *);\r
+static int handleLlSpecial (void);\r
+static void handleMacro (void);\r
+static bool processMacro (void);\r
+static /*@only@*/ cstring makeIdentifier (char *);\r
+\r
+/* yes, this is exported! */\r
+bool g_expectingTypeName = TRUE; /* beginning of file can be type name! */\r
+\r
+static bool expectingMetaStateName = FALSE;\r
+\r
+static int returnInt (ctype, long);\r
+static int returnFloat (ctype, double);\r
+static int returnChar (char);\r
+static void setTokLength (int) /*@modifies g_currentloc@*/ ;\r
+static void setTokLengthT (size_t) /*@modifies g_currentloc@*/ ;\r
+\r
+static void advanceLine (void)\r
+{\r
+ tokLength = 0;\r
+ beginLine ();\r
+}\r
+ \r
+/*@-allmacros@*/\r
+# define RETURN_INT(c,i) \\r
+ do { lastWasString = FALSE; \\r
+ return (returnInt (c, i)); } while (FALSE)\r
+\r
+# define RETURN_FLOAT(c,f) \\r
+ do { lastWasString = FALSE; \\r
+ return (returnFloat (c, f)); \\r
+ } while (FALSE)\r
+\r
+# define RETURN_CHAR(c) \\r
+ do { lastWasString = FALSE; \\r
+ return (returnChar (c)); \\r
+ } while (FALSE)\r
+\r
+# define RETURN_TOK(t) \\r
+ do { yylval.tok = lltok_create (t, fileloc_decColumn (g_currentloc, tokLength)); \\r
+ tokLength = 0; \\r
+ lastWasString = FALSE; \\r
+ return (t); } while (FALSE)\r
+\r
+# define RETURN_TYPE(t, ct) \\r
+ do { yylval.ctyp = ct; tokLength = 0; return (t); } while (FALSE)\r
+\r
+/* don't fileloc_decColumn (g_currentloc, tokLength)); \r
+ the string could have \n's in it!\r
+*/\r
+\r
+# define RETURN_STRING(c) \\r
+ do { yylval.expr = exprNode_stringLiteral (c, fileloc_decColumn (g_currentloc, tokLength)); \\r
+ tokLength = 0; \\r
+ lastWasString = TRUE; \\r
+ return (CCONSTANT); } while (FALSE)\r
+\r
+# define RETURN_EXPR(e) \\r
+ do { yylval.expr = e; \\r
+ tokLength = 0; \\r
+ lastWasString = TRUE; \\r
+ return (CCONSTANT); } while (FALSE)\r
+\r
+/*@=allmacros@*/\r
+\r
+static void setTokLength (int len) \r
+{\r
+ addColumn (len);\r
+ tokLength = len;\r
+ DPRINTF (("Set tok length: %d", len));\r
+}\r
+\r
+static void setTokLengthT (size_t len)\r
+{\r
+ setTokLength (size_toInt (len));\r
+}\r
+\r
+# include "flex.head"\r
+\r
+/*@-unrecog@*/ /*@i5343@*/\r
+\r
+%}\r
+\r
+%%\r
+\r
+"/*" { llfatalbug (cstring_makeLiteral ("Comment in pre-processor output")); }\r
+\r
+"#"{Letter}({Letter}|{Digit})* { \r
+ context_saveLocation (); \r
+ setTokLength (longUnsigned_toInt (mstring_length (yytext))); \r
+\r
+ if (processHashIdentifier (makeIdentifier (yytext + 1)))\r
+ {\r
+ if (lastWasString)\r
+ {\r
+ /* was nothing! */ /*@i32@*/\r
+ RETURN_STRING (cstring_makeLiteral ("\"\""));\r
+ }\r
+ else\r
+ {\r
+ RETURN_STRING (cstring_makeLiteral ("\"\""));\r
+ }\r
+ }\r
+ else\r
+ { \r
+ if (handleSpecial (yytext)) \r
+ { \r
+ setTokLength (1); \r
+ RETURN_TOK (0); \r
+ }\r
+ }\r
+ } \r
+"#" { if (handleSpecial (yytext)) \r
+ { \r
+ setTokLength (1); RETURN_TOK (0); \r
+ }\r
+ }\r
+"..." { setTokLength (3); RETURN_TOK (CTOK_ELIPSIS); }\r
+"break" { setTokLength (5); RETURN_TOK (BREAK); }\r
+"case" { setTokLength (4); RETURN_TOK (CASE); }\r
+"continue" { setTokLength (8); RETURN_TOK (CONTINUE); }\r
+"default" { setTokLength (7); RETURN_TOK (DEFAULT); }\r
+"do" { setTokLength (2); RETURN_TOK (DO); }\r
+"else" { setTokLength (4); RETURN_TOK (CELSE); }\r
+"for" { setTokLength (3); RETURN_TOK (CFOR); }\r
+"goto" { setTokLength (4); RETURN_TOK (GOTO); }\r
+"if" { setTokLength (2); RETURN_TOK (CIF); }\r
+"return" { setTokLength (6); RETURN_TOK (RETURN); }\r
+"sizeof" { setTokLength (6); RETURN_TOK (CSIZEOF); }\r
+"offsetof" { setTokLength (8); RETURN_TOK (COFFSETOF); }\r
+"switch" { setTokLength (6); RETURN_TOK (SWITCH); }\r
+"while" { setTokLength (5); RETURN_TOK (WHILE); }\r
+"va_arg" { setTokLength (6); RETURN_TOK (VA_ARG); } \r
+"va_dcl" { setTokLength (6); RETURN_TOK (VA_DCL); } \r
+"inline" { \r
+ /* gcc extension...this might not be appropriate */\r
+ setTokLength (6); RETURN_TOK (QINLINE); }\r
+\r
+"struct" { setTokLength (6); RETURN_TOK (CSTRUCT); } \r
+"typedef" { setTokLength (7); RETURN_TOK (CTYPEDEF); }\r
+\r
+"union" { setTokLength (5); RETURN_TOK (CUNION); }\r
+"enum" { setTokLength (4); RETURN_TOK (CENUM); }\r
+\r
+"void" { setTokLength (4); RETURN_TYPE (CVOID, ctype_void); }\r
+"int" { setTokLength (3); RETURN_TYPE (CINT, ctype_int); }\r
+"double" { setTokLength (6); RETURN_TYPE (CDOUBLE, ctype_double); }\r
+"char" { setTokLength (4); RETURN_TYPE (CGCHAR, ctype_char); }\r
+"float" { setTokLength (5); RETURN_TYPE (CGFLOAT, ctype_float); }\r
+\r
+"long" { setTokLength (4); RETURN_TOK (QLONG); }\r
+"short" { setTokLength (5); RETURN_TOK (QSHORT); }\r
+"unsigned" { setTokLength (8); RETURN_TOK (QUNSIGNED); }\r
+"signed" { setTokLength (6); RETURN_TOK (QSIGNED); }\r
+\r
+"volatile" { setTokLength (8); RETURN_TOK (QVOLATILE); }\r
+"const" { setTokLength (5); RETURN_TOK (QCONST); }\r
+\r
+ /* some systems expect this! [gack!] */ \r
+"__const" { setTokLength (7); RETURN_TOK (QCONST); }\r
+\r
+"extern" { setTokLength (6); RETURN_TOK (QEXTERN); }\r
+"auto" { setTokLength (4); RETURN_TOK (QAUTO); }\r
+"register" { setTokLength (8); RETURN_TOK (QREGISTER); }\r
+"static" { setTokLength (6); RETURN_TOK (QSTATIC); }\r
+\r
+\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }\r
+L\"(\\.|[^\\"])*\"([ \t\n]*\"(\\.|[^\\"])*\")* { RETURN_EXPR (processString ()); }\r
+"out" { return (processSpec (QOUT)); }\r
+"in" { return (processSpec (QIN)); }\r
+"partial" { return (processSpec (QPARTIAL)); }\r
+"special" { return (processSpec (QSPECIAL)); }\r
+"anytype" { return (processSpec (QANYTYPE)); }\r
+"integraltype" { return (processSpec (QINTEGRALTYPE)); }\r
+"unsignedintegraltype" { return (processSpec (QUNSIGNEDINTEGRALTYPE)); }\r
+"signedintegraltype" { return (processSpec (QSIGNEDINTEGRALTYPE)); }\r
+"keep" { return (processSpec (QKEEP)); }\r
+"null" { return (processSpec (QNULL)); } \r
+"notnull" { return (processSpec (QNOTNULL)); } \r
+"isnull" { return (processSpec (QISNULL)); } \r
+"truenull" { return (processSpec (QTRUENULL)); } \r
+"falsenull" { return (processSpec (QFALSENULL)); } \r
+"relnull" { return (processSpec (QRELNULL)); }\r
+"reldef" { return (processSpec (QRELDEF)); }\r
+"exposed" { return (processSpec (QEXPOSED)); }\r
+"newref" { return (processSpec (QNEWREF)); }\r
+"tempref" { return (processSpec (QTEMPREF)); }\r
+"killref" { return (processSpec (QKILLREF)); }\r
+"refcounted" { return (processSpec (QREFCOUNTED)); }\r
+"checked" { return (processSpec (QCHECKED)); }\r
+"checkmod" { return (processSpec (QCHECKMOD)); }\r
+"checkedstrict" { return (processSpec (QCHECKEDSTRICT)); }\r
+"unchecked" { return (processSpec (QUNCHECKED)); }\r
+"only" { return (processSpec (QONLY)); }\r
+"owned" { return (processSpec (QOWNED)); }\r
+"observer" { return (processSpec (QOBSERVER)); }\r
+"dependent" { return (processSpec (QDEPENDENT)); }\r
+"unused" { return (processSpec (QUNUSED)); }\r
+"external" { return (processSpec (QEXTERNAL)); }\r
+"sef" { return (processSpec (QSEF)); }\r
+"shared" { return (processSpec (QSHARED)); }\r
+"yield" { return (processSpec (QYIELD)); }\r
+"undef" { return (processSpec (QUNDEF)); }\r
+"killed" { return (processSpec (QKILLED)); }\r
+"nullterminated" { return (processSpec (QNULLTERMINATED));}\r
+"MaxSet" { return (processSpec (QMAXSET));}\r
+"MaxRead" { return (processSpec (QMAXREAD));}\r
+"maxSet" { return (processSpec (QMAXSET));}\r
+"maxRead" { return (processSpec (QMAXREAD));}\r
+\r
+{Letter}({Letter}|{Digit})* { int tok; \r
+ context_saveLocation (); \r
+ setTokLength (longUnsigned_toInt (mstring_length (yytext))); \r
+ tok = processIdentifier (makeIdentifier (yytext)); \r
+ if (tok != BADTOK)\r
+ {\r
+ return (tok);\r
+ }\r
+ }\r
+0[xX]{H}+ { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_int, processHex ()); /* evs 2000-05-17 was ctype_uint */\r
+ }\r
+0[xX]{H}+{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_lint, processHex ()); }\r
+0[xX]{H}+{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_llint, processHex ()); }\r
+0[xX]{H}+{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_uint, processHex ()); }\r
+0[xX]{H}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ulint, processHex ()); }\r
+0[xX]{H}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processHex ()); }\r
+0[xX]{H}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processHex ()); }\r
+0{Digit}+ { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_int, processOctal ()); } \r
+0{Digit}+{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_uint, processOctal ()); } \r
+0{Digit}+{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_lint, processOctal ()); } \r
+0{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_llint, processOctal ()); } \r
+0{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ulint, processOctal ()); } \r
+0{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processOctal ()); } \r
+0{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processOctal ()); } \r
+{Digit}+ { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_int, processDec ()); } \r
+{Digit}+{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_uint, processDec ()); } \r
+{Digit}+{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_lint, processDec ()); } \r
+{Digit}+{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_llint, processDec ()); } \r
+{Digit}+{ULSuffix} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ulint, processDec ()); } \r
+{Digit}+{U}{L}{L} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processDec ()); } \r
+{Digit}+{L}{L}{U} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_INT (ctype_ullint, processDec ()); } \r
+'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_CHAR (processChar ()); }\r
+L'(\\.|[^\\'])+' { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_CHAR (processChar ()); }\r
+{Digit}+{E}[fF] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_float, processFloat ()); }\r
+{Digit}+{E}[lL] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_ldouble, processFloat ()); }\r
+{Digit}+{E} { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_double, processFloat ()); }\r
+\r
+{Digit}*"."{Digit}+({E})?[fF] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_float, processFloat ()); }\r
+{Digit}*"."{Digit}+({E})?[lL] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_ldouble, processFloat ()); }\r
+{Digit}*"."{Digit}+({E})? { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_double, processFloat ()); }\r
+\r
+{Digit}+"."{Digit}*({E})?[fF] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_float, processFloat ()); }\r
+{Digit}+"."{Digit}*({E})?[lL] { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_ldouble, processFloat ()); }\r
+{Digit}+"."{Digit}*({E})? { setTokLengthT (mstring_length (yytext)); \r
+ RETURN_FLOAT (ctype_double, processFloat ()); }\r
+\r
+">>=" { setTokLength (3); RETURN_TOK (RIGHT_ASSIGN); }\r
+"<<=" { setTokLength (3); RETURN_TOK (LEFT_ASSIGN); }\r
+"+=" { setTokLength (2); RETURN_TOK (ADD_ASSIGN); }\r
+"-=" { setTokLength (2); RETURN_TOK (SUB_ASSIGN); }\r
+"*=" { setTokLength (2); RETURN_TOK (MUL_ASSIGN); }\r
+"/=" { setTokLength (2); RETURN_TOK (DIV_ASSIGN); }\r
+"%=" { setTokLength (2); RETURN_TOK (MOD_ASSIGN); }\r
+"&=" { setTokLength (2); RETURN_TOK (AND_ASSIGN); }\r
+"^=" { setTokLength (2); RETURN_TOK (XOR_ASSIGN); }\r
+"|=" { setTokLength (2); RETURN_TOK (OR_ASSIGN); }\r
+">>" { setTokLength (2); RETURN_TOK (RIGHT_OP); }\r
+"<<" { setTokLength (2); RETURN_TOK (LEFT_OP); }\r
+"++" { setTokLength (2); RETURN_TOK (INC_OP); }\r
+"--" { setTokLength (2); RETURN_TOK (DEC_OP); }\r
+"->" { setTokLength (2); RETURN_TOK (ARROW_OP); }\r
+"&&" { setTokLength (2); RETURN_TOK (AND_OP); }\r
+"||" { setTokLength (2); RETURN_TOK (OR_OP); }\r
+"<=" { setTokLength (2); RETURN_TOK (LE_OP); }\r
+">=" { setTokLength (2); RETURN_TOK (GE_OP); }\r
+"==" { setTokLength (2); RETURN_TOK (EQ_OP); }\r
+"!=" { setTokLength (2); RETURN_TOK (NE_OP); }\r
+";" { setTokLength (1); RETURN_TOK (TSEMI); }\r
+"{" { setTokLength (1); RETURN_TOK (TLBRACE); }\r
+"}" { setTokLength (1); RETURN_TOK (TRBRACE); }\r
+"," { setTokLength (1); RETURN_TOK (TCOMMA); }\r
+":" { setTokLength (1); RETURN_TOK (TCOLON); }\r
+"=" { setTokLength (1); RETURN_TOK (TASSIGN); }\r
+"(" { setTokLength (1); RETURN_TOK (TLPAREN); }\r
+")" { setTokLength (1); RETURN_TOK (TRPAREN); }\r
+"[" { setTokLength (1); RETURN_TOK (TLSQBR); }\r
+"]" { setTokLength (1); RETURN_TOK (TRSQBR); }\r
+"." { setTokLength (1); RETURN_TOK (TDOT); }\r
+"&" { setTokLength (1); RETURN_TOK (TAMPERSAND); }\r
+"!" { setTokLength (1); RETURN_TOK (TEXCL); }\r
+\r
+\r
+"~" { setTokLength (1); RETURN_TOK (TTILDE); }\r
+"-" { setTokLength (1); RETURN_TOK (TMINUS); }\r
+"+" { setTokLength (1); RETURN_TOK (TPLUS); }\r
+"*" { setTokLength (1); RETURN_TOK (TMULT); }\r
+"/" { setTokLength (1); RETURN_TOK (TDIV); }\r
+"%" { setTokLength (1); RETURN_TOK (TPERCENT); }\r
+"<" { setTokLength (1); RETURN_TOK (TLT); }\r
+">" { setTokLength (1); RETURN_TOK (TGT); }\r
+"^" { setTokLength (1); RETURN_TOK (TCIRC); }\r
+"|" { setTokLength (1); RETURN_TOK (TBAR); }\r
+"?" { setTokLength (1); RETURN_TOK (TQUEST); }\r
+\r
+\r
+"/\\" { setTokLength (1); RETURN_TOK (TCAND); }\r
+\r
+\r
+[ \t\v\f] { incColumn (); }\r
+\n { context_incLineno ();\r
+ if (tokLength != 0) { \r
+ tokLength = 0; \r
+ /* No error to report \r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Likely parse error: token spans multiple lines."),\r
+ g_currentloc);\r
+ */\r
+ }\r
+ \r
+ if (continueLine)\r
+ {\r
+ continueLine = FALSE;\r
+ }\r
+ else \r
+ {\r
+ if (context_inMacro ())\r
+ {\r
+ /* Don't use RETURN_TOK */\r
+ yylval.tok = lltok_create (TENDMACRO, g_currentloc);\r
+ lastWasString = FALSE;\r
+ return (TENDMACRO);\r
+ } \r
+ }\r
+ }\r
+"@@MR@@" { setTokLength (6); \r
+ \r
+ if (processMacro ()) {\r
+ if (context_inIterDef ()) \r
+ { \r
+ RETURN_TOK (LLMACROITER); \r
+ }\r
+ if (context_inIterEnd ())\r
+ {\r
+ RETURN_TOK (LLMACROEND); \r
+ }\r
+ if (context_inMacro ())\r
+ {\r
+ RETURN_TOK (LLMACRO); \r
+ }\r
+ }\r
+ }\r
+"@QLMR" { if (context_inHeader () || context_inFunction ())\r
+ { \r
+ handleMacro ();\r
+ }\r
+ else\r
+ {\r
+ int nspchar = ninput ();\r
+ int nspaces;\r
+\r
+ /* \r
+ ** This is a hack to get the column number correct.\r
+ */\r
+\r
+ llassert (nspchar >= '0' && nspchar <= '9');\r
+ \r
+ nspaces = nspchar - '0';\r
+\r
+ setTokLength (5 + nspaces); \r
+ \r
+ if (processMacro ()) \r
+ {\r
+ if (context_inIterDef ()) \r
+ {\r
+ RETURN_TOK (LLMACROITER); \r
+ }\r
+ if (context_inIterEnd ())\r
+ {\r
+ RETURN_TOK (LLMACROEND); \r
+ }\r
+ if (context_inMacro ())\r
+ { \r
+ RETURN_TOK (LLMACRO); \r
+ }\r
+ }\r
+ }\r
+ }\r
+"@.CT" { setTokLength (4); lldiagmsg (ctype_unparseTable ()); }\r
+"@.FA" { setTokLength (4); lldiagmsg (message ("Access types: %q", typeIdSet_unparse (context_fileAccessTypes ()))); }\r
+"@.F" { setTokLength (3); \r
+ lldiagmsg (message ("%q: *** marker ***", fileloc_unparse (g_currentloc)));\r
+ }\r
+"@.L" { setTokLength (3); usymtab_printLocal (); }\r
+"@.A" { setTokLength (3); lldiagmsg (usymtab_unparseAliases ()); }\r
+"@.C" { setTokLength (3); lldiagmsg (context_unparse ()); }\r
+"@.W" { setTokLength (3); lldiagmsg (context_unparseClauses ()); }\r
+"@.G" { setTokLength (3); usymtab_printGuards (); }\r
+"@.S" { setTokLength (3); usymtab_printOut (); }\r
+"@.X" { setTokLength (3); usymtab_printAll (); }\r
+"@.Z" { setTokLength (3); usymtab_printComplete (); }\r
+"@.T" { setTokLength (3); usymtab_printTypes (); }\r
+"@.K" { setTokLength (3); lldiagmsg (usymtab_unparseStack ()); }\r
+"@.M" { setTokLength (3); \r
+ lldiagmsg (message ("Can modify: %q", \r
+ sRefSet_unparse (context_modList ()))); \r
+ }\r
+"%{" { /* BEFORE_COMMENT_MARKER */\r
+ int tok; \r
+ incColumn (); incColumn ();\r
+ tok = handleLlSpecial (); \r
+\r
+ if (tok != BADTOK)\r
+ {\r
+ if (tok == CANNOTATION) {\r
+ return (tok);\r
+ } else {\r
+ /* Beware - this bashes yylval! */\r
+ RETURN_TOK (tok); \r
+ }\r
+ }\r
+ }\r
+"%}" { /* AFTER_COMMENT_MARKER */ \r
+ setTokLength (2);\r
+ inSpecPart = FALSE;\r
+ RETURN_TOK (QENDMACRO); }\r
+"\\" { incColumn (); continueLine = TRUE; }\r
+. { incColumn (); \r
+ if ((int) *yytext == 13 ) {\r
+ ;\r
+ } else {\r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Invalid character (ascii: %d), skipping character",\r
+ (int)(*yytext)),\r
+ g_currentloc);\r
+ }\r
+ }\r
+%%\r
+\r
+struct skeyword\r
+{\r
+ /*@null@*/ /*@observer@*/ char *name;\r
+ int token;\r
+} ;\r
+\r
+/*\r
+** These tokens are followed by syntax that is parsed by the \r
+** grammar proper.\r
+*/\r
+\r
+struct skeyword s_parsetable[] = {\r
+ { "modifies", QMODIFIES } ,\r
+ { "globals", QGLOBALS } ,\r
+ { "alt", QALT } ,\r
+ { "warn", QWARN } ,\r
+ { "constant", QCONSTANT } ,\r
+ { "function", QFUNCTION } ,\r
+ { "iter", QITER } ,\r
+ { "defines", QDEFINES } ,\r
+ { "uses", QUSES } ,\r
+ { "allocates", QALLOCATES } ,\r
+ { "sets", QSETS } ,\r
+ { "releases", QRELEASES } ,\r
+ { "pre", QPRECLAUSE } ,\r
+ { "post", QPOSTCLAUSE } ,\r
+ { "setBufferSize", QSETBUFFERSIZE},\r
+ { "setStringLength", QSETSTRINGLENGTH},\r
+ { "testinRange", QTESTINRANGE},\r
+ { "requires", QPRECLAUSE } ,\r
+ { "ensures", QPOSTCLAUSE } ,\r
+ { NULL, BADTOK } \r
+} ;\r
+\r
+/*\r
+** These tokens are either stand-alone tokens, or followed by \r
+** token-specific text.\r
+*/\r
+\r
+struct skeyword s_keytable[] = {\r
+ { "anytype", QANYTYPE } ,\r
+ { "integraltype", QINTEGRALTYPE } ,\r
+ { "unsignedintegraltype", QUNSIGNEDINTEGRALTYPE } ,\r
+ { "signedintegraltype", QSIGNEDINTEGRALTYPE } ,\r
+ { "out", QOUT } ,\r
+ { "in", QIN } ,\r
+ { "only", QONLY } , \r
+ { "owned", QOWNED } ,\r
+ { "dependent", QDEPENDENT } ,\r
+ { "partial", QPARTIAL } ,\r
+ { "special", QSPECIAL } ,\r
+ { "truenull", QTRUENULL } ,\r
+ { "falsenull", QFALSENULL } ,\r
+ { "keep", QKEEP } ,\r
+ { "kept", QKEPT } ,\r
+ { "notnull", QNOTNULL } ,\r
+ { "abstract", QABSTRACT } ,\r
+ { "concrete", QCONCRETE } ,\r
+ { "mutable", QMUTABLE } ,\r
+ { "immutable", QIMMUTABLE } ,\r
+ { "unused", QUNUSED } ,\r
+ { "external", QEXTERNAL } ,\r
+ { "sef", QSEF } ,\r
+ { "unique", QUNIQUE } ,\r
+ { "returned", QRETURNED } ,\r
+ { "exposed", QEXPOSED } ,\r
+ { "refcounted", QREFCOUNTED } ,\r
+ { "refs", QREFS } ,\r
+ { "newref", QNEWREF } ,\r
+ { "tempref", QTEMPREF } ,\r
+ { "killref", QKILLREF } ,\r
+ { "null", QNULL } ,\r
+ { "relnull", QRELNULL } ,\r
+ { "nullterminated", QNULLTERMINATED }, \r
+ { "setBufferSize", QSETBUFFERSIZE },\r
+ { "testInRange", QTESTINRANGE},\r
+ { "MaxSet", QMAXSET},\r
+ { "MaxRead", QMAXREAD},\r
+ { "reldef", QRELDEF } ,\r
+ { "observer", QOBSERVER } ,\r
+ { "exits", QEXITS } ,\r
+ { "mayexit", QMAYEXIT } ,\r
+ { "trueexit", QTRUEEXIT } ,\r
+ { "falseexit", QFALSEEXIT } ,\r
+ { "neverexit", QNEVEREXIT } ,\r
+ { "temp", QTEMP } ,\r
+ { "shared", QSHARED } ,\r
+ { "ref", QREF } ,\r
+ { "unchecked", QUNCHECKED } ,\r
+ { "checked", QCHECKED } ,\r
+ { "checkmod", QCHECKMOD } ,\r
+ { "checkedstrict", QCHECKEDSTRICT } ,\r
+ { "innercontinue", QINNERCONTINUE } ,\r
+ { "innerbreak", QINNERBREAK } ,\r
+ { "loopbreak", QLOOPBREAK } ,\r
+ { "switchbreak", QSWITCHBREAK } ,\r
+ { "safebreak", QSAFEBREAK } , \r
+ { "fallthrough", QFALLTHROUGH } ,\r
+ { "l_fallthrou", QLINTFALLTHROUGH } , \r
+ { "l_fallth", QLINTFALLTHRU } ,\r
+ { "notreached", QNOTREACHED } ,\r
+ { "l_notreach", QLINTNOTREACHED } ,\r
+ { "printflike", QPRINTFLIKE } ,\r
+ { "l_printfli", QLINTPRINTFLIKE } ,\r
+ { "scanflike", QSCANFLIKE } ,\r
+ { "messagelike", QMESSAGELIKE } ,\r
+ { "l_argsus", QARGSUSED } ,\r
+ { NULL, BADTOK } \r
+} ;\r
+\r
+/*\r
+** would be better if these weren't hard coded...\r
+*/\r
+\r
+static bool isArtificial (cstring s)\r
+{\r
+ return (cstring_equalLit (s, "modifies") \r
+ || cstring_equalLit (s, "globals") \r
+ || cstring_equalLit (s, "warn")\r
+ || cstring_equalLit (s, "alt"));\r
+}\r
+\r
+void swallowMacro (void)\r
+{\r
+ int i;\r
+ bool skipnext = FALSE;\r
+\r
+ while ((i = lminput ()) != EOF)\r
+ {\r
+ char c = (char) i;\r
+ \r
+ \r
+ if (c == '\\')\r
+ {\r
+ skipnext = TRUE;\r
+ }\r
+ else if (c == '\n')\r
+ {\r
+ if (skipnext)\r
+ {\r
+ skipnext = FALSE;\r
+ }\r
+ else\r
+ {\r
+ reader_checkUngetc (i, yyin);\r
+ return;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (i != EOF)\r
+ {\r
+ reader_checkUngetc (i, yyin);\r
+ }\r
+}\r
+\r
+static int commentMarkerToken (cstring s)\r
+{\r
+ int i = 0;\r
+ \r
+ while (s_parsetable[i].name != NULL) \r
+ {\r
+ DPRINTF (("Try :%s:%s:", s, s_parsetable[i].name));\r
+\r
+ if (cstring_equalLit (s, s_parsetable[i].name))\r
+ {\r
+ return s_parsetable[i].token;\r
+ }\r
+\r
+ i++;\r
+ }\r
+\r
+ return BADTOK;\r
+}\r
+\r
+static int tokenMacroCode (cstring s)\r
+{\r
+ int i = 0;\r
+ \r
+ while (s_keytable[i].name != NULL) \r
+ {\r
+ if (cstring_equalLit (s, s_keytable[i].name)) \r
+ {\r
+ if (s_keytable[i].token == QLINTFALLTHROUGH) \r
+ {\r
+ voptgenerror\r
+ (FLG_WARNLINTCOMMENTS,\r
+ cstring_makeLiteral\r
+ ("Traditional lint comment /*FALLTHROUGH*/ used. "\r
+ "This is interpreted by "\r
+ "LCLint in the same way as most Unix lints, but it is "\r
+ "preferable to replace it with the /*@fallthrough@*/ "\r
+ "semantic comment"),\r
+ g_currentloc);\r
+ return QFALLTHROUGH; \r
+ }\r
+ else if (s_keytable[i].token == QLINTFALLTHRU)\r
+ {\r
+ voptgenerror \r
+ (FLG_WARNLINTCOMMENTS,\r
+ cstring_makeLiteral\r
+ ("Traditional lint comment /*FALLTHRU*/ used. "\r
+ "This is interpreted by "\r
+ "LCLint in the same way as most Unix lints, but it is "\r
+ "preferable to replace it with the /*@fallthrough@*/ "\r
+ "semantic comment"),\r
+ g_currentloc);\r
+ return QFALLTHROUGH;\r
+ }\r
+ else if (s_keytable[i].token == QLINTNOTREACHED)\r
+ {\r
+ voptgenerror \r
+ (FLG_WARNLINTCOMMENTS,\r
+ cstring_makeLiteral\r
+ ("Traditional lint comment /*NOTREACHED*/ used. "\r
+ "This is interpreted by "\r
+ "LCLint in the same way as most Unix lints, but it is "\r
+ "preferable to replace it with the /*@notreached@*/ "\r
+ "semantic comment."),\r
+ g_currentloc);\r
+ \r
+ return QNOTREACHED;\r
+ }\r
+ else if (s_keytable[i].token == QPRINTFLIKE)\r
+ {\r
+ setSpecialFunction (qual_createPrintfLike ());\r
+ return SKIPTOK;\r
+ }\r
+ else if (s_keytable[i].token == QLINTPRINTFLIKE)\r
+ { \r
+ voptgenerror \r
+ (FLG_WARNLINTCOMMENTS,\r
+ cstring_makeLiteral\r
+ ("Traditional lint comment /*PRINTFLIKE*/ used. "\r
+ "This is interpreted by "\r
+ "LCLint in the same way as most Unix lints, but it is "\r
+ "preferable to replace it with either /*@printflike@*/, "\r
+ "/*@scanflike@*/ or /*@messagelike@*/."),\r
+ g_currentloc);\r
+ \r
+ setSpecialFunction (qual_createPrintfLike ());\r
+ return SKIPTOK;\r
+ }\r
+ else if (s_keytable[i].token == QSCANFLIKE)\r
+ {\r
+ setSpecialFunction (qual_createScanfLike ());\r
+ return SKIPTOK;\r
+ }\r
+ else if (s_keytable[i].token == QMESSAGELIKE)\r
+ {\r
+ setSpecialFunction (qual_createMessageLike ());\r
+ return SKIPTOK;\r
+ }\r
+ else if (s_keytable[i].token == QARGSUSED)\r
+ {\r
+ voptgenerror\r
+ (FLG_WARNLINTCOMMENTS,\r
+ cstring_makeLiteral\r
+ ("Traditional lint comment /*ARGSUSED*/ used. "\r
+ "This is interpreted by "\r
+ "LCLint in the same way as most Unix lints, but it is "\r
+ "preferable to use /*@unused@*/ annotations on "\r
+ "the unused parameters."),\r
+ g_currentloc);\r
+ \r
+ setArgsUsed ();\r
+ return SKIPTOK;\r
+ }\r
+ \r
+ return s_keytable[i].token;\r
+ }\r
+ \r
+ i++;\r
+ }\r
+ \r
+ return BADTOK;\r
+}\r
+\r
+static int lminput ()\r
+{\r
+ if (savechar == '\0')\r
+ {\r
+ incColumn ();\r
+ return (input ());\r
+ }\r
+ else\r
+ {\r
+ int save = (int) savechar;\r
+ savechar = '\0';\r
+ return save;\r
+ }\r
+}\r
+\r
+static void lmsavechar (char c)\r
+{\r
+ if (savechar == '\0') savechar = c;\r
+ else\r
+ {\r
+ llbuglit ("lmsavechar: override");\r
+ }\r
+}\r
+\r
+static int returnFloat (ctype ct, double f)\r
+{\r
+ yylval.expr = exprNode_floatLiteral (f, ct, cstring_fromChars (yytext), \r
+ fileloc_decColumn (g_currentloc, tokLength));\r
+ tokLength = 0; \r
+ return (CCONSTANT);\r
+}\r
+\r
+static int returnInt (ctype ct, long i)\r
+{\r
+ ctype c = ct;\r
+\r
+ if (ctype_equal (ct, ctype_int))\r
+ {\r
+ if (i == 0)\r
+ {\r
+ c = context_typeofZero ();\r
+ }\r
+ else if (i == 1)\r
+ {\r
+ c = context_typeofOne ();\r
+ }\r
+ }\r
+ \r
+ yylval.expr = exprNode_numLiteral (c, cstring_fromChars (yytext), \r
+ fileloc_decColumn (g_currentloc, tokLength), i); \r
+ tokLength = 0; \r
+ return (CCONSTANT);\r
+}\r
+\r
+static int returnChar (char c)\r
+{\r
+ yylval.expr = exprNode_charLiteral (c, cstring_fromChars (yytext), \r
+ fileloc_decColumn (g_currentloc, tokLength));\r
+ tokLength = 0; \r
+ return (CCONSTANT);\r
+}\r
+\r
+static int ninput () \r
+{\r
+ int c = lminput ();\r
+\r
+ if (c != EOF && ((char)c == '\n'))\r
+ {\r
+ context_incLineno ();\r
+ }\r
+\r
+ return c;\r
+}\r
+\r
+static char macro_nextChar ()\r
+{\r
+ static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;\r
+ int ic;\r
+ char c;\r
+\r
+ ic = lminput ();\r
+ c = char_fromInt (ic);\r
+ \r
+ if (!in_quote && !in_char && (c == '\\' || c == BEFORE_COMMENT_MARKER[0]))\r
+ {\r
+ if (c == '\\')\r
+ {\r
+ while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')\r
+ {\r
+ ; /* skip to newline */\r
+ }\r
+ \r
+ context_incLineno ();\r
+ \r
+ if (c != '\0')\r
+ {\r
+ return macro_nextChar ();\r
+ }\r
+ else \r
+ {\r
+ return c;\r
+ }\r
+ }\r
+ else /* if (c == '@') */\r
+ {\r
+ llassert (FALSE); /*@i23@*/\r
+ if (handleLlSpecial () != BADTOK)\r
+ {\r
+ llerrorlit (FLG_SYNTAX, "Macro cannot use special syntax");\r
+ }\r
+\r
+ return macro_nextChar ();\r
+ }\r
+ }\r
+ else if (!in_escape && c == '\"')\r
+ {\r
+ in_quote = !in_quote;\r
+ }\r
+ else if (!in_escape && c == '\'')\r
+ {\r
+ in_char = !in_char;\r
+ }\r
+ else if ((in_quote || in_char) && c == '\\')\r
+ {\r
+ in_escape = !in_escape;\r
+ }\r
+ else if ((in_quote || in_char) && in_escape)\r
+ {\r
+ in_escape = FALSE;\r
+ }\r
+ else if (!in_quote && c == '/')\r
+ {\r
+ char c2;\r
+ \r
+ if ((c2 = char_fromInt (lminput ())) == '*')\r
+ {\r
+ while (c2 != '\0')\r
+ {\r
+ while ((c2 = char_fromInt (lminput ())) != '\0'\r
+ && c2 != '\n' && c2 != '*')\r
+ {\r
+ ;\r
+ }\r
+ \r
+ if (c2 == '*')\r
+ {\r
+ while ((c2 = char_fromInt (lminput ())) != '\0' \r
+ && c2 == '*')\r
+ {\r
+ ;\r
+ }\r
+\r
+ if (c2 == '/')\r
+ {\r
+ goto outofcomment;\r
+ }\r
+ }\r
+ else \r
+ {\r
+ llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));\r
+ }\r
+ }\r
+ outofcomment:\r
+ return macro_nextChar ();\r
+ }\r
+ else\r
+ {\r
+ /*** putchar does not work! why? puts to stdio...??! ***/\r
+ lmsavechar (c2);\r
+ }\r
+ }\r
+ return c;\r
+}\r
+\r
+/*\r
+** keeps semantic comments\r
+*/\r
+\r
+static char macro_nextCharC ()\r
+{\r
+ static bool in_quote = FALSE, in_escape = FALSE, in_char = FALSE;\r
+ char c;\r
+\r
+ c = char_fromInt (lminput ());\r
+\r
+ if (!in_quote && !in_char && c == '\\')\r
+ {\r
+ while ((c = char_fromInt (lminput ())) != '\0' && c != '\n')\r
+ {\r
+ ; /* skip to newline */\r
+ }\r
+ \r
+ context_incLineno ();\r
+ \r
+ if (c != '\0')\r
+ {\r
+ return macro_nextCharC ();\r
+ }\r
+ else\r
+ {\r
+ return c;\r
+ }\r
+ }\r
+ else if (!in_escape && c == '\"')\r
+ {\r
+ in_quote = !in_quote;\r
+ }\r
+ else if (!in_escape && c == '\'')\r
+ {\r
+ in_char = !in_char;\r
+ }\r
+ else if ((in_quote || in_char) && c == '\\')\r
+ {\r
+ in_escape = !in_escape;\r
+ }\r
+ else if ((in_quote || in_char) && in_escape)\r
+ {\r
+ in_escape = FALSE;\r
+ }\r
+ else if (!in_quote && c == '/')\r
+ {\r
+ char c2;\r
+ \r
+ if ((c2 = char_fromInt (lminput ())) == '*')\r
+ {\r
+ while (c2 != '\0')\r
+ {\r
+ while ((c2 = char_fromInt (lminput ())) != '\0' \r
+ && c2 != '\n' && c2 != '*')\r
+ {\r
+ ;\r
+ }\r
+ \r
+ if (c2 == '*')\r
+ {\r
+ while ((c2 = char_fromInt (lminput ())) != '\0'\r
+ && c2 == '*')\r
+ {\r
+ ;\r
+ }\r
+\r
+ if (c2 == '/') \r
+ {\r
+ goto outofcomment;\r
+ }\r
+ }\r
+ else \r
+ {\r
+ llfatalerror (cstring_makeLiteral ("Macro: bad comment!"));\r
+ }\r
+ }\r
+ outofcomment:\r
+ return macro_nextCharC ();\r
+ }\r
+ else\r
+ {\r
+ lmsavechar (c2);\r
+ }\r
+ }\r
+ return c;\r
+}\r
+\r
+/*\r
+** skips whitespace (handles line continuations)\r
+** returns first non-whitespace character\r
+*/\r
+\r
+static char skip_whitespace ()\r
+{\r
+ char c;\r
+\r
+ while ((c = macro_nextChar ()) == ' ' || c == '\t')\r
+ {\r
+ ;\r
+ }\r
+\r
+ return c;\r
+}\r
+\r
+static void handleMacro ()\r
+{\r
+ cstring mac = cstring_undefined;\r
+ int macrocode;\r
+ char c;\r
+\r
+ while (currentColumn () > 2)\r
+ {\r
+ mac = cstring_appendChar (mac, ' ');\r
+ setTokLength (-1);\r
+ }\r
+\r
+ c = macro_nextCharC ();\r
+\r
+ if (c >= '0' && c <= '9')\r
+ {\r
+ int i;\r
+\r
+ for (i = 0; i < ((c - '0') + 1); i++)\r
+ {\r
+ mac = cstring_appendChar (mac, ' ');\r
+ }\r
+ }\r
+ else\r
+ {\r
+ BADBRANCH;\r
+ }\r
+\r
+ while (((c = macro_nextCharC ()) != '\0') && (c != '\n'))\r
+ {\r
+ mac = cstring_appendChar (mac, c);\r
+ }\r
+\r
+ \r
+ macrocode = tokenMacroCode (mac);\r
+\r
+ if (macrocode == BADTOK && !isArtificial (mac))\r
+ {\r
+ context_addMacroCache (mac);\r
+ }\r
+ else\r
+ {\r
+ cstring_free (mac);\r
+ }\r
+\r
+ if (c == '\n')\r
+ {\r
+ context_incLineno ();\r
+ }\r
+}\r
+\r
+static bool processMacro (void)\r
+{\r
+ uentry e2;\r
+ ctype ct;\r
+ int noparams = 0;\r
+ cstring fname = cstring_undefined;\r
+ bool res = TRUE;\r
+ bool isspecfcn = FALSE;\r
+ bool isiter = FALSE;\r
+ bool skipparam = FALSE;\r
+ bool isenditer = FALSE;\r
+ bool unknownm = FALSE;\r
+ bool hasParams = FALSE;\r
+ bool emptyMacro = FALSE;\r
+ char c = skip_whitespace ();\r
+ fileloc loc = fileloc_noColumn (g_currentloc);\r
+\r
+ /* are both of these necessary? what do they mean? */\r
+ uentryList specparams = uentryList_undefined;\r
+ uentryList pn = uentryList_undefined;\r
+\r
+ context_resetMacroMissingParams ();\r
+\r
+ if (c == '\0' || c == '\n')\r
+ {\r
+ llcontbug (cstring_makeLiteral ("Bad macro"));\r
+ fileloc_free (loc);\r
+ return FALSE;\r
+ }\r
+ \r
+ fname = cstring_appendChar (fname, c); \r
+\r
+ while ((c = macro_nextChar ()) != '(' && c != '\0'\r
+ && c != ' ' && c != '\t' && c != '\n')\r
+ {\r
+ fname = cstring_appendChar (fname, c);\r
+ }\r
+\r
+ if (c == ' ' || c == '\t' || c == '\n')\r
+ {\r
+ char oldc = c;\r
+\r
+ if (c != '\n')\r
+ {\r
+ while (c == ' ' || c == '\t')\r
+ {\r
+ c = macro_nextChar ();\r
+ }\r
+ unput (c);\r
+ }\r
+\r
+ if (c == '\n')\r
+ {\r
+ emptyMacro = TRUE;\r
+ unput (c);\r
+ }\r
+\r
+ c = oldc;\r
+ }\r
+\r
+ hasParams = (c == '(');\r
+ \r
+ if (usymtab_exists (fname))\r
+ {\r
+ e2 = usymtab_lookupExpose (fname);\r
+ ct = uentry_getType (e2);\r
+\r
+ if (uentry_isCodeDefined (e2) \r
+ && fileloc_isUser (uentry_whereDefined (e2)))\r
+ {\r
+ if (optgenerror \r
+ (FLG_MACROREDEF,\r
+ message ("Macro %s already defined", fname),\r
+ loc))\r
+ {\r
+ uentry_showWhereDefined (e2);\r
+ uentry_clearDefined (e2);\r
+ }\r
+\r
+ if (uentry_isFunction (e2))\r
+ {\r
+ uentry_setType (e2, ctype_unknown);\r
+ ct = ctype_unknown;\r
+ unknownm = TRUE;\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ else\r
+ {\r
+ context_enterConstantMacro (e2);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (uentry_isForward (e2) && uentry_isFunction (e2))\r
+ {\r
+ unknownm = TRUE;\r
+\r
+ voptgenerror \r
+ (FLG_MACROFCNDECL,\r
+ message\r
+ ("Parameterized macro has no prototype or specification: %s ", \r
+ fname),\r
+ loc);\r
+ \r
+ ct = ctype_unknown;\r
+ uentry_setType (e2, ctype_unknown);\r
+ uentry_setFunctionDefined (e2, loc); \r
+ uentry_setUsed (e2, fileloc_undefined);\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ else\r
+ {\r
+ if (uentry_isIter (e2))\r
+ {\r
+ isiter = TRUE;\r
+ specparams = uentry_getParams (e2);\r
+ noparams = uentryList_size (specparams);\r
+ uentry_setDefined (e2, loc);\r
+ context_enterIterDef (e2); \r
+ }\r
+ else if (uentry_isEndIter (e2))\r
+ {\r
+ isenditer = TRUE;\r
+ uentry_setDefined (e2, loc);\r
+ context_enterIterEnd (e2); /* don't care about it now */\r
+ /* but should parse like an iter! */\r
+ }\r
+ else if (uentry_isConstant (e2))\r
+ {\r
+ if (hasParams)\r
+ {\r
+ voptgenerror \r
+ (FLG_INCONDEFS, \r
+ message ("Constant %s implemented as parameterized macro",\r
+ fname),\r
+ g_currentloc);\r
+ \r
+ uentry_showWhereSpecified (e2);\r
+ uentry_setType (e2, ctype_unknown);\r
+ uentry_makeConstantFunction (e2);\r
+ uentry_setDefined (e2, g_currentloc);\r
+ uentry_setFunctionDefined (e2, g_currentloc);\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ else\r
+ {\r
+ if (!uentry_isSpecified (e2))\r
+ {\r
+ fileloc oloc = uentry_whereDeclared (e2);\r
+\r
+ if (fileloc_isLib (oloc))\r
+ {\r
+ ;\r
+ }\r
+ else if (fileloc_isUndefined (oloc)\r
+ || fileloc_isPreproc (oloc))\r
+ {\r
+ if (!emptyMacro)\r
+ {\r
+ voptgenerror\r
+ (FLG_MACROCONSTDECL,\r
+ message \r
+ ("Macro constant %q not declared",\r
+ uentry_getName (e2)),\r
+ loc); \r
+ }\r
+ }\r
+ else if (!fileloc_withinLines (oloc, loc, 2))\r
+ { /* bogus! will give errors if there is too much whitespace */\r
+ voptgenerror\r
+ (FLG_SYNTAX,\r
+ message \r
+ ("Macro constant name %s does not match name in "\r
+ "previous constant declaration. This constant "\r
+ "is declared at %q", fname, \r
+ fileloc_unparse (oloc)),\r
+ loc);\r
+ }\r
+ }\r
+\r
+ context_enterConstantMacro (e2); \r
+ cstring_free (fname);\r
+ fileloc_free (loc);\r
+ return res;\r
+ }\r
+\r
+ }\r
+ else if (ctype_isFunction (ct))\r
+ {\r
+ isspecfcn = TRUE;\r
+ specparams = ctype_argsFunction (ct);\r
+ noparams = uentryList_size (specparams);\r
+ \r
+ uentry_setFunctionDefined (e2, loc); \r
+ context_enterMacro (e2);\r
+ }\r
+ else if (uentry_isVar (e2))\r
+ {\r
+ if (hasParams)\r
+ {\r
+ voptgenerror\r
+ (FLG_INCONDEFS,\r
+ message ("Variable %s implemented as parameterized macro", \r
+ fname),\r
+ loc);\r
+\r
+ uentry_showWhereSpecified (e2);\r
+ uentry_setType (e2, ctype_unknown);\r
+ uentry_makeVarFunction (e2);\r
+ uentry_setDefined (e2, g_currentloc);\r
+ uentry_setFunctionDefined (e2, g_currentloc);\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ else\r
+ {\r
+ uentry ucons = uentry_makeConstant (fname,\r
+ ctype_unknown,\r
+ loc);\r
+ if (uentry_isExpandedMacro (e2))\r
+ {\r
+ ; /* okay */\r
+ }\r
+ else\r
+ {\r
+ if (optgenerror \r
+ (FLG_INCONDEFS,\r
+ message ("Variable %s implemented by a macro",\r
+ fname),\r
+ loc))\r
+ {\r
+ uentry_showWhereSpecified (e2);\r
+ }\r
+ }\r
+\r
+ uentry_setDefined (e2, loc);\r
+ uentry_setUsed (ucons, loc);\r
+\r
+ context_enterConstantMacro (ucons);\r
+ uentry_markOwned (ucons);\r
+ cstring_free (fname);\r
+ return res;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (uentry_isDatatype (e2))\r
+ {\r
+ vgenhinterror \r
+ (FLG_SYNTAX,\r
+ message ("Type implemented as macro: %x", \r
+ uentry_getName (e2)),\r
+ message ("A type is implemented using a macro definition. A "\r
+ "typedef should be used instead."),\r
+ g_currentloc);\r
+\r
+ swallowMacro ();\r
+ /* Must exit scope (not sure why a new scope was entered?) */\r
+ usymtab_quietExitScope (g_currentloc);\r
+ uentry_setDefined (e2, g_currentloc);\r
+ res = FALSE;\r
+ }\r
+ else\r
+ {\r
+ llcontbug \r
+ (message ("Unexpanded macro not function or constant: %q", \r
+ uentry_unparse (e2)));\r
+ uentry_setType (e2, ctype_unknown);\r
+ \r
+ if (hasParams)\r
+ {\r
+ uentry_makeVarFunction (e2);\r
+ uentry_setDefined (e2, g_currentloc);\r
+ uentry_setFunctionDefined (e2, g_currentloc);\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uentry ce;\r
+\r
+ /* evans 2001-09-09 - if it has params, assume a function */\r
+ if (hasParams)\r
+ {\r
+ voptgenerror \r
+ (FLG_MACROMATCHNAME,\r
+ message ("Unexpanded macro %s does not match name of a declared "\r
+ "function. The name used in the control "\r
+ "comment on the previous line should match.",\r
+ fname),\r
+ loc);\r
+ \r
+ ce = uentry_makeFunction (fname, ctype_unknown, \r
+ typeId_invalid,\r
+ globSet_undefined,\r
+ sRefSet_undefined,\r
+ warnClause_undefined,\r
+ fileloc_undefined); \r
+ uentry_setUsed (ce, loc); /* perhaps bogus? */\r
+ e2 = usymtab_supEntryReturn (ce);\r
+ context_enterUnknownMacro (e2); \r
+ }\r
+ else\r
+ {\r
+ voptgenerror \r
+ (FLG_MACROMATCHNAME,\r
+ message ("Unexpanded macro %s does not match name of a constant "\r
+ "or iter declaration. The name used in the control "\r
+ "comment on the previous line should match. "\r
+ "(Assuming macro defines a constant.)", \r
+ fname),\r
+ loc);\r
+ \r
+ ce = uentry_makeConstant (fname, ctype_unknown, fileloc_undefined); \r
+ uentry_setUsed (ce, loc); /* perhaps bogus? */\r
+ e2 = usymtab_supEntryReturn (ce);\r
+ \r
+ context_enterConstantMacro (e2); \r
+ cstring_free (fname);\r
+ fileloc_free (loc);\r
+ return res;\r
+ }\r
+ }\r
+ \r
+ /* in macros, ( must follow immediatetly after name */\r
+ \r
+ if (hasParams)\r
+ {\r
+ int paramno = 0;\r
+ \r
+ c = skip_whitespace ();\r
+\r
+ while (c != ')' && c != '\0')\r
+ {\r
+ uentry param;\r
+ bool suppress = context_inSuppressRegion ();\r
+ cstring paramname = cstring_undefined;\r
+\r
+ /*\r
+ ** save the parameter location\r
+ */\r
+\r
+ decColumn ();\r
+ context_saveLocation ();\r
+ incColumn ();\r
+\r
+ while (c != ' ' && c != '\t' && c != ',' && c != '\0' && c != ')')\r
+ {\r
+ paramname = cstring_appendChar (paramname, c);\r
+ c = macro_nextChar ();\r
+ }\r
+ \r
+ if (c == ' ' || c == '\t') c = skip_whitespace ();\r
+\r
+ if (c == ',')\r
+ {\r
+ c = macro_nextChar ();\r
+ if (c == ' ' || c == '\t') c = skip_whitespace ();\r
+ }\r
+ \r
+ if (c == '\0')\r
+ {\r
+ llfatalerror (cstring_makeLiteral\r
+ ("Bad macro syntax: uentryList"));\r
+ }\r
+ \r
+ if ((isspecfcn || isiter) && (paramno < noparams)\r
+ && !uentry_isElipsisMarker (uentryList_getN \r
+ (specparams, paramno)))\r
+ {\r
+ fileloc sloc = context_getSaveLocation ();\r
+ uentry decl = uentryList_getN (specparams, paramno);\r
+ sRef sr;\r
+ \r
+ param = uentry_nameCopy (paramname, decl);\r
+ \r
+ uentry_setParam (param);\r
+ sr = sRef_makeParam (paramno, uentry_getType (param), stateInfo_makeLoc (sloc));\r
+\r
+ if (sRef_getNullState (sr) == NS_ABSNULL)\r
+ {\r
+ ctype pt = ctype_realType (uentry_getType (param));\r
+\r
+ if (ctype_isUser (pt))\r
+ {\r
+ uentry te = usymtab_getTypeEntrySafe (ctype_typeId (pt));\r
+ \r
+ if (uentry_isValid (te))\r
+ {\r
+ sRef_setStateFromUentry (sr, te);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ sRef_setNullState (sr, NS_UNKNOWN, sloc);\r
+ }\r
+ }\r
+\r
+ uentry_setSref (param, sr);\r
+ uentry_setDeclaredForceOnly (param, sloc);\r
+\r
+ skipparam = isiter && uentry_isOut (uentryList_getN (specparams, paramno));\r
+ }\r
+ else\r
+ {\r
+ fileloc sloc = context_getSaveLocation ();\r
+\r
+ param = uentry_makeVariableSrefParam \r
+ (paramname, ctype_unknown, fileloc_copy (sloc), \r
+ sRef_makeParam (paramno, ctype_unknown, stateInfo_makeLoc (sloc)));\r
+ DPRINTF (("Unknown param: %s", uentry_unparseFull (param)));\r
+ cstring_free (paramname);\r
+\r
+ sRef_setPosNull (uentry_getSref (param), sloc);\r
+ uentry_setDeclaredForce (param, sloc);\r
+\r
+ skipparam = FALSE;\r
+ fileloc_free (sloc);\r
+ }\r
+\r
+ if (!skipparam)\r
+ {\r
+ llassert (!uentry_isElipsisMarker (param));\r
+\r
+ if (!suppress)\r
+ {\r
+ sRef_makeUnsafe (uentry_getSref (param));\r
+ }\r
+ \r
+ pn = uentryList_add (pn, uentry_copy (param));\r
+ usymtab_supEntry (param);\r
+ }\r
+ else\r
+ {\r
+ /* don't add param */\r
+ uentry_free (param);\r
+ }\r
+\r
+ if (c == ',') \r
+ {\r
+ (void) macro_nextChar ();\r
+ c = skip_whitespace ();\r
+ }\r
+\r
+ paramno++;\r
+ }\r
+ \r
+ if (c == ')')\r
+ {\r
+ if (isspecfcn || isiter)\r
+ {\r
+ if (paramno != noparams && noparams >= 0)\r
+ {\r
+ advanceLine ();\r
+\r
+ voptgenerror \r
+ (FLG_INCONDEFS,\r
+ message ("Macro %s specified with %d args, defined with %d", \r
+ fname, noparams, paramno),\r
+ g_currentloc);\r
+\r
+ uentry_showWhereSpecified (e2);\r
+ uentry_resetParams (e2, pn);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ uentry_resetParams (e2, pn);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*\r
+ ** the form should be:\r
+ **\r
+ ** # define newname oldname\r
+ ** where oldname refers to a function matching the specification\r
+ ** of newname.\r
+ */\r
+\r
+ if (unknownm)\r
+ {\r
+ sRef_setGlobalScope ();\r
+ usymtab_supGlobalEntry (uentry_makeVariableLoc (fname, ctype_unknown));\r
+ sRef_clearGlobalScope ();\r
+ }\r
+ else\r
+ {\r
+ context_setMacroMissingParams ();\r
+ }\r
+ }\r
+ \r
+ \r
+ /* context_setuentryList (pn); */\r
+ usymtab_enterScope ();\r
+\r
+ fileloc_free (loc);\r
+ cstring_free (fname);\r
+\r
+ return res;\r
+}\r
+\r
+static bool handleSpecial (char *yyt)\r
+{\r
+ char *l = mstring_create (MAX_NAME_LENGTH);\r
+ static bool reportcpp = FALSE;\r
+ int lineno = 0;\r
+ char c;\r
+ char *ol;\r
+ cstring olc;\r
+ \r
+ strcpy (l, yyt + 1);\r
+\r
+ /* Need to safe original l for deallocating. */\r
+ ol = l;\r
+\r
+ l += strlen (yyt) - 1;\r
+ \r
+ while ((c = char_fromInt (lminput ())) != '\n' && c != '\0')\r
+ {\r
+ *l++ = c;\r
+ }\r
+\r
+ *l = '\0';\r
+ olc = cstring_fromChars (ol);\r
+ \r
+ if (cstring_equalPrefixLit (olc, "pragma"))\r
+ {\r
+ char *pname = mstring_create (longUnsigned_fromInt (MAX_PRAGMA_LEN));\r
+ char *opname = pname;\r
+ char *ptr = ol + 6; /* pragma is six characters, plus space */\r
+ int len = 0;\r
+ \r
+ \r
+ /* skip whitespace */\r
+ while (((c = *ptr) != '\0') && isspace (c))\r
+ {\r
+ ptr++;\r
+ }\r
+\r
+ \r
+ while (((c = *ptr) != '\0') && !isspace (c))\r
+ {\r
+ len++;\r
+\r
+ if (len > MAX_PRAGMA_LEN)\r
+ {\r
+ break;\r
+ }\r
+\r
+ ptr++;\r
+ *pname++ = c;\r
+ }\r
+\r
+ *pname = '\0';\r
+ \r
+ if (len == PRAGMA_LEN_EXPAND \r
+ && mstring_equal (opname, PRAGMA_EXPAND))\r
+ {\r
+ cstring exname = cstring_undefined;\r
+ uentry ue;\r
+ \r
+ ptr++; \r
+ while (((c = *ptr) != '\0') && !isspace (c))\r
+ {\r
+ exname = cstring_appendChar (exname, c);\r
+ ptr++;\r
+ }\r
+ \r
+ \r
+ ue = usymtab_lookupExposeGlob (exname);\r
+ \r
+ if (uentry_isExpandedMacro (ue))\r
+ {\r
+ if (fileloc_isPreproc (uentry_whereDefined (ue)))\r
+ {\r
+ fileloc_setColumn (g_currentloc, 1);\r
+ uentry_setDefined (ue, g_currentloc);\r
+ }\r
+ }\r
+\r
+ cstring_free (exname);\r
+ }\r
+ }\r
+ else if (cstring_equalPrefixLit (olc, "ident"))\r
+ {\r
+ /* Some pre-processors will leave these in the code. Ignore rest of line */\r
+ }\r
+ /*\r
+ ** Yuk...Win32 filenames can have spaces in them...we need to read\r
+ ** to the matching end quote.\r
+ */\r
+ else if ((sscanf (ol, "line %d \"", &lineno) == 1)\r
+ || (sscanf (ol, " %d \"", &lineno) == 1))\r
+ {\r
+ char *tmp = ol;\r
+ cstring fname;\r
+ fileId fid;\r
+\r
+ /*@access cstring@*/\r
+ while (*tmp != '\"' && *tmp != '\0')\r
+ {\r
+ tmp++;\r
+ }\r
+\r
+ llassert (*tmp == '\"');\r
+\r
+ tmp++;\r
+\r
+ fname = tmp;\r
+ \r
+ while (*tmp != '\"' && *tmp != '\0')\r
+ {\r
+ tmp++;\r
+ }\r
+\r
+ llassert (*tmp == '\"');\r
+\r
+ *tmp = '\0';\r
+\r
+# if defined(OS2) || defined(MSDOS) || defined(WIN32)\r
+\r
+ /*\r
+ ** DOS-like path delimiters get delivered in pairs, something like \r
+ ** \"..\\\\file.h\", so we have to make it normal again. We do NOT\r
+ ** remove the pre dirs yet as we usually specify tmp paths relative\r
+ ** to the current directory, so tmp files would not get found in\r
+ ** the hash table. If this method fails we try it again later. \r
+ */\r
+\r
+ {\r
+ char *stmp = fname;\r
+ \r
+ /*\r
+ ** Skip past the drive marker.\r
+ */\r
+ \r
+ if (strchr (stmp, ':') != NULL)\r
+ {\r
+ stmp = strchr (stmp, ':') + 1;\r
+ }\r
+ \r
+ while ((stmp = strchr (stmp, CONNECTCHAR)) != NULL )\r
+ {\r
+ if (*(stmp+1) == CONNECTCHAR)\r
+ {\r
+ memmove (stmp, stmp+1, strlen (stmp));\r
+ }\r
+ \r
+ stmp++;\r
+ }\r
+ \r
+ fid = fileTable_lookupBase (context_fileTable (), fname);\r
+ if (!(fileId_isValid (fid)))\r
+ {\r
+ fname = removePreDirs (fname);\r
+ fid = fileTable_lookupBase (context_fileTable (), fname);\r
+ }\r
+ }\r
+# else /* !defined(OS2) && !defined(MSDOS) */\r
+ fname = removePreDirs (fname);\r
+ fid = fileTable_lookupBase (context_fileTable (), fname); \r
+# endif /* !defined(OS2) && !defined(MSDOS) */\r
+ \r
+ if (!(fileId_isValid (fid)))\r
+ {\r
+ if (context_inXHFile ())\r
+ {\r
+ fid = fileTable_addXHFile (context_fileTable (), fname);\r
+ }\r
+ else if (isHeaderFile (fname))\r
+ {\r
+ fid = fileTable_addHeaderFile (context_fileTable (), fname);\r
+ }\r
+ else\r
+ {\r
+ fid = fileTable_addFile (context_fileTable (), fname);\r
+ }\r
+ }\r
+ \r
+ setFileLine (fid, lineno);\r
+ /*@noaccess cstring@*/\r
+ }\r
+ else if ((sscanf (ol, "line %d", &lineno) == 1) \r
+ || (sscanf (ol, " %d", &lineno) == 1))\r
+ {\r
+ setLine (lineno); /* next line is <cr> */\r
+ }\r
+ else\r
+ {\r
+ if (mstring_equal (ol, "")) {\r
+ DPRINTF (("Empty pp command!"));\r
+ /*\r
+ ** evs 2000-05-16: This is a horrible kludge, to get around a bug (well, difficulty) in the pre-processor.\r
+ ** We handle a plain # in the input file, by echoing it, and ignoring it in the post-pp-file.\r
+ */\r
+ mstring_free (ol);\r
+ return FALSE;\r
+ } else {\r
+ if (!reportcpp)\r
+ {\r
+ \r
+ } else {\r
+ llbug (message ("File contains preprocessor command: #%s", \r
+ cstring_fromChars (ol)));\r
+ reportcpp = TRUE;\r
+ }\r
+ }\r
+ \r
+ sfree (ol);\r
+ return TRUE;\r
+ }\r
+\r
+ sfree (ol);\r
+ return FALSE;\r
+}\r
+ \r
+static int handleLlSpecial ()\r
+{ \r
+ bool hasnl = FALSE;\r
+ int ic; \r
+ char c;\r
+ char *s = mstring_createEmpty ();\r
+ char *os; \r
+ int tok;\r
+ int charsread = 0;\r
+ fileloc loc;\r
+\r
+ loc = fileloc_copy (g_currentloc);\r
+ DPRINTF (("Handle special: %s", fileloc_unparse (loc)));\r
+\r
+ while (((ic = ninput ()) != 0) && isalpha (ic))\r
+ {\r
+ c = (char) ic;\r
+ s = mstring_append (s, c);\r
+ charsread++;\r
+ }\r
+\r
+ DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));\r
+ os = s;\r
+\r
+ if (charsread == 0 && ic == (int) AFTER_COMMENT_MARKER[0])\r
+ {\r
+ ic = ninput ();\r
+\r
+ llassert (ic == AFTER_COMMENT_MARKER[1]);\r
+ \r
+ if (*s == '\0')\r
+ {\r
+ sfree (os);\r
+ fileloc_free (loc);\r
+ return QNOMODS; /* special token no modifications token */\r
+ }\r
+ }\r
+ \r
+ DPRINTF (("Coment marker: %s", os));\r
+ tok = commentMarkerToken (cstring_fromChars (os));\r
+\r
+ if (tok != BADTOK)\r
+ {\r
+ tokLength = charsread;\r
+ sfree (os);\r
+ inSpecPart = TRUE;\r
+ fileloc_free (loc);\r
+ return tok;\r
+ }\r
+\r
+ DPRINTF (("Not a comment marker..."));\r
+ /* Add rest of the comment */\r
+ \r
+ if (ic != 0 && ic != EOF)\r
+ {\r
+ c = (char) ic;\r
+ \r
+ s = mstring_append (s, c);\r
+ charsread++;\r
+\r
+ while (((ic = ninput ()) != 0) && (ic != EOF)\r
+ && (ic != AFTER_COMMENT_MARKER[0]))\r
+ {\r
+ c = (char) ic;\r
+\r
+ /* evans 2001-09-01 added to prevent assertion failures for uncloses syntactic comments */\r
+\r
+ if (c == '\n') {\r
+ hasnl = TRUE; /* This prevents tokLength from being set later. */\r
+ tokLength = 0; \r
+\r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Likely parse error: syntactic comment token spans multiple lines: %s",\r
+ cstring_fromChars (s)),\r
+ g_currentloc);\r
+ }\r
+\r
+ s = mstring_append (s, c);\r
+ charsread++;\r
+ }\r
+ }\r
+\r
+ DPRINTF (("Read: %s / %s", s, fileloc_unparse (g_currentloc)));\r
+\r
+ if (ic == AFTER_COMMENT_MARKER[0]) \r
+ {\r
+ int nc = ninput ();\r
+ llassert ((char) nc == AFTER_COMMENT_MARKER[1]);\r
+ charsread++;\r
+ }\r
+\r
+ os = s;\r
+\r
+ while (*s == ' ' || *s == '\t' || *s == '\n') \r
+ {\r
+ s++;\r
+ }\r
+\r
+ if (*s == '-' || *s == '+' || *s == '=') /* setting flags */\r
+ {\r
+ c = *s;\r
+\r
+ while (c == '-' || c == '+' || c == '=')\r
+ {\r
+ ynm set = ynm_fromCodeChar (c);\r
+ cstring thisflag;\r
+\r
+ s++;\r
+ \r
+ thisflag = cstring_fromChars (s);\r
+ \r
+ while ((c = *s) != '\0' && (c != '-') && (c != '=')\r
+ && (c != '+') && (c != ' ') && (c != '\t') && (c != '\n'))\r
+ {\r
+ s++;\r
+ }\r
+\r
+ *s = '\0';\r
+\r
+ if (!context_getFlag (FLG_NOCOMMENTS))\r
+ {\r
+ cstring flagname = thisflag;\r
+ flagcode fflag = identifyFlag (flagname);\r
+ \r
+ if (flagcode_isSkip (fflag))\r
+ {\r
+ ;\r
+ }\r
+ else if (flagcode_isInvalid (fflag))\r
+ {\r
+ if (isMode (flagname))\r
+ {\r
+ if (ynm_isMaybe (set))\r
+ {\r
+ llerror\r
+ (FLG_BADFLAG, \r
+ message \r
+ ("Semantic comment attempts to restore flag %s. "\r
+ "A mode flag cannot be restored.",\r
+ flagname));\r
+ }\r
+ else\r
+ {\r
+ context_setMode (flagname);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ voptgenerror\r
+ (FLG_UNRECOGFLAGCOMMENTS,\r
+ message ("Unrecognized option in semantic comment: %s", \r
+ flagname),\r
+ g_currentloc);\r
+ }\r
+ }\r
+ else if (flagcode_isGlobalFlag (fflag))\r
+ {\r
+ voptgenerror\r
+ (FLG_BADFLAG, \r
+ message \r
+ ("Semantic comment attempts to set global flag %s. "\r
+ "A global flag cannot be set locally.",\r
+ flagname),\r
+ g_currentloc);\r
+ }\r
+ else\r
+ {\r
+ context_fileSetFlag (fflag, set);\r
+ \r
+ if (flagcode_hasArgument (fflag))\r
+ {\r
+ if (ynm_isMaybe (set))\r
+ {\r
+ voptgenerror\r
+ (FLG_BADFLAG, \r
+ message \r
+ ("Semantic comment attempts to restore flag %s. "\r
+ "A flag for setting a value cannot be restored.",\r
+ flagname),\r
+ g_currentloc);\r
+ }\r
+ else\r
+ { /* cut-and-pastied from llmain...blecch */\r
+ cstring extra = cstring_undefined;\r
+ char *rest;\r
+ char *orest;\r
+ char rchar;\r
+ \r
+ *s = c;\r
+ rest = mstring_copy (s);\r
+ orest = rest;\r
+ *s = '\0';\r
+ \r
+ while ((rchar = *rest) != '\0'\r
+ && (isspace (rchar)))\r
+ {\r
+ rest++;\r
+ s++;\r
+ }\r
+ \r
+ while ((rchar = *rest) != '\0'\r
+ && !isspace (rchar))\r
+ {\r
+ extra = cstring_appendChar (extra, rchar);\r
+ rest++; \r
+ s++;\r
+ }\r
+ \r
+ sfree (orest);\r
+ \r
+ if (cstring_isUndefined (extra))\r
+ {\r
+ llerror \r
+ (FLG_BADFLAG,\r
+ message\r
+ ("Flag %s (in semantic comment) must be followed by an argument",\r
+ flagcode_unparse (fflag)));\r
+ }\r
+ else\r
+ {\r
+ s--;\r
+ \r
+ if (flagcode_hasValue (fflag))\r
+ {\r
+ setValueFlag (fflag, extra);\r
+ }\r
+ else if (flagcode_hasString (fflag))\r
+ {\r
+ setStringFlag (fflag, extra);\r
+ }\r
+ else\r
+ {\r
+ BADEXIT;\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+\r
+ *s = c;\r
+ while ((c == ' ') || (c == '\t') || (c == '\n'))\r
+ {\r
+ c = *(++s);\r
+ }\r
+ } \r
+\r
+ if (context_inHeader () && !isArtificial (cstring_fromChars (os)))\r
+ {\r
+ DPRINTF (("Here adding comment: %s", os));\r
+ context_addComment (cstring_fromCharsNew (os));\r
+ }\r
+ else\r
+ {\r
+ ;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ char *t = s;\r
+ int macrocode;\r
+ char tchar = '\0';\r
+ annotationInfo ainfo;\r
+\r
+ while (*s != '\0' && *s != ' ' && *s != '\t' && *s != '\n') \r
+ {\r
+ s++;\r
+ }\r
+\r
+ if (*s != '\0') \r
+ {\r
+ tchar = *s;\r
+ *s = '\0';\r
+ s++;\r
+ }\r
+ \r
+ t = cstring_toCharsSafe (cstring_downcase (cstring_fromChars (t)));\r
+ macrocode = tokenMacroCode (cstring_fromChars (t));\r
+\r
+ if (macrocode != BADTOK)\r
+ {\r
+ tokLength = hasnl ? 0 : mstring_length (t);\r
+ \r
+ sfree (t);\r
+ sfree (os);\r
+ fileloc_free (loc);\r
+\r
+ if (macrocode == SKIPTOK)\r
+ {\r
+ return BADTOK;\r
+ }\r
+\r
+ return macrocode;\r
+ }\r
+ \r
+ ainfo = context_lookupAnnotation (cstring_fromChars (os));\r
+ \r
+ if (annotationInfo_isDefined (ainfo)) {\r
+ DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));\r
+ /*@i324@*/ yylval.annotation = ainfo;\r
+ tokLength = 0;\r
+ sfree (os);\r
+ sfree (t);\r
+ fileloc_free (loc);\r
+ return CANNOTATION;\r
+ } \r
+\r
+ if (context_inHeader ())\r
+ {\r
+ if (tchar != '\0')\r
+ {\r
+ *(s-1) = tchar;\r
+ }\r
+ \r
+ if ((context_inMacro () || context_inGlobalContext ())\r
+ && macrocode != SKIPTOK\r
+ && !isArtificial (cstring_fromChars (os))) \r
+ {\r
+ DPRINTF (("Add comment: %s", os));\r
+ context_addComment (cstring_fromCharsNew (os));\r
+ }\r
+ else\r
+ {\r
+ ; \r
+ }\r
+ \r
+ if (tchar != '\0')\r
+ {\r
+ *(s-1) = '\0';\r
+ }\r
+ }\r
+\r
+ if (mstring_equal (t, "ignore"))\r
+ {\r
+ if (!context_getFlag (FLG_NOCOMMENTS))\r
+ {\r
+ context_enterSuppressRegion ();\r
+ }\r
+ }\r
+ else if ((*t == 'i' || *t == 't')\r
+ && (*(t + 1) == '\0'))\r
+ {\r
+ if (!context_getFlag (FLG_NOCOMMENTS)\r
+ && (*t == 'i' || context_getFlag (FLG_TMPCOMMENTS)))\r
+ {\r
+ context_enterSuppressLine (-1); /* infinite suppression */\r
+ }\r
+ }\r
+ else if (((*t == 'i') || (*t == 't'))\r
+ && ((*(t + 1) >= '0' && *(t + 1) <= '9')))\r
+ {\r
+ bool tmpcomment = (*t == 't');\r
+ int val = -1; \r
+ char *tt = t; /* don't mangle t, since it is free'd */\r
+ char lc = *(++tt);\r
+\r
+ if (lc >= '0' && lc <= '9')\r
+ {\r
+ val = (int)(lc - '0');\r
+ \r
+ lc = *(++tt); \r
+ while (lc >= '0' && lc <= '9')\r
+ {\r
+ val *= 10;\r
+ val += lc - '0';\r
+ lc = *(++tt);\r
+ }\r
+ }\r
+\r
+ \r
+ if (!context_getFlag (FLG_NOCOMMENTS)\r
+ && (!tmpcomment || context_getFlag (FLG_TMPCOMMENTS)))\r
+ {\r
+ context_enterSuppressLine (val);\r
+ }\r
+ }\r
+ else if (mstring_equal (t, "end"))\r
+ {\r
+ if (!context_getFlag (FLG_NOCOMMENTS))\r
+ {\r
+ context_exitSuppressRegion ();\r
+ }\r
+ }\r
+ else if (mstring_equal (t, "notfunction"))\r
+ {\r
+ ; /* handled by pcpp */\r
+ }\r
+ else if (mstring_equal (t, "access"))\r
+ {\r
+ cstring tname;\r
+ \r
+ while (TRUE)\r
+ {\r
+ while ((c = *s) && (c == ' ' || c == '\t' || c == '\n'))\r
+ {\r
+ s++;\r
+ }\r
+ \r
+ if (c == '\0')\r
+ {\r
+ break;\r
+ }\r
+\r
+ tname = cstring_fromChars (s);\r
+ \r
+ while ((c = *s) != '\0' && c != ' ' \r
+ && c != '\t' && c != '\n' && c != ',') \r
+ {\r
+ s++;\r
+ }\r
+\r
+ *s = '\0';\r
+\r
+ DPRINTF (("Access %s", tname));\r
+\r
+ if (!context_getFlag (FLG_NOCOMMENTS) \r
+ && !context_getFlag (FLG_NOACCESS))\r
+ {\r
+ if (usymtab_existsType (tname))\r
+ {\r
+ typeId uid = usymtab_getTypeId (tname);\r
+ uentry ue = usymtab_getTypeEntry (uid);\r
+\r
+ if (uentry_isAbstractDatatype (ue))\r
+ {\r
+ context_addFileAccessType (uid);\r
+ DPRINTF (("Adding access to: %s / %d", tname, uid));\r
+ }\r
+ else\r
+ {\r
+ voptgenerror\r
+ (FLG_COMMENTERROR,\r
+ message\r
+ ("Non-abstract type %s used in access comment",\r
+ tname),\r
+ g_currentloc);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (!(context_inSuppressRegion ()\r
+ || context_inSuppressZone (g_currentloc)))\r
+ {\r
+ voptgenerror\r
+ (FLG_COMMENTERROR,\r
+ message\r
+ ("Unrecognized type %s used in access comment",\r
+ tname),\r
+ g_currentloc);\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (c != '\0') \r
+ {\r
+ s++;\r
+ }\r
+ \r
+ if (c != ',' && c != ' ')\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else if (mstring_equal (t, "noaccess"))\r
+ {\r
+ cstring tname;\r
+ char lc;\r
+ \r
+ while (TRUE)\r
+ {\r
+ while ((lc = *s) && (lc == ' ' || lc == '\t' || lc == '\n')) \r
+ {\r
+ s++;\r
+ }\r
+ \r
+ if (lc == '\0')\r
+ {\r
+ break;\r
+ }\r
+\r
+ tname = cstring_fromChars (s);\r
+ \r
+ while ((lc = *s) != '\0' && lc != ' ' && lc != '\t' \r
+ && lc != '\n' && lc != ',') \r
+ {\r
+ s++;\r
+ }\r
+\r
+ *s = '\0';\r
+\r
+ if (!context_getFlag (FLG_NOCOMMENTS) \r
+ && !context_getFlag (FLG_NOACCESS))\r
+ {\r
+ if (usymtab_existsType (tname))\r
+ {\r
+ typeId tuid = usymtab_getTypeId (tname);\r
+ \r
+ if (context_couldHaveAccess (tuid))\r
+ {\r
+ DPRINTF (("Removing access: %s", tname));\r
+ context_removeFileAccessType (tuid);\r
+ }\r
+ else\r
+ {\r
+ if (!(context_inSuppressRegion () \r
+ || context_inSuppressZone (g_currentloc)))\r
+ {\r
+ uentry ue = usymtab_getTypeEntry (tuid);\r
+ \r
+ if (uentry_isAbstractDatatype (ue))\r
+ {\r
+ voptgenerror\r
+ (FLG_COMMENTERROR,\r
+ message\r
+ ("Non-accessible abstract type %s used in noaccess comment",\r
+ tname),\r
+ g_currentloc);\r
+ }\r
+ else\r
+ {\r
+ voptgenerror\r
+ (FLG_COMMENTERROR,\r
+ message\r
+ ("Non-abstract type %s used in noaccess comment",\r
+ tname),\r
+ g_currentloc);\r
+ }\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (!(context_inSuppressRegion () \r
+ || context_inSuppressZone (g_currentloc)))\r
+ {\r
+ voptgenerror\r
+ (FLG_COMMENTERROR,\r
+ message\r
+ ("Unrecognized type %s used in noaccess comment",\r
+ tname),\r
+ g_currentloc);\r
+ }\r
+ }\r
+ }\r
+ \r
+ if (lc != '\0') \r
+ {\r
+ s++;\r
+ }\r
+ \r
+ if (lc != ',' && lc != ' ')\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ voptgenerror (FLG_UNRECOGCOMMENTS, \r
+ message ("Semantic comment unrecognized: %s", \r
+ cstring_fromChars (os)), loc);\r
+ }\r
+\r
+ sfree (t);\r
+ }\r
+ \r
+ sfree (os);\r
+ fileloc_free (loc);\r
+ return BADTOK;\r
+}\r
+\r
+static /*@only@*/ cstring makeIdentifier (char *s)\r
+{\r
+ char *c = mstring_create (size_toInt (strlen (s)) + 1);\r
+ cstring id = cstring_fromChars (c);\r
+\r
+ while (isalnum (*s) || (*s == '_') || (*s == '$')) \r
+ {\r
+ *c++ = *s++;\r
+ }\r
+\r
+ *c = '\0';\r
+ return (id);\r
+}\r
+\r
+/*@observer@*/ /*@dependent@*/ uentry coerceId (cstring cn)\r
+{\r
+ if (!(usymtab_exists (cn)))\r
+ {\r
+ fileloc loc = fileloc_createExternal ();\r
+ \r
+ /*\r
+ ** We need to put this in a global scope, otherwise the sRef will be deallocated.\r
+ */\r
+ \r
+ uentry ce = uentry_makeUnrecognized (cn, loc);\r
+ \r
+ if (!context_inIterEnd ())\r
+ {\r
+ voptgenerror \r
+ (FLG_SYSTEMUNRECOG, \r
+ message ("Unrecognized (possibly system) identifier: %q", \r
+ uentry_getName (ce)), \r
+ g_currentloc);\r
+ }\r
+ \r
+ return ce;\r
+ }\r
+ \r
+ return (usymtab_lookup (cn));\r
+}\r
+\r
+/*\r
+** like, coerceId, but doesn't supercede for iters\r
+*/\r
+\r
+/*@observer@*/ uentry coerceIterId (cstring cn)\r
+{\r
+ if (!(usymtab_exists (cn)))\r
+ {\r
+ return uentry_undefined;\r
+ }\r
+ \r
+ return (usymtab_lookup (cn));\r
+}\r
+\r
+/*@observer@*/ cstring LastIdentifier ()\r
+{\r
+ return (lastidprocessed);\r
+}\r
+\r
+static int processIdentifier (cstring id)\r
+{\r
+ uentry le;\r
+\r
+ if (context_getFlag (FLG_GRAMMAR))\r
+ {\r
+ lldiagmsg (message ("Process identifier: %s", id));\r
+ }\r
+\r
+ context_clearJustPopped ();\r
+ lastidprocessed = id; \r
+\r
+ if (context_inFunctionHeader ())\r
+ {\r
+ int tok = commentMarkerToken (id);\r
+ DPRINTF (("in function decl..."));\r
+\r
+ if (tok != BADTOK)\r
+ {\r
+ return tok;\r
+ }\r
+ else \r
+ {\r
+ tok = tokenMacroCode (id);\r
+\r
+ if (tok != BADTOK)\r
+ {\r
+ return tok;\r
+ }\r
+ else \r
+ {\r
+ annotationInfo ainfo;\r
+\r
+ if (expectingMetaStateName) \r
+ {\r
+ metaStateInfo msinfo = context_lookupMetaStateInfo (id);\r
+\r
+ if (metaStateInfo_isDefined (msinfo))\r
+ {\r
+ yylval.msinfo = msinfo;\r
+ return METASTATE_NAME;\r
+ }\r
+ else\r
+ {\r
+ DPRINTF (("Not meta state name: %s", cstring_toCharsSafe (id)));\r
+ }\r
+ }\r
+ \r
+ ainfo = context_lookupAnnotation (id);\r
+ \r
+ if (annotationInfo_isDefined (ainfo)) \r
+ {\r
+ DPRINTF (("Found annotation: %s", annotationInfo_unparse (ainfo)));\r
+ /*@i324@*/ yylval.annotation = ainfo;\r
+ return CANNOTATION;\r
+ }\r
+ else\r
+ {\r
+ DPRINTF (("Not annotation: %s", id));\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ /* Consider handling: Defined by C99 as static const char __func__[] */\r
+\r
+ if (context_getFlag (FLG_GNUEXTENSIONS))\r
+ {\r
+ int tok = BADTOK;\r
+ \r
+ if (cstring_equalLit (id, "__stdcall")\r
+ || cstring_equalLit (id, "__cdecl")\r
+ || cstring_equalLit (id, "__extension__"))\r
+ {\r
+ return BADTOK;\r
+ }\r
+ else if (cstring_equalLit (id, "__volatile__"))\r
+ {\r
+ tok = QVOLATILE;\r
+ }\r
+ else if (cstring_equalLit (id, "__signed"))\r
+ {\r
+ tok = QSIGNED;\r
+ }\r
+ else if (cstring_equalLit (id, "__unsigned"))\r
+ {\r
+ tok = QUNSIGNED;\r
+ }\r
+ else if (cstring_equalLit (id, "__const__"))\r
+ {\r
+ tok = QCONST;\r
+ }\r
+ else if (cstring_equalLit (id, "__alignof__")) \r
+ {\r
+ tok = CALIGNOF; /* alignof is parsed like sizeof */\r
+ }\r
+ else if (cstring_equalLit (id, "__FUNCTION__")\r
+ || cstring_equalLit (id, "__PRETTY_FUNCTION__")) \r
+ {\r
+ /* These tokens hold the name of the current function as strings */\r
+ yylval.expr = exprNode_stringLiteral (id, fileloc_copy (g_currentloc));\r
+ tokLength = 0;\r
+ lastWasString = TRUE;\r
+ tok = CCONSTANT;\r
+ return tok;\r
+ }\r
+ else if (cstring_equalLit (id, "__attribute__")\r
+ || cstring_equalLit (id, "__asm__")\r
+ || cstring_equalLit (id, "_asm")\r
+ || cstring_equalLit (id, "__asm")\r
+ || cstring_equalLit (id, "__declspec"))\r
+ {\r
+ int depth = 0;\r
+ bool useparens = FALSE;\r
+ bool usebraces = FALSE;\r
+ bool inquote = FALSE;\r
+ bool inescape = FALSE;\r
+ int ic;\r
+\r
+ while ((ic = input ()) != EOF)\r
+ {\r
+ \r
+ if (inescape)\r
+ {\r
+ inescape = FALSE;\r
+ }\r
+ else if (ic == '\\')\r
+ {\r
+ inescape = TRUE;\r
+ }\r
+ else if (ic == '\"')\r
+ {\r
+ inquote = !inquote;\r
+ }\r
+ else if (!inquote)\r
+ {\r
+ if (ic == '(')\r
+ {\r
+ if (!useparens)\r
+ {\r
+ if (!usebraces)\r
+ {\r
+ useparens = TRUE;\r
+ }\r
+ }\r
+\r
+ if (useparens)\r
+ {\r
+ depth++;\r
+ }\r
+ }\r
+ else if (ic == '{')\r
+ {\r
+ if (!usebraces)\r
+ {\r
+ if (!useparens)\r
+ {\r
+ usebraces = TRUE;\r
+ }\r
+ }\r
+\r
+ if (usebraces)\r
+ {\r
+ depth++;\r
+ }\r
+ }\r
+ else if (ic == ')' && useparens)\r
+ {\r
+ depth--;\r
+ if (depth == 0) break;\r
+ }\r
+ else if (ic == '}' && usebraces)\r
+ {\r
+ depth--;\r
+ if (depth == 0) break;\r
+ }\r
+ else if (ic == '}' \r
+ && !usebraces && !useparens\r
+ && cstring_equalLit (id, "__asm"))\r
+ {\r
+ /*\r
+ ** We need this because some MS VC++ include files\r
+ ** have __asm mov ... }\r
+ ** Its a kludge, but otherwise would need to parse\r
+ ** the asm code!\r
+ */ \r
+ return TRBRACE;\r
+ }\r
+ }\r
+\r
+ if (ic == '\n')\r
+ {\r
+ context_incLineno ();\r
+\r
+ if (cstring_equalLit (id, "__asm")\r
+ && !useparens && !usebraces)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ \r
+ llassert ((useparens && ic == ')')\r
+ || (usebraces && ic == '}')\r
+ || (!useparens && !usebraces));\r
+\r
+ return BADTOK;\r
+ }\r
+ else if (cstring_equalLit (id, "inline")\r
+ || cstring_equalLit (id, "__inline")\r
+ || cstring_equalLit (id, "_inline")\r
+ || cstring_equalLit (id, "__inline__"))\r
+ {\r
+ tok = QINLINE;\r
+ }\r
+ \r
+ if (tok != BADTOK)\r
+ {\r
+ RETURN_TOK (tok);\r
+ }\r
+ }\r
+\r
+ le = usymtab_lookupSafe (id);\r
+\r
+ /*@-dependenttrans@*/\r
+ \r
+ if (uentry_isIter (le))\r
+ {\r
+ /*@i32@*/ yylval.entry = le;\r
+ return (ITER_NAME);\r
+ }\r
+ else if (uentry_isEndIter (le))\r
+ {\r
+ /*@i32@*/ yylval.entry = le;\r
+ return (ITER_ENDNAME);\r
+ }\r
+ else if (uentry_isUndefined (le))\r
+ {\r
+ yylval.cname = id;\r
+\r
+ /* avoid parse errors for certain system built ins */\r
+\r
+ if (g_expectingTypeName && (cstring_firstChar (id) == '_')\r
+ && (cstring_secondChar (id) == '_'))\r
+ {\r
+ return (TYPE_NAME_OR_ID);\r
+ }\r
+\r
+ return (NEW_IDENTIFIER);\r
+ }\r
+ else if (!uentry_isDeclared (le) && !uentry_isCodeDefined (le))\r
+ {\r
+ if (uentry_isDatatype (le))\r
+ {\r
+ yylval.cname = id;\r
+ return (NEW_IDENTIFIER);\r
+ }\r
+ else\r
+ {\r
+ /*@i32@*/ yylval.entry = le; \r
+ return (IDENTIFIER); \r
+ }\r
+ }\r
+ else if (uentry_isDatatype (le))\r
+ {\r
+ if (!g_expectingTypeName)\r
+ {\r
+ yylval.cname = id;\r
+\r
+ return (NEW_IDENTIFIER);\r
+ }\r
+ else\r
+ {\r
+ yylval.ctyp = uentry_getAbstractType (le);\r
+ \r
+ uentry_setUsed (le, g_currentloc);\r
+ return (TYPE_NAME);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ /*@i32@*/ yylval.entry = le; \r
+ return (IDENTIFIER); \r
+ }\r
+\r
+ /*@=dependenttrans@*/\r
+}\r
+\r
+static bool processHashIdentifier (/*@only@*/ cstring id)\r
+{\r
+ if (context_inMacro () || context_inIterDef () ||\r
+ context_inIterEnd ())\r
+ {\r
+ uentry le;\r
+ \r
+ context_clearJustPopped ();\r
+\r
+ lastidprocessed = id; \r
+ le = usymtab_lookupSafe (id);\r
+\r
+ if (uentry_isParam (le) || uentry_isRefParam (le))\r
+ {\r
+ return TRUE;\r
+ }\r
+ else\r
+ {\r
+ return FALSE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ cstring_free (id);\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+\r
+static /*@only@*/ exprNode processString ()\r
+{\r
+ exprNode res;\r
+ fileloc loc;\r
+ char *nl = strchr (yytext, '\n');\r
+ cstring ns = cstring_fromCharsNew (yytext);\r
+\r
+ if (nl == NULL)\r
+ {\r
+ loc = fileloc_copy (g_currentloc);\r
+ addColumn (cstring_length (ns));\r
+ }\r
+ else\r
+ {\r
+ char *lastnl = nl;\r
+\r
+ loc = fileloc_copy (g_currentloc);\r
+\r
+ context_incLineno ();\r
+ \r
+ while ((nl = strchr ((nl + 1), '\n')) != NULL)\r
+ {\r
+ context_incLineno ();\r
+ lastnl = nl;\r
+ }\r
+ }\r
+\r
+ \r
+ res = exprNode_stringLiteral (ns, loc);\r
+ return (res);\r
+}\r
+\r
+static \r
+char processChar ()\r
+{\r
+ char fchar;\r
+ char next;\r
+\r
+ llassert (*yytext != '\0');\r
+ fchar = *(yytext + 1);\r
+ if (fchar != '\\') return fchar;\r
+ \r
+ next = *(yytext + 2);\r
+ \r
+ switch (next)\r
+ {\r
+ case 'n': return '\n';\r
+ case 't': return '\t';\r
+ case '\"': return '\"';\r
+ case '\'': return '\'';\r
+ case '\\': return '\\';\r
+ default: return '\0';\r
+ }\r
+}\r
+\r
+static\r
+double processFloat ()\r
+{\r
+ double ret = atof (yytext);\r
+\r
+ return (ret);\r
+}\r
+\r
+static\r
+long processHex ()\r
+{\r
+ int index = 2;\r
+ long val = 0;\r
+\r
+ llassert (yytext[0] == '0'\r
+ && (yytext[1] == 'X' || yytext[1] == 'x'));\r
+\r
+ while (yytext[index] != '\0') {\r
+ int tval;\r
+ char c = yytext[index];\r
+\r
+ if (c >= '0' && c <= '9') {\r
+ tval = (int) c - (int) '0';\r
+ } else if (c >= 'A' && c <= 'F') {\r
+ tval = (int) c - (int) 'A' + 10;\r
+ } else if (c >= 'a' && c <= 'f') {\r
+ tval = (int) c - (int) 'a' + 10;\r
+ } else if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {\r
+ index++;\r
+ while (yytext[index] != '\0') {\r
+ if (c == 'U' || c == 'L' || c == 'u' || c == 'l') {\r
+ ;\r
+ } else {\r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Invalid character (%c) following specifier in hex constant: %s",\r
+ c, cstring_fromChars (yytext)),\r
+ g_currentloc);\r
+ }\r
+ index++;\r
+ }\r
+\r
+ break;\r
+ } else {\r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Invalid character (%c) in hex constant: %s",\r
+ c, cstring_fromChars (yytext)),\r
+ g_currentloc);\r
+ break;\r
+ }\r
+\r
+ val = (val * 16) + tval;\r
+ index++;\r
+ }\r
+\r
+ DPRINTF (("Hex constant: %s = %ld", yytext, val));\r
+ return val;\r
+}\r
+\r
+static\r
+long processOctal ()\r
+{\r
+ int index = 1;\r
+ long val = 0;\r
+\r
+ llassert (yytext[0] == '0' && yytext[1] != 'X' && yytext[1] != 'x');\r
+ \r
+ while (yytext[index] != '\0') {\r
+ int tval;\r
+ char c = yytext[index];\r
+ \r
+ if (c >= '0' && c <= '7') {\r
+ tval = (int) c - (int) '0';\r
+ } else {\r
+ voptgenerror\r
+ (FLG_SYNTAX, \r
+ message ("Invalid character (%c) in octal constant: %s",\r
+ c, cstring_fromChars (yytext)),\r
+ g_currentloc);\r
+ break;\r
+ }\r
+\r
+ val = (val * 8) + tval;\r
+ index++;\r
+ }\r
+\r
+ DPRINTF (("Octal constant: %s = %ld", yytext, val));\r
+ return val;\r
+}\r
+\r
+static\r
+long processDec ()\r
+{\r
+ return (atol (yytext));\r
+}\r
+\r
+static int\r
+processSpec (int tok)\r
+{\r
+ size_t length = strlen (yytext);\r
+ \r
+ if (inSpecPart)\r
+ {\r
+ setTokLengthT (length);\r
+ RETURN_TOK (tok);\r
+ }\r
+ else\r
+ {\r
+ \r
+ context_saveLocation ();\r
+ setTokLengthT (length);\r
+ return (processIdentifier (makeIdentifier (yytext)));\r
+ }\r
+}\r
+\r
+void cscanner_expectingMetaStateName ()\r
+{\r
+ llassert (!expectingMetaStateName);\r
+ llassert (context_inFunctionHeader ());\r
+ expectingMetaStateName = TRUE;\r
+}\r
+\r
+void cscanner_clearExpectingMetaStateName ()\r
+{\r
+ llassert (expectingMetaStateName);\r
+ expectingMetaStateName = FALSE;\r
+}\r