]> code.delx.au - gnu-emacs/blobdiff - lisp/progmodes/ebnf2ps.el
Adam Hupp <adam at hupp.org>
[gnu-emacs] / lisp / progmodes / ebnf2ps.el
index 7f0a47bccf8189cc25d1cb16ce266a8cb2708a2a..be25293c643d280ae6db666cc8f399444da680d1 100644 (file)
@@ -1,19 +1,19 @@
 ;;; ebnf2ps.el --- translate an EBNF to a syntactic chart on PostScript
 
 ;;; ebnf2ps.el --- translate an EBNF to a syntactic chart on PostScript
 
-;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
+;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+;;   Free Software Foundation, Inc.
 
 
-;; Author: Vinicius Jose Latorre <vinicius@cpqd.com.br>
-;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
+;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
 ;; Keywords: wp, ebnf, PostScript
 ;; Keywords: wp, ebnf, PostScript
-;; Time-stamp: <2003/08/07 23:23:14 vinicius>
-;; Version: 3.6.1
-;; X-URL: http://www.cpqd.com.br/~vinicius/emacs/
+;; Version: 4.4
+;; X-URL: http://www.emacswiki.org/cgi-bin/wiki/ViniciusJoseLatorre
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 
 ;; This file is part of GNU Emacs.
 
 ;; GNU Emacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
