Added support for Erlang language, submitted by Brent Fulgham.

git-svn-id: svn://svn.code.sf.net/p/ctags/code/trunk@264 c5d04d22-be80-434c-894e-aa346cc9e8e8
This commit is contained in:
darren 2003-02-13 02:59:30 +00:00
parent bec43b5fae
commit 955dcc262d
16 changed files with 444 additions and 13 deletions

1
NEWS
View File

@ -4,6 +4,7 @@ ctags-5.5 (Fri Jan 31 2003)
* Changed kind indicator for methods from 'f' to 'm' [Tcl].
* Added support for dimensioned variables, contributed by Simon Bohlin [ASP].
* Added support for C# language.
* Added support for Erlang language, contributed by Brent Fulgham.
* Added support for SML (Standard ML) language, contributed by Venkatesh Prasad.
* Added tags for autocommand groups [Vim, Patch #664685].
* Added special handling of --options=NONE to disable automatic reading of

2
README
View File

@ -18,7 +18,7 @@ because most were easily fooled by a number of preprocessor contructs.
Exuberant Ctags offers the following features:
1. It supports the following languages: Assembler, AWK, ASP, BETA,
Bourne/Korn/Z Shell, C, C++, C#, COBOL, Eiffel, Fortran, Java, Lisp,
Bourne/Korn/Z Shell, C, C++, C#, COBOL, Eiffel, Erlang, Fortran, Java, Lisp,
Lua, Makefile, Pascal, Perl, PHP, PL/SQL, Python, REXX, Ruby, S-Lang,
Scheme, Tcl, Verilog, Vim, and YACC.

127
Test/maze.erl Normal file
View File

@ -0,0 +1,127 @@
-module(maze).
-vsn('2002.0317').
-author('cpressey@catseye.mb.ca').
-copyright('Copyright (c)2002 Cat`s Eye Technologies. All rights reserved.').
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions
%%% are met:
%%%
%%% Redistributions of source code must retain the above copyright
%%% notice, this list of conditions and the following disclaimer.
%%%
%%% Redistributions in binary form must reproduce the above copyright
%%% notice, this list of conditions and the following disclaimer in
%%% the documentation and/or other materials provided with the
%%% distribution.
%%%
%%% Neither the name of Cat's Eye Technologies nor the names of its
%%% contributors may be used to endorse or promote products derived
%%% from this software without specific prior written permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE.
-include("maze.hrl").
-export([build/0, generate/1]).
%%% BEGIN maze.erl %%%
%%% A simple maze-drawing program.
%% Driver function -----------------------------------------------------
build() ->
Tot = generate(#maze{}),
tot_print(Tot).
%% Maze generation function --------------------------------------------
generate(#maze{}=M) ->
seed(),
{X, Y} = {random:uniform(M#maze.width div 2) * 2, random:uniform(M#maze.height div 2) * 2},
R2 = tot_put(X, Y, tot_new(M#maze.width, M#maze.height, M#maze.wall), M#maze.space),
generate(M, R2, X, Y).
generate(#maze{}=M, R, X, Y) ->
lists:foldl(fun({DX, DY}, A) ->
NX = X + DX * 2, NY = Y + DY * 2,
W = M#maze.wall,
case catch tot_get(NX, NY, A) of
W ->
M1 = tot_put(X + DX, Y + DY, A, M#maze.space),
M2 = tot_put(NX, NY, M1, M#maze.space),
generate(M, M2, NX, NY);
_ -> A
end
end, R, scramble([{-1,0}, {1,0}, {0,-1}, {0,1}])).
%%% ToT (Tuple-of-Tuples) Utilities ------------------------------------
tot_new(W, H, Cell) ->
erlang:make_tuple(H, erlang:make_tuple(W, Cell)).
tot_get(X, Y, Tot) ->
element(X, element(Y, Tot)).
tot_put(X, Y, Tot, V) ->
setelement(Y, Tot, setelement(X, element(Y, Tot), V)).
tot_print(ToT) ->
tot_print(1, ToT).
tot_print(Y, ToT) when Y =< size(ToT) ->
tot_print_tuple(element(Y, ToT)),
io:fwrite("~n"),
tot_print(Y+1, ToT);
tot_print(Y, ToT) -> ok.
tot_print_tuple(T) ->
tot_print_tuple(1, T).
tot_print_tuple(X, T) when X =< size(T) ->
io:fwrite("~s", [[element(X, T)]]),
tot_print_tuple(X+1, T);
tot_print_tuple(X, T) -> ok.
%%% Randomness Functions -----------------------------------------------
%% Seed the random number generator so that it will produce unpredictable
%% values. Should be called once at startup, before using random numbers.
seed() ->
{H,M,S} = time(),
random:seed(S,M,H),
random:uniform(23). % prime the pump - first number can be iffy
%% Pick a random element from a tuple or a list (equal chance for every
%% element.)
pick(Tuple) when tuple(Tuple) ->
pick(tuple_to_list(Tuple));
pick(List) ->
lists:nth(random:uniform(length(List)), List).
%% Mix up the order (shuffle or scramble) a tuple or list.
scramble(Tuple) when tuple(Tuple) ->
list_to_tuple(scramble(tuple_to_list(Tuple)));
scramble(List) ->
scramble(List, []).
scramble([], Acc) -> Acc;
scramble(List, Acc) ->
S = pick(List),
scramble(List -- [S], Acc ++ [S]).
%%% END of maze.erl %%%

42
Test/maze.hrl Normal file
View File

@ -0,0 +1,42 @@
-vsn('2002.0317').
-author('cpressey@catseye.mb.ca').
-copyright('Copyright (c)2002 Cat`s Eye Technologies. All rights reserved.').
%%% Redistribution and use in source and binary forms, with or without
%%% modification, are permitted provided that the following conditions
%%% are met:
%%%
%%% Redistributions of source code must retain the above copyright
%%% notice, this list of conditions and the following disclaimer.
%%%
%%% Redistributions in binary form must reproduce the above copyright
%%% notice, this list of conditions and the following disclaimer in
%%% the documentation and/or other materials provided with the
%%% distribution.
%%%
%%% Neither the name of Cat's Eye Technologies nor the names of its
%%% contributors may be used to endorse or promote products derived
%%% from this software without specific prior written permission.
%%%
%%% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
%%% CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
%%% INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
%%% MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
%%% DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
%%% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
%%% OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
%%% PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
%%% OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
%%% ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
%%% OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
%%% OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
%%% POSSIBILITY OF SUCH DAMAGE.
%%% BEGIN maze.hrl %%%
-define(SPACE, $ ).
-define(WALL, $#).
-record(maze,{width = 40,height = 30, space = ?SPACE ,wall = ?WALL}).
%%% END of maze.erl %%%

23
ctags.1
View File

@ -88,6 +88,9 @@ names are mapped to languages according to the following default mappings
.B Eiffel
*.e
.TP 9
.B Erlang
*.erl *.hrl *.ERL *.HRL
.TP 9
.B Fortran
*.f *.for *.ftn *.f77 *.f90 *.f95 *.F *.FOR *.FTN *.F77 *.F90 *.F95
.TP 9
@ -1050,6 +1053,26 @@ local entities [off]
.PD 1
.RE
.TP 5
Erlang
.RS 5
.PD 0
.TP 4
.I a
atoms
.TP 4
.I d
macros
.TP 4
.I m
modules
.TP 4
.I r
records
.RE
.PD 1
.RE
.TP 5
Fortran
.RS 5

224
erlang.c Normal file
View File

@ -0,0 +1,224 @@
/*
* $Id$
*
* Copyright (c) 2003, Brent Fulgham <bfulgham@debian.org>
*
* 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 Erlang language
* files. Some of the parsing constructs are based on the Emacs 'etags'
* program by Francesco Potori <pot@gnu.org>
*/
/*
* INCLUDE FILES
*/
#include "general.h" /* must always come first */
#include <string.h>
#include "entry.h"
#include "options.h"
#include "read.h"
#include "routines.h"
#include "vstring.h"
/*
* DATA DEFINITIONS
*/
typedef enum {
K_FUNCTION, K_MODULE, K_RECORD, K_MACRO
} erlangKind;
static kindOption ErlangKinds[] = {
{TRUE, 'f', "function", "functions"},
{TRUE, 'm', "module", "modules"},
{TRUE, 'r', "record", "record definitions"},
{TRUE, 's', "macro", "macro definitions"},
};
/*
* FUNCTION DEFINITIONS
*/
/* tagEntryInfo and vString should be preinitialized/preallocated but not
* necessary. If successful you will find class name in vString
*/
static boolean isIdentifierFirstCharacter (int c)
{
return (boolean) (isalpha (c));
}
static boolean isIdentifierCharacter (int c)
{
return (boolean) (isalnum (c) || c == '_' || c == ':');
}
static const unsigned char *skipSpace (const unsigned char *cp)
{
while (isspace ((int) *cp))
++cp;
return cp;
}
static const unsigned char *parseIdentifier (
const unsigned char *cp, vString *const identifier)
{
vStringClear (identifier);
while (isIdentifierCharacter ((int) *cp))
{
vStringPut (identifier, (int) *cp);
++cp;
}
vStringTerminate (identifier);
return cp;
}
static void makeGenericTag (
erlangKind kind, vString *const identifier, vString *const module)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (identifier));
tag.kindName = ErlangKinds[kind].name;
tag.kind = ErlangKinds[kind].letter;
if (module && (vStringLength (module) > 0) )
{
tag.extensionFields.scope [0] = "module";
tag.extensionFields.scope [1] = vStringValue (module);
}
makeTagEntry (&tag);
}
static void makeErlangTag (const unsigned char *cp, erlangKind kind,
vString *const module)
{
vString *const identifier = vStringNew ();
cp = parseIdentifier (cp, identifier);
makeGenericTag (kind, identifier, module);
vStringDelete (identifier);
}
static void makeModuleTag (const unsigned char *cp, erlangKind kind,
vString *const module)
{
vString *const identifier = vStringNew ();
cp = parseIdentifier (cp, identifier);
makeGenericTag (kind, identifier, NULL);
/* All further entries go in the new module */
vStringCopy (module, identifier);
vStringDelete (identifier);
}
static void makeFunctionTag (vString *const name, vString *const module)
{
tagEntryInfo tag;
initTagEntry (&tag, vStringValue (name));
tag.kindName = ErlangKinds[K_FUNCTION].name;
tag.kind = ErlangKinds[K_FUNCTION].letter;
if (module && (vStringLength (module) > 0) )
{
tag.extensionFields.scope [0] = "module";
tag.extensionFields.scope [1] = vStringValue (module);
}
makeTagEntry (&tag);
}
/*
* Add a function definition tag if:
* 1) There is no white-space at the start of the line
* 2) It doesn't match the previous identifier
*/
static void parseFunction (const unsigned char *cp, vString *const previous,
vString *const module)
{
/*
* Rule 1 is met if we are in this routine, so just find the identifier,
* determine if it is different from the previous, and add it.
*/
vString *const identifier = vStringNew ();
cp = parseIdentifier (cp, identifier);
if ( (vStringLength (identifier) != vStringLength (previous) )
|| (strncmp (vStringValue (identifier), vStringValue (previous),
vStringLength (identifier)) != 0))
{
makeFunctionTag (identifier, module);
vStringCopy (previous, identifier);
}
vStringDelete (identifier);
}
/*
* Directives are of the form:
* -module(foo)
* -define(foo, bar)
* -record(graph, {vtab = notable, cyclic = true}).
*/
static void parseDirective (const unsigned char *cp,
vString *const module)
{
/*
* A directive will be either a record definition or a directive.
* Record definitions are handled separately
*/
vString *const directive = vStringNew ();
cp = parseIdentifier (cp, directive);
cp = skipSpace (cp);
if (*cp == '(')
++cp;
if (strncmp (vStringValue (directive), "record", 6) == 0)
makeErlangTag (cp, K_RECORD, module);
else if (strncmp (vStringValue (directive), "define", 6) == 0)
makeErlangTag (cp, K_MACRO, module);
else if (strncmp (vStringValue (directive), "module", 6) == 0)
makeModuleTag (cp, K_MODULE, module);
/* Otherwise, it was an import, export, etc. */
vStringDelete (directive);
}
static void findErlangTags (void)
{
vString *const previous = vStringNew ();
vString *const module = vStringNew ();
const unsigned char *line;
while ((line = fileReadLine ()) != NULL)
{
const unsigned char *cp = line;
if (*cp == '%') /* skip initial comment */
continue;
if (*cp == '"') /* strings sometimes start in column one */
continue;
if ( *cp == '-')
{
++cp; /* Move off of the '-' */
parseDirective(cp, module);
}
else if (isIdentifierFirstCharacter ((int) *cp))
parseFunction (cp, previous, module);
}
vStringDelete (previous);
vStringDelete (module);
}
extern parserDefinition *ErlangParser (void)
{
static const char *const extensions[] = { "erl", "ERL", "hrl", "HRL", NULL };
parserDefinition *def = parserNew ("Erlang");
def->kinds = ErlangKinds;
def->kindCount = KIND_COUNT (ErlangKinds);
def->extensions = extensions;
def->parser = findErlangTags;
return def;
}
/* vi:set tabstop=8 shiftwidth=4: */

View File

@ -161,7 +161,7 @@
<a href="countries.html">countries</a>
in <b>all 7 continents <i>(including Antarctica!)</i></b>
<li>
Supports 29 <a href="languages.html">programming languages</a>
Supports 30 <a href="languages.html">programming languages</a>
</li>
<li>Featured in the book,
<a href="http://www.oreilly.com/catalog/vi6/chapter/ch08.html#ch08_05.htm">

View File

@ -14,6 +14,7 @@ OBJECTS = \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \

View File

@ -19,6 +19,7 @@ SOURCES =
cobol.c ¶
eiffel.c ¶
entry.c ¶
erlang.c ¶
fortran.c ¶
get.c ¶
keyword.c ¶
@ -61,6 +62,7 @@ OBJ =
cobol.o ¶
eiffel.o ¶
entry.o ¶
erlang.o ¶
fortran.o ¶
get.o ¶
keyword.o ¶

View File

@ -49,6 +49,7 @@ OBJECTS = qdos.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \

View File

@ -8,11 +8,11 @@ CC = $(GCC) $(OPT)
# Object list
OBJECTS = \
o.args o.asm o.asp o.awk o.eiffel o.beta o.clang o.cobol o.entry \
o.fortran o.get o.keyword o.lisp o.lregex o.lua o.main o.make \
o.options o.parse o.pascal o.perl o.php o.python o.read o.rexx \
o.routines o.ruby o.scheme o.sh o.slang o.sort o.strlist o.tcl \
o.verilog o.vim o.vstring o.yacc
o.args o.asm o.asp o.awk o.beta o.clang o.cobol o.eiffel o.entry
o.erlang o.fortran o.get o.keyword o.lisp o.lregex o.lua o.main \
o.make o.options o.parse o.pascal o.perl o.php o.python o.read \
o.rexx o.routines o.ruby o.scheme o.sh o.slang o.sort o.strlist \
o.tcl o.verilog o.vim o.vstring o.yacc
all: $(OBJECTS)
gcc -o ctags $(OBJECTS) RegEx:libregex
@ -38,9 +38,6 @@ o.asp: c.asp
o.awk: c.awk
$(CC) -c c.awk -o o.awk
o.eiffel: c.eiffel
$(CC) -c c.eiffel -o o.eiffel
o.beta: c.beta
$(CC) -c c.beta -o o.beta
@ -50,9 +47,15 @@ o.clang: c.c
o.cobol: c.cobol
$(CC) -c c.cobol -o o.cobol
o.eiffel: c.eiffel
$(CC) -c c.eiffel -o o.eiffel
o.entry: c.entry
$(CC) -c c.entry -o o.entry
o.erlang: c.erlang
$(CC) -c c.erlang -o o.erlang
o.fortran: c.fortran
$(CC) -c c.fortran -o o.fortran

View File

@ -17,6 +17,7 @@ OBJECTS = \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \

View File

@ -25,6 +25,7 @@
CsharpParser, \
CobolParser, \
EiffelParser, \
ErlangParser, \
FortranParser, \
JavaParser, \
LispParser, \

4
sml.c
View File

@ -1,7 +1,7 @@
/*
* $Id$
*
* Copyright (c) 2002, Venkatesh Prasad Ranganath
* Copyright (c) 2002, Venkatesh Prasad Ranganath and Darren Hiebert
*
* This source code is released for free distribution under the terms of the
* GNU General Public License.
@ -198,3 +198,5 @@ extern parserDefinition *SmlParser (void)
def->parser = findSmlTags;
return def;
}
/* vi:set tabstop=8 shiftwidth=4: */

View File

@ -12,11 +12,12 @@ SOURCES = \
asm.c \
asp.c \
awk.c \
eiffel.c \
beta.c \
c.c \
cobol.c \
eiffel.c \
entry.c \
erlang.c \
fortran.c \
get.c \
keyword.c \
@ -61,11 +62,12 @@ OBJECTS = \
asm.$(OBJEXT) \
asp.$(OBJEXT) \
awk.$(OBJEXT) \
eiffel.$(OBJEXT) \
beta.$(OBJEXT) \
c.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \

View File

@ -18,6 +18,7 @@ Languages Supported by Exuberant Ctags:
<li>BETA</li>
<li>COBOL</li>
<li>Eiffel</li>
<li>Erlang</li>
<li>Fortran</li>
<li>Java</li>
<li>Lisp</li>