comp.lang.ada
 help / color / mirror / Atom feed
* Ada parser for Exuberant Ctags program
@ 2004-08-05 20:09 silversword31
  0 siblings, 0 replies; only message in thread
From: silversword31 @ 2004-08-05 20:09 UTC (permalink / raw)


I've wrote a parser for exuberant ctags 5.5.4. It capture procedures,
functions, type, subtype, package and package body.
It's not very complete but it's usefull :o)

Eric Fraxinous

Ps: I've used Pascal Parser for begining. Thank you Darren Hiebert for this
example :o)

---Code

/*
*
*
*   Copyright (c) 2004, Fraxinous Eric
*
*   This source code is released for free distribution under the terms of
the
*   GNU General Public License.
*
*   This module contains functions for generating tags for the Ada language
*/

/*
*   INCLUDE FILES
*/
#include "general.h" /* must always come first */

#include <string.h>

#include "entry.h"
#include "parse.h"
#include "read.h"
#include "vstring.h"

/*
*   DATA DEFINITIONS
*/
typedef enum {
    K_FUNCTION, K_PROCEDURE,K_FUNCTION_P, K_PROCEDURE_P, K_PACKAGE,
K_PACKAGE_BODY, K_TYPE, K_SUBTYPE
} AdaKind;

static kindOption AdaKinds [] = {
    { TRUE, 'f', "function",  "functions"},
    { TRUE, 'f', "procedure", "procedures"},
    { TRUE, 'p', "function",  "functions def"},
    { TRUE, 'p', "procedure", "procedures def"},
    { TRUE, 'c', "package",   "package"},
    { TRUE, 'b', "package body",   "package body"},
    { TRUE, 't', "type",    "type"},
    { TRUE, 't', "subtype",    "subtype"}
};

/*
*   FUNCTION DEFINITIONS
*/

static void createAdaTag (tagEntryInfo* const tag,
        const vString* const name, const int kind)
{
    if (AdaKinds [kind].enabled  &&  name != NULL  &&  vStringLength (name)
> 0)
    {
        initTagEntry (tag, vStringValue (name));

        tag->kindName = AdaKinds [kind].name;
        tag->kind     = AdaKinds [kind].letter;
    }
    else
        initTagEntry (tag, NULL);
}

static void makeAdaTag (const tagEntryInfo* const tag)
{
    if (tag->name != NULL)
 makeTagEntry (tag);
}

static const unsigned char* dbp;

#define starttoken(c) (isalpha ((int) c) || (int) c == '_')
#define intoken(c)    (isalnum ((int) c) || (int) c == '_' || (int) c ==
'.')
#define endtoken(c)   (! intoken (c)  &&  ! isdigit ((int) c))

static boolean tail (const char *cp)
{
    boolean result = FALSE;
    register int len = 0;

    while (*cp != '\0' && tolower ((int) *cp) == tolower ((int) dbp [len]))
 cp++, len++;
    if (*cp == '\0' && !intoken (dbp [len]))
    {
 dbp += len;
 result = TRUE;
    }
    return result;
}

/* Algorithm adapted from from GNU etags.
 * Locates tags for procedures & functions.  Doesn't do any type- or
 * var-definitions.  It does look for the keyword "extern" or "forward"
 * immediately following the procedure statement; if found, the tag is
 * skipped.
 */
