2 * Copyright (c) 2000-2005, Darren Hiebert
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * This module contains functions for generating tags for makefiles.
13 #include "general.h" /* must always come first */
33 K_MACRO
, K_TARGET
, K_INCLUDE
,
41 static roleDefinition MakeMakefileRoles
[] = {
42 { true, "included", "included" },
43 { true, "optional", "optionally included"},
46 static kindDefinition MakeKinds
[] = {
47 { true, 'm', "macro", "macros"},
48 { true, 't', "target", "targets"},
49 { true, 'I', "makefile", "makefiles",
50 .referenceOnly
= true, ATTACH_ROLES(MakeMakefileRoles
)},
55 * FUNCTION DEFINITIONS
58 static int nextChar (void)
60 int c
= getcFromInputFile ();
63 c
= getcFromInputFile ();
70 static void skipLine (void)
75 while (c
!= EOF
&& c
!= '\n');
77 ungetcToInputFile (c
);
80 static int skipToNonWhite (int c
)
82 while (c
!= '\n' && isspace (c
))
87 static bool isIdentifier (int c
)
89 return (bool)(c
!= '\0' && (isalnum (c
) || strchr (".-_/$(){}%", c
) != NULL
));
92 static bool isSpecialTarget (vString
*const name
)
95 /* All special targets begin with '.'. */
96 if (vStringLength (name
) < 1 || vStringChar (name
, i
++) != '.') {
99 while (i
< vStringLength (name
)) {
100 char ch
= vStringChar (name
, i
++);
101 if (ch
!= '_' && !isupper (ch
))
109 static void makeSimpleMakeTag (vString
*const name
, makeKind kind
)
111 if (!isLanguageEnabled (getInputLanguage ()))
114 makeSimpleTag (name
, kind
);
117 static void makeSimpleMakeRefTag (const vString
* const name
, const int kind
,
120 if (!isLanguageEnabled (getInputLanguage ()))
123 makeSimpleRefTag (name
, kind
, roleIndex
);
126 static void newTarget (vString
*const name
)
128 /* Ignore GNU Make's "special targets". */
129 if (isSpecialTarget (name
))
133 makeSimpleMakeTag (name
, K_TARGET
);
136 static void newMacro (vString
*const name
, bool with_define_directive
, bool appending
)
141 makeSimpleMakeTag (name
, K_MACRO
);
143 foreachSubparser(s
, false)
145 makeSubparser
*m
= (makeSubparser
*)s
;
147 if (m
->newMacroNotify
)
148 m
->newMacroNotify (m
, vStringValue(name
), with_define_directive
, appending
);
153 static void valueFound (vString
*const name
)
156 foreachSubparser(s
, false)
158 makeSubparser
*m
= (makeSubparser
*)s
;
161 m
->valueNotify (m
, vStringValue (name
));
166 static void directiveFound (vString
*const name
)
169 foreachSubparser (s
, false)
171 makeSubparser
*m
= (makeSubparser
*)s
;
173 if (m
->directiveNotify
)
174 m
->directiveNotify (m
, vStringValue (name
));
179 static void newInclude (vString
*const name
, bool optional
)
181 makeSimpleMakeRefTag (name
, K_INCLUDE
,
182 optional
? R_INCLUDE_OPTIONAL
: R_INCLUDE_GENERIC
);
185 static bool isAcceptableAsInclude (vString
*const name
)
187 if (strcmp (vStringValue (name
), "$") == 0)
192 static void readIdentifier (const int first
, vString
*const id
)
197 while (isIdentifier (c
) || (depth
> 0 && c
!= EOF
&& c
!= '\n'))
199 if (c
== '(' || c
== '{')
201 else if (depth
> 0 && (c
== ')' || c
== '}'))
206 ungetcToInputFile (c
);
209 static void findMakeTags (void)
211 stringList
*identifiers
= stringListNew ();
213 bool in_define
= false;
214 bool in_value
= false;
215 bool in_rule
= false;
216 bool variable_possible
= true;
217 bool appending
= false;
221 sub
= getSubparserRunningBaseparser();
223 chooseExclusiveSubparser (sub
, NULL
);
225 while ((c
= nextChar ()) != EOF
)
231 if (c
== '\t' || (c
= skipToNonWhite (c
)) == '#')
233 skipLine (); /* skip rule or comment */
242 stringListClear (identifiers
);
243 variable_possible
= (bool)(!in_rule
);
248 else if (isspace (c
))
252 else if (variable_possible
&& c
== '?')
255 ungetcToInputFile (c
);
256 variable_possible
= (c
== '=');
258 else if (variable_possible
&& c
== '+')
261 ungetcToInputFile (c
);
262 variable_possible
= (c
== '=');
265 else if ((! in_value
) && variable_possible
&& c
== ':' &&
266 stringListCount (identifiers
) > 0)
269 ungetcToInputFile (c
);
273 for (i
= 0; i
< stringListCount (identifiers
); i
++)
274 newTarget (stringListItem (identifiers
, i
));
275 stringListClear (identifiers
);
279 else if (variable_possible
&& c
== '=' &&
280 stringListCount (identifiers
) == 1)
282 newMacro (stringListItem (identifiers
, 0), false, appending
);
288 else if (variable_possible
&& isIdentifier (c
))
290 vString
*name
= vStringNew ();
291 readIdentifier (c
, name
);
292 stringListAdd (identifiers
, name
);
297 if (stringListCount (identifiers
) == 1)
299 if (in_define
&& ! strcmp (vStringValue (name
), "endef"))
303 else if (! strcmp (vStringValue (name
), "define"))
306 c
= skipToNonWhite (nextChar ());
308 /* all remaining characters on the line are the name -- even spaces */
309 while (c
!= EOF
&& c
!= '\n')
311 vStringPut (name
, c
);
315 ungetcToInputFile (c
);
316 vStringStripTrailing (name
);
318 newMacro (name
, true, false);
320 else if (! strcmp (vStringValue (name
), "export"))
321 stringListClear (identifiers
);
322 else if (! strcmp (vStringValue (name
), "include")
323 || ! strcmp (vStringValue (name
), "sinclude")
324 || ! strcmp (vStringValue (name
), "-include"))
326 bool optional
= (vStringValue (name
)[0] == 'i')? false: true;
329 c
= skipToNonWhite (nextChar ());
330 readIdentifier (c
, name
);
331 vStringStripTrailing (name
);
332 if (isAcceptableAsInclude(name
))
333 newInclude (name
, optional
);
335 /* non-space characters after readIdentifier() may
336 * be rejected by the function:
340 * Here, remove such characters from input stream.
344 while (c
!= EOF
&& c
!= '\n' && (!isspace (c
)));
346 ungetcToInputFile (c
);
348 if (c
== EOF
|| c
== '\n')
353 directiveFound (name
);
357 variable_possible
= false;
360 stringListDelete (identifiers
);
364 extern parserDefinition
* MakefileParser (void)
366 static const char *const patterns
[] = { "[Mm]akefile", "GNUmakefile", NULL
};
367 static const char *const extensions
[] = { "mak", "mk", NULL
};
368 static const char *const aliases
[] = {
369 /* the mode name in emacs */
372 parserDefinition
* const def
= parserNew ("Make");
373 def
->kindTable
= MakeKinds
;
374 def
->kindCount
= ARRAY_SIZE (MakeKinds
);
375 def
->patterns
= patterns
;
376 def
->extensions
= extensions
;
377 def
->aliases
= aliases
;
378 def
->parser
= findMakeTags
;