2 * Copyright (c) 2000-2003, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License.
7 * This module contains functions for generating tags for PERL language
14 #include "general.h" /* must always come first */
24 #define TRACE_PERL_C 0
25 #define TRACE if (TRACE_PERL_C) printf("perl.c:%d: ", __LINE__), printf
37 K_SUBROUTINE_DECLARATION
40 static kindOption PerlKinds
[] = {
41 { TRUE
, 'e', "enum", "constants" },
42 { TRUE
, 'o', "other", "formats" },
43 { TRUE
, 'm', "macro", "labels" },
44 { TRUE
, 'p', "package", "packages" },
45 { TRUE
, 'f', "function", "subroutines" },
46 { FALSE
, 'p', "prototype", "subroutine declarations" },
50 * FUNCTION DEFINITIONS
53 static boolean
isIdentifier1 (int c
)
55 return (boolean
) (isalpha (c
) || c
== '_');
58 static boolean
isIdentifier (int c
)
60 return (boolean
) (isalnum (c
) || c
== '_');
63 static boolean
isPodWord (const char *word
)
65 boolean result
= FALSE
;
68 const char *const pods
[] = {
69 "head1", "head2", "head3", "head4", "over", "item", "back",
70 "pod", "begin", "end", "for"
72 const size_t count
= sizeof (pods
) / sizeof (pods
[0]);
73 const char *white
= strpbrk (word
, " \t");
74 const size_t len
= (white
!=NULL
) ? (size_t)(white
-word
) : strlen (word
);
75 char *const id
= (char*) eMalloc (len
+ 1);
77 strncpy (id
, word
, len
);
79 for (i
= 0 ; i
< count
&& ! result
; ++i
)
81 if (strcmp (id
, pods
[i
]) == 0)
90 * Perl subroutine declaration may look like one of the following:
95 * sub abc (proto) :attr;
97 * Note that there may be more than one attribute. Attributes may
98 * have things in parentheses (they look like arguments). Anything
99 * inside of those parentheses goes. Prototypes may contain semi-colons.
100 * The matching end when we encounter (outside of any parentheses) either
101 * a semi-colon (that'd be a declaration) or an left curly brace
104 * This is pretty complicated parsing (plus we all know that only perl can
105 * parse Perl), so we are only promising best effort here.
107 * If we can't determine what this is (due to a file ending, for example),
108 * we will return FALSE.
110 static boolean
isSubroutineDeclaration (const unsigned char *cp
)
112 boolean attr
= FALSE
;
122 else if (TRUE
== attr
)
123 return FALSE
; /* Invalid attribute name */
144 if (isIdentifier1(*cp
)) {
146 while (isIdentifier (*cp
))
149 goto SUB_DECL_SWITCH
; /* Instead of --cp; */
153 } else if (nparens
) {
160 } while (NULL
!= (cp
= fileReadLine ()));
165 /* Algorithm adapted from from GNU etags.
166 * Perl support by Bart Robinson <lomew@cs.utah.edu>
167 * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/
169 static void findPerlTags (void)
171 vString
*name
= vStringNew ();
172 vString
*package
= NULL
;
173 boolean skipPodDoc
= FALSE
;
174 const unsigned char *line
;
176 while ((line
= fileReadLine ()) != NULL
)
178 boolean spaceRequired
= FALSE
;
179 boolean qualified
= FALSE
;
180 const unsigned char *cp
= line
;
181 perlKind kind
= K_NONE
;
186 if (strncmp ((const char*) line
, "=cut", (size_t) 4) == 0)
190 else if (line
[0] == '=')
192 skipPodDoc
= isPodWord ((const char*)line
+ 1);
195 else if (strcmp ((const char*) line
, "__DATA__") == 0)
197 else if (strcmp ((const char*) line
, "__END__") == 0)
199 else if (line
[0] == '#')
202 while (isspace (*cp
))
205 if (strncmp((const char*) cp
, "sub", (size_t) 3) == 0)
207 TRACE("this looks like a sub\n");
210 spaceRequired
= TRUE
;
213 else if (strncmp((const char*) cp
, "use", (size_t) 3) == 0)
218 while (*cp
&& isspace (*cp
))
220 if (strncmp((const char*) cp
, "constant", (size_t) 8) != 0)
224 spaceRequired
= TRUE
;
227 else if (strncmp((const char*) cp
, "package", (size_t) 7) == 0)
229 /* This will point to space after 'package' so that a tag
231 const unsigned char *space
= cp
+= 7;
234 package
= vStringNew ();
236 vStringClear (package
);
237 while (isspace (*cp
))
239 while ((int) *cp
!= ';' && !isspace ((int) *cp
))
241 vStringPut (package
, (int) *cp
);
244 vStringCatS (package
, "::");
246 cp
= space
; /* Rewind */
248 spaceRequired
= TRUE
;
251 else if (strncmp((const char*) cp
, "format", (size_t) 6) == 0)
255 spaceRequired
= TRUE
;
260 if (isIdentifier1 (*cp
))
262 const unsigned char *p
= cp
;
263 while (isIdentifier (*p
))
267 if ((int) *p
== ':' && (int) *(p
+ 1) != ':')
273 TRACE("cp0: %s\n", (const char *) cp
);
274 if (spaceRequired
&& *cp
&& !isspace (*cp
))
277 TRACE("cp1: %s\n", (const char *) cp
);
278 while (isspace (*cp
))
281 while (!*cp
|| '#' == *cp
) { /* Gobble up empty lines
283 cp
= fileReadLine ();
286 while (isspace (*cp
))
290 while (isIdentifier (*cp
) || (K_PACKAGE
== kind
&& ':' == *cp
))
292 vStringPut (name
, (int) *cp
);
296 if (K_FORMAT
== kind
&&
297 vStringLength (name
) == 0 && /* cp did not advance */
300 /* format's name is optional. If it's omitted, 'STDOUT'
302 vStringCatS (name
, "STDOUT");
305 vStringTerminate (name
);
306 TRACE("name: %s\n", name
->buffer
);
308 if (0 == vStringLength(name
)) {
313 if (K_SUBROUTINE
== kind
)
316 * isSubroutineDeclaration() may consume several lines. So
317 * we record line positions.
319 initTagEntry(&e
, vStringValue(name
));
321 if (TRUE
== isSubroutineDeclaration(cp
)) {
322 if (TRUE
== PerlKinds
[K_SUBROUTINE_DECLARATION
].enabled
) {
323 kind
= K_SUBROUTINE_DECLARATION
;
330 e
.kind
= PerlKinds
[kind
].letter
;
331 e
.kindName
= PerlKinds
[kind
].name
;
335 if (Option
.include
.qualifiedTags
&& qualified
&&
336 package
!= NULL
&& vStringLength (package
) > 0)
338 vString
*const qualifiedName
= vStringNew ();
339 vStringCopy (qualifiedName
, package
);
340 vStringCat (qualifiedName
, name
);
341 e
.name
= vStringValue(qualifiedName
);
343 vStringDelete (qualifiedName
);
345 } else if (vStringLength (name
) > 0)
347 makeSimpleTag (name
, PerlKinds
, kind
);
348 if (Option
.include
.qualifiedTags
&& qualified
&&
350 package
!= NULL
&& vStringLength (package
) > 0)
352 vString
*const qualifiedName
= vStringNew ();
353 vStringCopy (qualifiedName
, package
);
354 vStringCat (qualifiedName
, name
);
355 makeSimpleTag (qualifiedName
, PerlKinds
, kind
);
356 vStringDelete (qualifiedName
);
364 vStringDelete (name
);
366 vStringDelete (package
);
369 extern parserDefinition
* PerlParser (void)
371 static const char *const extensions
[] = { "pl", "pm", "plx", "perl", NULL
};
372 parserDefinition
* def
= parserNew ("Perl");
373 def
->kinds
= PerlKinds
;
374 def
->kindCount
= KIND_COUNT (PerlKinds
);
375 def
->extensions
= extensions
;
376 def
->parser
= findPerlTags
;
380 /* vi:set tabstop=4 shiftwidth=4 noexpandtab: */