File Annotation
Not logged in
dbda8d6ce9 2007-07-21       drh: static const char ident[] = "@(#) $Header: /cvstrac/cvstrac/makeheaders.c,v 1.4 2005/03/16 22:17:51 drh Exp $";
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This program scans C and C++ source files and automatically generates
dbda8d6ce9 2007-07-21       drh: ** appropriate header files.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #include <stdio.h>
dbda8d6ce9 2007-07-21       drh: #include <stdlib.h>
dbda8d6ce9 2007-07-21       drh: #include <ctype.h>
dbda8d6ce9 2007-07-21       drh: #include <memory.h>
dbda8d6ce9 2007-07-21       drh: #include <sys/stat.h>
dbda8d6ce9 2007-07-21       drh: #include <assert.h>
dbda8d6ce9 2007-07-21       drh: #ifndef WIN32
dbda8d6ce9 2007-07-21       drh: # include <unistd.h>
dbda8d6ce9 2007-07-21       drh: #else
dbda8d6ce9 2007-07-21       drh: # include <string.h>
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Macros for debugging.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh: static int debugMask = 0;
dbda8d6ce9 2007-07-21       drh: # define debug0(F,M)       if( (F)&debugMask ){ fprintf(stderr,M); }
dbda8d6ce9 2007-07-21       drh: # define debug1(F,M,A)     if( (F)&debugMask ){ fprintf(stderr,M,A); }
dbda8d6ce9 2007-07-21       drh: # define debug2(F,M,A,B)   if( (F)&debugMask ){ fprintf(stderr,M,A,B); }
dbda8d6ce9 2007-07-21       drh: # define debug3(F,M,A,B,C) if( (F)&debugMask ){ fprintf(stderr,M,A,B,C); }
dbda8d6ce9 2007-07-21       drh: # define PARSER      0x00000001
dbda8d6ce9 2007-07-21       drh: # define DECL_DUMP   0x00000002
dbda8d6ce9 2007-07-21       drh: # define TOKENIZER   0x00000004
dbda8d6ce9 2007-07-21       drh: #else
dbda8d6ce9 2007-07-21       drh: # define debug0(Flags, Format)
dbda8d6ce9 2007-07-21       drh: # define debug1(Flags, Format, A)
dbda8d6ce9 2007-07-21       drh: # define debug2(Flags, Format, A, B)
dbda8d6ce9 2007-07-21       drh: # define debug3(Flags, Format, A, B, C)
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following macros are purely for the purpose of testing this
dbda8d6ce9 2007-07-21       drh: ** program on itself.  They don't really contribute to the code.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define INTERFACE 1
dbda8d6ce9 2007-07-21       drh: #define EXPORT_INTERFACE 1
dbda8d6ce9 2007-07-21       drh: #define EXPORT
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Each token in a source file is represented by an instance of
dbda8d6ce9 2007-07-21       drh: ** the following structure.  Tokens are collected onto a list.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct Token Token;
dbda8d6ce9 2007-07-21       drh: struct Token {
dbda8d6ce9 2007-07-21       drh:   const char *zText;      /* The text of the token */
dbda8d6ce9 2007-07-21       drh:   int nText;              /* Number of characters in the token's text */
dbda8d6ce9 2007-07-21       drh:   int eType;              /* The type of this token */
dbda8d6ce9 2007-07-21       drh:   int nLine;              /* The line number on which the token starts */
dbda8d6ce9 2007-07-21       drh:   Token *pComment;        /* Most recent block comment before this token */
dbda8d6ce9 2007-07-21       drh:   Token *pNext;           /* Next token on the list */
dbda8d6ce9 2007-07-21       drh:   Token *pPrev;           /* Previous token on the list */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** During tokenization, information about the state of the input
dbda8d6ce9 2007-07-21       drh: ** stream is held in an instance of the following structure
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct InStream InStream;
dbda8d6ce9 2007-07-21       drh: struct InStream {
dbda8d6ce9 2007-07-21       drh:   const char *z;          /* Complete text of the input */
dbda8d6ce9 2007-07-21       drh:   int i;                  /* Next character to read from the input */
dbda8d6ce9 2007-07-21       drh:   int nLine;              /* The line number for character z[i] */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Each declaration in the C or C++ source files is parsed out and stored as
dbda8d6ce9 2007-07-21       drh: ** an instance of the following structure.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** A "forward declaration" is a declaration that an object exists that
dbda8d6ce9 2007-07-21       drh: ** doesn't tell about the objects structure.  A typical forward declaration
dbda8d6ce9 2007-07-21       drh: ** is:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **          struct Xyzzy;
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Not every object has a forward declaration.  If it does, thought, the
dbda8d6ce9 2007-07-21       drh: ** forward declaration will be contained in the zFwd field for C and
dbda8d6ce9 2007-07-21       drh: ** the zFwdCpp for C++.  The zDecl field contains the complete
dbda8d6ce9 2007-07-21       drh: ** declaration text.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct Decl Decl;
dbda8d6ce9 2007-07-21       drh: struct Decl {
dbda8d6ce9 2007-07-21       drh:   char *zName;       /* Name of the object being declared.  The appearance
dbda8d6ce9 2007-07-21       drh:                      ** of this name is a source file triggers the declaration
dbda8d6ce9 2007-07-21       drh:                      ** to be added to the header for that file. */
dbda8d6ce9 2007-07-21       drh:   char *zFile;       /* File from which extracted.  */
dbda8d6ce9 2007-07-21       drh:   char *zIf;         /* Surround the declaration with this #if */
dbda8d6ce9 2007-07-21       drh:   char *zFwd;        /* A forward declaration.  NULL if there is none. */
dbda8d6ce9 2007-07-21       drh:   char *zFwdCpp;     /* Use this forward declaration for C++. */
dbda8d6ce9 2007-07-21       drh:   char *zDecl;       /* A full declaration of this object */
dbda8d6ce9 2007-07-21       drh:   char *zExtra;      /* Extra declaration text inserted into class objects */
dbda8d6ce9 2007-07-21       drh:   int extraType;     /* Last public:, protected: or private: in zExtraDecl */
dbda8d6ce9 2007-07-21       drh:   struct Include *pInclude;   /* #includes that come before this declaration */
dbda8d6ce9 2007-07-21       drh:   int flags;         /* See the "Properties" below */
dbda8d6ce9 2007-07-21       drh:   Token *pComment;   /* A block comment associated with this declaration */
dbda8d6ce9 2007-07-21       drh:   Token tokenCode;   /* Implementation of functions and procedures */
dbda8d6ce9 2007-07-21       drh:   Decl *pSameName;   /* Next declaration with the same "zName" */
dbda8d6ce9 2007-07-21       drh:   Decl *pSameHash;   /* Next declaration with same hash but different zName */
dbda8d6ce9 2007-07-21       drh:   Decl *pNext;       /* Next declaration with a different name */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Properties associated with declarations.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** DP_Forward and DP_Declared are used during the generation of a single
dbda8d6ce9 2007-07-21       drh: ** header file in order to prevent duplicate declarations and definitions.
dbda8d6ce9 2007-07-21       drh: ** DP_Forward is set after the object has been given a forward declaration
dbda8d6ce9 2007-07-21       drh: ** and DP_Declared is set after the object gets a full declarations.
dbda8d6ce9 2007-07-21       drh: ** (Example:  A forward declaration is "typedef struct Abc Abc;" and the
dbda8d6ce9 2007-07-21       drh: ** full declaration is "struct Abc { int a; float b; };".)
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The DP_Export and DP_Local flags are more permanent.  They mark objects
dbda8d6ce9 2007-07-21       drh: ** that have EXPORT scope and LOCAL scope respectively.  If both of these
dbda8d6ce9 2007-07-21       drh: ** marks are missing, then the object has library scope.  The meanings of
dbda8d6ce9 2007-07-21       drh: ** the scopes are as follows:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **    LOCAL scope         The object is only usable within the file in
dbda8d6ce9 2007-07-21       drh: **                        which it is declared.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **    library scope       The object is visible and usable within other
dbda8d6ce9 2007-07-21       drh: **                        files in the same project.  By if the project is
dbda8d6ce9 2007-07-21       drh: **                        a library, then the object is not visible to users
dbda8d6ce9 2007-07-21       drh: **                        of the library.  (i.e. the object does not appear
dbda8d6ce9 2007-07-21       drh: **                        in the output when using the -H option.)
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **    EXPORT scope        The object is visible and usable everywhere.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The DP_Flag is a temporary use flag that is used during processing to
dbda8d6ce9 2007-07-21       drh: ** prevent an infinite loop.  It's use is localized.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
dbda8d6ce9 2007-07-21       drh: ** and are used to specify what type of declaration the object requires.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define DP_Forward      0x001   /* Has a forward declaration in this file */
dbda8d6ce9 2007-07-21       drh: #define DP_Declared     0x002   /* Has a full declaration in this file */
dbda8d6ce9 2007-07-21       drh: #define DP_Export       0x004   /* Export this declaration */
dbda8d6ce9 2007-07-21       drh: #define DP_Local        0x008   /* Declare in its home file only */
dbda8d6ce9 2007-07-21       drh: #define DP_Flag         0x010   /* Use to mark a subset of a Decl list
dbda8d6ce9 2007-07-21       drh:                                 ** for special processing */
dbda8d6ce9 2007-07-21       drh: #define DP_Cplusplus    0x020   /* Has C++ linkage and cannot appear in a
dbda8d6ce9 2007-07-21       drh:                                 ** C header file */
dbda8d6ce9 2007-07-21       drh: #define DP_ExternCReqd  0x040   /* Prepend 'extern "C"' in a C++ header.
dbda8d6ce9 2007-07-21       drh:                                 ** Prepend nothing in a C header */
dbda8d6ce9 2007-07-21       drh: #define DP_ExternReqd   0x080   /* Prepend 'extern "C"' in a C++ header if
dbda8d6ce9 2007-07-21       drh:                                 ** DP_Cplusplus is not also set. If DP_Cplusplus
dbda8d6ce9 2007-07-21       drh:                                 ** is set or this is a C header then
dbda8d6ce9 2007-07-21       drh:                                 ** prepend 'extern' */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Convenience macros for dealing with declaration properties
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define DeclHasProperty(D,P)    (((D)->flags&(P))==(P))
dbda8d6ce9 2007-07-21       drh: #define DeclHasAnyProperty(D,P) (((D)->flags&(P))!=0)
dbda8d6ce9 2007-07-21       drh: #define DeclSetProperty(D,P)    (D)->flags |= (P)
dbda8d6ce9 2007-07-21       drh: #define DeclClearProperty(D,P)  (D)->flags &= ~(P)
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** These are state properties of the parser.  Each of the values is
dbda8d6ce9 2007-07-21       drh: ** distinct from the DP_ values above so that both can be used in
dbda8d6ce9 2007-07-21       drh: ** the same "flags" field.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Be careful not to confuse PS_Export with DP_Export or
dbda8d6ce9 2007-07-21       drh: ** PS_Local with DP_Local.  Their names are similar, but the meanings
dbda8d6ce9 2007-07-21       drh: ** of these flags are very different.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define PS_Extern        0x000800    /* "extern" has been seen */
dbda8d6ce9 2007-07-21       drh: #define PS_Export        0x001000    /* If between "#if EXPORT_INTERFACE"
dbda8d6ce9 2007-07-21       drh:                                      ** and "#endif" */
dbda8d6ce9 2007-07-21       drh: #define PS_Export2       0x002000    /* If "EXPORT" seen */
dbda8d6ce9 2007-07-21       drh: #define PS_Typedef       0x004000    /* If "typedef" has been seen */
dbda8d6ce9 2007-07-21       drh: #define PS_Static        0x008000    /* If "static" has been seen */
dbda8d6ce9 2007-07-21       drh: #define PS_Interface     0x010000    /* If within #if INTERFACE..#endif */
dbda8d6ce9 2007-07-21       drh: #define PS_Method        0x020000    /* If "::" token has been seen */
dbda8d6ce9 2007-07-21       drh: #define PS_Local         0x040000    /* If within #if LOCAL_INTERFACE..#endif */
dbda8d6ce9 2007-07-21       drh: #define PS_Local2        0x080000    /* If "LOCAL" seen. */
dbda8d6ce9 2007-07-21       drh: #define PS_Public        0x100000    /* If "PUBLIC" seen. */
dbda8d6ce9 2007-07-21       drh: #define PS_Protected     0x200000    /* If "PROTECTED" seen. */
dbda8d6ce9 2007-07-21       drh: #define PS_Private       0x400000    /* If "PRIVATE" seen. */
dbda8d6ce9 2007-07-21       drh: #define PS_PPP           0x700000    /* If any of PUBLIC, PRIVATE, PROTECTED */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following set of flags are ORed into the "flags" field of
dbda8d6ce9 2007-07-21       drh: ** a Decl in order to identify what type of object is being
dbda8d6ce9 2007-07-21       drh: ** declared.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define TY_Class         0x00100000
dbda8d6ce9 2007-07-21       drh: #define TY_Subroutine    0x00200000
dbda8d6ce9 2007-07-21       drh: #define TY_Macro         0x00400000
dbda8d6ce9 2007-07-21       drh: #define TY_Typedef       0x00800000
dbda8d6ce9 2007-07-21       drh: #define TY_Variable      0x01000000
dbda8d6ce9 2007-07-21       drh: #define TY_Structure     0x02000000
dbda8d6ce9 2007-07-21       drh: #define TY_Union         0x04000000
dbda8d6ce9 2007-07-21       drh: #define TY_Enumeration   0x08000000
dbda8d6ce9 2007-07-21       drh: #define TY_Defunct       0x10000000  /* Used to erase a declaration */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
dbda8d6ce9 2007-07-21       drh: ** instances of the following structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct Ifmacro Ifmacro;
dbda8d6ce9 2007-07-21       drh: struct Ifmacro {
dbda8d6ce9 2007-07-21       drh:   int nLine;         /* Line number where this macro occurs */
dbda8d6ce9 2007-07-21       drh:   char *zCondition;  /* Text of the condition for this macro */
dbda8d6ce9 2007-07-21       drh:   Ifmacro *pNext;    /* Next down in the stack */
dbda8d6ce9 2007-07-21       drh:   int flags;         /* Can hold PS_Export, PS_Interface or PS_Local flags */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** When parsing a file, we need to keep track of what other files have
dbda8d6ce9 2007-07-21       drh: ** be #include-ed.  For each #include found, we create an instance of
dbda8d6ce9 2007-07-21       drh: ** the following structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct Include Include;
dbda8d6ce9 2007-07-21       drh: struct Include {
dbda8d6ce9 2007-07-21       drh:   char *zFile;       /* The name of file include.  Includes "" or <> */
dbda8d6ce9 2007-07-21       drh:   char *zIf;         /* If not NULL, #include should be enclosed in #if */
dbda8d6ce9 2007-07-21       drh:   char *zLabel;      /* A unique label used to test if this #include has
dbda8d6ce9 2007-07-21       drh:                       * appeared already in a file or not */
dbda8d6ce9 2007-07-21       drh:   Include *pNext;    /* Previous include file, or NULL if this is the first */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Identifiers found in a source file that might be used later to provoke
dbda8d6ce9 2007-07-21       drh: ** the copying of a declaration into the corresponding header file are
dbda8d6ce9 2007-07-21       drh: ** stored in a hash table as instances of the following structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct Ident Ident;
dbda8d6ce9 2007-07-21       drh: struct Ident {
dbda8d6ce9 2007-07-21       drh:   char *zName;        /* The text of this identifier */
dbda8d6ce9 2007-07-21       drh:   Ident *pCollide;    /* Next identifier with the same hash */
dbda8d6ce9 2007-07-21       drh:   Ident *pNext;       /* Next identifier in a list of them all */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** A complete table of identifiers is stored in an instance of
dbda8d6ce9 2007-07-21       drh: ** the next structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define IDENT_HASH_SIZE 2237
dbda8d6ce9 2007-07-21       drh: typedef struct IdentTable IdentTable;
dbda8d6ce9 2007-07-21       drh: struct IdentTable {
dbda8d6ce9 2007-07-21       drh:   Ident *pList;                     /* List of all identifiers in this table */
dbda8d6ce9 2007-07-21       drh:   Ident *apTable[IDENT_HASH_SIZE];  /* The hash table */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following structure holds all information for a single
dbda8d6ce9 2007-07-21       drh: ** source file named on the command line of this program.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct InFile InFile;
dbda8d6ce9 2007-07-21       drh: struct InFile {
dbda8d6ce9 2007-07-21       drh:   char *zSrc;              /* Name of input file */
dbda8d6ce9 2007-07-21       drh:   char *zHdr;              /* Name of the generated .h file for this input.
dbda8d6ce9 2007-07-21       drh:                            ** Will be NULL if input is to be scanned only */
dbda8d6ce9 2007-07-21       drh:   int flags;               /* One or more DP_, PS_ and/or TY_ flags */
dbda8d6ce9 2007-07-21       drh:   InFile *pNext;           /* Next input file in the list of them all */
dbda8d6ce9 2007-07-21       drh:   IdentTable idTable;      /* All identifiers in this input file */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** An unbounded string is able to grow without limit.  We use these
dbda8d6ce9 2007-07-21       drh: ** to construct large in-memory strings from lots of smaller components.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct String String;
dbda8d6ce9 2007-07-21       drh: struct String {
dbda8d6ce9 2007-07-21       drh:   int nAlloc;      /* Number of bytes allocated */
dbda8d6ce9 2007-07-21       drh:   int nUsed;       /* Number of bytes used (not counting null terminator) */
dbda8d6ce9 2007-07-21       drh:   char *zText;     /* Text of the string */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following structure contains a lot of state information used
dbda8d6ce9 2007-07-21       drh: ** while generating a .h file.  We put the information in this structure
dbda8d6ce9 2007-07-21       drh: ** and pass around a pointer to this structure, rather than pass around
dbda8d6ce9 2007-07-21       drh: ** all of the information separately.  This helps reduce the number of
dbda8d6ce9 2007-07-21       drh: ** arguments to generator functions.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: typedef struct GenState GenState;
dbda8d6ce9 2007-07-21       drh: struct GenState {
dbda8d6ce9 2007-07-21       drh:   String *pStr;          /* Write output to this string */
dbda8d6ce9 2007-07-21       drh:   IdentTable *pTable;    /* A table holding the zLabel of every #include that
dbda8d6ce9 2007-07-21       drh:                           * has already been generated.  Used to avoid
dbda8d6ce9 2007-07-21       drh:                           * generating duplicate #includes. */
dbda8d6ce9 2007-07-21       drh:   const char *zIf;       /* If not NULL, then we are within a #if with
dbda8d6ce9 2007-07-21       drh:                           * this argument. */
dbda8d6ce9 2007-07-21       drh:   int nErr;              /* Number of errors */
dbda8d6ce9 2007-07-21       drh:   const char *zFilename; /* Name of the source file being scanned */
dbda8d6ce9 2007-07-21       drh:   int flags;             /* Various flags (DP_ and PS_ flags above) */
dbda8d6ce9 2007-07-21       drh: };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following text line appears at the top of every file generated
dbda8d6ce9 2007-07-21       drh: ** by this program.  By recognizing this line, the program can be sure
dbda8d6ce9 2007-07-21       drh: ** never to read a file that it generated itself.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: const char zTopLine[] =
dbda8d6ce9 2007-07-21       drh:   "/* \aThis file was automatically generated.  Do not edit! */\n";
dbda8d6ce9 2007-07-21       drh: #define nTopLine (sizeof(zTopLine)-1)
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The name of the file currently being parsed.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static char *zFilename;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The stack of #if macros for the file currently being parsed.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Ifmacro *ifStack = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** A list of all files that have been #included so far in a file being
dbda8d6ce9 2007-07-21       drh: ** parsed.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Include *includeList = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The last block comment seen.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Token *blockComment = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following flag is set if the -doc flag appears on the
dbda8d6ce9 2007-07-21       drh: ** command line.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int doc_flag = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** If the following flag is set, then makeheaders will attempt to
dbda8d6ce9 2007-07-21       drh: ** generate prototypes for static functions and procedures.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int proto_static = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** A list of all declarations.  The list is held together using the
dbda8d6ce9 2007-07-21       drh: ** pNext field of the Decl structure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Decl *pDeclFirst;    /* First on the list */
dbda8d6ce9 2007-07-21       drh: static Decl *pDeclLast;     /* Last on the list */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** A hash table of all declarations
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define DECL_HASH_SIZE 3371
dbda8d6ce9 2007-07-21       drh: static Decl *apTable[DECL_HASH_SIZE];
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The TEST macro must be defined to something.  Make sure this is the
dbda8d6ce9 2007-07-21       drh: ** case.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #ifndef TEST
dbda8d6ce9 2007-07-21       drh: # define TEST 0
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef NOT_USED
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** We do our own assertion macro so that we can have more control
dbda8d6ce9 2007-07-21       drh: ** over debugging.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define Assert(X)    if(!(X)){ CantHappen(__LINE__); }
dbda8d6ce9 2007-07-21       drh: #define CANT_HAPPEN  CantHappen(__LINE__)
dbda8d6ce9 2007-07-21       drh: static void CantHappen(int iLine){
dbda8d6ce9 2007-07-21       drh:   fprintf(stderr,"Assertion failed on line %d\n",iLine);
dbda8d6ce9 2007-07-21       drh:   *(char*)1 = 0;  /* Force a core-dump */
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Memory allocation functions that are guaranteed never to return NULL.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void *SafeMalloc(int nByte){
dbda8d6ce9 2007-07-21       drh:   void *p = malloc( nByte );
dbda8d6ce9 2007-07-21       drh:   if( p==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"Out of memory.  Can't allocate %d bytes.\n",nByte);
dbda8d6ce9 2007-07-21       drh:     exit(1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return p;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: static void SafeFree(void *pOld){
dbda8d6ce9 2007-07-21       drh:   if( pOld ){
dbda8d6ce9 2007-07-21       drh:     free(pOld);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: static void *SafeRealloc(void *pOld, int nByte){
dbda8d6ce9 2007-07-21       drh:   void *p;
dbda8d6ce9 2007-07-21       drh:   if( pOld==0 ){
dbda8d6ce9 2007-07-21       drh:     p = SafeMalloc(nByte);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     p = realloc(pOld, nByte);
dbda8d6ce9 2007-07-21       drh:     if( p==0 ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,
dbda8d6ce9 2007-07-21       drh:         "Out of memory.  Can't enlarge an allocation to %d bytes\n",nByte);
dbda8d6ce9 2007-07-21       drh:       exit(1);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return p;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: static char *StrDup(const char *zSrc, int nByte){
dbda8d6ce9 2007-07-21       drh:   char *zDest;
dbda8d6ce9 2007-07-21       drh:   if( nByte<=0 ){
dbda8d6ce9 2007-07-21       drh:     nByte = strlen(zSrc);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zDest = SafeMalloc( nByte + 1 );
dbda8d6ce9 2007-07-21       drh:   strncpy(zDest,zSrc,nByte);
dbda8d6ce9 2007-07-21       drh:   zDest[nByte] = 0;
dbda8d6ce9 2007-07-21       drh:   return zDest;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return TRUE if the character X can be part of an identifier
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define ISALNUM(X)  ((X)=='_' || isalnum(X))
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Routines for dealing with unbounded strings.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void StringInit(String *pStr){
dbda8d6ce9 2007-07-21       drh:   pStr->nAlloc = 0;
dbda8d6ce9 2007-07-21       drh:   pStr->nUsed = 0;
dbda8d6ce9 2007-07-21       drh:   pStr->zText = 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: static void StringReset(String *pStr){
dbda8d6ce9 2007-07-21       drh:   SafeFree(pStr->zText);
dbda8d6ce9 2007-07-21       drh:   StringInit(pStr);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: static void StringAppend(String *pStr, const char *zText, int nByte){
dbda8d6ce9 2007-07-21       drh:   if( nByte<=0 ){
dbda8d6ce9 2007-07-21       drh:     nByte = strlen(zText);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pStr->nUsed + nByte >= pStr->nAlloc ){
dbda8d6ce9 2007-07-21       drh:     if( pStr->nAlloc==0 ){
dbda8d6ce9 2007-07-21       drh:       pStr->nAlloc = nByte + 100;
dbda8d6ce9 2007-07-21       drh:       pStr->zText = SafeMalloc( pStr->nAlloc );
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       pStr->nAlloc = pStr->nAlloc*2 + nByte;
dbda8d6ce9 2007-07-21       drh:       pStr->zText = SafeRealloc(pStr->zText, pStr->nAlloc);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   strncpy(&pStr->zText[pStr->nUsed],zText,nByte);
dbda8d6ce9 2007-07-21       drh:   pStr->nUsed += nByte;
dbda8d6ce9 2007-07-21       drh:   pStr->zText[pStr->nUsed] = 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #define StringGet(S) ((S)->zText?(S)->zText:"")
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Compute a hash on a string.  The number returned is a non-negative
dbda8d6ce9 2007-07-21       drh: ** value between 0 and 2**31 - 1
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int Hash(const char *z, int n){
dbda8d6ce9 2007-07-21       drh:   int h = 0;
dbda8d6ce9 2007-07-21       drh:   if( n<=0 ){
dbda8d6ce9 2007-07-21       drh:     n = strlen(z);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   while( n-- ){
dbda8d6ce9 2007-07-21       drh:     h = h ^ (h<<5) ^ *z++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return h & 0x7fffffff;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Given an identifier name, try to find a declaration for that
dbda8d6ce9 2007-07-21       drh: ** identifier in the hash table.  If found, return a pointer to
dbda8d6ce9 2007-07-21       drh: ** the Decl structure.  If not found, return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Decl *FindDecl(const char *zName, int len){
dbda8d6ce9 2007-07-21       drh:   int h;
dbda8d6ce9 2007-07-21       drh:   Decl *p;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( len<=0 ){
dbda8d6ce9 2007-07-21       drh:     len = strlen(zName);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   h = Hash(zName,len) % DECL_HASH_SIZE;
dbda8d6ce9 2007-07-21       drh:   p = apTable[h];
dbda8d6ce9 2007-07-21       drh:   while( p && (strncmp(p->zName,zName,len)!=0 || p->zName[len]!=0) ){
dbda8d6ce9 2007-07-21       drh:     p = p->pSameHash;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return p;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Install the given declaration both in the hash table and on
dbda8d6ce9 2007-07-21       drh: ** the list of all declarations.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void InstallDecl(Decl *pDecl){
dbda8d6ce9 2007-07-21       drh:   int h;
dbda8d6ce9 2007-07-21       drh:   Decl *pOther;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   h = Hash(pDecl->zName,0) % DECL_HASH_SIZE;
dbda8d6ce9 2007-07-21       drh:   pOther = apTable[h];
dbda8d6ce9 2007-07-21       drh:   while( pOther && strcmp(pDecl->zName,pOther->zName)!=0 ){
dbda8d6ce9 2007-07-21       drh:     pOther = pOther->pSameHash;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pOther ){
dbda8d6ce9 2007-07-21       drh:     pDecl->pSameName = pOther->pSameName;
dbda8d6ce9 2007-07-21       drh:     pOther->pSameName = pDecl;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pDecl->pSameName = 0;
dbda8d6ce9 2007-07-21       drh:     pDecl->pSameHash = apTable[h];
dbda8d6ce9 2007-07-21       drh:     apTable[h] = pDecl;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pDecl->pNext = 0;
dbda8d6ce9 2007-07-21       drh:   if( pDeclFirst==0 ){
dbda8d6ce9 2007-07-21       drh:     pDeclFirst = pDeclLast = pDecl;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pDeclLast->pNext = pDecl;
dbda8d6ce9 2007-07-21       drh:     pDeclLast = pDecl;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Look at the current ifStack.  If anything declared at the current
dbda8d6ce9 2007-07-21       drh: ** position must be surrounded with
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **      #if   STUFF
dbda8d6ce9 2007-07-21       drh: **      #endif
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Then this routine computes STUFF and returns a pointer to it.  Memory
dbda8d6ce9 2007-07-21       drh: ** to hold the value returned is obtained from malloc().
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static char *GetIfString(void){
dbda8d6ce9 2007-07-21       drh:   Ifmacro *pIf;
dbda8d6ce9 2007-07-21       drh:   char *zResult = 0;
dbda8d6ce9 2007-07-21       drh:   int hasIf = 0;
dbda8d6ce9 2007-07-21       drh:   String str;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pIf = ifStack; pIf; pIf=pIf->pNext){
dbda8d6ce9 2007-07-21       drh:     if( pIf->zCondition==0 || *pIf->zCondition==0 ) continue;
dbda8d6ce9 2007-07-21       drh:     if( !hasIf ){
dbda8d6ce9 2007-07-21       drh:       hasIf = 1;
dbda8d6ce9 2007-07-21       drh:       StringInit(&str);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       StringAppend(&str," && ",4);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     StringAppend(&str,pIf->zCondition,0);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( hasIf ){
dbda8d6ce9 2007-07-21       drh:     zResult = StrDup(StringGet(&str),0);
dbda8d6ce9 2007-07-21       drh:     StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     zResult = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return zResult;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Create a new declaration and put it in the hash table.  Also
dbda8d6ce9 2007-07-21       drh: ** return a pointer to it so that we can fill in the zFwd and zDecl
dbda8d6ce9 2007-07-21       drh: ** fields, and so forth.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Decl *CreateDecl(
dbda8d6ce9 2007-07-21       drh:   const char *zName,       /* Name of the object being declared. */
dbda8d6ce9 2007-07-21       drh:   int nName                /* Length of the name */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   pDecl = SafeMalloc( sizeof(Decl) + nName + 1);
dbda8d6ce9 2007-07-21       drh:   memset(pDecl,0,sizeof(Decl));
dbda8d6ce9 2007-07-21       drh:   pDecl->zName = (char*)&pDecl[1];
dbda8d6ce9 2007-07-21       drh:   sprintf(pDecl->zName,"%.*s",nName,zName);
dbda8d6ce9 2007-07-21       drh:   pDecl->zFile = zFilename;
dbda8d6ce9 2007-07-21       drh:   pDecl->pInclude = includeList;
dbda8d6ce9 2007-07-21       drh:   pDecl->zIf = GetIfString();
dbda8d6ce9 2007-07-21       drh:   InstallDecl(pDecl);
dbda8d6ce9 2007-07-21       drh:   return pDecl;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Insert a new identifier into an table of identifiers.  Return TRUE if
dbda8d6ce9 2007-07-21       drh: ** a new identifier was inserted and return FALSE if the identifier was
dbda8d6ce9 2007-07-21       drh: ** already in the table.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int IdentTableInsert(
dbda8d6ce9 2007-07-21       drh:   IdentTable *pTable,       /* The table into which we will insert */
dbda8d6ce9 2007-07-21       drh:   const char *zId,          /* Name of the identifiers */
dbda8d6ce9 2007-07-21       drh:   int nId                   /* Length of the identifier name */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int h;
dbda8d6ce9 2007-07-21       drh:   Ident *pId;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( nId<=0 ){
dbda8d6ce9 2007-07-21       drh:     nId = strlen(zId);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   h = Hash(zId,nId) % IDENT_HASH_SIZE;
dbda8d6ce9 2007-07-21       drh:   for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){
dbda8d6ce9 2007-07-21       drh:     if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
dbda8d6ce9 2007-07-21       drh:       /* printf("Already in table: %.*s\n",nId,zId); */
dbda8d6ce9 2007-07-21       drh:       return 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pId = SafeMalloc( sizeof(Ident) + nId + 1 );
dbda8d6ce9 2007-07-21       drh:   pId->zName = (char*)&pId[1];
dbda8d6ce9 2007-07-21       drh:   sprintf(pId->zName,"%.*s",nId,zId);
dbda8d6ce9 2007-07-21       drh:   pId->pNext = pTable->pList;
dbda8d6ce9 2007-07-21       drh:   pTable->pList = pId;
dbda8d6ce9 2007-07-21       drh:   pId->pCollide = pTable->apTable[h];
dbda8d6ce9 2007-07-21       drh:   pTable->apTable[h] = pId;
dbda8d6ce9 2007-07-21       drh:   /* printf("Add to table: %.*s\n",nId,zId); */
dbda8d6ce9 2007-07-21       drh:   return 1;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Check to see if the given value is in the given IdentTable.  Return
dbda8d6ce9 2007-07-21       drh: ** true if it is and false if it is not.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int IdentTableTest(
dbda8d6ce9 2007-07-21       drh:   IdentTable *pTable,       /* The table in which to search */
dbda8d6ce9 2007-07-21       drh:   const char *zId,          /* Name of the identifiers */
dbda8d6ce9 2007-07-21       drh:   int nId                   /* Length of the identifier name */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int h;
dbda8d6ce9 2007-07-21       drh:   Ident *pId;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( nId<=0 ){
dbda8d6ce9 2007-07-21       drh:     nId = strlen(zId);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   h = Hash(zId,nId) % IDENT_HASH_SIZE;
dbda8d6ce9 2007-07-21       drh:   for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){
dbda8d6ce9 2007-07-21       drh:     if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
dbda8d6ce9 2007-07-21       drh:       return 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Remove every identifier from the given table.   Reset the table to
dbda8d6ce9 2007-07-21       drh: ** its initial state.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void IdentTableReset(IdentTable *pTable){
dbda8d6ce9 2007-07-21       drh:   Ident *pId, *pNext;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pId = pTable->pList; pId; pId = pNext){
dbda8d6ce9 2007-07-21       drh:     pNext = pId->pNext;
dbda8d6ce9 2007-07-21       drh:     SafeFree(pId);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   memset(pTable,0,sizeof(IdentTable));
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print the name of every identifier in the given table, one per line
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void IdentTablePrint(IdentTable *pTable, FILE *pOut){
dbda8d6ce9 2007-07-21       drh:   Ident *pId;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pId = pTable->pList; pId; pId = pId->pNext){
dbda8d6ce9 2007-07-21       drh:     fprintf(pOut,"%s\n",pId->zName);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Read an entire file into memory.  Return a pointer to the memory.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The memory is obtained from SafeMalloc and must be freed by the
dbda8d6ce9 2007-07-21       drh: ** calling function.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If the read fails for any reason, 0 is returned.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static char *ReadFile(const char *zFilename){
dbda8d6ce9 2007-07-21       drh:   struct stat sStat;
dbda8d6ce9 2007-07-21       drh:   FILE *pIn;
dbda8d6ce9 2007-07-21       drh:   char *zBuf;
dbda8d6ce9 2007-07-21       drh:   int n;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( stat(zFilename,&sStat)!=0
dbda8d6ce9 2007-07-21       drh: #ifndef WIN32
dbda8d6ce9 2007-07-21       drh:     || !S_ISREG(sStat.st_mode)
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:   ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pIn = fopen(zFilename,"r");
dbda8d6ce9 2007-07-21       drh:   if( pIn==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zBuf = SafeMalloc( sStat.st_size + 1 );
dbda8d6ce9 2007-07-21       drh:   n = fread(zBuf,1,sStat.st_size,pIn);
dbda8d6ce9 2007-07-21       drh:   zBuf[n] = 0;
dbda8d6ce9 2007-07-21       drh:   fclose(pIn);
dbda8d6ce9 2007-07-21       drh:   return zBuf;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Write the contents of a string into a file.  Return the number of
dbda8d6ce9 2007-07-21       drh: ** errors
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int WriteFile(const char *zFilename, const char *zOutput){
dbda8d6ce9 2007-07-21       drh:   FILE *pOut;
dbda8d6ce9 2007-07-21       drh:   pOut = fopen(zFilename,"w");
dbda8d6ce9 2007-07-21       drh:   if( pOut==0 ){
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   fwrite(zOutput,1,strlen(zOutput),pOut);
dbda8d6ce9 2007-07-21       drh:   fclose(pOut);
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Major token types
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: #define TT_Space           1   /* Contiguous white space */
dbda8d6ce9 2007-07-21       drh: #define TT_Id              2   /* An identifier */
dbda8d6ce9 2007-07-21       drh: #define TT_Preprocessor    3   /* Any C preprocessor directive */
dbda8d6ce9 2007-07-21       drh: #define TT_Comment         4   /* Either C or C++ style comment */
dbda8d6ce9 2007-07-21       drh: #define TT_Number          5   /* Any numeric constant */
dbda8d6ce9 2007-07-21       drh: #define TT_String          6   /* String or character constants. ".." or '.' */
dbda8d6ce9 2007-07-21       drh: #define TT_Braces          7   /* All text between { and a matching } */
dbda8d6ce9 2007-07-21       drh: #define TT_EOF             8   /* End of file */
dbda8d6ce9 2007-07-21       drh: #define TT_Error           9   /* An error condition */
dbda8d6ce9 2007-07-21       drh: #define TT_BlockComment    10  /* A C-Style comment at the left margin that
dbda8d6ce9 2007-07-21       drh:                                 * spans multple lines */
dbda8d6ce9 2007-07-21       drh: #define TT_Other           0   /* None of the above */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Get a single low-level token from the input file.  Update the
dbda8d6ce9 2007-07-21       drh: ** file pointer so that it points to the first character beyond the
dbda8d6ce9 2007-07-21       drh: ** token.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** A "low-level token" is any token except TT_Braces.  A TT_Braces token
dbda8d6ce9 2007-07-21       drh: ** consists of many smaller tokens and is assembled by a routine that
dbda8d6ce9 2007-07-21       drh: ** calls this one.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The function returns the number of errors.  An error is an
dbda8d6ce9 2007-07-21       drh: ** unterminated string or character literal or an unterminated
dbda8d6ce9 2007-07-21       drh: ** comment.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Profiling shows that this routine consumes about half the
dbda8d6ce9 2007-07-21       drh: ** CPU time on a typical run of makeheaders.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int GetToken(InStream *pIn, Token *pToken){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   const char *z;
dbda8d6ce9 2007-07-21       drh:   int cStart;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh:   int startLine;   /* Line on which a structure begins */
dbda8d6ce9 2007-07-21       drh:   int nlisc = 0;   /* True if there is a new-line in a ".." or '..' */
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;    /* Number of errors seen */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   z = pIn->z;
dbda8d6ce9 2007-07-21       drh:   i = pIn->i;
dbda8d6ce9 2007-07-21       drh:   pToken->nLine = pIn->nLine;
dbda8d6ce9 2007-07-21       drh:   pToken->zText = &z[i];
dbda8d6ce9 2007-07-21       drh:   switch( z[i] ){
dbda8d6ce9 2007-07-21       drh:     case 0:
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_EOF;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = 0;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '#':
dbda8d6ce9 2007-07-21       drh:       if( i==0 || z[i-1]=='\n' || (i>1 && z[i-1]=='\r' && z[i-2]=='\n')){
dbda8d6ce9 2007-07-21       drh:         /* We found a preprocessor statement */
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Preprocessor;
dbda8d6ce9 2007-07-21       drh:         i++;
dbda8d6ce9 2007-07-21       drh:         while( z[i]!=0 && z[i]!='\n' ){
dbda8d6ce9 2007-07-21       drh:           if( z[i]=='\\' ){
dbda8d6ce9 2007-07-21       drh:             i++;
dbda8d6ce9 2007-07-21       drh:             if( z[i]=='\n' ) pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           i++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         /* Just an operator */
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:         pToken->nText = 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case ' ':
dbda8d6ce9 2007-07-21       drh:     case '\t':
dbda8d6ce9 2007-07-21       drh:     case '\r':
dbda8d6ce9 2007-07-21       drh:     case '\f':
dbda8d6ce9 2007-07-21       drh:     case '\n':
dbda8d6ce9 2007-07-21       drh:       while( isspace(z[i]) ){
dbda8d6ce9 2007-07-21       drh:         if( z[i]=='\n' ) pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:         i++;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Space;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '\\':
dbda8d6ce9 2007-07-21       drh:       pToken->nText = 2;
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:       if( z[i+1]=='\n' ){
dbda8d6ce9 2007-07-21       drh:         pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Space;
dbda8d6ce9 2007-07-21       drh:       }else if( z[i+1]==0 ){
dbda8d6ce9 2007-07-21       drh:         pToken->nText = 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '\'':
dbda8d6ce9 2007-07-21       drh:     case '\"':
dbda8d6ce9 2007-07-21       drh:       cStart = z[i];
dbda8d6ce9 2007-07-21       drh:       startLine = pIn->nLine;
dbda8d6ce9 2007-07-21       drh:       do{
dbda8d6ce9 2007-07-21       drh:         i++;
dbda8d6ce9 2007-07-21       drh:         c = z[i];
dbda8d6ce9 2007-07-21       drh:         if( c=='\n' ){
dbda8d6ce9 2007-07-21       drh:           if( !nlisc ){
dbda8d6ce9 2007-07-21       drh:             fprintf(stderr,
dbda8d6ce9 2007-07-21       drh:               "%s:%d: (warning) Newline in string or character literal.\n",
dbda8d6ce9 2007-07-21       drh:               zFilename, pIn->nLine);
dbda8d6ce9 2007-07-21       drh:             nlisc = 1;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( c=='\\' ){
dbda8d6ce9 2007-07-21       drh:           i++;
dbda8d6ce9 2007-07-21       drh:           c = z[i];
dbda8d6ce9 2007-07-21       drh:           if( c=='\n' ){
dbda8d6ce9 2007-07-21       drh:             pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else if( c==cStart ){
dbda8d6ce9 2007-07-21       drh:           i++;
dbda8d6ce9 2007-07-21       drh:           c = 0;
dbda8d6ce9 2007-07-21       drh:         }else if( c==0 ){
dbda8d6ce9 2007-07-21       drh:           fprintf(stderr, "%s:%d: Unterminated string or character literal.\n",
dbda8d6ce9 2007-07-21       drh:              zFilename, startLine);
dbda8d6ce9 2007-07-21       drh:           nErr++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }while( c );
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_String;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '/':
dbda8d6ce9 2007-07-21       drh:       if( z[i+1]=='/' ){
dbda8d6ce9 2007-07-21       drh:         /* C++ style comment */
dbda8d6ce9 2007-07-21       drh:         while( z[i] && z[i]!='\n' ){ i++; }
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Comment;
dbda8d6ce9 2007-07-21       drh:         pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       }else if( z[i+1]=='*' ){
dbda8d6ce9 2007-07-21       drh:         /* C style comment */
dbda8d6ce9 2007-07-21       drh:         int isBlockComment = i==0 || z[i-1]=='\n';
dbda8d6ce9 2007-07-21       drh:         i += 2;
dbda8d6ce9 2007-07-21       drh:         startLine = pIn->nLine;
dbda8d6ce9 2007-07-21       drh:         while( z[i] && (z[i]!='*' || z[i+1]!='/') ){
dbda8d6ce9 2007-07-21       drh:           if( z[i]=='\n' ){
dbda8d6ce9 2007-07-21       drh:             pIn->nLine++;
dbda8d6ce9 2007-07-21       drh:             if( isBlockComment ){
dbda8d6ce9 2007-07-21       drh:               if( z[i+1]=='*' || z[i+2]=='*' ){
dbda8d6ce9 2007-07-21       drh:                  isBlockComment = 2;
dbda8d6ce9 2007-07-21       drh:               }else{
dbda8d6ce9 2007-07-21       drh:                  isBlockComment = 0;
dbda8d6ce9 2007-07-21       drh:               }
dbda8d6ce9 2007-07-21       drh:             }
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:           i++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( z[i] ){
dbda8d6ce9 2007-07-21       drh:           i += 2;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           isBlockComment = 0;
dbda8d6ce9 2007-07-21       drh:           fprintf(stderr,"%s:%d: Unterminated comment\n",
dbda8d6ce9 2007-07-21       drh:             zFilename, startLine);
dbda8d6ce9 2007-07-21       drh:           nErr++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
dbda8d6ce9 2007-07-21       drh:         pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         /* A divide operator */
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:         pToken->nText = 1 + (z[i+1]=='+');
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '0':
dbda8d6ce9 2007-07-21       drh:       if( z[i+1]=='x' || z[i+1]=='X' ){
dbda8d6ce9 2007-07-21       drh:         /* A hex constant */
dbda8d6ce9 2007-07-21       drh:         i += 2;
dbda8d6ce9 2007-07-21       drh:         while( isxdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         /* An octal constant */
dbda8d6ce9 2007-07-21       drh:         while( isdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Number;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '1': case '2': case '3': case '4':
dbda8d6ce9 2007-07-21       drh:     case '5': case '6': case '7': case '8': case '9':
dbda8d6ce9 2007-07-21       drh:       while( isdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:       if( (c=z[i])=='.' ){
dbda8d6ce9 2007-07-21       drh:          i++;
dbda8d6ce9 2007-07-21       drh:          while( isdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:          c = z[i];
dbda8d6ce9 2007-07-21       drh:          if( c=='e' || c=='E' ){
dbda8d6ce9 2007-07-21       drh:            i++;
dbda8d6ce9 2007-07-21       drh:            if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:            while( isdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:            c = z[i];
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          if( c=='f' || c=='F' || c=='l' || c=='L' ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }else if( c=='e' || c=='E' ){
dbda8d6ce9 2007-07-21       drh:          i++;
dbda8d6ce9 2007-07-21       drh:          if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:          while( isdigit(z[i]) ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }else if( c=='L' || c=='l' ){
dbda8d6ce9 2007-07-21       drh:          i++;
dbda8d6ce9 2007-07-21       drh:          c = z[i];
dbda8d6ce9 2007-07-21       drh:          if( c=='u' || c=='U' ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }else if( c=='u' || c=='U' ){
dbda8d6ce9 2007-07-21       drh:          i++;
dbda8d6ce9 2007-07-21       drh:          c = z[i];
dbda8d6ce9 2007-07-21       drh:          if( c=='l' || c=='L' ){ i++; }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Number;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
dbda8d6ce9 2007-07-21       drh:     case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
dbda8d6ce9 2007-07-21       drh:     case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
dbda8d6ce9 2007-07-21       drh:     case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
dbda8d6ce9 2007-07-21       drh:     case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
dbda8d6ce9 2007-07-21       drh:     case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
dbda8d6ce9 2007-07-21       drh:     case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W':
dbda8d6ce9 2007-07-21       drh:     case 'X': case 'Y': case 'Z': case '_':
dbda8d6ce9 2007-07-21       drh:       while( isalnum(z[i]) || z[i]=='_' ){ i++; };
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Id;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = i - pIn->i;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case ':':
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = 1 + (z[i+1]==':');
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case '=':
dbda8d6ce9 2007-07-21       drh:     case '<':
dbda8d6ce9 2007-07-21       drh:     case '>':
dbda8d6ce9 2007-07-21       drh:     case '+':
dbda8d6ce9 2007-07-21       drh:     case '-':
dbda8d6ce9 2007-07-21       drh:     case '*':
dbda8d6ce9 2007-07-21       drh:     case '%':
dbda8d6ce9 2007-07-21       drh:     case '^':
dbda8d6ce9 2007-07-21       drh:     case '&':
dbda8d6ce9 2007-07-21       drh:     case '|':
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = 1 + (z[i+1]=='=');
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     default:
dbda8d6ce9 2007-07-21       drh:       pToken->eType = TT_Other;
dbda8d6ce9 2007-07-21       drh:       pToken->nText = 1;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pIn->i += pToken->nText;
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine recovers the next token from the input file which is
dbda8d6ce9 2007-07-21       drh: ** not a space or a comment or any text between an "#if 0" and "#endif".
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This routine returns the number of errors encountered.  An error
dbda8d6ce9 2007-07-21       drh: ** is an unterminated token or unmatched "#if 0".
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Profiling shows that this routine uses about a quarter of the
dbda8d6ce9 2007-07-21       drh: ** CPU time in a typical run.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int GetNonspaceToken(InStream *pIn, Token *pToken){
dbda8d6ce9 2007-07-21       drh:   int nIf = 0;
dbda8d6ce9 2007-07-21       drh:   int inZero = 0;
dbda8d6ce9 2007-07-21       drh:   const char *z;
dbda8d6ce9 2007-07-21       drh:   int value;
dbda8d6ce9 2007-07-21       drh:   int startLine;
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   startLine = pIn->nLine;
dbda8d6ce9 2007-07-21       drh:   while( 1 ){
dbda8d6ce9 2007-07-21       drh:     nErr += GetToken(pIn,pToken);
dbda8d6ce9 2007-07-21       drh:     /* printf("%04d: Type=%d nIf=%d [%.*s]\n",
dbda8d6ce9 2007-07-21       drh:        pToken->nLine,pToken->eType,nIf,pToken->nText,
dbda8d6ce9 2007-07-21       drh:        pToken->eType!=TT_Space ? pToken->zText : "<space>"); */
dbda8d6ce9 2007-07-21       drh:     pToken->pComment = blockComment;
dbda8d6ce9 2007-07-21       drh:     switch( pToken->eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_Comment:
dbda8d6ce9 2007-07-21       drh:       case TT_Space:
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_BlockComment:
dbda8d6ce9 2007-07-21       drh:         if( doc_flag ){
dbda8d6ce9 2007-07-21       drh:           blockComment = SafeMalloc( sizeof(Token) );
dbda8d6ce9 2007-07-21       drh:           *blockComment = *pToken;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_EOF:
dbda8d6ce9 2007-07-21       drh:         if( nIf ){
dbda8d6ce9 2007-07-21       drh:           fprintf(stderr,"%s:%d: Unterminated \"#if\"\n",
dbda8d6ce9 2007-07-21       drh:              zFilename, startLine);
dbda8d6ce9 2007-07-21       drh:           nErr++;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         return nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:         z = &pToken->zText[1];
dbda8d6ce9 2007-07-21       drh:         while( *z==' ' || *z=='\t' ) z++;
dbda8d6ce9 2007-07-21       drh:         if( sscanf(z,"if %d",&value)==1 && value==0 ){
dbda8d6ce9 2007-07-21       drh:           nIf++;
dbda8d6ce9 2007-07-21       drh:           inZero = 1;
dbda8d6ce9 2007-07-21       drh:         }else if( inZero ){
dbda8d6ce9 2007-07-21       drh:           if( strncmp(z,"if",2)==0 ){
dbda8d6ce9 2007-07-21       drh:             nIf++;
dbda8d6ce9 2007-07-21       drh:           }else if( strncmp(z,"endif",5)==0 ){
dbda8d6ce9 2007-07-21       drh:             nIf--;
dbda8d6ce9 2007-07-21       drh:             if( nIf==0 ) inZero = 0;
dbda8d6ce9 2007-07-21       drh:           }
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           return nErr;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         if( !inZero ){
dbda8d6ce9 2007-07-21       drh:           return nErr;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   /* NOT REACHED */
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine looks for identifiers (strings of contiguous alphanumeric
dbda8d6ce9 2007-07-21       drh: ** characters) within a preprocessor directive and adds every such string
dbda8d6ce9 2007-07-21       drh: ** found to the given identifier table
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
dbda8d6ce9 2007-07-21       drh:   Token sToken;
dbda8d6ce9 2007-07-21       drh:   InStream sIn;
dbda8d6ce9 2007-07-21       drh:   int go = 1;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   sIn.z = pToken->zText;
dbda8d6ce9 2007-07-21       drh:   sIn.i = 1;
dbda8d6ce9 2007-07-21       drh:   sIn.nLine = 1;
dbda8d6ce9 2007-07-21       drh:   while( go && sIn.i < pToken->nText ){
dbda8d6ce9 2007-07-21       drh:     GetToken(&sIn,&sToken);
dbda8d6ce9 2007-07-21       drh:     switch( sToken.eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_Id:
dbda8d6ce9 2007-07-21       drh:         IdentTableInsert(pTable,sToken.zText,sToken.nText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_EOF:
dbda8d6ce9 2007-07-21       drh:         go = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine gets the next token.  Everything contained within
dbda8d6ce9 2007-07-21       drh: ** {...} is collapsed into a single TT_Braces token.  Whitespace is
dbda8d6ce9 2007-07-21       drh: ** omitted.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If pTable is not NULL, then insert every identifier seen into the
dbda8d6ce9 2007-07-21       drh: ** IdentTable.  This includes any identifiers seen inside of {...}.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** The number of errors encountered is returned.  An error is an
dbda8d6ce9 2007-07-21       drh: ** unterminated token.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int GetBigToken(InStream *pIn, Token *pToken, IdentTable *pTable){
dbda8d6ce9 2007-07-21       drh:   const char *z, *zStart;
dbda8d6ce9 2007-07-21       drh:   int iStart;
dbda8d6ce9 2007-07-21       drh:   int nBrace;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh:   int nLine;
dbda8d6ce9 2007-07-21       drh:   int nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   nErr = GetNonspaceToken(pIn,pToken);
dbda8d6ce9 2007-07-21       drh:   switch( pToken->eType ){
dbda8d6ce9 2007-07-21       drh:     case TT_Id:
dbda8d6ce9 2007-07-21       drh:       if( pTable!=0 ){
dbda8d6ce9 2007-07-21       drh:         IdentTableInsert(pTable,pToken->zText,pToken->nText);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:       if( pTable!=0 ){
dbda8d6ce9 2007-07-21       drh:         FindIdentifiersInMacro(pToken,pTable);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Other:
dbda8d6ce9 2007-07-21       drh:       if( pToken->zText[0]=='{' ) break;
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     default:
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   z = pIn->z;
dbda8d6ce9 2007-07-21       drh:   iStart = pIn->i;
dbda8d6ce9 2007-07-21       drh:   zStart = pToken->zText;
dbda8d6ce9 2007-07-21       drh:   nLine = pToken->nLine;
dbda8d6ce9 2007-07-21       drh:   nBrace = 1;
dbda8d6ce9 2007-07-21       drh:   while( nBrace ){
dbda8d6ce9 2007-07-21       drh:     nErr += GetNonspaceToken(pIn,pToken);
dbda8d6ce9 2007-07-21       drh:     /* printf("%04d: nBrace=%d [%.*s]\n",pToken->nLine,nBrace,
dbda8d6ce9 2007-07-21       drh:        pToken->nText,pToken->zText); */
dbda8d6ce9 2007-07-21       drh:     switch( pToken->eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_EOF:
dbda8d6ce9 2007-07-21       drh:         fprintf(stderr,"%s:%d: Unterminated \"{\"\n",
dbda8d6ce9 2007-07-21       drh:            zFilename, nLine);
dbda8d6ce9 2007-07-21       drh:         nErr++;
dbda8d6ce9 2007-07-21       drh:         pToken->eType = TT_Error;
dbda8d6ce9 2007-07-21       drh:         return nErr;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Id:
dbda8d6ce9 2007-07-21       drh:         if( pTable ){
dbda8d6ce9 2007-07-21       drh:           IdentTableInsert(pTable,pToken->zText,pToken->nText);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:         if( pTable!=0 ){
dbda8d6ce9 2007-07-21       drh:           FindIdentifiersInMacro(pToken,pTable);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Other:
dbda8d6ce9 2007-07-21       drh:         if( (c = pToken->zText[0])=='{' ){
dbda8d6ce9 2007-07-21       drh:           nBrace++;
dbda8d6ce9 2007-07-21       drh:         }else if( c=='}' ){
dbda8d6ce9 2007-07-21       drh:           nBrace--;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pToken->eType = TT_Braces;
dbda8d6ce9 2007-07-21       drh:   pToken->nText = 1 + pIn->i - iStart;
dbda8d6ce9 2007-07-21       drh:   pToken->zText = zStart;
dbda8d6ce9 2007-07-21       drh:   pToken->nLine = nLine;
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine frees up a list of Tokens.  The pComment tokens are
dbda8d6ce9 2007-07-21       drh: ** not cleared by this.  So we leak a little memory when using the -doc
dbda8d6ce9 2007-07-21       drh: ** option.  So what.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void FreeTokenList(Token *pList){
dbda8d6ce9 2007-07-21       drh:   Token *pNext;
dbda8d6ce9 2007-07-21       drh:   while( pList ){
dbda8d6ce9 2007-07-21       drh:     pNext = pList->pNext;
dbda8d6ce9 2007-07-21       drh:     SafeFree(pList);
dbda8d6ce9 2007-07-21       drh:     pList = pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Tokenize an entire file.  Return a pointer to the list of tokens.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Space for each token is obtained from a separate malloc() call.  The
dbda8d6ce9 2007-07-21       drh: ** calling function is responsible for freeing this space.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If pTable is not NULL, then fill the table with all identifiers seen in
dbda8d6ce9 2007-07-21       drh: ** the input file.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Token *TokenizeFile(const char *zFile, IdentTable *pTable){
dbda8d6ce9 2007-07-21       drh:   InStream sIn;
dbda8d6ce9 2007-07-21       drh:   Token *pFirst = 0, *pLast = 0, *pNew;
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   sIn.z = zFile;
dbda8d6ce9 2007-07-21       drh:   sIn.i = 0;
dbda8d6ce9 2007-07-21       drh:   sIn.nLine = 1;
dbda8d6ce9 2007-07-21       drh:   blockComment = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   while( sIn.z[sIn.i]!=0 ){
dbda8d6ce9 2007-07-21       drh:     pNew = SafeMalloc( sizeof(Token) );
dbda8d6ce9 2007-07-21       drh:     nErr += GetBigToken(&sIn,pNew,pTable);
dbda8d6ce9 2007-07-21       drh:     debug3(TOKENIZER, "Token on line %d: [%.*s]\n",
dbda8d6ce9 2007-07-21       drh:        pNew->nLine, pNew->nText<50 ? pNew->nText : 50, pNew->zText);
dbda8d6ce9 2007-07-21       drh:     if( pFirst==0 ){
dbda8d6ce9 2007-07-21       drh:       pFirst = pLast = pNew;
dbda8d6ce9 2007-07-21       drh:       pNew->pPrev = 0;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       pLast->pNext = pNew;
dbda8d6ce9 2007-07-21       drh:       pNew->pPrev = pLast;
dbda8d6ce9 2007-07-21       drh:       pLast = pNew;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pNew->eType==TT_EOF ) break;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pLast ) pLast->pNext = 0;
dbda8d6ce9 2007-07-21       drh:   blockComment = 0;
dbda8d6ce9 2007-07-21       drh:   if( nErr ){
dbda8d6ce9 2007-07-21       drh:     FreeTokenList(pFirst);
dbda8d6ce9 2007-07-21       drh:     pFirst = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   return pFirst;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #if TEST==1
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Use the following routine to test or debug the tokenizer.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void main(int argc, char **argv){
dbda8d6ce9 2007-07-21       drh:   char *zFile;
dbda8d6ce9 2007-07-21       drh:   Token *pList, *p;
dbda8d6ce9 2007-07-21       drh:   IdentTable sTable;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( argc!=2 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"Usage: %s filename\n",*argv);
dbda8d6ce9 2007-07-21       drh:     exit(1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   memset(&sTable,0,sizeof(sTable));
dbda8d6ce9 2007-07-21       drh:   zFile = ReadFile(argv[1]);
dbda8d6ce9 2007-07-21       drh:   if( zFile==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"Can't read file \"%s\"\n",argv[1]);
dbda8d6ce9 2007-07-21       drh:     exit(1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pList = TokenizeFile(zFile,&sTable);
dbda8d6ce9 2007-07-21       drh:   for(p=pList; p; p=p->pNext){
dbda8d6ce9 2007-07-21       drh:     int j;
dbda8d6ce9 2007-07-21       drh:     switch( p->eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_Space:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Space\n",p->nLine);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Id:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Id           %.*s\n",p->nLine,p->nText,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Preprocessor %.*s\n",p->nLine,p->nText,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Comment:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Comment\n",p->nLine);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_BlockComment:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Block Comment\n",p->nLine);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Number:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Number       %.*s\n",p->nLine,p->nText,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_String:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: String       %.*s\n",p->nLine,p->nText,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Other:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Other        %.*s\n",p->nLine,p->nText,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_Braces:
dbda8d6ce9 2007-07-21       drh:         for(j=0; j<p->nText && j<30 && p->zText[j]!='\n'; j++){}
dbda8d6ce9 2007-07-21       drh:         printf("%4d: Braces       %.*s...}\n",p->nLine,j,p->zText);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       case TT_EOF:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: End of file\n",p->nLine);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         printf("%4d: type %d\n",p->nLine,p->eType);
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   FreeTokenList(pList);
dbda8d6ce9 2007-07-21       drh:   SafeFree(zFile);
dbda8d6ce9 2007-07-21       drh:   IdentTablePrint(&sTable,stdout);
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** For debugging purposes, write out a list of tokens.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void PrintTokens(Token *pFirst, Token *pLast){
dbda8d6ce9 2007-07-21       drh:   int needSpace = 0;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   pLast = pLast->pNext;
dbda8d6ce9 2007-07-21       drh:   while( pFirst!=pLast ){
dbda8d6ce9 2007-07-21       drh:     switch( pFirst->eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:         printf("\n%.*s\n",pFirst->nText,pFirst->zText);
dbda8d6ce9 2007-07-21       drh:         needSpace = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Id:
dbda8d6ce9 2007-07-21       drh:       case TT_Number:
dbda8d6ce9 2007-07-21       drh:         printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText);
dbda8d6ce9 2007-07-21       drh:         needSpace = 1;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         c = pFirst->zText[0];
dbda8d6ce9 2007-07-21       drh:         printf("%s%.*s",
dbda8d6ce9 2007-07-21       drh:           (needSpace && (c=='*' || c=='{')) ? " " : "",
dbda8d6ce9 2007-07-21       drh:           pFirst->nText, pFirst->zText);
dbda8d6ce9 2007-07-21       drh:         needSpace = pFirst->zText[0]==',';
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Convert a sequence of tokens into a string and return a pointer
dbda8d6ce9 2007-07-21       drh: ** to that string.  Space to hold the string is obtained from malloc()
dbda8d6ce9 2007-07-21       drh: ** and must be freed by the calling function.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Certain keywords (EXPORT, PRIVATE, PUBLIC, PROTECTED) are always
dbda8d6ce9 2007-07-21       drh: ** skipped.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If pSkip!=0 then skip over nSkip tokens beginning with pSkip.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If zTerm!=0 then append the text to the end.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static char *TokensToString(
dbda8d6ce9 2007-07-21       drh:   Token *pFirst,    /* First token in the string */
dbda8d6ce9 2007-07-21       drh:   Token *pLast,     /* Last token in the string */
dbda8d6ce9 2007-07-21       drh:   char *zTerm,      /* Terminate the string with this text if not NULL */
dbda8d6ce9 2007-07-21       drh:   Token *pSkip,     /* Skip this token if not NULL */
dbda8d6ce9 2007-07-21       drh:   int nSkip         /* Skip a total of this many tokens */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   char *zReturn;
dbda8d6ce9 2007-07-21       drh:   String str;
dbda8d6ce9 2007-07-21       drh:   int needSpace = 0;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh:   int iSkip = 0;
dbda8d6ce9 2007-07-21       drh:   int skipOne = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   StringInit(&str);
dbda8d6ce9 2007-07-21       drh:   pLast = pLast->pNext;
dbda8d6ce9 2007-07-21       drh:   while( pFirst!=pLast ){
dbda8d6ce9 2007-07-21       drh:     if( pFirst==pSkip ){ iSkip = nSkip; }
dbda8d6ce9 2007-07-21       drh:     if( iSkip>0 ){
dbda8d6ce9 2007-07-21       drh:       iSkip--;
dbda8d6ce9 2007-07-21       drh:       pFirst=pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:       continue;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     switch( pFirst->eType ){
dbda8d6ce9 2007-07-21       drh:       case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:         StringAppend(&str,"\n",1);
dbda8d6ce9 2007-07-21       drh:         StringAppend(&str,pFirst->zText,pFirst->nText);
dbda8d6ce9 2007-07-21       drh:         StringAppend(&str,"\n",1);
dbda8d6ce9 2007-07-21       drh:         needSpace = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case TT_Id:
dbda8d6ce9 2007-07-21       drh:         switch( pFirst->zText[0] ){
dbda8d6ce9 2007-07-21       drh:           case 'E':
dbda8d6ce9 2007-07-21       drh:             if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
dbda8d6ce9 2007-07-21       drh:               skipOne = 1;
dbda8d6ce9 2007-07-21       drh:             }
dbda8d6ce9 2007-07-21       drh:             break;
dbda8d6ce9 2007-07-21       drh:           case 'P':
dbda8d6ce9 2007-07-21       drh:             switch( pFirst->nText ){
dbda8d6ce9 2007-07-21       drh:               case 6:  skipOne = !strncmp(pFirst->zText,"PUBLIC", 6);    break;
dbda8d6ce9 2007-07-21       drh:               case 7:  skipOne = !strncmp(pFirst->zText,"PRIVATE",7);    break;
dbda8d6ce9 2007-07-21       drh:               case 9:  skipOne = !strncmp(pFirst->zText,"PROTECTED",9);  break;
dbda8d6ce9 2007-07-21       drh:               default: break;
dbda8d6ce9 2007-07-21       drh:             }
dbda8d6ce9 2007-07-21       drh:             break;
dbda8d6ce9 2007-07-21       drh:           default:
dbda8d6ce9 2007-07-21       drh:             break;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( skipOne ){
dbda8d6ce9 2007-07-21       drh:           pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:           continue;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         /* Fall thru to the next case */
dbda8d6ce9 2007-07-21       drh:       case TT_Number:
dbda8d6ce9 2007-07-21       drh:         if( needSpace ){
dbda8d6ce9 2007-07-21       drh:           StringAppend(&str," ",1);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         StringAppend(&str,pFirst->zText,pFirst->nText);
dbda8d6ce9 2007-07-21       drh:         needSpace = 1;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         c = pFirst->zText[0];
dbda8d6ce9 2007-07-21       drh:         if( needSpace && (c=='*' || c=='{') ){
dbda8d6ce9 2007-07-21       drh:           StringAppend(&str," ",1);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         StringAppend(&str,pFirst->zText,pFirst->nText);
dbda8d6ce9 2007-07-21       drh:         /* needSpace = pFirst->zText[0]==','; */
dbda8d6ce9 2007-07-21       drh:         needSpace = 0;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( zTerm && *zTerm ){
dbda8d6ce9 2007-07-21       drh:     StringAppend(&str,zTerm,strlen(zTerm));
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zReturn = StrDup(StringGet(&str),0);
dbda8d6ce9 2007-07-21       drh:   StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   return zReturn;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called when we see one of the keywords "struct",
dbda8d6ce9 2007-07-21       drh: ** "enum", "union" or "class".  This might be the beginning of a
dbda8d6ce9 2007-07-21       drh: ** type declaration.  This routine will process the declaration and
dbda8d6ce9 2007-07-21       drh: ** remove the declaration tokens from the input stream.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If this is a type declaration that is immediately followed by a
dbda8d6ce9 2007-07-21       drh: ** semicolon (in other words it isn't also a variable definition)
dbda8d6ce9 2007-07-21       drh: ** then set *pReset to ';'.  Otherwise leave *pReset at 0.  The
dbda8d6ce9 2007-07-21       drh: ** *pReset flag causes the parser to skip ahead to the next token
dbda8d6ce9 2007-07-21       drh: ** that begins with the value placed in the *pReset flag, if that
dbda8d6ce9 2007-07-21       drh: ** value is different from 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ProcessTypeDecl(Token *pList, int flags, int *pReset){
dbda8d6ce9 2007-07-21       drh:   Token *pName, *pEnd;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   String str;
dbda8d6ce9 2007-07-21       drh:   int need_to_collapse = 1;
dbda8d6ce9 2007-07-21       drh:   int type = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   *pReset = 0;
dbda8d6ce9 2007-07-21       drh:   if( pList==0 || pList->pNext==0 || pList->pNext->eType!=TT_Id ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pName = pList->pNext;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Catch the case of "struct Foo;" and skip it. */
dbda8d6ce9 2007-07-21       drh:   if( pName->pNext && pName->pNext->zText[0]==';' ){
dbda8d6ce9 2007-07-21       drh:     *pReset = ';';
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pEnd=pName->pNext; pEnd && pEnd->eType!=TT_Braces; pEnd=pEnd->pNext){
dbda8d6ce9 2007-07-21       drh:     switch( pEnd->zText[0] ){
dbda8d6ce9 2007-07-21       drh:       case '(':
dbda8d6ce9 2007-07-21       drh:       case '*':
dbda8d6ce9 2007-07-21       drh:       case '[':
dbda8d6ce9 2007-07-21       drh:       case '=':
dbda8d6ce9 2007-07-21       drh:       case ';':
dbda8d6ce9 2007-07-21       drh:         return 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pEnd==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** At this point, we know we have a type declaration that is bounded
dbda8d6ce9 2007-07-21       drh:   ** by pList and pEnd and has the name pName.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** If the braces are followed immedately by a semicolon, then we are
dbda8d6ce9 2007-07-21       drh:   ** dealing a type declaration only.  There is not variable definition
dbda8d6ce9 2007-07-21       drh:   ** following the type declaration.  So reset...
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){
dbda8d6ce9 2007-07-21       drh:     *pReset = ';';
dbda8d6ce9 2007-07-21       drh:     need_to_collapse = 0;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     need_to_collapse = 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( proto_static==0 && (flags & (PS_Local|PS_Export|PS_Interface))==0 ){
dbda8d6ce9 2007-07-21       drh:     /* Ignore these objects unless they are explicitly declared as interface,
dbda8d6ce9 2007-07-21       drh:     ** or unless the "-local" command line option was specified. */
dbda8d6ce9 2007-07-21       drh:     *pReset = ';';
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:   if( debugMask & PARSER ){
dbda8d6ce9 2007-07-21       drh:     printf("**** Found type: %.*s %.*s...\n",
dbda8d6ce9 2007-07-21       drh:       pList->nText, pList->zText, pName->nText, pName->zText);
dbda8d6ce9 2007-07-21       drh:     PrintTokens(pList,pEnd);
dbda8d6ce9 2007-07-21       drh:     printf(";\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Create a new Decl object for this definition.  Actually, if this
dbda8d6ce9 2007-07-21       drh:   ** is a C++ class definition, then the Decl object might already exist,
dbda8d6ce9 2007-07-21       drh:   ** so check first for that case before creating a new one.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   switch( *pList->zText ){
dbda8d6ce9 2007-07-21       drh:     case 'c':  type = TY_Class;        break;
dbda8d6ce9 2007-07-21       drh:     case 's':  type = TY_Structure;    break;
dbda8d6ce9 2007-07-21       drh:     case 'e':  type = TY_Enumeration;  break;
dbda8d6ce9 2007-07-21       drh:     case 'u':  type = TY_Union;        break;
dbda8d6ce9 2007-07-21       drh:     default:   /* Can't Happen */      break;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( type!=TY_Class ){
dbda8d6ce9 2007-07-21       drh:     pDecl = 0;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pDecl = FindDecl(pName->zText, pName->nText);
dbda8d6ce9 2007-07-21       drh:     if( pDecl && (pDecl->flags & type)!=type ) pDecl = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pDecl==0 ){
dbda8d6ce9 2007-07-21       drh:     pDecl = CreateDecl(pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( (flags & PS_Static) || !(flags & (PS_Interface|PS_Export)) ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   DeclSetProperty(pDecl,type);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* The object has a full declaration only if it is contained within
dbda8d6ce9 2007-07-21       drh:   ** "#if INTERFACE...#endif" or "#if EXPORT_INTERFACE...#endif" or
dbda8d6ce9 2007-07-21       drh:   ** "#if LOCAL_INTERFACE...#endif".  Otherwise, we only give it a
dbda8d6ce9 2007-07-21       drh:   ** forward declaration.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( flags & (PS_Local | PS_Export | PS_Interface)  ){
dbda8d6ce9 2007-07-21       drh:     pDecl->zDecl = TokensToString(pList,pEnd,";\n",0,0);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pDecl->zDecl = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pDecl->pComment = pList->pComment;
dbda8d6ce9 2007-07-21       drh:   StringInit(&str);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,"typedef ",0);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,pList->zText,pList->nText);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str," ",0);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str," ",0);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,";\n",2);
dbda8d6ce9 2007-07-21       drh:   pDecl->zFwd = StrDup(StringGet(&str),0);
dbda8d6ce9 2007-07-21       drh:   StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   StringInit(&str);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,pList->zText,pList->nText);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str," ",0);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str,";\n",2);
dbda8d6ce9 2007-07-21       drh:   pDecl->zFwdCpp = StrDup(StringGet(&str),0);
dbda8d6ce9 2007-07-21       drh:   StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   if( flags & PS_Export ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Export);
dbda8d6ce9 2007-07-21       drh:   }else if( flags & PS_Local ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Here's something weird.  ANSI-C doesn't allow a forward declaration
dbda8d6ce9 2007-07-21       drh:   ** of an enumeration.  So we have to build the typedef into the
dbda8d6ce9 2007-07-21       drh:   ** definition.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( pDecl->zDecl && DeclHasProperty(pDecl, TY_Enumeration) ){
dbda8d6ce9 2007-07-21       drh:     StringInit(&str);
dbda8d6ce9 2007-07-21       drh:     StringAppend(&str,pDecl->zDecl,0);
dbda8d6ce9 2007-07-21       drh:     StringAppend(&str,pDecl->zFwd,0);
dbda8d6ce9 2007-07-21       drh:     SafeFree(pDecl->zDecl);
dbda8d6ce9 2007-07-21       drh:     SafeFree(pDecl->zFwd);
dbda8d6ce9 2007-07-21       drh:     pDecl->zFwd = 0;
dbda8d6ce9 2007-07-21       drh:     pDecl->zDecl = StrDup(StringGet(&str),0);
dbda8d6ce9 2007-07-21       drh:     StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pName->pNext->zText[0]==':' ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Cplusplus);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pName->nText==5 && strncmp(pName->zText,"class",5)==0 ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Cplusplus);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Remove all but pList and pName from the input stream.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( need_to_collapse ){
dbda8d6ce9 2007-07-21       drh:     while( pEnd!=pName ){
dbda8d6ce9 2007-07-21       drh:       Token *pPrev = pEnd->pPrev;
dbda8d6ce9 2007-07-21       drh:       pPrev->pNext = pEnd->pNext;
dbda8d6ce9 2007-07-21       drh:       pEnd->pNext->pPrev = pPrev;
dbda8d6ce9 2007-07-21       drh:       SafeFree(pEnd);
dbda8d6ce9 2007-07-21       drh:       pEnd = pPrev;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Given a list of tokens that declare something (a function, procedure,
dbda8d6ce9 2007-07-21       drh: ** variable or typedef) find the token which contains the name of the
dbda8d6ce9 2007-07-21       drh: ** thing being declared.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Algorithm:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   The name is:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     1.  The first identifier that is followed by a "[", or
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     2.  The first identifier that is followed by a "(" where the
dbda8d6ce9 2007-07-21       drh: **         "(" is followed by another identifier, or
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     3.  The first identifier followed by "::", or
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **     4.  If none of the above, then the last identifier.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **   In all of the above, certain reserved words (like "char") are
dbda8d6ce9 2007-07-21       drh: **   not considered identifiers.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static Token *FindDeclName(Token *pFirst, Token *pLast){
dbda8d6ce9 2007-07-21       drh:   Token *pName = 0;
dbda8d6ce9 2007-07-21       drh:   Token *p;
dbda8d6ce9 2007-07-21       drh:   int c;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pFirst==0 || pLast==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pLast = pLast->pNext;
dbda8d6ce9 2007-07-21       drh:   for(p=pFirst; p && p!=pLast; p=p->pNext){
dbda8d6ce9 2007-07-21       drh:     if( p->eType==TT_Id ){
dbda8d6ce9 2007-07-21       drh:       static IdentTable sReserved;
dbda8d6ce9 2007-07-21       drh:       static int isInit = 0;
dbda8d6ce9 2007-07-21       drh:       static char *aWords[] = { "char", "class",
dbda8d6ce9 2007-07-21       drh:        "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
dbda8d6ce9 2007-07-21       drh:        "float", "int", "long",
dbda8d6ce9 2007-07-21       drh:        "PRIVATE", "PROTECTED", "PUBLIC",
dbda8d6ce9 2007-07-21       drh:        "register", "static", "struct", "sizeof", "signed", "typedef",
dbda8d6ce9 2007-07-21       drh:        "union", "volatile", "virtual", "void", };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       if( !isInit ){
dbda8d6ce9 2007-07-21       drh:         int i;
dbda8d6ce9 2007-07-21       drh:         for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
dbda8d6ce9 2007-07-21       drh:           IdentTableInsert(&sReserved,aWords[i],0);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         isInit = 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       if( !IdentTableTest(&sReserved,p->zText,p->nText) ){
dbda8d6ce9 2007-07-21       drh:         pName = p;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }else if( p==pFirst ){
dbda8d6ce9 2007-07-21       drh:       continue;
dbda8d6ce9 2007-07-21       drh:     }else if( (c=p->zText[0])=='[' && pName ){
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }else if( c=='(' && p->pNext && p->pNext->eType==TT_Id && pName ){
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }else if( c==':' && p->zText[1]==':' && pName ){
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return pName;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called when we see a method for a class that begins
dbda8d6ce9 2007-07-21       drh: ** with the PUBLIC, PRIVATE, or PROTECTED keywords.  Such methods are
dbda8d6ce9 2007-07-21       drh: ** added to their class definitions.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ProcessMethodDef(Token *pFirst, Token *pLast, int flags){
dbda8d6ce9 2007-07-21       drh:   Token *pCode;
dbda8d6ce9 2007-07-21       drh:   Token *pClass;
dbda8d6ce9 2007-07-21       drh:   char *zDecl;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   String str;
dbda8d6ce9 2007-07-21       drh:   int type;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   pCode = pLast;
dbda8d6ce9 2007-07-21       drh:   pLast = pLast->pPrev;
dbda8d6ce9 2007-07-21       drh:   while( pFirst->zText[0]=='P' ){
dbda8d6ce9 2007-07-21       drh:     int rc = 1;
dbda8d6ce9 2007-07-21       drh:     switch( pFirst->nText ){
dbda8d6ce9 2007-07-21       drh:       case 6:  rc = strncmp(pFirst->zText,"PUBLIC",6); break;
dbda8d6ce9 2007-07-21       drh:       case 7:  rc = strncmp(pFirst->zText,"PRIVATE",7); break;
dbda8d6ce9 2007-07-21       drh:       case 9:  rc = strncmp(pFirst->zText,"PROTECTED",9); break;
dbda8d6ce9 2007-07-21       drh:       default:  break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( rc ) break;
dbda8d6ce9 2007-07-21       drh:     pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pClass = FindDeclName(pFirst,pLast);
dbda8d6ce9 2007-07-21       drh:   if( pClass==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Unable to find the class name for this method\n",
dbda8d6ce9 2007-07-21       drh:        zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pDecl = FindDecl(pClass->zText, pClass->nText);
dbda8d6ce9 2007-07-21       drh:   if( pDecl==0 || (pDecl->flags & TY_Class)!=TY_Class ){
dbda8d6ce9 2007-07-21       drh:     pDecl = CreateDecl(pClass->zText, pClass->nText);
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl, TY_Class);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   StringInit(&str);
dbda8d6ce9 2007-07-21       drh:   if( pDecl->zExtra ){
dbda8d6ce9 2007-07-21       drh:     StringAppend(&str, pDecl->zExtra, 0);
dbda8d6ce9 2007-07-21       drh:     SafeFree(pDecl->zExtra);
dbda8d6ce9 2007-07-21       drh:     pDecl->zExtra = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   type = flags & PS_PPP;
dbda8d6ce9 2007-07-21       drh:   if( pDecl->extraType!=type ){
dbda8d6ce9 2007-07-21       drh:     if( type & PS_Public ){
dbda8d6ce9 2007-07-21       drh:       StringAppend(&str, "public:\n", 0);
dbda8d6ce9 2007-07-21       drh:       pDecl->extraType = PS_Public;
dbda8d6ce9 2007-07-21       drh:     }else if( type & PS_Protected ){
dbda8d6ce9 2007-07-21       drh:       StringAppend(&str, "protected:\n", 0);
dbda8d6ce9 2007-07-21       drh:       pDecl->extraType = PS_Protected;
dbda8d6ce9 2007-07-21       drh:     }else if( type & PS_Private ){
dbda8d6ce9 2007-07-21       drh:       StringAppend(&str, "private:\n", 0);
dbda8d6ce9 2007-07-21       drh:       pDecl->extraType = PS_Private;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str, "  ", 0);
dbda8d6ce9 2007-07-21       drh:   zDecl = TokensToString(pFirst, pLast, ";\n", pClass, 2);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str, zDecl, 0);
dbda8d6ce9 2007-07-21       drh:   SafeFree(zDecl);
dbda8d6ce9 2007-07-21       drh:   pDecl->zExtra = StrDup(StringGet(&str), 0);
dbda8d6ce9 2007-07-21       drh:   StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called when we see a function or procedure definition.
dbda8d6ce9 2007-07-21       drh: ** We make an entry in the declaration table that is a prototype for this
dbda8d6ce9 2007-07-21       drh: ** function or procedure.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ProcessProcedureDef(Token *pFirst, Token *pLast, int flags){
dbda8d6ce9 2007-07-21       drh:   Token *pName;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   Token *pCode;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pFirst==0 || pLast==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( flags & PS_Method ){
dbda8d6ce9 2007-07-21       drh:     if( flags & PS_PPP ){
dbda8d6ce9 2007-07-21       drh:       return ProcessMethodDef(pFirst, pLast, flags);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       return 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( (flags & PS_Static)!=0 && !proto_static ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pCode = pLast;
dbda8d6ce9 2007-07-21       drh:   while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
dbda8d6ce9 2007-07-21       drh:     pLast = pLast->pPrev;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( flags & (PS_Interface|PS_Export|PS_Local) ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pName = FindDeclName(pFirst,pLast);
dbda8d6ce9 2007-07-21       drh:   if( pName==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Malformed function or procedure definition.\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** At this point we've isolated a procedure declaration between pFirst
dbda8d6ce9 2007-07-21       drh:   ** and pLast with the name pName.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:   if( debugMask & PARSER ){
dbda8d6ce9 2007-07-21       drh:     printf("**** Found routine: %.*s on line %d...\n", pName->nText,
dbda8d6ce9 2007-07-21       drh:        pName->zText, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     PrintTokens(pFirst,pLast);
dbda8d6ce9 2007-07-21       drh:     printf(";\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:   pDecl = CreateDecl(pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   pDecl->pComment = pFirst->pComment;
dbda8d6ce9 2007-07-21       drh:   if( pCode && pCode->eType==TT_Braces ){
dbda8d6ce9 2007-07-21       drh:     pDecl->tokenCode = *pCode;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   DeclSetProperty(pDecl,TY_Subroutine);
dbda8d6ce9 2007-07-21       drh:   pDecl->zDecl = TokensToString(pFirst,pLast,";\n",0,0);
dbda8d6ce9 2007-07-21       drh:   if( (flags & (PS_Static|PS_Local2))!=0 ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:   }else if( (flags & (PS_Export2))!=0 ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Export);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( flags & DP_Cplusplus ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Cplusplus);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_ExternCReqd);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called whenever we see the "inline" keyword.  We
dbda8d6ce9 2007-07-21       drh: ** need to seek-out the inline function or procedure and make a
dbda8d6ce9 2007-07-21       drh: ** declaration out of the entire definition.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ProcessInlineProc(Token *pFirst, int flags, int *pReset){
dbda8d6ce9 2007-07-21       drh:   Token *pName;
dbda8d6ce9 2007-07-21       drh:   Token *pEnd;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pEnd=pFirst; pEnd; pEnd = pEnd->pNext){
dbda8d6ce9 2007-07-21       drh:     if( pEnd->zText[0]=='{' || pEnd->zText[0]==';' ){
dbda8d6ce9 2007-07-21       drh:       *pReset = pEnd->zText[0];
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( pEnd==0 ){
dbda8d6ce9 2007-07-21       drh:     *pReset = ';';
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: incomplete inline procedure definition\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pName = FindDeclName(pFirst,pEnd);
dbda8d6ce9 2007-07-21       drh:   if( pName==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: malformed inline procedure definition\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:   if( debugMask & PARSER ){
dbda8d6ce9 2007-07-21       drh:     printf("**** Found inline routine: %.*s on line %d...\n",
dbda8d6ce9 2007-07-21       drh:        pName->nText, pName->zText, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     PrintTokens(pFirst,pEnd);
dbda8d6ce9 2007-07-21       drh:     printf("\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:   pDecl = CreateDecl(pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   pDecl->pComment = pFirst->pComment;
dbda8d6ce9 2007-07-21       drh:   DeclSetProperty(pDecl,TY_Subroutine);
dbda8d6ce9 2007-07-21       drh:   pDecl->zDecl = TokensToString(pFirst,pEnd,";\n",0,0);
dbda8d6ce9 2007-07-21       drh:   if( (flags & (PS_Static|PS_Local|PS_Local2)) ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:   }else if( flags & (PS_Export|PS_Export2) ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Export);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( flags & DP_Cplusplus ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Cplusplus);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_ExternCReqd);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Determine if the tokens between pFirst and pEnd form a variable
dbda8d6ce9 2007-07-21       drh: ** definition or a function prototype.  Return TRUE if we are dealing
dbda8d6ce9 2007-07-21       drh: ** with a variable defintion and FALSE for a prototype.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** pEnd is the token that ends the object.  It can be either a ';' or
dbda8d6ce9 2007-07-21       drh: ** a '='.  If it is '=', then assume we have a variable definition.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If pEnd is ';', then the determination is more difficult.  We have
dbda8d6ce9 2007-07-21       drh: ** to search for an occurance of an ID followed immediately by '('.
dbda8d6ce9 2007-07-21       drh: ** If found, we have a prototype.  Otherwise we are dealing with a
dbda8d6ce9 2007-07-21       drh: ** variable definition.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int isVariableDef(Token *pFirst, Token *pEnd){
dbda8d6ce9 2007-07-21       drh:   if( pEnd && pEnd->zText[0]=='=' &&
dbda8d6ce9 2007-07-21       drh:     (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
dbda8d6ce9 2007-07-21       drh:   ){
dbda8d6ce9 2007-07-21       drh:     return 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
dbda8d6ce9 2007-07-21       drh:     if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){
dbda8d6ce9 2007-07-21       drh:       return 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return 1;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called whenever we encounter a ";" or "=".  The stuff
dbda8d6ce9 2007-07-21       drh: ** between pFirst and pLast constitutes either a typedef or a global
dbda8d6ce9 2007-07-21       drh: ** variable definition.  Do the right thing.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ProcessDecl(Token *pFirst, Token *pEnd, int flags){
dbda8d6ce9 2007-07-21       drh:   Token *pName;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   int isLocal = 0;
dbda8d6ce9 2007-07-21       drh:   int isVar;
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pFirst==0 || pEnd==0 ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( flags & PS_Typedef ){
dbda8d6ce9 2007-07-21       drh:     if( (flags & (PS_Export2|PS_Local2))!=0 ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s:%d: \"EXPORT\" or \"LOCAL\" ignored before typedef.\n",
dbda8d6ce9 2007-07-21       drh:         zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:       nErr++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( (flags & (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){
dbda8d6ce9 2007-07-21       drh:       /* It is illegal to duplicate a typedef in C (but OK in C++).
dbda8d6ce9 2007-07-21       drh:       ** So don't record typedefs that aren't within a C++ file or
dbda8d6ce9 2007-07-21       drh:       ** within #if INTERFACE..#endif */
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( (flags & (PS_Interface|PS_Export|PS_Local))==0 && proto_static==0 ){
dbda8d6ce9 2007-07-21       drh:       /* Ignore typedefs that are not with "#if INTERFACE..#endif" unless
dbda8d6ce9 2007-07-21       drh:       ** the "-local" command line option is used. */
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( (flags & (PS_Interface|PS_Export))==0 ){
dbda8d6ce9 2007-07-21       drh:       /* typedefs are always local, unless within #if INTERFACE..#endif */
dbda8d6ce9 2007-07-21       drh:       isLocal = 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( flags & (PS_Static|PS_Local2) ){
dbda8d6ce9 2007-07-21       drh:     if( proto_static==0 && (flags & PS_Local2)==0 ){
dbda8d6ce9 2007-07-21       drh:       /* Don't record static variables unless the "-local" command line
dbda8d6ce9 2007-07-21       drh:       ** option was specified or the "LOCAL" keyword is used. */
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     while( pFirst!=0 && pFirst->pNext!=pEnd &&
dbda8d6ce9 2007-07-21       drh:        ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
dbda8d6ce9 2007-07-21       drh:         || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
dbda8d6ce9 2007-07-21       drh:     ){
dbda8d6ce9 2007-07-21       drh:       /* Lose the initial "static" or local from local variables.
dbda8d6ce9 2007-07-21       drh:       ** We'll prepend "extern" later. */
dbda8d6ce9 2007-07-21       drh:       pFirst = pFirst->pNext;
dbda8d6ce9 2007-07-21       drh:       isLocal = 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pFirst==0 || !isLocal ){
dbda8d6ce9 2007-07-21       drh:       return nErr;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( flags & PS_Method ){
dbda8d6ce9 2007-07-21       drh:     /* Methods are declared by their class.  Don't declare separately. */
dbda8d6ce9 2007-07-21       drh:     return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   isVar =  (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
dbda8d6ce9 2007-07-21       drh:   if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
dbda8d6ce9 2007-07-21       drh:   && (flags & PS_Extern)==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     nErr++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pName = FindDeclName(pFirst,pEnd->pPrev);
dbda8d6ce9 2007-07-21       drh:   if( pName==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: Can't find a name for the object declared here.\n",
dbda8d6ce9 2007-07-21       drh:       zFilename, pFirst->nLine);
dbda8d6ce9 2007-07-21       drh:     return nErr+1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:   if( debugMask & PARSER ){
dbda8d6ce9 2007-07-21       drh:     if( flags & PS_Typedef ){
dbda8d6ce9 2007-07-21       drh:       printf("**** Found typedef %.*s at line %d...\n",
dbda8d6ce9 2007-07-21       drh:         pName->nText, pName->zText, pName->nLine);
dbda8d6ce9 2007-07-21       drh:     }else if( isVar ){
dbda8d6ce9 2007-07-21       drh:       printf("**** Found variable %.*s at line %d...\n",
dbda8d6ce9 2007-07-21       drh:         pName->nText, pName->zText, pName->nLine);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       printf("**** Found prototype %.*s at line %d...\n",
dbda8d6ce9 2007-07-21       drh:         pName->nText, pName->zText, pName->nLine);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     PrintTokens(pFirst,pEnd->pPrev);
dbda8d6ce9 2007-07-21       drh:     printf(";\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   pDecl = CreateDecl(pName->zText,pName->nText);
dbda8d6ce9 2007-07-21       drh:   if( (flags & PS_Typedef) ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl, TY_Typedef);
dbda8d6ce9 2007-07-21       drh:   }else if( isVar ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable);
dbda8d6ce9 2007-07-21       drh:     if( !(flags & DP_Cplusplus) ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(pDecl,DP_ExternCReqd);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl, TY_Subroutine);
dbda8d6ce9 2007-07-21       drh:     if( !(flags & DP_Cplusplus) ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(pDecl,DP_ExternCReqd);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pDecl->pComment = pFirst->pComment;
dbda8d6ce9 2007-07-21       drh:   pDecl->zDecl = TokensToString(pFirst,pEnd->pPrev,";\n",0,0);
dbda8d6ce9 2007-07-21       drh:   if( isLocal || (flags & (PS_Local|PS_Local2))!=0 ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:   }else if( flags & (PS_Export|PS_Export2) ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Export);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( flags & DP_Cplusplus ){
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,DP_Cplusplus);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Push an if condition onto the if stack
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void PushIfMacro(
dbda8d6ce9 2007-07-21       drh:   const char *zPrefix,      /* A prefix, like "define" or "!" */
dbda8d6ce9 2007-07-21       drh:   const char *zText,        /* The condition */
dbda8d6ce9 2007-07-21       drh:   int nText,                /* Number of characters in zText */
dbda8d6ce9 2007-07-21       drh:   int nLine,                /* Line number where this macro occurs */
dbda8d6ce9 2007-07-21       drh:   int flags                 /* Either 0, PS_Interface, PS_Export or PS_Local */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   Ifmacro *pIf;
dbda8d6ce9 2007-07-21       drh:   int nByte;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   nByte = sizeof(Ifmacro);
dbda8d6ce9 2007-07-21       drh:   if( zText ){
dbda8d6ce9 2007-07-21       drh:     if( zPrefix ){
dbda8d6ce9 2007-07-21       drh:       nByte += strlen(zPrefix) + 2;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     nByte += nText + 1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pIf = SafeMalloc( nByte );
dbda8d6ce9 2007-07-21       drh:   if( zText ){
dbda8d6ce9 2007-07-21       drh:     pIf->zCondition = (char*)&pIf[1];
dbda8d6ce9 2007-07-21       drh:     if( zPrefix ){
dbda8d6ce9 2007-07-21       drh:       sprintf(pIf->zCondition,"%s(%.*s)",zPrefix,nText,zText);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       sprintf(pIf->zCondition,"%.*s",nText,zText);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pIf->zCondition = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   pIf->nLine = nLine;
dbda8d6ce9 2007-07-21       drh:   pIf->flags = flags;
dbda8d6ce9 2007-07-21       drh:   pIf->pNext = ifStack;
dbda8d6ce9 2007-07-21       drh:   ifStack = pIf;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine is called to handle all preprocessor directives.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This routine will recompute the value of *pPresetFlags to be the
dbda8d6ce9 2007-07-21       drh: ** logical or of all flags on all nested #ifs.  The #ifs that set flags
dbda8d6ce9 2007-07-21       drh: ** are as follows:
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: **        conditional                   flag set
dbda8d6ce9 2007-07-21       drh: **        ------------------------      --------------------
dbda8d6ce9 2007-07-21       drh: **        #if INTERFACE                 PS_Interface
dbda8d6ce9 2007-07-21       drh: **        #if EXPORT_INTERFACE          PS_Export
dbda8d6ce9 2007-07-21       drh: **        #if LOCAL_INTERFACE           PS_Local
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** For example, if after processing the preprocessor token given
dbda8d6ce9 2007-07-21       drh: ** by pToken there is an "#if INTERFACE" on the preprocessor
dbda8d6ce9 2007-07-21       drh: ** stack, then *pPresetFlags will be set to PS_Interface.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ParsePreprocessor(Token *pToken, int flags, int *pPresetFlags){
dbda8d6ce9 2007-07-21       drh:   const char *zCmd;
dbda8d6ce9 2007-07-21       drh:   int nCmd;
dbda8d6ce9 2007-07-21       drh:   const char *zArg;
dbda8d6ce9 2007-07-21       drh:   int nArg;
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh:   Ifmacro *pIf;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   zCmd = &pToken->zText[1];
dbda8d6ce9 2007-07-21       drh:   while( isspace(*zCmd) && *zCmd!='\n' ){
dbda8d6ce9 2007-07-21       drh:     zCmd++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( !isalpha(*zCmd) ){
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   nCmd = 1;
dbda8d6ce9 2007-07-21       drh:   while( isalpha(zCmd[nCmd]) ){
dbda8d6ce9 2007-07-21       drh:     nCmd++;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Pop the if stack
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     pIf = ifStack;
dbda8d6ce9 2007-07-21       drh:     if( pIf==0 ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
dbda8d6ce9 2007-07-21       drh:       return 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     ifStack = pIf->pNext;
dbda8d6ce9 2007-07-21       drh:     SafeFree(pIf);
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Record a #define if we are in PS_Interface or PS_Export
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:     if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     zArg = &zCmd[6];
dbda8d6ce9 2007-07-21       drh:     while( *zArg && isspace(*zArg) && *zArg!='\n' ){
dbda8d6ce9 2007-07-21       drh:       zArg++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( *zArg==0 || *zArg=='\n' ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
dbda8d6ce9 2007-07-21       drh:     if( nArg==0 ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     pDecl = CreateDecl(zArg,nArg);
dbda8d6ce9 2007-07-21       drh:     pDecl->pComment = pToken->pComment;
dbda8d6ce9 2007-07-21       drh:     DeclSetProperty(pDecl,TY_Macro);
dbda8d6ce9 2007-07-21       drh:     pDecl->zDecl = SafeMalloc( pToken->nText + 2 );
dbda8d6ce9 2007-07-21       drh:     sprintf(pDecl->zDecl,"%.*s\n",pToken->nText,pToken->zText);
dbda8d6ce9 2007-07-21       drh:     if( flags & PS_Export ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(pDecl,DP_Export);
dbda8d6ce9 2007-07-21       drh:     }else if( flags & PS_Local ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(pDecl,DP_Local);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Record an #include if we are in PS_Interface or PS_Export
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     Include *pInclude;
dbda8d6ce9 2007-07-21       drh:     char *zIf;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     zArg = &zCmd[7];
dbda8d6ce9 2007-07-21       drh:     while( *zArg && isspace(*zArg) ){ zArg++; }
dbda8d6ce9 2007-07-21       drh:     for(nArg=0; !isspace(zArg[nArg]); nArg++){}
dbda8d6ce9 2007-07-21       drh:     if( (zArg[0]=='"' && zArg[nArg-1]!='"')
dbda8d6ce9 2007-07-21       drh:       ||(zArg[0]=='<' && zArg[nArg-1]!='>')
dbda8d6ce9 2007-07-21       drh:     ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s:%d: malformed #include statement.\n",
dbda8d6ce9 2007-07-21       drh:         zFilename,pToken->nLine);
dbda8d6ce9 2007-07-21       drh:       return 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     zIf = GetIfString();
dbda8d6ce9 2007-07-21       drh:     if( zIf ){
dbda8d6ce9 2007-07-21       drh:       pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
dbda8d6ce9 2007-07-21       drh:       pInclude->zFile = (char*)&pInclude[1];
dbda8d6ce9 2007-07-21       drh:       pInclude->zLabel = &pInclude->zFile[nArg+1];
dbda8d6ce9 2007-07-21       drh:       sprintf(pInclude->zFile,"%.*s",nArg,zArg);
dbda8d6ce9 2007-07-21       drh:       sprintf(pInclude->zLabel,"%.*s:%s",nArg,zArg,zIf);
dbda8d6ce9 2007-07-21       drh:       pInclude->zIf = &pInclude->zLabel[nArg+1];
dbda8d6ce9 2007-07-21       drh:       SafeFree(zIf);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       pInclude = SafeMalloc( sizeof(Include) + nArg + 1 );
dbda8d6ce9 2007-07-21       drh:       pInclude->zFile = (char*)&pInclude[1];
dbda8d6ce9 2007-07-21       drh:       sprintf(pInclude->zFile,"%.*s",nArg,zArg);
dbda8d6ce9 2007-07-21       drh:       pInclude->zIf = 0;
dbda8d6ce9 2007-07-21       drh:       pInclude->zLabel = pInclude->zFile;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pInclude->pNext = includeList;
dbda8d6ce9 2007-07-21       drh:     includeList = pInclude;
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==2 && strncmp(zCmd,"if",2)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Push an #if.  Watch for the special cases of INTERFACE
dbda8d6ce9 2007-07-21       drh:     ** and EXPORT_INTERFACE and LOCAL_INTERFACE
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     zArg = &zCmd[2];
dbda8d6ce9 2007-07-21       drh:     while( *zArg && isspace(*zArg) && *zArg!='\n' ){
dbda8d6ce9 2007-07-21       drh:       zArg++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( *zArg==0 || *zArg=='\n' ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     nArg = pToken->nText + (int)pToken->zText - (int)zArg;
dbda8d6ce9 2007-07-21       drh:     if( nArg==9 && strncmp(zArg,"INTERFACE",9)==0 ){
dbda8d6ce9 2007-07-21       drh:       PushIfMacro(0,0,0,pToken->nLine,PS_Interface);
dbda8d6ce9 2007-07-21       drh:     }else if( nArg==16 && strncmp(zArg,"EXPORT_INTERFACE",16)==0 ){
dbda8d6ce9 2007-07-21       drh:       PushIfMacro(0,0,0,pToken->nLine,PS_Export);
dbda8d6ce9 2007-07-21       drh:     }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){
dbda8d6ce9 2007-07-21       drh:       PushIfMacro(0,0,0,pToken->nLine,PS_Local);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       PushIfMacro(0,zArg,nArg,pToken->nLine,0);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Push an #ifdef.
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     zArg = &zCmd[5];
dbda8d6ce9 2007-07-21       drh:     while( *zArg && isspace(*zArg) && *zArg!='\n' ){
dbda8d6ce9 2007-07-21       drh:       zArg++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( *zArg==0 || *zArg=='\n' ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     nArg = pToken->nText + (int)pToken->zText - (int)zArg;
dbda8d6ce9 2007-07-21       drh:     PushIfMacro("defined",zArg,nArg,pToken->nLine,0);
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==6 && strncmp(zCmd,"ifndef",6)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Push an #ifndef.
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     zArg = &zCmd[6];
dbda8d6ce9 2007-07-21       drh:     while( *zArg && isspace(*zArg) && *zArg!='\n' ){
dbda8d6ce9 2007-07-21       drh:       zArg++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( *zArg==0 || *zArg=='\n' ){ return 0; }
dbda8d6ce9 2007-07-21       drh:     nArg = pToken->nText + (int)pToken->zText - (int)zArg;
dbda8d6ce9 2007-07-21       drh:     PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
dbda8d6ce9 2007-07-21       drh:   }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** Invert the #if on the top of the stack
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     if( ifStack==0 ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
dbda8d6ce9 2007-07-21       drh:          pToken->nLine);
dbda8d6ce9 2007-07-21       drh:       return 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pIf = ifStack;
dbda8d6ce9 2007-07-21       drh:     if( pIf->zCondition ){
dbda8d6ce9 2007-07-21       drh:       ifStack = ifStack->pNext;
dbda8d6ce9 2007-07-21       drh:       PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0);
dbda8d6ce9 2007-07-21       drh:       SafeFree(pIf);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       pIf->flags = 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     /*
dbda8d6ce9 2007-07-21       drh:     ** This directive can be safely ignored
dbda8d6ce9 2007-07-21       drh:     */
dbda8d6ce9 2007-07-21       drh:     return 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Recompute the preset flags
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   *pPresetFlags = 0;
dbda8d6ce9 2007-07-21       drh:   for(pIf = ifStack; pIf; pIf=pIf->pNext){
dbda8d6ce9 2007-07-21       drh:     *pPresetFlags |= pIf->flags;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Parse an entire file.  Return the number of errors.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** pList is a list of tokens in the file.  Whitespace tokens have been
dbda8d6ce9 2007-07-21       drh: ** eliminated, and text with {...} has been collapsed into a
dbda8d6ce9 2007-07-21       drh: ** single TT_Brace token.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** initFlags are a set of parse flags that should always be set for this
dbda8d6ce9 2007-07-21       drh: ** file.  For .c files this is normally 0.  For .h files it is PS_Interface.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ParseFile(Token *pList, int initFlags){
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh:   Token *pStart = 0;
dbda8d6ce9 2007-07-21       drh:   int flags = initFlags;
dbda8d6ce9 2007-07-21       drh:   int presetFlags = initFlags;
dbda8d6ce9 2007-07-21       drh:   int resetFlag = 0;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   includeList = 0;
dbda8d6ce9 2007-07-21       drh:   while( pList ){
dbda8d6ce9 2007-07-21       drh:     switch( pList->eType ){
dbda8d6ce9 2007-07-21       drh:     case TT_EOF:
dbda8d6ce9 2007-07-21       drh:       goto end_of_loop;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Preprocessor:
dbda8d6ce9 2007-07-21       drh:       nErr += ParsePreprocessor(pList,flags,&presetFlags);
dbda8d6ce9 2007-07-21       drh:       pStart = 0;
dbda8d6ce9 2007-07-21       drh:       presetFlags |= initFlags;
dbda8d6ce9 2007-07-21       drh:       flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Other:
dbda8d6ce9 2007-07-21       drh:       switch( pList->zText[0] ){
dbda8d6ce9 2007-07-21       drh:       case ';':
dbda8d6ce9 2007-07-21       drh:         nErr += ProcessDecl(pStart,pList,flags);
dbda8d6ce9 2007-07-21       drh:         pStart = 0;
dbda8d6ce9 2007-07-21       drh:         flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case '=':
dbda8d6ce9 2007-07-21       drh:         if( pList->pPrev->nText==8
dbda8d6ce9 2007-07-21       drh:             && strncmp(pList->pPrev->zText,"operator",8)==0 ){
dbda8d6ce9 2007-07-21       drh:           break;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         nErr += ProcessDecl(pStart,pList,flags);
dbda8d6ce9 2007-07-21       drh:         pStart = 0;
dbda8d6ce9 2007-07-21       drh:         while( pList && pList->zText[0]!=';' ){
dbda8d6ce9 2007-07-21       drh:           pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         if( pList==0 ) goto end_of_loop;
dbda8d6ce9 2007-07-21       drh:         flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       case ':':
dbda8d6ce9 2007-07-21       drh:         if( pList->zText[1]==':' ){
dbda8d6ce9 2007-07-21       drh:           flags |= PS_Method;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       default:
dbda8d6ce9 2007-07-21       drh:         break;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Braces:
dbda8d6ce9 2007-07-21       drh:       nErr += ProcessProcedureDef(pStart,pList,flags);
dbda8d6ce9 2007-07-21       drh:       pStart = 0;
dbda8d6ce9 2007-07-21       drh:       flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_Id:
dbda8d6ce9 2007-07-21       drh:        if( pStart==0 ){
dbda8d6ce9 2007-07-21       drh:           pStart = pList;
dbda8d6ce9 2007-07-21       drh:           flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:        }
dbda8d6ce9 2007-07-21       drh:        resetFlag = 0;
dbda8d6ce9 2007-07-21       drh:        switch( pList->zText[0] ){
dbda8d6ce9 2007-07-21       drh:        case 'c':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==5 && strncmp(pList->zText,"class",5)==0 ){
dbda8d6ce9 2007-07-21       drh:            nErr += ProcessTypeDecl(pList,flags,&resetFlag);
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'E':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==6 && strncmp(pList->zText,"EXPORT",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Export2;
dbda8d6ce9 2007-07-21       drh:            /* pStart = 0; */
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'e':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==4 && strncmp(pList->zText,"enum",4)==0 ){
dbda8d6ce9 2007-07-21       drh:            if( pList->pNext && pList->pNext->eType==TT_Braces ){
dbda8d6ce9 2007-07-21       drh:              pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:            }else{
dbda8d6ce9 2007-07-21       drh:              nErr += ProcessTypeDecl(pList,flags,&resetFlag);
dbda8d6ce9 2007-07-21       drh:            }
dbda8d6ce9 2007-07-21       drh:          }else if( pList->nText==6 && strncmp(pList->zText,"extern",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:            if( pList && pList->nText==3 && strncmp(pList->zText,"\"C\"",3)==0 ){
dbda8d6ce9 2007-07-21       drh:              pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:              flags &= ~DP_Cplusplus;
dbda8d6ce9 2007-07-21       drh:            }else{
dbda8d6ce9 2007-07-21       drh:              flags |= PS_Extern;
dbda8d6ce9 2007-07-21       drh:            }
dbda8d6ce9 2007-07-21       drh:            pStart = pList;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'i':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            nErr += ProcessInlineProc(pList,flags,&resetFlag);
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'L':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==5 && strncmp(pList->zText,"LOCAL",5)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Local2;
dbda8d6ce9 2007-07-21       drh:            pStart = pList;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'P':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==6 && strncmp(pList->zText, "PUBLIC",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Public;
dbda8d6ce9 2007-07-21       drh:            pStart = pList;
dbda8d6ce9 2007-07-21       drh:          }else if( pList->nText==7 && strncmp(pList->zText, "PRIVATE",7)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Private;
dbda8d6ce9 2007-07-21       drh:            pStart = pList;
dbda8d6ce9 2007-07-21       drh:          }else if( pList->nText==9 && strncmp(pList->zText,"PROTECTED",9)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Protected;
dbda8d6ce9 2007-07-21       drh:            pStart = pList;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 's':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==6 && strncmp(pList->zText,"struct",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            if( pList->pNext && pList->pNext->eType==TT_Braces ){
dbda8d6ce9 2007-07-21       drh:              pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:            }else{
dbda8d6ce9 2007-07-21       drh:              nErr += ProcessTypeDecl(pList,flags,&resetFlag);
dbda8d6ce9 2007-07-21       drh:            }
dbda8d6ce9 2007-07-21       drh:          }else if( pList->nText==6 && strncmp(pList->zText,"static",6)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Static;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 't':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==7 && strncmp(pList->zText,"typedef",7)==0 ){
dbda8d6ce9 2007-07-21       drh:            flags |= PS_Typedef;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        case 'u':
dbda8d6ce9 2007-07-21       drh:          if( pList->nText==5 && strncmp(pList->zText,"union",5)==0 ){
dbda8d6ce9 2007-07-21       drh:            if( pList->pNext && pList->pNext->eType==TT_Braces ){
dbda8d6ce9 2007-07-21       drh:              pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:            }else{
dbda8d6ce9 2007-07-21       drh:              nErr += ProcessTypeDecl(pList,flags,&resetFlag);
dbda8d6ce9 2007-07-21       drh:            }
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:        default:
dbda8d6ce9 2007-07-21       drh:          break;
dbda8d6ce9 2007-07-21       drh:        }
dbda8d6ce9 2007-07-21       drh:        if( resetFlag!=0 ){
dbda8d6ce9 2007-07-21       drh:          while( pList && pList->zText[0]!=resetFlag ){
dbda8d6ce9 2007-07-21       drh:            pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:          }
dbda8d6ce9 2007-07-21       drh:          if( pList==0 ) goto end_of_loop;
dbda8d6ce9 2007-07-21       drh:          pStart = 0;
dbda8d6ce9 2007-07-21       drh:          flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:        }
dbda8d6ce9 2007-07-21       drh:        break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     case TT_String:
dbda8d6ce9 2007-07-21       drh:     case TT_Number:
dbda8d6ce9 2007-07-21       drh:        break;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     default:
dbda8d6ce9 2007-07-21       drh:        pStart = pList;
dbda8d6ce9 2007-07-21       drh:        flags = presetFlags;
dbda8d6ce9 2007-07-21       drh:        break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     pList = pList->pNext;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   end_of_loop:
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Verify that all #ifs have a matching "#endif" */
dbda8d6ce9 2007-07-21       drh:   while( ifStack ){
dbda8d6ce9 2007-07-21       drh:     Ifmacro *pIf = ifStack;
dbda8d6ce9 2007-07-21       drh:     ifStack = pIf->pNext;
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"%s:%d: This '#if' has no '#endif'\n",zFilename,
dbda8d6ce9 2007-07-21       drh:       pIf->nLine);
dbda8d6ce9 2007-07-21       drh:     SafeFree(pIf);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** If the given Decl object has a non-null zExtra field, then the text
dbda8d6ce9 2007-07-21       drh: ** of that zExtra field needs to be inserted in the middle of the
dbda8d6ce9 2007-07-21       drh: ** zDecl field before the last "}" in the zDecl.  This routine does that.
dbda8d6ce9 2007-07-21       drh: ** If the zExtra is NULL, this routine is a no-op.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** zExtra holds extra method declarations for classes.  The declarations
dbda8d6ce9 2007-07-21       drh: ** have to be inserted into the class definition.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void InsertExtraDecl(Decl *pDecl){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   String str;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pDecl==0 || pDecl->zExtra==0 || pDecl->zDecl==0 ) return;
dbda8d6ce9 2007-07-21       drh:   i = strlen(pDecl->zDecl) - 1;
dbda8d6ce9 2007-07-21       drh:   while( i>0 && pDecl->zDecl[i]!='}' ){ i--; }
dbda8d6ce9 2007-07-21       drh:   StringInit(&str);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str, pDecl->zDecl, i);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str, pDecl->zExtra, 0);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&str, &pDecl->zDecl[i], 0);
dbda8d6ce9 2007-07-21       drh:   SafeFree(pDecl->zDecl);
dbda8d6ce9 2007-07-21       drh:   SafeFree(pDecl->zExtra);
dbda8d6ce9 2007-07-21       drh:   pDecl->zDecl = StrDup(StringGet(&str), 0);
dbda8d6ce9 2007-07-21       drh:   StringReset(&str);
dbda8d6ce9 2007-07-21       drh:   pDecl->zExtra = 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Reset the DP_Forward and DP_Declared flags on all Decl structures.
dbda8d6ce9 2007-07-21       drh: ** Set both flags for anything that is tagged as local and isn't
dbda8d6ce9 2007-07-21       drh: ** in the file zFilename so that it won't be printing in other files.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void ResetDeclFlags(char *zFilename){
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){
dbda8d6ce9 2007-07-21       drh:     DeclClearProperty(pDecl,DP_Forward|DP_Declared);
dbda8d6ce9 2007-07-21       drh:     if( DeclHasProperty(pDecl,DP_Local) && pDecl->zFile!=zFilename ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(pDecl,DP_Forward|DP_Declared);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Forward declaration of the ScanText() function.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void ScanText(const char*, GenState *pState);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The output in pStr is currently within an #if CONTEXT where context
dbda8d6ce9 2007-07-21       drh: ** is equal to *pzIf.  (*pzIf might be NULL to indicate that we are
dbda8d6ce9 2007-07-21       drh: ** not within any #if at the moment.)  We are getting ready to output
dbda8d6ce9 2007-07-21       drh: ** some text that needs to be within the context of "#if NEW" where
dbda8d6ce9 2007-07-21       drh: ** NEW is zIf.  Make an appropriate change to the context.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void ChangeIfContext(
dbda8d6ce9 2007-07-21       drh:   const char *zIf,       /* The desired #if context */
dbda8d6ce9 2007-07-21       drh:   GenState *pState       /* Current state of the code generator */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   if( zIf==0 ){
dbda8d6ce9 2007-07-21       drh:     if( pState->zIf==0 ) return;
dbda8d6ce9 2007-07-21       drh:     StringAppend(pState->pStr,"#endif\n",0);
dbda8d6ce9 2007-07-21       drh:     pState->zIf = 0;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     if( pState->zIf ){
dbda8d6ce9 2007-07-21       drh:       if( strcmp(zIf,pState->zIf)==0 ) return;
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,"#endif\n",0);
dbda8d6ce9 2007-07-21       drh:       pState->zIf = 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     ScanText(zIf, pState);
dbda8d6ce9 2007-07-21       drh:     if( pState->zIf!=0 ){
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,"#endif\n",0);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     StringAppend(pState->pStr,"#if ",0);
dbda8d6ce9 2007-07-21       drh:     StringAppend(pState->pStr,zIf,0);
dbda8d6ce9 2007-07-21       drh:     StringAppend(pState->pStr,"\n",0);
dbda8d6ce9 2007-07-21       drh:     pState->zIf = zIf;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Add to the string pStr a #include of every file on the list of
dbda8d6ce9 2007-07-21       drh: ** include files pInclude.  The table pTable contains all files that
dbda8d6ce9 2007-07-21       drh: ** have already been #included at least once.  Don't add any
dbda8d6ce9 2007-07-21       drh: ** duplicates.  Update pTable with every new #include that is added.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void AddIncludes(
dbda8d6ce9 2007-07-21       drh:   Include *pInclude,       /* Write every #include on this list */
dbda8d6ce9 2007-07-21       drh:   GenState *pState         /* Current state of the code generator */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   if( pInclude ){
dbda8d6ce9 2007-07-21       drh:     if( pInclude->pNext ){
dbda8d6ce9 2007-07-21       drh:       AddIncludes(pInclude->pNext,pState);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( IdentTableInsert(pState->pTable,pInclude->zLabel,0) ){
dbda8d6ce9 2007-07-21       drh:       ChangeIfContext(pInclude->zIf,pState);
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,"#include ",0);
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,pInclude->zFile,0);
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,"\n",1);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Add to the string pStr a declaration for the object described
dbda8d6ce9 2007-07-21       drh: ** in pDecl.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If pDecl has already been declared in this file, detect that
dbda8d6ce9 2007-07-21       drh: ** fact and abort early.  Do not duplicate a declaration.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If the needFullDecl flag is false and this object has a forward
dbda8d6ce9 2007-07-21       drh: ** declaration, then supply the forward declaration only.  A later
dbda8d6ce9 2007-07-21       drh: ** call to CompleteForwardDeclarations() will finish the declaration
dbda8d6ce9 2007-07-21       drh: ** for us.  But if needFullDecl is true, we must supply the full
dbda8d6ce9 2007-07-21       drh: ** declaration now.  Some objects do not have a forward declaration.
dbda8d6ce9 2007-07-21       drh: ** For those objects, we must print the full declaration now.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Because it is illegal to duplicate a typedef in C, care is taken
dbda8d6ce9 2007-07-21       drh: ** to insure that typedefs for the same identifier are only issued once.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void DeclareObject(
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl,        /* The thing to be declared */
dbda8d6ce9 2007-07-21       drh:   GenState *pState,   /* Current state of the code generator */
dbda8d6ce9 2007-07-21       drh:   int needFullDecl    /* Must have the full declaration.  A forward
dbda8d6ce9 2007-07-21       drh:                        * declaration isn't enough */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   Decl *p;               /* The object to be declared */
dbda8d6ce9 2007-07-21       drh:   int flag;
dbda8d6ce9 2007-07-21       drh:   int isCpp;             /* True if generating C++ */
dbda8d6ce9 2007-07-21       drh:   int doneTypedef = 0;   /* True if a typedef has been done for this object */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** For any object that has a forward declaration, go ahead and do the
dbda8d6ce9 2007-07-21       drh:   ** forward declaration first.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   isCpp = (pState->flags & DP_Cplusplus) != 0;
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( p->zFwd ){
dbda8d6ce9 2007-07-21       drh:       if( !DeclHasProperty(p,DP_Forward) ){
dbda8d6ce9 2007-07-21       drh:         DeclSetProperty(p,DP_Forward);
dbda8d6ce9 2007-07-21       drh:         if( strncmp(p->zFwd,"typedef",7)==0 ){
dbda8d6ce9 2007-07-21       drh:           if( doneTypedef ) continue;
dbda8d6ce9 2007-07-21       drh:           doneTypedef = 1;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:         ChangeIfContext(p->zIf,pState);
dbda8d6ce9 2007-07-21       drh:         StringAppend(pState->pStr,isCpp ? p->zFwdCpp : p->zFwd,0);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Early out if everything is already suitably declared.
dbda8d6ce9 2007-07-21       drh:   **
dbda8d6ce9 2007-07-21       drh:   ** This is a very important step because it prevents us from
dbda8d6ce9 2007-07-21       drh:   ** executing the code the follows in a recursive call to this
dbda8d6ce9 2007-07-21       drh:   ** function with the same value for pDecl.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   flag = needFullDecl ? DP_Declared|DP_Forward : DP_Forward;
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( !DeclHasProperty(p,flag) ) break;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( p==0 ){
dbda8d6ce9 2007-07-21       drh:     return;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Make sure we have all necessary #includes
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     AddIncludes(p->pInclude,pState);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Go ahead an mark everything as being declared, to prevent an
dbda8d6ce9 2007-07-21       drh:   ** infinite loop thru the ScanText() function.  At the same time,
dbda8d6ce9 2007-07-21       drh:   ** we decide which objects need a full declaration and mark them
dbda8d6ce9 2007-07-21       drh:   ** with the DP_Flag bit.  We are only able to use DP_Flag in this
dbda8d6ce9 2007-07-21       drh:   ** way because we know we'll never execute this far into this
dbda8d6ce9 2007-07-21       drh:   ** function on a recursive call with the same pDecl.  Hence, recursive
dbda8d6ce9 2007-07-21       drh:   ** calls to this function (through ScanText()) can never change the
dbda8d6ce9 2007-07-21       drh:   ** value of DP_Flag out from under us.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( !DeclHasProperty(p,DP_Declared)
dbda8d6ce9 2007-07-21       drh:      && (p->zFwd==0 || needFullDecl)
dbda8d6ce9 2007-07-21       drh:      && p->zDecl!=0
dbda8d6ce9 2007-07-21       drh:     ){
dbda8d6ce9 2007-07-21       drh:       DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       DeclClearProperty(p,DP_Flag);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Call ScanText() recusively (this routine is called from ScanText())
dbda8d6ce9 2007-07-21       drh:   ** to include declarations required to come before these declarations.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( DeclHasProperty(p,DP_Flag) ){
dbda8d6ce9 2007-07-21       drh:       if( p->zDecl[0]=='#' ){
dbda8d6ce9 2007-07-21       drh:         ScanText(&p->zDecl[1],pState);
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         InsertExtraDecl(p);
dbda8d6ce9 2007-07-21       drh:         ScanText(p->zDecl,pState);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Output the declarations.  Do this in two passes.  First
dbda8d6ce9 2007-07-21       drh:   ** output everything that isn't a typedef.  Then go back and
dbda8d6ce9 2007-07-21       drh:   ** get the typedefs by the same name.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( DeclHasProperty(p,DP_Flag) && !DeclHasProperty(p,TY_Typedef) ){
dbda8d6ce9 2007-07-21       drh:       if( DeclHasAnyProperty(p,TY_Enumeration) ){
dbda8d6ce9 2007-07-21       drh:         if( doneTypedef ) continue;
dbda8d6ce9 2007-07-21       drh:         doneTypedef = 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       ChangeIfContext(p->zIf,pState);
dbda8d6ce9 2007-07-21       drh:       if( !isCpp && DeclHasAnyProperty(p,DP_ExternReqd) ){
dbda8d6ce9 2007-07-21       drh:         StringAppend(pState->pStr,"extern ",0);
dbda8d6ce9 2007-07-21       drh:       }else if( isCpp && DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){
dbda8d6ce9 2007-07-21       drh:         StringAppend(pState->pStr,"extern ",0);
dbda8d6ce9 2007-07-21       drh:       }else if( isCpp && DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){
dbda8d6ce9 2007-07-21       drh:         StringAppend(pState->pStr,"extern \"C\" ",0);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       InsertExtraDecl(p);
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,p->zDecl,0);
dbda8d6ce9 2007-07-21       drh:       if( !isCpp && DeclHasProperty(p,DP_Cplusplus) ){
dbda8d6ce9 2007-07-21       drh:         fprintf(stderr,
dbda8d6ce9 2007-07-21       drh:           "%s: C code ought not reference the C++ object \"%s\"\n",
dbda8d6ce9 2007-07-21       drh:           pState->zFilename, p->zName);
dbda8d6ce9 2007-07-21       drh:         pState->nErr++;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       DeclClearProperty(p,DP_Flag);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   for(p=pDecl; p && !doneTypedef; p=p->pSameName){
dbda8d6ce9 2007-07-21       drh:     if( DeclHasProperty(p,DP_Flag) ){
dbda8d6ce9 2007-07-21       drh:       /* This has to be a typedef */
dbda8d6ce9 2007-07-21       drh:       doneTypedef = 1;
dbda8d6ce9 2007-07-21       drh:       ChangeIfContext(p->zIf,pState);
dbda8d6ce9 2007-07-21       drh:       InsertExtraDecl(p);
dbda8d6ce9 2007-07-21       drh:       StringAppend(pState->pStr,p->zDecl,0);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** This routine scans the input text given, and appends to the
dbda8d6ce9 2007-07-21       drh: ** string in pState->pStr the text of any declarations that must
dbda8d6ce9 2007-07-21       drh: ** occur before the text in zText.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If an identifier in zText is immediately followed by '*', then
dbda8d6ce9 2007-07-21       drh: ** only forward declarations are needed for that identifier.  If the
dbda8d6ce9 2007-07-21       drh: ** identifier name is not followed immediately by '*', we must supply
dbda8d6ce9 2007-07-21       drh: ** a full declaration.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void ScanText(
dbda8d6ce9 2007-07-21       drh:   const char *zText,    /* The input text to be scanned */
dbda8d6ce9 2007-07-21       drh:   GenState *pState      /* Current state of the code generator */
dbda8d6ce9 2007-07-21       drh: ){
dbda8d6ce9 2007-07-21       drh:   int nextValid = 0;    /* True is sNext contains valid data */
dbda8d6ce9 2007-07-21       drh:   InStream sIn;         /* The input text */
dbda8d6ce9 2007-07-21       drh:   Token sToken;         /* The current token being examined */
dbda8d6ce9 2007-07-21       drh:   Token sNext;          /* The next non-space token */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* printf("BEGIN SCAN TEXT on %s\n", zText); */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   sIn.z = zText;
dbda8d6ce9 2007-07-21       drh:   sIn.i = 0;
dbda8d6ce9 2007-07-21       drh:   sIn.nLine = 1;
dbda8d6ce9 2007-07-21       drh:   while( sIn.z[sIn.i]!=0 ){
dbda8d6ce9 2007-07-21       drh:     if( nextValid ){
dbda8d6ce9 2007-07-21       drh:       sToken = sNext;
dbda8d6ce9 2007-07-21       drh:       nextValid = 0;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       GetNonspaceToken(&sIn,&sToken);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( sToken.eType==TT_Id ){
dbda8d6ce9 2007-07-21       drh:       int needFullDecl;   /* True if we need to provide the full declaration,
dbda8d6ce9 2007-07-21       drh:                           ** not just the forward declaration */
dbda8d6ce9 2007-07-21       drh:       Decl *pDecl;        /* The declaration having the name in sToken */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       /*
dbda8d6ce9 2007-07-21       drh:       ** See if there is a declaration in the database with the name given
dbda8d6ce9 2007-07-21       drh:       ** by sToken.
dbda8d6ce9 2007-07-21       drh:       */
dbda8d6ce9 2007-07-21       drh:       pDecl = FindDecl(sToken.zText,sToken.nText);
dbda8d6ce9 2007-07-21       drh:       if( pDecl==0 ) continue;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       /*
dbda8d6ce9 2007-07-21       drh:       ** If we get this far, we've found an identifier that has a
dbda8d6ce9 2007-07-21       drh:       ** declaration in the database.  Now see if we the full declaration
dbda8d6ce9 2007-07-21       drh:       ** or just a forward declaration.
dbda8d6ce9 2007-07-21       drh:       */
dbda8d6ce9 2007-07-21       drh:       GetNonspaceToken(&sIn,&sNext);
dbda8d6ce9 2007-07-21       drh:       if( sNext.zText[0]=='*' ){
dbda8d6ce9 2007-07-21       drh:         needFullDecl = 0;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         needFullDecl = 1;
dbda8d6ce9 2007-07-21       drh:         nextValid = sNext.eType==TT_Id;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:       /*
dbda8d6ce9 2007-07-21       drh:       ** Generate the needed declaration.
dbda8d6ce9 2007-07-21       drh:       */
dbda8d6ce9 2007-07-21       drh:       DeclareObject(pDecl,pState,needFullDecl);
dbda8d6ce9 2007-07-21       drh:     }else if( sToken.eType==TT_Preprocessor ){
dbda8d6ce9 2007-07-21       drh:       sIn.i -= sToken.nText - 1;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   /* printf("END SCANTEXT\n"); */
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Provide a full declaration to any object which so far has had only
dbda8d6ce9 2007-07-21       drh: ** a foward declaration.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void CompleteForwardDeclarations(GenState *pState){
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   int progress;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   do{
dbda8d6ce9 2007-07-21       drh:     progress = 0;
dbda8d6ce9 2007-07-21       drh:     for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
dbda8d6ce9 2007-07-21       drh:       if( DeclHasProperty(pDecl,DP_Forward)
dbda8d6ce9 2007-07-21       drh:        && !DeclHasProperty(pDecl,DP_Declared)
dbda8d6ce9 2007-07-21       drh:       ){
dbda8d6ce9 2007-07-21       drh:         DeclareObject(pDecl,pState,1);
dbda8d6ce9 2007-07-21       drh:         progress = 1;
dbda8d6ce9 2007-07-21       drh:         assert( DeclHasProperty(pDecl,DP_Declared) );
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }while( progress );
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Generate an include file for the given source file.  Return the number
dbda8d6ce9 2007-07-21       drh: ** of errors encountered.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** if nolocal_flag is true, then we do not generate declarations for
dbda8d6ce9 2007-07-21       drh: ** objected marked DP_Local.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int MakeHeader(InFile *pFile, FILE *report, int nolocal_flag){
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;
dbda8d6ce9 2007-07-21       drh:   GenState sState;
dbda8d6ce9 2007-07-21       drh:   String outStr;
dbda8d6ce9 2007-07-21       drh:   IdentTable includeTable;
dbda8d6ce9 2007-07-21       drh:   Ident *pId;
dbda8d6ce9 2007-07-21       drh:   char *zNewVersion;
dbda8d6ce9 2007-07-21       drh:   char *zOldVersion;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( pFile->zHdr==0 || *pFile->zHdr==0 ) return 0;
dbda8d6ce9 2007-07-21       drh:   sState.pStr = &outStr;
dbda8d6ce9 2007-07-21       drh:   StringInit(&outStr);
dbda8d6ce9 2007-07-21       drh:   StringAppend(&outStr,zTopLine,nTopLine);
dbda8d6ce9 2007-07-21       drh:   sState.pTable = &includeTable;
dbda8d6ce9 2007-07-21       drh:   memset(&includeTable,0,sizeof(includeTable));
dbda8d6ce9 2007-07-21       drh:   sState.zIf = 0;
dbda8d6ce9 2007-07-21       drh:   sState.nErr = 0;
dbda8d6ce9 2007-07-21       drh:   sState.zFilename = pFile->zSrc;
dbda8d6ce9 2007-07-21       drh:   sState.flags = pFile->flags & DP_Cplusplus;
dbda8d6ce9 2007-07-21       drh:   ResetDeclFlags(nolocal_flag ? "no" : pFile->zSrc);
dbda8d6ce9 2007-07-21       drh:   for(pId = pFile->idTable.pList; pId; pId=pId->pNext){
dbda8d6ce9 2007-07-21       drh:     Decl *pDecl = FindDecl(pId->zName,0);
dbda8d6ce9 2007-07-21       drh:     if( pDecl ){
dbda8d6ce9 2007-07-21       drh:       DeclareObject(pDecl,&sState,1);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   CompleteForwardDeclarations(&sState);
dbda8d6ce9 2007-07-21       drh:   ChangeIfContext(0,&sState);
dbda8d6ce9 2007-07-21       drh:   nErr += sState.nErr;
dbda8d6ce9 2007-07-21       drh:   zOldVersion = ReadFile(pFile->zHdr);
dbda8d6ce9 2007-07-21       drh:   zNewVersion = StringGet(&outStr);
dbda8d6ce9 2007-07-21       drh:   if( report ) fprintf(report,"%s: ",pFile->zHdr);
dbda8d6ce9 2007-07-21       drh:   if( zOldVersion==0 ){
dbda8d6ce9 2007-07-21       drh:     if( report ) fprintf(report,"updated\n");
dbda8d6ce9 2007-07-21       drh:     if( WriteFile(pFile->zHdr,zNewVersion) ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
dbda8d6ce9 2007-07-21       drh:       nErr++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){
dbda8d6ce9 2007-07-21       drh:     if( report ) fprintf(report,"error!\n");
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,
dbda8d6ce9 2007-07-21       drh:        "%s: Can't overwrite this file because it wasn't previously\n"
dbda8d6ce9 2007-07-21       drh:        "%*s  generated by 'makeheaders'.\n",
dbda8d6ce9 2007-07-21       drh:        pFile->zHdr, strlen(pFile->zHdr), "");
dbda8d6ce9 2007-07-21       drh:     nErr++;
dbda8d6ce9 2007-07-21       drh:   }else if( strcmp(zOldVersion,zNewVersion)!=0 ){
dbda8d6ce9 2007-07-21       drh:     if( report ) fprintf(report,"updated\n");
dbda8d6ce9 2007-07-21       drh:     if( WriteFile(pFile->zHdr,zNewVersion) ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
dbda8d6ce9 2007-07-21       drh:       nErr++;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }else if( report ){
dbda8d6ce9 2007-07-21       drh:     fprintf(report,"unchanged\n");
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   SafeFree(zOldVersion);
dbda8d6ce9 2007-07-21       drh:   IdentTableReset(&includeTable);
dbda8d6ce9 2007-07-21       drh:   StringReset(&outStr);
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Generate a global header file -- a header file that contains all
dbda8d6ce9 2007-07-21       drh: ** declarations.  If the forExport flag is true, then only those
dbda8d6ce9 2007-07-21       drh: ** objects that are exported are included in the header file.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int MakeGlobalHeader(int forExport){
dbda8d6ce9 2007-07-21       drh:   GenState sState;
dbda8d6ce9 2007-07-21       drh:   String outStr;
dbda8d6ce9 2007-07-21       drh:   IdentTable includeTable;
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   sState.pStr = &outStr;
dbda8d6ce9 2007-07-21       drh:   StringInit(&outStr);
dbda8d6ce9 2007-07-21       drh:   /* StringAppend(&outStr,zTopLine,nTopLine); */
dbda8d6ce9 2007-07-21       drh:   sState.pTable = &includeTable;
dbda8d6ce9 2007-07-21       drh:   memset(&includeTable,0,sizeof(includeTable));
dbda8d6ce9 2007-07-21       drh:   sState.zIf = 0;
dbda8d6ce9 2007-07-21       drh:   sState.nErr = 0;
dbda8d6ce9 2007-07-21       drh:   sState.zFilename = "(all)";
dbda8d6ce9 2007-07-21       drh:   sState.flags = 0;
dbda8d6ce9 2007-07-21       drh:   ResetDeclFlags(0);
dbda8d6ce9 2007-07-21       drh:   for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
dbda8d6ce9 2007-07-21       drh:     if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){
dbda8d6ce9 2007-07-21       drh:       DeclareObject(pDecl,&sState,1);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   ChangeIfContext(0,&sState);
dbda8d6ce9 2007-07-21       drh:   printf("%s",StringGet(&outStr));
dbda8d6ce9 2007-07-21       drh:   IdentTableReset(&includeTable);
dbda8d6ce9 2007-07-21       drh:   StringReset(&outStr);
dbda8d6ce9 2007-07-21       drh:   return 0;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return the number of characters in the given string prior to the
dbda8d6ce9 2007-07-21       drh: ** first newline.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static int ClipTrailingNewline(char *z){
dbda8d6ce9 2007-07-21       drh:   int n = strlen(z);
dbda8d6ce9 2007-07-21       drh:   while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ){ n--; }
dbda8d6ce9 2007-07-21       drh:   return n;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Dump the entire declaration list for debugging purposes
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void DumpDeclList(void){
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){
dbda8d6ce9 2007-07-21       drh:     printf("**** %s from file %s ****\n",pDecl->zName,pDecl->zFile);
dbda8d6ce9 2007-07-21       drh:     if( pDecl->zIf ){
dbda8d6ce9 2007-07-21       drh:       printf("If: [%.*s]\n",ClipTrailingNewline(pDecl->zIf),pDecl->zIf);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->zFwd ){
dbda8d6ce9 2007-07-21       drh:       printf("Decl: [%.*s]\n",ClipTrailingNewline(pDecl->zFwd),pDecl->zFwd);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->zDecl ){
dbda8d6ce9 2007-07-21       drh:       InsertExtraDecl(pDecl);
dbda8d6ce9 2007-07-21       drh:       printf("Def: [%.*s]\n",ClipTrailingNewline(pDecl->zDecl),pDecl->zDecl);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->flags ){
dbda8d6ce9 2007-07-21       drh:       static struct {
dbda8d6ce9 2007-07-21       drh:         int mask;
dbda8d6ce9 2007-07-21       drh:         char *desc;
dbda8d6ce9 2007-07-21       drh:       } flagSet[] = {
dbda8d6ce9 2007-07-21       drh:         { TY_Class,       "class" },
dbda8d6ce9 2007-07-21       drh:         { TY_Enumeration, "enum" },
dbda8d6ce9 2007-07-21       drh:         { TY_Structure,   "struct" },
dbda8d6ce9 2007-07-21       drh:         { TY_Union,       "union" },
dbda8d6ce9 2007-07-21       drh:         { TY_Variable,    "variable" },
dbda8d6ce9 2007-07-21       drh:         { TY_Subroutine,  "function" },
dbda8d6ce9 2007-07-21       drh:         { TY_Typedef,     "typedef" },
dbda8d6ce9 2007-07-21       drh:         { TY_Macro,       "macro" },
dbda8d6ce9 2007-07-21       drh:         { DP_Export,      "export" },
dbda8d6ce9 2007-07-21       drh:         { DP_Local,       "local" },
dbda8d6ce9 2007-07-21       drh:         { DP_Cplusplus,   "C++" },
dbda8d6ce9 2007-07-21       drh:       };
dbda8d6ce9 2007-07-21       drh:       int i;
dbda8d6ce9 2007-07-21       drh:       printf("flags:");
dbda8d6ce9 2007-07-21       drh:       for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){
dbda8d6ce9 2007-07-21       drh:         if( flagSet[i].mask & pDecl->flags ){
dbda8d6ce9 2007-07-21       drh:           printf(" %s", flagSet[i].desc);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       printf("\n");
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->pInclude ){
dbda8d6ce9 2007-07-21       drh:       Include *p;
dbda8d6ce9 2007-07-21       drh:       printf("includes:");
dbda8d6ce9 2007-07-21       drh:       for(p=pDecl->pInclude; p; p=p->pNext){
dbda8d6ce9 2007-07-21       drh:         printf(" %s",p->zFile);
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       printf("\n");
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** When the "-doc" command-line option is used, this routine is called
dbda8d6ce9 2007-07-21       drh: ** to print all of the database information to standard output.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void DocumentationDump(void){
dbda8d6ce9 2007-07-21       drh:   Decl *pDecl;
dbda8d6ce9 2007-07-21       drh:   static struct {
dbda8d6ce9 2007-07-21       drh:     int mask;
dbda8d6ce9 2007-07-21       drh:     char flag;
dbda8d6ce9 2007-07-21       drh:   } flagSet[] = {
dbda8d6ce9 2007-07-21       drh:     { TY_Class,       'c' },
dbda8d6ce9 2007-07-21       drh:     { TY_Enumeration, 'e' },
dbda8d6ce9 2007-07-21       drh:     { TY_Structure,   's' },
dbda8d6ce9 2007-07-21       drh:     { TY_Union,       'u' },
dbda8d6ce9 2007-07-21       drh:     { TY_Variable,    'v' },
dbda8d6ce9 2007-07-21       drh:     { TY_Subroutine,  'f' },
dbda8d6ce9 2007-07-21       drh:     { TY_Typedef,     't' },
dbda8d6ce9 2007-07-21       drh:     { TY_Macro,       'm' },
dbda8d6ce9 2007-07-21       drh:     { DP_Export,      'x' },
dbda8d6ce9 2007-07-21       drh:     { DP_Local,       'l' },
dbda8d6ce9 2007-07-21       drh:     { DP_Cplusplus,   '+' },
dbda8d6ce9 2007-07-21       drh:   };
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){
dbda8d6ce9 2007-07-21       drh:     int i;
dbda8d6ce9 2007-07-21       drh:     int nLabel = 0;
dbda8d6ce9 2007-07-21       drh:     char *zDecl;
dbda8d6ce9 2007-07-21       drh:     char zLabel[50];
dbda8d6ce9 2007-07-21       drh:     for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){
dbda8d6ce9 2007-07-21       drh:       if( DeclHasProperty(pDecl,flagSet[i].mask) ){
dbda8d6ce9 2007-07-21       drh:         zLabel[nLabel++] = flagSet[i].flag;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( nLabel==0 ) continue;
dbda8d6ce9 2007-07-21       drh:     zLabel[nLabel] = 0;
dbda8d6ce9 2007-07-21       drh:     InsertExtraDecl(pDecl);
dbda8d6ce9 2007-07-21       drh:     zDecl = pDecl->zDecl;
dbda8d6ce9 2007-07-21       drh:     if( zDecl==0 ) zDecl = pDecl->zFwd;
dbda8d6ce9 2007-07-21       drh:     printf("%s %s %s %d %d %d %d %d %d\n",
dbda8d6ce9 2007-07-21       drh:        pDecl->zName,
dbda8d6ce9 2007-07-21       drh:        zLabel,
dbda8d6ce9 2007-07-21       drh:        pDecl->zFile,
dbda8d6ce9 2007-07-21       drh:        pDecl->pComment ? (int)pDecl->pComment/sizeof(Token) : 0,
dbda8d6ce9 2007-07-21       drh:        pDecl->pComment ? pDecl->pComment->nText+1 : 0,
dbda8d6ce9 2007-07-21       drh:        pDecl->zIf ? strlen(pDecl->zIf)+1 : 0,
dbda8d6ce9 2007-07-21       drh:        zDecl ? strlen(zDecl) : 0,
dbda8d6ce9 2007-07-21       drh:        pDecl->pComment ? pDecl->pComment->nLine : 0,
dbda8d6ce9 2007-07-21       drh:        pDecl->tokenCode.nText ? pDecl->tokenCode.nText+1 : 0
dbda8d6ce9 2007-07-21       drh:     );
dbda8d6ce9 2007-07-21       drh:     if( pDecl->pComment ){
dbda8d6ce9 2007-07-21       drh:       printf("%.*s\n",pDecl->pComment->nText, pDecl->pComment->zText);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->zIf ){
dbda8d6ce9 2007-07-21       drh:       printf("%s\n",pDecl->zIf);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( zDecl ){
dbda8d6ce9 2007-07-21       drh:       printf("%s",zDecl);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( pDecl->tokenCode.nText ){
dbda8d6ce9 2007-07-21       drh:       printf("%.*s\n",pDecl->tokenCode.nText, pDecl->tokenCode.zText);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Given the complete text of an input file, this routine prints a
dbda8d6ce9 2007-07-21       drh: ** documentation record for the header comment at the beginning of the
dbda8d6ce9 2007-07-21       drh: ** file (if the file has a header comment.)
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: void PrintModuleRecord(const char *zFile, const char *zFilename){
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh:   static int addr = 5;
dbda8d6ce9 2007-07-21       drh:   while( isspace(*zFile) ){ zFile++; }
dbda8d6ce9 2007-07-21       drh:   if( *zFile!='/' || zFile[1]!='*' ) return;
dbda8d6ce9 2007-07-21       drh:   for(i=2; zFile[i] && (zFile[i-1]!='/' || zFile[i-2]!='*'); i++){}
dbda8d6ce9 2007-07-21       drh:   if( zFile[i]==0 ) return;
dbda8d6ce9 2007-07-21       drh:   printf("%s M %s %d %d 0 0 0 0\n%.*s\n",
dbda8d6ce9 2007-07-21       drh:     zFilename, zFilename, addr, i+1, i, zFile);
dbda8d6ce9 2007-07-21       drh:   addr += 4;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Given an input argument to the program, construct a new InFile
dbda8d6ce9 2007-07-21       drh: ** object.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static InFile *CreateInFile(char *zArg, int *pnErr){
dbda8d6ce9 2007-07-21       drh:   int nSrc;
dbda8d6ce9 2007-07-21       drh:   char *zSrc;
dbda8d6ce9 2007-07-21       drh:   InFile *pFile;
dbda8d6ce9 2007-07-21       drh:   int i;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** Get the name of the input file to be scanned
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   zSrc = zArg;
dbda8d6ce9 2007-07-21       drh:   for(nSrc=0; zSrc[nSrc] && zArg[nSrc]!=':'; nSrc++){}
dbda8d6ce9 2007-07-21       drh:   pFile = SafeMalloc( sizeof(InFile) );
dbda8d6ce9 2007-07-21       drh:   memset(pFile,0,sizeof(InFile));
dbda8d6ce9 2007-07-21       drh:   pFile->zSrc = StrDup(zSrc,nSrc);
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Figure out if we are dealing with C or C++ code.  Assume any
dbda8d6ce9 2007-07-21       drh:   ** file with ".c" or ".h" is C code and all else is C++.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( nSrc>2 && zSrc[nSrc-2]=='.' && (zSrc[nSrc-1]=='c' || zSrc[nSrc-1]=='h')){
dbda8d6ce9 2007-07-21       drh:     pFile->flags &= ~DP_Cplusplus;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     pFile->flags |= DP_Cplusplus;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** If a separate header file is specified, use it
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   if( zSrc[nSrc]==':' ){
dbda8d6ce9 2007-07-21       drh:     int nHdr;
dbda8d6ce9 2007-07-21       drh:     char *zHdr;
dbda8d6ce9 2007-07-21       drh:     zHdr = &zSrc[nSrc+1];
dbda8d6ce9 2007-07-21       drh:     for(nHdr=0; zHdr[nHdr] && zHdr[nHdr]!=':'; nHdr++){}
dbda8d6ce9 2007-07-21       drh:     pFile->zHdr = StrDup(zHdr,nHdr);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Look for any 'c' or 'C' in the suffix of the file name and change
dbda8d6ce9 2007-07-21       drh:   ** that character to 'h' or 'H' respectively.  If no 'c' or 'C' is found,
dbda8d6ce9 2007-07-21       drh:   ** then assume we are dealing with a header.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   else{
dbda8d6ce9 2007-07-21       drh:     int foundC = 0;
dbda8d6ce9 2007-07-21       drh:     pFile->zHdr = StrDup(zSrc,nSrc);
dbda8d6ce9 2007-07-21       drh:     for(i = nSrc-1; i>0 && pFile->zHdr[i]!='.'; i--){
dbda8d6ce9 2007-07-21       drh:       if( pFile->zHdr[i]=='c' ){
dbda8d6ce9 2007-07-21       drh:         foundC = 1;
dbda8d6ce9 2007-07-21       drh:         pFile->zHdr[i] = 'h';
dbda8d6ce9 2007-07-21       drh:       }else if( pFile->zHdr[i]=='C' ){
dbda8d6ce9 2007-07-21       drh:         foundC = 1;
dbda8d6ce9 2007-07-21       drh:         pFile->zHdr[i] = 'H';
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( !foundC ){
dbda8d6ce9 2007-07-21       drh:       SafeFree(pFile->zHdr);
dbda8d6ce9 2007-07-21       drh:       pFile->zHdr = 0;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /*
dbda8d6ce9 2007-07-21       drh:   ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
dbda8d6ce9 2007-07-21       drh:   ** must be a header file.   In that case, we need to set the
dbda8d6ce9 2007-07-21       drh:   ** PS_Interface flag.
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   pFile->flags |= PS_Interface;
dbda8d6ce9 2007-07-21       drh:   for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
dbda8d6ce9 2007-07-21       drh:     if( zSrc[i]=='c' || zSrc[i]=='C' ){
dbda8d6ce9 2007-07-21       drh:       pFile->flags &= ~PS_Interface;
dbda8d6ce9 2007-07-21       drh:       break;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   /* Done!
dbda8d6ce9 2007-07-21       drh:   */
dbda8d6ce9 2007-07-21       drh:   return pFile;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /* MS-Windows and MS-DOS both have the following serious OS bug:  the
dbda8d6ce9 2007-07-21       drh: ** length of a command line is severely restricted.  But this program
dbda8d6ce9 2007-07-21       drh: ** occasionally requires long command lines.  Hence the following
dbda8d6ce9 2007-07-21       drh: ** work around.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** If the parameters "-f FILENAME" appear anywhere on the command line,
dbda8d6ce9 2007-07-21       drh: ** then the named file is scanned for additional command line arguments.
dbda8d6ce9 2007-07-21       drh: ** These arguments are substituted in place of the "FILENAME" argument
dbda8d6ce9 2007-07-21       drh: ** in the original argument list.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** This first parameter to this routine is the index of the "-f"
dbda8d6ce9 2007-07-21       drh: ** parameter in the argv[] array.  The argc and argv are passed by
dbda8d6ce9 2007-07-21       drh: ** pointer so that they can be changed.
dbda8d6ce9 2007-07-21       drh: **
dbda8d6ce9 2007-07-21       drh: ** Parsing of the parameters in the file is very simple.  Parameters
dbda8d6ce9 2007-07-21       drh: ** can be separated by any amount of white-space (including newlines
dbda8d6ce9 2007-07-21       drh: ** and carriage returns.)  There are now quoting characters of any
dbda8d6ce9 2007-07-21       drh: ** kind.  The length of a token is limited to about 1000 characters.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void AddParameters(int index, int *pArgc, char ***pArgv){
dbda8d6ce9 2007-07-21       drh:   int argc = *pArgc;      /* The original argc value */
dbda8d6ce9 2007-07-21       drh:   char **argv = *pArgv;   /* The original argv value */
dbda8d6ce9 2007-07-21       drh:   int newArgc;            /* Value for argc after inserting new arguments */
dbda8d6ce9 2007-07-21       drh:   char **zNew = 0;        /* The new argv after this routine is done */
dbda8d6ce9 2007-07-21       drh:   char *zFile;            /* Name of the input file */
dbda8d6ce9 2007-07-21       drh:   int nNew = 0;           /* Number of new entries in the argv[] file */
dbda8d6ce9 2007-07-21       drh:   int nAlloc = 0;         /* Space allocated for zNew[] */
dbda8d6ce9 2007-07-21       drh:   int i;                  /* Loop counter */
dbda8d6ce9 2007-07-21       drh:   int n;                  /* Number of characters in a new argument */
dbda8d6ce9 2007-07-21       drh:   int c;                  /* Next character of input */
dbda8d6ce9 2007-07-21       drh:   int startOfLine = 1;    /* True if we are where '#' can start a comment */
dbda8d6ce9 2007-07-21       drh:   FILE *in;               /* The input file */
dbda8d6ce9 2007-07-21       drh:   char zBuf[1000];        /* A single argument is accumulated here */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   if( index+1==argc ) return;
dbda8d6ce9 2007-07-21       drh:   zFile = argv[index+1];
dbda8d6ce9 2007-07-21       drh:   in = fopen(zFile,"r");
dbda8d6ce9 2007-07-21       drh:   if( in==0 ){
dbda8d6ce9 2007-07-21       drh:     fprintf(stderr,"Can't open input file \"%s\"\n",zFile);
dbda8d6ce9 2007-07-21       drh:     exit(1);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   c = ' ';
dbda8d6ce9 2007-07-21       drh:   while( c!=EOF ){
dbda8d6ce9 2007-07-21       drh:     while( c!=EOF && isspace(c) ){
dbda8d6ce9 2007-07-21       drh:       if( c=='\n' ){
dbda8d6ce9 2007-07-21       drh:         startOfLine = 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       c = getc(in);
dbda8d6ce9 2007-07-21       drh:       if( startOfLine && c=='#' ){
dbda8d6ce9 2007-07-21       drh:         while( c!=EOF && c!='\n' ){
dbda8d6ce9 2007-07-21       drh:           c = getc(in);
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     n = 0;
dbda8d6ce9 2007-07-21       drh:     while( c!=EOF && !isspace(c) ){
dbda8d6ce9 2007-07-21       drh:       if( n<sizeof(zBuf)-1 ){ zBuf[n++] = c; }
dbda8d6ce9 2007-07-21       drh:       startOfLine = 0;
dbda8d6ce9 2007-07-21       drh:       c = getc(in);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     zBuf[n] = 0;
dbda8d6ce9 2007-07-21       drh:     if( n>0 ){
dbda8d6ce9 2007-07-21       drh:       nNew++;
dbda8d6ce9 2007-07-21       drh:       if( nNew + argc > nAlloc ){
dbda8d6ce9 2007-07-21       drh:         if( nAlloc==0 ){
dbda8d6ce9 2007-07-21       drh:           nAlloc = 100 + argc;
dbda8d6ce9 2007-07-21       drh:           zNew = malloc( sizeof(char*) * nAlloc );
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           nAlloc *= 2;
dbda8d6ce9 2007-07-21       drh:           zNew = realloc( zNew, sizeof(char*) * nAlloc );
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:       if( zNew ){
dbda8d6ce9 2007-07-21       drh:         int j = nNew + index;
dbda8d6ce9 2007-07-21       drh:         zNew[j] = malloc( n + 1 );
dbda8d6ce9 2007-07-21       drh:         if( zNew[j] ){
dbda8d6ce9 2007-07-21       drh:           strcpy( zNew[j], zBuf );
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   newArgc = argc + nNew - 1;
dbda8d6ce9 2007-07-21       drh:   for(i=0; i<=index; i++){
dbda8d6ce9 2007-07-21       drh:     zNew[i] = argv[i];
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   for(i=nNew + index + 1; i<newArgc; i++){
dbda8d6ce9 2007-07-21       drh:     zNew[i] = argv[i + 1 - nNew];
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zNew[newArgc] = 0;
dbda8d6ce9 2007-07-21       drh:   *pArgc = newArgc;
dbda8d6ce9 2007-07-21       drh:   *pArgv = zNew;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #ifdef NOT_USED
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Return the time that the given file was last modified.  If we can't
dbda8d6ce9 2007-07-21       drh: ** locate the file (because, for example, it doesn't exist), then
dbda8d6ce9 2007-07-21       drh: ** return 0.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static unsigned int ModTime(const char *zFilename){
dbda8d6ce9 2007-07-21       drh:   unsigned int mTime = 0;
dbda8d6ce9 2007-07-21       drh:   struct stat sStat;
dbda8d6ce9 2007-07-21       drh:   if( stat(zFilename,&sStat)==0 ){
dbda8d6ce9 2007-07-21       drh:     mTime = sStat.st_mtime;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return mTime;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** Print a usage comment for this program.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static void Usage(const char *argv0, const char *argvN){
dbda8d6ce9 2007-07-21       drh:   fprintf(stderr,"%s: Illegal argument \"%s\"\n",argv0,argvN);
dbda8d6ce9 2007-07-21       drh:   fprintf(stderr,"Usage: %s [options] filename...\n"
dbda8d6ce9 2007-07-21       drh:     "Options:\n"
dbda8d6ce9 2007-07-21       drh:     "  -h          Generate a single .h to standard output.\n"
dbda8d6ce9 2007-07-21       drh:     "  -H          Like -h, but only output EXPORT declarations.\n"
dbda8d6ce9 2007-07-21       drh:     "  -v          (verbose) Write status information to the screen.\n"
dbda8d6ce9 2007-07-21       drh:     "  -doc        Generate no header files.  Instead, output information\n"
dbda8d6ce9 2007-07-21       drh:     "              that can be used by an automatic program documentation\n"
dbda8d6ce9 2007-07-21       drh:     "              and cross-reference generator.\n"
dbda8d6ce9 2007-07-21       drh:     "  -local      Generate prototypes for \"static\" functions and\n"
dbda8d6ce9 2007-07-21       drh:     "              procedures.\n"
dbda8d6ce9 2007-07-21       drh:     "  -f FILE     Read additional command-line arguments from the file named\n"
dbda8d6ce9 2007-07-21       drh:     "              \"FILE\".\n"
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:     "  -! MASK     Set the debugging mask to the number \"MASK\".\n"
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:     "  --          Treat all subsequent comment-line parameters as filenames,\n"
dbda8d6ce9 2007-07-21       drh:     "              even if they begin with \"-\".\n",
dbda8d6ce9 2007-07-21       drh:     argv0
dbda8d6ce9 2007-07-21       drh:   );
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: /*
dbda8d6ce9 2007-07-21       drh: ** The following text contains a few simple #defines that we want
dbda8d6ce9 2007-07-21       drh: ** to be available to every file.
dbda8d6ce9 2007-07-21       drh: */
dbda8d6ce9 2007-07-21       drh: static char zInit[] =
dbda8d6ce9 2007-07-21       drh:   "#define INTERFACE 0\n"
dbda8d6ce9 2007-07-21       drh:   "#define EXPORT_INTERFACE 0\n"
dbda8d6ce9 2007-07-21       drh:   "#define LOCAL_INTERFACE 0\n"
dbda8d6ce9 2007-07-21       drh:   "#define EXPORT\n"
dbda8d6ce9 2007-07-21       drh:   "#define LOCAL static\n"
dbda8d6ce9 2007-07-21       drh:   "#define PUBLIC\n"
dbda8d6ce9 2007-07-21       drh:   "#define PRIVATE\n"
dbda8d6ce9 2007-07-21       drh:   "#define PROTECTED\n"
dbda8d6ce9 2007-07-21       drh: ;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh: #if TEST==0
dbda8d6ce9 2007-07-21       drh: int main(int argc, char **argv){
dbda8d6ce9 2007-07-21       drh:   int i;                /* Loop counter */
dbda8d6ce9 2007-07-21       drh:   int nErr = 0;         /* Number of errors encountered */
dbda8d6ce9 2007-07-21       drh:   Token *pList;         /* List of input tokens for one file */
dbda8d6ce9 2007-07-21       drh:   InFile *pFileList = 0;/* List of all input files */
dbda8d6ce9 2007-07-21       drh:   InFile *pTail = 0;    /* Last file on the list */
dbda8d6ce9 2007-07-21       drh:   InFile *pFile;        /* for looping over the file list */
dbda8d6ce9 2007-07-21       drh:   int h_flag = 0;       /* True if -h is present.  Output unified header */
dbda8d6ce9 2007-07-21       drh:   int H_flag = 0;       /* True if -H is present.  Output EXPORT header */
dbda8d6ce9 2007-07-21       drh:   int v_flag = 0;       /* Verbose */
dbda8d6ce9 2007-07-21       drh:   int noMoreFlags;      /* True if -- has been seen. */
dbda8d6ce9 2007-07-21       drh:   FILE *report;         /* Send progress reports to this, if not NULL */
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:   noMoreFlags = 0;
dbda8d6ce9 2007-07-21       drh:   for(i=1; i<argc; i++){
dbda8d6ce9 2007-07-21       drh:     if( argv[i][0]=='-' && !noMoreFlags ){
dbda8d6ce9 2007-07-21       drh:       switch( argv[i][1] ){
dbda8d6ce9 2007-07-21       drh:         case 'h':   h_flag = 1;   break;
dbda8d6ce9 2007-07-21       drh:         case 'H':   H_flag = 1;   break;
dbda8d6ce9 2007-07-21       drh:         case 'v':   v_flag = 1;   break;
dbda8d6ce9 2007-07-21       drh:         case 'd':   doc_flag = 1; proto_static = 1; break;
dbda8d6ce9 2007-07-21       drh:         case 'l':   proto_static = 1; break;
dbda8d6ce9 2007-07-21       drh:         case 'f':   AddParameters(i, &argc, &argv); break;
dbda8d6ce9 2007-07-21       drh:         case '-':   noMoreFlags = 1;   break;
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:         case '!':   i++;  debugMask = strtol(argv[i],0,0); break;
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:         default:    Usage(argv[0],argv[i]); return 1;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       pFile = CreateInFile(argv[i],&nErr);
dbda8d6ce9 2007-07-21       drh:       if( pFile ){
dbda8d6ce9 2007-07-21       drh:         if( pFileList ){
dbda8d6ce9 2007-07-21       drh:           pTail->pNext = pFile;
dbda8d6ce9 2007-07-21       drh:           pTail = pFile;
dbda8d6ce9 2007-07-21       drh:         }else{
dbda8d6ce9 2007-07-21       drh:           pFileList = pTail = pFile;
dbda8d6ce9 2007-07-21       drh:         }
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( h_flag && H_flag ){
dbda8d6ce9 2007-07-21       drh:     h_flag = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( v_flag ){
dbda8d6ce9 2007-07-21       drh:     report = (h_flag || H_flag) ? stderr : stdout;
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     report = 0;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( nErr>0 ){
dbda8d6ce9 2007-07-21       drh:     return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   for(pFile=pFileList; pFile; pFile=pFile->pNext){
dbda8d6ce9 2007-07-21       drh:     char *zFile;
dbda8d6ce9 2007-07-21       drh: 
dbda8d6ce9 2007-07-21       drh:     zFilename = pFile->zSrc;
dbda8d6ce9 2007-07-21       drh:     if( zFilename==0 ) continue;
dbda8d6ce9 2007-07-21       drh:     zFile = ReadFile(zFilename);
dbda8d6ce9 2007-07-21       drh:     if( zFile==0 ){
dbda8d6ce9 2007-07-21       drh:       fprintf(stderr,"Can't read input file \"%s\"\n",zFilename);
dbda8d6ce9 2007-07-21       drh:       nErr++;
dbda8d6ce9 2007-07-21       drh:       continue;
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( strncmp(zFile,zTopLine,nTopLine)==0 ){
dbda8d6ce9 2007-07-21       drh:       pFile->zSrc = 0;
dbda8d6ce9 2007-07-21       drh:     }else{
dbda8d6ce9 2007-07-21       drh:       if( report ) fprintf(report,"Reading %s...\n",zFilename);
dbda8d6ce9 2007-07-21       drh:       pList = TokenizeFile(zFile,&pFile->idTable);
dbda8d6ce9 2007-07-21       drh:       if( pList ){
dbda8d6ce9 2007-07-21       drh:         nErr += ParseFile(pList,pFile->flags);
dbda8d6ce9 2007-07-21       drh:         FreeTokenList(pList);
dbda8d6ce9 2007-07-21       drh:       }else if( zFile[0]==0 ){
dbda8d6ce9 2007-07-21       drh:         fprintf(stderr,"Input file \"%s\" is empty.\n", zFilename);
dbda8d6ce9 2007-07-21       drh:         nErr++;
dbda8d6ce9 2007-07-21       drh:       }else{
dbda8d6ce9 2007-07-21       drh:         fprintf(stderr,"Errors while processing \"%s\"\n", zFilename);
dbda8d6ce9 2007-07-21       drh:         nErr++;
dbda8d6ce9 2007-07-21       drh:       }
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:     if( !doc_flag ) SafeFree(zFile);
dbda8d6ce9 2007-07-21       drh:     if( doc_flag ) PrintModuleRecord(zFile,zFilename);
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   if( nErr>0 ){
dbda8d6ce9 2007-07-21       drh:     return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #ifdef DEBUG
dbda8d6ce9 2007-07-21       drh:   if( debugMask & DECL_DUMP ){
dbda8d6ce9 2007-07-21       drh:     DumpDeclList();
dbda8d6ce9 2007-07-21       drh:     return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh: #endif
dbda8d6ce9 2007-07-21       drh:   if( doc_flag ){
dbda8d6ce9 2007-07-21       drh:     DocumentationDump();
dbda8d6ce9 2007-07-21       drh:     return nErr;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   zFilename = "--internal--";
dbda8d6ce9 2007-07-21       drh:   pList = TokenizeFile(zInit,0);
dbda8d6ce9 2007-07-21       drh:   if( pList==0 ){
dbda8d6ce9 2007-07-21       drh:     return nErr+1;
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   ParseFile(pList,PS_Interface);
dbda8d6ce9 2007-07-21       drh:   FreeTokenList(pList);
dbda8d6ce9 2007-07-21       drh:   if( h_flag || H_flag ){
dbda8d6ce9 2007-07-21       drh:     nErr += MakeGlobalHeader(H_flag);
dbda8d6ce9 2007-07-21       drh:   }else{
dbda8d6ce9 2007-07-21       drh:     for(pFile=pFileList; pFile; pFile=pFile->pNext){
dbda8d6ce9 2007-07-21       drh:       if( pFile->zSrc==0 ) continue;
dbda8d6ce9 2007-07-21       drh:       nErr += MakeHeader(pFile,report,0);
dbda8d6ce9 2007-07-21       drh:     }
dbda8d6ce9 2007-07-21       drh:   }
dbda8d6ce9 2007-07-21       drh:   return nErr;
dbda8d6ce9 2007-07-21       drh: }
dbda8d6ce9 2007-07-21       drh: #endif