static void findAdaTags (void)
{
    vString *name = vStringNew ();
    tagEntryInfo tag;
    AdaKind kind = K_FUNCTION;
    /* each of these flags is TRUE iff: */
    boolean incomment = FALSE; /* point is inside a comment */
    int comment_char = '\0';    /* type of current comment */
    boolean inquote = FALSE; /* point is inside '..' string */
    boolean get_tagname = FALSE;/* point is after PROCEDURE/FUNCTION
        keyword, so next item = potential tag */
    boolean found_tag = FALSE; /* point is after a potential tag */
    boolean inparms = FALSE; /* point is within parameter-list */
    boolean skip_line = FALSE; /* skip line ? */
    boolean verify_tag = FALSE; /* point has passed the parm-list, so the
       next token will determine whether this
       is a FORWARD/EXTERN to be ignored, or
       whether it is a real tag */

    dbp = fileReadLine ();
    while (dbp != NULL)
    {
 int c = *dbp++;
 if (c == '\0'|| skip_line)  /* if end of line */
 {
    if (found_tag) /* end of proc or fn stmt */
           {
        verify_tag = TRUE;
     }
            incomment = FALSE;
            skip_line = FALSE;
     dbp = fileReadLine ();
     if (dbp == NULL  ||  *dbp == '\0')
  continue;
     if (!((found_tag && verify_tag) || get_tagname))
  c = *dbp++;  /* only if don't need *dbp pointing
        to the beginning of the name of
        the procedure or function */
 }
 /* incomment test */
 if (tail("--"))
 {
     incomment = TRUE;
            skip_line = TRUE;
     continue;
 }
 else switch (c)
 {
     case '(':
  if (found_tag)  /* found '(' after tag, i.e., parm-list */
      inparms = TRUE;
  continue;
     case ')':  /* end of parms list */
  if (inparms)
      inparms = FALSE;
  continue;
     case ';':
  if (found_tag && !inparms) /* end of proc or fn stmt */
  {
      verify_tag = TRUE;
      if( kind == K_PROCEDURE)
   kind=K_PROCEDURE_P;
      if( kind == K_FUNCTION)
   kind=K_FUNCTION_P;
                    skip_line = FALSE;
      break;
  }
  continue;
     default:
  if(tail("is"))
  {
     if (found_tag && !inparms) /* end of proc or fn stmt */
                   {
      verify_tag = TRUE;
      if( kind == K_PROCEDURE_P)
      {
   kind=K_PROCEDURE;
                createAdaTag (&tag, name, kind);
       }
      if( kind == K_FUNCTION_P)
      {
   kind=K_FUNCTION;
                createAdaTag (&tag, name, kind);
       }
                    skip_line = FALSE;
      break;
  }
  else
      verify_tag = FALSE;
  }
 }
 if (found_tag && verify_tag && *dbp != ' ')
 {
     /* check if this is an "extern" declaration */
     if (*dbp == '\0')
  continue;
     if (found_tag && verify_tag && !inparms) /* not external proc, so make
tag */
     {
  found_tag = FALSE;
  verify_tag = FALSE;
  makeAdaTag (&tag);
  continue;
     }
 }
 if (get_tagname)  /* grab name of proc or fn */
 {
     const unsigned char *cp;

     if (*dbp == '\0')
  continue;

     /* grab block name */
     while (isspace ((int) *dbp))
  ++dbp;
     for (cp = dbp  ;  *cp != '\0' && !endtoken (*cp)  ;  cp++)
  continue;
     vStringNCopyS (name, (const char*) dbp,  cp - dbp);
     createAdaTag (&tag, name, kind);
     dbp = cp;  /* set dbp to e-o-token */
     get_tagname = FALSE;
     found_tag = TRUE;
     /* and proceed to check for "extern" */
 }
 else if (!incomment && !inquote && !found_tag)
 {
     switch (tolower ((int) c))
     {
  case 'p':
      if (tail ("rocedure"))
      {
   get_tagname = TRUE;
   kind = K_PROCEDURE_P;
      }
      if (tail ("ackage"))
      {
         if (tail (" body"))
         {
      get_tagname = TRUE;
      kind = K_PACKAGE_BODY;
         }
         else
         {
     get_tagname = TRUE;
     kind = K_PACKAGE;
         }
      }
      break;
  case 'f':
      if (tail ("unction"))
      {
   get_tagname = TRUE;
   kind = K_FUNCTION_P;
      }
      break;
  case 't':
      if (tail ("ype"))
      {
   get_tagname = TRUE;
   kind = K_TYPE;
      }
      break;
  case 's':
      if (tail ("ubtype"))
      {
   get_tagname = TRUE;
   kind = K_SUBTYPE;
      }
     }
 }    /* while not eof */
    }
}

extern parserDefinition* AdaParser (void)
{
    static const char *const extensions [] = { "adb", "ads", NULL };
    parserDefinition* def = parserNew ("Ada");
    def->extensions = extensions;
    def->kinds      = AdaKinds;
    def->kindCount  = KIND_COUNT (AdaKinds);
    def->parser     = findAdaTags;
    return def;
}

/* vi:set tabstop=8 shiftwidth=4: */






^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2004-08-05 20:09 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2004-08-05 20:09 Ada parser for Exuberant Ctags program silversword31

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox