[comp.lang.ada] VADS tags support under gnuemacs

sdl@MITRE-BEDFORD.ARPA (Litvintchouk) (03/09/88)

> We are using the Verdix compiler on a Sun Unix system. Verdix provides
> the command a.tags, which generates a tags file, using ctags format. I
> would like to be able to use these tags from within gnuemacs, but that
> editor only supports its own tags formats. Does anyone have a gnuemacs
> utility for reading a ctags file?

Yes, but I never did get my utility to work exactly like gnuemacs'
existing tags facility (never had the time).  The reason is that
gnuemacs only associates a file & single position with each tag,
whereas a.tags associates a file & regexp search string with each tag.
In this way, you can search for multiple occurrences (overloadings)
within a single file.  So, here's what I have.

First run a.tags to make the ctags file (use -t option to get the
types).

The interactive function visit-ada-tag-file will prompt you to specify
the tag file name created by a.tags.  It will read in the tag file and
"condition" it for Emacs regexp searching.

Once this is done, the interactive function goto-ada-tag will put up a
menu of all the tags, prompting with the Ada identifier surrounding
point.  You can use completion to select the tag you want.  The reason
why the Ada identifier surrounding point is used as a prompt is that
this makes it easy to jump between, say, a spec, its body, and its
body stub.  If the cursor is on the name of the unit (say FOO), then
goto-ada-tag will use FOO as the trial tag.

By the way, another useful thing we have is an extended dired mode
that invokes VADS tools on the files.  Just move the cursor to the
filename, and hit "c" (to compile), "m" (to run a.make), etc.  Also
works good with Suntools popup menus (we have a Suntools popup menu
interface to dired and other common modes).  Let me know if you're
interested.

Anyhoo, here's the VADS tags code....



;; GNU Emacs functions for working with Verdix Ada tags files.
;; Steven D. Litvintchouk / Mitre Corporation / January 1986
;;

(defvar last-ada-tag-string-searched  ""
  "Last Ada tag string searched for.  Saved so you can search for it again.")

