changeset 27451:f062cc830f07

*** empty log message ***
author Gerd Moellmann <gerd@gnu.org>
date Thu, 27 Jan 2000 14:31:16 +0000
parents 1f69452af743
children 7580a16f676c
files lisp/ChangeLog lisp/progmodes/ebnf-bnf.el lisp/progmodes/ebnf-iso.el lisp/progmodes/ebnf-otz.el lisp/progmodes/ebnf-yac.el lisp/progmodes/ebnf2ps.el
diffstat 6 files changed, 7683 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/ChangeLog	Thu Jan 27 11:40:40 2000 +0000
+++ b/lisp/ChangeLog	Thu Jan 27 14:31:16 2000 +0000
@@ -1,3 +1,9 @@
+2000-01-27  Gerd Moellmann  <gerd@gnu.org>
+
+	* progmodes/ebnf2ps.el, progmodes/ebnf-bnf.el,
+	progmodes/ebnf-iso.el, progmodes/ebnf-otz.el,
+	progmodes/ebnf-yac.el: New files.
+
 2000-01-26  Dave Love  <fx@gnu.org>
 
 	* emacs-lisp/checkdoc.el (checkdoc-interactive-loop): Don't lose
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ebnf-bnf.el	Thu Jan 27 14:31:16 2000 +0000
@@ -0,0 +1,583 @@
+;;; ebnf-bnf --- Parser for EBNF
+
+;; Copyright (C) 1999 Vinicius Jose Latorre
+
+;; Author:     Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Keywords:   wp, ebnf, PostScript
+;; Time-stamp: <99/11/20 18:05:05 vinicius>
+;; Version:    1.4
+
+;; This file is *NOT* (yet?) part of GNU Emacs.
+
+;; This program 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)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;
+;; This is part of ebnf2ps package.
+;;
+;; This package defines a parser for EBNF.
+;;
+;; See ebnf2ps.el for documentation.
+;;
+;;
+;; EBNF Syntax
+;; -----------
+;;
+;; The current EBNF that ebnf2ps accepts has the following constructions:
+;;
+;;    ;			comment (until end of line)
+;;    A			non-terminal
+;;    "C"		terminal
+;;    ?C?		special
+;;    $A		default non-terminal
+;;    $"C"		default terminal
+;;    $?C?		default special
+;;    A = B.		production (A is the header and B the body)
+;;    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)
+;;    (C)		group (expression C is grouped together)
+;;    [C]		optional (C may or not occurs)
+;;    C+		one or more occurrences of C
+;;    {C}+		one or more occurrences of C
+;;    {C}*		zero or more occurrences of C
+;;    {C}		zero or more occurrences of C
+;;    C / D		equivalent to: C {D C}*
+;;    {C || D}+		equivalent to: C {D C}*
+;;    {C || D}*		equivalent to: [C {D C}*]
+;;    {C || D}		equivalent to: [C {D C}*]
+;;
+;; The EBNF syntax written using the notation above is:
+;;
+;;    EBNF = {production}+.
+;;
+;;    production = non_terminal "=" body ".".   ;; production
+;;
+;;    body = {sequence || "|"}*.                ;; alternative
+;;
+;;    sequence = {exception}*.                  ;; sequence
+;;
+;;    exception = repeat [ "-" repeat].         ;; exception
+;;
+;;    repeat = [ integer "*" ] term.            ;; repetition
+;;
+;;    term = factor
+;;         | [factor] "+"                       ;; one-or-more
+;;         | [factor] "/" [factor]              ;; one-or-more
+;;         .
+;;
+;;    factor = [ "$" ] "\"" terminal "\""       ;; terminal
+;;           | [ "$" ] non_terminal             ;; non-terminal
+;;           | [ "$" ] "?" special "?"          ;; special
+;;           | "(" body ")"                     ;; group
+;;           | "[" body "]"                     ;; zero-or-one
+;;           | "{" body [ "||" body ] "}+"      ;; one-or-more
+;;           | "{" body [ "||" body ] "}*"      ;; zero-or-more
+;;           | "{" body [ "||" body ] "}"       ;; zero-or-more
+;;           .
+;;
+;;    non_terminal = "[A-Za-z\\240-\\377][!#%&'*-,0-:<>@-Z\\^-z~\\240-\\377]*".
+;;
+;;    terminal = "\\([^\"\\]\\|\\\\[ -~\\240-\\377]\\)+".
+;;
+;;    special = "[^?\\n\\000-\\010\\016-\\037\\177-\\237]*".
+;;
+;;    integer = "[0-9]+".
+;;
+;;    comment = ";" "[^\\n\\000-\\010\\016-\\037\\177-\\237]*" "\\n".
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+(require 'ebnf-otz)
+
+
+(defvar ebnf-bnf-lex nil
+  "Value returned by `ebnf-bnf-lex' function.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Syntatic analyzer
+
+
+;;; EBNF = {production}+.
+
+(defun ebnf-bnf-parser (start)
+  "EBNF parser."
+  (let ((total (+ (- ebnf-limit start) 1))
+	(bias (1- start))
+	(origin (point))
+	prod-list token rule)
+    (goto-char start)
+    (setq token (ebnf-bnf-lex))
+    (and (eq token 'end-of-input)
+	 (error "Invalid EBNF file format."))
+    (while (not (eq token 'end-of-input))
+      (ebnf-message-float
+       "Parsing...%s%%"
+       (/ (* (- (point) bias) 100.0) total))
+      (setq token (ebnf-production token)
+	    rule  (cdr token)
+	    token (car token))
+      (or (ebnf-add-empty-rule-list rule)
+	  (setq prod-list (cons rule prod-list))))
+    (goto-char origin)
+    prod-list))
+
+
+;;; production = non-terminal "=" body ".".
+
+(defun ebnf-production (token)
+  (let ((header ebnf-bnf-lex)
+	(action ebnf-action)
+	body)
+    (setq ebnf-action nil)
+    (or (eq token 'non-terminal)
+	(error "Invalid header production."))
+    (or (eq (ebnf-bnf-lex) 'equal)
+	(error "Invalid production: missing `='."))
+    (setq body (ebnf-body))
+    (or (eq (car body) 'period)
+	(error "Invalid production: missing `.'."))
+    (setq body (cdr body))
+    (ebnf-eps-add-production header)
+    (cons (ebnf-bnf-lex)
+	  (ebnf-make-production header body action))))
+
+
+;;; body = {sequence || "|"}*.
+
+(defun ebnf-body ()
+  (let (body sequence)
+    (while (eq (car (setq sequence (ebnf-sequence))) 'alternative)
+      (setq sequence (cdr sequence)
+	    body     (cons sequence body)))
+    (ebnf-token-alternative body sequence)))
+
+
+;;; sequence = {exception}*.
+
+(defun ebnf-sequence ()
+  (let ((token (ebnf-bnf-lex))
+	seq term)
+    (while (setq term  (ebnf-exception token)
+		 token (car term)
+		 term  (cdr term))
+      (setq seq (cons term seq)))
+    (cons token
+	  (cond
+	   ;; null sequence
+	   ((null seq)
+	    (ebnf-make-empty))
+	   ;; sequence with only one element
+	   ((= (length seq) 1)
+	    (car seq))
+	   ;; a real sequence
+	   (t
+	    (ebnf-make-sequence (nreverse seq)))
+	   ))))
+
+
+;;; exception = repeat [ "-" repeat].
+
+(defun ebnf-exception (token)
+  (let ((term (ebnf-repeat token)))
+    (if (not (eq (car term) 'except))
+	;; repeat
+	term
+      ;; repeat - repeat
+      (let ((exception (ebnf-repeat (ebnf-bnf-lex))))
+	(ebnf-no-non-terminal (cdr exception))
+	(ebnf-token-except (cdr term) exception)))))
+
+
+(defun ebnf-no-non-terminal (node)
+  (and (vectorp node)
+       (let ((kind (ebnf-node-kind node)))
+	 (cond
+	  ((eq kind 'ebnf-generate-non-terminal)
+	   (error "Exception sequence should not contain a non-terminal."))
+	  ((eq kind 'ebnf-generate-repeat)
+	   (ebnf-no-non-terminal (ebnf-node-separator node)))
+	  ((memq kind '(ebnf-generate-optional ebnf-generate-except))
+	   (ebnf-no-non-terminal (ebnf-node-list node)))
+	  ((memq kind '(ebnf-generate-one-or-more ebnf-generate-zero-or-more))
+	   (ebnf-no-non-terminal (ebnf-node-list node))
+	   (ebnf-no-non-terminal (ebnf-node-separator node)))
+	  ((memq kind '(ebnf-generate-alternative ebnf-generate-sequence))
+	   (let ((seq (ebnf-node-list node)))
+	     (while seq
+	       (ebnf-no-non-terminal (car seq))
+	       (setq seq (cdr seq)))))
+	  ))))
+
+
+;;; repeat = [ integer "*" ] term.
+
+(defun ebnf-repeat (token)
+  (if (not (eq token 'integer))
+      (ebnf-term token)
+    (let ((times ebnf-bnf-lex))
+      (or (eq (ebnf-bnf-lex) 'repeat)
+	  (error "Missing `*'."))
+      (ebnf-token-repeat times (ebnf-term (ebnf-bnf-lex))))))
+
+
+;;; term = factor
+;;;      | [factor] "+"                       ;; one-or-more
+;;;      | [factor] "/" [factor]              ;; one-or-more
+;;;      .
+
+(defun ebnf-term (token)
+  (let ((factor (ebnf-factor token)))
+    (and factor
+	 (setq token (ebnf-bnf-lex)))
+    (cond
+     ;; [factor] +
+     ((eq token 'one-or-more)
+      (cons (ebnf-bnf-lex)
+	    (and factor
+		 (let ((kind (ebnf-node-kind factor)))
+		   (cond
+		    ;; { A }+ + ==> { A }+
+		    ;; { A }* + ==> { A }*
+		    ((memq kind '(ebnf-generate-zero-or-more
+				  ebnf-generate-one-or-more))
+		     factor)
+		    ;; [ A ] + ==> { A }*
+		    ((eq kind 'ebnf-generate-optional)
+		     (ebnf-make-zero-or-more (list factor)))
+		    ;; A +
+		    (t
+		     (ebnf-make-one-or-more (list factor)))
+		    )))))
+     ;; [factor] / [factor]
+     ((eq token 'list)
+      (setq token (ebnf-bnf-lex))
+      (let ((sep (ebnf-factor token)))
+	(and sep
+	     (setq factor (or factor (ebnf-make-empty))))
+	(cons (if sep
+		  (ebnf-bnf-lex)
+		token)
+	      (and factor
+		   (ebnf-make-one-or-more factor sep)))))
+     ;; factor
+     (t
+      (cons token factor))
+     )))
+
+
+;;; factor = [ "$" ] "\"" terminal "\""         ;; terminal
+;;;        | [ "$" ] non_terminal               ;; non-terminal
+;;;        | [ "$" ] "?" special "?"            ;; special
+;;;        | "(" body ")"                       ;; group
+;;;        | "[" body "]"                       ;; zero-or-one
+;;;        | "{" body [ "||" body ] "}+"        ;; one-or-more
+;;;        | "{" body [ "||" body ] "}*"        ;; zero-or-more
+;;;        | "{" body [ "||" body ] "}"         ;; zero-or-more
+;;;        .
+
+(defun ebnf-factor (token)
+  (cond
+   ;; terminal
+   ((eq token 'terminal)
+    (ebnf-make-terminal ebnf-bnf-lex))
+   ;; non-terminal
+   ((eq token 'non-terminal)
+    (ebnf-make-non-terminal ebnf-bnf-lex))
+   ;; special
+   ((eq token 'special)
+    (ebnf-make-special ebnf-bnf-lex))
+   ;; group
+   ((eq token 'begin-group)
+    (let ((body (ebnf-body)))
+      (or (eq (car body) 'end-group)
+	  (error "Missing `)'."))
+      (cdr body)))
+   ;; optional
+   ((eq token 'begin-optional)
+    (let ((body (ebnf-body)))
+      (or (eq (car body) 'end-optional)
+	  (error "Missing `]'."))
+      (ebnf-token-optional (cdr body))))
+   ;; list
+   ((eq token 'begin-list)
+    (let* ((body      (ebnf-body))
+	   (token     (car body))
+	   (list-part (cdr body))
+	   sep-part)
+      (and (eq token 'list-separator)
+	   ;; { A || B }
+	   (setq body     (ebnf-body)	; get separator
+		 token    (car body)
+		 sep-part (cdr body)))
+      (cond
+       ;; { A }+
+       ((eq token 'end-one-or-more)
+	(ebnf-make-one-or-more list-part sep-part))
+       ;; { A }*
+       ((eq token 'end-zero-or-more)
+	(ebnf-make-zero-or-more list-part sep-part))
+       (t
+	(error "Missing `}+', `}*' or `}'."))
+       )))
+   ;; no term
+   (t
+    nil)
+   ))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lexical analyzer
+
+
+(defconst ebnf-bnf-token-table (make-vector 256 'error)
+  "Vector used to map characters to a lexical token.")
+
+
+(defun ebnf-bnf-initialize ()
+  "Initialize EBNF token table."
+  ;; control character & control 8-bit character are set to `error'
+  (let ((char ?\040))
+    ;; printable character:
+    (while (< char ?\060)
+      (aset ebnf-bnf-token-table char 'non-terminal)
+      (setq char (1+ char)))
+    ;; digits:
+    (while (< char ?\072)
+      (aset ebnf-bnf-token-table char 'integer)
+      (setq char (1+ char)))
+    ;; printable character:
+    (while (< char ?\177)
+      (aset ebnf-bnf-token-table char 'non-terminal)
+      (setq char (1+ char)))
+    ;; European 8-bit accentuated characters:
+    (setq char ?\240)
+    (while (< char ?\400)
+      (aset ebnf-bnf-token-table char 'non-terminal)
+      (setq char (1+ char)))
+    ;; Override space characters:
+    (aset ebnf-bnf-token-table ?\013 'space) ; [VT] vertical tab
+    (aset ebnf-bnf-token-table ?\n   'space) ; [NL] linefeed
+    (aset ebnf-bnf-token-table ?\r   'space) ; [CR] carriage return
+    (aset ebnf-bnf-token-table ?\t   'space) ; [HT] horizontal tab
+    (aset ebnf-bnf-token-table ?\    'space) ; [SP] space
+    ;; Override form feed character:
+    (aset ebnf-bnf-token-table ?\f 'form-feed) ; [FF] form feed
+    ;; Override other lexical characters:
+    (aset ebnf-bnf-token-table ?\" 'terminal)
+    (aset ebnf-bnf-token-table ?\? 'special)
+    (aset ebnf-bnf-token-table ?\( 'begin-group)
+    (aset ebnf-bnf-token-table ?\) 'end-group)
+    (aset ebnf-bnf-token-table ?*  'repeat)
+    (aset ebnf-bnf-token-table ?-  'except)
+    (aset ebnf-bnf-token-table ?=  'equal)
+    (aset ebnf-bnf-token-table ?\[ 'begin-optional)
+    (aset ebnf-bnf-token-table ?\] 'end-optional)
+    (aset ebnf-bnf-token-table ?\{ 'begin-list)
+    (aset ebnf-bnf-token-table ?|  'alternative)
+    (aset ebnf-bnf-token-table ?\} 'end-list)
+    (aset ebnf-bnf-token-table ?/  'list)
+    (aset ebnf-bnf-token-table ?+  'one-or-more)
+    (aset ebnf-bnf-token-table ?$  'default)
+    ;; Override comment character:
+    (aset ebnf-bnf-token-table ebnf-lex-comment-char 'comment)
+    ;; Override end of production character:
+    (aset ebnf-bnf-token-table ebnf-lex-eop-char     'period)))
+
+
+(defun ebnf-bnf-lex ()
+  "Lexical analyser for EBNF.
+
+Return a lexical token.
+
+See documentation for variable `ebnf-bnf-lex'."
+  (if (>= (point) ebnf-limit)
+      'end-of-input
+    (let (token)
+      ;; skip spaces and comments
+      (while (if (> (following-char) 255)
+		 (progn
+		   (setq token 'error)
+		   nil)
+	       (setq token (aref ebnf-bnf-token-table (following-char)))
+	       (cond
+		((eq token 'space)
+		 (skip-chars-forward " \013\n\r\t" ebnf-limit)
+		 (< (point) ebnf-limit))
+		((eq token 'comment)
+		 (ebnf-bnf-skip-comment))
+		((eq token 'form-feed)
+		 (forward-char)
+		 (setq ebnf-action 'form-feed))
+		(t nil)
+		)))
+      (setq ebnf-default-p nil)
+      (cond
+       ;; end of input
+       ((>= (point) ebnf-limit)
+	'end-of-input)
+       ;; error
+       ((eq token 'error)
+	(error "Illegal character."))
+       ;; default
+       ((eq token 'default)
+	(forward-char)
+	(if (memq (aref ebnf-bnf-token-table (following-char))
+		  '(terminal non-terminal special))
+	    (prog1
+		(ebnf-bnf-lex)
+	      (setq ebnf-default-p t))
+	  (error "Illegal `default' element.")))
+       ;; integer
+       ((eq token 'integer)
+	(setq ebnf-bnf-lex (ebnf-buffer-substring "0-9"))
+	'integer)
+       ;; special: ?special?
+       ((eq token 'special)
+	(setq ebnf-bnf-lex (concat "?"
+				   (ebnf-string " ->@-~" ?\? "special")
+				   "?"))
+	'special)
+       ;; terminal: "string"
+       ((eq token 'terminal)
+	(setq ebnf-bnf-lex (ebnf-unescape-string (ebnf-get-string)))
+	'terminal)
+       ;; non-terminal or terminal
+       ((eq token 'non-terminal)
+	(setq ebnf-bnf-lex (ebnf-buffer-substring
+			    "!#%&'*-,0-:<>@-Z\\^-z~\240-\377"))
+	(let ((case-fold-search ebnf-case-fold-search)
+	      match)
+	  (if (and ebnf-terminal-regexp
+		   (setq match (string-match ebnf-terminal-regexp
+					     ebnf-bnf-lex))
+		   (zerop match)
+		   (= (match-end 0) (length ebnf-bnf-lex)))
+	      'terminal
+	    'non-terminal)))
+       ;; end of list: }+, }*, }
+       ((eq token 'end-list)
+	(forward-char)
+	(cond
+	 ((= (following-char) ?+)
+	  (forward-char)
+	  'end-one-or-more)
+	 ((= (following-char) ?*)
+	  (forward-char)
+	  'end-zero-or-more)
+	 (t
+	  'end-zero-or-more)
+	 ))
+       ;; alternative: |, ||
+       ((eq token 'alternative)
+	(forward-char)
+	(if (/= (following-char) ?|)
+	    'alternative
+	  (forward-char)
+	  'list-separator))
+       ;; miscellaneous: {, (, ), [, ], ., =, /, +, -, *
+       (t
+	(forward-char)
+	token)
+       ))))
+
+
+(defconst ebnf-bnf-comment-chars "^\n\000-\010\016-\037\177-\237")
+
+
+(defun ebnf-bnf-skip-comment ()
+  (forward-char)
+  (cond
+   ;; open EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\[))
+    (ebnf-eps-add-context (ebnf-bnf-eps-filename)))
+   ;; close EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\]))
+    (ebnf-eps-remove-context (ebnf-bnf-eps-filename)))
+   ;; any other action in comment
+   (t
+    (setq ebnf-action (aref ebnf-comment-table (following-char)))
+    (skip-chars-forward ebnf-bnf-comment-chars ebnf-limit))
+   )
+  ;; check for a valid end of comment
+  (cond ((>= (point) ebnf-limit)
+	 nil)
+	((= (following-char) ?\n)
+	 (forward-char)
+	 t)
+	(t
+	 (error "Illegal character."))
+	))
+
+
+(defun ebnf-bnf-eps-filename ()
+  (forward-char)
+  (ebnf-buffer-substring ebnf-bnf-comment-chars))
+
+
+(defun ebnf-unescape-string (str)
+  (let* ((len (length str))
+	 (size (1- len))
+	 (istr 0)
+	 (n-esc 0))
+    ;; count number of escapes
+    (while (< istr size)
+      (setq istr (+ istr
+		    (if (= (aref str istr) ?\\)
+			(progn
+			  (setq n-esc (1+ n-esc))
+			  2)
+		      1))))
+    (if (zerop n-esc)
+	;; no escapes
+	str
+      ;; at least one escape
+      (let ((new (make-string (- len n-esc) ?\ ))
+	    (inew 0))
+	;; eliminate all escapes
+	(setq istr 0)
+	(while (> n-esc 0)
+	  (and (= (aref str istr) ?\\)
+	       (setq istr  (1+ istr)
+		     n-esc (1- n-esc)))
+	  (aset new inew (aref str istr))
+	  (setq inew (1+ inew)
+		istr (1+ istr)))
+	;; remaining string has no escape
+	(while (< istr len)
+	  (aset new inew (aref str istr))
+	  (setq inew (1+ inew)
+		istr (1+ istr)))
+	new))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'ebnf-bnf)
+
+
+;;; ebnf-bnf.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ebnf-iso.el	Thu Jan 27 14:31:16 2000 +0000
@@ -0,0 +1,607 @@
+;;; ebnf-iso --- Parser for ISO EBNF
+
+;; Copyright (C) 1999 Vinicius Jose Latorre
+
+;; Author:     Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Keywords:   wp, ebnf, PostScript
+;; Time-stamp: <99/11/20 18:04:11 vinicius>
+;; Version:    1.4
+
+;; This file is *NOT* (yet?) part of GNU Emacs.
+
+;; This program 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)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;
+;; This is part of ebnf2ps package.
+;;
+;; This package defines a parser for ISO EBNF.
+;;
+;; See ebnf2ps.el for documentation.
+;;
+;;
+;; ISO EBNF Syntax
+;; ---------------
+;;
+;;	See the URL:
+;;	`http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
+;;	("International Standard of the ISO EBNF Notation").
+;;
+;;
+;; ISO EBNF = syntax rule, {syntax rule};
+;;
+;; syntax rule = meta identifier, '=', definition list, ';';
+;;
+;; definition list = single definition, {'|', single definition};
+;;
+;; single definition = term, {',', term};
+;;
+;; term = factor, ['-', exception];
+;;
+;; exception = factor (* without <meta identifier> *);
+;;
+;; factor = [integer, '*'], primary;
+;;
+;; primary = optional sequence | repeated sequence | special sequence
+;;         | grouped sequence | meta identifier | terminal string
+;;         | empty;
+;;
+;; empty = ;
+;;
+;; optional sequence = '[', definition list, ']';
+;;
+;; repeated sequence = '{', definition list, '}';
+;;
+;; grouped sequence = '(', definition list, ')';
+;;
+;; terminal string = "'", character - "'", {character - "'"}, "'"
+;;                 | '"', character - '"', {character - '"'}, '"';
+;;
+;; special sequence = '?', {character - '?'}, '?';
+;;
+;; meta identifier = letter, { letter | decimal digit | ' ' };
+;;
+;; integer = decimal digit, {decimal digit};
+;;
+;; comment = '(*', {comment symbol}, '*)';
+;;
+;; comment symbol = comment (* <== NESTED COMMENT *)
+;;                | terminal string | special sequence | character;
+;;
+;; letter = ? A-Z a-z ?;
+;;
+;; decimal digit = ? 0-9 ?;
+;;
+;; character = letter | decimal digit
+;;           | ',' | '=' | '|' | '/' | '!' | '*' | '(' | ')' | '[' | ']' | '{'
+;;           | '}' | "'" | '"' | '?' | '-' | ';' | '.' | ' ' | ':' | '+' | '_'
+;;           | '%' | '@' | '&' | '#' | '$' | '<' | '>' | '\' | '^' | '`' | '~';
+;;
+;;
+;; There is also the following alternative representation:
+;;
+;; STANDARD   ALTERNATIVE
+;;    |    ==>   / or !
+;;    [    ==>   (/
+;;    ]    ==>   /)
+;;    {    ==>   (:
+;;    }    ==>   :)
+;;    ;    ==>   .
+;;
+;;
+;; Differences Between ISO EBNF And ebnf2ps ISO EBNF
+;; -------------------------------------------------
+;;
+;; ISO EBNF accepts the characters given by <character> production above,
+;; HORIZONTAL TAB (^I), VERTICAL TAB (^K), NEWLINE (^J or ^M) and FORM FEED
+;; (^L), any other characters are illegal.  But ebnf2ps accepts also the
+;; european 8-bit accentuated characters (from \240 to \377).
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+(require 'ebnf-otz)
+
+
+(defvar ebnf-iso-lex nil
+  "Value returned by `ebnf-iso-lex' function.")
+
+
+(defconst ebnf-no-meta-identifier nil)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Syntatic analyzer
+
+
+;;; ISO EBNF = syntax rule, {syntax rule};
+
+(defun ebnf-iso-parser (start)
+  "ISO EBNF parser."
+  (let ((total (+ (- ebnf-limit start) 1))
+	(bias (1- start))
+	(origin (point))
+	syntax-list token rule)
+    (goto-char start)
+    (setq token (ebnf-iso-lex))
+    (and (eq token 'end-of-input)
+	 (error "Invalid ISO EBNF file format."))
+    (while (not (eq token 'end-of-input))
+      (ebnf-message-float
+       "Parsing...%s%%"
+       (/ (* (- (point) bias) 100.0) total))
+      (setq token (ebnf-iso-syntax-rule token)
+	    rule  (cdr token)
+	    token (car token))
+      (or (ebnf-add-empty-rule-list rule)
+	  (setq syntax-list (cons rule syntax-list))))
+    (goto-char origin)
+    syntax-list))
+
+
+;;; syntax rule = meta identifier, '=', definition list, ';';
+
+(defun ebnf-iso-syntax-rule (token)
+  (let ((header ebnf-iso-lex)
+	(action ebnf-action)
+	body)
+    (setq ebnf-action nil)
+    (or (eq token 'non-terminal)
+	(error "Invalid meta identifier syntax rule."))
+    (or (eq (ebnf-iso-lex) 'equal)
+	(error "Invalid syntax rule: missing `='."))
+    (setq body (ebnf-iso-definition-list))
+    (or (eq (car body) 'period)
+	(error "Invalid syntax rule: missing `;' or `.'."))
+    (setq body (cdr body))
+    (ebnf-eps-add-production header)
+    (cons (ebnf-iso-lex)
+	  (ebnf-make-production header body action))))
+
+
+;;; definition list = single definition, {'|', single definition};
+
+(defun ebnf-iso-definition-list ()
+  (let (body sequence)
+    (while (eq (car (setq sequence (ebnf-iso-single-definition)))
+	       'alternative)
+      (setq sequence (cdr sequence)
+	    body     (cons sequence body)))
+    (ebnf-token-alternative body sequence)))
+
+
+;;; single definition = term, {',', term};
+
+(defun ebnf-iso-single-definition ()
+  (let (token seq term)
+    (while (and (setq term  (ebnf-iso-term (ebnf-iso-lex))
+		      token (car term)
+		      term  (cdr term))
+		(eq token 'catenate))
+      (setq seq (cons term seq)))
+    (cons token
+	  (cond
+	   ;; null sequence
+	   ((null seq)
+	    term)
+	   ;; sequence with only one element
+	   ((and (null term) (= (length seq) 1))
+	    (car seq))
+	   ;; a real sequence
+	   (t
+	    (ebnf-make-sequence (nreverse (cons term seq))))
+	   ))))
+
+
+;;; term = factor, ['-', exception];
+;;;
+;;; exception = factor (* without <meta identifier> *);
+
+(defun ebnf-iso-term (token)
+  (let ((factor (ebnf-iso-factor token)))
+    (if (not (eq (car factor) 'except))
+	;; factor
+	factor
+      ;; factor - exception
+      (let ((ebnf-no-meta-identifier t))
+	(ebnf-token-except (cdr factor) (ebnf-iso-factor (ebnf-iso-lex)))))))
+
+
+;;; factor = [integer, '*'], primary;
+
+(defun ebnf-iso-factor (token)
+  (if (eq token 'integer)
+      (let ((times ebnf-iso-lex))
+	(or (eq (ebnf-iso-lex) 'repeat)
+	    (error "Missing `*'."))
+	(ebnf-token-repeat times (ebnf-iso-primary (ebnf-iso-lex))))
+    (ebnf-iso-primary token)))
+
+
+;;; primary = optional sequence | repeated sequence | special sequence
+;;;         | grouped sequence | meta identifier | terminal string
+;;;         | empty;
+;;;
+;;; empty = ;
+;;;
+;;; optional sequence = '[', definition list, ']';
+;;;
+;;; repeated sequence = '{', definition list, '}';
+;;;
+;;; grouped sequence = '(', definition list, ')';
+;;;
+;;; terminal string = "'", character - "'", {character - "'"}, "'"
+;;;                 | '"', character - '"', {character - '"'}, '"';
+;;;
+;;; special sequence = '?', {character - '?'}, '?';
+;;;
+;;; meta identifier = letter, {letter | decimal digit};
+
+(defun ebnf-iso-primary (token)
+  (let ((primary
+	 (cond
+	  ;; terminal string
+	  ((eq token 'terminal)
+	   (ebnf-make-terminal ebnf-iso-lex))
+	  ;; meta identifier
+	  ((eq token 'non-terminal)
+	   (ebnf-make-non-terminal ebnf-iso-lex))
+	  ;; special sequence
+	  ((eq token 'special)
+	   (ebnf-make-special ebnf-iso-lex))
+	  ;; grouped sequence
+	  ((eq token 'begin-group)
+	   (let ((body (ebnf-iso-definition-list)))
+	     (or (eq (car body) 'end-group)
+		 (error "Missing `)'."))
+	     (cdr body)))
+	  ;; optional sequence
+	  ((eq token 'begin-optional)
+	   (let ((body (ebnf-iso-definition-list)))
+	     (or (eq (car body) 'end-optional)
+		 (error "Missing `]' or `/)'."))
+	     (ebnf-token-optional (cdr body))))
+	  ;; repeated sequence
+	  ((eq token 'begin-zero-or-more)
+	   (let* ((body   (ebnf-iso-definition-list))
+		  (repeat (cdr body)))
+	     (or (eq (car body) 'end-zero-or-more)
+		 (error "Missing `}' or `:)'."))
+	     (ebnf-make-zero-or-more repeat)))
+	  ;; empty
+	  (t
+	   nil)
+	  )))
+    (cons (if primary
+	      (ebnf-iso-lex)
+	    token)
+	  primary)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lexical analyzer
+
+
+(defconst ebnf-iso-token-table
+  ;; control character & 8-bit character are set to `error'
+  (let ((table (make-vector 256 'error))
+	(char ?\040))
+    ;; printable character
+    (while (< char ?\060)
+      (aset table char 'character)
+      (setq char (1+ char)))
+    ;; digits:
+    (while (< char ?\072)
+      (aset table char 'integer)
+      (setq char (1+ char)))
+    (while (< char ?\101)
+      (aset table char 'character)
+      (setq char (1+ char)))
+    ;; upper case letters:
+    (while (< char ?\133)
+      (aset table char 'non-terminal)
+      (setq char (1+ char)))
+    (while (< char ?\141)
+      (aset table char 'character)
+      (setq char (1+ char)))
+    ;; lower case letters:
+    (while (< char ?\173)
+      (aset table char 'non-terminal)
+      (setq char (1+ char)))
+    (while (< char ?\177)
+      (aset table char 'character)
+      (setq char (1+ char)))
+    ;; European 8-bit accentuated characters:
+    (setq char ?\240)
+    (while (< char ?\400)
+      (aset table char 'non-terminal)
+      (setq char (1+ char)))
+    ;; Override space characters:
+    (aset table ?\013 'space)		; [VT] vertical tab
+    (aset table ?\n   'space)		; [NL] linefeed
+    (aset table ?\r   'space)		; [CR] carriage return
+    (aset table ?\t   'space)		; [HT] horizontal tab
+    (aset table ?\    'space)		; [SP] space
+    ;; Override form feed character:
+    (aset table ?\f 'form-feed)		; [FF] form feed
+    ;; Override other lexical characters:
+    (aset table ?\" 'double-terminal)
+    (aset table ?\' 'single-terminal)
+    (aset table ?\? 'special)
+    (aset table ?*  'repeat)
+    (aset table ?,  'catenate)
+    (aset table ?-  'except)
+    (aset table ?=  'equal)
+    (aset table ?\) 'end-group)
+    table)
+  "Vector used to map characters to a lexical token.")
+
+
+(defun ebnf-iso-initialize ()
+  "Initialize ISO EBNF token table."
+  (if ebnf-iso-alternative-p
+      ;; Override alternative lexical characters:
+      (progn
+	(aset ebnf-iso-token-table ?\( 'left-parenthesis)
+	(aset ebnf-iso-token-table ?\[ 'character)
+	(aset ebnf-iso-token-table ?\] 'character)
+	(aset ebnf-iso-token-table ?\{ 'character)
+	(aset ebnf-iso-token-table ?\} 'character)
+	(aset ebnf-iso-token-table ?|  'character)
+	(aset ebnf-iso-token-table ?\; 'character)
+	(aset ebnf-iso-token-table ?/  'slash)
+	(aset ebnf-iso-token-table ?!  'alternative)
+	(aset ebnf-iso-token-table ?:  'colon)
+	(aset ebnf-iso-token-table ?.  'period))
+    ;; Override standard lexical characters:
+    (aset ebnf-iso-token-table ?\( 'begin-parenthesis)
+    (aset ebnf-iso-token-table ?\[ 'begin-optional)
+    (aset ebnf-iso-token-table ?\] 'end-optional)
+    (aset ebnf-iso-token-table ?\{ 'begin-zero-or-more)
+    (aset ebnf-iso-token-table ?\} 'end-zero-or-more)
+    (aset ebnf-iso-token-table ?|  'alternative)
+    (aset ebnf-iso-token-table ?\; 'period)
+    (aset ebnf-iso-token-table ?/  'character)
+    (aset ebnf-iso-token-table ?!  'character)
+    (aset ebnf-iso-token-table ?:  'character)
+    (aset ebnf-iso-token-table ?.  'character)))
+
+
+(defun ebnf-iso-lex ()
+  "Lexical analyser for ISO EBNF.
+
+Return a lexical token.
+
+See documentation for variable `ebnf-iso-lex'."
+  (if (>= (point) ebnf-limit)
+      'end-of-input
+    (let (token)
+      ;; skip spaces and comments
+      (while (if (> (following-char) 255)
+		 (progn
+		   (setq token 'error)
+		   nil)
+	       (setq token (aref ebnf-iso-token-table (following-char)))
+	       (cond
+		((eq token 'space)
+		 (skip-chars-forward " \013\n\r\t" ebnf-limit)
+		 (< (point) ebnf-limit))
+		((or (eq token 'begin-parenthesis)
+		     (eq token 'left-parenthesis))
+		 (forward-char)
+		 (if (/= (following-char) ?*)
+		     ;; no comment
+		     nil
+		   ;; comment
+		   (ebnf-iso-skip-comment)
+		   t))
+		((eq token 'form-feed)
+		 (forward-char)
+		 (setq ebnf-action 'form-feed))
+		(t nil)
+		)))
+      (cond
+       ;; end of input
+       ((>= (point) ebnf-limit)
+	'end-of-input)
+       ;; error
+       ((eq token 'error)
+	(error "Illegal character."))
+       ;; integer
+       ((eq token 'integer)
+	(setq ebnf-iso-lex (ebnf-buffer-substring "0-9"))
+	'integer)
+       ;; special: ?special?
+       ((eq token 'special)
+	(setq ebnf-iso-lex (concat "?"
+				   (ebnf-string " ->@-~" ?\? "special")
+				   "?"))
+	'special)
+       ;; terminal: "string"
+       ((eq token 'double-terminal)
+	(setq ebnf-iso-lex (ebnf-string " !#-~" ?\" "terminal"))
+	'terminal)
+       ;; terminal: 'string'
+       ((eq token 'single-terminal)
+	(setq ebnf-iso-lex (ebnf-string " -&(-~" ?\' "terminal"))
+	'terminal)
+       ;; non-terminal
+       ((eq token 'non-terminal)
+	(setq ebnf-iso-lex (ebnf-iso-normalize
+			    (ebnf-trim-right
+			     (ebnf-buffer-substring " 0-9A-Za-z\240-\377"))))
+	(and ebnf-no-meta-identifier
+	     (error "Exception sequence should not contain a meta identifier."))
+	'non-terminal)
+       ;; begin optional, begin list or begin group
+       ((eq token 'left-parenthesis)
+	(forward-char)
+	(cond ((= (following-char) ?/)
+	       (forward-char)
+	       'begin-optional)
+	      ((= (following-char) ?:)
+	       (forward-char)
+	       'begin-zero-or-more)
+	      (t
+	       'begin-group)
+	      ))
+       ;; end optional or alternative
+       ((eq token 'slash)
+	(forward-char)
+	(if (/= (following-char) ?\))
+	    'alternative
+	  (forward-char)
+	  'end-optional))
+       ;; end list
+       ((eq token 'colon)
+	(forward-char)
+	(if (/= (following-char) ?\))
+	    'character
+	  (forward-char)
+	  'end-zero-or-more))
+       ;; begin group
+       ((eq token 'begin-parenthesis)
+	'begin-group)
+       ;; miscellaneous
+       (t
+	(forward-char)
+	token)
+       ))))
+
+
+(defconst ebnf-iso-comment-chars "^*(\000-\010\016-\037\177-\237")
+
+
+(defun ebnf-iso-skip-comment ()
+  (forward-char)
+  (cond
+   ;; open EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\[))
+    (ebnf-eps-add-context (ebnf-iso-eps-filename)))
+   ;; close EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\]))
+    (ebnf-eps-remove-context (ebnf-iso-eps-filename)))
+   ;; any other action in comment
+   (t
+    (setq ebnf-action (aref ebnf-comment-table (following-char))))
+   )
+  (let ((pair 1))
+    (while (> pair 0)
+      (skip-chars-forward ebnf-iso-comment-chars ebnf-limit)
+      (cond ((>= (point) ebnf-limit)
+	     (error "Missing end of comment: `*)'."))
+	    ((= (following-char) ?*)
+	     (skip-chars-forward "*" ebnf-limit)
+	     (when (= (following-char) ?\))
+	       ;; end of comment
+	       (forward-char)
+	       (setq pair (1- pair))))
+	    ((= (following-char) ?\()
+	     (skip-chars-forward "(" ebnf-limit)
+	     (when (= (following-char) ?*)
+	       ;; beginning of comment
+	       (forward-char)
+	       (setq pair (1+ pair))))
+	    (t
+	     (error "Illegal character."))
+	    ))))
+
+
+(defun ebnf-iso-eps-filename ()
+  (forward-char)
+  (buffer-substring-no-properties
+   (point)
+   (let ((chars (concat ebnf-iso-comment-chars "\n"))
+	 found)
+     (while (not found)
+       (skip-chars-forward chars ebnf-limit)
+       (setq found
+	     (cond ((>= (point) ebnf-limit)
+		    (point))
+		   ((= (following-char) ?*)
+		    (skip-chars-forward "*" ebnf-limit)
+		    (if (/= (following-char) ?\))
+			nil
+		      (backward-char)
+		      (point)))
+		   ((= (following-char) ?\()
+		    (forward-char)
+		    (if (/= (following-char) ?*)
+			nil
+		      (backward-char)
+		      (point)))
+		   (t
+		    (point))
+		   )))
+     found)))
+
+
+(defun ebnf-iso-normalize (str)
+  (if (not ebnf-iso-normalize-p)
+      str
+    (let ((len (length str))
+	  (stri 0)
+	  (spaces 0))
+      ;; count exceeding spaces
+      (while (< stri len)
+	(if (/= (aref str stri) ?\ )
+	    (setq stri (1+ stri))
+	  (setq stri (1+ stri))
+	  (while (and (< stri len) (= (aref str stri) ?\ ))
+	    (setq stri   (1+ stri)
+		  spaces (1+ spaces)))))
+      (if (zerop spaces)
+	  ;; no exceeding space
+	  str
+	;; at least one exceeding space
+	(let ((new (make-string (- len spaces) ?\ ))
+	      (newi 0))
+	  ;; eliminate exceeding spaces
+	  (setq stri 0)
+	  (while (> spaces 0)
+	    (if (/= (aref str stri) ?\ )
+		(progn
+		  (aset new newi (aref str stri))
+		  (setq stri (1+ stri)
+			newi (1+ newi)))
+	      (aset new newi (aref str stri))
+	      (setq stri (1+ stri)
+		    newi (1+ newi))
+	      (while (and (> spaces 0) (= (aref str stri) ?\ ))
+		(setq stri   (1+ stri)
+		      spaces (1- spaces)))))
+	  ;; remaining is normalized
+	  (while (< stri len)
+	    (aset new newi (aref str stri))
+	    (setq stri (1+ stri)
+		  newi (1+ newi)))
+	  new)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'ebnf-iso)
+
+
+;;; ebnf-iso.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ebnf-otz.el	Thu Jan 27 14:31:16 2000 +0000
@@ -0,0 +1,661 @@
+;;; ebnf-otz --- Syntatic chart OpTimiZer
+
+;; Copyright (C) 1999 Vinicius Jose Latorre
+
+;; Author:     Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Keywords:   wp, ebnf, PostScript
+;; Time-stamp: <99/11/20 18:03:10 vinicius>
+;; Version:    1.0
+
+;; This file is *NOT* (yet?) part of GNU Emacs.
+
+;; This program 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)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;
+;; This is part of ebnf2ps package.
+;;
+;; This package defines an optimizer for ebnf2ps.
+;;
+;; See ebnf2ps.el for documentation.
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+(require 'ebnf2ps)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(defvar ebnf-empty-rule-list nil
+  "List of empty rule name.")
+
+
+(defun ebnf-add-empty-rule-list (rule)
+  "Add empty RULE in `ebnf-empty-rule-list'."
+  (and ebnf-ignore-empty-rule
+       (eq (ebnf-node-kind (ebnf-node-production rule))
+	   'ebnf-generate-empty)
+       (setq ebnf-empty-rule-list (cons (ebnf-node-name rule)
+					ebnf-empty-rule-list))))
+
+
+(defun ebnf-otz-initialize ()
+  "Initialize optimizer."
+  (setq ebnf-empty-rule-list nil))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Eliminate empty rules
+
+
+(defun ebnf-eliminate-empty-rules (syntax-list)
+  "Eliminate empty rules."
+  (while ebnf-empty-rule-list
+    (let ((ebnf-total (length syntax-list))
+	  (ebnf-nprod 0)
+	  (prod-list syntax-list)
+	  new-list before)
+      (while prod-list
+	(ebnf-message-info "Eliminating empty rules")
+	(let ((rule (car prod-list)))
+	  ;; if any non-terminal pertains to ebnf-empty-rule-list
+	  ;; then eliminate non-terminal from rule
+	  (if (ebnf-eliminate-empty rule)
+	      (setq before prod-list)
+	    ;; eliminate empty rule from syntax-list
+	    (setq new-list (cons (ebnf-node-name rule) new-list))
+	    (if before
+		(setcdr before (cdr prod-list))
+	      (setq syntax-list (cdr syntax-list)))))
+	(setq prod-list (cdr prod-list)))
+      (setq ebnf-empty-rule-list new-list)))
+  syntax-list)
+
+
+;; [production   width-func entry height width name production action]
+;; [sequence     width-func entry height width list]
+;; [alternative  width-func entry height width list]
+;; [non-terminal width-func entry height width name default]
+;; [empty        width-func entry height width]
+;; [terminal     width-func entry height width name default]
+;; [special      width-func entry height width name default]
+
+(defun ebnf-eliminate-empty (rule)
+  (let ((kind (ebnf-node-kind rule)))
+    (cond
+     ;; non-terminal
+     ((eq kind 'ebnf-generate-non-terminal)
+      (if (member (ebnf-node-name rule) ebnf-empty-rule-list)
+	  nil
+	rule))
+     ;; sequence
+     ((eq kind 'ebnf-generate-sequence)
+      (let ((seq    (ebnf-node-list rule))
+	    (header (ebnf-node-list rule))
+	    before elt)
+	(while seq
+	  (setq elt (car seq))
+	  (if (ebnf-eliminate-empty elt)
+	      (setq before seq)
+	    (if before
+		(setcdr before (cdr seq))
+	      (setq header (cdr header))))
+	  (setq seq (cdr seq)))
+	(when header
+	  (ebnf-node-list rule header)
+	  rule)))
+     ;; alternative
+     ((eq kind 'ebnf-generate-alternative)
+      (let ((seq    (ebnf-node-list rule))
+	    (header (ebnf-node-list rule))
+	    before elt)
+	(while seq
+	  (setq elt (car seq))
+	  (if (ebnf-eliminate-empty elt)
+	      (setq before seq)
+	    (if before
+		(setcdr before (cdr seq))
+	      (setq header (cdr header))))
+	  (setq seq (cdr seq)))
+	(when header
+	  (if (= (length header) 1)
+	      (car header)
+	    (ebnf-node-list rule header)
+	    rule))))
+     ;; production
+     ((eq kind 'ebnf-generate-production)
+      (let ((prod (ebnf-eliminate-empty (ebnf-node-production rule))))
+	(when prod
+	  (ebnf-node-production rule prod)
+	  rule)))
+     ;; terminal, special and empty
+     (t
+      rule)
+     )))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Optimizations
+
+
+;; *To be implemented*:
+;;    left recursion:
+;;    A = B | A C B | A C D.   ==>   A = B {C (B | D)}*.
+
+;;    right recursion:
+;;    A = B | C A.             ==>   A = {C}* B.
+;;    A = B | D | C A | E A.   ==>   A = { C | E }* ( B | D ).
+
+;;    optional:
+;;    A = B | C B.             ==>   A = [C] B.
+;;    A = B | B C.             ==>   A = B [C].
+;;    A = D | B D | B C D.     ==>   A = [B [C]] D.
+
+
+;; *Already implemented*:
+;;    left recursion:
+;;    A = B | A C.             ==>   A = B {C}*.
+;;    A = B | A B.             ==>   A = {B}+.
+;;    A =   | A B.             ==>   A = {B}*.
+;;    A = B | A C B.           ==>   A = {B || C}+.
+;;    A = B | D | A C | A E.   ==>   A = ( B | D ) { C | E }*.
+
+;;    optional:
+;;    A = B | .                ==>   A = [B].
+;;    A =   | B .              ==>   A = [B].
+
+;;    factoration:
+;;    A = B C | B D.           ==>   A = B (C | D).
+;;    A = C B | D B.           ==>   A = (C | D) B.
+;;    A = B C E | B D E.       ==>   A = B (C | D) E.
+
+;;    none:
+;;    A = B | C | .            ==>   A = B | C | .
+;;    A = B | C A D.           ==>   A = B | C A D.
+
+(defun ebnf-optimize (syntax-list)
+  "Syntatic chart optimizer."
+  (if (not ebnf-optimize)
+      syntax-list
+    (let ((ebnf-total (length syntax-list))
+	  (ebnf-nprod 0)
+	  new)
+      (while syntax-list
+	(setq new (cons (ebnf-optimize1 (car syntax-list)) new)
+	      syntax-list (cdr syntax-list)))
+      (nreverse new))))
+
+
+;; left recursion:
+;; 1.  A = B | A C.             ==>   A = B {C}*.
+;; 2.  A = B | A B.             ==>   A = {B}+.
+;; 3.  A =   | A B.             ==>   A = {B}*.
+;; 4.  A = B | A C B.           ==>   A = {B || C}+.
+;; 5.  A = B | D | A C | A E.   ==>   A = ( B | D ) { C | E }*.
+
+;; optional:
+;; 6.  A = B | .                ==>   A = [B].
+;; 7.  A =   | B .              ==>   A = [B].
+
+;; factoration:
+;; 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.
+
+(defun ebnf-optimize1 (prod)
+  (ebnf-message-info "Optimizing syntatic chart")
+  (let ((production (ebnf-node-production prod)))
+    (and (eq (ebnf-node-kind production) 'ebnf-generate-alternative)
+	 (let* ((hlist (ebnf-split-header-prefix
+			(ebnf-node-list production)
+			(ebnf-node-name prod)))
+		(nlist (car hlist))
+		(zlist (cdr hlist))
+		(elist (ebnf-split-header-suffix nlist zlist)))
+	   (ebnf-node-production
+	    prod
+	    (cond
+	     ;; cases 2., 4.
+	     (elist
+	      (and (eq elist t)
+		   (setq elist nil))
+	      (setq elist (or (ebnf-prefix-suffix elist)
+			      elist))
+	      (let* ((nl (ebnf-extract-empty nlist))
+		     (el (or (ebnf-prefix-suffix (cdr nl))
+			     (ebnf-create-alternative (cdr nl)))))
+		(if (car nl)
+		    (ebnf-make-zero-or-more el elist)
+		  (ebnf-make-one-or-more el elist))))
+	     ;; cases 1., 3., 5.
+	     (zlist
+	      (let* ((xlist (cdr (ebnf-extract-empty zlist)))
+		     (znode (ebnf-make-zero-or-more
+			     (or (ebnf-prefix-suffix xlist)
+				 (ebnf-create-alternative xlist))))
+		     (nnode (ebnf-map-list-to-optional nlist)))
+		(and nnode
+		     (setq nlist (list nnode)))
+		(if (or (null nlist)
+			(and (= (length nlist) 1)
+			     (eq (ebnf-node-kind (car nlist))
+				 'ebnf-generate-empty)))
+		    znode
+		  (ebnf-make-sequence
+		   (list (or (ebnf-prefix-suffix nlist)
+			     (ebnf-create-alternative nlist))
+			 znode)))))
+	     ;; cases 6., 7.
+	     ((ebnf-map-node-to-optional production)
+	      )
+	     ;; cases 8., 9., 10.
+	     ((ebnf-prefix-suffix nlist)
+	      )
+	     ;; none
+	     (t
+	      production)
+	     ))))
+    prod))
+
+
+(defun ebnf-split-header-prefix (node-list header)
+  (let* ((hlist (ebnf-split-header-prefix1 node-list header))
+	 (nlist (car hlist))
+	 zlist empty-p)
+    (while (setq hlist (cdr hlist))
+      (let ((elt (car hlist)))
+	(if (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
+	    (setq zlist (cons
+			 (let ((seq (cdr (ebnf-node-list elt))))
+			   (if (= (length seq) 1)
+			       (car seq)
+			     (ebnf-node-list elt seq)
+			     elt))
+			 zlist))
+	  (setq empty-p t))))
+    (and empty-p
+	 (setq zlist (cons (ebnf-make-empty)
+			   zlist)))
+    (cons nlist (nreverse zlist))))
+
+
+(defun ebnf-split-header-prefix1 (node-list header)
+  (let (hlist nlist)
+    (while node-list
+      (if (ebnf-node-equal-header (car node-list) header)
+	  (setq hlist (cons (car node-list) hlist))
+	(setq nlist (cons (car node-list) nlist)))
+      (setq node-list (cdr node-list)))
+    (cons (nreverse nlist) (nreverse hlist))))
+
+
+(defun ebnf-node-equal-header (node header)
+  (let ((kind (ebnf-node-kind node)))
+    (cond
+     ((eq kind 'ebnf-generate-sequence)
+      (ebnf-node-equal-header (car (ebnf-node-list node)) header))
+     ((eq kind 'ebnf-generate-non-terminal)
+      (string= (ebnf-node-name node) header))
+     (t
+      nil)
+     )))
+
+
+(defun ebnf-map-node-to-optional (node)
+  (and (eq (ebnf-node-kind node) 'ebnf-generate-alternative)
+       (ebnf-map-list-to-optional (ebnf-node-list node))))
+
+
+(defun ebnf-map-list-to-optional (nlist)
+  (and (= (length nlist) 2)
+       (let ((first  (nth 0 nlist))
+	     (second (nth 1 nlist)))
+	 (cond
+	  ;; empty second
+	  ((eq (ebnf-node-kind first) 'ebnf-generate-empty)
+	   (ebnf-make-optional second))
+	  ;; first empty
+	  ((eq (ebnf-node-kind second) 'ebnf-generate-empty)
+	   (ebnf-make-optional first))
+	  ;; first second
+	  (t
+	   nil)
+	  ))))
+
+
+(defun ebnf-extract-empty (elist)
+  (let ((now elist)
+	before empty-p)
+    (while now
+      (if (not (eq (ebnf-node-kind (car now)) 'ebnf-generate-empty))
+	  (setq before now)
+	(setq empty-p t)
+	(if before
+	    (setcdr before (cdr now))
+	  (setq elist (cdr elist))))
+      (setq now (cdr now)))
+    (cons empty-p elist)))
+
+
+(defun ebnf-split-header-suffix (nlist zlist)
+  (let (new empty-p)
+    (and (cond
+	  ((= (length nlist) 1)
+	   (let ((ok t)
+		 (elt (car nlist)))
+	     (while (and ok zlist)
+	       (setq ok    (ebnf-split-header-suffix1 elt (car zlist))
+		     zlist (cdr zlist))
+	       (if (eq ok t)
+		   (setq empty-p t)
+		 (setq new (cons ok new))))
+	     ok))
+	  ((= (length nlist) (length zlist))
+	   (let ((ok t))
+	     (while (and ok zlist)
+	       (setq ok    (ebnf-split-header-suffix1 (car nlist) (car zlist))
+		     nlist (cdr nlist)
+		     zlist (cdr zlist))
+	       (if (eq ok t)
+		   (setq empty-p t)
+		 (setq new (cons ok new))))
+	     ok))
+	  (t
+	   nil)
+	  )
+	 (let* ((lis (ebnf-unique-list new))
+		(len (length lis)))
+	   (cond
+	    ((zerop len)
+	     t)
+	    ((= len 1)
+	     (setq lis (car lis))
+	     (if empty-p
+		 (ebnf-make-optional lis)
+	       lis))
+	    (t
+	     (and empty-p
+		  (setq lis (cons (ebnf-make-empty) lis)))
+	     (ebnf-create-alternative (nreverse lis)))
+	    )))))
+
+
+(defun ebnf-split-header-suffix1 (ne ze)
+  (cond
+   ((eq (ebnf-node-kind ne) 'ebnf-generate-sequence)
+    (and (eq (ebnf-node-kind ze) 'ebnf-generate-sequence)
+	 (let ((nl (ebnf-node-list ne))
+	       (zl (ebnf-node-list ze))
+	       len z)
+	   (and (>= (length zl) (length nl))
+		(let ((ok t))
+		  (setq len (- (length zl) (length nl))
+			z   (nthcdr len zl))
+		  (while (and ok z)
+		    (setq ok (ebnf-node-equal (car z) (car nl))
+			  z  (cdr z)
+			  nl (cdr nl)))
+		  ok)
+		(if (zerop len)
+		    t
+		  (setcdr (nthcdr (1- len) zl) nil)
+		  ze)))))
+   ((eq (ebnf-node-kind ze) 'ebnf-generate-sequence)
+    (let* ((zl  (ebnf-node-list ze))
+	   (len (length zl)))
+      (and (ebnf-node-equal ne (car (nthcdr (1- len) zl)))
+	   (cond
+	    ((= len 1)
+	     t)
+	    ((= len 2)
+	     (car zl))
+	    (t
+	     (setcdr (nthcdr (- len 2) zl) nil)
+	     ze)
+	    ))))
+   (t
+    (ebnf-node-equal ne ze))
+   ))
+
+
+(defun ebnf-prefix-suffix (lis)
+  (and lis (listp lis)
+       (let* ((prefix (ebnf-split-prefix lis))
+	      (suffix (ebnf-split-suffix (cdr prefix)))
+	      (middle (cdr suffix)))
+	 (setq prefix (car prefix)
+	       suffix (car suffix))
+	 (and (or prefix suffix)
+	      (ebnf-make-sequence
+	       (nconc prefix
+		      (and middle
+			   (list (or (ebnf-map-list-to-optional middle)
+				     (ebnf-create-alternative middle))))
+		      suffix))))))
+
+
+(defun ebnf-split-prefix (lis)
+  (let* ((len  (length lis))
+	 (tail lis)
+	 (head (if (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence)
+		   (ebnf-node-list (car lis))
+		 (list (car lis))))
+	 (ipre (1+ len)))
+    ;; determine prefix length
+    (while (and (> ipre 0) (setq tail (cdr tail)))
+      (let ((cur head)
+	    (this (if (eq (ebnf-node-kind (car tail)) 'ebnf-generate-sequence)
+		      (ebnf-node-list (car tail))
+		    (list (car tail))))
+	    (i 0))
+	(while (and cur this
+		    (ebnf-node-equal (car cur) (car this)))
+	  (setq cur  (cdr cur)
+		this (cdr this)
+		i    (1+ i)))
+	(setq ipre (min ipre i))))
+    (if (or (zerop ipre) (> ipre len))
+	;; no prefix at all
+	(cons nil lis)
+      (let* ((tail   (nthcdr ipre head))
+	     ;; get prefix
+	     (prefix (progn
+		       (and tail
+			    (setcdr (nthcdr (1- ipre) head) nil))
+		       head))
+	     empty-p before)
+	;; adjust first element
+	(if (or (not (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence))
+		(null tail))
+	    (setq lis     (cdr lis)
+		  tail    lis
+		  empty-p t)
+	  (if (= (length tail) 1)
+	      (setcar lis (car tail))
+	    (ebnf-node-list (car lis) tail))
+	  (setq tail (cdr lis)))
+	;; eliminate prefix from lis based on ipre
+	(while tail
+	  (let ((elt (car tail))
+		rest)
+	    (if (and (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
+		     (setq rest (nthcdr ipre (ebnf-node-list elt))))
+		(progn
+		  (if (= (length rest) 1)
+		      (setcar tail (car rest))
+		    (ebnf-node-list elt rest))
+		  (setq before tail))
+	      (setq empty-p t)
+	      (if before
+		  (setcdr before (cdr tail))
+		(setq lis (cdr lis))))
+	    (setq tail (cdr tail))))
+	(cons prefix (ebnf-unique-list
+		      (if empty-p
+			  (nconc lis (list (ebnf-make-empty)))
+			lis)))))))
+
+
+(defun ebnf-split-suffix (lis)
+  (let* ((len  (length lis))
+	 (tail lis)
+	 (head (nreverse
+		(if (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence)
+		    (ebnf-node-list (car lis))
+		  (list (car lis)))))
+	 (isuf (1+ len)))
+    ;; determine suffix length
+    (while (and (> isuf 0) (setq tail (cdr tail)))
+      (let* ((cur head)
+	     (tlis (nreverse
+		    (if (eq (ebnf-node-kind (car tail)) 'ebnf-generate-sequence)
+			(ebnf-node-list (car tail))
+		      (list (car tail)))))
+	     (this tlis)
+	     (i 0))
+	(while (and cur this
+		    (ebnf-node-equal (car cur) (car this)))
+	  (setq cur  (cdr cur)
+		this (cdr this)
+		i    (1+ i)))
+	(nreverse tlis)
+	(setq isuf (min isuf i))))
+    (setq head (nreverse head))
+    (if (or (zerop isuf) (> isuf len))
+	;; no suffix at all
+	(cons nil lis)
+      (let* ((n      (- (length head) isuf))
+	     ;; get suffix
+	     (suffix (nthcdr n head))
+	     (tail   (and (> n 0)
+			  (progn
+			    (setcdr (nthcdr (1- n) head) nil)
+			    head)))
+	     before empty-p)
+	;; adjust first element
+	(if (or (not (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence))
+		(null tail))
+	    (setq lis     (cdr lis)
+		  tail    lis
+		  empty-p t)
+	  (if (= (length tail) 1)
+	      (setcar lis (car tail))
+	    (ebnf-node-list (car lis) tail))
+	  (setq tail (cdr lis)))
+	;; eliminate suffix from lis based on isuf
+	(while tail
+	  (let ((elt (car tail))
+		rest)
+	    (if (and (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
+		     (setq rest (ebnf-node-list elt)
+			   n    (- (length rest) isuf))
+		     (> n 0))
+		(progn
+		  (if (= n 1)
+		      (setcar tail (car rest))
+		    (setcdr (nthcdr (1- n) rest) nil)
+		    (ebnf-node-list elt rest))
+		  (setq before tail))
+	      (setq empty-p t)
+	      (if before
+		  (setcdr before (cdr tail))
+		(setq lis (cdr lis))))
+	    (setq tail (cdr tail))))
+	(cons suffix (ebnf-unique-list
+		      (if empty-p
+			  (nconc lis (list (ebnf-make-empty)))
+			lis)))))))
+
+
+(defun ebnf-unique-list (nlist)
+  (let ((current nlist)
+	before)
+    (while current
+      (let ((tail (cdr current))
+	    (head (car current))
+	    remove-p)
+	(while tail
+	  (if (not (ebnf-node-equal head (car tail)))
+	      (setq tail (cdr tail))
+	    (setq remove-p t
+		  tail     nil)
+	    (if before
+		(setcdr before (cdr current))
+	      (setq nlist (cdr nlist)))))
+	(or remove-p
+	    (setq before current))
+	(setq current (cdr current))))
+    nlist))
+
+
+(defun ebnf-node-equal (A B)
+  (let ((kindA (ebnf-node-kind A))
+	(kindB (ebnf-node-kind B)))
+    (and (eq kindA kindB)
+	 (cond
+	  ;; empty
+	  ((eq kindA 'ebnf-generate-empty)
+	   t)
+	  ;; non-terminal, terminal, special
+	  ((memq kindA '(ebnf-generate-non-terminal
+			 ebnf-generate-terminal
+			 ebnf-generate-special))
+	   (string= (ebnf-node-name A) (ebnf-node-name B)))
+	  ;; alternative, sequence
+	  ((memq kindA '(ebnf-generate-alternative ; any order
+			 ebnf-generate-sequence)) ; order is important
+	   (let ((listA (ebnf-node-list A))
+		 (listB (ebnf-node-list B)))
+	     (and (= (length listA) (length listB))
+		  (let ((ok t))
+		    (while (and ok listA)
+		      (setq ok    (ebnf-node-equal (car listA) (car listB))
+			    listA (cdr listA)
+			    listB (cdr listB)))
+		    ok))))
+	  ;; production
+	  ((eq kindA 'ebnf-generate-production)
+	   (and (string= (ebnf-node-name A) (ebnf-node-name B))
+		(ebnf-node-equal (ebnf-node-production A)
+				 (ebnf-node-production B))))
+	  ;; otherwise
+	  (t
+	   nil)
+	  ))))
+
+
+(defun ebnf-create-alternative (alt)
+  (if (> (length alt) 1)
+      (ebnf-make-alternative alt)
+    (car alt)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'ebnf-otz)
+
+
+;;; ebnf-otz.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ebnf-yac.el	Thu Jan 27 14:31:16 2000 +0000
@@ -0,0 +1,487 @@
+;;; ebnf-yac --- Parser for Yacc/Bison
+
+;; Copyright (C) 1999 Vinicius Jose Latorre
+
+;; Author:     Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Keywords:   wp, ebnf, PostScript
+;; Time-stamp: <99/11/20 18:02:43 vinicius>
+;; Version:    1.0
+
+;; This file is *NOT* (yet?) part of GNU Emacs.
+
+;; This program 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)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;;
+;; This is part of ebnf2ps package.
+;;
+;; This package defines a parser for Yacc/Bison.
+;;
+;; See ebnf2ps.el for documentation.
+;;
+;;
+;; Yacc/Bison Syntax
+;; -----------------
+;;
+;; YACC = { YACC-Definitions }* "%%" { YACC-Rule }* [ "%%" [ YACC-Code ] ].
+;;
+;; YACC-Definitions = "%token" [ "<" Name ">" ] Name-List
+;;                  | "any other Yacc definition"
+;;                  .
+;;
+;; YACC-Code = "any C definition".
+;;
+;; YACC-Rule = Name ":" Alternative ";".
+;;
+;; Alternative = { Sequence || "|" }*.
+;;
+;; Sequence = { Factor }*.
+;;
+;; Factor = Name
+;;        | "'" "character" "'"
+;;        | "error"
+;;        | "{" "C like commands" "}"
+;;        .
+;;
+;; Name-List = { Name || "," }*.
+;;
+;; Name = "[A-Za-z][A-Za-z0-9_.]*".
+;;
+;; Comment = "/*" "any character, but the sequence \"*/\"" "*/"
+;;         | "//" "any character" "\\n".
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+(require 'ebnf-otz)
+
+
+(defvar ebnf-yac-lex nil
+  "Value returned by `ebnf-yac-lex' function.")
+
+
+(defvar ebnf-yac-token-list nil
+  "List of `%TOKEN' names.")
+
+
+(defvar ebnf-yac-skip-char nil
+  "Non-nil means skip printable characters with no grammatical meaning.")
+
+
+(defvar ebnf-yac-error nil
+  "Non-nil means \"error\" occured.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Syntatic analyzer
+
+
+;;; YACC = { YACC-Definitions }* "%%" { YACC-Rule }* [ "%%" [ YACC-Code ] ].
+;;;
+;;; YACC-Code = "any C definition".
+
+(defun ebnf-yac-parser (start)
+  "yacc/Bison parser."
+  (let ((total (+ (- ebnf-limit start) 1))
+	(bias (1- start))
+	(origin (point))
+	syntax-list token rule)
+    (goto-char start)
+    (setq token (ebnf-yac-lex))
+    (and (eq token 'end-of-input)
+	 (error "Invalid Yacc/Bison file format."))
+    (or (eq (ebnf-yac-definitions token) 'yac-separator)
+	(error "Missing `%%%%'."))
+    (setq token (ebnf-yac-lex))
+    (while (not (memq token '(end-of-input yac-separator)))
+      (ebnf-message-float
+       "Parsing...%s%%"
+       (/ (* (- (point) bias) 100.0) total))
+      (setq token (ebnf-yac-rule token)
+	    rule  (cdr token)
+	    token (car token))
+      (or (ebnf-add-empty-rule-list rule)
+	  (setq syntax-list (cons rule syntax-list))))
+    (goto-char origin)
+    syntax-list))
+
+
+;;; YACC-Definitions = "%token" [ "<" Name ">" ] Name-List
+;;;                  | "any other Yacc definition"
+;;;                  .
+
+(defun ebnf-yac-definitions (token)
+  (let ((ebnf-yac-skip-char t))
+    (while (not (memq token '(yac-separator end-of-input)))
+      (setq token
+	    (cond
+	     ;; "%token" [ "<" Name ">" ] Name-List
+	     ((eq token 'yac-token)
+	      (setq token (ebnf-yac-lex))
+	      (when (eq token 'open-angle)
+		(or (eq (ebnf-yac-lex) 'non-terminal)
+		    (error "Missing type name."))
+		(or (eq (ebnf-yac-lex) 'close-angle)
+		    (error "Missing `>'."))
+		(setq token (ebnf-yac-lex)))
+	      (setq token               (ebnf-yac-name-list token)
+		    ebnf-yac-token-list (nconc (cdr token)
+					       ebnf-yac-token-list))
+	      (car token))
+	     ;; "any other Yacc definition"
+	     (t
+	      (ebnf-yac-lex))
+	     )))
+    token))
+
+
+;;; YACC-Rule = Name ":" Alternative ";".
+
+(defun ebnf-yac-rule (token)
+  (let ((header ebnf-yac-lex)
+	(action ebnf-action)
+	body)
+    (setq ebnf-action nil)
+    (or (eq token 'non-terminal)
+	(error "Invalid rule name."))
+    (or (eq (ebnf-yac-lex) 'colon)
+	(error "Invalid rule: missing `:'."))
+    (setq body (ebnf-yac-alternative))
+    (or (eq (car body) 'period)
+	(error "Invalid rule: missing `;'."))
+    (setq body (cdr body))
+    (ebnf-eps-add-production header)
+    (cons (ebnf-yac-lex)
+	  (ebnf-make-production header body action))))
+
+
+;;; Alternative = { Sequence || "|" }*.
+
+(defun ebnf-yac-alternative ()
+  (let (body sequence)
+    (while (eq (car (setq sequence (ebnf-yac-sequence)))
+	       'alternative)
+      (and (setq sequence (cdr sequence))
+	   (setq body     (cons sequence body))))
+    (ebnf-token-alternative body sequence)))
+
+
+;;; Sequence = { Factor }*.
+
+(defun ebnf-yac-sequence ()
+  (let (ebnf-yac-error token seq factor)
+    (while (setq token  (ebnf-yac-lex)
+		 factor (ebnf-yac-factor token))
+      (setq seq (cons factor seq)))
+    (cons token
+	  (cond
+	   ;; ignore error recovery
+	   ((and ebnf-yac-ignore-error-recovery ebnf-yac-error)
+	    nil)
+	   ;; null sequence
+	   ((null seq)
+	    (ebnf-make-empty))
+	   ;; sequence with only one element
+	   ((= (length seq) 1)
+	    (car seq))
+	   ;; a real sequence
+	   (t
+	    (ebnf-make-sequence (nreverse seq)))
+	   ))))
+
+
+;;; Factor = Name
+;;;        | "'" "character" "'"
+;;;        | "error"
+;;;        | "{" "C like commands" "}"
+;;;        .
+
+(defun ebnf-yac-factor (token)
+  (cond
+   ;; 'character'
+   ((eq token 'terminal)
+    (ebnf-make-terminal ebnf-yac-lex))
+   ;; Name
+   ((eq token 'non-terminal)
+    (ebnf-make-non-terminal ebnf-yac-lex))
+   ;; "error"
+   ((eq token 'yac-error)
+    (ebnf-make-special ebnf-yac-lex))
+   ;; not a factor
+   (t
+    nil)
+   ))
+
+
+;;; Name-List = { Name || "," }*.
+
+(defun ebnf-yac-name-list (token)
+  (let (names)
+    (when (eq token 'non-terminal)
+      (while (progn
+	       (setq names (cons ebnf-yac-lex names)
+		     token (ebnf-yac-lex))
+	       (eq token 'comma))
+	(or (eq (ebnf-yac-lex) 'non-terminal)
+	    (error "Missing token name."))))
+    (cons token names)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Lexical analyzer
+
+
+;;; Name = "[A-Za-z][A-Za-z0-9_.]*".
+;;;
+;;; Comment = "/*" "any character, but the sequence \"*/\"" "*/"
+;;;         | "//" "any character" "\\n".
+
+(defconst ebnf-yac-token-table
+  ;; control character & 8-bit character are set to `error'
+  (let ((table (make-vector 256 'error)))
+    ;; upper & lower case letters:
+    (mapcar
+     #'(lambda (char)
+	 (aset table char 'non-terminal))
+     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
+    ;; printable characters:
+    (mapcar
+     #'(lambda (char)
+	 (aset table char 'character))
+     "!#$&()*+-.0123456789=?@[\\]^_`~")
+    ;; Override space characters:
+    (aset table ?\n 'space)		; [NL] linefeed
+    (aset table ?\r 'space)		; [CR] carriage return
+    (aset table ?\t 'space)		; [HT] horizontal tab
+    (aset table ?\  'space)		; [SP] space
+    ;; Override form feed character:
+    (aset table ?\f 'form-feed)		; [FF] form feed
+    ;; Override other lexical characters:
+    (aset table ?<  'open-angle)
+    (aset table ?>  'close-angle)
+    (aset table ?,  'comma)
+    (aset table ?%  'yac-pragma)
+    (aset table ?/  'slash)
+    (aset table ?\{ 'yac-code)
+    (aset table ?\" 'string)
+    (aset table ?\' 'terminal)
+    (aset table ?:  'colon)
+    (aset table ?|  'alternative)
+    (aset table ?\; 'period)
+    table)
+  "Vector used to map characters to a lexical token.")
+
+
+(defun ebnf-yac-initialize ()
+  "Initializations for Yacc/Bison parser."
+  (setq ebnf-yac-token-list nil))
+
+
+(defun ebnf-yac-lex ()
+  "Lexical analyser for Yacc/Bison.
+
+Return a lexical token.
+
+See documentation for variable `ebnf-yac-lex'."
+  (if (>= (point) ebnf-limit)
+      'end-of-input
+    (let (token)
+      ;; skip spaces, code blocks and comments
+      (while (if (> (following-char) 255)
+		 (progn
+		   (setq token 'error)
+		   nil)
+	       (setq token (aref ebnf-yac-token-table (following-char)))
+	       (cond
+		((or (eq token 'space)
+		     (and ebnf-yac-skip-char
+			  (eq token 'character)))
+		 (ebnf-yac-skip-spaces))
+		((eq token 'yac-code)
+		 (ebnf-yac-skip-code))
+		((eq token 'slash)
+		 (ebnf-yac-handle-comment))
+		((eq token 'form-feed)
+		 (forward-char)
+		 (setq ebnf-action 'form-feed))
+		(t nil)
+		)))
+      (cond
+       ;; end of input
+       ((>= (point) ebnf-limit)
+	'end-of-input)
+       ;; error
+       ((eq token 'error)
+	(error "Illegal character."))
+       ;; "string"
+       ((eq token 'string)
+	(setq ebnf-yac-lex (ebnf-get-string))
+	'string)
+       ;; terminal: 'char'
+       ((eq token 'terminal)
+	(setq ebnf-yac-lex (ebnf-string " -&(-~" ?\' "terminal"))
+	'terminal)
+       ;; non-terminal, terminal or "error"
+       ((eq token 'non-terminal)
+	(setq ebnf-yac-lex (ebnf-buffer-substring "0-9A-Za-z_."))
+	(cond ((member ebnf-yac-lex ebnf-yac-token-list)
+	       'terminal)
+	      ((string= ebnf-yac-lex "error")
+	       (setq ebnf-yac-error t)
+	       'yac-error)
+	      (t
+	       'non-terminal)
+	      ))
+       ;; %% and Yacc pragmas (%TOKEN, %START, etc).
+       ((eq token 'yac-pragma)
+	(forward-char)
+	(cond
+	 ;; Yacc separator
+	 ((eq (following-char) ?%)
+	  (forward-char)
+	  'yac-separator)
+	 ;; %TOKEN
+	 ((string= (upcase (ebnf-buffer-substring "0-9A-Za-z_")) "TOKEN")
+	  'yac-token)
+	 ;; other Yacc pragmas
+	 (t
+	  'yac-pragma)
+	 ))
+       ;; miscellaneous
+       (t
+	(forward-char)
+	token)
+       ))))
+
+
+(defun ebnf-yac-skip-spaces ()
+  (skip-chars-forward
+   (if ebnf-yac-skip-char
+       "\n\r\t !#$&()*+-.0123456789=?@[\\\\]^_`~"
+     "\n\r\t ")
+   ebnf-limit)
+  (< (point) ebnf-limit))
+
+
+(defun ebnf-yac-skip-code ()
+  (forward-char)
+  (let ((pair 1))
+    (while (> pair 0)
+      (skip-chars-forward "^{}/'\"\000-\010\013\016-\037\177-\377" ebnf-limit)
+      (cond
+       ((= (following-char) ?{)
+	(forward-char)
+	(setq pair (1+ pair)))
+       ((= (following-char) ?})
+	(forward-char)
+	(setq pair (1- pair)))
+       ((= (following-char) ?/)
+	(ebnf-yac-handle-comment))
+       ((= (following-char) ?\")
+	(ebnf-get-string))
+       ((= (following-char) ?\')
+	(ebnf-string " -&(-~" ?\' "character"))
+       (t
+	(error "Illegal character."))
+       )))
+  (ebnf-yac-skip-spaces))
+
+
+(defun ebnf-yac-handle-comment ()
+  (forward-char)
+  (cond
+   ;; begin comment
+   ((= (following-char) ?*)
+    (ebnf-yac-skip-comment)
+    (ebnf-yac-skip-spaces))
+   ;; line comment
+   ((= (following-char) ?/)
+    (end-of-line)
+    (ebnf-yac-skip-spaces))
+   ;; no comment
+   (t nil)
+   ))
+
+
+(defconst ebnf-yac-comment-chars "^*\000-\010\013\016-\037\177-\237")
+
+
+(defun ebnf-yac-skip-comment ()
+  (forward-char)
+  (cond
+   ;; open EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\[))
+    (ebnf-eps-add-context (ebnf-yac-eps-filename)))
+   ;; close EPS file
+   ((and ebnf-eps-executing (= (following-char) ?\]))
+    (ebnf-eps-remove-context (ebnf-yac-eps-filename)))
+   ;; any other action in comment
+   (t
+    (setq ebnf-action (aref ebnf-comment-table (following-char))))
+   )
+  (let ((not-end t))
+    (while not-end
+      (skip-chars-forward ebnf-yac-comment-chars ebnf-limit)
+      (cond ((>= (point) ebnf-limit)
+	     (error "Missing end of comment: `*/'."))
+	    ((= (following-char) ?*)
+	     (skip-chars-forward "*" ebnf-limit)
+	     (when (= (following-char) ?/)
+	       ;; end of comment
+	       (forward-char)
+	       (setq not-end nil)))
+	    (t
+	     (error "Illegal character."))
+	    ))))
+
+
+(defun ebnf-yac-eps-filename ()
+  (forward-char)
+  (buffer-substring-no-properties
+   (point)
+   (let ((chars (concat ebnf-yac-comment-chars "\n"))
+	 found)
+     (while (not found)
+       (skip-chars-forward chars ebnf-limit)
+       (setq found
+	     (cond ((>= (point) ebnf-limit)
+		    (point))
+		   ((= (following-char) ?*)
+		    (skip-chars-forward "*" ebnf-limit)
+		    (if (/= (following-char) ?\/)
+			nil
+		      (backward-char)
+		      (point)))
+		   (t
+		    (point))
+		   )))
+     found)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'ebnf-yac)
+
+
+;;; ebnf-yac.el ends here
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lisp/progmodes/ebnf2ps.el	Thu Jan 27 14:31:16 2000 +0000
@@ -0,0 +1,5339 @@
+;;; ebnf2ps --- Translate an EBNF to a syntatic chart on PostScript
+
+;; Copyright (C) 1999 Vinicius Jose Latorre
+
+;; Author:     Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
+;; Keywords:   wp, ebnf, PostScript
+;; Time-stamp: <99/12/11 21:41:24 vinicius>
+;; Version:    3.1
+
+(defconst ebnf-version "3.1"
+  "ebnf2ps.el, v 3.1 <99/12/11 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 Jose Latorre <vinicius@cpqd.com.br>.
+")
+
+;; This file is *NOT* (yet?) part of GNU Emacs.
+
+;; This program 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)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; 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.
+
+;;; Commentary:
+
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Introduction
+;; ------------
+;;
+;; This package translates an EBNF to a syntatic chart on PostScript.
+;;
+;; To use ebnf2ps, insert in your ~/.emacs:
+;;
+;;        (require 'ebnf2ps)
+;;
+;; ebnf2ps uses ps-print package (version 3.05.1 or later), so see ps-print to
+;; know how to set options like landscape printing, page headings, margins, etc.
+;;
+;; NOTE: ps-print zebra stripes and line number options doesn't have effect on
+;;       ebnf2ps, they behave as it's turned off.
+;;
+;; For good performance, be sure to byte-compile ebnf2ps.el, e.g.
+;;
+;;    M-x byte-compile-file <give the path to ebnf2ps.el when prompted>
+;;
+;; This will generate ebnf2ps.elc, which will be loaded instead of ebnf2ps.el.
+;;
+;; ebnf2ps was tested with GNU Emacs 20.4.1.
+;;
+;;
+;; Using ebnf2ps
+;; -------------
+;;
+;; ebnf2ps provides six commands for generating PostScript syntatic chart images
+;; of Emacs buffers:
+;;
+;;        ebnf-print-buffer
+;;        ebnf-print-region
+;;        ebnf-spool-buffer
+;;        ebnf-spool-region
+;;        ebnf-eps-buffer
+;;        ebnf-eps-region
+;;
+;; These commands all perform essentially the same function: they generate
+;; PostScript syntatic chart images suitable for printing on a PostScript
+;; printer or displaying with GhostScript.  These commands are collectively
+;; referred to as "ebnf- commands".
+;;
+;; 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;
+;;
+;;        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.
+;;
+;; 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
+;; banner pages, and to make it easier to find your output at the printer (it's
+;; easier to pick up one 50-page printout than to find 50 single-page
+;; printouts).  As ebnf2ps and ps-print use the same Emacs buffer to spool
+;; images, you can intermix the spooling of ebnf2ps and ps-print images.
+;;
+;; ebnf2ps use the same hook of ps-print in the `kill-emacs-hook' so that you
+;; won't accidentally quit from Emacs while you have unprinted PostScript
+;; waiting in the spool buffer.  If you do attempt to exit with spooled
+;; PostScript, you'll be asked if you want to print it, and if you decline,
+;; 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:
+;;
+;;        buffer  - Print the entire buffer.
+;;
+;;        region  - Print just the current region.
+;;
+;; Two ebnf- command examples:
+;;
+;;        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.
+;;
+;; 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.
+;;
+;;
+;; Invoking Ebnf2ps
+;; ----------------
+;;
+;; To translate and print your buffer, type
+;;
+;;        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
+;;
+;;        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.
+;; The prefix argument is ignored by the commands that spool their images, but
+;; you may save the spooled images to a file by giving a prefix argument to
+;; `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.
+;;
+;; The prefix argument is also ignored by `ebnf-eps-buffer' and
+;; `ebnf-eps-region'.
+;;
+;; 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)
+;;
+;;
+;; EBNF Syntax
+;; -----------
+;;
+;; The current EBNF that ebnf2ps accepts has the following constructions:
+;;
+;;    ;			comment (until end of line)
+;;    A			non-terminal
+;;    "C"		terminal
+;;    ?C?		special
+;;    $A		default non-terminal (see text below)
+;;    $"C"		default terminal (see text below)
+;;    $?C?		default special (see text below)
+;;    A = B.		production (A is the header and B the body)
+;;    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)
+;;    (C)		group (expression C is grouped together)
+;;    [C]		optional (C may or not occurs)
+;;    C+		one or more occurrences of C
+;;    {C}+		one or more occurrences of C
+;;    {C}*		zero or more occurrences of C
+;;    {C}		zero or more occurrences of C
+;;    C / D		equivalent to: C {D C}*
+;;    {C || D}+		equivalent to: C {D C}*
+;;    {C || D}*		equivalent to: [C {D C}*]
+;;    {C || D}		equivalent to: [C {D C}*]
+;;
+;; The EBNF syntax written using the notation above is:
+;;
+;;    EBNF = {production}+.
+;;
+;;    production = non_terminal "=" body ".".   ;; production
+;;
+;;    body = {sequence || "|"}*.                ;; alternative
+;;
+;;    sequence = {exception}*.                  ;; sequence
+;;
+;;    exception = repeat [ "-" repeat].         ;; exception
+;;
+;;    repeat = [ integer "*" ] term.            ;; repetition
+;;
+;;    term = factor
+;;         | [factor] "+"                       ;; one-or-more
+;;         | [factor] "/" [factor]              ;; one-or-more
+;;         .
+;;
+;;    factor = [ "$" ] "\"" terminal "\""       ;; terminal
+;;           | [ "$" ] non_terminal             ;; non-terminal
+;;           | [ "$" ] "?" special "?"          ;; special
+;;           | "(" body ")"                     ;; group
+;;           | "[" body "]"                     ;; zero-or-one
+;;           | "{" body [ "||" body ] "}+"      ;; one-or-more
+;;           | "{" body [ "||" body ] "}*"      ;; zero-or-more
+;;           | "{" body [ "||" body ] "}"       ;; zero-or-more
+;;           .
+;;
+;;    non_terminal = "[A-Za-z\\240-\\377][!#%&'*-,0-:<>@-Z\\^-z~\\240-\\377]*".
+;;
+;;    terminal = "\\([^\"\\]\\|\\\\[ -~\\240-\\377]\\)+".
+;;
+;;    special = "[^?\\n\\000-\\010\\016-\\037\\177-\\237]*".
+;;
+;;    integer = "[0-9]+".
+;;
+;;    comment = ";" "[^\\n\\000-\\010\\016-\\037\\177-\\237]*" "\\n".
+;;
+;; Try to use the above EBNF to test ebnf2ps.
+;;
+;; The `default' terminal, non-terminal and special is a way to indicate a
+;; default path in a production.  For example, the production:
+;;
+;;    X = [ $A ( B | $C ) | D ].
+;;
+;; Indicates that the default meaning for "X" is "A C" if "X" is empty.
+;;
+;; The terminal name is controlled by `ebnf-terminal-regexp' and
+;; `ebnf-case-fold-search', so it's possible to match other kind of terminal
+;; name besides that enclosed by `"'.
+;;
+;; Let's see an example:
+;;
+;;    (setq ebnf-terminal-regexp "[A-Z][_A-Z]*") ; upper case name
+;;    (setq ebnf-case-fold-search nil) ; exact matching
+;;
+;; If you have the production:
+;;
+;;    Logical = "(" Expression ( OR | AND | "XOR" ) Expression ")".
+;;
+;; The names are classified as:
+;;
+;;    Logical  Expression		non-terminal
+;;    "("  OR  AND  "XOR"  ")"		terminal
+;;
+;; The line comment is controlled by `ebnf-lex-comment-char'.  The default value
+;; is ?\; (character `;').
+;;
+;; The end of production is controlled by `ebnf-lex-eop-char'.  The default
+;; value is ?. (character `.').
+;;
+;; The variable `ebnf-syntax' specifies which syntax to recognize:
+;;
+;;    `ebnf'		ebnf2ps recognizes the syntax described above.
+;;			The following variables *ONLY* have effect with this
+;;			setting:
+;;			`ebnf-terminal-regexp', `ebnf-case-fold-search',
+;;			`ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
+;;
+;;    `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").
+;;			The following variables *ONLY* have effect with this
+;;			setting:
+;;			`ebnf-iso-alternative-p' and `ebnf-iso-normalize-p'.
+;;
+;;    `yacc'		ebnf2ps recognizes the Yacc/Bison syntax.
+;;			The following variable *ONLY* has effect with this
+;;			setting:
+;;			`ebnf-yac-ignore-error-recovery'.
+;;
+;; Any other value is treated as `ebnf'.
+;;
+;; The default value is `ebnf'.
+;;
+;;
+;; Optimizations
+;; -------------
+;;
+;; The following EBNF optimizations are done:
+;;
+;;    [ { A }* ]          ==> { A }*
+;;    [ { A }+ ]          ==> { A }*
+;;    [ A ] +             ==> { A }*
+;;    { A }* +            ==> { A }*
+;;    { A }+ +            ==> { A }+
+;;    { A }-              ==> { A }+
+;;    [ A ]-              ==> A
+;;    ( A | EMPTY )-      ==> A
+;;    ( A | B | EMPTY )-  ==> A | B
+;;    [ A | B ]           ==> A | B | EMPTY
+;;    n * EMPTY           ==> EMPTY
+;;    EMPTY +             ==> EMPTY
+;;    EMPTY / EMPTY       ==> EMPTY
+;;    EMPTY - A           ==> EMPTY
+;;
+;; The following optimizations are done when `ebnf-optimize' is non-nil:
+;;
+;; left recursion:
+;;    1.  A = B | A C.             ==>   A = B {C}*.
+;;    2.  A = B | A B.             ==>   A = {B}+.
+;;    3.  A =   | A B.             ==>   A = {B}*.
+;;    4.  A = B | A C B.           ==>   A = {B || C}+.
+;;    5.  A = B | D | A C | A E.   ==>   A = ( B | D ) { C | E }*.
+;;
+;; optional:
+;;    6.  A = B | .                ==>   A = [B].
+;;    7.  A =   | B .              ==>   A = [B].
+;;
+;; factoration:
+;;    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'.
+;;
+;;
+;; Form Feed
+;; ---------
+;;
+;; You may use form feed (^L \014) to force a production to start on a new page,
+;; for example:
+;;
+;;    a) A = B | C.
+;;	 ^L
+;;	 X = Y | Z.
+;;
+;;    b) A = B ^L | C.
+;;	 X = Y | Z.
+;;
+;;    c) A = B ^L^L^L | C.^L
+;;	 ^L
+;;	 X = Y | Z.
+;;
+;; In all examples above, only the production X will start on a new page.
+;;
+;;
+;; Actions in Comments
+;; -------------------
+;;
+;; ebnf2ps accepts the following actions in comments:
+;;
+;;    ;>	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 next line.
+;;		It is useful when `ebnf-horizontal-orientation' is non-nil.
+;;
+;;    ;[EPS	open a new EPS file.  The EPS file name has the form:
+;;			<PREFIX><NAME>.eps
+;;		where <PREFIX> is given by variable `ebnf-eps-prefix' and <NAME>
+;;		is the string given by ;[ action comment, this string is mapped
+;;		to form a valid file name (see documentation for
+;;		`ebnf-eps-buffer' or `ebnf-eps-region').
+;;		It has effect only during `ebnf-eps-buffer' or
+;;		`ebnf-eps-region' execution.
+;;		It's an error to try to open an already opened EPS file.
+;;
+;;    ;]EPS	close an opened EPS file.
+;;		It has effect only during `ebnf-eps-buffer' or
+;;		`ebnf-eps-region' execution.
+;;		It's an error to try to close a not opened EPS file.
+;;
+;; So if you have:
+;;
+;;    (setq ebnf-horizontal-orientation nil)
+;;
+;;    A = t.
+;;    C = x.
+;;    ;> C and B are drawn in the same line
+;;    B = y.
+;;    W = v.
+;;
+;; The graphical result is:
+;;
+;;    +---+
+;;    | A |
+;;    +---+
+;;
+;;    +---------+   +-----+
+;;    |         |   |     |
+;;    |    C    |   |     |
+;;    |         |   |  B  |
+;;    +---------+   |     |
+;;                  |     |
+;;                  +-----+
+;;
+;;    +-----------+
+;;    |     W     |
+;;    +-----------+
+;;
+;; Note that if ascending production sort is used, the productions A and B will
+;; be drawn in the same line instead of C and B.
+;;
+;; If consecutive actions occur, only the last one takes effect, so if you have:
+;;
+;;    A = X.
+;;    ;<
+;;    ^L
+;;    ;>
+;;    B = Y.
+;;
+;; 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:
+;;
+;;    A = t;
+;;    C = x;
+;;    (*> C and B are drawn in the same line *)
+;;    B = y;
+;;    W = v;
+;;
+;; For an example of EPS action when executing `ebnf-eps-buffer' or
+;; `ebnf-eps-region':
+;;
+;;    Z = B0.
+;;    ;[CC
+;;    ;[AA
+;;    A = B1.
+;;    ;[BB
+;;    C = B2.
+;;    ;]AA
+;;    B = B3.
+;;    ;]BB
+;;    ;]CC
+;;    D = B4.
+;;    E = B5.
+;;    ;[CC
+;;    F = B6.
+;;    ;]CC
+;;    G = B7.
+;;
+;; 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
+;;
+;; 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
+;; it's not an existing production name.
+;;
+;; In the following case:
+;;
+;;    A = B0.
+;;    ;[AA
+;;    A = B1.
+;;    ;[BB
+;;    A = B2.
+;;
+;; The production A is generated in both files ebnf--AA.eps and ebnf--BB.eps.
+;;
+;;
+;; Utilities
+;; ---------
+;;
+;; Some tools are provided to help you.
+;;
+;; `ebnf-setup' returns the current setup.
+;;
+;; `ebnf-syntax-buffer' does a syntatic analysis of your EBNF in the current
+;; buffer.
+;;
+;; `ebnf-syntax-region' does a syntatic analysis of your EBNF in the current
+;; region.
+;;
+;; `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.
+;;
+;;
+;; Hooks
+;; -----
+;;
+;; ebn2ps has the following hook variables:
+;;
+;; `ebnf-hook'
+;;    It is evaluated once before any ebnf2ps process.
+;;
+;; `ebnf-production-hook'
+;;    It is evaluated on each beginning of production.
+;;
+;; `ebnf-page-hook'
+;;    It is evaluated on each beginning of page.
+;;
+;;
+;; Options
+;; -------
+;;
+;; Below it's shown a brief description of ebnf2ps options, please, see the
+;; options declaration in the code for a long documentation.
+;;
+;; `ebnf-horizontal-orientation'	Non-nil means productions are drawn
+;;					horizontally.
+;;
+;; `ebnf-horizontal-max-height'		Non-nil means to use maximum production
+;;					height in horizontal orientation.
+;;
+;; `ebnf-production-horizontal-space'	Specify horizontal space in points
+;;					between productions.
+;;
+;; `ebnf-production-vertical-space'	Specify vertical space in points between
+;;					productions.
+;;
+;; `ebnf-justify-sequence'		Specify justification of terms in a
+;;					sequence inside alternatives.
+;;
+;; `ebnf-terminal-regexp'		Specify how it's a terminal name.
+;;
+;; `ebnf-case-fold-search'		Non-nil means ignore case on matching.
+;;
+;; `ebnf-terminal-font'			Specify terminal font.
+;;
+;; `ebnf-terminal-shape'		Specify terminal box shape.
+;;
+;; `ebnf-terminal-shadow'		Non-nil means terminal box will have a
+;;					shadow.
+;;
+;; `ebnf-terminal-border-width'		Specify border width for terminal box.
+;;
+;; `ebnf-terminal-border-color'		Specify border color for terminal box.
+;;
+;; `ebnf-sort-production'		Specify how productions are sorted.
+;;
+;; `ebnf-production-font'		Specify production font.
+;;
+;; `ebnf-non-terminal-font'		Specify non-terminal font.
+;;
+;; `ebnf-non-terminal-shape'		Specify non-terminal box shape.
+;;
+;; `ebnf-non-terminal-shadow'		Non-nil means non-terminal box will have
+;;					a shadow.
+;;
+;; `ebnf-non-terminal-border-width'	Specify border width for non-terminal
+;;					box.
+;;
+;; `ebnf-non-terminal-border-color'	Specify border color for non-terminal
+;;					box.
+;;
+;; `ebnf-special-font'			Specify special font.
+;;
+;; `ebnf-special-shape'			Specify special box shape.
+;;
+;; `ebnf-special-shadow'		Non-nil means special box will have a
+;;					shadow.
+;;
+;; `ebnf-special-border-width'		Specify border width for special box.
+;;
+;; `ebnf-special-border-color'		Specify border color for special box.
+;;
+;; `ebnf-except-font'			Specify except font.
+;;
+;; `ebnf-except-shape'			Specify except box shape.
+;;
+;; `ebnf-except-shadow'			Non-nil means except box will have a
+;;					shadow.
+;;
+;; `ebnf-except-border-width'		Specify border width for except box.
+;;
+;; `ebnf-except-border-color'		Specify border color for except box.
+;;
+;; `ebnf-repeat-font'			Specify repeat font.
+;;
+;; `ebnf-repeat-shape'			Specify repeat box shape.
+;;
+;; `ebnf-repeat-shadow'			Non-nil means repeat box will have a
+;;					shadow.
+;;
+;; `ebnf-repeat-border-width'		Specify border width for repeat box.
+;;
+;; `ebnf-repeat-border-color'		Specify border color for repeat box.
+;;
+;; `ebnf-entry-percentage'		Specify entry height on alternatives.
+;;
+;; `ebnf-arrow-shape'			Specify the arrow shape.
+;;
+;; `ebnf-chart-shape'			Specify chart flow shape.
+;;
+;; `ebnf-color-p'			Non-nil means use color.
+;;
+;; `ebnf-line-width'			Specify flow line width.
+;;
+;; `ebnf-line-color'			Specify flow line color.
+;;
+;; `ebnf-user-arrow'			Specify a user arrow shape (a PostScript
+;;					code).
+;;
+;; `ebnf-debug-ps'			Non-nil means to generate PostScript
+;;					debug procedures.
+;;
+;; `ebnf-lex-comment-char'		Specify the line comment character.
+;;
+;; `ebnf-lex-eop-char'			Specify the end of production character.
+;;
+;; `ebnf-syntax'			Specify syntax to be recognized.
+;;
+;; `ebnf-iso-alternative-p'		Non-nil means use alternative ISO EBNF.
+;;
+;; `ebnf-iso-normalize-p'		Non-nil means normalize ISO EBNF syntax
+;;					names.
+;;
+;; `ebnf-default-width'			Specify additional border width over
+;;					default terminal, non-terminal or
+;;					special.
+;;
+;; `ebnf-eps-prefix'			Specify EPS prefix file name.
+;;
+;; `ebnf-use-float-format'		Non-nil means use `%f' float format.
+;;
+;; `ebnf-yac-ignore-error-recovery'	Non-nil means ignore error recovery.
+;;
+;; `ebnf-ignore-empty-rule'		Non-nil means ignore empty rules.
+;;
+;; `ebnf-optimize'			Non-nil means optimize syntatic chart of
+;;					rules.
+;;
+;; To set the above options you may:
+;;
+;; a) insert the code in your ~/.emacs, like:
+;;
+;;	 (setq ebnf-terminal-shape 'bevel)
+;;
+;;    This way always keep your default settings when you enter a new Emacs
+;;    session.
+;;
+;; b) or use `set-variable' in your Emacs session, like:
+;;
+;;	 M-x set-variable RET ebnf-terminal-shape RET bevel RET
+;;
+;;    This way keep your settings only during the current Emacs session.
+;;
+;; c) or use customization, for example:
+;;	 click on menu-bar *Help* option,
+;;	 then click on *Customize*,
+;;	 then click on *Browse Customization Groups*,
+;;	 expand *PostScript* group,
+;;	 expand *Ebnf2ps* group
+;;	 and then customize ebnf2ps options.
+;;    Through this way, you may choose if the settings are kept or not when
+;;    you leave out the current Emacs session.
+;;
+;; d) or see the option value:
+;;
+;;	 C-h v ebnf-terminal-shape RET
+;;
+;;    and click the *customize* hypertext button.
+;;    Through this way, you may choose if the settings are kept or not when
+;;    you leave out the current Emacs session.
+;;
+;; e) or invoke:
+;;
+;;	 M-x ebnf-customize RET
+;;
+;;    and then customize ebnf2ps options.
+;;    Through this way, you may choose if the settings are kept or not when
+;;    you leave out the current Emacs session.
+;;
+;;
+;; Styles
+;; ------
+;;
+;; Sometimes you need to change the EBNF style you are using, for example,
+;; change the shapes and colors.  These changes may force you to set some
+;; variables and after use, set back the variables to the old values.
+;;
+;; To help to handle this situation, ebnf2ps has the following commands to
+;; handle styles:
+;;
+;; `ebnf-insert-style'	Insert a new style NAME with inheritance INHERITS and
+;;			values VALUES.
+;;
+;; `ebnf-merge-style'	Merge values of style NAME with style VALUES.
+;;
+;; `ebnf-apply-style'	Set STYLE to current style.
+;;
+;; `ebnf-reset-style'	Reset current style.
+;;
+;; `ebnf-push-style'	Push the current style and set STYLE to current style.
+;;
+;; `ebnf-pop-style'	Pop a style and set it to current style.
+;;
+;; These commands helps 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.
+;;
+;; 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.
+;;
+;; See documentation for `ebnf-style-database'.
+;;
+;;
+;; Layout
+;; ------
+;;
+;; Below it is the layout of minimum area to draw each element, and it's used
+;; the following terms:
+;;
+;;    font height	is given by:
+;;			(terminal font height + non-terminal font height) / 2
+;;
+;;    entry		is the vertical position used to know where it should be
+;;			drawn the flow line in the current element.
+;;
+;;
+;;    * SPECIAL, TERMINAL and NON-TERMINAL
+;;
+;;           +==============+...................................
+;;           |              |      } font height / 2  } entry  }
+;;           |   XXXXXXXX...|.......                  }        }
+;;       ====+   XXXXXXXX   +====  } text height ......        } height
+;;       :   |   XXXXXXXX...|...:...                           }
+;;       :   |   :      :   |   :  } font height / 2           }
+;;       :   +==============+...:...............................
+;;       :   :   :      :   :   :
+;;       :   :   :      :   :   :......................
+;;       :   :   :      :   :      } font height      }
+;;       :   :   :      :   :.......                  }
+;;       :   :   :      :          } font height / 2  }
+;;       :   :   :      :...........                  }
+;;       :   :   :                 } text width       } width
+;;       :   :   :..................                  }
+;;       :   :                     } font height / 2  }
+;;       :   :......................                  }
+;;       :                         } font height      }
+;;       :.............................................
+;;
+;;
+;;    * OPTIONAL
+;;
+;;              +==========+.....................................
+;;              |          |         }        }                 }
+;;              |          |         } entry  }                 }
+;;              |          |         }        }                 }
+;;       ===+===+          +===+===...        } element height  } height
+;;       :   \  |          |  /   :           }                 }
+;;       :    + |          | +    :           }                 }
+;;       :    | +==========+.|.................                 }
+;;       :    | :          : |    :           } font height     }
+;;       :    +==============+...................................
+;;       :      :          :      :
+;;       :      :          :      :......................
+;;       :      :          :         } font height * 2  }
+;;       :      :          :..........                  }
+;;       :      :                    } element width    } width
+;;       :      :.....................                  }
+;;       :                           } font height * 2  }
+;;       :...............................................
+;;
+;;
+;;    * ALTERNATIVE
+;;
+;;               +===+...................................
+;;            +==+ A +==+       } A height     }        }
+;;            |  +===+..|........              } entry  }
+;;            +         +       } font height  }        }
+;;           /   +===+...\.......              }        }
+;;       ===+====+ B +====+===  } B height .....        } height
+;;       :   \   +===+.../.......                       }
+;;       :    +         +    :  } font height           }
+;;       :    |  +===+..|........                       }
+;;       :    +==+ C +==+    :  } C height              }
+;;       :     : +===+...................................
+;;       :     :       :     :
+;;       :     :       :     :......................
+;;       :     :       :        } font height * 2  }
+;;       :     :       :.........                  }
+;;       :     :                } max width        } width
+;;       :     :.................                  }
+;;       :                      } font height * 2  }
+;;       :..........................................
+;;
+;;       NOTES:
+;;          1. An empty alternative has zero of height.
+;;
+;;          2. The variable `ebnf-entry-percentage' is used to determine the
+;;             entry point.
+;;
+;;
+;;    * ZERO OR MORE
+;;
+;;               +===========+...............................
+;;             +=+ separator +=+        } separator height  }
+;;            /  +===========+..\........                   }
+;;           +                   +      }                   }
+;;           |                   |      } font height       }
+;;           +                   +      }                   }
+;;            \  +===========+../........                   } height = entry
+;;             +=+ element   +=+        } element height    }
+;;            /: +===========+..\........                   }
+;;           + :               : +      }                   }
+;;           + :               : +      } font height       }
+;;          /  :               :  \     }                   }
+;;       ==+=======================+==.......................
+;;       :     :               :     :
+;;       :     :               :     :.......................
+;;       :     :               :        } font height * 2   }
+;;       :     :               :.........                   }
+;;       :     :                        } max width         } width
+;;       :     :.........................                   }
+;;       :                              } font height * 2   }
+;;       :...................................................
+;;
+;;
+;;    * ONE OR MORE
+;;
+;;            +===========+......................................
+;;          +=+ separator +=+      } separator height  }        }
+;;         /  +===========+..\......                   }        }
+;;        +                   +    }                   } entry  }
+;;        |                   |    } font height       }        } height
+;;        +                   +    }                   }        }
+;;         \  +===========+../......                   }        }
+;;       ===+=+ element   +=+===   } element height ....        }
+;;       :  : +===========+......................................
+;;       :  :               :  :
+;;       :  :               :  :........................
+;;       :  :               :      } font height * 2   }
+;;       :  :               :.......                   }
+;;       :  :                      } max width         } width
+;;       :  :.......................                   }
+;;       :                         } font height * 2   }
+;;       :..............................................
+;;
+;;
+;;    * PRODUCTION
+;;
+;;       XXXXXX:......................................
+;;       XXXXXX:           } production font height  }
+;;       XXXXXX:............                         }
+;;                         } font height             }
+;;           +======+.......                         } height = entry
+;;           |      |      }                         }
+;;       ====+      +====  } element height          }
+;;       :   |      |   :  }                         }
+;;       :   +======+.................................
+;;       :   :      :   :
+;;       :   :      :   :......................
+;;       :   :      :      } font height * 2  }
+;;       :   :      :.......                  }
+;;       :   :             } element width    } width
+;;       :   :..............                  }
+;;       :                 } font height * 2  }
+;;       :.....................................
+;;
+;;
+;;    * REPEAT
+;;
+;;           +================+...................................
+;;           |                |      } font height / 2  } entry  }
+;;           |        +===+...|.......                  }        }
+;;       ====+  N *   | X |   +====  } X height .........        } height
+;;       :   |  :  :  +===+...|...:...                           }
+;;       :   |  :  :  :   :   |   :  } font height / 2           }
+;;       :   +================+...:...............................
+;;       :   :  :  :  :   :   :   :
+;;       :   :  :  :  :   :   :   :......................
+;;       :   :  :  :  :   :   :      } font height      }
+;;       :   :  :  :  :   :   :.......                  }
+;;       :   :  :  :  :   :          } font height / 2  }
+;;       :   :  :  :  :   :...........                  }
+;;       :   :  :  :  :              } X width          }
+;;       :   :  :  :  :...............                  }
+;;       :   :  :  :                 } font height / 2  } width
+;;       :   :  :  :..................                  }
+;;       :   :  :                    } text width       }
+;;       :   :  :.....................                  }
+;;       :   :                       } font height / 2  }
+;;       :   :........................                  }
+;;       :                           } font height      }
+;;       :...............................................
+;;
+;;
+;;    * EXCEPT
+;;
+;;           +==================+...................................
+;;           |                  |      } font height / 2  } entry  }
+;;           |  +===+   +===+...|.......                  }        }
+;;       ====+  | X | - | y |   +====  } max height .......        } height
+;;       :   |  +===+   +===+...|...:...                           }
+;;       :   |  :   :   :   :   |   :  } font height / 2           }
+;;       :   +==================+...:...............................
+;;       :   :  :   :   :   :   :   :
+;;       :   :  :   :   :   :   :   :......................
+;;       :   :  :   :   :   :   :      } font height      }
+;;       :   :  :   :   :   :   :.......                  }
+;;       :   :  :   :   :   :          } font height / 2  }
+;;       :   :  :   :   :   :...........                  }
+;;       :   :  :   :   :              } Y width          }
+;;       :   :  :   :   :...............                  }
+;;       :   :  :   :                  } font height      } width
+;;       :   :  :   :...................                  }
+;;       :   :  :                      } X width          }
+;;       :   :  :.......................                  }
+;;       :   :                         } font height / 2  }
+;;       :   :..........................                  }
+;;       :                             } font height      }
+;;       :.................................................
+;;
+;;       NOTE: If Y element is empty, it's draw nothing at Y place.
+;;
+;;
+;; Internal Structures
+;; -------------------
+;;
+;; ebnf2ps has two passes.  The first pass does a lexical and syntatic analysis
+;; of current buffer and generates an intermediate representation.  The second
+;; pass uses the intermediate representation to generate the PostScript syntatic
+;; chart.
+;;
+;; The intermediate representation is a list of vectors, the vector element
+;; represents a syntatic chart element.  Below is a vector representation for
+;; each syntatic chart element.
+;;
+;; [production   WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME    PRODUCTION ACTION]
+;; [alternative  WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH LIST]
+;; [sequence     WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH LIST]
+;; [terminal     WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME    DEFAULT]
+;; [non-terminal WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME    DEFAULT]
+;; [special      WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME    DEFAULT]
+;; [empty        WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH]
+;; [optional     WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT]
+;; [one-or-more  WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT SEPARATOR]
+;; [zero-or-more WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT SEPARATOR]
+;; [repeat       WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH TIMES   ELEMENT]
+;; [except       WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT ELEMENT]
+;;
+;; The first vector position is a function symbol used to generate PostScript
+;; for this element.
+;; WIDTH-FUN is a function symbol called to adjust the element width.
+;; DIM-FUN is a function symbol called to set the element dimensions.
+;; ENTRY is the element entry point.
+;; HEIGHT and WIDTH are the element height and width, respectively.
+;; NAME is a string that it's the element name.
+;; DEFAULT is a boolean that indicates if it's a `default' element.
+;; PRODUCTION and ELEMENT are vectors that represents sub-elements of current
+;; one.
+;; LIST is a list of vector that represents the list part for alternatives and
+;; sequences.
+;; SEPARATOR is a vector that represents the sub-element used to separate the
+;; list elements.
+;; TIMES is a string representing the number of times that ELEMENT is repeated
+;; on a repeat construction.
+;; ACTION indicates some action that should be done before production is
+;; generated.  The current actions are:
+;;
+;;    nil		no action.
+;;
+;;    form-feed		current production starts on a new page.
+;;
+;;    newline		current production starts on next line, this is useful
+;;			when `ebnf-horizontal-orientation' is non-nil.
+;;
+;;    keep-line		current production continues on the current line, this
+;;			is useful when `ebnf-horizontal-orientation' is nil.
+;;
+;;
+;; Things To Change
+;; ----------------
+;;
+;; . Handle situations when syntatic chart is out of paper.
+;; . Use other alphabet than ascii.
+;; . Optimizations...
+;;
+;;
+;; Acknowledgements
+;; ----------------
+;;
+;; Thanks to all who emailed comments.
+;;
+;;
+;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;;; code:
+
+
+(require 'ps-print)
+
+(and (string< ps-print-version "3.05.1")
+     (error "`ebnf2ps' requires `ps-print' package version 3.05.1 or later"))
+
+
+;; temporary fix for ps-print
+(or (fboundp 'set-buffer-multibyte)
+    (defun set-buffer-multibyte (arg)
+      (setq enable-multibyte-characters arg)))
+
+(or (fboundp 'string-as-unibyte)
+    (defun string-as-unibyte (arg) arg))
+
+(or (fboundp 'string-as-multibyte)
+    (defun string-as-multibyte (arg) arg))
+
+(or (fboundp 'charset-after)
+    (defun charset-after (&optional arg)
+      (char-charset (char-after arg))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User Variables:
+
+
+;;; Interface to the command system
+
+(defgroup postscript nil
+  "PostScript Group"
+  :tag "PostScript"
+  :group 'emacs)
+
+
+(defgroup ebnf2ps nil
+  "Translate an EBNF to a syntatic chart on PostScript"
+  :prefix "ebnf-"
+  :group 'wp
+  :group 'postscript)
+
+
+(defgroup ebnf-special nil
+  "Special customization"
+  :prefix "ebnf-"
+  :tag "Special"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-except nil
+  "Except customization"
+  :prefix "ebnf-"
+  :tag "Except"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-repeat nil
+  "Repeat customization"
+  :prefix "ebnf-"
+  :tag "Repeat"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-terminal nil
+  "Terminal customization"
+  :prefix "ebnf-"
+  :tag "Terminal"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-non-terminal nil
+  "Non-Terminal customization"
+  :prefix "ebnf-"
+  :tag "Non-Terminal"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-production nil
+  "Production customization"
+  :prefix "ebnf-"
+  :tag "Production"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-shape nil
+  "Shapes customization"
+  :prefix "ebnf-"
+  :tag "Shape"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-displacement nil
+  "Displacement customization"
+  :prefix "ebnf-"
+  :tag "Displacement"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-syntatic nil
+  "Syntatic customization"
+  :prefix "ebnf-"
+  :tag "Syntatic"
+  :group 'ebnf2ps)
+
+
+(defgroup ebnf-optimization nil
+  "Optimization customization"
+  :prefix "ebnf-"
+  :tag "Optimization"
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-horizontal-orientation nil
+  "*Non-nil means productions are drawn horizontally."
+  :type 'boolean
+  :group 'ebnf-displacement)
+
+
+(defcustom ebnf-horizontal-max-height nil
+  "*Non-nil means to use maximum production height in horizontal orientation.
+
+It is only used when `ebnf-horizontal-orientation' is non-nil."
+  :type 'boolean
+  :group 'ebnf-displacement)
+
+
+(defcustom ebnf-production-horizontal-space 0.0 ; use ebnf2ps default value
+  "*Specify horizontal space in points between productions.
+
+Value less or equal to zero forces ebnf2ps to set a proper default value."
+  :type 'number
+  :group 'ebnf-displacement)
+
+
+(defcustom ebnf-production-vertical-space 0.0 ; use ebnf2ps default value
+  "*Specify vertical space in points between productions.
+
+Value less or equal to zero forces ebnf2ps to set a proper default value."
+  :type 'number
+  :group 'ebnf-displacement)
+
+
+(defcustom ebnf-justify-sequence 'center
+  "*Specify justification of terms in a sequence inside alternatives.
+
+Valid values are:
+
+   `left'		left justification
+   `right'		right justification
+   any other value	centralize"
+  :type '(radio :tag "Sequence Justification"
+		(const left) (const right) (other :tag "center" center))
+  :group 'ebnf-displacement)
+
+
+(defcustom ebnf-special-font '(7 Courier "Black" "Gray95" bold italic)
+  "*Specify special font.
+
+See documentation for `ebnf-production-font'."
+  :type '(list :tag "Special 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))))
+  :group 'ebnf-special)
+
+
+(defcustom ebnf-special-shape 'bevel
+  "*Specify special box shape.
+
+See documentation for `ebnf-non-terminal-shape'."
+  :type '(radio :tag "Special Shape"
+		(const miter) (const round) (const bevel))
+  :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-border-width 0.5
+  "*Specify border width for special box."
+  :type 'number
+  :group 'ebnf-special)
+
+
+(defcustom ebnf-special-border-color "Black"
+  "*Specify border color for special box."
+  :type 'string
+  :group 'ebnf-special)
+
+
+(defcustom ebnf-except-font '(7 Courier "Black" "Gray90" bold italic)
+  "*Specify except font.
+
+See documentation for `ebnf-production-font'."
+  :type '(list :tag "Except 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))))
+  :group 'ebnf-except)
+
+
+(defcustom ebnf-except-shape 'bevel
+  "*Specify except box shape.
+
+See documentation for `ebnf-non-terminal-shape'."
+  :type '(radio :tag "Except Shape"
+		(const miter) (const round) (const bevel))
+  :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-border-width 0.25
+  "*Specify border width for except box."
+  :type 'number
+  :group 'ebnf-except)
+
+
+(defcustom ebnf-except-border-color "Black"
+  "*Specify border color for except box."
+  :type 'string
+  :group 'ebnf-except)
+
+
+(defcustom ebnf-repeat-font '(7 Courier "Black" "Gray85" bold italic)
+  "*Specify repeat font.
+
+See documentation for `ebnf-production-font'."
+  :type '(list :tag "Repeat 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))))
+  :group 'ebnf-repeat)
+
+
+(defcustom ebnf-repeat-shape 'bevel
+  "*Specify repeat box shape.
+
+See documentation for `ebnf-non-terminal-shape'."
+  :type '(radio :tag "Repeat Shape"
+		(const miter) (const round) (const bevel))
+  :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-border-width 0.0
+  "*Specify border width for repeat box."
+  :type 'number
+  :group 'ebnf-repeat)
+
+
+(defcustom ebnf-repeat-border-color "Black"
+  "*Specify border color for repeat box."
+  :type 'string
+  :group 'ebnf-repeat)
+
+
+(defcustom ebnf-terminal-font '(7 Courier "Black" "White")
+  "*Specify terminal font.
+
+See documentation for `ebnf-production-font'."
+  :type '(list :tag "Terminal 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))))
+  :group 'ebnf-terminal)
+
+
+(defcustom ebnf-terminal-shape 'miter
+  "*Specify terminal box shape.
+
+See documentation for `ebnf-non-terminal-shape'."
+  :type '(radio :tag "Terminal Shape"
+		(const miter) (const round) (const bevel))
+  :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-border-width 1.0
+  "*Specify border width for terminal box."
+  :type 'number
+  :group 'ebnf-terminal)
+
+
+(defcustom ebnf-terminal-border-color "Black"
+  "*Specify border color for terminal box."
+  :type 'string
+  :group 'ebnf-terminal)
+
+
+(defcustom ebnf-sort-production nil
+  "*Specify how productions are sorted.
+
+Valid values are:
+
+   nil			don't sort productions.
+   `ascending'		ascending sort.
+   any other value	descending sort."
+  :type '(radio :tag "Production Sort"
+		(const :tag "Ascending" ascending)
+		(const :tag "Descending" descending)
+		(other :tag "No Sort" nil))
+  :group 'ebnf-production)
+
+
+(defcustom ebnf-production-font '(10 Helvetica "Black" "White" bold)
+  "*Specify production header font.
+
+It is a list with the following form:
+
+   (SIZE NAME FOREGROUND BACKGROUND ATTRIBUTE...)
+
+Where:
+SIZE is the font size.
+NAME is the font name symbol.
+ATTRIBUTE is one of the following symbols:
+   bold      - use bold font.
+   italic    - use italic font.
+   underline - put a line under text.
+   strikeout - like underline, but the line is in middle of text.
+   overline  - like underline, but the line is over the text.
+   shadow    - text will have a shadow.
+   box       - text will be surrounded by a box.
+   outline   - print characters as hollow outlines.
+FOREGROUND is a foreground string color name; if it's nil, the default color is
+\"Black\".
+BACKGROUND is a background string color name; if it's nil, the default color is
+\"White\".
+
+See `ps-font-info-database' for valid font name."
+  :type '(list :tag "Production 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))))
+  :group 'ebnf-production)
+
+
+(defcustom ebnf-non-terminal-font '(7 Helvetica "Black" "White")
+  "*Specify non-terminal font.
+
+See documentation for `ebnf-production-font'."
+  :type '(list :tag "Non-Terminal 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))))
+  :group 'ebnf-non-terminal)
+
+
+(defcustom ebnf-non-terminal-shape 'round
+  "*Specify non-terminal box shape.
+
+Valid values are:
+
+   `miter'	+-------+
+		|       |
+		+-------+
+
+   `round'	 -------
+		(       )
+		 -------
+
+   `bevel'	/-------\\
+		|       |
+		\\-------/
+
+Any other value is treated as `miter'."
+  :type '(radio :tag "Non-Terminal Shape"
+		(const miter) (const round) (const bevel))
+  :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-border-width 1.0
+  "*Specify border width for non-terminal box."
+  :type 'number
+  :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-arrow-shape 'hollow
+  "*Specify the arrow shape.
+
+Valid values are:
+
+   `none'	======
+
+   `semi-up'	   *		   `transparent'  *
+		    *				  |*
+		=====*				  | *
+						==+==*
+						  | *
+						  |*
+						  *
+
+   `semi-down'	=====*		   `hollow'	  *
+		    *				  |*
+		   *				  | *
+						==+  *
+						  | *
+						  |*
+						  *
+
+   `simple'	   *		   `full'	  *
+		    *				  |*
+		=====*				  |X*
+		    *				==+XX*
+		   *				  |X*
+						  |*
+						  *
+
+   `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))
+  :group 'ebnf-shape)
+
+
+(defcustom ebnf-chart-shape 'round
+  "*Specify chart flow shape.
+
+See documentation for `ebnf-non-terminal-shape'."
+  :type '(radio :tag "Chart Flow Shape"
+		(const miter) (const round) (const bevel))
+  :group 'ebnf-shape)
+
+
+(defcustom ebnf-user-arrow nil
+  "*Specify a user arrow shape (a PostScript code).
+
+PostScript code should draw a right arrow.
+
+The anatomy of a right arrow is:
+
+   ...... Initial position
+   :
+   :     *.................
+   :     | *       }      }
+   :     |   *     } hT4  }
+   v     |     *   }      }
+   ======+======*...      } hT2
+   :     |     *:  }      }
+   :     |   *  :  } hT4  }
+   :     | *    :  }      }
+   :     *.................
+   :     :      :
+   :     :      :..........
+   :     :         } hT2  }
+   :     :..........      } hT
+   :               } hT2  }
+   :.......................
+
+Where `hT', `hT2' and `hT4' are predefined PostScript variable names that can be
+used to generate your own arrow.  As these variables are used along PostScript
+execution, *DON'T* modify the values of them.  Instead, copy the values, if you
+need to modify them.
+
+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'.
+
+See function `ebnf-user-arrow' for valid values and how values are processed."
+  :type '(radio :tag "User Arrow Shape"
+		(const nil)
+		string
+		symbol
+		(repeat :tag "List"
+			(radio string
+			       symbol
+			       sexp)))
+  :group 'ebnf-shape)
+
+
+(defcustom ebnf-syntax 'ebnf
+  "*Specify syntax to be recognized.
+
+Valid values are:
+
+   `ebnf'	ebnf2ps recognizes the syntax described above.
+		The following variables *ONLY* have effect with this
+		setting:
+		`ebnf-terminal-regexp', `ebnf-case-fold-search',
+		`ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
+
+   `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\").
+		The following variables *ONLY* have effect with this
+		setting:
+		`ebnf-iso-alternative-p' and `ebnf-iso-normalize-p'.
+
+   `yacc'	ebnf2ps recognizes the Yacc/Bison syntax.
+		The following variable *ONLY* has effect with this
+		setting:
+		`ebnf-yac-ignore-error-recovery'.
+
+Any other value is treated as `ebnf'."
+  :type '(radio :tag "Syntax"
+		(const ebnf) (const iso-ebnf) (const yacc))
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-lex-comment-char ?\;
+  "*Specify the line comment character.
+
+It's used only when `ebnf-syntax' is `ebnf'."
+  :type 'character
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-lex-eop-char ?.
+  "*Specify the end of production character.
+
+It's used only when `ebnf-syntax' is `ebnf'."
+  :type 'character
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-terminal-regexp nil
+  "*Specify how it's a terminal name.
+
+If it's nil, the terminal name must be enclosed by `\"'.
+If it's a string, it should be a regexp that it'll be used to determine a
+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)
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-case-fold-search nil
+  "*Non-nil means ignore case on matching.
+
+It's only used when `ebnf-terminal-regexp' is non-nil and when `ebnf-syntax' is
+`ebnf'."
+  :type 'boolean
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-iso-alternative-p nil
+  "*Non-nil means use alternative ISO EBNF.
+
+It's only used when `ebnf-syntax' is `iso-ebnf'.
+
+This variable affects the following symbol set:
+
+   STANDARD   ALTERNATIVE
+      |    ==>   / or !
+      [    ==>   (/
+      ]    ==>   /)
+      {    ==>   (:
+      }    ==>   :)
+      ;    ==>   ."
+  :type 'boolean
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-iso-normalize-p nil
+  "*Non-nil means normalize ISO EBNF syntax names.
+
+Normalize a name means that several contiguous spaces inside name become a
+single space, so \"A  B   C\" is normalized to  \"A B C\".
+
+It's only used when `ebnf-syntax' is `iso-ebnf'."
+  :type 'boolean
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-eps-prefix "ebnf--"
+  "*Specify EPS prefix file name.
+
+See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
+  :type 'string
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-entry-percentage 0.5	; middle
+  "*Specify entry height on alternatives.
+
+It must be a float between 0.0 (top) and 1.0 (bottom)."
+  :type 'number
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-default-width 0.6
+  "*Specify additional border width over default terminal, non-terminal or
+special."
+  :type 'number
+  :group 'ebnf2ps)
+
+
+;; Printing color requires x-color-values.
+(defcustom ebnf-color-p (or (fboundp 'x-color-values) ; Emacs
+			    (fboundp 'color-instance-rgb-components)) ; XEmacs
+  "*Non-nil means use color."
+  :type 'boolean
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-line-width 1.0
+  "*Specify flow line width."
+  :type 'number
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-line-color "Black"
+  "*Specify flow line color."
+  :type 'string
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-debug-ps nil
+  "*Non-nil means to generate PostScript debug procedures.
+
+It is intended to help PostScript programmers in debugging."
+  :type 'boolean
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-use-float-format t
+  "*Non-nil means use `%f' float format.
+
+The advantage of using float format is that ebnf2ps generates a little short
+PostScript file.
+
+If it occurs the error message:
+
+   Invalid format operation %f
+
+when executing ebnf2ps, set `ebnf-use-float-format' to nil."
+  :type 'boolean
+  :group 'ebnf2ps)
+
+
+(defcustom ebnf-yac-ignore-error-recovery nil
+  "*Non-nil means ignore error recovery.
+
+It's only used when `ebnf-syntax' is `yacc'."
+  :type 'boolean
+  :group 'ebnf-syntatic)
+
+
+(defcustom ebnf-ignore-empty-rule nil
+  "*Non-nil means ignore empty rules.
+
+It's interesting to set this variable if your Yacc/Bison grammar has a lot of
+middle action rule."
+  :type 'boolean
+  :group 'ebnf-optimization)
+
+
+(defcustom ebnf-optimize nil
+  "*Non-nil means optimize syntatic chart of rules.
+
+The following optimizations are done:
+
+   left recursion:
+   1.  A = B | A C.             ==>   A = B {C}*.
+   2.  A = B | A B.             ==>   A = {B}+.
+   3.  A =   | A B.             ==>   A = {B}*.
+   4.  A = B | A C B.           ==>   A = {B || C}+.
+   5.  A = B | D | A C | A E.   ==>   A = ( B | D ) { C | E }*.
+
+   optional:
+   6.  A = B | .                ==>   A = [B].
+   7.  A =   | B .              ==>   A = [B].
+
+   factoration:
+   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
+  :group 'ebnf-optimization)
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Customization
+
+
+;;;###autoload
+(defun ebnf-customize ()
+  "Customization for ebnf group."
+  (interactive)
+  (customize-group 'ebnf2ps))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; User commands
+
+
+;;;###autoload
+(defun ebnf-print-buffer (&optional filename)
+  "Generate and print a PostScript syntatic chart image of the buffer.
+
+When called with a numeric prefix argument (C-u), prompts the user for
+the name of a file to save the PostScript image in, instead of sending
+it to the printer.
+
+More specifically, the FILENAME argument is treated as follows: if it
+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)))
+  (ebnf-print-region (point-min) (point-max) filename))
+
+
+;;;###autoload
+(defun ebnf-print-region (from to &optional filename)
+  "Generate and print a PostScript syntatic 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)))
+  (run-hooks 'ebnf-hook)
+  (or (ebnf-spool-region from to)
+      (ps-do-despool filename)))
+
+
+;;;###autoload
+(defun ebnf-spool-buffer ()
+  "Generate and spool a PostScript syntatic chart image of the buffer.
+Like `ebnf-print-buffer' except that the PostScript image is saved in a
+local buffer to be sent to the printer later.
+
+Use the command `ebnf-despool' to send the spooled images to the printer."
+  (interactive)
+  (ebnf-spool-region (point-min) (point-max)))
+
+
+;;;###autoload
+(defun ebnf-spool-region (from to)
+  "Generate a PostScript syntatic chart image of the region and spool locally.
+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")
+  (ebnf-generate-region from to 'ebnf-generate))
+
+
+;;;###autoload
+(defun ebnf-eps-buffer ()
+  "Generate a PostScript syntatic chart image of the buffer in a EPS file.
+
+Indeed, for each production is generated a EPS file.
+The EPS file name has the following form:
+
+   <PREFIX><PRODUCTION>.eps
+
+<PREFIX>     is given by variable `ebnf-eps-prefix'.
+	     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\".
+
+WARNING: It's *NOT* asked any confirmation to override an existing file."
+  (interactive)
+  (ebnf-eps-region (point-min) (point-max)))
+
+
+;;;###autoload
+(defun ebnf-eps-region (from to)
+  "Generate a PostScript syntatic chart image of the region in a EPS file.
+
+Indeed, for each production is generated a EPS file.
+The EPS file name has the following form:
+
+   <PREFIX><PRODUCTION>.eps
+
+<PREFIX>     is given by variable `ebnf-eps-prefix'.
+	     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\".
+
+WARNING: It's *NOT* asked any confirmation to override an existing file."
+  (interactive "r")
+  (let ((ebnf-eps-executing t))
+    (ebnf-generate-region from to 'ebnf-generate-eps)))
+
+
+;;;###autoload
+(defalias 'ebnf-despool 'ps-despool)
+
+
+;;;###autoload
+(defun ebnf-syntax-buffer ()
+  "Does a syntatic analysis of the current buffer."
+  (interactive)
+  (ebnf-syntax-region (point-min) (point-max)))
+
+
+;;;###autoload
+(defun ebnf-syntax-region (from to)
+  "Does a syntatic analysis of a region."
+  (interactive "r")
+  (ebnf-generate-region from to nil))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Utilities
+
+
+;;;###autoload
+(defun ebnf-setup ()
+  "Return the current ebnf2ps setup."
+  (format
+   "
+\(setq ebnf-special-font                %s
+      ebnf-special-shape               %s
+      ebnf-special-shadow              %S
+      ebnf-special-border-width        %S
+      ebnf-special-border-color        %S
+      ebnf-except-font                 %s
+      ebnf-except-shape                %s
+      ebnf-except-shadow               %S
+      ebnf-except-border-width         %S
+      ebnf-except-border-color         %S
+      ebnf-repeat-font                 %s
+      ebnf-repeat-shape                %s
+      ebnf-repeat-shadow               %S
+      ebnf-repeat-border-width         %S
+      ebnf-repeat-border-color         %S
+      ebnf-terminal-regexp             %S
+      ebnf-case-fold-search            %S
+      ebnf-terminal-font               %s
+      ebnf-terminal-shape              %s
+      ebnf-terminal-shadow             %S
+      ebnf-terminal-border-width       %S
+      ebnf-terminal-border-color       %S
+      ebnf-non-terminal-font           %s
+      ebnf-non-terminal-shape          %s
+      ebnf-non-terminal-shadow         %S
+      ebnf-non-terminal-border-width   %S
+      ebnf-non-terminal-border-color   %S
+      ebnf-sort-production             %s
+      ebnf-production-font             %s
+      ebnf-arrow-shape                 %s
+      ebnf-chart-shape                 %s
+      ebnf-user-arrow                  %s
+      ebnf-horizontal-orientation      %S
+      ebnf-horizontal-max-height       %S
+      ebnf-production-horizontal-space %S
+      ebnf-production-vertical-space   %S
+      ebnf-justify-sequence            %s
+      ebnf-lex-comment-char            ?\\%03o
+      ebnf-lex-eop-char                ?\\%03o
+      ebnf-syntax                      %s
+      ebnf-iso-alternative-p           %S
+      ebnf-iso-normalize-p             %S
+      ebnf-eps-prefix                  %S
+      ebnf-entry-percentage            %S
+      ebnf-color-p                     %S
+      ebnf-line-width                  %S
+      ebnf-line-color                  %S
+      ebnf-debug-ps                    %S
+      ebnf-use-float-format            %S
+      ebnf-yac-ignore-error-recovery   %S
+      ebnf-ignore-empty-rule           %S
+      ebnf-optimize                    %S)
+"
+   (ps-print-quote ebnf-special-font)
+   (ps-print-quote ebnf-special-shape)
+   ebnf-special-shadow
+   ebnf-special-border-width
+   ebnf-special-border-color
+   (ps-print-quote ebnf-except-font)
+   (ps-print-quote ebnf-except-shape)
+   ebnf-except-shadow
+   ebnf-except-border-width
+   ebnf-except-border-color
+   (ps-print-quote ebnf-repeat-font)
+   (ps-print-quote ebnf-repeat-shape)
+   ebnf-repeat-shadow
+   ebnf-repeat-border-width
+   ebnf-repeat-border-color
+   ebnf-terminal-regexp
+   ebnf-case-fold-search
+   (ps-print-quote ebnf-terminal-font)
+   (ps-print-quote ebnf-terminal-shape)
+   ebnf-terminal-shadow
+   ebnf-terminal-border-width
+   ebnf-terminal-border-color
+   (ps-print-quote ebnf-non-terminal-font)
+   (ps-print-quote ebnf-non-terminal-shape)
+   ebnf-non-terminal-shadow
+   ebnf-non-terminal-border-width
+   ebnf-non-terminal-border-color
+   (ps-print-quote ebnf-sort-production)
+   (ps-print-quote ebnf-production-font)
+   (ps-print-quote ebnf-arrow-shape)
+   (ps-print-quote ebnf-chart-shape)
+   (ps-print-quote ebnf-user-arrow)
+   ebnf-horizontal-orientation
+   ebnf-horizontal-max-height
+   ebnf-production-horizontal-space
+   ebnf-production-vertical-space
+   (ps-print-quote ebnf-justify-sequence)
+   ebnf-lex-comment-char
+   ebnf-lex-eop-char
+   (ps-print-quote ebnf-syntax)
+   ebnf-iso-alternative-p
+   ebnf-iso-normalize-p
+   ebnf-eps-prefix
+   ebnf-entry-percentage
+   ebnf-color-p
+   ebnf-line-width
+   ebnf-line-color
+   ebnf-debug-ps
+   ebnf-use-float-format
+   ebnf-yac-ignore-error-recovery
+   ebnf-ignore-empty-rule
+   ebnf-optimize))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Style variables
+
+
+(defvar ebnf-stack-style nil
+  "Used in functions `ebnf-reset-style', `ebnf-push-style' and
+`ebnf-pop-style'.")
+
+
+(defvar ebnf-current-style 'default
+  "Used in functions `ebnf-apply-style' and `ebnf-push-style'.")
+
+
+(defconst ebnf-style-custom-list
+  '(ebnf-special-font
+    ebnf-special-shape
+    ebnf-special-shadow
+    ebnf-special-border-width
+    ebnf-special-border-color
+    ebnf-except-font
+    ebnf-except-shape
+    ebnf-except-shadow
+    ebnf-except-border-width
+    ebnf-except-border-color
+    ebnf-repeat-font
+    ebnf-repeat-shape
+    ebnf-repeat-shadow
+    ebnf-repeat-border-width
+    ebnf-repeat-border-color
+    ebnf-terminal-regexp
+    ebnf-case-fold-search
+    ebnf-terminal-font
+    ebnf-terminal-shape
+    ebnf-terminal-shadow
+    ebnf-terminal-border-width
+    ebnf-terminal-border-color
+    ebnf-non-terminal-font
+    ebnf-non-terminal-shape
+    ebnf-non-terminal-shadow
+    ebnf-non-terminal-border-width
+    ebnf-non-terminal-border-color
+    ebnf-sort-production
+    ebnf-production-font
+    ebnf-arrow-shape
+    ebnf-chart-shape
+    ebnf-user-arrow
+    ebnf-horizontal-orientation
+    ebnf-horizontal-max-height
+    ebnf-production-horizontal-space
+    ebnf-production-vertical-space
+    ebnf-justify-sequence
+    ebnf-lex-comment-char
+    ebnf-lex-eop-char
+    ebnf-syntax
+    ebnf-iso-alternative-p
+    ebnf-iso-normalize-p
+    ebnf-eps-prefix
+    ebnf-entry-percentage
+    ebnf-color-p
+    ebnf-line-width
+    ebnf-line-color
+    ebnf-debug-ps
+    ebnf-use-float-format
+    ebnf-yac-ignore-error-recovery
+    ebnf-ignore-empty-rule
+    ebnf-optimize)
+  "List of valid symbol custom variable.")
+
+
+(defvar ebnf-style-database
+  '(;; EBNF default
+    (default
+      nil
+      (ebnf-special-font          . '(7 Courier "Black" "Gray95" bold italic))
+      (ebnf-special-shape               . 'bevel)
+      (ebnf-special-shadow              . nil)
+      (ebnf-special-border-width        . 0.5)
+      (ebnf-special-border-color        . "Black")
+      (ebnf-except-font           . '(7 Courier "Black" "Gray90" bold italic))
+      (ebnf-except-shape                . 'bevel)
+      (ebnf-except-shadow               . nil)
+      (ebnf-except-border-width         . 0.25)
+      (ebnf-except-border-color         . "Black")
+      (ebnf-repeat-font           . '(7 Courier "Black" "Gray85" bold italic))
+      (ebnf-repeat-shape                . 'bevel)
+      (ebnf-repeat-shadow               . nil)
+      (ebnf-repeat-border-width         . 0.0)
+      (ebnf-repeat-border-color         . "Black")
+      (ebnf-terminal-regexp             . nil)
+      (ebnf-case-fold-search            . nil)
+      (ebnf-terminal-font               . '(7  Courier   "Black" "White"))
+      (ebnf-terminal-shape              . 'miter)
+      (ebnf-terminal-shadow             . nil)
+      (ebnf-terminal-border-width       . 1.0)
+      (ebnf-terminal-border-color       . "Black")
+      (ebnf-non-terminal-font           . '(7  Helvetica "Black" "White"))
+      (ebnf-non-terminal-shape          . 'round)
+      (ebnf-non-terminal-shadow         . nil)
+      (ebnf-non-terminal-border-width   . 1.0)
+      (ebnf-non-terminal-border-color   . "Black")
+      (ebnf-sort-production             . nil)
+      (ebnf-production-font             . '(10 Helvetica "Black" "White" bold))
+      (ebnf-arrow-shape                 . 'hollow)
+      (ebnf-chart-shape                 . 'round)
+      (ebnf-user-arrow                  . nil)
+      (ebnf-horizontal-orientation      . nil)
+      (ebnf-horizontal-max-height       . nil)
+      (ebnf-production-horizontal-space . 0.0)
+      (ebnf-production-vertical-space   . 0.0)
+      (ebnf-justify-sequence            . 'center)
+      (ebnf-lex-comment-char            . ?\;)
+      (ebnf-lex-eop-char                . ?.)
+      (ebnf-syntax                      . 'ebnf)
+      (ebnf-iso-alternative-p           . nil)
+      (ebnf-iso-normalize-p             . nil)
+      (ebnf-eps-prefix                  . "ebnf--")
+      (ebnf-entry-percentage            . 0.5)
+      (ebnf-color-p   . (or (fboundp 'x-color-values) ; Emacs
+			    (fboundp 'color-instance-rgb-components))) ; XEmacs
+      (ebnf-line-width                  . 1.0)
+      (ebnf-line-color                  . "Black")
+      (ebnf-debug-ps                    . nil)
+      (ebnf-use-float-format            . t)
+      (ebnf-yac-ignore-error-recovery   . nil)
+      (ebnf-ignore-empty-rule           . nil)
+      (ebnf-optimize                    . nil))
+    ;; Happy EBNF default
+    (happy
+     default
+     (ebnf-justify-sequence            . 'left)
+     (ebnf-lex-comment-char            . ?\#)
+     (ebnf-lex-eop-char                . ?\;))
+    ;; ISO EBNF default
+    (iso-ebnf
+     default
+     (ebnf-syntax                      . 'iso-ebnf))
+    ;; Yacc/Bison default
+    (yacc
+     default
+     (ebnf-syntax                      . 'yacc))
+    )
+  "Style database.
+
+Each element has the following form:
+
+   (CUSTOM INHERITS (VAR . VALUE)...)
+
+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.
+
+Don't handle this variable directly.  Use functions `ebnf-insert-style' and
+`ebnf-merge-style'.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Style commands
+
+
+;;;###autoload
+(defun ebnf-insert-style (name inherits &rest values)
+  "Insert a new style NAME with inheritance INHERITS and values VALUES."
+  (interactive)
+  (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))
+  (setq ebnf-style-database
+	(cons (cons name (cons inherits (ebnf-check-style-values values)))
+	      ebnf-style-database)))
+
+
+;;;###autoload
+(defun ebnf-merge-style (name &rest values)
+  "Merge values of style NAME with style VALUES."
+  (interactive)
+  (let ((style (or (assoc name ebnf-style-database)
+		   (error "Style name does'nt exist: %s" name)))
+	(merge (ebnf-check-style-values values))
+	val elt new check)
+    ;; modify value of existing variables
+    (setq val (nthcdr 2 style))
+    (while merge
+      (setq check (car merge)
+	    merge (cdr merge)
+	    elt   (assoc (car check) val))
+      (if elt
+	  (setcdr elt (cdr check))
+	(setq new (cons check new))))
+    ;; insert new variables
+    (nconc style (nreverse new))))
+
+
+;;;###autoload
+(defun ebnf-apply-style (style)
+  "Set STYLE to current style.
+
+It returns the old style symbol."
+  (interactive)
+  (prog1
+      ebnf-current-style
+    (and (ebnf-apply-style1 style)
+	 (setq ebnf-current-style style))))
+
+
+;;;###autoload
+(defun ebnf-reset-style (&optional style)
+  "Reset current style.
+
+It returns the old style symbol."
+  (interactive)
+  (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.
+
+It returns the old style symbol."
+  (interactive)
+  (prog1
+      ebnf-current-style
+    (setq ebnf-stack-style (cons ebnf-current-style ebnf-stack-style))
+    (and style
+	 (ebnf-apply-style style))))
+
+
+;;;###autoload
+(defun ebnf-pop-style ()
+  "Pop a style and set it to current style.
+
+It returns the old style symbol."
+  (interactive)
+  (prog1
+      (ebnf-apply-style (car ebnf-stack-style))
+    (setq ebnf-stack-style (cdr ebnf-stack-style))))
+
+
+(defun ebnf-apply-style1 (style)
+  (let ((value (cdr (assoc style ebnf-style-database))))
+    (prog1
+	value
+      (and (car value) (ebnf-apply-style1 (car value)))
+      (while (setq value (cdr value))
+	(set (caar value) (eval (cdar value)))))))
+
+
+(defun ebnf-check-style-values (values)
+  (let (style)
+    (while values
+      (and (memq (car values) ebnf-style-custom-list)
+	   (setq style (cons (car values) style)))
+      (setq values (cdr values)))
+    (nreverse style)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Internal variables
+
+
+(make-local-hook 'ebnf-hook)
+(make-local-hook 'ebnf-production-hook)
+(make-local-hook 'ebnf-page-hook)
+
+
+(defvar ebnf-eps-buffer-name " *EPS*")
+(defvar ebnf-parser-func     nil)
+(defvar ebnf-eps-executing   nil)
+(defvar ebnf-eps-upper-x     0.0)
+(make-variable-buffer-local 'ebnf-eps-upper-x)
+(defvar ebnf-eps-upper-y     0.0)
+(make-variable-buffer-local 'ebnf-eps-upper-y)
+(defvar ebnf-eps-prod-width  0.0)
+(make-variable-buffer-local 'ebnf-eps-prod-width)
+(defvar ebnf-eps-max-height 0.0)
+(make-variable-buffer-local 'ebnf-eps-max-height)
+(defvar ebnf-eps-max-width  0.0)
+(make-variable-buffer-local 'ebnf-eps-max-width)
+
+
+(defvar ebnf-eps-context nil
+  "List of EPS file name during parsing.
+
+See section \"Actions in Comments\" in ebnf2ps documentation.")
+
+
+(defvar ebnf-eps-production-list nil
+  "Alist associating production name with EPS file name list.
+
+Each element has the following form:
+
+   (PRODUCTION EPS-FILENAME...)
+
+PRODUCTION is the production name.
+EPS-FILENAME is the EPS file name.
+
+It's 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
+  '((none        . 0)
+    (semi-up     . 1)
+    (semi-down   . 2)
+    (simple      . 3)
+    (transparent . 4)
+    (hollow      . 5)
+    (full        . 6)
+    (user        . 7))
+  "Alist associating values for `ebnf-arrow-shape'.
+
+See documentation for `ebnf-arrow-shape'.")
+
+
+(defconst ebnf-terminal-shape-alist
+  '((miter . 0)
+    (round . 1)
+    (bevel . 2))
+  "Alist associating values from `ebnf-terminal-shape' to a bit vector.
+
+See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
+`ebnf-chart-shape'.")
+
+
+(defvar ebnf-limit            nil)
+(defvar ebnf-action           nil)
+(defvar ebnf-action-list      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-basic-width      0)
+(defvar ebnf-basic-height     0)
+(defvar ebnf-vertical-space   0)
+(defvar ebnf-horizontal-space 0)
+
+
+(defvar ebnf-settings         nil)
+(defvar ebnf-fonts-required   nil)
+
+
+(defconst ebnf-debug
+  "
+% === begin EBNF procedures to help debugging
+
+% Mark visually current point:  string debug
+/debug
+{/-s- exch def
+ currentpoint
+ gsave -s- show grestore
+ gsave
+ 20 20 rlineto
+ 0 -40 rlineto
+ -40 40 rlineto
+ 0 -40 rlineto
+ 20 20 rlineto
+ stroke
+ grestore
+ moveto
+}def
+
+% Show number value:  number string debug-number
+/debug-number
+{gsave
+ 20 0 rmoveto show ([) show 60 string cvs show (]) show
+ grestore
+}def
+
+% === end   EBNF procedures to help debugging
+
+"
+  "This is intended to help debugging PostScript programming.")
+
+
+(defconst ebnf-prologue
+  "
+% === begin EBNF engine
+
+% --- Basic Definitions
+
+/fS F
+/SpaceS FontHeight 0.5 mul def
+/HeightS FontHeight FontHeight add def
+
+/fE F
+/SpaceE FontHeight 0.5 mul def
+/HeightE FontHeight FontHeight add def
+
+/fR F
+/SpaceR FontHeight 0.5 mul def
+/HeightR FontHeight FontHeight add def
+
+/fT F
+/SpaceT FontHeight 0.5 mul def
+/HeightT FontHeight FontHeight add def
+
+/fNT F
+/SpaceNT FontHeight 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
+
+/Er 0.1 def	% Error factor
+
+
+/c{currentpoint}bind def
+/xyi{/xi c /yi exch def def}bind def
+/xyo{/xo c /yo exch def def}bind def
+/xyp{/xp c /yp exch def def}bind def
+/xyt{/xt c /yt exch def def}bind def
+
+% vertical movement: x y height vm
+/vm{add moveto}bind def
+
+% horizontal movement: x y width hm
+/hm{3 -1 roll exch add exch moveto}bind def
+
+% set color: [R G B] SetRGB
+/SetRGB{aload pop setrgbcolor}bind def
+
+% filling gray area: gray-scale FillGray
+/FillGray{gsave setgray fill grestore}bind def
+
+% filling color area: [R G B] FillRGB
+/FillRGB{gsave SetRGB fill grestore}bind def
+
+/Stroke{LineWidth setlinewidth LineColor SetRGB stroke}bind def
+/StrokeShape{borderwidth setlinewidth bordercolor SetRGB stroke}bind def
+/Gstroke{gsave Stroke grestore}bind def
+
+% Empty Line: width EL
+/EL{0 rlineto Gstroke}bind def
+
+% --- Arrows
+
+/Down{hT2 neg hT4 neg rlineto}bind def
+
+/Arrow
+{hT2 neg hT4 rmoveto
+ hT2 hT4 neg rlineto
+ Down
+}bind def
+
+/ArrowPath{c newpath moveto Arrow closepath}bind def
+
+%>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
+]def
+
+/RA
+{hT 0 rlineto
+ c
+ RA-vector ArrowShape get exec
+ Gstroke
+ moveto
+}def
+
+% rotation DrawArrow
+/DrawArrow
+{gsave
+ 0 0 translate
+ rotate
+ RA
+ c
+ grestore
+ rmoveto
+}def
+
+%>Left Arrow: LA
+%  /
+% +---*
+%  \\
+/LA{180 DrawArrow}def
+
+%>Up Arrow: UA
+%  +
+% /|\\
+%  |
+%  *
+/UA{90 DrawArrow}def
+
+%>Down Arrow: DA
+%  *
+%  |
+% \\|/
+%  +
+/DA{270 DrawArrow}def
+
+% --- Corners
+
+%>corner Right Descendent: height arrow corner_RD
+%   _             | arrow
+%  /   height > 0 |  0 - none
+% |               |  1 - right
+% *    ---------- |  2 - left
+% |               |  3 - vertical
+%  \\   height < 0 |
+%   -             |
+/cRD0-vector
+[% 0 - none
+ {0 h rlineto
+  hT 0 rlineto}
+ % 1 - right
+ {0 h rlineto
+  RA}
+ % 2 - left
+ {hT 0 rmoveto xyi
+  LA
+  0 h neg rlineto
+  xi yi moveto}
+ % 3 - vertical
+ {hT h rmoveto xyi
+  hT neg 0 rlineto
+  h 0 gt{DA}{UA}ifelse
+  xi yi moveto}
+]def
+
+/cRD-vector
+[{cRD0-vector arrow get exec}	% 0 - miter
+ {0 0 0 h hT h rcurveto}	% 1 - rounded
+ {hT h rlineto}			% 2 - bevel
+]def
+
+/corner_RD
+{/arrow exch def /h exch def
+ cRD-vector ChartShape get exec
+ Gstroke
+}def
+
+%>corner Right Ascendent: height arrow corner_RA
+%                 | arrow
+%    | height > 0 |  0 - none
+%   /             |  1 - right
+% *-   ---------- |  2 - left
+%   \\             |  3 - vertical
+%    | height < 0 |
+%                 |
+/cRA0-vector
+[% 0 - none
+ {hT 0 rlineto
+  0 h rlineto}
+ % 1 - right
+ {RA
+  0 h rlineto}
+ % 2 - left
+ {hT h rmoveto xyi
+  0 h neg rlineto
+  LA
+  xi yi moveto}
+ % 3 - vertical
+ {hT h rmoveto xyi
+  h 0 gt{DA}{UA}ifelse
+  hT neg 0 rlineto
+  xi yi moveto}
+]def
+
+/cRA-vector
+[{cRA0-vector arrow get exec}	% 0 - miter
+ {0 0 hT 0 hT h rcurveto}	% 1 - rounded
+ {hT h rlineto}			% 2 - bevel
+]def
+
+/corner_RA
+{/arrow exch def /h exch def
+ cRA-vector ChartShape get exec
+ Gstroke
+}def
+
+%>corner Left Descendent: height arrow corner_LD
+%  _              | arrow
+%   \\  height > 0 |  0 - none
+%    |            |  1 - right
+%    * ---------- |  2 - left
+%    |            |  3 - vertical
+%   /  height < 0 |
+%  -              |
+/cLD0-vector
+[% 0 - none
+ {0 h rlineto
+  hT neg 0 rlineto}
+ % 1 - right
+ {hT neg h rmoveto xyi
+  RA
+  0 h neg rlineto
+  xi yi moveto}
+ % 2 - left
+ {0 h rlineto
+  LA}
+ % 3 - vertical
+ {hT neg h rmoveto xyi
+  hT 0 rlineto
+  h 0 gt{DA}{UA}ifelse
+  xi yi moveto}
+]def
+
+/cLD-vector
+[{cLD0-vector arrow get exec}	% 0 - miter
+ {0 0 0 h hT neg h rcurveto}	% 1 - rounded
+ {hT neg h rlineto}		% 2 - bevel
+]def
+
+/corner_LD
+{/arrow exch def /h exch def
+ cLD-vector ChartShape get exec
+ Gstroke
+}def
+
+%>corner Left Ascendent: height arrow corner_LA
+%                 | arrow
+% |    height > 0 |  0 - none
+%  \\              |  1 - right
+%   -* ---------- |  2 - left
+%  /              |  3 - vertical
+% |    height < 0 |
+%                 |
+/cLA0-vector
+[% 0 - none
+ {hT neg 0 rlineto
+  0 h rlineto}
+ % 1 - right
+ {hT neg h rmoveto xyi
+  0 h neg rlineto
+  RA
+  xi yi moveto}
+ % 2 - left
+ {LA
+  0 h rlineto}
+ % 3 - vertical
+ {hT neg h rmoveto xyi
+  h 0 gt{DA}{UA}ifelse
+  hT 0 rlineto
+  xi yi moveto}
+]def
+
+/cLA-vector
+[{cLA0-vector arrow get exec}		% 0 - miter
+ {0 0 hT neg 0 hT neg h rcurveto}	% 1 - rounded
+ {hT neg h rlineto}			% 2 - bevel
+]def
+
+/corner_LA
+{/arrow exch def /h exch def
+ cLA-vector ChartShape get exec
+ Gstroke
+}def
+
+% --- Flow Stuff
+
+% height prepare_height |- line_height corner_height corner_height
+/prepare_height
+{dup 0 gt
+ {T sub hT}
+ {T add hT neg}ifelse
+ dup
+}def
+
+%>Left Alternative: height LAlt
+%      _
+%     /
+%    |   height > 0
+%    |
+%   /
+% *-     ----------
+%   \\
+%    |
+%    |   height < 0
+%     \\
+%      -
+/LAlt
+{dup 0 eq
+ {T exch rlineto}
+ {dup abs T lt
+  {0.5 mul dup
+   1 corner_RA
+   0 corner_RD}
+  {prepare_height
+   1 corner_RA
+   exch 0 exch rlineto
+   0 corner_RD
+  }ifelse
+ }ifelse
+}def
+
+%>Left Loop: height LLoop
+%   _
+%  /
+% |      height > 0
+% |
+%  \\
+%   -*   ----------
+%  /
+% |
+% |      height < 0
+%  \\
+%   -
+/LLoop
+{prepare_height
+ 3 corner_LA
+ exch 0 exch rlineto
+ 0 corner_RD
+}def
+
+%>Right Alternative: height RAlt
+% _
+%  \\
+%   |    height > 0
+%   |
+%    \\
+%     -* ----------
+%    /
+%   |
+%   |    height < 0
+%  /
+% -
+/RAlt
+{dup 0 eq
+ {T neg exch rlineto}
+ {dup abs T lt
+  {0.5 mul dup
+   1 corner_LA
+   0 corner_LD}
+  {prepare_height
+   1 corner_LA
+   exch 0 exch rlineto
+   0 corner_LD
+  }ifelse
+ }ifelse
+}def
+
+%>Right Loop: height RLoop
+%  _
+%   \\
+%    |   height > 0
+%    |
+%   /
+% *-     ----------
+%   \\
+%    |
+%    |   height < 0
+%   /
+%  -
+/RLoop
+{prepare_height
+ 1 corner_RA
+ exch 0 exch rlineto
+ 0 corner_LD
+}def
+
+% --- Terminal, Non-terminal and Special Basics
+
+% string width prepare-width |- string
+/prepare-width
+{/width exch def
+ dup stringwidth pop space add space add width exch sub 0.5 mul
+ /w exch def
+}def
+
+% string width begin-right
+/begin-right
+{xyo
+ prepare-width
+ w hT sub EL
+ RA
+}def
+
+% end-right
+/end-right
+{xo width add Er add yo moveto
+ w Er add neg EL
+ xo yo moveto
+}def
+
+% string width begin-left
+/begin-left
+{xyo
+ prepare-width
+ w EL
+}def
+
+% end-left
+/end-left
+{xo width add Er add yo moveto
+ hT w sub Er add EL
+ LA
+ xo yo moveto
+}def
+
+/ShapePath-vector
+[% 0 - miter
+ {xx yy moveto
+  xx YY lineto
+  XX YY lineto
+  XX yy lineto}
+ % 1 - rounded
+ {/half YY yy sub 0.5 mul abs def
+  xx half add YY moveto
+  0 0 half neg 0 half neg half neg rcurveto
+  0 0 0 half neg half half neg rcurveto
+  XX xx sub abs half sub half sub 0 rlineto
+  0 0 half 0 half half rcurveto
+  0 0 0 half half neg half rcurveto}
+ % 2 - bevel
+ {/quarter YY yy sub 0.25 mul abs def
+  xx quarter add YY moveto
+  quarter neg quarter neg rlineto
+  0 quarter quarter add neg rlineto
+  quarter quarter neg rlineto
+  XX xx sub abs quarter sub quarter sub 0 rlineto
+  quarter quarter rlineto
+  0 quarter quarter add rlineto
+  quarter neg quarter rlineto}
+]def
+
+/doShapePath
+{newpath
+ ShapePath-vector shape get exec
+ closepath
+}def
+
+/doShapeShadow
+{gsave
+ Xshadow Xshadow add Xshadow add
+ Yshadow Yshadow add Yshadow add translate
+ doShapePath
+ 0.9 FillGray
+ grestore
+}def
+
+/doShape
+{gsave
+ doShapePath
+ shapecolor FillRGB
+ StrokeShape
+ grestore
+}def
+
+% string SBound |- string
+/SBound
+{/xx c dup /yy exch def
+ FontHeight add /YY exch def def
+ dup stringwidth pop xx add /XX exch def
+ Effect 8 and 0 ne
+ {/yy yy YShadow add def
+  /XX XX XShadow add def
+ }if
+}def
+
+% string SBox
+/SBox
+{gsave
+ c space sub moveto
+ SBound
+ /XX XX space add space add def
+ /YY YY space add def
+ /yy yy space sub def
+ shadow{doShapeShadow}if
+ doShape
+ space Descent abs rmoveto
+ foreground SetRGB S
+ grestore
+}def
+
+% --- Terminal
+
+% TeRminal: string TR
+/TR
+{/Effect EffectT def
+ /shape ShapeT def
+ /shapecolor BackgroundT def
+ /borderwidth BorderWidthT def
+ /bordercolor BorderColorT def
+ /foreground ForegroundT def
+ /shadow ShadowT def
+ SBox
+}def
+
+%>Right Terminal: string width RT |- x y
+/RT
+{xyt
+ /fT F
+ /space SpaceT def
+ begin-right
+ TR
+ end-right
+ xt yt
+}def
+
+%>Left Terminal: string width LT |- x y
+/LT
+{xyt
+ /fT F
+ /space SpaceT def
+ begin-left
+ TR
+ end-left
+ xt yt
+}def
+
+%>Right Terminal Default: string width RTD |- x y
+/RTD
+{/-save- BorderWidthT def
+ /BorderWidthT BorderWidthT DefaultWidth add def
+ RT
+ /BorderWidthT -save- def
+}def
+
+%>Left Terminal Default: string width LTD |- x y
+/LTD
+{/-save- BorderWidthT def
+ /BorderWidthT BorderWidthT DefaultWidth add def
+ LT
+ /BorderWidthT -save- def
+}def
+
+% --- Non-Terminal
+
+% Non-Terminal: string NT
+/NT
+{/Effect EffectNT def
+ /shape ShapeNT def
+ /shapecolor BackgroundNT def
+ /borderwidth BorderWidthNT def
+ /bordercolor BorderColorNT def
+ /foreground ForegroundNT def
+ /shadow ShadowNT def
+ SBox
+}def
+
+%>Right Non-Terminal: string width RNT |- x y
+/RNT
+{xyt
+ /fNT F
+ /space SpaceNT def
+ begin-right
+ NT
+ end-right
+ xt yt
+}def
+
+%>Left Non-Terminal: string width LNT |- x y
+/LNT
+{xyt
+ /fNT F
+ /space SpaceNT def
+ begin-left
+ NT
+ end-left
+ xt yt
+}def
+
+%>Right Non-Terminal Default: string width RNTD |- x y
+/RNTD
+{/-save- BorderWidthNT def
+ /BorderWidthNT BorderWidthNT DefaultWidth add def
+ RNT
+ /BorderWidthNT -save- def
+}def
+
+%>Left Non-Terminal Default: string width LNTD |- x y
+/LNTD
+{/-save- BorderWidthNT def
+ /BorderWidthNT BorderWidthNT DefaultWidth add def
+ LNT
+ /BorderWidthNT -save- def
+}def
+
+% --- Special
+
+% SPecial: string SP
+/SP
+{/Effect EffectS def
+ /shape ShapeS def
+ /shapecolor BackgroundS def
+ /borderwidth BorderWidthS def
+ /bordercolor BorderColorS def
+ /foreground ForegroundS def
+ /shadow ShadowS def
+ SBox
+}def
+
+%>Right SPecial: string width RSP |- x y
+/RSP
+{xyt
+ /fS F
+ /space SpaceS def
+ begin-right
+ SP
+ end-right
+ xt yt
+}def
+
+%>Left SPecial: string width LSP |- x y
+/LSP
+{xyt
+ /fS F
+ /space SpaceS def
+ begin-left
+ SP
+ end-left
+ xt yt
+}def
+
+%>Right SPecial Default: string width RSPD |- x y
+/RSPD
+{/-save- BorderWidthS def
+ /BorderWidthS BorderWidthS DefaultWidth add def
+ RSP
+ /BorderWidthS -save- def
+}def
+
+%>Left SPecial Default: string width LSPD |- x y
+/LSPD
+{/-save- BorderWidthS def
+ /BorderWidthS BorderWidthS DefaultWidth add def
+ LSP
+ /BorderWidthS -save- def
+}def
+
+% --- Repeat and Except basics
+
+/begin-direction
+{/w width rwidth sub 0.5 mul def
+ width 0 rmoveto}def
+
+/end-direction
+{gsave
+ /xx c entry add /YY exch def def
+ /yy YY height sub def
+ /XX xx rwidth add def
+ shadow{doShapeShadow}if
+ doShape
+ grestore
+}def
+
+/right-direction
+{begin-direction
+ w neg EL
+ xt yt moveto
+ w hT sub EL RA
+ end-direction
+}def
+
+/left-direction
+{begin-direction
+ hT w sub EL LA
+ xt yt moveto
+ w EL
+ end-direction
+}def
+
+% --- Repeat
+
+% entry height width rwidth begin-repeat
+/begin-repeat
+{/rwidth exch def
+ /width exch def
+ /height exch def
+ /entry exch def
+ /fR F
+ /space SpaceR def
+ /Effect EffectR def
+ /shape ShapeR def
+ /shapecolor BackgroundR def
+ /borderwidth BorderWidthR def
+ /bordercolor BorderColorR def
+ /foreground ForegroundR def
+ /shadow ShadowR def
+ xyt
+}def
+
+% string end-repeat |- x y
+/end-repeat
+{gsave
+ space Descent rmoveto
+ foreground SetRGB S
+ c Descent sub
+ grestore
+ exch space add exch moveto
+ xt yt
+}def
+
+%>Right RePeat: string entry height width rwidth RRP |- x y
+/RRP{begin-repeat right-direction end-repeat}def
+
+%>Left RePeat: string entry height width rwidth LRP |- x y
+/LRP{begin-repeat left-direction end-repeat}def
+
+% --- Except
+
+% entry height width rwidth begin-except
+/begin-except
+{/rwidth exch def
+ /width exch def
+ /height exch def
+ /entry exch def
+ /fE F
+ /space SpaceE def
+ /Effect EffectE def
+ /shape ShapeE def
+ /shapecolor BackgroundE def
+ /borderwidth BorderWidthE def
+ /bordercolor BorderColorE def
+ /foreground ForegroundE def
+ /shadow ShadowE def
+ xyt
+}def
+
+% x-width end-except |- x y
+/end-except
+{gsave
+ space space add add Descent rmoveto
+ (-) foreground SetRGB S
+ grestore
+ space 0 rmoveto
+ xt yt
+}def
+
+%>Right EXcept: x-width entry height width rwidth REX |- x y
+/REX{begin-except right-direction end-except}def
+
+%>Left EXcept: x-width entry height width rwidth LEX |- x y
+/LEX{begin-except left-direction end-except}def
+
+% --- Sequence
+
+%>Beginning Of Sequence: BOS |- x y
+/BOS{currentpoint}bind def
+
+%>End Of Sequence: x y x1 y1 EOS |- x y
+/EOS{pop pop}bind def
+
+% --- Production
+
+%>Beginning Of Production: string width height BOP |- y x
+/BOP
+{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
+ xw yw moveto
+ hT EL RA
+ xp yw moveto
+ T EL
+ yp xp
+}def
+
+%>End Of Production: y x delta EOP
+/EOPH{add exch moveto}bind def			% horizontal
+/EOPV{exch pop sub 0 exch moveto}bind def	% vertical
+
+% --- Empty Alternative
+
+%>Empty Alternative: width EA |- x y
+/EA
+{gsave
+ Er add 0 rlineto
+ Stroke
+ grestore
+ c
+}def
+
+% --- Alternative
+
+%>AlTernative: h1 h2 ... hn n width AT |- x y
+/AT
+{xyo xo add /xw exch def
+ xw yo moveto
+ Er EL
+ {xw yo moveto
+  dup RAlt
+  xo yo moveto
+  LAlt}repeat
+ xo yo
+}def
+
+% --- Optional
+
+%>OPtional: height width OP |- x y
+/OP
+{xyo
+ T sub /ow exch def
+ ow Er sub 0 rmoveto
+ T Er add EL
+ neg dup RAlt
+ ow T sub neg EL
+ xo yo moveto
+ LAlt
+ xo yo moveto
+ T EL
+ xo yo
+}def
+
+% --- List Flow
+
+%>One or More: height width OM |- x y
+/OM
+{xyo
+ /ow exch def
+ ow Er add 0 rmoveto
+ T Er add neg EL
+ dup RLoop
+ xo T add yo moveto
+ LLoop
+ xo yo moveto
+ T EL
+ xo yo
+}def
+
+%>Zero or More: h2 h1 width ZM |- x y
+/ZM
+{xyo
+ Er add EL
+ Er neg 0 rmoveto
+ dup RAlt
+ exch dup RLoop
+ xo yo moveto
+ exch dup LAlt
+ exch LLoop
+ yo add xo T add exch moveto
+ xo yo
+}def
+
+% === end EBNF engine
+
+"
+  "EBNF PostScript prologue")
+
+
+(defconst ebnf-eps-prologue
+  "
+/#ebnf2ps#dict 230 dict def
+#ebnf2ps#dict begin
+
+% Initiliaze variables to avoid name-conflicting with document variables.
+% This is the case when using `bind' operator.
+/-fillp-		0 def		/h		0 def
+/-ox-			0 def		/half		0 def
+/-oy-			0 def		/height		0 def
+/-save-			0 def		/ow		0 def
+/Ascent			0 def		/quarter	0 def
+/Descent		0 def		/rXX		0 def
+/Effect			0 def		/rYY		0 def
+/FontHeight		0 def		/rwidth		0 def
+/LineThickness		0 def		/rxx		0 def
+/OverlinePosition	0 def		/ryy		0 def
+/SpaceBackground	0 def		/shadow		0 def
+/StrikeoutPosition	0 def		/shape		0 def
+/UnderlinePosition	0 def		/shapecolor	0 def
+/XBox			0 def		/space		0 def
+/XX			0 def		/st		1 string def
+/Xshadow		0 def		/w		0 def
+/YBox			0 def		/width		0 def
+/YY			0 def		/xi		0 def
+/Yshadow		0 def		/xo		0 def
+/arrow			0 def		/xp		0 def
+/bg			false def	/xt		0 def
+/bgcolor		0 def		/xw		0 def
+/bordercolor		0 def		/xx		0 def
+/borderwidth		0 def		/yi		0 def
+/dd			0 def		/yo		0 def
+/entry			0 def		/yp		0 def
+/foreground		0 def		/yt		0 def
+					/yy		0 def
+
+
+% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
+/ISOLatin1Encoding where
+{pop}
+{% -- The ISO Latin-1 encoding vector isn't known, so define it.
+ % -- The first half is the same as the standard encoding,
+ % -- except for minus instead of hyphen at code 055.
+ /ISOLatin1Encoding
+  StandardEncoding 0  45 getinterval aload pop
+  /minus
+  StandardEncoding 46 82 getinterval aload pop
+ %*** NOTE: the following are missing in the Adobe documentation,
+ %*** but appear in the displayed table:
+ %*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
+ % 0200 (128)
+  /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+  /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
+  /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
+  /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
+ % 0240 (160)
+  /space /exclamdown /cent /sterling
+	/currency /yen /brokenbar /section
+  /dieresis /copyright /ordfeminine /guillemotleft
+	/logicalnot /hyphen /registered /macron
+  /degree /plusminus /twosuperior /threesuperior
+	/acute /mu /paragraph /periodcentered
+  /cedilla /onesuperior /ordmasculine /guillemotright
+	/onequarter /onehalf /threequarters /questiondown
+ % 0300 (192)
+  /Agrave /Aacute /Acircumflex /Atilde
+	/Adieresis /Aring /AE /Ccedilla
+  /Egrave /Eacute /Ecircumflex /Edieresis
+	/Igrave /Iacute /Icircumflex /Idieresis
+  /Eth /Ntilde /Ograve /Oacute
+	/Ocircumflex /Otilde /Odieresis /multiply
+  /Oslash /Ugrave /Uacute /Ucircumflex
+	/Udieresis /Yacute /Thorn /germandbls
+ % 0340 (224)
+  /agrave /aacute /acircumflex /atilde
+	/adieresis /aring /ae /ccedilla
+  /egrave /eacute /ecircumflex /edieresis
+	/igrave /iacute /icircumflex /idieresis
+  /eth /ntilde /ograve /oacute
+	/ocircumflex /otilde /odieresis /divide
+  /oslash /ugrave /uacute /ucircumflex
+	/udieresis /yacute /thorn /ydieresis
+ 256 packedarray def
+}ifelse
+
+/reencodeFontISO	%def
+{dup
+ length 12 add dict	% Make a new font (a new dict the same size
+			% as the old one) with room for our new symbols.
+
+ begin			% Make the new font the current dictionary.
+  {1 index /FID ne
+   {def}{pop pop}ifelse
+  }forall		% Copy each of the symbols from the old dictionary
+			% to the new one except for the font ID.
+
+  currentdict /FontType get 0 ne
+  {/Encoding ISOLatin1Encoding def}if	% Override the encoding with
+					% the ISOLatin1 encoding.
+
+  % Use the font's bounding box to determine the ascent, descent,
+  % and overall height; don't forget that these values have to be
+  % transformed using the font's matrix.
+
+  %          ^    (x2 y2)
+  %          |       |
+  %          |       v
+  %          |  +----+ - -
+  %          |  |    |   ^
+  %          |  |    |   | Ascent (usually > 0)
+  %          |  |    |   |
+  % (0 0) -> +--+----+-------->
+  %             |    |   |
+  %             |    |   v Descent (usually < 0)
+  % (x1 y1) --> +----+ - -
+
+  currentdict /FontType get 0 ne
+  {/FontBBox load aload pop		% -- x1 y1 x2 y2
+   FontMatrix transform /Ascent  exch def pop
+   FontMatrix transform /Descent exch def pop}
+  {/PrimaryFont FDepVector 0 get def
+   PrimaryFont /FontBBox get aload pop
+   PrimaryFont /FontMatrix get transform /Ascent exch def pop
+   PrimaryFont /FontMatrix get transform /Descent exch def pop
+  }ifelse
+
+  /FontHeight Ascent Descent sub def	% use `sub' because descent < 0
+
+  % Define these in case they're not in the FontInfo
+  % (also, here they're easier to get to).
+  /UnderlinePosition  Descent 0.70 mul def
+  /OverlinePosition   Descent UnderlinePosition sub Ascent add def
+  /StrikeoutPosition  Ascent 0.30 mul def
+  /LineThickness      FontHeight 0.05 mul def
+  /Xshadow            FontHeight  0.08 mul def
+  /Yshadow            FontHeight -0.09 mul def
+  /SpaceBackground    Descent neg UnderlinePosition add def
+  /XBox               Descent neg def
+  /YBox               LineThickness 0.7 mul def
+
+  currentdict	% Leave the new font on the stack
+ end		% Stop using the font as the current dictionary
+ definefont	% Put the font into the font dictionary
+ pop		% Discard the returned font
+}bind def
+
+% Font definition
+/DefFont{findfont exch scalefont reencodeFontISO}def
+
+% Font selection
+/F
+{findfont
+ dup /Ascent            get /Ascent            exch def
+ dup /Descent           get /Descent           exch def
+ dup /FontHeight        get /FontHeight        exch def
+ dup /UnderlinePosition get /UnderlinePosition exch def
+ dup /OverlinePosition  get /OverlinePosition  exch def
+ dup /StrikeoutPosition get /StrikeoutPosition exch def
+ dup /LineThickness     get /LineThickness     exch def
+ dup /Xshadow           get /Xshadow           exch def
+ dup /Yshadow           get /Yshadow           exch def
+ dup /SpaceBackground   get /SpaceBackground   exch def
+ dup /XBox              get /XBox              exch def
+ dup /YBox              get /YBox              exch def
+ setfont
+}def
+
+/BG
+{dup /bg exch def
+ {mark 4 1 roll ]}
+ {[ 1.0 1.0 1.0 ]}
+ ifelse
+ /bgcolor exch def
+}def
+
+% stack:  --
+/FillBgColor{bgcolor aload pop setrgbcolor fill}bind def
+
+% stack:  fill-or-not lower-x lower-y upper-x upper-y  |-  --
+/doRect
+{/rYY exch def
+ /rXX exch def
+ /ryy exch def
+ /rxx exch def
+ gsave
+ newpath
+ rXX rYY moveto
+ rxx rYY lineto
+ rxx ryy lineto
+ rXX ryy lineto
+ closepath
+ % top of stack: fill-or-not
+ {FillBgColor}
+ {LineThickness setlinewidth stroke}
+ ifelse
+ grestore
+}bind def
+
+% stack:  string fill-or-not  |-  --
+/doOutline
+{/-fillp- exch def
+ /-ox- currentpoint /-oy- exch def def
+ gsave
+ LineThickness setlinewidth
+ {st 0 3 -1 roll put
+  st dup true charpath
+  -fillp- {gsave FillBgColor grestore}if
+  stroke stringwidth
+  -oy- add /-oy- exch def
+  -ox- add /-ox- exch def
+  -ox- -oy- moveto
+ }forall
+ grestore
+ -ox- -oy- moveto
+}bind def
+
+% stack:  fill-or-not delta  |-  --
+/doBox
+{/dd exch def
+ xx XBox sub dd sub yy YBox sub dd sub
+ XX XBox add dd add YY YBox add dd add
+ doRect
+}bind def
+
+% stack:  string  |-  --
+/doShadow
+{gsave
+ Xshadow Yshadow rmoveto
+ false doOutline
+ grestore
+}bind def
+
+% stack:  position  |-  --
+/Hline
+{currentpoint exch pop add dup
+ gsave
+ newpath
+ xx exch moveto
+ XX exch lineto
+ closepath
+ LineThickness setlinewidth stroke
+ grestore
+}bind def
+
+% stack:  string  |-  --
+% effect: 1  - underline  2   - strikeout  4  - overline
+%         8  - shadow     16  - box        32 - outline
+/S
+{/xx currentpoint dup Descent add /yy exch def
+ Ascent add /YY exch def def
+ dup stringwidth pop xx add /XX exch def
+ Effect 8 and 0 ne
+ {/yy yy Yshadow add def
+  /XX XX Xshadow add def
+ }if
+ bg
+ {true
+  Effect 16 and 0 ne
+  {SpaceBackground doBox}
+  {xx yy XX YY doRect}
+  ifelse
+ }if						% background
+ Effect 16 and 0 ne{false 0 doBox}if		% box
+ Effect 8  and 0 ne{dup doShadow}if		% shadow
+ Effect 32 and 0 ne
+ {true doOutline}				% outline
+ {show}						% normal text
+ ifelse
+ Effect 1  and 0 ne{UnderlinePosition Hline}if	% underline
+ Effect 2  and 0 ne{StrikeoutPosition Hline}if	% strikeout
+ Effect 4  and 0 ne{OverlinePosition  Hline}if	% overline
+}bind def
+
+"
+  "EBNF EPS prologue")
+
+
+(defconst ebnf-eps-begin
+  "
+end
+
+% x y #ebnf2ps#begin
+/#ebnf2ps#begin
+{#ebnf2ps#dict begin /#ebnf2ps#save save def
+ moveto false BG 0.0 0.0 0.0 setrgbcolor}def
+
+/#ebnf2ps#end{showpage #ebnf2ps#save restore end}def
+
+%%EndPrologue
+"
+  "EBNF EPS begin")
+
+
+(defconst ebnf-eps-end
+  "#ebnf2ps#end
+%%EOF
+"
+  "EBNF EPS end")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Formatting
+
+
+(defvar ebnf-format-float "%1.3f")
+
+
+(defun ebnf-format-float (&rest floats)
+  (mapconcat
+   #'(lambda (float)
+       (format ebnf-format-float float))
+   floats
+   " "))
+
+
+(defun ebnf-format-color (format-str color default)
+  (let* ((the-color (or color default))
+	 (rgb (mapcar 'ps-color-value (ps-color-values the-color))))
+    (format format-str
+	    (concat "["
+		    (ebnf-format-float (nth 0 rgb) (nth 1 rgb) (nth 2 rgb))
+		    "]")
+	    the-color)))
+
+
+(defvar ebnf-message-float "%3.2f")
+
+
+(defsubst ebnf-message-float (format-str value)
+  (message format-str
+	   (format ebnf-message-float value)))
+
+
+(defsubst ebnf-message-info (messag)
+  (message "%s...%3d%%"
+	   messag
+	   (round (/ (* (setq ebnf-nprod (1+ ebnf-nprod)) 100.0) ebnf-total))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Macros
+
+
+(defmacro ebnf-node-kind (vec &optional value)
+  (if value
+      `(aset ,vec 0 ,value)
+    `(aref ,vec 0)))
+
+
+(defmacro ebnf-node-width-func (node width)
+  `(funcall (aref ,node 1) ,node ,width))
+
+
+(defmacro ebnf-node-dimension-func (node &optional value)
+  (if value
+      `(aset ,node 2 ,value)
+    `(funcall (aref ,node 2) ,node)))
+
+
+(defmacro ebnf-node-entry (vec &optional value)
+  (if value
+      `(aset ,vec 3 ,value)
+    `(aref ,vec 3)))
+
+
+(defmacro ebnf-node-height (vec &optional value)
+  (if value
+      `(aset ,vec 4 ,value)
+    `(aref ,vec 4)))
+
+
+(defmacro ebnf-node-width (vec &optional value)
+  (if value
+      `(aset ,vec 5 ,value)
+    `(aref ,vec 5)))
+
+
+(defmacro ebnf-node-name (vec)
+  `(aref ,vec 6))
+
+
+(defmacro ebnf-node-list (vec &optional value)
+  (if value
+      `(aset ,vec 6 ,value)
+    `(aref ,vec 6)))
+
+
+(defmacro ebnf-node-default (vec)
+  `(aref ,vec 7))
+
+
+(defmacro ebnf-node-production (vec &optional value)
+  (if value
+      `(aset ,vec 7 ,value)
+    `(aref ,vec 7)))
+
+
+(defmacro ebnf-node-separator (vec &optional value)
+  (if value
+      `(aset ,vec 7 ,value)
+    `(aref ,vec 7)))
+
+
+(defmacro ebnf-node-action (vec &optional value)
+  (if value
+      `(aset ,vec 8 ,value)
+    `(aref ,vec 8)))
+
+
+(defmacro ebnf-node-generation (node)
+  `(funcall (ebnf-node-kind ,node) ,node))
+
+
+(defmacro ebnf-max-width (prod)
+  `(max (ebnf-node-width ,prod)
+	(+ (* (length (ebnf-node-name ,prod))
+	      ebnf-font-width-P)
+	   ebnf-production-horizontal-space)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; PostScript generation
+
+
+(defun ebnf-generate-eps (ebnf-tree)
+  (let* ((ps-color-p           (and ebnf-color-p (ps-color-device)))
+	 (ps-print-color-scale (if ps-color-p
+				   (float (car (ps-color-values "white")))
+				 1.0))
+	 (ebnf-total           (length ebnf-tree))
+	 (ebnf-nprod           0)
+	 (old-ps-output        (symbol-function 'ps-output))
+	 (old-ps-output-string (symbol-function 'ps-output-string))
+	 (eps-buffer           (get-buffer-create ebnf-eps-buffer-name))
+	 ebnf-debug-ps error-msg horizontal
+	 prod prod-name prod-width prod-height prod-list file-list)
+    ;; redefines `ps-output' and `ps-output-string'
+    (defalias 'ps-output        'ebnf-eps-output)
+    (defalias 'ps-output-string 'ps-output-string-prim)
+    ;; generate EPS file
+    (save-excursion
+      (condition-case data
+	  (progn
+	    (while ebnf-tree
+	      (setq prod        (car ebnf-tree)
+		    prod-name   (ebnf-node-name prod)
+		    prod-width  (ebnf-max-width prod)
+		    prod-height (ebnf-node-height prod)
+		    horizontal  (memq (ebnf-node-action prod) ebnf-action-list))
+	      ;; generate production in EPS buffer
+	      (save-excursion
+		(set-buffer eps-buffer)
+		(setq ebnf-eps-upper-x    0.0
+		      ebnf-eps-upper-y    0.0
+		      ebnf-eps-max-width  prod-width
+		      ebnf-eps-max-height prod-height)
+		(ebnf-generate-production prod))
+	      (if (setq prod-list (cdr (assoc prod-name
+					      ebnf-eps-production-list)))
+		  ;; insert EPS buffer in all buffer associated with production
+		  (ebnf-eps-production-list prod-list 'file-list horizontal
+					    prod-width prod-height eps-buffer)
+		;; write EPS file for production
+		(ebnf-eps-finish-and-write eps-buffer
+					   (ebnf-eps-filename prod-name)))
+	      ;; prepare for next loop
+	      (save-excursion
+		(set-buffer eps-buffer)
+		(erase-buffer))
+	      (setq ebnf-tree (cdr ebnf-tree)))
+	    ;; write and kill temporary buffers
+	    (ebnf-eps-write-kill-temp file-list t)
+	    (setq file-list nil))
+	;; handler
+	((quit error)
+	 (setq error-msg (error-message-string data)))))
+    ;; restore `ps-output' and `ps-output-string'
+    (defalias 'ps-output        old-ps-output)
+    (defalias 'ps-output-string old-ps-output-string)
+    ;; kill temporary buffers
+    (kill-buffer eps-buffer)
+    (ebnf-eps-write-kill-temp file-list nil)
+    (and error-msg (error error-msg))
+    (message " ")))
+
+
+;; write and kill temporary buffers
+(defun ebnf-eps-write-kill-temp (file-list write-p)
+  (while file-list
+    (let ((buffer (get-buffer (concat " *" (car file-list) "*"))))
+      (when buffer
+	(and write-p
+	     (ebnf-eps-finish-and-write buffer (car file-list)))
+	(kill-buffer buffer)))
+    (setq file-list (cdr file-list))))
+
+
+;; insert EPS buffer in all buffer associated with production
+(defun ebnf-eps-production-list (prod-list file-list-sym horizontal
+					   prod-width prod-height eps-buffer)
+  (while prod-list
+    (add-to-list file-list-sym (car prod-list))
+    (save-excursion
+      (set-buffer (get-buffer-create (concat " *" (car prod-list) "*")))
+      (goto-char (point-max))
+      (cond
+       ;; first production
+       ((zerop (buffer-size))
+	(setq ebnf-eps-upper-x    0.0
+	      ebnf-eps-upper-y    0.0
+	      ebnf-eps-max-width  prod-width
+	      ebnf-eps-max-height prod-height))
+       ;; horizontal
+       (horizontal
+	(ebnf-eop-horizontal ebnf-eps-prod-width)
+	(setq ebnf-eps-max-width  (+ ebnf-eps-max-width
+				     ebnf-production-horizontal-space
+				     prod-width)
+	      ebnf-eps-max-height (max ebnf-eps-max-height prod-height)))
+       ;; vertical
+       (t
+	(ebnf-eop-vertical ebnf-eps-max-height)
+	(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))
+	      ebnf-eps-max-width  prod-width
+	      ebnf-eps-max-height prod-height))
+       )
+      (setq ebnf-eps-prod-width prod-width)
+      (insert-buffer eps-buffer))
+    (setq prod-list (cdr prod-list))))
+
+
+(defun ebnf-generate (ebnf-tree)
+  (let* ((ps-color-p           (and ebnf-color-p (ps-color-device)))
+	 (ps-print-color-scale (if ps-color-p
+				   (float (car (ps-color-values "white")))
+				 1.0))
+	 ps-zebra-stripes ps-line-number ps-razzle-dazzle
+	 ps-print-hook
+	 ps-print-begin-sheet-hook
+	 ps-print-begin-page-hook
+	 ps-print-begin-column-hook)
+    (ps-generate (current-buffer) (point-min) (point-max)
+		 'ebnf-generate-postscript)))
+
+
+(defvar ebnf-tree      nil)
+(defvar ebnf-direction "R")
+(defvar ebnf-total     0)
+(defvar ebnf-nprod     0)
+
+
+(defun ebnf-generate-postscript (from to)
+  (ebnf-begin-file)
+  (if ebnf-horizontal-max-height
+      (ebnf-generate-with-max-height)
+    (ebnf-generate-without-max-height))
+  (message " "))
+
+
+(defun ebnf-generate-with-max-height ()
+  (let ((ebnf-total (length ebnf-tree))
+	(ebnf-nprod 0)
+	next-line max-height prod the-width)
+    (while ebnf-tree
+      ;; find next line point
+      (setq next-line  ebnf-tree
+	    prod       (car ebnf-tree)
+	    max-height (ebnf-node-height prod))
+      (ebnf-begin-line prod (ebnf-max-width prod))
+      (while (and (setq next-line (cdr next-line))
+		  (setq prod      (car next-line))
+		  (memq (ebnf-node-action prod) ebnf-action-list)
+		  (setq the-width (ebnf-max-width prod))
+		  (<= the-width ps-width-remaining))
+	(setq max-height         (max max-height (ebnf-node-height prod))
+	      ps-width-remaining (- ps-width-remaining
+				    (+ the-width
+				       ebnf-production-horizontal-space))))
+      ;; generate current line
+      (ebnf-newline max-height)
+      (setq prod (car ebnf-tree))
+      (ebnf-generate-production prod)
+      (while (not (eq (setq ebnf-tree (cdr ebnf-tree)) next-line))
+	(ebnf-eop-horizontal (ebnf-max-width prod))
+	(setq prod (car ebnf-tree))
+	(ebnf-generate-production prod))
+      (ebnf-eop-vertical max-height))))
+
+
+(defun ebnf-generate-without-max-height ()
+  (let ((ebnf-total (length ebnf-tree))
+	(ebnf-nprod 0)
+	max-height prod bef-width cur-width)
+    (while ebnf-tree
+      ;; generate current line
+      (setq prod       (car ebnf-tree)
+	    max-height (ebnf-node-height prod)
+	    bef-width  (ebnf-max-width prod))
+      (ebnf-begin-line prod bef-width)
+      (ebnf-generate-production prod)
+      (while (and (setq ebnf-tree (cdr ebnf-tree))
+		  (setq prod      (car ebnf-tree))
+		  (memq (ebnf-node-action prod) ebnf-action-list)
+		  (setq cur-width (ebnf-max-width prod))
+		  (<= cur-width ps-width-remaining)
+		  (<= (ebnf-node-height prod) ps-height-remaining))
+	(ebnf-eop-horizontal bef-width)
+	(ebnf-generate-production prod)
+	(setq bef-width          cur-width
+	      max-height         (max max-height (ebnf-node-height prod))
+	      ps-width-remaining (- ps-width-remaining
+				    (+ cur-width
+				       ebnf-production-horizontal-space))))
+      (ebnf-eop-vertical max-height)
+      ;; prepare next line
+      (ebnf-newline max-height))))
+
+
+(defun ebnf-begin-line (prod width)
+  (and (or (eq (ebnf-node-action prod) 'form-feed)
+	   (> (ebnf-node-height prod) ps-height-remaining))
+       (ebnf-new-page))
+  (setq ps-width-remaining (- ps-width-remaining
+			      (+ width
+				 ebnf-production-horizontal-space))))
+
+
+(defun ebnf-newline (height)
+  (and (> height ps-height-remaining)
+       (ebnf-new-page))
+  (setq ps-width-remaining  ps-print-width
+	ps-height-remaining (- ps-height-remaining
+			       (+ height
+				  ebnf-production-vertical-space))))
+
+
+;; [production width-fun dim-fun entry height width name production action]
+(defun ebnf-generate-production (production)
+  (ebnf-message-info "Generating")
+  (run-hooks 'ebnf-production-hook)
+  (ps-output-string (ebnf-node-name production))
+  (ps-output " "
+	     (ebnf-format-float
+	      (ebnf-node-width production)
+	      (+ ebnf-basic-height
+		 (ebnf-node-entry (ebnf-node-production production))))
+	     " BOP\n")
+  (ebnf-node-generation (ebnf-node-production production))
+  (ps-output "EOS\n"))
+
+
+;; [alternative width-fun dim-fun entry height width list]
+(defun ebnf-generate-alternative (alternative)
+  (let ((alt   (ebnf-node-list alternative))
+	(entry (ebnf-node-entry alternative))
+	(nlist 0)
+	alt-height alt-entry)
+    (while alt
+      (ps-output (ebnf-format-float (- entry (ebnf-node-entry (car alt))))
+		 " ")
+      (setq entry (- entry (ebnf-node-height (car alt)) ebnf-vertical-space)
+	    nlist (1+ nlist)
+	    alt   (cdr alt)))
+    (ps-output (format "%d " nlist)
+	       (ebnf-format-float (ebnf-node-width alternative))
+	       " AT\n")
+    (setq alt (ebnf-node-list alternative))
+    (when alt
+      (ebnf-node-generation (car alt))
+      (setq alt-height (- (ebnf-node-height (car alt))
+			  (ebnf-node-entry (car alt)))))
+    (while (setq alt (cdr alt))
+      (setq alt-entry (ebnf-node-entry (car alt)))
+      (ebnf-vertical-movement
+       (- (+ alt-height ebnf-vertical-space alt-entry)))
+      (ebnf-node-generation (car alt))
+      (setq alt-height (- (ebnf-node-height (car alt)) alt-entry))))
+  (ps-output "EOS\n"))
+
+
+;; [sequence width-fun dim-fun entry height width list]
+(defun ebnf-generate-sequence (sequence)
+  (ps-output "BOS\n")
+  (let ((seq (ebnf-node-list sequence))
+	seq-width)
+    (when seq
+      (ebnf-node-generation (car seq))
+      (setq seq-width (ebnf-node-width (car seq))))
+    (while (setq seq (cdr seq))
+      (ebnf-horizontal-movement seq-width)
+      (ebnf-node-generation (car seq))
+      (setq seq-width (ebnf-node-width (car seq)))))
+  (ps-output "EOS\n"))
+
+
+;; [terminal width-fun dim-fun entry height width name]
+(defun ebnf-generate-terminal (terminal)
+  (ebnf-gen-terminal terminal "T"))
+
+
+;; [non-terminal width-fun dim-fun entry height width name]
+(defun ebnf-generate-non-terminal (non-terminal)
+  (ebnf-gen-terminal non-terminal "NT"))
+
+
+;; [empty width-fun dim-fun entry height width]
+(defun ebnf-generate-empty (empty)
+  (ebnf-empty-alternative (ebnf-node-width empty)))
+
+
+;; [optional width-fun dim-fun entry height width element]
+(defun ebnf-generate-optional (optional)
+  (let ((the-optional (ebnf-node-list optional)))
+    (ps-output (ebnf-format-float
+		(+ (- (ebnf-node-height the-optional)
+		      (ebnf-node-entry optional))
+		   ebnf-vertical-space)
+		(ebnf-node-width optional))
+	       " OP\n")
+    (ebnf-node-generation the-optional)
+    (ps-output "EOS\n")))
+
+
+;; [one-or-more width-fun dim-fun entry height width element separator]
+(defun ebnf-generate-one-or-more (one-or-more)
+  (let* ((width (ebnf-node-width one-or-more))
+	 (sep   (ebnf-node-separator one-or-more))
+	 (entry (- (ebnf-node-entry one-or-more)
+		   (if sep
+		       (ebnf-node-entry sep)
+		     0))))
+    (ps-output (ebnf-format-float entry width)
+	       " OM\n")
+    (ebnf-node-generation (ebnf-node-list one-or-more))
+    (ebnf-vertical-movement entry)
+    (if sep
+	(let ((ebnf-direction "L"))
+	  (ebnf-node-generation sep))
+      (ebnf-empty-alternative (- width ebnf-horizontal-space))))
+  (ps-output "EOS\n"))
+
+
+;; [zero-or-more width-fun dim-fun entry height width element separator]
+(defun ebnf-generate-zero-or-more (zero-or-more)
+  (let* ((width      (ebnf-node-width zero-or-more))
+	 (node-list  (ebnf-node-list zero-or-more))
+	 (list-entry (ebnf-node-entry node-list))
+	 (node-sep   (ebnf-node-separator zero-or-more))
+	 (entry      (+ list-entry
+			ebnf-vertical-space
+			(if node-sep
+			    (- (ebnf-node-height node-sep)
+			       (ebnf-node-entry node-sep))
+			  0))))
+    (ps-output (ebnf-format-float entry
+				  (+ (- (ebnf-node-height node-list)
+					list-entry)
+				     ebnf-vertical-space)
+				  width)
+	       " ZM\n")
+    (ebnf-node-generation (ebnf-node-list zero-or-more))
+    (ebnf-vertical-movement entry)
+    (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))))
+  (ps-output "EOS\n"))
+
+
+;; [special width-fun dim-fun entry height width name]
+(defun ebnf-generate-special (special)
+  (ebnf-gen-terminal special "SP"))
+
+
+;; [repeat width-fun dim-fun entry height width times element]
+(defun ebnf-generate-repeat (repeat)
+  (let ((times   (ebnf-node-name repeat))
+	(element (ebnf-node-separator repeat)))
+    (ps-output-string times)
+    (ps-output " "
+	       (ebnf-format-float
+		(ebnf-node-entry repeat)
+		(ebnf-node-height repeat)
+		(ebnf-node-width repeat)
+		(if element
+		    (+ (ebnf-node-width element)
+		       ebnf-space-R ebnf-space-R ebnf-space-R
+		       (* (length times) ebnf-font-width-R))
+		  0.0))
+	       " " ebnf-direction "RP\n")
+    (and element
+	 (ebnf-node-generation element)))
+  (ps-output "EOS\n"))
+
+
+;; [except width-fun dim-fun entry height width element element]
+(defun ebnf-generate-except (except)
+  (let* ((element   (ebnf-node-list except))
+	 (exception (ebnf-node-separator except))
+	 (width     (ebnf-node-width element)))
+    (ps-output (ebnf-format-float
+		width
+		(ebnf-node-entry except)
+		(ebnf-node-height except)
+		(ebnf-node-width except)
+		(+ width
+		   ebnf-space-E ebnf-space-E ebnf-space-E
+		   ebnf-font-width-E
+		   (if exception
+		       (+ (ebnf-node-width exception) ebnf-space-E)
+		     0.0)))
+	       " " ebnf-direction "EX\n")
+    (ebnf-node-generation (ebnf-node-list except))
+    (when exception
+      (ebnf-horizontal-movement (+ width ebnf-space-E
+				   ebnf-font-width-E ebnf-space-E))
+      (ebnf-node-generation exception)))
+  (ps-output "EOS\n"))
+
+
+(defun ebnf-gen-terminal (node code)
+  (ps-output-string (ebnf-node-name node))
+  (ps-output " " (ebnf-format-float (ebnf-node-width node))
+	     " " ebnf-direction code
+	     (if (ebnf-node-default node)
+		 "D\n"
+	       "\n")))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Internal functions
+
+
+(defvar ebnf-map-name
+  (let ((map (make-vector 256 ?\_)))
+    (mapcar #'(lambda (char)
+		(aset map char char))
+	    (concat "#$%&+-.0123456789=?@~"
+		    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+		    "abcdefghijklmnopqrstuvwxyz"))
+    map))
+
+
+(defun ebnf-eps-filename (str)
+  (let* ((len  (length str))
+	 (stri 0)
+	 (new  (make-string len ?\ )))
+    (while (< stri len)
+      (aset new stri (aref ebnf-map-name (aref str stri)))
+      (setq stri (1+ stri)))
+    (concat ebnf-eps-prefix new ".eps")))
+
+
+(defun ebnf-eps-output (&rest args)
+  (while args
+    (insert (car args))
+    (setq args (cdr args))))
+
+
+(defun ebnf-generate-region (from to gen-func)
+  (run-hooks 'ebnf-hook)
+  (let ((ebnf-limit (max from to))
+	the-point)
+    (save-excursion
+      (save-restriction
+	(save-match-data
+	  (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))))))
+	    ;; handler
+	    ((quit error)
+	     (ding)
+	     (setq the-point (max (1- (point)) (point-min)))
+	     (message (error-message-string data)))))))
+    (cond
+     (the-point
+      (goto-char the-point))
+     (gen-func
+      nil)
+     (t
+      (message "EBNF syntatic analysis: NO ERRORS.")))))
+
+
+(defun ebnf-parse-and-sort (start)
+  (ebnf-begin-job)
+  (let ((tree (funcall ebnf-parser-func start)))
+    (if ebnf-sort-production
+	(progn
+	  (message "Sorting...")
+	  (sort tree
+		(if (eq ebnf-sort-production 'ascending)
+		    'ebnf-sorter-ascending
+		  'ebnf-sorter-descending)))
+      (nreverse tree))))
+
+
+(defun ebnf-sorter-ascending (first second)
+  (string< (ebnf-node-name first)
+	   (ebnf-node-name second)))
+
+
+(defun ebnf-sorter-descending (first second)
+  (string< (ebnf-node-name second)
+	   (ebnf-node-name first)))
+
+
+(defun ebnf-empty-alternative (width)
+  (ps-output (ebnf-format-float width) " EA\n"))
+
+
+(defun ebnf-vertical-movement (height)
+  (ps-output (ebnf-format-float height) " vm\n"))
+
+
+(defun ebnf-horizontal-movement (width)
+  (ps-output (ebnf-format-float width) " hm\n"))
+
+
+(defun ebnf-entry (height)
+  (* height ebnf-entry-percentage))
+
+
+(defun ebnf-eop-vertical (height)
+  (ps-output (ebnf-format-float (+ height ebnf-production-vertical-space))
+	     " EOPV\n\n"))
+
+
+(defun ebnf-eop-horizontal (width)
+  (ps-output (ebnf-format-float (+ width ebnf-production-horizontal-space))
+	     " EOPH\n\n"))
+
+
+(defun ebnf-new-page ()
+  (when (< ps-height-remaining ps-print-height)
+    (run-hooks 'ebnf-page-hook)
+    (ps-next-page)
+    (ps-output "\n")))
+
+
+(defsubst ebnf-font-size (font) (nth 0 font))
+(defsubst ebnf-font-name (font) (nth 1 font))
+(defsubst ebnf-font-foreground (font) (nth 2 font))
+(defsubst ebnf-font-background (font) (nth 3 font))
+(defsubst ebnf-font-list (font) (nthcdr 4 font))
+(defsubst ebnf-font-attributes (font)
+  (lsh (ps-extension-bit (cdr font)) -2))
+
+
+(defconst ebnf-font-name-select
+  (vector 'normal 'bold 'italic 'bold-italic))
+
+
+(defun ebnf-font-name-select (font)
+  (let* ((font-list  (ebnf-font-list font))
+	 (font-index (+ (if (memq 'bold   font-list) 1 0)
+			(if (memq 'italic font-list) 2 0)))
+	 (name       (ebnf-font-name font))
+	 (database   (cdr (assoc name ps-font-info-database)))
+	 (info-list  (or (cdr (assoc 'fonts database))
+			 (error "Invalid font: %s" name))))
+    (or (cdr (assoc (aref ebnf-font-name-select font-index)
+		    info-list))
+	(error "Invalid attributes for font %s" name))))
+
+
+(defun ebnf-font-select (font select)
+  (let* ((name     (ebnf-font-name font))
+	 (database (cdr (assoc name ps-font-info-database)))
+	 (size     (cdr (assoc 'size database)))
+	 (base     (cdr (assoc select database))))
+    (if (and size base)
+	(/ (* (ebnf-font-size font) base)
+	   size)
+      (error "Invalid font: %s" name))))
+
+
+(defsubst ebnf-font-width (font)
+  (ebnf-font-select font 'avg-char-width))
+(defsubst ebnf-font-height (font)
+  (ebnf-font-select font 'line-height))
+
+
+(defun ebnf-begin-job ()
+  (ps-printing-region nil)
+  (if ebnf-use-float-format
+      (setq ebnf-format-float  "%1.3f"
+	    ebnf-message-float "%3.2f")
+    (setq ebnf-format-float  "%s"
+	  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)))
+  (and ebnf-terminal-regexp		; ensures that it's a string or nil
+       (not (stringp ebnf-terminal-regexp))
+       (setq ebnf-terminal-regexp nil))
+  (or (and ebnf-eps-prefix		; ensures that it's a string
+	   (stringp ebnf-eps-prefix))
+      (setq ebnf-eps-prefix "ebnf--"))
+  (setq ebnf-entry-percentage		; ensures value between 0.0 and 1.0
+	(min (max ebnf-entry-percentage 0.0) 1.0)
+	ebnf-action-list         (if ebnf-horizontal-orientation
+				     '(nil keep-line)
+				   '(keep-line))
+	ebnf-settings            nil
+	ebnf-fonts-required      nil
+	ebnf-action              nil
+	ebnf-default-p           nil
+	ebnf-eps-context         nil
+	ebnf-eps-production-list nil
+	ebnf-eps-upper-x         0.0
+	ebnf-eps-upper-y         0.0
+	ebnf-font-height-P       (ebnf-font-height ebnf-production-font)
+	ebnf-font-height-T       (ebnf-font-height ebnf-terminal-font)
+	ebnf-font-height-NT      (ebnf-font-height ebnf-non-terminal-font)
+	ebnf-font-height-S       (ebnf-font-height ebnf-special-font)
+	ebnf-font-height-E       (ebnf-font-height ebnf-except-font)
+	ebnf-font-height-R       (ebnf-font-height ebnf-repeat-font)
+	ebnf-font-width-P        (ebnf-font-width ebnf-production-font)
+	ebnf-font-width-T        (ebnf-font-width ebnf-terminal-font)
+	ebnf-font-width-NT       (ebnf-font-width ebnf-non-terminal-font)
+	ebnf-font-width-S        (ebnf-font-width ebnf-special-font)
+	ebnf-font-width-E        (ebnf-font-width ebnf-except-font)
+	ebnf-font-width-R        (ebnf-font-width ebnf-repeat-font)
+	ebnf-space-T             (* ebnf-font-height-T 0.5)
+	ebnf-space-NT            (* ebnf-font-height-NT 0.5)
+	ebnf-space-S             (* ebnf-font-height-S 0.5)
+	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)
+    ;; ensures value is greater than zero
+    (or (and (numberp ebnf-production-horizontal-space)
+	     (> ebnf-production-horizontal-space 0.0))
+	(setq ebnf-production-horizontal-space basic))
+    ;; 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))))
+
+
+(defsubst ebnf-shape-value (sym alist)
+  (or (cdr (assq sym alist)) 0))
+
+
+(defsubst ebnf-boolean (value)
+  (if value "true" "false"))
+
+
+(defun ebnf-begin-file ()
+  (ps-flush-output)
+  (save-excursion
+    (set-buffer ps-spool-buffer)
+    (goto-char (point-min))
+    (and (search-forward "%%Creator: " nil t)
+	 (not (search-forward "& ebnf2ps v"
+			      (save-excursion (end-of-line) (point))
+			      t))
+	 (progn
+	   ;; adjust creator comment
+	   (end-of-line)
+	   (backward-char)
+	   (insert " & ebnf2ps v" ebnf-version)
+	   ;; insert ebnf settings & engine
+	   (goto-char (point-max))
+	   (search-backward "\n%%EndPrologue\n")
+	   (ebnf-insert-ebnf-prologue)
+	   (ps-output "\n")))))
+
+
+(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: " (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy)
+     "\n%%Creator: " (user-full-name) " (using ebnf2ps v" ebnf-version ")"
+     "\n%%DocumentNeededResources: font "
+     (or ebnf-fonts-required
+	 (setq ebnf-fonts-required
+	       (let ((fonts (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)))))
+		 (concat (car fonts)
+			 (and (cdr fonts) "\n%%+ font ")
+			 (mapconcat 'identity (cdr fonts) "\n%%+ font ")))))
+     "\n%%Pages: 0\n%%EndComments\n\n%%BeginPrologue\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 ()
+  (insert
+   (or ebnf-settings
+       (setq ebnf-settings
+	     (concat
+	      "\n\n% === begin EBNF settings\n\n"
+	      ;; production
+	      (format "/fP            %s /%s DefFont\n"
+		      (ebnf-format-float (ebnf-font-size ebnf-production-font))
+		      (ebnf-font-name-select ebnf-production-font))
+	      (ebnf-format-color "/ForegroundP   %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-production-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundP   %s def %% %s\n"
+				 (ebnf-font-background ebnf-production-font)
+				 "White")
+	      (format "/EffectP       %d def\n"
+		      (ebnf-font-attributes ebnf-production-font))
+	      ;; terminal
+	      (format "/fT            %s /%s DefFont\n"
+		      (ebnf-format-float (ebnf-font-size ebnf-terminal-font))
+		      (ebnf-font-name-select ebnf-terminal-font))
+	      (ebnf-format-color "/ForegroundT   %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-terminal-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundT   %s def %% %s\n"
+				 (ebnf-font-background ebnf-terminal-font)
+				 "White")
+	      (format "/EffectT       %d def\n"
+		      (ebnf-font-attributes ebnf-terminal-font))
+	      (format "/BorderWidthT  %s def\n"
+		      (ebnf-format-float ebnf-terminal-border-width))
+	      (ebnf-format-color "/BorderColorT  %s def %% %s\n"
+				 ebnf-terminal-border-color
+				 "Black")
+	      (format "/ShapeT        %d def\n"
+		      (ebnf-shape-value ebnf-terminal-shape
+					ebnf-terminal-shape-alist))
+	      (format "/ShadowT       %s def\n"
+		      (ebnf-boolean ebnf-terminal-shadow))
+	      ;; non-terminal
+	      (format "/fNT           %s /%s DefFont\n"
+		      (ebnf-format-float
+		       (ebnf-font-size ebnf-non-terminal-font))
+		      (ebnf-font-name-select ebnf-non-terminal-font))
+	      (ebnf-format-color "/ForegroundNT  %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-non-terminal-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundNT  %s def %% %s\n"
+				 (ebnf-font-background ebnf-non-terminal-font)
+				 "White")
+	      (format "/EffectNT      %d def\n"
+		      (ebnf-font-attributes ebnf-non-terminal-font))
+	      (format "/BorderWidthNT %s def\n"
+		      (ebnf-format-float ebnf-non-terminal-border-width))
+	      (ebnf-format-color "/BorderColorNT %s def %% %s\n"
+				 ebnf-non-terminal-border-color
+				 "Black")
+	      (format "/ShapeNT       %d def\n"
+		      (ebnf-shape-value ebnf-non-terminal-shape
+					ebnf-terminal-shape-alist))
+	      (format "/ShadowNT      %s def\n"
+		      (ebnf-boolean ebnf-non-terminal-shadow))
+	      ;; special
+	      (format "/fS            %s /%s DefFont\n"
+		      (ebnf-format-float (ebnf-font-size ebnf-special-font))
+		      (ebnf-font-name-select ebnf-special-font))
+	      (ebnf-format-color "/ForegroundS   %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-special-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundS   %s def %% %s\n"
+				 (ebnf-font-background ebnf-special-font)
+				 "Gray95")
+	      (format "/EffectS       %d def\n"
+		      (ebnf-font-attributes ebnf-special-font))
+	      (format "/BorderWidthS  %s def\n"
+		      (ebnf-format-float ebnf-special-border-width))
+	      (ebnf-format-color "/BorderColorS  %s def %% %s\n"
+				 ebnf-special-border-color
+				 "Black")
+	      (format "/ShapeS        %d def\n"
+		      (ebnf-shape-value ebnf-special-shape
+					ebnf-terminal-shape-alist))
+	      (format "/ShadowS       %s def\n"
+		      (ebnf-boolean ebnf-special-shadow))
+	      ;; except
+	      (format "/fE            %s /%s DefFont\n"
+		      (ebnf-format-float (ebnf-font-size ebnf-except-font))
+		      (ebnf-font-name-select ebnf-except-font))
+	      (ebnf-format-color "/ForegroundE   %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-except-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundE   %s def %% %s\n"
+				 (ebnf-font-background ebnf-except-font)
+				 "Gray90")
+	      (format "/EffectE       %d def\n"
+		      (ebnf-font-attributes ebnf-except-font))
+	      (format "/BorderWidthE  %s def\n"
+		      (ebnf-format-float ebnf-except-border-width))
+	      (ebnf-format-color "/BorderColorE  %s def %% %s\n"
+				 ebnf-except-border-color
+				 "Black")
+	      (format "/ShapeE        %d def\n"
+		      (ebnf-shape-value ebnf-except-shape
+					ebnf-terminal-shape-alist))
+	      (format "/ShadowE       %s def\n"
+		      (ebnf-boolean ebnf-except-shadow))
+	      ;; repeat
+	      (format "/fR            %s /%s DefFont\n"
+		      (ebnf-format-float (ebnf-font-size ebnf-repeat-font))
+		      (ebnf-font-name-select ebnf-repeat-font))
+	      (ebnf-format-color "/ForegroundR   %s def %% %s\n"
+				 (ebnf-font-foreground ebnf-repeat-font)
+				 "Black")
+	      (ebnf-format-color "/BackgroundR   %s def %% %s\n"
+				 (ebnf-font-background ebnf-repeat-font)
+				 "Gray85")
+	      (format "/EffectR       %d def\n"
+		      (ebnf-font-attributes ebnf-repeat-font))
+	      (format "/BorderWidthR  %s def\n"
+		      (ebnf-format-float ebnf-repeat-border-width))
+	      (ebnf-format-color "/BorderColorR  %s def %% %s\n"
+				 ebnf-repeat-border-color
+				 "Black")
+	      (format "/ShapeR        %d def\n"
+		      (ebnf-shape-value ebnf-repeat-shape
+					ebnf-terminal-shape-alist))
+	      (format "/ShadowR       %s def\n"
+		      (ebnf-boolean ebnf-repeat-shadow))
+	      ;; miscellaneous
+	      (format "/DefaultWidth  %s def\n"
+		      (ebnf-format-float ebnf-default-width))
+	      (format "/LineWidth     %s def\n"
+		      (ebnf-format-float ebnf-line-width))
+	      (ebnf-format-color "/LineColor     %s def %% %s\n"
+				 ebnf-line-color
+				 "Black")
+	      (format "/ArrowShape    %d def\n"
+		      (ebnf-shape-value ebnf-arrow-shape
+					ebnf-arrow-shape-alist))
+	      (format "/ChartShape    %d def\n"
+		      (ebnf-shape-value ebnf-chart-shape
+					ebnf-terminal-shape-alist))
+	      (format "/UserArrow{%s}def\n"
+		      (ebnf-user-arrow ebnf-user-arrow))
+	      "\n% === end   EBNF settings\n\n"
+	      (and ebnf-debug-ps ebnf-debug))))
+   ebnf-prologue))
+
+
+(defun ebnf-user-arrow (user-arrow)
+  "Return a user arrow shape from USER-ARROW (a PostScript code).
+
+This function is only called when `ebnf-arrow-shape' is set to symbol `user'.
+
+If is a string, should be a PostScript procedure body.
+If is a variable symbol, should contain a string.
+If is a function symbol, it is called and the result is applied recursively.
+If is a cons and car is a function symbol, it is called as:
+   (funcall (car cons) (cdr cons))
+and the result is applied recursively.
+If is a cons and car is not a function symbol, it is applied recursively on
+car and cdr, and the results are concatened as:
+   (concat RESULT-FROM-CAR \" \" RESULT-FROM-CDR)
+If is a list and car is a function symbol, it is called as:
+   (apply (car list) (cdr list))
+and the result is applied recursively.
+If is a list and car is not a function symbol, it is applied recursively on
+each element and the resulting list is concatened as:
+   (mapconcat 'identity RESULTING-LIST \" \")
+Otherwise, it is treated as an empty string."
+  (cond
+   ((null user-arrow)
+    "")
+   ((stringp user-arrow)
+    user-arrow)
+   ((and (symbolp user-arrow) (fboundp user-arrow))
+    (ebnf-user-arrow (funcall user-arrow)))
+   ((and (symbolp user-arrow) (boundp user-arrow))
+    (ebnf-user-arrow (symbol-value user-arrow)))
+   ((consp user-arrow)
+    (if (and (symbolp (car user-arrow)) (fboundp (car user-arrow)))
+	(ebnf-user-arrow (funcall (car user-arrow) (cdr user-arrow)))
+      (concat (ebnf-user-arrow (car user-arrow))
+	      " "
+	      (ebnf-user-arrow (cdr user-arrow)))))
+   ((listp user-arrow)
+    (if (and (symbolp (car user-arrow))
+	     (fboundp (car user-arrow)))
+	(ebnf-user-arrow (apply (car user-arrow) (cdr user-arrow)))
+      (mapconcat 'ebnf-user-arrow user-arrow " ")))
+   (t
+    "")
+   ))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Adjusting dimensions
+
+
+(defun ebnf-dimensions (tree)
+  (let ((ebnf-total (length tree))
+	(ebnf-nprod 0))
+    (mapcar 'ebnf-production-dimension tree))
+  tree)
+
+
+;; [empty width-fun dim-fun entry height width]
+;;(defun ebnf-empty-dimension (empty)
+;;  )
+
+
+;; [production width-fun dim-fun entry height width name production action]
+(defun ebnf-production-dimension (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
+		    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))))
+
+
+;; [terminal width-fun dim-fun entry height width name]
+(defun ebnf-terminal-dimension (terminal)
+  (ebnf-terminal-dimension1 terminal
+			    ebnf-font-height-T
+			    ebnf-font-width-T
+			    ebnf-space-T))
+
+
+;; [non-terminal width-fun dim-fun entry height width name]
+(defun ebnf-non-terminal-dimension (non-terminal)
+  (ebnf-terminal-dimension1 non-terminal
+			    ebnf-font-height-NT
+			    ebnf-font-width-NT
+			    ebnf-space-NT))
+
+
+;; [special width-fun dim-fun entry height width name]
+(defun ebnf-special-dimension (special)
+  (ebnf-terminal-dimension1 special
+			    ebnf-font-height-S
+			    ebnf-font-width-S
+			    ebnf-space-S))
+
+
+(defun ebnf-terminal-dimension1 (node font-height font-width space)
+  (let ((height (+ space font-height space))
+	(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
+			      (* len font-width)
+			      space ebnf-basic-width))))
+
+
+(defconst ebnf-null-vector (vector t t t 0.0 0.0 0.0))
+
+
+;; [repeat width-fun dim-fun entry height width times element]
+(defun ebnf-repeat-dimension (repeat)
+  (let ((times   (ebnf-node-name repeat))
+	(element (ebnf-node-separator repeat)))
+    (if element
+	(ebnf-node-dimension-func element)
+      (setq element ebnf-null-vector))
+    (ebnf-node-entry  repeat (+ (ebnf-node-entry element)
+				ebnf-space-R))
+    (ebnf-node-height repeat (+ (max (ebnf-node-height element)
+				     ebnf-font-height-S)
+				ebnf-space-R ebnf-space-R))
+    (ebnf-node-width  repeat (+ (ebnf-node-width element)
+				ebnf-space-R ebnf-space-R ebnf-space-R
+				ebnf-horizontal-space
+				(* (length times) ebnf-font-width-R)))))
+
+
+;; [except width-fun dim-fun entry height width element element]
+(defun ebnf-except-dimension (except)
+  (let ((factor  (ebnf-node-list except))
+	(element (ebnf-node-separator except)))
+    (ebnf-node-dimension-func factor)
+    (if element
+	(ebnf-node-dimension-func element)
+      (setq element ebnf-null-vector))
+    (ebnf-node-entry  except (+ (max (ebnf-node-entry factor)
+				     (ebnf-node-entry element))
+				ebnf-space-E))
+    (ebnf-node-height except (+ (max (ebnf-node-height factor)
+				     (ebnf-node-height element))
+				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-space-E ebnf-space-E
+				ebnf-font-width-E
+				ebnf-horizontal-space))))
+
+
+;; [alternative width-fun dim-fun entry height width list]
+(defun ebnf-alternative-dimension (alternative)
+  (let ((body (ebnf-node-list alternative))
+	(lis  (ebnf-node-list alternative)))
+    (while lis
+      (ebnf-node-dimension-func (car lis))
+      (setq lis (cdr lis)))
+    (let ((height 0.0)
+	  (width  0.0)
+	  (alt    body)
+	  (tail   (car (last body)))
+	  (entry  (ebnf-node-entry (car body)))
+	  node)
+      (while alt
+	(setq node   (car alt)
+	      alt    (cdr alt)
+	      height (+ (ebnf-node-height node) height)
+	      width  (max (ebnf-node-width node) width)))
+      (ebnf-adjust-width body width)
+      (setq height (+ height (* (1- (length body)) ebnf-vertical-space)))
+      (ebnf-node-entry  alternative (+ entry
+				       (ebnf-entry
+					(- height entry
+					   (- (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))))
+
+
+;; [optional width-fun dim-fun entry height width element]
+(defun 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)
+				  ebnf-horizontal-space))))
+
+
+;; [one-or-more width-fun dim-fun entry height width element separator]
+(defun 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)
+    (and sep-part
+	 (ebnf-node-dimension-func sep-part))
+    (let ((height (+ (if sep-part
+			 (ebnf-node-height sep-part)
+		       0.0)
+		     ebnf-vertical-space
+		     (ebnf-node-height list-part)))
+	  (width  (max (if sep-part
+			   (ebnf-node-width sep-part)
+			 0.0)
+		       (ebnf-node-width list-part))))
+      (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 list-part)))
+      (ebnf-node-height or-more height)
+      (ebnf-node-width  or-more (+ width ebnf-horizontal-space)))))
+
+
+;; [zero-or-more width-fun dim-fun entry height width element separator]
+(defun 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)
+    (and sep-part
+	 (ebnf-node-dimension-func sep-part))
+    (let ((height (+ (if sep-part
+			 (ebnf-node-height sep-part)
+		       0.0)
+		     ebnf-vertical-space
+		     (ebnf-node-height list-part)
+		     ebnf-vertical-space))
+	  (width  (max (if sep-part
+			   (ebnf-node-width sep-part)
+			 0.0)
+		       (ebnf-node-width list-part))))
+      (when sep-part
+	(ebnf-adjust-width list-part width)
+	(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)))))
+
+
+;; [sequence width-fun dim-fun entry height width list]
+(defun ebnf-sequence-dimension (sequence)
+  (let ((above 0.0)
+	(below 0.0)
+	(width 0.0)
+	(lis   (ebnf-node-list sequence))
+	entry node)
+    (while lis
+      (setq node (car lis)
+	    lis  (cdr lis))
+      (ebnf-node-dimension-func node)
+      (setq entry (ebnf-node-entry node)
+	    above (max above entry)
+	    below (max below (- (ebnf-node-height node) entry))
+	    width (+ width (ebnf-node-width node))))
+    (ebnf-node-entry  sequence above)
+    (ebnf-node-height sequence (+ above below))
+    (ebnf-node-width  sequence width)))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Adjusting width
+
+
+(defun ebnf-adjust-width (node width)
+  (cond
+   ((listp node)
+    (prog1
+	node
+      (while node
+	(setcar node (ebnf-adjust-width (car node) width))
+	(setq node (cdr node)))))
+   ((vectorp node)
+    (cond
+     ;; nothing to be done
+     ((= width (ebnf-node-width node))
+      node)
+     ;; left justify term
+     ((eq ebnf-justify-sequence 'left)
+      (ebnf-adjust-empty node width nil))
+     ;; right justify terms
+     ((eq ebnf-justify-sequence 'right)
+      (ebnf-adjust-empty node width t))
+     ;; centralize terms
+     (t
+      (ebnf-node-width-func node width)
+      (ebnf-node-width node width)
+      node)
+     ))
+   (t
+    node)
+   ))
+
+
+(defun ebnf-adjust-empty (node width last-p)
+  (if (eq (ebnf-node-kind node) 'ebnf-generate-empty)
+      (progn
+	(ebnf-node-width node width)
+	node)
+    (let ((empty (ebnf-make-empty (- width (ebnf-node-width node)))))
+      (ebnf-make-dup-sequence node
+			      (if last-p
+				  (list empty node)
+				(list node empty))))))
+
+
+;; [terminal     width-fun dim-fun entry height width name]
+;; [non-terminal width-fun dim-fun entry height width name]
+;; [empty        width-fun dim-fun entry height width]
+;; [special      width-fun dim-fun entry height width name]
+;; [repeat       width-fun dim-fun entry height width times element]
+;; [except       width-fun dim-fun entry height width element element]
+;;(defun ebnf-terminal-width (terminal width)
+;;  )
+
+
+;; [alternative width-fun dim-fun entry height width list]
+;; [optional    width-fun dim-fun entry height width element]
+(defun ebnf-alternative-width (alternative width)
+  (ebnf-adjust-width (ebnf-node-list alternative)
+		     (- width ebnf-horizontal-space)))
+
+
+;; [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)
+  (setq width (- width ebnf-horizontal-space))
+  (ebnf-node-list or-more
+		  (ebnf-justify-list or-more
+				     (ebnf-node-list or-more)
+				     width))
+  (ebnf-node-separator or-more
+		       (ebnf-justify-list or-more
+					  (ebnf-node-separator or-more)
+					  width)))
+
+
+;; [sequence width-fun dim-fun entry height width list]
+(defun ebnf-sequence-width (sequence width)
+  (ebnf-node-list sequence
+		  (ebnf-justify-list sequence (ebnf-node-list sequence) width)))
+
+
+(defun ebnf-justify-list (node seq width)
+  (let ((seq-width (ebnf-node-width node)))
+    (if (= width seq-width)
+	seq
+      (cond
+       ;; left justify terms
+       ((eq ebnf-justify-sequence 'left)
+	(ebnf-justify node seq seq-width width t))
+       ;; right justify terms
+       ((eq ebnf-justify-sequence 'right)
+	(ebnf-justify node seq seq-width width nil))
+       ;; centralize terms
+       (t
+	(let ((the-width (/ (- width seq-width) (length seq)))
+	      (lis seq))
+	  (while lis
+	    (ebnf-adjust-width (car lis)
+			       (+ (ebnf-node-width (car lis))
+				  the-width))
+	    (setq lis (cdr lis)))
+	  seq))
+       ))))
+
+
+(defun ebnf-justify (node seq seq-width width last-p)
+  (let ((term (car (if last-p (last seq) seq))))
+    (cond
+     ;; adjust empty term
+     ((eq (ebnf-node-kind term) 'ebnf-generate-empty)
+      (ebnf-node-width term (+ (- width seq-width)
+			       (ebnf-node-width term)))
+      seq)
+     ;; insert empty at end ==> left justify
+     (last-p
+      (nconc seq
+	     (list (ebnf-make-empty (- width seq-width)))))
+     ;; insert empty at beginning ==> right justify
+     (t
+      (cons (ebnf-make-empty (- width seq-width))
+	    seq))
+     )))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Functions used by parsers
+
+
+(defun ebnf-eps-add-context (name)
+  (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)))))
+
+
+(defun ebnf-eps-remove-context (name)
+  (let ((filename (ebnf-eps-filename name)))
+    (if (member filename ebnf-eps-context)
+	(setq ebnf-eps-context (delete filename ebnf-eps-context))
+      (error "Try to close a not opened EPS file: %s" filename))))
+
+
+(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))))))
+
+
+(defun ebnf-dup-list (old)
+  (let (new)
+    (while old
+      (setq new (cons (car old) new)
+	    old (cdr old)))
+    (nreverse new)))
+
+
+(defun ebnf-buffer-substring (chars)
+  (buffer-substring-no-properties
+   (point)
+   (progn
+     (skip-chars-forward chars ebnf-limit)
+     (point))))
+
+
+(defun ebnf-string (chars eos-char kind)
+  (forward-char)
+  (buffer-substring-no-properties
+   (point)
+   (progn
+     (skip-chars-forward (concat chars "\240-\377") ebnf-limit)
+     (if (or (eobp) (/= (following-char) eos-char))
+	 (error "Illegal %s: missing `%c'." kind eos-char)
+       (forward-char)
+       (1- (point))))))
+
+
+(defun ebnf-get-string ()
+  (forward-char)
+  (buffer-substring-no-properties (point) (ebnf-end-of-string)))
+
+
+(defun ebnf-end-of-string ()
+  (let ((n 1))
+    (while (> (logand n 1) 0)
+      (skip-chars-forward "^\"" ebnf-limit)
+      (setq n (- (skip-chars-backward "\\\\")))
+      (goto-char (+ (point) n 1))))
+  (if (= (preceding-char) ?\")
+      (1- (point))
+    (error "Missing `\"'.")))
+
+
+(defun ebnf-trim-right (str)
+  (let* ((len   (1- (length str)))
+	 (index len))
+    (while (and (> index 0) (= (aref str index) ?\ ))
+      (setq index (1- index)))
+    (if (= index len)
+	str
+      (substring str 0 (1+ index)))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Vector creation
+
+
+(defun ebnf-make-empty (&optional width)
+  (vector 'ebnf-generate-empty
+	  'ignore
+	  'ignore
+	  0.0
+	  0.0
+	  (or width ebnf-horizontal-space)))
+
+
+(defun ebnf-make-terminal (name)
+  (ebnf-make-terminal1 name
+		       'ebnf-generate-terminal
+		       'ebnf-terminal-dimension))
+
+
+(defun ebnf-make-non-terminal (name)
+  (ebnf-make-terminal1 name
+		       'ebnf-generate-non-terminal
+		       'ebnf-non-terminal-dimension))
+
+
+(defun ebnf-make-special (name)
+  (ebnf-make-terminal1 name
+		       'ebnf-generate-special
+		       'ebnf-special-dimension))
+
+
+(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))
+
+
+(defun ebnf-make-one-or-more (list-part &optional sep-part)
+  (ebnf-make-or-more1 'ebnf-generate-one-or-more
+		      'ebnf-one-or-more-dimension
+		      list-part
+		      sep-part))
+
+
+(defun ebnf-make-zero-or-more (list-part &optional sep-part)
+  (ebnf-make-or-more1 'ebnf-generate-zero-or-more
+		      'ebnf-zero-or-more-dimension
+		      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)
+	      (ebnf-make-sequence list-part)
+	    list-part)
+	  (if (and sep-part (listp sep-part))
+	      (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))
+
+
+(defun ebnf-make-alternative (body)
+  (vector 'ebnf-generate-alternative
+	  'ebnf-alternative-width
+	  'ebnf-alternative-dimension
+	  0.0
+	  0.0
+	  0.0
+	  body))
+
+
+(defun ebnf-make-optional (body)
+  (vector 'ebnf-generate-optional
+	  'ebnf-alternative-width
+	  'ebnf-optional-dimension
+	  0.0
+	  0.0
+	  0.0
+	  body))
+
+
+(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))
+
+
+(defun ebnf-make-sequence (seq)
+  (vector 'ebnf-generate-sequence
+	  'ebnf-sequence-width
+	  'ebnf-sequence-dimension
+	  0.0
+	  0.0
+	  0.0
+	  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))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Optimizers used by parsers
+
+
+(defun ebnf-token-except (element exception)
+  (cons (prog1
+	    (car exception)
+	  (setq exception (cdr exception)))
+	(and element			; EMPTY - A ==> EMPTY
+	     (let ((kind (ebnf-node-kind element)))
+	       (cond
+		;; [ A ]- ==> A
+		((and (null exception)
+		      (eq kind 'ebnf-generate-optional))
+		 (ebnf-node-list element))
+		;; { A }- ==> { A }+
+		((and (null exception)
+		      (eq kind 'ebnf-generate-zero-or-more))
+		 (ebnf-node-kind element 'ebnf-generate-one-or-more)
+		 (ebnf-node-dimension-func element 'ebnf-one-or-more-dimension)
+		 element)
+		;; ( A | EMPTY )-      ==> A
+		;; ( A | B | EMPTY )-  ==> A | B
+		((and (null exception)
+		      (eq kind 'ebnf-generate-alternative)
+		      (eq (ebnf-node-kind (car (last (ebnf-node-list element))))
+			  'ebnf-generate-empty))
+		 (let ((elt (ebnf-node-list element))
+		       bef)
+		   (while (cdr elt)
+		     (setq bef elt
+			   elt (cdr elt)))
+		   (if (null bef)
+		       ;; this should not happen!!?!
+		       (setq element (ebnf-make-empty
+				      (ebnf-node-width element)))
+		     (setcdr bef nil)
+		     (setq elt (ebnf-node-list element))
+		     (and (= (length elt) 1)
+			  (setq element (car elt))))
+		   element))
+		;; A - B
+		(t
+		 (ebnf-make-except element exception))
+		)))))
+
+
+(defun ebnf-token-repeat (times repeat)
+  (if (null (cdr repeat))
+      ;; n * EMPTY ==> EMPTY
+      repeat
+    ;; n * term
+    (cons (car repeat)
+	  (ebnf-make-repeat times (cdr repeat)))))
+
+
+(defun ebnf-token-optional (body)
+  (let ((kind (ebnf-node-kind body)))
+    (cond
+     ;; [ EMPTY ] ==> EMPTY
+     ((eq kind 'ebnf-generate-empty)
+      nil)
+     ;; [ { A }* ] ==> { A }*
+     ((eq kind 'ebnf-generate-zero-or-more)
+      body)
+     ;; [ { A }+ ] ==> { A }*
+     ((eq kind 'ebnf-generate-one-or-more)
+      (ebnf-node-kind body 'ebnf-generate-zero-or-more)
+      body)
+     ;; [ A | B ] ==> A | B | EMPTY
+     ((eq kind 'ebnf-generate-alternative)
+      (ebnf-node-list body (nconc (ebnf-node-list body)
+				  (list (ebnf-make-empty))))
+      body)
+     ;; [ A ]
+     (t
+      (ebnf-make-optional body))
+     )))
+
+
+(defun ebnf-token-alternative (body sequence)
+  (if (null body)
+      (if (cdr sequence)
+	  sequence
+	(cons (car sequence)
+	      (ebnf-make-empty)))
+    (cons (car sequence)
+	  (let ((seq (cdr sequence)))
+	    (if (and (= (length body) 1) (null seq))
+		(car body)
+	      (ebnf-make-alternative (nreverse (if seq
+						   (cons seq body)
+						 body))))))))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Variables used by parsers
+
+
+(defconst ebnf-comment-table
+  (let ((table (make-vector 256 nil)))
+    ;; Override special comment character:
+    (aset table ?< 'newline)
+    (aset table ?> 'keep-line)
+    table)
+  "Vector used to map characters to a special comment token.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; To make this file smaller, some commands go in a separate file.
+;; But autoload them here to make the separation invisible.
+
+(autoload 'ebnf-bnf-parser            "ebnf-bnf"
+  "EBNF parser.")
+
+(autoload 'ebnf-bnf-initialize        "ebnf-bnf"
+  "Initialize EBNF token table.")
+
+(autoload 'ebnf-iso-parser            "ebnf-iso"
+  "ISO EBNF parser.")
+
+(autoload 'ebnf-iso-initialize        "ebnf-iso"
+  "Initialize ISO EBNF token table.")
+
+(autoload 'ebnf-yac-parser            "ebnf-yac"
+  "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-optimize              "ebnf-otz"
+  "Syntatic chart optimizer.")
+
+(autoload 'ebnf-otz-initialize        "ebnf-otz"
+  "Initialize optimizer.")
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
+(provide 'ebnf2ps)
+
+
+;;; ebnf2ps.el ends here