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