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