2 * Copyright (c) 2001-2002, 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 the Pascal language,
8 * including some extensions for Object Pascal.
14 #include "general.h" /* must always come first */
28 K_FUNCTION
, K_PROCEDURE
31 static kindDefinition PascalKinds
[] = {
32 { true, 'f', "function", "functions"},
33 { true, 'p', "procedure", "procedures"}
37 * FUNCTION DEFINITIONS
40 static void createPascalTag (
41 tagEntryInfo
* const tag
, const vString
* const name
, const int kind
,
42 const vString
*arglist
, const vString
*vartype
)
44 if (PascalKinds
[kind
].enabled
&& name
!= NULL
&& vStringLength (name
) > 0)
46 initTagEntry (tag
, vStringValue (name
), kind
);
47 if (arglist
&& !vStringIsEmpty (arglist
))
49 tag
->extensionFields
.signature
= vStringValue (arglist
);
51 if (vartype
&& !vStringIsEmpty (vartype
))
53 tag
->extensionFields
.typeRef
[0] = "typename";
54 tag
->extensionFields
.typeRef
[1] = vStringValue (vartype
);
58 /* TODO: Passing NULL as name makes an assertion behind initTagEntry failure */
59 initTagEntry (tag
, NULL
, KIND_GHOST_INDEX
);
62 static void makePascalTag (const tagEntryInfo
* const tag
)
64 if (tag
->name
!= NULL
)
68 static const unsigned char* dbp
;
70 #define starttoken(c) (isalpha ((unsigned char) c) || (int) c == '_')
71 #define intoken(c) (isalnum ((unsigned char) c) || (int) c == '_' || (int) c == '.')
72 #define endtoken(c) (! intoken (c) && ! isdigit ((unsigned char) c))
74 static bool tail (const char *cp
)
79 while (*cp
!= '\0' && tolower ((unsigned char) *cp
) == tolower (dbp
[len
]))
81 if (*cp
== '\0' && !intoken (dbp
[len
]))
89 static void parseArglist (const char *buf
, vString
*arglist
, vString
*vartype
)
91 const char *start
, *end
;
94 if (NULL
== buf
|| arglist
== NULL
)
97 /* parse argument list which can be missing like in "function ginit:integer;" */
98 if (NULL
!= (start
= strchr (buf
, '(')))
100 for (level
= 1, end
= start
+ 1; level
> 0; ++end
)
104 else if ('(' == *end
)
106 else if (')' == *end
)
110 else /* if no argument list was found, continue looking for a return value */
116 /* parse return type if requested by passing a non-NULL vartype argument */
119 char *var
, *var_start
;
121 if (NULL
!= (var
= strchr (end
, ':')))
123 var
++; /* skip ':' */
124 while (isspace ((unsigned char) *var
))
127 if (starttoken (*var
))
131 while (intoken (*var
))
135 vStringNCatS (vartype
, var_start
, var
- var_start
);
141 if (NULL
== start
) /* no argument list */
142 vStringCatS (arglist
, "()");
144 vStringNCatS (arglist
, start
, end
- start
);
147 /* Algorithm adapted from from GNU etags.
148 * Locates tags for procedures & functions. Doesn't do any type- or
149 * var-definitions. It does look for the keyword "extern" or "forward"
150 * immediately following the procedure statement; if found, the tag is
153 static void findPascalTags (void)
155 vString
*name
= vStringNew ();
156 vString
*arglist
= vStringNew ();
157 vString
*vartype
= vStringNew ();
159 pascalKind kind
= K_FUNCTION
;
160 /* each of these flags is true iff: */
161 bool incomment
= false; /* point is inside a comment */
162 int comment_char
= '\0'; /* type of current comment */
163 bool inquote
= false; /* point is inside '..' string */
164 bool get_tagname
= false;/* point is after PROCEDURE/FUNCTION
165 keyword, so next item = potential tag */
166 bool found_tag
= false; /* point is after a potential tag */
167 bool inparms
= false; /* point is within parameter-list */
168 bool verify_tag
= false;
169 /* point has passed the parm-list, so the next token will determine
170 * whether this is a FORWARD/EXTERN to be ignored, or whether it is a
174 dbp
= readLineFromInputFile ();
179 if (c
== '\0') /* if end of line */
181 if (incomment
&& comment_char
== '/')
184 dbp
= readLineFromInputFile ();
185 if (dbp
== NULL
|| *dbp
== '\0')
187 if (!((found_tag
&& verify_tag
) || get_tagname
))
189 /* only if don't need *dbp pointing to the beginning of
190 * the name of the procedure or function
195 if (comment_char
== '{' && c
== '}')
197 else if (comment_char
== '(' && c
== '*' && *dbp
== ')')
213 inquote
= true; /* found first quote */
215 case '{': /* found open { comment */
220 if (*dbp
== '/') /* found one line // comment */
228 if (*dbp
== '*') /* found open (* comment */
234 else if (found_tag
) /* found '(' after tag, i.e., parm-list */
237 case ')': /* end of parms list */
242 if (found_tag
&& !inparms
) /* end of proc or fn stmt */
249 if (found_tag
&& verify_tag
&& *dbp
!= ' ')
251 /* check if this is an "extern" declaration */
254 if (tolower (*dbp
== 'e'))
256 if (tail ("extern")) /* superfluous, really! */
262 else if (tolower (*dbp
) == 'f')
264 if (tail ("forward")) /* check for forward reference */
270 if (found_tag
&& verify_tag
) /* not external proc, so make tag */
274 makePascalTag (&tag
);
278 if (get_tagname
) /* grab name of proc or fn */
280 const unsigned char *cp
;
285 /* grab block name */
286 while (isspace (*dbp
))
288 if (!starttoken(*dbp
))
290 for (cp
= dbp
; *cp
!= '\0' && !endtoken (*cp
) ; cp
++)
292 vStringNCopyS (name
, (const char*) dbp
, cp
- dbp
);
294 vStringClear (arglist
);
295 vStringClear (vartype
);
296 parseArglist ((const char*) cp
, arglist
, (kind
== K_FUNCTION
) ? vartype
: NULL
);
298 createPascalTag (&tag
, name
, kind
, arglist
, (kind
== K_FUNCTION
) ? vartype
: NULL
);
299 dbp
= cp
; /* set dbp to e-o-token */
302 /* and proceed to check for "extern" */
304 else if (!incomment
&& !inquote
&& !found_tag
)
309 if (tail ("onstructor"))
316 if (tail ("estructor"))
323 if (tail ("rocedure"))
330 if (tail ("unction"))
337 } /* while not eof */
339 vStringDelete (arglist
);
340 vStringDelete (vartype
);
341 vStringDelete (name
);
344 extern parserDefinition
* PascalParser (void)
346 static const char *const extensions
[] = { "p", "pas", NULL
};
347 parserDefinition
* def
= parserNew ("Pascal");
348 def
->extensions
= extensions
;
349 def
->kindTable
= PascalKinds
;
350 def
->kindCount
= ARRAY_SIZE (PascalKinds
);
351 def
->parser
= findPascalTags
;