xref: /Universal-ctags/parsers/perl.c (revision 08bf1b999d211d0a18de5b4e5f65ad0f8dbf1c51)
13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO *   Copyright (c) 2000-2003, Darren Hiebert
33ae02089SMasatake YAMATO *
43ae02089SMasatake YAMATO *   This source code is released for free distribution under the terms of the
50ce38835Sviccuad *   GNU General Public License version 2 or (at your option) any later version.
63ae02089SMasatake YAMATO *
73ae02089SMasatake YAMATO *   This module contains functions for generating tags for PERL language
83ae02089SMasatake YAMATO *   files.
93ae02089SMasatake YAMATO */
103ae02089SMasatake YAMATO 
113ae02089SMasatake YAMATO /*
123ae02089SMasatake YAMATO *   INCLUDE FILES
133ae02089SMasatake YAMATO */
143ae02089SMasatake YAMATO #include "general.h"  /* must always come first */
153ae02089SMasatake YAMATO 
163ae02089SMasatake YAMATO #include <string.h>
173ae02089SMasatake YAMATO 
183ae02089SMasatake YAMATO #include "entry.h"
19cd677fe6SMasatake YAMATO #include "perl.h"
209092a057SMasatake YAMATO #include "promise.h"
213ae02089SMasatake YAMATO #include "read.h"
223ae02089SMasatake YAMATO #include "routines.h"
23acae9f99SDmitri Tikhonov #include "selectors.h"
24cd677fe6SMasatake YAMATO #include "subparser.h"
253ae02089SMasatake YAMATO #include "vstring.h"
2635c59e96SMasatake YAMATO #include "xtag.h"
273ae02089SMasatake YAMATO 
283ae02089SMasatake YAMATO #define TRACE_PERL_C 0
293ae02089SMasatake YAMATO #define TRACE if (TRACE_PERL_C) printf("perl.c:%d: ", __LINE__), printf
303ae02089SMasatake YAMATO 
313ae02089SMasatake YAMATO /*
323ae02089SMasatake YAMATO *   DATA DEFINITIONS
333ae02089SMasatake YAMATO */
34cd677fe6SMasatake YAMATO typedef enum PerlKindType perlKind;
35b02a66cdSMasatake YAMATO typedef enum PerlModuleRoleType perlModuleRole;
36b02a66cdSMasatake YAMATO 
37b02a66cdSMasatake YAMATO static roleDefinition PerlModuleRoles [] = {
38b02a66cdSMasatake YAMATO 	{ true, "used",   "specified in `use' built-in function" },
3950c83de6SMasatake YAMATO 	{ true, "unused", "specified in `no' built-in function" },
40b02a66cdSMasatake YAMATO };
413ae02089SMasatake YAMATO 
42*08bf1b99SMasatake YAMATO typedef enum {
43*08bf1b99SMasatake YAMATO 	R_HEREDOC_ENDLABEL,
44*08bf1b99SMasatake YAMATO } perlHeredocRole;
45*08bf1b99SMasatake YAMATO 
46*08bf1b99SMasatake YAMATO static roleDefinition PerlHeredocRoles [] = {
47*08bf1b99SMasatake YAMATO 	{ true, "endmarker", "end marker" },
48*08bf1b99SMasatake YAMATO };
49*08bf1b99SMasatake YAMATO 
50e112e8abSMasatake YAMATO static kindDefinition PerlKinds [] = {
51ce990805SThomas Braun 	{ true,  'c', "constant",               "constants" },
52ce990805SThomas Braun 	{ true,  'f', "format",                 "formats" },
53ce990805SThomas Braun 	{ true,  'l', "label",                  "labels" },
54ce990805SThomas Braun 	{ true,  'p', "package",                "packages" },
55ce990805SThomas Braun 	{ true,  's', "subroutine",             "subroutines" },
56ce990805SThomas Braun 	{ false, 'd', "subroutineDeclaration",  "subroutine declarations" },
57b02a66cdSMasatake YAMATO 	{ false, 'M', "module",                 "modules",
58b02a66cdSMasatake YAMATO 	  .referenceOnly = true,  ATTACH_ROLES(PerlModuleRoles)},
59*08bf1b99SMasatake YAMATO 	{ false, 'h', "heredoc", "marker for here document",
60*08bf1b99SMasatake YAMATO 	  .referenceOnly = false, ATTACH_ROLES (PerlHeredocRoles) },
61*08bf1b99SMasatake YAMATO };
62*08bf1b99SMasatake YAMATO 
63*08bf1b99SMasatake YAMATO struct hereDocMarker {
64*08bf1b99SMasatake YAMATO 	vString *marker;
65*08bf1b99SMasatake YAMATO 	bool indented;
66*08bf1b99SMasatake YAMATO 	int corkIndex;
67*08bf1b99SMasatake YAMATO };
68*08bf1b99SMasatake YAMATO 
69*08bf1b99SMasatake YAMATO struct hereDocMarkerManager {
70*08bf1b99SMasatake YAMATO 	ptrArray *markers;
71*08bf1b99SMasatake YAMATO 	size_t current;
723ae02089SMasatake YAMATO };
733ae02089SMasatake YAMATO 
743ae02089SMasatake YAMATO /*
753ae02089SMasatake YAMATO *   FUNCTION DEFINITIONS
763ae02089SMasatake YAMATO */
773ae02089SMasatake YAMATO 
notifyEnteringPod()78d7ad8c78SMasatake YAMATO static void notifyEnteringPod ()
79cd677fe6SMasatake YAMATO {
80cd677fe6SMasatake YAMATO 	subparser *sub;
81cd677fe6SMasatake YAMATO 
82cd677fe6SMasatake YAMATO 	foreachSubparser (sub, false)
83cd677fe6SMasatake YAMATO 	{
84cd677fe6SMasatake YAMATO 		perlSubparser *perlsub = (perlSubparser *)sub;
85cd677fe6SMasatake YAMATO 		if (perlsub->enteringPodNotify)
86cd677fe6SMasatake YAMATO 		{
87cd677fe6SMasatake YAMATO 			enterSubparser (sub);
88cd677fe6SMasatake YAMATO 			perlsub->enteringPodNotify (perlsub);
89cd677fe6SMasatake YAMATO 			leaveSubparser ();
90cd677fe6SMasatake YAMATO 		}
91cd677fe6SMasatake YAMATO 	}
92cd677fe6SMasatake YAMATO }
93cd677fe6SMasatake YAMATO 
notifyLeavingPod()94cd677fe6SMasatake YAMATO static void notifyLeavingPod ()
95cd677fe6SMasatake YAMATO {
96cd677fe6SMasatake YAMATO 	subparser *sub;
97cd677fe6SMasatake YAMATO 
98cd677fe6SMasatake YAMATO 	foreachSubparser (sub, false)
99cd677fe6SMasatake YAMATO 	{
100cd677fe6SMasatake YAMATO 		perlSubparser *perlsub = (perlSubparser *)sub;
101cd677fe6SMasatake YAMATO 		if (perlsub->leavingPodNotify)
102cd677fe6SMasatake YAMATO 		{
103cd677fe6SMasatake YAMATO 			enterSubparser (sub);
104cd677fe6SMasatake YAMATO 			perlsub->leavingPodNotify (perlsub);
105cd677fe6SMasatake YAMATO 			leaveSubparser ();
106cd677fe6SMasatake YAMATO 		}
107cd677fe6SMasatake YAMATO 	}
108cd677fe6SMasatake YAMATO }
109cd677fe6SMasatake YAMATO 
notifyFindingQuotedWord(int moduleIndex,const char * qwd)1105be4c343SMasatake YAMATO static void notifyFindingQuotedWord (int moduleIndex,
1115be4c343SMasatake YAMATO 									 const char *qwd)
1125be4c343SMasatake YAMATO {
1135be4c343SMasatake YAMATO 	subparser *sub;
1145be4c343SMasatake YAMATO 
1155be4c343SMasatake YAMATO 	foreachSubparser (sub, false)
1165be4c343SMasatake YAMATO 	{
1175be4c343SMasatake YAMATO 		perlSubparser *perlsub = (perlSubparser *)sub;
1185be4c343SMasatake YAMATO 		if (perlsub->findingQuotedWordNotify)
1195be4c343SMasatake YAMATO 		{
1205be4c343SMasatake YAMATO 			enterSubparser (sub);
1215be4c343SMasatake YAMATO 			perlsub->findingQuotedWordNotify (perlsub,
1225be4c343SMasatake YAMATO 											  moduleIndex,
1235be4c343SMasatake YAMATO 											  qwd);
1245be4c343SMasatake YAMATO 			leaveSubparser ();
1255be4c343SMasatake YAMATO 		}
1265be4c343SMasatake YAMATO 	}
1275be4c343SMasatake YAMATO }
1285be4c343SMasatake YAMATO 
isIdentifier1(int c)129ce990805SThomas Braun static bool isIdentifier1 (int c)
1303ae02089SMasatake YAMATO {
131ce990805SThomas Braun 	return (bool) (isalpha (c) || c == '_');
1323ae02089SMasatake YAMATO }
1333ae02089SMasatake YAMATO 
isIdentifier(int c)134ce990805SThomas Braun static bool isIdentifier (int c)
1353ae02089SMasatake YAMATO {
136ce990805SThomas Braun 	return (bool) (isalnum (c) || c == '_');
1373ae02089SMasatake YAMATO }
1383ae02089SMasatake YAMATO 
isPodWord(const char * word)139ce990805SThomas Braun static bool isPodWord (const char *word)
1403ae02089SMasatake YAMATO {
1413ae02089SMasatake YAMATO 	/* Perl POD words are three to eight characters in size.  We use this
1423ae02089SMasatake YAMATO 	 * fact to find (or not find) the right side of the word and then
1433ae02089SMasatake YAMATO 	 * perform comparisons, if necessary, of POD words of that size.
1443ae02089SMasatake YAMATO 	 */
1453ae02089SMasatake YAMATO 	size_t len;
1463ae02089SMasatake YAMATO 	for (len = 0; len < 9; ++len)
1473ae02089SMasatake YAMATO 		if ('\0' == word[len] || ' ' == word[len] || '\t' == word[len])
1483ae02089SMasatake YAMATO 			break;
1493ae02089SMasatake YAMATO 	switch (len) {
1503ae02089SMasatake YAMATO 		case 3:
1513ae02089SMasatake YAMATO 			return 0 == strncmp(word, "end", 3)
1523ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "for", 3)
1533ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "pod", 3);
1543ae02089SMasatake YAMATO 		case 4:
1553ae02089SMasatake YAMATO 			return 0 == strncmp(word, "back", 4)
1563ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "item", 4)
1573ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "over", 4);
1583ae02089SMasatake YAMATO 		case 5:
1593ae02089SMasatake YAMATO 			return 0 == strncmp(word, "begin", 5)
1603ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "head1", 5)
1613ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "head2", 5)
1623ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "head3", 5)
1633ae02089SMasatake YAMATO 				|| 0 == strncmp(word, "head4", 5);
1643ae02089SMasatake YAMATO 		case 8:
1653ae02089SMasatake YAMATO 			return 0 == strncmp(word, "encoding", 8);
1663ae02089SMasatake YAMATO 		default:
167ce990805SThomas Braun 			return false;
1683ae02089SMasatake YAMATO 	}
1693ae02089SMasatake YAMATO }
1703ae02089SMasatake YAMATO 
1713ae02089SMasatake YAMATO /*
1723ae02089SMasatake YAMATO  * Perl subroutine declaration may look like one of the following:
1733ae02089SMasatake YAMATO  *
1743ae02089SMasatake YAMATO  *  sub abc;
1753ae02089SMasatake YAMATO  *  sub abc :attr;
1763ae02089SMasatake YAMATO  *  sub abc (proto);
1773ae02089SMasatake YAMATO  *  sub abc (proto) :attr;
1783ae02089SMasatake YAMATO  *
1793ae02089SMasatake YAMATO  * Note that there may be more than one attribute.  Attributes may
1803ae02089SMasatake YAMATO  * have things in parentheses (they look like arguments).  Anything
1813ae02089SMasatake YAMATO  * inside of those parentheses goes.  Prototypes may contain semi-colons.
1823ae02089SMasatake YAMATO  * The matching end when we encounter (outside of any parentheses) either
1833ae02089SMasatake YAMATO  * a semi-colon (that'd be a declaration) or an left curly brace
1843ae02089SMasatake YAMATO  * (definition).
1853ae02089SMasatake YAMATO  *
1863ae02089SMasatake YAMATO  * This is pretty complicated parsing (plus we all know that only perl can
1873ae02089SMasatake YAMATO  * parse Perl), so we are only promising best effort here.
1883ae02089SMasatake YAMATO  *
1893ae02089SMasatake YAMATO  * If we can't determine what this is (due to a file ending, for example),
190ce990805SThomas Braun  * we will return false.
1913ae02089SMasatake YAMATO  */
isSubroutineDeclaration(const unsigned char * cp)192ce990805SThomas Braun static bool isSubroutineDeclaration (const unsigned char *cp)
1933ae02089SMasatake YAMATO {
194ce990805SThomas Braun 	bool attr = false;
1953ae02089SMasatake YAMATO 	int nparens = 0;
1963ae02089SMasatake YAMATO 
1973ae02089SMasatake YAMATO 	do {
1983ae02089SMasatake YAMATO 		for ( ; *cp; ++cp) {
1993ae02089SMasatake YAMATO SUB_DECL_SWITCH:
2003ae02089SMasatake YAMATO 			switch (*cp) {
2013ae02089SMasatake YAMATO 				case ':':
2023ae02089SMasatake YAMATO 					if (nparens)
2033ae02089SMasatake YAMATO 						break;
204ce990805SThomas Braun 					else if (true == attr)
205ce990805SThomas Braun 						return false;    /* Invalid attribute name */
2063ae02089SMasatake YAMATO 					else
207ce990805SThomas Braun 						attr = true;
2083ae02089SMasatake YAMATO 					break;
2093ae02089SMasatake YAMATO 				case '(':
2103ae02089SMasatake YAMATO 					++nparens;
2113ae02089SMasatake YAMATO 					break;
2123ae02089SMasatake YAMATO 				case ')':
2133ae02089SMasatake YAMATO 					--nparens;
2143ae02089SMasatake YAMATO 					break;
2153ae02089SMasatake YAMATO 				case ' ':
2163ae02089SMasatake YAMATO 				case '\t':
2173ae02089SMasatake YAMATO 					break;
2183ae02089SMasatake YAMATO 				case ';':
2193ae02089SMasatake YAMATO 					if (!nparens)
220ce990805SThomas Braun 						return true;
2213ae02089SMasatake YAMATO 				case '{':
2223ae02089SMasatake YAMATO 					if (!nparens)
223ce990805SThomas Braun 						return false;
2243ae02089SMasatake YAMATO 				default:
2253ae02089SMasatake YAMATO 					if (attr) {
2263ae02089SMasatake YAMATO 						if (isIdentifier1(*cp)) {
2273ae02089SMasatake YAMATO 							cp++;
2283ae02089SMasatake YAMATO 							while (isIdentifier (*cp))
2293ae02089SMasatake YAMATO 								cp++;
230ce990805SThomas Braun 							attr = false;
2313ae02089SMasatake YAMATO 							goto SUB_DECL_SWITCH; /* Instead of --cp; */
2323ae02089SMasatake YAMATO 						} else {
233ce990805SThomas Braun 							return false;
2343ae02089SMasatake YAMATO 						}
2353ae02089SMasatake YAMATO 					} else if (nparens) {
2363ae02089SMasatake YAMATO 						break;
2373ae02089SMasatake YAMATO 					} else {
238ce990805SThomas Braun 						return false;
2393ae02089SMasatake YAMATO 					}
2403ae02089SMasatake YAMATO 			}
2413ae02089SMasatake YAMATO 		}
2421b312fe7SMasatake YAMATO 	} while (NULL != (cp = readLineFromInputFile ()));
2433ae02089SMasatake YAMATO 
244ce990805SThomas Braun 	return false;
2453ae02089SMasatake YAMATO }
2463ae02089SMasatake YAMATO 
2473ae02089SMasatake YAMATO /* `end' points to the equal sign.  Parse from right to left to get the
2483ae02089SMasatake YAMATO  * identifier.  Assume we're dealing with something of form \s*\w+\s*=>
2493ae02089SMasatake YAMATO  */
makeTagFromLeftSide(const char * begin,const char * end,vString * name,vString * package)2503ae02089SMasatake YAMATO static void makeTagFromLeftSide (const char *begin, const char *end,
2513ae02089SMasatake YAMATO 	vString *name, vString *package)
2523ae02089SMasatake YAMATO {
2533ae02089SMasatake YAMATO 	tagEntryInfo entry;
2543ae02089SMasatake YAMATO 	const char *b, *e;
255cd677fe6SMasatake YAMATO 	if (! PerlKinds[KIND_PERL_CONSTANT].enabled)
2564a95e4a5SColomban Wendling 		return;
2573ae02089SMasatake YAMATO 	for (e = end - 1; e > begin && isspace(*e); --e)
2583ae02089SMasatake YAMATO 		;
2593ae02089SMasatake YAMATO 	if (e < begin)
2603ae02089SMasatake YAMATO 		return;
2613ae02089SMasatake YAMATO 	for (b = e; b >= begin && isIdentifier(*b); --b)
2623ae02089SMasatake YAMATO 		;
2633ae02089SMasatake YAMATO 	/* Identifier must be either beginning of line of have some whitespace
2643ae02089SMasatake YAMATO 	 * on its left:
2653ae02089SMasatake YAMATO 	 */
2663ae02089SMasatake YAMATO 	if (b < begin || isspace(*b) || ',' == *b)
2673ae02089SMasatake YAMATO 		++b;
2683ae02089SMasatake YAMATO 	else if (b != begin)
2693ae02089SMasatake YAMATO 		return;
270a8e897fcSDmitri Tikhonov 	if (e - b + 1 <= 0)
271a8e897fcSDmitri Tikhonov 		return;			/* Left side of => has an invalid identifier. */
2723ae02089SMasatake YAMATO 	vStringClear(name);
2733ae02089SMasatake YAMATO 	vStringNCatS(name, b, e - b + 1);
274cd677fe6SMasatake YAMATO 	initTagEntry(&entry, vStringValue(name), KIND_PERL_CONSTANT);
2753ae02089SMasatake YAMATO 	makeTagEntry(&entry);
27635c59e96SMasatake YAMATO 	if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && package && vStringLength(package)) {
2773ae02089SMasatake YAMATO 		vStringClear(name);
2783ae02089SMasatake YAMATO 		vStringCopy(name, package);
2793ae02089SMasatake YAMATO 		vStringNCatS(name, b, e - b + 1);
280cd677fe6SMasatake YAMATO 		initTagEntry(&entry, vStringValue(name), KIND_PERL_CONSTANT);
2815022e63aSMasatake YAMATO 		markTagExtraBit (&entry, XTAG_QUALIFIED_TAGS);
2823ae02089SMasatake YAMATO 		makeTagEntry(&entry);
2833ae02089SMasatake YAMATO 	}
2843ae02089SMasatake YAMATO }
2853ae02089SMasatake YAMATO 
makeTagForModule(const char * name,int role)2865be4c343SMasatake YAMATO static int makeTagForModule (const char *name, int role)
287b02a66cdSMasatake YAMATO {
288b02a66cdSMasatake YAMATO 	tagEntryInfo entry;
289b02a66cdSMasatake YAMATO 	initRefTagEntry(&entry, name, KIND_PERL_MODULE, role);
2905be4c343SMasatake YAMATO 	return makeTagEntry(&entry);
291b02a66cdSMasatake YAMATO }
292b02a66cdSMasatake YAMATO 
2933ae02089SMasatake YAMATO enum const_state { CONST_STATE_NEXT_LINE, CONST_STATE_HIT_END };
2943ae02089SMasatake YAMATO 
2953ae02089SMasatake YAMATO /* Parse a single line, find as many NAME => VALUE pairs as we can and try
2963ae02089SMasatake YAMATO  * to detect the end of the hashref.
2973ae02089SMasatake YAMATO  */
parseConstantsFromLine(const char * cp,vString * name,vString * package)2983ae02089SMasatake YAMATO static enum const_state parseConstantsFromLine (const char *cp,
2993ae02089SMasatake YAMATO 	vString *name, vString *package)
3003ae02089SMasatake YAMATO {
3013ae02089SMasatake YAMATO 	while (1) {
3023ae02089SMasatake YAMATO 		const size_t sz = strcspn(cp, "#}=");
3033ae02089SMasatake YAMATO 		switch (cp[sz]) {
3043ae02089SMasatake YAMATO 			case '=':
305ebaf5175SMasatake YAMATO 				if ('>' == cp[sz + 1])
3063ae02089SMasatake YAMATO 					makeTagFromLeftSide(cp, cp + sz, name, package);
3073ae02089SMasatake YAMATO 				break;
3083ae02089SMasatake YAMATO 			case '}':	/* Assume this is the end of the hashref. */
3093ae02089SMasatake YAMATO 				return CONST_STATE_HIT_END;
3103ae02089SMasatake YAMATO 			case '\0':	/* End of the line. */
3113ae02089SMasatake YAMATO 			case '#':	/* Assume this is a comment and thus end of the line. */
3123ae02089SMasatake YAMATO 				return CONST_STATE_NEXT_LINE;
3133ae02089SMasatake YAMATO 		}
3143ae02089SMasatake YAMATO 		cp += sz + 1;
3153ae02089SMasatake YAMATO 	}
3163ae02089SMasatake YAMATO }
3173ae02089SMasatake YAMATO 
3183ae02089SMasatake YAMATO /* Parse constants declared via hash reference, like this:
3193ae02089SMasatake YAMATO  * use constant {
3203ae02089SMasatake YAMATO  *   A => 1,
3213ae02089SMasatake YAMATO  *   B => 2,
3223ae02089SMasatake YAMATO  * };
3233ae02089SMasatake YAMATO  * The approach we take is simplistic, but it covers the vast majority of
3243ae02089SMasatake YAMATO  * cases well.  There can be some false positives.
3253ae02089SMasatake YAMATO  * Returns 0 if found the end of the hashref, -1 if we hit EOF
3263ae02089SMasatake YAMATO  */
parseConstantsFromHashRef(const unsigned char * cp,vString * name,vString * package)3273ae02089SMasatake YAMATO static int parseConstantsFromHashRef (const unsigned char *cp,
3283ae02089SMasatake YAMATO 	vString *name, vString *package)
3293ae02089SMasatake YAMATO {
3303ae02089SMasatake YAMATO 	while (1) {
3313ae02089SMasatake YAMATO 		enum const_state state =
3323ae02089SMasatake YAMATO 			parseConstantsFromLine((const char *) cp, name, package);
3333ae02089SMasatake YAMATO 		switch (state) {
3343ae02089SMasatake YAMATO 			case CONST_STATE_NEXT_LINE:
3351b312fe7SMasatake YAMATO 				cp = readLineFromInputFile();
3363ae02089SMasatake YAMATO 				if (cp)
3373ae02089SMasatake YAMATO 					break;
3383ae02089SMasatake YAMATO 				else
3393ae02089SMasatake YAMATO 					return -1;
3403ae02089SMasatake YAMATO 			case CONST_STATE_HIT_END:
3413ae02089SMasatake YAMATO 				return 0;
3423ae02089SMasatake YAMATO 		}
3433ae02089SMasatake YAMATO 	}
3443ae02089SMasatake YAMATO }
3453ae02089SMasatake YAMATO 
parseQuotedWords(const unsigned char * cp,vString * name,int moduleIndex)3465be4c343SMasatake YAMATO static void parseQuotedWords(const unsigned char *cp,
3475be4c343SMasatake YAMATO 							 vString *name, int moduleIndex)
3485be4c343SMasatake YAMATO {
3495be4c343SMasatake YAMATO 	unsigned char end = *cp++;
3505be4c343SMasatake YAMATO 	switch (end)
3515be4c343SMasatake YAMATO 	{
3525be4c343SMasatake YAMATO 	case '[': end = ']'; break;
3535be4c343SMasatake YAMATO 	case '(': end = ')'; break;
3545be4c343SMasatake YAMATO 	case '{': end = '}'; break;
3555be4c343SMasatake YAMATO 	case '<': end = '>'; break;
3565be4c343SMasatake YAMATO 	}
3575be4c343SMasatake YAMATO 
3585be4c343SMasatake YAMATO 	do {
3595be4c343SMasatake YAMATO 		while (*cp && *cp != end)
3605be4c343SMasatake YAMATO 		{
3615be4c343SMasatake YAMATO 			if (isspace(*cp))
3625be4c343SMasatake YAMATO 			{
3635be4c343SMasatake YAMATO 				notifyFindingQuotedWord (moduleIndex, vStringValue(name));
3645be4c343SMasatake YAMATO 				vStringClear(name);
3655be4c343SMasatake YAMATO 				cp++;
3665be4c343SMasatake YAMATO 				continue;
3675be4c343SMasatake YAMATO 			}
3685be4c343SMasatake YAMATO 
3695be4c343SMasatake YAMATO 			if (*cp == '\\')
3705be4c343SMasatake YAMATO 			{
3715be4c343SMasatake YAMATO 				cp++;
3725be4c343SMasatake YAMATO 				if (*cp == '\0')
3735be4c343SMasatake YAMATO 					break;
3745be4c343SMasatake YAMATO 			}
3755be4c343SMasatake YAMATO 
3765be4c343SMasatake YAMATO 			vStringPut(name, *cp);
3775be4c343SMasatake YAMATO 			cp++;
3785be4c343SMasatake YAMATO 		}
3795be4c343SMasatake YAMATO 		if (!vStringIsEmpty(name))
3805be4c343SMasatake YAMATO 			notifyFindingQuotedWord (moduleIndex, vStringValue(name));
3815be4c343SMasatake YAMATO 
3825be4c343SMasatake YAMATO 		if (*cp == end)
3835be4c343SMasatake YAMATO 			break;
3845be4c343SMasatake YAMATO 	} while ((cp = readLineFromInputFile()) != NULL);
3855be4c343SMasatake YAMATO }
3865be4c343SMasatake YAMATO 
387*08bf1b99SMasatake YAMATO /*
388*08bf1b99SMasatake YAMATO  * Extract heredoc markers and skip the heredoc areas.
389*08bf1b99SMasatake YAMATO  *
390*08bf1b99SMasatake YAMATO  * - https://perldoc.perl.org/perlop#%3C%3CEOF
391*08bf1b99SMasatake YAMATO  */
hereDocMarkerNew(bool indented)392*08bf1b99SMasatake YAMATO static struct hereDocMarker *hereDocMarkerNew (bool indented)
393*08bf1b99SMasatake YAMATO {
394*08bf1b99SMasatake YAMATO 	struct hereDocMarker *marker = xMalloc(1, struct hereDocMarker);
395*08bf1b99SMasatake YAMATO 
396*08bf1b99SMasatake YAMATO 	marker->indented = indented;
397*08bf1b99SMasatake YAMATO 	marker->marker = vStringNew();
398*08bf1b99SMasatake YAMATO 	marker->corkIndex = CORK_NIL;
399*08bf1b99SMasatake YAMATO 
400*08bf1b99SMasatake YAMATO 	return marker;
401*08bf1b99SMasatake YAMATO }
402*08bf1b99SMasatake YAMATO 
hereDocMarkerDelete(struct hereDocMarker * marker)403*08bf1b99SMasatake YAMATO static void hereDocMarkerDelete (struct hereDocMarker *marker)
404*08bf1b99SMasatake YAMATO {
405*08bf1b99SMasatake YAMATO 	vStringDelete (marker->marker);
406*08bf1b99SMasatake YAMATO 	eFree (marker);
407*08bf1b99SMasatake YAMATO }
408*08bf1b99SMasatake YAMATO 
readHereDocMarker(unsigned char * line,vString * marker,unsigned char quote_char)409*08bf1b99SMasatake YAMATO static unsigned char *readHereDocMarker (unsigned char *line,
410*08bf1b99SMasatake YAMATO 										 vString *marker,
411*08bf1b99SMasatake YAMATO 										 unsigned char quote_char)
412*08bf1b99SMasatake YAMATO {
413*08bf1b99SMasatake YAMATO 	unsigned char *cp = line;
414*08bf1b99SMasatake YAMATO 	bool backslash = false;
415*08bf1b99SMasatake YAMATO 
416*08bf1b99SMasatake YAMATO 	for (cp = line; *cp != '\0'; cp++)
417*08bf1b99SMasatake YAMATO 	{
418*08bf1b99SMasatake YAMATO 		if (backslash)
419*08bf1b99SMasatake YAMATO 		{
420*08bf1b99SMasatake YAMATO 			vStringPut (marker, *cp);
421*08bf1b99SMasatake YAMATO 			backslash = false;
422*08bf1b99SMasatake YAMATO 			continue;
423*08bf1b99SMasatake YAMATO 		}
424*08bf1b99SMasatake YAMATO 
425*08bf1b99SMasatake YAMATO 		if (quote_char == '"' && (*cp == '\\'))
426*08bf1b99SMasatake YAMATO 		{
427*08bf1b99SMasatake YAMATO 			backslash = true;
428*08bf1b99SMasatake YAMATO 			continue;
429*08bf1b99SMasatake YAMATO 		}
430*08bf1b99SMasatake YAMATO 
431*08bf1b99SMasatake YAMATO 		if (quote_char && *cp == quote_char)
432*08bf1b99SMasatake YAMATO 		{
433*08bf1b99SMasatake YAMATO 			cp++;
434*08bf1b99SMasatake YAMATO 			break;
435*08bf1b99SMasatake YAMATO 		}
436*08bf1b99SMasatake YAMATO 
437*08bf1b99SMasatake YAMATO 		if (!quote_char && !isIdentifier(*cp))
438*08bf1b99SMasatake YAMATO 			break;
439*08bf1b99SMasatake YAMATO 
440*08bf1b99SMasatake YAMATO 		vStringPut (marker, *cp);
441*08bf1b99SMasatake YAMATO 	}
442*08bf1b99SMasatake YAMATO 
443*08bf1b99SMasatake YAMATO 	return cp;
444*08bf1b99SMasatake YAMATO }
445*08bf1b99SMasatake YAMATO 
collectHereDocMarkers(struct hereDocMarkerManager * mgr,const unsigned char * line)446*08bf1b99SMasatake YAMATO static void collectHereDocMarkers (struct hereDocMarkerManager *mgr,
447*08bf1b99SMasatake YAMATO 								   const unsigned char *line)
448*08bf1b99SMasatake YAMATO {
449*08bf1b99SMasatake YAMATO 	unsigned char *starter = (unsigned char*)strstr((char *)line, "<<");
450*08bf1b99SMasatake YAMATO 	unsigned char *cp = NULL;
451*08bf1b99SMasatake YAMATO 	bool indented = false;
452*08bf1b99SMasatake YAMATO 	unsigned char quote_char = 0;
453*08bf1b99SMasatake YAMATO 
454*08bf1b99SMasatake YAMATO 	if (starter == NULL)
455*08bf1b99SMasatake YAMATO 		return;
456*08bf1b99SMasatake YAMATO 
457*08bf1b99SMasatake YAMATO 	cp = starter + 2;
458*08bf1b99SMasatake YAMATO 	while (isspace (*cp))
459*08bf1b99SMasatake YAMATO 		cp++;
460*08bf1b99SMasatake YAMATO 
461*08bf1b99SMasatake YAMATO 	if (*cp == '\0')
462*08bf1b99SMasatake YAMATO 		return;
463*08bf1b99SMasatake YAMATO 
464*08bf1b99SMasatake YAMATO 	/* Is shift operator? */
465*08bf1b99SMasatake YAMATO 	if (isdigit (*cp))
466*08bf1b99SMasatake YAMATO 	{
467*08bf1b99SMasatake YAMATO 		/* Scan the rest of the string. */
468*08bf1b99SMasatake YAMATO 		collectHereDocMarkers (mgr, ++cp);
469*08bf1b99SMasatake YAMATO 		return;
470*08bf1b99SMasatake YAMATO 	}
471*08bf1b99SMasatake YAMATO 
472*08bf1b99SMasatake YAMATO 	if (*cp == '~') {
473*08bf1b99SMasatake YAMATO 		indented = true;
474*08bf1b99SMasatake YAMATO 		cp++;
475*08bf1b99SMasatake YAMATO 		if (*cp == '\0')
476*08bf1b99SMasatake YAMATO 			return;
477*08bf1b99SMasatake YAMATO 		while (isspace (*cp))
478*08bf1b99SMasatake YAMATO 			cp++;
479*08bf1b99SMasatake YAMATO 		if (*cp == '\0')
480*08bf1b99SMasatake YAMATO 			return;
481*08bf1b99SMasatake YAMATO 	}
482*08bf1b99SMasatake YAMATO 
483*08bf1b99SMasatake YAMATO 	switch (*cp)
484*08bf1b99SMasatake YAMATO 	{
485*08bf1b99SMasatake YAMATO 	case '\'':
486*08bf1b99SMasatake YAMATO 	case '"':
487*08bf1b99SMasatake YAMATO 	case '`':
488*08bf1b99SMasatake YAMATO 		quote_char = *cp;
489*08bf1b99SMasatake YAMATO 		/* Fall through */
490*08bf1b99SMasatake YAMATO 	case '\\':
491*08bf1b99SMasatake YAMATO 		cp++;
492*08bf1b99SMasatake YAMATO 		if (*cp == '\0')
493*08bf1b99SMasatake YAMATO 			return;
494*08bf1b99SMasatake YAMATO 		break;
495*08bf1b99SMasatake YAMATO 	default:
496*08bf1b99SMasatake YAMATO 		break;
497*08bf1b99SMasatake YAMATO 	}
498*08bf1b99SMasatake YAMATO 
499*08bf1b99SMasatake YAMATO 	struct hereDocMarker *marker = hereDocMarkerNew (indented);
500*08bf1b99SMasatake YAMATO 	const unsigned char *last_cp = cp;
501*08bf1b99SMasatake YAMATO 	cp = readHereDocMarker(cp, marker->marker, quote_char);
502*08bf1b99SMasatake YAMATO 	if (vStringLength (marker->marker) > 0)
503*08bf1b99SMasatake YAMATO 	{
504*08bf1b99SMasatake YAMATO 		marker->corkIndex = makeSimpleTag (marker->marker,
505*08bf1b99SMasatake YAMATO 										   KIND_PERL_HEREDOCMARKER);
506*08bf1b99SMasatake YAMATO 		ptrArrayAdd (mgr->markers, marker);
507*08bf1b99SMasatake YAMATO 	}
508*08bf1b99SMasatake YAMATO 	else
509*08bf1b99SMasatake YAMATO 		hereDocMarkerDelete (marker);
510*08bf1b99SMasatake YAMATO 
511*08bf1b99SMasatake YAMATO 	if (*cp != '\0' && cp != last_cp)
512*08bf1b99SMasatake YAMATO 		collectHereDocMarkers (mgr, cp);
513*08bf1b99SMasatake YAMATO }
514*08bf1b99SMasatake YAMATO 
isInHereDoc(struct hereDocMarkerManager * mgr,const unsigned char * line)515*08bf1b99SMasatake YAMATO static bool isInHereDoc (struct hereDocMarkerManager *mgr,
516*08bf1b99SMasatake YAMATO 						 const unsigned char *line)
517*08bf1b99SMasatake YAMATO {
518*08bf1b99SMasatake YAMATO 	if (ptrArrayCount (mgr->markers) == 0)
519*08bf1b99SMasatake YAMATO 		return false;
520*08bf1b99SMasatake YAMATO 
521*08bf1b99SMasatake YAMATO 	const unsigned char *cp = line;
522*08bf1b99SMasatake YAMATO 	struct hereDocMarker *current = ptrArrayItem (mgr->markers, mgr->current);
523*08bf1b99SMasatake YAMATO 	if (current->indented)
524*08bf1b99SMasatake YAMATO 	{
525*08bf1b99SMasatake YAMATO 		while (isspace(*cp))
526*08bf1b99SMasatake YAMATO 			cp++;
527*08bf1b99SMasatake YAMATO 	}
528*08bf1b99SMasatake YAMATO 	if (strncmp((const char *)cp, vStringValue (current->marker), vStringLength (current->marker)) == 0
529*08bf1b99SMasatake YAMATO 		&& (cp [vStringLength (current->marker)] == '\0'
530*08bf1b99SMasatake YAMATO 			|| (!isIdentifier (cp [vStringLength (current->marker)]))))
531*08bf1b99SMasatake YAMATO 	{
532*08bf1b99SMasatake YAMATO 		tagEntryInfo *tag = getEntryInCorkQueue (current->corkIndex);
533*08bf1b99SMasatake YAMATO 		if (tag)
534*08bf1b99SMasatake YAMATO 			tag->extensionFields.endLine = getInputLineNumber();
535*08bf1b99SMasatake YAMATO 		mgr->current++;
536*08bf1b99SMasatake YAMATO 		if (mgr->current == ptrArrayCount (mgr->markers))
537*08bf1b99SMasatake YAMATO 		{
538*08bf1b99SMasatake YAMATO 			ptrArrayClear (mgr->markers);
539*08bf1b99SMasatake YAMATO 			mgr->current = 0;
540*08bf1b99SMasatake YAMATO 		}
541*08bf1b99SMasatake YAMATO 	}
542*08bf1b99SMasatake YAMATO 	return true;
543*08bf1b99SMasatake YAMATO }
544*08bf1b99SMasatake YAMATO 
initHereDocMarkerManager(struct hereDocMarkerManager * mgr)545*08bf1b99SMasatake YAMATO static void initHereDocMarkerManager(struct hereDocMarkerManager *mgr)
546*08bf1b99SMasatake YAMATO {
547*08bf1b99SMasatake YAMATO 	mgr->markers = ptrArrayNew((ptrArrayDeleteFunc)hereDocMarkerDelete);
548*08bf1b99SMasatake YAMATO 	mgr->current = 0;
549*08bf1b99SMasatake YAMATO }
550*08bf1b99SMasatake YAMATO 
finiHereDocMarkerManager(struct hereDocMarkerManager * mgr)551*08bf1b99SMasatake YAMATO static void finiHereDocMarkerManager(struct hereDocMarkerManager *mgr)
552*08bf1b99SMasatake YAMATO {
553*08bf1b99SMasatake YAMATO 	ptrArrayDelete (mgr->markers);
554*08bf1b99SMasatake YAMATO 	mgr->markers = NULL;
555*08bf1b99SMasatake YAMATO 	mgr->current = 0;
556*08bf1b99SMasatake YAMATO }
557*08bf1b99SMasatake YAMATO 
5583ae02089SMasatake YAMATO /* Algorithm adapted from from GNU etags.
5593ae02089SMasatake YAMATO  * Perl support by Bart Robinson <lomew@cs.utah.edu>
5603ae02089SMasatake YAMATO  * Perl sub names: look for /^ [ \t\n]sub [ \t\n]+ [^ \t\n{ (]+/
5613ae02089SMasatake YAMATO  */
findPerlTags(void)5623ae02089SMasatake YAMATO static void findPerlTags (void)
5633ae02089SMasatake YAMATO {
5643ae02089SMasatake YAMATO 	vString *name = vStringNew ();
5653ae02089SMasatake YAMATO 	vString *package = NULL;
566ce990805SThomas Braun 	bool skipPodDoc = false;
5673ae02089SMasatake YAMATO 	const unsigned char *line;
5689092a057SMasatake YAMATO 	unsigned long podStart = 0UL;
5693ae02089SMasatake YAMATO 
5703b0c2ae1SMasatake YAMATO 	/* A pod area can be after __END__ marker.
5713b0c2ae1SMasatake YAMATO 	 * Perl parser itself doesn't need to parse the area
5723b0c2ae1SMasatake YAMATO 	 * after the marker. Parsing the area is needed only
5733b0c2ae1SMasatake YAMATO 	 * if Perl parser runs Pod parser as a guest.
5743b0c2ae1SMasatake YAMATO 	 * This variable is set true when it is needed.
5753b0c2ae1SMasatake YAMATO 	 */
5763b0c2ae1SMasatake YAMATO 	bool parse_only_pod_area = false;
5773b0c2ae1SMasatake YAMATO 
5783ae02089SMasatake YAMATO 	/* Core modules AutoLoader and SelfLoader support delayed compilation
5793ae02089SMasatake YAMATO 	 * by allowing Perl code that follows __END__ and __DATA__ tokens,
5803ae02089SMasatake YAMATO 	 * respectively.  When we detect that one of these modules is used
5813ae02089SMasatake YAMATO 	 * in the file, we continue processing even after we see the
5823ae02089SMasatake YAMATO 	 * corresponding token that would usually terminate parsing of the
5833ae02089SMasatake YAMATO 	 * file.
5843ae02089SMasatake YAMATO 	 */
5853ae02089SMasatake YAMATO 	enum {
5863ae02089SMasatake YAMATO 		RESPECT_END		= (1 << 0),
5873ae02089SMasatake YAMATO 		RESPECT_DATA	= (1 << 1),
5883ae02089SMasatake YAMATO 	} respect_token = RESPECT_END | RESPECT_DATA;
5893ae02089SMasatake YAMATO 
590*08bf1b99SMasatake YAMATO 	struct hereDocMarkerManager hdoc_mgr;
591*08bf1b99SMasatake YAMATO 	initHereDocMarkerManager (&hdoc_mgr);
592*08bf1b99SMasatake YAMATO 
5931b312fe7SMasatake YAMATO 	while ((line = readLineFromInputFile ()) != NULL)
5943ae02089SMasatake YAMATO 	{
595ce990805SThomas Braun 		bool spaceRequired = false;
596ce990805SThomas Braun 		bool qualified = false;
5973ae02089SMasatake YAMATO 		const unsigned char *cp = line;
598cd677fe6SMasatake YAMATO 		perlKind kind = KIND_PERL_NONE;
5993ae02089SMasatake YAMATO 		tagEntryInfo e;
6003ae02089SMasatake YAMATO 
601*08bf1b99SMasatake YAMATO 		if (isInHereDoc (&hdoc_mgr, line))
602*08bf1b99SMasatake YAMATO 			continue;
603*08bf1b99SMasatake YAMATO 
6043ae02089SMasatake YAMATO 		if (skipPodDoc)
6053ae02089SMasatake YAMATO 		{
6063ae02089SMasatake YAMATO 			if (strncmp ((const char*) line, "=cut", (size_t) 4) == 0)
6079092a057SMasatake YAMATO 			{
608ce990805SThomas Braun 				skipPodDoc = false;
6099092a057SMasatake YAMATO 				if (podStart != 0UL)
6109092a057SMasatake YAMATO 				{
611cd677fe6SMasatake YAMATO 					notifyLeavingPod ();
6129092a057SMasatake YAMATO 					makePromise ("Pod",
6139092a057SMasatake YAMATO 						     podStart, 0,
6149092a057SMasatake YAMATO 						     getInputLineNumber(), 0,
6159092a057SMasatake YAMATO 						     getSourceLineNumber());
6169092a057SMasatake YAMATO 					podStart = 0UL;
6179092a057SMasatake YAMATO 				}
6189092a057SMasatake YAMATO 			}
6193ae02089SMasatake YAMATO 			continue;
6203ae02089SMasatake YAMATO 		}
6213ae02089SMasatake YAMATO 		else if (line [0] == '=')
6223ae02089SMasatake YAMATO 		{
6233ae02089SMasatake YAMATO 			skipPodDoc = isPodWord ((const char*)line + 1);
6249092a057SMasatake YAMATO 			if (skipPodDoc)
625cd677fe6SMasatake YAMATO 			{
6269092a057SMasatake YAMATO 				podStart = getSourceLineNumber ();
627d7ad8c78SMasatake YAMATO 				notifyEnteringPod ();
628cd677fe6SMasatake YAMATO 			}
6293ae02089SMasatake YAMATO 			continue;
6303ae02089SMasatake YAMATO 		}
6313ae02089SMasatake YAMATO 		else if (strcmp ((const char*) line, "__DATA__") == 0)
6323ae02089SMasatake YAMATO 		{
6333ae02089SMasatake YAMATO 			if (respect_token & RESPECT_DATA)
6343b0c2ae1SMasatake YAMATO 			{
6353b0c2ae1SMasatake YAMATO 				if (isXtagEnabled (XTAG_GUEST))
6363b0c2ae1SMasatake YAMATO 					parse_only_pod_area = true;
6373b0c2ae1SMasatake YAMATO 				else
6383ae02089SMasatake YAMATO 					break;
6393b0c2ae1SMasatake YAMATO 			}
6403ae02089SMasatake YAMATO 			else
6413ae02089SMasatake YAMATO 				continue;
6423ae02089SMasatake YAMATO 		}
6433ae02089SMasatake YAMATO 		else if (strcmp ((const char*) line, "__END__") == 0)
6443ae02089SMasatake YAMATO 		{
6453ae02089SMasatake YAMATO 			if (respect_token & RESPECT_END)
6463b0c2ae1SMasatake YAMATO 			{
6473b0c2ae1SMasatake YAMATO 				if (isXtagEnabled (XTAG_GUEST))
6483b0c2ae1SMasatake YAMATO 					parse_only_pod_area = true;
6493b0c2ae1SMasatake YAMATO 				else
6503ae02089SMasatake YAMATO 					break;
6513b0c2ae1SMasatake YAMATO 			}
6523ae02089SMasatake YAMATO 			else
6533ae02089SMasatake YAMATO 				continue;
6543ae02089SMasatake YAMATO 		}
6553ae02089SMasatake YAMATO 		else if (line [0] == '#')
6563ae02089SMasatake YAMATO 			continue;
6573ae02089SMasatake YAMATO 
6583b0c2ae1SMasatake YAMATO 		if (parse_only_pod_area)
6593b0c2ae1SMasatake YAMATO 			continue;
6603b0c2ae1SMasatake YAMATO 
6613ae02089SMasatake YAMATO 		while (isspace (*cp))
6623ae02089SMasatake YAMATO 			cp++;
6633ae02089SMasatake YAMATO 
664*08bf1b99SMasatake YAMATO 		collectHereDocMarkers (&hdoc_mgr, cp);
665*08bf1b99SMasatake YAMATO 
6663ae02089SMasatake YAMATO 		if (strncmp((const char*) cp, "sub", (size_t) 3) == 0)
6673ae02089SMasatake YAMATO 		{
6683ae02089SMasatake YAMATO 			TRACE("this looks like a sub\n");
6693ae02089SMasatake YAMATO 			cp += 3;
670cd677fe6SMasatake YAMATO 			kind = KIND_PERL_SUBROUTINE;
671ce990805SThomas Braun 			spaceRequired = true;
672ce990805SThomas Braun 			qualified = true;
6733ae02089SMasatake YAMATO 		}
6743ae02089SMasatake YAMATO 		else if (strncmp((const char*) cp, "use", (size_t) 3) == 0)
6753ae02089SMasatake YAMATO 		{
6763ae02089SMasatake YAMATO 			cp += 3;
6773ae02089SMasatake YAMATO 			if (!isspace(*cp))
6783ae02089SMasatake YAMATO 				continue;
6793ae02089SMasatake YAMATO 			while (*cp && isspace (*cp))
6803ae02089SMasatake YAMATO 				++cp;
6813ae02089SMasatake YAMATO 			if (strncmp((const char*) cp, "AutoLoader", (size_t) 10) == 0) {
6823ae02089SMasatake YAMATO 				respect_token &= ~RESPECT_END;
683b02a66cdSMasatake YAMATO 				makeTagForModule("AutoLoader", ROLE_PERL_MODULE_USED);
6843ae02089SMasatake YAMATO 				continue;
6853ae02089SMasatake YAMATO 			}
6863ae02089SMasatake YAMATO 			if (strncmp((const char*) cp, "SelfLoader", (size_t) 10) == 0) {
6873ae02089SMasatake YAMATO 				respect_token &= ~RESPECT_DATA;
688b02a66cdSMasatake YAMATO 				makeTagForModule("SelfLoader", ROLE_PERL_MODULE_USED);
6893ae02089SMasatake YAMATO 				continue;
6903ae02089SMasatake YAMATO 			}
691b02a66cdSMasatake YAMATO 
692b02a66cdSMasatake YAMATO 			vString *module = NULL;
693b02a66cdSMasatake YAMATO 			while (isalnum(*cp) || *cp == ':' || *cp == '.') {
694b02a66cdSMasatake YAMATO 				if (!module)
695b02a66cdSMasatake YAMATO 					module = vStringNew();
696b02a66cdSMasatake YAMATO 				vStringPut(module, *cp);
697b02a66cdSMasatake YAMATO 				++cp;
698b02a66cdSMasatake YAMATO 			}
69950c83de6SMasatake YAMATO 			if (!module)
70050c83de6SMasatake YAMATO 				continue;
70150c83de6SMasatake YAMATO 
7025be4c343SMasatake YAMATO 			int q = makeTagForModule(vStringValue(module), ROLE_PERL_MODULE_USED);
70350c83de6SMasatake YAMATO 			bool isConstant = (strcmp(vStringValue(module), "constant") == 0);
704b02a66cdSMasatake YAMATO 			vStringDelete(module);
705b02a66cdSMasatake YAMATO 			if (!isConstant)
7065be4c343SMasatake YAMATO 			{
7075be4c343SMasatake YAMATO 				while (isspace(*cp))
7085be4c343SMasatake YAMATO 					cp++;
7095be4c343SMasatake YAMATO 				if (strncmp("qw", (const char *)cp, 2) != 0)
7103ae02089SMasatake YAMATO 					continue;
7115be4c343SMasatake YAMATO 				cp += 2;
7125be4c343SMasatake YAMATO 				while (isspace(*cp))
7135be4c343SMasatake YAMATO 					cp++;
7145be4c343SMasatake YAMATO 				if (*cp == '\0')
7155be4c343SMasatake YAMATO 					continue;
7165be4c343SMasatake YAMATO 				vStringClear (name);
7175be4c343SMasatake YAMATO 
7185be4c343SMasatake YAMATO 				parseQuotedWords(cp, name, q);
7195be4c343SMasatake YAMATO 				vStringClear (name);
7205be4c343SMasatake YAMATO 				continue;
7215be4c343SMasatake YAMATO 			}
722b02a66cdSMasatake YAMATO 
7233ae02089SMasatake YAMATO 			/* Skip up to the first non-space character, skipping empty
7243ae02089SMasatake YAMATO 			 * and comment lines.
7253ae02089SMasatake YAMATO 			 */
7263ae02089SMasatake YAMATO 			while (isspace(*cp))
7273ae02089SMasatake YAMATO 				cp++;
7283ae02089SMasatake YAMATO 			while (!*cp || '#' == *cp) {
7291b312fe7SMasatake YAMATO 				cp = readLineFromInputFile ();
7303ae02089SMasatake YAMATO 				if (!cp)
7313ae02089SMasatake YAMATO 					goto END_MAIN_WHILE;
7323ae02089SMasatake YAMATO 				while (isspace (*cp))
7333ae02089SMasatake YAMATO 					cp++;
7343ae02089SMasatake YAMATO 			}
7353ae02089SMasatake YAMATO 			if ('{' == *cp) {
7363ae02089SMasatake YAMATO 				++cp;
7373ae02089SMasatake YAMATO 				if (0 == parseConstantsFromHashRef(cp, name, package)) {
7383ae02089SMasatake YAMATO 					vStringClear(name);
7393ae02089SMasatake YAMATO 					continue;
7403ae02089SMasatake YAMATO 				} else
7413ae02089SMasatake YAMATO 					goto END_MAIN_WHILE;
7423ae02089SMasatake YAMATO 			}
743cd677fe6SMasatake YAMATO 			kind = KIND_PERL_CONSTANT;
744ce990805SThomas Braun 			spaceRequired = false;
745ce990805SThomas Braun 			qualified = true;
7463ae02089SMasatake YAMATO 		}
74750c83de6SMasatake YAMATO 		else if (strncmp((const char*) cp, "no", (size_t) 2) == 0 && isspace(cp[2]))
74850c83de6SMasatake YAMATO 		{
74950c83de6SMasatake YAMATO 			cp += 3;
75050c83de6SMasatake YAMATO 			while (isspace (*cp))
75150c83de6SMasatake YAMATO 				cp++;
75250c83de6SMasatake YAMATO 			vString *module = NULL;
75350c83de6SMasatake YAMATO 			while (isalnum(*cp) || *cp == ':' || *cp == '.') {
75450c83de6SMasatake YAMATO 				if (!module)
75550c83de6SMasatake YAMATO 					module = vStringNew();
75650c83de6SMasatake YAMATO 				vStringPut(module, *cp);
75750c83de6SMasatake YAMATO 				++cp;
75850c83de6SMasatake YAMATO 			}
75950c83de6SMasatake YAMATO 			if (module) {
76050c83de6SMasatake YAMATO 				makeTagForModule(vStringValue(module), ROLE_PERL_MODULE_UNUSED);
76150c83de6SMasatake YAMATO 				vStringDelete(module);
76250c83de6SMasatake YAMATO 			}
76350c83de6SMasatake YAMATO 			continue;
76450c83de6SMasatake YAMATO 		}
7653ae02089SMasatake YAMATO 		else if (strncmp((const char*) cp, "package", (size_t) 7) == 0 &&
7663ae02089SMasatake YAMATO 				 ('\0' == cp[7] || isspace(cp[7])))
7673ae02089SMasatake YAMATO 		{
768d95a4d7cSDmitri Tikhonov 			cp += 7;
7693ae02089SMasatake YAMATO 			while (isspace (*cp))
7703ae02089SMasatake YAMATO 				cp++;
7713ae02089SMasatake YAMATO 			while (!*cp || '#' == *cp) {
7721b312fe7SMasatake YAMATO 				cp = readLineFromInputFile ();
7733ae02089SMasatake YAMATO 				if (!cp)
7743ae02089SMasatake YAMATO 					goto END_MAIN_WHILE;
7753ae02089SMasatake YAMATO 				while (isspace (*cp))
7763ae02089SMasatake YAMATO 					cp++;
7773ae02089SMasatake YAMATO 			}
7783ae02089SMasatake YAMATO 			if (package == NULL)
7793ae02089SMasatake YAMATO 				package = vStringNew ();
7803ae02089SMasatake YAMATO 			else
7813ae02089SMasatake YAMATO 				vStringClear (package);
7823ae02089SMasatake YAMATO 			const unsigned char *const first = cp;
7833ae02089SMasatake YAMATO 			while (*cp && (int) *cp != ';'  &&  !isspace ((int) *cp))
7843ae02089SMasatake YAMATO 			{
7853ae02089SMasatake YAMATO 				vStringPut (package, (int) *cp);
7863ae02089SMasatake YAMATO 				cp++;
7873ae02089SMasatake YAMATO 			}
7883ae02089SMasatake YAMATO 			vStringCatS (package, "::");
7893ae02089SMasatake YAMATO 
7903ae02089SMasatake YAMATO 			cp = first;	 /* Rewind */
791cd677fe6SMasatake YAMATO 			kind = KIND_PERL_PACKAGE;
792ce990805SThomas Braun 			spaceRequired = false;
793ce990805SThomas Braun 			qualified = true;
7943ae02089SMasatake YAMATO 		}
7953ae02089SMasatake YAMATO 		else if (strncmp((const char*) cp, "format", (size_t) 6) == 0)
7963ae02089SMasatake YAMATO 		{
7973ae02089SMasatake YAMATO 			cp += 6;
798cd677fe6SMasatake YAMATO 			kind = KIND_PERL_FORMAT;
799ce990805SThomas Braun 			spaceRequired = true;
800ce990805SThomas Braun 			qualified = true;
8013ae02089SMasatake YAMATO 		}
8023ae02089SMasatake YAMATO 		else
8033ae02089SMasatake YAMATO 		{
8043ae02089SMasatake YAMATO 			if (isIdentifier1 (*cp))
8053ae02089SMasatake YAMATO 			{
8063ae02089SMasatake YAMATO 				const unsigned char *p = cp;
8073ae02089SMasatake YAMATO 				while (isIdentifier (*p))
8083ae02089SMasatake YAMATO 					++p;
8093ae02089SMasatake YAMATO 				while (isspace (*p))
8103ae02089SMasatake YAMATO 					++p;
8113ae02089SMasatake YAMATO 				if ((int) *p == ':' && (int) *(p + 1) != ':')
812cd677fe6SMasatake YAMATO 					kind = KIND_PERL_LABEL;
8133ae02089SMasatake YAMATO 			}
8143ae02089SMasatake YAMATO 		}
815cd677fe6SMasatake YAMATO 		if (kind != KIND_PERL_NONE)
8163ae02089SMasatake YAMATO 		{
8173ae02089SMasatake YAMATO 			TRACE("cp0: %s\n", (const char *) cp);
8183ae02089SMasatake YAMATO 			if (spaceRequired && *cp && !isspace (*cp))
8193ae02089SMasatake YAMATO 				continue;
8203ae02089SMasatake YAMATO 
8213ae02089SMasatake YAMATO 			TRACE("cp1: %s\n", (const char *) cp);
8223ae02089SMasatake YAMATO 			while (isspace (*cp))
8233ae02089SMasatake YAMATO 				cp++;
8243ae02089SMasatake YAMATO 
8253ae02089SMasatake YAMATO 			while (!*cp || '#' == *cp) { /* Gobble up empty lines
8263ae02089SMasatake YAMATO 				                            and comments */
8271b312fe7SMasatake YAMATO 				cp = readLineFromInputFile ();
8283ae02089SMasatake YAMATO 				if (!cp)
8293ae02089SMasatake YAMATO 					goto END_MAIN_WHILE;
8303ae02089SMasatake YAMATO 				while (isspace (*cp))
8313ae02089SMasatake YAMATO 					cp++;
8323ae02089SMasatake YAMATO 			}
8333ae02089SMasatake YAMATO 
834cd677fe6SMasatake YAMATO 			while (isIdentifier (*cp) || (KIND_PERL_PACKAGE == kind && ':' == *cp))
8353ae02089SMasatake YAMATO 			{
8363ae02089SMasatake YAMATO 				vStringPut (name, (int) *cp);
8373ae02089SMasatake YAMATO 				cp++;
8383ae02089SMasatake YAMATO 			}
8393ae02089SMasatake YAMATO 
840cd677fe6SMasatake YAMATO 			if (KIND_PERL_FORMAT == kind &&
8413ae02089SMasatake YAMATO 				vStringLength (name) == 0 && /* cp did not advance */
8423ae02089SMasatake YAMATO 				'=' == *cp)
8433ae02089SMasatake YAMATO 			{
8443ae02089SMasatake YAMATO 				/* format's name is optional.  If it's omitted, 'STDOUT'
8453ae02089SMasatake YAMATO 				   is assumed. */
8463ae02089SMasatake YAMATO 				vStringCatS (name, "STDOUT");
8473ae02089SMasatake YAMATO 			}
8483ae02089SMasatake YAMATO 
849e852ee0eSMasatake YAMATO 			TRACE("name: %s\n", vStringValue (name));
8503ae02089SMasatake YAMATO 
8513ae02089SMasatake YAMATO 			if (0 == vStringLength(name)) {
8523ae02089SMasatake YAMATO 				vStringClear(name);
8533ae02089SMasatake YAMATO 				continue;
8543ae02089SMasatake YAMATO 			}
8553ae02089SMasatake YAMATO 
856cd677fe6SMasatake YAMATO 			if (KIND_PERL_SUBROUTINE == kind)
8573ae02089SMasatake YAMATO 			{
8583ae02089SMasatake YAMATO 				/*
8593ae02089SMasatake YAMATO 				 * isSubroutineDeclaration() may consume several lines.  So
8603ae02089SMasatake YAMATO 				 * we record line positions.
8613ae02089SMasatake YAMATO 				 */
86216a2541cSMasatake YAMATO 				initTagEntry(&e, vStringValue(name), KIND_GHOST_INDEX);
8633ae02089SMasatake YAMATO 
864ce990805SThomas Braun 				if (true == isSubroutineDeclaration(cp)) {
865cd677fe6SMasatake YAMATO 					if (true == PerlKinds[KIND_PERL_SUBROUTINE_DECLARATION].enabled) {
866cd677fe6SMasatake YAMATO 						kind = KIND_PERL_SUBROUTINE_DECLARATION;
8673ae02089SMasatake YAMATO 					} else {
8683ae02089SMasatake YAMATO 						vStringClear (name);
8693ae02089SMasatake YAMATO 						continue;
8703ae02089SMasatake YAMATO 					}
8714a95e4a5SColomban Wendling 				} else if (! PerlKinds[kind].enabled) {
8724a95e4a5SColomban Wendling 					continue;
8733ae02089SMasatake YAMATO 				}
8743ae02089SMasatake YAMATO 
875f92e6bf2SMasatake YAMATO 				e.kindIndex = kind;
8763ae02089SMasatake YAMATO 
8773ae02089SMasatake YAMATO 				makeTagEntry(&e);
8783ae02089SMasatake YAMATO 
87935c59e96SMasatake YAMATO 				if (isXtagEnabled (XTAG_QUALIFIED_TAGS) && qualified &&
8803ae02089SMasatake YAMATO 					package != NULL  && vStringLength (package) > 0)
8813ae02089SMasatake YAMATO 				{
8823ae02089SMasatake YAMATO 					vString *const qualifiedName = vStringNew ();
8833ae02089SMasatake YAMATO 					vStringCopy (qualifiedName, package);
8843ae02089SMasatake YAMATO 					vStringCat (qualifiedName, name);
8853ae02089SMasatake YAMATO 					e.name = vStringValue(qualifiedName);
8865022e63aSMasatake YAMATO 					markTagExtraBit (&e, XTAG_QUALIFIED_TAGS);
8873ae02089SMasatake YAMATO 					makeTagEntry(&e);
8883ae02089SMasatake YAMATO 					vStringDelete (qualifiedName);
8893ae02089SMasatake YAMATO 				}
8903ae02089SMasatake YAMATO 			} else if (vStringLength (name) > 0)
8913ae02089SMasatake YAMATO 			{
89216a2541cSMasatake YAMATO 				makeSimpleTag (name, kind);
89335c59e96SMasatake YAMATO 				if (isXtagEnabled(XTAG_QUALIFIED_TAGS) && qualified &&
894cd677fe6SMasatake YAMATO 					KIND_PERL_PACKAGE != kind &&
8953ae02089SMasatake YAMATO 					package != NULL  && vStringLength (package) > 0)
8963ae02089SMasatake YAMATO 				{
8975022e63aSMasatake YAMATO 					tagEntryInfo fqe;
8983ae02089SMasatake YAMATO 					vString *const qualifiedName = vStringNew ();
8993ae02089SMasatake YAMATO 					vStringCopy (qualifiedName, package);
9003ae02089SMasatake YAMATO 					vStringCat (qualifiedName, name);
90116a2541cSMasatake YAMATO 					initTagEntry (&fqe, vStringValue (qualifiedName), kind);
9025022e63aSMasatake YAMATO 					markTagExtraBit (&fqe, XTAG_QUALIFIED_TAGS);
903ee6261abSMasatake YAMATO 					makeTagEntry (&fqe);
9043ae02089SMasatake YAMATO 					vStringDelete (qualifiedName);
9053ae02089SMasatake YAMATO 				}
9063ae02089SMasatake YAMATO 			}
9073ae02089SMasatake YAMATO 			vStringClear (name);
9083ae02089SMasatake YAMATO 		}
9093ae02089SMasatake YAMATO 	}
9103ae02089SMasatake YAMATO 
9113ae02089SMasatake YAMATO END_MAIN_WHILE:
9123ae02089SMasatake YAMATO 	vStringDelete (name);
913*08bf1b99SMasatake YAMATO 	finiHereDocMarkerManager (&hdoc_mgr);
9143ae02089SMasatake YAMATO 	if (package != NULL)
9153ae02089SMasatake YAMATO 		vStringDelete (package);
9163ae02089SMasatake YAMATO }
9173ae02089SMasatake YAMATO 
PerlParser(void)9183ae02089SMasatake YAMATO extern parserDefinition* PerlParser (void)
9193ae02089SMasatake YAMATO {
92029aa5086SYura Mikhel 	static const char *const extensions [] = { "pl", "pm", "ph", "plx", "perl", NULL };
921785a3ec8SMasatake YAMATO 	static const char *const aliases [] = {
922785a3ec8SMasatake YAMATO 		/* cperl is an Emacs' editing mode for Perl source code  */
923785a3ec8SMasatake YAMATO 		"cperl",
924785a3ec8SMasatake YAMATO 		NULL };
9255a38b5ceSMasatake YAMATO 	static selectLanguage selectors [] = { selectByPickingPerlVersion,
9265a38b5ceSMasatake YAMATO 					       NULL };
9273ae02089SMasatake YAMATO 	parserDefinition* def = parserNew ("Perl");
92809ae690fSMasatake YAMATO 	def->kindTable      = PerlKinds;
9293db72c21SMasatake YAMATO 	def->kindCount  = ARRAY_SIZE (PerlKinds);
9303ae02089SMasatake YAMATO 	def->extensions = extensions;
9313ae02089SMasatake YAMATO 	def->parser     = findPerlTags;
9325a38b5ceSMasatake YAMATO 	def->selectLanguage = selectors;
933785a3ec8SMasatake YAMATO 	def->aliases    = aliases;
934cd677fe6SMasatake YAMATO 
935cd677fe6SMasatake YAMATO 	/* Subparsers need this */
9366b1a862eSMasatake YAMATO 	def->useCork = CORK_QUEUE;
937cd677fe6SMasatake YAMATO 
9383ae02089SMasatake YAMATO 	return def;
9393ae02089SMasatake YAMATO }
940