changeset 34011:075cc818f566

New commands to run ANTLR from within Emacs and to create Makefile rules. (antlr-tool-command): New user option. (antlr-ask-about-save): New user option. (antlr-makefile-specification): New user option. (antlr-file-formats-alist): New variable. (antlr-special-file-formats): New variable. (antlr-unknown-file-formats): New user option. (antlr-help-unknown-file-text): New variable. (antlr-help-rules-intro): New variable. (antlr-mode-map): Add [C-c C-r] for `antlr-run-tool'. (antlr-mode-menu): Add entries. (antlr-file-dependencies): New function. (antlr-directory-dependencies): New function. (antlr-superclasses-glibs): New function. (antlr-run-tool): New command. (antlr-makefile-insert-variable): New function. (antlr-insert-makefile-rules): New function. (antlr-show-makefile-rules): New command. More Emacs/XEmacs stuff. (antlr-no-action-keywords): New constant with value nil. (antlr-font-lock-keywords-alist): Use it. Old value would break syntax highlighting in Emacs-21.0. (antlr-default-directory): Emacs/XEmacs dependend function. (antlr-read-shell-command): Ditto. (antlr-with-displaying-help-buffer): Ditto. imenu, parsing and highlighting changes. (antlr-imenu-create-index-function): Don't create extra submenus for definitions in different grammar classes. It is not necessary for the menu and would make command `imenu' awkward to use. (antlr-skip-file-prelude): With ANTLR-2.7+, you can specify named header actions and more than one. (antlr-font-lock-tokendef-face): Changed color. (antlr-font-lock-tokenref-face): Changed color. (antlr-font-lock-additional-keywords): Also highlight lowercase. (antlr-mode-syntax-table): New variable. (antlr-mode): Populate and use it instead `java-mode-syntax-table'. (antlr-with-syntax-table): Don't copy syntax table. Minor changes: language setting. (antlr-language-alist): The value for file option "language" can be both an identifier and a string. Reported by Rajesh Radhakrishnan <radhakrs@email.uc.edu>. (antlr-language-limit-n-regexp): Change accordingly. Minor changes: tabs, hiding. (antlr-tab-offset-alist): Set `indent-tabs-mode' to nil instead t. (antlr-action-visibility): Also allow value nil to also hide the braces. Renamed from `antlr-tiny-action-length'. Suggested by Jay@aol.com. (antlr-hide-actions): Change accordingly. Hide line if completely hidden action is on a line of its own.
author Gerd Moellmann <gerd@gnu.org>
date Wed, 29 Nov 2000 16:55:47 +0000
parents a26368ea650a
children 65aae8790910
files lisp/progmodes/antlr-mode.el
diffstat 1 files changed, 538 insertions(+), 104 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/progmodes/antlr-mode.el	Wed Nov 29 16:49:08 2000 +0000
+++ b/lisp/progmodes/antlr-mode.el	Wed Nov 29 16:55:47 2000 +0000
@@ -1,9 +1,9 @@
 ;;; antlr-mode.el --- Major mode for ANTLR grammar files
 
-;; Copyright (C) 1999-2000 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
 ;;
 ;; Author: Christoph.Wedler@sap.com
-;; Version: $Id: antlr-mode.el,v 1.2 1999/12/16 19:30:34 wedler Exp $
+;; Version: 1.4
 ;; X-URL: http://www.fmi.uni-passau.de/~wedler/antlr-mode/
 
 ;; This file is part of GNU Emacs.
@@ -29,42 +29,58 @@
 ;; ANTLR is ANother Tool for Language Recognition (an excellent alternative to
 ;; lex/yacc), see <http://www.ANTLR.org> and <news:comp.compilers.tools.pccts>.
 
-;; Variable `antlr-language' is set according to the language in actions and
-;; semantic predicates of the grammar (see ANTLR's file option "language").
-;; The supported languages are "Java" (java-mode) and "Cpp" (c++-mode).  This
-;; package uses features of the Emacs package cc-mode.
+;; This package provides the following features:
+;;  * Syntax coloring (via font-lock) for grammar symbols and the code in
+;;    actions.  The latter depends on the language settings.
+;;  * Indentation for the current line (TAB) and selected region (C-M-\).
+;;  * Support for imenu/speedbar: menu "Index" (Parser, Lexer, TreeParser).
+;;  * Commands to move to previous/next rule, beginning/end of rule body etc.
+;;  * Commands to hide/unhide actions, upcase/downcase literals.
+;;  * Run ANTLR from within Emacs, create Makefile dependencies.
 
-;; This package provides the following features:
-;;  * Indentation for the current line (TAB) and selected region (C-M-\).
-;;  * Syntax coloring (via font-lock) with language dependent coloring.
-;;  * Support for imenu/speedbar: menu "Index" (Parser, Lexer, TreeParser).
-;;  * Direct move to previous/next rule, beginning/end of rule body etc.
+;; LANGUAGE SETTINGS.  This mode needs to know which language is used in
+;; actions and semantic predicated of the grammar.  This information is used
+;; for syntax coloring and the creation of the Makefile dependencies.  It is
+;; stored in variable `antlr-language' and automatically set according to
+;; ANTLR's file option "language", see `antlr-language-alist'.  The supported
+;; languages are "Java" (java-mode) and "Cpp" (c++-mode).
 
 ;; INDENTATION.  This package supports ANTLR's (intended) indentation style
 ;; which is based on a simple paren/brace/bracket depth-level calculation, see
 ;; `antlr-indent-line'.  The indentation engine of cc-mode is only used inside
 ;; block comments (it is not easy to use it for actions, esp if they come early
-;; in the rule body).  By default, this package uses TABs for a basic offset of
-;; 4 to be consistent to both ANTLR's conventions (TABs usage) and the
+;; in the rule body).  By default, this package defines a tab width of 4 to be
+;; consistent to both ANTLR's conventions (TABs usage) and the
 ;; `c-indentation-style' "java" which sets `c-basic-offset' to 4, see
 ;; `antlr-tab-offset-alist'.  You might want to set this variable to nil.
 
 ;; SYNTAX COLORING comes in three phases.  First, comments and strings are
 ;; highlighted.  Second, the grammar code is highlighted according to
-;; `antlr-font-lock-additional-keywords' (rule refs: blue, token refs: brown,
-;; definition: ditto+bold).  Third, actions, semantic predicates and arguments
-;; are highlighted according to the usual font-lock keywords of
+;; `antlr-font-lock-additional-keywords' (rule refs: dark blue, token refs:
+;; dark orange, definition: bold blue).  Third, actions, semantic predicates
+;; and arguments are highlighted according to the usual font-lock keywords of
 ;; `antlr-language', see also `antlr-font-lock-maximum-decoration'.  We define
 ;; special font-lock faces for the grammar code to allow you to distinguish
 ;; ANTLR keywords from Java/C++ keywords.
 
