123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700 |
- ;;; ebnf-otz.el --- syntactic chart OpTimiZer
- ;; Copyright (C) 1999-2012 Free Software Foundation, Inc.
- ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
- ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
- ;; Keywords: wp, ebnf, PostScript
- ;; Version: 1.0
- ;; Package: ebnf2ps
- ;; This file is part of GNU Emacs.
- ;; GNU Emacs is free software: you can redistribute it and/or modify
- ;; it under the terms of the GNU General Public License as published by
- ;; the Free Software Foundation, either version 3 of the License, or
- ;; (at your option) any later version.
- ;; GNU Emacs is distributed in the hope that it will be useful,
- ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ;; GNU General Public License for more details.
- ;; You should have received a copy of the GNU General Public License
- ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
- ;;; Commentary:
- ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;
- ;;
- ;; This is part of ebnf2ps package.
- ;;
- ;; This package defines an optimizer for ebnf2ps.
- ;;
- ;; See ebnf2ps.el for documentation.
- ;;
- ;;
- ;; Optimizations
- ;; -------------
- ;;
- ;;
- ;; *To be implemented*:
- ;; left recursion:
- ;; A = B | A C B | A C D. ==> A = B {C (B | D)}*.
- ;;
- ;; right recursion:
- ;; A = B | C A. ==> A = {C}* B.
- ;; A = B | D | C A | E A. ==> A = { C | E }* ( B | D ).
- ;;
- ;; optional:
- ;; A = B | C B. ==> A = [C] B.
- ;; A = B | B C. ==> A = B [C].
- ;; A = D | B D | B C D. ==> A = [B [C]] D.
- ;;
- ;;
- ;; *Already implemented*:
- ;; left recursion:
- ;; A = B | A C. ==> A = B {C}*.
- ;; A = B | A B. ==> A = {B}+.
- ;; A = | A B. ==> A = {B}*.
- ;; A = B | A C B. ==> A = {B || C}+.
- ;; A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
- ;;
- ;; optional:
- ;; A = B | . ==> A = [B].
- ;; A = | B . ==> A = [B].
- ;;
- ;; factorization:
- ;; A = B C | B D. ==> A = B (C | D).
- ;; A = C B | D B. ==> A = (C | D) B.
- ;; A = B C E | B D E. ==> A = B (C | D) E.
- ;;
- ;; none:
- ;; A = B | C | . ==> A = B | C | .
- ;; A = B | C A D. ==> A = B | C A D.
- ;;
- ;;
- ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;;; Code:
- (require 'ebnf2ps)
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (defvar ebnf-empty-rule-list nil
- "List of empty rule name.")
- (defun ebnf-add-empty-rule-list (rule)
- "Add empty RULE in `ebnf-empty-rule-list'."
- (and ebnf-ignore-empty-rule
- (eq (ebnf-node-kind (ebnf-node-production rule))
- 'ebnf-generate-empty)
- (setq ebnf-empty-rule-list (cons (ebnf-node-name rule)
- ebnf-empty-rule-list))))
- (defun ebnf-otz-initialize ()
- "Initialize optimizer."
- (setq ebnf-empty-rule-list nil))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Eliminate empty rules
- (defun ebnf-eliminate-empty-rules (syntax-list)
- "Eliminate empty rules."
- (while ebnf-empty-rule-list
- (let ((ebnf-total (length syntax-list))
- (ebnf-nprod 0)
- (prod-list syntax-list)
- new-list before)
- (while prod-list
- (ebnf-message-info "Eliminating empty rules")
- (let ((rule (car prod-list)))
- ;; if any non-terminal pertains to ebnf-empty-rule-list
- ;; then eliminate non-terminal from rule
- (if (ebnf-eliminate-empty rule)
- (setq before prod-list)
- ;; eliminate empty rule from syntax-list
- (setq new-list (cons (ebnf-node-name rule) new-list))
- (if before
- (setcdr before (cdr prod-list))
- (setq syntax-list (cdr syntax-list)))))
- (setq prod-list (cdr prod-list)))
- (setq ebnf-empty-rule-list new-list)))
- syntax-list)
- ;; [production width-func entry height width name production action]
- ;; [sequence width-func entry height width list]
- ;; [alternative width-func entry height width list]
- ;; [non-terminal width-func entry height width name default]
- ;; [empty width-func entry height width]
- ;; [terminal width-func entry height width name default]
- ;; [special width-func entry height width name default]
- (defun ebnf-eliminate-empty (rule)
- (let ((kind (ebnf-node-kind rule)))
- (cond
- ;; non-terminal
- ((eq kind 'ebnf-generate-non-terminal)
- (if (member (ebnf-node-name rule) ebnf-empty-rule-list)
- nil
- rule))
- ;; sequence
- ((eq kind 'ebnf-generate-sequence)
- (let ((seq (ebnf-node-list rule))
- (header (ebnf-node-list rule))
- before elt)
- (while seq
- (setq elt (car seq))
- (if (ebnf-eliminate-empty elt)
- (setq before seq)
- (if before
- (setcdr before (cdr seq))
- (setq header (cdr header))))
- (setq seq (cdr seq)))
- (when header
- (ebnf-node-list rule header)
- rule)))
- ;; alternative
- ((eq kind 'ebnf-generate-alternative)
- (let ((seq (ebnf-node-list rule))
- (header (ebnf-node-list rule))
- before elt)
- (while seq
- (setq elt (car seq))
- (if (ebnf-eliminate-empty elt)
- (setq before seq)
- (if before
- (setcdr before (cdr seq))
- (setq header (cdr header))))
- (setq seq (cdr seq)))
- (when header
- (if (= (length header) 1)
- (car header)
- (ebnf-node-list rule header)
- rule))))
- ;; production
- ((eq kind 'ebnf-generate-production)
- (let ((prod (ebnf-eliminate-empty (ebnf-node-production rule))))
- (when prod
- (ebnf-node-production rule prod)
- rule)))
- ;; terminal, special and empty
- (t
- rule)
- )))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- ;; Optimizations
- ;; *To be implemented*:
- ;; left recursion:
- ;; A = B | A C B | A C D. ==> A = B {C (B | D)}*.
- ;; right recursion:
- ;; A = B | C A. ==> A = {C}* B.
- ;; A = B | D | C A | E A. ==> A = { C | E }* ( B | D ).
- ;; optional:
- ;; A = B | C B. ==> A = [C] B.
- ;; A = B | B C. ==> A = B [C].
- ;; A = D | B D | B C D. ==> A = [B [C]] D.
- ;; *Already implemented*:
- ;; left recursion:
- ;; A = B | A C. ==> A = B {C}*.
- ;; A = B | A B. ==> A = {B}+.
- ;; A = | A B. ==> A = {B}*.
- ;; A = B | A C B. ==> A = {B || C}+.
- ;; A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
- ;; optional:
- ;; A = B | . ==> A = [B].
- ;; A = | B . ==> A = [B].
- ;; factorization:
- ;; A = B C | B D. ==> A = B (C | D).
- ;; A = C B | D B. ==> A = (C | D) B.
- ;; A = B C E | B D E. ==> A = B (C | D) E.
- ;; none:
- ;; A = B | C | . ==> A = B | C | .
- ;; A = B | C A D. ==> A = B | C A D.
- (defun ebnf-optimize (syntax-list)
- "Syntactic chart optimizer."
- (if (not ebnf-optimize)
- syntax-list
- (let ((ebnf-total (length syntax-list))
- (ebnf-nprod 0)
- new)
- (while syntax-list
- (setq new (cons (ebnf-optimize1 (car syntax-list)) new)
- syntax-list (cdr syntax-list)))
- (nreverse new))))
- ;; left recursion:
- ;; 1. A = B | A C. ==> A = B {C}*.
- ;; 2. A = B | A B. ==> A = {B}+.
- ;; 3. A = | A B. ==> A = {B}*.
- ;; 4. A = B | A C B. ==> A = {B || C}+.
- ;; 5. A = B | D | A C | A E. ==> A = ( B | D ) { C | E }*.
- ;; optional:
- ;; 6. A = B | . ==> A = [B].
- ;; 7. A = | B . ==> A = [B].
- ;; factorization:
- ;; 8. A = B C | B D. ==> A = B (C | D).
- ;; 9. A = C B | D B. ==> A = (C | D) B.
- ;; 10. A = B C E | B D E. ==> A = B (C | D) E.
- (defun ebnf-optimize1 (prod)
- (ebnf-message-info "Optimizing syntactic chart")
- (let ((production (ebnf-node-production prod)))
- (and (eq (ebnf-node-kind production) 'ebnf-generate-alternative)
- (let* ((hlist (ebnf-split-header-prefix
- (ebnf-node-list production)
- (ebnf-node-name prod)))
- (nlist (car hlist))
- (zlist (cdr hlist))
- (elist (ebnf-split-header-suffix nlist zlist)))
- (ebnf-node-production
- prod
- (cond
- ;; cases 2., 4.
- (elist
- (and (eq elist t)
- (setq elist nil))
- (setq elist (or (ebnf-prefix-suffix elist)
- elist))
- (let* ((nl (ebnf-extract-empty nlist))
- (el (or (ebnf-prefix-suffix (cdr nl))
- (ebnf-create-alternative (cdr nl)))))
- (if (car nl)
- (ebnf-make-zero-or-more el elist)
- (ebnf-make-one-or-more el elist))))
- ;; cases 1., 3., 5.
- (zlist
- (let* ((xlist (cdr (ebnf-extract-empty zlist)))
- (znode (ebnf-make-zero-or-more
- (or (ebnf-prefix-suffix xlist)
- (ebnf-create-alternative xlist))))
- (nnode (ebnf-map-list-to-optional nlist)))
- (and nnode
- (setq nlist (list nnode)))
- (if (or (null nlist)
- (and (= (length nlist) 1)
- (eq (ebnf-node-kind (car nlist))
- 'ebnf-generate-empty)))
- znode
- (ebnf-make-sequence
- (list (or (ebnf-prefix-suffix nlist)
- (ebnf-create-alternative nlist))
- znode)))))
- ;; cases 6., 7.
- ((ebnf-map-node-to-optional production)
- )
- ;; cases 8., 9., 10.
- ((ebnf-prefix-suffix nlist)
- )
- ;; none
- (t
- production)
- ))))
- prod))
- (defun ebnf-split-header-prefix (node-list header)
- (let* ((hlist (ebnf-split-header-prefix1 node-list header))
- (nlist (car hlist))
- zlist empty-p)
- (while (setq hlist (cdr hlist))
- (let ((elt (car hlist)))
- (if (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
- (setq zlist (cons
- (let ((seq (cdr (ebnf-node-list elt))))
- (if (= (length seq) 1)
- (car seq)
- (ebnf-node-list elt seq)
- elt))
- zlist))
- (setq empty-p t))))
- (and empty-p
- (setq zlist (cons (ebnf-make-empty)
- zlist)))
- (cons nlist (nreverse zlist))))
- (defun ebnf-split-header-prefix1 (node-list header)
- (let (hlist nlist)
- (while node-list
- (if (ebnf-node-equal-header (car node-list) header)
- (setq hlist (cons (car node-list) hlist))
- (setq nlist (cons (car node-list) nlist)))
- (setq node-list (cdr node-list)))
- (cons (nreverse nlist) (nreverse hlist))))
- (defun ebnf-node-equal-header (node header)
- (let ((kind (ebnf-node-kind node)))
- (cond
- ((eq kind 'ebnf-generate-sequence)
- (ebnf-node-equal-header (car (ebnf-node-list node)) header))
- ((eq kind 'ebnf-generate-non-terminal)
- (string= (ebnf-node-name node) header))
- (t
- nil)
- )))
- (defun ebnf-map-node-to-optional (node)
- (and (eq (ebnf-node-kind node) 'ebnf-generate-alternative)
- (ebnf-map-list-to-optional (ebnf-node-list node))))
- (defun ebnf-map-list-to-optional (nlist)
- (and (= (length nlist) 2)
- (let ((first (nth 0 nlist))
- (second (nth 1 nlist)))
- (cond
- ;; empty second
- ((eq (ebnf-node-kind first) 'ebnf-generate-empty)
- (ebnf-make-optional second))
- ;; first empty
- ((eq (ebnf-node-kind second) 'ebnf-generate-empty)
- (ebnf-make-optional first))
- ;; first second
- (t
- nil)
- ))))
- (defun ebnf-extract-empty (elist)
- (let ((now elist)
- before empty-p)
- (while now
- (if (not (eq (ebnf-node-kind (car now)) 'ebnf-generate-empty))
- (setq before now)
- (setq empty-p t)
- (if before
- (setcdr before (cdr now))
- (setq elist (cdr elist))))
- (setq now (cdr now)))
- (cons empty-p elist)))
- (defun ebnf-split-header-suffix (nlist zlist)
- (let (new empty-p)
- (and (cond
- ((= (length nlist) 1)
- (let ((ok t)
- (elt (car nlist)))
- (while (and ok zlist)
- (setq ok (ebnf-split-header-suffix1 elt (car zlist))
- zlist (cdr zlist))
- (if (eq ok t)
- (setq empty-p t)
- (setq new (cons ok new))))
- ok))
- ((= (length nlist) (length zlist))
- (let ((ok t))
- (while (and ok zlist)
- (setq ok (ebnf-split-header-suffix1 (car nlist) (car zlist))
- nlist (cdr nlist)
- zlist (cdr zlist))
- (if (eq ok t)
- (setq empty-p t)
- (setq new (cons ok new))))
- ok))
- (t
- nil)
- )
- (let* ((lis (ebnf-unique-list new))
- (len (length lis)))
- (cond
- ((zerop len)
- t)
- ((= len 1)
- (setq lis (car lis))
- (if empty-p
- (ebnf-make-optional lis)
- lis))
- (t
- (and empty-p
- (setq lis (cons (ebnf-make-empty) lis)))
- (ebnf-create-alternative (nreverse lis)))
- )))))
- (defun ebnf-split-header-suffix1 (ne ze)
- (cond
- ((eq (ebnf-node-kind ne) 'ebnf-generate-sequence)
- (and (eq (ebnf-node-kind ze) 'ebnf-generate-sequence)
- (let ((nl (ebnf-node-list ne))
- (zl (ebnf-node-list ze))
- len z)
- (and (>= (length zl) (length nl))
- (let ((ok t))
- (setq len (- (length zl) (length nl))
- z (nthcdr len zl))
- (while (and ok z)
- (setq ok (ebnf-node-equal (car z) (car nl))
- z (cdr z)
- nl (cdr nl)))
- ok)
- (if (zerop len)
- t
- (setcdr (nthcdr (1- len) zl) nil)
- ze)))))
- ((eq (ebnf-node-kind ze) 'ebnf-generate-sequence)
- (let* ((zl (ebnf-node-list ze))
- (len (length zl)))
- (and (ebnf-node-equal ne (car (nthcdr (1- len) zl)))
- (cond
- ((= len 1)
- t)
- ((= len 2)
- (car zl))
- (t
- (setcdr (nthcdr (- len 2) zl) nil)
- ze)
- ))))
- (t
- (ebnf-node-equal ne ze))
- ))
- (defun ebnf-prefix-suffix (lis)
- (and lis (listp lis)
- (let* ((prefix (ebnf-split-prefix lis))
- (suffix (ebnf-split-suffix (cdr prefix)))
- (middle (cdr suffix)))
- (setq prefix (car prefix)
- suffix (car suffix))
- (and (or prefix suffix)
- (ebnf-make-sequence
- (nconc prefix
- (and middle
- (list (or (ebnf-map-list-to-optional middle)
- (ebnf-create-alternative middle))))
- suffix))))))
- (defun ebnf-split-prefix (lis)
- (let* ((len (length lis))
- (tail lis)
- (head (if (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence)
- (ebnf-node-list (car lis))
- (list (car lis))))
- (ipre (1+ len)))
- ;; determine prefix length
- (while (and (> ipre 0) (setq tail (cdr tail)))
- (let ((cur head)
- (this (if (eq (ebnf-node-kind (car tail)) 'ebnf-generate-sequence)
- (ebnf-node-list (car tail))
- (list (car tail))))
- (i 0))
- (while (and cur this
- (ebnf-node-equal (car cur) (car this)))
- (setq cur (cdr cur)
- this (cdr this)
- i (1+ i)))
- (setq ipre (min ipre i))))
- (if (or (zerop ipre) (> ipre len))
- ;; no prefix at all
- (cons nil lis)
- (let* ((tail (nthcdr ipre head))
- ;; get prefix
- (prefix (progn
- (and tail
- (setcdr (nthcdr (1- ipre) head) nil))
- head))
- empty-p before)
- ;; adjust first element
- (if (or (not (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence))
- (null tail))
- (setq lis (cdr lis)
- tail lis
- empty-p t)
- (if (= (length tail) 1)
- (setcar lis (car tail))
- (ebnf-node-list (car lis) tail))
- (setq tail (cdr lis)))
- ;; eliminate prefix from lis based on ipre
- (while tail
- (let ((elt (car tail))
- rest)
- (if (and (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
- (setq rest (nthcdr ipre (ebnf-node-list elt))))
- (progn
- (if (= (length rest) 1)
- (setcar tail (car rest))
- (ebnf-node-list elt rest))
- (setq before tail))
- (setq empty-p t)
- (if before
- (setcdr before (cdr tail))
- (setq lis (cdr lis))))
- (setq tail (cdr tail))))
- (cons prefix (ebnf-unique-list
- (if empty-p
- (nconc lis (list (ebnf-make-empty)))
- lis)))))))
- (defun ebnf-split-suffix (lis)
- (let* ((len (length lis))
- (tail lis)
- (head (nreverse
- (if (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence)
- (ebnf-node-list (car lis))
- (list (car lis)))))
- (isuf (1+ len)))
- ;; determine suffix length
- (while (and (> isuf 0) (setq tail (cdr tail)))
- (let* ((cur head)
- (tlis (nreverse
- (if (eq (ebnf-node-kind (car tail)) 'ebnf-generate-sequence)
- (ebnf-node-list (car tail))
- (list (car tail)))))
- (this tlis)
- (i 0))
- (while (and cur this
- (ebnf-node-equal (car cur) (car this)))
- (setq cur (cdr cur)
- this (cdr this)
- i (1+ i)))
- (nreverse tlis)
- (setq isuf (min isuf i))))
- (setq head (nreverse head))
- (if (or (zerop isuf) (> isuf len))
- ;; no suffix at all
- (cons nil lis)
- (let* ((n (- (length head) isuf))
- ;; get suffix
- (suffix (nthcdr n head))
- (tail (and (> n 0)
- (progn
- (setcdr (nthcdr (1- n) head) nil)
- head)))
- before empty-p)
- ;; adjust first element
- (if (or (not (eq (ebnf-node-kind (car lis)) 'ebnf-generate-sequence))
- (null tail))
- (setq lis (cdr lis)
- tail lis
- empty-p t)
- (if (= (length tail) 1)
- (setcar lis (car tail))
- (ebnf-node-list (car lis) tail))
- (setq tail (cdr lis)))
- ;; eliminate suffix from lis based on isuf
- (while tail
- (let ((elt (car tail))
- rest)
- (if (and (eq (ebnf-node-kind elt) 'ebnf-generate-sequence)
- (setq rest (ebnf-node-list elt)
- n (- (length rest) isuf))
- (> n 0))
- (progn
- (if (= n 1)
- (setcar tail (car rest))
- (setcdr (nthcdr (1- n) rest) nil)
- (ebnf-node-list elt rest))
- (setq before tail))
- (setq empty-p t)
- (if before
- (setcdr before (cdr tail))
- (setq lis (cdr lis))))
- (setq tail (cdr tail))))
- (cons suffix (ebnf-unique-list
- (if empty-p
- (nconc lis (list (ebnf-make-empty)))
- lis)))))))
- (defun ebnf-unique-list (nlist)
- (let ((current nlist)
- before)
- (while current
- (let ((tail (cdr current))
- (head (car current))
- remove-p)
- (while tail
- (if (not (ebnf-node-equal head (car tail)))
- (setq tail (cdr tail))
- (setq remove-p t
- tail nil)
- (if before
- (setcdr before (cdr current))
- (setq nlist (cdr nlist)))))
- (or remove-p
- (setq before current))
- (setq current (cdr current))))
- nlist))
- (defun ebnf-node-equal (A B)
- (let ((kindA (ebnf-node-kind A))
- (kindB (ebnf-node-kind B)))
- (and (eq kindA kindB)
- (cond
- ;; empty
- ((eq kindA 'ebnf-generate-empty)
- t)
- ;; non-terminal, terminal, special
- ((memq kindA '(ebnf-generate-non-terminal
- ebnf-generate-terminal
- ebnf-generate-special))
- (string= (ebnf-node-name A) (ebnf-node-name B)))
- ;; alternative, sequence
- ((memq kindA '(ebnf-generate-alternative ; any order
- ebnf-generate-sequence)) ; order is important
- (let ((listA (ebnf-node-list A))
- (listB (ebnf-node-list B)))
- (and (= (length listA) (length listB))
- (let ((ok t))
- (while (and ok listA)
- (setq ok (ebnf-node-equal (car listA) (car listB))
- listA (cdr listA)
- listB (cdr listB)))
- ok))))
- ;; production
- ((eq kindA 'ebnf-generate-production)
- (and (string= (ebnf-node-name A) (ebnf-node-name B))
- (ebnf-node-equal (ebnf-node-production A)
- (ebnf-node-production B))))
- ;; otherwise
- (t
- nil)
- ))))
- (defun ebnf-create-alternative (alt)
- (if (> (length alt) 1)
- (ebnf-make-alternative alt)
- (car alt)))
- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
- (provide 'ebnf-otz)
- ;;; ebnf-otz.el ends here
|