From xemacs-m  Tue Feb  4 14:22:27 1997
Received: from steadfast.teradyne.com (steadfast.teradyne.com [131.101.1.200])
	by xemacs.org (8.8.5/8.8.5) with ESMTP id OAA07861
	for <xemacs-beta@xemacs.org>; Tue, 4 Feb 1997 14:22:26 -0600 (CST)
Received: from engine.ecf.teradyne.com (engine.ecf.teradyne.com [131.101.192.6]) by steadfast.teradyne.com (8.7.1/8.7.1) with ESMTP id PAA25207; Tue, 4 Feb 1997 15:23:46 -0500 (EST)
Received: from midnight.eng.ecf.teradyne.com (midnight.ecf.teradyne.com [131.101.192.49]) by engine.ecf.teradyne.com (8.7.1/8.7.1) with SMTP id VAA18281; Tue, 4 Feb 1997 21:19:57 +0100 (MET)
Received: by midnight.eng.ecf.teradyne.com (SMI-8.6/SMI-SVR4)
	id VAA02927; Tue, 4 Feb 1997 21:19:56 +0100
To: Michael McNamara <mac@silicon-sorcery.com>
Cc: XEmacs Beta Mailing List <xemacs-beta@xemacs.org>,
        Jens Edelmann <edelmann@ecf.teradyne.com>
