Merge pull request #651 from b4n/vte-in-various-prefs
[geany-mirror.git] / ctags / parsers / objc.c
blob2593f831bc81015550f6cc2c2d990485aab119ec
2 /*
3 * Copyright (c) 2010, Vincent Berthoux
5 * This source code is released for free distribution under the terms of the
6 * GNU General Public License.
8 * This module contains functions for generating tags for Objective C
9 * language files.
12 * INCLUDE FILES
14 #include "general.h" /* must always come first */
16 #include <string.h>
18 #include "keyword.h"
19 #include "entry.h"
20 #include "options.h"
21 #include "read.h"
22 #include "vstring.h"
24 /* To get rid of unused parameter warning in
25 * -Wextra */
26 #ifdef UNUSED
27 #elif defined(__GNUC__)
28 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
29 #elif defined(__LCLINT__)
30 # define UNUSED(x) /*@unused@*/ x
31 #else
32 # define UNUSED(x) x
33 #endif
35 typedef enum {
36 K_INTERFACE,
37 K_IMPLEMENTATION,
38 K_PROTOCOL,
39 K_METHOD,
40 K_CLASSMETHOD,
41 K_VAR,
42 K_FIELD,
43 K_FUNCTION,
44 K_PROPERTY,
45 K_TYPEDEF,
46 K_STRUCT,
47 K_ENUM,
48 K_MACRO
49 } objcKind;
51 static kindOption ObjcKinds[] = {
52 {TRUE, 'i', "interface", "class interface"},
53 {TRUE, 'I', "implementation", "class implementation"},
54 {TRUE, 'P', "protocol", "Protocol"},
55 {TRUE, 'm', "method", "Object's method"},
56 {TRUE, 'c', "class", "Class' method"},
57 {TRUE, 'v', "var", "Global variable"},
58 {TRUE, 'F', "field", "Object field"},
59 {TRUE, 'f', "function", "A function"},
60 {TRUE, 'p', "property", "A property"},
61 {TRUE, 't', "typedef", "A type alias"},
62 {TRUE, 's', "struct", "A type structure"},
63 {TRUE, 'e', "enum", "An enumeration"},
64 {TRUE, 'M', "macro", "A preprocessor macro"},
67 typedef enum {
68 ObjcTYPEDEF,
69 ObjcSTRUCT,
70 ObjcENUM,
71 ObjcIMPLEMENTATION,
72 ObjcINTERFACE,
73 ObjcPROTOCOL,
74 ObjcENCODE,
75 ObjcSYNCHRONIZED,
76 ObjcSELECTOR,
77 ObjcPROPERTY,
78 ObjcEND,
79 ObjcDEFS,
80 ObjcCLASS,
81 ObjcPRIVATE,
82 ObjcPACKAGE,
83 ObjcPUBLIC,
84 ObjcPROTECTED,
85 ObjcSYNTHESIZE,
86 ObjcDYNAMIC,
87 ObjcOPTIONAL,
88 ObjcREQUIRED,
89 ObjcSTRING,
90 ObjcIDENTIFIER,
92 Tok_COMA, /* ',' */
93 Tok_PLUS, /* '+' */
94 Tok_MINUS, /* '-' */
95 Tok_PARL, /* '(' */
96 Tok_PARR, /* ')' */
97 Tok_CurlL, /* '{' */
98 Tok_CurlR, /* '}' */
99 Tok_SQUAREL, /* '[' */
100 Tok_SQUARER, /* ']' */
101 Tok_semi, /* ';' */
102 Tok_dpoint, /* ':' */
103 Tok_Sharp, /* '#' */
104 Tok_Backslash, /* '\\' */
105 Tok_EOL, /* '\r''\n' */
106 Tok_any,
108 Tok_EOF /* END of file */
109 } objcKeyword;
111 typedef objcKeyword objcToken;
113 typedef struct sOBjcKeywordDesc {
114 const char *name;
115 objcKeyword id;
116 } objcKeywordDesc;
119 static const objcKeywordDesc objcKeywordTable[] = {
120 {"typedef", ObjcTYPEDEF},
121 {"struct", ObjcSTRUCT},
122 {"enum", ObjcENUM},
123 {"@implementation", ObjcIMPLEMENTATION},
124 {"@interface", ObjcINTERFACE},
125 {"@protocol", ObjcPROTOCOL},
126 {"@encode", ObjcENCODE},
127 {"@property", ObjcPROPERTY},
128 {"@synchronized", ObjcSYNCHRONIZED},
129 {"@selector", ObjcSELECTOR},
130 {"@end", ObjcEND},
131 {"@defs", ObjcDEFS},
132 {"@class", ObjcCLASS},
133 {"@private", ObjcPRIVATE},
134 {"@package", ObjcPACKAGE},
135 {"@public", ObjcPUBLIC},
136 {"@protected", ObjcPROTECTED},
137 {"@synthesize", ObjcSYNTHESIZE},
138 {"@dynamic", ObjcDYNAMIC},
139 {"@optional", ObjcOPTIONAL},
140 {"@required", ObjcREQUIRED},
143 static langType Lang_ObjectiveC;
145 /*//////////////////////////////////////////////////////////////////
146 //// lexingInit */
147 typedef struct _lexingState {
148 vString *name; /* current parsed identifier/operator */
149 const unsigned char *cp; /* position in stream */
150 } lexingState;
152 static void initKeywordHash (void)
154 const size_t count = sizeof (objcKeywordTable) / sizeof (objcKeywordDesc);
155 size_t i;
157 for (i = 0; i < count; ++i)
159 addKeyword (objcKeywordTable[i].name, Lang_ObjectiveC,
160 (int) objcKeywordTable[i].id);
164 /*//////////////////////////////////////////////////////////////////////
165 //// Lexing */
166 static boolean isNum (char c)
168 return c >= '0' && c <= '9';
171 static boolean isLowerAlpha (char c)
173 return c >= 'a' && c <= 'z';
176 static boolean isUpperAlpha (char c)
178 return c >= 'A' && c <= 'Z';
181 static boolean isAlpha (char c)
183 return isLowerAlpha (c) || isUpperAlpha (c);
186 static boolean isIdent (char c)
188 return isNum (c) || isAlpha (c) || c == '_';
191 static boolean isSpace (char c)
193 return c == ' ' || c == '\t';
196 /* return true if it end with an end of line */
197 static void eatWhiteSpace (lexingState * st)
199 const unsigned char *cp = st->cp;
200 while (isSpace (*cp))
201 cp++;
203 st->cp = cp;
206 static void eatString (lexingState * st)
208 boolean lastIsBackSlash = FALSE;
209 boolean unfinished = TRUE;
210 const unsigned char *c = st->cp + 1;
212 while (unfinished)
214 /* end of line should never happen.
215 * we tolerate it */
216 if (c == NULL || c[0] == '\0')
217 break;
218 else if (*c == '"' && !lastIsBackSlash)
219 unfinished = FALSE;
220 else
221 lastIsBackSlash = *c == '\\';
223 c++;
226 st->cp = c;
229 static void eatComment (lexingState * st)
231 boolean unfinished = TRUE;
232 boolean lastIsStar = FALSE;
233 const unsigned char *c = st->cp + 2;
235 while (unfinished)
237 /* we've reached the end of the line..
238 * so we have to reload a line... */
239 if (c == NULL || *c == '\0')
241 st->cp = fileReadLine ();
242 /* WOOPS... no more input...
243 * we return, next lexing read
244 * will be null and ok */
245 if (st->cp == NULL)
246 return;
247 c = st->cp;
249 /* we've reached the end of the comment */
250 else if (*c == '/' && lastIsStar)
251 unfinished = FALSE;
252 else
254 lastIsStar = '*' == *c;
255 c++;
259 st->cp = c;
262 static void readIdentifier (lexingState * st)
264 const unsigned char *p;
265 vStringClear (st->name);
267 /* first char is a simple letter */
268 if (isAlpha (*st->cp) || *st->cp == '_')
269 vStringPut (st->name, (int) *st->cp);
271 /* Go till you get identifier chars */
272 for (p = st->cp + 1; isIdent (*p); p++)
273 vStringPut (st->name, (int) *p);
275 st->cp = p;
277 vStringTerminate (st->name);
280 /* read the @something directives */
281 static void readIdentifierObjcDirective (lexingState * st)
283 const unsigned char *p;
284 vStringClear (st->name);
286 /* first char is a simple letter */
287 if (*st->cp == '@')
288 vStringPut (st->name, (int) *st->cp);
290 /* Go till you get identifier chars */
291 for (p = st->cp + 1; isIdent (*p); p++)
292 vStringPut (st->name, (int) *p);
294 st->cp = p;
296 vStringTerminate (st->name);
299 /* The lexer is in charge of reading the file.
300 * Some of sub-lexer (like eatComment) also read file.
301 * lexing is finished when the lexer return Tok_EOF */
302 static objcKeyword lex (lexingState * st)
304 int retType;
306 /* handling data input here */
307 while (st->cp == NULL || st->cp[0] == '\0')
309 st->cp = fileReadLine ();
310 if (st->cp == NULL)
311 return Tok_EOF;
313 return Tok_EOL;
316 if (isAlpha (*st->cp))
318 readIdentifier (st);
319 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
321 if (retType == -1) /* If it's not a keyword */
323 return ObjcIDENTIFIER;
325 else
327 return retType;
330 else if (*st->cp == '@')
332 readIdentifierObjcDirective (st);
333 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
335 if (retType == -1) /* If it's not a keyword */
337 return Tok_any;
339 else
341 return retType;
344 else if (isSpace (*st->cp))
346 eatWhiteSpace (st);
347 return lex (st);
349 else
350 switch (*st->cp)
352 case '(':
353 st->cp++;
354 return Tok_PARL;
356 case '\\':
357 st->cp++;
358 return Tok_Backslash;
360 case '#':
361 st->cp++;
362 return Tok_Sharp;
364 case '/':
365 if (st->cp[1] == '*') /* ergl, a comment */
367 eatComment (st);
368 return lex (st);
370 else if (st->cp[1] == '/')
372 st->cp = NULL;
373 return lex (st);
375 else
377 st->cp++;
378 return Tok_any;
380 break;
382 case ')':
383 st->cp++;
384 return Tok_PARR;
385 case '{':
386 st->cp++;
387 return Tok_CurlL;
388 case '}':
389 st->cp++;
390 return Tok_CurlR;
391 case '[':
392 st->cp++;
393 return Tok_SQUAREL;
394 case ']':
395 st->cp++;
396 return Tok_SQUARER;
397 case ',':
398 st->cp++;
399 return Tok_COMA;
400 case ';':
401 st->cp++;
402 return Tok_semi;
403 case ':':
404 st->cp++;
405 return Tok_dpoint;
406 case '"':
407 eatString (st);
408 return Tok_any;
409 case '+':
410 st->cp++;
411 return Tok_PLUS;
412 case '-':
413 st->cp++;
414 return Tok_MINUS;
416 default:
417 st->cp++;
418 break;
421 /* default return if nothing is recognized,
422 * shouldn't happen, but at least, it will
423 * be handled without destroying the parsing. */
424 return Tok_any;
427 /*//////////////////////////////////////////////////////////////////////
428 //// Parsing */
429 typedef void (*parseNext) (vString * const ident, objcToken what);
431 /********** Helpers */
432 /* This variable hold the 'parser' which is going to
433 * handle the next token */
434 static parseNext toDoNext;
436 /* Special variable used by parser eater to
437 * determine which action to put after their
438 * job is finished. */
439 static parseNext comeAfter;
441 /* Used by some parsers detecting certain token
442 * to revert to previous parser. */
443 static parseNext fallback;
446 /********** Grammar */
447 static void globalScope (vString * const ident, objcToken what);
448 static void parseMethods (vString * const ident, objcToken what);
449 static void parseImplemMethods (vString * const ident, objcToken what);
450 static vString *tempName = NULL;
451 static vString *parentName = NULL;
452 static objcKind parentType = K_INTERFACE;
454 /* used to prepare tag for OCaml, just in case their is a need to
455 * add additional information to the tag. */
456 static void prepareTag (tagEntryInfo * tag, vString const *name, objcKind kind)
458 initTagEntry (tag, vStringValue (name));
459 tag->kindName = ObjcKinds[kind].name;
460 tag->kind = ObjcKinds[kind].letter;
462 if (parentName != NULL)
464 tag->extensionFields.scope[0] = ObjcKinds[parentType].name;
465 tag->extensionFields.scope[1] = vStringValue (parentName);
469 static void pushEnclosingContext (const vString * parent, objcKind type)
471 vStringCopy (parentName, parent);
472 parentType = type;
475 static void popEnclosingContext (void)
477 vStringClear (parentName);
480 /* Used to centralise tag creation, and be able to add
481 * more information to it in the future */
482 static void addTag (vString * const ident, int kind)
484 tagEntryInfo toCreate;
486 if (! ObjcKinds[kind].enabled)
487 return;
489 prepareTag (&toCreate, ident, kind);
490 makeTagEntry (&toCreate);
493 static objcToken waitedToken, fallBackToken;
495 /* Ignore everything till waitedToken and jump to comeAfter.
496 * If the "end" keyword is encountered break, doesn't remember
497 * why though. */
498 static void tillToken (vString * const UNUSED (ident), objcToken what)
500 if (what == waitedToken)
501 toDoNext = comeAfter;
504 static void tillTokenOrFallBack (vString * const UNUSED (ident), objcToken what)
506 if (what == waitedToken)
507 toDoNext = comeAfter;
508 else if (what == fallBackToken)
510 toDoNext = fallback;
514 static int ignoreBalanced_count = 0;
515 static void ignoreBalanced (vString * const UNUSED (ident), objcToken what)
518 switch (what)
520 case Tok_PARL:
521 case Tok_CurlL:
522 case Tok_SQUAREL:
523 ignoreBalanced_count++;
524 break;
526 case Tok_PARR:
527 case Tok_CurlR:
528 case Tok_SQUARER:
529 ignoreBalanced_count--;
530 break;
532 default:
533 /* don't care */
534 break;
537 if (ignoreBalanced_count == 0)
538 toDoNext = comeAfter;
541 static void parseFields (vString * const ident, objcToken what)
543 switch (what)
545 case Tok_CurlR:
546 toDoNext = &parseMethods;
547 break;
549 case Tok_SQUAREL:
550 case Tok_PARL:
551 toDoNext = &ignoreBalanced;
552 comeAfter = &parseFields;
553 break;
555 /* we got an identifier, keep track of it */
556 case ObjcIDENTIFIER:
557 vStringCopy (tempName, ident);
558 break;
560 /* our last kept identifier must be our variable name =) */
561 case Tok_semi:
562 addTag (tempName, K_FIELD);
563 vStringClear (tempName);
564 break;
566 default:
567 /* NOTHING */
568 break;
572 static objcKind methodKind;
575 static vString *fullMethodName;
576 static vString *prevIdent;
578 static void parseMethodsName (vString * const ident, objcToken what)
580 switch (what)
582 case Tok_PARL:
583 toDoNext = &tillToken;
584 comeAfter = &parseMethodsName;
585 waitedToken = Tok_PARR;
586 break;
588 case Tok_dpoint:
589 vStringCat (fullMethodName, prevIdent);
590 vStringCatS (fullMethodName, ":");
591 vStringClear (prevIdent);
592 break;
594 case ObjcIDENTIFIER:
595 vStringCopy (prevIdent, ident);
596 break;
598 case Tok_CurlL:
599 case Tok_semi:
600 /* method name is not simple */
601 if (vStringLength (fullMethodName) != '\0')
603 addTag (fullMethodName, methodKind);
604 vStringClear (fullMethodName);
606 else
607 addTag (prevIdent, methodKind);
609 toDoNext = &parseMethods;
610 parseImplemMethods (ident, what);
611 vStringClear (prevIdent);
612 break;
614 default:
615 break;
619 static void parseMethodsImplemName (vString * const ident, objcToken what)
621 switch (what)
623 case Tok_PARL:
624 toDoNext = &tillToken;
625 comeAfter = &parseMethodsImplemName;
626 waitedToken = Tok_PARR;
627 break;
629 case Tok_dpoint:
630 vStringCat (fullMethodName, prevIdent);
631 vStringCatS (fullMethodName, ":");
632 vStringClear (prevIdent);
633 break;
635 case ObjcIDENTIFIER:
636 vStringCopy (prevIdent, ident);
637 break;
639 case Tok_CurlL:
640 case Tok_semi:
641 /* method name is not simple */
642 if (vStringLength (fullMethodName) != '\0')
644 addTag (fullMethodName, methodKind);
645 vStringClear (fullMethodName);
647 else
648 addTag (prevIdent, methodKind);
650 toDoNext = &parseImplemMethods;
651 parseImplemMethods (ident, what);
652 vStringClear (prevIdent);
653 break;
655 default:
656 break;
660 static void parseImplemMethods (vString * const ident, objcToken what)
662 switch (what)
664 case Tok_PLUS: /* + */
665 toDoNext = &parseMethodsImplemName;
666 methodKind = K_CLASSMETHOD;
667 break;
669 case Tok_MINUS: /* - */
670 toDoNext = &parseMethodsImplemName;
671 methodKind = K_METHOD;
672 break;
674 case ObjcEND: /* @end */
675 popEnclosingContext ();
676 toDoNext = &globalScope;
677 break;
679 case Tok_CurlL: /* { */
680 toDoNext = &ignoreBalanced;
681 ignoreBalanced (ident, what);
682 comeAfter = &parseImplemMethods;
683 break;
685 default:
686 break;
690 static void parseProperty (vString * const ident, objcToken what)
692 switch (what)
694 case Tok_PARL:
695 toDoNext = &tillToken;
696 comeAfter = &parseProperty;
697 waitedToken = Tok_PARR;
698 break;
700 /* we got an identifier, keep track of it */
701 case ObjcIDENTIFIER:
702 vStringCopy (tempName, ident);
703 break;
705 /* our last kept identifier must be our variable name =) */
706 case Tok_semi:
707 addTag (tempName, K_PROPERTY);
708 vStringClear (tempName);
709 toDoNext = &parseMethods;
710 break;
712 default:
713 break;
717 static void parseMethods (vString * const UNUSED (ident), objcToken what)
719 switch (what)
721 case Tok_PLUS: /* + */
722 toDoNext = &parseMethodsName;
723 methodKind = K_CLASSMETHOD;
724 break;
726 case Tok_MINUS: /* - */
727 toDoNext = &parseMethodsName;
728 methodKind = K_METHOD;
729 break;
731 case ObjcPROPERTY:
732 toDoNext = &parseProperty;
733 break;
735 case ObjcEND: /* @end */
736 popEnclosingContext ();
737 toDoNext = &globalScope;
738 break;
740 case Tok_CurlL: /* { */
741 toDoNext = &parseFields;
742 break;
744 default:
745 break;
750 static void parseProtocol (vString * const ident, objcToken what)
752 if (what == ObjcIDENTIFIER)
754 pushEnclosingContext (ident, K_PROTOCOL);
755 addTag (ident, K_PROTOCOL);
757 toDoNext = &parseMethods;
760 static void parseImplementation (vString * const ident, objcToken what)
762 if (what == ObjcIDENTIFIER)
764 addTag (ident, K_IMPLEMENTATION);
765 pushEnclosingContext (ident, K_IMPLEMENTATION);
767 toDoNext = &parseImplemMethods;
770 static void parseInterface (vString * const ident, objcToken what)
772 if (what == ObjcIDENTIFIER)
774 addTag (ident, K_INTERFACE);
775 pushEnclosingContext (ident, K_INTERFACE);
778 toDoNext = &parseMethods;
781 static void parseStructMembers (vString * const ident, objcToken what)
783 static parseNext prev = NULL;
785 if (prev != NULL)
787 comeAfter = prev;
788 prev = NULL;
791 switch (what)
793 case ObjcIDENTIFIER:
794 vStringCopy (tempName, ident);
795 break;
797 case Tok_semi: /* ';' */
798 addTag (tempName, K_FIELD);
799 vStringClear (tempName);
800 break;
802 /* some types are complex, the only one
803 * we will loose is the function type.
805 case Tok_CurlL: /* '{' */
806 case Tok_PARL: /* '(' */
807 case Tok_SQUAREL: /* '[' */
808 toDoNext = &ignoreBalanced;
809 prev = comeAfter;
810 comeAfter = &parseStructMembers;
811 ignoreBalanced (ident, what);
812 break;
814 case Tok_CurlR:
815 toDoNext = comeAfter;
816 break;
818 default:
819 /* don't care */
820 break;
824 /* Called just after the struct keyword */
825 static boolean parseStruct_gotName = FALSE;
826 static void parseStruct (vString * const ident, objcToken what)
828 switch (what)
830 case ObjcIDENTIFIER:
831 if (!parseStruct_gotName)
833 addTag (ident, K_STRUCT);
834 pushEnclosingContext (ident, K_STRUCT);
835 parseStruct_gotName = TRUE;
837 else
839 parseStruct_gotName = FALSE;
840 popEnclosingContext ();
841 toDoNext = comeAfter;
842 comeAfter (ident, what);
844 break;
846 case Tok_CurlL:
847 toDoNext = &parseStructMembers;
848 break;
850 /* maybe it was just a forward declaration
851 * in which case, we pop the context */
852 case Tok_semi:
853 if (parseStruct_gotName)
854 popEnclosingContext ();
856 toDoNext = comeAfter;
857 comeAfter (ident, what);
858 break;
860 default:
861 /* we don't care */
862 break;
866 /* Parse enumeration members, ignoring potential initialization */
867 static parseNext parseEnumFields_prev = NULL;
868 static void parseEnumFields (vString * const ident, objcToken what)
870 if (parseEnumFields_prev != NULL)
872 comeAfter = parseEnumFields_prev;
873 parseEnumFields_prev = NULL;
876 switch (what)
878 case ObjcIDENTIFIER:
879 addTag (ident, K_ENUM);
880 parseEnumFields_prev = comeAfter;
881 waitedToken = Tok_COMA;
882 /* last item might not have a coma */
883 fallBackToken = Tok_CurlR;
884 fallback = comeAfter;
885 comeAfter = parseEnumFields;
886 toDoNext = &tillTokenOrFallBack;
887 break;
889 case Tok_CurlR:
890 toDoNext = comeAfter;
891 popEnclosingContext ();
892 break;
894 default:
895 /* don't care */
896 break;
900 /* parse enum ... { ... */
901 static boolean parseEnum_named = FALSE;
902 static void parseEnum (vString * const ident, objcToken what)
904 switch (what)
906 case ObjcIDENTIFIER:
907 if (!parseEnum_named)
909 addTag (ident, K_ENUM);
910 pushEnclosingContext (ident, K_ENUM);
911 parseEnum_named = TRUE;
913 else
915 parseEnum_named = FALSE;
916 popEnclosingContext ();
917 toDoNext = comeAfter;
918 comeAfter (ident, what);
920 break;
922 case Tok_CurlL: /* '{' */
923 toDoNext = &parseEnumFields;
924 parseEnum_named = FALSE;
925 break;
927 case Tok_semi: /* ';' */
928 if (parseEnum_named)
929 popEnclosingContext ();
930 toDoNext = comeAfter;
931 comeAfter (ident, what);
932 break;
934 default:
935 /* don't care */
936 break;
940 /* Parse something like
941 * typedef .... ident ;
942 * ignoring the defined type but in the case of struct,
943 * in which case struct are parsed.
945 static void parseTypedef (vString * const ident, objcToken what)
947 switch (what)
949 case ObjcSTRUCT:
950 toDoNext = &parseStruct;
951 comeAfter = &parseTypedef;
952 break;
954 case ObjcENUM:
955 toDoNext = &parseEnum;
956 comeAfter = &parseTypedef;
957 break;
959 case ObjcIDENTIFIER:
960 vStringCopy (tempName, ident);
961 break;
963 case Tok_semi: /* ';' */
964 addTag (tempName, K_TYPEDEF);
965 vStringClear (tempName);
966 toDoNext = &globalScope;
967 break;
969 default:
970 /* we don't care */
971 break;
975 static boolean ignorePreprocStuff_escaped = FALSE;
976 static void ignorePreprocStuff (vString * const UNUSED (ident), objcToken what)
978 switch (what)
980 case Tok_Backslash:
981 ignorePreprocStuff_escaped = TRUE;
982 break;
984 case Tok_EOL:
985 if (ignorePreprocStuff_escaped)
987 ignorePreprocStuff_escaped = FALSE;
989 else
991 toDoNext = &globalScope;
993 break;
995 default:
996 ignorePreprocStuff_escaped = FALSE;
997 break;
1001 static void parseMacroName (vString * const ident, objcToken what)
1003 if (what == ObjcIDENTIFIER)
1004 addTag (ident, K_MACRO);
1006 toDoNext = &ignorePreprocStuff;
1009 static void parsePreproc (vString * const ident, objcToken what)
1011 switch (what)
1013 case ObjcIDENTIFIER:
1014 if (strcmp (vStringValue (ident), "define") == 0)
1015 toDoNext = &parseMacroName;
1016 else
1017 toDoNext = &ignorePreprocStuff;
1018 break;
1020 default:
1021 toDoNext = &ignorePreprocStuff;
1022 break;
1026 /* Handle the "strong" top levels, all 'big' declarations
1027 * happen here */
1028 static void globalScope (vString * const ident, objcToken what)
1030 switch (what)
1032 case Tok_Sharp:
1033 toDoNext = &parsePreproc;
1034 break;
1036 case ObjcSTRUCT:
1037 toDoNext = &parseStruct;
1038 comeAfter = &globalScope;
1039 break;
1041 case ObjcIDENTIFIER:
1042 /* we keep track of the identifier if we
1043 * come across a function. */
1044 vStringCopy (tempName, ident);
1045 break;
1047 case Tok_PARL:
1048 /* if we find an opening parenthesis it means we
1049 * found a function (or a macro...) */
1050 addTag (tempName, K_FUNCTION);
1051 vStringClear (tempName);
1052 comeAfter = &globalScope;
1053 toDoNext = &ignoreBalanced;
1054 ignoreBalanced (ident, what);
1055 break;
1057 case ObjcINTERFACE:
1058 toDoNext = &parseInterface;
1059 break;
1061 case ObjcIMPLEMENTATION:
1062 toDoNext = &parseImplementation;
1063 break;
1065 case ObjcPROTOCOL:
1066 toDoNext = &parseProtocol;
1067 break;
1069 case ObjcTYPEDEF:
1070 toDoNext = parseTypedef;
1071 comeAfter = &globalScope;
1072 break;
1074 case Tok_CurlL:
1075 comeAfter = &globalScope;
1076 toDoNext = &ignoreBalanced;
1077 ignoreBalanced (ident, what);
1078 break;
1080 case ObjcEND:
1081 case ObjcPUBLIC:
1082 case ObjcPROTECTED:
1083 case ObjcPRIVATE:
1085 default:
1086 /* we don't care */
1087 break;
1091 /*////////////////////////////////////////////////////////////////
1092 //// Deal with the system */
1094 static void findObjcTags (void)
1096 vString *name = vStringNew ();
1097 lexingState st;
1098 objcToken tok;
1100 parentName = vStringNew ();
1101 tempName = vStringNew ();
1102 fullMethodName = vStringNew ();
1103 prevIdent = vStringNew ();
1105 /* (Re-)initialize state variables, this might be a second file */
1106 comeAfter = NULL;
1107 fallback = NULL;
1108 parentType = K_INTERFACE;
1109 ignoreBalanced_count = 0;
1110 methodKind = 0;
1111 parseStruct_gotName = FALSE;
1112 parseEnumFields_prev = NULL;
1113 parseEnum_named = FALSE;
1114 ignorePreprocStuff_escaped = FALSE;
1116 st.name = vStringNew ();
1117 st.cp = fileReadLine ();
1118 toDoNext = &globalScope;
1119 tok = lex (&st);
1120 while (tok != Tok_EOF)
1122 (*toDoNext) (st.name, tok);
1123 tok = lex (&st);
1125 vStringDelete(st.name);
1127 vStringDelete (name);
1128 vStringDelete (parentName);
1129 vStringDelete (tempName);
1130 vStringDelete (fullMethodName);
1131 vStringDelete (prevIdent);
1132 parentName = NULL;
1133 tempName = NULL;
1134 prevIdent = NULL;
1135 fullMethodName = NULL;
1138 static void objcInitialize (const langType language)
1140 Lang_ObjectiveC = language;
1142 initKeywordHash ();
1145 extern parserDefinition *ObjcParser (void)
1147 static const char *const extensions[] = { "m", "h", NULL };
1148 parserDefinition *def = parserNew ("ObjectiveC");
1149 def->kinds = ObjcKinds;
1150 def->kindCount = KIND_COUNT (ObjcKinds);
1151 def->extensions = extensions;
1152 def->parser = findObjcTags;
1153 def->initialize = objcInitialize;
1155 return def;