FreeBasic: Update keywords
[geany-mirror.git] / tagmanager / ctags / objc.c
blob16363449dd4934eb1f611b8edee19ab41a97eebb
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;
485 prepareTag (&toCreate, ident, kind);
486 makeTagEntry (&toCreate);
489 static objcToken waitedToken, fallBackToken;
491 /* Ignore everything till waitedToken and jump to comeAfter.
492 * If the "end" keyword is encountered break, doesn't remember
493 * why though. */
494 static void tillToken (vString * const UNUSED (ident), objcToken what)
496 if (what == waitedToken)
497 toDoNext = comeAfter;
500 static void tillTokenOrFallBack (vString * const UNUSED (ident), objcToken what)
502 if (what == waitedToken)
503 toDoNext = comeAfter;
504 else if (what == fallBackToken)
506 toDoNext = fallback;
510 static int ignoreBalanced_count = 0;
511 static void ignoreBalanced (vString * const UNUSED (ident), objcToken what)
514 switch (what)
516 case Tok_PARL:
517 case Tok_CurlL:
518 case Tok_SQUAREL:
519 ignoreBalanced_count++;
520 break;
522 case Tok_PARR:
523 case Tok_CurlR:
524 case Tok_SQUARER:
525 ignoreBalanced_count--;
526 break;
528 default:
529 /* don't care */
530 break;
533 if (ignoreBalanced_count == 0)
534 toDoNext = comeAfter;
537 static void parseFields (vString * const ident, objcToken what)
539 switch (what)
541 case Tok_CurlR:
542 toDoNext = &parseMethods;
543 break;
545 case Tok_SQUAREL:
546 case Tok_PARL:
547 toDoNext = &ignoreBalanced;
548 comeAfter = &parseFields;
549 break;
551 /* we got an identifier, keep track of it */
552 case ObjcIDENTIFIER:
553 vStringCopy (tempName, ident);
554 break;
556 /* our last kept identifier must be our variable name =) */
557 case Tok_semi:
558 addTag (tempName, K_FIELD);
559 vStringClear (tempName);
560 break;
562 default:
563 /* NOTHING */
564 break;
568 objcKind methodKind;
571 static vString *fullMethodName;
572 static vString *prevIdent;
574 static void parseMethodsName (vString * const ident, objcToken what)
576 switch (what)
578 case Tok_PARL:
579 toDoNext = &tillToken;
580 comeAfter = &parseMethodsName;
581 waitedToken = Tok_PARR;
582 break;
584 case Tok_dpoint:
585 vStringCat (fullMethodName, prevIdent);
586 vStringCatS (fullMethodName, ":");
587 vStringClear (prevIdent);
588 break;
590 case ObjcIDENTIFIER:
591 vStringCopy (prevIdent, ident);
592 break;
594 case Tok_CurlL:
595 case Tok_semi:
596 /* method name is not simple */
597 if (vStringLength (fullMethodName) != '\0')
599 addTag (fullMethodName, methodKind);
600 vStringClear (fullMethodName);
602 else
603 addTag (prevIdent, methodKind);
605 toDoNext = &parseMethods;
606 parseImplemMethods (ident, what);
607 vStringClear (prevIdent);
608 break;
610 default:
611 break;
615 static void parseMethodsImplemName (vString * const ident, objcToken what)
617 switch (what)
619 case Tok_PARL:
620 toDoNext = &tillToken;
621 comeAfter = &parseMethodsImplemName;
622 waitedToken = Tok_PARR;
623 break;
625 case Tok_dpoint:
626 vStringCat (fullMethodName, prevIdent);
627 vStringCatS (fullMethodName, ":");
628 vStringClear (prevIdent);
629 break;
631 case ObjcIDENTIFIER:
632 vStringCopy (prevIdent, ident);
633 break;
635 case Tok_CurlL:
636 case Tok_semi:
637 /* method name is not simple */
638 if (vStringLength (fullMethodName) != '\0')
640 addTag (fullMethodName, methodKind);
641 vStringClear (fullMethodName);
643 else
644 addTag (prevIdent, methodKind);
646 toDoNext = &parseImplemMethods;
647 parseImplemMethods (ident, what);
648 vStringClear (prevIdent);
649 break;
651 default:
652 break;
656 static void parseImplemMethods (vString * const ident, objcToken what)
658 switch (what)
660 case Tok_PLUS: /* + */
661 toDoNext = &parseMethodsImplemName;
662 methodKind = K_CLASSMETHOD;
663 break;
665 case Tok_MINUS: /* - */
666 toDoNext = &parseMethodsImplemName;
667 methodKind = K_METHOD;
668 break;
670 case ObjcEND: /* @end */
671 popEnclosingContext ();
672 toDoNext = &globalScope;
673 break;
675 case Tok_CurlL: /* { */
676 toDoNext = &ignoreBalanced;
677 ignoreBalanced (ident, what);
678 comeAfter = &parseImplemMethods;
679 break;
681 default:
682 break;
686 static void parseProperty (vString * const ident, objcToken what)
688 switch (what)
690 case Tok_PARL:
691 toDoNext = &tillToken;
692 comeAfter = &parseProperty;
693 waitedToken = Tok_PARR;
694 break;
696 /* we got an identifier, keep track of it */
697 case ObjcIDENTIFIER:
698 vStringCopy (tempName, ident);
699 break;
701 /* our last kept identifier must be our variable name =) */
702 case Tok_semi:
703 addTag (tempName, K_PROPERTY);
704 vStringClear (tempName);
705 break;
707 default:
708 break;
712 static void parseMethods (vString * const UNUSED (ident), objcToken what)
714 switch (what)
716 case Tok_PLUS: /* + */
717 toDoNext = &parseMethodsName;
718 methodKind = K_CLASSMETHOD;
719 break;
721 case Tok_MINUS: /* - */
722 toDoNext = &parseMethodsName;
723 methodKind = K_METHOD;
724 break;
726 case ObjcPROPERTY:
727 toDoNext = &parseProperty;
728 break;
730 case ObjcEND: /* @end */
731 popEnclosingContext ();
732 toDoNext = &globalScope;
733 break;
735 case Tok_CurlL: /* { */
736 toDoNext = &parseFields;
737 break;
739 default:
740 break;
745 static void parseProtocol (vString * const ident, objcToken what)
747 if (what == ObjcIDENTIFIER)
749 pushEnclosingContext (ident, K_PROTOCOL);
750 addTag (ident, K_PROTOCOL);
752 toDoNext = &parseMethods;
755 static void parseImplementation (vString * const ident, objcToken what)
757 if (what == ObjcIDENTIFIER)
759 addTag (ident, K_IMPLEMENTATION);
760 pushEnclosingContext (ident, K_IMPLEMENTATION);
762 toDoNext = &parseImplemMethods;
765 static void parseInterface (vString * const ident, objcToken what)
767 if (what == ObjcIDENTIFIER)
769 addTag (ident, K_INTERFACE);
770 pushEnclosingContext (ident, K_INTERFACE);
773 toDoNext = &parseMethods;
776 static void parseStructMembers (vString * const ident, objcToken what)
778 static parseNext prev = NULL;
780 if (prev != NULL)
782 comeAfter = prev;
783 prev = NULL;
786 switch (what)
788 case ObjcIDENTIFIER:
789 vStringCopy (tempName, ident);
790 break;
792 case Tok_semi: /* ';' */
793 addTag (tempName, K_FIELD);
794 vStringClear (tempName);
795 break;
797 /* some types are complex, the only one
798 * we will loose is the function type.
800 case Tok_CurlL: /* '{' */
801 case Tok_PARL: /* '(' */
802 case Tok_SQUAREL: /* '[' */
803 toDoNext = &ignoreBalanced;
804 prev = comeAfter;
805 comeAfter = &parseStructMembers;
806 ignoreBalanced (ident, what);
807 break;
809 case Tok_CurlR:
810 toDoNext = comeAfter;
811 break;
813 default:
814 /* don't care */
815 break;
819 /* Called just after the struct keyword */
820 static boolean parseStruct_gotName = FALSE;
821 static void parseStruct (vString * const ident, objcToken what)
823 switch (what)
825 case ObjcIDENTIFIER:
826 if (!parseStruct_gotName)
828 addTag (ident, K_STRUCT);
829 pushEnclosingContext (ident, K_STRUCT);
830 parseStruct_gotName = TRUE;
832 else
834 parseStruct_gotName = FALSE;
835 popEnclosingContext ();
836 toDoNext = comeAfter;
837 comeAfter (ident, what);
839 break;
841 case Tok_CurlL:
842 toDoNext = &parseStructMembers;
843 break;
845 /* maybe it was just a forward declaration
846 * in which case, we pop the context */
847 case Tok_semi:
848 if (parseStruct_gotName)
849 popEnclosingContext ();
851 toDoNext = comeAfter;
852 comeAfter (ident, what);
853 break;
855 default:
856 /* we don't care */
857 break;
861 /* Parse enumeration members, ignoring potential initialization */
862 static parseNext parseEnumFields_prev = NULL;
863 static void parseEnumFields (vString * const ident, objcToken what)
865 if (parseEnumFields_prev != NULL)
867 comeAfter = parseEnumFields_prev;
868 parseEnumFields_prev = NULL;
871 switch (what)
873 case ObjcIDENTIFIER:
874 addTag (ident, K_ENUM);
875 parseEnumFields_prev = comeAfter;
876 waitedToken = Tok_COMA;
877 /* last item might not have a coma */
878 fallBackToken = Tok_CurlR;
879 fallback = comeAfter;
880 comeAfter = parseEnumFields;
881 toDoNext = &tillTokenOrFallBack;
882 break;
884 case Tok_CurlR:
885 toDoNext = comeAfter;
886 popEnclosingContext ();
887 break;
889 default:
890 /* don't care */
891 break;
895 /* parse enum ... { ... */
896 static boolean parseEnum_named = FALSE;
897 static void parseEnum (vString * const ident, objcToken what)
899 switch (what)
901 case ObjcIDENTIFIER:
902 if (!parseEnum_named)
904 addTag (ident, K_ENUM);
905 pushEnclosingContext (ident, K_ENUM);
906 parseEnum_named = TRUE;
908 else
910 parseEnum_named = FALSE;
911 popEnclosingContext ();
912 toDoNext = comeAfter;
913 comeAfter (ident, what);
915 break;
917 case Tok_CurlL: /* '{' */
918 toDoNext = &parseEnumFields;
919 parseEnum_named = FALSE;
920 break;
922 case Tok_semi: /* ';' */
923 if (parseEnum_named)
924 popEnclosingContext ();
925 toDoNext = comeAfter;
926 comeAfter (ident, what);
927 break;
929 default:
930 /* don't care */
931 break;
935 /* Parse something like
936 * typedef .... ident ;
937 * ignoring the defined type but in the case of struct,
938 * in which case struct are parsed.
940 static void parseTypedef (vString * const ident, objcToken what)
942 switch (what)
944 case ObjcSTRUCT:
945 toDoNext = &parseStruct;
946 comeAfter = &parseTypedef;
947 break;
949 case ObjcENUM:
950 toDoNext = &parseEnum;
951 comeAfter = &parseTypedef;
952 break;
954 case ObjcIDENTIFIER:
955 vStringCopy (tempName, ident);
956 break;
958 case Tok_semi: /* ';' */
959 addTag (tempName, K_TYPEDEF);
960 vStringClear (tempName);
961 toDoNext = &globalScope;
962 break;
964 default:
965 /* we don't care */
966 break;
970 static boolean ignorePreprocStuff_escaped = FALSE;
971 static void ignorePreprocStuff (vString * const UNUSED (ident), objcToken what)
973 switch (what)
975 case Tok_Backslash:
976 ignorePreprocStuff_escaped = TRUE;
977 break;
979 case Tok_EOL:
980 if (ignorePreprocStuff_escaped)
982 ignorePreprocStuff_escaped = FALSE;
984 else
986 toDoNext = &globalScope;
988 break;
990 default:
991 ignorePreprocStuff_escaped = FALSE;
992 break;
996 static void parseMacroName (vString * const ident, objcToken what)
998 if (what == ObjcIDENTIFIER)
999 addTag (ident, K_MACRO);
1001 toDoNext = &ignorePreprocStuff;
1004 static void parsePreproc (vString * const ident, objcToken what)
1006 switch (what)
1008 case ObjcIDENTIFIER:
1009 if (strcmp (vStringValue (ident), "define") == 0)
1010 toDoNext = &parseMacroName;
1011 else
1012 toDoNext = &ignorePreprocStuff;
1013 break;
1015 default:
1016 toDoNext = &ignorePreprocStuff;
1017 break;
1021 /* Handle the "strong" top levels, all 'big' declarations
1022 * happen here */
1023 static void globalScope (vString * const ident, objcToken what)
1025 switch (what)
1027 case Tok_Sharp:
1028 toDoNext = &parsePreproc;
1029 break;
1031 case ObjcSTRUCT:
1032 toDoNext = &parseStruct;
1033 comeAfter = &globalScope;
1034 break;
1036 case ObjcIDENTIFIER:
1037 /* we keep track of the identifier if we
1038 * come across a function. */
1039 vStringCopy (tempName, ident);
1040 break;
1042 case Tok_PARL:
1043 /* if we find an opening parenthesis it means we
1044 * found a function (or a macro...) */
1045 addTag (tempName, K_FUNCTION);
1046 vStringClear (tempName);
1047 comeAfter = &globalScope;
1048 toDoNext = &ignoreBalanced;
1049 ignoreBalanced (ident, what);
1050 break;
1052 case ObjcINTERFACE:
1053 toDoNext = &parseInterface;
1054 break;
1056 case ObjcIMPLEMENTATION:
1057 toDoNext = &parseImplementation;
1058 break;
1060 case ObjcPROTOCOL:
1061 toDoNext = &parseProtocol;
1062 break;
1064 case ObjcTYPEDEF:
1065 toDoNext = parseTypedef;
1066 comeAfter = &globalScope;
1067 break;
1069 case Tok_CurlL:
1070 comeAfter = &globalScope;
1071 toDoNext = &ignoreBalanced;
1072 ignoreBalanced (ident, what);
1073 break;
1075 case ObjcEND:
1076 case ObjcPUBLIC:
1077 case ObjcPROTECTED:
1078 case ObjcPRIVATE:
1080 default:
1081 /* we don't care */
1082 break;
1086 /*////////////////////////////////////////////////////////////////
1087 //// Deal with the system */
1089 static void findObjcTags (void)
1091 vString *name = vStringNew ();
1092 lexingState st;
1093 objcToken tok;
1095 parentName = vStringNew ();
1096 tempName = vStringNew ();
1097 fullMethodName = vStringNew ();
1098 prevIdent = vStringNew ();
1100 /* (Re-)initialize state variables, this might be a second file */
1101 comeAfter = NULL;
1102 fallback = NULL;
1103 parentType = K_INTERFACE;
1104 ignoreBalanced_count = 0;
1105 methodKind = 0;
1106 parseStruct_gotName = FALSE;
1107 parseEnumFields_prev = NULL;
1108 parseEnum_named = FALSE;
1109 ignorePreprocStuff_escaped = FALSE;
1111 st.name = vStringNew ();
1112 st.cp = fileReadLine ();
1113 toDoNext = &globalScope;
1114 tok = lex (&st);
1115 while (tok != Tok_EOF)
1117 (*toDoNext) (st.name, tok);
1118 tok = lex (&st);
1121 vStringDelete (name);
1122 vStringDelete (parentName);
1123 vStringDelete (tempName);
1124 vStringDelete (fullMethodName);
1125 vStringDelete (prevIdent);
1126 parentName = NULL;
1127 tempName = NULL;
1128 prevIdent = NULL;
1129 fullMethodName = NULL;
1132 static void objcInitialize (const langType language)
1134 Lang_ObjectiveC = language;
1136 initKeywordHash ();
1139 extern parserDefinition *ObjcParser (void)
1141 static const char *const extensions[] = { "m", "h", NULL };
1142 parserDefinition *def = parserNew ("ObjectiveC");
1143 def->kinds = ObjcKinds;
1144 def->kindCount = KIND_COUNT (ObjcKinds);
1145 def->extensions = extensions;
1146 def->parser = findObjcTags;
1147 def->initialize = objcInitialize;
1149 return def;