1 | /* Program to extract function declarations from C/C++ source code |
---|
2 | * |
---|
3 | * Written by Eric R. Smith and placed in the public domain |
---|
4 | * |
---|
5 | * Thanks to: |
---|
6 | * |
---|
7 | * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles |
---|
8 | * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix |
---|
9 | * manual page, and some ANSI and C++ improvements. |
---|
10 | * Skip Gilbrech for code to skip parameter names in prototypes. |
---|
11 | * ... and many others for helpful comments and suggestions. |
---|
12 | * |
---|
13 | * Many extension were made for use in ARB build process |
---|
14 | * by Ralf Westram <ralf@arb-home.de> |
---|
15 | */ |
---|
16 | |
---|
17 | #include <cstddef> |
---|
18 | #include <cstdlib> |
---|
19 | #include <cassert> |
---|
20 | #include <unistd.h> |
---|
21 | #include <cstdio> |
---|
22 | #include <cctype> |
---|
23 | #include <cstring> |
---|
24 | #include <cstdarg> |
---|
25 | |
---|
26 | #include <arb_early_check.h> |
---|
27 | #include <attributes.h> |
---|
28 | |
---|
29 | #include <arb_simple_assert.h> |
---|
30 | #include <arbtools.h> |
---|
31 | |
---|
32 | #define mp_assert(cond) arb_assert(cond) |
---|
33 | |
---|
34 | static void Version(); |
---|
35 | |
---|
36 | #if defined(DEBUG) |
---|
37 | // #define DEBUG_PRINTS |
---|
38 | #endif // DEBUG |
---|
39 | |
---|
40 | #ifdef DEBUG_PRINTS |
---|
41 | #define DEBUG_PRINT(s) fputs((s), stderr) |
---|
42 | #define DEBUG_PRINT_STRING(name, str) fprintf(stderr, "%s'%s'\n", name, str) |
---|
43 | #else |
---|
44 | #define DEBUG_PRINT(s) |
---|
45 | #define DEBUG_PRINT_STRING(name, str) |
---|
46 | #endif |
---|
47 | |
---|
48 | #define PRINT(s) fputs((s), stdout) |
---|
49 | |
---|
50 | #define IS_CSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_')) |
---|
51 | #define ABORTED ((Word *) -1) |
---|
52 | #define MAXPARAM 20 // max. number of parameters to a function |
---|
53 | #define NEWBUFSIZ (20480*sizeof(char)) // new buffer size |
---|
54 | |
---|
55 | |
---|
56 | static int donum = 0; // print line numbers? |
---|
57 | static int define_macro = 0; // define macro for K&R prototypes? |
---|
58 | static int use_macro = 0; // use a macro to support K&R prototypes? |
---|
59 | static int use_main = 0; // add prototype for main? |
---|
60 | static int no_parm_names = 0; // no parm names - only types |
---|
61 | static int print_extern = 0; // use "extern" before function declarations |
---|
62 | static int dont_promote = 0; // don't promote prototypes |
---|
63 | static int promote_lines = 0; // promote 'AISC_MKPT_PROMOTE'-lines |
---|
64 | static int aisc = 0; // aisc compatible output |
---|
65 | static int cansibycplus = 0; // produce extern "C" |
---|
66 | static int promote_extern_c = 0; // produce extern "C" into prototype |
---|
67 | static int extern_c_seen = 0; // true if extern "C" was parsed |
---|
68 | static int search__ATTR__ = 0; // search for ARB-__attribute__-macros (__ATTR__) ? |
---|
69 | |
---|
70 | static const char *include_wrapper = NULp; // add include wrapper (contains name of header or NULp) |
---|
71 | |
---|
72 | static int inquote = 0; // in a quote?? |
---|
73 | static int newline_seen = 1; // are we at the start of a line |
---|
74 | static int glastc = ' '; // last char. seen by getsym() |
---|
75 | |
---|
76 | static char *current_file = NULp; // name of current file |
---|
77 | static char *current_dir = NULp; // name of current directory |
---|
78 | static const char *header_comment = NULp; // comment written into header |
---|
79 | static long linenum = 1L; // line number in current file |
---|
80 | |
---|
81 | static char const *macro_name = "P_"; // macro to use for prototypes |
---|
82 | static char const *ourname; // our name, from argv[] array |
---|
83 | |
---|
84 | // ------------------------------------------------------------ |
---|
85 | |
---|
86 | static void errorAt(long line, const char *msg) { |
---|
87 | printf("\n" |
---|
88 | "#line %li \"%s/%s\"\n" |
---|
89 | "#error in aisc_mkpt: %s\n", |
---|
90 | line, |
---|
91 | current_dir, |
---|
92 | current_file, |
---|
93 | msg); |
---|
94 | } |
---|
95 | |
---|
96 | static void error(const char *msg) { |
---|
97 | errorAt(linenum, msg); |
---|
98 | } |
---|
99 | |
---|
100 | static void errorf(const char *format, ...) __attribute__((format(__printf__, 1, 2))); |
---|
101 | static void errorf(const char *format, ...) { |
---|
102 | const int BUFFERSIZE = 1000; |
---|
103 | char buffer[BUFFERSIZE]; |
---|
104 | va_list args; |
---|
105 | |
---|
106 | va_start(args, format); |
---|
107 | int printed = vsprintf(buffer, format, args); |
---|
108 | if (printed >= BUFFERSIZE) { |
---|
109 | fputs("buffer overflow\n", stderr); |
---|
110 | exit(EXIT_FAILURE); |
---|
111 | } |
---|
112 | va_end(args); |
---|
113 | |
---|
114 | error(buffer); |
---|
115 | } |
---|
116 | |
---|
117 | // ------------------------------------------------------------ |
---|
118 | |
---|
119 | struct SymPart { |
---|
120 | char *part; |
---|
121 | int len; // len of part |
---|
122 | bool atStart; // part has to match at start of name |
---|
123 | |
---|
124 | SymPart *And; |
---|
125 | SymPart *next; |
---|
126 | }; |
---|
127 | |
---|
128 | static SymPart* makeSymPart(char *token) { |
---|
129 | SymPart *sp = (SymPart*)malloc(sizeof(*sp)); |
---|
130 | |
---|
131 | sp->atStart = token[0] == '^'; |
---|
132 | char *part = sp->atStart ? token+1 : token; |
---|
133 | char *plus = strchr(part, '+'); |
---|
134 | |
---|
135 | if (plus) { |
---|
136 | *plus++ = 0; |
---|
137 | sp->And = makeSymPart(plus); |
---|
138 | } |
---|
139 | else { |
---|
140 | sp->And = NULp; |
---|
141 | } |
---|
142 | sp->part = strdup(part); |
---|
143 | sp->len = strlen(sp->part); |
---|
144 | |
---|
145 | sp->next = NULp; |
---|
146 | |
---|
147 | return sp; |
---|
148 | } |
---|
149 | |
---|
150 | static void addSymParts(SymPart*& symParts, const char *parts) { |
---|
151 | char *p = strdup(parts); |
---|
152 | const char *sep = ","; |
---|
153 | char *s = strtok(p, sep); |
---|
154 | |
---|
155 | while (s) { |
---|
156 | SymPart *sp = makeSymPart(s); |
---|
157 | sp->next = symParts; |
---|
158 | symParts = sp; |
---|
159 | s = strtok(NULp, sep); |
---|
160 | } |
---|
161 | |
---|
162 | free(p); |
---|
163 | } |
---|
164 | |
---|
165 | static bool matchesSymPart(const SymPart* symParts, const char *name) { |
---|
166 | const SymPart *sp = symParts; |
---|
167 | bool matches = false; |
---|
168 | |
---|
169 | while (sp && !matches) { |
---|
170 | if (sp->atStart) { |
---|
171 | matches = strncmp(name, sp->part, sp->len) == 0; |
---|
172 | } |
---|
173 | else { |
---|
174 | matches = strstr(name, sp->part); |
---|
175 | } |
---|
176 | if (matches && sp->And) matches = matchesSymPart(sp->And, name); |
---|
177 | sp = sp->next; |
---|
178 | } |
---|
179 | |
---|
180 | return matches; |
---|
181 | } |
---|
182 | |
---|
183 | static void freeSymParts(SymPart*& symParts) { |
---|
184 | SymPart *next = symParts; |
---|
185 | |
---|
186 | while (next) { |
---|
187 | SymPart *del = next; |
---|
188 | next = del->next; |
---|
189 | |
---|
190 | if (del->And) freeSymParts(del->And); |
---|
191 | free(del->part); |
---|
192 | free(del); |
---|
193 | } |
---|
194 | |
---|
195 | symParts = NULp; |
---|
196 | } |
---|
197 | |
---|
198 | // ---------------------------------------- |
---|
199 | |
---|
200 | static SymPart *requiredSymParts = NULp; // only create prototypes if function-name matches one of these parts |
---|
201 | static SymPart *excludedSymParts = NULp; // DONT create prototypes if function-name matches one of these parts |
---|
202 | |
---|
203 | inline void addRequiredSymParts(const char *parts) { addSymParts(requiredSymParts, parts); } |
---|
204 | inline void addExcludedSymParts(const char *parts) { addSymParts(excludedSymParts, parts); } |
---|
205 | |
---|
206 | inline void freeRequiredSymParts() { freeSymParts(requiredSymParts); } |
---|
207 | inline void freeExcludedSymParts() { freeSymParts(excludedSymParts); } |
---|
208 | |
---|
209 | inline bool hasRequiredSymPart(const char *name) { return !requiredSymParts || matchesSymPart(requiredSymParts, name); } |
---|
210 | inline bool hasExcludedSymPart(const char *name) { return excludedSymParts && matchesSymPart(excludedSymParts, name); } |
---|
211 | |
---|
212 | inline bool wantPrototypeFor(const char *name) { |
---|
213 | return hasRequiredSymPart(name) && !hasExcludedSymPart(name); |
---|
214 | } |
---|
215 | |
---|
216 | // ---------------------------------------- |
---|
217 | |
---|
218 | struct Word { |
---|
219 | Word *next; |
---|
220 | char string[1]; |
---|
221 | }; |
---|
222 | |
---|
223 | // Routines for manipulating lists of words. |
---|
224 | |
---|
225 | static Word *word_alloc(const char *s) { |
---|
226 | Word *w; |
---|
227 | |
---|
228 | /* note that sizeof(Word) already contains space for a terminating null |
---|
229 | * however, we add 1 so that typefixhack can promote "float" to "double" |
---|
230 | * by just doing a strcpy. |
---|
231 | */ |
---|
232 | w = (Word *) malloc(sizeof(Word) + strlen(s) + 1); |
---|
233 | strcpy(w->string, s); |
---|
234 | w->next = NULp; |
---|
235 | return w; |
---|
236 | } |
---|
237 | |
---|
238 | static void word_free(Word*& word) { |
---|
239 | Word *w = word; |
---|
240 | while (w) { |
---|
241 | Word *oldw = w; |
---|
242 | w = w->next; |
---|
243 | free(oldw); |
---|
244 | } |
---|
245 | word = NULp; |
---|
246 | } |
---|
247 | |
---|
248 | static int List_len(Word *w) { |
---|
249 | // return the length of a list |
---|
250 | // empty words are not counted |
---|
251 | int count = 0; |
---|
252 | |
---|
253 | while (w) { |
---|
254 | if (*w->string) count++; |
---|
255 | w = w->next; |
---|
256 | } |
---|
257 | return count; |
---|
258 | } |
---|
259 | |
---|
260 | static Word *word_append(Word *w1, Word *w2) { |
---|
261 | // Append two lists, and return the result |
---|
262 | |
---|
263 | Word *r, *w; |
---|
264 | |
---|
265 | r = w = word_alloc(""); |
---|
266 | |
---|
267 | while (w1) { |
---|
268 | w->next = word_alloc(w1->string); |
---|
269 | w = w->next; |
---|
270 | w1 = w1->next; |
---|
271 | } |
---|
272 | while (w2) { |
---|
273 | w->next = word_alloc(w2->string); |
---|
274 | w = w->next; |
---|
275 | w2 = w2->next; |
---|
276 | } |
---|
277 | |
---|
278 | return r; |
---|
279 | } |
---|
280 | |
---|
281 | static int foundin(Word *w1, Word *w2) { |
---|
282 | // see if the last entry in w2 is in w1 |
---|
283 | |
---|
284 | while (w2->next) |
---|
285 | w2 = w2->next; |
---|
286 | |
---|
287 | while (w1) { |
---|
288 | if (strcmp(w1->string, w2->string)==0) |
---|
289 | return 1; |
---|
290 | w1 = w1->next; |
---|
291 | } |
---|
292 | return 0; |
---|
293 | } |
---|
294 | |
---|
295 | static void addword(Word *w, const char *s) { |
---|
296 | // add the string s to the given list of words |
---|
297 | |
---|
298 | while (w->next) w = w->next; |
---|
299 | w->next = word_alloc(s); |
---|
300 | |
---|
301 | DEBUG_PRINT("addword: '"); |
---|
302 | DEBUG_PRINT(s); |
---|
303 | DEBUG_PRINT("'\n"); |
---|
304 | } |
---|
305 | |
---|
306 | static void typefixhack(Word *w) { |
---|
307 | // typefixhack: promote formal parameters of type "char", "unsigned char", |
---|
308 | // "short", or "unsigned short" to "int". |
---|
309 | |
---|
310 | Word *oldw = NULp; |
---|
311 | |
---|
312 | if (dont_promote) |
---|
313 | return; |
---|
314 | |
---|
315 | while (w) { |
---|
316 | if (*w->string) { |
---|
317 | if ((strcmp(w->string, "char")==0 || strcmp(w->string, "short")==0) && (List_len(w->next) < 2)) { |
---|
318 | // delete any "unsigned" specifier present -- yes, it's supposed to do this |
---|
319 | if (oldw && strcmp(oldw->string, "unsigned")==0) { |
---|
320 | oldw->next = w->next; |
---|
321 | free(w); |
---|
322 | w = oldw; |
---|
323 | } |
---|
324 | strcpy(w->string, "int"); |
---|
325 | } |
---|
326 | else if (strcmp(w->string, "float")==0 && List_len(w->next) < 2) { |
---|
327 | strcpy(w->string, "double"); |
---|
328 | } |
---|
329 | } |
---|
330 | w = w->next; |
---|
331 | } |
---|
332 | } |
---|
333 | |
---|
334 | static int ngetc(FILE *f) { |
---|
335 | // read a character: if it's a newline, increment the line count |
---|
336 | |
---|
337 | int c; |
---|
338 | |
---|
339 | c = getc(f); |
---|
340 | if (c == '\n') linenum++; |
---|
341 | |
---|
342 | return c; |
---|
343 | } |
---|
344 | |
---|
345 | #define MAX_COMMENT_SIZE 10000 |
---|
346 | |
---|
347 | static char last_comment[MAX_COMMENT_SIZE]; |
---|
348 | static int lc_size = 0; |
---|
349 | static char *found__ATTR__ = NULp; |
---|
350 | |
---|
351 | static void clear_found_attribute() { |
---|
352 | free(found__ATTR__); |
---|
353 | found__ATTR__ = NULp; |
---|
354 | } |
---|
355 | |
---|
356 | static const char *nextNonSpace(const char* ptr) { |
---|
357 | while (isspace(*ptr)) ++ptr; |
---|
358 | return ptr; |
---|
359 | } |
---|
360 | static const char *nextNonWord(const char* ptr) { |
---|
361 | while (isalnum(*ptr) || *ptr == '_') ++ptr; |
---|
362 | return ptr; |
---|
363 | } |
---|
364 | |
---|
365 | inline const char *matchingParen(const char *from) { |
---|
366 | int open = 1; |
---|
367 | int i; |
---|
368 | for (i = 1; from[i] && open>0; ++i) { |
---|
369 | switch (from[i]) { |
---|
370 | case '(': open++; break; |
---|
371 | case ')': open--; break; |
---|
372 | } |
---|
373 | } |
---|
374 | if (open) return NULp; // no matching closing paren |
---|
375 | return from+i-1; |
---|
376 | } |
---|
377 | |
---|
378 | // ----------------- |
---|
379 | // LinePart |
---|
380 | |
---|
381 | class LinePart { |
---|
382 | const char *line; |
---|
383 | size_t linelen; // of line |
---|
384 | |
---|
385 | size_t pos; |
---|
386 | size_t size; |
---|
387 | |
---|
388 | bool part_is_legal() { return (pos <= linelen) && ((pos+size) <= linelen); } |
---|
389 | |
---|
390 | void set(size_t newPos, size_t newSize) { |
---|
391 | pos = newPos; |
---|
392 | size = newSize; |
---|
393 | mp_assert(part_is_legal()); |
---|
394 | } |
---|
395 | |
---|
396 | public: |
---|
397 | |
---|
398 | LinePart(const char *wholeLine, size_t len = -1U) |
---|
399 | : line(wholeLine), |
---|
400 | linelen(len != -1U ? len : strlen(line)) |
---|
401 | { |
---|
402 | mp_assert(line[linelen] == 0); |
---|
403 | undefine(); |
---|
404 | } |
---|
405 | |
---|
406 | size_t get_size() const { return size; } |
---|
407 | bool is_empty() const { return !size; } |
---|
408 | |
---|
409 | const char *whole_line() const { return line; } |
---|
410 | |
---|
411 | void define(const char *start, const char *end) { set(start-line, end-start+1); } |
---|
412 | void undefine() { set(0, 0); } |
---|
413 | |
---|
414 | void copyTo(char *buffer) const { |
---|
415 | mp_assert(!is_empty()); |
---|
416 | memcpy(buffer, line+pos, size); |
---|
417 | buffer[size] = 0; |
---|
418 | } |
---|
419 | |
---|
420 | LinePart behind() const { |
---|
421 | mp_assert(!is_empty()); |
---|
422 | size_t behind_offset = pos+size; |
---|
423 | mp_assert(linelen >= behind_offset); |
---|
424 | return LinePart(line+behind_offset, linelen-behind_offset); |
---|
425 | } |
---|
426 | |
---|
427 | void error(const char *format) { |
---|
428 | // 'format' has to contain one '%s' |
---|
429 | mp_assert(!is_empty()); |
---|
430 | char part[get_size()+1]; |
---|
431 | copyTo(part); |
---|
432 | errorf(format, part); |
---|
433 | undefine(); |
---|
434 | } |
---|
435 | }; |
---|
436 | |
---|
437 | |
---|
438 | // ------------------ |
---|
439 | // PartQueue |
---|
440 | |
---|
441 | class PartQueue : virtual Noncopyable { |
---|
442 | LinePart first; |
---|
443 | PartQueue *next; |
---|
444 | size_t size; |
---|
445 | |
---|
446 | bool is_empty() const { return !size; } |
---|
447 | size_t get_size() const { return size; } |
---|
448 | |
---|
449 | void copyPartsTo(char *buffer) const { |
---|
450 | mp_assert(!first.is_empty()); |
---|
451 | first.copyTo(buffer); |
---|
452 | buffer += first.get_size(); |
---|
453 | if (next) { |
---|
454 | *buffer++ = ' '; |
---|
455 | next->copyPartsTo(buffer); |
---|
456 | } |
---|
457 | } |
---|
458 | |
---|
459 | public: |
---|
460 | PartQueue(LinePart first_) |
---|
461 | : first(first_), |
---|
462 | next(NULp), |
---|
463 | size(first.get_size()) |
---|
464 | {} |
---|
465 | ~PartQueue() { delete next; } |
---|
466 | |
---|
467 | void append(PartQueue *mp) { |
---|
468 | mp_assert(!next); |
---|
469 | next = mp; |
---|
470 | size += 1+mp->get_size(); // add pos for space |
---|
471 | } |
---|
472 | |
---|
473 | char *to_string() { |
---|
474 | char *result = (char *)malloc(get_size()+1); |
---|
475 | copyPartsTo(result); |
---|
476 | mp_assert(get_size() == strlen(result)); |
---|
477 | return result; |
---|
478 | } |
---|
479 | }; |
---|
480 | |
---|
481 | // ------------------------ |
---|
482 | // AttributeParser |
---|
483 | |
---|
484 | class AttributeParser { |
---|
485 | const char *attrName; |
---|
486 | size_t attrNameLen; |
---|
487 | bool expandName; // try to expand 'attrName' |
---|
488 | bool expectParens; // otherwise parens are optional |
---|
489 | |
---|
490 | public: |
---|
491 | AttributeParser(const char *attrName_, bool expandName_, bool expectParens_) |
---|
492 | : attrName(attrName_), |
---|
493 | attrNameLen(strlen(attrName)), |
---|
494 | expandName(expandName_), |
---|
495 | expectParens(expectParens_) |
---|
496 | {} |
---|
497 | |
---|
498 | private: |
---|
499 | void parse_one_attr(LinePart& part) const { |
---|
500 | const char *found = strstr(part.whole_line(), attrName); |
---|
501 | if (found) { |
---|
502 | const char *behind = found+attrNameLen; |
---|
503 | if (expandName) behind = nextNonWord(behind); |
---|
504 | const char *openParen = nextNonSpace(behind); |
---|
505 | |
---|
506 | if (*openParen == '(') { |
---|
507 | const char *closeParen = matchingParen(openParen); |
---|
508 | if (closeParen) part.define(found, closeParen); |
---|
509 | else { |
---|
510 | part.define(found, openParen); |
---|
511 | part.error("Could not find matching paren after '%s'"); |
---|
512 | } |
---|
513 | } |
---|
514 | else { |
---|
515 | part.define(found, behind-1); |
---|
516 | if (expectParens) part.error("Expected to see '(' after '%s'"); |
---|
517 | } |
---|
518 | } |
---|
519 | } |
---|
520 | |
---|
521 | // rest is not really part of this class - may go to abstract base class if needed |
---|
522 | |
---|
523 | PartQueue *parse_all(LinePart from) const { |
---|
524 | parse_one_attr(from); |
---|
525 | if (from.is_empty()) return NULp; |
---|
526 | |
---|
527 | PartQueue *head = new PartQueue(from); |
---|
528 | PartQueue *rest = parse_all(from.behind()); |
---|
529 | if (rest) head->append(rest); |
---|
530 | |
---|
531 | return head; |
---|
532 | } |
---|
533 | |
---|
534 | public: |
---|
535 | char *parse(const char *toParse, size_t toParseSize) const { |
---|
536 | char *result = NULp; |
---|
537 | PartQueue *found_attributes = parse_all(LinePart(toParse, toParseSize)); |
---|
538 | |
---|
539 | if (found_attributes) { |
---|
540 | result = found_attributes->to_string(); |
---|
541 | delete found_attributes; |
---|
542 | } |
---|
543 | return result; |
---|
544 | } |
---|
545 | }; |
---|
546 | |
---|
547 | static void search_comment_for_attribute() { |
---|
548 | if (!found__ATTR__) { // only parse once (until reset) |
---|
549 | if (search__ATTR__) { |
---|
550 | last_comment[lc_size] = 0; // close string |
---|
551 | |
---|
552 | static AttributeParser ATTR_parser("__ATTR__", true, false); |
---|
553 | found__ATTR__ = ATTR_parser.parse(last_comment, lc_size); |
---|
554 | } |
---|
555 | } |
---|
556 | } |
---|
557 | |
---|
558 | struct promotion { |
---|
559 | char *to_promote; // text to promote to header |
---|
560 | promotion *next; |
---|
561 | }; |
---|
562 | |
---|
563 | static promotion *promotions = NULp; |
---|
564 | |
---|
565 | static void add_promotion(char *to_promote) { |
---|
566 | promotion *new_promotion = (promotion*)malloc(sizeof(promotion)); |
---|
567 | new_promotion->to_promote = to_promote; |
---|
568 | new_promotion->next = NULp; |
---|
569 | |
---|
570 | if (!promotions) { |
---|
571 | promotions = new_promotion; |
---|
572 | } |
---|
573 | else { // append |
---|
574 | promotion *last = promotions; |
---|
575 | while (last->next) last = last->next; |
---|
576 | |
---|
577 | last->next = new_promotion; |
---|
578 | } |
---|
579 | } |
---|
580 | |
---|
581 | static void print_promotions() { |
---|
582 | promotion *p = promotions; |
---|
583 | |
---|
584 | if (promotions) fputc('\n', stdout); |
---|
585 | |
---|
586 | while (p) { |
---|
587 | promotion *next = p->next; |
---|
588 | |
---|
589 | printf("%s\n", p->to_promote); |
---|
590 | free(p->to_promote); |
---|
591 | free(p); |
---|
592 | |
---|
593 | p = next; |
---|
594 | } |
---|
595 | |
---|
596 | if (promotions) fputc('\n', stdout); |
---|
597 | promotions = NULp; |
---|
598 | } |
---|
599 | |
---|
600 | static const char *promotion_tag = "AISC_MKPT_PROMOTE:"; |
---|
601 | static int promotion_tag_len = 18; |
---|
602 | |
---|
603 | static void search_comment_for_promotion() { |
---|
604 | char *promotion_found; |
---|
605 | last_comment[lc_size] = 0; // close string |
---|
606 | |
---|
607 | promotion_found = strstr(last_comment, promotion_tag); |
---|
608 | while (promotion_found) { |
---|
609 | char *behind_promo = promotion_found+promotion_tag_len; |
---|
610 | mp_assert(behind_promo[-1] == ':'); // wrong promotion_tag_len |
---|
611 | |
---|
612 | char *eol = strchr(behind_promo, '\n'); |
---|
613 | if (!eol) eol = strchr(behind_promo, 0); |
---|
614 | |
---|
615 | if (eol) { |
---|
616 | while (eol>behind_promo && eol[-1] == ' ') --eol; // trim spaces at eol |
---|
617 | } |
---|
618 | |
---|
619 | mp_assert(eol); |
---|
620 | if (!eol) { |
---|
621 | promotion_found = NULp; |
---|
622 | } |
---|
623 | else { |
---|
624 | int promo_length = eol-behind_promo; |
---|
625 | char *to_promote = (char*)malloc(promo_length+1); |
---|
626 | |
---|
627 | memcpy(to_promote, behind_promo, promo_length); |
---|
628 | to_promote[promo_length] = 0; |
---|
629 | |
---|
630 | DEBUG_PRINT("promotion found!\n"); |
---|
631 | |
---|
632 | add_promotion(to_promote); |
---|
633 | promotion_found = strstr(eol, promotion_tag); |
---|
634 | } |
---|
635 | } |
---|
636 | } |
---|
637 | |
---|
638 | /* read the next character from the file. If the character is '\' then |
---|
639 | * read and skip the next character. Any comment sequence is converted |
---|
640 | * to a blank. |
---|
641 | * |
---|
642 | * if a comment contains __ATTR__ and search__ATTR__ != 0 |
---|
643 | * the attribute string is stored in found__ATTR__ |
---|
644 | */ |
---|
645 | |
---|
646 | |
---|
647 | static int fnextch(FILE *f) { |
---|
648 | int c, lastc, incomment; |
---|
649 | |
---|
650 | c = ngetc(f); |
---|
651 | while (c == '\\') { |
---|
652 | DEBUG_PRINT("fnextch: in backslash loop\n"); |
---|
653 | ngetc(f); // skip a character |
---|
654 | c = ngetc(f); |
---|
655 | } |
---|
656 | if (c == '/' && !inquote) { |
---|
657 | c = ngetc(f); |
---|
658 | if (c == '*') { |
---|
659 | long commentStartLine = linenum; |
---|
660 | |
---|
661 | incomment = 1; |
---|
662 | c = ' '; |
---|
663 | DEBUG_PRINT("fnextch: comment seen\n"); |
---|
664 | lc_size = 0; |
---|
665 | |
---|
666 | while (incomment) { |
---|
667 | lastc = c; |
---|
668 | c = ngetc(f); |
---|
669 | last_comment[lc_size++] = c; |
---|
670 | mp_assert(lc_size<MAX_COMMENT_SIZE); |
---|
671 | |
---|
672 | if (lastc == '*' && c == '/') incomment = 0; |
---|
673 | else if (c < 0) { |
---|
674 | error("EOF reached in comment"); |
---|
675 | errorAt(commentStartLine, "comment started here"); |
---|
676 | return c; |
---|
677 | } |
---|
678 | } |
---|
679 | if (search__ATTR__) search_comment_for_attribute(); |
---|
680 | if (promote_lines) search_comment_for_promotion(); |
---|
681 | return fnextch(f); |
---|
682 | } |
---|
683 | else if (c == '/') { // C++ style comment |
---|
684 | incomment = 1; |
---|
685 | c = ' '; |
---|
686 | DEBUG_PRINT("fnextch: C++ comment seen\n"); |
---|
687 | lc_size = 0; |
---|
688 | |
---|
689 | while (incomment) { |
---|
690 | lastc = c; |
---|
691 | c = ngetc(f); |
---|
692 | last_comment[lc_size++] = c; |
---|
693 | mp_assert(lc_size<MAX_COMMENT_SIZE); |
---|
694 | |
---|
695 | if (lastc != '\\' && c == '\n') incomment = 0; |
---|
696 | else if (c < 0) break; |
---|
697 | } |
---|
698 | if (search__ATTR__) search_comment_for_attribute(); |
---|
699 | if (promote_lines) search_comment_for_promotion(); |
---|
700 | |
---|
701 | if (c == '\n') return c; |
---|
702 | return fnextch(f); |
---|
703 | } |
---|
704 | else { |
---|
705 | // if we pre-fetched a linefeed, remember to adjust the line number |
---|
706 | if (c == '\n') linenum--; |
---|
707 | ungetc(c, f); |
---|
708 | return '/'; |
---|
709 | } |
---|
710 | } |
---|
711 | return c; |
---|
712 | } |
---|
713 | |
---|
714 | |
---|
715 | static int nextch(FILE *f) { |
---|
716 | // Get the next "interesting" character. Comments are skipped, and strings |
---|
717 | // are converted to "0". Also, if a line starts with "#" it is skipped. |
---|
718 | |
---|
719 | int c = fnextch(f); |
---|
720 | |
---|
721 | // skip preprocessor directives |
---|
722 | // EXCEPTION: #line nnn or #nnn lines are interpreted |
---|
723 | |
---|
724 | if (newline_seen && c == '#') { |
---|
725 | // skip blanks |
---|
726 | do { |
---|
727 | c = fnextch(f); |
---|
728 | } while (c >= 0 && (c == '\t' || c == ' ')); |
---|
729 | |
---|
730 | // check for #line |
---|
731 | if (c == 'l') { |
---|
732 | c = fnextch(f); |
---|
733 | if (c != 'i') // not a #line directive |
---|
734 | goto skip_rest_of_line; |
---|
735 | do { |
---|
736 | c = fnextch(f); |
---|
737 | } while (c >= 0 && c != '\n' && !isdigit(c)); |
---|
738 | } |
---|
739 | |
---|
740 | // if we have a digit it's a line number, from the preprocessor |
---|
741 | if (c >= 0 && isdigit(c)) { |
---|
742 | char numbuf[10]; |
---|
743 | char *p = numbuf; |
---|
744 | for (int n = 8; n >= 0; --n) { |
---|
745 | *p++ = c; |
---|
746 | c = fnextch(f); |
---|
747 | if (c <= 0 || !isdigit(c)) |
---|
748 | break; |
---|
749 | } |
---|
750 | *p = 0; |
---|
751 | linenum = atol(numbuf) - 1; |
---|
752 | } |
---|
753 | |
---|
754 | // skip the rest of the line |
---|
755 | skip_rest_of_line : |
---|
756 | while (c >= 0 && c != '\n') |
---|
757 | c = fnextch(f); |
---|
758 | if (c < 0) |
---|
759 | return c; |
---|
760 | } |
---|
761 | newline_seen = (c == '\n'); |
---|
762 | |
---|
763 | if (c == '\'' || c == '\"') { |
---|
764 | char buffer[11]; |
---|
765 | int index = 0; |
---|
766 | long quoteStartLine = linenum; |
---|
767 | |
---|
768 | DEBUG_PRINT("nextch: in a quote\n"); |
---|
769 | inquote = c; |
---|
770 | while ((c = fnextch(f)) >= 0) { |
---|
771 | if (c == inquote) { |
---|
772 | buffer[index] = 0; |
---|
773 | DEBUG_PRINT("quoted content='"); |
---|
774 | DEBUG_PRINT(buffer); |
---|
775 | DEBUG_PRINT("'\n"); |
---|
776 | |
---|
777 | DEBUG_PRINT("nextch: out of quote\n"); |
---|
778 | |
---|
779 | if (linenum != quoteStartLine) { |
---|
780 | error("multiline quotes"); |
---|
781 | errorAt(quoteStartLine, "quotes opened here"); |
---|
782 | } |
---|
783 | |
---|
784 | if (inquote=='\"' && strcmp(buffer, "C")==0) { |
---|
785 | inquote = 0; |
---|
786 | return '$'; // found "C" (needed for 'extern "C"') |
---|
787 | } |
---|
788 | inquote = 0; |
---|
789 | return '0'; |
---|
790 | } |
---|
791 | else { |
---|
792 | if (index<10) buffer[index++] = c; |
---|
793 | } |
---|
794 | } |
---|
795 | error("EOF in a quote"); |
---|
796 | errorAt(quoteStartLine, "quote started here"); |
---|
797 | DEBUG_PRINT("nextch: EOF in a quote\n"); |
---|
798 | } |
---|
799 | return c; |
---|
800 | } |
---|
801 | |
---|
802 | static int getsym(char *buf, FILE *f) { |
---|
803 | /* Get the next symbol from the file, skipping blanks. |
---|
804 | * Return 0 if OK, -1 for EOF. |
---|
805 | * Also collapses everything between { and } |
---|
806 | */ |
---|
807 | |
---|
808 | int c; |
---|
809 | int inbrack = 0; |
---|
810 | |
---|
811 | #if defined(DEBUG_PRINTS) |
---|
812 | char *bufStart = buf; |
---|
813 | #endif // DEBUG_PRINTS |
---|
814 | |
---|
815 | c = glastc; |
---|
816 | while ((c > 0) && isspace(c)) { |
---|
817 | c = nextch(f); |
---|
818 | } |
---|
819 | |
---|
820 | if (c < 0) { |
---|
821 | DEBUG_PRINT("EOF read in getsym\n"); |
---|
822 | return -1; |
---|
823 | } |
---|
824 | |
---|
825 | if (c == '{') { |
---|
826 | long bracketStartLine = linenum; |
---|
827 | |
---|
828 | inbrack = 1; |
---|
829 | DEBUG_PRINT("getsym: in '{'\n"); |
---|
830 | while (inbrack) { |
---|
831 | c = nextch(f); |
---|
832 | if (c < 0) { |
---|
833 | error("EOF seen in bracket loop (unbalanced brackets?)"); |
---|
834 | errorAt(bracketStartLine, "bracket opened here"); |
---|
835 | DEBUG_PRINT("getsym: EOF seen in bracket loop\n"); |
---|
836 | glastc = c; |
---|
837 | return c; |
---|
838 | } |
---|
839 | if (c == '{') { |
---|
840 | inbrack++; |
---|
841 | #if defined(DEBUG_PRINTS) |
---|
842 | fprintf(stderr, "inbrack=%i (line=%li)\n", inbrack, linenum); |
---|
843 | #endif // DEBUG_PRINTS |
---|
844 | } |
---|
845 | else if (c == '}') { |
---|
846 | inbrack--; |
---|
847 | #if defined(DEBUG_PRINTS) |
---|
848 | fprintf(stderr, "inbrack=%i (line=%li)\n", inbrack, linenum); |
---|
849 | #endif // DEBUG_PRINTS |
---|
850 | } |
---|
851 | } |
---|
852 | strcpy(buf, "{}"); |
---|
853 | glastc = nextch(f); |
---|
854 | DEBUG_PRINT("getsym: returning brackets '"); |
---|
855 | } |
---|
856 | else if (!IS_CSYM(c)) { |
---|
857 | *buf++ = c; |
---|
858 | *buf = 0; |
---|
859 | glastc = nextch(f); |
---|
860 | |
---|
861 | DEBUG_PRINT("getsym: returning special symbol '"); |
---|
862 | } |
---|
863 | else { |
---|
864 | while (IS_CSYM(c)) { |
---|
865 | *buf++ = c; |
---|
866 | c = nextch(f); |
---|
867 | } |
---|
868 | *buf = 0; |
---|
869 | glastc = c; |
---|
870 | DEBUG_PRINT("getsym: returning word '"); |
---|
871 | } |
---|
872 | |
---|
873 | DEBUG_PRINT(bufStart); |
---|
874 | DEBUG_PRINT("'\n"); |
---|
875 | |
---|
876 | return 0; |
---|
877 | } |
---|
878 | |
---|
879 | static int skipit(char *buf, FILE *f) { |
---|
880 | // skip until a ";" or the end of a function declaration is seen |
---|
881 | |
---|
882 | int i; |
---|
883 | do { |
---|
884 | DEBUG_PRINT("in skipit loop\n"); |
---|
885 | |
---|
886 | i = getsym(buf, f); |
---|
887 | if (i < 0) return i; |
---|
888 | |
---|
889 | DEBUG_PRINT("skipit: '"); |
---|
890 | DEBUG_PRINT(buf); |
---|
891 | DEBUG_PRINT("'\n"); |
---|
892 | |
---|
893 | } while (*buf != ';' && *buf != '{'); |
---|
894 | |
---|
895 | return 0; |
---|
896 | } |
---|
897 | |
---|
898 | static int is_type_word(char *s) { |
---|
899 | // find most common type specifiers for purpose of ruling them out as parm names |
---|
900 | |
---|
901 | static const char *typewords[] = { |
---|
902 | "char", "const", "double", "enum", |
---|
903 | "float", "int", "long", "short", |
---|
904 | "signed", "struct", "union", "unsigned", |
---|
905 | "void", "volatile", NULp |
---|
906 | }; |
---|
907 | |
---|
908 | const char **ss; |
---|
909 | |
---|
910 | for (ss = typewords; *ss; ++ss) |
---|
911 | if (strcmp(s, *ss) == 0) |
---|
912 | return 1; |
---|
913 | |
---|
914 | return 0; |
---|
915 | } |
---|
916 | |
---|
917 | |
---|
918 | /* Ad-hoc macro to recognize parameter name for purposes of removal. |
---|
919 | * Idea is to remove the bulk of easily recognized parm names without |
---|
920 | * losing too many type specifiers. (sg) |
---|
921 | */ |
---|
922 | #define IS_PARM_NAME(w) \ |
---|
923 | (IS_CSYM(*(w)->string) && !is_type_word((w)->string) && \ |
---|
924 | (!(w)->next || *(w)->next->string == ',' || \ |
---|
925 | *(w)->next->string == '[')) |
---|
926 | |
---|
927 | |
---|
928 | static Word *typelist(Word *p) { |
---|
929 | // given a list representing a type and a variable name, extract just |
---|
930 | // the base type, e.g. "struct word *x" would yield "struct word" |
---|
931 | |
---|
932 | Word *w, *r; |
---|
933 | |
---|
934 | r = w = word_alloc(""); |
---|
935 | while (p && p->next) { |
---|
936 | // handle int *x --> int |
---|
937 | if (p->string[0] && !IS_CSYM(p->string[0])) |
---|
938 | break; |
---|
939 | // handle int x[] --> int |
---|
940 | if (p->next->string[0] == '[') |
---|
941 | break; |
---|
942 | w->next = word_alloc(p->string); |
---|
943 | w = w->next; |
---|
944 | p = p->next; |
---|
945 | } |
---|
946 | return r; |
---|
947 | } |
---|
948 | |
---|
949 | static Word *getparamlist(FILE *f) { |
---|
950 | // Get a parameter list; when this is called the next symbol in line |
---|
951 | // should be the first thing in the list. |
---|
952 | |
---|
953 | Word *pname[MAXPARAM]; // parameter names |
---|
954 | Word *tlist = NULp; // type name |
---|
955 | Word *plist; // temporary |
---|
956 | int np = 0; // number of parameters |
---|
957 | int typed[MAXPARAM]; // parameter has been given a type |
---|
958 | int tlistdone; // finished finding the type name |
---|
959 | int sawsomething; |
---|
960 | int i; |
---|
961 | int inparen = 0; |
---|
962 | char buf[80]; |
---|
963 | |
---|
964 | Word *result = NULp; |
---|
965 | |
---|
966 | DEBUG_PRINT("in getparamlist\n"); |
---|
967 | for (i = 0; i < MAXPARAM; i++) |
---|
968 | typed[i] = 0; |
---|
969 | |
---|
970 | plist = word_alloc(""); |
---|
971 | |
---|
972 | // first, get the stuff inside brackets (if anything) |
---|
973 | |
---|
974 | sawsomething = 0; // gets set nonzero when we see an arg |
---|
975 | for (;;) { |
---|
976 | if (getsym(buf, f) < 0) { |
---|
977 | goto cleanup; |
---|
978 | } |
---|
979 | if (*buf == ')' && (--inparen < 0)) { |
---|
980 | if (sawsomething) { // if we've seen an arg |
---|
981 | pname[np] = plist; |
---|
982 | plist = word_alloc(""); // @@@ Value stored to 'plist' is never read |
---|
983 | np++; |
---|
984 | } |
---|
985 | break; |
---|
986 | } |
---|
987 | if (*buf == ';') { // something weird |
---|
988 | result = ABORTED; |
---|
989 | goto cleanup; |
---|
990 | } |
---|
991 | sawsomething = 1; // there's something in the arg. list |
---|
992 | if (*buf == ',' && inparen == 0) { |
---|
993 | pname[np] = plist; |
---|
994 | plist = word_alloc(""); |
---|
995 | np++; |
---|
996 | } |
---|
997 | else { |
---|
998 | addword(plist, buf); |
---|
999 | if (*buf == '(') inparen++; |
---|
1000 | } |
---|
1001 | } |
---|
1002 | |
---|
1003 | // next, get the declarations after the function header |
---|
1004 | |
---|
1005 | inparen = 0; |
---|
1006 | |
---|
1007 | word_free(plist); |
---|
1008 | |
---|
1009 | tlist = word_alloc(""); |
---|
1010 | plist = word_alloc(""); |
---|
1011 | |
---|
1012 | tlistdone = 0; |
---|
1013 | sawsomething = 0; |
---|
1014 | |
---|
1015 | for (;;) { |
---|
1016 | if (getsym(buf, f) < 0) { |
---|
1017 | goto cleanup; |
---|
1018 | } |
---|
1019 | |
---|
1020 | if (*buf == ',' && !inparen) { // handle a list like "int x,y,z" |
---|
1021 | if (!sawsomething) { |
---|
1022 | goto cleanup; |
---|
1023 | } |
---|
1024 | for (i = 0; i < np; i++) { |
---|
1025 | if (!typed[i] && foundin(plist, pname[i])) { |
---|
1026 | typed[i] = 1; |
---|
1027 | word_free(pname[i]); |
---|
1028 | pname[i] = word_append(tlist, plist); |
---|
1029 | // promote types |
---|
1030 | typefixhack(pname[i]); |
---|
1031 | break; |
---|
1032 | } |
---|
1033 | } |
---|
1034 | if (!tlistdone) { |
---|
1035 | word_free(tlist); |
---|
1036 | tlist = typelist(plist); |
---|
1037 | tlistdone = 1; |
---|
1038 | } |
---|
1039 | word_free(plist); |
---|
1040 | plist = word_alloc(""); |
---|
1041 | } |
---|
1042 | else if (*buf == ';') { // handle the end of a list |
---|
1043 | if (!sawsomething) { |
---|
1044 | result = ABORTED; |
---|
1045 | goto cleanup; |
---|
1046 | } |
---|
1047 | for (i = 0; i < np; i++) { |
---|
1048 | if (!typed[i] && foundin(plist, pname[i])) { |
---|
1049 | typed[i] = 1; |
---|
1050 | word_free(pname[i]); |
---|
1051 | pname[i] = word_append(tlist, plist); |
---|
1052 | typefixhack(pname[i]); |
---|
1053 | break; |
---|
1054 | } |
---|
1055 | } |
---|
1056 | tlistdone = 0; |
---|
1057 | word_free(tlist); |
---|
1058 | word_free(plist); |
---|
1059 | tlist = word_alloc(""); |
---|
1060 | plist = word_alloc(""); |
---|
1061 | } |
---|
1062 | else if (strcmp(buf, "{}") == 0) break; // handle the beginning of the function |
---|
1063 | else if (strcmp(buf, "register")) { // otherwise, throw the word into the list (except for "register") |
---|
1064 | addword(plist, buf); |
---|
1065 | if (*buf == '(') inparen++; |
---|
1066 | else if (*buf == ')') inparen--; |
---|
1067 | else sawsomething = 1; |
---|
1068 | } |
---|
1069 | } |
---|
1070 | |
---|
1071 | // Now take the info we have and build a prototype list |
---|
1072 | |
---|
1073 | word_free(plist); |
---|
1074 | word_free(tlist); |
---|
1075 | |
---|
1076 | // empty parameter list means "void" |
---|
1077 | if (np == 0) { |
---|
1078 | result = word_alloc("void"); |
---|
1079 | goto cleanup; |
---|
1080 | } |
---|
1081 | |
---|
1082 | plist = tlist = word_alloc(""); |
---|
1083 | |
---|
1084 | /* how to handle parameters which contain only one word ? |
---|
1085 | * |
---|
1086 | * void -> void |
---|
1087 | * UNFIXED -> UNFIXED see ../SL/CB/cb_base.h@UNFIXED |
---|
1088 | * xxx -> int xxx (if AUTO_INT is defined) |
---|
1089 | * int -> int dummyXX (otherwise) |
---|
1090 | */ |
---|
1091 | |
---|
1092 | // #define AUTO_INT |
---|
1093 | |
---|
1094 | { |
---|
1095 | #if !defined(AUTO_INT) |
---|
1096 | int dummy_counter = 1; |
---|
1097 | char dummy_name[] = "dummy_xx"; |
---|
1098 | #define DUMMY_COUNTER_POS 6 |
---|
1099 | #endif |
---|
1100 | |
---|
1101 | for (i = 0; i < np; i++) { |
---|
1102 | #if !defined(AUTO_INT) |
---|
1103 | int add_dummy_name = 0; |
---|
1104 | #endif |
---|
1105 | { |
---|
1106 | Word *pn_list = pname[i]; |
---|
1107 | int cnt = 0; |
---|
1108 | bool is_void = false; |
---|
1109 | bool is_UNFIXED = false; |
---|
1110 | |
---|
1111 | while (pn_list) { // count words |
---|
1112 | if (pn_list->string[0]) { |
---|
1113 | ++cnt; |
---|
1114 | if (strcmp(pn_list->string, "void")==0) is_void = true; |
---|
1115 | if (strcmp(pn_list->string, "UNFIXED")==0) is_UNFIXED = true; |
---|
1116 | } |
---|
1117 | pn_list = pn_list->next; |
---|
1118 | } |
---|
1119 | if (cnt==1 && !is_void && !is_UNFIXED) { // only name, but neither 'void' nor 'UNFIXED' |
---|
1120 | // no type or no parameter name |
---|
1121 | #ifdef AUTO_INT |
---|
1122 | // If no type provided, make it an "int" |
---|
1123 | addword(tlist, "int"); // add int to tlist before adding pname[i] |
---|
1124 | #else |
---|
1125 | add_dummy_name = 1; // add a dummy name after adding pname[i] |
---|
1126 | #endif |
---|
1127 | } |
---|
1128 | } |
---|
1129 | |
---|
1130 | while (tlist->next) tlist = tlist->next; |
---|
1131 | |
---|
1132 | tlist->next = pname[i]; |
---|
1133 | pname[i] = NULp; |
---|
1134 | |
---|
1135 | #if !defined(AUTO_INT) |
---|
1136 | if (add_dummy_name) { |
---|
1137 | mp_assert(dummy_counter<100); |
---|
1138 | dummy_name[DUMMY_COUNTER_POS] = (dummy_counter/10)+'0'; |
---|
1139 | dummy_name[DUMMY_COUNTER_POS] = (dummy_counter%10)+'0'; |
---|
1140 | addword(tlist, dummy_name); |
---|
1141 | dummy_counter++; |
---|
1142 | } |
---|
1143 | #endif |
---|
1144 | |
---|
1145 | if (i < np - 1) addword(tlist, ","); |
---|
1146 | } |
---|
1147 | } |
---|
1148 | |
---|
1149 | result = plist; |
---|
1150 | plist = NULp; |
---|
1151 | tlist = NULp; |
---|
1152 | |
---|
1153 | cleanup: |
---|
1154 | |
---|
1155 | word_free(plist); |
---|
1156 | word_free(tlist); |
---|
1157 | for (int n = 0; n<np; ++n) { |
---|
1158 | word_free(pname[n]); |
---|
1159 | } |
---|
1160 | |
---|
1161 | return result; |
---|
1162 | } |
---|
1163 | |
---|
1164 | inline Word *getLastPtrRef(Word *w) { |
---|
1165 | Word *last = NULp; |
---|
1166 | while (w) { |
---|
1167 | if (!strchr("&*", w->string[0])) break; |
---|
1168 | last = w; |
---|
1169 | w = w->next; |
---|
1170 | } |
---|
1171 | return last; |
---|
1172 | } |
---|
1173 | |
---|
1174 | static void emit(Word *wlist, Word *plist, long startline) { |
---|
1175 | // emit a function declaration. The attributes and name of the function |
---|
1176 | // are in wlist; the parameters are in plist. |
---|
1177 | |
---|
1178 | Word *w; |
---|
1179 | int count = 0; |
---|
1180 | int isstatic = 0; |
---|
1181 | int ismain = 0; |
---|
1182 | int refs = 0; |
---|
1183 | |
---|
1184 | if (promote_lines) print_promotions(); |
---|
1185 | |
---|
1186 | for (w = wlist; w; w = w->next) { |
---|
1187 | if (w->string[0]) { |
---|
1188 | count ++; |
---|
1189 | if (strcmp(w->string, "static") == 0) isstatic = 1; |
---|
1190 | else if (strcmp(w->string, "main") == 0) ismain = 1; |
---|
1191 | } |
---|
1192 | } |
---|
1193 | |
---|
1194 | if (ismain && !use_main) return; |
---|
1195 | |
---|
1196 | if (aisc) { |
---|
1197 | if (count < 2) { |
---|
1198 | printf("int\t"); |
---|
1199 | w = wlist; |
---|
1200 | } |
---|
1201 | else { |
---|
1202 | refs = 0; |
---|
1203 | for (w = wlist; w; w = w->next) { |
---|
1204 | if (w->string[0]) { |
---|
1205 | printf("%s,\t", w->string); |
---|
1206 | w = w->next; |
---|
1207 | break; |
---|
1208 | } |
---|
1209 | } |
---|
1210 | } |
---|
1211 | for (; w; w = w->next) { |
---|
1212 | if (w->string[0] == '*') { |
---|
1213 | refs++; |
---|
1214 | continue; |
---|
1215 | } |
---|
1216 | if (w->string[0]) { |
---|
1217 | printf("%s,", w->string); |
---|
1218 | break; |
---|
1219 | } |
---|
1220 | } |
---|
1221 | if (refs) { |
---|
1222 | printf("\tlink%i", refs); |
---|
1223 | refs = 0; |
---|
1224 | } |
---|
1225 | else { |
---|
1226 | printf("\tterm"); |
---|
1227 | } |
---|
1228 | |
---|
1229 | if (strcmp(plist->string, "void") != 0) { // if parameter is not 'void' |
---|
1230 | printf(",\t{\n"); |
---|
1231 | printf("\t@TYPE,\t@IDENT,\t@REF;\n"); |
---|
1232 | |
---|
1233 | int name_seen = 0; |
---|
1234 | int unnamed_counter = 1; |
---|
1235 | for (w = plist; w; w = w->next) { |
---|
1236 | if (w->string[0] == '*') { |
---|
1237 | refs++; |
---|
1238 | name_seen = 0; |
---|
1239 | continue; |
---|
1240 | } |
---|
1241 | if (w->string[0] == ',') { |
---|
1242 | if (refs) { |
---|
1243 | printf("\tlink%i;\n", refs); |
---|
1244 | refs = 0; |
---|
1245 | continue; |
---|
1246 | } |
---|
1247 | else { |
---|
1248 | printf("\tterm;\n"); |
---|
1249 | continue; |
---|
1250 | } |
---|
1251 | } |
---|
1252 | if (w->string[0]) { |
---|
1253 | printf("\t%s,", w->string); |
---|
1254 | name_seen = 1; |
---|
1255 | } |
---|
1256 | } |
---|
1257 | if (refs) { |
---|
1258 | if (!name_seen) { // automatically insert missing parameter names |
---|
1259 | printf("\tunnamed%i,", unnamed_counter++); |
---|
1260 | } |
---|
1261 | printf("\tlink%i;\n", refs); |
---|
1262 | refs = 0; |
---|
1263 | } |
---|
1264 | else { |
---|
1265 | printf("\tterm;\n"); |
---|
1266 | } |
---|
1267 | printf("}"); |
---|
1268 | } |
---|
1269 | printf(";\n\n"); |
---|
1270 | return; |
---|
1271 | } |
---|
1272 | DEBUG_PRINT("emit called\n"); |
---|
1273 | if (donum) |
---|
1274 | printf("/*%8ld */ ", startline); |
---|
1275 | |
---|
1276 | |
---|
1277 | // if the -e flag was given, and it's not a static function, print "extern" |
---|
1278 | |
---|
1279 | if (print_extern && !isstatic) { |
---|
1280 | printf("extern "); |
---|
1281 | } |
---|
1282 | |
---|
1283 | int spaceBeforeNext = 0; |
---|
1284 | if (count < 2) { |
---|
1285 | printf("int"); |
---|
1286 | spaceBeforeNext = 1; |
---|
1287 | } |
---|
1288 | |
---|
1289 | for (w = wlist; w; w = w->next) { |
---|
1290 | if (spaceBeforeNext) { |
---|
1291 | DEBUG_PRINT("emit[1] ' '\n"); |
---|
1292 | putchar(' '); |
---|
1293 | } |
---|
1294 | printf("%s", w->string); |
---|
1295 | DEBUG_PRINT_STRING("emit[2] ", w->string); |
---|
1296 | spaceBeforeNext = IS_CSYM(w->string[0]); |
---|
1297 | } |
---|
1298 | |
---|
1299 | if (use_macro) printf(" %s((", macro_name); |
---|
1300 | else putchar('('); |
---|
1301 | DEBUG_PRINT("emit[3] '('\n"); |
---|
1302 | |
---|
1303 | spaceBeforeNext = 0; |
---|
1304 | for (w = plist; w; w = w->next) { |
---|
1305 | if (no_parm_names && IS_PARM_NAME(w)) continue; |
---|
1306 | |
---|
1307 | const char *token = w->string; |
---|
1308 | char tokStart = token[0]; |
---|
1309 | |
---|
1310 | if (!tokStart) continue; // empty token |
---|
1311 | |
---|
1312 | if (tokStart == ',') spaceBeforeNext = 1; |
---|
1313 | else if (strchr("[])", tokStart)) spaceBeforeNext = 0; |
---|
1314 | else { |
---|
1315 | int nextSpaceBeforeNext; |
---|
1316 | if (strchr("&*", tokStart)) { |
---|
1317 | if (spaceBeforeNext) { |
---|
1318 | Word *lastPtrRef = getLastPtrRef(w); |
---|
1319 | if (lastPtrRef->string[0] == '&') spaceBeforeNext = 0; |
---|
1320 | } |
---|
1321 | nextSpaceBeforeNext = tokStart == '&'; |
---|
1322 | } |
---|
1323 | else { |
---|
1324 | nextSpaceBeforeNext = IS_CSYM(tokStart);; |
---|
1325 | } |
---|
1326 | if (spaceBeforeNext) { |
---|
1327 | putchar(' '); |
---|
1328 | DEBUG_PRINT("emit[4] ' '\n"); |
---|
1329 | } |
---|
1330 | spaceBeforeNext = nextSpaceBeforeNext; |
---|
1331 | } |
---|
1332 | fputs(token, stdout); |
---|
1333 | DEBUG_PRINT_STRING("emit[5] ", token); |
---|
1334 | } |
---|
1335 | |
---|
1336 | if (use_macro) PRINT("))"); |
---|
1337 | else PRINT(")"); |
---|
1338 | DEBUG_PRINT("emit[6] ')'\n"); |
---|
1339 | |
---|
1340 | if (found__ATTR__) { PRINT(" "); PRINT(found__ATTR__); } |
---|
1341 | |
---|
1342 | PRINT(";\n"); |
---|
1343 | } |
---|
1344 | |
---|
1345 | static void getdecl(FILE *f, const char *header) { |
---|
1346 | // parse all function declarations and print to STDOUT |
---|
1347 | |
---|
1348 | Word *wlist = NULp; |
---|
1349 | char buf[80]; |
---|
1350 | int sawsomething; |
---|
1351 | long startline; // line where declaration started |
---|
1352 | int oktoprint; |
---|
1353 | int header_printed = 0; |
---|
1354 | |
---|
1355 | current_file = strdup(header); |
---|
1356 | |
---|
1357 | again : |
---|
1358 | DEBUG_PRINT("again\n"); |
---|
1359 | |
---|
1360 | word_free(wlist); |
---|
1361 | wlist = word_alloc(""); |
---|
1362 | |
---|
1363 | bool seen__ATTR = false; |
---|
1364 | |
---|
1365 | sawsomething = 0; |
---|
1366 | oktoprint = 1; |
---|
1367 | extern_c_seen = 0; |
---|
1368 | |
---|
1369 | for (;;) { |
---|
1370 | DEBUG_PRINT("main getdecl loop\n"); |
---|
1371 | if (getsym(buf, f) < 0) { |
---|
1372 | DEBUG_PRINT("EOF in getdecl loop\n"); |
---|
1373 | goto end; |
---|
1374 | } |
---|
1375 | |
---|
1376 | DEBUG_PRINT("getdecl: '"); |
---|
1377 | DEBUG_PRINT(buf); |
---|
1378 | DEBUG_PRINT("'\n"); |
---|
1379 | |
---|
1380 | // try to guess when a declaration is not an external function definition |
---|
1381 | if (strcmp(buf, ",")==0 || |
---|
1382 | strcmp(buf, "=")==0 || |
---|
1383 | strcmp(buf, "typedef")==0 || |
---|
1384 | strcmp(buf, "[")==0) |
---|
1385 | { |
---|
1386 | skipit(buf, f); |
---|
1387 | goto again; |
---|
1388 | } |
---|
1389 | |
---|
1390 | if (strcmp(buf, "{}")==0) { |
---|
1391 | if (!extern_c_seen) skipit(buf, f); |
---|
1392 | goto again; |
---|
1393 | } |
---|
1394 | |
---|
1395 | if (strcmp(buf, "extern")==0) { |
---|
1396 | if (getsym(buf, f)<0) { |
---|
1397 | DEBUG_PRINT("EOF in getdecl loop\n"); |
---|
1398 | goto end; |
---|
1399 | } |
---|
1400 | |
---|
1401 | DEBUG_PRINT("test auf extern \"C\": '"); |
---|
1402 | DEBUG_PRINT(buf); |
---|
1403 | DEBUG_PRINT("'\n"); |
---|
1404 | |
---|
1405 | if (strcmp(buf, "$") == 0) { // symbol used if "C" was found |
---|
1406 | extern_c_seen = 1; |
---|
1407 | if (promote_extern_c) { |
---|
1408 | addword(wlist, "extern"); |
---|
1409 | addword(wlist, "\"C\" "); |
---|
1410 | sawsomething = 1; |
---|
1411 | } |
---|
1412 | continue; |
---|
1413 | } |
---|
1414 | |
---|
1415 | skipit(buf, f); |
---|
1416 | goto again; |
---|
1417 | } |
---|
1418 | |
---|
1419 | if (strncmp(buf, "__ATTR__", 8) == 0) { // prefix attribute (should only be used for static and inline) |
---|
1420 | DEBUG_PRINT("seen prefix __ATTR__: '"); |
---|
1421 | DEBUG_PRINT(buf); |
---|
1422 | DEBUG_PRINT("'\n"); |
---|
1423 | |
---|
1424 | seen__ATTR = true; |
---|
1425 | } |
---|
1426 | |
---|
1427 | if (strcmp(buf, "static") == 0 || |
---|
1428 | strcmp(buf, "inline") == 0 || |
---|
1429 | strcmp(buf, "CONSTEXPR_INLINE") == 0) // see ../TEMPLATES/cxxforward.h@CONSTEXPR_INLINE |
---|
1430 | { |
---|
1431 | oktoprint = 0; |
---|
1432 | } |
---|
1433 | |
---|
1434 | |
---|
1435 | if (strcmp(buf, ";") == 0) goto again; |
---|
1436 | |
---|
1437 | // A left parenthesis *might* indicate a function definition |
---|
1438 | if (strcmp(buf, "(")==0) { |
---|
1439 | startline = linenum; |
---|
1440 | Word *plist = NULp; |
---|
1441 | if (!sawsomething || !(plist = getparamlist(f))) { |
---|
1442 | skipit(buf, f); |
---|
1443 | goto again; |
---|
1444 | } |
---|
1445 | if (plist == ABORTED) |
---|
1446 | goto again; |
---|
1447 | |
---|
1448 | // It seems to have been what we wanted |
---|
1449 | |
---|
1450 | if (oktoprint) { // check function-name |
---|
1451 | Word *w; |
---|
1452 | |
---|
1453 | for (w=wlist; w->next && oktoprint; w=w->next) { |
---|
1454 | if (w->string[0]==':' && w->string[1]==0) oktoprint = 0; // do not emit prototypes for member functions |
---|
1455 | } |
---|
1456 | |
---|
1457 | if (oktoprint && !wantPrototypeFor(w->string)) { |
---|
1458 | oktoprint = 0; // => do not emit prototype |
---|
1459 | } |
---|
1460 | } |
---|
1461 | |
---|
1462 | if (seen__ATTR && oktoprint) { |
---|
1463 | DEBUG_PRINT("attempt to emit seen__ATTR (suppressed)"); |
---|
1464 | oktoprint = 0; |
---|
1465 | } |
---|
1466 | |
---|
1467 | if (oktoprint) { |
---|
1468 | if (!header_printed) { |
---|
1469 | if (aisc) printf("\n# %s\n", header); |
---|
1470 | else printf("\n/* %s */\n", header); |
---|
1471 | header_printed = 1; |
---|
1472 | } |
---|
1473 | emit(wlist, plist, startline); |
---|
1474 | } |
---|
1475 | clear_found_attribute(); |
---|
1476 | |
---|
1477 | word_free(plist); |
---|
1478 | goto again; |
---|
1479 | } |
---|
1480 | |
---|
1481 | addword(wlist, buf); |
---|
1482 | sawsomething = 1; |
---|
1483 | } |
---|
1484 | |
---|
1485 | end: |
---|
1486 | word_free(wlist); |
---|
1487 | } |
---|
1488 | |
---|
1489 | __ATTR__NORETURN static void Usage(const char *msg = NULp) { |
---|
1490 | fprintf(stderr, |
---|
1491 | "\naisc_mkpts - ARB prototype generator" |
---|
1492 | "\nUsage: %s [options] [files ...]", ourname); |
---|
1493 | fputs("\nSupported options:" |
---|
1494 | "\n -F part[,part]* only promote declarations for functionnames containing one of the parts" |
---|
1495 | "\n if 'part' starts with a '^' functionname has to start with rest of part" |
---|
1496 | "\n -S (like -F) do NOT promote matching declarations (defaults to -S '^TEST_,^NOTEST_')" |
---|
1497 | "\n" |
---|
1498 | "\n Instead of ',' (=or) you may use '+' (=and)" |
---|
1499 | "\n" |
---|
1500 | "\n -G search for ARB macro __ATTR__ in comment behind function header" |
---|
1501 | "\n -P promote /*AISC_MKPT_PROMOTE:forHeader*/ to header" |
---|
1502 | "\n" |
---|
1503 | "\n -w gen.h add standard include wrapper (needs name of generated header)" |
---|
1504 | "\n -c \"text\" add text as comment into header" |
---|
1505 | "\n" |
---|
1506 | "\n -C insert 'extern \"C\"'" |
---|
1507 | "\n -E prefix 'extern \"C\"' at prototype" |
---|
1508 | "\n" |
---|
1509 | "\n -W don't promote types in old style declarations" |
---|
1510 | "\n -x omit parameter names in prototypes" |
---|
1511 | "\n" |
---|
1512 | "\n -K use K&R prototype macro (default assumes header files are strict ANSI)" |
---|
1513 | "\n -D define K&R prototype macro" |
---|
1514 | "\n -p sym use \"sym\" as the prototype macro (default \"P_\")" |
---|
1515 | "\n" |
---|
1516 | "\n -m promote declaration of 'main()' (default is to skip it)" |
---|
1517 | "\n -a make a function list for aisc_includes (default: generate C prototypes)" |
---|
1518 | "\n -e put an explicit \"extern\" keyword in declarations" |
---|
1519 | "\n -n put line numbers of declarations as comments" |
---|
1520 | "\n" |
---|
1521 | "\n -V print version number" |
---|
1522 | "\n -h print this help" |
---|
1523 | "\n" |
---|
1524 | , stderr); |
---|
1525 | if (msg) fprintf(stderr, "\nError: %s", msg); |
---|
1526 | fputc('\n', stderr); |
---|
1527 | exit(EXIT_FAILURE); |
---|
1528 | } |
---|
1529 | |
---|
1530 | static int string_comparator(const void *v0, const void *v1) { |
---|
1531 | return strcmp(*(const char **)v0, *(const char **)v1); |
---|
1532 | } |
---|
1533 | |
---|
1534 | __ATTR__NORETURN static void MissingArgumentFor(char option) { |
---|
1535 | char buffer[100]; |
---|
1536 | sprintf(buffer, "option -%c expects an argument", option); |
---|
1537 | Usage(buffer); |
---|
1538 | } |
---|
1539 | __ATTR__NORETURN static void UnknownOption(char option) { |
---|
1540 | char buffer[100]; |
---|
1541 | sprintf(buffer, "unknown option -%c", option); |
---|
1542 | Usage(buffer); |
---|
1543 | } |
---|
1544 | |
---|
1545 | int ARB_main(int argc, char *argv[]) { |
---|
1546 | bool exit_if_noargs = false; |
---|
1547 | |
---|
1548 | if (argv[0] && argv[0][0]) { |
---|
1549 | ourname = strrchr(argv[0], '/'); |
---|
1550 | if (!ourname) ourname = argv[0]; |
---|
1551 | } |
---|
1552 | else ourname = "mkptypes"; |
---|
1553 | |
---|
1554 | argv++; argc--; |
---|
1555 | |
---|
1556 | addExcludedSymParts("^TEST_,^NOTEST_"); // exclude unit tests |
---|
1557 | |
---|
1558 | char *iobuf = (char *)malloc(NEWBUFSIZ); |
---|
1559 | while (*argv && **argv == '-') { |
---|
1560 | const char *t = *argv++; --argc; t++; |
---|
1561 | while (*t) { |
---|
1562 | if (*t == 'e') print_extern = 1; |
---|
1563 | else if (*t == 'C') cansibycplus = 1; |
---|
1564 | else if (*t == 'E') promote_extern_c = 1; |
---|
1565 | else if (*t == 'W') dont_promote = 1; |
---|
1566 | else if (*t == 'a') aisc = 1; |
---|
1567 | else if (*t == 'G') search__ATTR__ = 1; |
---|
1568 | else if (*t == 'n') donum = 1; |
---|
1569 | else if (*t == 'x') no_parm_names = 1; // no parm names, only types (sg) |
---|
1570 | else if (*t == 'D') define_macro = 1; |
---|
1571 | else if (*t == 'K') use_macro = 1; |
---|
1572 | else if (*t == 'P') promote_lines = 1; |
---|
1573 | else if (*t == 'm') use_main = 1; |
---|
1574 | else if (*t == 'p') { |
---|
1575 | t = *argv++; --argc; |
---|
1576 | if (!t) MissingArgumentFor(*t); |
---|
1577 | use_macro = 1; |
---|
1578 | macro_name = t; |
---|
1579 | break; |
---|
1580 | } |
---|
1581 | else if (*t == 'c') { |
---|
1582 | t = *argv++; --argc; |
---|
1583 | if (!t) MissingArgumentFor(*t); |
---|
1584 | header_comment = t; |
---|
1585 | break; |
---|
1586 | } |
---|
1587 | else if (*t == 'w') { |
---|
1588 | t = *argv++; --argc; |
---|
1589 | if (!t) MissingArgumentFor(*t); |
---|
1590 | include_wrapper = t; |
---|
1591 | break; |
---|
1592 | } |
---|
1593 | else if (*t == 'F') { |
---|
1594 | t = *argv++; --argc; |
---|
1595 | if (!t) MissingArgumentFor(*t); |
---|
1596 | addRequiredSymParts(t); |
---|
1597 | break; |
---|
1598 | } |
---|
1599 | else if (*t == 'S') { |
---|
1600 | t = *argv++; --argc; |
---|
1601 | if (!t) MissingArgumentFor(*t); |
---|
1602 | freeExcludedSymParts(); |
---|
1603 | addExcludedSymParts(t); |
---|
1604 | break; |
---|
1605 | } |
---|
1606 | else if (*t == 'V') { |
---|
1607 | exit_if_noargs = true; |
---|
1608 | Version(); |
---|
1609 | } |
---|
1610 | else if (*t == 'h') Usage(); |
---|
1611 | else UnknownOption(*t); |
---|
1612 | t++; |
---|
1613 | } |
---|
1614 | } |
---|
1615 | |
---|
1616 | if (argc == 0 && exit_if_noargs) { |
---|
1617 | exit(EXIT_FAILURE); |
---|
1618 | } |
---|
1619 | |
---|
1620 | char *include_macro = NULp; |
---|
1621 | if (aisc) { |
---|
1622 | if (header_comment) { |
---|
1623 | printf("# %s\n#\n", header_comment); |
---|
1624 | } |
---|
1625 | fputs("# This file is generated by aisc_mkpt.\n" |
---|
1626 | "# Any changes you make here will be overwritten later!\n" |
---|
1627 | "\n" |
---|
1628 | "@FUNCTION_TYPE, @FUNCTION, @FUNCTION_REF;", stdout); |
---|
1629 | } |
---|
1630 | else { |
---|
1631 | fputs("/*", stdout); |
---|
1632 | if (header_comment) printf(" %s.\n *\n *", header_comment); |
---|
1633 | fputs(" This file is generated by aisc_mkpt.\n" |
---|
1634 | " * Any changes you make here will be overwritten later!\n" |
---|
1635 | " */\n" |
---|
1636 | "\n" |
---|
1637 | , stdout); |
---|
1638 | |
---|
1639 | if (include_wrapper) { |
---|
1640 | int p; |
---|
1641 | include_macro = strdup(include_wrapper); |
---|
1642 | for (p = 0; include_macro[p]; p++) { |
---|
1643 | char c = include_macro[p]; |
---|
1644 | c = strchr(".-", c) ? '_' : toupper(c); |
---|
1645 | include_macro[p] = c; |
---|
1646 | } |
---|
1647 | |
---|
1648 | printf("#ifndef %s\n" |
---|
1649 | "#define %s\n" |
---|
1650 | "\n", |
---|
1651 | include_macro, |
---|
1652 | include_macro); |
---|
1653 | } |
---|
1654 | |
---|
1655 | if (use_macro) { |
---|
1656 | if (define_macro) { |
---|
1657 | fprintf(stdout, |
---|
1658 | "#ifndef %s\n" |
---|
1659 | "# if defined(__STDC__) || defined(__cplusplus)\n" |
---|
1660 | "# define %s(s) s\n" |
---|
1661 | "# else\n" |
---|
1662 | "# define %s(s) ()\n" |
---|
1663 | "# endif\n" |
---|
1664 | "#else\n" |
---|
1665 | "# error %s already defined elsewhere\n" |
---|
1666 | "#endif\n\n", |
---|
1667 | macro_name, macro_name, macro_name, macro_name); |
---|
1668 | } |
---|
1669 | else { |
---|
1670 | fprintf(stdout, |
---|
1671 | "#ifndef %s\n" |
---|
1672 | "# error %s is not defined\n" |
---|
1673 | "#endif\n\n", |
---|
1674 | macro_name, macro_name); |
---|
1675 | } |
---|
1676 | } |
---|
1677 | if (search__ATTR__) { |
---|
1678 | fputs("/* define ARB attributes: */\n" |
---|
1679 | "#ifndef ATTRIBUTES_H\n" |
---|
1680 | "# include <attributes.h>\n" |
---|
1681 | "#endif\n\n", stdout); |
---|
1682 | } |
---|
1683 | if (cansibycplus) { |
---|
1684 | fputs("#ifdef __cplusplus\n" |
---|
1685 | "extern \"C\" {\n" |
---|
1686 | "#endif\n\n", stdout); |
---|
1687 | } |
---|
1688 | } |
---|
1689 | |
---|
1690 | current_dir = getcwd(NULp, 255); |
---|
1691 | if (argc == 0) { |
---|
1692 | getdecl(stdin, "<from stdin>"); |
---|
1693 | } |
---|
1694 | else { |
---|
1695 | const char *filename[1000]; |
---|
1696 | int fcount = 0; |
---|
1697 | |
---|
1698 | while (argc > 0 && *argv) { |
---|
1699 | filename[fcount++] = *argv; |
---|
1700 | argc--; argv++; |
---|
1701 | } |
---|
1702 | |
---|
1703 | qsort(&filename, fcount, sizeof(filename[0]), string_comparator); |
---|
1704 | |
---|
1705 | for (int i = 0; i<fcount; ++i) { |
---|
1706 | DEBUG_PRINT("trying new file '"); |
---|
1707 | DEBUG_PRINT(filename[i]); |
---|
1708 | DEBUG_PRINT("'\n"); |
---|
1709 | |
---|
1710 | FILE *f = fopen(filename[i], "r"); |
---|
1711 | if (!f) { |
---|
1712 | perror(filename[i]); |
---|
1713 | exit(EXIT_FAILURE); |
---|
1714 | } |
---|
1715 | if (iobuf) setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ); |
---|
1716 | |
---|
1717 | linenum = 1; |
---|
1718 | newline_seen = 1; |
---|
1719 | glastc = ' '; |
---|
1720 | getdecl(f, filename[i]); |
---|
1721 | fclose(f); |
---|
1722 | |
---|
1723 | free(current_file); |
---|
1724 | current_file = NULp; |
---|
1725 | } |
---|
1726 | } |
---|
1727 | if (aisc) { |
---|
1728 | } |
---|
1729 | else { |
---|
1730 | if (cansibycplus) { |
---|
1731 | fputs("\n#ifdef __cplusplus\n" |
---|
1732 | "}\n" |
---|
1733 | "#endif\n", stdout); |
---|
1734 | } |
---|
1735 | if (use_macro && define_macro) { |
---|
1736 | printf("\n#undef %s\n", macro_name); // clean up namespace |
---|
1737 | } |
---|
1738 | |
---|
1739 | if (include_wrapper) { |
---|
1740 | printf("\n" |
---|
1741 | "#else\n" |
---|
1742 | "#error %s included twice\n" |
---|
1743 | "#endif /* %s */\n", |
---|
1744 | include_wrapper, |
---|
1745 | include_macro); |
---|
1746 | } |
---|
1747 | } |
---|
1748 | |
---|
1749 | free(include_macro); |
---|
1750 | |
---|
1751 | freeRequiredSymParts(); |
---|
1752 | freeExcludedSymParts(); |
---|
1753 | |
---|
1754 | free(current_file); |
---|
1755 | free(current_dir); |
---|
1756 | |
---|
1757 | free(iobuf); |
---|
1758 | |
---|
1759 | return EXIT_SUCCESS; |
---|
1760 | } |
---|
1761 | |
---|
1762 | static void Version() { |
---|
1763 | fprintf(stderr, "%s 1.1 ARB\n", ourname); |
---|
1764 | } |
---|
1765 | |
---|
1766 | // -------------------------------------------------------------------------------- |
---|
1767 | |
---|
1768 | #ifdef UNIT_TESTS |
---|
1769 | |
---|
1770 | #include <test_unit.h> |
---|
1771 | |
---|
1772 | inline const char *test_extract(const char *str) { |
---|
1773 | search__ATTR__ = true; |
---|
1774 | |
---|
1775 | clear_found_attribute(); |
---|
1776 | |
---|
1777 | strcpy(last_comment, str); |
---|
1778 | lc_size = strlen(last_comment); |
---|
1779 | |
---|
1780 | search_comment_for_attribute(); |
---|
1781 | |
---|
1782 | return found__ATTR__; |
---|
1783 | } |
---|
1784 | |
---|
1785 | #define TEST_ATTR_____(comment,extracted) TEST_EXPECT_EQUAL(test_extract(comment), extracted) |
---|
1786 | |
---|
1787 | void TEST_attribute_parser() { |
---|
1788 | TEST_ATTR_____("", (const char*)NULp); |
---|
1789 | TEST_ATTR_____("nothing here", (const char*)NULp); |
---|
1790 | |
---|
1791 | TEST_ATTR_____("bla bla __ATTR__DEPRECATED(\" my reason \") more content", "__ATTR__DEPRECATED(\" my reason \")"); |
---|
1792 | TEST_ATTR_____("bla bla __ATTR__FORMAT(pos) more content", "__ATTR__FORMAT(pos)"); |
---|
1793 | |
---|
1794 | TEST_ATTR_____("__ATTR__DEPRECATED", "__ATTR__DEPRECATED"); |
---|
1795 | TEST_ATTR_____("__ATTR__FORMAT(pos)", "__ATTR__FORMAT(pos)"); |
---|
1796 | TEST_ATTR_____("bla __ATTR__FORMAT(pos)", "__ATTR__FORMAT(pos)"); |
---|
1797 | TEST_ATTR_____("__ATTR__FORMAT(pos) bla", "__ATTR__FORMAT(pos)"); |
---|
1798 | TEST_ATTR_____(" __ATTR__FORMAT(pos) ", "__ATTR__FORMAT(pos)"); |
---|
1799 | |
---|
1800 | TEST_ATTR_____("__ATTR__FORMAT((pos)", (const char*)NULp); |
---|
1801 | TEST_ATTR_____("__attribute__(pos", (const char*)NULp); |
---|
1802 | TEST_ATTR_____("__ATTR__FORMAT(pos))", "__ATTR__FORMAT(pos)"); |
---|
1803 | TEST_ATTR_____("__ATTR__FORMAT((pos))", "__ATTR__FORMAT((pos))"); |
---|
1804 | TEST_ATTR_____("__ATTR__FORMAT((pos)+((sop)))", "__ATTR__FORMAT((pos)+((sop)))"); |
---|
1805 | TEST_ATTR_____("__ATTR__FORMAT(((pos)))+(sop))", "__ATTR__FORMAT(((pos)))"); |
---|
1806 | |
---|
1807 | TEST_ATTR_____("bla bla __ATTR__DEPRECATED __ATTR__FORMAT(pos) more content", "__ATTR__DEPRECATED __ATTR__FORMAT(pos)"); |
---|
1808 | TEST_ATTR_____("bla __ATTR__DEPRECATED bla more__ATTR__FORMAT(pos)content", "__ATTR__DEPRECATED __ATTR__FORMAT(pos)"); |
---|
1809 | |
---|
1810 | TEST_ATTR_____(" goes to header: __ATTR__NORETURN */", "__ATTR__NORETURN"); |
---|
1811 | |
---|
1812 | clear_found_attribute(); |
---|
1813 | } |
---|
1814 | TEST_PUBLISH(TEST_attribute_parser); |
---|
1815 | |
---|
1816 | #endif // UNIT_TESTS |
---|