+;; MAKEFILE CREATION.  Command \\[antlr-show-makefile-rules] shows/inserts the
+;; dependencies for all grammar files in the current directory.  It considers
+;; import/export vocabularies and grammar inheritance and provides a value for
+;; the -glib option if necessary (which you have to edit if the super-grammar
+;; is not in the same directory).
+
+;; TODO.  Support to insert/change file/grammar/rule/subrule options.  imenu
+;; support for method definitions in actions is not really planned (you can
+;; send be a patch, though).  This mode would become too dependent on cc-mode
+;; or I would have to do a lot of language-dependent things myself...
+
 ;; Bug fixes, bug reports, improvements, and suggestions are strongly
 ;; appreciated.  Please check the newest version first:
 ;;   http://www.fmi.uni-passau.de/~wedler/antlr-mode/changes.html
 
 ;;; Installation:
 
-;; This file requires Emacs-20.3, XEmacs-20.4 or higher.
+;; This file requires Emacs-20.3, XEmacs-20.4 or higher and package cc-mode.
 
 ;; If antlr-mode is not part of your distribution, put this file into your
 ;; load-path and the following into your ~/.emacs:
@@ -86,19 +102,33 @@
 ;;; Code:
 
 (provide 'antlr-mode)
-(eval-when-compile (require 'cc-mode))	; shut up most warnings
-(require 'easymenu)			; Emacs
-(eval-when-compile			; optional libraries
-  (defvar outline-level) (defvar imenu-use-markers))
-(eval-when-compile			; Emacs: cl, XEmacs vars
-  (require 'cl))
+(eval-when-compile			; required and optional libraries
+  (require 'cc-mode)
+  (defvar outline-level) (defvar imenu-use-markers)
+  (defvar imenu-create-index-function))
+(eval-when-compile			; Emacs: cl, easymenu
+  (require 'cl)
+  (require 'easymenu))
 (eval-when-compile			; XEmacs: Emacs vars
   (defvar inhibit-point-motion-hooks) (defvar deactivate-mark))
 
-(eval-and-compile
-  (if (string-match "XEmacs" emacs-version)
+(eval-and-compile			; XEmacs functions, simplified
+  (if (featurep 'xemacs)
       (defalias 'antlr-scan-sexps 'scan-sexps)
     (defalias 'antlr-scan-sexps 'antlr-scan-sexps-internal))
+  (if (fboundp 'default-directory)
+      (defalias 'antlr-default-directory 'default-directory)
+    (defun antlr-default-directory () default-directory))
+  (if (fboundp 'read-shell-command)
+      (defalias 'antlr-read-shell-command 'read-shell-command)
+    (defun antlr-read-shell-command (prompt &optional initial-input history)
+      (read-from-minibuffer prompt initial-input nil nil
+			    (or history 'shell-command-history))))
+  (if (fboundp 'with-displaying-help-buffer)
+      (defalias 'antlr-with-displaying-help-buffer 'with-displaying-help-buffer)
+    (defun antlr-with-displaying-help-buffer (thunk &optional name)
+      (with-output-to-temp-buffer "*Help*"
+	(save-excursion (funcall thunk)))))
   (if (and (fboundp 'buffer-syntactic-context)
 	   (fboundp 'buffer-syntactic-context-depth))
       (progn
@@ -121,7 +151,7 @@
   :link '(url-link "http://www.fmi.uni-passau.de/~wedler/antlr-mode/")
   :prefix "antlr-")
 
-(defconst antlr-version "1.3"
+(defconst antlr-version "1.4"
   "ANTLR major mode version number.")
 
 
@@ -137,16 +167,16 @@
 `enable-local-variables'.")
 
 (defcustom antlr-language-alist
-  '((java-mode "Java" nil "Java")
-    (c++-mode "C++" "Cpp"))
+  '((java-mode "Java" nil "\"Java\"" "Java")
+    (c++-mode "C++" "\"Cpp\"" "Cpp"))
   "List of ANTLR's supported languages.
 Each element in this list looks like
   (MAJOR-MODE MODELINE-STRING OPTION-VALUE...)
 
 MAJOR-MODE, the major mode of the code in the grammar's actions, is the
-value of `antlr-language' if the first regexp group matched by REGEXP in
-`antlr-language-limit-n-regexp' is one of the OPTION-VALUEs.  An
-OPTION-VALUE of nil denotes the fallback element.  MODELINE-STRING is
+value of `antlr-language' if the first group in the string matched by
+REGEXP in `antlr-language-limit-n-regexp' is one of the OPTION-VALUEs.
+An OPTION-VALUE of nil denotes the fallback element.  MODELINE-STRING is
 also displayed in the modeline next to \"Antlr\"."
   :group 'antlr
   :type '(repeat (group :value (java-mode "")
@@ -157,25 +187,28 @@
 					string )))))
 
 (defcustom antlr-language-limit-n-regexp
-  '(3000 . "language[ \t]*=[ \t]*\"\\([A-Z][A-Za-z_]*\\)\"")
+  '(3000 . "language[ \t]*=[ \t]*\\(\"?[A-Z][A-Za-z_]*\"?\\)")
   "Used to set a reasonable value for `antlr-language'.
 Looks like (LIMIT . REGEXP).  Search for REGEXP from the beginning of
-the buffer to LIMIT to set the language according to
-`antlr-language-alist'."
+the buffer to LIMIT and use the first group in the matched string to set
+the language according to `antlr-language-alist'."
   :group 'antlr
   :type '(cons (choice :tag "Limit" (const :tag "No" nil) (integer :value 0))
 	       regexp))
 
 
 ;;;===========================================================================
-;;;  Indent/Tabs
+;;;  Hide/Unhide, Indent/Tabs
 ;;;===========================================================================
 
-(defcustom antlr-tiny-action-length 3
-  "Maximal number of characters in actions never to hide.
-See command `antlr-hide-actions'."
+(defcustom antlr-action-visibility 3
+  "Visibility of actions when command `antlr-hide-actions' is used.
+If nil, the actions with their surrounding braces are hidden.  If a
+number, do not hide the braces, only hide the contents if its length is
+greater than this number."
   :group 'antlr
-  :type 'integer)
+  :type '(choice (const :tag "Completely hidden" nil)
+		 (integer :tag "Hidden if longer than" :value 3)))
 
 (defcustom antlr-indent-comment 'tab
   "*Non-nil, if the indentation should touch lines in block comments.
@@ -188,8 +221,8 @@
 		(sexp :tag "With TAB" :format "%t" :value tab)))
 
 (defcustom antlr-tab-offset-alist
-  '((antlr-mode nil 4 t)
-    (java-mode "antlr" 4 t))
+  '((antlr-mode nil 4 nil)
+    (java-mode "antlr" 4 nil))
   "Alist to determine whether to use ANTLR's convention for TABs.
 Each element looks like (MAJOR-MODE REGEXP TAB-WIDTH INDENT-TABS-MODE).
 The first element whose MAJOR-MODE is nil or equal to `major-mode' and
@@ -211,6 +244,113 @@
 
 
 ;;;===========================================================================
+;;;  Run tool, create Makefile dependencies
+;;;===========================================================================
+
+(defcustom antlr-tool-command "java antlr.Tool"
+  "*Command used in \\[antlr-run-tool] to run the Antlr tool.
+This variable should include all options passed to Antlr except the
+option \"-glib\" which is automatically suggested if necessary."
+  :group 'antlr
+  :type 'string)
+
+(defcustom antlr-ask-about-save t
+  "*If not nil, \\[antlr-run-tool] asks which buffers to save.
+Otherwise, it saves all modified buffers before running without asking."
+  :group 'antlr
+  :type 'boolean)
+
+(defcustom antlr-makefile-specification
+  '("\n" ("GENS" "GENS%d" " \\\n\t") "$(ANTLR)")
+  "*Variable to specify the appearance of the generated makefile rules.
+This variable influences the output of \\[antlr-show-makefile-rules].
+It looks like (RULE-SEP GEN-VAR-SPEC COMMAND).
+
+RULE-SEP is the string to separate different makefile rules.  COMMAND is
+a string with the command which runs the Antlr tool, it should include
+all options except the option \"-glib\" which is automatically added
+if necessary.
+
+If GEN-VAR-SPEC is nil, each target directly consists of a list of
+files.  If GEN-VAR-SPEC looks like (GEN-VAR GEN-VAR-FORMAT GEN-SEP), a
+Makefile variable is created for each rule target.
+
+Then, GEN-VAR is a string with the name of the variable which contains
+the file names of all makefile rules.  GEN-VAR-FORMAT is a format string
+producing the variable of each target with substitution COUNT/%d where
+COUNT starts with 1.  GEN-SEP is used to separate long variable values."
+  :group 'antlr
+  :type '(list (string :tag "Rule separator")
+	       (choice
+		(const :tag "Direct targets" nil)
+		(list :tag "Variables for targets"
+		      (string :tag "Variable for all targets")
+		      (string :tag "Format for each target variable")
+		      (string :tag "Variable separator")))
+	       (string :tag "ANTLR command")))
+
+(defvar antlr-file-formats-alist
+  '((java-mode ("%sTokenTypes.java") ("%s.java"))
+    (c++-mode ("%sTokenTypes.hpp") ("%s.cpp" "%s.hpp")))
+  "Language dependent formats which specify generated files.
+Each element in this list looks looks like
+  (MAJOR-MODE (VOCAB-FILE-FORMAT...) (CLASS-FILE-FORMAT...)).
+
+The element whose MAJOR-MODE is equal to `antlr-language' is used to
+specify the generated files which are language dependent.  See variable
+`antlr-special-file-formats' for language independent files.
+
+VOCAB-FILE-FORMAT is a format string, it specifies with substitution
+VOCAB/%s the generated file for each export vocabulary VOCAB.
+CLASS-FILE-FORMAT is a format string, it specifies with substitution
+CLASS/%s the generated file for each grammar class CLASS.")
+
+(defvar antlr-special-file-formats '("%sTokenTypes.txt" "expanded%s.g")
+  "Language independent formats which specify generated files.
+The value looks like (VOCAB-FILE-FORMAT EXPANDED-GRAMMAR-FORMAT).
+
+VOCAB-FILE-FORMAT is a format string, it specifies with substitution
+VOCAB/%s the generated or input file for each export or import
+vocabulary VOCAB, respectively.  EXPANDED-GRAMMAR-FORMAT is a format
+string, it specifies with substitution GRAMMAR/%s the constructed
+grammar file if the file GRAMMAR.g contains a grammar class which
+extends a class other than \"Lexer\", \"Parser\" or \"TreeParser\".
+
+See variable `antlr-file-formats-alist' for language dependent
+formats.")
+
+(defvar antlr-unknown-file-formats '("?%s?.g" "?%s?")
+  "*Formats which specify the names of unknown files.
+The value looks like (SUPER-GRAMMAR-FILE-FORMAT SUPER-EVOCAB-FORMAT).
+
+SUPER-GRAMMAR-FORMAT is a format string, it specifies with substitution
+SUPER/%s the name of a grammar file for Antlr's option \"-glib\" if no
+grammar file in the current directory defines the class SUPER or if it
+is defined more than once.  SUPER-EVOCAB-FORMAT is a format string, it
+specifies with substitution SUPER/%s the name for the export vocabulary
+of above mentioned class SUPER.")
+
+(defvar antlr-help-unknown-file-text
+  "## The following rules contain filenames of the form
+##  \"?SUPERCLASS?.g\" (and \"?SUPERCLASS?TokenTypes.txt\")
+## where SUPERCLASS is not found to be defined in any grammar file of
+## the current directory or is defined more than once.  Please replace
+## these filenames by the grammar files (and their exportVocab).\n\n"
+  "String indicating the existence of unknown files in the Makefile.
+See \\[antlr-show-makefile-rules] and `antlr-unknown-file-formats'.")
+
+(defvar antlr-help-rules-intro
+  "The following Makefile rules define the dependencies for all (non-
+expanded) grammars in directory \"%s\".\n
+They are stored in the kill-ring, i.e., you can insert them with C-y
+into your Makefile.  You can also invoke M-x antlr-show-makefile-rules
+from within a Makefile to insert them directly.\n\n\n"
+  "Introduction to use with \\[antlr-show-makefile-rules].
+It is a format string and used with substitution DIRECTORY/%s where
+DIRECTORY is the name of the current directory.")
+
+
+;;;===========================================================================
 ;;;  Menu
 ;;;===========================================================================
 
@@ -234,6 +374,7 @@
     (define-key map "\C-c\C-b" 'c-backward-into-nomenclature)
     (define-key map "\C-c\C-c" 'comment-region)
     (define-key map "\C-c\C-v" 'antlr-hide-actions)
+    (define-key map "\C-c\C-r" 'antlr-run-tool)
     ;; I'm too lazy to define my own:
     (define-key map "\ea" 'c-beginning-of-statement)
     (define-key map "\ee" 'c-end-of-statement)
@@ -270,7 +411,10 @@
 		    "---"
 		    ["Hide Actions (incl. Args)" antlr-hide-actions t]
 		    ["Hide Actions (excl. Args)" (antlr-hide-actions 2) t]
-		    ["Unhide All Actions" (antlr-hide-actions 0) t]))
+		    ["Unhide All Actions" (antlr-hide-actions 0) t]
+		    "---"
+		    ["Run Tool on Grammar" antlr-run-tool t]
+		    ["Show Makefile Rules" antlr-show-makefile-rules t]))
 
 
 ;;;===========================================================================
@@ -306,13 +450,20 @@
 				      (const :tag "maximum" t)
 				      (integer :tag "level" 1))))))
 
+(defconst antlr-no-action-keywords nil
+  ;; Using nil directly won't work (would use highest level, see
+  ;; `font-lock-choose-keywords'), but a non-symbol, i.e., (list), at `car'
+  ;; would break Emacs-21.0:
+  "Empty font-lock keywords for actions.
+Do not change the value of this constant.")
+
 (defvar antlr-font-lock-keywords-alist
   '((java-mode
-     (list)				; nil won't work (would use level-3)
+     antlr-no-action-keywords
      java-font-lock-keywords-1 java-font-lock-keywords-2
      java-font-lock-keywords-3)
     (c++-mode
-     (list)				; nil won't work (would use level-3)
+     antlr-no-action-keywords
      c++-font-lock-keywords-1 c++-font-lock-keywords-2
      c++-font-lock-keywords-3))
   "List of font-lock keywords for actions in the grammar.
@@ -338,7 +489,7 @@
 
 (defvar antlr-font-lock-tokendef-face 'antlr-font-lock-tokendef-face)
 (defface antlr-font-lock-tokendef-face
-  '((((class color) (background light)) (:foreground "brown3" :bold t)))
+  '((((class color) (background light)) (:foreground "blue" :bold t)))
   "ANTLR token references (definition)."
   :group 'antlr)
 
@@ -350,7 +501,7 @@
 
 (defvar antlr-font-lock-tokenref-face 'antlr-font-lock-tokenref-face)
 (defface antlr-font-lock-tokenref-face
-  '((((class color) (background light)) (:foreground "brown4")))
+  '((((class color) (background light)) (:foreground "orange4")))
   "ANTLR token references (usage)."
   :group 'antlr)
 
@@ -362,7 +513,7 @@
 
 (defvar antlr-font-lock-additional-keywords
   `((antlr-invalidate-context-cache)
-    ("\\$setType[ \t]*(\\([A-Z\300-\326\330-\337]\\sw*\\))"
+    ("\\$setType[ \t]*(\\([A-Za-z\300-\326\330-\337]\\sw*\\))"
      (1 antlr-font-lock-tokendef-face))
     ("\\$\\sw+" (0 font-lock-keyword-face))
     ;; the tokens are already fontified as string/docstrings:
@@ -373,7 +524,7 @@
 	    '((0 nil))))		; XEmacs bug workaround
     (,(lambda (limit)
 	(antlr-re-search-forward
-	 "^\\(class\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+\\(extends\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;" limit))
+	 "^\\(class\\)[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+\\(extends\\)[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;" limit))
      (1 antlr-font-lock-keyword-face)
      (2 antlr-font-lock-ruledef-face)
      (3 antlr-font-lock-keyword-face)
@@ -426,14 +577,17 @@
 (defvar antlr-mode-hook nil
   "Hook called by `antlr-mode'.")
 
+(defvar antlr-mode-syntax-table nil
+  "Syntax table used in `antlr-mode' buffers.
+If non-nil, it will be initialized in `antlr-mode'.")
+
 ;; used for "in Java/C++ code" = syntactic-depth>0
 (defvar antlr-action-syntax-table nil
   "Syntax table used for ANTLR action parsing.
-Initialized by `java-mode-syntax-table', i.e., the syntax table used for
-grammar files, changed by SYNTAX-ALIST in `antlr-font-lock-defaults'.
-This table should be selected if you use `buffer-syntactic-context' and
-`buffer-syntactic-context-depth' in order not to confuse their
-context_cache.")
+Initialized by `antlr-mode-syntax-table', changed by SYNTAX-ALIST in
+`antlr-font-lock-defaults'.  This table should be selected if you use
+`buffer-syntactic-context' and `buffer-syntactic-context-depth' in order
+not to confuse their context_cache.")
 
 (defvar antlr-mode-abbrev-table nil
   "Abbreviation table used in `antlr-mode' buffers.")
@@ -450,11 +604,12 @@
 ;;;  Syntax functions -- Emacs vs XEmacs dependent
 ;;;===========================================================================
 
-;; From help.el (XEmacs-21.1)
+;; From help.el (XEmacs-21.1), without `copy-syntax-table'
 (defmacro antlr-with-syntax-table (syntab &rest body)
+  "Evaluate BODY with the syntax table SYNTAB."
   `(let ((stab (syntax-table)))
      (unwind-protect
-	 (progn (set-syntax-table (copy-syntax-table ,syntab)) ,@body)
+	 (progn (set-syntax-table ,syntab) ,@body)
        (set-syntax-table stab))))
 (put 'antlr-with-syntax-table 'lisp-indent-function 1)
 (put 'antlr-with-syntax-table 'edebug-form-spec '(form body))
@@ -585,10 +740,6 @@
 (defun antlr-imenu-create-index-function ()
   "Return imenu index-alist for ANTLR grammar files."
   (let ((items nil)
-	(lexer nil)
-	(parser nil)
-	(treeparser nil)
-	(misc nil)
 	(classes nil)
 	(semi (point-max)))
     ;; Using `imenu-progress-message' would require imenu for compilation --
@@ -603,24 +754,12 @@
 	    (progn (forward-char) (antlr-skip-exception-part t))
 	  (antlr-skip-file-prelude t))
 	(if (looking-at "{") (antlr-skip-sexps 1))
-	(if (looking-at "class[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;")
-	    (progn
-	      (push (cons (match-string 1)
-			  (if imenu-use-markers
-			      (copy-marker (match-beginning 1))
-			    (match-beginning 1)))
-		    classes)
-	      (if items
-		  (let ((super (match-string 2)))
-		    (cond ((string-equal super "Parser")
-			   (setq parser (nconc items parser)))
-			  ((string-equal super "Lexer")
-			   (setq lexer (nconc items lexer)))
-			  ((string-equal super "TreeParser")
-			   (setq treeparser (nconc items treeparser)))
-			  (t
-			   (setq misc (nconc items misc))))
-		    (setq items nil))))
+	(if (looking-at "class[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;")
+	    (push (cons (match-string 1)
+			(if imenu-use-markers
+			    (copy-marker (match-beginning 1))
+			  (match-beginning 1)))
+		  classes)
 	  (if (looking-at "p\\(ublic\\|rotected\\|rivate\\)")
 	      (antlr-skip-sexps 1))
 	  (when (looking-at "\\sw+")
@@ -629,15 +768,6 @@
 			    (copy-marker (match-beginning 0))
 			  (match-beginning 0)))
 		  items)))))
-    (or items				; outside any class
-	(prog1 (setq items misc) (setq misc nil))
-	(prog1 (setq items parser) (setq parser nil))
-	(prog1 (setq items lexer) (setq lexer nil))
-	(prog1 (setq items treeparser) (setq treeparser nil)))
-    (if misc (push (cons "Miscellaneous" misc) items))
-    (if treeparser (push (cons "TreeParser" treeparser) items))
-    (if lexer (push (cons "Lexer" lexer) items))
-    (if parser (push (cons "Parser" parser) items))
     (if classes (cons (cons "Classes" classes) items) items)))
 
 
@@ -670,12 +800,14 @@
 
 (defun antlr-skip-file-prelude (skip-comment)
   "Skip the file prelude: the header and file options.
-If SKIP-COMMENT is non-nil, also skip the comment after that part."
+If SKIP-COMMENT is non-nil, also skip the comment after that part.
+Return the start position of the file prelude."
   (let* ((pos (point))
 	 (pos0 pos))
     (c-forward-syntactic-ws)
     (if skip-comment (setq pos0 (point)))
-    (if (looking-at "header\\>") (setq pos (antlr-skip-sexps 2)))
+    (while (looking-at "header\\>[ \t]*\\(\"\\)?")
+      (setq pos (antlr-skip-sexps (if (match-beginning 1) 3 2))))
     (if (looking-at "options\\>") (setq pos (antlr-skip-sexps 2)))
     (or skip-comment (goto-char pos))
     pos0))
@@ -831,8 +963,9 @@
 Hide all actions including arguments in brackets if ARG is 1 or if
 called interactively without prefix argument.  Hide all actions
 excluding arguments in brackets if ARG is 2 or higher.  Unhide all
-actions if ARG is 0 or negative.  Never hide actions whose character
-length is shorter or equal to `antlr-tiny-action-length'."
+actions if ARG is 0 or negative.  See `antlr-action-visibility'.
+
+Display a message unless optional argument SILENT is non-nil."
   (interactive "p")
   ;; from Emacs/lazy-lock: `save-buffer-state'
   (let ((modified (buffer-modified-p))
@@ -842,18 +975,29 @@
 	buffer-file-name buffer-file-truename)
     (if (> arg 0)
 	(let ((regexp (if (= arg 1) "[]}]" "}"))
-	      (diff (+ (max antlr-tiny-action-length 0) 2)))
+	      (diff (and antlr-action-visibility
+			 (+ (max antlr-action-visibility 0) 2))))
 	  (antlr-hide-actions 0 t)
 	  (save-excursion
 	    (goto-char (point-min))
 	    (antlr-with-syntax-table antlr-action-syntax-table
 	      (antlr-invalidate-context-cache)
 	      (while (antlr-re-search-forward regexp nil)
-		(let* ((end (point))
-		       (beg (antlr-scan-sexps (point) -1 nil t)))
-		  (and beg (> end (+ beg diff))
-		       (add-text-properties (1+ beg) (1- end)
-					    '(invisible t intangible t)))))))
+		(let ((beg (antlr-scan-sexps (point) -1 nil t)))
+		  (when beg
+		    (if diff		; braces are visible
+			(if (> (point) (+ beg diff))
+			    (add-text-properties (1+ beg) (1- (point))
+						 '(invisible t intangible t)))
+		      ;; if actions is on line(s) of its own, hide WS
+		      (and (looking-at "[ \t]*$")
+			   (save-excursion
+			     (goto-char beg)
+			     (skip-chars-backward " \t")
+			     (and (bolp) (setq beg (point))))
+			   (beginning-of-line 2)) ; beginning of next line
+		      (add-text-properties beg (point)
+					   '(invisible t intangible t))))))))
 	  (or silent
 	      (message "Hide all actions (%s arguments)...done"
 		       (if (= arg 1) "including" "excluding"))))
@@ -866,6 +1010,290 @@
 
 
 ;;;===========================================================================
+;;;  Compute dependencies
+;;;===========================================================================
+
+(defun antlr-file-dependencies ()
+  "Return dependencies for grammar in current buffer.
+The result looks like (FILE (CLASSES . SUPERS) VOCABS . LANGUAGE)
+where CLASSES = ((CLASS . CLASS-EVOCAB) ...),
+      SUPERS  = ((SUPER . USE-EVOCAB-P) ...), and
+      VOCABS  = ((EVOCAB ...) . (IVOCAB ...))
+
+FILE is the current buffer's file-name without directory part and
+LANGUAGE is the value of `antlr-language' in the current buffer.  Each
+EVOCAB is an export vocabulary and each IVOCAB is an import vocabulary.
+
+Each CLASS is a grammar class with its export vocabulary CLASS-EVOCAB.
+Each SUPER is a super-grammar class where USE-EVOCAB-P indicates whether
+its export vocabulary is used as an import vocabulary."
+  (unless buffer-file-name
+    (error "Grammar buffer does not visit a file"))
+  (let (classes exportVocabs importVocabs superclasses default-vocab)
+    (antlr-with-syntax-table antlr-action-syntax-table
+      (goto-char (point-min))
+      (while (antlr-re-search-forward "class[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;" nil)
+	;; parse class definition --------------------------------------------
+	(let* ((class (match-string 1))
+	       (sclass (match-string 2))
+	       ;; export vocab defaults to class name (first grammar in file)
+	       ;; or to the export vocab of the first grammar in file:
+	       (evocab (or default-vocab class))
+	       (ivocab nil))
+	  (goto-char (match-end 0))
+	  (c-forward-syntactic-ws)
+	  (while (looking-at "options\\>\\|\\(tokens\\)\\>")
+	    (if (match-beginning 1)
+		(antlr-skip-sexps 2)
+	      (goto-char (match-end 0))
+	      (c-forward-syntactic-ws)
+	      ;; parse grammar option section --------------------------------
+	      (when (eq (char-after (point)) ?\{)
+		(let* ((beg (1+ (point)))
+		       (end (1- (antlr-skip-sexps 1)))
+		       (cont (point)))
+		(goto-char beg)
+		(if (re-search-forward "\\<exportVocab[ \t]*=[ \t]*\\([A-Za-z\300-\326\330-\337]\\sw*\\)" end t)
+		    (setq evocab (match-string 1)))
+		(goto-char beg)
+		(if (re-search-forward "\\<importVocab[ \t]*=[ \t]*\\([A-Za-z\300-\326\330-\337]\\sw*\\)" end t)
+		    (setq ivocab (match-string 1)))
+		(goto-char cont)))))
+	  (unless (member sclass '("Parser" "Lexer" "TreeParser"))
+	    (let ((super (assoc sclass superclasses)))
+	      (if super
+		  (or ivocab (setcdr super t))
+		(push (cons sclass (null ivocab)) superclasses))))
+	  ;; remember class with export vocabulary:
+	  (push (cons class evocab) classes)
+	  ;; default export vocab is export vocab of first grammar in file:
+	  (or default-vocab (setq default-vocab evocab))
+	  (or (member evocab exportVocabs) (push evocab exportVocabs))
+	  (or (null ivocab)
+	      (member ivocab importVocabs) (push ivocab importVocabs)))))
+    (if classes
+	(list* (file-name-nondirectory buffer-file-name)
+	       (cons (nreverse classes) (nreverse superclasses))
+	       (cons (nreverse exportVocabs) (nreverse importVocabs))
+	       antlr-language))))
+
+(defun antlr-directory-dependencies (dirname)
+  "Return dependencies for all grammar files in directory DIRNAME.
+The result looks like ((CLASS-SPEC ...) . (FILE-DEP ...))
+where CLASS-SPEC = (CLASS (FILE . EVOCAB) ...).
+
+FILE-DEP are the dependencies for each grammar file in DIRNAME, see
+`antlr-file-dependencies'.  For each grammar class CLASS, FILE is a
+grammar file in which CLASS is defined and EVOCAB is the name of the
+export vocabulary specified in that file."
+  (let ((grammar (directory-files dirname t "\\.g\\'")))
+    (when grammar
+      (let ((temp-buffer (get-buffer-create
+			  (generate-new-buffer-name " *temp*")))
+	    (antlr-imenu-name nil)		; dynamic-let: no imenu
+	    (expanded-regexp (concat (format (regexp-quote
+					      (cadr antlr-special-file-formats))
+					     ".+")
+				     "\\'"))
+	    classes dependencies)
+	(unwind-protect
+	    (save-excursion
+	      (set-buffer temp-buffer)
+	      (widen)			; just in case...
+	      (dolist (file grammar)
+		(when (and (file-regular-p file)
+			   (null (string-match expanded-regexp file)))
+		  (insert-file-contents file t nil nil t)
+		  (normal-mode t)	; necessary for major-mode, syntax
+					; table and `antlr-language'
+		  (when (eq major-mode 'antlr-mode)
+		    (let* ((file-deps (antlr-file-dependencies))
+			   (file (car file-deps)))
+		      (when file-deps
+			(dolist (class-def (caadr file-deps))
+			  (let ((file-evocab (cons file (cdr class-def)))
+				(class-spec (assoc (car class-def) classes)))
+			    (if class-spec
+				(nconc (cdr class-spec) (list file-evocab))
+			      (push (list (car class-def) file-evocab)
+				    classes))))
+			(push file-deps dependencies)))))))
+	  (kill-buffer temp-buffer))
+	(cons (nreverse classes) (nreverse dependencies))))))
+
+
+;;;===========================================================================
+;;;  Compilation: run ANTLR tool
+;;;===========================================================================
+
+(defun antlr-superclasses-glibs (supers classes)
+  "Compute the grammar lib option for the super grammars SUPERS.
+Look in CLASSES for the right grammar lib files for SUPERS.  SUPERS is
+part SUPER in the result of `antlr-file-dependencies'.  CLASSES is the
+part (CLASS-SPEC ...) in the result of `antlr-directory-dependencies'.
+
+The result looks like (OPTION WITH-UNKNOWN GLIB ...).  OPTION is the
+complete \"-glib\" option.  WITH-UNKNOWN has value t iff there is none
+or more than one grammar file for at least one super grammar.
+
+Each GLIB looks like (GRAMMAR-FILE . EVOCAB).  GRAMMAR-FILE is a file in
+which a super-grammar is defined.  EVOCAB is the value of the export
+vocabulary of the super-grammar or nil if it is not needed."
+  ;; If the superclass is defined in the same file, that file will be included
+  ;; with -glib again.  This will lead to a redefinition.  But defining a
+  ;; analyzer of the same class twice in a file will lead to an error anyway...
+  (let (glibs unknown)
+    (while supers
+      (let* ((super (pop supers))
+	     (sup-files (cdr (assoc (car super) classes)))
+	     (file (and sup-files (null (cdr sup-files)) (car sup-files))))
+	(or file (setq unknown t))	; not exactly one file
+	(push (cons (or (car file)
+			(format (car antlr-unknown-file-formats)
+				(car super)))
+		    (and (cdr super)
+			 (or (cdr file)
+			     (format (cadr antlr-unknown-file-formats)
+				     (car super)))))
+	      glibs)))
+    (cons (if glibs (concat " -glib " (mapconcat 'car glibs ";")) "")
+	  (cons unknown glibs))))
+
+(defun antlr-run-tool (command file &optional saved)
+  "Run Antlr took COMMAND on grammar FILE.
+When called interactively, COMMAND is read from the minibuffer and
+defaults to `antlr-tool-command' with a computed \"-glib\" option if
+necessary.
+
+Save all buffers first unless optional value SAVED is non-nil.  When
+called interactively, the buffers are always saved, see also variable
+`antlr-ask-about-save'."
+  (interactive
+   ;; code in `interactive' is not compiled: do not use cl macros (`cdadr')
+   (let* ((supers (cdr (cadr (save-excursion
+			       (save-restriction
+				 (widen)
+				 (antlr-file-dependencies))))))
+	  (glibs ""))
+     (when supers
+       (save-some-buffers (not antlr-ask-about-save) nil)
+       (setq glibs (car (antlr-superclasses-glibs
+			 supers
+			 (car (antlr-directory-dependencies
+			       (antlr-default-directory)))))))
+     (list (antlr-read-shell-command "Run Antlr on current file with: "
+				     (concat antlr-tool-command glibs " "))
+	   buffer-file-name
+	   supers)))
+  (or saved (save-some-buffers (not antlr-ask-about-save)))
+  (let ((default-directory (file-name-directory file)))
+    (require 'compile)			; only `compile' autoload
+    (compile-internal (concat command " " (file-name-nondirectory file))
+		      "No more errors" "Antlr-Run")))
+
+
+;;;===========================================================================
+;;;  Makefile creation
+;;;===========================================================================
+
+(defun antlr-makefile-insert-variable (number pre post)
+  "Insert Makefile variable numbered NUMBER according to specification.
+Also insert strings PRE and POST before and after the variable."
+  (let ((spec (cadr antlr-makefile-specification)))
+    (when spec
+      (insert pre
+	      (if number (format (cadr spec) number) (car spec))
+	      post))))
+
+(defun antlr-insert-makefile-rules (&optional in-makefile)
+  "Insert Makefile rules in the current buffer at point.
+IN-MAKEFILE is non-nil, if the current buffer is the Makefile.  See
+command `antlr-show-makefile-rules' for detail."
+  (let* ((dirname (antlr-default-directory))
+	 (deps0 (antlr-directory-dependencies dirname))
+	 (classes (car deps0))		; CLASS -> (FILE . EVOCAB) ...
+	 (deps (cdr deps0))		; FILE -> (c . s) (ev . iv) . LANGUAGE
+	 (with-error nil)
+	 (gen-sep (or (caddr (cadr antlr-makefile-specification)) " "))
+	 (n (and (cdr deps) (cadr antlr-makefile-specification) 0)))
+    (or in-makefile (set-buffer standard-output))
+    (dolist (dep deps)
+      (let ((supers (cdadr dep))
+	    (lang (cdr (assoc (cdddr dep) antlr-file-formats-alist))))
+	(if n (incf n))
+	(antlr-makefile-insert-variable n "" " =")
+	(if supers
+	    (insert " "
+		    (format (cadr antlr-special-file-formats)
+			    (file-name-sans-extension (car dep)))))
+	(dolist (class-def (caadr dep))
+	  (let ((sep gen-sep))
+	    (dolist (class-file (cadr lang))
+	      (insert sep (format class-file (car class-def)))
+	      (setq sep " "))))
+	(dolist (evocab (caaddr dep))
+	  (let ((sep gen-sep))
+	    (dolist (vocab-file (cons (car antlr-special-file-formats)
+				      (car lang)))
+	      (insert sep (format vocab-file evocab))
+	      (setq sep " "))))
+	(antlr-makefile-insert-variable n "\n$(" ")")
+	(insert ": " (car dep))
+	(dolist (ivocab (cdaddr dep))
+	  (insert " " (format (car antlr-special-file-formats) ivocab)))
+	(let ((glibs (antlr-superclasses-glibs supers classes)))
+	  (if (cadr glibs) (setq with-error t))
+	  (dolist (super (cddr glibs))
+	    (insert " " (car super))
+	    (if (cdr super)
+		(insert " " (format (car antlr-special-file-formats)
+				    (cdr super)))))
+	  (insert "\n\t"
+		  (caddr antlr-makefile-specification)
+		  (car glibs)
+		  " $<\n"
+		  (car antlr-makefile-specification)))))
+    (if n
+	(let ((i 0))
+	  (antlr-makefile-insert-variable nil "" " =")
+	  (while (<= (incf i) n)
+	    (antlr-makefile-insert-variable i " $(" ")"))
+	  (insert "\n" (car antlr-makefile-specification))))
+    (if (string-equal (car antlr-makefile-specification) "\n")
+	(backward-delete-char 1))
+    (when with-error
+      (goto-char (point-min))
+      (insert antlr-help-unknown-file-text))
+    (unless in-makefile
+      (copy-region-as-kill (point-min) (point-max))
+      (goto-char (point-min))
+      (insert (format antlr-help-rules-intro dirname)))))
+
+;;;###autoload
+(defun antlr-show-makefile-rules ()
+  "Show Makefile rules for all grammar files in the current directory.
+If the `major-mode' of the current buffer has the value `makefile-mode',
+the rules are directory inserted at point.  Otherwise, a *Help* buffer
+is shown with the rules which are also put into the `kill-ring' for
+\\[yank].
+
+This command considers import/export vocabularies and grammar
+inheritance and provides a value for the \"-glib\" option if necessary.
+Customize variable `antlr-makefile-specification' for the appearance of
+the rules.
+
+If the file for a super-grammar cannot be determined, special file names
+are used according to variable `antlr-unknown-file-formats' and a
+commentary with value `antlr-help-unknown-file-text' is added.  The
+*Help* buffer always starts with the text in `antlr-help-rules-intro'."
+  (interactive)
+  (if (null (eq major-mode 'makefile-mode))
+      (antlr-with-displaying-help-buffer 'antlr-insert-makefile-rules)
+    (push-mark)
+    (antlr-insert-makefile-rules t)))
+
+
+;;;===========================================================================
 ;;;  Indentation
 ;;;===========================================================================
 
@@ -918,7 +1346,7 @@
 	(incf indent (antlr-syntactic-context))
 	(and (> indent 0) (looking-at antlr-indent-item-regexp) (decf indent))
 	(setq indent (* indent c-basic-offset)))
-      ;; the usual major-mode indent stuff:
+      ;; the usual major-mode indent stuff -----------------------------------
       (setq orig (- (point-max) orig))
       (unless (= (current-column) indent)
 	(delete-region bol boi)
@@ -1019,11 +1447,14 @@
   (setq major-mode 'antlr-mode
 	mode-name "Antlr")
   (setq local-abbrev-table antlr-mode-abbrev-table)
-  (set-syntax-table java-mode-syntax-table)
+  (unless antlr-mode-syntax-table
+    (setq antlr-mode-syntax-table (make-syntax-table))
+    (c-populate-syntax-table antlr-mode-syntax-table))
+  (set-syntax-table antlr-mode-syntax-table)
   (unless antlr-action-syntax-table
     (let ((slist (nth 3 antlr-font-lock-defaults)))
       (setq antlr-action-syntax-table
-	    (copy-syntax-table java-mode-syntax-table))
+	    (copy-syntax-table antlr-mode-syntax-table))
       (while slist
 	(modify-syntax-entry (caar slist) (cdar slist)
 			     antlr-action-syntax-table)
@@ -1081,9 +1512,9 @@
   (antlr-set-tabs)
   (run-hooks 'antlr-mode-hook))
 
-;; In XEmacs, a smarter version of `buffers-menu-grouping-function' could use
-;; the following property.  The header of the submenu would be "Antlr" instead
-;; of "Antlr/C++" or "Antlr/Java" (depending on the buffer ordering).
+;; A smarter version of `group-buffers-menu-by-mode-then-alphabetically' (in
+;; XEmacs) could use the following property.  The header of the submenu would
+;; be "Antlr" instead of "Antlr.C++" or (not and!) "Antlr.Java".
 (put 'antlr-mode 'mode-name "Antlr")
 
 ;;;###autoload
@@ -1104,6 +1535,9 @@
 ;;; antlr-mode.el ends here
 
 ; LocalWords:  antlr ANother ANTLR's Cpp Lexer TreeParser esp refs VALUEs ea ee
-; LocalWords:  Java's Nomencl ruledef tokendef ruleref tokenref setType ader
+; LocalWords:  Java's Nomencl ruledef tokendef ruleref tokenref setType ader ev
 ; LocalWords:  ivate syntab lexer treeparser lic rotected rivate bor boi AFAIK
-; LocalWords:  slist knr inexpr
+; LocalWords:  slist knr inexpr unhide jit GENS SEP GEN sTokenTypes hpp cpp DEP
+; LocalWords:  VOCAB EVOCAB Antlr's TokenTypes exportVocab incl excl SUPERS gen
+; LocalWords:  VOCABS IVOCAB exportVocabs importVocabs superclasses vocab kens
+; LocalWords:  sclass evocab ivocab importVocab deps glibs supers sep dep lang