Browse files

Added support for Erlang language, submitted by Brent Fulgham.

  • Loading branch information...
1 parent c694577 commit 5869b890533edcc733cf9dd648cf0e8b9cdda214 Darren Hiebert committed Feb 13, 2003
Showing with 444 additions and 13 deletions.
  1. +1 −0 NEWS
  2. +1 −1 README
  3. +127 −0 Test/maze.erl
  4. +42 −0 Test/maze.hrl
  5. +23 −0 ctags.1
  6. +224 −0 erlang.c
  7. +1 −1 index.html
  8. +1 −0 mk_manx.mak
  9. +2 −0 mk_mpw.mak
  10. +1 −0 mk_qdos.mak
  11. +11 −8 mk_risc.mak
  12. +1 −0 mk_sas.mak
  13. +1 −0 parsers.h
  14. +3 −1 sml.c
  15. +4 −2 source.mak
  16. +1 −0 website/languages.html
View
1 NEWS
@@ -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
View
2 README
@@ -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.
View
127 Test/maze.erl
@@ -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 %%%
View
42 Test/maze.hrl
@@ -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 %%%
View
23 ctags.1
@@ -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
@@ -1051,6 +1054,26 @@ local entities [off]
.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
.PD 0
View
224 erlang.c
@@ -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
2 index.html
@@ -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
1 mk_manx.mak
@@ -14,6 +14,7 @@ OBJECTS = \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
+ erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
View
2 mk_mpw.mak
@@ -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
1 mk_qdos.mak
@@ -49,6 +49,7 @@ OBJECTS = qdos.$(OBJEXT) \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
+ erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
View
19 mk_risc.mak
@@ -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
1 mk_sas.mak
@@ -17,6 +17,7 @@ OBJECTS = \
cobol.$(OBJEXT) \
eiffel.$(OBJEXT) \
entry.$(OBJEXT) \
+ erlang.$(OBJEXT) \
fortran.$(OBJEXT) \
get.$(OBJEXT) \
keyword.$(OBJEXT) \
View
1 parsers.h
@@ -25,6 +25,7 @@
CsharpParser, \
CobolParser, \
EiffelParser, \
+ ErlangParser, \
FortranParser, \
JavaParser, \
LispParser, \
View
4 sml.c
@@ -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
6 source.mak
@@ -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
1 website/languages.html
@@ -18,6 +18,7 @@
<li>BETA</li>
<li>COBOL</li>
<li>Eiffel</li>
+ <li>Erlang</li>
<li>Fortran</li>
<li>Java</li>
<li>Lisp</li>

0 comments on commit 5869b89

Please sign in to comment.