-;; the Free Software Foundation; either version 2, or (at your option)
+;; the Free Software Foundation; either version 3, or (at your option)
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 ;; any later version.
 
 ;; GNU Emacs is distributed in the hope that it will be useful,
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
 
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
-;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+;; Boston, MA 02110-1301, USA.
 
 
-(defconst ebnf-version "3.6.1"
-  "ebnf2ps.el, v 3.6.1 <2001/09/24 vinicius>
+(defconst ebnf-version "4.4"
+  "ebnf2ps.el, v 4.4 <2007/02/12 vinicius>
 
 Vinicius's last change version.  When reporting bugs, please also
 report the version of Emacs, if any, that ebnf2ps was running with.
 
 Please send all bug fixes and enhancements to
 
 Vinicius's last change version.  When reporting bugs, please also
 report the version of Emacs, if any, that ebnf2ps was running with.
 
 Please send all bug fixes and enhancements to
-       Vinicius Jose Latorre <vinicius@cpqd.com.br>.
+       Vinicius Jose Latorre <viniciusjl@ig.com.br>.
 ")
 
 
 ")
 
 
@@ -69,15 +69,21 @@ Please send all bug fixes and enhancements to
 ;; Using ebnf2ps
 ;; -------------
 ;;
 ;; Using ebnf2ps
 ;; -------------
 ;;
-;; ebnf2ps provides six commands for generating PostScript syntactic chart
-;; images of Emacs buffers:
-;;
-;;     ebnf-print-buffer
-;;     ebnf-print-region
-;;     ebnf-spool-buffer
-;;     ebnf-spool-region
-;;     ebnf-eps-buffer
-;;     ebnf-eps-region
+;; ebnf2ps provides the following commands for generating PostScript syntactic
+;; chart images of Emacs buffers:
+;;
+;;    ebnf-print-directory
+;;    ebnf-print-file
+;;    ebnf-print-buffer
+;;    ebnf-print-region
+;;    ebnf-spool-directory
+;;    ebnf-spool-file
+;;    ebnf-spool-buffer
+;;    ebnf-spool-region
+;;    ebnf-eps-directory
+;;    ebnf-eps-file
+;;    ebnf-eps-buffer
+;;    ebnf-eps-region
 ;;
 ;; These commands all perform essentially the same function: they generate
 ;; PostScript syntactic chart images suitable for printing on a PostScript
 ;;
 ;; These commands all perform essentially the same function: they generate
 ;; PostScript syntactic chart images suitable for printing on a PostScript
@@ -87,14 +93,14 @@ Please send all bug fixes and enhancements to
 ;; The word "print", "spool" and "eps" in the command name determines when the
 ;; PostScript image is sent to the printer (or file):
 ;;
 ;; The word "print", "spool" and "eps" in the command name determines when the
 ;; PostScript image is sent to the printer (or file):
 ;;
-;;     print  - The PostScript image is immediately sent to the printer;
+;;    print  - The PostScript image is immediately sent to the printer;
 ;;
 ;;
-;;     spool  - The PostScript image is saved temporarily in an Emacs buffer.
-;;              Many images may be spooled locally before printing them.  To
-;;              send the spooled images to the printer, use the command
-;;              `ebnf-despool'.
+;;    spool  - The PostScript image is saved temporarily in an Emacs buffer.
+;;             Many images may be spooled locally before printing them.  To
+;;             send the spooled images to the printer, use the command
+;;             `ebnf-despool'.
 ;;
 ;;
-;;     eps    - The PostScript image is immediately sent to a EPS file.
+;;    eps    - The PostScript image is immediately sent to an EPS file.
 ;;
 ;; The spooling mechanism is the same as used by ps-print and was designed for
 ;; printing lots of small files to save paper that would otherwise be wasted on
 ;;
 ;; The spooling mechanism is the same as used by ps-print and was designed for
 ;; printing lots of small files to save paper that would otherwise be wasted on
@@ -110,25 +116,30 @@ Please send all bug fixes and enhancements to
 ;; you'll be asked to confirm the exit; this is modeled on the confirmation
 ;; that Emacs uses for modified buffers.
 ;;
 ;; you'll be asked to confirm the exit; this is modeled on the confirmation
 ;; that Emacs uses for modified buffers.
 ;;
-;; The word "buffer" or "region" in the command name determines how much of the
-;; buffer is printed:
+;; The word "directory", "file", "buffer" or "region" in the command name
+;; determines how much of the buffer is printed:
+;;
+;;    directory  - Read files in the directory and print them.
+;;
+;;    file       - Read file and print it.
 ;;
 ;;
-;;     buffer  - Print the entire buffer.
+;;    buffer     - Print the entire buffer.
 ;;
 ;;
-;;     region  - Print just the current region.
+;;    region     - Print just the current region.
 ;;
 ;; Two ebnf- command examples:
 ;;
 ;;
 ;; Two ebnf- command examples:
 ;;
-;;     ebnf-print-buffer  - translate and print the entire buffer, and send it
-;;                          immediately to the printer.
+;;    ebnf-print-buffer  - translate and print the entire buffer, and send it
+;;                         immediately to the printer.
 ;;
 ;;
-;;     ebnf-spool-region  - translate and print just the current region, and
-;;                          spool the image in Emacs to send to the printer
-;;                          later.
+;;    ebnf-spool-region  - translate and print just the current region, and
+;;                         spool the image in Emacs to send to the printer
+;;                         later.
 ;;
 ;;
-;; Note that `ebnf-eps-buffer' and `ebnf-eps-region' never spool the EPS image,
-;; so they don't use the ps-print spooling mechanism.  See section "Actions in
-;; Comments" for an explanation about EPS file generation.
+;; Note that `ebnf-eps-directory', `ebnf-eps-file', `ebnf-eps-buffer' and
+;; `ebnf-eps-region' never spool the EPS image, so they don't use the ps-print
+;; spooling mechanism.  See section "Actions in Comments" for an explanation
+;; about EPS file generation.
 ;;
 ;;
 ;; Invoking Ebnf2ps
 ;;
 ;;
 ;; Invoking Ebnf2ps
@@ -136,13 +147,13 @@ Please send all bug fixes and enhancements to
 ;;
 ;; To translate and print your buffer, type
 ;;
 ;;
 ;; To translate and print your buffer, type
 ;;
-;;        M-x ebnf-print-buffer
+;;    M-x ebnf-print-buffer
 ;;
 ;; or substitute one of the other four ebnf- commands.  The command will
 ;; generate the PostScript image and print or spool it as specified.  By giving
 ;; the command a prefix argument
 ;;
 ;;
 ;; or substitute one of the other four ebnf- commands.  The command will
 ;; generate the PostScript image and print or spool it as specified.  By giving
 ;; the command a prefix argument
 ;;
-;;        C-u M-x ebnf-print-buffer
+;;    C-u M-x ebnf-print-buffer
 ;;
 ;; it will save the PostScript image to a file instead of sending it to the
 ;; printer; you will be prompted for the name of the file to save the image to.
 ;;
 ;; it will save the PostScript image to a file instead of sending it to the
 ;; printer; you will be prompted for the name of the file to save the image to.
@@ -150,7 +161,7 @@ Please send all bug fixes and enhancements to
 ;; you may save the spooled images to a file by giving a prefix argument to
 ;; `ebnf-despool':
 ;;
 ;; you may save the spooled images to a file by giving a prefix argument to
 ;; `ebnf-despool':
 ;;
-;;        C-u M-x ebnf-despool
+;;    C-u M-x ebnf-despool
 ;;
 ;; When invoked this way, `ebnf-despool' will prompt you for the name of the
 ;; file to save to.
 ;;
 ;; When invoked this way, `ebnf-despool' will prompt you for the name of the
 ;; file to save to.
@@ -160,14 +171,41 @@ Please send all bug fixes and enhancements to
 ;;
 ;; Any of the `ebnf-' commands can be bound to keys.  Here are some examples:
 ;;
 ;;
 ;; Any of the `ebnf-' commands can be bound to keys.  Here are some examples:
 ;;
-;;   (global-set-key 'f22 'ebnf-print-buffer) ;f22 is prsc
-;;   (global-set-key '(shift f22) 'ebnf-print-region)
-;;   (global-set-key '(control f22) 'ebnf-despool)
+;;    (global-set-key 'f22 'ebnf-print-buffer) ;f22 is prsc
+;;    (global-set-key '(shift f22) 'ebnf-print-region)
+;;    (global-set-key '(control f22) 'ebnf-despool)
+;;
+;;
+;; Invoking Ebnf2ps in Batch
+;; -------------------------
+;;
+;; It's possible also to run ebnf2ps in batch, this is useful when, for
+;; example, you have a directory with a lot of files containing the EBNF to be
+;; translated to PostScript.
+;;
+;; To run ebnf2ps in batch type, for example:
+;;
+;;    emacs -batch -l setup-ebnf2ps.el -f ebnf-eps-directory
+;;
+;; Where setup-ebnf2ps.el should be a file containing:
+;;
+;;    ;; set load-path if ebnf2ps isn't installed in your Emacs environment
+;;    (setq load-path (append (list "/dir/of/ebnf2ps") load-path))
+;;    (require 'ebnf2ps)
+;;    ;; insert here your ebnf2ps settings
+;;    (setq ebnf-terminal-shape 'bevel)
+;;    ;; etc.
 ;;
 ;;
 ;; EBNF Syntax
 ;; -----------
 ;;
 ;;
 ;;
 ;; EBNF Syntax
 ;; -----------
 ;;
+;; BNF (Backus Naur Form) notation is defined like languages, and like
+;; languages there are rules about name formation and syntax.  In this section
+;; it's defined a BNF syntax that it's called simply EBNF (Extended BNF).
+;; ebnf2ps package also deal with other BNF notation.  Please, see the variable
+;; `ebnf-syntax' documentation below in this section.
+;;
 ;; The current EBNF that ebnf2ps accepts has the following constructions:
 ;;
 ;;    ;                        comment (until end of line)
 ;; The current EBNF that ebnf2ps accepts has the following constructions:
 ;;
 ;;    ;                        comment (until end of line)
@@ -181,7 +219,10 @@ Please send all bug fixes and enhancements to
 ;;    C D              sequence (C occurs before D)
 ;;    C | D            alternative (C or D occurs)
 ;;    A - B            exception (A excluding B, B without any non-terminal)
 ;;    C D              sequence (C occurs before D)
 ;;    C | D            alternative (C or D occurs)
 ;;    A - B            exception (A excluding B, B without any non-terminal)
-;;    n * A            repetition (A repeats n (integer) times)
+;;    n * A            repetition (A repeats at least n (integer) times)
+;;    n * n A          repetition (A repeats exactly n (integer) times)
+;;    n * m A          repetition (A repeats at least n (integer) and at most
+;;                     m (integer) times)
 ;;    (C)              group (expression C is grouped together)
 ;;    [C]              optional (C may or not occurs)
 ;;    C+               one or more occurrences of C
 ;;    (C)              group (expression C is grouped together)
 ;;    [C]              optional (C may or not occurs)
 ;;    C+               one or more occurrences of C
@@ -205,7 +246,7 @@ Please send all bug fixes and enhancements to
 ;;
 ;;    exception = repeat [ "-" repeat].         ;; exception
 ;;
 ;;
 ;;    exception = repeat [ "-" repeat].         ;; exception
 ;;
-;;    repeat = [ integer "*" ] term.            ;; repetition
+;;    repeat = [ integer "*" [ integer ]] term. ;; repetition
 ;;
 ;;    term = factor
 ;;         | [factor] "+"                       ;; one-or-more
 ;;
 ;;    term = factor
 ;;         | [factor] "+"                       ;; one-or-more
@@ -223,14 +264,30 @@ Please send all bug fixes and enhancements to
 ;;           .
 ;;
 ;;    non_terminal = "[!#%&'*-,0-:<>@-Z\\\\^-z~\\240-\\377]+".
 ;;           .
 ;;
 ;;    non_terminal = "[!#%&'*-,0-:<>@-Z\\\\^-z~\\240-\\377]+".
+;;    ;; that is, a valid non_terminal accepts decimal digits, letters (upper
+;;    ;; and lower), 8-bit accentuated characters,
+;;    ;; "!", "#", "%", "&", "'", "*", "+", ",", ":",
+;;    ;; "<", ">", "@", "\", "^", "_", "`" and "~".
 ;;
 ;;    terminal = "\\([^\"\\]\\|\\\\[ -~\\240-\\377]\\)+".
 ;;
 ;;    terminal = "\\([^\"\\]\\|\\\\[ -~\\240-\\377]\\)+".
+;;    ;; that is, a valid terminal accepts any printable character (including
+;;    ;; 8-bit accentuated characters) except `"', as `"' is used to delimit a
+;;    ;; terminal.  Also, accepts escaped characters, that is, a character
+;;    ;; pair starting with `\' followed by a printable character, for
+;;    ;; example: \", \\.
 ;;
 ;;
-;;    special = "[^?\\n\\000-\\010\\016-\\037\\177-\\237]*".
+;;    special = "[^?\\000-\\010\\012-\\037\\177-\\237]*".
+;;    ;; that is, a valid special accepts any printable character (including
+;;    ;; 8-bit accentuated characters) and tabs except `?', as `?' is used to
+;;    ;; delimit a special.
 ;;
 ;;    integer = "[0-9]+".
 ;;
 ;;    integer = "[0-9]+".
+;;    ;; that is, an integer is a sequence of one or more decimal digits.
 ;;
 ;;    comment = ";" "[^\\n\\000-\\010\\016-\\037\\177-\\237]*" "\\n".
 ;;
 ;;    comment = ";" "[^\\n\\000-\\010\\016-\\037\\177-\\237]*" "\\n".
+;;    ;; that is, a comment starts with the character `;' and terminates at end
+;;    ;; of line.  Also, it only accepts printable characters (including 8-bit
+;;    ;; accentuated characters) and tabs.
 ;;
 ;; Try to use the above EBNF to test ebnf2ps.
 ;;
 ;;
 ;; Try to use the above EBNF to test ebnf2ps.
 ;;
@@ -273,6 +330,10 @@ Please send all bug fixes and enhancements to
 ;;                     `ebnf-terminal-regexp', `ebnf-case-fold-search',
 ;;                     `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
 ;;
 ;;                     `ebnf-terminal-regexp', `ebnf-case-fold-search',
 ;;                     `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
 ;;
+;;    `abnf'           ebnf2ps recognizes the syntax described in the URL:
+;;                     `http://www.ietf.org/rfc/rfc2234.txt'
+;;                     ("Augmented BNF for Syntax Specifications: ABNF").
+;;
 ;;    `iso-ebnf'       ebnf2ps recognizes the syntax described in the URL:
 ;;                     `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
 ;;                     ("International Standard of the ISO EBNF Notation").
 ;;    `iso-ebnf'       ebnf2ps recognizes the syntax described in the URL:
 ;;                     `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
 ;;                     ("International Standard of the ISO EBNF Notation").
@@ -285,6 +346,14 @@ Please send all bug fixes and enhancements to
 ;;                     setting:
 ;;                     `ebnf-yac-ignore-error-recovery'.
 ;;
 ;;                     setting:
 ;;                     `ebnf-yac-ignore-error-recovery'.
 ;;
+;;    `ebnfx'          ebnf2ps recognizes the syntax described in the URL:
+;;                  `http://www.w3.org/TR/2004/REC-xml-20040204/#sec-notation'
+;;                  ("Extensible Markup Language (XML) 1.0 (Third Edition)")
+;;
+;;    `dtd'            ebnf2ps recognizes the syntax described in the URL:
+;;                     `http://www.w3.org/TR/2004/REC-xml-20040204/'
+;;                  ("Extensible Markup Language (XML) 1.0 (Third Edition)")
+;;
 ;; Any other value is treated as `ebnf'.
 ;;
 ;; The default value is `ebnf'.
 ;; Any other value is treated as `ebnf'.
 ;;
 ;; The default value is `ebnf'.
@@ -323,7 +392,7 @@ Please send all bug fixes and enhancements to
 ;;    6.  A = B | .                ==>   A = [B].
 ;;    7.  A =   | B .              ==>   A = [B].
 ;;
 ;;    6.  A = B | .                ==>   A = [B].
 ;;    7.  A =   | B .              ==>   A = [B].
 ;;
-;; factoration:
+;; factorization:
 ;;    8.  A = B C | B D.           ==>   A = B (C | D).
 ;;    9.  A = C B | D B.           ==>   A = (C | D) B.
 ;;    10. A = B C E | B D E.       ==>   A = B (C | D) E.
 ;;    8.  A = B C | B D.           ==>   A = B (C | D).
 ;;    9.  A = C B | D B.           ==>   A = (C | D) B.
 ;;    10. A = B C E | B D E.       ==>   A = B (C | D) E.
@@ -356,6 +425,8 @@ Please send all bug fixes and enhancements to
 ;;
 ;; ebnf2ps accepts the following actions in comments:
 ;;
 ;;
 ;; ebnf2ps accepts the following actions in comments:
 ;;
+;;    ;^       same as form feed.  See section Form Feed above.
+;;
 ;;    ;>       the next production starts in the same line as the current one.
 ;;             It is useful when `ebnf-horizontal-orientation' is nil.
 ;;
 ;;    ;>       the next production starts in the same line as the current one.
 ;;             It is useful when `ebnf-horizontal-orientation' is nil.
 ;;
@@ -377,6 +448,24 @@ Please send all bug fixes and enhancements to
 ;;             `ebnf-eps-region' execution.
 ;;             It's an error to try to close a not opened EPS file.
 ;;
 ;;             `ebnf-eps-region' execution.
 ;;             It's an error to try to close a not opened EPS file.
 ;;
+;;    ;Hheader generate a header in current EPS file.  The header string can
+;;             have the following formats:
+;;
+;;             %%      prints a % character.
+;;
+;;             %H      prints the `ebnf-eps-header' (which see) value.
+;;
+;;             %F      prints the `ebnf-eps-footer' (which see) value.
+;;
+;;             Any  other format is ignored, that is, if, for example, it's
+;;             used %s then %s characters are stripped out from the header.
+;;             If header is an empty string, no header is generated until a
+;;             non-empty header is specified or `ebnf-eps-header' has a
+;;             non-empty string value.
+;;
+;;    ;Ffooter generate a footer in current EPS file.  Similar to ;H action
+;;             comment.
+;;
 ;; So if you have:
 ;;
 ;;    (setq ebnf-horizontal-orientation nil)
 ;; So if you have:
 ;;
 ;;    (setq ebnf-horizontal-orientation nil)
@@ -420,8 +509,8 @@ Please send all bug fixes and enhancements to
 ;; Only the ;> will take effect, that is, A and B will be drawn in the same
 ;; line.
 ;;
 ;; Only the ;> will take effect, that is, A and B will be drawn in the same
 ;; line.
 ;;
-;; In ISO EBNF the above actions are specified as (*>*), (*<*), (*[EPS*) and
-;; (*]EPS*).  The first example above should be written:
+;; In ISO EBNF the above actions are specified as (*^*), (*>*), (*<*), (*[EPS*)
+;; and (*]EPS*).  The first example above should be written:
 ;;
 ;;    A = t;
 ;;    C = x;
 ;;
 ;;    A = t;
 ;;    C = x;
@@ -451,14 +540,14 @@ Please send all bug fixes and enhancements to
 ;;
 ;; The following table summarizes the results:
 ;;
 ;;
 ;; The following table summarizes the results:
 ;;
-;; EPS FILE NAME    NO SORT    ASCENDING SORT    DESCENDING SORT
-;; ebnf--AA.eps     A C        A C               C A
-;; ebnf--BB.eps     C B        B C               C B
-;; ebnf--CC.eps     A C B F    A B C F           F C B A
-;; ebnf--D.eps      D          D                 D
-;; ebnf--E.eps      E          E                 E
-;; ebnf--G.eps      G          G                 G
-;; ebnf--Z.eps      Z          Z                 Z
+;;    EPS FILE NAME    NO SORT    ASCENDING SORT    DESCENDING SORT
+;;    ebnf--AA.eps     A C        A C               C A
+;;    ebnf--BB.eps     C B        B C               C B
+;;    ebnf--CC.eps     A C B F    A B C F           F C B A
+;;    ebnf--D.eps      D          D                 D
+;;    ebnf--E.eps      E          E                 E
+;;    ebnf--G.eps      G          G                 G
+;;    ebnf--Z.eps      Z          Z                 Z
 ;;
 ;; As you can see if EPS actions is not used, each single production is
 ;; generated per EPS file.  To avoid overriding EPS files, use names in ;[ that
 ;;
 ;; As you can see if EPS actions is not used, each single production is
 ;; generated per EPS file.  To avoid overriding EPS files, use names in ;[ that
@@ -475,6 +564,16 @@ Please send all bug fixes and enhancements to
 ;; The production A is generated in both files ebnf--AA.eps and ebnf--BB.eps.
 ;;
 ;;
 ;; The production A is generated in both files ebnf--AA.eps and ebnf--BB.eps.
 ;;
 ;;
+;; Log Messages
+;; ------------
+;;
+;; The buffer *Ebnf2ps Log* is where the ebnf2ps log messages are inserted.
+;; These messages are intended to help debugging ebnf2ps.
+;;
+;; The log messages are enabled by `ebnf-log' option (which see).  The default
+;; value is nil, that is, no log messages are generated.
+;;
+;;
 ;; Utilities
 ;; ---------
 ;;
 ;; Utilities
 ;; ---------
 ;;
@@ -482,6 +581,12 @@ Please send all bug fixes and enhancements to
 ;;
 ;; `ebnf-setup' returns the current setup.
 ;;
 ;;
 ;; `ebnf-setup' returns the current setup.
 ;;
+;; `ebnf-syntax-directory' does a syntactic analysis of your EBNF files in the
+;; given directory.
+;;
+;; `ebnf-syntax-file' does a syntactic analysis of your EBNF in the given
+;; file.
+;;
 ;; `ebnf-syntax-buffer' does a syntactic analysis of your EBNF in the current
 ;; buffer.
 ;;
 ;; `ebnf-syntax-buffer' does a syntactic analysis of your EBNF in the current
 ;; buffer.
 ;;
@@ -490,8 +595,9 @@ Please send all bug fixes and enhancements to
 ;;
 ;; `ebnf-customize' activates a customization buffer for ebnf2ps options.
 ;;
 ;;
 ;; `ebnf-customize' activates a customization buffer for ebnf2ps options.
 ;;
-;; `ebnf-syntax-buffer', `ebnf-syntax-region' and `ebnf-customize' can be bound
-;; to keys in the same way as `ebnf-' commands.
+;; `ebnf-syntax-directory', `ebnf-syntax-file', `ebnf-syntax-buffer',
+;; `ebnf-syntax-region' and `ebnf-customize' can be bound to keys in the same
+;; way as `ebnf-' commands.
 ;;
 ;;
 ;; Hooks
 ;;
 ;;
 ;; Hooks
@@ -545,6 +651,9 @@ Please send all bug fixes and enhancements to
 ;;
 ;; `ebnf-terminal-border-color'                Specify border color for terminal box.
 ;;
 ;;
 ;; `ebnf-terminal-border-color'                Specify border color for terminal box.
 ;;
+;; `ebnf-production-name-p'            Non-nil means production name will be
+;;                                     printed.
+;;
 ;; `ebnf-sort-production'              Specify how productions are sorted.
 ;;
 ;; `ebnf-production-font'              Specify production font.
 ;; `ebnf-sort-production'              Specify how productions are sorted.
 ;;
 ;; `ebnf-production-font'              Specify production font.
@@ -562,6 +671,9 @@ Please send all bug fixes and enhancements to
 ;; `ebnf-non-terminal-border-color'    Specify border color for non-terminal
 ;;                                     box.
 ;;
 ;; `ebnf-non-terminal-border-color'    Specify border color for non-terminal
 ;;                                     box.
 ;;
+;; `ebnf-special-show-delimiter'       Non-nil means special delimiter
+;;                                     (character `?') is shown.
+;;
 ;; `ebnf-special-font'                 Specify special font.
 ;;
 ;; `ebnf-special-shape'                        Specify special box shape.
 ;; `ebnf-special-font'                 Specify special font.
 ;;
 ;; `ebnf-special-shape'                        Specify special box shape.
@@ -607,6 +719,11 @@ Please send all bug fixes and enhancements to
 ;;
 ;; `ebnf-line-color'                   Specify flow line color.
 ;;
 ;;
 ;; `ebnf-line-color'                   Specify flow line color.
 ;;
+;; `ebnf-arrow-extra-width'            Specify extra width for arrow shape
+;;                                     drawing.
+;;
+;; `ebnf-arrow-scale'                  Specify the arrow scale.
+;;
 ;; `ebnf-user-arrow'                   Specify a sexp for user arrow shape (a
 ;;                                     PostScript code).
 ;;
 ;; `ebnf-user-arrow'                   Specify a sexp for user arrow shape (a
 ;;                                     PostScript code).
 ;;
@@ -629,10 +746,24 @@ Please send all bug fixes and enhancements to
 ;;                                     default terminal, non-terminal or
 ;;                                     special.
 ;;
 ;;                                     default terminal, non-terminal or
 ;;                                     special.
 ;;
+;; `ebnf-file-suffix-regexp'           Specify file name suffix that contains
+;;                                     EBNF.
+;;
 ;; `ebnf-eps-prefix'                   Specify EPS prefix file name.
 ;;
 ;; `ebnf-eps-prefix'                   Specify EPS prefix file name.
 ;;
+;; `ebnf-eps-header-font'              Specify EPS header font.
+;;
+;; `ebnf-eps-header'                   Specify EPS header.
+;;
+;; `ebnf-eps-footer-font'              Specify EPS footer font.
+;;
+;; `ebnf-eps-footer'                   Specify EPS footer.
+;;
 ;; `ebnf-use-float-format'             Non-nil means use `%f' float format.
 ;;
 ;; `ebnf-use-float-format'             Non-nil means use `%f' float format.
 ;;
+;; `ebnf-stop-on-error'                        Non-nil means signal error and stop.
+;;                                     Nil means signal error and continue.
+;;
 ;; `ebnf-yac-ignore-error-recovery'    Non-nil means ignore error recovery.
 ;;
 ;; `ebnf-ignore-empty-rule'            Non-nil means ignore empty rules.
 ;; `ebnf-yac-ignore-error-recovery'    Non-nil means ignore error recovery.
 ;;
 ;; `ebnf-ignore-empty-rule'            Non-nil means ignore empty rules.
@@ -640,6 +771,8 @@ Please send all bug fixes and enhancements to
 ;; `ebnf-optimize'                     Non-nil means optimize syntactic chart
 ;;                                     of rules.
 ;;
 ;; `ebnf-optimize'                     Non-nil means optimize syntactic chart
 ;;                                     of rules.
 ;;
+;; `ebnf-log'                          Non-nil means generate log messages.
+;;
 ;; To set the above options you may:
 ;;
 ;; a) insert the code in your ~/.emacs, like:
 ;; To set the above options you may:
 ;;
 ;; a) insert the code in your ~/.emacs, like:
@@ -692,28 +825,33 @@ Please send all bug fixes and enhancements to
 ;; To help to handle this situation, ebnf2ps has the following commands to
 ;; handle styles:
 ;;
 ;; To help to handle this situation, ebnf2ps has the following commands to
 ;; handle styles:
 ;;
+;; `ebnf-find-style'   Return style definition if NAME is already defined;
+;;                     otherwise, return nil.
+;;
 ;; `ebnf-insert-style' Insert a new style NAME with inheritance INHERITS and
 ;;                     values VALUES.
 ;;
 ;; `ebnf-insert-style' Insert a new style NAME with inheritance INHERITS and
 ;;                     values VALUES.
 ;;
+;; `ebnf-delete-style' Delete style NAME.
+;;
 ;; `ebnf-merge-style'  Merge values of style NAME with style VALUES.
 ;;
 ;; `ebnf-merge-style'  Merge values of style NAME with style VALUES.
 ;;
-;; `ebnf-apply-style'  Set STYLE to current style.
+;; `ebnf-apply-style'  Set STYLE as the current style.
 ;;
 ;; `ebnf-reset-style'  Reset current style.
 ;;
 ;;
 ;; `ebnf-reset-style'  Reset current style.
 ;;
-;; `ebnf-push-style'   Push the current style and set STYLE to current style.
+;; `ebnf-push-style'   Push the current style and set STYLE as the current
+;;                     style.
 ;;
 ;;
-;; `ebnf-pop-style'    Pop a style and set it to current style.
+;; `ebnf-pop-style'    Pop a style and set it as the current style.
 ;;
 ;;
-;; These commands helps to put together a lot of variable settings in a group
+;; These commands help to put together a lot of variable settings in a group
 ;; and name this group.  So when you wish to apply these settings it's only
 ;; needed to give the name.
 ;;
 ;; and name this group.  So when you wish to apply these settings it's only
 ;; needed to give the name.
 ;;
-;; There is also a notion of simple inheritance of style; so if you declare
-;; that a style A inherits from a style B, all settings of B is applied first
-;; and then the settings of A is applied.  This is useful when you wish to
-;; modify some aspects of an existing style, but at same time wish to keep it
-;; unmodified.
+;; There is also a notion of simple inheritance of style: if you declare that
+;; style A inherits from style B, all settings of B are applied first and then
+;; the settings of A are applied.  This is useful when you wish to modify some
+;; aspects of an existing style, but at same time wish to keep it unmodified.
 ;;
 ;; See documentation for `ebnf-style-database'.
 ;;
 ;;
 ;; See documentation for `ebnf-style-database'.
 ;;
@@ -730,6 +868,8 @@ Please send all bug fixes and enhancements to
 ;;    entry            is the vertical position used to know where it should
 ;;                     be drawn the flow line in the current element.
 ;;
 ;;    entry            is the vertical position used to know where it should
 ;;                     be drawn the flow line in the current element.
 ;;
+;;    extra            is given by `ebnf-arrow-extra-width'.
+;;
 ;;
 ;;    * SPECIAL, TERMINAL and NON-TERMINAL
 ;;
 ;;
 ;;    * SPECIAL, TERMINAL and NON-TERMINAL
 ;;
@@ -741,17 +881,17 @@ Please send all bug fixes and enhancements to
 ;;       :   |   :      :   |   :  } font height / 2           }
 ;;       :   +==============+...:...............................
 ;;       :   :   :      :   :   :
 ;;       :   |   :      :   |   :  } font height / 2           }
 ;;       :   +==============+...:...............................
 ;;       :   :   :      :   :   :
-;;       :   :   :      :   :   :......................
-;;       :   :   :      :   :      } font height      }
-;;       :   :   :      :   :.......                  }
-;;       :   :   :      :          } font height / 2  }
-;;       :   :   :      :...........                  }
-;;       :   :   :                 } text width       } width
-;;       :   :   :..................                  }
-;;       :   :                     } font height / 2  }
-;;       :   :......................                  }
-;;       :                         } font height      }
-;;       :.............................................
+;;       :   :   :      :   :   :.........................
+;;       :   :   :      :   :      } font height          }
+;;       :   :   :      :   :.......                      }
+;;       :   :   :      :          } font height / 2      }
+;;       :   :   :      :...........                      }
+;;       :   :   :                 } text width           } width
+;;       :   :   :..................                      }
+;;       :   :                     } font height / 2      }
+;;       :   :......................                      }
+;;       :                         } font height + extra  }
+;;       :.................................................
 ;;
 ;;
 ;;    * OPTIONAL
 ;;
 ;;
 ;;    * OPTIONAL
@@ -882,21 +1022,21 @@ Please send all bug fixes and enhancements to
 ;;       :   |  :  :  :   :   |   :  } font height / 2           }
 ;;       :   +================+...:...............................
 ;;       :   :  :  :  :   :   :   :
 ;;       :   |  :  :  :   :   |   :  } font height / 2           }
 ;;       :   +================+...:...............................
 ;;       :   :  :  :  :   :   :   :
-;;       :   :  :  :  :   :   :   :......................
-;;       :   :  :  :  :   :   :      } font height      }
-;;       :   :  :  :  :   :   :.......                  }
-;;       :   :  :  :  :   :          } font height / 2  }
-;;       :   :  :  :  :   :...........                  }
-;;       :   :  :  :  :              } X width          }
-;;       :   :  :  :  :...............                  }
-;;       :   :  :  :                 } font height / 2  } width
-;;       :   :  :  :..................                  }
-;;       :   :  :                    } text width       }
-;;       :   :  :.....................                  }
-;;       :   :                       } font height / 2  }
-;;       :   :........................                  }
-;;       :                           } font height      }
-;;       :...............................................
+;;       :   :  :  :  :   :   :   :..........................
+;;       :   :  :  :  :   :   :      } font height          }
+;;       :   :  :  :  :   :   :.......                      }
+;;       :   :  :  :  :   :          } font height / 2      }
+;;       :   :  :  :  :   :...........                      }
+;;       :   :  :  :  :              } X width              }
+;;       :   :  :  :  :...............                      }
+;;       :   :  :  :                 } font height / 2      } width
+;;       :   :  :  :..................                      }
+;;       :   :  :                    } text width           }
+;;       :   :  :.....................                      }
+;;       :   :                       } font height / 2      }
+;;       :   :........................                      }
+;;       :                           } font height + extra  }
+;;       :...................................................
 ;;
 ;;
 ;;    * EXCEPT
 ;;
 ;;
 ;;    * EXCEPT
@@ -909,21 +1049,21 @@ Please send all bug fixes and enhancements to
 ;;       :   |  :   :   :   :   |   :  } font height / 2           }
 ;;       :   +==================+...:...............................
 ;;       :   :  :   :   :   :   :   :
 ;;       :   |  :   :   :   :   |   :  } font height / 2           }
 ;;       :   +==================+...:...............................
 ;;       :   :  :   :   :   :   :   :
-;;       :   :  :   :   :   :   :   :......................
-;;       :   :  :   :   :   :   :      } font height      }
-;;       :   :  :   :   :   :   :.......                  }
-;;       :   :  :   :   :   :          } font height / 2  }
-;;       :   :  :   :   :   :...........                  }
-;;       :   :  :   :   :              } Y width          }
-;;       :   :  :   :   :...............                  }
-;;       :   :  :   :                  } font height      } width
-;;       :   :  :   :...................                  }
-;;       :   :  :                      } X width          }
-;;       :   :  :.......................                  }
-;;       :   :                         } font height / 2  }
-;;       :   :..........................                  }
-;;       :                             } font height      }
-;;       :.................................................
+;;       :   :  :   :   :   :   :   :..........................
+;;       :   :  :   :   :   :   :      } font height          }
+;;       :   :  :   :   :   :   :.......                      }
+;;       :   :  :   :   :   :          } font height / 2      }
+;;       :   :  :   :   :   :...........                      }
+;;       :   :  :   :   :              } Y width              }
+;;       :   :  :   :   :...............                      }
+;;       :   :  :   :                  } font height          } width
+;;       :   :  :   :...................                      }
+;;       :   :  :                      } X width              }
+;;       :   :  :.......................                      }
+;;       :   :                         } font height / 2      }
+;;       :   :..........................                      }
+;;       :                             } font height + extra  }
+;;       :.....................................................
 ;;
 ;;       NOTE: If Y element is empty, it's draw nothing at Y place.
 ;;
 ;;
 ;;       NOTE: If Y element is empty, it's draw nothing at Y place.
 ;;
@@ -994,6 +1134,20 @@ Please send all bug fixes and enhancements to
 ;; Acknowledgements
 ;; ----------------
 ;;
 ;; Acknowledgements
 ;; ----------------
 ;;
+;; Thanks to Eli Zaretskii <eliz@gnu.org> for some doc fixes.
+;;
+;; Thanks to Drew Adams <drew.adams@oracle.com> for suggestions:
+;;    - `ebnf-arrow-extra-width', `ebnf-arrow-scale',
+;;     `ebnf-production-name-p', `ebnf-stop-on-error',
+;;     `ebnf-file-suffix-regexp'and `ebnf-special-show-delimiter' variables.
+;;    - `ebnf-delete-style', `ebnf-eps-file' and `ebnf-eps-directory'
+;;     commands.
+;;    - some docs fix.
+;;
+;; Thanks to Matthew K. Junker <junker@alum.mit.edu> for the suggestion to deal
+;; with some Bison features (%right, %left and %prec pragmas).  His suggestion
+;; was extended to deal with %nonassoc pragma too.
+;;
 ;; Thanks to all who emailed comments.
 ;;
 ;;
 ;; Thanks to all who emailed comments.
 ;;
 ;;
@@ -1007,6 +1161,21 @@ Please send all bug fixes and enhancements to
 (and (string< ps-print-version "5.2.3")
      (error "`ebnf2ps' requires `ps-print' package version 5.2.3 or later"))
 
 (and (string< ps-print-version "5.2.3")
      (error "`ebnf2ps' requires `ps-print' package version 5.2.3 or later"))
 
+
+;; to avoid gripes with Emacs 20
+(or (fboundp 'assq-delete-all)
+    (defun assq-delete-all (key alist)
+      "Delete from ALIST all elements whose car is KEY.
+Return the modified alist.
+Elements of ALIST that are not conses are ignored."
+      (let ((tail alist))
+       (while tail
+         (if (and (consp (car tail))
+                  (eq (car (car tail)) key))
+             (setq alist (delq (car tail) alist)))
+         (setq tail (cdr tail)))
+       alist)))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User Variables:
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; User Variables:
@@ -1015,91 +1184,104 @@ Please send all bug fixes and enhancements to
 ;;; Interface to the command system
 
 (defgroup postscript nil
 ;;; Interface to the command system
 
 (defgroup postscript nil
-  "PostScript Group"
+  "PostScript Group."
   :tag "PostScript"
   :tag "PostScript"
+  :version "20"
   :group 'emacs)
 
 
 (defgroup ebnf2ps nil
   :group 'emacs)
 
 
 (defgroup ebnf2ps nil
-  "Translate an EBNF to a syntactic chart on PostScript"
+  "Translate an EBNF to a syntactic chart on PostScript."
   :prefix "ebnf-"
   :prefix "ebnf-"
+  :version "20"
   :group 'wp
   :group 'postscript)
 
 
 (defgroup ebnf-special nil
   :group 'wp
   :group 'postscript)
 
 
 (defgroup ebnf-special nil
-  "Special customization"
+  "Special customization."
   :prefix "ebnf-"
   :tag "Special"
   :prefix "ebnf-"
   :tag "Special"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-except nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-except nil
-  "Except customization"
+  "Except customization."
   :prefix "ebnf-"
   :tag "Except"
   :prefix "ebnf-"
   :tag "Except"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-repeat nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-repeat nil
-  "Repeat customization"
+  "Repeat customization."
   :prefix "ebnf-"
   :tag "Repeat"
   :prefix "ebnf-"
   :tag "Repeat"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-terminal nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-terminal nil
-  "Terminal customization"
+  "Terminal customization."
   :prefix "ebnf-"
   :tag "Terminal"
   :prefix "ebnf-"
   :tag "Terminal"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-non-terminal nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-non-terminal nil
-  "Non-Terminal customization"
+  "Non-Terminal customization."
   :prefix "ebnf-"
   :tag "Non-Terminal"
   :prefix "ebnf-"
   :tag "Non-Terminal"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-production nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-production nil
-  "Production customization"
+  "Production customization."
   :prefix "ebnf-"
   :tag "Production"
   :prefix "ebnf-"
   :tag "Production"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-shape nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-shape nil
-  "Shapes customization"
+  "Shapes customization."
   :prefix "ebnf-"
   :tag "Shape"
   :prefix "ebnf-"
   :tag "Shape"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-displacement nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-displacement nil
-  "Displacement customization"
+  "Displacement customization."
   :prefix "ebnf-"
   :tag "Displacement"
   :prefix "ebnf-"
   :tag "Displacement"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-syntactic nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-syntactic nil
-  "Syntactic customization"
+  "Syntactic customization."
   :prefix "ebnf-"
   :tag "Syntactic"
   :prefix "ebnf-"
   :tag "Syntactic"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-optimization nil
   :group 'ebnf2ps)
 
 
 (defgroup ebnf-optimization nil
-  "Optimization customization"
+  "Optimization customization."
   :prefix "ebnf-"
   :tag "Optimization"
   :prefix "ebnf-"
   :tag "Optimization"
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-horizontal-orientation nil
   "*Non-nil means productions are drawn horizontally."
   :type 'boolean
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-horizontal-orientation nil
   "*Non-nil means productions are drawn horizontally."
   :type 'boolean
+  :version "20"
   :group 'ebnf-displacement)
 
 
   :group 'ebnf-displacement)
 
 
@@ -1108,6 +1290,7 @@ Please send all bug fixes and enhancements to
 
 It is only used when `ebnf-horizontal-orientation' is non-nil."
   :type 'boolean
 
 It is only used when `ebnf-horizontal-orientation' is non-nil."
   :type 'boolean
+  :version "20"
   :group 'ebnf-displacement)
 
 
   :group 'ebnf-displacement)
 
 
@@ -1116,6 +1299,7 @@ It is only used when `ebnf-horizontal-orientation' is non-nil."
 
 Value less or equal to zero forces ebnf2ps to set a proper default value."
   :type 'number
 
 Value less or equal to zero forces ebnf2ps to set a proper default value."
   :type 'number
+  :version "20"
   :group 'ebnf-displacement)
 
 
   :group 'ebnf-displacement)
 
 
@@ -1124,6 +1308,7 @@ Value less or equal to zero forces ebnf2ps to set a proper default value."
 
 Value less or equal to zero forces ebnf2ps to set a proper default value."
   :type 'number
 
 Value less or equal to zero forces ebnf2ps to set a proper default value."
   :type 'number
+  :version "20"
   :group 'ebnf-displacement)
 
 
   :group 'ebnf-displacement)
 
 
@@ -1137,9 +1322,17 @@ Valid values are:
    any other value     centralize"
   :type '(radio :tag "Sequence Justification"
                (const left) (const right) (other :tag "center" center))
    any other value     centralize"
   :type '(radio :tag "Sequence Justification"
                (const left) (const right) (other :tag "center" center))
+  :version "20"
   :group 'ebnf-displacement)
 
 
   :group 'ebnf-displacement)
 
 
+(defcustom ebnf-special-show-delimiter t
+  "*Non-nil means special delimiter (character `?') is shown."
+  :type 'boolean
+  :version "20"
+  :group 'ebnf-special)
+
+
 (defcustom ebnf-special-font '(7 Courier "Black" "Gray95" bold italic)
   "*Specify special font.
 
 (defcustom ebnf-special-font '(7 Courier "Black" "Gray95" bold italic)
   "*Specify special font.
 
@@ -1158,6 +1351,7 @@ See documentation for `ebnf-production-font'."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-special)
 
 
   :group 'ebnf-special)
 
 
@@ -1167,24 +1361,28 @@ See documentation for `ebnf-production-font'."
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Special Shape"
                (const miter) (const round) (const bevel))
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Special Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-shadow nil
   "*Non-nil means special box will have a shadow."
   :type 'boolean
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-shadow nil
   "*Non-nil means special box will have a shadow."
   :type 'boolean
+  :version "20"
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-border-width 0.5
   "*Specify border width for special box."
   :type 'number
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-border-width 0.5
   "*Specify border width for special box."
   :type 'number
+  :version "20"
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-border-color "Black"
   "*Specify border color for special box."
   :type 'string
   :group 'ebnf-special)
 
 
 (defcustom ebnf-special-border-color "Black"
   "*Specify border color for special box."
   :type 'string
+  :version "20"
   :group 'ebnf-special)
 
 
   :group 'ebnf-special)
 
 
@@ -1206,6 +1404,7 @@ See documentation for `ebnf-production-font'."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-except)
 
 
   :group 'ebnf-except)
 
 
@@ -1215,24 +1414,28 @@ See documentation for `ebnf-production-font'."
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Except Shape"
                (const miter) (const round) (const bevel))
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Except Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-shadow nil
   "*Non-nil means except box will have a shadow."
   :type 'boolean
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-shadow nil
   "*Non-nil means except box will have a shadow."
   :type 'boolean
+  :version "20"
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-border-width 0.25
   "*Specify border width for except box."
   :type 'number
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-border-width 0.25
   "*Specify border width for except box."
   :type 'number
+  :version "20"
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-border-color "Black"
   "*Specify border color for except box."
   :type 'string
   :group 'ebnf-except)
 
 
 (defcustom ebnf-except-border-color "Black"
   "*Specify border color for except box."
   :type 'string
+  :version "20"
   :group 'ebnf-except)
 
 
   :group 'ebnf-except)
 
 
@@ -1254,6 +1457,7 @@ See documentation for `ebnf-production-font'."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-repeat)
 
 
   :group 'ebnf-repeat)
 
 
@@ -1263,24 +1467,28 @@ See documentation for `ebnf-production-font'."
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Repeat Shape"
                (const miter) (const round) (const bevel))
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Repeat Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-shadow nil
   "*Non-nil means repeat box will have a shadow."
   :type 'boolean
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-shadow nil
   "*Non-nil means repeat box will have a shadow."
   :type 'boolean
+  :version "20"
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-border-width 0.0
   "*Specify border width for repeat box."
   :type 'number
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-border-width 0.0
   "*Specify border width for repeat box."
   :type 'number
+  :version "20"
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-border-color "Black"
   "*Specify border color for repeat box."
   :type 'string
   :group 'ebnf-repeat)
 
 
 (defcustom ebnf-repeat-border-color "Black"
   "*Specify border color for repeat box."
   :type 'string
+  :version "20"
   :group 'ebnf-repeat)
 
 
   :group 'ebnf-repeat)
 
 
@@ -1302,6 +1510,7 @@ See documentation for `ebnf-production-font'."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-terminal)
 
 
   :group 'ebnf-terminal)
 
 
@@ -1311,27 +1520,38 @@ See documentation for `ebnf-production-font'."
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Terminal Shape"
                (const miter) (const round) (const bevel))
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Terminal Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-shadow nil
   "*Non-nil means terminal box will have a shadow."
   :type 'boolean
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-shadow nil
   "*Non-nil means terminal box will have a shadow."
   :type 'boolean
+  :version "20"
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-border-width 1.0
   "*Specify border width for terminal box."
   :type 'number
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-border-width 1.0
   "*Specify border width for terminal box."
   :type 'number
+  :version "20"
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-border-color "Black"
   "*Specify border color for terminal box."
   :type 'string
   :group 'ebnf-terminal)
 
 
 (defcustom ebnf-terminal-border-color "Black"
   "*Specify border color for terminal box."
   :type 'string
+  :version "20"
   :group 'ebnf-terminal)
 
 
   :group 'ebnf-terminal)
 
 
+(defcustom ebnf-production-name-p t
+  "*Non-nil means production name will be printed."
+  :type 'boolean
+  :version "20"
+  :group 'ebnf-production)
+
+
 (defcustom ebnf-sort-production nil
   "*Specify how productions are sorted.
 
 (defcustom ebnf-sort-production nil
   "*Specify how productions are sorted.
 
@@ -1344,6 +1564,7 @@ Valid values are:
                (const :tag "Ascending" ascending)
                (const :tag "Descending" descending)
                (other :tag "No Sort" nil))
                (const :tag "Ascending" ascending)
                (const :tag "Descending" descending)
                (other :tag "No Sort" nil))
+  :version "20"
   :group 'ebnf-production)
 
 
   :group 'ebnf-production)
 
 
@@ -1386,6 +1607,7 @@ See `ps-font-info-database' for valid font name."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-production)
 
 
   :group 'ebnf-production)
 
 
@@ -1407,6 +1629,7 @@ See documentation for `ebnf-production-font'."
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
                               (const underline) (const strikeout)
                               (const overline)  (const shadow)
                               (const box)       (const outline))))
+  :version "20"
   :group 'ebnf-non-terminal)
 
 
   :group 'ebnf-non-terminal)
 
 
@@ -1430,24 +1653,28 @@ Valid values are:
 Any other value is treated as `miter'."
   :type '(radio :tag "Non-Terminal Shape"
                (const miter) (const round) (const bevel))
 Any other value is treated as `miter'."
   :type '(radio :tag "Non-Terminal Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-shadow nil
   "*Non-nil means non-terminal box will have a shadow."
   :type 'boolean
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-shadow nil
   "*Non-nil means non-terminal box will have a shadow."
   :type 'boolean
+  :version "20"
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-border-width 1.0
   "*Specify border width for non-terminal box."
   :type 'number
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-border-width 1.0
   "*Specify border width for non-terminal box."
   :type 'number
+  :version "20"
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-border-color "Black"
   "*Specify border color for non-terminal box."
   :type 'string
   :group 'ebnf-non-terminal)
 
 
 (defcustom ebnf-non-terminal-border-color "Black"
   "*Specify border color for non-terminal box."
   :type 'string
+  :version "20"
   :group 'ebnf-non-terminal)
 
 
   :group 'ebnf-non-terminal)
 
 
@@ -1482,14 +1709,29 @@ Valid values are:
                                                  |*
                                                  *
 
                                                  |*
                                                  *
 
+   `semi-up-hollow'               `semi-up-full'
+                 *                               *
+                 |*                              |*
+                 | *                             |X*
+               ==+==*                          ==+==*
+
+   `semi-down-hollow'             `semi-down-full'
+               ==+==*                          ==+==*
+                 | *                             |X*
+                 |*                              |*
+                 *                               *
+
    `user'      See also documentation for variable `ebnf-user-arrow'.
 
 Any other value is treated as `none'."
   :type '(radio :tag "Arrow Shape"
    `user'      See also documentation for variable `ebnf-user-arrow'.
 
 Any other value is treated as `none'."
   :type '(radio :tag "Arrow Shape"
-               (const none)        (const semi-up)
-               (const semi-down)   (const simple)
-               (const transparent) (const hollow)
-               (const full)        (const user))
+               (const none)             (const semi-up)
+               (const semi-down)        (const simple)
+               (const transparent)      (const hollow)
+               (const full)             (const semi-up-hollow)
+               (const semi-down-hollow) (const semi-up-full)
+               (const semi-down-full)   (const user))
+  :version "20"
   :group 'ebnf-shape)
 
 
   :group 'ebnf-shape)
 
 
@@ -1499,6 +1741,7 @@ Any other value is treated as `none'."
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Chart Flow Shape"
                (const miter) (const round) (const bevel))
 See documentation for `ebnf-non-terminal-shape'."
   :type '(radio :tag "Chart Flow Shape"
                (const miter) (const round) (const bevel))
+  :version "20"
   :group 'ebnf-shape)
 
 
   :group 'ebnf-shape)
 
 
@@ -1538,6 +1781,7 @@ The relation between these variables is: hT = 2 * hT2 = 4 * hT4.
 The variable `ebnf-user-arrow' is only used when `ebnf-arrow-shape' is set to
 symbol `user'."
   :type '(sexp :tag "User Arrow Shape")
 The variable `ebnf-user-arrow' is only used when `ebnf-arrow-shape' is set to
 symbol `user'."
   :type '(sexp :tag "User Arrow Shape")
+  :version "20"
   :group 'ebnf-shape)
 
 
   :group 'ebnf-shape)
 
 
@@ -1553,6 +1797,10 @@ Valid values are:
                `ebnf-terminal-regexp', `ebnf-case-fold-search',
                `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
 
                `ebnf-terminal-regexp', `ebnf-case-fold-search',
                `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
 
+   `abnf'      ebnf2ps recognizes the syntax described in the URL:
+               `http://www.ietf.org/rfc/rfc2234.txt'
+               (\"Augmented BNF for Syntax Specifications: ABNF\").
+
    `iso-ebnf'  ebnf2ps recognizes the syntax described in the URL:
                `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
                (\"International Standard of the ISO EBNF Notation\").
    `iso-ebnf'  ebnf2ps recognizes the syntax described in the URL:
                `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
                (\"International Standard of the ISO EBNF Notation\").
@@ -1565,9 +1813,19 @@ Valid values are:
                setting:
                `ebnf-yac-ignore-error-recovery'.
 
                setting:
                `ebnf-yac-ignore-error-recovery'.
 
+   `ebnfx'     ebnf2ps recognizes the syntax described in the URL:
+               `http://www.w3.org/TR/2004/REC-xml-20040204/#sec-notation'
+               (\"Extensible Markup Language (XML) 1.0 (Third Edition)\")
+
+   `dtd'       ebnf2ps recognizes the syntax described in the URL:
+               `http://www.w3.org/TR/2004/REC-xml-20040204/'
+               (\"Extensible Markup Language (XML) 1.0 (Third Edition)\")
+
 Any other value is treated as `ebnf'."
   :type '(radio :tag "Syntax"
 Any other value is treated as `ebnf'."
   :type '(radio :tag "Syntax"
-               (const ebnf) (const iso-ebnf) (const yacc))
+               (const ebnf) (const abnf)  (const iso-ebnf)
+               (const yacc) (const ebnfx) (const dtd))
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1576,6 +1834,7 @@ Any other value is treated as `ebnf'."
 
 It's used only when `ebnf-syntax' is `ebnf'."
   :type 'character
 
 It's used only when `ebnf-syntax' is `ebnf'."
   :type 'character
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1584,6 +1843,7 @@ It's used only when `ebnf-syntax' is `ebnf'."
 
 It's used only when `ebnf-syntax' is `ebnf'."
   :type 'character
 
 It's used only when `ebnf-syntax' is `ebnf'."
   :type 'character
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1597,6 +1857,7 @@ terminal name; terminal name may also be enclosed by `\"'.
 It's used only when `ebnf-syntax' is `ebnf'."
   :type '(radio :tag "Terminal Name"
                (const nil) regexp)
 It's used only when `ebnf-syntax' is `ebnf'."
   :type '(radio :tag "Terminal Name"
                (const nil) regexp)
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1606,6 +1867,7 @@ It's used only when `ebnf-syntax' is `ebnf'."
 It's only used when `ebnf-terminal-regexp' is non-nil and when `ebnf-syntax' is
 `ebnf'."
   :type 'boolean
 It's only used when `ebnf-terminal-regexp' is non-nil and when `ebnf-syntax' is
 `ebnf'."
   :type 'boolean
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1624,6 +1886,7 @@ This variable affects the following symbol set:
       }    ==>   :)
       ;    ==>   ."
   :type 'boolean
       }    ==>   :)
       ;    ==>   ."
   :type 'boolean
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1635,14 +1898,145 @@ single space, so \"A  B   C\" is normalized to  \"A B C\".
 
 It's only used when `ebnf-syntax' is `iso-ebnf'."
   :type 'boolean
 
 It's only used when `ebnf-syntax' is `iso-ebnf'."
   :type 'boolean
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
+(defcustom ebnf-file-suffix-regexp "\.[Bb][Nn][Ff]$"
+  "*Specify file name suffix that contains EBNF.
+
+See `ebnf-eps-directory' command."
+  :type 'regexp
+  :version "20"
+  :group 'ebnf2ps)
+
+
 (defcustom ebnf-eps-prefix "ebnf--"
   "*Specify EPS prefix file name.
 
 See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
   :type 'string
 (defcustom ebnf-eps-prefix "ebnf--"
   "*Specify EPS prefix file name.
 
 See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
   :type 'string
+  :version "20"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-eps-header-font '(11 Helvetica "Black" "White" bold)
+  "*Specify EPS header font.
+
+See documentation for `ebnf-production-font'.
+
+See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
+  :type '(list :tag "EPS Header Font"
+              (number :tag "Font Size")
+              (symbol :tag "Font Name")
+              (choice :tag "Foreground Color"
+                      (string :tag "Name")
+                      (other :tag "Default" nil))
+              (choice :tag "Background Color"
+                      (string :tag "Name")
+                      (other :tag "Default" nil))
+              (repeat :tag "Font Attributes" :inline t
+                      (choice (const bold)      (const italic)
+                              (const underline) (const strikeout)
+                              (const overline)  (const shadow)
+                              (const box)       (const outline))))
+  :version "22"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-eps-header nil
+  "*Specify EPS header.
+
+The value should be a string, a symbol or nil.
+
+String is inserted unchanged.
+
+For symbol bounded to a function, the function is called and should return a
+string.  For symbol bounded to a value, the value should be a string.
+
+If symbol is unbounded, it is silently ignored.
+
+Empty string or nil mean that no header will be generated.
+
+Note that when the header action comment (;H in EBNF syntax) is specified, the
+string in the header action comment is processed and, if it returns a non-empty
+string, it's used to generate the header.  The header action comment accepts
+the following formats:
+
+   %%  prints a % character.
+
+   %H  prints the `ebnf-eps-header' value.
+
+   %F  prints the `ebnf-eps-footer' (which see) value.
+
+Any other format is ignored, that is, if, for example, it's used %s then %s
+characters are stripped out from the header.  If header action comment is an
+empty string, no header is generated until a non-empty header is specified or
+`ebnf-eps-header' has a non-empty string value."
+  :type '(repeat (choice :menu-tag "EPS Header"
+                        :tag "EPS Header"
+                        string symbol (const :tag "No Header" nil )))
+  :version "22"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-eps-footer-font '(7 Helvetica "Black" "White" bold)
+  "*Specify EPS footer font.
+
+See documentation for `ebnf-production-font'.
+
+See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
+  :type '(list :tag "EPS Footer Font"
+              (number :tag "Font Size")
+              (symbol :tag "Font Name")
+              (choice :tag "Foreground Color"
+                      (string :tag "Name")
+                      (other :tag "Default" nil))
+              (choice :tag "Background Color"
+                      (string :tag "Name")
+                      (other :tag "Default" nil))
+              (repeat :tag "Font Attributes" :inline t
+                      (choice (const bold)      (const italic)
+                              (const underline) (const strikeout)
+                              (const overline)  (const shadow)
+                              (const box)       (const outline))))
+  :version "22"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-eps-footer nil
+  "*Specify EPS footer.
+
+The value should be a string, a symbol or nil.
+
+String is inserted unchanged.
+
+For symbol bounded to a function, the function is called and should return a
+string.  For symbol bounded to a value, the value should be a string.
+
+If symbol is unbounded, it is silently ignored.
+
+Empty string or nil mean that no footer will be generated.
+
+Note that when the footer action comment (;F in EBNF syntax) is specified, the
+string in the footer action comment is processed and, if it returns a non-empty
+string, it's used to generate the footer.  The footer action comment accepts
+the following formats:
+
+   %%  prints a % character.
+
+   %H  prints the `ebnf-eps-header' (which see) value.
+
+   %F  prints the `ebnf-eps-footer' value.
+
+Any other format is ignored, that is, if, for example, it's used %s then %s
+characters are stripped out from the footer.  If footer action comment is an
+empty string, no footer is generated until a non-empty footer is specified or
+`ebnf-eps-footer' has a non-empty string value."
+  :type '(repeat (choice :menu-tag "EPS Footer"
+                        :tag "EPS Footer"
+                        string symbol (const :tag "No Footer" nil )))
+  :version "22"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
@@ -1651,6 +2045,7 @@ See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
 
 It must be a float between 0.0 (top) and 1.0 (bottom)."
   :type 'number
 
 It must be a float between 0.0 (top) and 1.0 (bottom)."
   :type 'number
+  :version "20"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
@@ -1658,6 +2053,7 @@ It must be a float between 0.0 (top) and 1.0 (bottom)."
   "*Specify additional border width over default terminal, non-terminal or
 special."
   :type 'number
   "*Specify additional border width over default terminal, non-terminal or
 special."
   :type 'number
+  :version "20"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
@@ -1666,26 +2062,53 @@ special."
                            (fboundp 'color-instance-rgb-components)) ; XEmacs
   "*Non-nil means use color."
   :type 'boolean
                            (fboundp 'color-instance-rgb-components)) ; XEmacs
   "*Non-nil means use color."
   :type 'boolean
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-line-width 1.0
   "*Specify flow line width."
   :type 'number
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-line-width 1.0
   "*Specify flow line width."
   :type 'number
+  :version "20"
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-line-color "Black"
   "*Specify flow line color."
   :type 'string
   :group 'ebnf2ps)
 
 
 (defcustom ebnf-line-color "Black"
   "*Specify flow line color."
   :type 'string
+  :version "20"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
+(defcustom ebnf-arrow-extra-width
+  (if (eq ebnf-arrow-shape 'none)
+      0.0
+    (* (sqrt 5.0) 0.65 ebnf-line-width))
+  "*Specify extra width for arrow shape drawing.
+
+The extra width is used to avoid that the arrowhead and the terminal border
+overlap.  It depens on `ebnf-arrow-shape' and `ebnf-line-width'."
+  :type 'number
+  :version "22"
+  :group 'ebnf-shape)
+
+
+(defcustom ebnf-arrow-scale 1.0
+  "*Specify the arrow scale.
+
+Values lower than 1.0, shrink the arrow.
+Values greater than 1.0, expand the arrow."
+  :type 'number
+  :version "22"
+  :group 'ebnf-shape)
+
+
 (defcustom ebnf-debug-ps nil
   "*Non-nil means to generate PostScript debug procedures.
 
 It is intended to help PostScript programmers in debugging."
   :type 'boolean
 (defcustom ebnf-debug-ps nil
   "*Non-nil means to generate PostScript debug procedures.
 
 It is intended to help PostScript programmers in debugging."
   :type 'boolean
+  :version "20"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
@@ -1701,6 +2124,14 @@ If it occurs the error message:
 
 when executing ebnf2ps, set `ebnf-use-float-format' to nil."
   :type 'boolean
 
 when executing ebnf2ps, set `ebnf-use-float-format' to nil."
   :type 'boolean
+  :version "20"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-stop-on-error nil
+  "*Non-nil means signal error and stop.  Otherwise, signal error and continue."
+  :type 'boolean
+  :version "20"
   :group 'ebnf2ps)
 
 
   :group 'ebnf2ps)
 
 
@@ -1709,6 +2140,7 @@ when executing ebnf2ps, set `ebnf-use-float-format' to nil."
 
 It's only used when `ebnf-syntax' is `yacc'."
   :type 'boolean
 
 It's only used when `ebnf-syntax' is `yacc'."
   :type 'boolean
+  :version "20"
   :group 'ebnf-syntactic)
 
 
   :group 'ebnf-syntactic)
 
 
@@ -1718,6 +2150,7 @@ It's only used when `ebnf-syntax' is `yacc'."
 It's interesting to set this variable if your Yacc/Bison grammar has a lot of
 middle action rule."
   :type 'boolean
 It's interesting to set this variable if your Yacc/Bison grammar has a lot of
 middle action rule."
   :type 'boolean
+  :version "20"
   :group 'ebnf-optimization)
 
 
   :group 'ebnf-optimization)
 
 
@@ -1737,15 +2170,41 @@ The following optimizations are done:
    6.  A = B | .                ==>   A = [B].
    7.  A =   | B .              ==>   A = [B].
 
    6.  A = B | .                ==>   A = [B].
    7.  A =   | B .              ==>   A = [B].
 
-   factoration:
+   factorization:
    8.  A = B C | B D.           ==>   A = B (C | D).
    9.  A = C B | D B.           ==>   A = (C | D) B.
    10. A = B C E | B D E.       ==>   A = B (C | D) E.
 
 The above optimizations are specially useful when `ebnf-syntax' is `yacc'."
   :type 'boolean
    8.  A = B C | B D.           ==>   A = B (C | D).
    9.  A = C B | D B.           ==>   A = (C | D) B.
    10. A = B C E | B D E.       ==>   A = B (C | D) E.
 
 The above optimizations are specially useful when `ebnf-syntax' is `yacc'."
   :type 'boolean
+  :version "20"
   :group 'ebnf-optimization)
 
   :group 'ebnf-optimization)
 
+
+(defcustom ebnf-log nil
+  "*Non-nil means generate log messages.
+
+The log messages are generated into the buffer *Ebnf2ps Log*.
+These messages are intended to help debugging ebnf2ps."
+  :type 'boolean
+  :version "22"
+  :group 'ebnf2ps)
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; To make this file smaller, some commands go in a separate file.
+;; But autoload them here to make the separation invisible.
+;; Autoload is here to avoid compilation gripes.
+
+(autoload 'ebnf-eliminate-empty-rules "ebnf-otz"
+  "Eliminate empty rules.")
+
+(autoload 'ebnf-optimize              "ebnf-otz"
+  "Syntactic chart optimizer.")
+
+(autoload 'ebnf-otz-initialize        "ebnf-otz"
+  "Initialize optimizer.")
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Customization
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Customization
@@ -1762,6 +2221,36 @@ The above optimizations are specially useful when `ebnf-syntax' is `yacc'."
 ;; User commands
 
 
 ;; User commands
 
 
+;;;###autoload
+(defun ebnf-print-directory (&optional directory)
+  "Generate and print a PostScript syntactic chart image of DIRECTORY.
+
+If DIRECTORY is nil, it's used `default-directory'.
+
+The files in DIRECTORY that matches `ebnf-file-suffix-regexp' (which see) are
+processed.
+
+See also `ebnf-print-buffer'."
+  (interactive
+   (list (read-file-name "Directory containing EBNF files (print): "
+                        nil default-directory)))
+  (ebnf-log-header "(ebnf-print-directory %S)" directory)
+  (ebnf-directory 'ebnf-print-buffer directory))
+
+
+;;;###autoload
+(defun ebnf-print-file (file &optional do-not-kill-buffer-when-done)
+  "Generate and print a PostScript syntactic chart image of the file FILE.
+
+If optional arg DO-NOT-KILL-BUFFER-WHEN-DONE is non-nil, the buffer isn't
+killed after process termination.
+
+See also `ebnf-print-buffer'."
+  (interactive "fEBNF file to generate PostScript and print from: ")
+  (ebnf-log-header "(ebnf-print-file %S %S)" file do-not-kill-buffer-when-done)
+  (ebnf-file 'ebnf-print-buffer file do-not-kill-buffer-when-done))
+
+
 ;;;###autoload
 (defun ebnf-print-buffer (&optional filename)
   "Generate and print a PostScript syntactic chart image of the buffer.
 ;;;###autoload
 (defun ebnf-print-buffer (&optional filename)
   "Generate and print a PostScript syntactic chart image of the buffer.
@@ -1775,6 +2264,7 @@ is nil, send the image to the printer.  If FILENAME is a string, save
 the PostScript image in a file with that name.  If FILENAME is a
 number, prompt the user for the name of the file to save in."
   (interactive (list (ps-print-preprint current-prefix-arg)))
 the PostScript image in a file with that name.  If FILENAME is a
 number, prompt the user for the name of the file to save in."
   (interactive (list (ps-print-preprint current-prefix-arg)))
+  (ebnf-log-header "(ebnf-print-buffer %S)" filename)
   (ebnf-print-region (point-min) (point-max) filename))
 
 
   (ebnf-print-region (point-min) (point-max) filename))
 
 
@@ -1783,11 +2273,42 @@ number, prompt the user for the name of the file to save in."
   "Generate and print a PostScript syntactic chart image of the region.
 Like `ebnf-print-buffer', but prints just the current region."
   (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
   "Generate and print a PostScript syntactic chart image of the region.
 Like `ebnf-print-buffer', but prints just the current region."
   (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
+  (ebnf-log-header "(ebnf-print-region %S %S %S)" from to filename)
   (run-hooks 'ebnf-hook)
   (or (ebnf-spool-region from to)
       (ps-do-despool filename)))
 
 
   (run-hooks 'ebnf-hook)
   (or (ebnf-spool-region from to)
       (ps-do-despool filename)))
 
 
+;;;###autoload
+(defun ebnf-spool-directory (&optional directory)
+  "Generate and spool a PostScript syntactic chart image of DIRECTORY.
+
+If DIRECTORY is nil, it's used `default-directory'.
+
+The files in DIRECTORY that matches `ebnf-file-suffix-regexp' (which see) are
+processed.
+
+See also `ebnf-spool-buffer'."
+  (interactive
+   (list (read-file-name "Directory containing EBNF files (spool): "
+                        nil default-directory)))
+  (ebnf-log-header "(ebnf-spool-directory %S)" directory)
+  (ebnf-directory 'ebnf-spool-buffer directory))
+
+
+;;;###autoload
+(defun ebnf-spool-file (file &optional do-not-kill-buffer-when-done)
+  "Generate and spool a PostScript syntactic chart image of the file FILE.
+
+If optional arg DO-NOT-KILL-BUFFER-WHEN-DONE is non-nil, the buffer isn't
+killed after process termination.
+
+See also `ebnf-spool-buffer'."
+  (interactive "fEBNF file to generate PostScript and spool from: ")
+  (ebnf-log-header "(ebnf-spool-file %S %S)" file do-not-kill-buffer-when-done)
+  (ebnf-file 'ebnf-spool-buffer file do-not-kill-buffer-when-done))
+
+
 ;;;###autoload
 (defun ebnf-spool-buffer ()
   "Generate and spool a PostScript syntactic chart image of the buffer.
 ;;;###autoload
 (defun ebnf-spool-buffer ()
   "Generate and spool a PostScript syntactic chart image of the buffer.
@@ -1796,6 +2317,7 @@ local buffer to be sent to the printer later.
 
 Use the command `ebnf-despool' to send the spooled images to the printer."
   (interactive)
 
 Use the command `ebnf-despool' to send the spooled images to the printer."
   (interactive)
+  (ebnf-log-header "(ebnf-spool-buffer)")
   (ebnf-spool-region (point-min) (point-max)))
 
 
   (ebnf-spool-region (point-min) (point-max)))
 
 
@@ -1806,14 +2328,45 @@ Like `ebnf-spool-buffer', but spools just the current region.
 
 Use the command `ebnf-despool' to send the spooled images to the printer."
   (interactive "r")
 
 Use the command `ebnf-despool' to send the spooled images to the printer."
   (interactive "r")
+  (ebnf-log-header "(ebnf-spool-region %S)" from to)
   (ebnf-generate-region from to 'ebnf-generate))
 
 
   (ebnf-generate-region from to 'ebnf-generate))
 
 
+;;;###autoload
+(defun ebnf-eps-directory (&optional directory)
+  "Generate EPS files from EBNF files in DIRECTORY.
+
+If DIRECTORY is nil, it's used `default-directory'.
+
+The files in DIRECTORY that matches `ebnf-file-suffix-regexp' (which see) are
+processed.
+
+See also `ebnf-eps-buffer'."
+  (interactive
+   (list (read-file-name "Directory containing EBNF files (EPS): "
+                        nil default-directory)))
+  (ebnf-log-header "(ebnf-eps-directory %S)" directory)
+  (ebnf-directory 'ebnf-eps-buffer directory))
+
+
+;;;###autoload
+(defun ebnf-eps-file (file &optional do-not-kill-buffer-when-done)
+  "Generate an EPS file from EBNF file FILE.
+
+If optional arg DO-NOT-KILL-BUFFER-WHEN-DONE is non-nil, the buffer isn't
+killed after EPS generation.
+
+See also `ebnf-eps-buffer'."
+  (interactive "fEBNF file to generate EPS file from: ")
+  (ebnf-log-header "(ebnf-eps-file %S %S)" file do-not-kill-buffer-when-done)
+  (ebnf-file 'ebnf-eps-buffer file do-not-kill-buffer-when-done))
+
+
 ;;;###autoload
 (defun ebnf-eps-buffer ()
 ;;;###autoload
 (defun ebnf-eps-buffer ()
-  "Generate a PostScript syntactic chart image of the buffer in a EPS file.
+  "Generate a PostScript syntactic chart image of the buffer in an EPS file.
 
 
-Indeed, for each production is generated a EPS file.
+Generate an EPS file for each production in the buffer.
 The EPS file name has the following form:
 
    <PREFIX><PRODUCTION>.eps
 The EPS file name has the following form:
 
    <PREFIX><PRODUCTION>.eps
@@ -1822,20 +2375,23 @@ The EPS file name has the following form:
             The default value is \"ebnf--\".
 
 <PRODUCTION> is the production name.
             The default value is \"ebnf--\".
 
 <PRODUCTION> is the production name.
-            The production name is mapped to form a valid file name.
-            For example, the production name \"A/B + C\" is mapped to
-            \"A_B_+_C\" and the EPS file name used is \"ebnf--A_B_+_C.eps\".
+            Some characters in the production file name are replaced to
+            produce a valid file name.  For example, the production name
+            \"A/B + C\" is modified to produce \"A_B_+_C\", and the EPS
+            file name used in this case will be \"ebnf--A_B_+_C.eps\".
 
 
-WARNING: It's *NOT* asked any confirmation to override an existing file."
+WARNING: This function does *NOT* ask any confirmation to override existing
+        files."
   (interactive)
   (interactive)
+  (ebnf-log-header "(ebnf-eps-buffer)")
   (ebnf-eps-region (point-min) (point-max)))
 
 
 ;;;###autoload
 (defun ebnf-eps-region (from to)
   (ebnf-eps-region (point-min) (point-max)))
 
 
 ;;;###autoload
 (defun ebnf-eps-region (from to)
-  "Generate a PostScript syntactic chart image of the region in a EPS file.
+  "Generate a PostScript syntactic chart image of the region in an EPS file.
 
 
-Indeed, for each production is generated a EPS file.
+Generate an EPS file for each production in the region.
 The EPS file name has the following form:
 
    <PREFIX><PRODUCTION>.eps
 The EPS file name has the following form:
 
    <PREFIX><PRODUCTION>.eps
@@ -1844,12 +2400,15 @@ The EPS file name has the following form:
             The default value is \"ebnf--\".
 
 <PRODUCTION> is the production name.
             The default value is \"ebnf--\".
 
 <PRODUCTION> is the production name.
-            The production name is mapped to form a valid file name.
-            For example, the production name \"A/B + C\" is mapped to
-            \"A_B_+_C\" and the EPS file name used is \"ebnf--A_B_+_C.eps\".
+            Some characters in the production file name are replaced to
+            produce a valid file name.  For example, the production name
+            \"A/B + C\" is modified to produce \"A_B_+_C\", and the EPS
+            file name used in this case will be \"ebnf--A_B_+_C.eps\".
 
 
-WARNING: It's *NOT* asked any confirmation to override an existing file."
+WARNING: This function does *NOT* ask any confirmation to override existing
+        files."
   (interactive "r")
   (interactive "r")
+  (ebnf-log-header "(ebnf-eps-region %S %S)" from to)
   (let ((ebnf-eps-executing t))
     (ebnf-generate-region from to 'ebnf-generate-eps)))
 
   (let ((ebnf-eps-executing t))
     (ebnf-generate-region from to 'ebnf-generate-eps)))
 
@@ -1858,17 +2417,49 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
 (defalias 'ebnf-despool 'ps-despool)
 
 
 (defalias 'ebnf-despool 'ps-despool)
 
 
+;;;###autoload
+(defun ebnf-syntax-directory (&optional directory)
+  "Do a syntactic analysis of the files in DIRECTORY.
+
+If DIRECTORY is nil, use `default-directory'.
+
+Only the files in DIRECTORY that match `ebnf-file-suffix-regexp' (which see)
+are processed.
+
+See also `ebnf-syntax-buffer'."
+  (interactive
+   (list (read-file-name "Directory containing EBNF files (syntax): "
+                        nil default-directory)))
+  (ebnf-log-header "(ebnf-syntax-directory %S)" directory)
+  (ebnf-directory 'ebnf-syntax-buffer directory))
+
+
+;;;###autoload
+(defun ebnf-syntax-file (file &optional do-not-kill-buffer-when-done)
+  "Do a syntactic analysis of the named FILE.
+
+If optional arg DO-NOT-KILL-BUFFER-WHEN-DONE is non-nil, the buffer isn't
+killed after syntax checking.
+
+See also `ebnf-syntax-buffer'."
+  (interactive "fEBNF file to check syntax: ")
+  (ebnf-log-header "(ebnf-syntax-file %S %S)" file do-not-kill-buffer-when-done)
+  (ebnf-file 'ebnf-syntax-buffer file do-not-kill-buffer-when-done))
+
+
 ;;;###autoload
 (defun ebnf-syntax-buffer ()
 ;;;###autoload
 (defun ebnf-syntax-buffer ()
-  "Does a syntactic analysis of the current buffer."
+  "Do a syntactic analysis of the current buffer."
   (interactive)
   (interactive)
+  (ebnf-log-header "(ebnf-syntax-buffer)")
   (ebnf-syntax-region (point-min) (point-max)))
 
 
 ;;;###autoload
 (defun ebnf-syntax-region (from to)
   (ebnf-syntax-region (point-min) (point-max)))
 
 
 ;;;###autoload
 (defun ebnf-syntax-region (from to)
-  "Does a syntactic analysis of a region."
+  "Do a syntactic analysis of a region."
   (interactive "r")
   (interactive "r")
+  (ebnf-log-header "(ebnf-syntax-region %S %S)" from to)
   (ebnf-generate-region from to nil))
 
 \f
   (ebnf-generate-region from to nil))
 
 \f
@@ -1883,7 +2474,10 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
    "
 ;;; ebnf2ps.el version %s
 
    "
 ;;; ebnf2ps.el version %s
 
-\(setq ebnf-special-font                %s
+;;; Emacs version %S
+
+\(setq ebnf-special-show-delimiter      %S
+      ebnf-special-font                %s
       ebnf-special-shape               %s
       ebnf-special-shadow              %S
       ebnf-special-border-width        %S
       ebnf-special-shape               %s
       ebnf-special-shadow              %S
       ebnf-special-border-width        %S
@@ -1910,6 +2504,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
       ebnf-non-terminal-shadow         %S
       ebnf-non-terminal-border-width   %S
       ebnf-non-terminal-border-color   %S
       ebnf-non-terminal-shadow         %S
       ebnf-non-terminal-border-width   %S
       ebnf-non-terminal-border-color   %S
+      ebnf-production-name-p           %S
       ebnf-sort-production             %s
       ebnf-production-font             %s
       ebnf-arrow-shape                 %s
       ebnf-sort-production             %s
       ebnf-production-font             %s
       ebnf-arrow-shape                 %s
@@ -1925,20 +2520,31 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
       ebnf-syntax                      %s
       ebnf-iso-alternative-p           %S
       ebnf-iso-normalize-p             %S
       ebnf-syntax                      %s
       ebnf-iso-alternative-p           %S
       ebnf-iso-normalize-p             %S
+      ebnf-file-suffix-regexp          %S
       ebnf-eps-prefix                  %S
       ebnf-eps-prefix                  %S
+      ebnf-eps-header-font             %s
+      ebnf-eps-header                  %s
+      ebnf-eps-footer-font             %s
+      ebnf-eps-footer                  %s
       ebnf-entry-percentage            %S
       ebnf-color-p                     %S
       ebnf-line-width                  %S
       ebnf-line-color                  %S
       ebnf-entry-percentage            %S
       ebnf-color-p                     %S
       ebnf-line-width                  %S
       ebnf-line-color                  %S
+      ebnf-arrow-extra-width           %S
+      ebnf-arrow-scale                 %S
       ebnf-debug-ps                    %S
       ebnf-use-float-format            %S
       ebnf-debug-ps                    %S
       ebnf-use-float-format            %S
+      ebnf-stop-on-error               %S
       ebnf-yac-ignore-error-recovery   %S
       ebnf-ignore-empty-rule           %S
       ebnf-yac-ignore-error-recovery   %S
       ebnf-ignore-empty-rule           %S
-      ebnf-optimize                    %S)
+      ebnf-optimize                    %S
+      ebnf-log                         %S)
 
 ;;; ebnf2ps.el - end of settings
 "
    ebnf-version
 
 ;;; ebnf2ps.el - end of settings
 "
    ebnf-version
+   emacs-version
+   ebnf-special-show-delimiter
    (ps-print-quote ebnf-special-font)
    (ps-print-quote ebnf-special-shape)
    ebnf-special-shadow
    (ps-print-quote ebnf-special-font)
    (ps-print-quote ebnf-special-shape)
    ebnf-special-shadow
@@ -1966,6 +2572,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
    ebnf-non-terminal-shadow
    ebnf-non-terminal-border-width
    ebnf-non-terminal-border-color
    ebnf-non-terminal-shadow
    ebnf-non-terminal-border-width
    ebnf-non-terminal-border-color
+   ebnf-production-name-p
    (ps-print-quote ebnf-sort-production)
    (ps-print-quote ebnf-production-font)
    (ps-print-quote ebnf-arrow-shape)
    (ps-print-quote ebnf-sort-production)
    (ps-print-quote ebnf-production-font)
    (ps-print-quote ebnf-arrow-shape)
@@ -1981,16 +2588,25 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
    (ps-print-quote ebnf-syntax)
    ebnf-iso-alternative-p
    ebnf-iso-normalize-p
    (ps-print-quote ebnf-syntax)
    ebnf-iso-alternative-p
    ebnf-iso-normalize-p
+   ebnf-file-suffix-regexp
    ebnf-eps-prefix
    ebnf-eps-prefix
+   (ps-print-quote ebnf-eps-header-font)
+   (ps-print-quote ebnf-eps-header)
+   (ps-print-quote ebnf-eps-footer-font)
+   (ps-print-quote ebnf-eps-footer)
    ebnf-entry-percentage
    ebnf-color-p
    ebnf-line-width
    ebnf-line-color
    ebnf-entry-percentage
    ebnf-color-p
    ebnf-line-width
    ebnf-line-color
+   ebnf-arrow-extra-width
+   ebnf-arrow-scale
    ebnf-debug-ps
    ebnf-use-float-format
    ebnf-debug-ps
    ebnf-use-float-format
+   ebnf-stop-on-error
    ebnf-yac-ignore-error-recovery
    ebnf-ignore-empty-rule
    ebnf-yac-ignore-error-recovery
    ebnf-ignore-empty-rule
-   ebnf-optimize))
+   ebnf-optimize
+   ebnf-log))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -2007,7 +2623,8 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
 
 
 (defconst ebnf-style-custom-list
 
 
 (defconst ebnf-style-custom-list
-  '(ebnf-special-font
+  '(ebnf-special-show-delimiter
+    ebnf-special-font
     ebnf-special-shape
     ebnf-special-shadow
     ebnf-special-border-width
     ebnf-special-shape
     ebnf-special-shadow
     ebnf-special-border-width
@@ -2034,6 +2651,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
     ebnf-non-terminal-shadow
     ebnf-non-terminal-border-width
     ebnf-non-terminal-border-color
     ebnf-non-terminal-shadow
     ebnf-non-terminal-border-width
     ebnf-non-terminal-border-color
+    ebnf-production-name-p
     ebnf-sort-production
     ebnf-production-font
     ebnf-arrow-shape
     ebnf-sort-production
     ebnf-production-font
     ebnf-arrow-shape
@@ -2049,13 +2667,19 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
     ebnf-syntax
     ebnf-iso-alternative-p
     ebnf-iso-normalize-p
     ebnf-syntax
     ebnf-iso-alternative-p
     ebnf-iso-normalize-p
+    ebnf-file-suffix-regexp
     ebnf-eps-prefix
     ebnf-eps-prefix
+    ebnf-eps-header-font
+    ebnf-eps-header
+    ebnf-eps-footer-font
+    ebnf-eps-footer
     ebnf-entry-percentage
     ebnf-color-p
     ebnf-line-width
     ebnf-line-color
     ebnf-debug-ps
     ebnf-use-float-format
     ebnf-entry-percentage
     ebnf-color-p
     ebnf-line-width
     ebnf-line-color
     ebnf-debug-ps
     ebnf-use-float-format
+    ebnf-stop-on-error
     ebnf-yac-ignore-error-recovery
     ebnf-ignore-empty-rule
     ebnf-optimize)
     ebnf-yac-ignore-error-recovery
     ebnf-ignore-empty-rule
     ebnf-optimize)
@@ -2066,6 +2690,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
   '(;; EBNF default
     (default
       nil
   '(;; EBNF default
     (default
       nil
+      (ebnf-special-show-delimiter      . t)
       (ebnf-special-font          . '(7 Courier "Black" "Gray95" bold italic))
       (ebnf-special-shape               . 'bevel)
       (ebnf-special-shadow              . nil)
       (ebnf-special-font          . '(7 Courier "Black" "Gray95" bold italic))
       (ebnf-special-shape               . 'bevel)
       (ebnf-special-shadow              . nil)
@@ -2093,6 +2718,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
       (ebnf-non-terminal-shadow         . nil)
       (ebnf-non-terminal-border-width   . 1.0)
       (ebnf-non-terminal-border-color   . "Black")
       (ebnf-non-terminal-shadow         . nil)
       (ebnf-non-terminal-border-width   . 1.0)
       (ebnf-non-terminal-border-color   . "Black")
+      (ebnf-production-name-p           . t)
       (ebnf-sort-production             . nil)
       (ebnf-production-font             . '(10 Helvetica "Black" "White" bold))
       (ebnf-arrow-shape                 . 'hollow)
       (ebnf-sort-production             . nil)
       (ebnf-production-font             . '(10 Helvetica "Black" "White" bold))
       (ebnf-arrow-shape                 . 'hollow)
@@ -2108,7 +2734,12 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
       (ebnf-syntax                      . 'ebnf)
       (ebnf-iso-alternative-p           . nil)
       (ebnf-iso-normalize-p             . nil)
       (ebnf-syntax                      . 'ebnf)
       (ebnf-iso-alternative-p           . nil)
       (ebnf-iso-normalize-p             . nil)
+      (ebnf-file-suffix-regexp          . "\.[Bb][Nn][Ff]$")
       (ebnf-eps-prefix                  . "ebnf--")
       (ebnf-eps-prefix                  . "ebnf--")
+      (ebnf-eps-header-font             . '(11 Helvetica "Black" "White" bold))
+      (ebnf-eps-header                  . nil)
+      (ebnf-eps-footer-font             . '(7 Helvetica "Black" "White" bold))
+      (ebnf-eps-footer                  . nil)
       (ebnf-entry-percentage            . 0.5)
       (ebnf-color-p   . (or (fboundp 'x-color-values) ; Emacs
                            (fboundp 'color-instance-rgb-components))) ; XEmacs
       (ebnf-entry-percentage            . 0.5)
       (ebnf-color-p   . (or (fboundp 'x-color-values) ; Emacs
                            (fboundp 'color-instance-rgb-components))) ; XEmacs
@@ -2116,6 +2747,7 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
       (ebnf-line-color                  . "Black")
       (ebnf-debug-ps                    . nil)
       (ebnf-use-float-format            . t)
       (ebnf-line-color                  . "Black")
       (ebnf-debug-ps                    . nil)
       (ebnf-use-float-format            . t)
+      (ebnf-stop-on-error               . nil)
       (ebnf-yac-ignore-error-recovery   . nil)
       (ebnf-ignore-empty-rule           . nil)
       (ebnf-optimize                    . nil))
       (ebnf-yac-ignore-error-recovery   . nil)
       (ebnf-ignore-empty-rule           . nil)
       (ebnf-optimize                    . nil))
@@ -2125,6 +2757,10 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
      (ebnf-justify-sequence            . 'left)
      (ebnf-lex-comment-char            . ?\#)
      (ebnf-lex-eop-char                . ?\;))
      (ebnf-justify-sequence            . 'left)
      (ebnf-lex-comment-char            . ?\#)
      (ebnf-lex-eop-char                . ?\;))
+    ;; ABNF default
+    (abnf
+     default
+     (ebnf-syntax                      . 'abnf))
     ;; ISO EBNF default
     (iso-ebnf
      default
     ;; ISO EBNF default
     (iso-ebnf
      default
@@ -2133,49 +2769,98 @@ WARNING: It's *NOT* asked any confirmation to override an existing file."
     (yacc
      default
      (ebnf-syntax                      . 'yacc))
     (yacc
      default
      (ebnf-syntax                      . 'yacc))
+    ;; ebnfx default
+    (ebnfx
+     default
+     (ebnf-syntax                      . 'ebnfx))
+    ;; dtd default
+    (dtd
+     default
+     (ebnf-syntax                      . 'dtd))
     )
   "Style database.
 
 Each element has the following form:
 
     )
   "Style database.
 
 Each element has the following form:
 
-   (CUSTOM INHERITS (VAR . VALUE)...)
+   (NAME INHERITS (VAR . VALUE)...)
+
+Where:
+
+NAME           is a symbol name style.
+
+INHERITS       is a symbol name style from which the current style inherits
+               the context.  If INHERITS is nil, then there is no inheritance.
 
 
-CUSTOM is a symbol name style.
-INHERITS is a symbol name style from which the current style inherits the
-context.  If INHERITS is nil, means that there is no inheritance.
-VAR is a valid ebnf2ps symbol custom variable.  See `ebnf-style-custom-list'
-for valid symbol variable.
-VALUE is a sexp which it'll be evaluated to set the value to VAR.  So, don't
-forget to quote symbols and constant lists.  See `default' style for an
-example.
+               This is a simple inheritance of style: if you declare that
+               style A inherits from style B, all settings of B are applied
+               first, and then the settings of A are applied.  This is useful
+               when you wish to modify some aspects of an existing style, but
+               at the same time wish to keep it unmodified.
 
 
-Don't handle this variable directly.  Use functions `ebnf-insert-style' and
-`ebnf-merge-style'.")
+VAR            is a valid ebnf2ps symbol custom variable.
+               See `ebnf-style-custom-list' for valid symbol variables.
+
+VALUE          is a sexp which will be evaluated to set the value of VAR.
+               Don't forget to quote symbols and constant lists.
+               See `default' style for an example.
+
+Don't use this variable directly.  Use functions `ebnf-insert-style',
+`ebnf-delete-style' and `ebnf-merge-style'.")
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Style commands
 
 
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Style commands
 
 
+;;;###autoload
+(defun ebnf-find-style (name)
+  "Return style definition if NAME is already defined; otherwise, return nil.
+
+See `ebnf-style-database' documentation."
+  (interactive "SStyle name: ")
+  (assoc name ebnf-style-database))
+
+
 ;;;###autoload
 (defun ebnf-insert-style (name inherits &rest values)
 ;;;###autoload
 (defun ebnf-insert-style (name inherits &rest values)
-  "Insert a new style NAME with inheritance INHERITS and values VALUES."
-  (interactive)
+  "Insert a new style NAME with inheritance INHERITS and values VALUES.
+
+See `ebnf-style-database' documentation."
+  (interactive "SStyle name: \nSStyle inherits from: \nXStyle values: ")
   (and (assoc name ebnf-style-database)
        (error "Style name already exists: %s" name))
   (or (assoc inherits ebnf-style-database)
   (and (assoc name ebnf-style-database)
        (error "Style name already exists: %s" name))
   (or (assoc inherits ebnf-style-database)
-      (error "Style inheritance name does'nt exist: %s" inherits))
+      (error "Style inheritance name doesn't exist: %s" inherits))
   (setq ebnf-style-database
        (cons (cons name (cons inherits (ebnf-check-style-values values)))
              ebnf-style-database)))
 
 
   (setq ebnf-style-database
        (cons (cons name (cons inherits (ebnf-check-style-values values)))
              ebnf-style-database)))
 
 
+;;;###autoload
+(defun ebnf-delete-style (name)
+  "Delete style NAME.
+
+See `ebnf-style-database' documentation."
+  (interactive "SDelete style name: ")
+  (or (assoc name ebnf-style-database)
+      (error "Style name doesn't exist: %s" name))
+  (let ((db ebnf-style-database))
+    (while db
+      (and (eq (nth 1 (car db)) name)
+          (error "Style name `%s' is inherited by `%s' style"
+                 name (nth 0 (car db))))
+      (setq db (cdr db))))
+  (setq ebnf-style-database (assq-delete-all name ebnf-style-database)))
+
+
 ;;;###autoload
 (defun ebnf-merge-style (name &rest values)
 ;;;###autoload
 (defun ebnf-merge-style (name &rest values)
-  "Merge values of style NAME with style VALUES."
-  (interactive)
+  "Merge values of style NAME with style VALUES.
+
+See `ebnf-style-database' documentation."
+  (interactive "SStyle name: \nXStyle values: ")
   (let ((style (or (assoc name ebnf-style-database)
   (let ((style (or (assoc name ebnf-style-database)
-                  (error "Style name does'nt exist: %s" name)))
+                  (error "Style name doesn't exist: %s" name)))
        (merge (ebnf-check-style-values values))
        val elt new check)
     ;; modify value of existing variables
        (merge (ebnf-check-style-values values))
        val elt new check)
     ;; modify value of existing variables
@@ -2193,10 +2878,12 @@ Don't handle this variable directly.  Use functions `ebnf-insert-style' and
 
 ;;;###autoload
 (defun ebnf-apply-style (style)
 
 ;;;###autoload
 (defun ebnf-apply-style (style)
-  "Set STYLE to current style.
+  "Set STYLE as the current style.
 
 
-It returns the old style symbol."
-  (interactive)
+Returns the old style symbol.
+
+See `ebnf-style-database' documentation."
+  (interactive "SApply style: ")
   (prog1
       ebnf-current-style
     (and (ebnf-apply-style1 style)
   (prog1
       ebnf-current-style
     (and (ebnf-apply-style1 style)
@@ -2207,18 +2894,24 @@ It returns the old style symbol."
 (defun ebnf-reset-style (&optional style)
   "Reset current style.
 
 (defun ebnf-reset-style (&optional style)
   "Reset current style.
 
-It returns the old style symbol."
-  (interactive)
+Returns the old style symbol.
+
+See `ebnf-style-database' documentation."
+  (interactive "SReset style: ")
   (setq ebnf-stack-style nil)
   (ebnf-apply-style (or style 'default)))
 
 
 ;;;###autoload
 (defun ebnf-push-style (&optional style)
   (setq ebnf-stack-style nil)
   (ebnf-apply-style (or style 'default)))
 
 
 ;;;###autoload
 (defun ebnf-push-style (&optional style)
-  "Push the current style and set STYLE to current style.
+  "Push the current style onto a stack and set STYLE as the current style.
 
 
-It returns the old style symbol."
-  (interactive)
+Returns the old style symbol.
+
+See also `ebnf-pop-style'.
+
+See `ebnf-style-database' documentation."
+  (interactive "SPush style: ")
   (prog1
       ebnf-current-style
     (setq ebnf-stack-style (cons ebnf-current-style ebnf-stack-style))
   (prog1
       ebnf-current-style
     (setq ebnf-stack-style (cons ebnf-current-style ebnf-stack-style))
@@ -2228,9 +2921,13 @@ It returns the old style symbol."
 
 ;;;###autoload
 (defun ebnf-pop-style ()
 
 ;;;###autoload
 (defun ebnf-pop-style ()
-  "Pop a style and set it to current style.
+  "Pop a style from the stack of pushed styles and set it as the current style.
+
+Returns the old style symbol.
+
+See also `ebnf-push-style'.
 
 
-It returns the old style symbol."
+See `ebnf-style-database' documentation."
   (interactive)
   (prog1
       (ebnf-apply-style (car ebnf-stack-style))
   (interactive)
   (prog1
       (ebnf-apply-style (car ebnf-stack-style))
@@ -2249,7 +2946,7 @@ It returns the old style symbol."
 (defun ebnf-check-style-values (values)
   (let (style)
     (while values
 (defun ebnf-check-style-values (values)
   (let (style)
     (while values
-      (and (memq (car values) ebnf-style-custom-list)
+      (and (memq (caar values) ebnf-style-custom-list)
           (setq style (cons (car values) style)))
       (setq values (cdr values)))
     (nreverse style)))
           (setq style (cons (car values) style)))
       (setq values (cdr values)))
     (nreverse style)))
@@ -2259,18 +2956,20 @@ It returns the old style symbol."
 ;; Internal variables
 
 
 ;; Internal variables
 
 
-(defvar ebnf-eps-buffer-name " *EPS*")
-(defvar ebnf-parser-func     nil)
-(defvar ebnf-eps-executing   nil)
-(defvar ebnf-eps-upper-x     0.0)
+(defvar ebnf-eps-buffer-name    " *EPS*")
+(defvar ebnf-parser-func        nil)
+(defvar ebnf-eps-executing      nil)
+(defvar ebnf-eps-header-comment nil)
+(defvar ebnf-eps-footer-comment nil)
+(defvar ebnf-eps-upper-x        0.0)
 (make-variable-buffer-local 'ebnf-eps-upper-x)
 (make-variable-buffer-local 'ebnf-eps-upper-x)
-(defvar ebnf-eps-upper-y     0.0)
+(defvar ebnf-eps-upper-y        0.0)
 (make-variable-buffer-local 'ebnf-eps-upper-y)
 (make-variable-buffer-local 'ebnf-eps-upper-y)
-(defvar ebnf-eps-prod-width  0.0)
+(defvar ebnf-eps-prod-width     0.0)
 (make-variable-buffer-local 'ebnf-eps-prod-width)
 (make-variable-buffer-local 'ebnf-eps-prod-width)
-(defvar ebnf-eps-max-height 0.0)
+(defvar ebnf-eps-max-height     0.0)
 (make-variable-buffer-local 'ebnf-eps-max-height)
 (make-variable-buffer-local 'ebnf-eps-max-height)
-(defvar ebnf-eps-max-width  0.0)
+(defvar ebnf-eps-max-width      0.0)
 (make-variable-buffer-local 'ebnf-eps-max-width)
 
 
 (make-variable-buffer-local 'ebnf-eps-max-width)
 
 
@@ -2280,6 +2979,23 @@ It returns the old style symbol."
 See section \"Actions in Comments\" in ebnf2ps documentation.")
 
 
 See section \"Actions in Comments\" in ebnf2ps documentation.")
 
 
+(defvar ebnf-eps-file-alist nil
+"Alist associating file name with EPS header and footer.
+
+Each element has the following form:
+
+   (EPS-FILENAME HEADER FOOTER)
+
+EPS-FILENAME is the EPS file name.
+HEADER is the header string or nil.
+FOOTER is the footer string or nil.
+
+It's generated during parsing and used during EPS generation.
+
+See `ebnf-eps-context' and section \"Actions in Comments\" in ebnf2ps
+documentation.")
+
+
 (defvar ebnf-eps-production-list nil
   "Alist associating production name with EPS file name list.
 
 (defvar ebnf-eps-production-list nil
   "Alist associating production name with EPS file name list.
 
@@ -2290,21 +3006,25 @@ Each element has the following form:
 PRODUCTION is the production name.
 EPS-FILENAME is the EPS file name.
 
 PRODUCTION is the production name.
 EPS-FILENAME is the EPS file name.
 
-It's generated during parsing and used during EPS generation.
+This is generated during parsing and used during EPS generation.
 
 See `ebnf-eps-context' and section \"Actions in Comments\" in ebnf2ps
 documentation.")
 
 
 (defconst ebnf-arrow-shape-alist
 
 See `ebnf-eps-context' and section \"Actions in Comments\" in ebnf2ps
 documentation.")
 
 
 (defconst ebnf-arrow-shape-alist
-  '((none        . 0)
-    (semi-up     . 1)
-    (semi-down   . 2)
-    (simple      . 3)
-    (transparent . 4)
-    (hollow      . 5)
-    (full        . 6)
-    (user        . 7))
+  '((none             . 0)
+    (semi-up          . 1)
+    (semi-down        . 2)
+    (simple           . 3)
+    (transparent      . 4)
+    (hollow           . 5)
+    (full             . 6)
+    (semi-up-hollow   . 7)
+    (semi-up-full     . 8)
+    (semi-down-hollow . 9)
+    (semi-down-full   . 10)
+    (user             . 11))
   "Alist associating values for `ebnf-arrow-shape'.
 
 See documentation for `ebnf-arrow-shape'.")
   "Alist associating values for `ebnf-arrow-shape'.
 
 See documentation for `ebnf-arrow-shape'.")
@@ -2320,41 +3040,43 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 `ebnf-chart-shape'.")
 
 
 `ebnf-chart-shape'.")
 
 
-(defvar ebnf-limit            nil)
-(defvar ebnf-action           nil)
-(defvar ebnf-action-list      nil)
+(defvar ebnf-limit          nil)
+(defvar ebnf-action         nil)
+(defvar ebnf-action-list    nil)
 
 
 
 
-(defvar ebnf-default-p        nil)
+(defvar ebnf-default-p      nil)
 
 
 
 
-(defvar ebnf-font-height-P    0)
-(defvar ebnf-font-height-T    0)
-(defvar ebnf-font-height-NT   0)
-(defvar ebnf-font-height-S    0)
-(defvar ebnf-font-height-E    0)
-(defvar ebnf-font-height-R    0)
-(defvar ebnf-font-width-P     0)
-(defvar ebnf-font-width-T     0)
-(defvar ebnf-font-width-NT    0)
-(defvar ebnf-font-width-S     0)
-(defvar ebnf-font-width-E     0)
-(defvar ebnf-font-width-R     0)
-(defvar ebnf-space-T          0)
-(defvar ebnf-space-NT         0)
-(defvar ebnf-space-S          0)
-(defvar ebnf-space-E          0)
-(defvar ebnf-space-R          0)
+(defvar ebnf-font-height-P  0)
+(defvar ebnf-font-height-T  0)
+(defvar ebnf-font-height-NT 0)
+(defvar ebnf-font-height-S  0)
+(defvar ebnf-font-height-E  0)
+(defvar ebnf-font-height-R  0)
+(defvar ebnf-font-width-P   0)
+(defvar ebnf-font-width-T   0)
+(defvar ebnf-font-width-NT  0)
+(defvar ebnf-font-width-S   0)
+(defvar ebnf-font-width-E   0)
+(defvar ebnf-font-width-R   0)
+(defvar ebnf-space-T        0)
+(defvar ebnf-space-NT       0)
+(defvar ebnf-space-S        0)
+(defvar ebnf-space-E        0)
+(defvar ebnf-space-R        0)
 
 
 
 
-(defvar ebnf-basic-width      0)
-(defvar ebnf-basic-height     0)
-(defvar ebnf-vertical-space   0)
-(defvar ebnf-horizontal-space 0)
+(defvar ebnf-basic-width-extra  0)
+(defvar ebnf-basic-width        0)
+(defvar ebnf-basic-height       0)
+(defvar ebnf-basic-empty-height 0)
+(defvar ebnf-vertical-space     0)
+(defvar ebnf-horizontal-space   0)
 
 
 
 
-(defvar ebnf-settings         nil)
-(defvar ebnf-fonts-required   nil)
+(defvar ebnf-settings       nil)
+(defvar ebnf-fonts-required nil)
 
 
 (defconst ebnf-debug
 
 
 (defconst ebnf-debug
@@ -2417,9 +3139,9 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 /HeightNT FontHeight FontHeight add def
 
 /T HeightT HeightNT add 0.5 mul def
 /HeightNT FontHeight FontHeight add def
 
 /T HeightT HeightNT add 0.5 mul def
-/hT T 0.5 mul def
-/hT2 hT 0.5 mul def
-/hT4 hT 0.25 mul def
+/hT   T 0.5  mul def
+/hT2 hT 0.5  mul ArrowScale mul def
+/hT4 hT 0.25 mul ArrowScale mul def
 
 /Er 0.1 def    % Error factor
 
 
 /Er 0.1 def    % Error factor
 
@@ -2464,19 +3186,39 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 
 /ArrowPath{c newpath moveto Arrow closepath}bind def
 
 
 /ArrowPath{c newpath moveto Arrow closepath}bind def
 
+/UpPath
+{c newpath moveto
+ hT2 neg 0   rmoveto
+ 0       hT4 rlineto
+ hT2 hT4 neg rlineto
+ closepath
+}bind def
+
+/DownPath
+{c newpath moveto
+ hT2 neg 0   rmoveto
+ 0   hT4 neg rlineto
+ hT2     hT4 rlineto
+ closepath
+}bind def
+
 %>Right Arrow: RA
 %    \\
 % *---+
 %    /
 /RA-vector
 %>Right Arrow: RA
 %    \\
 % *---+
 %    /
 /RA-vector
-[{}                                    % 0 - none
- {hT2 neg hT4 rlineto}                 % 1 - semi-up
- {Down}                                        % 2 - semi-down
- {Arrow}                               % 3 - simple
- {Gstroke ArrowPath}                   % 4 - transparent
- {Gstroke ArrowPath 1 FillGray}                % 5 - hollow
- {Gstroke ArrowPath LineColor FillRGB} % 6 - full
- {Gstroke gsave UserArrow grestore}    % 7 - user
+[{}                                    % 0  - none
+ {hT2 neg hT4 rlineto}                 % 1  - semi-up
+ {Down}                                        % 2  - semi-down
+ {Arrow}                               % 3  - simple
+ {Gstroke ArrowPath}                   % 4  - transparent
+ {Gstroke ArrowPath 1 FillGray}                % 5  - hollow
+ {Gstroke ArrowPath LineColor FillRGB} % 6  - full
+ {Gstroke UpPath 1 FillGray}           % 7  - semi-up-hollow
+ {Gstroke UpPath LineColor FillRGB}    % 8  - semi-up-full
+ {Gstroke DownPath 1 FillGray}         % 9  - semi-down-hollow
+ {Gstroke DownPath LineColor FillRGB}  % 10 - semi-down-full
+ {Gstroke gsave UserArrow grestore}    % 11 - user
 ]def
 
 /RA
 ]def
 
 /RA
@@ -2485,6 +3227,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
  RA-vector ArrowShape get exec
  Gstroke
  moveto
  RA-vector ArrowShape get exec
  Gstroke
  moveto
+ ExtraWidth 0 rmoveto
 }def
 
 % rotation DrawArrow
 }def
 
 % rotation DrawArrow
@@ -2678,8 +3421,8 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 
 % --- Flow Stuff
 
 
 % --- Flow Stuff
 
-% height prepare_height |- line_height corner_height corner_height
-/prepare_height
+% height prepare-height |- line_height corner_height corner_height
+/prepare-height
 {dup 0 gt
  {T sub hT}
  {T add hT neg}ifelse
 {dup 0 gt
  {T sub hT}
  {T add hT neg}ifelse
@@ -2705,7 +3448,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
   {0.5 mul dup
    1 corner_RA
    0 corner_RD}
   {0.5 mul dup
    1 corner_RA
    0 corner_RD}
-  {prepare_height
+  {prepare-height
    1 corner_RA
    exch 0 exch rlineto
    0 corner_RD
    1 corner_RA
    exch 0 exch rlineto
    0 corner_RD
@@ -2726,7 +3469,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 %  \\
 %   -
 /LLoop
 %  \\
 %   -
 /LLoop
-{prepare_height
+{prepare-height
  3 corner_LA
  exch 0 exch rlineto
  0 corner_RD
  3 corner_LA
  exch 0 exch rlineto
  0 corner_RD
@@ -2751,7 +3494,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
   {0.5 mul dup
    1 corner_LA
    0 corner_LD}
   {0.5 mul dup
    1 corner_LA
    0 corner_LD}
-  {prepare_height
+  {prepare-height
    1 corner_LA
    exch 0 exch rlineto
    0 corner_LD
    1 corner_LA
    exch 0 exch rlineto
    0 corner_LD
@@ -2772,7 +3515,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 %   /
 %  -
 /RLoop
 %   /
 %  -
 /RLoop
-{prepare_height
+{prepare-height
  1 corner_RA
  exch 0 exch rlineto
  0 corner_LD
  1 corner_RA
  exch 0 exch rlineto
  0 corner_LD
@@ -2783,7 +3526,7 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 % string width prepare-width |- string
 /prepare-width
 {/width exch def
 % string width prepare-width |- string
 /prepare-width
 {/width exch def
- dup stringwidth pop space add space add width exch sub 0.5 mul
+ dup stringwidth pop space add space add width exch sub ExtraWidth sub 0.5 mul
  /w exch def
 }def
 
  /w exch def
 }def
 
@@ -3168,10 +3911,11 @@ See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
 {xyp
  neg yp add /yw exch def
  xp add T sub /xw exch def
 {xyp
  neg yp add /yw exch def
  xp add T sub /xw exch def
- /Effect EffectP def
- /fP F ForegroundP SetRGB BackgroundP aload pop true BG S
- /Effect 0 def
- ( :) S false BG
+ dup length 0 gt       % empty string ==> no production name
+ {/Effect EffectP def
+  /fP F ForegroundP SetRGB BackgroundP aload pop true BG S
+  /Effect 0 def
+  ( :) S false BG}if
  xw yw moveto
  hT EL RA
  xp yw moveto
  xw yw moveto
  hT EL RA
  xp yw moveto
@@ -3560,6 +4304,113 @@ end
 "
   "EBNF EPS end")
 
 "
   "EBNF EPS end")
 
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Header & Footer
+
+
+(defun ebnf-eps-header-footer (value)
+  ;; evaluate header/footer value
+  ;; return a string or nil
+  (let ((tmp (if (symbolp value)
+                (cond ((fboundp value) (funcall value))
+                      ((boundp value)  (symbol-value value))
+                      (t               nil))
+              value)))
+    (and (stringp tmp) tmp)))
+
+
+(defun ebnf-eps-header ()
+  ;; evaluate header value
+  (ebnf-eps-header-footer ebnf-eps-header))
+
+
+(defun ebnf-eps-footer ()
+  ;; evaluate footer value
+  (ebnf-eps-header-footer ebnf-eps-footer))
+
+
+;; hacked fom `ps-output-string-prim' (ps-print.el)
+(defun ebnf-eps-string (string)
+  (let* ((str   (string-as-unibyte string))
+        (len   (length str))
+        (index 0)
+        (new   "(")                    ; insert start-string delimiter
+        start special)
+    ;; Find and quote special characters as necessary for PS
+    ;; This skips everything except control chars, non-ASCII chars, (, ) and \.
+    (while (setq start (string-match "[^]-~ -'*-[]" str index))
+      (setq special (aref str start)
+           new     (concat new
+                           (substring str index start)
+                           (if (and (<= 0 special) (<= special 255))
+                               (aref ps-string-escape-codes special)
+                             ;; insert hexadecimal representation if character
+                             ;; code is out of range
+                             (format "\\%04X" special)))
+           index   (1+ start)))
+    (concat new
+           (and (< index len)
+                (substring str index len))
+           ")")))                      ; insert end-string delimiter
+
+
+(defun ebnf-eps-header-footer-comment (str)
+  ;; parse header/footer comment string
+  (let ((len   (1- (length str)))
+       (index 0)
+       new start fmt)
+    (while (setq start (string-match "%" str index))
+      (setq fmt   (if (< start len) (aref str (1+ start)) ?\?)
+           new   (concat new
+                         (substring str index start)
+                         (cond ((= fmt ?%) "%")
+                               ((= fmt ?H) (ebnf-eps-header))
+                               ((= fmt ?F) (ebnf-eps-footer))
+                               (t nil)
+                               ))
+           index (+ start 2)))
+    (ebnf-eps-string (concat new
+                            (and (<= index len)
+                                 (substring str index (1+ len)))))))
+
+
+(defun ebnf-eps-header-footer-p (value)
+  ;; return t if value is non-nil and is not an empty string
+  (not (or (null value)
+          (and (stringp value) (string= value "")))))
+
+
+(defun ebnf-eps-header-comment (str)
+  ;; set header comment if header is on
+  (when (ebnf-eps-header-footer-p ebnf-eps-header)
+    (setq ebnf-eps-header-comment (ebnf-eps-header-footer-comment str))))
+
+
+(defun ebnf-eps-footer-comment (str)
+  ;; set footer comment if footer is on
+  (when (ebnf-eps-header-footer-p ebnf-eps-footer)
+    (setq ebnf-eps-footer-comment (ebnf-eps-header-footer-comment str))))
+
+
+(defun ebnf-eps-header-footer-file (filename)
+  ;; associate header and footer with a filename
+  (let ((filehf (assoc filename ebnf-eps-file-alist))
+       (header (or ebnf-eps-header-comment (ebnf-eps-header)))
+       (footer (or ebnf-eps-footer-comment (ebnf-eps-footer))))
+    (if (null filehf)
+       (setq ebnf-eps-file-alist (cons (list filename header footer)
+                                       ebnf-eps-file-alist))
+      (setcar (nthcdr 1 filehf) header)
+      (setcar (nthcdr 2 filehf) footer))))
+
+
+(defun ebnf-eps-header-footer-set (filename)
+  ;; set header and footer from a filename
+  (let ((header-footer (assoc filename ebnf-eps-file-alist)))
+    (setq ebnf-eps-header-comment (nth 1 header-footer)
+         ebnf-eps-footer-comment (nth 2 header-footer))))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Formatting
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Formatting
@@ -3594,6 +4445,10 @@ end
           (format ebnf-message-float value)))
 
 
           (format ebnf-message-float value)))
 
 
+(defvar ebnf-total 0)
+(defvar ebnf-nprod 0)
+
+
 (defsubst ebnf-message-info (messag)
   (message "%s...%3d%%"
           messag
 (defsubst ebnf-message-info (messag)
   (message "%s...%3d%%"
           messag
@@ -3794,7 +4649,7 @@ end
              ebnf-eps-max-height prod-height))
        )
       (setq ebnf-eps-prod-width prod-width)
              ebnf-eps-max-height prod-height))
        )
       (setq ebnf-eps-prod-width prod-width)
-      (insert-buffer eps-buffer))
+      (insert-buffer-substring eps-buffer))
     (setq prod-list (cdr prod-list))))
 
 
     (setq prod-list (cdr prod-list))))
 
 
@@ -3814,8 +4669,6 @@ end
 
 (defvar ebnf-tree      nil)
 (defvar ebnf-direction "R")
 
 (defvar ebnf-tree      nil)
 (defvar ebnf-direction "R")
-(defvar ebnf-total     0)
-(defvar ebnf-nprod     0)
 
 
 (defun ebnf-generate-postscript (from to)
 
 
 (defun ebnf-generate-postscript (from to)
@@ -3907,11 +4760,15 @@ end
 (defun ebnf-generate-production (production)
   (ebnf-message-info "Generating")
   (run-hooks 'ebnf-production-hook)
 (defun ebnf-generate-production (production)
   (ebnf-message-info "Generating")
   (run-hooks 'ebnf-production-hook)
-  (ps-output-string (ebnf-node-name production))
+  (ps-output-string (if ebnf-production-name-p
+                       (ebnf-node-name production)
+                     ""))
   (ps-output " "
             (ebnf-format-float
              (ebnf-node-width production)
   (ps-output " "
             (ebnf-format-float
              (ebnf-node-width production)
-             (+ ebnf-basic-height
+             (+ (if ebnf-production-name-p
+                    ebnf-basic-height
+                  0.0)
                 (ebnf-node-entry (ebnf-node-production production))))
             " BOP\n")
   (ebnf-node-generation (ebnf-node-production production))
                 (ebnf-node-entry (ebnf-node-production production))))
             " BOP\n")
   (ebnf-node-generation (ebnf-node-production production))
@@ -4005,7 +4862,9 @@ end
     (if sep
        (let ((ebnf-direction "L"))
          (ebnf-node-generation sep))
     (if sep
        (let ((ebnf-direction "L"))
          (ebnf-node-generation sep))
-      (ebnf-empty-alternative (- width ebnf-horizontal-space))))
+      (ebnf-empty-alternative (- width
+                                ebnf-horizontal-space
+                                ebnf-basic-width-extra))))
   (ps-output "EOS\n"))
 
 
   (ps-output "EOS\n"))
 
 
@@ -4020,7 +4879,7 @@ end
                        (if node-sep
                            (- (ebnf-node-height node-sep)
                               (ebnf-node-entry node-sep))
                        (if node-sep
                            (- (ebnf-node-height node-sep)
                               (ebnf-node-entry node-sep))
-                         0))))
+                         ebnf-basic-empty-height))))
     (ps-output (ebnf-format-float entry
                                  (+ (- (ebnf-node-height node-list)
                                        list-entry)
     (ps-output (ebnf-format-float entry
                                  (+ (- (ebnf-node-height node-list)
                                        list-entry)
@@ -4032,7 +4891,9 @@ end
     (if (ebnf-node-separator zero-or-more)
        (let ((ebnf-direction "L"))
          (ebnf-node-generation (ebnf-node-separator zero-or-more)))
     (if (ebnf-node-separator zero-or-more)
        (let ((ebnf-direction "L"))
          (ebnf-node-generation (ebnf-node-separator zero-or-more)))
-      (ebnf-empty-alternative (- width ebnf-horizontal-space))))
+      (ebnf-empty-alternative (- width
+                                ebnf-horizontal-space
+                                ebnf-basic-width-extra))))
   (ps-output "EOS\n"))
 
 
   (ps-output "EOS\n"))
 
 
@@ -4100,6 +4961,35 @@ end
 ;; Internal functions
 
 
 ;; Internal functions
 
 
+(defun ebnf-directory (fun &optional directory)
+  "Process files in DIRECTORY applying function FUN on each file.
+
+If DIRECTORY is nil, use `default-directory'.
+
+Only files in DIRECTORY that match `ebnf-file-suffix-regexp' (which see) are
+processed."
+  (let ((files (directory-files (or directory default-directory)
+                               t ebnf-file-suffix-regexp)))
+    (while files
+      (set-buffer (find-file-noselect (car files)))
+      (funcall fun)
+      (setq buffer-backed-up t)                    ; Do not back it up.
+      (save-buffer)                        ; Just save new version.
+      (kill-buffer (current-buffer))
+      (setq files (cdr files)))))
+
+
+(defun ebnf-file (fun file &optional do-not-kill-buffer-when-done)
+  "Process the named FILE applying function FUN.
+
+If optional arg DO-NOT-KILL-BUFFER-WHEN-DONE is non-nil, the buffer isn't
+killed after process termination."
+  (set-buffer (find-file-noselect file))
+  (funcall fun)
+  (or do-not-kill-buffer-when-done
+      (kill-buffer (current-buffer))))
+
+
 ;; function `ebnf-range-regexp' is used to avoid a bug of `skip-chars-forward'
 ;; on version 20.4.1, that is, it doesn't accept ranges like "\240-\377" (or
 ;; "\177-\237"), but it accepts the character sequence from \240 to \377 (or
 ;; function `ebnf-range-regexp' is used to avoid a bug of `skip-chars-forward'
 ;; on version 20.4.1, that is, it doesn't accept ranges like "\240-\377" (or
 ;; "\177-\237"), but it accepts the character sequence from \240 to \377 (or
@@ -4125,6 +5015,8 @@ end
 (defun ebnf-eps-filename (str)
   (let* ((len  (length str))
         (stri 0)
 (defun ebnf-eps-filename (str)
   (let* ((len  (length str))
         (stri 0)
+        ;; to keep compatibility with Emacs 20 & 21:
+        ;; DO NOT REPLACE `?\ ' BY `?\s'
         (new  (make-string len ?\ )))
     (while (< stri len)
       (aset new stri (aref ebnf-map-name (aref str stri)))
         (new  (make-string len ?\ )))
     (while (< stri len)
       (aset new stri (aref ebnf-map-name (aref str stri)))
@@ -4141,6 +5033,7 @@ end
 (defun ebnf-generate-region (from to gen-func)
   (run-hooks 'ebnf-hook)
   (let ((ebnf-limit (max from to))
 (defun ebnf-generate-region (from to gen-func)
   (run-hooks 'ebnf-hook)
   (let ((ebnf-limit (max from to))
+       (error-msg "SYNTAX")
        the-point)
     (save-excursion
       (save-restriction
        the-point)
     (save-excursion
       (save-restriction
@@ -4148,25 +5041,44 @@ end
          (condition-case data
              (let ((tree (ebnf-parse-and-sort (min from to))))
                (when gen-func
          (condition-case data
              (let ((tree (ebnf-parse-and-sort (min from to))))
                (when gen-func
-                 (funcall gen-func
-                          (ebnf-dimensions
-                           (ebnf-optimize
-                            (ebnf-eliminate-empty-rules tree))))))
+                 (setq error-msg "EMPTY RULES"
+                       tree      (ebnf-eliminate-empty-rules tree))
+                 (setq error-msg "OPTMIZE"
+                       tree      (ebnf-optimize tree))
+                 (setq error-msg "DIMENSIONS"
+                       tree      (ebnf-dimensions tree))
+                 (setq error-msg "GENERATION")
+                 (funcall gen-func tree))
+               (setq error-msg nil))   ; here it's ok
            ;; handler
            ((quit error)
             (ding)
            ;; handler
            ((quit error)
             (ding)
-            (setq the-point (max (1- (point)) (point-min)))
-            (message (error-message-string data)))))))
+            (setq the-point (max (1- (point)) (point-min))
+                  error-msg (concat error-msg ": "
+                                    (error-message-string data)
+                                    ", "
+                                    (and (string= error-msg "SYNTAX")
+                                         (format "at position %d "
+                                                 the-point))
+                                    (format "in buffer \"%s\"."
+                                            (buffer-name)))))))))
     (cond
     (cond
-     (the-point
-      (goto-char the-point))
+     ;; error occurred
+     (error-msg
+      (goto-char the-point)
+      (if ebnf-stop-on-error
+         (error error-msg)
+       (message "%s" error-msg)))
+     ;; generated output OK
      (gen-func
       nil)
      (gen-func
       nil)
+     ;; syntax checked OK
      (t
       (message "EBNF syntactic analysis: NO ERRORS.")))))
 
 
 (defun ebnf-parse-and-sort (start)
      (t
       (message "EBNF syntactic analysis: NO ERRORS.")))))
 
 
 (defun ebnf-parse-and-sort (start)
+  (ebnf-log "(ebnf-parse-and-sort %S)" start)
   (ebnf-begin-job)
   (let ((tree (funcall ebnf-parser-func start)))
     (if ebnf-sort-production
   (ebnf-begin-job)
   (let ((tree (funcall ebnf-parser-func start)))
     (if ebnf-sort-production
@@ -4265,6 +5177,17 @@ end
   (ebnf-font-select font 'line-height))
 
 
   (ebnf-font-select font 'line-height))
 
 
+(defconst ebnf-syntax-alist
+  ;; 0.syntax  1.parser         2.initializer
+  '((iso-ebnf  ebnf-iso-parser  ebnf-iso-initialize)
+    (yacc      ebnf-yac-parser  ebnf-yac-initialize)
+    (abnf      ebnf-abn-parser  ebnf-abn-initialize)
+    (ebnf      ebnf-bnf-parser  ebnf-bnf-initialize)
+    (ebnfx     ebnf-ebx-parser  ebnf-ebx-initialize)
+    (dtd       ebnf-dtd-parser  ebnf-dtd-initialize))
+  "Alist associating EBNF syntax with a parser and an initializer.")
+
+
 (defun ebnf-begin-job ()
   (ps-printing-region nil nil nil)
   (if ebnf-use-float-format
 (defun ebnf-begin-job ()
   (ps-printing-region nil nil nil)
   (if ebnf-use-float-format
@@ -4274,15 +5197,10 @@ end
          ebnf-message-float "%s"))
   (ebnf-otz-initialize)
   ;; to avoid compilation gripes when calling autoloaded functions
          ebnf-message-float "%s"))
   (ebnf-otz-initialize)
   ;; to avoid compilation gripes when calling autoloaded functions
-  (funcall (cond ((eq ebnf-syntax 'iso-ebnf)
-                 (setq ebnf-parser-func 'ebnf-iso-parser)
-                 'ebnf-iso-initialize)
-                ((eq ebnf-syntax 'yacc)
-                 (setq ebnf-parser-func 'ebnf-yac-parser)
-                 'ebnf-yac-initialize)
-                (t
-                 (setq ebnf-parser-func 'ebnf-bnf-parser)
-                 'ebnf-bnf-initialize)))
+  (let ((init (or (assoc ebnf-syntax ebnf-syntax-alist)
+                 (assoc 'ebnf ebnf-syntax-alist))))
+    (setq ebnf-parser-func (nth 1 init))
+    (funcall (nth 2 init)))
   (and ebnf-terminal-regexp            ; ensures that it's a string or nil
        (not (stringp ebnf-terminal-regexp))
        (setq ebnf-terminal-regexp nil))
   (and ebnf-terminal-regexp            ; ensures that it's a string or nil
        (not (stringp ebnf-terminal-regexp))
        (setq ebnf-terminal-regexp nil))
@@ -4299,7 +5217,10 @@ end
        ebnf-action              nil
        ebnf-default-p           nil
        ebnf-eps-context         nil
        ebnf-action              nil
        ebnf-default-p           nil
        ebnf-eps-context         nil
+       ebnf-eps-file-alist      nil
        ebnf-eps-production-list nil
        ebnf-eps-production-list nil
+       ebnf-eps-header-comment  nil
+       ebnf-eps-footer-comment  nil
        ebnf-eps-upper-x         0.0
        ebnf-eps-upper-y         0.0
        ebnf-font-height-P       (ebnf-font-height ebnf-production-font)
        ebnf-eps-upper-x         0.0
        ebnf-eps-upper-y         0.0
        ebnf-font-height-P       (ebnf-font-height ebnf-production-font)
@@ -4320,10 +5241,14 @@ end
        ebnf-space-E             (* ebnf-font-height-E 0.5)
        ebnf-space-R             (* ebnf-font-height-R 0.5))
   (let ((basic (+ ebnf-font-height-T ebnf-font-height-NT)))
        ebnf-space-E             (* ebnf-font-height-E 0.5)
        ebnf-space-R             (* ebnf-font-height-R 0.5))
   (let ((basic (+ ebnf-font-height-T ebnf-font-height-NT)))
-    (setq ebnf-basic-width      (* basic 0.5)
-         ebnf-horizontal-space (+ basic basic)
-         ebnf-basic-height     ebnf-basic-width
-         ebnf-vertical-space   ebnf-basic-width)
+    (setq ebnf-basic-width        (* basic 0.5)
+         ebnf-horizontal-space   (+ basic basic)
+         ebnf-basic-empty-height (* ebnf-basic-width 0.5)
+         ebnf-basic-height       ebnf-basic-width
+         ebnf-vertical-space     ebnf-basic-width
+         ebnf-basic-width-extra  (- ebnf-basic-width
+                                    ebnf-arrow-extra-width
+                                    0.1)) ; error factor
     ;; ensures value is greater than zero
     (or (and (numberp ebnf-production-horizontal-space)
             (> ebnf-production-horizontal-space 0.0))
     ;; ensures value is greater than zero
     (or (and (numberp ebnf-production-horizontal-space)
             (> ebnf-production-horizontal-space 0.0))
@@ -4331,7 +5256,18 @@ end
     ;; ensures value is greater than zero
     (or (and (numberp ebnf-production-vertical-space)
             (> ebnf-production-vertical-space 0.0))
     ;; ensures value is greater than zero
     (or (and (numberp ebnf-production-vertical-space)
             (> ebnf-production-vertical-space 0.0))
-       (setq ebnf-production-vertical-space basic))))
+       (setq ebnf-production-vertical-space basic)))
+  (ebnf-log "(ebnf-begin-job)")
+  (ebnf-log "   ebnf-arrow-extra-width ............ : %7.3f"      ebnf-arrow-extra-width)
+  (ebnf-log "   ebnf-arrow-scale .................. : %7.3f"      ebnf-arrow-scale)
+  (ebnf-log "   ebnf-basic-width-extra ............ : %7.3f"      ebnf-basic-width-extra)
+  (ebnf-log "   ebnf-basic-width .................. : %7.3f (T)"  ebnf-basic-width)
+  (ebnf-log "   ebnf-horizontal-space ............. : %7.3f (4T)" ebnf-horizontal-space)
+  (ebnf-log "   ebnf-basic-empty-height ........... : %7.3f (hT)" ebnf-basic-empty-height)
+  (ebnf-log "   ebnf-basic-height ................. : %7.3f (T)"  ebnf-basic-height)
+  (ebnf-log "   ebnf-vertical-space ............... : %7.3f (T)"  ebnf-vertical-space)
+  (ebnf-log "   ebnf-production-horizontal-space .. : %7.3f (2T)" ebnf-production-horizontal-space)
+  (ebnf-log "   ebnf-production-vertical-space .... : %7.3f (2T)" ebnf-production-vertical-space))
 
 
 (defsubst ebnf-shape-value (sym alist)
 
 
 (defsubst ebnf-shape-value (sym alist)
@@ -4354,7 +5290,7 @@ end
         (progn
           ;; adjust creator comment
           (end-of-line)
         (progn
           ;; adjust creator comment
           (end-of-line)
-          (backward-char)
+          ;; (backward-char)
           (insert " & ebnf2ps v" ebnf-version)
           ;; insert ebnf settings & engine
           (goto-char (point-max))
           (insert " & ebnf2ps v" ebnf-version)
           ;; insert ebnf settings & engine
           (goto-char (point-max))
@@ -4364,52 +5300,56 @@ end
 
 
 (defun ebnf-eps-finish-and-write (buffer filename)
 
 
 (defun ebnf-eps-finish-and-write (buffer filename)
-  (save-excursion
-    (set-buffer buffer)
-    (setq ebnf-eps-upper-x (max ebnf-eps-upper-x ebnf-eps-max-width)
-         ebnf-eps-upper-y (if (zerop ebnf-eps-upper-y)
-                              ebnf-eps-max-height
-                            (+ ebnf-eps-upper-y
-                               ebnf-production-vertical-space
-                               ebnf-eps-max-height)))
-    ;; prologue
-    (goto-char (point-min))
-    (insert
-     "%!PS-Adobe-3.0 EPSF-3.0"
-     "\n%%BoundingBox: 0 0 "
-     (format "%d %d" (1+ ebnf-eps-upper-x) (1+ ebnf-eps-upper-y))
-     "\n%%Title: " filename
-     "\n%%CreationDate: " (format-time-string "%T %b %d %Y")
-     "\n%%Creator: " (user-full-name) " (using ebnf2ps v" ebnf-version ")"
-     "\n%%DocumentNeededResources: font "
-     (or ebnf-fonts-required
-        (setq ebnf-fonts-required
-              (mapconcat 'identity
-                         (ps-remove-duplicates
-                          (mapcar 'ebnf-font-name-select
-                                  (list ebnf-production-font
-                                        ebnf-terminal-font
-                                        ebnf-non-terminal-font
-                                        ebnf-special-font
-                                        ebnf-except-font
-                                        ebnf-repeat-font)))
-                         "\n%%+ font ")))
-     "\n%%Pages: 0\n%%EndComments\n\n%%BeginProlog\n"
-     ebnf-eps-prologue)
-    (ebnf-insert-ebnf-prologue)
-    (insert ebnf-eps-begin
-           "\n0 " (ebnf-format-float
-                   (- ebnf-eps-upper-y (* ebnf-font-height-P 0.7)))
-           " #ebnf2ps#begin\n")
-    ;; epilogue
-    (goto-char (point-max))
-    (insert ebnf-eps-end)
-    ;; write file
-    (message "Saving...")
-    (setq filename (expand-file-name filename))
-    (let ((coding-system-for-write 'raw-text-unix))
-      (write-region (point-min) (point-max) filename))
-    (message "Wrote %s" filename)))
+  (when (buffer-modified-p buffer)
+    (save-excursion
+      (set-buffer buffer)
+      (ebnf-eps-header-footer-set filename)
+      (setq ebnf-eps-upper-x (max ebnf-eps-upper-x ebnf-eps-max-width)
+           ebnf-eps-upper-y (if (zerop ebnf-eps-upper-y)
+                                ebnf-eps-max-height
+                              (+ ebnf-eps-upper-y
+                                 ebnf-production-vertical-space
+                                 ebnf-eps-max-height)))
+      ;; prologue
+      (goto-char (point-min))
+      (insert
+       "%!PS-Adobe-3.0 EPSF-3.0"
+       "\n%%BoundingBox: 0 0 "
+       (format "%d %d" (1+ ebnf-eps-upper-x) (1+ ebnf-eps-upper-y))
+       "\n%%Title: " filename
+       "\n%%CreationDate: " (format-time-string "%T %b %d %Y")
+       "\n%%Creator: " (user-full-name) " (using ebnf2ps v" ebnf-version ")"
+       "\n%%DocumentNeededResources: font "
+       (or ebnf-fonts-required
+          (setq ebnf-fonts-required
+                (mapconcat 'identity
+                           (ps-remove-duplicates
+                            (mapcar 'ebnf-font-name-select
+                                    (list ebnf-production-font
+                                          ebnf-terminal-font
+                                          ebnf-non-terminal-font
+                                          ebnf-special-font
+                                          ebnf-except-font
+                                          ebnf-repeat-font
+                                          ebnf-eps-header-font
+                                          ebnf-eps-footer-font)))
+                           "\n%%+ font ")))
+       "\n%%Pages: 0\n%%EndComments\n\n%%BeginProlog\n"
+       ebnf-eps-prologue)
+      (ebnf-insert-ebnf-prologue)
+      (insert ebnf-eps-begin
+             "\n0 " (ebnf-format-float
+                     (- ebnf-eps-upper-y (* ebnf-font-height-P 0.7)))
+             " #ebnf2ps#begin\n")
+      ;; epilogue
+      (goto-char (point-max))
+      (insert ebnf-eps-end)
+      ;; write file
+      (message "Saving...")
+      (setq filename (expand-file-name filename))
+      (let ((coding-system-for-write 'raw-text-unix))
+       (write-region (point-min) (point-max) filename))
+      (message "Wrote %s" filename))))
 
 
 (defun ebnf-insert-ebnf-prologue ()
 
 
 (defun ebnf-insert-ebnf-prologue ()
@@ -4418,6 +5358,42 @@ end
        (setq ebnf-settings
             (concat
              "\n\n% === begin EBNF settings\n\n"
        (setq ebnf-settings
             (concat
              "\n\n% === begin EBNF settings\n\n"
+             (format "/Header        %s def\n"
+                     (or ebnf-eps-header-comment "()"))
+             (format "/Footer        %s def\n"
+                     (or ebnf-eps-footer-comment "()"))
+             ;; header
+             (format "/ShowHeader    %s def\n"
+                     (ebnf-boolean
+                      (ebnf-eps-header-footer-p ebnf-eps-header)))
+             (format "/fH            %s /%s DefFont\n"
+                     (ebnf-format-float
+                      (ebnf-font-size ebnf-eps-header-font))
+                     (ebnf-font-name-select ebnf-eps-header-font))
+             (ebnf-format-color "/ForegroundH   %s def %% %s\n"
+                                (ebnf-font-foreground ebnf-eps-header-font)
+                                "Black")
+             (ebnf-format-color "/BackgroundH   %s def %% %s\n"
+                                (ebnf-font-background ebnf-eps-header-font)
+                                "White")
+             (format "/EffectH       %d def\n"
+                     (ebnf-font-attributes ebnf-eps-header-font))
+             ;; footer
+             (format "/ShowFooter    %s def\n"
+                     (ebnf-boolean
+                      (ebnf-eps-header-footer-p ebnf-eps-footer)))
+             (format "/fF            %s /%s DefFont\n"
+                     (ebnf-format-float
+                      (ebnf-font-size ebnf-eps-footer-font))
+                     (ebnf-font-name-select ebnf-eps-footer-font))
+             (ebnf-format-color "/ForegroundF   %s def %% %s\n"
+                                (ebnf-font-foreground ebnf-eps-footer-font)
+                                "Black")
+             (ebnf-format-color "/BackgroundF   %s def %% %s\n"
+                                (ebnf-font-background ebnf-eps-footer-font)
+                                "White")
+             (format "/EffectF       %d def\n"
+                     (ebnf-font-attributes ebnf-eps-footer-font))
              ;; production
              (format "/fP            %s /%s DefFont\n"
                      (ebnf-format-float (ebnf-font-size ebnf-production-font))
              ;; production
              (format "/fP            %s /%s DefFont\n"
                      (ebnf-format-float (ebnf-font-size ebnf-production-font))
@@ -4542,6 +5518,10 @@ end
              (format "/ShadowR       %s def\n"
                      (ebnf-boolean ebnf-repeat-shadow))
              ;; miscellaneous
              (format "/ShadowR       %s def\n"
                      (ebnf-boolean ebnf-repeat-shadow))
              ;; miscellaneous
+             (format "/ExtraWidth    %s def\n"
+                     (ebnf-format-float ebnf-arrow-extra-width))
+             (format "/ArrowScale    %s def\n"
+                     (ebnf-format-float ebnf-arrow-scale))
              (format "/DefaultWidth  %s def\n"
                      (ebnf-format-float ebnf-default-width))
              (format "/LineWidth     %s def\n"
              (format "/DefaultWidth  %s def\n"
                      (ebnf-format-float ebnf-default-width))
              (format "/LineWidth     %s def\n"
@@ -4570,6 +5550,7 @@ end
 
 
 (defun ebnf-dimensions (tree)
 
 
 (defun ebnf-dimensions (tree)
+  (ebnf-log "(ebnf-dimensions tree)")
   (let ((ebnf-total (length tree))
        (ebnf-nprod 0))
     (mapcar 'ebnf-production-dimension tree))
   (let ((ebnf-total (length tree))
        (ebnf-nprod 0))
     (mapcar 'ebnf-production-dimension tree))
@@ -4583,20 +5564,31 @@ end
 
 ;; [production width-fun dim-fun entry height width name production action]
 (defun ebnf-production-dimension (production)
 
 ;; [production width-fun dim-fun entry height width name production action]
 (defun ebnf-production-dimension (production)
+  (ebnf-log "(ebnf-production-dimension production)")
   (ebnf-message-info "Calculating dimensions")
   (ebnf-node-dimension-func (ebnf-node-production production))
   (let* ((prod   (ebnf-node-production production))
   (ebnf-message-info "Calculating dimensions")
   (ebnf-node-dimension-func (ebnf-node-production production))
   (let* ((prod   (ebnf-node-production production))
-        (height (+ ebnf-font-height-P
+        (height (+ (if ebnf-production-name-p
+                       ebnf-font-height-P
+                     0.0)
+                   ebnf-line-width ebnf-line-width
                    ebnf-basic-height
                    (ebnf-node-height prod))))
     (ebnf-node-entry  production height)
     (ebnf-node-height production height)
     (ebnf-node-width  production (+ (ebnf-node-width prod)
                    ebnf-basic-height
                    (ebnf-node-height prod))))
     (ebnf-node-entry  production height)
     (ebnf-node-height production height)
     (ebnf-node-width  production (+ (ebnf-node-width prod)
-                                   ebnf-horizontal-space))))
+                                   ebnf-line-width
+                                   ebnf-horizontal-space
+                                   ebnf-basic-width-extra)))
+  (ebnf-log "   production name   : %S"    (ebnf-node-name   production))
+  (ebnf-log "   production entry  : %7.3f" (ebnf-node-entry  production))
+  (ebnf-log "   production height : %7.3f" (ebnf-node-height production))
+  (ebnf-log "   production width  : %7.3f" (ebnf-node-width  production)))
 
 
 ;; [terminal width-fun dim-fun entry height width name]
 (defun ebnf-terminal-dimension (terminal)
 
 
 ;; [terminal width-fun dim-fun entry height width name]
 (defun ebnf-terminal-dimension (terminal)
+  (ebnf-log "(ebnf-terminal-dimension terminal)")
   (ebnf-terminal-dimension1 terminal
                            ebnf-font-height-T
                            ebnf-font-width-T
   (ebnf-terminal-dimension1 terminal
                            ebnf-font-height-T
                            ebnf-font-width-T
@@ -4605,6 +5597,7 @@ end
 
 ;; [non-terminal width-fun dim-fun entry height width name]
 (defun ebnf-non-terminal-dimension (non-terminal)
 
 ;; [non-terminal width-fun dim-fun entry height width name]
 (defun ebnf-non-terminal-dimension (non-terminal)
+  (ebnf-log "(ebnf-non-terminal-dimension non-terminal)")
   (ebnf-terminal-dimension1 non-terminal
                            ebnf-font-height-NT
                            ebnf-font-width-NT
   (ebnf-terminal-dimension1 non-terminal
                            ebnf-font-height-NT
                            ebnf-font-width-NT
@@ -4613,6 +5606,7 @@ end
 
 ;; [special width-fun dim-fun entry height width name]
 (defun ebnf-special-dimension (special)
 
 ;; [special width-fun dim-fun entry height width name]
 (defun ebnf-special-dimension (special)
+  (ebnf-log "(ebnf-special-dimension special)")
   (ebnf-terminal-dimension1 special
                            ebnf-font-height-S
                            ebnf-font-width-S
   (ebnf-terminal-dimension1 special
                            ebnf-font-height-S
                            ebnf-font-width-S
@@ -4624,9 +5618,16 @@ end
        (len    (length (ebnf-node-name node))))
     (ebnf-node-entry  node (* height 0.5))
     (ebnf-node-height node height)
        (len    (length (ebnf-node-name node))))
     (ebnf-node-entry  node (* height 0.5))
     (ebnf-node-height node height)
-    (ebnf-node-width  node (+ ebnf-basic-width space
+    (ebnf-node-width  node (+ ebnf-basic-width
+                             ebnf-arrow-extra-width
+                             space
                              (* len font-width)
                              (* len font-width)
-                             space ebnf-basic-width))))
+                             space
+                             ebnf-basic-width)))
+  (ebnf-log "   name   : %S"    (ebnf-node-name   node))
+  (ebnf-log "   entry  : %7.3f" (ebnf-node-entry  node))
+  (ebnf-log "   height : %7.3f" (ebnf-node-height node))
+  (ebnf-log "   width  : %7.3f" (ebnf-node-width  node)))
 
 
 (defconst ebnf-null-vector (vector t t t 0.0 0.0 0.0))
 
 
 (defconst ebnf-null-vector (vector t t t 0.0 0.0 0.0))
@@ -4634,6 +5635,7 @@ end
 
 ;; [repeat width-fun dim-fun entry height width times element]
 (defun ebnf-repeat-dimension (repeat)
 
 ;; [repeat width-fun dim-fun entry height width times element]
 (defun ebnf-repeat-dimension (repeat)
+  (ebnf-log "(ebnf-repeat-dimension repeat)")
   (let ((times   (ebnf-node-name repeat))
        (element (ebnf-node-separator repeat)))
     (if element
   (let ((times   (ebnf-node-name repeat))
        (element (ebnf-node-separator repeat)))
     (if element
@@ -4645,13 +5647,18 @@ end
                                     ebnf-font-height-S)
                                ebnf-space-R ebnf-space-R))
     (ebnf-node-width  repeat (+ (ebnf-node-width element)
                                     ebnf-font-height-S)
                                ebnf-space-R ebnf-space-R))
     (ebnf-node-width  repeat (+ (ebnf-node-width element)
+                               ebnf-arrow-extra-width
                                ebnf-space-R ebnf-space-R ebnf-space-R
                                ebnf-horizontal-space
                                ebnf-space-R ebnf-space-R ebnf-space-R
                                ebnf-horizontal-space
-                               (* (length times) ebnf-font-width-R)))))
+                               (* (length times) ebnf-font-width-R))))
+  (ebnf-log "   repeat entry  : %7.3f" (ebnf-node-entry  repeat))
+  (ebnf-log "   repeat height : %7.3f" (ebnf-node-height repeat))
+  (ebnf-log "   repeat width  : %7.3f" (ebnf-node-width  repeat)))
 
 
 ;; [except width-fun dim-fun entry height width element element]
 (defun ebnf-except-dimension (except)
 
 
 ;; [except width-fun dim-fun entry height width element element]
 (defun ebnf-except-dimension (except)
+  (ebnf-log "(ebnf-except-dimension except)")
   (let ((factor  (ebnf-node-list except))
        (element (ebnf-node-separator except)))
     (ebnf-node-dimension-func factor)
   (let ((factor  (ebnf-node-list except))
        (element (ebnf-node-separator except)))
     (ebnf-node-dimension-func factor)
@@ -4666,14 +5673,19 @@ end
                                ebnf-space-E ebnf-space-E))
     (ebnf-node-width  except (+ (ebnf-node-width factor)
                                (ebnf-node-width element)
                                ebnf-space-E ebnf-space-E))
     (ebnf-node-width  except (+ (ebnf-node-width factor)
                                (ebnf-node-width element)
+                               ebnf-arrow-extra-width
                                ebnf-space-E ebnf-space-E
                                ebnf-space-E ebnf-space-E
                                ebnf-font-width-E
                                ebnf-space-E ebnf-space-E
                                ebnf-space-E ebnf-space-E
                                ebnf-font-width-E
-                               ebnf-horizontal-space))))
+                               ebnf-horizontal-space)))
+  (ebnf-log "   except entry  : %7.3f" (ebnf-node-entry  except))
+  (ebnf-log "   except height : %7.3f" (ebnf-node-height except))
+  (ebnf-log "   except width  : %7.3f" (ebnf-node-width  except)))
 
 
 ;; [alternative width-fun dim-fun entry height width list]
 (defun ebnf-alternative-dimension (alternative)
 
 
 ;; [alternative width-fun dim-fun entry height width list]
 (defun ebnf-alternative-dimension (alternative)
+  (ebnf-log "(ebnf-alternative-dimension alternative)")
   (let ((body (ebnf-node-list alternative))
        (lis  (ebnf-node-list alternative)))
     (while lis
   (let ((body (ebnf-node-list alternative))
        (lis  (ebnf-node-list alternative)))
     (while lis
@@ -4698,23 +5710,33 @@ end
                                           (- (ebnf-node-height tail)
                                              (ebnf-node-entry tail))))))
       (ebnf-node-height alternative height)
                                           (- (ebnf-node-height tail)
                                              (ebnf-node-entry tail))))))
       (ebnf-node-height alternative height)
-      (ebnf-node-width  alternative (+ width ebnf-horizontal-space))
-      (ebnf-node-list   alternative body))))
+      (ebnf-node-width  alternative (+ width
+                                      ebnf-horizontal-space
+                                      ebnf-basic-width-extra))
+      (ebnf-node-list   alternative body)))
+  (ebnf-log "   alternative entry  : %7.3f" (ebnf-node-entry  alternative))
+  (ebnf-log "   alternative height : %7.3f" (ebnf-node-height alternative))
+  (ebnf-log "   alternative width  : %7.3f" (ebnf-node-width  alternative)))
 
 
 ;; [optional width-fun dim-fun entry height width element]
 (defun ebnf-optional-dimension (optional)
 
 
 ;; [optional width-fun dim-fun entry height width element]
 (defun ebnf-optional-dimension (optional)
+  (ebnf-log "(ebnf-optional-dimension optional)")
   (let ((body (ebnf-node-list optional)))
     (ebnf-node-dimension-func body)
     (ebnf-node-entry  optional (ebnf-node-entry body))
     (ebnf-node-height optional (+ (ebnf-node-height body)
                                  ebnf-vertical-space))
     (ebnf-node-width  optional (+ (ebnf-node-width body)
   (let ((body (ebnf-node-list optional)))
     (ebnf-node-dimension-func body)
     (ebnf-node-entry  optional (ebnf-node-entry body))
     (ebnf-node-height optional (+ (ebnf-node-height body)
                                  ebnf-vertical-space))
     (ebnf-node-width  optional (+ (ebnf-node-width body)
-                                 ebnf-horizontal-space))))
+                                 ebnf-horizontal-space)))
+  (ebnf-log "   optional entry  : %7.3f" (ebnf-node-entry  optional))
+  (ebnf-log "   optional height : %7.3f" (ebnf-node-height optional))
+  (ebnf-log "   optional width  : %7.3f" (ebnf-node-width  optional)))
 
 
 ;; [one-or-more width-fun dim-fun entry height width element separator]
 (defun ebnf-one-or-more-dimension (or-more)
 
 
 ;; [one-or-more width-fun dim-fun entry height width element separator]
 (defun ebnf-one-or-more-dimension (or-more)
+  (ebnf-log "(ebnf-one-or-more-dimension or-more)")
   (let ((list-part (ebnf-node-list or-more))
        (sep-part  (ebnf-node-separator or-more)))
     (ebnf-node-dimension-func list-part)
   (let ((list-part (ebnf-node-list or-more))
        (sep-part  (ebnf-node-separator or-more)))
     (ebnf-node-dimension-func list-part)
@@ -4722,7 +5744,7 @@ end
         (ebnf-node-dimension-func sep-part))
     (let ((height (+ (if sep-part
                         (ebnf-node-height sep-part)
         (ebnf-node-dimension-func sep-part))
     (let ((height (+ (if sep-part
                         (ebnf-node-height sep-part)
-                      0.0)
+                      ebnf-basic-empty-height)
                     ebnf-vertical-space
                     (ebnf-node-height list-part)))
          (width  (max (if sep-part
                     ebnf-vertical-space
                     (ebnf-node-height list-part)))
          (width  (max (if sep-part
@@ -4732,14 +5754,21 @@ end
       (when sep-part
        (ebnf-adjust-width list-part width)
        (ebnf-adjust-width sep-part width))
       (when sep-part
        (ebnf-adjust-width list-part width)
        (ebnf-adjust-width sep-part width))
-      (ebnf-node-entry  or-more (+ (- height (ebnf-node-height list-part))
+      (ebnf-node-entry  or-more (+ (- height
+                                     (ebnf-node-height list-part))
                                   (ebnf-node-entry list-part)))
       (ebnf-node-height or-more height)
                                   (ebnf-node-entry list-part)))
       (ebnf-node-height or-more height)
-      (ebnf-node-width  or-more (+ width ebnf-horizontal-space)))))
+      (ebnf-node-width  or-more (+ width
+                                  ebnf-horizontal-space
+                                  ebnf-basic-width-extra))))
+  (ebnf-log "   one-or-more entry  : %7.3f" (ebnf-node-entry  or-more))
+  (ebnf-log "   one-or-more height : %7.3f" (ebnf-node-height or-more))
+  (ebnf-log "   one-or-more width  : %7.3f" (ebnf-node-width  or-more)))
 
 
 ;; [zero-or-more width-fun dim-fun entry height width element separator]
 (defun ebnf-zero-or-more-dimension (or-more)
 
 
 ;; [zero-or-more width-fun dim-fun entry height width element separator]
 (defun ebnf-zero-or-more-dimension (or-more)
+  (ebnf-log "(ebnf-zero-or-more-dimension or-more)")
   (let ((list-part (ebnf-node-list or-more))
        (sep-part  (ebnf-node-separator or-more)))
     (ebnf-node-dimension-func list-part)
   (let ((list-part (ebnf-node-list or-more))
        (sep-part  (ebnf-node-separator or-more)))
     (ebnf-node-dimension-func list-part)
@@ -4747,7 +5776,7 @@ end
         (ebnf-node-dimension-func sep-part))
     (let ((height (+ (if sep-part
                         (ebnf-node-height sep-part)
         (ebnf-node-dimension-func sep-part))
     (let ((height (+ (if sep-part
                         (ebnf-node-height sep-part)
-                      0.0)
+                      ebnf-basic-empty-height)
                     ebnf-vertical-space
                     (ebnf-node-height list-part)
                     ebnf-vertical-space))
                     ebnf-vertical-space
                     (ebnf-node-height list-part)
                     ebnf-vertical-space))
@@ -4760,11 +5789,17 @@ end
        (ebnf-adjust-width sep-part width))
       (ebnf-node-entry  or-more height)
       (ebnf-node-height or-more height)
        (ebnf-adjust-width sep-part width))
       (ebnf-node-entry  or-more height)
       (ebnf-node-height or-more height)
-      (ebnf-node-width  or-more (+ width ebnf-horizontal-space)))))
+      (ebnf-node-width  or-more (+ width
+                                  ebnf-horizontal-space
+                                  ebnf-basic-width-extra))))
+  (ebnf-log "   zero-or-more entry  : %7.3f" (ebnf-node-entry  or-more))
+  (ebnf-log "   zero-or-more height : %7.3f" (ebnf-node-height or-more))
+  (ebnf-log "   zero-or-more width  : %7.3f" (ebnf-node-width  or-more)))
 
 
 ;; [sequence width-fun dim-fun entry height width list]
 (defun ebnf-sequence-dimension (sequence)
 
 
 ;; [sequence width-fun dim-fun entry height width list]
 (defun ebnf-sequence-dimension (sequence)
+  (ebnf-log "(ebnf-sequence-dimension sequence)")
   (let ((above 0.0)
        (below 0.0)
        (width 0.0)
   (let ((above 0.0)
        (below 0.0)
        (width 0.0)
@@ -4780,7 +5815,10 @@ end
            width (+ width (ebnf-node-width node))))
     (ebnf-node-entry  sequence above)
     (ebnf-node-height sequence (+ above below))
            width (+ width (ebnf-node-width node))))
     (ebnf-node-entry  sequence above)
     (ebnf-node-height sequence (+ above below))
-    (ebnf-node-width  sequence width)))
+    (ebnf-node-width  sequence width))
+  (ebnf-log "   sequence entry  : %7.3f" (ebnf-node-entry  sequence))
+  (ebnf-log "   sequence height : %7.3f" (ebnf-node-height sequence))
+  (ebnf-log "   sequence width  : %7.3f" (ebnf-node-width  sequence)))
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -4848,7 +5886,7 @@ end
 
 ;; [one-or-more  width-fun dim-fun entry height width element separator]
 ;; [zero-or-more width-fun dim-fun entry height width element separator]
 
 ;; [one-or-more  width-fun dim-fun entry height width element separator]
 ;; [zero-or-more width-fun dim-fun entry height width element separator]
-(defun ebnf-list-width (or-more width)
+(defun ebnf-element-width (or-more width)
   (setq width (- width ebnf-horizontal-space))
   (ebnf-node-list or-more
                  (ebnf-justify-list or-more
   (setq width (- width ebnf-horizontal-space))
   (ebnf-node-list or-more
                  (ebnf-justify-list or-more
@@ -4879,7 +5917,10 @@ end
        ;; right justify terms
        ((eq ebnf-justify-sequence 'right)
        (ebnf-justify node seq seq-width width nil))
        ;; right justify terms
        ((eq ebnf-justify-sequence 'right)
        (ebnf-justify node seq seq-width width nil))
-       ;; centralize terms
+       ;; centralize terms -- element
+       ((vectorp seq)
+       (ebnf-adjust-width seq width))
+       ;; centralize terms -- list
        (t
        (let ((the-width (/ (- width seq-width) (length seq)))
              (lis seq))
        (t
        (let ((the-width (/ (- width seq-width) (length seq)))
              (lis seq))
@@ -4919,7 +5960,8 @@ end
   (let ((filename (ebnf-eps-filename name)))
     (if (member filename ebnf-eps-context)
        (error "Try to open an already opened EPS file: %s" filename)
   (let ((filename (ebnf-eps-filename name)))
     (if (member filename ebnf-eps-context)
        (error "Try to open an already opened EPS file: %s" filename)
-      (setq ebnf-eps-context (cons filename ebnf-eps-context)))))
+      (setq ebnf-eps-context (cons filename ebnf-eps-context)))
+    (ebnf-eps-header-footer-file filename)))
 
 
 (defun ebnf-eps-remove-context (name)
 
 
 (defun ebnf-eps-remove-context (name)
@@ -4930,14 +5972,16 @@ end
 
 
 (defun ebnf-eps-add-production (header)
 
 
 (defun ebnf-eps-add-production (header)
-  (and ebnf-eps-executing
-       ebnf-eps-context
-       (let ((prod (assoc header ebnf-eps-production-list)))
-        (if prod
-            (setcdr prod (append ebnf-eps-context (cdr prod)))
-          (setq ebnf-eps-production-list
-                (cons (cons header (ebnf-dup-list ebnf-eps-context))
-                      ebnf-eps-production-list))))))
+  (when ebnf-eps-executing
+    (if ebnf-eps-context
+       (let ((prod (assoc header ebnf-eps-production-list)))
+         (if prod
+             (setcdr prod (ebnf-dup-list
+                           (append ebnf-eps-context (cdr prod))))
+           (setq ebnf-eps-production-list
+                 (cons (cons header (ebnf-dup-list ebnf-eps-context))
+                       ebnf-eps-production-list))))
+      (ebnf-eps-header-footer-file (ebnf-eps-filename header)))))
 
 
 (defun ebnf-dup-list (old)
 
 
 (defun ebnf-dup-list (old)
@@ -4968,7 +6012,7 @@ end
      ;;(skip-chars-forward (concat chars "\240-\377") ebnf-limit)
      (skip-chars-forward (concat chars ebnf-8-bit-chars) ebnf-limit)
      (if (or (eobp) (/= (following-char) eos-char))
      ;;(skip-chars-forward (concat chars "\240-\377") ebnf-limit)
      (skip-chars-forward (concat chars ebnf-8-bit-chars) ebnf-limit)
      (if (or (eobp) (/= (following-char) eos-char))
-        (error "Illegal %s: missing `%c'" kind eos-char)
+        (error "Invalid %s: missing `%c'" kind eos-char)
        (forward-char)
        (1- (point))))))
 
        (forward-char)
        (1- (point))))))
 
@@ -4992,6 +6036,8 @@ end
 (defun ebnf-trim-right (str)
   (let* ((len   (1- (length str)))
         (index len))
 (defun ebnf-trim-right (str)
   (let* ((len   (1- (length str)))
         (index len))
+    ;; to keep compatibility with Emacs 20 & 21:
+    ;; DO NOT REPLACE `?\ ' BY `?\s'
     (while (and (> index 0) (= (aref str index) ?\ ))
       (setq index (1- index)))
     (if (= index len)
     (while (and (> index 0) (= (aref str index) ?\ ))
       (setq index (1- index)))
     (if (= index len)
@@ -5004,12 +6050,12 @@ end
 
 
 (defun ebnf-make-empty (&optional width)
 
 
 (defun ebnf-make-empty (&optional width)
-  (vector 'ebnf-generate-empty
-         'ignore
-         'ignore
-         0.0
-         0.0
-         (or width ebnf-horizontal-space)))
+  (vector 'ebnf-generate-empty         ; 0 generator
+         'ignore                       ; 1 width fun
+         'ignore                       ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         (or width ebnf-horizontal-space))) ; 5 width
 
 
 (defun ebnf-make-terminal (name)
 
 
 (defun ebnf-make-terminal (name)
@@ -5031,18 +6077,19 @@ end
 
 
 (defun ebnf-make-terminal1 (name gen-func dim-func)
 
 
 (defun ebnf-make-terminal1 (name gen-func dim-func)
-  (vector gen-func
-         'ignore
-         dim-func
-         0.0
-         0.0
-         0.0
-         (let ((len (length name)))
-           (cond ((> len 2) name)
-                 ((= len 2) (concat " " name))
-                 ((= len 1) (concat " " name " "))
-                 (t         "   ")))
-         ebnf-default-p))
+  (vector gen-func                     ; 0 generatore
+         'ignore                       ; 1 width fun
+         dim-func                      ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         (let ((len (length name)))    ; 6 name
+           (cond ((> len 3) name)
+                 ((= len 3) (concat name " "))
+                 ((= len 2) (concat " " name " "))
+                 ((= len 1) (concat " " name "  "))
+                 (t         "    ")))
+         ebnf-default-p))              ; 7 is default?
 
 
 (defun ebnf-make-one-or-more (list-part &optional sep-part)
 
 
 (defun ebnf-make-one-or-more (list-part &optional sep-part)
@@ -5060,92 +6107,104 @@ end
 
 
 (defun ebnf-make-or-more1 (gen-func dim-func list-part sep-part)
 
 
 (defun ebnf-make-or-more1 (gen-func dim-func list-part sep-part)
-  (vector gen-func
-         'ebnf-list-width
-         dim-func
-         0.0
-         0.0
-         0.0
-         (if (listp list-part)
+  (vector gen-func                     ; 0 generator
+         'ebnf-element-width           ; 1 width fun
+         dim-func                      ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         (if (listp list-part)         ; 6 element
              (ebnf-make-sequence list-part)
            list-part)
              (ebnf-make-sequence list-part)
            list-part)
-         (if (and sep-part (listp sep-part))
+         (if (and sep-part (listp sep-part)) ; 7 separator
              (ebnf-make-sequence sep-part)
            sep-part)))
 
 
 (defun ebnf-make-production (name prod action)
              (ebnf-make-sequence sep-part)
            sep-part)))
 
 
 (defun ebnf-make-production (name prod action)
-  (vector 'ebnf-generate-production
-         'ignore
-         'ebnf-production-dimension
-         0.0
-         0.0
-         0.0
-         name
-         prod
-         action))
+  (vector 'ebnf-generate-production    ; 0 generator
+         'ignore                       ; 1 width fun
+         'ebnf-production-dimension    ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         name                          ; 6 production name
+         prod                          ; 7 production body
+         action))                      ; 8 production action
 
 
 (defun ebnf-make-alternative (body)
 
 
 (defun ebnf-make-alternative (body)
-  (vector 'ebnf-generate-alternative
-         'ebnf-alternative-width
-         'ebnf-alternative-dimension
-         0.0
-         0.0
-         0.0
-         body))
+  (vector 'ebnf-generate-alternative   ; 0 generator
+         'ebnf-alternative-width       ; 1 width fun
+         'ebnf-alternative-dimension   ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         body))                        ; 6 alternative list
 
 
 (defun ebnf-make-optional (body)
 
 
 (defun ebnf-make-optional (body)
-  (vector 'ebnf-generate-optional
-         'ebnf-alternative-width
-         'ebnf-optional-dimension
-         0.0
-         0.0
-         0.0
-         body))
+  (vector 'ebnf-generate-optional      ; 0 generator
+         'ebnf-alternative-width       ; 1 width fun
+         'ebnf-optional-dimension      ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         body))                        ; 6 optional element
 
 
 (defun ebnf-make-except (factor exception)
 
 
 (defun ebnf-make-except (factor exception)
-  (vector 'ebnf-generate-except
-         'ignore
-         'ebnf-except-dimension
-         0.0
-         0.0
-         0.0
-         factor
-         exception))
-
-
-(defun ebnf-make-repeat (times primary)
-  (vector 'ebnf-generate-repeat
-         'ignore
-         'ebnf-repeat-dimension
-         0.0
-         0.0
-         0.0
-         (concat times " *")
-         primary))
+  (vector 'ebnf-generate-except                ; 0 generator
+         'ignore                       ; 1 width fun
+         'ebnf-except-dimension        ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         factor                        ; 6 base element
+         exception))                   ; 7 exception element
+
+
+(defun ebnf-make-repeat (times primary &optional upper)
+  (vector 'ebnf-generate-repeat                ; 0 generator
+         'ignore                       ; 1 width fun
+         'ebnf-repeat-dimension        ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+                                       ; 6 times
+         (cond ((and times upper)      ; L * U, L * L
+                (if (string= times upper)
+                    (if (string= times "")
+                        " * "
+                      times)
+                  (concat times " * " upper)))
+               (times                  ; L *
+                (concat times " *"))
+               (upper                  ; * U
+                (concat "* " upper))
+               (t                      ; *
+                " * "))
+         primary))                     ; 7 element
 
 
 (defun ebnf-make-sequence (seq)
 
 
 (defun ebnf-make-sequence (seq)
-  (vector 'ebnf-generate-sequence
-         'ebnf-sequence-width
-         'ebnf-sequence-dimension
-         0.0
-         0.0
-         0.0
-         seq))
+  (vector 'ebnf-generate-sequence      ; 0 generator
+         'ebnf-sequence-width          ; 1 width fun
+         'ebnf-sequence-dimension      ; 2 dimension fun
+         0.0                           ; 3 entry
+         0.0                           ; 4 height
+         0.0                           ; 5 width
+         seq))                         ; 6 sequence
 
 
 (defun ebnf-make-dup-sequence (node seq)
 
 
 (defun ebnf-make-dup-sequence (node seq)
-  (vector 'ebnf-generate-sequence
-         'ebnf-sequence-width
-         'ebnf-sequence-dimension
-          (ebnf-node-entry node)
-          (ebnf-node-height node)
-          (ebnf-node-width node)
-          seq))
+  (vector 'ebnf-generate-sequence      ; 0 generator
+         'ebnf-sequence-width          ; 1 width fun
+         'ebnf-sequence-dimension      ; 2 dimension fun
+         (ebnf-node-entry node)        ; 3 entry
+         (ebnf-node-height node)       ; 4 height
+         (ebnf-node-width node)        ; 5 width
+         seq))                         ; 6 sequence
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -5196,13 +6255,13 @@ end
                )))))
 
 
                )))))
 
 
-(defun ebnf-token-repeat (times repeat)
+(defun ebnf-token-repeat (times repeat &optional upper)
   (if (null (cdr repeat))
       ;; n * EMPTY ==> EMPTY
       repeat
     ;; n * term
     (cons (car repeat)
   (if (null (cdr repeat))
       ;; n * EMPTY ==> EMPTY
       repeat
     ;; n * term
     (cons (car repeat)
-         (ebnf-make-repeat times (cdr repeat)))))
+         (ebnf-make-repeat times (cdr repeat) upper))))
 
 
 (defun ebnf-token-optional (body)
 
 
 (defun ebnf-token-optional (body)
@@ -5232,17 +6291,35 @@ end
 (defun ebnf-token-alternative (body sequence)
   (if (null body)
       (if (cdr sequence)
 (defun ebnf-token-alternative (body sequence)
   (if (null body)
       (if (cdr sequence)
+         ;; no alternative
          sequence
          sequence
-       (cons (car sequence)
+       ;; empty element
+       (cons (car sequence)            ; token
              (ebnf-make-empty)))
              (ebnf-make-empty)))
-    (cons (car sequence)
+    (cons (car sequence)               ; token
          (let ((seq (cdr sequence)))
            (if (and (= (length body) 1) (null seq))
          (let ((seq (cdr sequence)))
            (if (and (= (length body) 1) (null seq))
+               ;; alternative with one element
                (car body)
                (car body)
+             ;; a real alternative
              (ebnf-make-alternative (nreverse (if seq
                                                   (cons seq body)
                                                 body))))))))
 
              (ebnf-make-alternative (nreverse (if seq
                                                   (cons seq body)
                                                 body))))))))
 
+
+(defun ebnf-token-sequence (sequence)
+  (cond
+   ;; null sequence
+   ((null sequence)
+    (ebnf-make-empty))
+   ;; sequence with only one element
+   ((= (length sequence) 1)
+    (car sequence))
+   ;; a real sequence
+   (t
+    (ebnf-make-sequence (nreverse sequence)))
+   ))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Variables used by parsers
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; Variables used by parsers
@@ -5253,14 +6330,43 @@ end
     ;; Override special comment character:
     (aset table ?< 'newline)
     (aset table ?> 'keep-line)
     ;; Override special comment character:
     (aset table ?< 'newline)
     (aset table ?> 'keep-line)
+    (aset table ?^ 'form-feed)
     table)
   "Vector used to map characters to a special comment token.")
 
     table)
   "Vector used to map characters to a special comment token.")
 
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Log message
+
+
+(defun ebnf-log-header (format-str &rest args)
+  (when ebnf-log
+    (apply
+     'ebnf-log
+     (concat
+      "\n\n===============================================================\n\n"
+      format-str)
+     args)))
+
+
+(defun ebnf-log (format-str &rest args)
+  (when ebnf-log
+    (save-excursion
+      (set-buffer (get-buffer-create "*Ebnf2ps Log*"))
+      (goto-char (point-max))
+      (insert (apply 'format format-str args) "\n"))))
+
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; To make this file smaller, some commands go in a separate file.
 ;; But autoload them here to make the separation invisible.
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;; To make this file smaller, some commands go in a separate file.
 ;; But autoload them here to make the separation invisible.
 
+(autoload 'ebnf-abn-parser            "ebnf-abn"
+  "ABNF parser.")
+
+(autoload 'ebnf-abn-initialize        "ebnf-abn"
+  "Initialize ABNF token table.")
+
 (autoload 'ebnf-bnf-parser            "ebnf-bnf"
   "EBNF parser.")
 
 (autoload 'ebnf-bnf-parser            "ebnf-bnf"
   "EBNF parser.")
 
@@ -5279,14 +6385,17 @@ end
 (autoload 'ebnf-yac-initialize        "ebnf-yac"
   "Initializations for Yacc/Bison parser.")
 
 (autoload 'ebnf-yac-initialize        "ebnf-yac"
   "Initializations for Yacc/Bison parser.")
 
-(autoload 'ebnf-eliminate-empty-rules "ebnf-otz"
-  "Eliminate empty rules.")
+(autoload 'ebnf-ebx-parser            "ebnf-ebx"
+  "EBNFX parser.")
 
 
-(autoload 'ebnf-optimize              "ebnf-otz"
-  "Syntactic chart optimizer.")
+(autoload 'ebnf-ebx-initialize        "ebnf-ebx"
+  "Initializations for EBNFX parser.")
 
 
-(autoload 'ebnf-otz-initialize        "ebnf-otz"
-  "Initialize optimizer.")
+(autoload 'ebnf-dtd-parser            "ebnf-dtd"
+  "DTD parser.")
+
+(autoload 'ebnf-dtd-initialize        "ebnf-dtd"
+  "Initializations for DTD parser.")
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
 \f
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -5294,4 +6403,5 @@ end
 
 (provide 'ebnf2ps)
 
 
 (provide 'ebnf2ps)
 
+;;; arch-tag: 148bc8af-5398-468b-b922-eeb7afef3e4f
 ;;; ebnf2ps.el ends here
 ;;; ebnf2ps.el ends here