X-Face: 4[iHdXiTu\V3u[~\I)<f9HC);%~nG8`oUqv#uzvs6=\V{AjN6Sn
 c/qi;YLwRmEbt8Y*=j5n(urqY@chPh@J'D"QlqD!C8>*}#kYF[-tYl3VZga/HSOP|K,{L
 Rtu@f0y/=O&Cu}\:~d|P$JON?pn?j,&CnPb1z#/TL9bkAJwyol&a:SvYj-VYbM=Dtxhk9
 =w|R6U3_;SH&B<Mfy6Q%#
Subject: Update of verilog-mode.el<2.21> for XEmacs-20.0 (3/4)
Mime-Version: 1.0 (split by tm-edit 7.101)
Content-Type: message/partial; id="Tue_Feb__4_21:19:50_1997@midnight.ecf.teradyne.com"; number=3; total=4
From: Adrian Aichner <aichner@ecf.teradyne.com>
Date: 04 Feb 1997 21:19:54 +0100
Message-ID: <rxsu3nscoid.fsf@midnight.ecf.teradyne.com>
Lines: 999
X-Mailer: Red Gnus v0.84/XEmacs 20.0

		(cond 
		 ((match-end 1) ; begin
		  (setq nest (1- nest))
		  (if (= 0 nest)
		      ;; Now previous line describes syntax
		      (throw 'skip 1))
		  (if (and snest
			   (= snest nest))
		      (setq reg sreg))
		  )
		 ((match-end 2) ; end
		  (setq nest (1+ nest))
		  )
		 ((match-end 3)
		  ;; endcase, jump to case
		  (setq snest nest)
		  (setq nest (1+ nest))
		  (setq sreg reg)
		  (setq reg "\\(\\<case[xz]?\\>[^:]\\)\\|\\(\\<endcase\\>\\)" )
		  )
		 ((match-end 4)
		  ;; join, jump to fork
		  (setq snest nest)
		  (setq nest (1+ nest))
		  (setq sreg reg)
		  (setq reg "\\(\\<fork\\>\\)\\|\\(\\<join\\>\\)" )
		  )
		 )
		)
	      )
	    )
	  )
      )
    )
  )
(defun verilog-continued-line ()
  "Return true if this is a continued line.
   Set point to where line starts"
  (let ((continued 't))
    (if (eq 0 (forward-line -1))
	(progn
	  (end-of-line)
	  (verilog-backward-ws&directives)
	  (if (bobp)
	      (setq continued nil)
	    (while (and continued
			(save-excursion
			  (skip-chars-backward " \t") 
			  (not (bolp))))
	      (setq continued (verilog-backward-token))
	      ) ;; while
	    )
	  )
      (setq continued nil)
      )
    continued)
  )

(defun verilog-backward-token ()
  "step backward token, returning true if we are now at an end of line token"
  (verilog-backward-syntactic-ws)
  (cond 
   ((bolp)
    nil)
   (;-- Anything ending in a ; is complete
    (= (preceding-char) ?\;)
    nil)
;;   (;-- Anything ending in a , is deemed complete
;;    (= (preceding-char) ?\,)
;;    nil)
   
   (;-- Could be 'case (foo)' or 'always @(bar)' which is complete
    (= (preceding-char) ?\))
    (progn
      (backward-char)
      (backward-up-list 1)
      (verilog-backward-syntactic-ws)
      (forward-word -1)
      (not (looking-at "\\<case[xz]?\\>[^:]"))))
   
   (;-- any of begin|initial|while are complete statements; 'begin : foo' is also complete
    t
    (forward-word -1)
    (cond 
     ( 
      (looking-at "\\(initial\\>\\)\\|\\(always\\>\\)")  
      t)
     ( 
      (looking-at verilog-indent-reg) 
      nil)
     (t
      (let 
	  ((back (point)))
	(verilog-backward-syntactic-ws)
	(cond
	 ((= (preceding-char) ?\:)
	  (backward-char)
	  (verilog-backward-syntactic-ws)
	  (backward-sexp)
	  (if (looking-at "begin")
	      nil
	    t)
	  )
	 ((= (preceding-char) ?\#)
	  (backward-char)
	  t)
	 
	 (t
	  (goto-char back)
	  t)
	 )
	)
      )
     )
    )
   )
)

(defun verilog-backward-syntactic-ws (&optional lim)
  ;; Backward skip over syntactic whitespace for Emacs 19.
  (save-restriction
    (let* ((lim (or lim (point-min)))
	   (here lim)
	   bol
	   )
      (if (< lim (point))
	  (progn
	    (narrow-to-region lim (point))
	    (while (/= here (point))
	      (setq here (point))
	      (forward-comment (-(buffer-size)))
	      (save-excursion
		(setq bol (progn (beginning-of-line) (point))))
	      (search-backward "//" bol t)
	      )))
      )))

(defun verilog-forward-syntactic-ws (&optional lim)
  ;; forward skip over syntactic whitespace for Emacs 19.
  (save-restriction
    (let* ((lim (or lim (point-max)))
	   (here lim)
	   )
      (if (> lim (point))
	  (progn
	    (narrow-to-region (point) lim)
	    (while (/= here (point))
	      (setq here (point))
	      (forward-comment (buffer-size))
	      )))
      )))

(defun verilog-backward-ws&directives (&optional lim)
  ;; Backward skip over syntactic whitespace and compiler directives for Emacs 19.
  (save-restriction
    (let* ((lim (or lim (point-min)))
	   (here lim)
	   jump
	   )
      (if (< lim (point))
	  (progn
	    (let ((state 
		   (save-excursion
		     (parse-partial-sexp (point-min) (point)))))
	      (cond
	       ((nth 4 state) ;; in /* */ comment
		(verilog-re-search-backward "/\*" nil 'move)
		)
	       ((nth 7 state) ;; in // comment
		(verilog-re-search-backward "//" nil 'move)
		)))
	    (narrow-to-region lim (point))
	    (while (/= here (point))
	      (setq here (point))
	      (forward-comment (-(buffer-size)))
	      (save-excursion
		(beginning-of-line)
		(if (looking-at "[ \t]*\\(`define\\)\\|\\(`ifdef\\)\\|\\(`else\\)\\|\\(`endif\\)\\|\\(`timescale\\)\\|\\(`include\\)")
		    (setq jump t)
		  (setq jump nil)))
	      (if jump
		  (beginning-of-line))
	      )))
      )))

(defun verilog-forward-ws&directives (&optional lim)
  ;; forward skip over syntactic whitespace and compiler directives for Emacs 19.
  (save-restriction
    (let* ((lim (or lim (point-max)))
	   (here lim)
	   jump
	   )
      (if (> lim (point))
	  (progn
	    (let ((state 
		   (save-excursion
		     (parse-partial-sexp (point-min) (point)))))
	      (cond
	       ((nth 4 state) ;; in /* */ comment
		(verilog-re-search-forward "/\*" nil 'move)
		)
	       ((nth 7 state) ;; in // comment
		(verilog-re-search-forward "//" nil 'move)
		)))
	    (narrow-to-region (point) lim)
	    (while (/= here (point))
	      (setq here (point))
	      (forward-comment (buffer-size))
	      (save-excursion
		(beginning-of-line)
		(if (looking-at "[ \t]*\\(`define\\)\\|\\(`ifdef\\)\\|\\(`else\\)\\|\\(`endif\\)\\|\\(`timescale\\)")
		    (setq jump t)))
	      (if jump
		  (beginning-of-line 2))
	      )))
      )))
(defun verilog-parenthesis-depth ()
 "Return non zero if in parenthetical-expression"
 (save-excursion
   (car (parse-partial-sexp (point-min) (point)))))

