Make parser includes closer to uctags and sync parser license header
[geany-mirror.git] / ctags / parsers / objc.c
blobfb42469fe503a358070b4069e08576bffdf4bf86
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 version 2 or (at your option) any later version.
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 "routines.h"
23 #include "vstring.h"
25 /* To get rid of unused parameter warning in
26 * -Wextra */
27 #ifdef UNUSED
28 #elif defined(__GNUC__)
29 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
30 #elif defined(__LCLINT__)
31 # define UNUSED(x) /*@unused@*/ x
32 #else
33 # define UNUSED(x) x
34 #endif
36 typedef enum {
37 K_INTERFACE,
38 K_IMPLEMENTATION,
39 K_PROTOCOL,
40 K_METHOD,
41 K_CLASSMETHOD,
42 K_VAR,
43 K_FIELD,
44 K_FUNCTION,
45 K_PROPERTY,
46 K_TYPEDEF,
47 K_STRUCT,
48 K_ENUM,
49 K_MACRO
50 } objcKind;
52 static kindOption ObjcKinds[] = {
53 {TRUE, 'i', "interface", "class interface"},
54 {TRUE, 'I', "implementation", "class implementation"},
55 {TRUE, 'P', "protocol", "Protocol"},
56 {TRUE, 'm', "method", "Object's method"},
57 {TRUE, 'c', "class", "Class' method"},
58 {TRUE, 'v', "var", "Global variable"},
59 {TRUE, 'F', "field", "Object field"},
60 {TRUE, 'f', "function", "A function"},
61 {TRUE, 'p', "property", "A property"},
62 {TRUE, 't', "typedef", "A type alias"},
63 {TRUE, 's', "struct", "A type structure"},
64 {TRUE, 'e', "enum", "An enumeration"},
65 {TRUE, 'M', "macro", "A preprocessor macro"},
68 typedef enum {
69 ObjcTYPEDEF,
70 ObjcSTRUCT,
71 ObjcENUM,
72 ObjcIMPLEMENTATION,
73 ObjcINTERFACE,
74 ObjcPROTOCOL,
75 ObjcENCODE,
76 ObjcSYNCHRONIZED,
77 ObjcSELECTOR,
78 ObjcPROPERTY,
79 ObjcEND,
80 ObjcDEFS,
81 ObjcCLASS,
82 ObjcPRIVATE,
83 ObjcPACKAGE,
84 ObjcPUBLIC,
85 ObjcPROTECTED,
86 ObjcSYNTHESIZE,
87 ObjcDYNAMIC,
88 ObjcOPTIONAL,
89 ObjcREQUIRED,
90 ObjcSTRING,
91 ObjcIDENTIFIER,
93 Tok_COMA, /* ',' */
94 Tok_PLUS, /* '+' */
95 Tok_MINUS, /* '-' */
96 Tok_PARL, /* '(' */
97 Tok_PARR, /* ')' */
98 Tok_CurlL, /* '{' */
99 Tok_CurlR, /* '}' */
100 Tok_SQUAREL, /* '[' */
101 Tok_SQUARER, /* ']' */
102 Tok_semi, /* ';' */
103 Tok_dpoint, /* ':' */
104 Tok_Sharp, /* '#' */
105 Tok_Backslash, /* '\\' */
106 Tok_EOL, /* '\r''\n' */
107 Tok_any,
109 Tok_EOF /* END of file */
110 } objcKeyword;
112 typedef objcKeyword objcToken;
114 typedef struct sOBjcKeywordDesc {
115 const char *name;
116 objcKeyword id;
117 } objcKeywordDesc;
120 static const objcKeywordDesc objcKeywordTable[] = {
121 {"typedef", ObjcTYPEDEF},
122 {"struct", ObjcSTRUCT},
123 {"enum", ObjcENUM},
124 {"@implementation", ObjcIMPLEMENTATION},
125 {"@interface", ObjcINTERFACE},
126 {"@protocol", ObjcPROTOCOL},
127 {"@encode", ObjcENCODE},
128 {"@property", ObjcPROPERTY},
129 {"@synchronized", ObjcSYNCHRONIZED},
130 {"@selector", ObjcSELECTOR},
131 {"@end", ObjcEND},
132 {"@defs", ObjcDEFS},
133 {"@class", ObjcCLASS},
134 {"@private", ObjcPRIVATE},
135 {"@package", ObjcPACKAGE},
136 {"@public", ObjcPUBLIC},
137 {"@protected", ObjcPROTECTED},
138 {"@synthesize", ObjcSYNTHESIZE},
139 {"@dynamic", ObjcDYNAMIC},
140 {"@optional", ObjcOPTIONAL},
141 {"@required", ObjcREQUIRED},
144 static langType Lang_ObjectiveC;
146 /*//////////////////////////////////////////////////////////////////
147 //// lexingInit */
148 typedef struct _lexingState {
149 vString *name; /* current parsed identifier/operator */
150 const unsigned char *cp; /* position in stream */
151 } lexingState;
153 static void initKeywordHash (void)
155 const size_t count = sizeof (objcKeywordTable) / sizeof (objcKeywordDesc);
156 size_t i;
158 for (i = 0; i < count; ++i)
160 addKeyword (objcKeywordTable[i].name, Lang_ObjectiveC,
161 (int) objcKeywordTable[i].id);
165 /*//////////////////////////////////////////////////////////////////////
166 //// Lexing */
167 static boolean isNum (char c)
169 return c >= '0' && c <= '9';
172 static boolean isLowerAlpha (char c)
174 return c >= 'a' && c <= 'z';
177 static boolean isUpperAlpha (char c)
179 return c >= 'A' && c <= 'Z';
182 static boolean isAlpha (char c)
184 return isLowerAlpha (c) || isUpperAlpha (c);
187 static boolean isIdent (char c)
189 return isNum (c) || isAlpha (c) || c == '_';
192 static boolean isSpace (char c)
194 return c == ' ' || c == '\t';
197 /* return true if it end with an end of line */
198 static void eatWhiteSpace (lexingState * st)
200 const unsigned char *cp = st->cp;
201 while (isSpace (*cp))
202 cp++;
204 st->cp = cp;
207 static void eatString (lexingState * st)
209 boolean lastIsBackSlash = FALSE;
210 boolean unfinished = TRUE;
211 const unsigned char *c = st->cp + 1;
213 while (unfinished)
215 /* end of line should never happen.
216 * we tolerate it */
217 if (c == NULL || c[0] == '\0')
218 break;
219 else if (*c == '"' && !lastIsBackSlash)
220 unfinished = FALSE;
221 else
222 lastIsBackSlash = *c == '\\';
224 c++;
227 st->cp = c;
230 static void eatComment (lexingState * st)
232 boolean unfinished = TRUE;
233 boolean lastIsStar = FALSE;
234 const unsigned char *c = st->cp + 2;
236 while (unfinished)
238 /* we've reached the end of the line..
239 * so we have to reload a line... */
240 if (c == NULL || *c == '\0')
242 st->cp = fileReadLine ();
243 /* WOOPS... no more input...
244 * we return, next lexing read
245 * will be null and ok */
246 if (st->cp == NULL)
247 return;
248 c = st->cp;
250 /* we've reached the end of the comment */
251 else if (*c == '/' && lastIsStar)
252 unfinished = FALSE;
253 else
255 lastIsStar = '*' == *c;
256 c++;
260 st->cp = c;
263 static void readIdentifier (lexingState * st)
265 const unsigned char *p;
266 vStringClear (st->name);
268 /* first char is a simple letter */
269 if (isAlpha (*st->cp) || *st->cp == '_')
270 vStringPut (st->name, (int) *st->cp);
272 /* Go till you get identifier chars */
273 for (p = st->cp + 1; isIdent (*p); p++)
274 vStringPut (st->name, (int) *p);
276 st->cp = p;
278 vStringTerminate (st->name);
281 /* read the @something directives */
282 static void readIdentifierObjcDirective (lexingState * st)
284 const unsigned char *p;
285 vStringClear (st->name);
287 /* first char is a simple letter */
288 if (*st->cp == '@')
289 vStringPut (st->name, (int) *st->cp);
291 /* Go till you get identifier chars */
292 for (p = st->cp + 1; isIdent (*p); p++)
293 vStringPut (st->name, (int) *p);
295 st->cp = p;
297 vStringTerminate (st->name);
300 /* The lexer is in charge of reading the file.
301 * Some of sub-lexer (like eatComment) also read file.
302 * lexing is finished when the lexer return Tok_EOF */
303 static objcKeyword lex (lexingState * st)
305 int retType;
307 /* handling data input here */
308 while (st->cp == NULL || st->cp[0] == '\0')
310 st->cp = fileReadLine ();
311 if (st->cp == NULL)
312 return Tok_EOF;
314 return Tok_EOL;
317 if (isAlpha (*st->cp))
319 readIdentifier (st);
320 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
322 if (retType == -1) /* If it's not a keyword */
324 return ObjcIDENTIFIER;
326 else
328 return retType;
331 else if (*st->cp == '@')
333 readIdentifierObjcDirective (st);
334 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
336 if (retType == -1) /* If it's not a keyword */
338 return Tok_any;
340 else
342 return retType;
345 else if (isSpace (*st->cp))
347 eatWhiteSpace (st);
348 return lex (st);
350 else
351 switch (*st->cp)
353 case '(':
354 st->cp++;
355 return Tok_PARL;
357 case '\\':
358 st->cp++;
359 return Tok_Backslash;
361 case '#':
362 st->cp++;
363 return Tok_Sharp;
365 case '/':
366 if (st->cp[1] == '*') /* ergl, a comment */
368 eatComment (st);
369 return lex (st);
371 else if (st->cp[1] == '/')
373 st->cp = NULL;
374 return lex (st);
376 else
378 st->cp++;
379 return Tok_any;
381 break;
383 case ')':
384 st->cp++;
385 return Tok_PARR;
386 case '{':
387 st->cp++;
388 return Tok_CurlL;
389 case '}':
390 st->cp++;
391 return Tok_CurlR;
392 case '[':
393 st->cp++;
394 return Tok_SQUAREL;
395 case ']':
396 st->cp++;
397 return Tok_SQUARER;
398 case ',':
399 st->cp++;
400 return Tok_COMA;
401 case ';':
402 st->cp++;
403 return Tok_semi;
404 case ':':
405 st->cp++;
406 return Tok_dpoint;
407 case '"':
408 eatString (st);
409 return Tok_any;
410 case '+':
411 st->cp++;
412 return Tok_PLUS;
413 case '-':
414 st->cp++;
415 return Tok_MINUS;
417 default:
418 st->cp++;
419 break;
422 /* default return if nothing is recognized,
423 * shouldn't happen, but at least, it will
424 * be handled without destroying the parsing. */
425 return Tok_any;
428 /*//////////////////////////////////////////////////////////////////////
429 //// Parsing */
430 typedef void (*parseNext) (vString * const ident, objcToken what);
432 /********** Helpers */
433 /* This variable hold the 'parser' which is going to
434 * handle the next token */
435 static parseNext toDoNext;
437 /* Special variable used by parser eater to
438 * determine which action to put after their
439 * job is finished. */
440 static parseNext comeAfter;
442 /* Used by some parsers detecting certain token
443 * to revert to previous parser. */
444 static parseNext fallback;
447 /********** Grammar */
448 static void globalScope (vString * const ident, objcToken what);
449 static void parseMethods (vString * const ident, objcToken what);
450 static void parseImplemMethods (vString * const ident, objcToken what);
451 static vString *tempName = NULL;
452 static vString *parentName = NULL;
453 static objcKind parentType = K_INTERFACE;
455 /* used to prepare tag for OCaml, just in case their is a need to
456 * add additional information to the tag. */
457 static void prepareTag (tagEntryInfo * tag, vString const *name, objcKind kind)
459 initTagEntry (tag, vStringValue (name));
460 tag->kindName = ObjcKinds[kind].name;
461 tag->kind = ObjcKinds[kind].letter;
463 if (parentName != NULL)
465 tag->extensionFields.scope[0] = ObjcKinds[parentType].name;
466 tag->extensionFields.scope[1] = vStringValue (parentName);
470 static void pushEnclosingContext (const vString * parent, objcKind type)
472 vStringCopy (parentName, parent);
473 parentType = type;
476 static void popEnclosingContext (void)
478 vStringClear (parentName);
481 /* Used to centralise tag creation, and be able to add
482 * more information to it in the future */
483 static void addTag (vString * const ident, int kind)
485 tagEntryInfo toCreate;
487 if (! ObjcKinds[kind].enabled)
488 return;
490 prepareTag (&toCreate, ident, kind);
491 makeTagEntry (&toCreate);
494 static objcToken waitedToken, fallBackToken;
496 /* Ignore everything till waitedToken and jump to comeAfter.
497 * If the "end" keyword is encountered break, doesn't remember
498 * why though. */
499 static void tillToken (vString * const UNUSED (ident), objcToken what)
501 if (what == waitedToken)
502 toDoNext = comeAfter;
505 static void tillTokenOrFallBack (vString * const UNUSED (ident), objcToken what)
507 if (what == waitedToken)
508 toDoNext = comeAfter;
509 else if (what == fallBackToken)
511 toDoNext = fallback;
515 static int ignoreBalanced_count = 0;
516 static void ignoreBalanced (vString * const UNUSED (ident), objcToken what)
519 switch (what)
521 case Tok_PARL:
522 case Tok_CurlL:
523 case Tok_SQUAREL:
524 ignoreBalanced_count++;
525 break;
527 case Tok_PARR:
528 case Tok_CurlR:
529 case Tok_SQUARER:
530 ignoreBalanced_count--;
531 break;
533 default:
534 /* don't care */
535 break;
538 if (ignoreBalanced_count == 0)
539 toDoNext = comeAfter;
542 static void parseFields (vString * const ident, objcToken what)
544 switch (what)
546 case Tok_CurlR:
547 toDoNext = &parseMethods;
548 break;
550 case Tok_SQUAREL:
551 case Tok_PARL:
552 toDoNext = &ignoreBalanced;
553 comeAfter = &parseFields;
554 break;
556 /* we got an identifier, keep track of it */
557 case ObjcIDENTIFIER:
558 vStringCopy (tempName, ident);
559 break;
561 /* our last kept identifier must be our variable name =) */
562 case Tok_semi:
563 addTag (tempName, K_FIELD);
564 vStringClear (tempName);
565 break;
567 default:
568 /* NOTHING */
569 break;
573 static objcKind methodKind;
576 static vString *fullMethodName;
577 static vString *prevIdent;
579 static void parseMethodsName (vString * const ident, objcToken what)
581 switch (what)
583 case Tok_PARL:
584 toDoNext = &tillToken;
585 comeAfter = &parseMethodsName;
586 waitedToken = Tok_PARR;
587 break;
589 case Tok_dpoint:
590 vStringCat (fullMethodName, prevIdent);
591 vStringCatS (fullMethodName, ":");
592 vStringClear (prevIdent);
593 break;
595 case ObjcIDENTIFIER:
596 vStringCopy (prevIdent, ident);
597 break;
599 case Tok_CurlL:
600 case Tok_semi:
601 /* method name is not simple */
602 if (vStringLength (fullMethodName) != '\0')
604 addTag (fullMethodName, methodKind);
605 vStringClear (fullMethodName);
607 else
608 addTag (prevIdent, methodKind);
610 toDoNext = &parseMethods;
611 parseImplemMethods (ident, what);
612 vStringClear (prevIdent);
613 break;
615 default:
616 break;
620 static void parseMethodsImplemName (vString * const ident, objcToken what)
622 switch (what)
624 case Tok_PARL:
625 toDoNext = &tillToken;
626 comeAfter = &parseMethodsImplemName;
627 waitedToken = Tok_PARR;
628 break;
630 case Tok_dpoint:
631 vStringCat (fullMethodName, prevIdent);
632 vStringCatS (fullMethodName, ":");
633 vStringClear (prevIdent);
634 break;
636 case ObjcIDENTIFIER:
637 vStringCopy (prevIdent, ident);
638 break;
640 case Tok_CurlL:
641 case Tok_semi:
642 /* method name is not simple */
643 if (vStringLength (fullMethodName) != '\0')
645 addTag (fullMethodName, methodKind);
646 vStringClear (fullMethodName);
648 else
649 addTag (prevIdent, methodKind);
651 toDoNext = &parseImplemMethods;
652 parseImplemMethods (ident, what);
653 vStringClear (prevIdent);
654 break;
656 default:
657 break;
661 static void parseImplemMethods (vString * const ident, objcToken what)
663 switch (what)
665 case Tok_PLUS: /* + */
666 toDoNext = &parseMethodsImplemName;
667 methodKind = K_CLASSMETHOD;
668 break;
670 case Tok_MINUS: /* - */
671 toDoNext = &parseMethodsImplemName;
672 methodKind = K_METHOD;
673 break;
675 case ObjcEND: /* @end */
676 popEnclosingContext ();
677 toDoNext = &globalScope;
678 break;
680 case Tok_CurlL: /* { */
681 toDoNext = &ignoreBalanced;
682 ignoreBalanced (ident, what);
683 comeAfter = &parseImplemMethods;
684 break;
686 default:
687 break;
691 static void parseProperty (vString * const ident, objcToken what)
693 switch (what)
695 case Tok_PARL:
696 toDoNext = &tillToken;
697 comeAfter = &parseProperty;
698 waitedToken = Tok_PARR;
699 break;
701 /* we got an identifier, keep track of it */
702 case ObjcIDENTIFIER:
703 vStringCopy (tempName, ident);
704 break;
706 /* our last kept identifier must be our variable name =) */
707 case Tok_semi:
708 addTag (tempName, K_PROPERTY);
709 vStringClear (tempName);
710 toDoNext = &parseMethods;
711 break;
713 default:
714 break;
718 static void parseMethods (vString * const UNUSED (ident), objcToken what)
720 switch (what)
722 case Tok_PLUS: /* + */
723 toDoNext = &parseMethodsName;
724 methodKind = K_CLASSMETHOD;
725 break;
727 case Tok_MINUS: /* - */
728 toDoNext = &parseMethodsName;
729 methodKind = K_METHOD;
730 break;
732 case ObjcPROPERTY:
733 toDoNext = &parseProperty;
734 break;
736 case ObjcEND: /* @end */
737 popEnclosingContext ();
738 toDoNext = &globalScope;
739 break;
741 case Tok_CurlL: /* { */
742 toDoNext = &parseFields;
743 break;
745 default:
746 break;
751 static void parseProtocol (vString * const ident, objcToken what)
753 if (what == ObjcIDENTIFIER)
755 pushEnclosingContext (ident, K_PROTOCOL);
756 addTag (ident, K_PROTOCOL);
758 toDoNext = &parseMethods;
761 static void parseImplementation (vString * const ident, objcToken what)
763 if (what == ObjcIDENTIFIER)
765 addTag (ident, K_IMPLEMENTATION);
766 pushEnclosingContext (ident, K_IMPLEMENTATION);
768 toDoNext = &parseImplemMethods;
771 static void parseInterface (vString * const ident, objcToken what)
773 if (what == ObjcIDENTIFIER)
775 addTag (ident, K_INTERFACE);
776 pushEnclosingContext (ident, K_INTERFACE);
779 toDoNext = &parseMethods;
782 static void parseStructMembers (vString * const ident, objcToken what)
784 static parseNext prev = NULL;
786 if (prev != NULL)
788 comeAfter = prev;
789 prev = NULL;
792 switch (what)
794 case ObjcIDENTIFIER:
795 vStringCopy (tempName, ident);
796 break;
798 case Tok_semi: /* ';' */
799 addTag (tempName, K_FIELD);
800 vStringClear (tempName);
801 break;
803 /* some types are complex, the only one
804 * we will loose is the function type.
806 case Tok_CurlL: /* '{' */
807 case Tok_PARL: /* '(' */
808 case Tok_SQUAREL: /* '[' */
809 toDoNext = &ignoreBalanced;
810 prev = comeAfter;
811 comeAfter = &parseStructMembers;
812 ignoreBalanced (ident, what);
813 break;
815 case Tok_CurlR:
816 toDoNext = comeAfter;
817 break;
819 default:
820 /* don't care */
821 break;
825 /* Called just after the struct keyword */
826 static boolean parseStruct_gotName = FALSE;
827 static void parseStruct (vString * const ident, objcToken what)
829 switch (what)
831 case ObjcIDENTIFIER:
832 if (!parseStruct_gotName)
834 addTag (ident, K_STRUCT);
835 pushEnclosingContext (ident, K_STRUCT);
836 parseStruct_gotName = TRUE;
838 else
840 parseStruct_gotName = FALSE;
841 popEnclosingContext ();
842 toDoNext = comeAfter;
843 comeAfter (ident, what);
845 break;
847 case Tok_CurlL:
848 toDoNext = &parseStructMembers;
849 break;
851 /* maybe it was just a forward declaration
852 * in which case, we pop the context */
853 case Tok_semi:
854 if (parseStruct_gotName)
855 popEnclosingContext ();
857 toDoNext = comeAfter;
858 comeAfter (ident, what);
859 break;
861 default:
862 /* we don't care */
863 break;
867 /* Parse enumeration members, ignoring potential initialization */
868 static parseNext parseEnumFields_prev = NULL;
869 static void parseEnumFields (vString * const ident, objcToken what)
871 if (parseEnumFields_prev != NULL)
873 comeAfter = parseEnumFields_prev;
874 parseEnumFields_prev = NULL;
877 switch (what)
879 case ObjcIDENTIFIER:
880 addTag (ident, K_ENUM);
881 parseEnumFields_prev = comeAfter;
882 waitedToken = Tok_COMA;
883 /* last item might not have a coma */
884 fallBackToken = Tok_CurlR;
885 fallback = comeAfter;
886 comeAfter = parseEnumFields;
887 toDoNext = &tillTokenOrFallBack;
888 break;
890 case Tok_CurlR:
891 toDoNext = comeAfter;
892 popEnclosingContext ();
893 break;
895 default:
896 /* don't care */
897 break;
901 /* parse enum ... { ... */
902 static boolean parseEnum_named = FALSE;
903 static void parseEnum (vString * const ident, objcToken what)
905 switch (what)
907 case ObjcIDENTIFIER:
908 if (!parseEnum_named)
910 addTag (ident, K_ENUM);
911 pushEnclosingContext (ident, K_ENUM);
912 parseEnum_named = TRUE;
914 else
916 parseEnum_named = FALSE;
917 popEnclosingContext ();
918 toDoNext = comeAfter;
919 comeAfter (ident, what);
921 break;
923 case Tok_CurlL: /* '{' */
924 toDoNext = &parseEnumFields;
925 parseEnum_named = FALSE;
926 break;
928 case Tok_semi: /* ';' */
929 if (parseEnum_named)
930 popEnclosingContext ();
931 toDoNext = comeAfter;
932 comeAfter (ident, what);
933 break;
935 default:
936 /* don't care */
937 break;
941 /* Parse something like
942 * typedef .... ident ;
943 * ignoring the defined type but in the case of struct,
944 * in which case struct are parsed.
946 static void parseTypedef (vString * const ident, objcToken what)
948 switch (what)
950 case ObjcSTRUCT:
951 toDoNext = &parseStruct;
952 comeAfter = &parseTypedef;
953 break;
955 case ObjcENUM:
956 toDoNext = &parseEnum;
957 comeAfter = &parseTypedef;
958 break;
960 case ObjcIDENTIFIER:
961 vStringCopy (tempName, ident);
962 break;
964 case Tok_semi: /* ';' */
965 addTag (tempName, K_TYPEDEF);
966 vStringClear (tempName);
967 toDoNext = &globalScope;
968 break;
970 default:
971 /* we don't care */
972 break;
976 static boolean ignorePreprocStuff_escaped = FALSE;
977 static void ignorePreprocStuff (vString * const UNUSED (ident), objcToken what)
979 switch (what)
981 case Tok_Backslash:
982 ignorePreprocStuff_escaped = TRUE;
983 break;
985 case Tok_EOL:
986 if (ignorePreprocStuff_escaped)
988 ignorePreprocStuff_escaped = FALSE;
990 else
992 toDoNext = &globalScope;
994 break;
996 default:
997 ignorePreprocStuff_escaped = FALSE;
998 break;
1002 static void parseMacroName (vString * const ident, objcToken what)
1004 if (what == ObjcIDENTIFIER)
1005 addTag (ident, K_MACRO);
1007 toDoNext = &ignorePreprocStuff;
1010 static void parsePreproc (vString * const ident, objcToken what)
1012 switch (what)
1014 case ObjcIDENTIFIER:
1015 if (strcmp (vStringValue (ident), "define") == 0)
1016 toDoNext = &parseMacroName;
1017 else
1018 toDoNext = &ignorePreprocStuff;
1019 break;
1021 default:
1022 toDoNext = &ignorePreprocStuff;
1023 break;
1027 /* Handle the "strong" top levels, all 'big' declarations
1028 * happen here */
1029 static void globalScope (vString * const ident, objcToken what)
1031 switch (what)
1033 case Tok_Sharp:
1034 toDoNext = &parsePreproc;
1035 break;
1037 case ObjcSTRUCT:
1038 toDoNext = &parseStruct;
1039 comeAfter = &globalScope;
1040 break;
1042 case ObjcIDENTIFIER:
1043 /* we keep track of the identifier if we
1044 * come across a function. */
1045 vStringCopy (tempName, ident);
1046 break;
1048 case Tok_PARL:
1049 /* if we find an opening parenthesis it means we
1050 * found a function (or a macro...) */
1051 addTag (tempName, K_FUNCTION);
1052 vStringClear (tempName);
1053 comeAfter = &globalScope;
1054 toDoNext = &ignoreBalanced;
1055 ignoreBalanced (ident, what);
1056 break;
1058 case ObjcINTERFACE:
1059 toDoNext = &parseInterface;
1060 break;
1062 case ObjcIMPLEMENTATION:
1063 toDoNext = &parseImplementation;
1064 break;
1066 case ObjcPROTOCOL:
1067 toDoNext = &parseProtocol;
1068 break;
1070 case ObjcTYPEDEF:
1071 toDoNext = parseTypedef;
1072 comeAfter = &globalScope;
1073 break;
1075 case Tok_CurlL:
1076 comeAfter = &globalScope;
1077 toDoNext = &ignoreBalanced;
1078 ignoreBalanced (ident, what);
1079 break;
1081 case ObjcEND:
1082 case ObjcPUBLIC:
1083 case ObjcPROTECTED:
1084 case ObjcPRIVATE:
1086 default:
1087 /* we don't care */
1088 break;
1092 /*////////////////////////////////////////////////////////////////
1093 //// Deal with the system */
1095 static void findObjcTags (void)
1097 vString *name = vStringNew ();
1098 lexingState st;
1099 objcToken tok;
1101 parentName = vStringNew ();
1102 tempName = vStringNew ();
1103 fullMethodName = vStringNew ();
1104 prevIdent = vStringNew ();
1106 /* (Re-)initialize state variables, this might be a second file */
1107 comeAfter = NULL;
1108 fallback = NULL;
1109 parentType = K_INTERFACE;
1110 ignoreBalanced_count = 0;
1111 methodKind = 0;
1112 parseStruct_gotName = FALSE;
1113 parseEnumFields_prev = NULL;
1114 parseEnum_named = FALSE;
1115 ignorePreprocStuff_escaped = FALSE;
1117 st.name = vStringNew ();
1118 st.cp = fileReadLine ();
1119 toDoNext = &globalScope;
1120 tok = lex (&st);
1121 while (tok != Tok_EOF)
1123 (*toDoNext) (st.name, tok);
1124 tok = lex (&st);
1126 vStringDelete(st.name);
1128 vStringDelete (name);
1129 vStringDelete (parentName);
1130 vStringDelete (tempName);
1131 vStringDelete (fullMethodName);
1132 vStringDelete (prevIdent);
1133 parentName = NULL;
1134 tempName = NULL;
1135 prevIdent = NULL;
1136 fullMethodName = NULL;
1139 static void objcInitialize (const langType language)
1141 Lang_ObjectiveC = language;
1143 initKeywordHash ();
1146 extern parserDefinition *ObjcParser (void)
1148 static const char *const extensions[] = { "m", "h", NULL };
1149 parserDefinition *def = parserNew ("ObjectiveC");
1150 def->kinds = ObjcKinds;
1151 def->kindCount = KIND_COUNT (ObjcKinds);
1152 def->extensions = extensions;
1153 def->parser = findObjcTags;
1154 def->initialize = objcInitialize;
1156 return def;