|
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 |