Use ARRAY_SIZE() in parsers
[geany-mirror.git] / ctags / parsers / objc.c
blob7d409d8b9afdd3918aa848cbb40239ebee72dc7b
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 static const keywordTable objcKeywordTable[] = {
115 {"typedef", ObjcTYPEDEF},
116 {"struct", ObjcSTRUCT},
117 {"enum", ObjcENUM},
118 {"@implementation", ObjcIMPLEMENTATION},
119 {"@interface", ObjcINTERFACE},
120 {"@protocol", ObjcPROTOCOL},
121 {"@encode", ObjcENCODE},
122 {"@property", ObjcPROPERTY},
123 {"@synchronized", ObjcSYNCHRONIZED},
124 {"@selector", ObjcSELECTOR},
125 {"@end", ObjcEND},
126 {"@defs", ObjcDEFS},
127 {"@class", ObjcCLASS},
128 {"@private", ObjcPRIVATE},
129 {"@package", ObjcPACKAGE},
130 {"@public", ObjcPUBLIC},
131 {"@protected", ObjcPROTECTED},
132 {"@synthesize", ObjcSYNTHESIZE},
133 {"@dynamic", ObjcDYNAMIC},
134 {"@optional", ObjcOPTIONAL},
135 {"@required", ObjcREQUIRED},
138 static langType Lang_ObjectiveC;
140 /*//////////////////////////////////////////////////////////////////
141 //// lexingInit */
142 typedef struct _lexingState {
143 vString *name; /* current parsed identifier/operator */
144 const unsigned char *cp; /* position in stream */
145 } lexingState;
147 /*//////////////////////////////////////////////////////////////////////
148 //// Lexing */
149 static boolean isNum (char c)
151 return c >= '0' && c <= '9';
154 static boolean isLowerAlpha (char c)
156 return c >= 'a' && c <= 'z';
159 static boolean isUpperAlpha (char c)
161 return c >= 'A' && c <= 'Z';
164 static boolean isAlpha (char c)
166 return isLowerAlpha (c) || isUpperAlpha (c);
169 static boolean isIdent (char c)
171 return isNum (c) || isAlpha (c) || c == '_';
174 static boolean isSpace (char c)
176 return c == ' ' || c == '\t';
179 /* return true if it end with an end of line */
180 static void eatWhiteSpace (lexingState * st)
182 const unsigned char *cp = st->cp;
183 while (isSpace (*cp))
184 cp++;
186 st->cp = cp;
189 static void eatString (lexingState * st)
191 boolean lastIsBackSlash = FALSE;
192 boolean unfinished = TRUE;
193 const unsigned char *c = st->cp + 1;
195 while (unfinished)
197 /* end of line should never happen.
198 * we tolerate it */
199 if (c == NULL || c[0] == '\0')
200 break;
201 else if (*c == '"' && !lastIsBackSlash)
202 unfinished = FALSE;
203 else
204 lastIsBackSlash = *c == '\\';
206 c++;
209 st->cp = c;
212 static void eatComment (lexingState * st)
214 boolean unfinished = TRUE;
215 boolean lastIsStar = FALSE;
216 const unsigned char *c = st->cp + 2;
218 while (unfinished)
220 /* we've reached the end of the line..
221 * so we have to reload a line... */
222 if (c == NULL || *c == '\0')
224 st->cp = readLineFromInputFile ();
225 /* WOOPS... no more input...
226 * we return, next lexing read
227 * will be null and ok */
228 if (st->cp == NULL)
229 return;
230 c = st->cp;
232 /* we've reached the end of the comment */
233 else if (*c == '/' && lastIsStar)
234 unfinished = FALSE;
235 else
237 lastIsStar = '*' == *c;
238 c++;
242 st->cp = c;
245 static void readIdentifier (lexingState * st)
247 const unsigned char *p;
248 vStringClear (st->name);
250 /* first char is a simple letter */
251 if (isAlpha (*st->cp) || *st->cp == '_')
252 vStringPut (st->name, (int) *st->cp);
254 /* Go till you get identifier chars */
255 for (p = st->cp + 1; isIdent (*p); p++)
256 vStringPut (st->name, (int) *p);
258 st->cp = p;
260 vStringTerminate (st->name);
263 /* read the @something directives */
264 static void readIdentifierObjcDirective (lexingState * st)
266 const unsigned char *p;
267 vStringClear (st->name);
269 /* first char is a simple letter */
270 if (*st->cp == '@')
271 vStringPut (st->name, (int) *st->cp);
273 /* Go till you get identifier chars */
274 for (p = st->cp + 1; isIdent (*p); p++)
275 vStringPut (st->name, (int) *p);
277 st->cp = p;
279 vStringTerminate (st->name);
282 /* The lexer is in charge of reading the file.
283 * Some of sub-lexer (like eatComment) also read file.
284 * lexing is finished when the lexer return Tok_EOF */
285 static objcKeyword lex (lexingState * st)
287 int retType;
289 /* handling data input here */
290 while (st->cp == NULL || st->cp[0] == '\0')
292 st->cp = readLineFromInputFile ();
293 if (st->cp == NULL)
294 return Tok_EOF;
296 return Tok_EOL;
299 if (isAlpha (*st->cp))
301 readIdentifier (st);
302 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
304 if (retType == -1) /* If it's not a keyword */
306 return ObjcIDENTIFIER;
308 else
310 return retType;
313 else if (*st->cp == '@')
315 readIdentifierObjcDirective (st);
316 retType = lookupKeyword (vStringValue (st->name), Lang_ObjectiveC);
318 if (retType == -1) /* If it's not a keyword */
320 return Tok_any;
322 else
324 return retType;
327 else if (isSpace (*st->cp))
329 eatWhiteSpace (st);
330 return lex (st);
332 else
333 switch (*st->cp)
335 case '(':
336 st->cp++;
337 return Tok_PARL;
339 case '\\':
340 st->cp++;
341 return Tok_Backslash;
343 case '#':
344 st->cp++;
345 return Tok_Sharp;
347 case '/':
348 if (st->cp[1] == '*') /* ergl, a comment */
350 eatComment (st);
351 return lex (st);
353 else if (st->cp[1] == '/')
355 st->cp = NULL;
356 return lex (st);
358 else
360 st->cp++;
361 return Tok_any;
363 break;
365 case ')':
366 st->cp++;
367 return Tok_PARR;
368 case '{':
369 st->cp++;
370 return Tok_CurlL;
371 case '}':
372 st->cp++;
373 return Tok_CurlR;
374 case '[':
375 st->cp++;
376 return Tok_SQUAREL;
377 case ']':
378 st->cp++;
379 return Tok_SQUARER;
380 case ',':
381 st->cp++;
382 return Tok_COMA;
383 case ';':
384 st->cp++;
385 return Tok_semi;
386 case ':':
387 st->cp++;
388 return Tok_dpoint;
389 case '"':
390 eatString (st);
391 return Tok_any;
392 case '+':
393 st->cp++;
394 return Tok_PLUS;
395 case '-':
396 st->cp++;
397 return Tok_MINUS;
399 default:
400 st->cp++;
401 break;
404 /* default return if nothing is recognized,
405 * shouldn't happen, but at least, it will
406 * be handled without destroying the parsing. */
407 return Tok_any;
410 /*//////////////////////////////////////////////////////////////////////
411 //// Parsing */
412 typedef void (*parseNext) (vString * const ident, objcToken what);
414 /********** Helpers */
415 /* This variable hold the 'parser' which is going to
416 * handle the next token */
417 static parseNext toDoNext;
419 /* Special variable used by parser eater to
420 * determine which action to put after their
421 * job is finished. */
422 static parseNext comeAfter;
424 /* Used by some parsers detecting certain token
425 * to revert to previous parser. */
426 static parseNext fallback;
429 /********** Grammar */
430 static void globalScope (vString * const ident, objcToken what);
431 static void parseMethods (vString * const ident, objcToken what);
432 static void parseImplemMethods (vString * const ident, objcToken what);
433 static vString *tempName = NULL;
434 static vString *parentName = NULL;
435 static objcKind parentType = K_INTERFACE;
437 /* used to prepare tag for OCaml, just in case their is a need to
438 * add additional information to the tag. */
439 static void prepareTag (tagEntryInfo * tag, vString const *name, objcKind kind)
441 initTagEntry (tag, vStringValue (name), &(ObjcKinds[kind]));
443 if (parentName != NULL)
445 tag->extensionFields.scopeKind = &(ObjcKinds[parentType]);
446 tag->extensionFields.scopeName = vStringValue (parentName);
450 static void pushEnclosingContext (const vString * parent, objcKind type)
452 vStringCopy (parentName, parent);
453 parentType = type;
456 static void popEnclosingContext (void)
458 vStringClear (parentName);
461 /* Used to centralise tag creation, and be able to add
462 * more information to it in the future */
463 static void addTag (vString * const ident, int kind)
465 tagEntryInfo toCreate;
467 if (! ObjcKinds[kind].enabled)
468 return;
470 prepareTag (&toCreate, ident, kind);
471 makeTagEntry (&toCreate);
474 static objcToken waitedToken, fallBackToken;
476 /* Ignore everything till waitedToken and jump to comeAfter.
477 * If the "end" keyword is encountered break, doesn't remember
478 * why though. */
479 static void tillToken (vString * const UNUSED (ident), objcToken what)
481 if (what == waitedToken)
482 toDoNext = comeAfter;
485 static void tillTokenOrFallBack (vString * const UNUSED (ident), objcToken what)
487 if (what == waitedToken)
488 toDoNext = comeAfter;
489 else if (what == fallBackToken)
491 toDoNext = fallback;
495 static int ignoreBalanced_count = 0;
496 static void ignoreBalanced (vString * const UNUSED (ident), objcToken what)
499 switch (what)
501 case Tok_PARL:
502 case Tok_CurlL:
503 case Tok_SQUAREL:
504 ignoreBalanced_count++;
505 break;
507 case Tok_PARR:
508 case Tok_CurlR:
509 case Tok_SQUARER:
510 ignoreBalanced_count--;
511 break;
513 default:
514 /* don't care */
515 break;
518 if (ignoreBalanced_count == 0)
519 toDoNext = comeAfter;
522 static void parseFields (vString * const ident, objcToken what)
524 switch (what)
526 case Tok_CurlR:
527 toDoNext = &parseMethods;
528 break;
530 case Tok_SQUAREL:
531 case Tok_PARL:
532 toDoNext = &ignoreBalanced;
533 comeAfter = &parseFields;
534 break;
536 /* we got an identifier, keep track of it */
537 case ObjcIDENTIFIER:
538 vStringCopy (tempName, ident);
539 break;
541 /* our last kept identifier must be our variable name =) */
542 case Tok_semi:
543 addTag (tempName, K_FIELD);
544 vStringClear (tempName);
545 break;
547 default:
548 /* NOTHING */
549 break;
553 static objcKind methodKind;
556 static vString *fullMethodName;
557 static vString *prevIdent;
559 static void parseMethodsName (vString * const ident, objcToken what)
561 switch (what)
563 case Tok_PARL:
564 toDoNext = &tillToken;
565 comeAfter = &parseMethodsName;
566 waitedToken = Tok_PARR;
567 break;
569 case Tok_dpoint:
570 vStringCat (fullMethodName, prevIdent);
571 vStringCatS (fullMethodName, ":");
572 vStringClear (prevIdent);
573 break;
575 case ObjcIDENTIFIER:
576 vStringCopy (prevIdent, ident);
577 break;
579 case Tok_CurlL:
580 case Tok_semi:
581 /* method name is not simple */
582 if (vStringLength (fullMethodName) != '\0')
584 addTag (fullMethodName, methodKind);
585 vStringClear (fullMethodName);
587 else
588 addTag (prevIdent, methodKind);
590 toDoNext = &parseMethods;
591 parseImplemMethods (ident, what);
592 vStringClear (prevIdent);
593 break;
595 default:
596 break;
600 static void parseMethodsImplemName (vString * const ident, objcToken what)
602 switch (what)
604 case Tok_PARL:
605 toDoNext = &tillToken;
606 comeAfter = &parseMethodsImplemName;
607 waitedToken = Tok_PARR;
608 break;
610 case Tok_dpoint:
611 vStringCat (fullMethodName, prevIdent);
612 vStringCatS (fullMethodName, ":");
613 vStringClear (prevIdent);
614 break;
616 case ObjcIDENTIFIER:
617 vStringCopy (prevIdent, ident);
618 break;
620 case Tok_CurlL:
621 case Tok_semi:
622 /* method name is not simple */
623 if (vStringLength (fullMethodName) != '\0')
625 addTag (fullMethodName, methodKind);
626 vStringClear (fullMethodName);
628 else
629 addTag (prevIdent, methodKind);
631 toDoNext = &parseImplemMethods;
632 parseImplemMethods (ident, what);
633 vStringClear (prevIdent);
634 break;
636 default:
637 break;
641 static void parseImplemMethods (vString * const ident, objcToken what)
643 switch (what)
645 case Tok_PLUS: /* + */
646 toDoNext = &parseMethodsImplemName;
647 methodKind = K_CLASSMETHOD;
648 break;
650 case Tok_MINUS: /* - */
651 toDoNext = &parseMethodsImplemName;
652 methodKind = K_METHOD;
653 break;
655 case ObjcEND: /* @end */
656 popEnclosingContext ();
657 toDoNext = &globalScope;
658 break;
660 case Tok_CurlL: /* { */
661 toDoNext = &ignoreBalanced;
662 ignoreBalanced (ident, what);
663 comeAfter = &parseImplemMethods;
664 break;
666 default:
667 break;
671 static void parseProperty (vString * const ident, objcToken what)
673 switch (what)
675 case Tok_PARL:
676 toDoNext = &tillToken;
677 comeAfter = &parseProperty;
678 waitedToken = Tok_PARR;
679 break;
681 /* we got an identifier, keep track of it */
682 case ObjcIDENTIFIER:
683 vStringCopy (tempName, ident);
684 break;
686 /* our last kept identifier must be our variable name =) */
687 case Tok_semi:
688 addTag (tempName, K_PROPERTY);
689 vStringClear (tempName);
690 toDoNext = &parseMethods;
691 break;
693 default:
694 break;
698 static void parseMethods (vString * const UNUSED (ident), objcToken what)
700 switch (what)
702 case Tok_PLUS: /* + */
703 toDoNext = &parseMethodsName;
704 methodKind = K_CLASSMETHOD;
705 break;
707 case Tok_MINUS: /* - */
708 toDoNext = &parseMethodsName;
709 methodKind = K_METHOD;
710 break;
712 case ObjcPROPERTY:
713 toDoNext = &parseProperty;
714 break;
716 case ObjcEND: /* @end */
717 popEnclosingContext ();
718 toDoNext = &globalScope;
719 break;
721 case Tok_CurlL: /* { */
722 toDoNext = &parseFields;
723 break;
725 default:
726 break;
731 static void parseProtocol (vString * const ident, objcToken what)
733 if (what == ObjcIDENTIFIER)
735 pushEnclosingContext (ident, K_PROTOCOL);
736 addTag (ident, K_PROTOCOL);
738 toDoNext = &parseMethods;
741 static void parseImplementation (vString * const ident, objcToken what)
743 if (what == ObjcIDENTIFIER)
745 addTag (ident, K_IMPLEMENTATION);
746 pushEnclosingContext (ident, K_IMPLEMENTATION);
748 toDoNext = &parseImplemMethods;
751 static void parseInterface (vString * const ident, objcToken what)
753 if (what == ObjcIDENTIFIER)
755 addTag (ident, K_INTERFACE);
756 pushEnclosingContext (ident, K_INTERFACE);
759 toDoNext = &parseMethods;
762 static void parseStructMembers (vString * const ident, objcToken what)
764 static parseNext prev = NULL;
766 if (prev != NULL)
768 comeAfter = prev;
769 prev = NULL;
772 switch (what)
774 case ObjcIDENTIFIER:
775 vStringCopy (tempName, ident);
776 break;
778 case Tok_semi: /* ';' */
779 addTag (tempName, K_FIELD);
780 vStringClear (tempName);
781 break;
783 /* some types are complex, the only one
784 * we will loose is the function type.
786 case Tok_CurlL: /* '{' */
787 case Tok_PARL: /* '(' */
788 case Tok_SQUAREL: /* '[' */
789 toDoNext = &ignoreBalanced;
790 prev = comeAfter;
791 comeAfter = &parseStructMembers;
792 ignoreBalanced (ident, what);
793 break;
795 case Tok_CurlR:
796 toDoNext = comeAfter;
797 break;
799 default:
800 /* don't care */
801 break;
805 /* Called just after the struct keyword */
806 static boolean parseStruct_gotName = FALSE;
807 static void parseStruct (vString * const ident, objcToken what)
809 switch (what)
811 case ObjcIDENTIFIER:
812 if (!parseStruct_gotName)
814 addTag (ident, K_STRUCT);
815 pushEnclosingContext (ident, K_STRUCT);
816 parseStruct_gotName = TRUE;
818 else
820 parseStruct_gotName = FALSE;
821 popEnclosingContext ();
822 toDoNext = comeAfter;
823 comeAfter (ident, what);
825 break;
827 case Tok_CurlL:
828 toDoNext = &parseStructMembers;
829 break;
831 /* maybe it was just a forward declaration
832 * in which case, we pop the context */
833 case Tok_semi:
834 if (parseStruct_gotName)
835 popEnclosingContext ();
837 toDoNext = comeAfter;
838 comeAfter (ident, what);
839 break;
841 default:
842 /* we don't care */
843 break;
847 /* Parse enumeration members, ignoring potential initialization */
848 static parseNext parseEnumFields_prev = NULL;
849 static void parseEnumFields (vString * const ident, objcToken what)
851 if (parseEnumFields_prev != NULL)
853 comeAfter = parseEnumFields_prev;
854 parseEnumFields_prev = NULL;
857 switch (what)
859 case ObjcIDENTIFIER:
860 addTag (ident, K_ENUM);
861 parseEnumFields_prev = comeAfter;
862 waitedToken = Tok_COMA;
863 /* last item might not have a coma */
864 fallBackToken = Tok_CurlR;
865 fallback = comeAfter;
866 comeAfter = parseEnumFields;
867 toDoNext = &tillTokenOrFallBack;
868 break;
870 case Tok_CurlR:
871 toDoNext = comeAfter;
872 popEnclosingContext ();
873 break;
875 default:
876 /* don't care */
877 break;
881 /* parse enum ... { ... */
882 static boolean parseEnum_named = FALSE;
883 static void parseEnum (vString * const ident, objcToken what)
885 switch (what)
887 case ObjcIDENTIFIER:
888 if (!parseEnum_named)
890 addTag (ident, K_ENUM);
891 pushEnclosingContext (ident, K_ENUM);
892 parseEnum_named = TRUE;
894 else
896 parseEnum_named = FALSE;
897 popEnclosingContext ();
898 toDoNext = comeAfter;
899 comeAfter (ident, what);
901 break;
903 case Tok_CurlL: /* '{' */
904 toDoNext = &parseEnumFields;
905 parseEnum_named = FALSE;
906 break;
908 case Tok_semi: /* ';' */
909 if (parseEnum_named)
910 popEnclosingContext ();
911 toDoNext = comeAfter;
912 comeAfter (ident, what);
913 break;
915 default:
916 /* don't care */
917 break;
921 /* Parse something like
922 * typedef .... ident ;
923 * ignoring the defined type but in the case of struct,
924 * in which case struct are parsed.
926 static void parseTypedef (vString * const ident, objcToken what)
928 switch (what)
930 case ObjcSTRUCT:
931 toDoNext = &parseStruct;
932 comeAfter = &parseTypedef;
933 break;
935 case ObjcENUM:
936 toDoNext = &parseEnum;
937 comeAfter = &parseTypedef;
938 break;
940 case ObjcIDENTIFIER:
941 vStringCopy (tempName, ident);
942 break;
944 case Tok_semi: /* ';' */
945 addTag (tempName, K_TYPEDEF);
946 vStringClear (tempName);
947 toDoNext = &globalScope;
948 break;
950 default:
951 /* we don't care */
952 break;
956 static boolean ignorePreprocStuff_escaped = FALSE;
957 static void ignorePreprocStuff (vString * const UNUSED (ident), objcToken what)
959 switch (what)
961 case Tok_Backslash:
962 ignorePreprocStuff_escaped = TRUE;
963 break;
965 case Tok_EOL:
966 if (ignorePreprocStuff_escaped)
968 ignorePreprocStuff_escaped = FALSE;
970 else
972 toDoNext = &globalScope;
974 break;
976 default:
977 ignorePreprocStuff_escaped = FALSE;
978 break;
982 static void parseMacroName (vString * const ident, objcToken what)
984 if (what == ObjcIDENTIFIER)
985 addTag (ident, K_MACRO);
987 toDoNext = &ignorePreprocStuff;
990 static void parsePreproc (vString * const ident, objcToken what)
992 switch (what)
994 case ObjcIDENTIFIER:
995 if (strcmp (vStringValue (ident), "define") == 0)
996 toDoNext = &parseMacroName;
997 else
998 toDoNext = &ignorePreprocStuff;
999 break;
1001 default:
1002 toDoNext = &ignorePreprocStuff;
1003 break;
1007 /* Handle the "strong" top levels, all 'big' declarations
1008 * happen here */
1009 static void globalScope (vString * const ident, objcToken what)
1011 switch (what)
1013 case Tok_Sharp:
1014 toDoNext = &parsePreproc;
1015 break;
1017 case ObjcSTRUCT:
1018 toDoNext = &parseStruct;
1019 comeAfter = &globalScope;
1020 break;
1022 case ObjcIDENTIFIER:
1023 /* we keep track of the identifier if we
1024 * come across a function. */
1025 vStringCopy (tempName, ident);
1026 break;
1028 case Tok_PARL:
1029 /* if we find an opening parenthesis it means we
1030 * found a function (or a macro...) */
1031 addTag (tempName, K_FUNCTION);
1032 vStringClear (tempName);
1033 comeAfter = &globalScope;
1034 toDoNext = &ignoreBalanced;
1035 ignoreBalanced (ident, what);
1036 break;
1038 case ObjcINTERFACE:
1039 toDoNext = &parseInterface;
1040 break;
1042 case ObjcIMPLEMENTATION:
1043 toDoNext = &parseImplementation;
1044 break;
1046 case ObjcPROTOCOL:
1047 toDoNext = &parseProtocol;
1048 break;
1050 case ObjcTYPEDEF:
1051 toDoNext = parseTypedef;
1052 comeAfter = &globalScope;
1053 break;
1055 case Tok_CurlL:
1056 comeAfter = &globalScope;
1057 toDoNext = &ignoreBalanced;
1058 ignoreBalanced (ident, what);
1059 break;
1061 case ObjcEND:
1062 case ObjcPUBLIC:
1063 case ObjcPROTECTED:
1064 case ObjcPRIVATE:
1066 default:
1067 /* we don't care */
1068 break;
1072 /*////////////////////////////////////////////////////////////////
1073 //// Deal with the system */
1075 static void findObjcTags (void)
1077 vString *name = vStringNew ();
1078 lexingState st;
1079 objcToken tok;
1081 parentName = vStringNew ();
1082 tempName = vStringNew ();
1083 fullMethodName = vStringNew ();
1084 prevIdent = vStringNew ();
1086 /* (Re-)initialize state variables, this might be a second file */
1087 comeAfter = NULL;
1088 fallback = NULL;
1089 parentType = K_INTERFACE;
1090 ignoreBalanced_count = 0;
1091 methodKind = 0;
1092 parseStruct_gotName = FALSE;
1093 parseEnumFields_prev = NULL;
1094 parseEnum_named = FALSE;
1095 ignorePreprocStuff_escaped = FALSE;
1097 st.name = vStringNew ();
1098 st.cp = readLineFromInputFile ();
1099 toDoNext = &globalScope;
1100 tok = lex (&st);
1101 while (tok != Tok_EOF)
1103 (*toDoNext) (st.name, tok);
1104 tok = lex (&st);
1106 vStringDelete(st.name);
1108 vStringDelete (name);
1109 vStringDelete (parentName);
1110 vStringDelete (tempName);
1111 vStringDelete (fullMethodName);
1112 vStringDelete (prevIdent);
1113 parentName = NULL;
1114 tempName = NULL;
1115 prevIdent = NULL;
1116 fullMethodName = NULL;
1119 static void objcInitialize (const langType language)
1121 Lang_ObjectiveC = language;
1124 extern parserDefinition *ObjcParser (void)
1126 static const char *const extensions[] = { "m", "h", NULL };
1127 parserDefinition *def = parserNewFull ("ObjectiveC", KIND_FILE_ALT);
1128 def->kinds = ObjcKinds;
1129 def->kindCount = ARRAY_SIZE (ObjcKinds);
1130 def->extensions = extensions;
1131 def->parser = findObjcTags;
1132 def->initialize = objcInitialize;
1133 def->keywordTable = objcKeywordTable;
1134 def->keywordCount = ARRAY_SIZE (objcKeywordTable);
1135 return def;