(defun verilog-in-comment-or-string-p ()
 "Return true if in a string or comment"
 (let ((state 
	(save-excursion
	  (parse-partial-sexp (point-min) (point)))))
   (or (nth 3 state) (nth 4 state) (nth 7 state))) ; Inside string or comment
 )

(defun verilog-in-star-comment-p ()
 "Return true if in a star comment"
 (let ((state 
	(save-excursion
	  (parse-partial-sexp (point-min) (point)))))
   (nth 4 state))
 )

(defun verilog-in-paren ()
 "Return true if in a parenthetical expression"
 (let ((state 
	(save-excursion
	  (parse-partial-sexp (point-min) (point)))))
   (/= 0 (nth 0 state)))
 )

(defun verilog-skip-forward-comment-or-string ()
 "Return true if in a string or comment"
 (let ((state 
	(save-excursion
	  (parse-partial-sexp (point-min) (point)))))
   (cond
    ((nth 3 state)			;Inside string
     (goto-char (nth 3 state))
     t)
    ((nth 7 state)			;Inside // comment
     (forward-line 1)
     t)
    ((nth 4 state)			;Inside any comment (hence /**/)
     (search-forward "*/"))
    (t
     nil)
    )
   )
 )

(defun verilog-skip-backward-comment-or-string ()
 "Return true if in a string or comment"
 (let ((state 
	(save-excursion
	  (parse-partial-sexp (point-min) (point)))))
   (cond
    ((nth 3 state)			;Inside string
     (search-backward "\"")
     t)
    ((nth 7 state)			;Inside // comment
     (search-backward "//")
     t)
    ((nth 4 state)			;Inside /* */ comment
     (search-backward "/*")
     t)
    (t
     nil)
    )
   )
 )

(defun verilog-skip-forward-comment-p ()
  "If in comment, move to end and return true"
  (let (state)
    (progn 
      (setq state
	    (save-excursion
	      (parse-partial-sexp (point-min) (point))))
      (cond 
       ((nth 3 state)
	t)
       ((nth 7 state)			;Inside // comment
	(end-of-line)
	(forward-char 1)
	t)
       ((nth 4 state)			;Inside any comment
	t)
       (t
	nil)
       )
      )
    )
  )

