1 ;;; antlr-mode.el --- Major mode for ANTLR grammar files
3 ;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
5 ;; Author: Christoph.Wedler@sap.com
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)
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.
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 ;; This package provides the following features:
33 ;; * Syntax coloring (via font-lock) for grammar symbols and the code in
34 ;; actions. The latter depends on the language settings.
35 ;; * Indentation for the current line (TAB) and selected region (C-M-\).
36 ;; * Support for imenu/speedbar: menu "Index" (Parser, Lexer, TreeParser).
37 ;; * Commands to move to previous/next rule, beginning/end of rule body etc.
38 ;; * Commands to hide/unhide actions, upcase/downcase literals.
39 ;; * Run ANTLR from within Emacs, create Makefile dependencies.
41 ;; LANGUAGE SETTINGS. This mode needs to know which language is used in
42 ;; actions and semantic predicated of the grammar. This information is used
43 ;; for syntax coloring and the creation of the Makefile dependencies. It is
44 ;; stored in variable `antlr-language' and automatically set according to
45 ;; ANTLR's file option "language", see `antlr-language-alist'. The supported
46 ;; languages are "Java" (java-mode) and "Cpp" (c++-mode).
48 ;; INDENTATION. This package supports ANTLR's (intended) indentation style
49 ;; which is based on a simple paren/brace/bracket depth-level calculation, see
50 ;; `antlr-indent-line'. The indentation engine of cc-mode is only used inside
51 ;; block comments (it is not easy to use it for actions, esp if they come early
52 ;; in the rule body). By default, this package defines a tab width of 4 to be
53 ;; consistent to both ANTLR's conventions (TABs usage) and the
54 ;; `c-indentation-style' "java" which sets `c-basic-offset' to 4, see
55 ;; `antlr-tab-offset-alist'. You might want to set this variable to nil.
57 ;; SYNTAX COLORING comes in three phases. First, comments and strings are
58 ;; highlighted. Second, the grammar code is highlighted according to
59 ;; `antlr-font-lock-additional-keywords' (rule refs: dark blue, token refs:
60 ;; dark orange, definition: bold blue). Third, actions, semantic predicates
61 ;; and arguments are highlighted according to the usual font-lock keywords of
62 ;; `antlr-language', see also `antlr-font-lock-maximum-decoration'. We define
63 ;; special font-lock faces for the grammar code to allow you to distinguish
64 ;; ANTLR keywords from Java/C++ keywords.
66 ;; MAKEFILE CREATION. Command \\[antlr-show-makefile-rules] shows/inserts the
67 ;; dependencies for all grammar files in the current directory. It considers
68 ;; import/export vocabularies and grammar inheritance and provides a value for
69 ;; the -glib option if necessary (which you have to edit if the super-grammar
70 ;; is not in the same directory).
72 ;; TODO. Support to insert/change file/grammar/rule/subrule options. imenu
73 ;; support for method definitions in actions is not really planned (you can
74 ;; send be a patch, though). This mode would become too dependent on cc-mode
75 ;; or I would have to do a lot of language-dependent things myself...
77 ;; Bug fixes, bug reports, improvements, and suggestions are strongly
78 ;; appreciated. Please check the newest version first:
79 ;; http://www.fmi.uni-passau.de/~wedler/antlr-mode/changes.html
83 ;; This file requires Emacs-20.3, XEmacs-20.4 or higher and package cc-mode.
85 ;; If antlr-mode is not part of your distribution, put this file into your
86 ;; load-path and the following into your ~/.emacs:
87 ;; (autoload 'antlr-mode "antlr-mode" nil t)
88 ;; (setq auto-mode-alist (cons '("\\.g\\'" . antlr-mode) auto-mode-alist))
89 ;; (add-hook 'speedbar-load-hook ; would be too late in antlr-mode.el
90 ;; (lambda () (speedbar-add-supported-extension ".g")))
92 ;; If you edit ANTLR's source files, you might also want to use
93 ;; (autoload 'antlr-set-tabs "antlr-mode")
94 ;; (add-hook 'java-mode-hook 'antlr-set-tabs)
96 ;; I strongly recommend to use font-lock with a support mode like fast-lock,
97 ;; lazy-lock or better jit-lock (Emacs-21.1+) / lazy-shot (XEmacs).
99 ;; To customize, use `M-x customize-group RET antlr RET' or the custom browser
100 ;; (Emacs->Programming->Languages->Antlr).
104 (provide 'antlr-mode
)
105 (eval-when-compile ; required and optional libraries
107 (defvar outline-level
) (defvar imenu-use-markers
)
108 (defvar imenu-create-index-function
))
109 (eval-when-compile ; Emacs: cl, easymenu
112 (eval-when-compile ; XEmacs: Emacs vars
113 (defvar inhibit-point-motion-hooks
) (defvar deactivate-mark
))
115 (eval-and-compile ; XEmacs functions, simplified
116 (if (featurep 'xemacs
)
117 (defalias 'antlr-scan-sexps
'scan-sexps
)
118 (defalias 'antlr-scan-sexps
'antlr-scan-sexps-internal
))
119 (if (fboundp 'default-directory
)
120 (defalias 'antlr-default-directory
'default-directory
)
121 (defun antlr-default-directory () default-directory
))
122 (if (fboundp 'read-shell-command
)
123 (defalias 'antlr-read-shell-command
'read-shell-command
)
124 (defun antlr-read-shell-command (prompt &optional initial-input history
)
125 (read-from-minibuffer prompt initial-input nil nil
126 (or history
'shell-command-history
))))
127 (if (fboundp 'with-displaying-help-buffer
)
128 (defalias 'antlr-with-displaying-help-buffer
'with-displaying-help-buffer
)
129 (defun antlr-with-displaying-help-buffer (thunk &optional name
)
130 (with-output-to-temp-buffer "*Help*"
131 (save-excursion (funcall thunk
)))))
132 (if (and (fboundp 'buffer-syntactic-context
)
133 (fboundp 'buffer-syntactic-context-depth
))
135 (defalias 'antlr-invalidate-context-cache
'antlr-xemacs-bug-workaround
)
136 (defalias 'antlr-syntactic-context
'antlr-fast-syntactic-context
))
137 (defalias 'antlr-invalidate-context-cache
'ignore
)
138 (defalias 'antlr-syntactic-context
'antlr-slow-syntactic-context
)))
142 ;;;;##########################################################################
144 ;;;;##########################################################################
148 "Major mode for ANTLR grammar files."
150 :link
'(emacs-commentary-link "antlr-mode.el")
151 :link
'(url-link "http://www.fmi.uni-passau.de/~wedler/antlr-mode/")
154 (defconst antlr-version
"1.4"
155 "ANTLR major mode version number.")
158 ;;;===========================================================================
159 ;;; Controlling ANTLR's code generator (language option)
160 ;;;===========================================================================
162 (defvar antlr-language nil
163 "Major mode corresponding to ANTLR's \"language\" option.
164 Set via `antlr-language-alist'. The only useful place to change this
165 buffer-local variable yourself is in `antlr-mode-hook' or in the \"local
166 variable list\" near the end of the file, see
167 `enable-local-variables'.")
169 (defcustom antlr-language-alist
170 '((java-mode "Java" nil
"\"Java\"" "Java")
171 (c++-mode
"C++" "\"Cpp\"" "Cpp"))
172 "List of ANTLR's supported languages.
173 Each element in this list looks like
174 (MAJOR-MODE MODELINE-STRING OPTION-VALUE...)
176 MAJOR-MODE, the major mode of the code in the grammar's actions, is the
177 value of `antlr-language' if the first group in the string matched by
178 REGEXP in `antlr-language-limit-n-regexp' is one of the OPTION-VALUEs.
179 An OPTION-VALUE of nil denotes the fallback element. MODELINE-STRING is
180 also displayed in the modeline next to \"Antlr\"."
182 :type
'(repeat (group :value
(java-mode "")
183 (function :tag
"Major mode")
184 (string :tag
"Modeline string")
185 (repeat :tag
"ANTLR language option" :inline t
186 (choice (const :tag
"Default" nil
)
189 (defcustom antlr-language-limit-n-regexp
190 '(3000 .
"language[ \t]*=[ \t]*\\(\"?[A-Z][A-Za-z_]*\"?\\)")
191 "Used to set a reasonable value for `antlr-language'.
192 Looks like (LIMIT . REGEXP). Search for REGEXP from the beginning of
193 the buffer to LIMIT and use the first group in the matched string to set
194 the language according to `antlr-language-alist'."
196 :type
'(cons (choice :tag
"Limit" (const :tag
"No" nil
) (integer :value
0))
200 ;;;===========================================================================
201 ;;; Hide/Unhide, Indent/Tabs
202 ;;;===========================================================================
204 (defcustom antlr-action-visibility
3
205 "Visibility of actions when command `antlr-hide-actions' is used.
206 If nil, the actions with their surrounding braces are hidden. If a
207 number, do not hide the braces, only hide the contents if its length is
208 greater than this number."
210 :type
'(choice (const :tag
"Completely hidden" nil
)
211 (integer :tag
"Hidden if longer than" :value
3)))
213 (defcustom antlr-indent-comment
'tab
214 "*Non-nil, if the indentation should touch lines in block comments.
215 If nil, no continuation line of a block comment is changed. If t, they
216 are changed according to `c-indentation-line'. When not nil and not t,
217 they are only changed by \\[antlr-indent-command]."
219 :type
'(radio (const :tag
"No" nil
)
220 (const :tag
"Always" t
)
221 (sexp :tag
"With TAB" :format
"%t" :value tab
)))
223 (defcustom antlr-tab-offset-alist
224 '((antlr-mode nil
4 nil
)
225 (java-mode "antlr" 4 nil
))
226 "Alist to determine whether to use ANTLR's convention for TABs.
227 Each element looks like (MAJOR-MODE REGEXP TAB-WIDTH INDENT-TABS-MODE).
228 The first element whose MAJOR-MODE is nil or equal to `major-mode' and
229 whose REGEXP is nil or matches `buffer-file-name' is used to set
230 `tab-width' and `indent-tabs-mode'. This is useful to support both
231 ANTLR's and Java's indentation styles. Used by `antlr-set-tabs'."
233 :type
'(repeat (group :value
(antlr-mode nil
8 nil
)
234 (choice (const :tag
"All" nil
)
235 (function :tag
"Major mode"))
236 (choice (const :tag
"All" nil
) regexp
)
237 (integer :tag
"Tab width")
238 (boolean :tag
"Indent-tabs-mode"))))
240 (defvar antlr-indent-item-regexp
241 "[]}):;|&]\\|default[ \t]*:\\|case[ \t]+\\('\\\\?.'\\|[0-9]+\\|[A-Za-z_][A-Za-z_0-9]*\\)[ \t]*:" ; & is local ANTLR extension
242 "Regexp matching lines which should be indented by one TAB less.
243 See command \\[antlr-indent-command].")
246 ;;;===========================================================================
247 ;;; Run tool, create Makefile dependencies
248 ;;;===========================================================================
250 (defcustom antlr-tool-command
"java antlr.Tool"
251 "*Command used in \\[antlr-run-tool] to run the Antlr tool.
252 This variable should include all options passed to Antlr except the
253 option \"-glib\" which is automatically suggested if necessary."
257 (defcustom antlr-ask-about-save t
258 "*If not nil, \\[antlr-run-tool] asks which buffers to save.
259 Otherwise, it saves all modified buffers before running without asking."
263 (defcustom antlr-makefile-specification
264 '("\n" ("GENS" "GENS%d" " \\\n\t") "$(ANTLR)")
265 "*Variable to specify the appearance of the generated makefile rules.
266 This variable influences the output of \\[antlr-show-makefile-rules].
267 It looks like (RULE-SEP GEN-VAR-SPEC COMMAND).
269 RULE-SEP is the string to separate different makefile rules. COMMAND is
270 a string with the command which runs the Antlr tool, it should include
271 all options except the option \"-glib\" which is automatically added
274 If GEN-VAR-SPEC is nil, each target directly consists of a list of
275 files. If GEN-VAR-SPEC looks like (GEN-VAR GEN-VAR-FORMAT GEN-SEP), a
276 Makefile variable is created for each rule target.
278 Then, GEN-VAR is a string with the name of the variable which contains
279 the file names of all makefile rules. GEN-VAR-FORMAT is a format string
280 producing the variable of each target with substitution COUNT/%d where
281 COUNT starts with 1. GEN-SEP is used to separate long variable values."
283 :type
'(list (string :tag
"Rule separator")
285 (const :tag
"Direct targets" nil
)
286 (list :tag
"Variables for targets"
287 (string :tag
"Variable for all targets")
288 (string :tag
"Format for each target variable")
289 (string :tag
"Variable separator")))
290 (string :tag
"ANTLR command")))
292 (defvar antlr-file-formats-alist
293 '((java-mode ("%sTokenTypes.java") ("%s.java"))
294 (c++-mode
("%sTokenTypes.hpp") ("%s.cpp" "%s.hpp")))
295 "Language dependent formats which specify generated files.
296 Each element in this list looks looks like
297 (MAJOR-MODE (VOCAB-FILE-FORMAT...) (CLASS-FILE-FORMAT...)).
299 The element whose MAJOR-MODE is equal to `antlr-language' is used to
300 specify the generated files which are language dependent. See variable
301 `antlr-special-file-formats' for language independent files.
303 VOCAB-FILE-FORMAT is a format string, it specifies with substitution
304 VOCAB/%s the generated file for each export vocabulary VOCAB.
305 CLASS-FILE-FORMAT is a format string, it specifies with substitution
306 CLASS/%s the generated file for each grammar class CLASS.")
308 (defvar antlr-special-file-formats
'("%sTokenTypes.txt" "expanded%s.g")
309 "Language independent formats which specify generated files.
310 The value looks like (VOCAB-FILE-FORMAT EXPANDED-GRAMMAR-FORMAT).
312 VOCAB-FILE-FORMAT is a format string, it specifies with substitution
313 VOCAB/%s the generated or input file for each export or import
314 vocabulary VOCAB, respectively. EXPANDED-GRAMMAR-FORMAT is a format
315 string, it specifies with substitution GRAMMAR/%s the constructed
316 grammar file if the file GRAMMAR.g contains a grammar class which
317 extends a class other than \"Lexer\", \"Parser\" or \"TreeParser\".
319 See variable `antlr-file-formats-alist' for language dependent
322 (defvar antlr-unknown-file-formats
'("?%s?.g" "?%s?")
323 "*Formats which specify the names of unknown files.
324 The value looks like (SUPER-GRAMMAR-FILE-FORMAT SUPER-EVOCAB-FORMAT).
326 SUPER-GRAMMAR-FORMAT is a format string, it specifies with substitution
327 SUPER/%s the name of a grammar file for Antlr's option \"-glib\" if no
328 grammar file in the current directory defines the class SUPER or if it
329 is defined more than once. SUPER-EVOCAB-FORMAT is a format string, it
330 specifies with substitution SUPER/%s the name for the export vocabulary
331 of above mentioned class SUPER.")
333 (defvar antlr-help-unknown-file-text
334 "## The following rules contain filenames of the form
335 ## \"?SUPERCLASS?.g\" (and \"?SUPERCLASS?TokenTypes.txt\")
336 ## where SUPERCLASS is not found to be defined in any grammar file of
337 ## the current directory or is defined more than once. Please replace
338 ## these filenames by the grammar files (and their exportVocab).\n\n"
339 "String indicating the existence of unknown files in the Makefile.
340 See \\[antlr-show-makefile-rules] and `antlr-unknown-file-formats'.")
342 (defvar antlr-help-rules-intro
343 "The following Makefile rules define the dependencies for all (non-
344 expanded) grammars in directory \"%s\".\n
345 They are stored in the kill-ring, i.e., you can insert them with C-y
346 into your Makefile. You can also invoke M-x antlr-show-makefile-rules
347 from within a Makefile to insert them directly.\n\n\n"
348 "Introduction to use with \\[antlr-show-makefile-rules].
349 It is a format string and used with substitution DIRECTORY/%s where
350 DIRECTORY is the name of the current directory.")
353 ;;;===========================================================================
355 ;;;===========================================================================
357 (defcustom antlr-imenu-name t
358 "*Non-nil, if a \"Index\" menu should be added to the menubar.
359 If it is a string, it is used instead \"Index\". Requires package
362 :type
'(choice (const :tag
"No menu" nil
)
363 (const :tag
"Index menu" t
)
364 (string :tag
"Other menu name")))
366 (defvar antlr-mode-map
367 (let ((map (make-sparse-keymap)))
368 (define-key map
"\t" 'antlr-indent-command
)
369 (define-key map
"\e\C-a" 'antlr-beginning-of-rule
)
370 (define-key map
"\e\C-e" 'antlr-end-of-rule
)
371 (define-key map
"\C-c\C-a" 'antlr-beginning-of-body
)
372 (define-key map
"\C-c\C-e" 'antlr-end-of-body
)
373 (define-key map
"\C-c\C-f" 'c-forward-into-nomenclature
)
374 (define-key map
"\C-c\C-b" 'c-backward-into-nomenclature
)
375 (define-key map
"\C-c\C-c" 'comment-region
)
376 (define-key map
"\C-c\C-v" 'antlr-hide-actions
)
377 (define-key map
"\C-c\C-r" 'antlr-run-tool
)
378 ;; I'm too lazy to define my own:
379 (define-key map
"\ea" 'c-beginning-of-statement
)
380 (define-key map
"\ee" 'c-end-of-statement
)
382 "Keymap used in `antlr-mode' buffers.")
384 (easy-menu-define antlr-mode-menu
388 ["Indent Line" antlr-indent-command
389 :active
(not buffer-read-only
)]
390 ["Indent for Comment" indent-for-comment
391 :active
(not buffer-read-only
)]
392 ["Comment Out Region" comment-region
393 :active
(and (not buffer-read-only
)
394 (c-region-is-active-p))]
396 (comment-region (region-beginning) (region-end) '(4))
397 :active
(and (not buffer-read-only
)
398 (c-region-is-active-p))]
400 ["Backward Rule" antlr-beginning-of-rule t
]
401 ["Forward Rule" antlr-end-of-rule t
]
402 ["Start of Rule Body" antlr-beginning-of-body
403 :active
(antlr-inside-rule-p)]
404 ["End of Rule Body" antlr-end-of-body
405 :active
(antlr-inside-rule-p)]
407 ["Backward Statement" c-beginning-of-statement t
]
408 ["Forward Statement" c-end-of-statement t
]
409 ["Backward Into Nomencl." c-backward-into-nomenclature t
]
410 ["Forward Into Nomencl." c-forward-into-nomenclature t
]
412 ["Hide Actions (incl. Args)" antlr-hide-actions t
]
413 ["Hide Actions (excl. Args)" (antlr-hide-actions 2) t
]
414 ["Unhide All Actions" (antlr-hide-actions 0) t
]
416 ["Run Tool on Grammar" antlr-run-tool t
]
417 ["Show Makefile Rules" antlr-show-makefile-rules t
]))
420 ;;;===========================================================================
422 ;;;===========================================================================
424 (defcustom antlr-font-lock-maximum-decoration
'inherit
425 "*The maximum decoration level for fontifying actions.
426 Value `none' means, do not fontify actions, just normal grammar code
427 according to `antlr-font-lock-additional-keywords'. Value `inherit'
428 means, use value of `font-lock-maximum-decoration'. Any other value is
429 interpreted as in `font-lock-maximum-decoration' with no level-0
430 fontification, see `antlr-font-lock-keywords-alist'.
432 While calculating the decoration level for actions, `major-mode' is
433 bound to `antlr-language'. For example, with value
434 ((java-mode . 2) (c++-mode . 0))
435 Java actions are fontified with level 2 and C++ actions are not
437 :type
'(choice (const :tag
"none" none
)
438 (const :tag
"inherit" inherit
)
439 (const :tag
"default" nil
)
440 (const :tag
"maximum" t
)
441 (integer :tag
"level" 1)
442 (repeat :menu-tag
"mode specific" :tag
"mode specific"
444 (cons :tag
"Instance"
447 (symbol :tag
"name"))
448 (radio :tag
"Decoration"
449 (const :tag
"default" nil
)
450 (const :tag
"maximum" t
)
451 (integer :tag
"level" 1))))))
453 (defconst antlr-no-action-keywords nil
454 ;; Using nil directly won't work (would use highest level, see
455 ;; `font-lock-choose-keywords'), but a non-symbol, i.e., (list), at `car'
456 ;; would break Emacs-21.0:
457 "Empty font-lock keywords for actions.
458 Do not change the value of this constant.")
460 (defvar antlr-font-lock-keywords-alist
462 antlr-no-action-keywords
463 java-font-lock-keywords-1 java-font-lock-keywords-2
464 java-font-lock-keywords-3
)
466 antlr-no-action-keywords
467 c
++-font-lock-keywords-1 c
++-font-lock-keywords-2
468 c
++-font-lock-keywords-3
))
469 "List of font-lock keywords for actions in the grammar.
470 Each element in this list looks like
471 (MAJOR-MODE KEYWORD...)
473 If `antlr-language' is equal to MAJOR-MODE, the KEYWORDs are the
474 font-lock keywords according to `font-lock-defaults' used for the code
475 in the grammar's actions and semantic predicates, see
476 `antlr-font-lock-maximum-decoration'.")
478 (defvar antlr-font-lock-keyword-face
'antlr-font-lock-keyword-face
)
479 (defface antlr-font-lock-keyword-face
480 '((((class color
) (background light
)) (:foreground
"black" :bold t
)))
484 (defvar antlr-font-lock-ruledef-face
'antlr-font-lock-ruledef-face
)
485 (defface antlr-font-lock-ruledef-face
486 '((((class color
) (background light
)) (:foreground
"blue" :bold t
)))
487 "ANTLR rule references (definition)."
490 (defvar antlr-font-lock-tokendef-face
'antlr-font-lock-tokendef-face
)
491 (defface antlr-font-lock-tokendef-face
492 '((((class color
) (background light
)) (:foreground
"blue" :bold t
)))
493 "ANTLR token references (definition)."
496 (defvar antlr-font-lock-ruleref-face
'antlr-font-lock-ruleref-face
)
497 (defface antlr-font-lock-ruleref-face
498 '((((class color
) (background light
)) (:foreground
"blue4")))
499 "ANTLR rule references (usage)."
502 (defvar antlr-font-lock-tokenref-face
'antlr-font-lock-tokenref-face
)
503 (defface antlr-font-lock-tokenref-face
504 '((((class color
) (background light
)) (:foreground
"orange4")))
505 "ANTLR token references (usage)."
508 (defvar antlr-font-lock-literal-face
'antlr-font-lock-literal-face
)
509 (defface antlr-font-lock-literal-face
510 '((((class color
) (background light
)) (:foreground
"brown4" :bold t
)))
511 "ANTLR literal tokens consisting merely of letter-like characters."
514 (defvar antlr-font-lock-additional-keywords
515 `((antlr-invalidate-context-cache)
516 ("\\$setType[ \t]*(\\([A-Za-z\300-\326\330-\337]\\sw*\\))"
517 (1 antlr-font-lock-tokendef-face
))
518 ("\\$\\sw+" (0 font-lock-keyword-face
))
519 ;; the tokens are already fontified as string/docstrings:
521 (antlr-re-search-forward "\"\\(\\sw\\(\\sw\\|-\\)*\\)\"" limit
))
522 (1 antlr-font-lock-literal-face t
)
523 ,@(and (string-match "XEmacs" emacs-version
)
524 '((0 nil
)))) ; XEmacs bug workaround
526 (antlr-re-search-forward
527 "^\\(class\\)[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+\\(extends\\)[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;" limit
))
528 (1 antlr-font-lock-keyword-face
)
529 (2 antlr-font-lock-ruledef-face
)
530 (3 antlr-font-lock-keyword-face
)
531 (4 (if (member (match-string 4) '("Lexer" "Parser" "TreeParser"))
532 'antlr-font-lock-keyword-face
533 'font-lock-type-face
)))
535 (antlr-re-search-forward
536 "\\<\\(header\\|options\\|tokens\\|exception\\|catch\\|returns\\)\\>"
538 (1 antlr-font-lock-keyword-face
))
540 (antlr-re-search-forward
541 "^\\(private\\|public\\|protected\\)\\>\\([ \t]+\\(\\sw+\\)\\)?"
543 (1 font-lock-type-face
) ; not XEmacs' java level-3 fruit salad
544 (3 (if (antlr-upcase-p (char-after (match-beginning 3)))
545 'antlr-font-lock-tokendef-face
546 'antlr-font-lock-ruledef-face
) nil t
))
548 (antlr-re-search-forward "^\\sw+" limit
))
549 (0 (if (antlr-upcase-p (char-after (match-beginning 0)))
550 'antlr-font-lock-tokendef-face
551 'antlr-font-lock-ruledef-face
) nil t
))
553 ;; not only before a rule ref, also before a literal
554 (antlr-re-search-forward "\\<\\(\\sw+\\)[ \t]*:" limit
))
555 (1 font-lock-variable-name-face
))
557 (antlr-re-search-forward "\\<\\(\\sw+[ \t]*=[ \t]*\\)?\\(\\sw+[ \t]*:[ \t]*\\)?\\(\\sw+\\)" limit
))
558 ;;(1 antlr-font-lock-default-face nil t) ; fool java-font-lock-keywords
559 (3 (if (antlr-upcase-p (char-after (match-beginning 3)))
560 'antlr-font-lock-tokenref-face
561 'antlr-font-lock-ruleref-face
))))
562 "Font-lock keywords for ANTLR's normal grammar code.
563 See `antlr-font-lock-keywords-alist' for the keywords of actions.")
565 (defvar antlr-font-lock-defaults
566 '(antlr-font-lock-keywords
567 nil nil
((?_ .
"w") (?\
( .
".") (?\
) .
".")) beginning-of-defun
)
568 "Font-lock defaults used for ANTLR syntax coloring.
569 The SYNTAX-ALIST element is also used to initialize
570 `antlr-action-syntax-table'.")
573 ;;;===========================================================================
574 ;;; Internal variables
575 ;;;===========================================================================
577 (defvar antlr-mode-hook nil
578 "Hook called by `antlr-mode'.")
580 (defvar antlr-mode-syntax-table nil
581 "Syntax table used in `antlr-mode' buffers.
582 If non-nil, it will be initialized in `antlr-mode'.")
584 ;; used for "in Java/C++ code" = syntactic-depth>0
585 (defvar antlr-action-syntax-table nil
586 "Syntax table used for ANTLR action parsing.
587 Initialized by `antlr-mode-syntax-table', changed by SYNTAX-ALIST in
588 `antlr-font-lock-defaults'. This table should be selected if you use
589 `buffer-syntactic-context' and `buffer-syntactic-context-depth' in order
590 not to confuse their context_cache.")
592 (defvar antlr-mode-abbrev-table nil
593 "Abbreviation table used in `antlr-mode' buffers.")
594 (define-abbrev-table 'antlr-mode-abbrev-table
())
598 ;;;;##########################################################################
600 ;;;;##########################################################################
603 ;;;===========================================================================
604 ;;; Syntax functions -- Emacs vs XEmacs dependent
605 ;;;===========================================================================
607 ;; From help.el (XEmacs-21.1), without `copy-syntax-table'
608 (defmacro antlr-with-syntax-table
(syntab &rest body
)
609 "Evaluate BODY with the syntax table SYNTAB."
610 `(let ((stab (syntax-table)))
612 (progn (set-syntax-table ,syntab
) ,@body
)
613 (set-syntax-table stab
))))
614 (put 'antlr-with-syntax-table
'lisp-indent-function
1)
615 (put 'antlr-with-syntax-table
'edebug-form-spec
'(form body
))
617 (defun antlr-scan-sexps-internal (from count
&optional dummy no-error
)
618 ;; checkdoc-params: (from count dummy)
619 "Like `scan-sexps' but with additional arguments.
620 When optional arg NO-ERROR is non-nil, `scan-sexps' will return nil
621 instead of signaling an error."
624 (scan-sexps from count
)
626 (scan-sexps from count
)))
628 (defun antlr-xemacs-bug-workaround (&rest dummies
)
629 ;; checkdoc-params: (dummies)
630 "Invalidate context_cache for syntactical context information."
631 ;; XEmacs bug workaround
633 (set-buffer (get-buffer-create " ANTLR XEmacs bug workaround"))
634 (buffer-syntactic-context-depth))
637 (defun antlr-fast-syntactic-context ()
638 "Return some syntactic context information.
639 Return `string' if point is within a string, `block-comment' or
640 `comment' is point is within a comment or the depth within all
641 parenthesis-syntax delimiters at point otherwise.
642 WARNING: this may alter `match-data'."
643 (or (buffer-syntactic-context) (buffer-syntactic-context-depth)))
645 (defun antlr-slow-syntactic-context ()
646 "Return some syntactic context information.
647 Return `string' if point is within a string, `block-comment' or
648 `comment' is point is within a comment or the depth within all
649 parenthesis-syntax delimiters at point otherwise.
650 WARNING: this may alter `match-data'."
651 (let ((orig (point)))
653 (let ((state (parse-partial-sexp (point) orig
)))
655 (cond ((nth 3 state
) 'string
)
656 ((nth 4 state
) 'comment
) ; block-comment? -- we don't care
660 ;;;===========================================================================
662 ;;;===========================================================================
664 (defun antlr-upcase-p (char)
665 "Non-nil, if CHAR is an uppercase character (if CHAR was a char)."
666 ;; in XEmacs, upcase only works for ASCII
667 (or (and (<= ?A char
) (<= char ?Z
))
668 (and (<= ?
\300 char
) (<= char ?
\337)))) ; ?\327 is no letter
670 (defun antlr-re-search-forward (regexp bound
)
671 "Search forward from point for regular expression REGEXP.
672 Set point to the end of the occurrence found, and return point. Return
673 nil if no occurrence was found. Do not search within comments, strings
674 and actions/semantic predicates. BOUND bounds the search; it is a
675 buffer position. See also the functions `match-beginning', `match-end'
676 and `replace-match'."
677 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
679 (while (and (re-search-forward regexp bound
'limit
)
681 (if (eq (antlr-syntactic-context) 0)
684 (if continue nil
(point))))
686 (defun antlr-search-forward (string)
687 "Search forward from point for STRING.
688 Set point to the end of the occurrence found, and return point. Return
689 nil if no occurrence was found. Do not search within comments, strings
690 and actions/semantic predicates."
691 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
693 (while (and (search-forward string nil
'limit
)
694 (if (eq (antlr-syntactic-context) 0) (setq continue nil
) t
)))
695 (if continue nil
(point))))
697 (defun antlr-search-backward (string)
698 "Search backward from point for STRING.
699 Set point to the beginning of the occurrence found, and return point.
700 Return nil if no occurrence was found. Do not search within comments,
701 strings and actions/semantic predicates."
702 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
704 (while (and (search-backward string nil
'limit
)
705 (if (eq (antlr-syntactic-context) 0) (setq continue nil
) t
)))
706 (if continue nil
(point))))
708 (defsubst antlr-skip-sexps
(count)
709 "Skip the next COUNT balanced expressions and the comments after it.
710 Return position before the comments after the last expression."
711 (goto-char (or (antlr-scan-sexps (point) count nil t
) (point-max)))
713 (c-forward-syntactic-ws)))
716 ;;;===========================================================================
718 ;;;===========================================================================
720 (defun antlr-font-lock-keywords ()
721 "Return font-lock keywords for current buffer.
722 See `antlr-font-lock-additional-keywords', `antlr-language' and
723 `antlr-font-lock-maximum-decoration'."
724 (if (eq antlr-font-lock-maximum-decoration
'none
)
725 antlr-font-lock-additional-keywords
726 (append antlr-font-lock-additional-keywords
727 (eval (let ((major-mode antlr-language
)) ; dynamic
728 (font-lock-choose-keywords
729 (cdr (assq antlr-language
730 antlr-font-lock-keywords-alist
))
731 (if (eq antlr-font-lock-maximum-decoration
'inherit
)
732 font-lock-maximum-decoration
733 antlr-font-lock-maximum-decoration
)))))))
736 ;;;===========================================================================
738 ;;;===========================================================================
740 (defun antlr-imenu-create-index-function ()
741 "Return imenu index-alist for ANTLR grammar files."
745 ;; Using `imenu-progress-message' would require imenu for compilation --
746 ;; nobody is missing these messages...
747 (antlr-with-syntax-table antlr-action-syntax-table
748 ;; We stick to the imenu standard and search backwards, although I don't
749 ;; think this is right. It is slower and more likely not to work during
750 ;; editing (you are more likely to add functions to the end of the file).
753 (if (setq semi
(antlr-search-backward ";"))
754 (progn (forward-char) (antlr-skip-exception-part t
))
755 (antlr-skip-file-prelude t
))
756 (if (looking-at "{") (antlr-skip-sexps 1))
757 (if (looking-at "class[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;")
758 (push (cons (match-string 1)
759 (if imenu-use-markers
760 (copy-marker (match-beginning 1))
761 (match-beginning 1)))
763 (if (looking-at "p\\(ublic\\|rotected\\|rivate\\)")
764 (antlr-skip-sexps 1))
765 (when (looking-at "\\sw+")
766 (push (cons (match-string 0)
767 (if imenu-use-markers
768 (copy-marker (match-beginning 0))
769 (match-beginning 0)))
771 (if classes
(cons (cons "Classes" classes
) items
) items
)))
774 ;;;===========================================================================
775 ;;; Parse grammar files (internal functions)
776 ;;;===========================================================================
778 (defun antlr-skip-exception-part (skip-comment)
779 "Skip exception part of current rule, i.e., everything after `;'.
780 This also includes the options and tokens part of a grammar class
781 header. If SKIP-COMMENT is non-nil, also skip the comment after that
785 (c-forward-syntactic-ws)
786 (while (looking-at "options\\>\\|tokens\\>")
788 (setq pos
(antlr-skip-sexps 2)))
790 ;; Problem: an action only belongs to a class def, not a normal rule.
791 ;; But checking the current rule type is too expensive => only expect
792 ;; an action if we have found an option or tokens part.
793 (if (looking-at "{") (setq pos
(antlr-skip-sexps 1)))
794 (while (looking-at "exception\\>")
795 (setq pos
(antlr-skip-sexps 1))
796 (if (looking-at "\\[") (setq pos
(antlr-skip-sexps 1)))
797 (while (looking-at "catch\\>")
798 (setq pos
(antlr-skip-sexps 3)))))
799 (or skip-comment
(goto-char pos
))))
801 (defun antlr-skip-file-prelude (skip-comment)
802 "Skip the file prelude: the header and file options.
803 If SKIP-COMMENT is non-nil, also skip the comment after that part.
804 Return the start position of the file prelude."
807 (c-forward-syntactic-ws)
808 (if skip-comment
(setq pos0
(point)))
809 (while (looking-at "header\\>[ \t]*\\(\"\\)?")
810 (setq pos
(antlr-skip-sexps (if (match-beginning 1) 3 2))))
811 (if (looking-at "options\\>") (setq pos
(antlr-skip-sexps 2)))
812 (or skip-comment
(goto-char pos
))
815 (defun antlr-next-rule (arg skip-comment
)
816 "Move forward to next end of rule. Do it ARG many times.
817 A grammar class header and the file prelude are also considered as a
818 rule. Negative argument ARG means move back to ARGth preceding end of
819 rule. The behavior is not defined when ARG is zero. If SKIP-COMMENT
820 is non-nil, move to beginning of the rule."
821 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
825 ;; first look whether point is in exception part
826 (if (antlr-search-backward ";")
830 (antlr-skip-exception-part skip-comment
))
831 (antlr-skip-file-prelude skip-comment
))
833 (unless (and (< (point) pos
) (zerop (incf arg
)))
834 ;; if we have moved backward, we already moved one defun backward
835 (goto-char beg
) ; rewind (to ";" / point)
836 (while (and arg
(<= (incf arg
) 0))
837 (if (antlr-search-backward ";")
841 (setq pos
(antlr-skip-file-prelude skip-comment
))
844 (goto-char (if (>= pos beg
) (point-min) pos
)))
845 (goto-char (if (or (>= (point) beg
) (= (point) pos
))
848 (when arg
; always found a ";"
850 (antlr-skip-exception-part skip-comment
)))
851 (if (<= (point) pos
) ; moved backward?
852 (goto-char pos
) ; rewind
853 (decf arg
)) ; already moved one defun forward
855 (while (>= (decf arg
) 0)
856 (antlr-search-forward ";"))
857 (antlr-skip-exception-part skip-comment
)))))
859 (defun antlr-outside-rule-p ()
860 "Non-nil if point is outside a grammar rule.
861 Move to the beginning of the current rule if point is inside a rule."
862 ;; WARNING: Should only be used with `antlr-action-syntax-table'!
864 (antlr-next-rule -
1 nil
)
865 (let ((between (or (bobp) (< (point) pos
))))
866 (c-forward-syntactic-ws)
867 (and between
(> (point) pos
) (goto-char pos
)))))
870 ;;;===========================================================================
871 ;;; Parse grammar files (commands)
872 ;;;===========================================================================
873 ;; No (interactive "_") in Emacs... use `zmacs-region-stays'.
875 (defun antlr-inside-rule-p ()
876 "Non-nil if point is inside a grammar rule.
877 A grammar class header and the file prelude are also considered as a
880 (antlr-with-syntax-table antlr-action-syntax-table
881 (not (antlr-outside-rule-p)))))
883 (defun antlr-end-of-rule (&optional arg
)
884 "Move forward to next end of rule. Do it ARG [default: 1] many times.
885 A grammar class header and the file prelude are also considered as a
886 rule. Negative argument ARG means move back to ARGth preceding end of
887 rule. If ARG is zero, run `antlr-end-of-body'."
891 (antlr-with-syntax-table antlr-action-syntax-table
892 (antlr-next-rule arg nil
))
893 (setq zmacs-region-stays t
)))
895 (defun antlr-beginning-of-rule (&optional arg
)
896 "Move backward to preceding beginning of rule. Do it ARG many times.
897 A grammar class header and the file prelude are also considered as a
898 rule. Negative argument ARG means move forward to ARGth next beginning
899 of rule. If ARG is zero, run `antlr-beginning-of-body'."
902 (antlr-beginning-of-body)
903 (antlr-with-syntax-table antlr-action-syntax-table
904 (antlr-next-rule (- arg
) t
))
905 (setq zmacs-region-stays t
)))
907 (defun antlr-end-of-body (&optional msg
)
908 "Move to position after the `;' of the current rule.
909 A grammar class header is also considered as a rule. With optional
910 prefix arg MSG, move to `:'."
912 (antlr-with-syntax-table antlr-action-syntax-table
913 (let ((orig (point)))
914 (if (antlr-outside-rule-p)
915 (error "Outside an ANTLR rule"))
917 (when (< (antlr-skip-file-prelude t
) (point))
918 ;; Yes, we are in the file prelude
920 (error (or msg
"The file prelude is without `;'")))
921 (antlr-search-forward ";")
924 (progn (goto-char bor
)
925 (or (antlr-search-forward ":") (point-max))))
928 (c-forward-syntactic-ws)))))
929 (setq zmacs-region-stays t
))
931 (defun antlr-beginning-of-body ()
932 "Move to the first element after the `:' of the current rule."
934 (antlr-end-of-body "Class headers and the file prelude are without `:'"))
937 ;;;===========================================================================
938 ;;; Literal normalization, Hide Actions
939 ;;;===========================================================================
941 (defun antlr-downcase-literals (&optional transform
)
942 "Convert all literals in buffer to lower case.
943 If non-nil, TRANSFORM is used on literals instead of `downcase-region'."
945 (or transform
(setq transform
'downcase-region
))
948 (goto-char (point-min))
949 (antlr-with-syntax-table antlr-action-syntax-table
950 (antlr-invalidate-context-cache)
951 (while (antlr-re-search-forward "\"\\(\\sw\\(\\sw\\|-\\)*\\)\"" nil
)
952 (funcall transform
(match-beginning 0) (match-end 0))
954 (message "Transformed %d literals" literals
)))
956 (defun antlr-upcase-literals ()
957 "Convert all literals in buffer to upper case."
959 (antlr-downcase-literals 'upcase-region
))
961 (defun antlr-hide-actions (arg &optional silent
)
962 "Hide or unhide all actions in buffer.
963 Hide all actions including arguments in brackets if ARG is 1 or if
964 called interactively without prefix argument. Hide all actions
965 excluding arguments in brackets if ARG is 2 or higher. Unhide all
966 actions if ARG is 0 or negative. See `antlr-action-visibility'.
968 Display a message unless optional argument SILENT is non-nil."
970 ;; from Emacs/lazy-lock: `save-buffer-state'
971 (let ((modified (buffer-modified-p))
972 (buffer-undo-list t
) (inhibit-read-only t
)
973 (inhibit-point-motion-hooks t
) deactivate-mark
; Emacs only
974 before-change-functions after-change-functions
975 buffer-file-name buffer-file-truename
)
977 (let ((regexp (if (= arg
1) "[]}]" "}"))
978 (diff (and antlr-action-visibility
979 (+ (max antlr-action-visibility
0) 2))))
980 (antlr-hide-actions 0 t
)
982 (goto-char (point-min))
983 (antlr-with-syntax-table antlr-action-syntax-table
984 (antlr-invalidate-context-cache)
985 (while (antlr-re-search-forward regexp nil
)
986 (let ((beg (antlr-scan-sexps (point) -
1 nil t
)))
988 (if diff
; braces are visible
989 (if (> (point) (+ beg diff
))
990 (add-text-properties (1+ beg
) (1- (point))
991 '(invisible t intangible t
)))
992 ;; if actions is on line(s) of its own, hide WS
993 (and (looking-at "[ \t]*$")
996 (skip-chars-backward " \t")
997 (and (bolp) (setq beg
(point))))
998 (beginning-of-line 2)) ; beginning of next line
999 (add-text-properties beg
(point)
1000 '(invisible t intangible t
))))))))
1002 (message "Hide all actions (%s arguments)...done"
1003 (if (= arg
1) "including" "excluding"))))
1004 (remove-text-properties (point-min) (point-max)
1005 '(invisible nil intangible nil
))
1007 (message "Unhide all actions (including arguments)...done")))
1008 (and (not modified
) (buffer-modified-p)
1009 (set-buffer-modified-p nil
))))
1012 ;;;===========================================================================
1013 ;;; Compute dependencies
1014 ;;;===========================================================================
1016 (defun antlr-file-dependencies ()
1017 "Return dependencies for grammar in current buffer.
1018 The result looks like (FILE (CLASSES . SUPERS) VOCABS . LANGUAGE)
1019 where CLASSES = ((CLASS . CLASS-EVOCAB) ...),
1020 SUPERS = ((SUPER . USE-EVOCAB-P) ...), and
1021 VOCABS = ((EVOCAB ...) . (IVOCAB ...))
1023 FILE is the current buffer's file-name without directory part and
1024 LANGUAGE is the value of `antlr-language' in the current buffer. Each
1025 EVOCAB is an export vocabulary and each IVOCAB is an import vocabulary.
1027 Each CLASS is a grammar class with its export vocabulary CLASS-EVOCAB.
1028 Each SUPER is a super-grammar class where USE-EVOCAB-P indicates whether
1029 its export vocabulary is used as an import vocabulary."
1030 (unless buffer-file-name
1031 (error "Grammar buffer does not visit a file"))
1032 (let (classes exportVocabs importVocabs superclasses default-vocab
)
1033 (antlr-with-syntax-table antlr-action-syntax-table
1034 (goto-char (point-min))
1035 (while (antlr-re-search-forward "class[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]+extends[ \t]+\\([A-Za-z\300-\326\330-\337]\\sw*\\)[ \t]*;" nil
)
1036 ;; parse class definition --------------------------------------------
1037 (let* ((class (match-string 1))
1038 (sclass (match-string 2))
1039 ;; export vocab defaults to class name (first grammar in file)
1040 ;; or to the export vocab of the first grammar in file:
1041 (evocab (or default-vocab class
))
1043 (goto-char (match-end 0))
1044 (c-forward-syntactic-ws)
1045 (while (looking-at "options\\>\\|\\(tokens\\)\\>")
1046 (if (match-beginning 1)
1047 (antlr-skip-sexps 2)
1048 (goto-char (match-end 0))
1049 (c-forward-syntactic-ws)
1050 ;; parse grammar option section --------------------------------
1051 (when (eq (char-after (point)) ?\
{)
1052 (let* ((beg (1+ (point)))
1053 (end (1- (antlr-skip-sexps 1)))
1056 (if (re-search-forward "\\<exportVocab[ \t]*=[ \t]*\\([A-Za-z\300-\326\330-\337]\\sw*\\)" end t
)
1057 (setq evocab
(match-string 1)))
1059 (if (re-search-forward "\\<importVocab[ \t]*=[ \t]*\\([A-Za-z\300-\326\330-\337]\\sw*\\)" end t
)
1060 (setq ivocab
(match-string 1)))
1061 (goto-char cont
)))))
1062 (unless (member sclass
'("Parser" "Lexer" "TreeParser"))
1063 (let ((super (assoc sclass superclasses
)))
1065 (or ivocab
(setcdr super t
))
1066 (push (cons sclass
(null ivocab
)) superclasses
))))
1067 ;; remember class with export vocabulary:
1068 (push (cons class evocab
) classes
)
1069 ;; default export vocab is export vocab of first grammar in file:
1070 (or default-vocab
(setq default-vocab evocab
))
1071 (or (member evocab exportVocabs
) (push evocab exportVocabs
))
1073 (member ivocab importVocabs
) (push ivocab importVocabs
)))))
1075 (list* (file-name-nondirectory buffer-file-name
)
1076 (cons (nreverse classes
) (nreverse superclasses
))
1077 (cons (nreverse exportVocabs
) (nreverse importVocabs
))
1080 (defun antlr-directory-dependencies (dirname)
1081 "Return dependencies for all grammar files in directory DIRNAME.
1082 The result looks like ((CLASS-SPEC ...) . (FILE-DEP ...))
1083 where CLASS-SPEC = (CLASS (FILE . EVOCAB) ...).
1085 FILE-DEP are the dependencies for each grammar file in DIRNAME, see
1086 `antlr-file-dependencies'. For each grammar class CLASS, FILE is a
1087 grammar file in which CLASS is defined and EVOCAB is the name of the
1088 export vocabulary specified in that file."
1089 (let ((grammar (directory-files dirname t
"\\.g\\'")))
1091 (let ((temp-buffer (get-buffer-create
1092 (generate-new-buffer-name " *temp*")))
1093 (antlr-imenu-name nil
) ; dynamic-let: no imenu
1094 (expanded-regexp (concat (format (regexp-quote
1095 (cadr antlr-special-file-formats
))
1098 classes dependencies
)
1101 (set-buffer temp-buffer
)
1102 (widen) ; just in case...
1103 (dolist (file grammar
)
1104 (when (and (file-regular-p file
)
1105 (null (string-match expanded-regexp file
)))
1106 (insert-file-contents file t nil nil t
)
1107 (normal-mode t
) ; necessary for major-mode, syntax
1108 ; table and `antlr-language'
1109 (when (eq major-mode
'antlr-mode
)
1110 (let* ((file-deps (antlr-file-dependencies))
1111 (file (car file-deps
)))
1113 (dolist (class-def (caadr file-deps
))
1114 (let ((file-evocab (cons file
(cdr class-def
)))
1115 (class-spec (assoc (car class-def
) classes
)))
1117 (nconc (cdr class-spec
) (list file-evocab
))
1118 (push (list (car class-def
) file-evocab
)
1120 (push file-deps dependencies
)))))))
1121 (kill-buffer temp-buffer
))
1122 (cons (nreverse classes
) (nreverse dependencies
))))))
1125 ;;;===========================================================================
1126 ;;; Compilation: run ANTLR tool
1127 ;;;===========================================================================
1129 (defun antlr-superclasses-glibs (supers classes
)
1130 "Compute the grammar lib option for the super grammars SUPERS.
1131 Look in CLASSES for the right grammar lib files for SUPERS. SUPERS is
1132 part SUPER in the result of `antlr-file-dependencies'. CLASSES is the
1133 part (CLASS-SPEC ...) in the result of `antlr-directory-dependencies'.
1135 The result looks like (OPTION WITH-UNKNOWN GLIB ...). OPTION is the
1136 complete \"-glib\" option. WITH-UNKNOWN has value t iff there is none
1137 or more than one grammar file for at least one super grammar.
1139 Each GLIB looks like (GRAMMAR-FILE . EVOCAB). GRAMMAR-FILE is a file in
1140 which a super-grammar is defined. EVOCAB is the value of the export
1141 vocabulary of the super-grammar or nil if it is not needed."
1142 ;; If the superclass is defined in the same file, that file will be included
1143 ;; with -glib again. This will lead to a redefinition. But defining a
1144 ;; analyzer of the same class twice in a file will lead to an error anyway...
1145 (let (glibs unknown
)
1147 (let* ((super (pop supers
))
1148 (sup-files (cdr (assoc (car super
) classes
)))
1149 (file (and sup-files
(null (cdr sup-files
)) (car sup-files
))))
1150 (or file
(setq unknown t
)) ; not exactly one file
1151 (push (cons (or (car file
)
1152 (format (car antlr-unknown-file-formats
)
1156 (format (cadr antlr-unknown-file-formats
)
1159 (cons (if glibs
(concat " -glib " (mapconcat 'car glibs
";")) "")
1160 (cons unknown glibs
))))
1162 (defun antlr-run-tool (command file
&optional saved
)
1163 "Run Antlr took COMMAND on grammar FILE.
1164 When called interactively, COMMAND is read from the minibuffer and
1165 defaults to `antlr-tool-command' with a computed \"-glib\" option if
1168 Save all buffers first unless optional value SAVED is non-nil. When
1169 called interactively, the buffers are always saved, see also variable
1170 `antlr-ask-about-save'."
1172 ;; code in `interactive' is not compiled: do not use cl macros (`cdadr')
1173 (let* ((supers (cdr (cadr (save-excursion
1176 (antlr-file-dependencies))))))
1179 (save-some-buffers (not antlr-ask-about-save
) nil
)
1180 (setq glibs
(car (antlr-superclasses-glibs
1182 (car (antlr-directory-dependencies
1183 (antlr-default-directory)))))))
1184 (list (antlr-read-shell-command "Run Antlr on current file with: "
1185 (concat antlr-tool-command glibs
" "))
1188 (or saved
(save-some-buffers (not antlr-ask-about-save
)))
1189 (let ((default-directory (file-name-directory file
)))
1190 (require 'compile
) ; only `compile' autoload
1191 (compile-internal (concat command
" " (file-name-nondirectory file
))
1192 "No more errors" "Antlr-Run")))
1195 ;;;===========================================================================
1196 ;;; Makefile creation
1197 ;;;===========================================================================
1199 (defun antlr-makefile-insert-variable (number pre post
)
1200 "Insert Makefile variable numbered NUMBER according to specification.
1201 Also insert strings PRE and POST before and after the variable."
1202 (let ((spec (cadr antlr-makefile-specification
)))
1205 (if number
(format (cadr spec
) number
) (car spec
))
1208 (defun antlr-insert-makefile-rules (&optional in-makefile
)
1209 "Insert Makefile rules in the current buffer at point.
1210 IN-MAKEFILE is non-nil, if the current buffer is the Makefile. See
1211 command `antlr-show-makefile-rules' for detail."
1212 (let* ((dirname (antlr-default-directory))
1213 (deps0 (antlr-directory-dependencies dirname
))
1214 (classes (car deps0
)) ; CLASS -> (FILE . EVOCAB) ...
1215 (deps (cdr deps0
)) ; FILE -> (c . s) (ev . iv) . LANGUAGE
1217 (gen-sep (or (caddr (cadr antlr-makefile-specification
)) " "))
1218 (n (and (cdr deps
) (cadr antlr-makefile-specification
) 0)))
1219 (or in-makefile
(set-buffer standard-output
))
1221 (let ((supers (cdadr dep
))
1222 (lang (cdr (assoc (cdddr dep
) antlr-file-formats-alist
))))
1224 (antlr-makefile-insert-variable n
"" " =")
1227 (format (cadr antlr-special-file-formats
)
1228 (file-name-sans-extension (car dep
)))))
1229 (dolist (class-def (caadr dep
))
1230 (let ((sep gen-sep
))
1231 (dolist (class-file (cadr lang
))
1232 (insert sep
(format class-file
(car class-def
)))
1234 (dolist (evocab (caaddr dep
))
1235 (let ((sep gen-sep
))
1236 (dolist (vocab-file (cons (car antlr-special-file-formats
)
1238 (insert sep
(format vocab-file evocab
))
1240 (antlr-makefile-insert-variable n
"\n$(" ")")
1241 (insert ": " (car dep
))
1242 (dolist (ivocab (cdaddr dep
))
1243 (insert " " (format (car antlr-special-file-formats
) ivocab
)))
1244 (let ((glibs (antlr-superclasses-glibs supers classes
)))
1245 (if (cadr glibs
) (setq with-error t
))
1246 (dolist (super (cddr glibs
))
1247 (insert " " (car super
))
1249 (insert " " (format (car antlr-special-file-formats
)
1252 (caddr antlr-makefile-specification
)
1255 (car antlr-makefile-specification
)))))
1258 (antlr-makefile-insert-variable nil
"" " =")
1259 (while (<= (incf i
) n
)
1260 (antlr-makefile-insert-variable i
" $(" ")"))
1261 (insert "\n" (car antlr-makefile-specification
))))
1262 (if (string-equal (car antlr-makefile-specification
) "\n")
1263 (backward-delete-char 1))
1265 (goto-char (point-min))
1266 (insert antlr-help-unknown-file-text
))
1268 (copy-region-as-kill (point-min) (point-max))
1269 (goto-char (point-min))
1270 (insert (format antlr-help-rules-intro dirname
)))))
1273 (defun antlr-show-makefile-rules ()
1274 "Show Makefile rules for all grammar files in the current directory.
1275 If the `major-mode' of the current buffer has the value `makefile-mode',
1276 the rules are directory inserted at point. Otherwise, a *Help* buffer
1277 is shown with the rules which are also put into the `kill-ring' for
1280 This command considers import/export vocabularies and grammar
1281 inheritance and provides a value for the \"-glib\" option if necessary.
1282 Customize variable `antlr-makefile-specification' for the appearance of
1285 If the file for a super-grammar cannot be determined, special file names
1286 are used according to variable `antlr-unknown-file-formats' and a
1287 commentary with value `antlr-help-unknown-file-text' is added. The
1288 *Help* buffer always starts with the text in `antlr-help-rules-intro'."
1290 (if (null (eq major-mode
'makefile-mode
))
1291 (antlr-with-displaying-help-buffer 'antlr-insert-makefile-rules
)
1293 (antlr-insert-makefile-rules t
)))
1296 ;;;===========================================================================
1298 ;;;===========================================================================
1300 (defun antlr-indent-line ()
1301 "Indent the current line as ANTLR grammar code.
1302 The indentation of non-comment lines are calculated by `c-basic-offset',
1304 - the level of the paren/brace/bracket depth,
1305 - plus 0/2/1, depending on the position inside the rule: header, body,
1307 - minus 1 if `antlr-indent-item-regexp' matches the beginning of the
1308 line starting from the first non-blank.
1310 Lines inside block comments are not changed or indented by
1311 `c-indent-line', see `antlr-indent-comment'."
1312 (let ((orig (point)) bol boi indent syntax
)
1315 (skip-chars-forward " \t")
1317 ;; check syntax at beginning of indentation ------------------------------
1318 (antlr-with-syntax-table antlr-action-syntax-table
1319 (antlr-invalidate-context-cache)
1320 (cond ((symbolp (setq syntax
(antlr-syntactic-context)))
1321 (setq indent nil
)) ; block-comments, strings, (comments)
1322 ((eq (char-after) ?
#) ; cpp directive
1324 (setq indent
0)) ; indentation at 0
1326 (antlr-next-rule -
1 t
)
1327 (if (antlr-search-forward ":") (< boi
(1- (point))) t
))
1328 (setq indent
0)) ; in rule header
1329 ((if (antlr-search-forward ";") (< boi
(point)) t
)
1330 (setq indent
2)) ; in rule body
1333 (antlr-skip-exception-part nil
)
1334 (setq indent
(if (> (point) boi
) 1 0))))) ; in exception part?
1335 ;; compute the corresponding indentation and indent ----------------------
1339 (and (eq antlr-indent-comment t
)
1340 (not (eq syntax
'string
))
1344 (unless (symbolp syntax
) ; direct indentation
1345 (antlr-invalidate-context-cache)
1346 (incf indent
(antlr-syntactic-context))
1347 (and (> indent
0) (looking-at antlr-indent-item-regexp
) (decf indent
))
1348 (setq indent
(* indent c-basic-offset
)))
1349 ;; the usual major-mode indent stuff -----------------------------------
1350 (setq orig
(- (point-max) orig
))
1351 (unless (= (current-column) indent
)
1352 (delete-region bol boi
)
1355 ;; If initial point was within line's indentation,
1356 ;; position after the indentation. Else stay at same point in text.
1357 (if (> (- (point-max) orig
) (point))
1358 (goto-char (- (point-max) orig
))))))
1360 (defun antlr-indent-command (&optional arg
)
1361 "Indent the current line or insert tabs/spaces.
1362 With optional prefix argument ARG or if the previous command was this
1363 command, insert ARG tabs or spaces according to `indent-tabs-mode'.
1364 Otherwise, indent the current line with `antlr-indent-line'."
1366 (if (or arg
(eq last-command
'antlr-indent-command
))
1368 (let ((antlr-indent-comment (and antlr-indent-comment t
))) ; dynamic
1369 (antlr-indent-line))))
1372 ;;;===========================================================================
1374 ;;;===========================================================================
1376 (defun antlr-c-common-init ()
1377 "Like `c-common-init' except menu, auto-hungry and c-style stuff."
1379 (make-local-variable 'paragraph-start
)
1380 (make-local-variable 'paragraph-separate
)
1381 (make-local-variable 'paragraph-ignore-fill-prefix
)
1382 (make-local-variable 'require-final-newline
)
1383 (make-local-variable 'parse-sexp-ignore-comments
)
1384 (make-local-variable 'indent-line-function
)
1385 (make-local-variable 'indent-region-function
)
1386 (make-local-variable 'comment-start
)
1387 (make-local-variable 'comment-end
)
1388 (make-local-variable 'comment-column
)
1389 (make-local-variable 'comment-start-skip
)
1390 (make-local-variable 'comment-multi-line
)
1391 (make-local-variable 'outline-regexp
)
1392 (make-local-variable 'outline-level
)
1393 (make-local-variable 'adaptive-fill-regexp
)
1394 (make-local-variable 'adaptive-fill-mode
)
1395 (make-local-variable 'imenu-generic-expression
) ;set in the mode functions
1396 (and (boundp 'comment-line-break-function
)
1397 (make-local-variable 'comment-line-break-function
))
1398 ;; Emacs 19.30 and beyond only, AFAIK
1399 (if (boundp 'fill-paragraph-function
)
1401 (make-local-variable 'fill-paragraph-function
)
1402 (setq fill-paragraph-function
'c-fill-paragraph
)))
1403 ;; now set their values
1404 (setq paragraph-start
(concat page-delimiter
"\\|$")
1405 paragraph-separate paragraph-start
1406 paragraph-ignore-fill-prefix t
1407 require-final-newline t
1408 parse-sexp-ignore-comments t
1409 indent-line-function
'c-indent-line
1410 indent-region-function
'c-indent-region
1411 outline-regexp
"[^#\n\^M]"
1412 outline-level
'c-outline-level
1414 comment-start-skip
"/\\*+ *\\|// *"
1415 comment-multi-line nil
1416 comment-line-break-function
'c-comment-line-break-function
1417 adaptive-fill-regexp nil
1418 adaptive-fill-mode nil
)
1419 ;; we have to do something special for c-offsets-alist so that the
1420 ;; buffer local value has its own alist structure.
1421 (setq c-offsets-alist
(copy-alist c-offsets-alist
))
1422 ;; setup the comment indent variable in a Emacs version portable way
1423 ;; ignore any byte compiler warnings you might get here
1424 (make-local-variable 'comment-indent-function
)
1425 (setq comment-indent-function
'c-comment-indent
))
1427 (defun antlr-language-for-option (option-value)
1428 "Find element in `antlr-language-alist' for OPTION-VALUE."
1429 ;; Like (find OPTION-VALUE antlr-language-alist :key 'cddr :test 'member)
1430 (let ((seq antlr-language-alist
)
1434 (if (member option-value
(cddr r
))
1435 (setq seq nil
) ; stop
1436 (setq r nil
))) ; no result yet
1440 (defun antlr-mode ()
1441 "Major mode for editing ANTLR grammar files.
1444 (c-initialize-cc-mode) ; for java syntax table
1445 (kill-all-local-variables)
1446 ;; ANTLR specific ----------------------------------------------------------
1447 (setq major-mode
'antlr-mode
1449 (setq local-abbrev-table antlr-mode-abbrev-table
)
1450 (unless antlr-mode-syntax-table
1451 (setq antlr-mode-syntax-table
(make-syntax-table))
1452 (c-populate-syntax-table antlr-mode-syntax-table
))
1453 (set-syntax-table antlr-mode-syntax-table
)
1454 (unless antlr-action-syntax-table
1455 (let ((slist (nth 3 antlr-font-lock-defaults
)))
1456 (setq antlr-action-syntax-table
1457 (copy-syntax-table antlr-mode-syntax-table
))
1459 (modify-syntax-entry (caar slist
) (cdar slist
)
1460 antlr-action-syntax-table
)
1461 (setq slist
(cdr slist
)))))
1462 (use-local-map antlr-mode-map
)
1463 (make-local-variable 'antlr-language
)
1464 (unless antlr-language
1466 (goto-char (point-min))
1467 (setq antlr-language
1468 (car (or (and (re-search-forward (cdr antlr-language-limit-n-regexp
)
1469 (car antlr-language-limit-n-regexp
)
1471 (antlr-language-for-option (match-string 1)))
1472 (antlr-language-for-option nil
))))))
1473 (if (stringp (cadr (assq antlr-language antlr-language-alist
)))
1476 (cadr (assq antlr-language antlr-language-alist
)))))
1477 ;; indentation, for the C engine -------------------------------------------
1478 (antlr-c-common-init)
1479 (setq indent-line-function
'antlr-indent-line
1480 indent-region-function nil
) ; too lazy
1481 (setq comment-start
"// "
1483 (c-set-style "java")
1484 (if (eq antlr-language
'c
++-mode
)
1485 (setq c-conditional-key c-C
++-conditional-key
1486 c-comment-start-regexp c-C
++-comment-start-regexp
1487 c-class-key c-C
++-class-key
1488 c-extra-toplevel-key c-C
++-extra-toplevel-key
1489 c-access-key c-C
++-access-key
1490 c-recognize-knr-p nil
)
1491 (setq c-conditional-key c-Java-conditional-key
1492 c-comment-start-regexp c-Java-comment-start-regexp
1493 c-class-key c-Java-class-key
1496 c-recognize-knr-p nil
1497 c-access-key c-Java-access-key
)
1498 (and (boundp 'c-inexpr-class-key
) (boundp 'c-Java-inexpr-class-key
)
1499 (setq c-inexpr-class-key c-Java-inexpr-class-key
)))
1500 ;; various -----------------------------------------------------------------
1501 (make-local-variable 'font-lock-defaults
)
1502 (setq font-lock-defaults antlr-font-lock-defaults
)
1503 (easy-menu-add antlr-mode-menu
)
1504 (make-local-variable 'imenu-create-index-function
)
1505 (setq imenu-create-index-function
'antlr-imenu-create-index-function
)
1506 (make-local-variable 'imenu-generic-expression
)
1507 (setq imenu-generic-expression t
) ; fool stupid test
1508 (and antlr-imenu-name
; there should be a global variable...
1509 (fboundp 'imenu-add-to-menubar
)
1510 (imenu-add-to-menubar
1511 (if (stringp antlr-imenu-name
) antlr-imenu-name
"Index")))
1513 (run-hooks 'antlr-mode-hook
))
1515 ;; A smarter version of `group-buffers-menu-by-mode-then-alphabetically' (in
1516 ;; XEmacs) could use the following property. The header of the submenu would
1517 ;; be "Antlr" instead of "Antlr.C++" or (not and!) "Antlr.Java".
1518 (put 'antlr-mode
'mode-name
"Antlr")
1521 (defun antlr-set-tabs ()
1522 "Use ANTLR's convention for TABs according to `antlr-tab-offset-alist'.
1523 Used in `antlr-mode'. Also a useful function in `java-mode-hook'."
1524 (if buffer-file-name
1525 (let ((alist antlr-tab-offset-alist
) elem
)
1527 (setq elem
(pop alist
))
1528 (and (or (null (car elem
)) (eq (car elem
) major-mode
))
1529 (or (null (cadr elem
))
1530 (string-match (cadr elem
) buffer-file-name
))
1531 (setq tab-width
(caddr elem
)
1532 indent-tabs-mode
(cadddr elem
)
1535 ;;; antlr-mode.el ends here
1537 ; LocalWords: antlr ANother ANTLR's Cpp Lexer TreeParser esp refs VALUEs ea ee
1538 ; LocalWords: Java's Nomencl ruledef tokendef ruleref tokenref setType ader ev
1539 ; LocalWords: ivate syntab lexer treeparser lic rotected rivate bor boi AFAIK
1540 ; LocalWords: slist knr inexpr unhide jit GENS SEP GEN sTokenTypes hpp cpp DEP
1541 ; LocalWords: VOCAB EVOCAB Antlr's TokenTypes exportVocab incl excl SUPERS gen
1542 ; LocalWords: VOCABS IVOCAB exportVocabs importVocabs superclasses vocab kens
1543 ; LocalWords: sclass evocab ivocab importVocab deps glibs supers sep dep lang