Fossil SCM

fossil-scm / tools / makeheaders.c
Source Blame History 3441 lines
b62f651… stephan 1 /*
b62f651… stephan 2 ** This program is free software; you can redistribute it and/or
b62f651… stephan 3 ** modify it under the terms of the Simplified BSD License (also
b62f651… stephan 4 ** known as the "2-Clause License" or "FreeBSD License".)
b62f651… stephan 5 **
b62f651… stephan 6 ** Copyright 1993 D. Richard Hipp. All rights reserved.
b62f651… stephan 7 **
b62f651… stephan 8 ** Redistribution and use in source and binary forms, with or
b62f651… stephan 9 ** without modification, are permitted provided that the following
b62f651… stephan 10 ** conditions are met:
b62f651… stephan 11 **
b62f651… stephan 12 ** 1. Redistributions of source code must retain the above copyright
b62f651… stephan 13 ** notice, this list of conditions and the following disclaimer.
b62f651… stephan 14 **
b62f651… stephan 15 ** 2. Redistributions in binary form must reproduce the above copyright
b62f651… stephan 16 ** notice, this list of conditions and the following disclaimer in
b62f651… stephan 17 ** the documentation and/or other materials provided with the
b62f651… stephan 18 ** distribution.
b62f651… stephan 19 **
b62f651… stephan 20 ** This software is provided "as is" and any express or implied warranties,
b62f651… stephan 21 ** including, but not limited to, the implied warranties of merchantability
b62f651… stephan 22 ** and fitness for a particular purpose are disclaimed. In no event shall
b62f651… stephan 23 ** the author or contributors be liable for any direct, indirect, incidental,
b62f651… stephan 24 ** special, exemplary, or consequential damages (including, but not limited
b62f651… stephan 25 ** to, procurement of substitute goods or services; loss of use, data or
b62f651… stephan 26 ** profits; or business interruption) however caused and on any theory of
b62f651… stephan 27 ** liability, whether in contract, strict liability, or tort (including
b62f651… stephan 28 ** negligence or otherwise) arising in any way out of the use of this
b62f651… stephan 29 ** software, even if advised of the possibility of such damage.
b62f651… stephan 30 **
b62f651… stephan 31 ** This program is distributed in the hope that it will be useful,
b62f651… stephan 32 ** but without any warranty; without even the implied warranty of
b62f651… stephan 33 ** merchantability or fitness for a particular purpose.
b62f651… stephan 34 */
b62f651… stephan 35 #include <stdio.h>
b62f651… stephan 36 #include <stdlib.h>
b62f651… stephan 37 #include <ctype.h>
b62f651… stephan 38 #include <memory.h>
b62f651… stephan 39 #include <sys/stat.h>
b62f651… stephan 40 #include <assert.h>
b62f651… stephan 41 #include <string.h>
b62f651… stephan 42
275da70… danield 43 #if defined( __MINGW32__) || defined(__DMC__) || \
275da70… danield 44 defined(_MSC_VER) || defined(__POCC__)
b62f651… stephan 45 # ifndef WIN32
b62f651… stephan 46 # define WIN32
b62f651… stephan 47 # endif
b62f651… stephan 48 #else
b62f651… stephan 49 # include <unistd.h>
b62f651… stephan 50 #endif
b62f651… stephan 51
b62f651… stephan 52 /*
b62f651… stephan 53 ** Macros for debugging.
b62f651… stephan 54 */
b62f651… stephan 55 #ifdef DEBUG
b62f651… stephan 56 static int debugMask = 0;
b62f651… stephan 57 # define debug0(F,M) if( (F)&debugMask ){ fprintf(stderr,M); }
b62f651… stephan 58 # define debug1(F,M,A) if( (F)&debugMask ){ fprintf(stderr,M,A); }
b62f651… stephan 59 # define debug2(F,M,A,B) if( (F)&debugMask ){ fprintf(stderr,M,A,B); }
b62f651… stephan 60 # define debug3(F,M,A,B,C) if( (F)&debugMask ){ fprintf(stderr,M,A,B,C); }
b62f651… stephan 61 # define PARSER 0x00000001
b62f651… stephan 62 # define DECL_DUMP 0x00000002
b62f651… stephan 63 # define TOKENIZER 0x00000004
b62f651… stephan 64 #else
b62f651… stephan 65 # define debug0(Flags, Format)
b62f651… stephan 66 # define debug1(Flags, Format, A)
b62f651… stephan 67 # define debug2(Flags, Format, A, B)
b62f651… stephan 68 # define debug3(Flags, Format, A, B, C)
b62f651… stephan 69 #endif
b62f651… stephan 70
b62f651… stephan 71 /*
b62f651… stephan 72 ** The following macros are purely for the purpose of testing this
b62f651… stephan 73 ** program on itself. They don't really contribute to the code.
b62f651… stephan 74 */
b62f651… stephan 75 #define INTERFACE 1
b62f651… stephan 76 #define EXPORT_INTERFACE 1
b62f651… stephan 77 #define EXPORT
b62f651… stephan 78
b62f651… stephan 79 /*
b62f651… stephan 80 ** Each token in a source file is represented by an instance of
b62f651… stephan 81 ** the following structure. Tokens are collected onto a list.
b62f651… stephan 82 */
b62f651… stephan 83 typedef struct Token Token;
b62f651… stephan 84 struct Token {
b62f651… stephan 85 const char *zText; /* The text of the token */
b62f651… stephan 86 int nText; /* Number of characters in the token's text */
b62f651… stephan 87 int eType; /* The type of this token */
b62f651… stephan 88 int nLine; /* The line number on which the token starts */
b62f651… stephan 89 Token *pComment; /* Most recent block comment before this token */
b62f651… stephan 90 Token *pNext; /* Next token on the list */
b62f651… stephan 91 Token *pPrev; /* Previous token on the list */
b62f651… stephan 92 };
b62f651… stephan 93
b62f651… stephan 94 /*
b62f651… stephan 95 ** During tokenization, information about the state of the input
b62f651… stephan 96 ** stream is held in an instance of the following structure
b62f651… stephan 97 */
b62f651… stephan 98 typedef struct InStream InStream;
b62f651… stephan 99 struct InStream {
b62f651… stephan 100 const char *z; /* Complete text of the input */
b62f651… stephan 101 int i; /* Next character to read from the input */
b62f651… stephan 102 int nLine; /* The line number for character z[i] */
b62f651… stephan 103 };
b62f651… stephan 104
b62f651… stephan 105 /*
b62f651… stephan 106 ** Each declaration in the C or C++ source files is parsed out and stored as
b62f651… stephan 107 ** an instance of the following structure.
b62f651… stephan 108 **
b62f651… stephan 109 ** A "forward declaration" is a declaration that an object exists that
b62f651… stephan 110 ** doesn't tell about the objects structure. A typical forward declaration
b62f651… stephan 111 ** is:
b62f651… stephan 112 **
b62f651… stephan 113 ** struct Xyzzy;
b62f651… stephan 114 **
b62f651… stephan 115 ** Not every object has a forward declaration. If it does, thought, the
b62f651… stephan 116 ** forward declaration will be contained in the zFwd field for C and
b62f651… stephan 117 ** the zFwdCpp for C++. The zDecl field contains the complete
b62f651… stephan 118 ** declaration text.
b62f651… stephan 119 */
b62f651… stephan 120 typedef struct Decl Decl;
b62f651… stephan 121 struct Decl {
b62f651… stephan 122 char *zName; /* Name of the object being declared. The appearance
b62f651… stephan 123 ** of this name is a source file triggers the declaration
b62f651… stephan 124 ** to be added to the header for that file. */
b62f651… stephan 125 const char *zFile; /* File from which extracted. */
b62f651… stephan 126 char *zIf; /* Surround the declaration with this #if */
b62f651… stephan 127 char *zFwd; /* A forward declaration. NULL if there is none. */
b62f651… stephan 128 char *zFwdCpp; /* Use this forward declaration for C++. */
b62f651… stephan 129 char *zDecl; /* A full declaration of this object */
b62f651… stephan 130 char *zExtra; /* Extra declaration text inserted into class objects */
b62f651… stephan 131 int extraType; /* Last public:, protected: or private: in zExtraDecl */
b62f651… stephan 132 struct Include *pInclude; /* #includes that come before this declaration */
b62f651… stephan 133 int flags; /* See the "Properties" below */
b62f651… stephan 134 Token *pComment; /* A block comment associated with this declaration */
b62f651… stephan 135 Token tokenCode; /* Implementation of functions and procedures */
b62f651… stephan 136 Decl *pSameName; /* Next declaration with the same "zName" */
b62f651… stephan 137 Decl *pSameHash; /* Next declaration with same hash but different zName */
b62f651… stephan 138 Decl *pNext; /* Next declaration with a different name */
b62f651… stephan 139 };
b62f651… stephan 140
b62f651… stephan 141 /*
b62f651… stephan 142 ** Properties associated with declarations.
b62f651… stephan 143 **
b62f651… stephan 144 ** DP_Forward and DP_Declared are used during the generation of a single
b62f651… stephan 145 ** header file in order to prevent duplicate declarations and definitions.
b62f651… stephan 146 ** DP_Forward is set after the object has been given a forward declaration
b62f651… stephan 147 ** and DP_Declared is set after the object gets a full declarations.
b62f651… stephan 148 ** (Example: A forward declaration is "typedef struct Abc Abc;" and the
b62f651… stephan 149 ** full declaration is "struct Abc { int a; float b; };".)
b62f651… stephan 150 **
b62f651… stephan 151 ** The DP_Export and DP_Local flags are more permanent. They mark objects
b62f651… stephan 152 ** that have EXPORT scope and LOCAL scope respectively. If both of these
b62f651… stephan 153 ** marks are missing, then the object has library scope. The meanings of
b62f651… stephan 154 ** the scopes are as follows:
b62f651… stephan 155 **
b62f651… stephan 156 ** LOCAL scope The object is only usable within the file in
b62f651… stephan 157 ** which it is declared.
b62f651… stephan 158 **
b62f651… stephan 159 ** library scope The object is visible and usable within other
b62f651… stephan 160 ** files in the same project. By if the project is
b62f651… stephan 161 ** a library, then the object is not visible to users
b62f651… stephan 162 ** of the library. (i.e. the object does not appear
b62f651… stephan 163 ** in the output when using the -H option.)
b62f651… stephan 164 **
b62f651… stephan 165 ** EXPORT scope The object is visible and usable everywhere.
b62f651… stephan 166 **
b62f651… stephan 167 ** The DP_Flag is a temporary use flag that is used during processing to
b62f651… stephan 168 ** prevent an infinite loop. It's use is localized.
b62f651… stephan 169 **
b62f651… stephan 170 ** The DP_Cplusplus, DP_ExternCReqd and DP_ExternReqd flags are permanent
b62f651… stephan 171 ** and are used to specify what type of declaration the object requires.
b62f651… stephan 172 */
b62f651… stephan 173 #define DP_Forward 0x001 /* Has a forward declaration in this file */
b62f651… stephan 174 #define DP_Declared 0x002 /* Has a full declaration in this file */
b62f651… stephan 175 #define DP_Export 0x004 /* Export this declaration */
b62f651… stephan 176 #define DP_Local 0x008 /* Declare in its home file only */
b62f651… stephan 177 #define DP_Flag 0x010 /* Use to mark a subset of a Decl list
b62f651… stephan 178 ** for special processing */
b62f651… stephan 179 #define DP_Cplusplus 0x020 /* Has C++ linkage and cannot appear in a
b62f651… stephan 180 ** C header file */
b62f651… stephan 181 #define DP_ExternCReqd 0x040 /* Prepend 'extern "C"' in a C++ header.
b62f651… stephan 182 ** Prepend nothing in a C header */
b62f651… stephan 183 #define DP_ExternReqd 0x080 /* Prepend 'extern "C"' in a C++ header if
b62f651… stephan 184 ** DP_Cplusplus is not also set. If DP_Cplusplus
b62f651… stephan 185 ** is set or this is a C header then
b62f651… stephan 186 ** prepend 'extern' */
b62f651… stephan 187
b62f651… stephan 188 /*
b62f651… stephan 189 ** Convenience macros for dealing with declaration properties
b62f651… stephan 190 */
b62f651… stephan 191 #define DeclHasProperty(D,P) (((D)->flags&(P))==(P))
b62f651… stephan 192 #define DeclHasAnyProperty(D,P) (((D)->flags&(P))!=0)
b62f651… stephan 193 #define DeclSetProperty(D,P) (D)->flags |= (P)
b62f651… stephan 194 #define DeclClearProperty(D,P) (D)->flags &= ~(P)
b62f651… stephan 195
b62f651… stephan 196 /*
b62f651… stephan 197 ** These are state properties of the parser. Each of the values is
b62f651… stephan 198 ** distinct from the DP_ values above so that both can be used in
b62f651… stephan 199 ** the same "flags" field.
b62f651… stephan 200 **
b62f651… stephan 201 ** Be careful not to confuse PS_Export with DP_Export or
b62f651… stephan 202 ** PS_Local with DP_Local. Their names are similar, but the meanings
b62f651… stephan 203 ** of these flags are very different.
b62f651… stephan 204 */
b62f651… stephan 205 #define PS_Extern 0x000800 /* "extern" has been seen */
b62f651… stephan 206 #define PS_Export 0x001000 /* If between "#if EXPORT_INTERFACE"
b62f651… stephan 207 ** and "#endif" */
b62f651… stephan 208 #define PS_Export2 0x002000 /* If "EXPORT" seen */
b62f651… stephan 209 #define PS_Typedef 0x004000 /* If "typedef" has been seen */
b62f651… stephan 210 #define PS_Static 0x008000 /* If "static" has been seen */
b62f651… stephan 211 #define PS_Interface 0x010000 /* If within #if INTERFACE..#endif */
b62f651… stephan 212 #define PS_Method 0x020000 /* If "::" token has been seen */
b62f651… stephan 213 #define PS_Local 0x040000 /* If within #if LOCAL_INTERFACE..#endif */
b62f651… stephan 214 #define PS_Local2 0x080000 /* If "LOCAL" seen. */
b62f651… stephan 215 #define PS_Public 0x100000 /* If "PUBLIC" seen. */
b62f651… stephan 216 #define PS_Protected 0x200000 /* If "PROTECTED" seen. */
b62f651… stephan 217 #define PS_Private 0x400000 /* If "PRIVATE" seen. */
b62f651… stephan 218 #define PS_PPP 0x700000 /* If any of PUBLIC, PRIVATE, PROTECTED */
b62f651… stephan 219
b62f651… stephan 220 /*
b62f651… stephan 221 ** The following set of flags are ORed into the "flags" field of
b62f651… stephan 222 ** a Decl in order to identify what type of object is being
b62f651… stephan 223 ** declared.
b62f651… stephan 224 */
b62f651… stephan 225 #define TY_Class 0x00100000
b62f651… stephan 226 #define TY_Subroutine 0x00200000
b62f651… stephan 227 #define TY_Macro 0x00400000
b62f651… stephan 228 #define TY_Typedef 0x00800000
b62f651… stephan 229 #define TY_Variable 0x01000000
b62f651… stephan 230 #define TY_Structure 0x02000000
b62f651… stephan 231 #define TY_Union 0x04000000
b62f651… stephan 232 #define TY_Enumeration 0x08000000
b62f651… stephan 233 #define TY_Defunct 0x10000000 /* Used to erase a declaration */
b62f651… stephan 234
b62f651… stephan 235 /*
b62f651… stephan 236 ** Each nested #if (or #ifdef or #ifndef) is stored in a stack of
b62f651… stephan 237 ** instances of the following structure.
b62f651… stephan 238 */
b62f651… stephan 239 typedef struct Ifmacro Ifmacro;
b62f651… stephan 240 struct Ifmacro {
b62f651… stephan 241 int nLine; /* Line number where this macro occurs */
b62f651… stephan 242 char *zCondition; /* Text of the condition for this macro */
b62f651… stephan 243 Ifmacro *pNext; /* Next down in the stack */
b62f651… stephan 244 int flags; /* Can hold PS_Export, PS_Interface or PS_Local flags */
b62f651… stephan 245 };
b62f651… stephan 246
b62f651… stephan 247 /*
b62f651… stephan 248 ** When parsing a file, we need to keep track of what other files have
b62f651… stephan 249 ** be #include-ed. For each #include found, we create an instance of
b62f651… stephan 250 ** the following structure.
b62f651… stephan 251 */
b62f651… stephan 252 typedef struct Include Include;
b62f651… stephan 253 struct Include {
b62f651… stephan 254 char *zFile; /* The name of file include. Includes "" or <> */
b62f651… stephan 255 char *zIf; /* If not NULL, #include should be enclosed in #if */
b62f651… stephan 256 char *zLabel; /* A unique label used to test if this #include has
b62f651… stephan 257 * appeared already in a file or not */
b62f651… stephan 258 Include *pNext; /* Previous include file, or NULL if this is the first */
b62f651… stephan 259 };
b62f651… stephan 260
b62f651… stephan 261 /*
b62f651… stephan 262 ** Identifiers found in a source file that might be used later to provoke
b62f651… stephan 263 ** the copying of a declaration into the corresponding header file are
b62f651… stephan 264 ** stored in a hash table as instances of the following structure.
b62f651… stephan 265 */
b62f651… stephan 266 typedef struct Ident Ident;
b62f651… stephan 267 struct Ident {
b62f651… stephan 268 char *zName; /* The text of this identifier */
b62f651… stephan 269 Ident *pCollide; /* Next identifier with the same hash */
b62f651… stephan 270 Ident *pNext; /* Next identifier in a list of them all */
b62f651… stephan 271 };
b62f651… stephan 272
b62f651… stephan 273 /*
b62f651… stephan 274 ** A complete table of identifiers is stored in an instance of
b62f651… stephan 275 ** the next structure.
b62f651… stephan 276 */
b62f651… stephan 277 #define IDENT_HASH_SIZE 2237
b62f651… stephan 278 typedef struct IdentTable IdentTable;
b62f651… stephan 279 struct IdentTable {
b62f651… stephan 280 Ident *pList; /* List of all identifiers in this table */
b62f651… stephan 281 Ident *apTable[IDENT_HASH_SIZE]; /* The hash table */
b62f651… stephan 282 };
b62f651… stephan 283
b62f651… stephan 284 /*
b62f651… stephan 285 ** The following structure holds all information for a single
b62f651… stephan 286 ** source file named on the command line of this program.
b62f651… stephan 287 */
b62f651… stephan 288 typedef struct InFile InFile;
b62f651… stephan 289 struct InFile {
b62f651… stephan 290 char *zSrc; /* Name of input file */
b62f651… stephan 291 char *zHdr; /* Name of the generated .h file for this input.
b62f651… stephan 292 ** Will be NULL if input is to be scanned only */
b62f651… stephan 293 int flags; /* One or more DP_, PS_ and/or TY_ flags */
b62f651… stephan 294 InFile *pNext; /* Next input file in the list of them all */
b62f651… stephan 295 IdentTable idTable; /* All identifiers in this input file */
b62f651… stephan 296 };
b62f651… stephan 297
b62f651… stephan 298 /*
b62f651… stephan 299 ** An unbounded string is able to grow without limit. We use these
b62f651… stephan 300 ** to construct large in-memory strings from lots of smaller components.
b62f651… stephan 301 */
b62f651… stephan 302 typedef struct String String;
b62f651… stephan 303 struct String {
b62f651… stephan 304 int nAlloc; /* Number of bytes allocated */
b62f651… stephan 305 int nUsed; /* Number of bytes used (not counting nul terminator) */
b62f651… stephan 306 char *zText; /* Text of the string */
b62f651… stephan 307 };
b62f651… stephan 308
b62f651… stephan 309 /*
b62f651… stephan 310 ** The following structure contains a lot of state information used
b62f651… stephan 311 ** while generating a .h file. We put the information in this structure
b62f651… stephan 312 ** and pass around a pointer to this structure, rather than pass around
b62f651… stephan 313 ** all of the information separately. This helps reduce the number of
b62f651… stephan 314 ** arguments to generator functions.
b62f651… stephan 315 */
b62f651… stephan 316 typedef struct GenState GenState;
b62f651… stephan 317 struct GenState {
b62f651… stephan 318 String *pStr; /* Write output to this string */
b62f651… stephan 319 IdentTable *pTable; /* A table holding the zLabel of every #include that
b62f651… stephan 320 * has already been generated. Used to avoid
b62f651… stephan 321 * generating duplicate #includes. */
b62f651… stephan 322 const char *zIf; /* If not NULL, then we are within a #if with
b62f651… stephan 323 * this argument. */
b62f651… stephan 324 int nErr; /* Number of errors */
b62f651… stephan 325 const char *zFilename; /* Name of the source file being scanned */
b62f651… stephan 326 int flags; /* Various flags (DP_ and PS_ flags above) */
b62f651… stephan 327 };
b62f651… stephan 328
b62f651… stephan 329 /*
b62f651… stephan 330 ** The following text line appears at the top of every file generated
b62f651… stephan 331 ** by this program. By recognizing this line, the program can be sure
b62f651… stephan 332 ** never to read a file that it generated itself.
b62f651… stephan 333 **
b62f651… stephan 334 ** The "#undef INTERFACE" part is a hack to work around a name collision
b62f651… stephan 335 ** in MSVC 2008.
b62f651… stephan 336 */
b62f651… stephan 337 const char zTopLine[] =
b62f651… stephan 338 "/* \aThis file was automatically generated. Do not edit! */\n"
b62f651… stephan 339 "#undef INTERFACE\n";
b62f651… stephan 340 #define nTopLine (sizeof(zTopLine)-1)
b62f651… stephan 341
b62f651… stephan 342 /*
b62f651… stephan 343 ** The name of the file currently being parsed.
b62f651… stephan 344 */
b62f651… stephan 345 static const char *zFilename;
b62f651… stephan 346
b62f651… stephan 347 /*
b62f651… stephan 348 ** The stack of #if macros for the file currently being parsed.
b62f651… stephan 349 */
b62f651… stephan 350 static Ifmacro *ifStack = 0;
b62f651… stephan 351
b62f651… stephan 352 /*
b62f651… stephan 353 ** A list of all files that have been #included so far in a file being
b62f651… stephan 354 ** parsed.
b62f651… stephan 355 */
b62f651… stephan 356 static Include *includeList = 0;
b62f651… stephan 357
b62f651… stephan 358 /*
b62f651… stephan 359 ** The last block comment seen.
b62f651… stephan 360 */
b62f651… stephan 361 static Token *blockComment = 0;
b62f651… stephan 362
b62f651… stephan 363 /*
b62f651… stephan 364 ** The following flag is set if the -doc flag appears on the
b62f651… stephan 365 ** command line.
b62f651… stephan 366 */
b62f651… stephan 367 static int doc_flag = 0;
b62f651… stephan 368
b62f651… stephan 369 /*
b62f651… stephan 370 ** If the following flag is set, then makeheaders will attempt to
b62f651… stephan 371 ** generate prototypes for static functions and procedures.
b62f651… stephan 372 */
b62f651… stephan 373 static int proto_static = 0;
b62f651… stephan 374
b62f651… stephan 375 /*
b62f651… stephan 376 ** A list of all declarations. The list is held together using the
b62f651… stephan 377 ** pNext field of the Decl structure.
b62f651… stephan 378 */
b62f651… stephan 379 static Decl *pDeclFirst; /* First on the list */
b62f651… stephan 380 static Decl *pDeclLast; /* Last on the list */
b62f651… stephan 381
b62f651… stephan 382 /*
b62f651… stephan 383 ** A hash table of all declarations
b62f651… stephan 384 */
b62f651… stephan 385 #define DECL_HASH_SIZE 3371
b62f651… stephan 386 static Decl *apTable[DECL_HASH_SIZE];
b62f651… stephan 387
b62f651… stephan 388 /*
b62f651… stephan 389 ** The TEST macro must be defined to something. Make sure this is the
b62f651… stephan 390 ** case.
b62f651… stephan 391 */
b62f651… stephan 392 #ifndef TEST
b62f651… stephan 393 # define TEST 0
b62f651… stephan 394 #endif
b62f651… stephan 395
b62f651… stephan 396 #ifdef NOT_USED
b62f651… stephan 397 /*
b62f651… stephan 398 ** We do our own assertion macro so that we can have more control
b62f651… stephan 399 ** over debugging.
b62f651… stephan 400 */
b62f651… stephan 401 #define Assert(X) if(!(X)){ CantHappen(__LINE__); }
b62f651… stephan 402 #define CANT_HAPPEN CantHappen(__LINE__)
b62f651… stephan 403 static void CantHappen(int iLine){
b62f651… stephan 404 fprintf(stderr,"Assertion failed on line %d\n",iLine);
b62f651… stephan 405 *(char*)1 = 0; /* Force a core-dump */
b62f651… stephan 406 }
b62f651… stephan 407 #endif
b62f651… stephan 408
b62f651… stephan 409 /*
b62f651… stephan 410 ** Memory allocation functions that are guaranteed never to return NULL.
b62f651… stephan 411 */
b62f651… stephan 412 static void *SafeMalloc(int nByte){
b62f651… stephan 413 void *p = malloc( nByte );
b62f651… stephan 414 if( p==0 ){
b62f651… stephan 415 fprintf(stderr,"Out of memory. Can't allocate %d bytes.\n",nByte);
b62f651… stephan 416 exit(1);
b62f651… stephan 417 }
b62f651… stephan 418 return p;
b62f651… stephan 419 }
b62f651… stephan 420 static void SafeFree(void *pOld){
b62f651… stephan 421 if( pOld ){
b62f651… stephan 422 free(pOld);
b62f651… stephan 423 }
b62f651… stephan 424 }
b62f651… stephan 425 static void *SafeRealloc(void *pOld, int nByte){
b62f651… stephan 426 void *p;
b62f651… stephan 427 if( pOld==0 ){
b62f651… stephan 428 p = SafeMalloc(nByte);
b62f651… stephan 429 }else{
b62f651… stephan 430 p = realloc(pOld, nByte);
b62f651… stephan 431 if( p==0 ){
b62f651… stephan 432 fprintf(stderr,
b62f651… stephan 433 "Out of memory. Can't enlarge an allocation to %d bytes\n",nByte);
b62f651… stephan 434 exit(1);
b62f651… stephan 435 }
b62f651… stephan 436 }
b62f651… stephan 437 return p;
b62f651… stephan 438 }
b62f651… stephan 439 static char *StrDup(const char *zSrc, int nByte){
b62f651… stephan 440 char *zDest;
b62f651… stephan 441 if( nByte<=0 ){
b62f651… stephan 442 nByte = strlen(zSrc);
b62f651… stephan 443 }
b62f651… stephan 444 zDest = SafeMalloc( nByte + 1 );
b62f651… stephan 445 strncpy(zDest,zSrc,nByte);
b62f651… stephan 446 zDest[nByte] = 0;
b62f651… stephan 447 return zDest;
b62f651… stephan 448 }
b62f651… stephan 449
b62f651… stephan 450 /*
b62f651… stephan 451 ** Return TRUE if the character X can be part of an identifier
b62f651… stephan 452 */
b62f651… stephan 453 #define ISALNUM(X) ((X)=='_' || isalnum(X))
b62f651… stephan 454
b62f651… stephan 455 /*
b62f651… stephan 456 ** Routines for dealing with unbounded strings.
b62f651… stephan 457 */
b62f651… stephan 458 static void StringInit(String *pStr){
b62f651… stephan 459 pStr->nAlloc = 0;
b62f651… stephan 460 pStr->nUsed = 0;
b62f651… stephan 461 pStr->zText = 0;
b62f651… stephan 462 }
b62f651… stephan 463 static void StringReset(String *pStr){
b62f651… stephan 464 SafeFree(pStr->zText);
b62f651… stephan 465 StringInit(pStr);
b62f651… stephan 466 }
b62f651… stephan 467 static void StringAppend(String *pStr, const char *zText, int nByte){
b62f651… stephan 468 if( nByte<=0 ){
b62f651… stephan 469 nByte = strlen(zText);
b62f651… stephan 470 }
b62f651… stephan 471 if( pStr->nUsed + nByte >= pStr->nAlloc ){
b62f651… stephan 472 if( pStr->nAlloc==0 ){
b62f651… stephan 473 pStr->nAlloc = nByte + 100;
b62f651… stephan 474 pStr->zText = SafeMalloc( pStr->nAlloc );
b62f651… stephan 475 }else{
b62f651… stephan 476 pStr->nAlloc = pStr->nAlloc*2 + nByte;
b62f651… stephan 477 pStr->zText = SafeRealloc(pStr->zText, pStr->nAlloc);
b62f651… stephan 478 }
b62f651… stephan 479 }
b62f651… stephan 480 strncpy(&pStr->zText[pStr->nUsed],zText,nByte);
b62f651… stephan 481 pStr->nUsed += nByte;
b62f651… stephan 482 pStr->zText[pStr->nUsed] = 0;
b62f651… stephan 483 }
b62f651… stephan 484 #define StringGet(S) ((S)->zText?(S)->zText:"")
b62f651… stephan 485
b62f651… stephan 486 /*
b62f651… stephan 487 ** Compute a hash on a string. The number returned is a non-negative
b62f651… stephan 488 ** value between 0 and 2**31 - 1
b62f651… stephan 489 */
b62f651… stephan 490 static int Hash(const char *z, int n){
a456dcb… drh 491 unsigned int h = 0;
b62f651… stephan 492 if( n<=0 ){
b62f651… stephan 493 n = strlen(z);
b62f651… stephan 494 }
b62f651… stephan 495 while( n-- ){
b62f651… stephan 496 h = h ^ (h<<5) ^ *z++;
b62f651… stephan 497 }
a456dcb… drh 498 return (int)(h & 0x7fffffff);
b62f651… stephan 499 }
b62f651… stephan 500
b62f651… stephan 501 /*
b62f651… stephan 502 ** Given an identifier name, try to find a declaration for that
b62f651… stephan 503 ** identifier in the hash table. If found, return a pointer to
b62f651… stephan 504 ** the Decl structure. If not found, return 0.
b62f651… stephan 505 */
b62f651… stephan 506 static Decl *FindDecl(const char *zName, int len){
b62f651… stephan 507 int h;
b62f651… stephan 508 Decl *p;
b62f651… stephan 509
b62f651… stephan 510 if( len<=0 ){
b62f651… stephan 511 len = strlen(zName);
b62f651… stephan 512 }
b62f651… stephan 513 h = Hash(zName,len) % DECL_HASH_SIZE;
b62f651… stephan 514 p = apTable[h];
b62f651… stephan 515 while( p && (strncmp(p->zName,zName,len)!=0 || p->zName[len]!=0) ){
b62f651… stephan 516 p = p->pSameHash;
b62f651… stephan 517 }
b62f651… stephan 518 return p;
b62f651… stephan 519 }
b62f651… stephan 520
b62f651… stephan 521 /*
b62f651… stephan 522 ** Install the given declaration both in the hash table and on
b62f651… stephan 523 ** the list of all declarations.
b62f651… stephan 524 */
b62f651… stephan 525 static void InstallDecl(Decl *pDecl){
b62f651… stephan 526 int h;
b62f651… stephan 527 Decl *pOther;
b62f651… stephan 528
b62f651… stephan 529 h = Hash(pDecl->zName,0) % DECL_HASH_SIZE;
b62f651… stephan 530 pOther = apTable[h];
b62f651… stephan 531 while( pOther && strcmp(pDecl->zName,pOther->zName)!=0 ){
b62f651… stephan 532 pOther = pOther->pSameHash;
b62f651… stephan 533 }
b62f651… stephan 534 if( pOther ){
b62f651… stephan 535 pDecl->pSameName = pOther->pSameName;
b62f651… stephan 536 pOther->pSameName = pDecl;
b62f651… stephan 537 }else{
b62f651… stephan 538 pDecl->pSameName = 0;
b62f651… stephan 539 pDecl->pSameHash = apTable[h];
b62f651… stephan 540 apTable[h] = pDecl;
b62f651… stephan 541 }
b62f651… stephan 542 pDecl->pNext = 0;
b62f651… stephan 543 if( pDeclFirst==0 ){
b62f651… stephan 544 pDeclFirst = pDeclLast = pDecl;
b62f651… stephan 545 }else{
b62f651… stephan 546 pDeclLast->pNext = pDecl;
b62f651… stephan 547 pDeclLast = pDecl;
b62f651… stephan 548 }
b62f651… stephan 549 }
b62f651… stephan 550
b62f651… stephan 551 /*
b62f651… stephan 552 ** Look at the current ifStack. If anything declared at the current
b62f651… stephan 553 ** position must be surrounded with
b62f651… stephan 554 **
b62f651… stephan 555 ** #if STUFF
b62f651… stephan 556 ** #endif
b62f651… stephan 557 **
b62f651… stephan 558 ** Then this routine computes STUFF and returns a pointer to it. Memory
b62f651… stephan 559 ** to hold the value returned is obtained from malloc().
b62f651… stephan 560 */
b62f651… stephan 561 static char *GetIfString(void){
b62f651… stephan 562 Ifmacro *pIf;
b62f651… stephan 563 char *zResult = 0;
b62f651… stephan 564 int hasIf = 0;
b62f651… stephan 565 String str;
b62f651… stephan 566
b62f651… stephan 567 for(pIf = ifStack; pIf; pIf=pIf->pNext){
b62f651… stephan 568 if( pIf->zCondition==0 || *pIf->zCondition==0 ) continue;
b62f651… stephan 569 if( !hasIf ){
b62f651… stephan 570 hasIf = 1;
b62f651… stephan 571 StringInit(&str);
b62f651… stephan 572 }else{
b62f651… stephan 573 StringAppend(&str," && ",4);
b62f651… stephan 574 }
b62f651… stephan 575 StringAppend(&str,pIf->zCondition,0);
b62f651… stephan 576 }
b62f651… stephan 577 if( hasIf ){
b62f651… stephan 578 zResult = StrDup(StringGet(&str),0);
b62f651… stephan 579 StringReset(&str);
b62f651… stephan 580 }else{
b62f651… stephan 581 zResult = 0;
b62f651… stephan 582 }
b62f651… stephan 583 return zResult;
b62f651… stephan 584 }
b62f651… stephan 585
b62f651… stephan 586 /*
b62f651… stephan 587 ** Create a new declaration and put it in the hash table. Also
b62f651… stephan 588 ** return a pointer to it so that we can fill in the zFwd and zDecl
b62f651… stephan 589 ** fields, and so forth.
b62f651… stephan 590 */
b62f651… stephan 591 static Decl *CreateDecl(
b62f651… stephan 592 const char *zName, /* Name of the object being declared. */
b62f651… stephan 593 int nName /* Length of the name */
b62f651… stephan 594 ){
b62f651… stephan 595 Decl *pDecl;
b62f651… stephan 596
b62f651… stephan 597 pDecl = SafeMalloc( sizeof(Decl) + nName + 1);
b62f651… stephan 598 memset(pDecl,0,sizeof(Decl));
b62f651… stephan 599 pDecl->zName = (char*)&pDecl[1];
8c7bf45… drh 600 memcpy(pDecl->zName, zName, nName);
8c7bf45… drh 601 pDecl->zName[nName] = 0;
b62f651… stephan 602 pDecl->zFile = zFilename;
b62f651… stephan 603 pDecl->pInclude = includeList;
b62f651… stephan 604 pDecl->zIf = GetIfString();
b62f651… stephan 605 InstallDecl(pDecl);
b62f651… stephan 606 return pDecl;
b62f651… stephan 607 }
b62f651… stephan 608
b62f651… stephan 609 /*
b62f651… stephan 610 ** Insert a new identifier into an table of identifiers. Return TRUE if
b62f651… stephan 611 ** a new identifier was inserted and return FALSE if the identifier was
b62f651… stephan 612 ** already in the table.
b62f651… stephan 613 */
b62f651… stephan 614 static int IdentTableInsert(
b62f651… stephan 615 IdentTable *pTable, /* The table into which we will insert */
b62f651… stephan 616 const char *zId, /* Name of the identifiers */
b62f651… stephan 617 int nId /* Length of the identifier name */
b62f651… stephan 618 ){
b62f651… stephan 619 int h;
b62f651… stephan 620 Ident *pId;
b62f651… stephan 621
b62f651… stephan 622 if( nId<=0 ){
b62f651… stephan 623 nId = strlen(zId);
b62f651… stephan 624 }
b62f651… stephan 625 h = Hash(zId,nId) % IDENT_HASH_SIZE;
b62f651… stephan 626 for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){
b62f651… stephan 627 if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
b62f651… stephan 628 /* printf("Already in table: %.*s\n",nId,zId); */
b62f651… stephan 629 return 0;
b62f651… stephan 630 }
b62f651… stephan 631 }
b62f651… stephan 632 pId = SafeMalloc( sizeof(Ident) + nId + 1 );
b62f651… stephan 633 pId->zName = (char*)&pId[1];
8c7bf45… drh 634 memcpy(pId->zName, zId, nId);
8c7bf45… drh 635 pId->zName[nId] = 0;
b62f651… stephan 636 pId->pNext = pTable->pList;
b62f651… stephan 637 pTable->pList = pId;
b62f651… stephan 638 pId->pCollide = pTable->apTable[h];
b62f651… stephan 639 pTable->apTable[h] = pId;
b62f651… stephan 640 /* printf("Add to table: %.*s\n",nId,zId); */
b62f651… stephan 641 return 1;
b62f651… stephan 642 }
b62f651… stephan 643
b62f651… stephan 644 /*
b62f651… stephan 645 ** Check to see if the given value is in the given IdentTable. Return
b62f651… stephan 646 ** true if it is and false if it is not.
b62f651… stephan 647 */
b62f651… stephan 648 static int IdentTableTest(
b62f651… stephan 649 IdentTable *pTable, /* The table in which to search */
b62f651… stephan 650 const char *zId, /* Name of the identifiers */
b62f651… stephan 651 int nId /* Length of the identifier name */
b62f651… stephan 652 ){
b62f651… stephan 653 int h;
b62f651… stephan 654 Ident *pId;
b62f651… stephan 655
b62f651… stephan 656 if( nId<=0 ){
b62f651… stephan 657 nId = strlen(zId);
b62f651… stephan 658 }
b62f651… stephan 659 h = Hash(zId,nId) % IDENT_HASH_SIZE;
b62f651… stephan 660 for(pId = pTable->apTable[h]; pId; pId=pId->pCollide){
b62f651… stephan 661 if( strncmp(zId,pId->zName,nId)==0 && pId->zName[nId]==0 ){
b62f651… stephan 662 return 1;
b62f651… stephan 663 }
b62f651… stephan 664 }
b62f651… stephan 665 return 0;
b62f651… stephan 666 }
b62f651… stephan 667
b62f651… stephan 668 /*
b62f651… stephan 669 ** Remove every identifier from the given table. Reset the table to
b62f651… stephan 670 ** its initial state.
b62f651… stephan 671 */
b62f651… stephan 672 static void IdentTableReset(IdentTable *pTable){
b62f651… stephan 673 Ident *pId, *pNext;
b62f651… stephan 674
b62f651… stephan 675 for(pId = pTable->pList; pId; pId = pNext){
b62f651… stephan 676 pNext = pId->pNext;
b62f651… stephan 677 SafeFree(pId);
b62f651… stephan 678 }
b62f651… stephan 679 memset(pTable,0,sizeof(IdentTable));
b62f651… stephan 680 }
b62f651… stephan 681
b62f651… stephan 682 #ifdef DEBUG
b62f651… stephan 683 /*
b62f651… stephan 684 ** Print the name of every identifier in the given table, one per line
b62f651… stephan 685 */
b62f651… stephan 686 static void IdentTablePrint(IdentTable *pTable, FILE *pOut){
b62f651… stephan 687 Ident *pId;
b62f651… stephan 688
b62f651… stephan 689 for(pId = pTable->pList; pId; pId = pId->pNext){
b62f651… stephan 690 fprintf(pOut,"%s\n",pId->zName);
b62f651… stephan 691 }
b62f651… stephan 692 }
b62f651… stephan 693 #endif
b62f651… stephan 694
b62f651… stephan 695 /*
b62f651… stephan 696 ** Read an entire file into memory. Return a pointer to the memory.
b62f651… stephan 697 **
b62f651… stephan 698 ** The memory is obtained from SafeMalloc and must be freed by the
b62f651… stephan 699 ** calling function.
b62f651… stephan 700 **
b62f651… stephan 701 ** If the read fails for any reason, 0 is returned.
b62f651… stephan 702 */
b62f651… stephan 703 static char *ReadFile(const char *zFilename){
b62f651… stephan 704 struct stat sStat;
b62f651… stephan 705 FILE *pIn;
b62f651… stephan 706 char *zBuf;
b62f651… stephan 707 int n;
b62f651… stephan 708
b62f651… stephan 709 if( stat(zFilename,&sStat)!=0
b62f651… stephan 710 #ifndef WIN32
b62f651… stephan 711 || !S_ISREG(sStat.st_mode)
b62f651… stephan 712 #endif
b62f651… stephan 713 ){
b62f651… stephan 714 return 0;
b62f651… stephan 715 }
b62f651… stephan 716 pIn = fopen(zFilename,"r");
b62f651… stephan 717 if( pIn==0 ){
b62f651… stephan 718 return 0;
b62f651… stephan 719 }
b62f651… stephan 720 zBuf = SafeMalloc( sStat.st_size + 1 );
b62f651… stephan 721 n = fread(zBuf,1,sStat.st_size,pIn);
b62f651… stephan 722 zBuf[n] = 0;
b62f651… stephan 723 fclose(pIn);
b62f651… stephan 724 return zBuf;
b62f651… stephan 725 }
b62f651… stephan 726
b62f651… stephan 727 /*
b62f651… stephan 728 ** Write the contents of a string into a file. Return the number of
b62f651… stephan 729 ** errors
b62f651… stephan 730 */
b62f651… stephan 731 static int WriteFile(const char *zFilename, const char *zOutput){
b62f651… stephan 732 FILE *pOut;
b62f651… stephan 733 pOut = fopen(zFilename,"w");
b62f651… stephan 734 if( pOut==0 ){
b62f651… stephan 735 return 1;
b62f651… stephan 736 }
b62f651… stephan 737 fwrite(zOutput,1,strlen(zOutput),pOut);
b62f651… stephan 738 fclose(pOut);
b62f651… stephan 739 return 0;
b62f651… stephan 740 }
b62f651… stephan 741
b62f651… stephan 742 /*
b62f651… stephan 743 ** Major token types
b62f651… stephan 744 */
b62f651… stephan 745 #define TT_Space 1 /* Contiguous white space */
b62f651… stephan 746 #define TT_Id 2 /* An identifier */
b62f651… stephan 747 #define TT_Preprocessor 3 /* Any C preprocessor directive */
b62f651… stephan 748 #define TT_Comment 4 /* Either C or C++ style comment */
b62f651… stephan 749 #define TT_Number 5 /* Any numeric constant */
b62f651… stephan 750 #define TT_String 6 /* String or character constants. ".." or '.' */
b62f651… stephan 751 #define TT_Braces 7 /* All text between { and a matching } */
b62f651… stephan 752 #define TT_EOF 8 /* End of file */
b62f651… stephan 753 #define TT_Error 9 /* An error condition */
b62f651… stephan 754 #define TT_BlockComment 10 /* A C-Style comment at the left margin that
b62f651… stephan 755 * spans multiple lines */
b62f651… stephan 756 #define TT_Other 0 /* None of the above */
b62f651… stephan 757
b62f651… stephan 758 /*
b62f651… stephan 759 ** Get a single low-level token from the input file. Update the
b62f651… stephan 760 ** file pointer so that it points to the first character beyond the
b62f651… stephan 761 ** token.
b62f651… stephan 762 **
b62f651… stephan 763 ** A "low-level token" is any token except TT_Braces. A TT_Braces token
b62f651… stephan 764 ** consists of many smaller tokens and is assembled by a routine that
b62f651… stephan 765 ** calls this one.
b62f651… stephan 766 **
b62f651… stephan 767 ** The function returns the number of errors. An error is an
b62f651… stephan 768 ** unterminated string or character literal or an unterminated
b62f651… stephan 769 ** comment.
b62f651… stephan 770 **
b62f651… stephan 771 ** Profiling shows that this routine consumes about half the
b62f651… stephan 772 ** CPU time on a typical run of makeheaders.
b62f651… stephan 773 */
b62f651… stephan 774 static int GetToken(InStream *pIn, Token *pToken){
b62f651… stephan 775 int i;
b62f651… stephan 776 const char *z;
b62f651… stephan 777 int cStart;
b62f651… stephan 778 int c;
b62f651… stephan 779 int startLine; /* Line on which a structure begins */
b62f651… stephan 780 int nlisc = 0; /* True if there is a new-line in a ".." or '..' */
b62f651… stephan 781 int nErr = 0; /* Number of errors seen */
b62f651… stephan 782
b62f651… stephan 783 z = pIn->z;
b62f651… stephan 784 i = pIn->i;
b62f651… stephan 785 pToken->nLine = pIn->nLine;
b62f651… stephan 786 pToken->zText = &z[i];
b62f651… stephan 787 switch( z[i] ){
b62f651… stephan 788 case 0:
b62f651… stephan 789 pToken->eType = TT_EOF;
b62f651… stephan 790 pToken->nText = 0;
b62f651… stephan 791 break;
b62f651… stephan 792
b62f651… stephan 793 case '#':
b62f651… stephan 794 if( i==0 || z[i-1]=='\n' || (i>1 && z[i-1]=='\r' && z[i-2]=='\n')){
b62f651… stephan 795 /* We found a preprocessor statement */
b62f651… stephan 796 pToken->eType = TT_Preprocessor;
b62f651… stephan 797 i++;
b62f651… stephan 798 while( z[i]!=0 && z[i]!='\n' ){
b62f651… stephan 799 if( z[i]=='\\' ){
b62f651… stephan 800 i++;
b62f651… stephan 801 if( z[i]=='\n' ) pIn->nLine++;
b62f651… stephan 802 }
b62f651… stephan 803 i++;
b62f651… stephan 804 }
b62f651… stephan 805 pToken->nText = i - pIn->i;
b62f651… stephan 806 }else{
b62f651… stephan 807 /* Just an operator */
b62f651… stephan 808 pToken->eType = TT_Other;
b62f651… stephan 809 pToken->nText = 1;
b62f651… stephan 810 }
b62f651… stephan 811 break;
b62f651… stephan 812
b62f651… stephan 813 case ' ':
b62f651… stephan 814 case '\t':
b62f651… stephan 815 case '\r':
b62f651… stephan 816 case '\f':
b62f651… stephan 817 case '\n':
b62f651… stephan 818 while( isspace(z[i]) ){
b62f651… stephan 819 if( z[i]=='\n' ) pIn->nLine++;
b62f651… stephan 820 i++;
b62f651… stephan 821 }
b62f651… stephan 822 pToken->eType = TT_Space;
b62f651… stephan 823 pToken->nText = i - pIn->i;
b62f651… stephan 824 break;
b62f651… stephan 825
b62f651… stephan 826 case '\\':
b62f651… stephan 827 pToken->nText = 2;
b62f651… stephan 828 pToken->eType = TT_Other;
b62f651… stephan 829 if( z[i+1]=='\n' ){
b62f651… stephan 830 pIn->nLine++;
b62f651… stephan 831 pToken->eType = TT_Space;
b62f651… stephan 832 }else if( z[i+1]==0 ){
b62f651… stephan 833 pToken->nText = 1;
b62f651… stephan 834 }
b62f651… stephan 835 break;
b62f651… stephan 836
b62f651… stephan 837 case '\'':
b62f651… stephan 838 case '\"':
b62f651… stephan 839 cStart = z[i];
b62f651… stephan 840 startLine = pIn->nLine;
b62f651… stephan 841 do{
b62f651… stephan 842 i++;
b62f651… stephan 843 c = z[i];
b62f651… stephan 844 if( c=='\n' ){
b62f651… stephan 845 if( !nlisc ){
b62f651… stephan 846 fprintf(stderr,
b62f651… stephan 847 "%s:%d: (warning) Newline in string or character literal.\n",
b62f651… stephan 848 zFilename, pIn->nLine);
b62f651… stephan 849 nlisc = 1;
b62f651… stephan 850 }
b62f651… stephan 851 pIn->nLine++;
b62f651… stephan 852 }
b62f651… stephan 853 if( c=='\\' ){
b62f651… stephan 854 i++;
b62f651… stephan 855 c = z[i];
b62f651… stephan 856 if( c=='\n' ){
b62f651… stephan 857 pIn->nLine++;
b62f651… stephan 858 }
b62f651… stephan 859 }else if( c==cStart ){
b62f651… stephan 860 i++;
b62f651… stephan 861 c = 0;
b62f651… stephan 862 }else if( c==0 ){
b62f651… stephan 863 fprintf(stderr, "%s:%d: Unterminated string or character literal.\n",
b62f651… stephan 864 zFilename, startLine);
b62f651… stephan 865 nErr++;
b62f651… stephan 866 }
b62f651… stephan 867 }while( c );
b62f651… stephan 868 pToken->eType = TT_String;
b62f651… stephan 869 pToken->nText = i - pIn->i;
b62f651… stephan 870 break;
b62f651… stephan 871
b62f651… stephan 872 case '/':
b62f651… stephan 873 if( z[i+1]=='/' ){
b62f651… stephan 874 /* C++ style comment */
b62f651… stephan 875 while( z[i] && z[i]!='\n' ){ i++; }
b62f651… stephan 876 pToken->eType = TT_Comment;
b62f651… stephan 877 pToken->nText = i - pIn->i;
b62f651… stephan 878 }else if( z[i+1]=='*' ){
b62f651… stephan 879 /* C style comment */
b62f651… stephan 880 int isBlockComment = i==0 || z[i-1]=='\n';
b62f651… stephan 881 i += 2;
b62f651… stephan 882 startLine = pIn->nLine;
b62f651… stephan 883 while( z[i] && (z[i]!='*' || z[i+1]!='/') ){
b62f651… stephan 884 if( z[i]=='\n' ){
b62f651… stephan 885 pIn->nLine++;
b62f651… stephan 886 if( isBlockComment ){
b62f651… stephan 887 if( z[i+1]=='*' || z[i+2]=='*' ){
b62f651… stephan 888 isBlockComment = 2;
b62f651… stephan 889 }else{
b62f651… stephan 890 isBlockComment = 0;
b62f651… stephan 891 }
b62f651… stephan 892 }
b62f651… stephan 893 }
b62f651… stephan 894 i++;
b62f651… stephan 895 }
b62f651… stephan 896 if( z[i] ){
b62f651… stephan 897 i += 2;
b62f651… stephan 898 }else{
b62f651… stephan 899 isBlockComment = 0;
b62f651… stephan 900 fprintf(stderr,"%s:%d: Unterminated comment\n",
b62f651… stephan 901 zFilename, startLine);
b62f651… stephan 902 nErr++;
b62f651… stephan 903 }
b62f651… stephan 904 pToken->eType = isBlockComment==2 ? TT_BlockComment : TT_Comment;
b62f651… stephan 905 pToken->nText = i - pIn->i;
b62f651… stephan 906 }else{
b62f651… stephan 907 /* A divide operator */
b62f651… stephan 908 pToken->eType = TT_Other;
b62f651… stephan 909 pToken->nText = 1 + (z[i+1]=='+');
b62f651… stephan 910 }
b62f651… stephan 911 break;
b62f651… stephan 912
b62f651… stephan 913 case '0':
b62f651… stephan 914 if( z[i+1]=='x' || z[i+1]=='X' ){
b62f651… stephan 915 /* A hex constant */
b62f651… stephan 916 i += 2;
b62f651… stephan 917 while( isxdigit(z[i]) ){ i++; }
b62f651… stephan 918 }else{
b62f651… stephan 919 /* An octal constant */
b62f651… stephan 920 while( isdigit(z[i]) ){ i++; }
b62f651… stephan 921 }
b62f651… stephan 922 pToken->eType = TT_Number;
b62f651… stephan 923 pToken->nText = i - pIn->i;
b62f651… stephan 924 break;
b62f651… stephan 925
b62f651… stephan 926 case '1': case '2': case '3': case '4':
b62f651… stephan 927 case '5': case '6': case '7': case '8': case '9':
b62f651… stephan 928 while( isdigit(z[i]) ){ i++; }
b62f651… stephan 929 if( (c=z[i])=='.' ){
b62f651… stephan 930 i++;
b62f651… stephan 931 while( isdigit(z[i]) ){ i++; }
b62f651… stephan 932 c = z[i];
b62f651… stephan 933 if( c=='e' || c=='E' ){
b62f651… stephan 934 i++;
b62f651… stephan 935 if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; }
b62f651… stephan 936 while( isdigit(z[i]) ){ i++; }
b62f651… stephan 937 c = z[i];
b62f651… stephan 938 }
b62f651… stephan 939 if( c=='f' || c=='F' || c=='l' || c=='L' ){ i++; }
b62f651… stephan 940 }else if( c=='e' || c=='E' ){
b62f651… stephan 941 i++;
b62f651… stephan 942 if( ((c=z[i])=='+' || c=='-') && isdigit(z[i+1]) ){ i++; }
b62f651… stephan 943 while( isdigit(z[i]) ){ i++; }
b62f651… stephan 944 }else if( c=='L' || c=='l' ){
b62f651… stephan 945 i++;
b62f651… stephan 946 c = z[i];
b62f651… stephan 947 if( c=='u' || c=='U' ){ i++; }
b62f651… stephan 948 }else if( c=='u' || c=='U' ){
b62f651… stephan 949 i++;
b62f651… stephan 950 c = z[i];
b62f651… stephan 951 if( c=='l' || c=='L' ){ i++; }
b62f651… stephan 952 }
b62f651… stephan 953 pToken->eType = TT_Number;
b62f651… stephan 954 pToken->nText = i - pIn->i;
b62f651… stephan 955 break;
b62f651… stephan 956
b62f651… stephan 957 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
b62f651… stephan 958 case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
b62f651… stephan 959 case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
b62f651… stephan 960 case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B':
b62f651… stephan 961 case 'C': case 'D': case 'E': case 'F': case 'G': case 'H': case 'I':
b62f651… stephan 962 case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P':
b62f651… stephan 963 case 'Q': case 'R': case 'S': case 'T': case 'U': case 'V': case 'W':
b62f651… stephan 964 case 'X': case 'Y': case 'Z': case '_':
b62f651… stephan 965 while( isalnum(z[i]) || z[i]=='_' ){ i++; };
b62f651… stephan 966 pToken->eType = TT_Id;
b62f651… stephan 967 pToken->nText = i - pIn->i;
b62f651… stephan 968 break;
b62f651… stephan 969
b62f651… stephan 970 case ':':
b62f651… stephan 971 pToken->eType = TT_Other;
b62f651… stephan 972 pToken->nText = 1 + (z[i+1]==':');
b62f651… stephan 973 break;
b62f651… stephan 974
b62f651… stephan 975 case '=':
b62f651… stephan 976 case '<':
b62f651… stephan 977 case '>':
b62f651… stephan 978 case '+':
b62f651… stephan 979 case '-':
b62f651… stephan 980 case '*':
b62f651… stephan 981 case '%':
b62f651… stephan 982 case '^':
b62f651… stephan 983 case '&':
b62f651… stephan 984 case '|':
b62f651… stephan 985 pToken->eType = TT_Other;
b62f651… stephan 986 pToken->nText = 1 + (z[i+1]=='=');
b62f651… stephan 987 break;
b62f651… stephan 988
b62f651… stephan 989 default:
b62f651… stephan 990 pToken->eType = TT_Other;
b62f651… stephan 991 pToken->nText = 1;
b62f651… stephan 992 break;
b62f651… stephan 993 }
b62f651… stephan 994 pIn->i += pToken->nText;
b62f651… stephan 995 return nErr;
b62f651… stephan 996 }
b62f651… stephan 997
b62f651… stephan 998 /*
b62f651… stephan 999 ** This routine recovers the next token from the input file which is
b62f651… stephan 1000 ** not a space or a comment or any text between an "#if 0" and "#endif".
b62f651… stephan 1001 **
b62f651… stephan 1002 ** This routine returns the number of errors encountered. An error
b62f651… stephan 1003 ** is an unterminated token or unmatched "#if 0".
b62f651… stephan 1004 **
b62f651… stephan 1005 ** Profiling shows that this routine uses about a quarter of the
b62f651… stephan 1006 ** CPU time in a typical run.
b62f651… stephan 1007 */
b62f651… stephan 1008 static int GetNonspaceToken(InStream *pIn, Token *pToken){
b62f651… stephan 1009 int nIf = 0;
b62f651… stephan 1010 int inZero = 0;
b62f651… stephan 1011 const char *z;
b62f651… stephan 1012 int value;
b62f651… stephan 1013 int startLine;
b62f651… stephan 1014 int nErr = 0;
b62f651… stephan 1015
b62f651… stephan 1016 startLine = pIn->nLine;
b62f651… stephan 1017 while( 1 ){
b62f651… stephan 1018 nErr += GetToken(pIn,pToken);
b62f651… stephan 1019 /* printf("%04d: Type=%d nIf=%d [%.*s]\n",
b62f651… stephan 1020 pToken->nLine,pToken->eType,nIf,pToken->nText,
b62f651… stephan 1021 pToken->eType!=TT_Space ? pToken->zText : "<space>"); */
b62f651… stephan 1022 pToken->pComment = blockComment;
b62f651… stephan 1023 switch( pToken->eType ){
b62f651… stephan 1024 case TT_Comment: /*0123456789 12345678 */
b62f651… stephan 1025 if( strncmp(pToken->zText, "/*MAKEHEADERS-STOP", 18)==0 ) return nErr;
b62f651… stephan 1026 break;
b62f651… stephan 1027
b62f651… stephan 1028 case TT_Space:
b62f651… stephan 1029 break;
b62f651… stephan 1030
b62f651… stephan 1031 case TT_BlockComment:
b62f651… stephan 1032 if( doc_flag ){
b62f651… stephan 1033 blockComment = SafeMalloc( sizeof(Token) );
b62f651… stephan 1034 *blockComment = *pToken;
b62f651… stephan 1035 }
b62f651… stephan 1036 break;
b62f651… stephan 1037
b62f651… stephan 1038 case TT_EOF:
b62f651… stephan 1039 if( nIf ){
b62f651… stephan 1040 fprintf(stderr,"%s:%d: Unterminated \"#if\"\n",
b62f651… stephan 1041 zFilename, startLine);
b62f651… stephan 1042 nErr++;
b62f651… stephan 1043 }
b62f651… stephan 1044 return nErr;
b62f651… stephan 1045
b62f651… stephan 1046 case TT_Preprocessor:
b62f651… stephan 1047 z = &pToken->zText[1];
b62f651… stephan 1048 while( *z==' ' || *z=='\t' ) z++;
b62f651… stephan 1049 if( sscanf(z,"if %d",&value)==1 && value==0 ){
b62f651… stephan 1050 nIf++;
b62f651… stephan 1051 inZero = 1;
b62f651… stephan 1052 }else if( inZero ){
b62f651… stephan 1053 if( strncmp(z,"if",2)==0 ){
b62f651… stephan 1054 nIf++;
b62f651… stephan 1055 }else if( strncmp(z,"endif",5)==0 ){
b62f651… stephan 1056 nIf--;
b62f651… stephan 1057 if( nIf==0 ) inZero = 0;
b62f651… stephan 1058 }
b62f651… stephan 1059 }else{
b62f651… stephan 1060 return nErr;
b62f651… stephan 1061 }
b62f651… stephan 1062 break;
b62f651… stephan 1063
b62f651… stephan 1064 default:
b62f651… stephan 1065 if( !inZero ){
b62f651… stephan 1066 return nErr;
b62f651… stephan 1067 }
b62f651… stephan 1068 break;
b62f651… stephan 1069 }
b62f651… stephan 1070 }
b62f651… stephan 1071 /* NOT REACHED */
b62f651… stephan 1072 }
b62f651… stephan 1073
b62f651… stephan 1074 /*
b62f651… stephan 1075 ** This routine looks for identifiers (strings of contiguous alphanumeric
b62f651… stephan 1076 ** characters) within a preprocessor directive and adds every such string
b62f651… stephan 1077 ** found to the given identifier table
b62f651… stephan 1078 */
b62f651… stephan 1079 static void FindIdentifiersInMacro(Token *pToken, IdentTable *pTable){
b62f651… stephan 1080 Token sToken;
b62f651… stephan 1081 InStream sIn;
b62f651… stephan 1082 int go = 1;
b62f651… stephan 1083
b62f651… stephan 1084 sIn.z = pToken->zText;
b62f651… stephan 1085 sIn.i = 1;
b62f651… stephan 1086 sIn.nLine = 1;
b62f651… stephan 1087 while( go && sIn.i < pToken->nText ){
b62f651… stephan 1088 GetToken(&sIn,&sToken);
b62f651… stephan 1089 switch( sToken.eType ){
b62f651… stephan 1090 case TT_Id:
b62f651… stephan 1091 IdentTableInsert(pTable,sToken.zText,sToken.nText);
b62f651… stephan 1092 break;
b62f651… stephan 1093
b62f651… stephan 1094 case TT_EOF:
b62f651… stephan 1095 go = 0;
b62f651… stephan 1096 break;
b62f651… stephan 1097
b62f651… stephan 1098 default:
b62f651… stephan 1099 break;
b62f651… stephan 1100 }
b62f651… stephan 1101 }
b62f651… stephan 1102 }
b62f651… stephan 1103
b62f651… stephan 1104 /*
b62f651… stephan 1105 ** This routine gets the next token. Everything contained within
b62f651… stephan 1106 ** {...} is collapsed into a single TT_Braces token. Whitespace is
b62f651… stephan 1107 ** omitted.
b62f651… stephan 1108 **
b62f651… stephan 1109 ** If pTable is not NULL, then insert every identifier seen into the
b62f651… stephan 1110 ** IdentTable. This includes any identifiers seen inside of {...}.
b62f651… stephan 1111 **
b62f651… stephan 1112 ** The number of errors encountered is returned. An error is an
b62f651… stephan 1113 ** unterminated token.
b62f651… stephan 1114 */
b62f651… stephan 1115 static int GetBigToken(InStream *pIn, Token *pToken, IdentTable *pTable){
b62f651… stephan 1116 const char *zStart;
b62f651… stephan 1117 int iStart;
b62f651… stephan 1118 int nBrace;
b62f651… stephan 1119 int c;
b62f651… stephan 1120 int nLine;
b62f651… stephan 1121 int nErr;
b62f651… stephan 1122
b62f651… stephan 1123 nErr = GetNonspaceToken(pIn,pToken);
b62f651… stephan 1124 switch( pToken->eType ){
b62f651… stephan 1125 case TT_Id:
b62f651… stephan 1126 if( pTable!=0 ){
b62f651… stephan 1127 IdentTableInsert(pTable,pToken->zText,pToken->nText);
b62f651… stephan 1128 }
b62f651… stephan 1129 return nErr;
b62f651… stephan 1130
b62f651… stephan 1131 case TT_Preprocessor:
b62f651… stephan 1132 if( pTable!=0 ){
b62f651… stephan 1133 FindIdentifiersInMacro(pToken,pTable);
b62f651… stephan 1134 }
b62f651… stephan 1135 return nErr;
b62f651… stephan 1136
b62f651… stephan 1137 case TT_Other:
b62f651… stephan 1138 if( pToken->zText[0]=='{' ) break;
b62f651… stephan 1139 return nErr;
b62f651… stephan 1140
b62f651… stephan 1141 default:
b62f651… stephan 1142 return nErr;
b62f651… stephan 1143 }
b62f651… stephan 1144
b62f651… stephan 1145 iStart = pIn->i;
b62f651… stephan 1146 zStart = pToken->zText;
b62f651… stephan 1147 nLine = pToken->nLine;
b62f651… stephan 1148 nBrace = 1;
b62f651… stephan 1149 while( nBrace ){
b62f651… stephan 1150 nErr += GetNonspaceToken(pIn,pToken);
b62f651… stephan 1151 /* printf("%04d: nBrace=%d [%.*s]\n",pToken->nLine,nBrace,
b62f651… stephan 1152 pToken->nText,pToken->zText); */
b62f651… stephan 1153 switch( pToken->eType ){
b62f651… stephan 1154 case TT_EOF:
b62f651… stephan 1155 fprintf(stderr,"%s:%d: Unterminated \"{\"\n",
b62f651… stephan 1156 zFilename, nLine);
b62f651… stephan 1157 nErr++;
b62f651… stephan 1158 pToken->eType = TT_Error;
b62f651… stephan 1159 return nErr;
b62f651… stephan 1160
b62f651… stephan 1161 case TT_Id:
b62f651… stephan 1162 if( pTable ){
b62f651… stephan 1163 IdentTableInsert(pTable,pToken->zText,pToken->nText);
b62f651… stephan 1164 }
b62f651… stephan 1165 break;
b62f651… stephan 1166
b62f651… stephan 1167 case TT_Preprocessor:
b62f651… stephan 1168 if( pTable!=0 ){
b62f651… stephan 1169 FindIdentifiersInMacro(pToken,pTable);
b62f651… stephan 1170 }
b62f651… stephan 1171 break;
b62f651… stephan 1172
b62f651… stephan 1173 case TT_Other:
b62f651… stephan 1174 if( (c = pToken->zText[0])=='{' ){
b62f651… stephan 1175 nBrace++;
b62f651… stephan 1176 }else if( c=='}' ){
b62f651… stephan 1177 nBrace--;
b62f651… stephan 1178 }
b62f651… stephan 1179 break;
b62f651… stephan 1180
b62f651… stephan 1181 default:
b62f651… stephan 1182 break;
b62f651… stephan 1183 }
b62f651… stephan 1184 }
b62f651… stephan 1185 pToken->eType = TT_Braces;
b62f651… stephan 1186 pToken->nText = 1 + pIn->i - iStart;
b62f651… stephan 1187 pToken->zText = zStart;
b62f651… stephan 1188 pToken->nLine = nLine;
b62f651… stephan 1189 return nErr;
b62f651… stephan 1190 }
b62f651… stephan 1191
b62f651… stephan 1192 /*
b62f651… stephan 1193 ** This routine frees up a list of Tokens. The pComment tokens are
b62f651… stephan 1194 ** not cleared by this. So we leak a little memory when using the -doc
b62f651… stephan 1195 ** option. So what.
b62f651… stephan 1196 */
b62f651… stephan 1197 static void FreeTokenList(Token *pList){
b62f651… stephan 1198 Token *pNext;
b62f651… stephan 1199 while( pList ){
b62f651… stephan 1200 pNext = pList->pNext;
b62f651… stephan 1201 SafeFree(pList);
b62f651… stephan 1202 pList = pNext;
b62f651… stephan 1203 }
b62f651… stephan 1204 }
b62f651… stephan 1205
b62f651… stephan 1206 /*
b62f651… stephan 1207 ** Tokenize an entire file. Return a pointer to the list of tokens.
b62f651… stephan 1208 **
b62f651… stephan 1209 ** Space for each token is obtained from a separate malloc() call. The
b62f651… stephan 1210 ** calling function is responsible for freeing this space.
b62f651… stephan 1211 **
b62f651… stephan 1212 ** If pTable is not NULL, then fill the table with all identifiers seen in
b62f651… stephan 1213 ** the input file.
b62f651… stephan 1214 */
b62f651… stephan 1215 static Token *TokenizeFile(const char *zFile, IdentTable *pTable){
b62f651… stephan 1216 InStream sIn;
b62f651… stephan 1217 Token *pFirst = 0, *pLast = 0, *pNew;
b62f651… stephan 1218 int nErr = 0;
b62f651… stephan 1219
b62f651… stephan 1220 sIn.z = zFile;
b62f651… stephan 1221 sIn.i = 0;
b62f651… stephan 1222 sIn.nLine = 1;
b62f651… stephan 1223 blockComment = 0;
b62f651… stephan 1224
b62f651… stephan 1225 while( sIn.z[sIn.i]!=0 ){
b62f651… stephan 1226 pNew = SafeMalloc( sizeof(Token) );
b62f651… stephan 1227 nErr += GetBigToken(&sIn,pNew,pTable);
b62f651… stephan 1228 debug3(TOKENIZER, "Token on line %d: [%.*s]\n",
b62f651… stephan 1229 pNew->nLine, pNew->nText<50 ? pNew->nText : 50, pNew->zText);
b62f651… stephan 1230 if( pFirst==0 ){
b62f651… stephan 1231 pFirst = pLast = pNew;
b62f651… stephan 1232 pNew->pPrev = 0;
b62f651… stephan 1233 }else{
b62f651… stephan 1234 pLast->pNext = pNew;
b62f651… stephan 1235 pNew->pPrev = pLast;
b62f651… stephan 1236 pLast = pNew;
b62f651… stephan 1237 }
b62f651… stephan 1238 if( pNew->eType==TT_EOF ) break;
b62f651… stephan 1239 }
b62f651… stephan 1240 if( pLast ) pLast->pNext = 0;
b62f651… stephan 1241 blockComment = 0;
b62f651… stephan 1242 if( nErr ){
b62f651… stephan 1243 FreeTokenList(pFirst);
b62f651… stephan 1244 pFirst = 0;
b62f651… stephan 1245 }
b62f651… stephan 1246
b62f651… stephan 1247 return pFirst;
b62f651… stephan 1248 }
b62f651… stephan 1249
b62f651… stephan 1250 #if TEST==1
b62f651… stephan 1251 /*
b62f651… stephan 1252 ** Use the following routine to test or debug the tokenizer.
b62f651… stephan 1253 */
b62f651… stephan 1254 void main(int argc, char **argv){
b62f651… stephan 1255 char *zFile;
b62f651… stephan 1256 Token *pList, *p;
b62f651… stephan 1257 IdentTable sTable;
b62f651… stephan 1258
b62f651… stephan 1259 if( argc!=2 ){
b62f651… stephan 1260 fprintf(stderr,"Usage: %s filename\n",*argv);
b62f651… stephan 1261 exit(1);
b62f651… stephan 1262 }
b62f651… stephan 1263 memset(&sTable,0,sizeof(sTable));
b62f651… stephan 1264 zFile = ReadFile(argv[1]);
b62f651… stephan 1265 if( zFile==0 ){
b62f651… stephan 1266 fprintf(stderr,"Can't read file \"%s\"\n",argv[1]);
b62f651… stephan 1267 exit(1);
b62f651… stephan 1268 }
b62f651… stephan 1269 pList = TokenizeFile(zFile,&sTable);
b62f651… stephan 1270 for(p=pList; p; p=p->pNext){
b62f651… stephan 1271 int j;
b62f651… stephan 1272 switch( p->eType ){
b62f651… stephan 1273 case TT_Space:
b62f651… stephan 1274 printf("%4d: Space\n",p->nLine);
b62f651… stephan 1275 break;
b62f651… stephan 1276 case TT_Id:
b62f651… stephan 1277 printf("%4d: Id %.*s\n",p->nLine,p->nText,p->zText);
b62f651… stephan 1278 break;
b62f651… stephan 1279 case TT_Preprocessor:
b62f651… stephan 1280 printf("%4d: Preprocessor %.*s\n",p->nLine,p->nText,p->zText);
b62f651… stephan 1281 break;
b62f651… stephan 1282 case TT_Comment:
b62f651… stephan 1283 printf("%4d: Comment\n",p->nLine);
b62f651… stephan 1284 break;
b62f651… stephan 1285 case TT_BlockComment:
b62f651… stephan 1286 printf("%4d: Block Comment\n",p->nLine);
b62f651… stephan 1287 break;
b62f651… stephan 1288 case TT_Number:
b62f651… stephan 1289 printf("%4d: Number %.*s\n",p->nLine,p->nText,p->zText);
b62f651… stephan 1290 break;
b62f651… stephan 1291 case TT_String:
b62f651… stephan 1292 printf("%4d: String %.*s\n",p->nLine,p->nText,p->zText);
b62f651… stephan 1293 break;
b62f651… stephan 1294 case TT_Other:
b62f651… stephan 1295 printf("%4d: Other %.*s\n",p->nLine,p->nText,p->zText);
b62f651… stephan 1296 break;
b62f651… stephan 1297 case TT_Braces:
b62f651… stephan 1298 for(j=0; j<p->nText && j<30 && p->zText[j]!='\n'; j++){}
b62f651… stephan 1299 printf("%4d: Braces %.*s...}\n",p->nLine,j,p->zText);
b62f651… stephan 1300 break;
b62f651… stephan 1301 case TT_EOF:
b62f651… stephan 1302 printf("%4d: End of file\n",p->nLine);
b62f651… stephan 1303 break;
b62f651… stephan 1304 default:
b62f651… stephan 1305 printf("%4d: type %d\n",p->nLine,p->eType);
b62f651… stephan 1306 break;
b62f651… stephan 1307 }
b62f651… stephan 1308 }
b62f651… stephan 1309 FreeTokenList(pList);
b62f651… stephan 1310 SafeFree(zFile);
b62f651… stephan 1311 IdentTablePrint(&sTable,stdout);
b62f651… stephan 1312 }
b62f651… stephan 1313 #endif
b62f651… stephan 1314
b62f651… stephan 1315 #ifdef DEBUG
b62f651… stephan 1316 /*
b62f651… stephan 1317 ** For debugging purposes, write out a list of tokens.
b62f651… stephan 1318 */
b62f651… stephan 1319 static void PrintTokens(Token *pFirst, Token *pLast){
b62f651… stephan 1320 int needSpace = 0;
b62f651… stephan 1321 int c;
b62f651… stephan 1322
b62f651… stephan 1323 pLast = pLast->pNext;
b62f651… stephan 1324 while( pFirst!=pLast ){
b62f651… stephan 1325 switch( pFirst->eType ){
b62f651… stephan 1326 case TT_Preprocessor:
b62f651… stephan 1327 printf("\n%.*s\n",pFirst->nText,pFirst->zText);
b62f651… stephan 1328 needSpace = 0;
b62f651… stephan 1329 break;
b62f651… stephan 1330
b62f651… stephan 1331 case TT_Id:
b62f651… stephan 1332 case TT_Number:
b62f651… stephan 1333 printf("%s%.*s", needSpace ? " " : "", pFirst->nText, pFirst->zText);
b62f651… stephan 1334 needSpace = 1;
b62f651… stephan 1335 break;
b62f651… stephan 1336
b62f651… stephan 1337 default:
b62f651… stephan 1338 c = pFirst->zText[0];
b62f651… stephan 1339 printf("%s%.*s",
b62f651… stephan 1340 (needSpace && (c=='*' || c=='{')) ? " " : "",
b62f651… stephan 1341 pFirst->nText, pFirst->zText);
b62f651… stephan 1342 needSpace = pFirst->zText[0]==',';
b62f651… stephan 1343 break;
b62f651… stephan 1344 }
b62f651… stephan 1345 pFirst = pFirst->pNext;
b62f651… stephan 1346 }
b62f651… stephan 1347 }
b62f651… stephan 1348 #endif
b62f651… stephan 1349
b62f651… stephan 1350 /*
b62f651… stephan 1351 ** Convert a sequence of tokens into a string and return a pointer
b62f651… stephan 1352 ** to that string. Space to hold the string is obtained from malloc()
b62f651… stephan 1353 ** and must be freed by the calling function.
b62f651… stephan 1354 **
b62f651… stephan 1355 ** Certain keywords (EXPORT, PRIVATE, PUBLIC, PROTECTED) are always
b62f651… stephan 1356 ** skipped.
b62f651… stephan 1357 **
b62f651… stephan 1358 ** If pSkip!=0 then skip over nSkip tokens beginning with pSkip.
b62f651… stephan 1359 **
b62f651… stephan 1360 ** If zTerm!=0 then append the text to the end.
b62f651… stephan 1361 */
b62f651… stephan 1362 static char *TokensToString(
b62f651… stephan 1363 Token *pFirst, /* First token in the string */
b62f651… stephan 1364 Token *pLast, /* Last token in the string */
b62f651… stephan 1365 char *zTerm, /* Terminate the string with this text if not NULL */
b62f651… stephan 1366 Token *pSkip, /* Skip this token if not NULL */
b62f651… stephan 1367 int nSkip /* Skip a total of this many tokens */
b62f651… stephan 1368 ){
b62f651… stephan 1369 char *zReturn;
b62f651… stephan 1370 String str;
b62f651… stephan 1371 int needSpace = 0;
b62f651… stephan 1372 int c;
b62f651… stephan 1373 int iSkip = 0;
b62f651… stephan 1374 int skipOne = 0;
b62f651… stephan 1375
b62f651… stephan 1376 StringInit(&str);
b62f651… stephan 1377 pLast = pLast->pNext;
b62f651… stephan 1378 while( pFirst!=pLast ){
b62f651… stephan 1379 if( pFirst==pSkip ){ iSkip = nSkip; }
b62f651… stephan 1380 if( iSkip>0 ){
b62f651… stephan 1381 iSkip--;
b62f651… stephan 1382 pFirst=pFirst->pNext;
b62f651… stephan 1383 continue;
b62f651… stephan 1384 }
b62f651… stephan 1385 switch( pFirst->eType ){
b62f651… stephan 1386 case TT_Preprocessor:
b62f651… stephan 1387 StringAppend(&str,"\n",1);
b62f651… stephan 1388 StringAppend(&str,pFirst->zText,pFirst->nText);
b62f651… stephan 1389 StringAppend(&str,"\n",1);
b62f651… stephan 1390 needSpace = 0;
b62f651… stephan 1391 break;
b62f651… stephan 1392
b62f651… stephan 1393 case TT_Id:
b62f651… stephan 1394 switch( pFirst->zText[0] ){
b62f651… stephan 1395 case 'E':
b62f651… stephan 1396 if( pFirst->nText==6 && strncmp(pFirst->zText,"EXPORT",6)==0 ){
b62f651… stephan 1397 skipOne = 1;
b62f651… stephan 1398 }
b62f651… stephan 1399 break;
b62f651… stephan 1400 case 'P':
b62f651… stephan 1401 switch( pFirst->nText ){
b62f651… stephan 1402 case 6: skipOne = !strncmp(pFirst->zText,"PUBLIC", 6); break;
b62f651… stephan 1403 case 7: skipOne = !strncmp(pFirst->zText,"PRIVATE",7); break;
b62f651… stephan 1404 case 9: skipOne = !strncmp(pFirst->zText,"PROTECTED",9); break;
b62f651… stephan 1405 default: break;
b62f651… stephan 1406 }
b62f651… stephan 1407 break;
b62f651… stephan 1408 default:
b62f651… stephan 1409 break;
b62f651… stephan 1410 }
b62f651… stephan 1411 if( skipOne ){
b62f651… stephan 1412 pFirst = pFirst->pNext;
b62f651… stephan 1413 skipOne = 0;
b62f651… stephan 1414 continue;
b62f651… stephan 1415 }
b62f651… stephan 1416 /* Fall thru to the next case */
b62f651… stephan 1417 case TT_Number:
b62f651… stephan 1418 if( needSpace ){
b62f651… stephan 1419 StringAppend(&str," ",1);
b62f651… stephan 1420 }
b62f651… stephan 1421 StringAppend(&str,pFirst->zText,pFirst->nText);
b62f651… stephan 1422 needSpace = 1;
b62f651… stephan 1423 break;
b62f651… stephan 1424
b62f651… stephan 1425 default:
b62f651… stephan 1426 c = pFirst->zText[0];
b62f651… stephan 1427 if( needSpace && (c=='*' || c=='{') ){
b62f651… stephan 1428 StringAppend(&str," ",1);
b62f651… stephan 1429 }
b62f651… stephan 1430 StringAppend(&str,pFirst->zText,pFirst->nText);
b62f651… stephan 1431 /* needSpace = pFirst->zText[0]==','; */
b62f651… stephan 1432 needSpace = 0;
b62f651… stephan 1433 break;
b62f651… stephan 1434 }
b62f651… stephan 1435 pFirst = pFirst->pNext;
b62f651… stephan 1436 }
b62f651… stephan 1437 if( zTerm && *zTerm ){
b62f651… stephan 1438 StringAppend(&str,zTerm,strlen(zTerm));
b62f651… stephan 1439 }
b62f651… stephan 1440 zReturn = StrDup(StringGet(&str),0);
b62f651… stephan 1441 StringReset(&str);
b62f651… stephan 1442 return zReturn;
b62f651… stephan 1443 }
b62f651… stephan 1444
b62f651… stephan 1445 /*
b62f651… stephan 1446 ** This routine is called when we see one of the keywords "struct",
b62f651… stephan 1447 ** "enum", "union" or "class". This might be the beginning of a
b62f651… stephan 1448 ** type declaration. This routine will process the declaration and
b62f651… stephan 1449 ** remove the declaration tokens from the input stream.
b62f651… stephan 1450 **
b62f651… stephan 1451 ** If this is a type declaration that is immediately followed by a
b62f651… stephan 1452 ** semicolon (in other words it isn't also a variable definition)
b62f651… stephan 1453 ** then set *pReset to ';'. Otherwise leave *pReset at 0. The
b62f651… stephan 1454 ** *pReset flag causes the parser to skip ahead to the next token
b62f651… stephan 1455 ** that begins with the value placed in the *pReset flag, if that
b62f651… stephan 1456 ** value is different from 0.
b62f651… stephan 1457 */
b62f651… stephan 1458 static int ProcessTypeDecl(Token *pList, int flags, int *pReset){
b62f651… stephan 1459 Token *pName, *pEnd;
b62f651… stephan 1460 Decl *pDecl;
b62f651… stephan 1461 String str;
b62f651… stephan 1462 int need_to_collapse = 1;
b62f651… stephan 1463 int type = 0;
b62f651… stephan 1464
b62f651… stephan 1465 *pReset = 0;
b62f651… stephan 1466 if( pList==0 || pList->pNext==0 || pList->pNext->eType!=TT_Id ){
b62f651… stephan 1467 return 0;
b62f651… stephan 1468 }
b62f651… stephan 1469 pName = pList->pNext;
b62f651… stephan 1470
b62f651… stephan 1471 /* Catch the case of "struct Foo;" and skip it. */
b62f651… stephan 1472 if( pName->pNext && pName->pNext->zText[0]==';' ){
b62f651… stephan 1473 *pReset = ';';
b62f651… stephan 1474 return 0;
b62f651… stephan 1475 }
b62f651… stephan 1476
b62f651… stephan 1477 for(pEnd=pName->pNext; pEnd && pEnd->eType!=TT_Braces; pEnd=pEnd->pNext){
b62f651… stephan 1478 switch( pEnd->zText[0] ){
b62f651… stephan 1479 case '(':
b62f651… stephan 1480 case ')':
b62f651… stephan 1481 case '*':
b62f651… stephan 1482 case '[':
b62f651… stephan 1483 case '=':
b62f651… stephan 1484 case ';':
b62f651… stephan 1485 return 0;
b62f651… stephan 1486 }
b62f651… stephan 1487 }
b62f651… stephan 1488 if( pEnd==0 ){
b62f651… stephan 1489 return 0;
b62f651… stephan 1490 }
b62f651… stephan 1491
b62f651… stephan 1492 /*
b62f651… stephan 1493 ** At this point, we know we have a type declaration that is bounded
b62f651… stephan 1494 ** by pList and pEnd and has the name pName.
b62f651… stephan 1495 */
b62f651… stephan 1496
b62f651… stephan 1497 /*
b62f651… stephan 1498 ** If the braces are followed immediately by a semicolon, then we are
b62f651… stephan 1499 ** dealing a type declaration only. There is not variable definition
b62f651… stephan 1500 ** following the type declaration. So reset...
b62f651… stephan 1501 */
b62f651… stephan 1502 if( pEnd->pNext==0 || pEnd->pNext->zText[0]==';' ){
b62f651… stephan 1503 *pReset = ';';
b62f651… stephan 1504 need_to_collapse = 0;
b62f651… stephan 1505 }else{
b62f651… stephan 1506 need_to_collapse = 1;
b62f651… stephan 1507 }
b62f651… stephan 1508
b62f651… stephan 1509 if( proto_static==0 && (flags & (PS_Local|PS_Export|PS_Interface))==0 ){
b62f651… stephan 1510 /* Ignore these objects unless they are explicitly declared as interface,
b62f651… stephan 1511 ** or unless the "-local" command line option was specified. */
b62f651… stephan 1512 *pReset = ';';
b62f651… stephan 1513 return 0;
b62f651… stephan 1514 }
b62f651… stephan 1515
b62f651… stephan 1516 #ifdef DEBUG
b62f651… stephan 1517 if( debugMask & PARSER ){
b62f651… stephan 1518 printf("**** Found type: %.*s %.*s...\n",
b62f651… stephan 1519 pList->nText, pList->zText, pName->nText, pName->zText);
b62f651… stephan 1520 PrintTokens(pList,pEnd);
b62f651… stephan 1521 printf(";\n");
b62f651… stephan 1522 }
b62f651… stephan 1523 #endif
b62f651… stephan 1524
b62f651… stephan 1525 /*
b62f651… stephan 1526 ** Create a new Decl object for this definition. Actually, if this
b62f651… stephan 1527 ** is a C++ class definition, then the Decl object might already exist,
b62f651… stephan 1528 ** so check first for that case before creating a new one.
b62f651… stephan 1529 */
b62f651… stephan 1530 switch( *pList->zText ){
b62f651… stephan 1531 case 'c': type = TY_Class; break;
b62f651… stephan 1532 case 's': type = TY_Structure; break;
b62f651… stephan 1533 case 'e': type = TY_Enumeration; break;
b62f651… stephan 1534 case 'u': type = TY_Union; break;
b62f651… stephan 1535 default: /* Can't Happen */ break;
b62f651… stephan 1536 }
b62f651… stephan 1537 if( type!=TY_Class ){
b62f651… stephan 1538 pDecl = 0;
b62f651… stephan 1539 }else{
b62f651… stephan 1540 pDecl = FindDecl(pName->zText, pName->nText);
b62f651… stephan 1541 if( pDecl && (pDecl->flags & type)!=type ) pDecl = 0;
b62f651… stephan 1542 }
b62f651… stephan 1543 if( pDecl==0 ){
b62f651… stephan 1544 pDecl = CreateDecl(pName->zText,pName->nText);
b62f651… stephan 1545 }
b62f651… stephan 1546 if( (flags & PS_Static) || !(flags & (PS_Interface|PS_Export)) ){
b62f651… stephan 1547 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 1548 }
b62f651… stephan 1549 DeclSetProperty(pDecl,type);
b62f651… stephan 1550
b62f651… stephan 1551 /* The object has a full declaration only if it is contained within
b62f651… stephan 1552 ** "#if INTERFACE...#endif" or "#if EXPORT_INTERFACE...#endif" or
b62f651… stephan 1553 ** "#if LOCAL_INTERFACE...#endif". Otherwise, we only give it a
b62f651… stephan 1554 ** forward declaration.
b62f651… stephan 1555 */
b62f651… stephan 1556 if( flags & (PS_Local | PS_Export | PS_Interface) ){
b62f651… stephan 1557 pDecl->zDecl = TokensToString(pList,pEnd,";\n",0,0);
b62f651… stephan 1558 }else{
b62f651… stephan 1559 pDecl->zDecl = 0;
b62f651… stephan 1560 }
b62f651… stephan 1561 pDecl->pComment = pList->pComment;
b62f651… stephan 1562 StringInit(&str);
b62f651… stephan 1563 StringAppend(&str,"typedef ",0);
b62f651… stephan 1564 StringAppend(&str,pList->zText,pList->nText);
b62f651… stephan 1565 StringAppend(&str," ",0);
b62f651… stephan 1566 StringAppend(&str,pName->zText,pName->nText);
b62f651… stephan 1567 StringAppend(&str," ",0);
b62f651… stephan 1568 StringAppend(&str,pName->zText,pName->nText);
b62f651… stephan 1569 StringAppend(&str,";\n",2);
b62f651… stephan 1570 pDecl->zFwd = StrDup(StringGet(&str),0);
b62f651… stephan 1571 StringReset(&str);
b62f651… stephan 1572 StringInit(&str);
b62f651… stephan 1573 StringAppend(&str,pList->zText,pList->nText);
b62f651… stephan 1574 StringAppend(&str," ",0);
b62f651… stephan 1575 StringAppend(&str,pName->zText,pName->nText);
b62f651… stephan 1576 StringAppend(&str,";\n",2);
b62f651… stephan 1577 pDecl->zFwdCpp = StrDup(StringGet(&str),0);
b62f651… stephan 1578 StringReset(&str);
b62f651… stephan 1579 if( flags & PS_Export ){
b62f651… stephan 1580 DeclSetProperty(pDecl,DP_Export);
b62f651… stephan 1581 }else if( flags & PS_Local ){
b62f651… stephan 1582 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 1583 }
b62f651… stephan 1584
b62f651… stephan 1585 /* Here's something weird. ANSI-C doesn't allow a forward declaration
b62f651… stephan 1586 ** of an enumeration. So we have to build the typedef into the
b62f651… stephan 1587 ** definition.
b62f651… stephan 1588 */
b62f651… stephan 1589 if( pDecl->zDecl && DeclHasProperty(pDecl, TY_Enumeration) ){
b62f651… stephan 1590 StringInit(&str);
b62f651… stephan 1591 StringAppend(&str,pDecl->zDecl,0);
b62f651… stephan 1592 StringAppend(&str,pDecl->zFwd,0);
b62f651… stephan 1593 SafeFree(pDecl->zDecl);
b62f651… stephan 1594 SafeFree(pDecl->zFwd);
b62f651… stephan 1595 pDecl->zFwd = 0;
b62f651… stephan 1596 pDecl->zDecl = StrDup(StringGet(&str),0);
b62f651… stephan 1597 StringReset(&str);
b62f651… stephan 1598 }
b62f651… stephan 1599
b62f651… stephan 1600 if( pName->pNext->zText[0]==':' ){
b62f651… stephan 1601 DeclSetProperty(pDecl,DP_Cplusplus);
b62f651… stephan 1602 }
b62f651… stephan 1603 if( pName->nText==5 && strncmp(pName->zText,"class",5)==0 ){
b62f651… stephan 1604 DeclSetProperty(pDecl,DP_Cplusplus);
b62f651… stephan 1605 }
b62f651… stephan 1606
b62f651… stephan 1607 /*
b62f651… stephan 1608 ** Remove all but pList and pName from the input stream.
b62f651… stephan 1609 */
b62f651… stephan 1610 if( need_to_collapse ){
b62f651… stephan 1611 while( pEnd!=pName ){
b62f651… stephan 1612 Token *pPrev = pEnd->pPrev;
b62f651… stephan 1613 pPrev->pNext = pEnd->pNext;
b62f651… stephan 1614 pEnd->pNext->pPrev = pPrev;
b62f651… stephan 1615 SafeFree(pEnd);
b62f651… stephan 1616 pEnd = pPrev;
b62f651… stephan 1617 }
b62f651… stephan 1618 }
b62f651… stephan 1619 return 0;
b62f651… stephan 1620 }
b62f651… stephan 1621
b62f651… stephan 1622 /*
b62f651… stephan 1623 ** Given a list of tokens that declare something (a function, procedure,
b62f651… stephan 1624 ** variable or typedef) find the token which contains the name of the
b62f651… stephan 1625 ** thing being declared.
b62f651… stephan 1626 **
b62f651… stephan 1627 ** Algorithm:
b62f651… stephan 1628 **
b62f651… stephan 1629 ** The name is:
b62f651… stephan 1630 **
b62f651… stephan 1631 ** 1. The first identifier that is followed by a "[", or
b62f651… stephan 1632 **
b62f651… stephan 1633 ** 2. The first identifier that is followed by a "(" where the
b62f651… stephan 1634 ** "(" is followed by another identifier, or
b62f651… stephan 1635 **
b62f651… stephan 1636 ** 3. The first identifier followed by "::", or
b62f651… stephan 1637 **
b62f651… stephan 1638 ** 4. If none of the above, then the last identifier.
b62f651… stephan 1639 **
b62f651… stephan 1640 ** In all of the above, certain reserved words (like "char") are
b62f651… stephan 1641 ** not considered identifiers.
b62f651… stephan 1642 */
b62f651… stephan 1643 static Token *FindDeclName(Token *pFirst, Token *pLast){
b62f651… stephan 1644 Token *pName = 0;
b62f651… stephan 1645 Token *p;
b62f651… stephan 1646 int c;
b62f651… stephan 1647
b62f651… stephan 1648 if( pFirst==0 || pLast==0 ){
b62f651… stephan 1649 return 0;
b62f651… stephan 1650 }
b62f651… stephan 1651 pLast = pLast->pNext;
b62f651… stephan 1652 for(p=pFirst; p && p!=pLast; p=p->pNext){
b62f651… stephan 1653 if( p->eType==TT_Id ){
b62f651… stephan 1654 static IdentTable sReserved;
b62f651… stephan 1655 static int isInit = 0;
b62f651… stephan 1656 static const char *aWords[] = { "char", "class",
b62f651… stephan 1657 "const", "double", "enum", "extern", "EXPORT", "ET_PROC",
b62f651… stephan 1658 "float", "int", "long",
b62f651… stephan 1659 "PRIVATE", "PROTECTED", "PUBLIC",
b62f651… stephan 1660 "register", "static", "struct", "sizeof", "signed", "typedef",
b62f651… stephan 1661 "union", "volatile", "virtual", "void", };
b62f651… stephan 1662
b62f651… stephan 1663 if( !isInit ){
b62f651… stephan 1664 int i;
b62f651… stephan 1665 for(i=0; i<sizeof(aWords)/sizeof(aWords[0]); i++){
b62f651… stephan 1666 IdentTableInsert(&sReserved,aWords[i],0);
b62f651… stephan 1667 }
b62f651… stephan 1668 isInit = 1;
b62f651… stephan 1669 }
b62f651… stephan 1670 if( !IdentTableTest(&sReserved,p->zText,p->nText) ){
b62f651… stephan 1671 pName = p;
b62f651… stephan 1672 }
b62f651… stephan 1673 }else if( p==pFirst ){
b62f651… stephan 1674 continue;
b62f651… stephan 1675 }else if( (c=p->zText[0])=='[' && pName ){
b62f651… stephan 1676 break;
b62f651… stephan 1677 }else if( c=='(' && p->pNext && p->pNext->eType==TT_Id && pName ){
b62f651… stephan 1678 break;
b62f651… stephan 1679 }else if( c==':' && p->zText[1]==':' && pName ){
b62f651… stephan 1680 break;
b62f651… stephan 1681 }
b62f651… stephan 1682 }
b62f651… stephan 1683 return pName;
b62f651… stephan 1684 }
b62f651… stephan 1685
b62f651… stephan 1686 /*
b62f651… stephan 1687 ** This routine is called when we see a method for a class that begins
b62f651… stephan 1688 ** with the PUBLIC, PRIVATE, or PROTECTED keywords. Such methods are
b62f651… stephan 1689 ** added to their class definitions.
b62f651… stephan 1690 */
b62f651… stephan 1691 static int ProcessMethodDef(Token *pFirst, Token *pLast, int flags){
b62f651… stephan 1692 Token *pClass;
b62f651… stephan 1693 char *zDecl;
b62f651… stephan 1694 Decl *pDecl;
b62f651… stephan 1695 String str;
b62f651… stephan 1696 int type;
b62f651… stephan 1697
b62f651… stephan 1698 pLast = pLast->pPrev;
b62f651… stephan 1699 while( pFirst->zText[0]=='P' ){
b62f651… stephan 1700 int rc = 1;
b62f651… stephan 1701 switch( pFirst->nText ){
b62f651… stephan 1702 case 6: rc = strncmp(pFirst->zText,"PUBLIC",6); break;
b62f651… stephan 1703 case 7: rc = strncmp(pFirst->zText,"PRIVATE",7); break;
b62f651… stephan 1704 case 9: rc = strncmp(pFirst->zText,"PROTECTED",9); break;
b62f651… stephan 1705 default: break;
b62f651… stephan 1706 }
b62f651… stephan 1707 if( rc ) break;
b62f651… stephan 1708 pFirst = pFirst->pNext;
b62f651… stephan 1709 }
b62f651… stephan 1710 pClass = FindDeclName(pFirst,pLast);
b62f651… stephan 1711 if( pClass==0 ){
b62f651… stephan 1712 fprintf(stderr,"%s:%d: Unable to find the class name for this method\n",
b62f651… stephan 1713 zFilename, pFirst->nLine);
b62f651… stephan 1714 return 1;
b62f651… stephan 1715 }
b62f651… stephan 1716 pDecl = FindDecl(pClass->zText, pClass->nText);
b62f651… stephan 1717 if( pDecl==0 || (pDecl->flags & TY_Class)!=TY_Class ){
b62f651… stephan 1718 pDecl = CreateDecl(pClass->zText, pClass->nText);
b62f651… stephan 1719 DeclSetProperty(pDecl, TY_Class);
b62f651… stephan 1720 }
b62f651… stephan 1721 StringInit(&str);
b62f651… stephan 1722 if( pDecl->zExtra ){
b62f651… stephan 1723 StringAppend(&str, pDecl->zExtra, 0);
b62f651… stephan 1724 SafeFree(pDecl->zExtra);
b62f651… stephan 1725 pDecl->zExtra = 0;
b62f651… stephan 1726 }
b62f651… stephan 1727 type = flags & PS_PPP;
b62f651… stephan 1728 if( pDecl->extraType!=type ){
b62f651… stephan 1729 if( type & PS_Public ){
b62f651… stephan 1730 StringAppend(&str, "public:\n", 0);
b62f651… stephan 1731 pDecl->extraType = PS_Public;
b62f651… stephan 1732 }else if( type & PS_Protected ){
b62f651… stephan 1733 StringAppend(&str, "protected:\n", 0);
b62f651… stephan 1734 pDecl->extraType = PS_Protected;
b62f651… stephan 1735 }else if( type & PS_Private ){
b62f651… stephan 1736 StringAppend(&str, "private:\n", 0);
b62f651… stephan 1737 pDecl->extraType = PS_Private;
b62f651… stephan 1738 }
b62f651… stephan 1739 }
b62f651… stephan 1740 StringAppend(&str, " ", 0);
b62f651… stephan 1741 zDecl = TokensToString(pFirst, pLast, ";\n", pClass, 2);
b62f651… stephan 1742 if(strncmp(zDecl, pClass->zText, pClass->nText)==0){
b62f651… stephan 1743 /* If member initializer list is found after a constructor,
b62f651… stephan 1744 ** skip that part. */
b62f651… stephan 1745 char * colon = strchr(zDecl, ':');
b62f651… stephan 1746 if(colon!=0 && colon[1]!=0){
b62f651… stephan 1747 *colon++ = ';';
b62f651… stephan 1748 *colon++ = '\n';
b62f651… stephan 1749 *colon = 0;
b62f651… stephan 1750 }
b62f651… stephan 1751 }
b62f651… stephan 1752 StringAppend(&str, zDecl, 0);
b62f651… stephan 1753 SafeFree(zDecl);
b62f651… stephan 1754 pDecl->zExtra = StrDup(StringGet(&str), 0);
b62f651… stephan 1755 StringReset(&str);
b62f651… stephan 1756 return 0;
b62f651… stephan 1757 }
b62f651… stephan 1758
b62f651… stephan 1759 /*
b62f651… stephan 1760 ** This routine is called when we see a function or procedure definition.
b62f651… stephan 1761 ** We make an entry in the declaration table that is a prototype for this
b62f651… stephan 1762 ** function or procedure.
b62f651… stephan 1763 */
b62f651… stephan 1764 static int ProcessProcedureDef(Token *pFirst, Token *pLast, int flags){
b62f651… stephan 1765 Token *pName;
b62f651… stephan 1766 Decl *pDecl;
b62f651… stephan 1767 Token *pCode;
b62f651… stephan 1768
b62f651… stephan 1769 if( pFirst==0 || pLast==0 ){
b62f651… stephan 1770 return 0;
b62f651… stephan 1771 }
b62f651… stephan 1772 if( flags & PS_Method ){
b62f651… stephan 1773 if( flags & PS_PPP ){
b62f651… stephan 1774 return ProcessMethodDef(pFirst, pLast, flags);
b62f651… stephan 1775 }else{
b62f651… stephan 1776 return 0;
b62f651… stephan 1777 }
b62f651… stephan 1778 }
b62f651… stephan 1779 if( (flags & PS_Static)!=0 && !proto_static ){
b62f651… stephan 1780 return 0;
b62f651… stephan 1781 }
b62f651… stephan 1782 pCode = pLast;
b62f651… stephan 1783 while( pLast && pLast!=pFirst && pLast->zText[0]!=')' ){
b62f651… stephan 1784 pLast = pLast->pPrev;
b62f651… stephan 1785 }
b62f651… stephan 1786 if( pLast==0 || pLast==pFirst || pFirst->pNext==pLast ){
b62f651… stephan 1787 fprintf(stderr,"%s:%d: Unrecognized syntax.\n",
b62f651… stephan 1788 zFilename, pFirst->nLine);
b62f651… stephan 1789 return 1;
b62f651… stephan 1790 }
b62f651… stephan 1791 if( flags & (PS_Interface|PS_Export|PS_Local) ){
b62f651… stephan 1792 fprintf(stderr,"%s:%d: Missing \"inline\" on function or procedure.\n",
b62f651… stephan 1793 zFilename, pFirst->nLine);
b62f651… stephan 1794 return 1;
b62f651… stephan 1795 }
b62f651… stephan 1796 pName = FindDeclName(pFirst,pLast);
b62f651… stephan 1797 if( pName==0 ){
b62f651… stephan 1798 fprintf(stderr,"%s:%d: Malformed function or procedure definition.\n",
b62f651… stephan 1799 zFilename, pFirst->nLine);
b62f651… stephan 1800 return 1;
b62f651… stephan 1801 }
b62f651… stephan 1802 if( strncmp(pName->zText,"main",pName->nText)==0 ){
b62f651… stephan 1803 /* skip main() decl. */
b62f651… stephan 1804 return 0;
b62f651… stephan 1805 }
b62f651… stephan 1806 /*
b62f651… stephan 1807 ** At this point we've isolated a procedure declaration between pFirst
b62f651… stephan 1808 ** and pLast with the name pName.
b62f651… stephan 1809 */
b62f651… stephan 1810 #ifdef DEBUG
b62f651… stephan 1811 if( debugMask & PARSER ){
b62f651… stephan 1812 printf("**** Found routine: %.*s on line %d...\n", pName->nText,
b62f651… stephan 1813 pName->zText, pFirst->nLine);
b62f651… stephan 1814 PrintTokens(pFirst,pLast);
b62f651… stephan 1815 printf(";\n");
b62f651… stephan 1816 }
b62f651… stephan 1817 #endif
b62f651… stephan 1818 pDecl = CreateDecl(pName->zText,pName->nText);
b62f651… stephan 1819 pDecl->pComment = pFirst->pComment;
b62f651… stephan 1820 if( pCode && pCode->eType==TT_Braces ){
b62f651… stephan 1821 pDecl->tokenCode = *pCode;
b62f651… stephan 1822 }
b62f651… stephan 1823 DeclSetProperty(pDecl,TY_Subroutine);
b62f651… stephan 1824 pDecl->zDecl = TokensToString(pFirst,pLast,";\n",0,0);
b62f651… stephan 1825 if( (flags & (PS_Static|PS_Local2))!=0 ){
b62f651… stephan 1826 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 1827 }else if( (flags & (PS_Export2))!=0 ){
b62f651… stephan 1828 DeclSetProperty(pDecl,DP_Export);
b62f651… stephan 1829 }
b62f651… stephan 1830
b62f651… stephan 1831 if( flags & DP_Cplusplus ){
b62f651… stephan 1832 DeclSetProperty(pDecl,DP_Cplusplus);
b62f651… stephan 1833 }else{
b62f651… stephan 1834 DeclSetProperty(pDecl,DP_ExternCReqd);
b62f651… stephan 1835 }
b62f651… stephan 1836
b62f651… stephan 1837 return 0;
b62f651… stephan 1838 }
b62f651… stephan 1839
b62f651… stephan 1840 /*
b62f651… stephan 1841 ** This routine is called whenever we see the "inline" keyword. We
b62f651… stephan 1842 ** need to seek-out the inline function or procedure and make a
b62f651… stephan 1843 ** declaration out of the entire definition.
b62f651… stephan 1844 */
b62f651… stephan 1845 static int ProcessInlineProc(Token *pFirst, int flags, int *pReset){
b62f651… stephan 1846 Token *pName;
b62f651… stephan 1847 Token *pEnd;
b62f651… stephan 1848 Decl *pDecl;
b62f651… stephan 1849
b62f651… stephan 1850 for(pEnd=pFirst; pEnd; pEnd = pEnd->pNext){
b62f651… stephan 1851 if( pEnd->zText[0]=='{' || pEnd->zText[0]==';' ){
b62f651… stephan 1852 *pReset = pEnd->zText[0];
b62f651… stephan 1853 break;
b62f651… stephan 1854 }
b62f651… stephan 1855 }
b62f651… stephan 1856 if( pEnd==0 ){
b62f651… stephan 1857 *pReset = ';';
b62f651… stephan 1858 fprintf(stderr,"%s:%d: incomplete inline procedure definition\n",
b62f651… stephan 1859 zFilename, pFirst->nLine);
b62f651… stephan 1860 return 1;
b62f651… stephan 1861 }
b62f651… stephan 1862 pName = FindDeclName(pFirst,pEnd);
b62f651… stephan 1863 if( pName==0 ){
b62f651… stephan 1864 fprintf(stderr,"%s:%d: malformed inline procedure definition\n",
b62f651… stephan 1865 zFilename, pFirst->nLine);
b62f651… stephan 1866 return 1;
b62f651… stephan 1867 }
b62f651… stephan 1868
b62f651… stephan 1869 #ifdef DEBUG
b62f651… stephan 1870 if( debugMask & PARSER ){
b62f651… stephan 1871 printf("**** Found inline routine: %.*s on line %d...\n",
b62f651… stephan 1872 pName->nText, pName->zText, pFirst->nLine);
b62f651… stephan 1873 PrintTokens(pFirst,pEnd);
b62f651… stephan 1874 printf("\n");
b62f651… stephan 1875 }
b62f651… stephan 1876 #endif
b62f651… stephan 1877 pDecl = CreateDecl(pName->zText,pName->nText);
b62f651… stephan 1878 pDecl->pComment = pFirst->pComment;
b62f651… stephan 1879 DeclSetProperty(pDecl,TY_Subroutine);
b62f651… stephan 1880 pDecl->zDecl = TokensToString(pFirst,pEnd,";\n",0,0);
b62f651… stephan 1881 if( (flags & (PS_Static|PS_Local|PS_Local2)) ){
b62f651… stephan 1882 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 1883 }else if( flags & (PS_Export|PS_Export2) ){
b62f651… stephan 1884 DeclSetProperty(pDecl,DP_Export);
b62f651… stephan 1885 }
b62f651… stephan 1886
b62f651… stephan 1887 if( flags & DP_Cplusplus ){
b62f651… stephan 1888 DeclSetProperty(pDecl,DP_Cplusplus);
b62f651… stephan 1889 }else{
b62f651… stephan 1890 DeclSetProperty(pDecl,DP_ExternCReqd);
b62f651… stephan 1891 }
b62f651… stephan 1892
b62f651… stephan 1893 return 0;
b62f651… stephan 1894 }
b62f651… stephan 1895
b62f651… stephan 1896 /*
b62f651… stephan 1897 ** Determine if the tokens between pFirst and pEnd form a variable
b62f651… stephan 1898 ** definition or a function prototype. Return TRUE if we are dealing
b62f651… stephan 1899 ** with a variable defintion and FALSE for a prototype.
b62f651… stephan 1900 **
b62f651… stephan 1901 ** pEnd is the token that ends the object. It can be either a ';' or
b62f651… stephan 1902 ** a '='. If it is '=', then assume we have a variable definition.
b62f651… stephan 1903 **
b62f651… stephan 1904 ** If pEnd is ';', then the determination is more difficult. We have
b62f651… stephan 1905 ** to search for an occurrence of an ID followed immediately by '('.
b62f651… stephan 1906 ** If found, we have a prototype. Otherwise we are dealing with a
b62f651… stephan 1907 ** variable definition.
b62f651… stephan 1908 */
b62f651… stephan 1909 static int isVariableDef(Token *pFirst, Token *pEnd){
b62f651… stephan 1910 if( pEnd && pEnd->zText[0]=='=' &&
b62f651… stephan 1911 (pEnd->pPrev->nText!=8 || strncmp(pEnd->pPrev->zText,"operator",8)!=0)
b62f651… stephan 1912 ){
b62f651… stephan 1913 return 1;
b62f651… stephan 1914 }
b62f651… stephan 1915 while( pFirst && pFirst!=pEnd && pFirst->pNext && pFirst->pNext!=pEnd ){
b62f651… stephan 1916 if( pFirst->eType==TT_Id && pFirst->pNext->zText[0]=='(' ){
b62f651… stephan 1917 return 0;
b62f651… stephan 1918 }
b62f651… stephan 1919 pFirst = pFirst->pNext;
b62f651… stephan 1920 }
b62f651… stephan 1921 return 1;
b62f651… stephan 1922 }
b62f651… stephan 1923
b62f651… stephan 1924 /*
b62f651… stephan 1925 ** Return TRUE if pFirst is the first token of a static assert.
b62f651… stephan 1926 */
b62f651… stephan 1927 static int isStaticAssert(Token *pFirst){
b62f651… stephan 1928 if( (pFirst->nText==13 && strncmp(pFirst->zText, "static_assert", 13)==0)
b62f651… stephan 1929 || (pFirst->nText==14 && strncmp(pFirst->zText, "_Static_assert", 14)==0)
b62f651… stephan 1930 ){
b62f651… stephan 1931 return 1;
b62f651… stephan 1932 }else{
b62f651… stephan 1933 return 0;
b62f651… stephan 1934 }
b62f651… stephan 1935 }
b62f651… stephan 1936
b62f651… stephan 1937 /*
b62f651… stephan 1938 ** This routine is called whenever we encounter a ";" or "=". The stuff
b62f651… stephan 1939 ** between pFirst and pLast constitutes either a typedef or a global
b62f651… stephan 1940 ** variable definition. Do the right thing.
b62f651… stephan 1941 */
b62f651… stephan 1942 static int ProcessDecl(Token *pFirst, Token *pEnd, int flags){
b62f651… stephan 1943 Token *pName;
b62f651… stephan 1944 Decl *pDecl;
b62f651… stephan 1945 int isLocal = 0;
b62f651… stephan 1946 int isVar;
b62f651… stephan 1947 int nErr = 0;
b62f651… stephan 1948
b62f651… stephan 1949 if( pFirst==0 || pEnd==0 ){
b62f651… stephan 1950 return 0;
b62f651… stephan 1951 }
b62f651… stephan 1952 if( flags & PS_Typedef ){
b62f651… stephan 1953 if( (flags & (PS_Export2|PS_Local2))!=0 ){
b62f651… stephan 1954 fprintf(stderr,"%s:%d: \"EXPORT\" or \"LOCAL\" ignored before typedef.\n",
b62f651… stephan 1955 zFilename, pFirst->nLine);
b62f651… stephan 1956 nErr++;
b62f651… stephan 1957 }
b62f651… stephan 1958 if( (flags & (PS_Interface|PS_Export|PS_Local|DP_Cplusplus))==0 ){
b62f651… stephan 1959 /* It is illegal to duplicate a typedef in C (but OK in C++).
b62f651… stephan 1960 ** So don't record typedefs that aren't within a C++ file or
b62f651… stephan 1961 ** within #if INTERFACE..#endif */
b62f651… stephan 1962 return nErr;
b62f651… stephan 1963 }
b62f651… stephan 1964 if( (flags & (PS_Interface|PS_Export|PS_Local))==0 && proto_static==0 ){
b62f651… stephan 1965 /* Ignore typedefs that are not with "#if INTERFACE..#endif" unless
b62f651… stephan 1966 ** the "-local" command line option is used. */
b62f651… stephan 1967 return nErr;
b62f651… stephan 1968 }
b62f651… stephan 1969 if( (flags & (PS_Interface|PS_Export))==0 ){
b62f651… stephan 1970 /* typedefs are always local, unless within #if INTERFACE..#endif */
b62f651… stephan 1971 isLocal = 1;
b62f651… stephan 1972 }
b62f651… stephan 1973 }else if( flags & (PS_Static|PS_Local2) ){
b62f651… stephan 1974 if( proto_static==0 && (flags & PS_Local2)==0 ){
b62f651… stephan 1975 /* Don't record static variables unless the "-local" command line
b62f651… stephan 1976 ** option was specified or the "LOCAL" keyword is used. */
b62f651… stephan 1977 return nErr;
b62f651… stephan 1978 }
b62f651… stephan 1979 while( pFirst!=0 && pFirst->pNext!=pEnd &&
b62f651… stephan 1980 ((pFirst->nText==6 && strncmp(pFirst->zText,"static",6)==0)
b62f651… stephan 1981 || (pFirst->nText==5 && strncmp(pFirst->zText,"LOCAL",6)==0))
b62f651… stephan 1982 ){
b62f651… stephan 1983 /* Lose the initial "static" or local from local variables.
b62f651… stephan 1984 ** We'll prepend "extern" later. */
b62f651… stephan 1985 pFirst = pFirst->pNext;
b62f651… stephan 1986 isLocal = 1;
b62f651… stephan 1987 }
b62f651… stephan 1988 if( pFirst==0 || !isLocal ){
b62f651… stephan 1989 return nErr;
b62f651… stephan 1990 }
b62f651… stephan 1991 }else if( flags & PS_Method ){
b62f651… stephan 1992 /* Methods are declared by their class. Don't declare separately. */
b62f651… stephan 1993 return nErr;
b62f651… stephan 1994 }else if( isStaticAssert(pFirst) ){
b62f651… stephan 1995 return 0;
b62f651… stephan 1996 }
b62f651… stephan 1997 isVar = (flags & (PS_Typedef|PS_Method))==0 && isVariableDef(pFirst,pEnd);
b62f651… stephan 1998 if( isVar && (flags & (PS_Interface|PS_Export|PS_Local))!=0
b62f651… stephan 1999 && (flags & PS_Extern)==0 ){
b62f651… stephan 2000 fprintf(stderr,"%s:%d: Can't define a variable in this context\n",
b62f651… stephan 2001 zFilename, pFirst->nLine);
b62f651… stephan 2002 nErr++;
b62f651… stephan 2003 }
b62f651… stephan 2004 pName = FindDeclName(pFirst,pEnd->pPrev);
b62f651… stephan 2005 if( pName==0 ){
b62f651… stephan 2006 if( pFirst->nText==4 && strncmp(pFirst->zText,"enum",4)==0 ){
b62f651… stephan 2007 /* Ignore completely anonymous enums. See documentation section 3.8.1. */
b62f651… stephan 2008 return nErr;
b62f651… stephan 2009 }else{
b62f651… stephan 2010 fprintf(stderr,"%s:%d: Can't find a name for the object declared here.\n",
b62f651… stephan 2011 zFilename, pFirst->nLine);
b62f651… stephan 2012 return nErr+1;
b62f651… stephan 2013 }
b62f651… stephan 2014 }
b62f651… stephan 2015
b62f651… stephan 2016 #ifdef DEBUG
b62f651… stephan 2017 if( debugMask & PARSER ){
b62f651… stephan 2018 if( flags & PS_Typedef ){
b62f651… stephan 2019 printf("**** Found typedef %.*s at line %d...\n",
b62f651… stephan 2020 pName->nText, pName->zText, pName->nLine);
b62f651… stephan 2021 }else if( isVar ){
b62f651… stephan 2022 printf("**** Found variable %.*s at line %d...\n",
b62f651… stephan 2023 pName->nText, pName->zText, pName->nLine);
b62f651… stephan 2024 }else{
b62f651… stephan 2025 printf("**** Found prototype %.*s at line %d...\n",
b62f651… stephan 2026 pName->nText, pName->zText, pName->nLine);
b62f651… stephan 2027 }
b62f651… stephan 2028 PrintTokens(pFirst,pEnd->pPrev);
b62f651… stephan 2029 printf(";\n");
b62f651… stephan 2030 }
b62f651… stephan 2031 #endif
b62f651… stephan 2032
b62f651… stephan 2033 pDecl = CreateDecl(pName->zText,pName->nText);
b62f651… stephan 2034 if( (flags & PS_Typedef) ){
b62f651… stephan 2035 DeclSetProperty(pDecl, TY_Typedef);
b62f651… stephan 2036 }else if( isVar ){
b62f651… stephan 2037 DeclSetProperty(pDecl,DP_ExternReqd | TY_Variable);
b62f651… stephan 2038 if( !(flags & DP_Cplusplus) ){
b62f651… stephan 2039 DeclSetProperty(pDecl,DP_ExternCReqd);
b62f651… stephan 2040 }
b62f651… stephan 2041 }else{
b62f651… stephan 2042 DeclSetProperty(pDecl, TY_Subroutine);
b62f651… stephan 2043 if( !(flags & DP_Cplusplus) ){
b62f651… stephan 2044 DeclSetProperty(pDecl,DP_ExternCReqd);
b62f651… stephan 2045 }
b62f651… stephan 2046 }
b62f651… stephan 2047 pDecl->pComment = pFirst->pComment;
b62f651… stephan 2048 pDecl->zDecl = TokensToString(pFirst,pEnd->pPrev,";\n",0,0);
b62f651… stephan 2049 if( isLocal || (flags & (PS_Local|PS_Local2))!=0 ){
b62f651… stephan 2050 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 2051 }else if( flags & (PS_Export|PS_Export2) ){
b62f651… stephan 2052 DeclSetProperty(pDecl,DP_Export);
b62f651… stephan 2053 }
b62f651… stephan 2054 if( flags & DP_Cplusplus ){
b62f651… stephan 2055 DeclSetProperty(pDecl,DP_Cplusplus);
b62f651… stephan 2056 }
b62f651… stephan 2057 return nErr;
b62f651… stephan 2058 }
b62f651… stephan 2059
b62f651… stephan 2060 /*
b62f651… stephan 2061 ** Push an if condition onto the if stack
b62f651… stephan 2062 */
b62f651… stephan 2063 static void PushIfMacro(
b62f651… stephan 2064 const char *zPrefix, /* A prefix, like "define" or "!" */
b62f651… stephan 2065 const char *zText, /* The condition */
b62f651… stephan 2066 int nText, /* Number of characters in zText */
b62f651… stephan 2067 int nLine, /* Line number where this macro occurs */
b62f651… stephan 2068 int flags /* Either 0, PS_Interface, PS_Export or PS_Local */
b62f651… stephan 2069 ){
b62f651… stephan 2070 Ifmacro *pIf;
b62f651… stephan 2071 int nByte;
b62f651… stephan 2072
b62f651… stephan 2073 nByte = sizeof(Ifmacro);
b62f651… stephan 2074 if( zText ){
b62f651… stephan 2075 if( zPrefix ){
b62f651… stephan 2076 nByte += strlen(zPrefix) + 2;
b62f651… stephan 2077 }
b62f651… stephan 2078 nByte += nText + 1;
b62f651… stephan 2079 }
b62f651… stephan 2080 pIf = SafeMalloc( nByte );
b62f651… stephan 2081 if( zText ){
b62f651… stephan 2082 pIf->zCondition = (char*)&pIf[1];
b62f651… stephan 2083 if( zPrefix ){
8c7bf45… drh 2084 int nPrefix = (int)strlen(zPrefix);
8c7bf45… drh 2085 memcpy(pIf->zCondition, zPrefix, nPrefix);
8c7bf45… drh 2086 pIf->zCondition[nPrefix] = '(';
8c7bf45… drh 2087 memcpy(&pIf->zCondition[nPrefix+1], zText, nText);
8c7bf45… drh 2088 memcpy(&pIf->zCondition[nPrefix+nText+1], ")", 2);
b62f651… stephan 2089 }else{
8c7bf45… drh 2090 memcpy(pIf->zCondition, zText, nText);
8c7bf45… drh 2091 pIf->zCondition[nText] = 0;
b62f651… stephan 2092 }
b62f651… stephan 2093 }else{
b62f651… stephan 2094 pIf->zCondition = 0;
b62f651… stephan 2095 }
b62f651… stephan 2096 pIf->nLine = nLine;
b62f651… stephan 2097 pIf->flags = flags;
b62f651… stephan 2098 pIf->pNext = ifStack;
b62f651… stephan 2099 ifStack = pIf;
b62f651… stephan 2100 }
b62f651… stephan 2101
b62f651… stephan 2102 /*
b62f651… stephan 2103 ** This routine is called to handle all preprocessor directives.
b62f651… stephan 2104 **
b62f651… stephan 2105 ** This routine will recompute the value of *pPresetFlags to be the
b62f651… stephan 2106 ** logical or of all flags on all nested #ifs. The #ifs that set flags
b62f651… stephan 2107 ** are as follows:
b62f651… stephan 2108 **
b62f651… stephan 2109 ** conditional flag set
b62f651… stephan 2110 ** ------------------------ --------------------
b62f651… stephan 2111 ** #if INTERFACE PS_Interface
b62f651… stephan 2112 ** #if EXPORT_INTERFACE PS_Export
b62f651… stephan 2113 ** #if LOCAL_INTERFACE PS_Local
b62f651… stephan 2114 **
b62f651… stephan 2115 ** For example, if after processing the preprocessor token given
b62f651… stephan 2116 ** by pToken there is an "#if INTERFACE" on the preprocessor
b62f651… stephan 2117 ** stack, then *pPresetFlags will be set to PS_Interface.
b62f651… stephan 2118 */
b62f651… stephan 2119 static int ParsePreprocessor(Token *pToken, int flags, int *pPresetFlags){
b62f651… stephan 2120 const char *zCmd;
b62f651… stephan 2121 int nCmd;
b62f651… stephan 2122 const char *zArg;
b62f651… stephan 2123 int nArg;
b62f651… stephan 2124 int nErr = 0;
b62f651… stephan 2125 Ifmacro *pIf;
b62f651… stephan 2126
b62f651… stephan 2127 zCmd = &pToken->zText[1];
b62f651… stephan 2128 while( isspace(*zCmd) && *zCmd!='\n' ){
b62f651… stephan 2129 zCmd++;
b62f651… stephan 2130 }
b62f651… stephan 2131 if( !isalpha(*zCmd) ){
b62f651… stephan 2132 return 0;
b62f651… stephan 2133 }
b62f651… stephan 2134 nCmd = 1;
b62f651… stephan 2135 while( isalpha(zCmd[nCmd]) ){
b62f651… stephan 2136 nCmd++;
b62f651… stephan 2137 }
b62f651… stephan 2138
b62f651… stephan 2139 if( nCmd==5 && strncmp(zCmd,"endif",5)==0 ){
b62f651… stephan 2140 /*
b62f651… stephan 2141 ** Pop the if stack
b62f651… stephan 2142 */
b62f651… stephan 2143 pIf = ifStack;
b62f651… stephan 2144 if( pIf==0 ){
b62f651… stephan 2145 fprintf(stderr,"%s:%d: extra '#endif'.\n",zFilename,pToken->nLine);
b62f651… stephan 2146 return 1;
b62f651… stephan 2147 }
b62f651… stephan 2148 ifStack = pIf->pNext;
b62f651… stephan 2149 SafeFree(pIf);
b62f651… stephan 2150 }else if( nCmd==6 && strncmp(zCmd,"define",6)==0 ){
b62f651… stephan 2151 /*
b62f651… stephan 2152 ** Record a #define if we are in PS_Interface or PS_Export
b62f651… stephan 2153 */
b62f651… stephan 2154 Decl *pDecl;
b62f651… stephan 2155 if( !(flags & (PS_Local|PS_Interface|PS_Export)) ){ return 0; }
b62f651… stephan 2156 zArg = &zCmd[6];
b62f651… stephan 2157 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
b62f651… stephan 2158 zArg++;
b62f651… stephan 2159 }
b62f651… stephan 2160 if( *zArg==0 || *zArg=='\n' ){ return 0; }
b62f651… stephan 2161 for(nArg=0; ISALNUM(zArg[nArg]); nArg++){}
b62f651… stephan 2162 if( nArg==0 ){ return 0; }
b62f651… stephan 2163 pDecl = CreateDecl(zArg,nArg);
b62f651… stephan 2164 pDecl->pComment = pToken->pComment;
b62f651… stephan 2165 DeclSetProperty(pDecl,TY_Macro);
b62f651… stephan 2166 pDecl->zDecl = SafeMalloc( pToken->nText + 2 );
8c7bf45… drh 2167 memcpy(pDecl->zDecl, pToken->zText, pToken->nText);
8c7bf45… drh 2168 memcpy(&pDecl->zDecl[pToken->nText], "\n", 2);
b62f651… stephan 2169 if( flags & PS_Export ){
b62f651… stephan 2170 DeclSetProperty(pDecl,DP_Export);
b62f651… stephan 2171 }else if( flags & PS_Local ){
b62f651… stephan 2172 DeclSetProperty(pDecl,DP_Local);
b62f651… stephan 2173 }
b62f651… stephan 2174 }else if( nCmd==7 && strncmp(zCmd,"include",7)==0 ){
b62f651… stephan 2175 /*
b62f651… stephan 2176 ** Record an #include if we are in PS_Interface or PS_Export
b62f651… stephan 2177 */
b62f651… stephan 2178 Include *pInclude;
b62f651… stephan 2179 char *zIf;
b62f651… stephan 2180
b62f651… stephan 2181 if( !(flags & (PS_Interface|PS_Export)) ){ return 0; }
b62f651… stephan 2182 zArg = &zCmd[7];
b62f651… stephan 2183 while( *zArg && isspace(*zArg) ){ zArg++; }
b62f651… stephan 2184 for(nArg=0; !isspace(zArg[nArg]); nArg++){}
b62f651… stephan 2185 if( (zArg[0]=='"' && zArg[nArg-1]!='"')
b62f651… stephan 2186 ||(zArg[0]=='<' && zArg[nArg-1]!='>')
b62f651… stephan 2187 ){
b62f651… stephan 2188 fprintf(stderr,"%s:%d: malformed #include statement.\n",
b62f651… stephan 2189 zFilename,pToken->nLine);
b62f651… stephan 2190 return 1;
b62f651… stephan 2191 }
b62f651… stephan 2192 zIf = GetIfString();
b62f651… stephan 2193 if( zIf ){
b62f651… stephan 2194 pInclude = SafeMalloc( sizeof(Include) + nArg*2 + strlen(zIf) + 10 );
b62f651… stephan 2195 pInclude->zFile = (char*)&pInclude[1];
b62f651… stephan 2196 pInclude->zLabel = &pInclude->zFile[nArg+1];
8c7bf45… drh 2197 memcpy(pInclude->zFile, zArg, nArg);
8c7bf45… drh 2198 pInclude->zFile[nArg] = 0;
8c7bf45… drh 2199 memcpy(pInclude->zLabel, zArg, nArg);
8c7bf45… drh 2200 pInclude->zLabel[nArg] = ':';
8c7bf45… drh 2201 memcpy(&pInclude->zLabel[nArg+1], zIf, strlen(zIf)+1);
b62f651… stephan 2202 pInclude->zIf = &pInclude->zLabel[nArg+1];
b62f651… stephan 2203 SafeFree(zIf);
b62f651… stephan 2204 }else{
b62f651… stephan 2205 pInclude = SafeMalloc( sizeof(Include) + nArg + 1 );
b62f651… stephan 2206 pInclude->zFile = (char*)&pInclude[1];
8c7bf45… drh 2207 memcpy(pInclude->zFile, zArg, nArg);
8c7bf45… drh 2208 pInclude->zFile[nArg] = 0;
b62f651… stephan 2209 pInclude->zIf = 0;
b62f651… stephan 2210 pInclude->zLabel = pInclude->zFile;
b62f651… stephan 2211 }
b62f651… stephan 2212 pInclude->pNext = includeList;
b62f651… stephan 2213 includeList = pInclude;
b62f651… stephan 2214 }else if( nCmd==2 && strncmp(zCmd,"if",2)==0 ){
b62f651… stephan 2215 /*
b62f651… stephan 2216 ** Push an #if. Watch for the special cases of INTERFACE
b62f651… stephan 2217 ** and EXPORT_INTERFACE and LOCAL_INTERFACE
b62f651… stephan 2218 */
b62f651… stephan 2219 zArg = &zCmd[2];
b62f651… stephan 2220 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
b62f651… stephan 2221 zArg++;
b62f651… stephan 2222 }
b62f651… stephan 2223 if( *zArg==0 || *zArg=='\n' ){ return 0; }
b62f651… stephan 2224 nArg = pToken->nText + (int)(pToken->zText - zArg);
bb01182… stephan 2225 if (pToken->zText[pToken->nText-1] == '\r') { nArg--; }
b62f651… stephan 2226 if( nArg==9 && strncmp(zArg,"INTERFACE",9)==0 ){
b62f651… stephan 2227 PushIfMacro(0,0,0,pToken->nLine,PS_Interface);
b62f651… stephan 2228 }else if( nArg==16 && strncmp(zArg,"EXPORT_INTERFACE",16)==0 ){
b62f651… stephan 2229 PushIfMacro(0,0,0,pToken->nLine,PS_Export);
b62f651… stephan 2230 }else if( nArg==15 && strncmp(zArg,"LOCAL_INTERFACE",15)==0 ){
b62f651… stephan 2231 PushIfMacro(0,0,0,pToken->nLine,PS_Local);
275da70… danield 2232 }else if( nArg==15 &&
275da70… danield 2233 strncmp(zArg,"MAKEHEADERS_STOPLOCAL_INTERFACE",15)==0 ){
b62f651… stephan 2234 PushIfMacro(0,0,0,pToken->nLine,PS_Local);
b62f651… stephan 2235 }else{
b62f651… stephan 2236 PushIfMacro(0,zArg,nArg,pToken->nLine,0);
b62f651… stephan 2237 }
b62f651… stephan 2238 }else if( nCmd==5 && strncmp(zCmd,"ifdef",5)==0 ){
b62f651… stephan 2239 /*
b62f651… stephan 2240 ** Push an #ifdef.
b62f651… stephan 2241 */
b62f651… stephan 2242 zArg = &zCmd[5];
b62f651… stephan 2243 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
b62f651… stephan 2244 zArg++;
b62f651… stephan 2245 }
b62f651… stephan 2246 if( *zArg==0 || *zArg=='\n' ){ return 0; }
b62f651… stephan 2247 nArg = pToken->nText + (int)(pToken->zText - zArg);
74bd3fd… stephan 2248 if (pToken->zText[pToken->nText-1] == '\r') { nArg--; }
b62f651… stephan 2249 PushIfMacro("defined",zArg,nArg,pToken->nLine,0);
b62f651… stephan 2250 }else if( nCmd==6 && strncmp(zCmd,"ifndef",6)==0 ){
b62f651… stephan 2251 /*
b62f651… stephan 2252 ** Push an #ifndef.
b62f651… stephan 2253 */
b62f651… stephan 2254 zArg = &zCmd[6];
b62f651… stephan 2255 while( *zArg && isspace(*zArg) && *zArg!='\n' ){
b62f651… stephan 2256 zArg++;
b62f651… stephan 2257 }
b62f651… stephan 2258 if( *zArg==0 || *zArg=='\n' ){ return 0; }
b62f651… stephan 2259 nArg = pToken->nText + (int)(pToken->zText - zArg);
74bd3fd… stephan 2260 if (pToken->zText[pToken->nText-1] == '\r') { nArg--; }
b62f651… stephan 2261 PushIfMacro("!defined",zArg,nArg,pToken->nLine,0);
b62f651… stephan 2262 }else if( nCmd==4 && strncmp(zCmd,"else",4)==0 ){
b62f651… stephan 2263 /*
b62f651… stephan 2264 ** Invert the #if on the top of the stack
b62f651… stephan 2265 */
b62f651… stephan 2266 if( ifStack==0 ){
b62f651… stephan 2267 fprintf(stderr,"%s:%d: '#else' without an '#if'\n",zFilename,
b62f651… stephan 2268 pToken->nLine);
b62f651… stephan 2269 return 1;
b62f651… stephan 2270 }
b62f651… stephan 2271 pIf = ifStack;
b62f651… stephan 2272 if( pIf->zCondition ){
b62f651… stephan 2273 ifStack = ifStack->pNext;
b62f651… stephan 2274 PushIfMacro("!",pIf->zCondition,strlen(pIf->zCondition),pIf->nLine,0);
b62f651… stephan 2275 SafeFree(pIf);
b62f651… stephan 2276 }else{
b62f651… stephan 2277 pIf->flags = 0;
b62f651… stephan 2278 }
b62f651… stephan 2279 }else{
b62f651… stephan 2280 /*
b62f651… stephan 2281 ** This directive can be safely ignored
b62f651… stephan 2282 */
b62f651… stephan 2283 return 0;
b62f651… stephan 2284 }
b62f651… stephan 2285
b62f651… stephan 2286 /*
b62f651… stephan 2287 ** Recompute the preset flags
b62f651… stephan 2288 */
b62f651… stephan 2289 *pPresetFlags = 0;
b62f651… stephan 2290 for(pIf = ifStack; pIf; pIf=pIf->pNext){
b62f651… stephan 2291 *pPresetFlags |= pIf->flags;
b62f651… stephan 2292 }
b62f651… stephan 2293
b62f651… stephan 2294 return nErr;
b62f651… stephan 2295 }
b62f651… stephan 2296
b62f651… stephan 2297 /*
b62f651… stephan 2298 ** Parse an entire file. Return the number of errors.
b62f651… stephan 2299 **
b62f651… stephan 2300 ** pList is a list of tokens in the file. Whitespace tokens have been
b62f651… stephan 2301 ** eliminated, and text with {...} has been collapsed into a
b62f651… stephan 2302 ** single TT_Brace token.
b62f651… stephan 2303 **
b62f651… stephan 2304 ** initFlags are a set of parse flags that should always be set for this
b62f651… stephan 2305 ** file. For .c files this is normally 0. For .h files it is PS_Interface.
b62f651… stephan 2306 */
b62f651… stephan 2307 static int ParseFile(Token *pList, int initFlags){
b62f651… stephan 2308 int nErr = 0;
b62f651… stephan 2309 Token *pStart = 0;
b62f651… stephan 2310 int flags = initFlags;
b62f651… stephan 2311 int presetFlags = initFlags;
b62f651… stephan 2312 int resetFlag = 0;
b62f651… stephan 2313
b62f651… stephan 2314 includeList = 0;
b62f651… stephan 2315 while( pList ){
b62f651… stephan 2316 switch( pList->eType ){
b62f651… stephan 2317 case TT_EOF:
b62f651… stephan 2318 goto end_of_loop;
b62f651… stephan 2319
b62f651… stephan 2320 case TT_Preprocessor:
b62f651… stephan 2321 nErr += ParsePreprocessor(pList,flags,&presetFlags);
b62f651… stephan 2322 pStart = 0;
b62f651… stephan 2323 presetFlags |= initFlags;
b62f651… stephan 2324 flags = presetFlags;
b62f651… stephan 2325 break;
b62f651… stephan 2326
b62f651… stephan 2327 case TT_Other:
b62f651… stephan 2328 switch( pList->zText[0] ){
b62f651… stephan 2329 case ';':
b62f651… stephan 2330 nErr += ProcessDecl(pStart,pList,flags);
b62f651… stephan 2331 pStart = 0;
b62f651… stephan 2332 flags = presetFlags;
b62f651… stephan 2333 break;
b62f651… stephan 2334
b62f651… stephan 2335 case '=':
b62f651… stephan 2336 if( pList->pPrev->nText==8
b62f651… stephan 2337 && strncmp(pList->pPrev->zText,"operator",8)==0 ){
b62f651… stephan 2338 break;
b62f651… stephan 2339 }
b62f651… stephan 2340 nErr += ProcessDecl(pStart,pList,flags);
b62f651… stephan 2341 pStart = 0;
b62f651… stephan 2342 while( pList && pList->zText[0]!=';' ){
b62f651… stephan 2343 pList = pList->pNext;
b62f651… stephan 2344 }
b62f651… stephan 2345 if( pList==0 ) goto end_of_loop;
b62f651… stephan 2346 flags = presetFlags;
b62f651… stephan 2347 break;
b62f651… stephan 2348
b62f651… stephan 2349 case ':':
b62f651… stephan 2350 if( pList->zText[1]==':' ){
b62f651… stephan 2351 flags |= PS_Method;
b62f651… stephan 2352 }
b62f651… stephan 2353 break;
b62f651… stephan 2354
b62f651… stephan 2355 default:
b62f651… stephan 2356 break;
b62f651… stephan 2357 }
b62f651… stephan 2358 break;
b62f651… stephan 2359
b62f651… stephan 2360 case TT_Braces:
b62f651… stephan 2361 nErr += ProcessProcedureDef(pStart,pList,flags);
b62f651… stephan 2362 pStart = 0;
b62f651… stephan 2363 flags = presetFlags;
b62f651… stephan 2364 break;
b62f651… stephan 2365
b62f651… stephan 2366 case TT_Id:
b62f651… stephan 2367 if( pStart==0 ){
b62f651… stephan 2368 pStart = pList;
b62f651… stephan 2369 flags = presetFlags;
b62f651… stephan 2370 }
b62f651… stephan 2371 resetFlag = 0;
b62f651… stephan 2372 switch( pList->zText[0] ){
b62f651… stephan 2373 case 'c':
b62f651… stephan 2374 if( pList->nText==5 && strncmp(pList->zText,"class",5)==0 ){
b62f651… stephan 2375 nErr += ProcessTypeDecl(pList,flags,&resetFlag);
b62f651… stephan 2376 }
b62f651… stephan 2377 break;
b62f651… stephan 2378
b62f651… stephan 2379 case 'E':
b62f651… stephan 2380 if( pList->nText==6 && strncmp(pList->zText,"EXPORT",6)==0 ){
b62f651… stephan 2381 flags |= PS_Export2;
b62f651… stephan 2382 /* pStart = 0; */
b62f651… stephan 2383 }
b62f651… stephan 2384 break;
b62f651… stephan 2385
b62f651… stephan 2386 case 'e':
b62f651… stephan 2387 if( pList->nText==4 && strncmp(pList->zText,"enum",4)==0 ){
b62f651… stephan 2388 if( pList->pNext && pList->pNext->eType==TT_Braces ){
b62f651… stephan 2389 pList = pList->pNext;
b62f651… stephan 2390 }else{
b62f651… stephan 2391 nErr += ProcessTypeDecl(pList,flags,&resetFlag);
b62f651… stephan 2392 }
b62f651… stephan 2393 }else if( pList->nText==6 && strncmp(pList->zText,"extern",6)==0 ){
b62f651… stephan 2394 pList = pList->pNext;
b62f651… stephan 2395 if( pList && pList->nText==3 && strncmp(pList->zText,"\"C\"",3)==0 ){
b62f651… stephan 2396 pList = pList->pNext;
b62f651… stephan 2397 flags &= ~DP_Cplusplus;
b62f651… stephan 2398 }else{
b62f651… stephan 2399 flags |= PS_Extern;
b62f651… stephan 2400 }
b62f651… stephan 2401 pStart = pList;
b62f651… stephan 2402 }
b62f651… stephan 2403 break;
b62f651… stephan 2404
b62f651… stephan 2405 case 'i':
b62f651… stephan 2406 if( pList->nText==6 && strncmp(pList->zText,"inline",6)==0
b62f651… stephan 2407 && (flags & PS_Static)==0
b62f651… stephan 2408 ){
b62f651… stephan 2409 nErr += ProcessInlineProc(pList,flags,&resetFlag);
b62f651… stephan 2410 }
b62f651… stephan 2411 break;
b62f651… stephan 2412
b62f651… stephan 2413 case 'L':
b62f651… stephan 2414 if( pList->nText==5 && strncmp(pList->zText,"LOCAL",5)==0 ){
b62f651… stephan 2415 flags |= PS_Local2;
b62f651… stephan 2416 pStart = pList;
b62f651… stephan 2417 }
b62f651… stephan 2418 break;
b62f651… stephan 2419
b62f651… stephan 2420 case 'P':
b62f651… stephan 2421 if( pList->nText==6 && strncmp(pList->zText, "PUBLIC",6)==0 ){
b62f651… stephan 2422 flags |= PS_Public;
b62f651… stephan 2423 pStart = pList;
b62f651… stephan 2424 }else if( pList->nText==7 && strncmp(pList->zText, "PRIVATE",7)==0 ){
b62f651… stephan 2425 flags |= PS_Private;
b62f651… stephan 2426 pStart = pList;
b62f651… stephan 2427 }else if( pList->nText==9 && strncmp(pList->zText,"PROTECTED",9)==0 ){
b62f651… stephan 2428 flags |= PS_Protected;
b62f651… stephan 2429 pStart = pList;
b62f651… stephan 2430 }
b62f651… stephan 2431 break;
b62f651… stephan 2432
b62f651… stephan 2433 case 's':
b62f651… stephan 2434 if( pList->nText==6 && strncmp(pList->zText,"struct",6)==0 ){
b62f651… stephan 2435 if( pList->pNext && pList->pNext->eType==TT_Braces ){
b62f651… stephan 2436 pList = pList->pNext;
b62f651… stephan 2437 }else{
b62f651… stephan 2438 nErr += ProcessTypeDecl(pList,flags,&resetFlag);
b62f651… stephan 2439 }
b62f651… stephan 2440 }else if( pList->nText==6 && strncmp(pList->zText,"static",6)==0 ){
b62f651… stephan 2441 flags |= PS_Static;
b62f651… stephan 2442 }
b62f651… stephan 2443 break;
b62f651… stephan 2444
b62f651… stephan 2445 case 't':
b62f651… stephan 2446 if( pList->nText==7 && strncmp(pList->zText,"typedef",7)==0 ){
b62f651… stephan 2447 flags |= PS_Typedef;
b62f651… stephan 2448 }
b62f651… stephan 2449 break;
b62f651… stephan 2450
b62f651… stephan 2451 case 'u':
b62f651… stephan 2452 if( pList->nText==5 && strncmp(pList->zText,"union",5)==0 ){
b62f651… stephan 2453 if( pList->pNext && pList->pNext->eType==TT_Braces ){
b62f651… stephan 2454 pList = pList->pNext;
b62f651… stephan 2455 }else{
b62f651… stephan 2456 nErr += ProcessTypeDecl(pList,flags,&resetFlag);
b62f651… stephan 2457 }
b62f651… stephan 2458 }
b62f651… stephan 2459 break;
b62f651… stephan 2460
b62f651… stephan 2461 default:
b62f651… stephan 2462 break;
b62f651… stephan 2463 }
b62f651… stephan 2464 if( resetFlag!=0 ){
b62f651… stephan 2465 while( pList && pList->zText[0]!=resetFlag ){
b62f651… stephan 2466 pList = pList->pNext;
b62f651… stephan 2467 }
b62f651… stephan 2468 if( pList==0 ) goto end_of_loop;
b62f651… stephan 2469 pStart = 0;
b62f651… stephan 2470 flags = presetFlags;
b62f651… stephan 2471 }
b62f651… stephan 2472 break;
b62f651… stephan 2473
b62f651… stephan 2474 case TT_String:
b62f651… stephan 2475 case TT_Number:
b62f651… stephan 2476 break;
b62f651… stephan 2477
b62f651… stephan 2478 default:
b62f651… stephan 2479 pStart = pList;
b62f651… stephan 2480 flags = presetFlags;
b62f651… stephan 2481 break;
b62f651… stephan 2482 }
b62f651… stephan 2483 pList = pList->pNext;
b62f651… stephan 2484 }
b62f651… stephan 2485 end_of_loop:
b62f651… stephan 2486
b62f651… stephan 2487 /* Verify that all #ifs have a matching "#endif" */
b62f651… stephan 2488 while( ifStack ){
b62f651… stephan 2489 Ifmacro *pIf = ifStack;
b62f651… stephan 2490 ifStack = pIf->pNext;
b62f651… stephan 2491 fprintf(stderr,"%s:%d: This '#if' has no '#endif'\n",zFilename,
b62f651… stephan 2492 pIf->nLine);
b62f651… stephan 2493 SafeFree(pIf);
b62f651… stephan 2494 }
b62f651… stephan 2495
b62f651… stephan 2496 return nErr;
b62f651… stephan 2497 }
b62f651… stephan 2498
b62f651… stephan 2499 /*
b62f651… stephan 2500 ** If the given Decl object has a non-null zExtra field, then the text
b62f651… stephan 2501 ** of that zExtra field needs to be inserted in the middle of the
b62f651… stephan 2502 ** zDecl field before the last "}" in the zDecl. This routine does that.
b62f651… stephan 2503 ** If the zExtra is NULL, this routine is a no-op.
b62f651… stephan 2504 **
b62f651… stephan 2505 ** zExtra holds extra method declarations for classes. The declarations
b62f651… stephan 2506 ** have to be inserted into the class definition.
b62f651… stephan 2507 */
b62f651… stephan 2508 static void InsertExtraDecl(Decl *pDecl){
b62f651… stephan 2509 int i;
b62f651… stephan 2510 String str;
b62f651… stephan 2511
b62f651… stephan 2512 if( pDecl==0 || pDecl->zExtra==0 || pDecl->zDecl==0 ) return;
b62f651… stephan 2513 i = strlen(pDecl->zDecl) - 1;
b62f651… stephan 2514 while( i>0 && pDecl->zDecl[i]!='}' ){ i--; }
b62f651… stephan 2515 StringInit(&str);
b62f651… stephan 2516 StringAppend(&str, pDecl->zDecl, i);
b62f651… stephan 2517 StringAppend(&str, pDecl->zExtra, 0);
b62f651… stephan 2518 StringAppend(&str, &pDecl->zDecl[i], 0);
b62f651… stephan 2519 SafeFree(pDecl->zDecl);
b62f651… stephan 2520 SafeFree(pDecl->zExtra);
b62f651… stephan 2521 pDecl->zDecl = StrDup(StringGet(&str), 0);
b62f651… stephan 2522 StringReset(&str);
b62f651… stephan 2523 pDecl->zExtra = 0;
b62f651… stephan 2524 }
b62f651… stephan 2525
b62f651… stephan 2526 /*
b62f651… stephan 2527 ** Reset the DP_Forward and DP_Declared flags on all Decl structures.
b62f651… stephan 2528 ** Set both flags for anything that is tagged as local and isn't
b62f651… stephan 2529 ** in the file zFilename so that it won't be printing in other files.
b62f651… stephan 2530 */
b62f651… stephan 2531 static void ResetDeclFlags(char *zFilename){
b62f651… stephan 2532 Decl *pDecl;
b62f651… stephan 2533
b62f651… stephan 2534 for(pDecl = pDeclFirst; pDecl; pDecl = pDecl->pNext){
b62f651… stephan 2535 DeclClearProperty(pDecl,DP_Forward|DP_Declared);
b62f651… stephan 2536 if( DeclHasProperty(pDecl,DP_Local) && pDecl->zFile!=zFilename ){
b62f651… stephan 2537 DeclSetProperty(pDecl,DP_Forward|DP_Declared);
b62f651… stephan 2538 }
b62f651… stephan 2539 }
b62f651… stephan 2540 }
b62f651… stephan 2541
b62f651… stephan 2542 /*
b62f651… stephan 2543 ** Forward declaration of the ScanText() function.
b62f651… stephan 2544 */
b62f651… stephan 2545 static void ScanText(const char*, GenState *pState);
b62f651… stephan 2546
b62f651… stephan 2547 /*
b62f651… stephan 2548 ** The output in pStr is currently within an #if CONTEXT where context
b62f651… stephan 2549 ** is equal to *pzIf. (*pzIf might be NULL to indicate that we are
b62f651… stephan 2550 ** not within any #if at the moment.) We are getting ready to output
b62f651… stephan 2551 ** some text that needs to be within the context of "#if NEW" where
b62f651… stephan 2552 ** NEW is zIf. Make an appropriate change to the context.
b62f651… stephan 2553 */
b62f651… stephan 2554 static void ChangeIfContext(
b62f651… stephan 2555 const char *zIf, /* The desired #if context */
b62f651… stephan 2556 GenState *pState /* Current state of the code generator */
b62f651… stephan 2557 ){
b62f651… stephan 2558 if( zIf==0 ){
b62f651… stephan 2559 if( pState->zIf==0 ) return;
b62f651… stephan 2560 StringAppend(pState->pStr,"#endif\n",0);
b62f651… stephan 2561 pState->zIf = 0;
b62f651… stephan 2562 }else{
b62f651… stephan 2563 if( pState->zIf ){
b62f651… stephan 2564 if( strcmp(zIf,pState->zIf)==0 ) return;
b62f651… stephan 2565 StringAppend(pState->pStr,"#endif\n",0);
b62f651… stephan 2566 pState->zIf = 0;
b62f651… stephan 2567 }
b62f651… stephan 2568 ScanText(zIf, pState);
b62f651… stephan 2569 if( pState->zIf!=0 ){
b62f651… stephan 2570 StringAppend(pState->pStr,"#endif\n",0);
b62f651… stephan 2571 }
b62f651… stephan 2572 StringAppend(pState->pStr,"#if ",0);
b62f651… stephan 2573 StringAppend(pState->pStr,zIf,0);
b62f651… stephan 2574 StringAppend(pState->pStr,"\n",0);
b62f651… stephan 2575 pState->zIf = zIf;
b62f651… stephan 2576 }
b62f651… stephan 2577 }
b62f651… stephan 2578
b62f651… stephan 2579 /*
b62f651… stephan 2580 ** Add to the string pStr a #include of every file on the list of
b62f651… stephan 2581 ** include files pInclude. The table pTable contains all files that
b62f651… stephan 2582 ** have already been #included at least once. Don't add any
b62f651… stephan 2583 ** duplicates. Update pTable with every new #include that is added.
b62f651… stephan 2584 */
b62f651… stephan 2585 static void AddIncludes(
b62f651… stephan 2586 Include *pInclude, /* Write every #include on this list */
b62f651… stephan 2587 GenState *pState /* Current state of the code generator */
b62f651… stephan 2588 ){
b62f651… stephan 2589 if( pInclude ){
b62f651… stephan 2590 if( pInclude->pNext ){
b62f651… stephan 2591 AddIncludes(pInclude->pNext,pState);
b62f651… stephan 2592 }
b62f651… stephan 2593 if( IdentTableInsert(pState->pTable,pInclude->zLabel,0) ){
b62f651… stephan 2594 ChangeIfContext(pInclude->zIf,pState);
b62f651… stephan 2595 StringAppend(pState->pStr,"#include ",0);
b62f651… stephan 2596 StringAppend(pState->pStr,pInclude->zFile,0);
b62f651… stephan 2597 StringAppend(pState->pStr,"\n",1);
b62f651… stephan 2598 }
b62f651… stephan 2599 }
b62f651… stephan 2600 }
b62f651… stephan 2601
b62f651… stephan 2602 /*
b62f651… stephan 2603 ** Add to the string pStr a declaration for the object described
b62f651… stephan 2604 ** in pDecl.
b62f651… stephan 2605 **
b62f651… stephan 2606 ** If pDecl has already been declared in this file, detect that
b62f651… stephan 2607 ** fact and abort early. Do not duplicate a declaration.
b62f651… stephan 2608 **
b62f651… stephan 2609 ** If the needFullDecl flag is false and this object has a forward
b62f651… stephan 2610 ** declaration, then supply the forward declaration only. A later
b62f651… stephan 2611 ** call to CompleteForwardDeclarations() will finish the declaration
b62f651… stephan 2612 ** for us. But if needFullDecl is true, we must supply the full
b62f651… stephan 2613 ** declaration now. Some objects do not have a forward declaration.
b62f651… stephan 2614 ** For those objects, we must print the full declaration now.
b62f651… stephan 2615 **
b62f651… stephan 2616 ** Because it is illegal to duplicate a typedef in C, care is taken
b62f651… stephan 2617 ** to insure that typedefs for the same identifier are only issued once.
b62f651… stephan 2618 */
b62f651… stephan 2619 static void DeclareObject(
b62f651… stephan 2620 Decl *pDecl, /* The thing to be declared */
b62f651… stephan 2621 GenState *pState, /* Current state of the code generator */
b62f651… stephan 2622 int needFullDecl /* Must have the full declaration. A forward
b62f651… stephan 2623 * declaration isn't enough */
b62f651… stephan 2624 ){
b62f651… stephan 2625 Decl *p; /* The object to be declared */
b62f651… stephan 2626 int flag;
b62f651… stephan 2627 int isCpp; /* True if generating C++ */
b62f651… stephan 2628 int doneTypedef = 0; /* True if a typedef has been done for this object */
b62f651… stephan 2629
b62f651… stephan 2630 /* printf("BEGIN %s of %s\n",needFullDecl?"FULL":"PROTOTYPE",pDecl->zName);*/
b62f651… stephan 2631 /*
b62f651… stephan 2632 ** For any object that has a forward declaration, go ahead and do the
b62f651… stephan 2633 ** forward declaration first.
b62f651… stephan 2634 */
b62f651… stephan 2635 isCpp = (pState->flags & DP_Cplusplus) != 0;
b62f651… stephan 2636 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2637 if( p->zFwd ){
b62f651… stephan 2638 if( !DeclHasProperty(p,DP_Forward) ){
b62f651… stephan 2639 DeclSetProperty(p,DP_Forward);
b62f651… stephan 2640 if( strncmp(p->zFwd,"typedef",7)==0 ){
b62f651… stephan 2641 if( doneTypedef ) continue;
b62f651… stephan 2642 doneTypedef = 1;
b62f651… stephan 2643 }
b62f651… stephan 2644 ChangeIfContext(p->zIf,pState);
b62f651… stephan 2645 StringAppend(pState->pStr,isCpp ? p->zFwdCpp : p->zFwd,0);
b62f651… stephan 2646 }
b62f651… stephan 2647 }
b62f651… stephan 2648 }
b62f651… stephan 2649
b62f651… stephan 2650 /*
b62f651… stephan 2651 ** Early out if everything is already suitably declared.
b62f651… stephan 2652 **
b62f651… stephan 2653 ** This is a very important step because it prevents us from
b62f651… stephan 2654 ** executing the code the follows in a recursive call to this
b62f651… stephan 2655 ** function with the same value for pDecl.
b62f651… stephan 2656 */
b62f651… stephan 2657 flag = needFullDecl ? DP_Declared|DP_Forward : DP_Forward;
b62f651… stephan 2658 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2659 if( !DeclHasProperty(p,flag) ) break;
b62f651… stephan 2660 }
b62f651… stephan 2661 if( p==0 ){
b62f651… stephan 2662 return;
b62f651… stephan 2663 }
b62f651… stephan 2664
b62f651… stephan 2665 /*
b62f651… stephan 2666 ** Make sure we have all necessary #includes
b62f651… stephan 2667 */
b62f651… stephan 2668 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2669 AddIncludes(p->pInclude,pState);
b62f651… stephan 2670 }
b62f651… stephan 2671
b62f651… stephan 2672 /*
b62f651… stephan 2673 ** Go ahead an mark everything as being declared, to prevent an
b62f651… stephan 2674 ** infinite loop thru the ScanText() function. At the same time,
b62f651… stephan 2675 ** we decide which objects need a full declaration and mark them
b62f651… stephan 2676 ** with the DP_Flag bit. We are only able to use DP_Flag in this
b62f651… stephan 2677 ** way because we know we'll never execute this far into this
b62f651… stephan 2678 ** function on a recursive call with the same pDecl. Hence, recursive
b62f651… stephan 2679 ** calls to this function (through ScanText()) can never change the
b62f651… stephan 2680 ** value of DP_Flag out from under us.
b62f651… stephan 2681 */
b62f651… stephan 2682 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2683 if( !DeclHasProperty(p,DP_Declared)
b62f651… stephan 2684 && (p->zFwd==0 || needFullDecl)
b62f651… stephan 2685 && p->zDecl!=0
b62f651… stephan 2686 ){
b62f651… stephan 2687 DeclSetProperty(p,DP_Forward|DP_Declared|DP_Flag);
b62f651… stephan 2688 }else{
b62f651… stephan 2689 DeclClearProperty(p,DP_Flag);
b62f651… stephan 2690 }
b62f651… stephan 2691 }
b62f651… stephan 2692
b62f651… stephan 2693 /*
b62f651… stephan 2694 ** Call ScanText() recursively (this routine is called from ScanText())
b62f651… stephan 2695 ** to include declarations required to come before these declarations.
b62f651… stephan 2696 */
b62f651… stephan 2697 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2698 if( DeclHasProperty(p,DP_Flag) ){
b62f651… stephan 2699 if( p->zDecl[0]=='#' ){
b62f651… stephan 2700 ScanText(&p->zDecl[1],pState);
b62f651… stephan 2701 }else{
b62f651… stephan 2702 InsertExtraDecl(p);
b62f651… stephan 2703 ScanText(p->zDecl,pState);
b62f651… stephan 2704 }
b62f651… stephan 2705 }
b62f651… stephan 2706 }
b62f651… stephan 2707
b62f651… stephan 2708 /*
b62f651… stephan 2709 ** Output the declarations. Do this in two passes. First
b62f651… stephan 2710 ** output everything that isn't a typedef. Then go back and
b62f651… stephan 2711 ** get the typedefs by the same name.
b62f651… stephan 2712 */
b62f651… stephan 2713 for(p=pDecl; p; p=p->pSameName){
b62f651… stephan 2714 if( DeclHasProperty(p,DP_Flag) && !DeclHasProperty(p,TY_Typedef) ){
b62f651… stephan 2715 if( DeclHasAnyProperty(p,TY_Enumeration) ){
b62f651… stephan 2716 if( doneTypedef ) continue;
b62f651… stephan 2717 doneTypedef = 1;
b62f651… stephan 2718 }
b62f651… stephan 2719 ChangeIfContext(p->zIf,pState);
b62f651… stephan 2720 if( !isCpp && DeclHasAnyProperty(p,DP_ExternReqd) ){
b62f651… stephan 2721 StringAppend(pState->pStr,"extern ",0);
b62f651… stephan 2722 }else if( isCpp && DeclHasProperty(p,DP_Cplusplus|DP_ExternReqd) ){
b62f651… stephan 2723 StringAppend(pState->pStr,"extern ",0);
b62f651… stephan 2724 }else if( isCpp && DeclHasAnyProperty(p,DP_ExternCReqd|DP_ExternReqd) ){
b62f651… stephan 2725 StringAppend(pState->pStr,"extern \"C\" ",0);
b62f651… stephan 2726 }
b62f651… stephan 2727 InsertExtraDecl(p);
b62f651… stephan 2728 StringAppend(pState->pStr,p->zDecl,0);
b62f651… stephan 2729 if( !isCpp && DeclHasProperty(p,DP_Cplusplus) ){
b62f651… stephan 2730 fprintf(stderr,
b62f651… stephan 2731 "%s: C code ought not reference the C++ object \"%s\"\n",
b62f651… stephan 2732 pState->zFilename, p->zName);
b62f651… stephan 2733 pState->nErr++;
b62f651… stephan 2734 }
b62f651… stephan 2735 DeclClearProperty(p,DP_Flag);
b62f651… stephan 2736 }
b62f651… stephan 2737 }
b62f651… stephan 2738 for(p=pDecl; p && !doneTypedef; p=p->pSameName){
b62f651… stephan 2739 if( DeclHasProperty(p,DP_Flag) ){
b62f651… stephan 2740 /* This has to be a typedef */
b62f651… stephan 2741 doneTypedef = 1;
b62f651… stephan 2742 ChangeIfContext(p->zIf,pState);
b62f651… stephan 2743 InsertExtraDecl(p);
b62f651… stephan 2744 StringAppend(pState->pStr,p->zDecl,0);
b62f651… stephan 2745 }
b62f651… stephan 2746 }
b62f651… stephan 2747 }
b62f651… stephan 2748
b62f651… stephan 2749 /*
b62f651… stephan 2750 ** This routine scans the input text given, and appends to the
b62f651… stephan 2751 ** string in pState->pStr the text of any declarations that must
b62f651… stephan 2752 ** occur before the text in zText.
b62f651… stephan 2753 **
b62f651… stephan 2754 ** If an identifier in zText is immediately followed by '*', then
b62f651… stephan 2755 ** only forward declarations are needed for that identifier. If the
b62f651… stephan 2756 ** identifier name is not followed immediately by '*', we must supply
b62f651… stephan 2757 ** a full declaration.
b62f651… stephan 2758 */
b62f651… stephan 2759 static void ScanText(
b62f651… stephan 2760 const char *zText, /* The input text to be scanned */
b62f651… stephan 2761 GenState *pState /* Current state of the code generator */
b62f651… stephan 2762 ){
b62f651… stephan 2763 int nextValid = 0; /* True is sNext contains valid data */
b62f651… stephan 2764 InStream sIn; /* The input text */
b62f651… stephan 2765 Token sToken; /* The current token being examined */
b62f651… stephan 2766 Token sNext; /* The next non-space token */
b62f651… stephan 2767
b62f651… stephan 2768 /* printf("BEGIN SCAN TEXT on %s\n", zText); */
b62f651… stephan 2769
b62f651… stephan 2770 sIn.z = zText;
b62f651… stephan 2771 sIn.i = 0;
b62f651… stephan 2772 sIn.nLine = 1;
b62f651… stephan 2773 while( sIn.z[sIn.i]!=0 ){
b62f651… stephan 2774 if( nextValid ){
b62f651… stephan 2775 sToken = sNext;
b62f651… stephan 2776 nextValid = 0;
b62f651… stephan 2777 }else{
b62f651… stephan 2778 GetNonspaceToken(&sIn,&sToken);
b62f651… stephan 2779 }
b62f651… stephan 2780 if( sToken.eType==TT_Id ){
b62f651… stephan 2781 int needFullDecl; /* True if we need to provide the full declaration,
b62f651… stephan 2782 ** not just the forward declaration */
b62f651… stephan 2783 Decl *pDecl; /* The declaration having the name in sToken */
b62f651… stephan 2784
b62f651… stephan 2785 /*
b62f651… stephan 2786 ** See if there is a declaration in the database with the name given
b62f651… stephan 2787 ** by sToken.
b62f651… stephan 2788 */
b62f651… stephan 2789 pDecl = FindDecl(sToken.zText,sToken.nText);
b62f651… stephan 2790 if( pDecl==0 ) continue;
b62f651… stephan 2791
b62f651… stephan 2792 /*
b62f651… stephan 2793 ** If we get this far, we've found an identifier that has a
b62f651… stephan 2794 ** declaration in the database. Now see if we the full declaration
b62f651… stephan 2795 ** or just a forward declaration.
b62f651… stephan 2796 */
b62f651… stephan 2797 GetNonspaceToken(&sIn,&sNext);
b62f651… stephan 2798 if( sNext.zText[0]=='*' ){
b62f651… stephan 2799 needFullDecl = 0;
b62f651… stephan 2800 }else{
b62f651… stephan 2801 needFullDecl = 1;
b62f651… stephan 2802 nextValid = sNext.eType==TT_Id;
b62f651… stephan 2803 }
b62f651… stephan 2804
b62f651… stephan 2805 /*
b62f651… stephan 2806 ** Generate the needed declaration.
b62f651… stephan 2807 */
b62f651… stephan 2808 DeclareObject(pDecl,pState,needFullDecl);
b62f651… stephan 2809 }else if( sToken.eType==TT_Preprocessor ){
b62f651… stephan 2810 sIn.i -= sToken.nText - 1;
b62f651… stephan 2811 }
b62f651… stephan 2812 }
b62f651… stephan 2813 /* printf("END SCANTEXT\n"); */
b62f651… stephan 2814 }
b62f651… stephan 2815
b62f651… stephan 2816 /*
b62f651… stephan 2817 ** Provide a full declaration to any object which so far has had only
b62f651… stephan 2818 ** a forward declaration.
b62f651… stephan 2819 */
b62f651… stephan 2820 static void CompleteForwardDeclarations(GenState *pState){
b62f651… stephan 2821 Decl *pDecl;
b62f651… stephan 2822 int progress;
b62f651… stephan 2823
b62f651… stephan 2824 do{
b62f651… stephan 2825 progress = 0;
b62f651… stephan 2826 for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
b62f651… stephan 2827 if( DeclHasProperty(pDecl,DP_Forward)
b62f651… stephan 2828 && !DeclHasProperty(pDecl,DP_Declared)
b62f651… stephan 2829 ){
b62f651… stephan 2830 DeclareObject(pDecl,pState,1);
b62f651… stephan 2831 progress = 1;
b62f651… stephan 2832 assert( DeclHasProperty(pDecl,DP_Declared) );
b62f651… stephan 2833 }
b62f651… stephan 2834 }
b62f651… stephan 2835 }while( progress );
b62f651… stephan 2836 }
b62f651… stephan 2837
b62f651… stephan 2838 /*
b62f651… stephan 2839 ** Generate an include file for the given source file. Return the number
b62f651… stephan 2840 ** of errors encountered.
b62f651… stephan 2841 **
b62f651… stephan 2842 ** if nolocal_flag is true, then we do not generate declarations for
b62f651… stephan 2843 ** objected marked DP_Local.
b62f651… stephan 2844 */
b62f651… stephan 2845 static int MakeHeader(InFile *pFile, FILE *report, int nolocal_flag){
b62f651… stephan 2846 int nErr = 0;
b62f651… stephan 2847 GenState sState;
b62f651… stephan 2848 String outStr;
b62f651… stephan 2849 IdentTable includeTable;
b62f651… stephan 2850 Ident *pId;
b62f651… stephan 2851 char *zNewVersion;
b62f651… stephan 2852 char *zOldVersion;
b62f651… stephan 2853
b62f651… stephan 2854 if( pFile->zHdr==0 || *pFile->zHdr==0 ) return 0;
b62f651… stephan 2855 sState.pStr = &outStr;
b62f651… stephan 2856 StringInit(&outStr);
b62f651… stephan 2857 StringAppend(&outStr,zTopLine,nTopLine);
b62f651… stephan 2858 sState.pTable = &includeTable;
b62f651… stephan 2859 memset(&includeTable,0,sizeof(includeTable));
b62f651… stephan 2860 sState.zIf = 0;
b62f651… stephan 2861 sState.nErr = 0;
b62f651… stephan 2862 sState.zFilename = pFile->zSrc;
b62f651… stephan 2863 sState.flags = pFile->flags & DP_Cplusplus;
b62f651… stephan 2864 ResetDeclFlags(nolocal_flag ? "no" : pFile->zSrc);
b62f651… stephan 2865 for(pId = pFile->idTable.pList; pId; pId=pId->pNext){
b62f651… stephan 2866 Decl *pDecl = FindDecl(pId->zName,0);
b62f651… stephan 2867 if( pDecl ){
b62f651… stephan 2868 DeclareObject(pDecl,&sState,1);
b62f651… stephan 2869 }
b62f651… stephan 2870 }
b62f651… stephan 2871 CompleteForwardDeclarations(&sState);
b62f651… stephan 2872 ChangeIfContext(0,&sState);
b62f651… stephan 2873 nErr += sState.nErr;
b62f651… stephan 2874 zOldVersion = ReadFile(pFile->zHdr);
b62f651… stephan 2875 zNewVersion = StringGet(&outStr);
b62f651… stephan 2876 if( report ) fprintf(report,"%s: ",pFile->zHdr);
b62f651… stephan 2877 if( zOldVersion==0 ){
b62f651… stephan 2878 if( report ) fprintf(report,"updated\n");
b62f651… stephan 2879 if( WriteFile(pFile->zHdr,zNewVersion) ){
b62f651… stephan 2880 fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
b62f651… stephan 2881 nErr++;
b62f651… stephan 2882 }
b62f651… stephan 2883 }else if( strncmp(zOldVersion,zTopLine,nTopLine)!=0 ){
b62f651… stephan 2884 if( report ) fprintf(report,"error!\n");
b62f651… stephan 2885 fprintf(stderr,
b62f651… stephan 2886 "%s: Can't overwrite this file because it wasn't previously\n"
b62f651… stephan 2887 "%*s generated by 'makeheaders'.\n",
b62f651… stephan 2888 pFile->zHdr, (int)strlen(pFile->zHdr), "");
b62f651… stephan 2889 nErr++;
b62f651… stephan 2890 }else if( strcmp(zOldVersion,zNewVersion)!=0 ){
b62f651… stephan 2891 if( report ) fprintf(report,"updated\n");
b62f651… stephan 2892 if( WriteFile(pFile->zHdr,zNewVersion) ){
b62f651… stephan 2893 fprintf(stderr,"%s: Can't write to file\n",pFile->zHdr);
b62f651… stephan 2894 nErr++;
b62f651… stephan 2895 }
b62f651… stephan 2896 }else if( report ){
b62f651… stephan 2897 fprintf(report,"unchanged\n");
b62f651… stephan 2898 }
b62f651… stephan 2899 SafeFree(zOldVersion);
b62f651… stephan 2900 IdentTableReset(&includeTable);
b62f651… stephan 2901 StringReset(&outStr);
b62f651… stephan 2902 return nErr;
b62f651… stephan 2903 }
b62f651… stephan 2904
b62f651… stephan 2905 /*
b62f651… stephan 2906 ** Generate a global header file -- a header file that contains all
b62f651… stephan 2907 ** declarations. If the forExport flag is true, then only those
b62f651… stephan 2908 ** objects that are exported are included in the header file.
b62f651… stephan 2909 */
b62f651… stephan 2910 static int MakeGlobalHeader(int forExport){
b62f651… stephan 2911 GenState sState;
b62f651… stephan 2912 String outStr;
b62f651… stephan 2913 IdentTable includeTable;
b62f651… stephan 2914 Decl *pDecl;
b62f651… stephan 2915
b62f651… stephan 2916 sState.pStr = &outStr;
b62f651… stephan 2917 StringInit(&outStr);
b62f651… stephan 2918 /* StringAppend(&outStr,zTopLine,nTopLine); */
b62f651… stephan 2919 sState.pTable = &includeTable;
b62f651… stephan 2920 memset(&includeTable,0,sizeof(includeTable));
b62f651… stephan 2921 sState.zIf = 0;
b62f651… stephan 2922 sState.nErr = 0;
b62f651… stephan 2923 sState.zFilename = "(all)";
b62f651… stephan 2924 sState.flags = 0;
b62f651… stephan 2925 ResetDeclFlags(0);
b62f651… stephan 2926 for(pDecl=pDeclFirst; pDecl; pDecl=pDecl->pNext){
b62f651… stephan 2927 if( forExport==0 || DeclHasProperty(pDecl,DP_Export) ){
b62f651… stephan 2928 DeclareObject(pDecl,&sState,1);
b62f651… stephan 2929 }
b62f651… stephan 2930 }
b62f651… stephan 2931 ChangeIfContext(0,&sState);
b62f651… stephan 2932 printf("%s",StringGet(&outStr));
b62f651… stephan 2933 IdentTableReset(&includeTable);
b62f651… stephan 2934 StringReset(&outStr);
b62f651… stephan 2935 return 0;
b62f651… stephan 2936 }
b62f651… stephan 2937
b62f651… stephan 2938 #ifdef DEBUG
b62f651… stephan 2939 /*
b62f651… stephan 2940 ** Return the number of characters in the given string prior to the
b62f651… stephan 2941 ** first newline.
b62f651… stephan 2942 */
b62f651… stephan 2943 static int ClipTrailingNewline(char *z){
b62f651… stephan 2944 int n = strlen(z);
b62f651… stephan 2945 while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ){ n--; }
b62f651… stephan 2946 return n;
b62f651… stephan 2947 }
b62f651… stephan 2948
b62f651… stephan 2949 /*
b62f651… stephan 2950 ** Dump the entire declaration list for debugging purposes
b62f651… stephan 2951 */
b62f651… stephan 2952 static void DumpDeclList(void){
b62f651… stephan 2953 Decl *pDecl;
b62f651… stephan 2954
b62f651… stephan 2955 for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){
b62f651… stephan 2956 printf("**** %s from file %s ****\n",pDecl->zName,pDecl->zFile);
b62f651… stephan 2957 if( pDecl->zIf ){
b62f651… stephan 2958 printf("If: [%.*s]\n",ClipTrailingNewline(pDecl->zIf),pDecl->zIf);
b62f651… stephan 2959 }
b62f651… stephan 2960 if( pDecl->zFwd ){
b62f651… stephan 2961 printf("Decl: [%.*s]\n",ClipTrailingNewline(pDecl->zFwd),pDecl->zFwd);
b62f651… stephan 2962 }
b62f651… stephan 2963 if( pDecl->zDecl ){
b62f651… stephan 2964 InsertExtraDecl(pDecl);
b62f651… stephan 2965 printf("Def: [%.*s]\n",ClipTrailingNewline(pDecl->zDecl),pDecl->zDecl);
b62f651… stephan 2966 }
b62f651… stephan 2967 if( pDecl->flags ){
b62f651… stephan 2968 static struct {
b62f651… stephan 2969 int mask;
b62f651… stephan 2970 char *desc;
b62f651… stephan 2971 } flagSet[] = {
b62f651… stephan 2972 { TY_Class, "class" },
b62f651… stephan 2973 { TY_Enumeration, "enum" },
b62f651… stephan 2974 { TY_Structure, "struct" },
b62f651… stephan 2975 { TY_Union, "union" },
b62f651… stephan 2976 { TY_Variable, "variable" },
b62f651… stephan 2977 { TY_Subroutine, "function" },
b62f651… stephan 2978 { TY_Typedef, "typedef" },
b62f651… stephan 2979 { TY_Macro, "macro" },
b62f651… stephan 2980 { DP_Export, "export" },
b62f651… stephan 2981 { DP_Local, "local" },
b62f651… stephan 2982 { DP_Cplusplus, "C++" },
b62f651… stephan 2983 };
b62f651… stephan 2984 int i;
b62f651… stephan 2985 printf("flags:");
b62f651… stephan 2986 for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){
b62f651… stephan 2987 if( flagSet[i].mask & pDecl->flags ){
b62f651… stephan 2988 printf(" %s", flagSet[i].desc);
b62f651… stephan 2989 }
b62f651… stephan 2990 }
b62f651… stephan 2991 printf("\n");
b62f651… stephan 2992 }
b62f651… stephan 2993 if( pDecl->pInclude ){
b62f651… stephan 2994 Include *p;
b62f651… stephan 2995 printf("includes:");
b62f651… stephan 2996 for(p=pDecl->pInclude; p; p=p->pNext){
b62f651… stephan 2997 printf(" %s",p->zFile);
b62f651… stephan 2998 }
b62f651… stephan 2999 printf("\n");
b62f651… stephan 3000 }
b62f651… stephan 3001 }
b62f651… stephan 3002 }
b62f651… stephan 3003 #endif
b62f651… stephan 3004
b62f651… stephan 3005 /*
b62f651… stephan 3006 ** When the "-doc" command-line option is used, this routine is called
b62f651… stephan 3007 ** to print all of the database information to standard output.
b62f651… stephan 3008 */
b62f651… stephan 3009 static void DocumentationDump(void){
b62f651… stephan 3010 Decl *pDecl;
b62f651… stephan 3011 static struct {
b62f651… stephan 3012 int mask;
b62f651… stephan 3013 char flag;
b62f651… stephan 3014 } flagSet[] = {
b62f651… stephan 3015 { TY_Class, 'c' },
b62f651… stephan 3016 { TY_Enumeration, 'e' },
b62f651… stephan 3017 { TY_Structure, 's' },
b62f651… stephan 3018 { TY_Union, 'u' },
b62f651… stephan 3019 { TY_Variable, 'v' },
b62f651… stephan 3020 { TY_Subroutine, 'f' },
b62f651… stephan 3021 { TY_Typedef, 't' },
b62f651… stephan 3022 { TY_Macro, 'm' },
b62f651… stephan 3023 { DP_Export, 'x' },
b62f651… stephan 3024 { DP_Local, 'l' },
b62f651… stephan 3025 { DP_Cplusplus, '+' },
b62f651… stephan 3026 };
b62f651… stephan 3027
b62f651… stephan 3028 for(pDecl = pDeclFirst; pDecl; pDecl=pDecl->pNext){
b62f651… stephan 3029 int i;
b62f651… stephan 3030 int nLabel = 0;
b62f651… stephan 3031 char *zDecl;
b62f651… stephan 3032 char zLabel[50];
b62f651… stephan 3033 for(i=0; i<sizeof(flagSet)/sizeof(flagSet[0]); i++){
b62f651… stephan 3034 if( DeclHasProperty(pDecl,flagSet[i].mask) ){
b62f651… stephan 3035 zLabel[nLabel++] = flagSet[i].flag;
b62f651… stephan 3036 }
b62f651… stephan 3037 }
b62f651… stephan 3038 if( nLabel==0 ) continue;
b62f651… stephan 3039 zLabel[nLabel] = 0;
b62f651… stephan 3040 InsertExtraDecl(pDecl);
b62f651… stephan 3041 zDecl = pDecl->zDecl;
b62f651… stephan 3042 if( zDecl==0 ) zDecl = pDecl->zFwd;
b62f651… stephan 3043 printf("%s %s %s %p %d %d %d %d %d\n",
b62f651… stephan 3044 pDecl->zName,
b62f651… stephan 3045 zLabel,
b62f651… stephan 3046 pDecl->zFile,
b62f651… stephan 3047 pDecl->pComment,
b62f651… stephan 3048 pDecl->pComment ? pDecl->pComment->nText+1 : 0,
b62f651… stephan 3049 pDecl->zIf ? (int)strlen(pDecl->zIf)+1 : 0,
b62f651… stephan 3050 zDecl ? (int)strlen(zDecl) : 0,
b62f651… stephan 3051 pDecl->pComment ? pDecl->pComment->nLine : 0,
b62f651… stephan 3052 pDecl->tokenCode.nText ? pDecl->tokenCode.nText+1 : 0
b62f651… stephan 3053 );
b62f651… stephan 3054 if( pDecl->pComment ){
b62f651… stephan 3055 printf("%.*s\n",pDecl->pComment->nText, pDecl->pComment->zText);
b62f651… stephan 3056 }
b62f651… stephan 3057 if( pDecl->zIf ){
b62f651… stephan 3058 printf("%s\n",pDecl->zIf);
b62f651… stephan 3059 }
b62f651… stephan 3060 if( zDecl ){
b62f651… stephan 3061 printf("%s",zDecl);
b62f651… stephan 3062 }
b62f651… stephan 3063 if( pDecl->tokenCode.nText ){
b62f651… stephan 3064 printf("%.*s\n",pDecl->tokenCode.nText, pDecl->tokenCode.zText);
b62f651… stephan 3065 }
b62f651… stephan 3066 }
b62f651… stephan 3067 }
b62f651… stephan 3068
b62f651… stephan 3069 /*
b62f651… stephan 3070 ** Given the complete text of an input file, this routine prints a
b62f651… stephan 3071 ** documentation record for the header comment at the beginning of the
b62f651… stephan 3072 ** file (if the file has a header comment.)
b62f651… stephan 3073 */
b62f651… stephan 3074 void PrintModuleRecord(const char *zFile, const char *zFilename){
b62f651… stephan 3075 int i;
b62f651… stephan 3076 static int addr = 5;
b62f651… stephan 3077 while( isspace(*zFile) ){ zFile++; }
b62f651… stephan 3078 if( *zFile!='/' || zFile[1]!='*' ) return;
b62f651… stephan 3079 for(i=2; zFile[i] && (zFile[i-1]!='/' || zFile[i-2]!='*'); i++){}
b62f651… stephan 3080 if( zFile[i]==0 ) return;
b62f651… stephan 3081 printf("%s M %s %d %d 0 0 0 0\n%.*s\n",
b62f651… stephan 3082 zFilename, zFilename, addr, i+1, i, zFile);
b62f651… stephan 3083 addr += 4;
b62f651… stephan 3084 }
b62f651… stephan 3085
b62f651… stephan 3086
b62f651… stephan 3087 /*
b62f651… stephan 3088 ** Given an input argument to the program, construct a new InFile
b62f651… stephan 3089 ** object.
b62f651… stephan 3090 */
b62f651… stephan 3091 static InFile *CreateInFile(char *zArg, int *pnErr){
b62f651… stephan 3092 int nSrc;
b62f651… stephan 3093 char *zSrc;
b62f651… stephan 3094 InFile *pFile;
b62f651… stephan 3095 int i;
b62f651… stephan 3096
b62f651… stephan 3097 /*
b62f651… stephan 3098 ** Get the name of the input file to be scanned. The input file is
b62f651… stephan 3099 ** everything before the first ':' or the whole file if no ':' is seen.
b62f651… stephan 3100 **
b62f651… stephan 3101 ** Except, on windows, ignore any ':' that occurs as the second character
b62f651… stephan 3102 ** since it might be part of the drive specifier. So really, the ":' has
b62f651… stephan 3103 ** to be the 3rd or later character in the name. This precludes 1-character
b62f651… stephan 3104 ** file names, which really should not be a problem.
b62f651… stephan 3105 */
b62f651… stephan 3106 zSrc = zArg;
b62f651… stephan 3107 for(nSrc=2; zSrc[nSrc] && zArg[nSrc]!=':'; nSrc++){}
b62f651… stephan 3108 pFile = SafeMalloc( sizeof(InFile) );
b62f651… stephan 3109 memset(pFile,0,sizeof(InFile));
b62f651… stephan 3110 pFile->zSrc = StrDup(zSrc,nSrc);
b62f651… stephan 3111
b62f651… stephan 3112 /* Figure out if we are dealing with C or C++ code. Assume any
b62f651… stephan 3113 ** file with ".c" or ".h" is C code and all else is C++.
b62f651… stephan 3114 */
b62f651… stephan 3115 if( nSrc>2 && zSrc[nSrc-2]=='.' && (zSrc[nSrc-1]=='c' || zSrc[nSrc-1]=='h')){
b62f651… stephan 3116 pFile->flags &= ~DP_Cplusplus;
b62f651… stephan 3117 }else{
b62f651… stephan 3118 pFile->flags |= DP_Cplusplus;
b62f651… stephan 3119 }
b62f651… stephan 3120
b62f651… stephan 3121 /*
b62f651… stephan 3122 ** If a separate header file is specified, use it
b62f651… stephan 3123 */
b62f651… stephan 3124 if( zSrc[nSrc]==':' ){
b62f651… stephan 3125 int nHdr;
b62f651… stephan 3126 char *zHdr;
b62f651… stephan 3127 zHdr = &zSrc[nSrc+1];
b62f651… stephan 3128 for(nHdr=0; zHdr[nHdr]; nHdr++){}
b62f651… stephan 3129 pFile->zHdr = StrDup(zHdr,nHdr);
b62f651… stephan 3130 }
b62f651… stephan 3131
b62f651… stephan 3132 /* Look for any 'c' or 'C' in the suffix of the file name and change
b62f651… stephan 3133 ** that character to 'h' or 'H' respectively. If no 'c' or 'C' is found,
b62f651… stephan 3134 ** then assume we are dealing with a header.
b62f651… stephan 3135 */
b62f651… stephan 3136 else{
b62f651… stephan 3137 int foundC = 0;
b62f651… stephan 3138 pFile->zHdr = StrDup(zSrc,nSrc);
b62f651… stephan 3139 for(i = nSrc-1; i>0 && pFile->zHdr[i]!='.'; i--){
b62f651… stephan 3140 if( pFile->zHdr[i]=='c' ){
b62f651… stephan 3141 foundC = 1;
b62f651… stephan 3142 pFile->zHdr[i] = 'h';
b62f651… stephan 3143 }else if( pFile->zHdr[i]=='C' ){
b62f651… stephan 3144 foundC = 1;
b62f651… stephan 3145 pFile->zHdr[i] = 'H';
b62f651… stephan 3146 }
b62f651… stephan 3147 }
b62f651… stephan 3148 if( !foundC ){
b62f651… stephan 3149 SafeFree(pFile->zHdr);
b62f651… stephan 3150 pFile->zHdr = 0;
b62f651… stephan 3151 }
b62f651… stephan 3152 }
b62f651… stephan 3153
b62f651… stephan 3154 /*
b62f651… stephan 3155 ** If pFile->zSrc contains no 'c' or 'C' in its extension, it
b62f651… stephan 3156 ** must be a header file. In that case, we need to set the
b62f651… stephan 3157 ** PS_Interface flag.
b62f651… stephan 3158 */
b62f651… stephan 3159 pFile->flags |= PS_Interface;
b62f651… stephan 3160 for(i=nSrc-1; i>0 && zSrc[i]!='.'; i--){
b62f651… stephan 3161 if( zSrc[i]=='c' || zSrc[i]=='C' ){
b62f651… stephan 3162 pFile->flags &= ~PS_Interface;
b62f651… stephan 3163 break;
b62f651… stephan 3164 }
b62f651… stephan 3165 }
b62f651… stephan 3166
b62f651… stephan 3167 /* Done!
b62f651… stephan 3168 */
b62f651… stephan 3169 return pFile;
b62f651… stephan 3170 }
b62f651… stephan 3171
c0b9b44… stephan 3172 /* Local strcpy() clone to squelch an unwarranted warning from OpenBSD. */
c0b9b44… stephan 3173 static void local_strcpy(char *dest, const char *src){
c0b9b44… stephan 3174 while( (*(dest++) = *(src++))!=0 ){}
c0b9b44… stephan 3175 }
c0b9b44… stephan 3176
b62f651… stephan 3177 /* MS-Windows and MS-DOS both have the following serious OS bug: the
b62f651… stephan 3178 ** length of a command line is severely restricted. But this program
b62f651… stephan 3179 ** occasionally requires long command lines. Hence the following
b62f651… stephan 3180 ** work around.
b62f651… stephan 3181 **
b62f651… stephan 3182 ** If the parameters "-f FILENAME" appear anywhere on the command line,
b62f651… stephan 3183 ** then the named file is scanned for additional command line arguments.
b62f651… stephan 3184 ** These arguments are substituted in place of the "FILENAME" argument
b62f651… stephan 3185 ** in the original argument list.
b62f651… stephan 3186 **
b62f651… stephan 3187 ** This first parameter to this routine is the index of the "-f"
b62f651… stephan 3188 ** parameter in the argv[] array. The argc and argv are passed by
b62f651… stephan 3189 ** pointer so that they can be changed.
b62f651… stephan 3190 **
b62f651… stephan 3191 ** Parsing of the parameters in the file is very simple. Parameters
b62f651… stephan 3192 ** can be separated by any amount of white-space (including newlines
b62f651… stephan 3193 ** and carriage returns.) There are now quoting characters of any
b62f651… stephan 3194 ** kind. The length of a token is limited to about 1000 characters.
b62f651… stephan 3195 */
b62f651… stephan 3196 static void AddParameters(int index, int *pArgc, char ***pArgv){
b62f651… stephan 3197 int argc = *pArgc; /* The original argc value */
b62f651… stephan 3198 char **argv = *pArgv; /* The original argv value */
b62f651… stephan 3199 int newArgc; /* Value for argc after inserting new arguments */
b62f651… stephan 3200 char **zNew = 0; /* The new argv after this routine is done */
b62f651… stephan 3201 char *zFile; /* Name of the input file */
b62f651… stephan 3202 int nNew = 0; /* Number of new entries in the argv[] file */
b62f651… stephan 3203 int nAlloc = 0; /* Space allocated for zNew[] */
b62f651… stephan 3204 int i; /* Loop counter */
b62f651… stephan 3205 int n; /* Number of characters in a new argument */
b62f651… stephan 3206 int c; /* Next character of input */
b62f651… stephan 3207 int startOfLine = 1; /* True if we are where '#' can start a comment */
b62f651… stephan 3208 FILE *in; /* The input file */
b62f651… stephan 3209 char zBuf[1000]; /* A single argument is accumulated here */
b62f651… stephan 3210
b62f651… stephan 3211 if( index+1==argc ) return;
b62f651… stephan 3212 zFile = argv[index+1];
b62f651… stephan 3213 in = fopen(zFile,"r");
b62f651… stephan 3214 if( in==0 ){
b62f651… stephan 3215 fprintf(stderr,"Can't open input file \"%s\"\n",zFile);
b62f651… stephan 3216 exit(1);
b62f651… stephan 3217 }
b62f651… stephan 3218 c = ' ';
b62f651… stephan 3219 while( c!=EOF ){
b62f651… stephan 3220 while( c!=EOF && isspace(c) ){
b62f651… stephan 3221 if( c=='\n' ){
b62f651… stephan 3222 startOfLine = 1;
b62f651… stephan 3223 }
b62f651… stephan 3224 c = getc(in);
b62f651… stephan 3225 if( startOfLine && c=='#' ){
b62f651… stephan 3226 while( c!=EOF && c!='\n' ){
b62f651… stephan 3227 c = getc(in);
b62f651… stephan 3228 }
b62f651… stephan 3229 }
b62f651… stephan 3230 }
b62f651… stephan 3231 n = 0;
b62f651… stephan 3232 while( c!=EOF && !isspace(c) ){
b62f651… stephan 3233 if( n<sizeof(zBuf)-1 ){ zBuf[n++] = c; }
b62f651… stephan 3234 startOfLine = 0;
b62f651… stephan 3235 c = getc(in);
b62f651… stephan 3236 }
b62f651… stephan 3237 zBuf[n] = 0;
b62f651… stephan 3238 if( n>0 ){
b62f651… stephan 3239 nNew++;
b62f651… stephan 3240 if( nNew + argc > nAlloc ){
b62f651… stephan 3241 if( nAlloc==0 ){
b62f651… stephan 3242 nAlloc = 100 + argc;
b62f651… stephan 3243 zNew = malloc( sizeof(char*) * nAlloc );
b62f651… stephan 3244 }else{
b62f651… stephan 3245 nAlloc *= 2;
b62f651… stephan 3246 zNew = realloc( zNew, sizeof(char*) * nAlloc );
b62f651… stephan 3247 }
b62f651… stephan 3248 }
b62f651… stephan 3249 if( zNew ){
b62f651… stephan 3250 int j = nNew + index;
b62f651… stephan 3251 zNew[j] = malloc( n + 1 );
b62f651… stephan 3252 if( zNew[j] ){
c0b9b44… stephan 3253 local_strcpy( zNew[j], zBuf );
b62f651… stephan 3254 }
b62f651… stephan 3255 }
b62f651… stephan 3256 }
b62f651… stephan 3257 }
b62f651… stephan 3258 fclose(in);
b62f651… stephan 3259 newArgc = argc + nNew - 1;
b62f651… stephan 3260 for(i=0; i<=index; i++){
b62f651… stephan 3261 zNew[i] = argv[i];
b62f651… stephan 3262 }
b62f651… stephan 3263 for(i=nNew + index + 1; i<newArgc; i++){
b62f651… stephan 3264 zNew[i] = argv[i + 1 - nNew];
b62f651… stephan 3265 }
b62f651… stephan 3266 zNew[newArgc] = 0;
b62f651… stephan 3267 *pArgc = newArgc;
b62f651… stephan 3268 *pArgv = zNew;
b62f651… stephan 3269 }
b62f651… stephan 3270
b62f651… stephan 3271 #ifdef NOT_USED
b62f651… stephan 3272 /*
b62f651… stephan 3273 ** Return the time that the given file was last modified. If we can't
b62f651… stephan 3274 ** locate the file (because, for example, it doesn't exist), then
b62f651… stephan 3275 ** return 0.
b62f651… stephan 3276 */
b62f651… stephan 3277 static unsigned int ModTime(const char *zFilename){
b62f651… stephan 3278 unsigned int mTime = 0;
b62f651… stephan 3279 struct stat sStat;
b62f651… stephan 3280 if( stat(zFilename,&sStat)==0 ){
b62f651… stephan 3281 mTime = sStat.st_mtime;
b62f651… stephan 3282 }
b62f651… stephan 3283 return mTime;
b62f651… stephan 3284 }
b62f651… stephan 3285 #endif
b62f651… stephan 3286
b62f651… stephan 3287 /*
b62f651… stephan 3288 ** Print a usage comment for this program.
b62f651… stephan 3289 */
b62f651… stephan 3290 static void Usage(const char *argv0, const char *argvN){
b62f651… stephan 3291 fprintf(stderr,"%s: Illegal argument \"%s\"\n",argv0,argvN);
b62f651… stephan 3292 fprintf(stderr,"Usage: %s [options] filename...\n"
b62f651… stephan 3293 "Options:\n"
b62f651… stephan 3294 " -h Generate a single .h to standard output.\n"
b62f651… stephan 3295 " -H Like -h, but only output EXPORT declarations.\n"
b62f651… stephan 3296 " -v (verbose) Write status information to the screen.\n"
b62f651… stephan 3297 " -doc Generate no header files. Instead, output information\n"
b62f651… stephan 3298 " that can be used by an automatic program documentation\n"
b62f651… stephan 3299 " and cross-reference generator.\n"
b62f651… stephan 3300 " -local Generate prototypes for \"static\" functions and\n"
b62f651… stephan 3301 " procedures.\n"
b62f651… stephan 3302 " -f FILE Read additional command-line arguments from the file named\n"
b62f651… stephan 3303 " \"FILE\".\n"
b62f651… stephan 3304 #ifdef DEBUG
b62f651… stephan 3305 " -! MASK Set the debugging mask to the number \"MASK\".\n"
b62f651… stephan 3306 #endif
b62f651… stephan 3307 " -- Treat all subsequent comment-line parameters as filenames,\n"
b62f651… stephan 3308 " even if they begin with \"-\".\n",
b62f651… stephan 3309 argv0
b62f651… stephan 3310 );
b62f651… stephan 3311 }
b62f651… stephan 3312
b62f651… stephan 3313 /*
b62f651… stephan 3314 ** The following text contains a few simple #defines that we want
b62f651… stephan 3315 ** to be available to every file.
b62f651… stephan 3316 */
b62f651… stephan 3317 static const char zInit[] =
b62f651… stephan 3318 "#define INTERFACE 0\n"
b62f651… stephan 3319 "#define EXPORT_INTERFACE 0\n"
b62f651… stephan 3320 "#define LOCAL_INTERFACE 0\n"
b62f651… stephan 3321 "#define EXPORT\n"
b62f651… stephan 3322 "#define LOCAL static\n"
b62f651… stephan 3323 "#define PUBLIC\n"
b62f651… stephan 3324 "#define PRIVATE\n"
b62f651… stephan 3325 "#define PROTECTED\n"
b62f651… stephan 3326 ;
b62f651… stephan 3327
b62f651… stephan 3328 #if TEST==0
b62f651… stephan 3329 int main(int argc, char **argv){
b62f651… stephan 3330 int i; /* Loop counter */
b62f651… stephan 3331 int nErr = 0; /* Number of errors encountered */
b62f651… stephan 3332 Token *pList; /* List of input tokens for one file */
b62f651… stephan 3333 InFile *pFileList = 0;/* List of all input files */
b62f651… stephan 3334 InFile *pTail = 0; /* Last file on the list */
b62f651… stephan 3335 InFile *pFile; /* for looping over the file list */
b62f651… stephan 3336 int h_flag = 0; /* True if -h is present. Output unified header */
b62f651… stephan 3337 int H_flag = 0; /* True if -H is present. Output EXPORT header */
b62f651… stephan 3338 int v_flag = 0; /* Verbose */
b62f651… stephan 3339 int noMoreFlags; /* True if -- has been seen. */
b62f651… stephan 3340 FILE *report; /* Send progress reports to this, if not NULL */
b62f651… stephan 3341
b62f651… stephan 3342 noMoreFlags = 0;
b62f651… stephan 3343 for(i=1; i<argc; i++){
b62f651… stephan 3344 if( argv[i][0]=='-' && !noMoreFlags ){
b62f651… stephan 3345 switch( argv[i][1] ){
b62f651… stephan 3346 case 'h': h_flag = 1; break;
b62f651… stephan 3347 case 'H': H_flag = 1; break;
b62f651… stephan 3348 case 'v': v_flag = 1; break;
b62f651… stephan 3349 case 'd': doc_flag = 1; proto_static = 1; break;
b62f651… stephan 3350 case 'l': proto_static = 1; break;
b62f651… stephan 3351 case 'f': AddParameters(i, &argc, &argv); break;
b62f651… stephan 3352 case '-': noMoreFlags = 1; break;
b62f651… stephan 3353 #ifdef DEBUG
b62f651… stephan 3354 case '!': i++; debugMask = strtol(argv[i],0,0); break;
b62f651… stephan 3355 #endif
b62f651… stephan 3356 default: Usage(argv[0],argv[i]); return 1;
b62f651… stephan 3357 }
b62f651… stephan 3358 }else{
b62f651… stephan 3359 pFile = CreateInFile(argv[i],&nErr);
b62f651… stephan 3360 if( pFile ){
b62f651… stephan 3361 if( pFileList ){
b62f651… stephan 3362 pTail->pNext = pFile;
b62f651… stephan 3363 pTail = pFile;
b62f651… stephan 3364 }else{
b62f651… stephan 3365 pFileList = pTail = pFile;
b62f651… stephan 3366 }
b62f651… stephan 3367 }
b62f651… stephan 3368 }
b62f651… stephan 3369 }
b62f651… stephan 3370 if( h_flag && H_flag ){
b62f651… stephan 3371 h_flag = 0;
b62f651… stephan 3372 }
b62f651… stephan 3373 if( v_flag ){
b62f651… stephan 3374 report = (h_flag || H_flag) ? stderr : stdout;
b62f651… stephan 3375 }else{
b62f651… stephan 3376 report = 0;
b62f651… stephan 3377 }
b62f651… stephan 3378 if( nErr>0 ){
b62f651… stephan 3379 return nErr;
b62f651… stephan 3380 }
b62f651… stephan 3381 for(pFile=pFileList; pFile; pFile=pFile->pNext){
b62f651… stephan 3382 char *zFile;
b62f651… stephan 3383
b62f651… stephan 3384 zFilename = pFile->zSrc;
b62f651… stephan 3385 if( zFilename==0 ) continue;
b62f651… stephan 3386 zFile = ReadFile(zFilename);
b62f651… stephan 3387 if( zFile==0 ){
b62f651… stephan 3388 fprintf(stderr,"Can't read input file \"%s\"\n",zFilename);
b62f651… stephan 3389 nErr++;
b62f651… stephan 3390 continue;
b62f651… stephan 3391 }
b62f651… stephan 3392 if( strncmp(zFile,zTopLine,nTopLine)==0 ){
b62f651… stephan 3393 pFile->zSrc = 0;
b62f651… stephan 3394 }else{
b62f651… stephan 3395 if( report ) fprintf(report,"Reading %s...\n",zFilename);
b62f651… stephan 3396 pList = TokenizeFile(zFile,&pFile->idTable);
b62f651… stephan 3397 if( pList ){
b62f651… stephan 3398 nErr += ParseFile(pList,pFile->flags);
b62f651… stephan 3399 FreeTokenList(pList);
b62f651… stephan 3400 }else if( zFile[0]==0 ){
b62f651… stephan 3401 fprintf(stderr,"Input file \"%s\" is empty.\n", zFilename);
b62f651… stephan 3402 nErr++;
b62f651… stephan 3403 }else{
b62f651… stephan 3404 fprintf(stderr,"Errors while processing \"%s\"\n", zFilename);
b62f651… stephan 3405 nErr++;
b62f651… stephan 3406 }
b62f651… stephan 3407 }
b62f651… stephan 3408 if( !doc_flag ) SafeFree(zFile);
b62f651… stephan 3409 if( doc_flag ) PrintModuleRecord(zFile,zFilename);
b62f651… stephan 3410 }
b62f651… stephan 3411 if( nErr>0 ){
b62f651… stephan 3412 return nErr;
b62f651… stephan 3413 }
b62f651… stephan 3414 #ifdef DEBUG
b62f651… stephan 3415 if( debugMask & DECL_DUMP ){
b62f651… stephan 3416 DumpDeclList();
b62f651… stephan 3417 return nErr;
b62f651… stephan 3418 }
b62f651… stephan 3419 #endif
b62f651… stephan 3420 if( doc_flag ){
b62f651… stephan 3421 DocumentationDump();
b62f651… stephan 3422 return nErr;
b62f651… stephan 3423 }
b62f651… stephan 3424 zFilename = "--internal--";
b62f651… stephan 3425 pList = TokenizeFile(zInit,0);
b62f651… stephan 3426 if( pList==0 ){
b62f651… stephan 3427 return nErr+1;
b62f651… stephan 3428 }
b62f651… stephan 3429 ParseFile(pList,PS_Interface);
b62f651… stephan 3430 FreeTokenList(pList);
b62f651… stephan 3431 if( h_flag || H_flag ){
b62f651… stephan 3432 nErr += MakeGlobalHeader(H_flag);
b62f651… stephan 3433 }else{
b62f651… stephan 3434 for(pFile=pFileList; pFile; pFile=pFile->pNext){
b62f651… stephan 3435 if( pFile->zSrc==0 ) continue;
b62f651… stephan 3436 nErr += MakeHeader(pFile,report,0);
b62f651… stephan 3437 }
b62f651… stephan 3438 }
b62f651… stephan 3439 return nErr;
b62f651… stephan 3440 }
b62f651… stephan 3441 #endif

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button