Add arch taglines
[bpt/emacs.git] / lisp / progmodes / ebnf2ps.el
CommitLineData
ab3256ed 1;;; ebnf2ps.el --- translate an EBNF to a syntactic chart on PostScript
984ae001 2
01d19dd7 3;; Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
984ae001 4
0b5ecd6d 5;; Author: Vinicius Jose Latorre <vinicius@cpqd.com.br>
984ae001 6;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
0b5ecd6d 7;; Keywords: wp, ebnf, PostScript
30fa28b4 8;; Time-stamp: <2003/08/08 23:09:36 vinicius>
68f38c8c 9;; Version: 3.6.1
0b5ecd6d 10;; X-URL: http://www.cpqd.com.br/~vinicius/emacs/
984ae001 11
8d9ea7b1 12;; This file is part of GNU Emacs.
984ae001 13
8d9ea7b1 14;; GNU Emacs is free software; you can redistribute it and/or modify
984ae001
GM
15;; it under the terms of the GNU General Public License as published by
16;; the Free Software Foundation; either version 2, or (at your option)
17;; any later version.
18
8d9ea7b1 19;; GNU Emacs is distributed in the hope that it will be useful,
984ae001
GM
20;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22;; GNU General Public License for more details.
23
24;; You should have received a copy of the GNU General Public License
25;; along with GNU Emacs; see the file COPYING. If not, write to the
26;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
27;; Boston, MA 02111-1307, USA.
28
68f38c8c
GM
29(defconst ebnf-version "3.6.1"
30 "ebnf2ps.el, v 3.6.1 <2001/09/24 vinicius>
8d9ea7b1
GM
31
32Vinicius's last change version. When reporting bugs, please also
33report the version of Emacs, if any, that ebnf2ps was running with.
34
35Please send all bug fixes and enhancements to
36 Vinicius Jose Latorre <vinicius@cpqd.com.br>.
37")
38
39
984ae001
GM
40;;; Commentary:
41
42;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
43;;
44;; Introduction
45;; ------------
46;;
ab3256ed 47;; This package translates an EBNF to a syntactic chart on PostScript.
984ae001
GM
48;;
49;; To use ebnf2ps, insert in your ~/.emacs:
50;;
51;; (require 'ebnf2ps)
52;;
b685181e
GM
53;; ebnf2ps uses ps-print package (version 5.2.3 or later), so see ps-print to
54;; know how to set options like landscape printing, page headings, margins,
55;; etc.
984ae001
GM
56;;
57;; NOTE: ps-print zebra stripes and line number options doesn't have effect on
58;; ebnf2ps, they behave as it's turned off.
59;;
60;; For good performance, be sure to byte-compile ebnf2ps.el, e.g.
61;;
62;; M-x byte-compile-file <give the path to ebnf2ps.el when prompted>
63;;
64;; This will generate ebnf2ps.elc, which will be loaded instead of ebnf2ps.el.
65;;
66;; ebnf2ps was tested with GNU Emacs 20.4.1.
67;;
68;;
69;; Using ebnf2ps
70;; -------------
71;;
ab3256ed 72;; ebnf2ps provides six commands for generating PostScript syntactic chart
b685181e 73;; images of Emacs buffers:
984ae001 74;;
b685181e
GM
75;; ebnf-print-buffer
76;; ebnf-print-region
77;; ebnf-spool-buffer
78;; ebnf-spool-region
79;; ebnf-eps-buffer
80;; ebnf-eps-region
984ae001
GM
81;;
82;; These commands all perform essentially the same function: they generate
ab3256ed 83;; PostScript syntactic chart images suitable for printing on a PostScript
984ae001
GM
84;; printer or displaying with GhostScript. These commands are collectively
85;; referred to as "ebnf- commands".
86;;
87;; The word "print", "spool" and "eps" in the command name determines when the
88;; PostScript image is sent to the printer (or file):
89;;
b685181e 90;; print - The PostScript image is immediately sent to the printer;
984ae001 91;;
b685181e
GM
92;; spool - The PostScript image is saved temporarily in an Emacs buffer.
93;; Many images may be spooled locally before printing them. To
94;; send the spooled images to the printer, use the command
95;; `ebnf-despool'.
984ae001 96;;
b685181e 97;; eps - The PostScript image is immediately sent to a EPS file.
984ae001
GM
98;;
99;; The spooling mechanism is the same as used by ps-print and was designed for
100;; printing lots of small files to save paper that would otherwise be wasted on
101;; banner pages, and to make it easier to find your output at the printer (it's
102;; easier to pick up one 50-page printout than to find 50 single-page
103;; printouts). As ebnf2ps and ps-print use the same Emacs buffer to spool
104;; images, you can intermix the spooling of ebnf2ps and ps-print images.
105;;
106;; ebnf2ps use the same hook of ps-print in the `kill-emacs-hook' so that you
107;; won't accidentally quit from Emacs while you have unprinted PostScript
108;; waiting in the spool buffer. If you do attempt to exit with spooled
109;; PostScript, you'll be asked if you want to print it, and if you decline,
b685181e
GM
110;; you'll be asked to confirm the exit; this is modeled on the confirmation
111;; that Emacs uses for modified buffers.
984ae001
GM
112;;
113;; The word "buffer" or "region" in the command name determines how much of the
114;; buffer is printed:
115;;
b685181e 116;; buffer - Print the entire buffer.
984ae001 117;;
b685181e 118;; region - Print just the current region.
984ae001
GM
119;;
120;; Two ebnf- command examples:
121;;
b685181e
GM
122;; ebnf-print-buffer - translate and print the entire buffer, and send it
123;; immediately to the printer.
984ae001 124;;
b685181e
GM
125;; ebnf-spool-region - translate and print just the current region, and
126;; spool the image in Emacs to send to the printer
127;; later.
984ae001
GM
128;;
129;; Note that `ebnf-eps-buffer' and `ebnf-eps-region' never spool the EPS image,
130;; so they don't use the ps-print spooling mechanism. See section "Actions in
131;; Comments" for an explanation about EPS file generation.
132;;
133;;
134;; Invoking Ebnf2ps
135;; ----------------
136;;
137;; To translate and print your buffer, type
138;;
139;; M-x ebnf-print-buffer
140;;
141;; or substitute one of the other four ebnf- commands. The command will
142;; generate the PostScript image and print or spool it as specified. By giving
143;; the command a prefix argument
144;;
145;; C-u M-x ebnf-print-buffer
146;;
147;; it will save the PostScript image to a file instead of sending it to the
148;; printer; you will be prompted for the name of the file to save the image to.
149;; The prefix argument is ignored by the commands that spool their images, but
150;; you may save the spooled images to a file by giving a prefix argument to
151;; `ebnf-despool':
152;;
153;; C-u M-x ebnf-despool
154;;
155;; When invoked this way, `ebnf-despool' will prompt you for the name of the
156;; file to save to.
157;;
158;; The prefix argument is also ignored by `ebnf-eps-buffer' and
159;; `ebnf-eps-region'.
160;;
161;; Any of the `ebnf-' commands can be bound to keys. Here are some examples:
162;;
163;; (global-set-key 'f22 'ebnf-print-buffer) ;f22 is prsc
164;; (global-set-key '(shift f22) 'ebnf-print-region)
165;; (global-set-key '(control f22) 'ebnf-despool)
166;;
167;;
168;; EBNF Syntax
169;; -----------
170;;
171;; The current EBNF that ebnf2ps accepts has the following constructions:
172;;
173;; ; comment (until end of line)
174;; A non-terminal
175;; "C" terminal
176;; ?C? special
177;; $A default non-terminal (see text below)
178;; $"C" default terminal (see text below)
179;; $?C? default special (see text below)
180;; A = B. production (A is the header and B the body)
181;; C D sequence (C occurs before D)
182;; C | D alternative (C or D occurs)
183;; A - B exception (A excluding B, B without any non-terminal)
184;; n * A repetition (A repeats n (integer) times)
185;; (C) group (expression C is grouped together)
186;; [C] optional (C may or not occurs)
187;; C+ one or more occurrences of C
188;; {C}+ one or more occurrences of C
189;; {C}* zero or more occurrences of C
190;; {C} zero or more occurrences of C
191;; C / D equivalent to: C {D C}*
192;; {C || D}+ equivalent to: C {D C}*
193;; {C || D}* equivalent to: [C {D C}*]
194;; {C || D} equivalent to: [C {D C}*]
195;;
196;; The EBNF syntax written using the notation above is:
197;;
198;; EBNF = {production}+.
199;;
200;; production = non_terminal "=" body ".". ;; production
201;;
202;; body = {sequence || "|"}*. ;; alternative
203;;
204;; sequence = {exception}*. ;; sequence
205;;
206;; exception = repeat [ "-" repeat]. ;; exception
207;;
208;; repeat = [ integer "*" ] term. ;; repetition
209;;
210;; term = factor
211;; | [factor] "+" ;; one-or-more
212;; | [factor] "/" [factor] ;; one-or-more
213;; .
214;;
215;; factor = [ "$" ] "\"" terminal "\"" ;; terminal
216;; | [ "$" ] non_terminal ;; non-terminal
217;; | [ "$" ] "?" special "?" ;; special
218;; | "(" body ")" ;; group
219;; | "[" body "]" ;; zero-or-one
220;; | "{" body [ "||" body ] "}+" ;; one-or-more
221;; | "{" body [ "||" body ] "}*" ;; zero-or-more
222;; | "{" body [ "||" body ] "}" ;; zero-or-more
223;; .
224;;
0b5ecd6d 225;; non_terminal = "[!#%&'*-,0-:<>@-Z\\\\^-z~\\240-\\377]+".
984ae001
GM
226;;
227;; terminal = "\\([^\"\\]\\|\\\\[ -~\\240-\\377]\\)+".
228;;
229;; special = "[^?\\n\\000-\\010\\016-\\037\\177-\\237]*".
230;;
231;; integer = "[0-9]+".
232;;
233;; comment = ";" "[^\\n\\000-\\010\\016-\\037\\177-\\237]*" "\\n".
234;;
235;; Try to use the above EBNF to test ebnf2ps.
236;;
237;; The `default' terminal, non-terminal and special is a way to indicate a
238;; default path in a production. For example, the production:
239;;
240;; X = [ $A ( B | $C ) | D ].
241;;
242;; Indicates that the default meaning for "X" is "A C" if "X" is empty.
243;;
244;; The terminal name is controlled by `ebnf-terminal-regexp' and
245;; `ebnf-case-fold-search', so it's possible to match other kind of terminal
246;; name besides that enclosed by `"'.
247;;
248;; Let's see an example:
249;;
250;; (setq ebnf-terminal-regexp "[A-Z][_A-Z]*") ; upper case name
251;; (setq ebnf-case-fold-search nil) ; exact matching
252;;
253;; If you have the production:
254;;
255;; Logical = "(" Expression ( OR | AND | "XOR" ) Expression ")".
256;;
257;; The names are classified as:
258;;
259;; Logical Expression non-terminal
260;; "(" OR AND "XOR" ")" terminal
261;;
b685181e
GM
262;; The line comment is controlled by `ebnf-lex-comment-char'. The default
263;; value is ?\; (character `;').
984ae001
GM
264;;
265;; The end of production is controlled by `ebnf-lex-eop-char'. The default
266;; value is ?. (character `.').
267;;
268;; The variable `ebnf-syntax' specifies which syntax to recognize:
269;;
270;; `ebnf' ebnf2ps recognizes the syntax described above.
271;; The following variables *ONLY* have effect with this
272;; setting:
273;; `ebnf-terminal-regexp', `ebnf-case-fold-search',
274;; `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
275;;
276;; `iso-ebnf' ebnf2ps recognizes the syntax described in the URL:
277;; `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
278;; ("International Standard of the ISO EBNF Notation").
279;; The following variables *ONLY* have effect with this
280;; setting:
281;; `ebnf-iso-alternative-p' and `ebnf-iso-normalize-p'.
282;;
283;; `yacc' ebnf2ps recognizes the Yacc/Bison syntax.
284;; The following variable *ONLY* has effect with this
285;; setting:
286;; `ebnf-yac-ignore-error-recovery'.
287;;
288;; Any other value is treated as `ebnf'.
289;;
290;; The default value is `ebnf'.
291;;
292;;
293;; Optimizations
294;; -------------
295;;
296;; The following EBNF optimizations are done:
297;;
298;; [ { A }* ] ==> { A }*
299;; [ { A }+ ] ==> { A }*
300;; [ A ] + ==> { A }*
301;; { A }* + ==> { A }*
302;; { A }+ + ==> { A }+
303;; { A }- ==> { A }+
304;; [ A ]- ==> A
305;; ( A | EMPTY )- ==> A
306;; ( A | B | EMPTY )- ==> A | B
307;; [ A | B ] ==> A | B | EMPTY
308;; n * EMPTY ==> EMPTY
309;; EMPTY + ==> EMPTY
310;; EMPTY / EMPTY ==> EMPTY
311;; EMPTY - A ==> EMPTY
312;;
313;; The following optimizations are done when `ebnf-optimize' is non-nil:
314;;
315;; left recursion:
316;; 1. A = B | A C. ==> A = B {C}*.
317;; 2. A = B | A B. ==> A = {B}+.
318;; 3. A = | A B. ==> A = {B}*.
319;; 4. A = B | A C B. ==> A = {B || C}+.
320;; 5. A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
321;;
322;; optional:
323;; 6. A = B | . ==> A = [B].
324;; 7. A = | B . ==> A = [B].
325;;
326;; factoration:
327;; 8. A = B C | B D. ==> A = B (C | D).
328;; 9. A = C B | D B. ==> A = (C | D) B.
329;; 10. A = B C E | B D E. ==> A = B (C | D) E.
330;;
331;; The above optimizations are specially useful when `ebnf-syntax' is `yacc'.
332;;
333;;
334;; Form Feed
335;; ---------
336;;
b685181e
GM
337;; You may use form feed (^L \014) to force a production to start on a new
338;; page, for example:
984ae001
GM
339;;
340;; a) A = B | C.
341;; ^L
342;; X = Y | Z.
343;;
344;; b) A = B ^L | C.
345;; X = Y | Z.
346;;
347;; c) A = B ^L^L^L | C.^L
348;; ^L
349;; X = Y | Z.
350;;
351;; In all examples above, only the production X will start on a new page.
352;;
353;;
354;; Actions in Comments
355;; -------------------
356;;
357;; ebnf2ps accepts the following actions in comments:
358;;
359;; ;> the next production starts in the same line as the current one.
360;; It is useful when `ebnf-horizontal-orientation' is nil.
361;;
362;; ;< the next production starts in the next line.
363;; It is useful when `ebnf-horizontal-orientation' is non-nil.
364;;
365;; ;[EPS open a new EPS file. The EPS file name has the form:
366;; <PREFIX><NAME>.eps
b685181e
GM
367;; where <PREFIX> is given by variable `ebnf-eps-prefix' and
368;; <NAME> is the string given by ;[ action comment, this string is
369;; mapped to form a valid file name (see documentation for
984ae001
GM
370;; `ebnf-eps-buffer' or `ebnf-eps-region').
371;; It has effect only during `ebnf-eps-buffer' or
372;; `ebnf-eps-region' execution.
373;; It's an error to try to open an already opened EPS file.
374;;
375;; ;]EPS close an opened EPS file.
376;; It has effect only during `ebnf-eps-buffer' or
377;; `ebnf-eps-region' execution.
378;; It's an error to try to close a not opened EPS file.
379;;
380;; So if you have:
381;;
382;; (setq ebnf-horizontal-orientation nil)
383;;
384;; A = t.
385;; C = x.
386;; ;> C and B are drawn in the same line
387;; B = y.
388;; W = v.
389;;
390;; The graphical result is:
391;;
392;; +---+
393;; | A |
394;; +---+
395;;
396;; +---------+ +-----+
397;; | | | |
398;; | C | | |
399;; | | | B |
400;; +---------+ | |
401;; | |
402;; +-----+
403;;
404;; +-----------+
405;; | W |
406;; +-----------+
407;;
408;; Note that if ascending production sort is used, the productions A and B will
409;; be drawn in the same line instead of C and B.
410;;
b685181e
GM
411;; If consecutive actions occur, only the last one takes effect, so if you
412;; have:
984ae001
GM
413;;
414;; A = X.
415;; ;<
416;; ^L
417;; ;>
418;; B = Y.
419;;
420;; Only the ;> will take effect, that is, A and B will be drawn in the same
421;; line.
422;;
423;; In ISO EBNF the above actions are specified as (*>*), (*<*), (*[EPS*) and
424;; (*]EPS*). The first example above should be written:
425;;
426;; A = t;
427;; C = x;
428;; (*> C and B are drawn in the same line *)
429;; B = y;
430;; W = v;
431;;
432;; For an example of EPS action when executing `ebnf-eps-buffer' or
433;; `ebnf-eps-region':
434;;
435;; Z = B0.
436;; ;[CC
437;; ;[AA
438;; A = B1.
439;; ;[BB
440;; C = B2.
441;; ;]AA
442;; B = B3.
443;; ;]BB
444;; ;]CC
445;; D = B4.
446;; E = B5.
447;; ;[CC
448;; F = B6.
449;; ;]CC
450;; G = B7.
451;;
452;; The following table summarizes the results:
453;;
454;; EPS FILE NAME NO SORT ASCENDING SORT DESCENDING SORT
455;; ebnf--AA.eps A C A C C A
456;; ebnf--BB.eps C B B C C B
457;; ebnf--CC.eps A C B F A B C F F C B A
458;; ebnf--D.eps D D D
459;; ebnf--E.eps E E E
460;; ebnf--G.eps G G G
461;; ebnf--Z.eps Z Z Z
462;;
463;; As you can see if EPS actions is not used, each single production is
464;; generated per EPS file. To avoid overriding EPS files, use names in ;[ that
465;; it's not an existing production name.
466;;
467;; In the following case:
468;;
469;; A = B0.
470;; ;[AA
471;; A = B1.
472;; ;[BB
473;; A = B2.
474;;
475;; The production A is generated in both files ebnf--AA.eps and ebnf--BB.eps.
476;;
477;;
478;; Utilities
479;; ---------
480;;
481;; Some tools are provided to help you.
482;;
483;; `ebnf-setup' returns the current setup.
484;;
ab3256ed 485;; `ebnf-syntax-buffer' does a syntactic analysis of your EBNF in the current
984ae001
GM
486;; buffer.
487;;
ab3256ed 488;; `ebnf-syntax-region' does a syntactic analysis of your EBNF in the current
984ae001
GM
489;; region.
490;;
491;; `ebnf-customize' activates a customization buffer for ebnf2ps options.
492;;
493;; `ebnf-syntax-buffer', `ebnf-syntax-region' and `ebnf-customize' can be bound
494;; to keys in the same way as `ebnf-' commands.
495;;
496;;
497;; Hooks
498;; -----
499;;
500;; ebn2ps has the following hook variables:
501;;
502;; `ebnf-hook'
503;; It is evaluated once before any ebnf2ps process.
504;;
505;; `ebnf-production-hook'
506;; It is evaluated on each beginning of production.
507;;
508;; `ebnf-page-hook'
509;; It is evaluated on each beginning of page.
510;;
511;;
512;; Options
513;; -------
514;;
515;; Below it's shown a brief description of ebnf2ps options, please, see the
516;; options declaration in the code for a long documentation.
517;;
518;; `ebnf-horizontal-orientation' Non-nil means productions are drawn
519;; horizontally.
520;;
521;; `ebnf-horizontal-max-height' Non-nil means to use maximum production
522;; height in horizontal orientation.
523;;
524;; `ebnf-production-horizontal-space' Specify horizontal space in points
525;; between productions.
526;;
b685181e
GM
527;; `ebnf-production-vertical-space' Specify vertical space in points
528;; between productions.
984ae001
GM
529;;
530;; `ebnf-justify-sequence' Specify justification of terms in a
531;; sequence inside alternatives.
532;;
533;; `ebnf-terminal-regexp' Specify how it's a terminal name.
534;;
535;; `ebnf-case-fold-search' Non-nil means ignore case on matching.
536;;
537;; `ebnf-terminal-font' Specify terminal font.
538;;
539;; `ebnf-terminal-shape' Specify terminal box shape.
540;;
541;; `ebnf-terminal-shadow' Non-nil means terminal box will have a
542;; shadow.
543;;
544;; `ebnf-terminal-border-width' Specify border width for terminal box.
545;;
546;; `ebnf-terminal-border-color' Specify border color for terminal box.
547;;
548;; `ebnf-sort-production' Specify how productions are sorted.
549;;
550;; `ebnf-production-font' Specify production font.
551;;
552;; `ebnf-non-terminal-font' Specify non-terminal font.
553;;
554;; `ebnf-non-terminal-shape' Specify non-terminal box shape.
555;;
b685181e
GM
556;; `ebnf-non-terminal-shadow' Non-nil means non-terminal box will
557;; have a shadow.
984ae001
GM
558;;
559;; `ebnf-non-terminal-border-width' Specify border width for non-terminal
560;; box.
561;;
562;; `ebnf-non-terminal-border-color' Specify border color for non-terminal
563;; box.
564;;
565;; `ebnf-special-font' Specify special font.
566;;
567;; `ebnf-special-shape' Specify special box shape.
568;;
569;; `ebnf-special-shadow' Non-nil means special box will have a
570;; shadow.
571;;
572;; `ebnf-special-border-width' Specify border width for special box.
573;;
574;; `ebnf-special-border-color' Specify border color for special box.
575;;
576;; `ebnf-except-font' Specify except font.
577;;
578;; `ebnf-except-shape' Specify except box shape.
579;;
580;; `ebnf-except-shadow' Non-nil means except box will have a
581;; shadow.
582;;
583;; `ebnf-except-border-width' Specify border width for except box.
584;;
585;; `ebnf-except-border-color' Specify border color for except box.
586;;
587;; `ebnf-repeat-font' Specify repeat font.
588;;
589;; `ebnf-repeat-shape' Specify repeat box shape.
590;;
591;; `ebnf-repeat-shadow' Non-nil means repeat box will have a
592;; shadow.
593;;
594;; `ebnf-repeat-border-width' Specify border width for repeat box.
595;;
596;; `ebnf-repeat-border-color' Specify border color for repeat box.
597;;
598;; `ebnf-entry-percentage' Specify entry height on alternatives.
599;;
600;; `ebnf-arrow-shape' Specify the arrow shape.
601;;
602;; `ebnf-chart-shape' Specify chart flow shape.
603;;
604;; `ebnf-color-p' Non-nil means use color.
605;;
606;; `ebnf-line-width' Specify flow line width.
607;;
608;; `ebnf-line-color' Specify flow line color.
609;;
bf061ba6 610;; `ebnf-user-arrow' Specify a sexp for user arrow shape (a
b685181e 611;; PostScript code).
984ae001
GM
612;;
613;; `ebnf-debug-ps' Non-nil means to generate PostScript
614;; debug procedures.
615;;
616;; `ebnf-lex-comment-char' Specify the line comment character.
617;;
b685181e
GM
618;; `ebnf-lex-eop-char' Specify the end of production
619;; character.
984ae001
GM
620;;
621;; `ebnf-syntax' Specify syntax to be recognized.
622;;
623;; `ebnf-iso-alternative-p' Non-nil means use alternative ISO EBNF.
624;;
625;; `ebnf-iso-normalize-p' Non-nil means normalize ISO EBNF syntax
626;; names.
627;;
628;; `ebnf-default-width' Specify additional border width over
629;; default terminal, non-terminal or
630;; special.
631;;
632;; `ebnf-eps-prefix' Specify EPS prefix file name.
633;;
634;; `ebnf-use-float-format' Non-nil means use `%f' float format.
635;;
636;; `ebnf-yac-ignore-error-recovery' Non-nil means ignore error recovery.
637;;
638;; `ebnf-ignore-empty-rule' Non-nil means ignore empty rules.
639;;
ab3256ed 640;; `ebnf-optimize' Non-nil means optimize syntactic chart
b685181e 641;; of rules.
984ae001
GM
642;;
643;; To set the above options you may:
644;;
645;; a) insert the code in your ~/.emacs, like:
646;;
647;; (setq ebnf-terminal-shape 'bevel)
648;;
649;; This way always keep your default settings when you enter a new Emacs
650;; session.
651;;
652;; b) or use `set-variable' in your Emacs session, like:
653;;
654;; M-x set-variable RET ebnf-terminal-shape RET bevel RET
655;;
656;; This way keep your settings only during the current Emacs session.
657;;
658;; c) or use customization, for example:
659;; click on menu-bar *Help* option,
660;; then click on *Customize*,
661;; then click on *Browse Customization Groups*,
662;; expand *PostScript* group,
663;; expand *Ebnf2ps* group
664;; and then customize ebnf2ps options.
665;; Through this way, you may choose if the settings are kept or not when
666;; you leave out the current Emacs session.
667;;
668;; d) or see the option value:
669;;
670;; C-h v ebnf-terminal-shape RET
671;;
672;; and click the *customize* hypertext button.
673;; Through this way, you may choose if the settings are kept or not when
674;; you leave out the current Emacs session.
675;;
676;; e) or invoke:
677;;
678;; M-x ebnf-customize RET
679;;
680;; and then customize ebnf2ps options.
681;; Through this way, you may choose if the settings are kept or not when
682;; you leave out the current Emacs session.
683;;
684;;
685;; Styles
686;; ------
687;;
688;; Sometimes you need to change the EBNF style you are using, for example,
689;; change the shapes and colors. These changes may force you to set some
690;; variables and after use, set back the variables to the old values.
691;;
692;; To help to handle this situation, ebnf2ps has the following commands to
693;; handle styles:
694;;
695;; `ebnf-insert-style' Insert a new style NAME with inheritance INHERITS and
696;; values VALUES.
697;;
698;; `ebnf-merge-style' Merge values of style NAME with style VALUES.
699;;
700;; `ebnf-apply-style' Set STYLE to current style.
701;;
702;; `ebnf-reset-style' Reset current style.
703;;
704;; `ebnf-push-style' Push the current style and set STYLE to current style.
705;;
706;; `ebnf-pop-style' Pop a style and set it to current style.
707;;
708;; These commands helps to put together a lot of variable settings in a group
709;; and name this group. So when you wish to apply these settings it's only
710;; needed to give the name.
711;;
b685181e
GM
712;; There is also a notion of simple inheritance of style; so if you declare
713;; that a style A inherits from a style B, all settings of B is applied first
714;; and then the settings of A is applied. This is useful when you wish to
715;; modify some aspects of an existing style, but at same time wish to keep it
984ae001
GM
716;; unmodified.
717;;
718;; See documentation for `ebnf-style-database'.
719;;
720;;
721;; Layout
722;; ------
723;;
724;; Below it is the layout of minimum area to draw each element, and it's used
725;; the following terms:
726;;
727;; font height is given by:
728;; (terminal font height + non-terminal font height) / 2
729;;
b685181e
GM
730;; entry is the vertical position used to know where it should
731;; be drawn the flow line in the current element.
984ae001
GM
732;;
733;;
734;; * SPECIAL, TERMINAL and NON-TERMINAL
735;;
736;; +==============+...................................
737;; | | } font height / 2 } entry }
738;; | XXXXXXXX...|....... } }
739;; ====+ XXXXXXXX +==== } text height ...... } height
740;; : | XXXXXXXX...|...:... }
741;; : | : : | : } font height / 2 }
742;; : +==============+...:...............................
743;; : : : : : :
744;; : : : : : :......................
745;; : : : : : } font height }
746;; : : : : :....... }
747;; : : : : } font height / 2 }
748;; : : : :........... }
749;; : : : } text width } width
750;; : : :.................. }
751;; : : } font height / 2 }
752;; : :...................... }
753;; : } font height }
754;; :.............................................
755;;
756;;
757;; * OPTIONAL
758;;
759;; +==========+.....................................
760;; | | } } }
761;; | | } entry } }
762;; | | } } }
763;; ===+===+ +===+===... } element height } height
764;; : \ | | / : } }
765;; : + | | + : } }
766;; : | +==========+.|................. }
767;; : | : : | : } font height }
768;; : +==============+...................................
769;; : : : :
770;; : : : :......................
771;; : : : } font height * 2 }
772;; : : :.......... }
773;; : : } element width } width
774;; : :..................... }
775;; : } font height * 2 }
776;; :...............................................
777;;
778;;
779;; * ALTERNATIVE
780;;
781;; +===+...................................
782;; +==+ A +==+ } A height } }
783;; | +===+..|........ } entry }
784;; + + } font height } }
785;; / +===+...\....... } }
786;; ===+====+ B +====+=== } B height ..... } height
787;; : \ +===+.../....... }
788;; : + + : } font height }
789;; : | +===+..|........ }
790;; : +==+ C +==+ : } C height }
791;; : : +===+...................................
792;; : : : :
793;; : : : :......................
794;; : : : } font height * 2 }
795;; : : :......... }
796;; : : } max width } width
797;; : :................. }
798;; : } font height * 2 }
799;; :..........................................
800;;
801;; NOTES:
802;; 1. An empty alternative has zero of height.
803;;
804;; 2. The variable `ebnf-entry-percentage' is used to determine the
805;; entry point.
806;;
807;;
808;; * ZERO OR MORE
809;;
810;; +===========+...............................
811;; +=+ separator +=+ } separator height }
812;; / +===========+..\........ }
813;; + + } }
814;; | | } font height }
815;; + + } }
816;; \ +===========+../........ } height = entry
817;; +=+ element +=+ } element height }
818;; /: +===========+..\........ }
819;; + : : + } }
820;; + : : + } font height }
821;; / : : \ } }
822;; ==+=======================+==.......................
823;; : : : :
824;; : : : :.......................
825;; : : : } font height * 2 }
826;; : : :......... }
827;; : : } max width } width
828;; : :......................... }
829;; : } font height * 2 }
830;; :...................................................
831;;
832;;
833;; * ONE OR MORE
834;;
835;; +===========+......................................
836;; +=+ separator +=+ } separator height } }
837;; / +===========+..\...... } }
838;; + + } } entry }
839;; | | } font height } } height
840;; + + } } }
841;; \ +===========+../...... } }
842;; ===+=+ element +=+=== } element height .... }
843;; : : +===========+......................................
844;; : : : :
845;; : : : :........................
846;; : : : } font height * 2 }
847;; : : :....... }
848;; : : } max width } width
849;; : :....................... }
850;; : } font height * 2 }
851;; :..............................................
852;;
853;;
854;; * PRODUCTION
855;;
856;; XXXXXX:......................................
857;; XXXXXX: } production font height }
858;; XXXXXX:............ }
859;; } font height }
860;; +======+....... } height = entry
861;; | | } }
862;; ====+ +==== } element height }
863;; : | | : } }
864;; : +======+.................................
865;; : : : :
866;; : : : :......................
867;; : : : } font height * 2 }
868;; : : :....... }
869;; : : } element width } width
870;; : :.............. }
871;; : } font height * 2 }
872;; :.....................................
873;;
874;;
875;; * REPEAT
876;;
877;; +================+...................................
878;; | | } font height / 2 } entry }
879;; | +===+...|....... } }
880;; ====+ N * | X | +==== } X height ......... } height
881;; : | : : +===+...|...:... }
882;; : | : : : : | : } font height / 2 }
883;; : +================+...:...............................
884;; : : : : : : : :
885;; : : : : : : : :......................
886;; : : : : : : : } font height }
887;; : : : : : : :....... }
888;; : : : : : : } font height / 2 }
889;; : : : : : :........... }
890;; : : : : : } X width }
891;; : : : : :............... }
892;; : : : : } font height / 2 } width
893;; : : : :.................. }
894;; : : : } text width }
895;; : : :..................... }
896;; : : } font height / 2 }
897;; : :........................ }
898;; : } font height }
899;; :...............................................
900;;
901;;
902;; * EXCEPT
903;;
904;; +==================+...................................
905;; | | } font height / 2 } entry }
906;; | +===+ +===+...|....... } }
907;; ====+ | X | - | y | +==== } max height ....... } height
908;; : | +===+ +===+...|...:... }
909;; : | : : : : | : } font height / 2 }
910;; : +==================+...:...............................
911;; : : : : : : : :
912;; : : : : : : : :......................
913;; : : : : : : : } font height }
914;; : : : : : : :....... }
915;; : : : : : : } font height / 2 }
916;; : : : : : :........... }
917;; : : : : : } Y width }
918;; : : : : :............... }
919;; : : : : } font height } width
920;; : : : :................... }
921;; : : : } X width }
922;; : : :....................... }
923;; : : } font height / 2 }
924;; : :.......................... }
925;; : } font height }
926;; :.................................................
927;;
928;; NOTE: If Y element is empty, it's draw nothing at Y place.
929;;
930;;
931;; Internal Structures
932;; -------------------
933;;
ab3256ed 934;; ebnf2ps has two passes. The first pass does a lexical and syntactic analysis
984ae001 935;; of current buffer and generates an intermediate representation. The second
b685181e 936;; pass uses the intermediate representation to generate the PostScript
ab3256ed 937;; syntactic chart.
984ae001
GM
938;;
939;; The intermediate representation is a list of vectors, the vector element
ab3256ed
JB
940;; represents a syntactic chart element. Below is a vector representation for
941;; each syntactic chart element.
984ae001 942;;
b685181e 943;; [production WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME PRODUCTION ACTION]
984ae001
GM
944;; [alternative WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH LIST]
945;; [sequence WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH LIST]
946;; [terminal WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME DEFAULT]
947;; [non-terminal WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME DEFAULT]
948;; [special WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH NAME DEFAULT]
949;; [empty WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH]
950;; [optional WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT]
951;; [one-or-more WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT SEPARATOR]
952;; [zero-or-more WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT SEPARATOR]
953;; [repeat WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH TIMES ELEMENT]
954;; [except WIDTH-FUN DIM-FUN ENTRY HEIGHT WIDTH ELEMENT ELEMENT]
955;;
956;; The first vector position is a function symbol used to generate PostScript
957;; for this element.
958;; WIDTH-FUN is a function symbol called to adjust the element width.
959;; DIM-FUN is a function symbol called to set the element dimensions.
960;; ENTRY is the element entry point.
961;; HEIGHT and WIDTH are the element height and width, respectively.
962;; NAME is a string that it's the element name.
963;; DEFAULT is a boolean that indicates if it's a `default' element.
964;; PRODUCTION and ELEMENT are vectors that represents sub-elements of current
965;; one.
966;; LIST is a list of vector that represents the list part for alternatives and
967;; sequences.
968;; SEPARATOR is a vector that represents the sub-element used to separate the
969;; list elements.
970;; TIMES is a string representing the number of times that ELEMENT is repeated
971;; on a repeat construction.
972;; ACTION indicates some action that should be done before production is
973;; generated. The current actions are:
974;;
975;; nil no action.
976;;
977;; form-feed current production starts on a new page.
978;;
979;; newline current production starts on next line, this is useful
980;; when `ebnf-horizontal-orientation' is non-nil.
981;;
982;; keep-line current production continues on the current line, this
983;; is useful when `ebnf-horizontal-orientation' is nil.
984;;
985;;
986;; Things To Change
987;; ----------------
988;;
ab3256ed 989;; . Handle situations when syntactic chart is out of paper.
984ae001
GM
990;; . Use other alphabet than ascii.
991;; . Optimizations...
992;;
993;;
994;; Acknowledgements
995;; ----------------
996;;
997;; Thanks to all who emailed comments.
998;;
999;;
1000;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1001
e8af40ee 1002;;; Code:
984ae001
GM
1003
1004
1005(require 'ps-print)
1006
b685181e
GM
1007(and (string< ps-print-version "5.2.3")
1008 (error "`ebnf2ps' requires `ps-print' package version 5.2.3 or later"))
984ae001
GM
1009
1010\f
1011;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1012;; User Variables:
1013
1014
1015;;; Interface to the command system
1016
1017(defgroup postscript nil
1018 "PostScript Group"
1019 :tag "PostScript"
1020 :group 'emacs)
1021
1022
1023(defgroup ebnf2ps nil
ab3256ed 1024 "Translate an EBNF to a syntactic chart on PostScript"
984ae001
GM
1025 :prefix "ebnf-"
1026 :group 'wp
1027 :group 'postscript)
1028
1029
1030(defgroup ebnf-special nil
1031 "Special customization"
1032 :prefix "ebnf-"
1033 :tag "Special"
1034 :group 'ebnf2ps)
1035
1036
1037(defgroup ebnf-except nil
1038 "Except customization"
1039 :prefix "ebnf-"
1040 :tag "Except"
1041 :group 'ebnf2ps)
1042
1043
1044(defgroup ebnf-repeat nil
1045 "Repeat customization"
1046 :prefix "ebnf-"
1047 :tag "Repeat"
1048 :group 'ebnf2ps)
1049
1050
1051(defgroup ebnf-terminal nil
1052 "Terminal customization"
1053 :prefix "ebnf-"
1054 :tag "Terminal"
1055 :group 'ebnf2ps)
1056
1057
1058(defgroup ebnf-non-terminal nil
1059 "Non-Terminal customization"
1060 :prefix "ebnf-"
1061 :tag "Non-Terminal"
1062 :group 'ebnf2ps)
1063
1064
1065(defgroup ebnf-production nil
1066 "Production customization"
1067 :prefix "ebnf-"
1068 :tag "Production"
1069 :group 'ebnf2ps)
1070
1071
1072(defgroup ebnf-shape nil
1073 "Shapes customization"
1074 :prefix "ebnf-"
1075 :tag "Shape"
1076 :group 'ebnf2ps)
1077
1078
1079(defgroup ebnf-displacement nil
1080 "Displacement customization"
1081 :prefix "ebnf-"
1082 :tag "Displacement"
1083 :group 'ebnf2ps)
1084
1085
ab3256ed
JB
1086(defgroup ebnf-syntactic nil
1087 "Syntactic customization"
984ae001 1088 :prefix "ebnf-"
ab3256ed 1089 :tag "Syntactic"
984ae001
GM
1090 :group 'ebnf2ps)
1091
1092
1093(defgroup ebnf-optimization nil
1094 "Optimization customization"
1095 :prefix "ebnf-"
1096 :tag "Optimization"
1097 :group 'ebnf2ps)
1098
1099
1100(defcustom ebnf-horizontal-orientation nil
1101 "*Non-nil means productions are drawn horizontally."
1102 :type 'boolean
1103 :group 'ebnf-displacement)
1104
1105
1106(defcustom ebnf-horizontal-max-height nil
1107 "*Non-nil means to use maximum production height in horizontal orientation.
1108
1109It is only used when `ebnf-horizontal-orientation' is non-nil."
1110 :type 'boolean
1111 :group 'ebnf-displacement)
1112
1113
1114(defcustom ebnf-production-horizontal-space 0.0 ; use ebnf2ps default value
1115 "*Specify horizontal space in points between productions.
1116
1117Value less or equal to zero forces ebnf2ps to set a proper default value."
1118 :type 'number
1119 :group 'ebnf-displacement)
1120
1121
1122(defcustom ebnf-production-vertical-space 0.0 ; use ebnf2ps default value
1123 "*Specify vertical space in points between productions.
1124
1125Value less or equal to zero forces ebnf2ps to set a proper default value."
1126 :type 'number
1127 :group 'ebnf-displacement)
1128
1129
1130(defcustom ebnf-justify-sequence 'center
1131 "*Specify justification of terms in a sequence inside alternatives.
1132
1133Valid values are:
1134
1135 `left' left justification
1136 `right' right justification
1137 any other value centralize"
1138 :type '(radio :tag "Sequence Justification"
1139 (const left) (const right) (other :tag "center" center))
1140 :group 'ebnf-displacement)
1141
1142
1143(defcustom ebnf-special-font '(7 Courier "Black" "Gray95" bold italic)
1144 "*Specify special font.
1145
1146See documentation for `ebnf-production-font'."
1147 :type '(list :tag "Special Font"
1148 (number :tag "Font Size")
1149 (symbol :tag "Font Name")
1150 (choice :tag "Foreground Color"
1151 (string :tag "Name")
1152 (other :tag "Default" nil))
1153 (choice :tag "Background Color"
1154 (string :tag "Name")
1155 (other :tag "Default" nil))
1156 (repeat :tag "Font Attributes" :inline t
1157 (choice (const bold) (const italic)
1158 (const underline) (const strikeout)
1159 (const overline) (const shadow)
1160 (const box) (const outline))))
1161 :group 'ebnf-special)
1162
1163
1164(defcustom ebnf-special-shape 'bevel
1165 "*Specify special box shape.
1166
1167See documentation for `ebnf-non-terminal-shape'."
1168 :type '(radio :tag "Special Shape"
1169 (const miter) (const round) (const bevel))
1170 :group 'ebnf-special)
1171
1172
1173(defcustom ebnf-special-shadow nil
1174 "*Non-nil means special box will have a shadow."
1175 :type 'boolean
1176 :group 'ebnf-special)
1177
1178
1179(defcustom ebnf-special-border-width 0.5
1180 "*Specify border width for special box."
1181 :type 'number
1182 :group 'ebnf-special)
1183
1184
1185(defcustom ebnf-special-border-color "Black"
1186 "*Specify border color for special box."
1187 :type 'string
1188 :group 'ebnf-special)
1189
1190
1191(defcustom ebnf-except-font '(7 Courier "Black" "Gray90" bold italic)
1192 "*Specify except font.
1193
1194See documentation for `ebnf-production-font'."
1195 :type '(list :tag "Except Font"
1196 (number :tag "Font Size")
1197 (symbol :tag "Font Name")
1198 (choice :tag "Foreground Color"
1199 (string :tag "Name")
1200 (other :tag "Default" nil))
1201 (choice :tag "Background Color"
1202 (string :tag "Name")
1203 (other :tag "Default" nil))
1204 (repeat :tag "Font Attributes" :inline t
1205 (choice (const bold) (const italic)
1206 (const underline) (const strikeout)
1207 (const overline) (const shadow)
1208 (const box) (const outline))))
1209 :group 'ebnf-except)
1210
1211
1212(defcustom ebnf-except-shape 'bevel
1213 "*Specify except box shape.
1214
1215See documentation for `ebnf-non-terminal-shape'."
1216 :type '(radio :tag "Except Shape"
1217 (const miter) (const round) (const bevel))
1218 :group 'ebnf-except)
1219
1220
1221(defcustom ebnf-except-shadow nil
1222 "*Non-nil means except box will have a shadow."
1223 :type 'boolean
1224 :group 'ebnf-except)
1225
1226
1227(defcustom ebnf-except-border-width 0.25
1228 "*Specify border width for except box."
1229 :type 'number
1230 :group 'ebnf-except)
1231
1232
1233(defcustom ebnf-except-border-color "Black"
1234 "*Specify border color for except box."
1235 :type 'string
1236 :group 'ebnf-except)
1237
1238
1239(defcustom ebnf-repeat-font '(7 Courier "Black" "Gray85" bold italic)
1240 "*Specify repeat font.
1241
1242See documentation for `ebnf-production-font'."
1243 :type '(list :tag "Repeat Font"
1244 (number :tag "Font Size")
1245 (symbol :tag "Font Name")
1246 (choice :tag "Foreground Color"
1247 (string :tag "Name")
1248 (other :tag "Default" nil))
1249 (choice :tag "Background Color"
1250 (string :tag "Name")
1251 (other :tag "Default" nil))
1252 (repeat :tag "Font Attributes" :inline t
1253 (choice (const bold) (const italic)
1254 (const underline) (const strikeout)
1255 (const overline) (const shadow)
1256 (const box) (const outline))))
1257 :group 'ebnf-repeat)
1258
1259
1260(defcustom ebnf-repeat-shape 'bevel
1261 "*Specify repeat box shape.
1262
1263See documentation for `ebnf-non-terminal-shape'."
1264 :type '(radio :tag "Repeat Shape"
1265 (const miter) (const round) (const bevel))
1266 :group 'ebnf-repeat)
1267
1268
1269(defcustom ebnf-repeat-shadow nil
1270 "*Non-nil means repeat box will have a shadow."
1271 :type 'boolean
1272 :group 'ebnf-repeat)
1273
1274
1275(defcustom ebnf-repeat-border-width 0.0
1276 "*Specify border width for repeat box."
1277 :type 'number
1278 :group 'ebnf-repeat)
1279
1280
1281(defcustom ebnf-repeat-border-color "Black"
1282 "*Specify border color for repeat box."
1283 :type 'string
1284 :group 'ebnf-repeat)
1285
1286
1287(defcustom ebnf-terminal-font '(7 Courier "Black" "White")
1288 "*Specify terminal font.
1289
1290See documentation for `ebnf-production-font'."
1291 :type '(list :tag "Terminal Font"
1292 (number :tag "Font Size")
1293 (symbol :tag "Font Name")
1294 (choice :tag "Foreground Color"
1295 (string :tag "Name")
1296 (other :tag "Default" nil))
1297 (choice :tag "Background Color"
1298 (string :tag "Name")
1299 (other :tag "Default" nil))
1300 (repeat :tag "Font Attributes" :inline t
1301 (choice (const bold) (const italic)
1302 (const underline) (const strikeout)
1303 (const overline) (const shadow)
1304 (const box) (const outline))))
1305 :group 'ebnf-terminal)
1306
1307
1308(defcustom ebnf-terminal-shape 'miter
1309 "*Specify terminal box shape.
1310
1311See documentation for `ebnf-non-terminal-shape'."
1312 :type '(radio :tag "Terminal Shape"
1313 (const miter) (const round) (const bevel))
1314 :group 'ebnf-terminal)
1315
1316
1317(defcustom ebnf-terminal-shadow nil
1318 "*Non-nil means terminal box will have a shadow."
1319 :type 'boolean
1320 :group 'ebnf-terminal)
1321
1322
1323(defcustom ebnf-terminal-border-width 1.0
1324 "*Specify border width for terminal box."
1325 :type 'number
1326 :group 'ebnf-terminal)
1327
1328
1329(defcustom ebnf-terminal-border-color "Black"
1330 "*Specify border color for terminal box."
1331 :type 'string
1332 :group 'ebnf-terminal)
1333
1334
1335(defcustom ebnf-sort-production nil
1336 "*Specify how productions are sorted.
1337
1338Valid values are:
1339
1340 nil don't sort productions.
1341 `ascending' ascending sort.
1342 any other value descending sort."
1343 :type '(radio :tag "Production Sort"
1344 (const :tag "Ascending" ascending)
1345 (const :tag "Descending" descending)
1346 (other :tag "No Sort" nil))
1347 :group 'ebnf-production)
1348
1349
1350(defcustom ebnf-production-font '(10 Helvetica "Black" "White" bold)
1351 "*Specify production header font.
1352
1353It is a list with the following form:
1354
1355 (SIZE NAME FOREGROUND BACKGROUND ATTRIBUTE...)
1356
1357Where:
1358SIZE is the font size.
1359NAME is the font name symbol.
1360ATTRIBUTE is one of the following symbols:
1361 bold - use bold font.
1362 italic - use italic font.
1363 underline - put a line under text.
1364 strikeout - like underline, but the line is in middle of text.
1365 overline - like underline, but the line is over the text.
1366 shadow - text will have a shadow.
1367 box - text will be surrounded by a box.
1368 outline - print characters as hollow outlines.
1369FOREGROUND is a foreground string color name; if it's nil, the default color is
1370\"Black\".
1371BACKGROUND is a background string color name; if it's nil, the default color is
1372\"White\".
1373
1374See `ps-font-info-database' for valid font name."
1375 :type '(list :tag "Production Font"
1376 (number :tag "Font Size")
1377 (symbol :tag "Font Name")
1378 (choice :tag "Foreground Color"
1379 (string :tag "Name")
1380 (other :tag "Default" nil))
1381 (choice :tag "Background Color"
1382 (string :tag "Name")
1383 (other :tag "Default" nil))
1384 (repeat :tag "Font Attributes" :inline t
1385 (choice (const bold) (const italic)
1386 (const underline) (const strikeout)
1387 (const overline) (const shadow)
1388 (const box) (const outline))))
1389 :group 'ebnf-production)
1390
1391
1392(defcustom ebnf-non-terminal-font '(7 Helvetica "Black" "White")
1393 "*Specify non-terminal font.
1394
1395See documentation for `ebnf-production-font'."
1396 :type '(list :tag "Non-Terminal Font"
1397 (number :tag "Font Size")
1398 (symbol :tag "Font Name")
1399 (choice :tag "Foreground Color"
1400 (string :tag "Name")
1401 (other :tag "Default" nil))
1402 (choice :tag "Background Color"
1403 (string :tag "Name")
1404 (other :tag "Default" nil))
1405 (repeat :tag "Font Attributes" :inline t
1406 (choice (const bold) (const italic)
1407 (const underline) (const strikeout)
1408 (const overline) (const shadow)
1409 (const box) (const outline))))
1410 :group 'ebnf-non-terminal)
1411
1412
1413(defcustom ebnf-non-terminal-shape 'round
1414 "*Specify non-terminal box shape.
1415
1416Valid values are:
1417
1418 `miter' +-------+
1419 | |
1420 +-------+
1421
1422 `round' -------
1423 ( )
1424 -------
1425
1426 `bevel' /-------\\
1427 | |
1428 \\-------/
1429
1430Any other value is treated as `miter'."
1431 :type '(radio :tag "Non-Terminal Shape"
1432 (const miter) (const round) (const bevel))
1433 :group 'ebnf-non-terminal)
1434
1435
1436(defcustom ebnf-non-terminal-shadow nil
1437 "*Non-nil means non-terminal box will have a shadow."
1438 :type 'boolean
1439 :group 'ebnf-non-terminal)
1440
1441
1442(defcustom ebnf-non-terminal-border-width 1.0
1443 "*Specify border width for non-terminal box."
1444 :type 'number
1445 :group 'ebnf-non-terminal)
1446
1447
1448(defcustom ebnf-non-terminal-border-color "Black"
1449 "*Specify border color for non-terminal box."
1450 :type 'string
1451 :group 'ebnf-non-terminal)
1452
1453
1454(defcustom ebnf-arrow-shape 'hollow
1455 "*Specify the arrow shape.
1456
1457Valid values are:
1458
1459 `none' ======
1460
1461 `semi-up' * `transparent' *
1462 * |*
1463 =====* | *
1464 ==+==*
1465 | *
1466 |*
1467 *
1468
1469 `semi-down' =====* `hollow' *
1470 * |*
1471 * | *
1472 ==+ *
1473 | *
1474 |*
1475 *
1476
1477 `simple' * `full' *
1478 * |*
1479 =====* |X*
1480 * ==+XX*
1481 * |X*
1482 |*
1483 *
1484
1485 `user' See also documentation for variable `ebnf-user-arrow'.
1486
1487Any other value is treated as `none'."
1488 :type '(radio :tag "Arrow Shape"
1489 (const none) (const semi-up)
1490 (const semi-down) (const simple)
1491 (const transparent) (const hollow)
1492 (const full) (const user))
1493 :group 'ebnf-shape)
1494
1495
1496(defcustom ebnf-chart-shape 'round
1497 "*Specify chart flow shape.
1498
1499See documentation for `ebnf-non-terminal-shape'."
1500 :type '(radio :tag "Chart Flow Shape"
1501 (const miter) (const round) (const bevel))
1502 :group 'ebnf-shape)
1503
1504
1505(defcustom ebnf-user-arrow nil
bf061ba6 1506 "*Specify a sexp for user arrow shape (a PostScript code).
984ae001 1507
bf061ba6
GM
1508When evaluated, the sexp should return nil or a string containing PostScript
1509code. PostScript code should draw a right arrow.
984ae001
GM
1510
1511The anatomy of a right arrow is:
1512
1513 ...... Initial position
1514 :
1515 : *.................
1516 : | * } }
1517 : | * } hT4 }
1518 v | * } }
1519 ======+======*... } hT2
1520 : | *: } }
1521 : | * : } hT4 }
1522 : | * : } }
1523 : *.................
1524 : : :
1525 : : :..........
1526 : : } hT2 }
1527 : :.......... } hT
1528 : } hT2 }
1529 :.......................
1530
b685181e
GM
1531Where `hT', `hT2' and `hT4' are predefined PostScript variable names that can
1532be used to generate your own arrow. As these variables are used along
1533PostScript execution, *DON'T* modify the values of them. Instead, copy the
1534values, if you need to modify them.
984ae001
GM
1535
1536The relation between these variables is: hT = 2 * hT2 = 4 * hT4.
1537
1538The variable `ebnf-user-arrow' is only used when `ebnf-arrow-shape' is set to
bf061ba6
GM
1539symbol `user'."
1540 :type '(sexp :tag "User Arrow Shape")
984ae001
GM
1541 :group 'ebnf-shape)
1542
1543
1544(defcustom ebnf-syntax 'ebnf
1545 "*Specify syntax to be recognized.
1546
1547Valid values are:
1548
887448e1
GM
1549 `ebnf' ebnf2ps recognizes the syntax described in ebnf2ps
1550 documentation.
984ae001
GM
1551 The following variables *ONLY* have effect with this
1552 setting:
1553 `ebnf-terminal-regexp', `ebnf-case-fold-search',
1554 `ebnf-lex-comment-char' and `ebnf-lex-eop-char'.
1555
1556 `iso-ebnf' ebnf2ps recognizes the syntax described in the URL:
1557 `http://www.cl.cam.ac.uk/~mgk25/iso-ebnf.html'
1558 (\"International Standard of the ISO EBNF Notation\").
1559 The following variables *ONLY* have effect with this
1560 setting:
1561 `ebnf-iso-alternative-p' and `ebnf-iso-normalize-p'.
1562
1563 `yacc' ebnf2ps recognizes the Yacc/Bison syntax.
1564 The following variable *ONLY* has effect with this
1565 setting:
1566 `ebnf-yac-ignore-error-recovery'.
1567
1568Any other value is treated as `ebnf'."
1569 :type '(radio :tag "Syntax"
1570 (const ebnf) (const iso-ebnf) (const yacc))
ab3256ed 1571 :group 'ebnf-syntactic)
984ae001
GM
1572
1573
1574(defcustom ebnf-lex-comment-char ?\;
1575 "*Specify the line comment character.
1576
1577It's used only when `ebnf-syntax' is `ebnf'."
1578 :type 'character
ab3256ed 1579 :group 'ebnf-syntactic)
984ae001
GM
1580
1581
1582(defcustom ebnf-lex-eop-char ?.
1583 "*Specify the end of production character.
1584
1585It's used only when `ebnf-syntax' is `ebnf'."
1586 :type 'character
ab3256ed 1587 :group 'ebnf-syntactic)
984ae001
GM
1588
1589
1590(defcustom ebnf-terminal-regexp nil
1591 "*Specify how it's a terminal name.
1592
1593If it's nil, the terminal name must be enclosed by `\"'.
1594If it's a string, it should be a regexp that it'll be used to determine a
1595terminal name; terminal name may also be enclosed by `\"'.
1596
1597It's used only when `ebnf-syntax' is `ebnf'."
1598 :type '(radio :tag "Terminal Name"
1599 (const nil) regexp)
ab3256ed 1600 :group 'ebnf-syntactic)
984ae001
GM
1601
1602
1603(defcustom ebnf-case-fold-search nil
1604 "*Non-nil means ignore case on matching.
1605
1606It's only used when `ebnf-terminal-regexp' is non-nil and when `ebnf-syntax' is
1607`ebnf'."
1608 :type 'boolean
ab3256ed 1609 :group 'ebnf-syntactic)
984ae001
GM
1610
1611
1612(defcustom ebnf-iso-alternative-p nil
1613 "*Non-nil means use alternative ISO EBNF.
1614
1615It's only used when `ebnf-syntax' is `iso-ebnf'.
1616
1617This variable affects the following symbol set:
1618
1619 STANDARD ALTERNATIVE
1620 | ==> / or !
1621 [ ==> (/
1622 ] ==> /)
1623 { ==> (:
1624 } ==> :)
1625 ; ==> ."
1626 :type 'boolean
ab3256ed 1627 :group 'ebnf-syntactic)
984ae001
GM
1628
1629
1630(defcustom ebnf-iso-normalize-p nil
1631 "*Non-nil means normalize ISO EBNF syntax names.
1632
1633Normalize a name means that several contiguous spaces inside name become a
1634single space, so \"A B C\" is normalized to \"A B C\".
1635
1636It's only used when `ebnf-syntax' is `iso-ebnf'."
1637 :type 'boolean
ab3256ed 1638 :group 'ebnf-syntactic)
984ae001
GM
1639
1640
1641(defcustom ebnf-eps-prefix "ebnf--"
1642 "*Specify EPS prefix file name.
1643
1644See `ebnf-eps-buffer' and `ebnf-eps-region' commands."
1645 :type 'string
1646 :group 'ebnf2ps)
1647
1648
1649(defcustom ebnf-entry-percentage 0.5 ; middle
1650 "*Specify entry height on alternatives.
1651
1652It must be a float between 0.0 (top) and 1.0 (bottom)."
1653 :type 'number
1654 :group 'ebnf2ps)
1655
1656
1657(defcustom ebnf-default-width 0.6
1658 "*Specify additional border width over default terminal, non-terminal or
1659special."
1660 :type 'number
1661 :group 'ebnf2ps)
1662
1663
1664;; Printing color requires x-color-values.
1665(defcustom ebnf-color-p (or (fboundp 'x-color-values) ; Emacs
1666 (fboundp 'color-instance-rgb-components)) ; XEmacs
1667 "*Non-nil means use color."
1668 :type 'boolean
1669 :group 'ebnf2ps)
1670
1671
1672(defcustom ebnf-line-width 1.0
1673 "*Specify flow line width."
1674 :type 'number
1675 :group 'ebnf2ps)
1676
1677
1678(defcustom ebnf-line-color "Black"
1679 "*Specify flow line color."
1680 :type 'string
1681 :group 'ebnf2ps)
1682
1683
1684(defcustom ebnf-debug-ps nil
1685 "*Non-nil means to generate PostScript debug procedures.
1686
1687It is intended to help PostScript programmers in debugging."
1688 :type 'boolean
1689 :group 'ebnf2ps)
1690
1691
1692(defcustom ebnf-use-float-format t
1693 "*Non-nil means use `%f' float format.
1694
1695The advantage of using float format is that ebnf2ps generates a little short
1696PostScript file.
1697
1698If it occurs the error message:
1699
1700 Invalid format operation %f
1701
1702when executing ebnf2ps, set `ebnf-use-float-format' to nil."
1703 :type 'boolean
1704 :group 'ebnf2ps)
1705
1706
1707(defcustom ebnf-yac-ignore-error-recovery nil
1708 "*Non-nil means ignore error recovery.
1709
1710It's only used when `ebnf-syntax' is `yacc'."
1711 :type 'boolean
ab3256ed 1712 :group 'ebnf-syntactic)
984ae001
GM
1713
1714
1715(defcustom ebnf-ignore-empty-rule nil
1716 "*Non-nil means ignore empty rules.
1717
1718It's interesting to set this variable if your Yacc/Bison grammar has a lot of
1719middle action rule."
1720 :type 'boolean
1721 :group 'ebnf-optimization)
1722
1723
1724(defcustom ebnf-optimize nil
ab3256ed 1725 "*Non-nil means optimize syntactic chart of rules.
984ae001
GM
1726
1727The following optimizations are done:
1728
1729 left recursion:
1730 1. A = B | A C. ==> A = B {C}*.
1731 2. A = B | A B. ==> A = {B}+.
1732 3. A = | A B. ==> A = {B}*.
1733 4. A = B | A C B. ==> A = {B || C}+.
1734 5. A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
1735
1736 optional:
1737 6. A = B | . ==> A = [B].
1738 7. A = | B . ==> A = [B].
1739
1740 factoration:
1741 8. A = B C | B D. ==> A = B (C | D).
1742 9. A = C B | D B. ==> A = (C | D) B.
1743 10. A = B C E | B D E. ==> A = B (C | D) E.
1744
1745The above optimizations are specially useful when `ebnf-syntax' is `yacc'."
1746 :type 'boolean
1747 :group 'ebnf-optimization)
1748
1749\f
1750;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1751;; Customization
1752
1753
1754;;;###autoload
1755(defun ebnf-customize ()
1756 "Customization for ebnf group."
1757 (interactive)
1758 (customize-group 'ebnf2ps))
1759
1760\f
1761;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1762;; User commands
1763
1764
1765;;;###autoload
1766(defun ebnf-print-buffer (&optional filename)
ab3256ed 1767 "Generate and print a PostScript syntactic chart image of the buffer.
984ae001
GM
1768
1769When called with a numeric prefix argument (C-u), prompts the user for
1770the name of a file to save the PostScript image in, instead of sending
1771it to the printer.
1772
1773More specifically, the FILENAME argument is treated as follows: if it
1774is nil, send the image to the printer. If FILENAME is a string, save
1775the PostScript image in a file with that name. If FILENAME is a
1776number, prompt the user for the name of the file to save in."
1777 (interactive (list (ps-print-preprint current-prefix-arg)))
1778 (ebnf-print-region (point-min) (point-max) filename))
1779
1780
1781;;;###autoload
1782(defun ebnf-print-region (from to &optional filename)
ab3256ed 1783 "Generate and print a PostScript syntactic chart image of the region.
984ae001
GM
1784Like `ebnf-print-buffer', but prints just the current region."
1785 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
1786 (run-hooks 'ebnf-hook)
1787 (or (ebnf-spool-region from to)
1788 (ps-do-despool filename)))
1789
1790
1791;;;###autoload
1792(defun ebnf-spool-buffer ()
ab3256ed 1793 "Generate and spool a PostScript syntactic chart image of the buffer.
984ae001
GM
1794Like `ebnf-print-buffer' except that the PostScript image is saved in a
1795local buffer to be sent to the printer later.
1796
1797Use the command `ebnf-despool' to send the spooled images to the printer."
1798 (interactive)
1799 (ebnf-spool-region (point-min) (point-max)))
1800
1801
1802;;;###autoload
1803(defun ebnf-spool-region (from to)
ab3256ed 1804 "Generate a PostScript syntactic chart image of the region and spool locally.
984ae001
GM
1805Like `ebnf-spool-buffer', but spools just the current region.
1806
1807Use the command `ebnf-despool' to send the spooled images to the printer."
1808 (interactive "r")
1809 (ebnf-generate-region from to 'ebnf-generate))
1810
1811
1812;;;###autoload
1813(defun ebnf-eps-buffer ()
ab3256ed 1814 "Generate a PostScript syntactic chart image of the buffer in a EPS file.
984ae001
GM
1815
1816Indeed, for each production is generated a EPS file.
1817The EPS file name has the following form:
1818
1819 <PREFIX><PRODUCTION>.eps
1820
1821<PREFIX> is given by variable `ebnf-eps-prefix'.
1822 The default value is \"ebnf--\".
1823
1824<PRODUCTION> is the production name.
1825 The production name is mapped to form a valid file name.
1826 For example, the production name \"A/B + C\" is mapped to
1827 \"A_B_+_C\" and the EPS file name used is \"ebnf--A_B_+_C.eps\".
1828
1829WARNING: It's *NOT* asked any confirmation to override an existing file."
1830 (interactive)
1831 (ebnf-eps-region (point-min) (point-max)))
1832
1833
1834;;;###autoload
1835(defun ebnf-eps-region (from to)
ab3256ed 1836 "Generate a PostScript syntactic chart image of the region in a EPS file.
984ae001
GM
1837
1838Indeed, for each production is generated a EPS file.
1839The EPS file name has the following form:
1840
1841 <PREFIX><PRODUCTION>.eps
1842
1843<PREFIX> is given by variable `ebnf-eps-prefix'.
1844 The default value is \"ebnf--\".
1845
1846<PRODUCTION> is the production name.
1847 The production name is mapped to form a valid file name.
1848 For example, the production name \"A/B + C\" is mapped to
1849 \"A_B_+_C\" and the EPS file name used is \"ebnf--A_B_+_C.eps\".
1850
1851WARNING: It's *NOT* asked any confirmation to override an existing file."
1852 (interactive "r")
1853 (let ((ebnf-eps-executing t))
1854 (ebnf-generate-region from to 'ebnf-generate-eps)))
1855
1856
1857;;;###autoload
1858(defalias 'ebnf-despool 'ps-despool)
1859
1860
1861;;;###autoload
1862(defun ebnf-syntax-buffer ()
ab3256ed 1863 "Does a syntactic analysis of the current buffer."
984ae001
GM
1864 (interactive)
1865 (ebnf-syntax-region (point-min) (point-max)))
1866
1867
1868;;;###autoload
1869(defun ebnf-syntax-region (from to)
ab3256ed 1870 "Does a syntactic analysis of a region."
984ae001
GM
1871 (interactive "r")
1872 (ebnf-generate-region from to nil))
1873
1874\f
1875;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1876;; Utilities
1877
1878
1879;;;###autoload
1880(defun ebnf-setup ()
1881 "Return the current ebnf2ps setup."
1882 (format
1883 "
6a5275dc
GM
1884;;; ebnf2ps.el version %s
1885
984ae001
GM
1886\(setq ebnf-special-font %s
1887 ebnf-special-shape %s
1888 ebnf-special-shadow %S
1889 ebnf-special-border-width %S
1890 ebnf-special-border-color %S
1891 ebnf-except-font %s
1892 ebnf-except-shape %s
1893 ebnf-except-shadow %S
1894 ebnf-except-border-width %S
1895 ebnf-except-border-color %S
1896 ebnf-repeat-font %s
1897 ebnf-repeat-shape %s
1898 ebnf-repeat-shadow %S
1899 ebnf-repeat-border-width %S
1900 ebnf-repeat-border-color %S
1901 ebnf-terminal-regexp %S
1902 ebnf-case-fold-search %S
1903 ebnf-terminal-font %s
1904 ebnf-terminal-shape %s
1905 ebnf-terminal-shadow %S
1906 ebnf-terminal-border-width %S
1907 ebnf-terminal-border-color %S
1908 ebnf-non-terminal-font %s
1909 ebnf-non-terminal-shape %s
1910 ebnf-non-terminal-shadow %S
1911 ebnf-non-terminal-border-width %S
1912 ebnf-non-terminal-border-color %S
1913 ebnf-sort-production %s
1914 ebnf-production-font %s
1915 ebnf-arrow-shape %s
1916 ebnf-chart-shape %s
1917 ebnf-user-arrow %s
1918 ebnf-horizontal-orientation %S
1919 ebnf-horizontal-max-height %S
1920 ebnf-production-horizontal-space %S
1921 ebnf-production-vertical-space %S
1922 ebnf-justify-sequence %s
1923 ebnf-lex-comment-char ?\\%03o
1924 ebnf-lex-eop-char ?\\%03o
1925 ebnf-syntax %s
1926 ebnf-iso-alternative-p %S
1927 ebnf-iso-normalize-p %S
1928 ebnf-eps-prefix %S
1929 ebnf-entry-percentage %S
1930 ebnf-color-p %S
1931 ebnf-line-width %S
1932 ebnf-line-color %S
1933 ebnf-debug-ps %S
1934 ebnf-use-float-format %S
1935 ebnf-yac-ignore-error-recovery %S
1936 ebnf-ignore-empty-rule %S
1937 ebnf-optimize %S)
6a5275dc
GM
1938
1939;;; ebnf2ps.el - end of settings
984ae001 1940"
6a5275dc 1941 ebnf-version
984ae001
GM
1942 (ps-print-quote ebnf-special-font)
1943 (ps-print-quote ebnf-special-shape)
1944 ebnf-special-shadow
1945 ebnf-special-border-width
1946 ebnf-special-border-color
1947 (ps-print-quote ebnf-except-font)
1948 (ps-print-quote ebnf-except-shape)
1949 ebnf-except-shadow
1950 ebnf-except-border-width
1951 ebnf-except-border-color
1952 (ps-print-quote ebnf-repeat-font)
1953 (ps-print-quote ebnf-repeat-shape)
1954 ebnf-repeat-shadow
1955 ebnf-repeat-border-width
1956 ebnf-repeat-border-color
1957 ebnf-terminal-regexp
1958 ebnf-case-fold-search
1959 (ps-print-quote ebnf-terminal-font)
1960 (ps-print-quote ebnf-terminal-shape)
1961 ebnf-terminal-shadow
1962 ebnf-terminal-border-width
1963 ebnf-terminal-border-color
1964 (ps-print-quote ebnf-non-terminal-font)
1965 (ps-print-quote ebnf-non-terminal-shape)
1966 ebnf-non-terminal-shadow
1967 ebnf-non-terminal-border-width
1968 ebnf-non-terminal-border-color
1969 (ps-print-quote ebnf-sort-production)
1970 (ps-print-quote ebnf-production-font)
1971 (ps-print-quote ebnf-arrow-shape)
1972 (ps-print-quote ebnf-chart-shape)
1973 (ps-print-quote ebnf-user-arrow)
1974 ebnf-horizontal-orientation
1975 ebnf-horizontal-max-height
1976 ebnf-production-horizontal-space
1977 ebnf-production-vertical-space
1978 (ps-print-quote ebnf-justify-sequence)
1979 ebnf-lex-comment-char
1980 ebnf-lex-eop-char
1981 (ps-print-quote ebnf-syntax)
1982 ebnf-iso-alternative-p
1983 ebnf-iso-normalize-p
1984 ebnf-eps-prefix
1985 ebnf-entry-percentage
1986 ebnf-color-p
1987 ebnf-line-width
1988 ebnf-line-color
1989 ebnf-debug-ps
1990 ebnf-use-float-format
1991 ebnf-yac-ignore-error-recovery
1992 ebnf-ignore-empty-rule
1993 ebnf-optimize))
1994
1995\f
1996;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1997;; Style variables
1998
1999
2000(defvar ebnf-stack-style nil
2001 "Used in functions `ebnf-reset-style', `ebnf-push-style' and
2002`ebnf-pop-style'.")
2003
2004
2005(defvar ebnf-current-style 'default
2006 "Used in functions `ebnf-apply-style' and `ebnf-push-style'.")
2007
2008
2009(defconst ebnf-style-custom-list
2010 '(ebnf-special-font
2011 ebnf-special-shape
2012 ebnf-special-shadow
2013 ebnf-special-border-width
2014 ebnf-special-border-color
2015 ebnf-except-font
2016 ebnf-except-shape
2017 ebnf-except-shadow
2018 ebnf-except-border-width
2019 ebnf-except-border-color
2020 ebnf-repeat-font
2021 ebnf-repeat-shape
2022 ebnf-repeat-shadow
2023 ebnf-repeat-border-width
2024 ebnf-repeat-border-color
2025 ebnf-terminal-regexp
2026 ebnf-case-fold-search
2027 ebnf-terminal-font
2028 ebnf-terminal-shape
2029 ebnf-terminal-shadow
2030 ebnf-terminal-border-width
2031 ebnf-terminal-border-color
2032 ebnf-non-terminal-font
2033 ebnf-non-terminal-shape
2034 ebnf-non-terminal-shadow
2035 ebnf-non-terminal-border-width
2036 ebnf-non-terminal-border-color
2037 ebnf-sort-production
2038 ebnf-production-font
2039 ebnf-arrow-shape
2040 ebnf-chart-shape
2041 ebnf-user-arrow
2042 ebnf-horizontal-orientation
2043 ebnf-horizontal-max-height
2044 ebnf-production-horizontal-space
2045 ebnf-production-vertical-space
2046 ebnf-justify-sequence
2047 ebnf-lex-comment-char
2048 ebnf-lex-eop-char
2049 ebnf-syntax
2050 ebnf-iso-alternative-p
2051 ebnf-iso-normalize-p
2052 ebnf-eps-prefix
2053 ebnf-entry-percentage
2054 ebnf-color-p
2055 ebnf-line-width
2056 ebnf-line-color
2057 ebnf-debug-ps
2058 ebnf-use-float-format
2059 ebnf-yac-ignore-error-recovery
2060 ebnf-ignore-empty-rule
2061 ebnf-optimize)
2062 "List of valid symbol custom variable.")
2063
2064
2065(defvar ebnf-style-database
2066 '(;; EBNF default
2067 (default
2068 nil
2069 (ebnf-special-font . '(7 Courier "Black" "Gray95" bold italic))
2070 (ebnf-special-shape . 'bevel)
2071 (ebnf-special-shadow . nil)
2072 (ebnf-special-border-width . 0.5)
2073 (ebnf-special-border-color . "Black")
2074 (ebnf-except-font . '(7 Courier "Black" "Gray90" bold italic))
2075 (ebnf-except-shape . 'bevel)
2076 (ebnf-except-shadow . nil)
2077 (ebnf-except-border-width . 0.25)
2078 (ebnf-except-border-color . "Black")
2079 (ebnf-repeat-font . '(7 Courier "Black" "Gray85" bold italic))
2080 (ebnf-repeat-shape . 'bevel)
2081 (ebnf-repeat-shadow . nil)
2082 (ebnf-repeat-border-width . 0.0)
2083 (ebnf-repeat-border-color . "Black")
2084 (ebnf-terminal-regexp . nil)
2085 (ebnf-case-fold-search . nil)
2086 (ebnf-terminal-font . '(7 Courier "Black" "White"))
2087 (ebnf-terminal-shape . 'miter)
2088 (ebnf-terminal-shadow . nil)
2089 (ebnf-terminal-border-width . 1.0)
2090 (ebnf-terminal-border-color . "Black")
2091 (ebnf-non-terminal-font . '(7 Helvetica "Black" "White"))
2092 (ebnf-non-terminal-shape . 'round)
2093 (ebnf-non-terminal-shadow . nil)
2094 (ebnf-non-terminal-border-width . 1.0)
2095 (ebnf-non-terminal-border-color . "Black")
2096 (ebnf-sort-production . nil)
2097 (ebnf-production-font . '(10 Helvetica "Black" "White" bold))
2098 (ebnf-arrow-shape . 'hollow)
2099 (ebnf-chart-shape . 'round)
2100 (ebnf-user-arrow . nil)
2101 (ebnf-horizontal-orientation . nil)
2102 (ebnf-horizontal-max-height . nil)
2103 (ebnf-production-horizontal-space . 0.0)
2104 (ebnf-production-vertical-space . 0.0)
2105 (ebnf-justify-sequence . 'center)
2106 (ebnf-lex-comment-char . ?\;)
2107 (ebnf-lex-eop-char . ?.)
2108 (ebnf-syntax . 'ebnf)
2109 (ebnf-iso-alternative-p . nil)
2110 (ebnf-iso-normalize-p . nil)
2111 (ebnf-eps-prefix . "ebnf--")
2112 (ebnf-entry-percentage . 0.5)
2113 (ebnf-color-p . (or (fboundp 'x-color-values) ; Emacs
2114 (fboundp 'color-instance-rgb-components))) ; XEmacs
2115 (ebnf-line-width . 1.0)
2116 (ebnf-line-color . "Black")
2117 (ebnf-debug-ps . nil)
2118 (ebnf-use-float-format . t)
2119 (ebnf-yac-ignore-error-recovery . nil)
2120 (ebnf-ignore-empty-rule . nil)
2121 (ebnf-optimize . nil))
2122 ;; Happy EBNF default
2123 (happy
2124 default
2125 (ebnf-justify-sequence . 'left)
2126 (ebnf-lex-comment-char . ?\#)
2127 (ebnf-lex-eop-char . ?\;))
2128 ;; ISO EBNF default
2129 (iso-ebnf
2130 default
2131 (ebnf-syntax . 'iso-ebnf))
2132 ;; Yacc/Bison default
2133 (yacc
2134 default
2135 (ebnf-syntax . 'yacc))
2136 )
2137 "Style database.
2138
2139Each element has the following form:
2140
2141 (CUSTOM INHERITS (VAR . VALUE)...)
2142
2143CUSTOM is a symbol name style.
2144INHERITS is a symbol name style from which the current style inherits the
2145context. If INHERITS is nil, means that there is no inheritance.
b685181e
GM
2146VAR is a valid ebnf2ps symbol custom variable. See `ebnf-style-custom-list'
2147for valid symbol variable.
984ae001
GM
2148VALUE is a sexp which it'll be evaluated to set the value to VAR. So, don't
2149forget to quote symbols and constant lists. See `default' style for an
2150example.
2151
2152Don't handle this variable directly. Use functions `ebnf-insert-style' and
2153`ebnf-merge-style'.")
2154
2155\f
2156;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2157;; Style commands
2158
2159
2160;;;###autoload
2161(defun ebnf-insert-style (name inherits &rest values)
2162 "Insert a new style NAME with inheritance INHERITS and values VALUES."
2163 (interactive)
2164 (and (assoc name ebnf-style-database)
2165 (error "Style name already exists: %s" name))
2166 (or (assoc inherits ebnf-style-database)
2167 (error "Style inheritance name does'nt exist: %s" inherits))
2168 (setq ebnf-style-database
2169 (cons (cons name (cons inherits (ebnf-check-style-values values)))
2170 ebnf-style-database)))
2171
2172
2173;;;###autoload
2174(defun ebnf-merge-style (name &rest values)
2175 "Merge values of style NAME with style VALUES."
2176 (interactive)
2177 (let ((style (or (assoc name ebnf-style-database)
2178 (error "Style name does'nt exist: %s" name)))
2179 (merge (ebnf-check-style-values values))
2180 val elt new check)
2181 ;; modify value of existing variables
2182 (setq val (nthcdr 2 style))
2183 (while merge
2184 (setq check (car merge)
2185 merge (cdr merge)
2186 elt (assoc (car check) val))
2187 (if elt
2188 (setcdr elt (cdr check))
2189 (setq new (cons check new))))
2190 ;; insert new variables
2191 (nconc style (nreverse new))))
2192
2193
2194;;;###autoload
2195(defun ebnf-apply-style (style)
2196 "Set STYLE to current style.
2197
2198It returns the old style symbol."
2199 (interactive)
2200 (prog1
2201 ebnf-current-style
2202 (and (ebnf-apply-style1 style)
2203 (setq ebnf-current-style style))))
2204
2205
2206;;;###autoload
2207(defun ebnf-reset-style (&optional style)
2208 "Reset current style.
2209
2210It returns the old style symbol."
2211 (interactive)
2212 (setq ebnf-stack-style nil)
2213 (ebnf-apply-style (or style 'default)))
2214
2215
2216;;;###autoload
2217(defun ebnf-push-style (&optional style)
2218 "Push the current style and set STYLE to current style.
2219
2220It returns the old style symbol."
2221 (interactive)
2222 (prog1
2223 ebnf-current-style
2224 (setq ebnf-stack-style (cons ebnf-current-style ebnf-stack-style))
2225 (and style
2226 (ebnf-apply-style style))))
2227
2228
2229;;;###autoload
2230(defun ebnf-pop-style ()
2231 "Pop a style and set it to current style.
2232
2233It returns the old style symbol."
2234 (interactive)
2235 (prog1
2236 (ebnf-apply-style (car ebnf-stack-style))
2237 (setq ebnf-stack-style (cdr ebnf-stack-style))))
2238
2239
2240(defun ebnf-apply-style1 (style)
2241 (let ((value (cdr (assoc style ebnf-style-database))))
2242 (prog1
2243 value
2244 (and (car value) (ebnf-apply-style1 (car value)))
2245 (while (setq value (cdr value))
2246 (set (caar value) (eval (cdar value)))))))
2247
2248
2249(defun ebnf-check-style-values (values)
2250 (let (style)
2251 (while values
2252 (and (memq (car values) ebnf-style-custom-list)
2253 (setq style (cons (car values) style)))
2254 (setq values (cdr values)))
2255 (nreverse style)))
2256
2257\f
2258;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2259;; Internal variables
2260
2261
984ae001
GM
2262(defvar ebnf-eps-buffer-name " *EPS*")
2263(defvar ebnf-parser-func nil)
2264(defvar ebnf-eps-executing nil)
2265(defvar ebnf-eps-upper-x 0.0)
2266(make-variable-buffer-local 'ebnf-eps-upper-x)
2267(defvar ebnf-eps-upper-y 0.0)
2268(make-variable-buffer-local 'ebnf-eps-upper-y)
2269(defvar ebnf-eps-prod-width 0.0)
2270(make-variable-buffer-local 'ebnf-eps-prod-width)
2271(defvar ebnf-eps-max-height 0.0)
2272(make-variable-buffer-local 'ebnf-eps-max-height)
2273(defvar ebnf-eps-max-width 0.0)
2274(make-variable-buffer-local 'ebnf-eps-max-width)
2275
2276
2277(defvar ebnf-eps-context nil
2278 "List of EPS file name during parsing.
2279
2280See section \"Actions in Comments\" in ebnf2ps documentation.")
2281
2282
2283(defvar ebnf-eps-production-list nil
2284 "Alist associating production name with EPS file name list.
2285
2286Each element has the following form:
2287
2288 (PRODUCTION EPS-FILENAME...)
2289
2290PRODUCTION is the production name.
2291EPS-FILENAME is the EPS file name.
2292
2293It's generated during parsing and used during EPS generation.
2294
2295See `ebnf-eps-context' and section \"Actions in Comments\" in ebnf2ps
2296documentation.")
2297
2298
2299(defconst ebnf-arrow-shape-alist
2300 '((none . 0)
2301 (semi-up . 1)
2302 (semi-down . 2)
2303 (simple . 3)
2304 (transparent . 4)
2305 (hollow . 5)
2306 (full . 6)
2307 (user . 7))
2308 "Alist associating values for `ebnf-arrow-shape'.
2309
2310See documentation for `ebnf-arrow-shape'.")
2311
2312
2313(defconst ebnf-terminal-shape-alist
2314 '((miter . 0)
2315 (round . 1)
2316 (bevel . 2))
2317 "Alist associating values from `ebnf-terminal-shape' to a bit vector.
2318
2319See documentation for `ebnf-terminal-shape', `ebnf-non-terminal-shape' and
2320`ebnf-chart-shape'.")
2321
2322
2323(defvar ebnf-limit nil)
2324(defvar ebnf-action nil)
2325(defvar ebnf-action-list nil)
2326
2327
2328(defvar ebnf-default-p nil)
2329
2330
2331(defvar ebnf-font-height-P 0)
2332(defvar ebnf-font-height-T 0)
2333(defvar ebnf-font-height-NT 0)
2334(defvar ebnf-font-height-S 0)
2335(defvar ebnf-font-height-E 0)
2336(defvar ebnf-font-height-R 0)
2337(defvar ebnf-font-width-P 0)
2338(defvar ebnf-font-width-T 0)
2339(defvar ebnf-font-width-NT 0)
2340(defvar ebnf-font-width-S 0)
2341(defvar ebnf-font-width-E 0)
2342(defvar ebnf-font-width-R 0)
2343(defvar ebnf-space-T 0)
2344(defvar ebnf-space-NT 0)
2345(defvar ebnf-space-S 0)
2346(defvar ebnf-space-E 0)
2347(defvar ebnf-space-R 0)
2348
2349
2350(defvar ebnf-basic-width 0)
2351(defvar ebnf-basic-height 0)
2352(defvar ebnf-vertical-space 0)
2353(defvar ebnf-horizontal-space 0)
2354
2355
2356(defvar ebnf-settings nil)
2357(defvar ebnf-fonts-required nil)
2358
2359
2360(defconst ebnf-debug
2361 "
2362% === begin EBNF procedures to help debugging
2363
2364% Mark visually current point: string debug
2365/debug
2366{/-s- exch def
2367 currentpoint
2368 gsave -s- show grestore
2369 gsave
2370 20 20 rlineto
2371 0 -40 rlineto
2372 -40 40 rlineto
2373 0 -40 rlineto
2374 20 20 rlineto
2375 stroke
2376 grestore
2377 moveto
2378}def
2379
2380% Show number value: number string debug-number
2381/debug-number
2382{gsave
2383 20 0 rmoveto show ([) show 60 string cvs show (]) show
2384 grestore
2385}def
2386
2387% === end EBNF procedures to help debugging
2388
2389"
2390 "This is intended to help debugging PostScript programming.")
2391
2392
2393(defconst ebnf-prologue
2394 "
2395% === begin EBNF engine
2396
2397% --- Basic Definitions
2398
2399/fS F
2400/SpaceS FontHeight 0.5 mul def
2401/HeightS FontHeight FontHeight add def
2402
2403/fE F
2404/SpaceE FontHeight 0.5 mul def
2405/HeightE FontHeight FontHeight add def
2406
2407/fR F
2408/SpaceR FontHeight 0.5 mul def
2409/HeightR FontHeight FontHeight add def
2410
2411/fT F
2412/SpaceT FontHeight 0.5 mul def
2413/HeightT FontHeight FontHeight add def
2414
2415/fNT F
2416/SpaceNT FontHeight 0.5 mul def
2417/HeightNT FontHeight FontHeight add def
2418
2419/T HeightT HeightNT add 0.5 mul def
2420/hT T 0.5 mul def
2421/hT2 hT 0.5 mul def
2422/hT4 hT 0.25 mul def
2423
2424/Er 0.1 def % Error factor
2425
2426
2427/c{currentpoint}bind def
2428/xyi{/xi c /yi exch def def}bind def
2429/xyo{/xo c /yo exch def def}bind def
2430/xyp{/xp c /yp exch def def}bind def
2431/xyt{/xt c /yt exch def def}bind def
2432
2433% vertical movement: x y height vm
2434/vm{add moveto}bind def
2435
2436% horizontal movement: x y width hm
2437/hm{3 -1 roll exch add exch moveto}bind def
2438
2439% set color: [R G B] SetRGB
2440/SetRGB{aload pop setrgbcolor}bind def
2441
2442% filling gray area: gray-scale FillGray
2443/FillGray{gsave setgray fill grestore}bind def
2444
2445% filling color area: [R G B] FillRGB
2446/FillRGB{gsave SetRGB fill grestore}bind def
2447
2448/Stroke{LineWidth setlinewidth LineColor SetRGB stroke}bind def
2449/StrokeShape{borderwidth setlinewidth bordercolor SetRGB stroke}bind def
2450/Gstroke{gsave Stroke grestore}bind def
2451
2452% Empty Line: width EL
2453/EL{0 rlineto Gstroke}bind def
2454
2455% --- Arrows
2456
2457/Down{hT2 neg hT4 neg rlineto}bind def
2458
2459/Arrow
2460{hT2 neg hT4 rmoveto
2461 hT2 hT4 neg rlineto
2462 Down
2463}bind def
2464
2465/ArrowPath{c newpath moveto Arrow closepath}bind def
2466
2467%>Right Arrow: RA
2468% \\
2469% *---+
2470% /
2471/RA-vector
2472[{} % 0 - none
2473 {hT2 neg hT4 rlineto} % 1 - semi-up
2474 {Down} % 2 - semi-down
2475 {Arrow} % 3 - simple
2476 {Gstroke ArrowPath} % 4 - transparent
2477 {Gstroke ArrowPath 1 FillGray} % 5 - hollow
2478 {Gstroke ArrowPath LineColor FillRGB} % 6 - full
2479 {Gstroke gsave UserArrow grestore} % 7 - user
2480]def
2481
2482/RA
2483{hT 0 rlineto
2484 c
2485 RA-vector ArrowShape get exec
2486 Gstroke
2487 moveto
2488}def
2489
2490% rotation DrawArrow
2491/DrawArrow
2492{gsave
2493 0 0 translate
2494 rotate
2495 RA
2496 c
2497 grestore
2498 rmoveto
2499}def
2500
2501%>Left Arrow: LA
2502% /
2503% +---*
2504% \\
2505/LA{180 DrawArrow}def
2506
2507%>Up Arrow: UA
2508% +
2509% /|\\
2510% |
2511% *
2512/UA{90 DrawArrow}def
2513
2514%>Down Arrow: DA
2515% *
2516% |
2517% \\|/
2518% +
2519/DA{270 DrawArrow}def
2520
2521% --- Corners
2522
2523%>corner Right Descendent: height arrow corner_RD
2524% _ | arrow
2525% / height > 0 | 0 - none
2526% | | 1 - right
2527% * ---------- | 2 - left
2528% | | 3 - vertical
2529% \\ height < 0 |
2530% - |
2531/cRD0-vector
2532[% 0 - none
2533 {0 h rlineto
2534 hT 0 rlineto}
2535 % 1 - right
2536 {0 h rlineto
2537 RA}
2538 % 2 - left
2539 {hT 0 rmoveto xyi
2540 LA
2541 0 h neg rlineto
2542 xi yi moveto}
2543 % 3 - vertical
2544 {hT h rmoveto xyi
2545 hT neg 0 rlineto
2546 h 0 gt{DA}{UA}ifelse
2547 xi yi moveto}
2548]def
2549
2550/cRD-vector
2551[{cRD0-vector arrow get exec} % 0 - miter
2552 {0 0 0 h hT h rcurveto} % 1 - rounded
2553 {hT h rlineto} % 2 - bevel
2554]def
2555
2556/corner_RD
2557{/arrow exch def /h exch def
2558 cRD-vector ChartShape get exec
2559 Gstroke
2560}def
2561
2562%>corner Right Ascendent: height arrow corner_RA
2563% | arrow
2564% | height > 0 | 0 - none
2565% / | 1 - right
2566% *- ---------- | 2 - left
2567% \\ | 3 - vertical
2568% | height < 0 |
2569% |
2570/cRA0-vector
2571[% 0 - none
2572 {hT 0 rlineto
2573 0 h rlineto}
2574 % 1 - right
2575 {RA
2576 0 h rlineto}
2577 % 2 - left
2578 {hT h rmoveto xyi
2579 0 h neg rlineto
2580 LA
2581 xi yi moveto}
2582 % 3 - vertical
2583 {hT h rmoveto xyi
2584 h 0 gt{DA}{UA}ifelse
2585 hT neg 0 rlineto
2586 xi yi moveto}
2587]def
2588
2589/cRA-vector
2590[{cRA0-vector arrow get exec} % 0 - miter
2591 {0 0 hT 0 hT h rcurveto} % 1 - rounded
2592 {hT h rlineto} % 2 - bevel
2593]def
2594
2595/corner_RA
2596{/arrow exch def /h exch def
2597 cRA-vector ChartShape get exec
2598 Gstroke
2599}def
2600
2601%>corner Left Descendent: height arrow corner_LD
2602% _ | arrow
2603% \\ height > 0 | 0 - none
2604% | | 1 - right
2605% * ---------- | 2 - left
2606% | | 3 - vertical
2607% / height < 0 |
2608% - |
2609/cLD0-vector
2610[% 0 - none
2611 {0 h rlineto
2612 hT neg 0 rlineto}
2613 % 1 - right
2614 {hT neg h rmoveto xyi
2615 RA
2616 0 h neg rlineto
2617 xi yi moveto}
2618 % 2 - left
2619 {0 h rlineto
2620 LA}
2621 % 3 - vertical
2622 {hT neg h rmoveto xyi
2623 hT 0 rlineto
2624 h 0 gt{DA}{UA}ifelse
2625 xi yi moveto}
2626]def
2627
2628/cLD-vector
2629[{cLD0-vector arrow get exec} % 0 - miter
2630 {0 0 0 h hT neg h rcurveto} % 1 - rounded
2631 {hT neg h rlineto} % 2 - bevel
2632]def
2633
2634/corner_LD
2635{/arrow exch def /h exch def
2636 cLD-vector ChartShape get exec
2637 Gstroke
2638}def
2639
2640%>corner Left Ascendent: height arrow corner_LA
2641% | arrow
2642% | height > 0 | 0 - none
2643% \\ | 1 - right
2644% -* ---------- | 2 - left
2645% / | 3 - vertical
2646% | height < 0 |
2647% |
2648/cLA0-vector
2649[% 0 - none
2650 {hT neg 0 rlineto
2651 0 h rlineto}
2652 % 1 - right
2653 {hT neg h rmoveto xyi
2654 0 h neg rlineto
2655 RA
2656 xi yi moveto}
2657 % 2 - left
2658 {LA
2659 0 h rlineto}
2660 % 3 - vertical
2661 {hT neg h rmoveto xyi
2662 h 0 gt{DA}{UA}ifelse
2663 hT 0 rlineto
2664 xi yi moveto}
2665]def
2666
2667/cLA-vector
2668[{cLA0-vector arrow get exec} % 0 - miter
2669 {0 0 hT neg 0 hT neg h rcurveto} % 1 - rounded
2670 {hT neg h rlineto} % 2 - bevel
2671]def
2672
2673/corner_LA
2674{/arrow exch def /h exch def
2675 cLA-vector ChartShape get exec
2676 Gstroke
2677}def
2678
2679% --- Flow Stuff
2680
2681% height prepare_height |- line_height corner_height corner_height
2682/prepare_height
2683{dup 0 gt
2684 {T sub hT}
2685 {T add hT neg}ifelse
2686 dup
2687}def
2688
2689%>Left Alternative: height LAlt
2690% _
2691% /
2692% | height > 0
2693% |
2694% /
2695% *- ----------
2696% \\
2697% |
2698% | height < 0
2699% \\
2700% -
2701/LAlt
2702{dup 0 eq
2703 {T exch rlineto}
2704 {dup abs T lt
2705 {0.5 mul dup
2706 1 corner_RA
2707 0 corner_RD}
2708 {prepare_height
2709 1 corner_RA
2710 exch 0 exch rlineto
2711 0 corner_RD
2712 }ifelse
2713 }ifelse
2714}def
2715
2716%>Left Loop: height LLoop
2717% _
2718% /
2719% | height > 0
2720% |
2721% \\
2722% -* ----------
2723% /
2724% |
2725% | height < 0
2726% \\
2727% -
2728/LLoop
2729{prepare_height
2730 3 corner_LA
2731 exch 0 exch rlineto
2732 0 corner_RD
2733}def
2734
2735%>Right Alternative: height RAlt
2736% _
2737% \\
2738% | height > 0
2739% |
2740% \\
2741% -* ----------
2742% /
2743% |
2744% | height < 0
2745% /
2746% -
2747/RAlt
2748{dup 0 eq
2749 {T neg exch rlineto}
2750 {dup abs T lt
2751 {0.5 mul dup
2752 1 corner_LA
2753 0 corner_LD}
2754 {prepare_height
2755 1 corner_LA
2756 exch 0 exch rlineto
2757 0 corner_LD
2758 }ifelse
2759 }ifelse
2760}def
2761
2762%>Right Loop: height RLoop
2763% _
2764% \\
2765% | height > 0
2766% |
2767% /
2768% *- ----------
2769% \\
2770% |
2771% | height < 0
2772% /
2773% -
2774/RLoop
2775{prepare_height
2776 1 corner_RA
2777 exch 0 exch rlineto
2778 0 corner_LD
2779}def
2780
2781% --- Terminal, Non-terminal and Special Basics
2782
2783% string width prepare-width |- string
2784/prepare-width
2785{/width exch def
2786 dup stringwidth pop space add space add width exch sub 0.5 mul
2787 /w exch def
2788}def
2789
2790% string width begin-right
2791/begin-right
2792{xyo
2793 prepare-width
2794 w hT sub EL
2795 RA
2796}def
2797
2798% end-right
2799/end-right
2800{xo width add Er add yo moveto
2801 w Er add neg EL
2802 xo yo moveto
2803}def
2804
2805% string width begin-left
2806/begin-left
2807{xyo
2808 prepare-width
2809 w EL
2810}def
2811
2812% end-left
2813/end-left
2814{xo width add Er add yo moveto
2815 hT w sub Er add EL
2816 LA
2817 xo yo moveto
2818}def
2819
2820/ShapePath-vector
2821[% 0 - miter
2822 {xx yy moveto
2823 xx YY lineto
2824 XX YY lineto
2825 XX yy lineto}
2826 % 1 - rounded
2827 {/half YY yy sub 0.5 mul abs def
2828 xx half add YY moveto
2829 0 0 half neg 0 half neg half neg rcurveto
2830 0 0 0 half neg half half neg rcurveto
2831 XX xx sub abs half sub half sub 0 rlineto
2832 0 0 half 0 half half rcurveto
2833 0 0 0 half half neg half rcurveto}
2834 % 2 - bevel
2835 {/quarter YY yy sub 0.25 mul abs def
2836 xx quarter add YY moveto
2837 quarter neg quarter neg rlineto
2838 0 quarter quarter add neg rlineto
2839 quarter quarter neg rlineto
2840 XX xx sub abs quarter sub quarter sub 0 rlineto
2841 quarter quarter rlineto
2842 0 quarter quarter add rlineto
2843 quarter neg quarter rlineto}
2844]def
2845
2846/doShapePath
2847{newpath
2848 ShapePath-vector shape get exec
2849 closepath
2850}def
2851
2852/doShapeShadow
2853{gsave
2854 Xshadow Xshadow add Xshadow add
2855 Yshadow Yshadow add Yshadow add translate
2856 doShapePath
2857 0.9 FillGray
2858 grestore
2859}def
2860
2861/doShape
2862{gsave
2863 doShapePath
2864 shapecolor FillRGB
2865 StrokeShape
2866 grestore
2867}def
2868
2869% string SBound |- string
2870/SBound
2871{/xx c dup /yy exch def
2872 FontHeight add /YY exch def def
2873 dup stringwidth pop xx add /XX exch def
2874 Effect 8 and 0 ne
2875 {/yy yy YShadow add def
2876 /XX XX XShadow add def
2877 }if
2878}def
2879
2880% string SBox
2881/SBox
2882{gsave
2883 c space sub moveto
2884 SBound
2885 /XX XX space add space add def
2886 /YY YY space add def
2887 /yy yy space sub def
2888 shadow{doShapeShadow}if
2889 doShape
2890 space Descent abs rmoveto
2891 foreground SetRGB S
2892 grestore
2893}def
2894
2895% --- Terminal
2896
2897% TeRminal: string TR
2898/TR
2899{/Effect EffectT def
2900 /shape ShapeT def
2901 /shapecolor BackgroundT def
2902 /borderwidth BorderWidthT def
2903 /bordercolor BorderColorT def
2904 /foreground ForegroundT def
2905 /shadow ShadowT def
2906 SBox
2907}def
2908
2909%>Right Terminal: string width RT |- x y
2910/RT
2911{xyt
2912 /fT F
2913 /space SpaceT def
2914 begin-right
2915 TR
2916 end-right
2917 xt yt
2918}def
2919
2920%>Left Terminal: string width LT |- x y
2921/LT
2922{xyt
2923 /fT F
2924 /space SpaceT def
2925 begin-left
2926 TR
2927 end-left
2928 xt yt
2929}def
2930
2931%>Right Terminal Default: string width RTD |- x y
2932/RTD
2933{/-save- BorderWidthT def
2934 /BorderWidthT BorderWidthT DefaultWidth add def
2935 RT
2936 /BorderWidthT -save- def
2937}def
2938
2939%>Left Terminal Default: string width LTD |- x y
2940/LTD
2941{/-save- BorderWidthT def
2942 /BorderWidthT BorderWidthT DefaultWidth add def
2943 LT
2944 /BorderWidthT -save- def
2945}def
2946
2947% --- Non-Terminal
2948
2949% Non-Terminal: string NT
2950/NT
2951{/Effect EffectNT def
2952 /shape ShapeNT def
2953 /shapecolor BackgroundNT def
2954 /borderwidth BorderWidthNT def
2955 /bordercolor BorderColorNT def
2956 /foreground ForegroundNT def
2957 /shadow ShadowNT def
2958 SBox
2959}def
2960
2961%>Right Non-Terminal: string width RNT |- x y
2962/RNT
2963{xyt
2964 /fNT F
2965 /space SpaceNT def
2966 begin-right
2967 NT
2968 end-right
2969 xt yt
2970}def
2971
2972%>Left Non-Terminal: string width LNT |- x y
2973/LNT
2974{xyt
2975 /fNT F
2976 /space SpaceNT def
2977 begin-left
2978 NT
2979 end-left
2980 xt yt
2981}def
2982
2983%>Right Non-Terminal Default: string width RNTD |- x y
2984/RNTD
2985{/-save- BorderWidthNT def
2986 /BorderWidthNT BorderWidthNT DefaultWidth add def
2987 RNT
2988 /BorderWidthNT -save- def
2989}def
2990
2991%>Left Non-Terminal Default: string width LNTD |- x y
2992/LNTD
2993{/-save- BorderWidthNT def
2994 /BorderWidthNT BorderWidthNT DefaultWidth add def
2995 LNT
2996 /BorderWidthNT -save- def
2997}def
2998
2999% --- Special
3000
3001% SPecial: string SP
3002/SP
3003{/Effect EffectS def
3004 /shape ShapeS def
3005 /shapecolor BackgroundS def
3006 /borderwidth BorderWidthS def
3007 /bordercolor BorderColorS def
3008 /foreground ForegroundS def
3009 /shadow ShadowS def
3010 SBox
3011}def
3012
3013%>Right SPecial: string width RSP |- x y
3014/RSP
3015{xyt
3016 /fS F
3017 /space SpaceS def
3018 begin-right
3019 SP
3020 end-right
3021 xt yt
3022}def
3023
3024%>Left SPecial: string width LSP |- x y
3025/LSP
3026{xyt
3027 /fS F
3028 /space SpaceS def
3029 begin-left
3030 SP
3031 end-left
3032 xt yt
3033}def
3034
3035%>Right SPecial Default: string width RSPD |- x y
3036/RSPD
3037{/-save- BorderWidthS def
3038 /BorderWidthS BorderWidthS DefaultWidth add def
3039 RSP
3040 /BorderWidthS -save- def
3041}def
3042
3043%>Left SPecial Default: string width LSPD |- x y
3044/LSPD
3045{/-save- BorderWidthS def
3046 /BorderWidthS BorderWidthS DefaultWidth add def
3047 LSP
3048 /BorderWidthS -save- def
3049}def
3050
3051% --- Repeat and Except basics
3052
3053/begin-direction
3054{/w width rwidth sub 0.5 mul def
3055 width 0 rmoveto}def
3056
3057/end-direction
3058{gsave
3059 /xx c entry add /YY exch def def
3060 /yy YY height sub def
3061 /XX xx rwidth add def
3062 shadow{doShapeShadow}if
3063 doShape
3064 grestore
3065}def
3066
3067/right-direction
3068{begin-direction
3069 w neg EL
3070 xt yt moveto
3071 w hT sub EL RA
3072 end-direction
3073}def
3074
3075/left-direction
3076{begin-direction
3077 hT w sub EL LA
3078 xt yt moveto
3079 w EL
3080 end-direction
3081}def
3082
3083% --- Repeat
3084
3085% entry height width rwidth begin-repeat
3086/begin-repeat
3087{/rwidth exch def
3088 /width exch def
3089 /height exch def
3090 /entry exch def
3091 /fR F
3092 /space SpaceR def
3093 /Effect EffectR def
3094 /shape ShapeR def
3095 /shapecolor BackgroundR def
3096 /borderwidth BorderWidthR def
3097 /bordercolor BorderColorR def
3098 /foreground ForegroundR def
3099 /shadow ShadowR def
3100 xyt
3101}def
3102
3103% string end-repeat |- x y
3104/end-repeat
3105{gsave
3106 space Descent rmoveto
3107 foreground SetRGB S
3108 c Descent sub
3109 grestore
3110 exch space add exch moveto
3111 xt yt
3112}def
3113
3114%>Right RePeat: string entry height width rwidth RRP |- x y
3115/RRP{begin-repeat right-direction end-repeat}def
3116
3117%>Left RePeat: string entry height width rwidth LRP |- x y
3118/LRP{begin-repeat left-direction end-repeat}def
3119
3120% --- Except
3121
3122% entry height width rwidth begin-except
3123/begin-except
3124{/rwidth exch def
3125 /width exch def
3126 /height exch def
3127 /entry exch def
3128 /fE F
3129 /space SpaceE def
3130 /Effect EffectE def
3131 /shape ShapeE def
3132 /shapecolor BackgroundE def
3133 /borderwidth BorderWidthE def
3134 /bordercolor BorderColorE def
3135 /foreground ForegroundE def
3136 /shadow ShadowE def
3137 xyt
3138}def
3139
3140% x-width end-except |- x y
3141/end-except
3142{gsave
3143 space space add add Descent rmoveto
3144 (-) foreground SetRGB S
3145 grestore
3146 space 0 rmoveto
3147 xt yt
3148}def
3149
3150%>Right EXcept: x-width entry height width rwidth REX |- x y
3151/REX{begin-except right-direction end-except}def
3152
3153%>Left EXcept: x-width entry height width rwidth LEX |- x y
3154/LEX{begin-except left-direction end-except}def
3155
3156% --- Sequence
3157
3158%>Beginning Of Sequence: BOS |- x y
3159/BOS{currentpoint}bind def
3160
3161%>End Of Sequence: x y x1 y1 EOS |- x y
3162/EOS{pop pop}bind def
3163
3164% --- Production
3165
3166%>Beginning Of Production: string width height BOP |- y x
3167/BOP
3168{xyp
3169 neg yp add /yw exch def
3170 xp add T sub /xw exch def
3171 /Effect EffectP def
3172 /fP F ForegroundP SetRGB BackgroundP aload pop true BG S
3173 /Effect 0 def
3174 ( :) S false BG
3175 xw yw moveto
3176 hT EL RA
3177 xp yw moveto
3178 T EL
3179 yp xp
3180}def
3181
3182%>End Of Production: y x delta EOP
3183/EOPH{add exch moveto}bind def % horizontal
3184/EOPV{exch pop sub 0 exch moveto}bind def % vertical
3185
3186% --- Empty Alternative
3187
3188%>Empty Alternative: width EA |- x y
3189/EA
3190{gsave
3191 Er add 0 rlineto
3192 Stroke
3193 grestore
3194 c
3195}def
3196
3197% --- Alternative
3198
3199%>AlTernative: h1 h2 ... hn n width AT |- x y
3200/AT
3201{xyo xo add /xw exch def
3202 xw yo moveto
3203 Er EL
3204 {xw yo moveto
3205 dup RAlt
3206 xo yo moveto
3207 LAlt}repeat
3208 xo yo
3209}def
3210
3211% --- Optional
3212
3213%>OPtional: height width OP |- x y
3214/OP
3215{xyo
3216 T sub /ow exch def
3217 ow Er sub 0 rmoveto
3218 T Er add EL
3219 neg dup RAlt
3220 ow T sub neg EL
3221 xo yo moveto
3222 LAlt
3223 xo yo moveto
3224 T EL
3225 xo yo
3226}def
3227
3228% --- List Flow
3229
3230%>One or More: height width OM |- x y
3231/OM
3232{xyo
3233 /ow exch def
3234 ow Er add 0 rmoveto
3235 T Er add neg EL
3236 dup RLoop
3237 xo T add yo moveto
3238 LLoop
3239 xo yo moveto
3240 T EL
3241 xo yo
3242}def
3243
3244%>Zero or More: h2 h1 width ZM |- x y
3245/ZM
3246{xyo
3247 Er add EL
3248 Er neg 0 rmoveto
3249 dup RAlt
3250 exch dup RLoop
3251 xo yo moveto
3252 exch dup LAlt
3253 exch LLoop
3254 yo add xo T add exch moveto
3255 xo yo
3256}def
3257
3258% === end EBNF engine
3259
3260"
3261 "EBNF PostScript prologue")
3262
3263
3264(defconst ebnf-eps-prologue
3265 "
3266/#ebnf2ps#dict 230 dict def
3267#ebnf2ps#dict begin
3268
3269% Initiliaze variables to avoid name-conflicting with document variables.
3270% This is the case when using `bind' operator.
3271/-fillp- 0 def /h 0 def
3272/-ox- 0 def /half 0 def
3273/-oy- 0 def /height 0 def
3274/-save- 0 def /ow 0 def
3275/Ascent 0 def /quarter 0 def
3276/Descent 0 def /rXX 0 def
3277/Effect 0 def /rYY 0 def
3278/FontHeight 0 def /rwidth 0 def
3279/LineThickness 0 def /rxx 0 def
3280/OverlinePosition 0 def /ryy 0 def
3281/SpaceBackground 0 def /shadow 0 def
3282/StrikeoutPosition 0 def /shape 0 def
3283/UnderlinePosition 0 def /shapecolor 0 def
3284/XBox 0 def /space 0 def
3285/XX 0 def /st 1 string def
3286/Xshadow 0 def /w 0 def
3287/YBox 0 def /width 0 def
3288/YY 0 def /xi 0 def
3289/Yshadow 0 def /xo 0 def
3290/arrow 0 def /xp 0 def
3291/bg false def /xt 0 def
3292/bgcolor 0 def /xw 0 def
3293/bordercolor 0 def /xx 0 def
3294/borderwidth 0 def /yi 0 def
3295/dd 0 def /yo 0 def
3296/entry 0 def /yp 0 def
3297/foreground 0 def /yt 0 def
3298 /yy 0 def
3299
3300
3301% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
3302/ISOLatin1Encoding where
3303{pop}
3304{% -- The ISO Latin-1 encoding vector isn't known, so define it.
3305 % -- The first half is the same as the standard encoding,
3306 % -- except for minus instead of hyphen at code 055.
3307 /ISOLatin1Encoding
3308 StandardEncoding 0 45 getinterval aload pop
3309 /minus
3310 StandardEncoding 46 82 getinterval aload pop
3311 %*** NOTE: the following are missing in the Adobe documentation,
3312 %*** but appear in the displayed table:
3313 %*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
3314 % 0200 (128)
3315 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
3316 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
3317 /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
3318 /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
3319 % 0240 (160)
3320 /space /exclamdown /cent /sterling
3321 /currency /yen /brokenbar /section
3322 /dieresis /copyright /ordfeminine /guillemotleft
3323 /logicalnot /hyphen /registered /macron
3324 /degree /plusminus /twosuperior /threesuperior
3325 /acute /mu /paragraph /periodcentered
3326 /cedilla /onesuperior /ordmasculine /guillemotright
3327 /onequarter /onehalf /threequarters /questiondown
3328 % 0300 (192)
3329 /Agrave /Aacute /Acircumflex /Atilde
3330 /Adieresis /Aring /AE /Ccedilla
3331 /Egrave /Eacute /Ecircumflex /Edieresis
3332 /Igrave /Iacute /Icircumflex /Idieresis
3333 /Eth /Ntilde /Ograve /Oacute
3334 /Ocircumflex /Otilde /Odieresis /multiply
3335 /Oslash /Ugrave /Uacute /Ucircumflex
3336 /Udieresis /Yacute /Thorn /germandbls
3337 % 0340 (224)
3338 /agrave /aacute /acircumflex /atilde
3339 /adieresis /aring /ae /ccedilla
3340 /egrave /eacute /ecircumflex /edieresis
3341 /igrave /iacute /icircumflex /idieresis
3342 /eth /ntilde /ograve /oacute
3343 /ocircumflex /otilde /odieresis /divide
3344 /oslash /ugrave /uacute /ucircumflex
3345 /udieresis /yacute /thorn /ydieresis
3346 256 packedarray def
3347}ifelse
3348
3349/reencodeFontISO %def
3350{dup
3351 length 12 add dict % Make a new font (a new dict the same size
3352 % as the old one) with room for our new symbols.
3353
3354 begin % Make the new font the current dictionary.
3355 {1 index /FID ne
3356 {def}{pop pop}ifelse
3357 }forall % Copy each of the symbols from the old dictionary
3358 % to the new one except for the font ID.
3359
3360 currentdict /FontType get 0 ne
3361 {/Encoding ISOLatin1Encoding def}if % Override the encoding with
3362 % the ISOLatin1 encoding.
3363
3364 % Use the font's bounding box to determine the ascent, descent,
3365 % and overall height; don't forget that these values have to be
3366 % transformed using the font's matrix.
3367
3368 % ^ (x2 y2)
3369 % | |
3370 % | v
3371 % | +----+ - -
3372 % | | | ^
3373 % | | | | Ascent (usually > 0)
3374 % | | | |
3375 % (0 0) -> +--+----+-------->
3376 % | | |
3377 % | | v Descent (usually < 0)
3378 % (x1 y1) --> +----+ - -
3379
3380 currentdict /FontType get 0 ne
3381 {/FontBBox load aload pop % -- x1 y1 x2 y2
3382 FontMatrix transform /Ascent exch def pop
3383 FontMatrix transform /Descent exch def pop}
3384 {/PrimaryFont FDepVector 0 get def
3385 PrimaryFont /FontBBox get aload pop
3386 PrimaryFont /FontMatrix get transform /Ascent exch def pop
3387 PrimaryFont /FontMatrix get transform /Descent exch def pop
3388 }ifelse
3389
3390 /FontHeight Ascent Descent sub def % use `sub' because descent < 0
3391
3392 % Define these in case they're not in the FontInfo
3393 % (also, here they're easier to get to).
3394 /UnderlinePosition Descent 0.70 mul def
3395 /OverlinePosition Descent UnderlinePosition sub Ascent add def
3396 /StrikeoutPosition Ascent 0.30 mul def
3397 /LineThickness FontHeight 0.05 mul def
3398 /Xshadow FontHeight 0.08 mul def
3399 /Yshadow FontHeight -0.09 mul def
3400 /SpaceBackground Descent neg UnderlinePosition add def
3401 /XBox Descent neg def
3402 /YBox LineThickness 0.7 mul def
3403
3404 currentdict % Leave the new font on the stack
3405 end % Stop using the font as the current dictionary
3406 definefont % Put the font into the font dictionary
3407 pop % Discard the returned font
3408}bind def
3409
3410% Font definition
3411/DefFont{findfont exch scalefont reencodeFontISO}def
3412
3413% Font selection
3414/F
3415{findfont
3416 dup /Ascent get /Ascent exch def
3417 dup /Descent get /Descent exch def
3418 dup /FontHeight get /FontHeight exch def
3419 dup /UnderlinePosition get /UnderlinePosition exch def
3420 dup /OverlinePosition get /OverlinePosition exch def
3421 dup /StrikeoutPosition get /StrikeoutPosition exch def
3422 dup /LineThickness get /LineThickness exch def
3423 dup /Xshadow get /Xshadow exch def
3424 dup /Yshadow get /Yshadow exch def
3425 dup /SpaceBackground get /SpaceBackground exch def
3426 dup /XBox get /XBox exch def
3427 dup /YBox get /YBox exch def
3428 setfont
3429}def
3430
3431/BG
3432{dup /bg exch def
3433 {mark 4 1 roll ]}
3434 {[ 1.0 1.0 1.0 ]}
3435 ifelse
3436 /bgcolor exch def
3437}def
3438
3439% stack: --
3440/FillBgColor{bgcolor aload pop setrgbcolor fill}bind def
3441
3442% stack: fill-or-not lower-x lower-y upper-x upper-y |- --
3443/doRect
3444{/rYY exch def
3445 /rXX exch def
3446 /ryy exch def
3447 /rxx exch def
3448 gsave
3449 newpath
3450 rXX rYY moveto
3451 rxx rYY lineto
3452 rxx ryy lineto
3453 rXX ryy lineto
3454 closepath
3455 % top of stack: fill-or-not
3456 {FillBgColor}
3457 {LineThickness setlinewidth stroke}
3458 ifelse
3459 grestore
3460}bind def
3461
3462% stack: string fill-or-not |- --
3463/doOutline
3464{/-fillp- exch def
3465 /-ox- currentpoint /-oy- exch def def
3466 gsave
3467 LineThickness setlinewidth
3468 {st 0 3 -1 roll put
3469 st dup true charpath
3470 -fillp- {gsave FillBgColor grestore}if
3471 stroke stringwidth
3472 -oy- add /-oy- exch def
3473 -ox- add /-ox- exch def
3474 -ox- -oy- moveto
3475 }forall
3476 grestore
3477 -ox- -oy- moveto
3478}bind def
3479
3480% stack: fill-or-not delta |- --
3481/doBox
3482{/dd exch def
3483 xx XBox sub dd sub yy YBox sub dd sub
3484 XX XBox add dd add YY YBox add dd add
3485 doRect
3486}bind def
3487
3488% stack: string |- --
3489/doShadow
3490{gsave
3491 Xshadow Yshadow rmoveto
3492 false doOutline
3493 grestore
3494}bind def
3495
3496% stack: position |- --
3497/Hline
3498{currentpoint exch pop add dup
3499 gsave
3500 newpath
3501 xx exch moveto
3502 XX exch lineto
3503 closepath
3504 LineThickness setlinewidth stroke
3505 grestore
3506}bind def
3507
3508% stack: string |- --
3509% effect: 1 - underline 2 - strikeout 4 - overline
3510% 8 - shadow 16 - box 32 - outline
3511/S
3512{/xx currentpoint dup Descent add /yy exch def
3513 Ascent add /YY exch def def
3514 dup stringwidth pop xx add /XX exch def
3515 Effect 8 and 0 ne
3516 {/yy yy Yshadow add def
3517 /XX XX Xshadow add def
3518 }if
3519 bg
3520 {true
3521 Effect 16 and 0 ne
3522 {SpaceBackground doBox}
3523 {xx yy XX YY doRect}
3524 ifelse
3525 }if % background
3526 Effect 16 and 0 ne{false 0 doBox}if % box
3527 Effect 8 and 0 ne{dup doShadow}if % shadow
3528 Effect 32 and 0 ne
3529 {true doOutline} % outline
3530 {show} % normal text
3531 ifelse
3532 Effect 1 and 0 ne{UnderlinePosition Hline}if % underline
3533 Effect 2 and 0 ne{StrikeoutPosition Hline}if % strikeout
3534 Effect 4 and 0 ne{OverlinePosition Hline}if % overline
3535}bind def
3536
3537"
3538 "EBNF EPS prologue")
3539
3540
3541(defconst ebnf-eps-begin
3542 "
3543end
3544
3545% x y #ebnf2ps#begin
3546/#ebnf2ps#begin
3547{#ebnf2ps#dict begin /#ebnf2ps#save save def
3548 moveto false BG 0.0 0.0 0.0 setrgbcolor}def
3549
3550/#ebnf2ps#end{showpage #ebnf2ps#save restore end}def
3551
0b5ecd6d 3552%%EndProlog
984ae001
GM
3553"
3554 "EBNF EPS begin")
3555
3556
3557(defconst ebnf-eps-end
3558 "#ebnf2ps#end
3559%%EOF
3560"
3561 "EBNF EPS end")
3562
3563\f
3564;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3565;; Formatting
3566
3567
3568(defvar ebnf-format-float "%1.3f")
3569
3570
3571(defun ebnf-format-float (&rest floats)
3572 (mapconcat
3573 #'(lambda (float)
3574 (format ebnf-format-float float))
3575 floats
3576 " "))
3577
3578
3579(defun ebnf-format-color (format-str color default)
3580 (let* ((the-color (or color default))
b685181e 3581 (rgb (ps-color-scale the-color)))
984ae001
GM
3582 (format format-str
3583 (concat "["
3584 (ebnf-format-float (nth 0 rgb) (nth 1 rgb) (nth 2 rgb))
3585 "]")
3586 the-color)))
3587
3588
3589(defvar ebnf-message-float "%3.2f")
3590
3591
3592(defsubst ebnf-message-float (format-str value)
3593 (message format-str
3594 (format ebnf-message-float value)))
3595
3596
30fa28b4
VJL
3597(defvar ebnf-total 0)
3598(defvar ebnf-nprod 0)
3599
3600
984ae001
GM
3601(defsubst ebnf-message-info (messag)
3602 (message "%s...%3d%%"
3603 messag
3604 (round (/ (* (setq ebnf-nprod (1+ ebnf-nprod)) 100.0) ebnf-total))))
3605
3606\f
3607;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3608;; Macros
3609
3610
3611(defmacro ebnf-node-kind (vec &optional value)
3612 (if value
3613 `(aset ,vec 0 ,value)
3614 `(aref ,vec 0)))
3615
3616
3617(defmacro ebnf-node-width-func (node width)
3618 `(funcall (aref ,node 1) ,node ,width))
3619
3620
3621(defmacro ebnf-node-dimension-func (node &optional value)
3622 (if value
3623 `(aset ,node 2 ,value)
3624 `(funcall (aref ,node 2) ,node)))
3625
3626
3627(defmacro ebnf-node-entry (vec &optional value)
3628 (if value
3629 `(aset ,vec 3 ,value)
3630 `(aref ,vec 3)))
3631
3632
3633(defmacro ebnf-node-height (vec &optional value)
3634 (if value
3635 `(aset ,vec 4 ,value)
3636 `(aref ,vec 4)))
3637
3638
3639(defmacro ebnf-node-width (vec &optional value)
3640 (if value
3641 `(aset ,vec 5 ,value)
3642 `(aref ,vec 5)))
3643
3644
3645(defmacro ebnf-node-name (vec)
3646 `(aref ,vec 6))
3647
3648
3649(defmacro ebnf-node-list (vec &optional value)
3650 (if value
3651 `(aset ,vec 6 ,value)
3652 `(aref ,vec 6)))
3653
3654
3655(defmacro ebnf-node-default (vec)
3656 `(aref ,vec 7))
3657
3658
3659(defmacro ebnf-node-production (vec &optional value)
3660 (if value
3661 `(aset ,vec 7 ,value)
3662 `(aref ,vec 7)))
3663
3664
3665(defmacro ebnf-node-separator (vec &optional value)
3666 (if value
3667 `(aset ,vec 7 ,value)
3668 `(aref ,vec 7)))
3669
3670
3671(defmacro ebnf-node-action (vec &optional value)
3672 (if value
3673 `(aset ,vec 8 ,value)
3674 `(aref ,vec 8)))
3675
3676
3677(defmacro ebnf-node-generation (node)
3678 `(funcall (ebnf-node-kind ,node) ,node))
3679
3680
3681(defmacro ebnf-max-width (prod)
3682 `(max (ebnf-node-width ,prod)
3683 (+ (* (length (ebnf-node-name ,prod))
3684 ebnf-font-width-P)
3685 ebnf-production-horizontal-space)))
3686
3687\f
3688;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
3689;; PostScript generation
3690
3691
3692(defun ebnf-generate-eps (ebnf-tree)
3693 (let* ((ps-color-p (and ebnf-color-p (ps-color-device)))
3694 (ps-print-color-scale (if ps-color-p
3695 (float (car (ps-color-values "white")))
3696 1.0))
3697 (ebnf-total (length ebnf-tree))
3698 (ebnf-nprod 0)
3699 (old-ps-output (symbol-function 'ps-output))
3700 (old-ps-output-string (symbol-function 'ps-output-string))
3701 (eps-buffer (get-buffer-create ebnf-eps-buffer-name))
3702 ebnf-debug-ps error-msg horizontal
3703 prod prod-name prod-width prod-height prod-list file-list)
3704 ;; redefines `ps-output' and `ps-output-string'
3705 (defalias 'ps-output 'ebnf-eps-output)
3706 (defalias 'ps-output-string 'ps-output-string-prim)
3707 ;; generate EPS file
3708 (save-excursion
3709 (condition-case data
3710 (progn
3711 (while ebnf-tree
3712 (setq prod (car ebnf-tree)
3713 prod-name (ebnf-node-name prod)
3714 prod-width (ebnf-max-width prod)
3715 prod-height (ebnf-node-height prod)
b685181e
GM
3716 horizontal (memq (ebnf-node-action prod)
3717 ebnf-action-list))
984ae001
GM
3718 ;; generate production in EPS buffer
3719 (save-excursion
3720 (set-buffer eps-buffer)
3721 (setq ebnf-eps-upper-x 0.0
3722 ebnf-eps-upper-y 0.0
3723 ebnf-eps-max-width prod-width
3724 ebnf-eps-max-height prod-height)
3725 (ebnf-generate-production prod))
3726 (if (setq prod-list (cdr (assoc prod-name
3727 ebnf-eps-production-list)))
3728 ;; insert EPS buffer in all buffer associated with production
3729 (ebnf-eps-production-list prod-list 'file-list horizontal
3730 prod-width prod-height eps-buffer)
3731 ;; write EPS file for production
3732 (ebnf-eps-finish-and-write eps-buffer
3733 (ebnf-eps-filename prod-name)))
3734 ;; prepare for next loop
3735 (save-excursion
3736 (set-buffer eps-buffer)
3737 (erase-buffer))
3738 (setq ebnf-tree (cdr ebnf-tree)))
3739 ;; write and kill temporary buffers
3740 (ebnf-eps-write-kill-temp file-list t)
3741 (setq file-list nil))
3742 ;; handler
3743 ((quit error)
3744 (setq error-msg (error-message-string data)))))
3745 ;; restore `ps-output' and `ps-output-string'
3746 (defalias 'ps-output old-ps-output)
3747 (defalias 'ps-output-string old-ps-output-string)
3748 ;; kill temporary buffers
3749 (kill-buffer eps-buffer)
3750 (ebnf-eps-write-kill-temp file-list nil)
3751 (and error-msg (error error-msg))
3752 (message " ")))
3753
3754
3755;; write and kill temporary buffers
3756(defun ebnf-eps-write-kill-temp (file-list write-p)
3757 (while file-list
3758 (let ((buffer (get-buffer (concat " *" (car file-list) "*"))))
3759 (when buffer
3760 (and write-p
3761 (ebnf-eps-finish-and-write buffer (car file-list)))
3762 (kill-buffer buffer)))
3763 (setq file-list (cdr file-list))))
3764
3765
3766;; insert EPS buffer in all buffer associated with production
3767(defun ebnf-eps-production-list (prod-list file-list-sym horizontal
3768 prod-width prod-height eps-buffer)
3769 (while prod-list
3770 (add-to-list file-list-sym (car prod-list))
3771 (save-excursion
3772 (set-buffer (get-buffer-create (concat " *" (car prod-list) "*")))
3773 (goto-char (point-max))
3774 (cond
3775 ;; first production
3776 ((zerop (buffer-size))
3777 (setq ebnf-eps-upper-x 0.0
3778 ebnf-eps-upper-y 0.0
3779 ebnf-eps-max-width prod-width
3780 ebnf-eps-max-height prod-height))
3781 ;; horizontal
3782 (horizontal
3783 (ebnf-eop-horizontal ebnf-eps-prod-width)
3784 (setq ebnf-eps-max-width (+ ebnf-eps-max-width
3785 ebnf-production-horizontal-space
3786 prod-width)
3787 ebnf-eps-max-height (max ebnf-eps-max-height prod-height)))
3788 ;; vertical
3789 (t
3790 (ebnf-eop-vertical ebnf-eps-max-height)
3791 (setq ebnf-eps-upper-x (max ebnf-eps-upper-x ebnf-eps-max-width)
3792 ebnf-eps-upper-y (if (zerop ebnf-eps-upper-y)
3793 ebnf-eps-max-height
3794 (+ ebnf-eps-upper-y
3795 ebnf-production-vertical-space
3796 ebnf-eps-max-height))
3797 ebnf-eps-max-width prod-width
3798 ebnf-eps-max-height prod-height))
3799 )
3800 (setq ebnf-eps-prod-width prod-width)
3801 (insert-buffer eps-buffer))
3802 (setq prod-list (cdr prod-list))))
3803
3804
3805(defun ebnf-generate (ebnf-tree)
3806 (let* ((ps-color-p (and ebnf-color-p (ps-color-device)))
3807 (ps-print-color-scale (if ps-color-p
3808 (float (car (ps-color-values "white")))
3809 1.0))
3810 ps-zebra-stripes ps-line-number ps-razzle-dazzle
3811 ps-print-hook
3812 ps-print-begin-sheet-hook
3813 ps-print-begin-page-hook
3814 ps-print-begin-column-hook)
3815 (ps-generate (current-buffer) (point-min) (point-max)
3816 'ebnf-generate-postscript)))
3817
3818
3819(defvar ebnf-tree nil)
3820(defvar ebnf-direction "R")
984ae001
GM
3821
3822
3823(defun ebnf-generate-postscript (from to)
3824 (ebnf-begin-file)
3825 (if ebnf-horizontal-max-height
3826 (ebnf-generate-with-max-height)
3827 (ebnf-generate-without-max-height))
3828 (message " "))
3829
3830
3831(defun ebnf-generate-with-max-height ()
3832 (let ((ebnf-total (length ebnf-tree))
3833 (ebnf-nprod 0)
3834 next-line max-height prod the-width)
3835 (while ebnf-tree
3836 ;; find next line point
3837 (setq next-line ebnf-tree
3838 prod (car ebnf-tree)
3839 max-height (ebnf-node-height prod))
3840 (ebnf-begin-line prod (ebnf-max-width prod))
3841 (while (and (setq next-line (cdr next-line))
3842 (setq prod (car next-line))
3843 (memq (ebnf-node-action prod) ebnf-action-list)
3844 (setq the-width (ebnf-max-width prod))
3845 (<= the-width ps-width-remaining))
3846 (setq max-height (max max-height (ebnf-node-height prod))
3847 ps-width-remaining (- ps-width-remaining
3848 (+ the-width
3849 ebnf-production-horizontal-space))))
3850 ;; generate current line
3851 (ebnf-newline max-height)
3852 (setq prod (car ebnf-tree))
3853 (ebnf-generate-production prod)
3854 (while (not (eq (setq ebnf-tree (cdr ebnf-tree)) next-line))
3855 (ebnf-eop-horizontal (ebnf-max-width prod))
3856 (setq prod (car ebnf-tree))
3857 (ebnf-generate-production prod))
3858 (ebnf-eop-vertical max-height))))
3859
3860
3861(defun ebnf-generate-without-max-height ()
3862 (let ((ebnf-total (length ebnf-tree))
3863 (ebnf-nprod 0)
3864 max-height prod bef-width cur-width)
3865 (while ebnf-tree
3866 ;; generate current line
3867 (setq prod (car ebnf-tree)
3868 max-height (ebnf-node-height prod)
3869 bef-width (ebnf-max-width prod))
3870 (ebnf-begin-line prod bef-width)
3871 (ebnf-generate-production prod)
3872 (while (and (setq ebnf-tree (cdr ebnf-tree))
3873 (setq prod (car ebnf-tree))
3874 (memq (ebnf-node-action prod) ebnf-action-list)
3875 (setq cur-width (ebnf-max-width prod))
3876 (<= cur-width ps-width-remaining)
3877 (<= (ebnf-node-height prod) ps-height-remaining))
3878 (ebnf-eop-horizontal bef-width)
3879 (ebnf-generate-production prod)
3880 (setq bef-width cur-width
3881 max-height (max max-height (ebnf-node-height prod))
3882 ps-width-remaining (- ps-width-remaining
3883 (+ cur-width
3884 ebnf-production-horizontal-space))))
3885 (ebnf-eop-vertical max-height)
3886 ;; prepare next line
3887 (ebnf-newline max-height))))
3888
3889
3890(defun ebnf-begin-line (prod width)
3891 (and (or (eq (ebnf-node-action prod) 'form-feed)
3892 (> (ebnf-node-height prod) ps-height-remaining))
3893 (ebnf-new-page))
3894 (setq ps-width-remaining (- ps-width-remaining
3895 (+ width
3896 ebnf-production-horizontal-space))))
3897
3898
3899(defun ebnf-newline (height)
3900 (and (> height ps-height-remaining)
3901 (ebnf-new-page))
3902 (setq ps-width-remaining ps-print-width
3903 ps-height-remaining (- ps-height-remaining
3904 (+ height
3905 ebnf-production-vertical-space))))
3906
3907
3908;; [production width-fun dim-fun entry height width name production action]
3909(defun ebnf-generate-production (production)
3910 (ebnf-message-info "Generating")
3911 (run-hooks 'ebnf-production-hook)
3912 (ps-output-string (ebnf-node-name production))
3913 (ps-output " "
3914 (ebnf-format-float
3915 (ebnf-node-width production)
3916 (+ ebnf-basic-height
3917 (ebnf-node-entry (ebnf-node-production production))))
3918 " BOP\n")
3919 (ebnf-node-generation (ebnf-node-production production))
3920 (ps-output "EOS\n"))
3921
3922
3923;; [alternative width-fun dim-fun entry height width list]
3924(defun ebnf-generate-alternative (alternative)
3925 (let ((alt (ebnf-node-list alternative))
3926 (entry (ebnf-node-entry alternative))
3927 (nlist 0)
3928 alt-height alt-entry)
3929 (while alt
3930 (ps-output (ebnf-format-float (- entry (ebnf-node-entry (car alt))))
3931 " ")
3932 (setq entry (- entry (ebnf-node-height (car alt)) ebnf-vertical-space)
3933 nlist (1+ nlist)
3934 alt (cdr alt)))
3935 (ps-output (format "%d " nlist)
3936 (ebnf-format-float (ebnf-node-width alternative))
3937 " AT\n")
3938 (setq alt (ebnf-node-list alternative))
3939 (when alt
3940 (ebnf-node-generation (car alt))
3941 (setq alt-height (- (ebnf-node-height (car alt))
3942 (ebnf-node-entry (car alt)))))
3943 (while (setq alt (cdr alt))
3944 (setq alt-entry (ebnf-node-entry (car alt)))
3945 (ebnf-vertical-movement
3946 (- (+ alt-height ebnf-vertical-space alt-entry)))
3947 (ebnf-node-generation (car alt))
3948 (setq alt-height (- (ebnf-node-height (car alt)) alt-entry))))
3949 (ps-output "EOS\n"))
3950
3951
3952;; [sequence width-fun dim-fun entry height width list]
3953(defun ebnf-generate-sequence (sequence)
3954 (ps-output "BOS\n")
3955 (let ((seq (ebnf-node-list sequence))
3956 seq-width)
3957 (when seq
3958 (ebnf-node-generation (car seq))
3959 (setq seq-width (ebnf-node-width (car seq))))
3960 (while (setq seq (cdr seq))
3961 (ebnf-horizontal-movement seq-width)
3962 (ebnf-node-generation (car seq))
3963 (setq seq-width (ebnf-node-width (car seq)))))
3964 (ps-output "EOS\n"))
3965
3966
3967;; [terminal width-fun dim-fun entry height width name]
3968(defun ebnf-generate-terminal (terminal)
3969 (ebnf-gen-terminal terminal "T"))
3970
3971
3972;; [non-terminal width-fun dim-fun entry height width name]
3973(defun ebnf-generate-non-terminal (non-terminal)
3974 (ebnf-gen-terminal non-terminal "NT"))
3975
3976
3977;; [empty width-fun dim-fun entry height width]
3978(defun ebnf-generate-empty (empty)
3979 (ebnf-empty-alternative (ebnf-node-width empty)))
3980
3981
3982;; [optional width-fun dim-fun entry height width element]
3983(defun ebnf-generate-optional (optional)
3984 (let ((the-optional (ebnf-node-list optional)))
3985 (ps-output (ebnf-format-float
3986 (+ (- (ebnf-node-height the-optional)
3987 (ebnf-node-entry optional))
3988 ebnf-vertical-space)
3989 (ebnf-node-width optional))
3990 " OP\n")
3991 (ebnf-node-generation the-optional)
3992 (ps-output "EOS\n")))
3993
3994
3995;; [one-or-more width-fun dim-fun entry height width element separator]
3996(defun ebnf-generate-one-or-more (one-or-more)
3997 (let* ((width (ebnf-node-width one-or-more))
3998 (sep (ebnf-node-separator one-or-more))
3999 (entry (- (ebnf-node-entry one-or-more)
4000 (if sep
4001 (ebnf-node-entry sep)
4002 0))))
4003 (ps-output (ebnf-format-float entry width)
4004 " OM\n")
4005 (ebnf-node-generation (ebnf-node-list one-or-more))
4006 (ebnf-vertical-movement entry)
4007 (if sep
4008 (let ((ebnf-direction "L"))
4009 (ebnf-node-generation sep))
4010 (ebnf-empty-alternative (- width ebnf-horizontal-space))))
4011 (ps-output "EOS\n"))
4012
4013
4014;; [zero-or-more width-fun dim-fun entry height width element separator]
4015(defun ebnf-generate-zero-or-more (zero-or-more)
4016 (let* ((width (ebnf-node-width zero-or-more))
4017 (node-list (ebnf-node-list zero-or-more))
4018 (list-entry (ebnf-node-entry node-list))
4019 (node-sep (ebnf-node-separator zero-or-more))
4020 (entry (+ list-entry
4021 ebnf-vertical-space
4022 (if node-sep
4023 (- (ebnf-node-height node-sep)
4024 (ebnf-node-entry node-sep))
4025 0))))
4026 (ps-output (ebnf-format-float entry
4027 (+ (- (ebnf-node-height node-list)
4028 list-entry)
4029 ebnf-vertical-space)
4030 width)
4031 " ZM\n")
4032 (ebnf-node-generation (ebnf-node-list zero-or-more))
4033 (ebnf-vertical-movement entry)
4034 (if (ebnf-node-separator zero-or-more)
4035 (let ((ebnf-direction "L"))
4036 (ebnf-node-generation (ebnf-node-separator zero-or-more)))
4037 (ebnf-empty-alternative (- width ebnf-horizontal-space))))
4038 (ps-output "EOS\n"))
4039
4040
4041;; [special width-fun dim-fun entry height width name]
4042(defun ebnf-generate-special (special)
4043 (ebnf-gen-terminal special "SP"))
4044
4045
4046;; [repeat width-fun dim-fun entry height width times element]
4047(defun ebnf-generate-repeat (repeat)
4048 (let ((times (ebnf-node-name repeat))
4049 (element (ebnf-node-separator repeat)))
4050 (ps-output-string times)
4051 (ps-output " "
4052 (ebnf-format-float
4053 (ebnf-node-entry repeat)
4054 (ebnf-node-height repeat)
4055 (ebnf-node-width repeat)
4056 (if element
4057 (+ (ebnf-node-width element)
4058 ebnf-space-R ebnf-space-R ebnf-space-R
4059 (* (length times) ebnf-font-width-R))
4060 0.0))
4061 " " ebnf-direction "RP\n")
4062 (and element
4063 (ebnf-node-generation element)))
4064 (ps-output "EOS\n"))
4065
4066
4067;; [except width-fun dim-fun entry height width element element]
4068(defun ebnf-generate-except (except)
4069 (let* ((element (ebnf-node-list except))
4070 (exception (ebnf-node-separator except))
4071 (width (ebnf-node-width element)))
4072 (ps-output (ebnf-format-float
4073 width
4074 (ebnf-node-entry except)
4075 (ebnf-node-height except)
4076 (ebnf-node-width except)
4077 (+ width
4078 ebnf-space-E ebnf-space-E ebnf-space-E
4079 ebnf-font-width-E
4080 (if exception
4081 (+ (ebnf-node-width exception) ebnf-space-E)
4082 0.0)))
4083 " " ebnf-direction "EX\n")
4084 (ebnf-node-generation (ebnf-node-list except))
4085 (when exception
4086 (ebnf-horizontal-movement (+ width ebnf-space-E
4087 ebnf-font-width-E ebnf-space-E))
4088 (ebnf-node-generation exception)))
4089 (ps-output "EOS\n"))
4090
4091
4092(defun ebnf-gen-terminal (node code)
4093 (ps-output-string (ebnf-node-name node))
4094 (ps-output " " (ebnf-format-float (ebnf-node-width node))
4095 " " ebnf-direction code
4096 (if (ebnf-node-default node)
4097 "D\n"
4098 "\n")))
4099
4100\f
4101;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4102;; Internal functions
4103
4104
6a5275dc
GM
4105;; function `ebnf-range-regexp' is used to avoid a bug of `skip-chars-forward'
4106;; on version 20.4.1, that is, it doesn't accept ranges like "\240-\377" (or
4107;; "\177-\237"), but it accepts the character sequence from \240 to \377 (or
4108;; from \177 to \237). It seems that version 20.7 has the same problem.
4109(defun ebnf-range-regexp (prefix from to)
4110 (let (str)
4111 (while (<= from to)
4112 (setq str (concat str (char-to-string from))
4113 from (1+ from)))
4114 (concat prefix str)))
4115
4116
984ae001
GM
4117(defvar ebnf-map-name
4118 (let ((map (make-vector 256 ?\_)))
4119 (mapcar #'(lambda (char)
4120 (aset map char char))
4121 (concat "#$%&+-.0123456789=?@~"
4122 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
4123 "abcdefghijklmnopqrstuvwxyz"))
4124 map))
4125
4126
4127(defun ebnf-eps-filename (str)
4128 (let* ((len (length str))
4129 (stri 0)
4130 (new (make-string len ?\ )))
4131 (while (< stri len)
4132 (aset new stri (aref ebnf-map-name (aref str stri)))
4133 (setq stri (1+ stri)))
4134 (concat ebnf-eps-prefix new ".eps")))
4135
4136
4137(defun ebnf-eps-output (&rest args)
4138 (while args
4139 (insert (car args))
4140 (setq args (cdr args))))
4141
4142
4143(defun ebnf-generate-region (from to gen-func)
4144 (run-hooks 'ebnf-hook)
4145 (let ((ebnf-limit (max from to))
4146 the-point)
4147 (save-excursion
4148 (save-restriction
4149 (save-match-data
4150 (condition-case data
4151 (let ((tree (ebnf-parse-and-sort (min from to))))
4152 (when gen-func
4153 (funcall gen-func
4154 (ebnf-dimensions
4155 (ebnf-optimize
4156 (ebnf-eliminate-empty-rules tree))))))
4157 ;; handler
4158 ((quit error)
4159 (ding)
4160 (setq the-point (max (1- (point)) (point-min)))
4161 (message (error-message-string data)))))))
4162 (cond
4163 (the-point
4164 (goto-char the-point))
4165 (gen-func
4166 nil)
4167 (t
ab3256ed 4168 (message "EBNF syntactic analysis: NO ERRORS.")))))
984ae001
GM
4169
4170
4171(defun ebnf-parse-and-sort (start)
4172 (ebnf-begin-job)
4173 (let ((tree (funcall ebnf-parser-func start)))
4174 (if ebnf-sort-production
4175 (progn
4176 (message "Sorting...")
4177 (sort tree
4178 (if (eq ebnf-sort-production 'ascending)
4179 'ebnf-sorter-ascending
4180 'ebnf-sorter-descending)))
4181 (nreverse tree))))
4182
4183
4184(defun ebnf-sorter-ascending (first second)
4185 (string< (ebnf-node-name first)
4186 (ebnf-node-name second)))
4187
4188
4189(defun ebnf-sorter-descending (first second)
4190 (string< (ebnf-node-name second)
4191 (ebnf-node-name first)))
4192
4193
4194(defun ebnf-empty-alternative (width)
4195 (ps-output (ebnf-format-float width) " EA\n"))
4196
4197
4198(defun ebnf-vertical-movement (height)
4199 (ps-output (ebnf-format-float height) " vm\n"))
4200
4201
4202(defun ebnf-horizontal-movement (width)
4203 (ps-output (ebnf-format-float width) " hm\n"))
4204
4205
4206(defun ebnf-entry (height)
4207 (* height ebnf-entry-percentage))
4208
4209
4210(defun ebnf-eop-vertical (height)
4211 (ps-output (ebnf-format-float (+ height ebnf-production-vertical-space))
4212 " EOPV\n\n"))
4213
4214
4215(defun ebnf-eop-horizontal (width)
4216 (ps-output (ebnf-format-float (+ width ebnf-production-horizontal-space))
4217 " EOPH\n\n"))
4218
4219
4220(defun ebnf-new-page ()
4221 (when (< ps-height-remaining ps-print-height)
4222 (run-hooks 'ebnf-page-hook)
4223 (ps-next-page)
4224 (ps-output "\n")))
4225
4226
4227(defsubst ebnf-font-size (font) (nth 0 font))
4228(defsubst ebnf-font-name (font) (nth 1 font))
4229(defsubst ebnf-font-foreground (font) (nth 2 font))
4230(defsubst ebnf-font-background (font) (nth 3 font))
4231(defsubst ebnf-font-list (font) (nthcdr 4 font))
4232(defsubst ebnf-font-attributes (font)
4233 (lsh (ps-extension-bit (cdr font)) -2))
4234
4235
4236(defconst ebnf-font-name-select
4237 (vector 'normal 'bold 'italic 'bold-italic))
4238
4239
4240(defun ebnf-font-name-select (font)
4241 (let* ((font-list (ebnf-font-list font))
4242 (font-index (+ (if (memq 'bold font-list) 1 0)
4243 (if (memq 'italic font-list) 2 0)))
4244 (name (ebnf-font-name font))
4245 (database (cdr (assoc name ps-font-info-database)))
4246 (info-list (or (cdr (assoc 'fonts database))
4247 (error "Invalid font: %s" name))))
4248 (or (cdr (assoc (aref ebnf-font-name-select font-index)
4249 info-list))
4250 (error "Invalid attributes for font %s" name))))
4251
4252
4253(defun ebnf-font-select (font select)
4254 (let* ((name (ebnf-font-name font))
4255 (database (cdr (assoc name ps-font-info-database)))
4256 (size (cdr (assoc 'size database)))
4257 (base (cdr (assoc select database))))
4258 (if (and size base)
4259 (/ (* (ebnf-font-size font) base)
4260 size)
4261 (error "Invalid font: %s" name))))
4262
4263
4264(defsubst ebnf-font-width (font)
4265 (ebnf-font-select font 'avg-char-width))
4266(defsubst ebnf-font-height (font)
4267 (ebnf-font-select font 'line-height))
4268
4269
4270(defun ebnf-begin-job ()
ae6f46f9 4271 (ps-printing-region nil nil nil)
984ae001
GM
4272 (if ebnf-use-float-format
4273 (setq ebnf-format-float "%1.3f"
4274 ebnf-message-float "%3.2f")
4275 (setq ebnf-format-float "%s"
4276 ebnf-message-float "%s"))
4277 (ebnf-otz-initialize)
4278 ;; to avoid compilation gripes when calling autoloaded functions
4279 (funcall (cond ((eq ebnf-syntax 'iso-ebnf)
4280 (setq ebnf-parser-func 'ebnf-iso-parser)
4281 'ebnf-iso-initialize)
4282 ((eq ebnf-syntax 'yacc)
4283 (setq ebnf-parser-func 'ebnf-yac-parser)
4284 'ebnf-yac-initialize)
4285 (t
4286 (setq ebnf-parser-func 'ebnf-bnf-parser)
4287 'ebnf-bnf-initialize)))
4288 (and ebnf-terminal-regexp ; ensures that it's a string or nil
4289 (not (stringp ebnf-terminal-regexp))
4290 (setq ebnf-terminal-regexp nil))
4291 (or (and ebnf-eps-prefix ; ensures that it's a string
4292 (stringp ebnf-eps-prefix))
4293 (setq ebnf-eps-prefix "ebnf--"))
4294 (setq ebnf-entry-percentage ; ensures value between 0.0 and 1.0
4295 (min (max ebnf-entry-percentage 0.0) 1.0)
4296 ebnf-action-list (if ebnf-horizontal-orientation
4297 '(nil keep-line)
4298 '(keep-line))
4299 ebnf-settings nil
4300 ebnf-fonts-required nil
4301 ebnf-action nil
4302 ebnf-default-p nil
4303 ebnf-eps-context nil
4304 ebnf-eps-production-list nil
4305 ebnf-eps-upper-x 0.0
4306 ebnf-eps-upper-y 0.0
4307 ebnf-font-height-P (ebnf-font-height ebnf-production-font)
4308 ebnf-font-height-T (ebnf-font-height ebnf-terminal-font)
4309 ebnf-font-height-NT (ebnf-font-height ebnf-non-terminal-font)
4310 ebnf-font-height-S (ebnf-font-height ebnf-special-font)
4311 ebnf-font-height-E (ebnf-font-height ebnf-except-font)
4312 ebnf-font-height-R (ebnf-font-height ebnf-repeat-font)
4313 ebnf-font-width-P (ebnf-font-width ebnf-production-font)
4314 ebnf-font-width-T (ebnf-font-width ebnf-terminal-font)
4315 ebnf-font-width-NT (ebnf-font-width ebnf-non-terminal-font)
4316 ebnf-font-width-S (ebnf-font-width ebnf-special-font)
4317 ebnf-font-width-E (ebnf-font-width ebnf-except-font)
4318 ebnf-font-width-R (ebnf-font-width ebnf-repeat-font)
4319 ebnf-space-T (* ebnf-font-height-T 0.5)
4320 ebnf-space-NT (* ebnf-font-height-NT 0.5)
4321 ebnf-space-S (* ebnf-font-height-S 0.5)
4322 ebnf-space-E (* ebnf-font-height-E 0.5)
4323 ebnf-space-R (* ebnf-font-height-R 0.5))
4324 (let ((basic (+ ebnf-font-height-T ebnf-font-height-NT)))
4325 (setq ebnf-basic-width (* basic 0.5)
4326 ebnf-horizontal-space (+ basic basic)
4327 ebnf-basic-height ebnf-basic-width
4328 ebnf-vertical-space ebnf-basic-width)
4329 ;; ensures value is greater than zero
4330 (or (and (numberp ebnf-production-horizontal-space)
4331 (> ebnf-production-horizontal-space 0.0))
4332 (setq ebnf-production-horizontal-space basic))
4333 ;; ensures value is greater than zero
4334 (or (and (numberp ebnf-production-vertical-space)
4335 (> ebnf-production-vertical-space 0.0))
4336 (setq ebnf-production-vertical-space basic))))
4337
4338
4339(defsubst ebnf-shape-value (sym alist)
4340 (or (cdr (assq sym alist)) 0))
4341
4342
4343(defsubst ebnf-boolean (value)
4344 (if value "true" "false"))
4345
4346
4347(defun ebnf-begin-file ()
4348 (ps-flush-output)
4349 (save-excursion
4350 (set-buffer ps-spool-buffer)
4351 (goto-char (point-min))
4352 (and (search-forward "%%Creator: " nil t)
4353 (not (search-forward "& ebnf2ps v"
4354 (save-excursion (end-of-line) (point))
4355 t))
4356 (progn
4357 ;; adjust creator comment
4358 (end-of-line)
4359 (backward-char)
4360 (insert " & ebnf2ps v" ebnf-version)
4361 ;; insert ebnf settings & engine
4362 (goto-char (point-max))
0b5ecd6d 4363 (search-backward "\n%%EndProlog\n")
984ae001
GM
4364 (ebnf-insert-ebnf-prologue)
4365 (ps-output "\n")))))
4366
4367
4368(defun ebnf-eps-finish-and-write (buffer filename)
4369 (save-excursion
4370 (set-buffer buffer)
4371 (setq ebnf-eps-upper-x (max ebnf-eps-upper-x ebnf-eps-max-width)
4372 ebnf-eps-upper-y (if (zerop ebnf-eps-upper-y)
4373 ebnf-eps-max-height
4374 (+ ebnf-eps-upper-y
4375 ebnf-production-vertical-space
4376 ebnf-eps-max-height)))
4377 ;; prologue
4378 (goto-char (point-min))
4379 (insert
4380 "%!PS-Adobe-3.0 EPSF-3.0"
4381 "\n%%BoundingBox: 0 0 "
4382 (format "%d %d" (1+ ebnf-eps-upper-x) (1+ ebnf-eps-upper-y))
4383 "\n%%Title: " filename
01d19dd7 4384 "\n%%CreationDate: " (format-time-string "%T %b %d %Y")
984ae001
GM
4385 "\n%%Creator: " (user-full-name) " (using ebnf2ps v" ebnf-version ")"
4386 "\n%%DocumentNeededResources: font "
4387 (or ebnf-fonts-required
4388 (setq ebnf-fonts-required
bf061ba6
GM
4389 (mapconcat 'identity
4390 (ps-remove-duplicates
4391 (mapcar 'ebnf-font-name-select
4392 (list ebnf-production-font
4393 ebnf-terminal-font
4394 ebnf-non-terminal-font
4395 ebnf-special-font
4396 ebnf-except-font
4397 ebnf-repeat-font)))
4398 "\n%%+ font ")))
0b5ecd6d 4399 "\n%%Pages: 0\n%%EndComments\n\n%%BeginProlog\n"
984ae001
GM
4400 ebnf-eps-prologue)
4401 (ebnf-insert-ebnf-prologue)
4402 (insert ebnf-eps-begin
4403 "\n0 " (ebnf-format-float
4404 (- ebnf-eps-upper-y (* ebnf-font-height-P 0.7)))
4405 " #ebnf2ps#begin\n")
4406 ;; epilogue
4407 (goto-char (point-max))
4408 (insert ebnf-eps-end)
4409 ;; write file
4410 (message "Saving...")
4411 (setq filename (expand-file-name filename))
4412 (let ((coding-system-for-write 'raw-text-unix))
4413 (write-region (point-min) (point-max) filename))
4414 (message "Wrote %s" filename)))
4415
4416
4417(defun ebnf-insert-ebnf-prologue ()
4418 (insert
4419 (or ebnf-settings
4420 (setq ebnf-settings
4421 (concat
4422 "\n\n% === begin EBNF settings\n\n"
4423 ;; production
4424 (format "/fP %s /%s DefFont\n"
4425 (ebnf-format-float (ebnf-font-size ebnf-production-font))
4426 (ebnf-font-name-select ebnf-production-font))
4427 (ebnf-format-color "/ForegroundP %s def %% %s\n"
4428 (ebnf-font-foreground ebnf-production-font)
4429 "Black")
4430 (ebnf-format-color "/BackgroundP %s def %% %s\n"
4431 (ebnf-font-background ebnf-production-font)
4432 "White")
4433 (format "/EffectP %d def\n"
4434 (ebnf-font-attributes ebnf-production-font))
4435 ;; terminal
4436 (format "/fT %s /%s DefFont\n"
4437 (ebnf-format-float (ebnf-font-size ebnf-terminal-font))
4438 (ebnf-font-name-select ebnf-terminal-font))
4439 (ebnf-format-color "/ForegroundT %s def %% %s\n"
4440 (ebnf-font-foreground ebnf-terminal-font)
4441 "Black")
4442 (ebnf-format-color "/BackgroundT %s def %% %s\n"
4443 (ebnf-font-background ebnf-terminal-font)
4444 "White")
4445 (format "/EffectT %d def\n"
4446 (ebnf-font-attributes ebnf-terminal-font))
4447 (format "/BorderWidthT %s def\n"
4448 (ebnf-format-float ebnf-terminal-border-width))
4449 (ebnf-format-color "/BorderColorT %s def %% %s\n"
4450 ebnf-terminal-border-color
4451 "Black")
4452 (format "/ShapeT %d def\n"
4453 (ebnf-shape-value ebnf-terminal-shape
4454 ebnf-terminal-shape-alist))
4455 (format "/ShadowT %s def\n"
4456 (ebnf-boolean ebnf-terminal-shadow))
4457 ;; non-terminal
4458 (format "/fNT %s /%s DefFont\n"
4459 (ebnf-format-float
4460 (ebnf-font-size ebnf-non-terminal-font))
4461 (ebnf-font-name-select ebnf-non-terminal-font))
4462 (ebnf-format-color "/ForegroundNT %s def %% %s\n"
4463 (ebnf-font-foreground ebnf-non-terminal-font)
4464 "Black")
4465 (ebnf-format-color "/BackgroundNT %s def %% %s\n"
4466 (ebnf-font-background ebnf-non-terminal-font)
4467 "White")
4468 (format "/EffectNT %d def\n"
4469 (ebnf-font-attributes ebnf-non-terminal-font))
4470 (format "/BorderWidthNT %s def\n"
4471 (ebnf-format-float ebnf-non-terminal-border-width))
4472 (ebnf-format-color "/BorderColorNT %s def %% %s\n"
4473 ebnf-non-terminal-border-color
4474 "Black")
4475 (format "/ShapeNT %d def\n"
4476 (ebnf-shape-value ebnf-non-terminal-shape
4477 ebnf-terminal-shape-alist))
4478 (format "/ShadowNT %s def\n"
4479 (ebnf-boolean ebnf-non-terminal-shadow))
4480 ;; special
4481 (format "/fS %s /%s DefFont\n"
4482 (ebnf-format-float (ebnf-font-size ebnf-special-font))
4483 (ebnf-font-name-select ebnf-special-font))
4484 (ebnf-format-color "/ForegroundS %s def %% %s\n"
4485 (ebnf-font-foreground ebnf-special-font)
4486 "Black")
4487 (ebnf-format-color "/BackgroundS %s def %% %s\n"
4488 (ebnf-font-background ebnf-special-font)
4489 "Gray95")
4490 (format "/EffectS %d def\n"
4491 (ebnf-font-attributes ebnf-special-font))
4492 (format "/BorderWidthS %s def\n"
4493 (ebnf-format-float ebnf-special-border-width))
4494 (ebnf-format-color "/BorderColorS %s def %% %s\n"
4495 ebnf-special-border-color
4496 "Black")
4497 (format "/ShapeS %d def\n"
4498 (ebnf-shape-value ebnf-special-shape
4499 ebnf-terminal-shape-alist))
4500 (format "/ShadowS %s def\n"
4501 (ebnf-boolean ebnf-special-shadow))
4502 ;; except
4503 (format "/fE %s /%s DefFont\n"
4504 (ebnf-format-float (ebnf-font-size ebnf-except-font))
4505 (ebnf-font-name-select ebnf-except-font))
4506 (ebnf-format-color "/ForegroundE %s def %% %s\n"
4507 (ebnf-font-foreground ebnf-except-font)
4508 "Black")
4509 (ebnf-format-color "/BackgroundE %s def %% %s\n"
4510 (ebnf-font-background ebnf-except-font)
4511 "Gray90")
4512 (format "/EffectE %d def\n"
4513 (ebnf-font-attributes ebnf-except-font))
4514 (format "/BorderWidthE %s def\n"
4515 (ebnf-format-float ebnf-except-border-width))
4516 (ebnf-format-color "/BorderColorE %s def %% %s\n"
4517 ebnf-except-border-color
4518 "Black")
4519 (format "/ShapeE %d def\n"
4520 (ebnf-shape-value ebnf-except-shape
4521 ebnf-terminal-shape-alist))
4522 (format "/ShadowE %s def\n"
4523 (ebnf-boolean ebnf-except-shadow))
4524 ;; repeat
4525 (format "/fR %s /%s DefFont\n"
4526 (ebnf-format-float (ebnf-font-size ebnf-repeat-font))
4527 (ebnf-font-name-select ebnf-repeat-font))
4528 (ebnf-format-color "/ForegroundR %s def %% %s\n"
4529 (ebnf-font-foreground ebnf-repeat-font)
4530 "Black")
4531 (ebnf-format-color "/BackgroundR %s def %% %s\n"
4532 (ebnf-font-background ebnf-repeat-font)
4533 "Gray85")
4534 (format "/EffectR %d def\n"
4535 (ebnf-font-attributes ebnf-repeat-font))
4536 (format "/BorderWidthR %s def\n"
4537 (ebnf-format-float ebnf-repeat-border-width))
4538 (ebnf-format-color "/BorderColorR %s def %% %s\n"
4539 ebnf-repeat-border-color
4540 "Black")
4541 (format "/ShapeR %d def\n"
4542 (ebnf-shape-value ebnf-repeat-shape
4543 ebnf-terminal-shape-alist))
4544 (format "/ShadowR %s def\n"
4545 (ebnf-boolean ebnf-repeat-shadow))
4546 ;; miscellaneous
4547 (format "/DefaultWidth %s def\n"
4548 (ebnf-format-float ebnf-default-width))
4549 (format "/LineWidth %s def\n"
4550 (ebnf-format-float ebnf-line-width))
4551 (ebnf-format-color "/LineColor %s def %% %s\n"
4552 ebnf-line-color
4553 "Black")
4554 (format "/ArrowShape %d def\n"
4555 (ebnf-shape-value ebnf-arrow-shape
4556 ebnf-arrow-shape-alist))
4557 (format "/ChartShape %d def\n"
4558 (ebnf-shape-value ebnf-chart-shape
4559 ebnf-terminal-shape-alist))
4560 (format "/UserArrow{%s}def\n"
bf061ba6
GM
4561 (let ((arrow (eval ebnf-user-arrow)))
4562 (if (stringp arrow)
4563 arrow
4564 "")))
984ae001
GM
4565 "\n% === end EBNF settings\n\n"
4566 (and ebnf-debug-ps ebnf-debug))))
4567 ebnf-prologue))
4568
984ae001
GM
4569\f
4570;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4571;; Adjusting dimensions
4572
4573
4574(defun ebnf-dimensions (tree)
4575 (let ((ebnf-total (length tree))
4576 (ebnf-nprod 0))
4577 (mapcar 'ebnf-production-dimension tree))
4578 tree)
4579
4580
4581;; [empty width-fun dim-fun entry height width]
4582;;(defun ebnf-empty-dimension (empty)
4583;; )
4584
4585
4586;; [production width-fun dim-fun entry height width name production action]
4587(defun ebnf-production-dimension (production)
4588 (ebnf-message-info "Calculating dimensions")
4589 (ebnf-node-dimension-func (ebnf-node-production production))
4590 (let* ((prod (ebnf-node-production production))
4591 (height (+ ebnf-font-height-P
4592 ebnf-basic-height
4593 (ebnf-node-height prod))))
4594 (ebnf-node-entry production height)
4595 (ebnf-node-height production height)
4596 (ebnf-node-width production (+ (ebnf-node-width prod)
4597 ebnf-horizontal-space))))
4598
4599
4600;; [terminal width-fun dim-fun entry height width name]
4601(defun ebnf-terminal-dimension (terminal)
4602 (ebnf-terminal-dimension1 terminal
4603 ebnf-font-height-T
4604 ebnf-font-width-T
4605 ebnf-space-T))
4606
4607
4608;; [non-terminal width-fun dim-fun entry height width name]
4609(defun ebnf-non-terminal-dimension (non-terminal)
4610 (ebnf-terminal-dimension1 non-terminal
4611 ebnf-font-height-NT
4612 ebnf-font-width-NT
4613 ebnf-space-NT))
4614
4615
4616;; [special width-fun dim-fun entry height width name]
4617(defun ebnf-special-dimension (special)
4618 (ebnf-terminal-dimension1 special
4619 ebnf-font-height-S
4620 ebnf-font-width-S
4621 ebnf-space-S))
4622
4623
4624(defun ebnf-terminal-dimension1 (node font-height font-width space)
4625 (let ((height (+ space font-height space))
4626 (len (length (ebnf-node-name node))))
4627 (ebnf-node-entry node (* height 0.5))
4628 (ebnf-node-height node height)
4629 (ebnf-node-width node (+ ebnf-basic-width space
4630 (* len font-width)
4631 space ebnf-basic-width))))
4632
4633
4634(defconst ebnf-null-vector (vector t t t 0.0 0.0 0.0))
4635
4636
4637;; [repeat width-fun dim-fun entry height width times element]
4638(defun ebnf-repeat-dimension (repeat)
4639 (let ((times (ebnf-node-name repeat))
4640 (element (ebnf-node-separator repeat)))
4641 (if element
4642 (ebnf-node-dimension-func element)
4643 (setq element ebnf-null-vector))
4644 (ebnf-node-entry repeat (+ (ebnf-node-entry element)
4645 ebnf-space-R))
4646 (ebnf-node-height repeat (+ (max (ebnf-node-height element)
4647 ebnf-font-height-S)
4648 ebnf-space-R ebnf-space-R))
4649 (ebnf-node-width repeat (+ (ebnf-node-width element)
4650 ebnf-space-R ebnf-space-R ebnf-space-R
4651 ebnf-horizontal-space
4652 (* (length times) ebnf-font-width-R)))))
4653
4654
4655;; [except width-fun dim-fun entry height width element element]
4656(defun ebnf-except-dimension (except)
4657 (let ((factor (ebnf-node-list except))
4658 (element (ebnf-node-separator except)))
4659 (ebnf-node-dimension-func factor)
4660 (if element
4661 (ebnf-node-dimension-func element)
4662 (setq element ebnf-null-vector))
4663 (ebnf-node-entry except (+ (max (ebnf-node-entry factor)
4664 (ebnf-node-entry element))
4665 ebnf-space-E))
4666 (ebnf-node-height except (+ (max (ebnf-node-height factor)
4667 (ebnf-node-height element))
4668 ebnf-space-E ebnf-space-E))
4669 (ebnf-node-width except (+ (ebnf-node-width factor)
4670 (ebnf-node-width element)
4671 ebnf-space-E ebnf-space-E
4672 ebnf-space-E ebnf-space-E
4673 ebnf-font-width-E
4674 ebnf-horizontal-space))))
4675
4676
4677;; [alternative width-fun dim-fun entry height width list]
4678(defun ebnf-alternative-dimension (alternative)
4679 (let ((body (ebnf-node-list alternative))
4680 (lis (ebnf-node-list alternative)))
4681 (while lis
4682 (ebnf-node-dimension-func (car lis))
4683 (setq lis (cdr lis)))
4684 (let ((height 0.0)
4685 (width 0.0)
4686 (alt body)
4687 (tail (car (last body)))
4688 (entry (ebnf-node-entry (car body)))
4689 node)
4690 (while alt
4691 (setq node (car alt)
4692 alt (cdr alt)
4693 height (+ (ebnf-node-height node) height)
4694 width (max (ebnf-node-width node) width)))
4695 (ebnf-adjust-width body width)
4696 (setq height (+ height (* (1- (length body)) ebnf-vertical-space)))
4697 (ebnf-node-entry alternative (+ entry
4698 (ebnf-entry
4699 (- height entry
4700 (- (ebnf-node-height tail)
4701 (ebnf-node-entry tail))))))
4702 (ebnf-node-height alternative height)
4703 (ebnf-node-width alternative (+ width ebnf-horizontal-space))
4704 (ebnf-node-list alternative body))))
4705
4706
4707;; [optional width-fun dim-fun entry height width element]
4708(defun ebnf-optional-dimension (optional)
4709 (let ((body (ebnf-node-list optional)))
4710 (ebnf-node-dimension-func body)
4711 (ebnf-node-entry optional (ebnf-node-entry body))
4712 (ebnf-node-height optional (+ (ebnf-node-height body)
4713 ebnf-vertical-space))
4714 (ebnf-node-width optional (+ (ebnf-node-width body)
4715 ebnf-horizontal-space))))
4716
4717
4718;; [one-or-more width-fun dim-fun entry height width element separator]
4719(defun ebnf-one-or-more-dimension (or-more)
4720 (let ((list-part (ebnf-node-list or-more))
4721 (sep-part (ebnf-node-separator or-more)))
4722 (ebnf-node-dimension-func list-part)
4723 (and sep-part
4724 (ebnf-node-dimension-func sep-part))
4725 (let ((height (+ (if sep-part
4726 (ebnf-node-height sep-part)
4727 0.0)
4728 ebnf-vertical-space
4729 (ebnf-node-height list-part)))
4730 (width (max (if sep-part
4731 (ebnf-node-width sep-part)
4732 0.0)
4733 (ebnf-node-width list-part))))
4734 (when sep-part
4735 (ebnf-adjust-width list-part width)
4736 (ebnf-adjust-width sep-part width))
4737 (ebnf-node-entry or-more (+ (- height (ebnf-node-height list-part))
4738 (ebnf-node-entry list-part)))
4739 (ebnf-node-height or-more height)
4740 (ebnf-node-width or-more (+ width ebnf-horizontal-space)))))
4741
4742
4743;; [zero-or-more width-fun dim-fun entry height width element separator]
4744(defun ebnf-zero-or-more-dimension (or-more)
4745 (let ((list-part (ebnf-node-list or-more))
4746 (sep-part (ebnf-node-separator or-more)))
4747 (ebnf-node-dimension-func list-part)
4748 (and sep-part
4749 (ebnf-node-dimension-func sep-part))
4750 (let ((height (+ (if sep-part
4751 (ebnf-node-height sep-part)
4752 0.0)
4753 ebnf-vertical-space
4754 (ebnf-node-height list-part)
4755 ebnf-vertical-space))
4756 (width (max (if sep-part
4757 (ebnf-node-width sep-part)
4758 0.0)
4759 (ebnf-node-width list-part))))
4760 (when sep-part
4761 (ebnf-adjust-width list-part width)
4762 (ebnf-adjust-width sep-part width))
4763 (ebnf-node-entry or-more height)
4764 (ebnf-node-height or-more height)
4765 (ebnf-node-width or-more (+ width ebnf-horizontal-space)))))
4766
4767
4768;; [sequence width-fun dim-fun entry height width list]
4769(defun ebnf-sequence-dimension (sequence)
4770 (let ((above 0.0)
4771 (below 0.0)
4772 (width 0.0)
4773 (lis (ebnf-node-list sequence))
4774 entry node)
4775 (while lis
4776 (setq node (car lis)
4777 lis (cdr lis))
4778 (ebnf-node-dimension-func node)
4779 (setq entry (ebnf-node-entry node)
4780 above (max above entry)
4781 below (max below (- (ebnf-node-height node) entry))
4782 width (+ width (ebnf-node-width node))))
4783 (ebnf-node-entry sequence above)
4784 (ebnf-node-height sequence (+ above below))
4785 (ebnf-node-width sequence width)))
4786
4787\f
4788;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4789;; Adjusting width
4790
4791
4792(defun ebnf-adjust-width (node width)
4793 (cond
4794 ((listp node)
4795 (prog1
4796 node
4797 (while node
4798 (setcar node (ebnf-adjust-width (car node) width))
4799 (setq node (cdr node)))))
4800 ((vectorp node)
4801 (cond
4802 ;; nothing to be done
4803 ((= width (ebnf-node-width node))
4804 node)
4805 ;; left justify term
4806 ((eq ebnf-justify-sequence 'left)
4807 (ebnf-adjust-empty node width nil))
4808 ;; right justify terms
4809 ((eq ebnf-justify-sequence 'right)
4810 (ebnf-adjust-empty node width t))
4811 ;; centralize terms
4812 (t
4813 (ebnf-node-width-func node width)
4814 (ebnf-node-width node width)
4815 node)
4816 ))
4817 (t
4818 node)
4819 ))
4820
4821
4822(defun ebnf-adjust-empty (node width last-p)
4823 (if (eq (ebnf-node-kind node) 'ebnf-generate-empty)
4824 (progn
4825 (ebnf-node-width node width)
4826 node)
4827 (let ((empty (ebnf-make-empty (- width (ebnf-node-width node)))))
4828 (ebnf-make-dup-sequence node
4829 (if last-p
4830 (list empty node)
4831 (list node empty))))))
4832
4833
4834;; [terminal width-fun dim-fun entry height width name]
4835;; [non-terminal width-fun dim-fun entry height width name]
4836;; [empty width-fun dim-fun entry height width]
4837;; [special width-fun dim-fun entry height width name]
4838;; [repeat width-fun dim-fun entry height width times element]
4839;; [except width-fun dim-fun entry height width element element]
4840;;(defun ebnf-terminal-width (terminal width)
4841;; )
4842
4843
4844;; [alternative width-fun dim-fun entry height width list]
4845;; [optional width-fun dim-fun entry height width element]
4846(defun ebnf-alternative-width (alternative width)
4847 (ebnf-adjust-width (ebnf-node-list alternative)
4848 (- width ebnf-horizontal-space)))
4849
4850
4851;; [one-or-more width-fun dim-fun entry height width element separator]
4852;; [zero-or-more width-fun dim-fun entry height width element separator]
4853(defun ebnf-list-width (or-more width)
4854 (setq width (- width ebnf-horizontal-space))
4855 (ebnf-node-list or-more
4856 (ebnf-justify-list or-more
4857 (ebnf-node-list or-more)
4858 width))
4859 (ebnf-node-separator or-more
4860 (ebnf-justify-list or-more
4861 (ebnf-node-separator or-more)
4862 width)))
4863
4864
4865;; [sequence width-fun dim-fun entry height width list]
4866(defun ebnf-sequence-width (sequence width)
4867 (ebnf-node-list sequence
b685181e
GM
4868 (ebnf-justify-list sequence
4869 (ebnf-node-list sequence)
4870 width)))
984ae001
GM
4871
4872
4873(defun ebnf-justify-list (node seq width)
4874 (let ((seq-width (ebnf-node-width node)))
4875 (if (= width seq-width)
4876 seq
4877 (cond
4878 ;; left justify terms
4879 ((eq ebnf-justify-sequence 'left)
4880 (ebnf-justify node seq seq-width width t))
4881 ;; right justify terms
4882 ((eq ebnf-justify-sequence 'right)
4883 (ebnf-justify node seq seq-width width nil))
4884 ;; centralize terms
4885 (t
4886 (let ((the-width (/ (- width seq-width) (length seq)))
4887 (lis seq))
4888 (while lis
4889 (ebnf-adjust-width (car lis)
4890 (+ (ebnf-node-width (car lis))
4891 the-width))
4892 (setq lis (cdr lis)))
4893 seq))
4894 ))))
4895
4896
4897(defun ebnf-justify (node seq seq-width width last-p)
4898 (let ((term (car (if last-p (last seq) seq))))
4899 (cond
4900 ;; adjust empty term
4901 ((eq (ebnf-node-kind term) 'ebnf-generate-empty)
4902 (ebnf-node-width term (+ (- width seq-width)
4903 (ebnf-node-width term)))
4904 seq)
4905 ;; insert empty at end ==> left justify
4906 (last-p
4907 (nconc seq
4908 (list (ebnf-make-empty (- width seq-width)))))
4909 ;; insert empty at beginning ==> right justify
4910 (t
4911 (cons (ebnf-make-empty (- width seq-width))
4912 seq))
4913 )))
4914
4915\f
4916;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
4917;; Functions used by parsers
4918
4919
4920(defun ebnf-eps-add-context (name)
4921 (let ((filename (ebnf-eps-filename name)))
4922 (if (member filename ebnf-eps-context)
4923 (error "Try to open an already opened EPS file: %s" filename)
4924 (setq ebnf-eps-context (cons filename ebnf-eps-context)))))
4925
4926
4927(defun ebnf-eps-remove-context (name)
4928 (let ((filename (ebnf-eps-filename name)))
4929 (if (member filename ebnf-eps-context)
4930 (setq ebnf-eps-context (delete filename ebnf-eps-context))
4931 (error "Try to close a not opened EPS file: %s" filename))))
4932
4933
4934(defun ebnf-eps-add-production (header)
4935 (and ebnf-eps-executing
4936 ebnf-eps-context
4937 (let ((prod (assoc header ebnf-eps-production-list)))
4938 (if prod
4939 (setcdr prod (append ebnf-eps-context (cdr prod)))
4940 (setq ebnf-eps-production-list
4941 (cons (cons header (ebnf-dup-list ebnf-eps-context))
4942 ebnf-eps-production-list))))))
4943
4944
4945(defun ebnf-dup-list (old)
4946 (let (new)
4947 (while old
4948 (setq new (cons (car old) new)
4949 old (cdr old)))
4950 (nreverse new)))
4951
4952
4953(defun ebnf-buffer-substring (chars)
4954 (buffer-substring-no-properties
4955 (point)
4956 (progn
4957 (skip-chars-forward chars ebnf-limit)
4958 (point))))
4959
4960
6a5275dc
GM
4961;; replace the range "\240-\377" (see `ebnf-range-regexp').
4962(defconst ebnf-8-bit-chars (ebnf-range-regexp "" ?\240 ?\377))
5268b442
GM
4963
4964
984ae001
GM
4965(defun ebnf-string (chars eos-char kind)
4966 (forward-char)
4967 (buffer-substring-no-properties
4968 (point)
4969 (progn
5268b442
GM
4970 ;;(skip-chars-forward (concat chars "\240-\377") ebnf-limit)
4971 (skip-chars-forward (concat chars ebnf-8-bit-chars) ebnf-limit)
984ae001 4972 (if (or (eobp) (/= (following-char) eos-char))
e8af40ee 4973 (error "Illegal %s: missing `%c'" kind eos-char)
984ae001
GM
4974 (forward-char)
4975 (1- (point))))))
4976
4977
4978(defun ebnf-get-string ()
4979 (forward-char)
4980 (buffer-substring-no-properties (point) (ebnf-end-of-string)))
4981
4982
4983(defun ebnf-end-of-string ()
4984 (let ((n 1))
4985 (while (> (logand n 1) 0)
4986 (skip-chars-forward "^\"" ebnf-limit)
4987 (setq n (- (skip-chars-backward "\\\\")))
4988 (goto-char (+ (point) n 1))))
4989 (if (= (preceding-char) ?\")
4990 (1- (point))
e8af40ee 4991 (error "Missing `\"'")))
984ae001
GM
4992
4993
4994(defun ebnf-trim-right (str)
4995 (let* ((len (1- (length str)))
4996 (index len))
4997 (while (and (> index 0) (= (aref str index) ?\ ))
4998 (setq index (1- index)))
4999 (if (= index len)
5000 str
5001 (substring str 0 (1+ index)))))
5002
5003\f
5004;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5005;; Vector creation
5006
5007
5008(defun ebnf-make-empty (&optional width)
5009 (vector 'ebnf-generate-empty
5010 'ignore
5011 'ignore
5012 0.0
5013 0.0
5014 (or width ebnf-horizontal-space)))
5015
5016
5017(defun ebnf-make-terminal (name)
5018 (ebnf-make-terminal1 name
5019 'ebnf-generate-terminal
5020 'ebnf-terminal-dimension))
5021
5022
5023(defun ebnf-make-non-terminal (name)
5024 (ebnf-make-terminal1 name
5025 'ebnf-generate-non-terminal
5026 'ebnf-non-terminal-dimension))
5027
5028
5029(defun ebnf-make-special (name)
5030 (ebnf-make-terminal1 name
5031 'ebnf-generate-special
5032 'ebnf-special-dimension))
5033
5034
5035(defun ebnf-make-terminal1 (name gen-func dim-func)
5036 (vector gen-func
5037 'ignore
5038 dim-func
5039 0.0
5040 0.0
5041 0.0
5042 (let ((len (length name)))
5043 (cond ((> len 2) name)
5044 ((= len 2) (concat " " name))
5045 ((= len 1) (concat " " name " "))
5046 (t " ")))
5047 ebnf-default-p))
5048
5049
5050(defun ebnf-make-one-or-more (list-part &optional sep-part)
5051 (ebnf-make-or-more1 'ebnf-generate-one-or-more
5052 'ebnf-one-or-more-dimension
5053 list-part
5054 sep-part))
5055
5056
5057(defun ebnf-make-zero-or-more (list-part &optional sep-part)
5058 (ebnf-make-or-more1 'ebnf-generate-zero-or-more
5059 'ebnf-zero-or-more-dimension
5060 list-part
5061 sep-part))
5062
5063
5064(defun ebnf-make-or-more1 (gen-func dim-func list-part sep-part)
5065 (vector gen-func
5066 'ebnf-list-width
5067 dim-func
5068 0.0
5069 0.0
5070 0.0
5071 (if (listp list-part)
5072 (ebnf-make-sequence list-part)
5073 list-part)
5074 (if (and sep-part (listp sep-part))
5075 (ebnf-make-sequence sep-part)
5076 sep-part)))
5077
5078
5079(defun ebnf-make-production (name prod action)
5080 (vector 'ebnf-generate-production
5081 'ignore
5082 'ebnf-production-dimension
5083 0.0
5084 0.0
5085 0.0
5086 name
5087 prod
5088 action))
5089
5090
5091(defun ebnf-make-alternative (body)
5092 (vector 'ebnf-generate-alternative
5093 'ebnf-alternative-width
5094 'ebnf-alternative-dimension
5095 0.0
5096 0.0
5097 0.0
5098 body))
5099
5100
5101(defun ebnf-make-optional (body)
5102 (vector 'ebnf-generate-optional
5103 'ebnf-alternative-width
5104 'ebnf-optional-dimension
5105 0.0
5106 0.0
5107 0.0
5108 body))
5109
5110
5111(defun ebnf-make-except (factor exception)
5112 (vector 'ebnf-generate-except
5113 'ignore
5114 'ebnf-except-dimension
5115 0.0
5116 0.0
5117 0.0
5118 factor
5119 exception))
5120
5121
5122(defun ebnf-make-repeat (times primary)
5123 (vector 'ebnf-generate-repeat
5124 'ignore
5125 'ebnf-repeat-dimension
5126 0.0
5127 0.0
5128 0.0
5129 (concat times " *")
5130 primary))
5131
5132
5133(defun ebnf-make-sequence (seq)
5134 (vector 'ebnf-generate-sequence
5135 'ebnf-sequence-width
5136 'ebnf-sequence-dimension
5137 0.0
5138 0.0
5139 0.0
5140 seq))
5141
5142
5143(defun ebnf-make-dup-sequence (node seq)
5144 (vector 'ebnf-generate-sequence
5145 'ebnf-sequence-width
5146 'ebnf-sequence-dimension
5147 (ebnf-node-entry node)
5148 (ebnf-node-height node)
5149 (ebnf-node-width node)
5150 seq))
5151
5152\f
5153;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5154;; Optimizers used by parsers
5155
5156
5157(defun ebnf-token-except (element exception)
5158 (cons (prog1
5159 (car exception)
5160 (setq exception (cdr exception)))
5161 (and element ; EMPTY - A ==> EMPTY
5162 (let ((kind (ebnf-node-kind element)))
5163 (cond
5164 ;; [ A ]- ==> A
5165 ((and (null exception)
5166 (eq kind 'ebnf-generate-optional))
5167 (ebnf-node-list element))
5168 ;; { A }- ==> { A }+
5169 ((and (null exception)
5170 (eq kind 'ebnf-generate-zero-or-more))
5171 (ebnf-node-kind element 'ebnf-generate-one-or-more)
5172 (ebnf-node-dimension-func element 'ebnf-one-or-more-dimension)
5173 element)
5174 ;; ( A | EMPTY )- ==> A
5175 ;; ( A | B | EMPTY )- ==> A | B
5176 ((and (null exception)
5177 (eq kind 'ebnf-generate-alternative)
b685181e
GM
5178 (eq (ebnf-node-kind
5179 (car (last (ebnf-node-list element))))
984ae001
GM
5180 'ebnf-generate-empty))
5181 (let ((elt (ebnf-node-list element))
5182 bef)
5183 (while (cdr elt)
5184 (setq bef elt
5185 elt (cdr elt)))
5186 (if (null bef)
5187 ;; this should not happen!!?!
5188 (setq element (ebnf-make-empty
5189 (ebnf-node-width element)))
5190 (setcdr bef nil)
5191 (setq elt (ebnf-node-list element))
5192 (and (= (length elt) 1)
5193 (setq element (car elt))))
5194 element))
5195 ;; A - B
5196 (t
5197 (ebnf-make-except element exception))
5198 )))))
5199
5200
5201(defun ebnf-token-repeat (times repeat)
5202 (if (null (cdr repeat))
5203 ;; n * EMPTY ==> EMPTY
5204 repeat
5205 ;; n * term
5206 (cons (car repeat)
5207 (ebnf-make-repeat times (cdr repeat)))))
5208
5209
5210(defun ebnf-token-optional (body)
5211 (let ((kind (ebnf-node-kind body)))
5212 (cond
5213 ;; [ EMPTY ] ==> EMPTY
5214 ((eq kind 'ebnf-generate-empty)
5215 nil)
5216 ;; [ { A }* ] ==> { A }*
5217 ((eq kind 'ebnf-generate-zero-or-more)
5218 body)
5219 ;; [ { A }+ ] ==> { A }*
5220 ((eq kind 'ebnf-generate-one-or-more)
5221 (ebnf-node-kind body 'ebnf-generate-zero-or-more)
5222 body)
5223 ;; [ A | B ] ==> A | B | EMPTY
5224 ((eq kind 'ebnf-generate-alternative)
5225 (ebnf-node-list body (nconc (ebnf-node-list body)
5226 (list (ebnf-make-empty))))
5227 body)
5228 ;; [ A ]
5229 (t
5230 (ebnf-make-optional body))
5231 )))
5232
5233
5234(defun ebnf-token-alternative (body sequence)
5235 (if (null body)
5236 (if (cdr sequence)
5237 sequence
5238 (cons (car sequence)
5239 (ebnf-make-empty)))
5240 (cons (car sequence)
5241 (let ((seq (cdr sequence)))
5242 (if (and (= (length body) 1) (null seq))
5243 (car body)
5244 (ebnf-make-alternative (nreverse (if seq
5245 (cons seq body)
5246 body))))))))
5247
5248\f
5249;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5250;; Variables used by parsers
5251
5252
5253(defconst ebnf-comment-table
5254 (let ((table (make-vector 256 nil)))
5255 ;; Override special comment character:
5256 (aset table ?< 'newline)
5257 (aset table ?> 'keep-line)
5258 table)
5259 "Vector used to map characters to a special comment token.")
5260
5261\f
5262;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5263;; To make this file smaller, some commands go in a separate file.
5264;; But autoload them here to make the separation invisible.
5265
5266(autoload 'ebnf-bnf-parser "ebnf-bnf"
5267 "EBNF parser.")
5268
5269(autoload 'ebnf-bnf-initialize "ebnf-bnf"
5270 "Initialize EBNF token table.")
5271
5272(autoload 'ebnf-iso-parser "ebnf-iso"
5273 "ISO EBNF parser.")
5274
5275(autoload 'ebnf-iso-initialize "ebnf-iso"
5276 "Initialize ISO EBNF token table.")
5277
5278(autoload 'ebnf-yac-parser "ebnf-yac"
5279 "Yacc/Bison parser.")
5280
5281(autoload 'ebnf-yac-initialize "ebnf-yac"
5282 "Initializations for Yacc/Bison parser.")
5283
5284(autoload 'ebnf-eliminate-empty-rules "ebnf-otz"
5285 "Eliminate empty rules.")
5286
5287(autoload 'ebnf-optimize "ebnf-otz"
ab3256ed 5288 "Syntactic chart optimizer.")
984ae001
GM
5289
5290(autoload 'ebnf-otz-initialize "ebnf-otz"
5291 "Initialize optimizer.")
5292
5293\f
5294;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
5295
5296
5297(provide 'ebnf2ps)
5298
ab5796a9 5299;;; arch-tag: 148bc8af-5398-468b-b922-eeb7afef3e4f
984ae001 5300;;; ebnf2ps.el ends here