13ae02089SMasatake YAMATO /*
23ae02089SMasatake YAMATO * Copyright (c) 2001-2002, 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 the Pascal language,
83ae02089SMasatake YAMATO * including some extensions for Object Pascal.
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"
193ae02089SMasatake YAMATO #include "parse.h"
203ae02089SMasatake YAMATO #include "read.h"
213db72c21SMasatake YAMATO #include "routines.h"
223ae02089SMasatake YAMATO #include "vstring.h"
233ae02089SMasatake YAMATO
243ae02089SMasatake YAMATO /*
253ae02089SMasatake YAMATO * DATA DEFINITIONS
263ae02089SMasatake YAMATO */
273ae02089SMasatake YAMATO typedef enum {
283ae02089SMasatake YAMATO K_FUNCTION, K_PROCEDURE
293ae02089SMasatake YAMATO } pascalKind;
303ae02089SMasatake YAMATO
31e112e8abSMasatake YAMATO static kindDefinition PascalKinds [] = {
32ce990805SThomas Braun { true, 'f', "function", "functions"},
33ce990805SThomas Braun { true, 'p', "procedure", "procedures"}
343ae02089SMasatake YAMATO };
353ae02089SMasatake YAMATO
363ae02089SMasatake YAMATO /*
373ae02089SMasatake YAMATO * FUNCTION DEFINITIONS
383ae02089SMasatake YAMATO */
393ae02089SMasatake YAMATO
createPascalTag(tagEntryInfo * const tag,const vString * const name,const int kind,const vString * arglist,const vString * vartype)403ae02089SMasatake YAMATO static void createPascalTag (
41bd605841SEnrico Tröger tagEntryInfo* const tag, const vString* const name, const int kind,
42bd605841SEnrico Tröger const vString *arglist, const vString *vartype)
433ae02089SMasatake YAMATO {
443ae02089SMasatake YAMATO if (PascalKinds [kind].enabled && name != NULL && vStringLength (name) > 0)
45bd605841SEnrico Tröger {
4616a2541cSMasatake YAMATO initTagEntry (tag, vStringValue (name), kind);
4786795b57SMasatake YAMATO if (arglist && !vStringIsEmpty (arglist))
48bd605841SEnrico Tröger {
49bd605841SEnrico Tröger tag->extensionFields.signature = vStringValue (arglist);
50bd605841SEnrico Tröger }
51bd605841SEnrico Tröger if (vartype && !vStringIsEmpty (vartype))
52bd605841SEnrico Tröger {
53bd605841SEnrico Tröger tag->extensionFields.typeRef[0] = "typename";
54bd605841SEnrico Tröger tag->extensionFields.typeRef[1] = vStringValue (vartype);
55bd605841SEnrico Tröger }
56bd605841SEnrico Tröger }
573ae02089SMasatake YAMATO else
5898392b01SMasatake YAMATO /* TODO: Passing NULL as name makes an assertion behind initTagEntry failure */
5916a2541cSMasatake YAMATO initTagEntry (tag, NULL, KIND_GHOST_INDEX);
603ae02089SMasatake YAMATO }
613ae02089SMasatake YAMATO
makePascalTag(const tagEntryInfo * const tag)623ae02089SMasatake YAMATO static void makePascalTag (const tagEntryInfo* const tag)
633ae02089SMasatake YAMATO {
643ae02089SMasatake YAMATO if (tag->name != NULL)
653ae02089SMasatake YAMATO makeTagEntry (tag);
663ae02089SMasatake YAMATO }
673ae02089SMasatake YAMATO
683ae02089SMasatake YAMATO static const unsigned char* dbp;
693ae02089SMasatake YAMATO
703ae02089SMasatake YAMATO #define starttoken(c) (isalpha ((int) c) || (int) c == '_')
713ae02089SMasatake YAMATO #define intoken(c) (isalnum ((int) c) || (int) c == '_' || (int) c == '.')
723ae02089SMasatake YAMATO #define endtoken(c) (! intoken (c) && ! isdigit ((int) c))
733ae02089SMasatake YAMATO
tail(const char * cp)74ce990805SThomas Braun static bool tail (const char *cp)
753ae02089SMasatake YAMATO {
76ce990805SThomas Braun bool result = false;
773ae02089SMasatake YAMATO register int len = 0;
783ae02089SMasatake YAMATO
793ae02089SMasatake YAMATO while (*cp != '\0' && tolower ((int) *cp) == tolower ((int) dbp [len]))
803ae02089SMasatake YAMATO cp++, len++;
813ae02089SMasatake YAMATO if (*cp == '\0' && !intoken (dbp [len]))
823ae02089SMasatake YAMATO {
833ae02089SMasatake YAMATO dbp += len;
84ce990805SThomas Braun result = true;
853ae02089SMasatake YAMATO }
863ae02089SMasatake YAMATO return result;
873ae02089SMasatake YAMATO }
883ae02089SMasatake YAMATO
parseArglist(const char * buf,vString * arglist,vString * vartype)89bd605841SEnrico Tröger static void parseArglist (const char *buf, vString *arglist, vString *vartype)
90bd605841SEnrico Tröger {
91bd605841SEnrico Tröger const char *start, *end;
92bd605841SEnrico Tröger int level;
93bd605841SEnrico Tröger
94bd605841SEnrico Tröger if (NULL == buf || arglist == NULL)
95bd605841SEnrico Tröger return;
96bd605841SEnrico Tröger
97bd605841SEnrico Tröger /* parse argument list which can be missing like in "function ginit:integer;" */
98bd605841SEnrico Tröger if (NULL != (start = strchr (buf, '(')))
99bd605841SEnrico Tröger {
100bd605841SEnrico Tröger for (level = 1, end = start + 1; level > 0; ++end)
101bd605841SEnrico Tröger {
102bd605841SEnrico Tröger if ('\0' == *end)
103bd605841SEnrico Tröger break;
104bd605841SEnrico Tröger else if ('(' == *end)
105bd605841SEnrico Tröger ++ level;
106bd605841SEnrico Tröger else if (')' == *end)
107bd605841SEnrico Tröger -- level;
108bd605841SEnrico Tröger }
109bd605841SEnrico Tröger }
110bd605841SEnrico Tröger else /* if no argument list was found, continue looking for a return value */
111bd605841SEnrico Tröger {
112bd605841SEnrico Tröger start = NULL;
113bd605841SEnrico Tröger end = buf;
114bd605841SEnrico Tröger }
115bd605841SEnrico Tröger
116bd605841SEnrico Tröger /* parse return type if requested by passing a non-NULL vartype argument */
117bd605841SEnrico Tröger if (NULL != vartype)
118bd605841SEnrico Tröger {
119bd605841SEnrico Tröger char *var, *var_start;
120bd605841SEnrico Tröger
121bd605841SEnrico Tröger if (NULL != (var = strchr (end, ':')))
122bd605841SEnrico Tröger {
123bd605841SEnrico Tröger var++; /* skip ':' */
124bd605841SEnrico Tröger while (isspace ((int) *var))
125bd605841SEnrico Tröger ++var;
126bd605841SEnrico Tröger
127bd605841SEnrico Tröger if (starttoken (*var))
128bd605841SEnrico Tröger {
129bd605841SEnrico Tröger var_start = var;
130bd605841SEnrico Tröger var++;
131bd605841SEnrico Tröger while (intoken (*var))
132bd605841SEnrico Tröger var++;
133bd605841SEnrico Tröger if (endtoken (*var))
134bd605841SEnrico Tröger {
135bd605841SEnrico Tröger vStringNCatS (vartype, var_start, var - var_start);
136bd605841SEnrico Tröger }
137bd605841SEnrico Tröger }
138bd605841SEnrico Tröger }
139bd605841SEnrico Tröger }
140bd605841SEnrico Tröger
141bd605841SEnrico Tröger if (NULL == start) /* no argument list */
142bd605841SEnrico Tröger vStringCatS (arglist, "()");
143bd605841SEnrico Tröger else
144bd605841SEnrico Tröger vStringNCatS (arglist, start, end - start);
145bd605841SEnrico Tröger }
146bd605841SEnrico Tröger
1473ae02089SMasatake YAMATO /* Algorithm adapted from from GNU etags.
1483ae02089SMasatake YAMATO * Locates tags for procedures & functions. Doesn't do any type- or
1493ae02089SMasatake YAMATO * var-definitions. It does look for the keyword "extern" or "forward"
1503ae02089SMasatake YAMATO * immediately following the procedure statement; if found, the tag is
1513ae02089SMasatake YAMATO * skipped.
1523ae02089SMasatake YAMATO */
findPascalTags(void)1533ae02089SMasatake YAMATO static void findPascalTags (void)
1543ae02089SMasatake YAMATO {
1553ae02089SMasatake YAMATO vString *name = vStringNew ();
156bd605841SEnrico Tröger vString *arglist = vStringNew ();
157bd605841SEnrico Tröger vString *vartype = vStringNew ();
1583ae02089SMasatake YAMATO tagEntryInfo tag;
1593ae02089SMasatake YAMATO pascalKind kind = K_FUNCTION;
160ce990805SThomas Braun /* each of these flags is true iff: */
161ce990805SThomas Braun bool incomment = false; /* point is inside a comment */
1623ae02089SMasatake YAMATO int comment_char = '\0'; /* type of current comment */
163ce990805SThomas Braun bool inquote = false; /* point is inside '..' string */
164ce990805SThomas Braun bool get_tagname = false;/* point is after PROCEDURE/FUNCTION
1653ae02089SMasatake YAMATO keyword, so next item = potential tag */
166ce990805SThomas Braun bool found_tag = false; /* point is after a potential tag */
167ce990805SThomas Braun bool inparms = false; /* point is within parameter-list */
168ce990805SThomas Braun bool verify_tag = false;
1693ae02089SMasatake YAMATO /* point has passed the parm-list, so the next token will determine
1703ae02089SMasatake YAMATO * whether this is a FORWARD/EXTERN to be ignored, or whether it is a
1713ae02089SMasatake YAMATO * real tag
1723ae02089SMasatake YAMATO */
1733ae02089SMasatake YAMATO
1741b312fe7SMasatake YAMATO dbp = readLineFromInputFile ();
1753ae02089SMasatake YAMATO while (dbp != NULL)
1763ae02089SMasatake YAMATO {
1773ae02089SMasatake YAMATO int c = *dbp++;
1783ae02089SMasatake YAMATO
1793ae02089SMasatake YAMATO if (c == '\0') /* if end of line */
1803ae02089SMasatake YAMATO {
1811b312fe7SMasatake YAMATO dbp = readLineFromInputFile ();
1823ae02089SMasatake YAMATO if (dbp == NULL || *dbp == '\0')
1833ae02089SMasatake YAMATO continue;
1843ae02089SMasatake YAMATO if (!((found_tag && verify_tag) || get_tagname))
1853ae02089SMasatake YAMATO c = *dbp++;
1863ae02089SMasatake YAMATO /* only if don't need *dbp pointing to the beginning of
1873ae02089SMasatake YAMATO * the name of the procedure or function
1883ae02089SMasatake YAMATO */
1893ae02089SMasatake YAMATO }
1903ae02089SMasatake YAMATO if (incomment)
1913ae02089SMasatake YAMATO {
1923ae02089SMasatake YAMATO if (comment_char == '{' && c == '}')
193ce990805SThomas Braun incomment = false;
1943ae02089SMasatake YAMATO else if (comment_char == '(' && c == '*' && *dbp == ')')
1953ae02089SMasatake YAMATO {
1963ae02089SMasatake YAMATO dbp++;
197ce990805SThomas Braun incomment = false;
1983ae02089SMasatake YAMATO }
1993ae02089SMasatake YAMATO continue;
2003ae02089SMasatake YAMATO }
2013ae02089SMasatake YAMATO else if (inquote)
2023ae02089SMasatake YAMATO {
2033ae02089SMasatake YAMATO if (c == '\'')
204ce990805SThomas Braun inquote = false;
2053ae02089SMasatake YAMATO continue;
2063ae02089SMasatake YAMATO }
2073ae02089SMasatake YAMATO else switch (c)
2083ae02089SMasatake YAMATO {
2093ae02089SMasatake YAMATO case '\'':
210ce990805SThomas Braun inquote = true; /* found first quote */
2113ae02089SMasatake YAMATO continue;
2123ae02089SMasatake YAMATO case '{': /* found open { comment */
213ce990805SThomas Braun incomment = true;
2143ae02089SMasatake YAMATO comment_char = c;
2153ae02089SMasatake YAMATO continue;
2163ae02089SMasatake YAMATO case '(':
2173ae02089SMasatake YAMATO if (*dbp == '*') /* found open (* comment */
2183ae02089SMasatake YAMATO {
219ce990805SThomas Braun incomment = true;
2203ae02089SMasatake YAMATO comment_char = c;
2213ae02089SMasatake YAMATO dbp++;
2223ae02089SMasatake YAMATO }
2233ae02089SMasatake YAMATO else if (found_tag) /* found '(' after tag, i.e., parm-list */
224ce990805SThomas Braun inparms = true;
2253ae02089SMasatake YAMATO continue;
2263ae02089SMasatake YAMATO case ')': /* end of parms list */
2273ae02089SMasatake YAMATO if (inparms)
228ce990805SThomas Braun inparms = false;
2293ae02089SMasatake YAMATO continue;
2303ae02089SMasatake YAMATO case ';':
2313ae02089SMasatake YAMATO if (found_tag && !inparms) /* end of proc or fn stmt */
2323ae02089SMasatake YAMATO {
233ce990805SThomas Braun verify_tag = true;
2343ae02089SMasatake YAMATO break;
2353ae02089SMasatake YAMATO }
2363ae02089SMasatake YAMATO continue;
2373ae02089SMasatake YAMATO }
2383ae02089SMasatake YAMATO if (found_tag && verify_tag && *dbp != ' ')
2393ae02089SMasatake YAMATO {
2403ae02089SMasatake YAMATO /* check if this is an "extern" declaration */
2413ae02089SMasatake YAMATO if (*dbp == '\0')
2423ae02089SMasatake YAMATO continue;
2433ae02089SMasatake YAMATO if (tolower ((int) *dbp == 'e'))
2443ae02089SMasatake YAMATO {
2453ae02089SMasatake YAMATO if (tail ("extern")) /* superfluous, really! */
2463ae02089SMasatake YAMATO {
247ce990805SThomas Braun found_tag = false;
248ce990805SThomas Braun verify_tag = false;
2493ae02089SMasatake YAMATO }
2503ae02089SMasatake YAMATO }
2513ae02089SMasatake YAMATO else if (tolower ((int) *dbp) == 'f')
2523ae02089SMasatake YAMATO {
2533ae02089SMasatake YAMATO if (tail ("forward")) /* check for forward reference */
2543ae02089SMasatake YAMATO {
255ce990805SThomas Braun found_tag = false;
256ce990805SThomas Braun verify_tag = false;
2573ae02089SMasatake YAMATO }
2583ae02089SMasatake YAMATO }
2593ae02089SMasatake YAMATO if (found_tag && verify_tag) /* not external proc, so make tag */
2603ae02089SMasatake YAMATO {
261ce990805SThomas Braun found_tag = false;
262ce990805SThomas Braun verify_tag = false;
2633ae02089SMasatake YAMATO makePascalTag (&tag);
2643ae02089SMasatake YAMATO continue;
2653ae02089SMasatake YAMATO }
2663ae02089SMasatake YAMATO }
2673ae02089SMasatake YAMATO if (get_tagname) /* grab name of proc or fn */
2683ae02089SMasatake YAMATO {
2693ae02089SMasatake YAMATO const unsigned char *cp;
2703ae02089SMasatake YAMATO
2713ae02089SMasatake YAMATO if (*dbp == '\0')
2723ae02089SMasatake YAMATO continue;
2733ae02089SMasatake YAMATO
2743ae02089SMasatake YAMATO /* grab block name */
2753ae02089SMasatake YAMATO while (isspace ((int) *dbp))
2763ae02089SMasatake YAMATO ++dbp;
277*781ef2d9SNick Treleaven if (!starttoken(*dbp))
278*781ef2d9SNick Treleaven continue;
2793ae02089SMasatake YAMATO for (cp = dbp ; *cp != '\0' && !endtoken (*cp) ; cp++)
2803ae02089SMasatake YAMATO continue;
2813ae02089SMasatake YAMATO vStringNCopyS (name, (const char*) dbp, cp - dbp);
282bd605841SEnrico Tröger
283bd605841SEnrico Tröger vStringClear (arglist);
284bd605841SEnrico Tröger vStringClear (vartype);
285bd605841SEnrico Tröger parseArglist ((const char*) cp, arglist, (kind == K_FUNCTION) ? vartype : NULL);
286bd605841SEnrico Tröger
287bd605841SEnrico Tröger createPascalTag (&tag, name, kind, arglist, (kind == K_FUNCTION) ? vartype : NULL);
2883ae02089SMasatake YAMATO dbp = cp; /* set dbp to e-o-token */
289ce990805SThomas Braun get_tagname = false;
290ce990805SThomas Braun found_tag = true;
2913ae02089SMasatake YAMATO /* and proceed to check for "extern" */
2923ae02089SMasatake YAMATO }
2933ae02089SMasatake YAMATO else if (!incomment && !inquote && !found_tag)
2943ae02089SMasatake YAMATO {
2953ae02089SMasatake YAMATO switch (tolower ((int) c))
2963ae02089SMasatake YAMATO {
2973ae02089SMasatake YAMATO case 'c':
2983ae02089SMasatake YAMATO if (tail ("onstructor"))
2993ae02089SMasatake YAMATO {
300ce990805SThomas Braun get_tagname = true;
3013ae02089SMasatake YAMATO kind = K_PROCEDURE;
3023ae02089SMasatake YAMATO }
3033ae02089SMasatake YAMATO break;
3043ae02089SMasatake YAMATO case 'd':
3053ae02089SMasatake YAMATO if (tail ("estructor"))
3063ae02089SMasatake YAMATO {
307ce990805SThomas Braun get_tagname = true;
3083ae02089SMasatake YAMATO kind = K_PROCEDURE;
3093ae02089SMasatake YAMATO }
3103ae02089SMasatake YAMATO break;
3113ae02089SMasatake YAMATO case 'p':
3123ae02089SMasatake YAMATO if (tail ("rocedure"))
3133ae02089SMasatake YAMATO {
314ce990805SThomas Braun get_tagname = true;
3153ae02089SMasatake YAMATO kind = K_PROCEDURE;
3163ae02089SMasatake YAMATO }
3173ae02089SMasatake YAMATO break;
3183ae02089SMasatake YAMATO case 'f':
3193ae02089SMasatake YAMATO if (tail ("unction"))
3203ae02089SMasatake YAMATO {
321ce990805SThomas Braun get_tagname = true;
3223ae02089SMasatake YAMATO kind = K_FUNCTION;
3233ae02089SMasatake YAMATO }
3243ae02089SMasatake YAMATO break;
3253ae02089SMasatake YAMATO }
3263ae02089SMasatake YAMATO } /* while not eof */
3273ae02089SMasatake YAMATO }
328bd605841SEnrico Tröger vStringDelete (arglist);
329bd605841SEnrico Tröger vStringDelete (vartype);
3303ae02089SMasatake YAMATO vStringDelete (name);
3313ae02089SMasatake YAMATO }
3323ae02089SMasatake YAMATO
PascalParser(void)3333ae02089SMasatake YAMATO extern parserDefinition* PascalParser (void)
3343ae02089SMasatake YAMATO {
3353ae02089SMasatake YAMATO static const char *const extensions [] = { "p", "pas", NULL };
3363ae02089SMasatake YAMATO parserDefinition* def = parserNew ("Pascal");
3373ae02089SMasatake YAMATO def->extensions = extensions;
33809ae690fSMasatake YAMATO def->kindTable = PascalKinds;
3393db72c21SMasatake YAMATO def->kindCount = ARRAY_SIZE (PascalKinds);
3403ae02089SMasatake YAMATO def->parser = findPascalTags;
3413ae02089SMasatake YAMATO return def;
3423ae02089SMasatake YAMATO }
343