(defun verilog-indent-line-relative ()
  "Cheap version of indent line that only looks at
  a few lines to determine indent level"
  (interactive)
  (let ((indent-str))
    (save-excursion
      (beginning-of-line)
      (if (looking-at "^[ \t]*$")
	  (cond  ;- A blank line; No need to be too smart.
	   ((bobp)
	    (setq indent-str (list 'cpp 0)))
	   ((verilog-continued-line)
	    (let ((sp (point)))
	      (if (verilog-continued-line)
		  (progn (goto-char sp)
			 (setq indent-str (list 'statement (verilog-indent-level))))
		(goto-char sp)
		(setq indent-str (list 'block (verilog-indent-level))))))
	   (t
	    (setq indent-str (verilog-calculate-indent))))
	(setq indent-str (verilog-calculate-indent))
	)
      )
    (verilog-do-indent indent-str)
    )
  )
(defun verilog-indent-line ()
  "Indent for special part of code."
  (if (looking-at verilog-directive-re)
      ;; We could nicely nest `ifdef's, but...
      (progn
	(delete-horizontal-space)
	(indent-to 0)
	(list 'cpp 0))			; Return verilog-calculate-indent data
    (verilog-do-indent (verilog-calculate-indent)))
  )

(defun verilog-do-indent (indent-str)
  ""
  (let ((type (car indent-str))
	(ind (car (cdr indent-str))))
    (delete-horizontal-space)
    (cond 
     (; handle comma continued exp
      (eq type 'cexp)
      (let ((here (point)))
	(if (progn (verilog-backward-syntactic-ws)
		   (= (preceding-char) ?\,))
	    (let* ( fst
		    (column 
		     (save-excursion
		       (backward-char 1)
		       (verilog-beg-of-statement)
		       (setq fst (point))
		       (if (looking-at verilog-declaration-re)
			   (progn ;; we have multiple words
			     (goto-char (match-end 0))
			     (skip-chars-forward " \t")
			     (if (= (following-char) ?\[)
				 (progn
				   (forward-char 1)
				   (backward-up-list -1)
				   (skip-chars-forward " \t")
				   )
			       )
			     )
			 (;; we have a single word
			  goto-char fst)
			 )
		       (current-column)
		       )
		     )
		    )
	      (goto-char here)
	      (beginning-of-line)
	      (delete-horizontal-space)
	      (indent-to  column))
	  (progn
	    (goto-char here)
	    (let ((val (eval (cdr (assoc type verilog-indent-alist)))))
	      ;;	(verilog-comment-depth type val)
	      (delete-horizontal-space)
	      (indent-to val)
	      ))
	  )
	)
      )
     (;-- Declaration -- maybe line 'em up
      (and (not (or
		 (eq type 'cpp)
		 (eq type 'comment)))
	   (looking-at verilog-declaration-re)
	   (or (memq 'all verilog-auto-lineup)
	       (memq 'declaration  verilog-auto-lineup)))
      (verilog-indent-declaration (cond ((eq type 'defun) 0)
					(t ind)))
      )
     (; handle inside parenthetical expressions
      (eq type 'cparenexp)
      (let ((column (save-excursion
		      (backward-up-list 1)
		      (forward-char 1)
		      (skip-chars-forward " \t")
		      (current-column))))
	(beginning-of-line)
	(delete-horizontal-space)
	(indent-to  column)))

     (;-- Case -- maybe line 'em up
      (and (eq type 'case) (not (looking-at "^[ \t]*$")))
      (progn
	(cond
	 ((looking-at "\\<endcase\\>")
	  (indent-to ind))
	 (t
	  (indent-to (eval (cdr (assoc type verilog-indent-alist))))
	  ))))
     
     (;-- Handle the ends
      (looking-at verilog-end-block-re)
      (if (eq type 'statement)
	  (indent-to (- ind verilog-indent-level))		 
	(indent-to ind)))
     (;-- defun
      (and (eq type 'defun)
	   (looking-at verilog-zero-indent-re))
      (indent-to 0))

     (;-- Everything else
      t
      (let ((val (eval (cdr (assoc type verilog-indent-alist)))))
	;;	(verilog-comment-depth type val)
	(delete-horizontal-space)
	(indent-to val)
	))
     )
    (if (looking-at "[ \t]+$")
	(skip-chars-forward " \t"))
    indent-str				; Return verilog-calculate-indent data
    )
)
  
(defun verilog-indent-level ()
  "Return the indent-level the current statement has."
  (save-excursion
    (beginning-of-line)
    (skip-chars-forward " \t")
    (current-column)))


(defun verilog-case-indent-level ()
  "Return the indent-level the current statement has.
Do not count named blocks or case-statements."
  (save-excursion
    (beginning-of-line)
    (skip-chars-forward " \t")
    (cond
     ((looking-at verilog-named-block-re)
      (current-column))
     ((and (not (looking-at verilog-case-re))
	   (looking-at "[^:;]+[ \t]*:"))
      (search-forward ":" nil t)
      (skip-chars-forward " \t")
      (current-column))
     (t
      (current-column)))))

(defun verilog-indent-comment (&optional arg)
  "Indent current line as comment.
If optional arg is non-nil, just return the
column number the line should be indented to."
  (let* ((stcol 
	  (cond 
	   ((verilog-in-star-comment-p)
	    (save-excursion
	      (re-search-backward "/\\*" nil t)
	      (1+(current-column))))
	   ( comment-column
	     comment-column )
	   (t
	    (save-excursion
	      (re-search-backward "//" nil t)
	      (current-column)))
	   )
	  ))
    (if arg 
	(progn
	  (delete-horizontal-space)
	  (indent-to stcol))
      stcol
      )
    )
  )

;;;


(defun verilog-indent-declaration (base-ind &optional arg start end)
  "Indent current lines as declaration, lining up the variable names"
  (interactive)
  (let ((pos (point-marker))
	(lim (save-excursion (progn (end-of-line) (point-marker))))
	)
    (if (and (not (or arg start)) (not (verilog-re-search-forward verilog-declaration-re lim t)))
	()
      (progn
	(beginning-of-line)
	(delete-horizontal-space)
	(indent-to (+ base-ind (eval (cdr (assoc 'declaration verilog-indent-alist)))))
	(let* ((pos2 (point-marker))
	       (more 1)
	       here
	       (stpos (if start start
		       (save-excursion
			 
			 (goto-char pos2)
			 (catch 'first
			   (while more
			     (setq here (point))
			     (verilog-backward-syntactic-ws)
			     (if (= (preceding-char) ?\;)
				 (backward-char))
			     (verilog-beg-of-statement)
			     (if (bobp)
				 (throw 'first (point-marker)))		
			     (if (looking-at verilog-declaration-re)
				 (setq more (/= (point) here))
			       (throw 'first (point-marker))))
			   (throw 'first (point-marker)))
			 )
		       )
		      )
	       (edpos (if end 
			  (set-marker (make-marker) end)
			lim))
	       ind)
	  (goto-char stpos)
	  ;; Indent lines in declaration block
	  (if arg
	      (while (<= (point) (marker-position edpos))
		(beginning-of-line)
		(delete-horizontal-space)
		(cond 
		 ((looking-at "^[ \t]*$")
		  ())
		 ((not (looking-at verilog-declaration-re))
		  (indent-to arg))
		 (t
		  (indent-to (+ arg verilog-indent-level))))
		(forward-line 1)))
	  
	  ;; Do lineup
	  (setq ind (verilog-get-lineup-indent stpos edpos))
	  (goto-char stpos)
	  (if (> (- edpos stpos) 100)
	      (message "Lining up declarations..(please stand by)"))
	  (let (e)
	    (while (progn (setq e (marker-position edpos))
			  (< (point) e))
	      (if (verilog-re-search-forward verilog-declaration-re-1 e 'move)
		  (just-one-space))
;;		  (forward-char -1))
	      (save-excursion
		(let ((p (point)))
		  (beginning-of-line)
		  (if (verilog-re-search-forward "\\[" p 'move)
		      (progn
			(forward-char -1)
			(just-one-space)))
		  ))
	      (delete-horizontal-space)
	      (indent-to ind)
	      (beginning-of-line)
	      (delete-horizontal-space)	      
	      (indent-to (+ base-ind (eval (cdr (assoc 'declaration verilog-indent-alist)))))
	      (forward-line 1)))))
	
      ;; If arg - move point
      (message "")
      (if arg (forward-line -1)
	(goto-char (marker-position pos))))))

;  "Return the indent level that will line up several lines within the region
;from b to e nicely. The lineup string is str."
(defun verilog-get-lineup-indent (b edpos)
  (save-excursion
    (let ((ind 0) e)
      (goto-char b)
      ;; Get rightmost position
      (while (progn (setq e (marker-position edpos))
		    (< (point) e))
	(if (verilog-re-search-forward verilog-declaration-re-1 e 'move)
	    (progn
	      (goto-char (match-end 0))
	      (verilog-backward-syntactic-ws)
	      (if (> (current-column) ind)
		  (setq ind (current-column)))
	      (goto-char (match-end 0)))))
      (if (> ind 0)
	  (1+ ind)
	;; No lineup-string found
	(goto-char b)
	(end-of-line)
	(skip-chars-backward " \t")
	(1+ (current-column))))))

;;    A useful mode debugging aide
(defun verilog-comment-depth (type val)
  ""
  (save-excursion 
    (let 
	((b (prog2
		(beginning-of-line)
		(point-marker)
	      (end-of-line)))
	 (e (point-marker)))	      
      (if (re-search-backward " /\\* \[#-\]# \[a-z\]+ \[0-9\]+ ## \\*/" b t) 
	  (progn 
	    (replace-match " /* -#  ## */") 
	    (end-of-line))
	(progn 
	  (end-of-line)
	  (insert " /* ##  ## */"))))
    (backward-char 6) 
    (insert 
     (format "%s %d" type val))
    )
  )
;;; 
;;;
;;; Completion
;;;
(defvar verilog-str nil)
(defvar verilog-all nil)
(defvar verilog-pred nil)
(defvar verilog-buffer-to-use nil)
(defvar verilog-flag nil)
(defvar verilog-toggle-completions nil
  "*Non-nil means \\<verilog-mode-map>\\[verilog-complete-word] should try all possible completions one by one.
Repeated use of \\[verilog-complete-word] will show you all of them.
Normally, when there is more than one possible completion,
it displays a list of all possible completions.")


(defvar verilog-type-keywords
  '("buf" "bufif0" "bufif1" "cmos" "defparam" "inout" "input"
    "integer" "nand" "nmos" "nor" "not" "notif0" "notif1" "or" "output" "parameter"
    "pmos" "pull0" "pull1" "pullup" "rcmos" "real" "realtime" "reg" "rnmos" "rpmos" "rtran"
    "rtranif0" "rtranif1" "time" "tran" "tranif0" "tranif1" "tri" "tri0" "tri1"
    "triand" "trior" "trireg" "wand" "wire" "wor" "xnor" "xor" )
  "*Keywords for types used when completing a word in a declaration or parmlist.
\(eg. integer, real, char.)  The types defined within the Verilog program
will be completed runtime, and should not be added to this list.")

(defvar verilog-defun-keywords
  '("begin" "function" "task" "initial" "always" "assign" "posedge" "negedge" "endmodule")
  "*Keywords to complete when standing at first word of a line in declarative scope.
\(eg. initial, always, begin, assign.)
The procedures and variables defined within the Verilog program
will be completed runtime and should not be added to this list.")

(defvar verilog-block-keywords
  '("begin" "fork" "join" "case" "end" "if" "else" "for" "while" "repeat")
  "*Keywords to complete when standing at first word of a line in behavorial scope.
\(eg. begin, if, then, else, for, fork.)
The procedures and variables defined within the Verilog program
will be completed runtime and should not be added to this list.")

(defvar verilog-tf-keywords
  '("begin" "fork" "join" "case" "end" "endtask" "endfunction" "if" "else" "for" "while" "repeat")
  "*Keywords to complete when standing at first word of a line in a task or function scope.
\(eg. begin, if, then, else, for, fork.)
The procedures and variables defined within the Verilog program
will be completed runtime and should not be added to this list.")

(defvar verilog-case-keywords
  '("begin" "fork" "join" "case" "end" "endcase" "if" "else" "for" "repeat")
  "*Keywords to complete when standing at first word of a line in behavorial scope.
\(eg. begin, if, then, else, for, fork.)
The procedures and variables defined within the Verilog program
will be completed runtime and should not be added to this list.")

(defvar verilog-separator-keywords
  '("else" "then" "begin")
  "*Keywords to complete when NOT standing at the first word of a statement.
\(eg. else, then.) 
Variables and function names defined within the
Verilog program are completed runtime and should not be added to this list.")

(defun verilog-string-diff (str1 str2)
  "Return index of first letter where STR1 and STR2 differs."
  (catch 'done
    (let ((diff 0))
      (while t
	(if (or (> (1+ diff) (length str1))
		(> (1+ diff) (length str2)))
	    (throw 'done diff))
	(or (equal (aref str1 diff) (aref str2 diff))
	    (throw 'done diff))
	(setq diff (1+ diff))))))

;; Calculate all possible completions for functions if argument is `function',
;; completions for procedures if argument is `procedure' or both functions and
;; procedures otherwise.

(defun verilog-func-completion (type)
  ;; Build regular expression for module/task/function names
  (if (string= verilog-str "")
      (setq verilog-str "[a-zA-Z_]"))
  (let ((verilog-str (concat (cond
			     ((eq type 'module) "\\<\\(module\\)\\s +")
			     ((eq type 'tf) "\\<\\(task\\|function\\)\\s +")
			     (t "\\<\\(task\\|function\\|module\\)\\s +"))
			    "\\<\\(" verilog-str "[a-zA-Z0-9_.]*\\)\\>"))
	match)
    
    (if (not (looking-at verilog-defun-re))
	(verilog-re-search-backward verilog-defun-re nil t))
    (forward-char 1)

    ;; Search through all reachable functions
    (goto-char (point-min))
    (while (verilog-re-search-forward verilog-str (point-max) t)
      (progn (setq match (buffer-substring (match-beginning 2)
					   (match-end 2)))
	     (if (or (null verilog-pred)
		     (funcall verilog-pred match))
		 (setq verilog-all (cons match verilog-all)))))
    (if (match-beginning 0)
	(goto-char (match-beginning 0)))))

(defun verilog-get-completion-decl ()
  ;; Macro for searching through current declaration (var, type or const)
  ;; for matches of `str' and adding the occurence tp `all'
  (let ((end (save-excursion (verilog-declaration-end)
			     (point)))
	match)
    ;; Traverse lines
    (while (< (point) end)
      (if (verilog-re-search-forward verilog-declaration-re-1 (verilog-get-end-of-line) t)
	  ;; Traverse current line
	  (while (and (verilog-re-search-forward 
		       (concat "\\((\\|\\<\\(var\\|type\\|const\\)\\>\\)\\|" 
			       verilog-symbol-re)
		       (verilog-get-beg-of-line) t)
		      (not (match-end 1)))
	    (setq match (buffer-substring (match-beginning 0) (match-end 0)))
	    (if (string-match (concat "\\<" verilog-str) match)
		(if (or (null verilog-pred)
			(funcall verilog-pred match))
		    (setq verilog-all (cons match verilog-all))))))
      (if (verilog-re-search-forward "\\<record\\>" (verilog-get-end-of-line) t)
	  (verilog-declaration-end)
	(forward-line 1)))))

(defun verilog-type-completion ()
  "Calculate all possible completions for types."
  (let ((start (point))
	goon)
    ;; Search for all reachable type declarations
    (while (or (verilog-beg-of-defun)
	       (setq goon (not goon)))
      (save-excursion
	(if (and (< start (prog1 (save-excursion (verilog-end-of-defun)
						 (point))
			    (forward-char 1)))
		 (verilog-re-search-forward
		  "\\<type\\>\\|\\<\\(begin\\|function\\|procedure\\)\\>"
		  start t)
		 (not (match-end 1)))
	    ;; Check current type declaration
	    (verilog-get-completion-decl))))))

(defun verilog-var-completion ()
  "Calculate all possible completions for variables (or constants)."
  nil)
;  Not done yet; in 1.99 perhaps
;  (let ((start (point))
;	goon twice)
;    ;; Search for all reachable var declarations
;    (while (or (verilog-beg-of-defun)
;	       (setq goon (not goon)))
;      (save-excursion
;	(if (> start (prog1 (save-excursion (verilog-end-of-defun)
;					    (point))))
;	    () ; Declarations not reacable
;	  (cond ((and (verilog-re-search-forward  verilog-declaration-re start t)
;		      ;; Check var/const declarations
;		      (verilog-get-completion-decl)))))))))


(defun verilog-keyword-completion (keyword-list)
  "Give list of all possible completions of keywords in KEYWORD-LIST."
  (mapcar '(lambda (s) 
	     (if (string-match (concat "\\<" verilog-str) s)
		 (if (or (null verilog-pred)
			 (funcall verilog-pred s))
		     (setq verilog-all (cons s verilog-all)))))
	  keyword-list))

;; Function passed to completing-read, try-completion or
;; all-completions to get completion on STR. If predicate is non-nil,
;; it must be a function to be called for every match to check if this
;; should really be a match. If flag is t, the function returns a list
;; of all possible completions. If it is nil it returns a string, the
;; longest possible completion, or t if STR is an exact match. If flag
;; is 'lambda, the function returns t if STR is an exact match, nil
;; otherwise.

(defun verilog-completion (verilog-str verilog-pred verilog-flag)
  (save-excursion
    (let ((verilog-all nil))
      ;; Set buffer to use for searching labels. This should be set
      ;; within functins which use verilog-completions
      (set-buffer verilog-buffer-to-use)

      ;; Determine what should be completed
      (let ((state (car (verilog-calculate-indent))))
	(cond ((eq state 'defun)
	       (save-excursion (verilog-var-completion))
	       (verilog-func-completion 'module)
	       (verilog-keyword-completion verilog-defun-keywords))

	      ((eq state 'block)
	       (save-excursion (verilog-var-completion))
	       (verilog-func-completion 'tf)
	       (verilog-keyword-completion verilog-block-keywords))

	      ((eq state 'case)
	       (save-excursion (verilog-var-completion))
	       (verilog-func-completion 'tf)
	       (verilog-keyword-completion verilog-case-keywords))

	      ((eq state 'tf)
	       (save-excursion (verilog-var-completion))
	       (verilog-func-completion 'tf)
	       (verilog-keyword-completion verilog-tf-keywords))
      
	      (t;--Anywhere else
	       (save-excursion (verilog-var-completion))
	       (verilog-func-completion 'both)
	       (verilog-keyword-completion verilog-separator-keywords))))
      
      ;; Now we have built a list of all matches. Give response to caller
      (verilog-completion-response))))

(defun verilog-completion-response ()
  (cond ((or (equal verilog-flag 'lambda) (null verilog-flag))
	 ;; This was not called by all-completions
	 (if (null verilog-all)
	     ;; Return nil if there was no matching label
	     nil
	   ;; Get longest string common in the labels
	   (let* ((elm (cdr verilog-all))
		  (match (car verilog-all))
		  (min (length match))
		  tmp)
	     (if (string= match verilog-str)
		 ;; Return t if first match was an exact match
		 (setq match t)
	       (while (not (null elm))
		 ;; Find longest common string
		 (if (< (setq tmp (verilog-string-diff match (car elm))) min)
		     (progn
		       (setq min tmp)
		       (setq match (substring match 0 min))))
		 ;; Terminate with match=t if this is an exact match
		 (if (string= (car elm) verilog-str)
		     (progn
		       (setq match t)
		       (setq elm nil))
		   (setq elm (cdr elm)))))
	     ;; If this is a test just for exact match, return nil ot t
	     (if (and (equal verilog-flag 'lambda) (not (equal match 't)))
		 nil
	       match))))
	;; If flag is t, this was called by all-completions. Return
	;; list of all possible completions
	(verilog-flag
	 verilog-all)))

(defvar verilog-last-word-numb 0)
(defvar verilog-last-word-shown nil)
(defvar verilog-last-completions nil)

(defun verilog-complete-word ()
  "Complete word at current point.
\(See also `verilog-toggle-completions', `verilog-type-keywords',
`verilog-start-keywords' and `verilog-separator-keywords'.)"
  (interactive)
  (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point)))
	 (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point)))
	 (verilog-str (buffer-substring b e))
	 ;; The following variable is used in verilog-completion
	 (verilog-buffer-to-use (current-buffer))
	 (allcomp (if (and verilog-toggle-completions
			   (string= verilog-last-word-shown verilog-str))
		      verilog-last-completions
		    (all-completions verilog-str 'verilog-completion)))
	 (match (if verilog-toggle-completions
		    "" (try-completion
			verilog-str (mapcar '(lambda (elm)
					      (cons elm 0)) allcomp)))))
    ;; Delete old string
    (delete-region b e)

    ;; Toggle-completions inserts whole labels
    (if verilog-toggle-completions
	(progn
	  ;; Update entry number in list
	  (setq verilog-last-completions allcomp
		verilog-last-word-numb 
		(if (>= verilog-last-word-numb (1- (length allcomp)))
		    0
		  (1+ verilog-last-word-numb)))
	  (setq verilog-last-word-shown (elt allcomp verilog-last-word-numb))
	  ;; Display next match or same string if no match was found
	  (if (not (null allcomp))
	      (insert "" verilog-last-word-shown)
	    (insert "" verilog-str)
	    (message "(No match)")))
      ;; The other form of completion does not necessarly do that.

      ;; Insert match if found, or the original string if no match
      (if (or (null match) (equal match 't))
	  (progn (insert "" verilog-str)
		 (message "(No match)"))
	(insert "" match))
      ;; Give message about current status of completion
      (cond ((equal match 't)
	     (if (not (null (cdr allcomp)))
		 (message "(Complete but not unique)")
	       (message "(Sole completion)")))
	    ;; Display buffer if the current completion didn't help 
	    ;; on completing the label.
	    ((and (not (null (cdr allcomp))) (= (length verilog-str)
						(length match)))
	     (with-output-to-temp-buffer "*Completions*"
	       (display-completion-list allcomp))
	     ;; Wait for a keypress. Then delete *Completion*  window
	     (momentary-string-display "" (point))
	     (delete-window (get-buffer-window (get-buffer "*Completions*")))
	     )))))

(defun verilog-show-completions ()
  "Show all possible completions at current point."
  (interactive)
  (let* ((b (save-excursion (skip-chars-backward "a-zA-Z0-9_") (point)))
	 (e (save-excursion (skip-chars-forward "a-zA-Z0-9_") (point)))
	 (verilog-str (buffer-substring b e))
	 ;; The following variable is used in verilog-completion
	 (verilog-buffer-to-use (current-buffer))
	 (allcomp (if (and verilog-toggle-completions
			   (string= verilog-last-word-shown verilog-str))
		      verilog-last-completions
		    (all-completions verilog-str 'verilog-completion))))
    ;; Show possible completions in a temporary buffer.
    (with-output-to-temp-buffer "*Completions*"
      (display-completion-list allcomp))
    ;; Wait for a keypress. Then delete *Completion*  window
    (momentary-string-display "" (point))
    (delete-window (get-buffer-window (get-buffer "*Completions*")))))


(defun verilog-get-default-symbol ()
  "Return symbol around current point as a string."
  (save-excursion
    (buffer-substring (progn
			(skip-chars-backward " \t")
			(skip-chars-backward "a-zA-Z0-9_")
			(point))
		      (progn
			(skip-chars-forward "a-zA-Z0-9_")
			(point)))))

(defun verilog-build-defun-re (str &optional arg)
  "Return function/task/module starting with STR as regular expression.
With optional second arg non-nil, STR is the complete name of the instruction."
  (if arg
      (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "\\)\\>")
    (concat "^\\(function\\|task\\|module\\)[ \t]+\\(" str "[a-zA-Z0-9_]*\\)\\>")))

;; Function passed to completing-read, try-completion or
;; all-completions to get completion on any function name. If
;; predicate is non-nil, it must be a function to be called for every
;; match to check if this should really be a match. If flag is t, the
;; function returns a list of all possible completions. If it is nil
;; it returns a string, the longest possible completion, or t if STR
;; is an exact match. If flag is 'lambda, the function returns t if
;; STR is an exact match, nil otherwise.

