aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes/antlr-mode.el
diff options
context:
space:
mode:
authorGerd Moellmann <[email protected]>2000-11-29 16:55:47 +0000
committerGerd Moellmann <[email protected]>2000-11-29 16:55:47 +0000
commit7c66d04999ce21b5ddedb22593832aa738e0a4aa (patch)
tree295f8f01a09aa0958bb9eb7b1b5d2a8f9179788e /lisp/progmodes/antlr-mode.el
parent7423978df5b5799702df88f321cb9c647cc18e1f (diff)
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 <[email protected]>. (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 [email protected]. (antlr-hide-actions): Change accordingly. Hide line if completely hidden action is on a line of its own.
Diffstat (limited to 'lisp/progmodes/antlr-mode.el')
-rw-r--r--lisp/progmodes/antlr-mode.el638
1 files changed, 536 insertions, 102 deletions
diff --git a/lisp/progmodes/antlr-mode.el b/lisp/progmodes/antlr-mode.el
index 32d32cc5fc..3f1d735b53 100644
--- a/lisp/progmodes/antlr-mode.el
+++ b/lisp/progmodes/antlr-mode.el
@@ -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: [email protected]
-;; 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-\).
-;; * 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.
+;; * 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.
+
+;; 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 @@ variable list\" near the end of the file, see
`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 @@ also displayed in the modeline next to \"Antlr\"."
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 @@ they are only changed by \\[antlr-indent-command]."
(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 @@ See command \\[antlr-indent-command].")
;;;===========================================================================
+;;; 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 @@ imenu."
(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 @@ imenu."
"---"
["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 @@ fontified at all."
(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 @@ in the grammar's actions and semantic predicates, see
(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 @@ in the grammar's actions and semantic predicates, see
(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 @@ in the grammar's actions and semantic predicates, see
(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 @@ in the grammar's actions and semantic predicates, see
'((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 @@ The SYNTAX-ALIST element is also used to initialize
(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 @@ context_cache.")
;;; 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 @@ See `antlr-font-lock-additional-keywords', `antlr-language' and
(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 @@ See `antlr-font-lock-additional-keywords', `antlr-language' and
(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 @@ See `antlr-font-lock-additional-keywords', `antlr-language' and
(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 @@ part."
(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 @@ If non-nil, TRANSFORM is used on literals instead of `downcase-region'."
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 @@ length is shorter or equal to `antlr-tiny-action-length'."
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 @@ length is shorter or equal to `antlr-tiny-action-length'."
;;;===========================================================================
+;;; 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 @@ Lines inside block comments are not changed or indented by
(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 @@ Otherwise, indent the current line with `antlr-indent-line'."
(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 @@ Otherwise, indent the current line with `antlr-indent-line'."
(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 @@ Used in `antlr-mode'. Also a useful function in `java-mode-hook'."
;;; 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