(defvar ada-non-identifier-regexp "[^a-zA-Z0-9_]"
  "Regexp which matches a character which can't appear in an
Ada identifier.")

(defvar ada-identifier-regexp "[a-zA-Z0-9_]"
  "Regexp which matches a character which can appear in an
Ada identifier.")

(defconst ada-reserved-words-list
      '("abort"     "declare"    "generic"  "of"         "select"
	"abs"       "delay"      "goto"     "or"         "separate"
	"accept"    "delta"                 "others"     "subtype"
	"access"    "digits"     "if"       "out"
	"all"       "do"         "in"                    "task"
	"and"                    "is"       "package"    "terminate"
	"array"                             "pragma"     "then"
	"at"        "else"                  "private"    "type"
	            "elsif"      "limited"  "procedure"
		    "end"        "loop"
	"begin"     "entry"                 "raise"      "use"
	"body"      "exception"             "range"
	            "exit"       "mod"      "record"     "when"
		                            "rem"        "while"
				 "new"      "renames"    "with"
	"case"      "for"        "not"      "return"
	"constant"  "function"   "null"     "reverse"    "xor"
	)
      "List of reserved words in Ada.")

(defvar ada-tag-alist  nil
  "Alist used for completions of Ada tags.  The alist consists of a list
of triples.  Each triple is a list of three elements:  the tag, the 
name of the file containing the tag, and a regexp string used to search
for the tag.")

(defun member (e l)
  "Returns non-nil if ELT is an element of LIST.  Comparison done with EQUAL.
The value is actually the tail of LIST whose car is ELT.
(Why isn't this a predefined function in Emacs-Lisp?)"
  (let ((templ l))
    (catch 'result
      (while templ
	(if (equal e (car templ))
	    (throw 'result (cdr templ))
	  (setq templ (cdr templ))))
      nil)))

(defun build-ada-tag-alist nil
  "Given a buffer containing a Verdix tag table, this subroutine 
builds the ada-tag-alist.  Should only be used after 
condition-ada-tag-table has been run over the tag table."
  (beginning-of-buffer)
  (setq ada-tag-alist nil)
  (while (not (eobp))
    (let ((start-of-tag (point)))
      (search-forward "\t")
      (backward-char 1)
      (let ((tag (buffer-substring start-of-tag (point))))
	(forward-char 1)
	(let ((start-of-filename (point)))
	  (search-forward "\t")
	  (backward-char 1)
	  (let ((filename (buffer-substring  start-of-filename (point))))
	    (forward-char 2)
	    (let ((start-of-search-string (point)))
	      (end-of-line)
	      (backward-char 1)
	      (let ((search-string
		     (buffer-substring start-of-search-string (point))))
		(setq ada-tag-alist
		      (cons (list tag filename search-string)
			    ada-tag-alist))
		(next-line 1)
		(beginning-of-line))))))))
  (beginning-of-buffer))


(defun  goto-ada-tag  (ada-tag)
  "Given a Verdix Ada tag, this function finds it from the tag table.
It finds the file (in another window) and searches for the tag within it.

A Verdix Ada tag looks like an Ada name, except for the following cases:
Specifications:  the Ada simple name is prefaced by s#
Stubs:           the Ada simple name is prefaced by stub#

Bodies, types, etc. use the unmodified Ada name.
Example:  procedure spec ABC in package P is tagged as P.s#ABC

The identifier surrounding or just before point is used as a prompt tag."

  (interactive
   (list
    (let* ((default-tag (current-ada-identifier))
	   (save-completion-ignore-case  completion-ignore-case)
	   (actual-tag (progn
			 (setq completion-ignore-case t)
			 (completing-read  "Ada tag: "
					   ada-tag-alist
					   'ada-tag-match-criterion
					   t
					   default-tag))))
      (setq completion-ignore-case save-completion-ignore-case)
      actual-tag)))
      
  (let* ((location-pair (cdr (assoc ada-tag ada-tag-alist)))
	 (filename (car location-pair))
	 (search-string (car (cdr location-pair))))
    (find-file-other-window filename)
    (beginning-of-buffer)
    (re-search-forward search-string)
    (setq last-ada-tag-string-searched  search-string)
    ))

(defun ada-tag-match-criterion (ada-tag)
  "For now, let all tags match."
  t)

(defun current-ada-identifier nil
   "Returns, as a string, the identifier surrounding or just before point.
The empty string is returned if the identifier is an Ada reserved word."
   (catch 'id-string
     (save-excursion
       (if (or (eobp) (looking-at ada-non-identifier-regexp))
	   (condition-case foo
	       (progn
		 (re-search-backward ada-identifier-regexp)
		 (forward-char 1))
	     (error (throw 'id-string "")))
	 (condition-case foo
	     (progn
	       (re-search-forward  ada-non-identifier-regexp)
	       (backward-char 1))
	   (error (end-of-buffer))))
       (set-mark (point))
       (backward-char 1)
       (condition-case foo
	   (progn
	     (re-search-backward  ada-non-identifier-regexp)
	     (forward-char 1))
	 (error (beginning-of-buffer)))
       (let ((identifier (buffer-substring (point) (mark))))
	 (if (member (downcase identifier) ada-reserved-words-list)
	     ""
	   identifier)))))

(defun tags-ada-continue-search  nil
  "Continue searching current file for next occurrence of last
Ada tag found."
  (interactive)
  (re-search-forward last-ada-tag-string-searched))

(defun visit-ada-tag-file  (tagfn)
  (interactive  "fTag file name: ")
  (message "Loading tags file, please wait...")
  (sit-for 0)
  (set-buffer (get-buffer-create "*tag-ada*"))
  (erase-buffer)
  (insert-file  tagfn)
  (condition-ada-tag-table)
  (beginning-of-buffer)
  (set-buffer-modified-p nil)
  (build-ada-tag-alist)
  (sit-for 0)
  (message "Done! Tags loaded & available for use!")
)

(defun condition-ada-tag-table  nil
  "Given a buffer containing a Verdix tag table, this subroutine
converts the regexp search strings generated by a.tags into a form
that is more compatible with what Emacs expects of regexps."
    (beginning-of-buffer)
    (replace-string "\\[" "[")           ;  \[  ->  [
    (beginning-of-buffer)
    (replace-string "\\*" "*")           ;  \*  ->  *
    (beginning-of-buffer)
    (replace-string """**" """\\**")     ;  "**  ->  "\**
    (beginning-of-buffer)
    (replace-string """*" """\\*")       ;  "*  ->  "\*
    (beginning-of-buffer)
    (replace-string """+" """\\+")       ;  "+  ->  "\+
    (beginning-of-buffer)
    (replace-string "*""\\+" "*\\+")	 ;  *"\+  ->  *\+
    (beginning-of-buffer)
    (replace-string "*""-" "*\\-")	 ;  *"-  ->  *\-
    (beginning-of-buffer)
    (replace-string "*""\\/" "*\\/")       ;  *"\/  ->  *\/
    (beginning-of-buffer)
    (replace-string "\\**" "\\*\\*")     ;  \**  ->  \*\*
    (beginning-of-buffer)

)





Steven Litvintchouk
MITRE Corporation
Burlington Road
Bedford, MA  01730
(617)271-7753

ARPA:  sdl@mitre-bedford.arpa
UUCP:  ...{cbosgd,decvax,genrad,ll-xn,mit-eddie,philabs,utzoo}!linus!sdl

	"Those who will be able to conquer software will be able to
	 conquer the world."  -- Tadahiro Sekimoto, president, NEC Corp.