(edebug-form-spec prop): use dolist.
[emacs.git] / lisp / progmodes / antlr-mode.el
blob32d32cc5fcad69b9dc19a386158df89cbaf6de04
1 ;;; antlr-mode.el --- Major mode for ANTLR grammar files
3 ;; Copyright (C) 1999-2000 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Christoph.Wedler@sap.com
6 ;; Version: $Id: antlr-mode.el,v 1.2 1999/12/16 19:30:34 wedler Exp $
7 ;; X-URL: http://www.fmi.uni-passau.de/~wedler/antlr-mode/
9 ;; This file is part of GNU Emacs.
11 ;; GNU Emacs is free software; you can redistribute it and/or modify
12 ;; it under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 2, or (at your option)
14 ;; any later version.
16 ;; GNU Emacs is distributed in the hope that it will be useful,
17 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ;; GNU General Public License for more details.
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with GNU Emacs; see the file COPYING. If not, write to the
23 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
24 ;; Boston, MA 02111-1307, USA.
26 ;;; Commentary:
28 ;; Major mode for editing ANTLR grammar files, i.e., files ending with `.g'.
29 ;; ANTLR is ANother Tool for Language Recognition (an excellent alternative to
30 ;; lex/yacc), see <http://www.ANTLR.org> and <news:comp.compilers.tools.pccts>.
32 ;; Variable `antlr-language' is set according to the language in actions and
33 ;; semantic predicates of the grammar (see ANTLR's file option "language").
34 ;; The supported languages are "Java" (java-mode) and "Cpp" (c++-mode). This
35 ;; package uses features of the Emacs package cc-mode.
37 ;; This package provides the following features:
38 ;; * Indentation for the current line (TAB) and selected region (C-M-\).
39 ;; * Syntax coloring (via font-lock) with language dependent coloring.
40 ;; * Support for imenu/speedbar: menu "Index" (Parser, Lexer, TreeParser).
41 ;; * Direct move to previous/next rule, beginning/end of rule body etc.
43 ;; INDENTATION. This package supports ANTLR's (intended) indentation style
44 ;; which is based on a simple paren/brace/bracket depth-level calculation, see
45 ;; `antlr-indent-line'. The indentation engine of cc-mode is only used inside
46 ;; block comments (it is not easy to use it for actions, esp if they come early
47 ;; in the rule body). By default, this package uses TABs for a basic offset of
48 ;; 4 to be consistent to both ANTLR's conventions (TABs usage) and the
49 ;; `c-indentation-style' "java" which sets `c-basic-offset' to 4, see
50 ;; `antlr-tab-offset-alist'. You might want to set this variable to nil.
52 ;; SYNTAX COLORING comes in three phases. First, comments and strings are
53 ;; highlighted. Second, the grammar code is highlighted according to
54 ;; `antlr-font-lock-additional-keywords' (rule refs: blue, token refs: brown,
55 ;; definition: ditto+bold). Third, actions, semantic predicates and arguments
56 ;; are highlighted according to the usual font-lock keywords of
57 ;; `antlr-language', see also `antlr-font-lock-maximum-decoration'. We define
58 ;; special font-lock faces for the grammar code to allow you to distinguish
59 ;; ANTLR keywords from Java/C++ keywords.
61 ;; Bug fixes, bug reports, improvements, and suggestions are strongly
62 ;; appreciated. Please check the newest version first:
63 ;; http://www.fmi.uni-passau.de/~wedler/antlr-mode/changes.html
65 ;;; Installation:
67 ;; This file requires Emacs-20.3, XEmacs-20.4 or higher.
69 ;; If antlr-mode is not part of your distribution, put this file into your
70 ;; load-path and the following into your ~/.emacs:
71 ;; (autoload 'antlr-mode "antlr-mode" nil t)
72 ;; (setq auto-mode-alist (cons '("\\.g\\'" . antlr-mode) auto-mode-alist))
73 ;; (add-hook 'speedbar-load-hook ; would be too late in antlr-mode.el
74 ;; (lambda () (speedbar-add-supported-extension ".g")))
76 ;; If you edit ANTLR's source files, you might also want to use
77 ;; (autoload 'antlr-set-tabs "antlr-mode")
78 ;; (add-hook 'java-mode-hook 'antlr-set-tabs)
80 ;; I strongly recommend to use font-lock with a support mode like fast-lock,
81 ;; lazy-lock or better jit-lock (Emacs-21.1+) / lazy-shot (XEmacs).
83 ;; To customize, use `M-x customize-group RET antlr RET' or the custom browser
84 ;; (Emacs->Programming->Languages->Antlr).
86 ;;; Code:
88 (provide 'antlr-mode)
89 (eval-when-compile (require 'cc-mode)) ; shut up most warnings
90 (require 'easymenu) ; Emacs
91 (eval-when-compile ; optional libraries
92 (defvar outline-level) (defvar imenu-use-markers))
93 (eval-when-compile ; Emacs: cl, XEmacs vars
94 (require 'cl))
95 (eval-when-compile ; XEmacs: Emacs vars
96 (defvar inhibit-point-motion-hooks) (defvar deactivate-mark))
98 (eval-and-compile
99 (if (string-match "XEmacs" emacs-version)
100 (defalias 'antlr-scan-sexps 'scan-sexps)
101 (defalias 'antlr-scan-sexps 'antlr-scan-sexps-internal))
102 (if (and (fboundp 'buffer-syntactic-context)
103 (fboundp 'buffer-syntactic-context-depth))
104 (progn
105 (defalias 'antlr-invalidate-context-cache 'antlr-xemacs-bug-workaround)
106 (defalias 'antlr-syntactic-context 'antlr-fast-syntactic-context))
107 (defalias 'antlr-invalidate-context-cache 'ignore)
108 (defalias 'antlr-syntactic-context 'antlr-slow-syntactic-context)))
112 ;;;;##########################################################################
113 ;;;; Variables
114 ;;;;##########################################################################
117 (defgroup antlr nil
118 "Major mode for ANTLR grammar files."
119 :group 'languages
120 :link '(emacs-commentary-link "antlr-mode.el")
121 :link '(url-link "http://www.fmi.uni-passau.de/~wedler/antlr-mode/")
122 :prefix "antlr-")
124 (defconst antlr-version "1.3"
125 "ANTLR major mode version number.")
128 ;;;===========================================================================
129 ;;; Controlling ANTLR's code generator (language option)
130 ;;;===========================================================================
132 (defvar antlr-language nil
133 "Major mode corresponding to ANTLR's \"language\" option.
134 Set via `antlr-language-alist'. The only useful place to change this
135 buffer-local variable yourself is in `antlr-mode-hook' or in the \"local
136 variable list\" near the end of the file, see
137 `enable-local-variables'.")
139 (defcustom antlr-language-alist
140 '((java-mode "Java" nil "Java")
141 (c++-mode "C++" "Cpp"))
142 "List of ANTLR's supported languages.
143 Each element in this list looks like
144 (MAJOR-MODE MODELINE-STRING OPTION-VALUE...)
146 MAJOR-MODE, the major mode of the code in the grammar's actions, is the
147 value of `antlr-language' if the first regexp group matched by REGEXP in
148 `antlr-language-limit-n-regexp' is one of the OPTION-VALUEs. An
149 OPTION-VALUE of nil denotes the fallback element. MODELINE-STRING is
150 also displayed in the modeline next to \"Antlr\"."
151 :group 'antlr
152 :type '(repeat (group :value (java-mode "")
153 (function :tag "Major mode")
154 (string :tag "Modeline string")
155 (repeat :tag "ANTLR language option" :inline t
156 (choice (const :tag "Default" nil)
157 string )))))
159 (defcustom antlr-language-limit-n-regexp
160 '(3000 . "language[ \t]*=[ \t]*\"\\([A-Z][A-Za-z_]*\\)\"")
161 "Used to set a reasonable value for `antlr-language'.
162 Looks like (LIMIT . REGEXP). Search for REGEXP from the beginning of
163 the buffer to LIMIT to set the language according to
164 `antlr-language-alist'."
165 :group 'antlr
166 :type '(cons (choice :tag "Limit" (const :tag "No" nil) (integer :value 0))
167 regexp))
170 ;;;===========================================================================
171 ;;; Indent/Tabs
172 ;;;===========================================================================
174 (defcustom antlr-tiny-action-length 3
175 "Maximal number of characters in actions never to hide.
176 See command `antlr-hide-actions'."
177 :group 'antlr
178 :type 'integer)
180 (defcustom antlr-indent-comment 'tab
181 "*Non-nil, if the indentation should touch lines in block comments.
182 If nil, no continuation line of a block comment is changed. If t, they
183 are changed according to `c-indentation-line'. When not nil and not t,
184 they are only changed by \\[antlr-indent-command]."
185 :group 'antlr
186 :type '(radio (const :tag "No" nil)
187 (const :tag "Always" t)
188 (sexp :tag "With TAB" :format "%t" :value tab)))
190 (defcustom antlr-tab-offset-alist
191 '((antlr-mode nil 4 t)
192 (java-mode "antlr" 4 t))
193 "Alist to determine whether to use ANTLR's convention for TABs.
194 Each element looks like (MAJOR-MODE REGEXP TAB-WIDTH INDENT-TABS-MODE).
195 The first element whose MAJOR-MODE is nil or equal to `major-mode' and
196 whose REGEXP is nil or matches `buffer-file-name' is used to set
197 `tab-width' and `indent-tabs-mode'. This is useful to support both
198 ANTLR's and Java's indentation styles. Used by `antlr-set-tabs'."
199 :group 'antlr
200 :type '(repeat (group :value (antlr-mode nil 8 nil)
201 (choice (const :tag "All" nil)
202 (function :tag "Major mode"))
203 (choice (const :tag "All" nil) regexp)
204 (integer :tag "Tab width")
205 (boolean :tag "Indent-tabs-mode"))))
207 (defvar antlr-indent-item-regexp
208 "[]}):;|&]\\|default[ \t]*:\\|case[ \t]+\\('\\\\?.'\\|[0-9]+\\|[A-Za-z_][A-Za-z_0-9]*\\)[ \t]*:" ; & is local ANTLR extension
209 "Regexp matching lines which should be indented by one TAB less.
210 See command \\[antlr-indent-command].")
213 ;;;===========================================================================
214 ;;; Menu
215 ;;;===========================================================================
217 (defcustom antlr-imenu-name t
218 "*Non-nil, if a \"Index\" menu should be added to the menubar.
219 If it is a string, it is used instead \"Index\". Requires package
220 imenu."
221 :group 'antlr
222 :type '(choice (const :tag "No menu" nil)
223 (const :tag "Index menu" t)
224 (string :tag "Other menu name")))
226 (defvar antlr-mode-map
227 (let ((map (make-sparse-keymap)))
228 (define-key map "\t" 'antlr-indent-command)
229 (define-key map "\e\C-a" 'antlr-beginning-of-rule)
230 (define-key map "\e\C-e" 'antlr-end-of-rule)
231 (define-key map "\C-c\C-a" 'antlr-beginning-of-body)
232 (define-key map "\C-c\C-e" 'antlr-end-of-body)
233 (define-key map "\C-c\C-f" 'c-forward-into-nomenclature)
234 (define-key map "\C-c\C-b" 'c-backward-into-nomenclature)
235 (define-key map "\C-c\C-c" 'comment-region)
236 (define-key map "\C-c\C-v" 'antlr-hide-actions)
237 ;; I'm too lazy to define my own:
238 (define-key map "\ea" 'c-beginning-of-statement)
239 (define-key map "\ee" 'c-end-of-statement)
240 map)
241 "Keymap used in `antlr-mode' buffers.")
243 (easy-menu-define antlr-mode-menu
244 antlr-mode-map
245 "Major mode menu."
246 '("Antlr"
247 ["Indent Line" antlr-indent-command
248 :active (not buffer-read-only)]
249 ["Indent for Comment" indent-for-comment
250 :active (not buffer-read-only)]
251 ["Comment Out Region" comment-region
252 :active (and (not buffer-read-only)
253 (c-region-is-active-p))]
254 ["Uncomment Region"
255 (comment-region (region-beginning) (region-end) '(4))
256 :active (and (not buffer-read-only)
257 (c-region-is-active-p))]
258 "---"
259 ["Backward Rule" antlr-beginning-of-rule t]
260 ["Forward Rule" antlr-end-of-rule t]
261 ["Start of Rule Body" antlr-beginning-of-body
262 :active (antlr-inside-rule-p)]
263 ["End of Rule Body" antlr-end-of-body
264 :active (antlr-inside-rule-p)]
265 "---"
266 ["Backward Statement" c-beginning-of-statement t]
267 ["Forward Statement" c-end-of-statement t]
268 ["Backward Into Nomencl." c-backward-into-nomenclature t]
269 ["Forward Into Nomencl." c-forward-into-nomenclature t]
270 "---"
271 ["Hide Actions (incl. Args)" antlr-hide-actions t]
272 ["Hide Actions (excl. Args)" (antlr-hide-actions 2) t]
273 ["Unhide All Actions" (antlr-hide-actions 0) t]))
276 ;;;===========================================================================
277 ;;; font-lock
278 ;;;===========================================================================
280 (defcustom antlr-font-lock-maximum-decoration 'inherit
281 "*The maximum decoration level for fontifying actions.
282 Value `none' means, do not fontify actions, just normal grammar code
283 according to `antlr-font-lock-additional-keywords'. Value `inherit'
284 means, use value of `font-lock-maximum-decoration'. Any other value is
285 interpreted as in `font-lock-maximum-decoration' with no level-0
286 fontification, see `antlr-font-lock-keywords-alist'.
288 While calculating the decoration level for actions, `major-mode' is
289 bound to `antlr-language'. For example, with value
290 ((java-mode . 2) (c++-mode . 0))
291 Java actions are fontified with level 2 and C++ actions are not
292 fontified at all."
293 :type '(choice (const :tag "none" none)
294 (const :tag "inherit" inherit)
295 (const :tag "default" nil)
296 (const :tag "maximum" t)
297 (integer :tag "level" 1)
298 (repeat :menu-tag "mode specific" :tag "mode specific"
299 :value ((t . t))
300 (cons :tag "Instance"
301 (radio :tag "Mode"
302 (const :tag "all" t)
303 (symbol :tag "name"))
304 (radio :tag "Decoration"
305 (const :tag "default" nil)
306 (const :tag "maximum" t)
307 (integer :tag "level" 1))))))
309 (defvar antlr-font-lock-keywords-alist
310 '((java-mode
311 (list) ; nil won't work (would use level-3)
312 java-font-lock-keywords-1 java-font-lock-keywords-2
313 java-font-lock-keywords-3)
314 (c++-mode
315 (list) ; nil won't work (would use level-3)
316 c++-font-lock-keywords-1 c++-font-lock-keywords-2
317 c++-font-lock-keywords-3))
318 "List of font-lock keywords for actions in the grammar.
319 Each element in this list looks like
320 (MAJOR-MODE KEYWORD...)
322 If `antlr-language' is equal to MAJOR-MODE, the KEYWORDs are the
323 font-lock keywords according to `font-lock-defaults' used for the code
324 in the grammar's actions and semantic predicates, see
325 `antlr-font-lock-maximum-decoration'.")
327 (defvar antlr-font-lock-keyword-face 'antlr-font-lock-keyword-face)
328 (defface antlr-font-lock-keyword-face
329 '((((class color) (background light)) (:foreground "black" :bold t)))
330 "ANTLR keywords."
331 :group 'antlr)
333 (defvar antlr-font-lock-ruledef-face 'antlr-font-lock-ruledef-face)
334 (defface antlr-font-lock-ruledef-face
335 '((((class color) (background light)) (:foreground "blue" :bold t)))
336 "ANTLR rule references (definition)."
337 :group 'antlr)
339 (defvar antlr-font-lock-tokendef-face 'antlr-font-lock-tokendef-face)
340 (defface antlr-font-lock-tokendef-face
341 '((((class color) (background light)) (:foreground "brown3" :bold t)))
342 "ANTLR token references (definition)."
343 :group 'antlr)
345 (defvar antlr-font-lock-ruleref-face 'antlr-font-lock-ruleref-face)
346 (defface antlr-font-lock-ruleref-face
347 '((((class color) (background light)) (:foreground "blue4")))
348 "ANTLR rule references (usage)."
349 :group 'antlr)
351 (defvar antlr-font-lock-tokenref-face 'antlr-font-lock-tokenref-face)
352 (defface antlr-font-lock-tokenref-face
353 '((((class color) (background light)) (:foreground "brown4")))
354 "ANTLR token references (usage)."
355 :group 'antlr)
357 (defvar antlr-font-lock-literal-face 'antlr-font-lock-literal-face)
358 (defface antlr-font-lock-literal-face
359 '((((class color) (background light)) (:foreground "brown4" :bold t)))
360 "ANTLR literal tokens consisting merely of letter-like characters."
361 :group 'antlr)
363 (defvar antlr-font-lock-additional-keywords
364 `((antlr-invalidate-context-cache)
365 ("\\$setType[ \t]*(\\([A-Z\300-\326\330-\337]\\sw*\\))"
366 (1 antlr-font-lock-tokendef-face))
367 ("\\$\\sw+" (0 font-lock-keyword-face))
368 ;; the tokens are already fontified as string/docstrings:
369 (,(lambda (limit)
370 (antlr-re-search-forward "\"\\(\\sw\\(\\sw\\|-\\)*\\)\"" limit))
371 (1 antlr-font-lock-literal-face t)
372 ,@(and (string-match "XEmacs" emacs-version)
373 '((0 nil)))) ; XEmacs bug workaround
374 (,(lambda (limit)
375 (antlr-re-search-forward
376 "^\\(class\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+\\(extends\\)[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;" limit))
377 (1 antlr-font-lock-keyword-face)
378 (2 antlr-font-lock-ruledef-face)
379 (3 antlr-font-lock-keyword-face)
380 (4 (if (member (match-string 4) '("Lexer" "Parser" "TreeParser"))
381 'antlr-font-lock-keyword-face
382 'font-lock-type-face)))
383 (,(lambda (limit)
384 (antlr-re-search-forward
385 "\\<\\(header\\|options\\|tokens\\|exception\\|catch\\|returns\\)\\>"
386 limit))
387 (1 antlr-font-lock-keyword-face))
388 (,(lambda (limit)
389 (antlr-re-search-forward
390 "^\\(private\\|public\\|protected\\)\\>\\([ \t]+\\(\\sw+\\)\\)?"
391 limit))
392 (1 font-lock-type-face) ; not XEmacs' java level-3 fruit salad
393 (3 (if (antlr-upcase-p (char-after (match-beginning 3)))
394 'antlr-font-lock-tokendef-face
395 'antlr-font-lock-ruledef-face) nil t))
396 (,(lambda (limit)
397 (antlr-re-search-forward "^\\sw+" limit))
398 (0 (if (antlr-upcase-p (char-after (match-beginning 0)))
399 'antlr-font-lock-tokendef-face
400 'antlr-font-lock-ruledef-face) nil t))
401 (,(lambda (limit)
402 ;; not only before a rule ref, also before a literal
403 (antlr-re-search-forward "\\<\\(\\sw+\\)[ \t]*:" limit))
404 (1 font-lock-variable-name-face))
405 (,(lambda (limit)
406 (antlr-re-search-forward "\\<\\(\\sw+[ \t]*=[ \t]*\\)?\\(\\sw+[ \t]*:[ \t]*\\)?\\(\\sw+\\)" limit))
407 ;;(1 antlr-font-lock-default-face nil t) ; fool java-font-lock-keywords
408 (3 (if (antlr-upcase-p (char-after (match-beginning 3)))
409 'antlr-font-lock-tokenref-face
410 'antlr-font-lock-ruleref-face))))
411 "Font-lock keywords for ANTLR's normal grammar code.
412 See `antlr-font-lock-keywords-alist' for the keywords of actions.")
414 (defvar antlr-font-lock-defaults
415 '(antlr-font-lock-keywords
416 nil nil ((?_ . "w") (?\( . ".") (?\) . ".")) beginning-of-defun)
417 "Font-lock defaults used for ANTLR syntax coloring.
418 The SYNTAX-ALIST element is also used to initialize
419 `antlr-action-syntax-table'.")
422 ;;;===========================================================================
423 ;;; Internal variables
424 ;;;===========================================================================
426 (defvar antlr-mode-hook nil
427 "Hook called by `antlr-mode'.")
429 ;; used for "in Java/C++ code" = syntactic-depth>0
430 (defvar antlr-action-syntax-table nil
431 "Syntax table used for ANTLR action parsing.
432 Initialized by `java-mode-syntax-table', i.e., the syntax table used for
433 grammar files, changed by SYNTAX-ALIST in `antlr-font-lock-defaults'.
434 This table should be selected if you use `buffer-syntactic-context' and
435 `buffer-syntactic-context-depth' in order not to confuse their
436 context_cache.")
438 (defvar antlr-mode-abbrev-table nil
439 "Abbreviation table used in `antlr-mode' buffers.")
440 (define-abbrev-table 'antlr-mode-abbrev-table ())
444 ;;;;##########################################################################
445 ;;;; The Code
446 ;;;;##########################################################################
449 ;;;===========================================================================
450 ;;; Syntax functions -- Emacs vs XEmacs dependent
451 ;;;===========================================================================
453 ;; From help.el (XEmacs-21.1)
454 (defmacro antlr-with-syntax-table (syntab &rest body)
455 `(let ((stab (syntax-table)))
456 (unwind-protect
457 (progn (set-syntax-table (copy-syntax-table ,syntab)) ,@body)
458 (set-syntax-table stab))))
459 (put 'antlr-with-syntax-table 'lisp-indent-function 1)
460 (put 'antlr-with-syntax-table 'edebug-form-spec '(form body))
462 (defun antlr-scan-sexps-internal (from count &optional dummy no-error)
463 ;; checkdoc-params: (from count dummy)
464 "Like `scan-sexps' but with additional arguments.
465 When optional arg NO-ERROR is non-nil, `scan-sexps' will return nil
466 instead of signaling an error."
467 (if no-error
468 (condition-case nil
469 (scan-sexps from count)
470 (t nil))
471 (scan-sexps from count)))
473 (defun antlr-xemacs-bug-workaround (&rest dummies)
474 ;; checkdoc-params: (dummies)
475 "Invalidate context_cache for syntactical context information."
476 ;; XEmacs bug workaround
477 (save-excursion
478 (set-buffer (get-buffer-create " ANTLR XEmacs bug workaround"))
479 (buffer-syntactic-context-depth))
480 nil)
482 (defun antlr-fast-syntactic-context ()
483 "Return some syntactic context information.
484 Return `string' if point is within a string, `block-comment' or
485 `comment' is point is within a comment or the depth within all
486 parenthesis-syntax delimiters at point otherwise.
487 WARNING: this may alter `match-data'."
488 (or (buffer-syntactic-context) (buffer-syntactic-context-depth)))
490 (defun antlr-slow-syntactic-context ()
491 "Return some syntactic context information.
492 Return `string' if point is within a string, `block-comment' or
493 `comment' is point is within a comment or the depth within all
494 parenthesis-syntax delimiters at point otherwise.
495 WARNING: this may alter `match-data'."
496 (let ((orig (point)))
497 (beginning-of-defun)
498 (let ((state (parse-partial-sexp (point) orig)))
499 (goto-char orig)
500 (cond ((nth 3 state) 'string)
501 ((nth 4 state) 'comment) ; block-comment? -- we don't care
502 (t (car state))))))
505 ;;;===========================================================================
506 ;;; Misc functions
507 ;;;===========================================================================
509 (defun antlr-upcase-p (char)
510 "Non-nil, if CHAR is an uppercase character (if CHAR was a char)."
511 ;; in XEmacs, upcase only works for ASCII
512 (or (and (<= ?A char) (<= char ?Z))
513 (and (<= ?\300 char) (<= char ?\337)))) ; ?\327 is no letter
515 (defun antlr-re-search-forward (regexp bound)
516 "Search forward from point for regular expression REGEXP.
517 Set point to the end of the occurrence found, and return point. Return
518 nil if no occurrence was found. Do not search within comments, strings
519 and actions/semantic predicates. BOUND bounds the search; it is a
520 buffer position. See also the functions `match-beginning', `match-end'
521 and `replace-match'."
522 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
523 (let ((continue t))
524 (while (and (re-search-forward regexp bound 'limit)
525 (save-match-data
526 (if (eq (antlr-syntactic-context) 0)
527 (setq continue nil)
528 t))))
529 (if continue nil (point))))
531 (defun antlr-search-forward (string)
532 "Search forward from point for STRING.
533 Set point to the end of the occurrence found, and return point. Return
534 nil if no occurrence was found. Do not search within comments, strings
535 and actions/semantic predicates."
536 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
537 (let ((continue t))
538 (while (and (search-forward string nil 'limit)
539 (if (eq (antlr-syntactic-context) 0) (setq continue nil) t)))
540 (if continue nil (point))))
542 (defun antlr-search-backward (string)
543 "Search backward from point for STRING.
544 Set point to the beginning of the occurrence found, and return point.
545 Return nil if no occurrence was found. Do not search within comments,
546 strings and actions/semantic predicates."
547 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
548 (let ((continue t))
549 (while (and (search-backward string nil 'limit)
550 (if (eq (antlr-syntactic-context) 0) (setq continue nil) t)))
551 (if continue nil (point))))
553 (defsubst antlr-skip-sexps (count)
554 "Skip the next COUNT balanced expressions and the comments after it.
555 Return position before the comments after the last expression."
556 (goto-char (or (antlr-scan-sexps (point) count nil t) (point-max)))
557 (prog1 (point)
558 (c-forward-syntactic-ws)))
561 ;;;===========================================================================
562 ;;; font-lock
563 ;;;===========================================================================
565 (defun antlr-font-lock-keywords ()
566 "Return font-lock keywords for current buffer.
567 See `antlr-font-lock-additional-keywords', `antlr-language' and
568 `antlr-font-lock-maximum-decoration'."
569 (if (eq antlr-font-lock-maximum-decoration 'none)
570 antlr-font-lock-additional-keywords
571 (append antlr-font-lock-additional-keywords
572 (eval (let ((major-mode antlr-language)) ; dynamic
573 (font-lock-choose-keywords
574 (cdr (assq antlr-language
575 antlr-font-lock-keywords-alist))
576 (if (eq antlr-font-lock-maximum-decoration 'inherit)
577 font-lock-maximum-decoration
578 antlr-font-lock-maximum-decoration)))))))
581 ;;;===========================================================================
582 ;;; imenu support
583 ;;;===========================================================================
585 (defun antlr-imenu-create-index-function ()
586 "Return imenu index-alist for ANTLR grammar files."
587 (let ((items nil)
588 (lexer nil)
589 (parser nil)
590 (treeparser nil)
591 (misc nil)
592 (classes nil)
593 (semi (point-max)))
594 ;; Using `imenu-progress-message' would require imenu for compilation --
595 ;; nobody is missing these messages...
596 (antlr-with-syntax-table antlr-action-syntax-table
597 ;; We stick to the imenu standard and search backwards, although I don't
598 ;; think this is right. It is slower and more likely not to work during
599 ;; editing (you are more likely to add functions to the end of the file).
600 (while semi
601 (goto-char semi)
602 (if (setq semi (antlr-search-backward ";"))
603 (progn (forward-char) (antlr-skip-exception-part t))
604 (antlr-skip-file-prelude t))
605 (if (looking-at "{") (antlr-skip-sexps 1))
606 (if (looking-at "class[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Z\300-\326\330-\337]\\sw*\\)[ \t]*;")
607 (progn
608 (push (cons (match-string 1)
609 (if imenu-use-markers
610 (copy-marker (match-beginning 1))
611 (match-beginning 1)))
612 classes)
613 (if items
614 (let ((super (match-string 2)))
615 (cond ((string-equal super "Parser")
616 (setq parser (nconc items parser)))
617 ((string-equal super "Lexer")
618 (setq lexer (nconc items lexer)))
619 ((string-equal super "TreeParser")
620 (setq treeparser (nconc items treeparser)))
622 (setq misc (nconc items misc))))
623 (setq items nil))))
624 (if (looking-at "p\\(ublic\\|rotected\\|rivate\\)")
625 (antlr-skip-sexps 1))
626 (when (looking-at "\\sw+")
627 (push (cons (match-string 0)
628 (if imenu-use-markers
629 (copy-marker (match-beginning 0))
630 (match-beginning 0)))
631 items)))))
632 (or items ; outside any class
633 (prog1 (setq items misc) (setq misc nil))
634 (prog1 (setq items parser) (setq parser nil))
635 (prog1 (setq items lexer) (setq lexer nil))
636 (prog1 (setq items treeparser) (setq treeparser nil)))
637 (if misc (push (cons "Miscellaneous" misc) items))
638 (if treeparser (push (cons "TreeParser" treeparser) items))
639 (if lexer (push (cons "Lexer" lexer) items))
640 (if parser (push (cons "Parser" parser) items))
641 (if classes (cons (cons "Classes" classes) items) items)))
644 ;;;===========================================================================
645 ;;; Parse grammar files (internal functions)
646 ;;;===========================================================================
648 (defun antlr-skip-exception-part (skip-comment)
649 "Skip exception part of current rule, i.e., everything after `;'.
650 This also includes the options and tokens part of a grammar class
651 header. If SKIP-COMMENT is non-nil, also skip the comment after that
652 part."
653 (let ((pos (point))
654 (class nil))
655 (c-forward-syntactic-ws)
656 (while (looking-at "options\\>\\|tokens\\>")
657 (setq class t)
658 (setq pos (antlr-skip-sexps 2)))
659 (if class
660 ;; Problem: an action only belongs to a class def, not a normal rule.
661 ;; But checking the current rule type is too expensive => only expect
662 ;; an action if we have found an option or tokens part.
663 (if (looking-at "{") (setq pos (antlr-skip-sexps 1)))
664 (while (looking-at "exception\\>")
665 (setq pos (antlr-skip-sexps 1))
666 (if (looking-at "\\[") (setq pos (antlr-skip-sexps 1)))
667 (while (looking-at "catch\\>")
668 (setq pos (antlr-skip-sexps 3)))))
669 (or skip-comment (goto-char pos))))
671 (defun antlr-skip-file-prelude (skip-comment)
672 "Skip the file prelude: the header and file options.
673 If SKIP-COMMENT is non-nil, also skip the comment after that part."
674 (let* ((pos (point))
675 (pos0 pos))
676 (c-forward-syntactic-ws)
677 (if skip-comment (setq pos0 (point)))
678 (if (looking-at "header\\>") (setq pos (antlr-skip-sexps 2)))
679 (if (looking-at "options\\>") (setq pos (antlr-skip-sexps 2)))
680 (or skip-comment (goto-char pos))
681 pos0))
683 (defun antlr-next-rule (arg skip-comment)
684 "Move forward to next end of rule. Do it ARG many times.
685 A grammar class header and the file prelude are also considered as a
686 rule. Negative argument ARG means move back to ARGth preceding end of
687 rule. The behavior is not defined when ARG is zero. If SKIP-COMMENT
688 is non-nil, move to beginning of the rule."
689 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
690 ;; PRE: ARG<>0
691 (let ((pos (point))
692 (beg (point)))
693 ;; first look whether point is in exception part
694 (if (antlr-search-backward ";")
695 (progn
696 (setq beg (point))
697 (forward-char)
698 (antlr-skip-exception-part skip-comment))
699 (antlr-skip-file-prelude skip-comment))
700 (if (< arg 0)
701 (unless (and (< (point) pos) (zerop (incf arg)))
702 ;; if we have moved backward, we already moved one defun backward
703 (goto-char beg) ; rewind (to ";" / point)
704 (while (and arg (<= (incf arg) 0))
705 (if (antlr-search-backward ";")
706 (setq beg (point))
707 (when (>= arg -1)
708 ;; try file prelude:
709 (setq pos (antlr-skip-file-prelude skip-comment))
710 (if (zerop arg)
711 (if (>= (point) beg)
712 (goto-char (if (>= pos beg) (point-min) pos)))
713 (goto-char (if (or (>= (point) beg) (= (point) pos))
714 (point-min) pos))))
715 (setq arg nil)))
716 (when arg ; always found a ";"
717 (forward-char)
718 (antlr-skip-exception-part skip-comment)))
719 (if (<= (point) pos) ; moved backward?
720 (goto-char pos) ; rewind
721 (decf arg)) ; already moved one defun forward
722 (unless (zerop arg)
723 (while (>= (decf arg) 0)
724 (antlr-search-forward ";"))
725 (antlr-skip-exception-part skip-comment)))))
727 (defun antlr-outside-rule-p ()
728 "Non-nil if point is outside a grammar rule.
729 Move to the beginning of the current rule if point is inside a rule."
730 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
731 (let ((pos (point)))
732 (antlr-next-rule -1 nil)
733 (let ((between (or (bobp) (< (point) pos))))
734 (c-forward-syntactic-ws)
735 (and between (> (point) pos) (goto-char pos)))))
738 ;;;===========================================================================
739 ;;; Parse grammar files (commands)
740 ;;;===========================================================================
741 ;; No (interactive "_") in Emacs... use `zmacs-region-stays'.
743 (defun antlr-inside-rule-p ()
744 "Non-nil if point is inside a grammar rule.
745 A grammar class header and the file prelude are also considered as a
746 rule."
747 (save-excursion
748 (antlr-with-syntax-table antlr-action-syntax-table
749 (not (antlr-outside-rule-p)))))
751 (defun antlr-end-of-rule (&optional arg)
752 "Move forward to next end of rule. Do it ARG [default: 1] many times.
753 A grammar class header and the file prelude are also considered as a
754 rule. Negative argument ARG means move back to ARGth preceding end of
755 rule. If ARG is zero, run `antlr-end-of-body'."
756 (interactive "p")
757 (if (zerop arg)
758 (antlr-end-of-body)
759 (antlr-with-syntax-table antlr-action-syntax-table
760 (antlr-next-rule arg nil))
761 (setq zmacs-region-stays t)))
763 (defun antlr-beginning-of-rule (&optional arg)
764 "Move backward to preceding beginning of rule. Do it ARG many times.
765 A grammar class header and the file prelude are also considered as a
766 rule. Negative argument ARG means move forward to ARGth next beginning
767 of rule. If ARG is zero, run `antlr-beginning-of-body'."
768 (interactive "p")
769 (if (zerop arg)
770 (antlr-beginning-of-body)
771 (antlr-with-syntax-table antlr-action-syntax-table
772 (antlr-next-rule (- arg) t))
773 (setq zmacs-region-stays t)))
775 (defun antlr-end-of-body (&optional msg)
776 "Move to position after the `;' of the current rule.
777 A grammar class header is also considered as a rule. With optional
778 prefix arg MSG, move to `:'."
779 (interactive)
780 (antlr-with-syntax-table antlr-action-syntax-table
781 (let ((orig (point)))
782 (if (antlr-outside-rule-p)
783 (error "Outside an ANTLR rule"))
784 (let ((bor (point)))
785 (when (< (antlr-skip-file-prelude t) (point))
786 ;; Yes, we are in the file prelude
787 (goto-char orig)
788 (error (or msg "The file prelude is without `;'")))
789 (antlr-search-forward ";")
790 (when msg
791 (when (< (point)
792 (progn (goto-char bor)
793 (or (antlr-search-forward ":") (point-max))))
794 (goto-char orig)
795 (error msg))
796 (c-forward-syntactic-ws)))))
797 (setq zmacs-region-stays t))
799 (defun antlr-beginning-of-body ()
800 "Move to the first element after the `:' of the current rule."
801 (interactive)
802 (antlr-end-of-body "Class headers and the file prelude are without `:'"))
805 ;;;===========================================================================
806 ;;; Literal normalization, Hide Actions
807 ;;;===========================================================================
809 (defun antlr-downcase-literals (&optional transform)
810 "Convert all literals in buffer to lower case.
811 If non-nil, TRANSFORM is used on literals instead of `downcase-region'."
812 (interactive)
813 (or transform (setq transform 'downcase-region))
814 (let ((literals 0))
815 (save-excursion
816 (goto-char (point-min))
817 (antlr-with-syntax-table antlr-action-syntax-table
818 (antlr-invalidate-context-cache)
819 (while (antlr-re-search-forward "\"\\(\\sw\\(\\sw\\|-\\)*\\)\"" nil)
820 (funcall transform (match-beginning 0) (match-end 0))
821 (incf literals))))
822 (message "Transformed %d literals" literals)))
824 (defun antlr-upcase-literals ()
825 "Convert all literals in buffer to upper case."
826 (interactive)
827 (antlr-downcase-literals 'upcase-region))
829 (defun antlr-hide-actions (arg &optional silent)
830 "Hide or unhide all actions in buffer.
831 Hide all actions including arguments in brackets if ARG is 1 or if
832 called interactively without prefix argument. Hide all actions
833 excluding arguments in brackets if ARG is 2 or higher. Unhide all
834 actions if ARG is 0 or negative. Never hide actions whose character
835 length is shorter or equal to `antlr-tiny-action-length'."
836 (interactive "p")
837 ;; from Emacs/lazy-lock: `save-buffer-state'
838 (let ((modified (buffer-modified-p))
839 (buffer-undo-list t) (inhibit-read-only t)
840 (inhibit-point-motion-hooks t) deactivate-mark ; Emacs only
841 before-change-functions after-change-functions
842 buffer-file-name buffer-file-truename)
843 (if (> arg 0)
844 (let ((regexp (if (= arg 1) "[]}]" "}"))
845 (diff (+ (max antlr-tiny-action-length 0) 2)))
846 (antlr-hide-actions 0 t)
847 (save-excursion
848 (goto-char (point-min))
849 (antlr-with-syntax-table antlr-action-syntax-table
850 (antlr-invalidate-context-cache)
851 (while (antlr-re-search-forward regexp nil)
852 (let* ((end (point))
853 (beg (antlr-scan-sexps (point) -1 nil t)))
854 (and beg (> end (+ beg diff))
855 (add-text-properties (1+ beg) (1- end)
856 '(invisible t intangible t)))))))
857 (or silent
858 (message "Hide all actions (%s arguments)...done"
859 (if (= arg 1) "including" "excluding"))))
860 (remove-text-properties (point-min) (point-max)
861 '(invisible nil intangible nil))
862 (or silent
863 (message "Unhide all actions (including arguments)...done")))
864 (and (not modified) (buffer-modified-p)
865 (set-buffer-modified-p nil))))
868 ;;;===========================================================================
869 ;;; Indentation
870 ;;;===========================================================================
872 (defun antlr-indent-line ()
873 "Indent the current line as ANTLR grammar code.
874 The indentation of non-comment lines are calculated by `c-basic-offset',
875 multiplied by:
876 - the level of the paren/brace/bracket depth,
877 - plus 0/2/1, depending on the position inside the rule: header, body,
878 exception part,
879 - minus 1 if `antlr-indent-item-regexp' matches the beginning of the
880 line starting from the first non-blank.
882 Lines inside block comments are not changed or indented by
883 `c-indent-line', see `antlr-indent-comment'."
884 (let ((orig (point)) bol boi indent syntax)
885 (beginning-of-line)
886 (setq bol (point))
887 (skip-chars-forward " \t")
888 (setq boi (point))
889 ;; check syntax at beginning of indentation ------------------------------
890 (antlr-with-syntax-table antlr-action-syntax-table
891 (antlr-invalidate-context-cache)
892 (cond ((symbolp (setq syntax (antlr-syntactic-context)))
893 (setq indent nil)) ; block-comments, strings, (comments)
894 ((eq (char-after) ?#) ; cpp directive
895 (setq syntax 'cpp)
896 (setq indent 0)) ; indentation at 0
897 ((progn
898 (antlr-next-rule -1 t)
899 (if (antlr-search-forward ":") (< boi (1- (point))) t))
900 (setq indent 0)) ; in rule header
901 ((if (antlr-search-forward ";") (< boi (point)) t)
902 (setq indent 2)) ; in rule body
904 (forward-char)
905 (antlr-skip-exception-part nil)
906 (setq indent (if (> (point) boi) 1 0))))) ; in exception part?
907 ;; compute the corresponding indentation and indent ----------------------
908 (if (null indent)
909 (progn
910 (goto-char orig)
911 (and (eq antlr-indent-comment t)
912 (not (eq syntax 'string))
913 (c-indent-line)))
914 ;; do it ourselves
915 (goto-char boi)
916 (unless (symbolp syntax) ; direct indentation
917 (antlr-invalidate-context-cache)
918 (incf indent (antlr-syntactic-context))
919 (and (> indent 0) (looking-at antlr-indent-item-regexp) (decf indent))
920 (setq indent (* indent c-basic-offset)))
921 ;; the usual major-mode indent stuff:
922 (setq orig (- (point-max) orig))
923 (unless (= (current-column) indent)
924 (delete-region bol boi)
925 (beginning-of-line)
926 (indent-to indent))
927 ;; If initial point was within line's indentation,
928 ;; position after the indentation. Else stay at same point in text.
929 (if (> (- (point-max) orig) (point))
930 (goto-char (- (point-max) orig))))))
932 (defun antlr-indent-command (&optional arg)
933 "Indent the current line or insert tabs/spaces.
934 With optional prefix argument ARG or if the previous command was this
935 command, insert ARG tabs or spaces according to `indent-tabs-mode'.
936 Otherwise, indent the current line with `antlr-indent-line'."
937 (interactive "P")
938 (if (or arg (eq last-command 'antlr-indent-command))
939 (insert-tab arg)
940 (let ((antlr-indent-comment (and antlr-indent-comment t))) ; dynamic
941 (antlr-indent-line))))
944 ;;;===========================================================================
945 ;;; Mode entry
946 ;;;===========================================================================
948 (defun antlr-c-common-init ()
949 "Like `c-common-init' except menu, auto-hungry and c-style stuff."
950 ;; X/Emacs 20 only
951 (make-local-variable 'paragraph-start)
952 (make-local-variable 'paragraph-separate)
953 (make-local-variable 'paragraph-ignore-fill-prefix)
954 (make-local-variable 'require-final-newline)
955 (make-local-variable 'parse-sexp-ignore-comments)
956 (make-local-variable 'indent-line-function)
957 (make-local-variable 'indent-region-function)
958 (make-local-variable 'comment-start)
959 (make-local-variable 'comment-end)
960 (make-local-variable 'comment-column)
961 (make-local-variable 'comment-start-skip)
962 (make-local-variable 'comment-multi-line)
963 (make-local-variable 'outline-regexp)
964 (make-local-variable 'outline-level)
965 (make-local-variable 'adaptive-fill-regexp)
966 (make-local-variable 'adaptive-fill-mode)
967 (make-local-variable 'imenu-generic-expression) ;set in the mode functions
968 (and (boundp 'comment-line-break-function)
969 (make-local-variable 'comment-line-break-function))
970 ;; Emacs 19.30 and beyond only, AFAIK
971 (if (boundp 'fill-paragraph-function)
972 (progn
973 (make-local-variable 'fill-paragraph-function)
974 (setq fill-paragraph-function 'c-fill-paragraph)))
975 ;; now set their values
976 (setq paragraph-start (concat page-delimiter "\\|$")
977 paragraph-separate paragraph-start
978 paragraph-ignore-fill-prefix t
979 require-final-newline t
980 parse-sexp-ignore-comments t
981 indent-line-function 'c-indent-line
982 indent-region-function 'c-indent-region
983 outline-regexp "[^#\n\^M]"
984 outline-level 'c-outline-level
985 comment-column 32
986 comment-start-skip "/\\*+ *\\|// *"
987 comment-multi-line nil
988 comment-line-break-function 'c-comment-line-break-function
989 adaptive-fill-regexp nil
990 adaptive-fill-mode nil)
991 ;; we have to do something special for c-offsets-alist so that the
992 ;; buffer local value has its own alist structure.
993 (setq c-offsets-alist (copy-alist c-offsets-alist))
994 ;; setup the comment indent variable in a Emacs version portable way
995 ;; ignore any byte compiler warnings you might get here
996 (make-local-variable 'comment-indent-function)
997 (setq comment-indent-function 'c-comment-indent))
999 (defun antlr-language-for-option (option-value)
1000 "Find element in `antlr-language-alist' for OPTION-VALUE."
1001 ;; Like (find OPTION-VALUE antlr-language-alist :key 'cddr :test 'member)
1002 (let ((seq antlr-language-alist)
1004 (while seq
1005 (setq r (pop seq))
1006 (if (member option-value (cddr r))
1007 (setq seq nil) ; stop
1008 (setq r nil))) ; no result yet
1011 ;;;###autoload
1012 (defun antlr-mode ()
1013 "Major mode for editing ANTLR grammar files.
1014 \\{antlr-mode-map}"
1015 (interactive)
1016 (c-initialize-cc-mode) ; for java syntax table
1017 (kill-all-local-variables)
1018 ;; ANTLR specific ----------------------------------------------------------
1019 (setq major-mode 'antlr-mode
1020 mode-name "Antlr")
1021 (setq local-abbrev-table antlr-mode-abbrev-table)
1022 (set-syntax-table java-mode-syntax-table)
1023 (unless antlr-action-syntax-table
1024 (let ((slist (nth 3 antlr-font-lock-defaults)))
1025 (setq antlr-action-syntax-table
1026 (copy-syntax-table java-mode-syntax-table))
1027 (while slist
1028 (modify-syntax-entry (caar slist) (cdar slist)
1029 antlr-action-syntax-table)
1030 (setq slist (cdr slist)))))
1031 (use-local-map antlr-mode-map)
1032 (make-local-variable 'antlr-language)
1033 (unless antlr-language
1034 (save-excursion
1035 (goto-char (point-min))
1036 (setq antlr-language
1037 (car (or (and (re-search-forward (cdr antlr-language-limit-n-regexp)
1038 (car antlr-language-limit-n-regexp)
1040 (antlr-language-for-option (match-string 1)))
1041 (antlr-language-for-option nil))))))
1042 (if (stringp (cadr (assq antlr-language antlr-language-alist)))
1043 (setq mode-name
1044 (concat "Antlr."
1045 (cadr (assq antlr-language antlr-language-alist)))))
1046 ;; indentation, for the C engine -------------------------------------------
1047 (antlr-c-common-init)
1048 (setq indent-line-function 'antlr-indent-line
1049 indent-region-function nil) ; too lazy
1050 (setq comment-start "// "
1051 comment-end "")
1052 (c-set-style "java")
1053 (if (eq antlr-language 'c++-mode)
1054 (setq c-conditional-key c-C++-conditional-key
1055 c-comment-start-regexp c-C++-comment-start-regexp
1056 c-class-key c-C++-class-key
1057 c-extra-toplevel-key c-C++-extra-toplevel-key
1058 c-access-key c-C++-access-key
1059 c-recognize-knr-p nil)
1060 (setq c-conditional-key c-Java-conditional-key
1061 c-comment-start-regexp c-Java-comment-start-regexp
1062 c-class-key c-Java-class-key
1063 c-method-key nil
1064 c-baseclass-key nil
1065 c-recognize-knr-p nil
1066 c-access-key c-Java-access-key)
1067 (and (boundp 'c-inexpr-class-key) (boundp 'c-Java-inexpr-class-key)
1068 (setq c-inexpr-class-key c-Java-inexpr-class-key)))
1069 ;; various -----------------------------------------------------------------
1070 (make-local-variable 'font-lock-defaults)
1071 (setq font-lock-defaults antlr-font-lock-defaults)
1072 (easy-menu-add antlr-mode-menu)
1073 (make-local-variable 'imenu-create-index-function)
1074 (setq imenu-create-index-function 'antlr-imenu-create-index-function)
1075 (make-local-variable 'imenu-generic-expression)
1076 (setq imenu-generic-expression t) ; fool stupid test
1077 (and antlr-imenu-name ; there should be a global variable...
1078 (fboundp 'imenu-add-to-menubar)
1079 (imenu-add-to-menubar
1080 (if (stringp antlr-imenu-name) antlr-imenu-name "Index")))
1081 (antlr-set-tabs)
1082 (run-hooks 'antlr-mode-hook))
1084 ;; In XEmacs, a smarter version of `buffers-menu-grouping-function' could use
1085 ;; the following property. The header of the submenu would be "Antlr" instead
1086 ;; of "Antlr/C++" or "Antlr/Java" (depending on the buffer ordering).
1087 (put 'antlr-mode 'mode-name "Antlr")
1089 ;;;###autoload
1090 (defun antlr-set-tabs ()
1091 "Use ANTLR's convention for TABs according to `antlr-tab-offset-alist'.
1092 Used in `antlr-mode'. Also a useful function in `java-mode-hook'."
1093 (if buffer-file-name
1094 (let ((alist antlr-tab-offset-alist) elem)
1095 (while alist
1096 (setq elem (pop alist))
1097 (and (or (null (car elem)) (eq (car elem) major-mode))
1098 (or (null (cadr elem))
1099 (string-match (cadr elem) buffer-file-name))
1100 (setq tab-width (caddr elem)
1101 indent-tabs-mode (cadddr elem)
1102 alist nil))))))
1104 ;;; antlr-mode.el ends here
1106 ; LocalWords: antlr ANother ANTLR's Cpp Lexer TreeParser esp refs VALUEs ea ee
1107 ; LocalWords: Java's Nomencl ruledef tokendef ruleref tokenref setType ader
1108 ; LocalWords: ivate syntab lexer treeparser lic rotected rivate bor boi AFAIK
1109 ; LocalWords: slist knr inexpr