comparison lisp/progmodes/ebnf-abn.el @ 54139:3aff710a91c0

ABNF parser (ebnf2ps)
author Vinicius Jose Latorre <viniciusjl@ig.com.br>
date Tue, 24 Feb 2004 22:58:07 +0000
parents
children 8e0088433ac7
comparison
equal deleted inserted replaced
54138:58d671d3b649 54139:3aff710a91c0
1 ;;; ebnf-abn.el --- parser for ABNF (Augmented BNF)
2
3 ;; Copyright (C) 2004 Free Sofware Foundation, Inc.
4
5 ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
6 ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
7 ;; Time-stamp: <2004/02/23 22:38:59 vinicius>
8 ;; Keywords: wp, ebnf, PostScript
9 ;; Version: 1.0
10
11 ;; This file is part of GNU Emacs.
12
13 ;; GNU Emacs is free software; you can redistribute it and/or modify
14 ;; it under the terms of the GNU General Public License as published by
15 ;; the Free Software Foundation; either version 2, or (at your option)
16 ;; any later version.
17
18 ;; GNU Emacs is distributed in the hope that it will be useful,
19 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 ;; GNU General Public License for more details.
22
23 ;; You should have received a copy of the GNU General Public License
24 ;; along with GNU Emacs; see the file COPYING. If not, write to the
25 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
26 ;; Boston, MA 02111-1307, USA.
27
28 ;;; Commentary:
29
30 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
31 ;;
32 ;;
33 ;; This is part of ebnf2ps package.
34 ;;
35 ;; This package defines a parser for ABNF (Augmented BNF).
36 ;;
37 ;; See ebnf2ps.el for documentation.
38 ;;
39 ;;
40 ;; ABNF Syntax
41 ;; -----------
42 ;;
43 ;; See the URL:
44 ;; `http://www.faqs.org/rfcs/rfc2234.html'
45 ;; or
46 ;; `http://www.rnp.br/ietf/rfc/rfc2234.txt'
47 ;; ("Augmented BNF for Syntax Specifications: ABNF").
48 ;;
49 ;;
50 ;; rulelist = 1*( rule / (*c-wsp c-nl) )
51 ;;
52 ;; rule = rulename defined-as elements c-nl
53 ;; ; continues if next line starts with white space
54 ;;
55 ;; rulename = ALPHA *(ALPHA / DIGIT / "-")
56 ;;
57 ;; defined-as = *c-wsp ("=" / "=/") *c-wsp
58 ;; ; basic rules definition and incremental
59 ;; ; alternatives
60 ;;
61 ;; elements = alternation *c-wsp
62 ;;
63 ;; c-wsp = WSP / (c-nl WSP)
64 ;;
65 ;; c-nl = comment / CRLF
66 ;; ; comment or newline
67 ;;
68 ;; comment = ";" *(WSP / VCHAR) CRLF
69 ;;
70 ;; alternation = concatenation
71 ;; *(*c-wsp "/" *c-wsp concatenation)
72 ;;
73 ;; concatenation = repetition *(1*c-wsp repetition)
74 ;;
75 ;; repetition = [repeat] element
76 ;;
77 ;; repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)
78 ;;
79 ;; element = rulename / group / option /
80 ;; char-val / num-val / prose-val
81 ;;
82 ;; group = "(" *c-wsp alternation *c-wsp ")"
83 ;;
84 ;; option = "[" *c-wsp alternation *c-wsp "]"
85 ;;
86 ;; char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
87 ;; ; quoted string of SP and VCHAR without DQUOTE
88 ;;
89 ;; num-val = "%" (bin-val / dec-val / hex-val)
90 ;;
91 ;; bin-val = "b" 1*BIT
92 ;; [ 1*("." 1*BIT) / ("-" 1*BIT) ]
93 ;; ; series of concatenated bit values
94 ;; ; or single ONEOF range
95 ;;
96 ;; dec-val = "d" 1*DIGIT
97 ;; [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
98 ;;
99 ;; hex-val = "x" 1*HEXDIG
100 ;; [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
101 ;;
102 ;; prose-val = "<" *(%x20-3D / %x3F-7E) ">"
103 ;; ; bracketed string of SP and VCHAR without
104 ;; ; angles
105 ;; ; prose description, to be used as last resort
106 ;;
107 ;; ; Core rules -- the coding depends on the system, here is used 7-bit ASCII
108 ;;
109 ;; ALPHA = %x41-5A / %x61-7A
110 ;; ; A-Z / a-z
111 ;;
112 ;; BIT = "0" / "1"
113 ;;
114 ;; CHAR = %x01-7F
115 ;; ; any 7-bit US-ASCII character, excluding NUL
116 ;;
117 ;; CR = %x0D
118 ;; ; carriage return
119 ;;
120 ;; CRLF = CR LF
121 ;; ; Internet standard newline
122 ;;
123 ;; CTL = %x00-1F / %x7F
124 ;; ; controls
125 ;;
126 ;; DIGIT = %x30-39
127 ;; ; 0-9
128 ;;
129 ;; DQUOTE = %x22
130 ;; ; " (Double Quote)
131 ;;
132 ;; HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
133 ;;
134 ;; HTAB = %x09
135 ;; ; horizontal tab
136 ;;
137 ;; LF = %x0A
138 ;; ; linefeed
139 ;;
140 ;; LWSP = *(WSP / CRLF WSP)
141 ;; ; linear white space (past newline)
142 ;;
143 ;; OCTET = %x00-FF
144 ;; ; 8 bits of data
145 ;;
146 ;; SP = %x20
147 ;; ; space
148 ;;
149 ;; VCHAR = %x21-7E
150 ;; ; visible (printing) characters
151 ;;
152 ;; WSP = SP / HTAB
153 ;; ; white space
154 ;;
155 ;;
156 ;; NOTES:
157 ;;
158 ;; 1. Rules name and terminal strings are case INSENSITIVE.
159 ;; So, the following rule names are all equals:
160 ;; Rule-name, rule-Name, rule-name, RULE-NAME
161 ;; Also, the following strings are equals:
162 ;; "abc", "ABC", "aBc", "Abc", "aBC", etc.
163 ;;
164 ;; 2. To have a case SENSITIVE string, use the character notation.
165 ;; For example, to specify the lowercase string "abc", use:
166 ;; %d97.98.99
167 ;;
168 ;; 3. There are no implicit spaces between elements, for example, the
169 ;; following rules:
170 ;;
171 ;; foo = %x61 ; a
172 ;;
173 ;; bar = %x62 ; b
174 ;;
175 ;; mumble = foo bar foo
176 ;;
177 ;; Are equivalent to the following rule:
178 ;;
179 ;; mumble = %x61.62.61
180 ;;
181 ;; If spaces are needed, it should be explicit specified, like:
182 ;;
183 ;; spaces = 1*(%x20 / %x09) ; one or more spaces or tabs
184 ;;
185 ;; mumble = foo spaces bar spaces foo
186 ;;
187 ;; 4. Lines starting with space or tab are considered a continuation line.
188 ;; For example, the rule:
189 ;;
190 ;; rule = foo
191 ;; bar
192 ;;
193 ;; Is equivalent to:
194 ;;
195 ;; rule = foo bar
196 ;;
197 ;;
198 ;; Differences Between ABNF And ebnf2ps ABNF
199 ;; -----------------------------------------
200 ;;
201 ;; Besides the characters that ABNF accepts, ebnf2ps ABNF accepts also the
202 ;; underscore (_) for rule name and european 8-bit accentuated characters (from
203 ;; \240 to \377) for rule name, string and comment.
204 ;;
205 ;;
206 ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
207
208 ;;; Code:
209
210
211 (require 'ebnf-otz)
212
213
214 (defvar ebnf-abn-lex nil
215 "Value returned by `ebnf-abn-lex' function.")
216
217
218 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
219 ;; Syntactic analyzer
220
221
222 ;;; rulelist = 1*( rule / (*c-wsp c-nl) )
223
224 (defun ebnf-abn-parser (start)
225 "ABNF parser."
226 (let ((total (+ (- ebnf-limit start) 1))
227 (bias (1- start))
228 (origin (point))
229 rule-list token rule)
230 (goto-char start)
231 (setq token (ebnf-abn-lex))
232 (and (eq token 'end-of-input)
233 (error "Invalid ABNF file format"))
234 (while (not (eq token 'end-of-input))
235 (ebnf-message-float
236 "Parsing...%s%%"
237 (/ (* (- (point) bias) 100.0) total))
238 (setq token (ebnf-abn-rule token)
239 rule (cdr token)
240 token (car token))
241 (or (ebnf-add-empty-rule-list rule)
242 (setq rule-list (cons rule rule-list))))
243 (goto-char origin)
244 rule-list))
245
246
247 ;;; rule = rulename defined-as elements c-nl
248 ;;; ; continues if next line starts with white space
249 ;;;
250 ;;; rulename = ALPHA *(ALPHA / DIGIT / "-")
251 ;;;
252 ;;; defined-as = *c-wsp ("=" / "=/") *c-wsp
253 ;;; ; basic rules definition and incremental
254 ;;; ; alternatives
255 ;;;
256 ;;; elements = alternation *c-wsp
257 ;;;
258 ;;; c-wsp = WSP / (c-nl WSP)
259 ;;;
260 ;;; c-nl = comment / CRLF
261 ;;; ; comment or newline
262 ;;;
263 ;;; comment = ";" *(WSP / VCHAR) CRLF
264
265
266 (defun ebnf-abn-rule (token)
267 (let ((name ebnf-abn-lex)
268 (action ebnf-action)
269 elements)
270 (setq ebnf-action nil)
271 (or (eq token 'non-terminal)
272 (error "Invalid rule name"))
273 (setq token (ebnf-abn-lex))
274 (or (memq token '(equal incremental-alternative))
275 (error "Invalid rule: missing `=' or `=/'"))
276 (and (eq token 'incremental-alternative)
277 (setq name (concat name " =/")))
278 (setq elements (ebnf-abn-alternation))
279 (or (memq (car elements) '(end-of-rule end-of-input))
280 (error "Invalid rule: there is no end of rule"))
281 (setq elements (cdr elements))
282 (ebnf-eps-add-production name)
283 (cons (ebnf-abn-lex)
284 (ebnf-make-production name elements action))))
285
286
287 ;;; alternation = concatenation
288 ;;; *(*c-wsp "/" *c-wsp concatenation)
289
290
291 (defun ebnf-abn-alternation ()
292 (let (body concatenation)
293 (while (eq (car (setq concatenation
294 (ebnf-abn-concatenation (ebnf-abn-lex))))
295 'alternative)
296 (setq body (cons (cdr concatenation) body)))
297 (ebnf-token-alternative body concatenation)))
298
299
300 ;;; concatenation = repetition *(1*c-wsp repetition)
301
302
303 (defun ebnf-abn-concatenation (token)
304 (let ((term (ebnf-abn-repetition token))
305 seq)
306 (or (setq token (car term)
307 term (cdr term))
308 (error "Empty element"))
309 (setq seq (cons term seq))
310 (while (setq term (ebnf-abn-repetition token)
311 token (car term)
312 term (cdr term))
313 (setq seq (cons term seq)))
314 (cons token
315 (if (= (length seq) 1)
316 ;; sequence with only one element
317 (car seq)
318 ;; a real sequence
319 (ebnf-make-sequence (nreverse seq))))))
320
321
322 ;;; repetition = [repeat] element
323 ;;;
324 ;;; repeat = 1*DIGIT / (*DIGIT "*" *DIGIT)
325
326
327 (defun ebnf-abn-repetition (token)
328 (let (lower upper)
329 ;; INTEGER [ "*" [ INTEGER ] ]
330 (when (eq token 'integer)
331 (setq lower ebnf-abn-lex
332 token (ebnf-abn-lex))
333 (or (eq token 'repeat)
334 (setq upper lower)))
335 ;; "*" [ INTEGER ]
336 (when (eq token 'repeat)
337 ;; only * ==> lower & upper are empty string
338 (or lower
339 (setq lower ""
340 upper ""))
341 (when (eq (setq token (ebnf-abn-lex)) 'integer)
342 (setq upper ebnf-abn-lex
343 token (ebnf-abn-lex))))
344 (let ((element (ebnf-abn-element token)))
345 (cond
346 ;; there is a repetition
347 (lower
348 (or element
349 (error "Missing element repetition"))
350 (setq token (ebnf-abn-lex))
351 (cond
352 ;; one or more
353 ((and (string= lower "1") (null upper))
354 (cons token (ebnf-make-one-or-more element)))
355 ;; zero or more
356 ((or (and (string= lower "0") (null upper))
357 (and (string= lower "") (string= upper "")))
358 (cons token (ebnf-make-zero-or-more element)))
359 ;; real repetition
360 (t
361 (ebnf-token-repeat lower (cons token element) upper))))
362 ;; there is an element
363 (element
364 (cons (ebnf-abn-lex) element))
365 ;; something that caller has to deal
366 (t
367 (cons token nil))))))
368
369
370 ;;; element = rulename / group / option /
371 ;;; char-val / num-val / prose-val
372 ;;;
373 ;;; group = "(" *c-wsp alternation *c-wsp ")"
374 ;;;
375 ;;; option = "[" *c-wsp alternation *c-wsp "]"
376 ;;;
377 ;;; char-val = DQUOTE *(%x20-21 / %x23-7E) DQUOTE
378 ;;; ; quoted string of SP and VCHAR without DQUOTE
379 ;;;
380 ;;; num-val = "%" (bin-val / dec-val / hex-val)
381 ;;;
382 ;;; bin-val = "b" 1*BIT
383 ;;; [ 1*("." 1*BIT) / ("-" 1*BIT) ]
384 ;;; ; series of concatenated bit values
385 ;;; ; or single ONEOF range
386 ;;;
387 ;;; dec-val = "d" 1*DIGIT
388 ;;; [ 1*("." 1*DIGIT) / ("-" 1*DIGIT) ]
389 ;;;
390 ;;; hex-val = "x" 1*HEXDIG
391 ;;; [ 1*("." 1*HEXDIG) / ("-" 1*HEXDIG) ]
392 ;;;
393 ;;; prose-val = "<" *(%x20-3D / %x3F-7E) ">"
394 ;;; ; bracketed string of SP and VCHAR without
395 ;;; ; angles
396 ;;; ; prose description, to be used as last resort
397
398
399 (defun ebnf-abn-element (token)
400 (cond
401 ;; terminal
402 ((eq token 'terminal)
403 (ebnf-make-terminal ebnf-abn-lex))
404 ;; non-terminal
405 ((eq token 'non-terminal)
406 (ebnf-make-non-terminal ebnf-abn-lex))
407 ;; group
408 ((eq token 'begin-group)
409 (let ((body (ebnf-abn-alternation)))
410 (or (eq (car body) 'end-group)
411 (error "Missing `)'"))
412 (cdr body)))
413 ;; optional
414 ((eq token 'begin-optional)
415 (let ((body (ebnf-abn-alternation)))
416 (or (eq (car body) 'end-optional)
417 (error "Missing `]'"))
418 (ebnf-token-optional (cdr body))))
419 ;; no element
420 (t
421 nil)
422 ))
423
424
425 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
426 ;; Lexical analyzer
427
428
429 (defconst ebnf-abn-token-table (make-vector 256 'error)
430 "Vector used to map characters to a lexical token.")
431
432
433 (defun ebnf-abn-initialize ()
434 "Initialize EBNF token table."
435 ;; control character & control 8-bit character are set to `error'
436 (let ((char ?\060))
437 ;; digits: 0-9
438 (while (< char ?\072)
439 (aset ebnf-abn-token-table char 'integer)
440 (setq char (1+ char)))
441 ;; printable character: A-Z
442 (setq char ?\101)
443 (while (< char ?\133)
444 (aset ebnf-abn-token-table char 'non-terminal)
445 (setq char (1+ char)))
446 ;; printable character: a-z
447 (setq char ?\141)
448 (while (< char ?\173)
449 (aset ebnf-abn-token-table char 'non-terminal)
450 (setq char (1+ char)))
451 ;; European 8-bit accentuated characters:
452 (setq char ?\240)
453 (while (< char ?\400)
454 (aset ebnf-abn-token-table char 'non-terminal)
455 (setq char (1+ char)))
456 ;; Override end of line characters:
457 (aset ebnf-abn-token-table ?\n 'end-of-rule) ; [NL] linefeed
458 (aset ebnf-abn-token-table ?\r 'end-of-rule) ; [CR] carriage return
459 ;; Override space characters:
460 (aset ebnf-abn-token-table ?\013 'space) ; [VT] vertical tab
461 (aset ebnf-abn-token-table ?\t 'space) ; [HT] horizontal tab
462 (aset ebnf-abn-token-table ?\ 'space) ; [SP] space
463 ;; Override form feed character:
464 (aset ebnf-abn-token-table ?\f 'form-feed) ; [FF] form feed
465 ;; Override other lexical characters:
466 (aset ebnf-abn-token-table ?< 'non-terminal)
467 (aset ebnf-abn-token-table ?% 'terminal)
468 (aset ebnf-abn-token-table ?\" 'terminal)
469 (aset ebnf-abn-token-table ?\( 'begin-group)
470 (aset ebnf-abn-token-table ?\) 'end-group)
471 (aset ebnf-abn-token-table ?* 'repeat)
472 (aset ebnf-abn-token-table ?= 'equal)
473 (aset ebnf-abn-token-table ?\[ 'begin-optional)
474 (aset ebnf-abn-token-table ?\] 'end-optional)
475 (aset ebnf-abn-token-table ?/ 'alternative)
476 ;; Override comment character:
477 (aset ebnf-abn-token-table ?\; 'comment)))
478
479
480 ;; replace the range "\240-\377" (see `ebnf-range-regexp').
481 (defconst ebnf-abn-non-terminal-chars
482 (ebnf-range-regexp "-_0-9A-Za-z" ?\240 ?\377))
483 (defconst ebnf-abn-non-terminal-letter-chars
484 (ebnf-range-regexp "A-Za-z" ?\240 ?\377))
485
486
487 (defun ebnf-abn-lex ()
488 "Lexical analyser for ABNF.
489
490 Return a lexical token.
491
492 See documentation for variable `ebnf-abn-lex'."
493 (if (>= (point) ebnf-limit)
494 'end-of-input
495 (let (token)
496 ;; skip spaces and comments
497 (while (if (> (following-char) 255)
498 (progn
499 (setq token 'error)
500 nil)
501 (setq token (aref ebnf-abn-token-table (following-char)))
502 (cond
503 ((eq token 'space)
504 (skip-chars-forward " \013\t" ebnf-limit)
505 (< (point) ebnf-limit))
506 ((eq token 'comment)
507 (ebnf-abn-skip-comment))
508 ((eq token 'form-feed)
509 (forward-char)
510 (setq ebnf-action 'form-feed))
511 ((eq token 'end-of-rule)
512 (ebnf-abn-skip-end-of-rule))
513 (t nil)
514 )))
515 (cond
516 ;; end of input
517 ((>= (point) ebnf-limit)
518 'end-of-input)
519 ;; error
520 ((eq token 'error)
521 (error "Illegal character"))
522 ;; end of rule
523 ((eq token 'end-of-rule)
524 'end-of-rule)
525 ;; integer
526 ((eq token 'integer)
527 (setq ebnf-abn-lex (ebnf-buffer-substring "0-9"))
528 'integer)
529 ;; terminal: "string" or %[bdx]NNN((.NNN)+|-NNN)?
530 ((eq token 'terminal)
531 (setq ebnf-abn-lex
532 (if (= (following-char) ?\")
533 (ebnf-abn-string)
534 (ebnf-abn-character)))
535 'terminal)
536 ;; non-terminal: NAME or <NAME>
537 ((eq token 'non-terminal)
538 (let ((prose-p (= (following-char) ?<)))
539 (when prose-p
540 (forward-char)
541 (or (looking-at ebnf-abn-non-terminal-letter-chars)
542 (error "Invalid prose value")))
543 (setq ebnf-abn-lex
544 (ebnf-buffer-substring ebnf-abn-non-terminal-chars))
545 (when prose-p
546 (or (= (following-char) ?>)
547 (error "Invalid prose value"))
548 (setq ebnf-abn-lex (concat "<" ebnf-abn-lex ">"))))
549 'non-terminal)
550 ;; equal: =, =/
551 ((eq token 'equal)
552 (forward-char)
553 (if (/= (following-char) ?/)
554 'equal
555 (forward-char)
556 'incremental-alternative))
557 ;; miscellaneous: (, ), [, ], /, *
558 (t
559 (forward-char)
560 token)
561 ))))
562
563
564 (defun ebnf-abn-skip-end-of-rule ()
565 (let (eor-p)
566 (while (progn
567 ;; end of rule ==> 2 or more consecutive end of lines
568 (setq eor-p (or (> (skip-chars-forward "\r\n" ebnf-limit) 1)
569 eor-p))
570 ;; skip spaces
571 (skip-chars-forward " \013\t" ebnf-limit)
572 ;; skip comments
573 (and (= (following-char) ?\;)
574 (ebnf-abn-skip-comment))))
575 (not eor-p)))
576
577
578 ;; replace the range "\177-\237" (see `ebnf-range-regexp').
579 (defconst ebnf-abn-comment-chars
580 (ebnf-range-regexp "^\n\000-\010\016-\037" ?\177 ?\237))
581
582
583 (defun ebnf-abn-skip-comment ()
584 (forward-char)
585 (cond
586 ;; open EPS file
587 ((and ebnf-eps-executing (= (following-char) ?\[))
588 (ebnf-eps-add-context (ebnf-abn-eps-filename)))
589 ;; close EPS file
590 ((and ebnf-eps-executing (= (following-char) ?\]))
591 (ebnf-eps-remove-context (ebnf-abn-eps-filename)))
592 ;; any other action in comment
593 (t
594 (setq ebnf-action (aref ebnf-comment-table (following-char)))
595 (skip-chars-forward ebnf-abn-comment-chars ebnf-limit))
596 )
597 ;; check for a valid end of comment
598 (cond ((>= (point) ebnf-limit)
599 nil)
600 ((= (following-char) ?\n)
601 t)
602 (t
603 (error "Illegal character"))
604 ))
605
606
607 (defun ebnf-abn-eps-filename ()
608 (forward-char)
609 (ebnf-buffer-substring ebnf-abn-comment-chars))
610
611
612 ;; replace the range "\240-\377" (see `ebnf-range-regexp').
613 (defconst ebnf-abn-string-chars
614 (ebnf-range-regexp " -!#-~" ?\240 ?\377))
615
616
617 (defun ebnf-abn-string ()
618 (buffer-substring-no-properties
619 (progn
620 (forward-char)
621 (point))
622 (progn
623 (skip-chars-forward ebnf-abn-string-chars ebnf-limit)
624 (or (= (following-char) ?\")
625 (error "Missing `\"'"))
626 (prog1
627 (point)
628 (forward-char)))))
629
630
631 (defun ebnf-abn-character ()
632 ;; %[bdx]NNN((-NNN)|(.NNN)+)?
633 (buffer-substring-no-properties
634 (point)
635 (progn
636 (forward-char)
637 (let* ((char (following-char))
638 (chars (cond ((or (= char ?B) (= char ?b)) "01")
639 ((or (= char ?D) (= char ?d)) "0-9")
640 ((or (= char ?X) (= char ?x)) "0-9A-Fa-f")
641 (t (error "Invalid terminal value")))))
642 (forward-char)
643 (or (> (skip-chars-forward chars ebnf-limit) 0)
644 (error "Invalid terminal value"))
645 (if (= (following-char) ?-)
646 (progn
647 (forward-char)
648 (or (> (skip-chars-forward chars ebnf-limit) 0)
649 (error "Invalid terminal value range")))
650 (while (= (following-char) ?.)
651 (forward-char)
652 (or (> (skip-chars-forward chars ebnf-limit) 0)
653 (error "Invalid terminal value")))))
654 (point))))
655
656
657 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
658
659
660 (provide 'ebnf-abn)
661
662
663 ;;; arch-tag:
664 ;;; ebnf-abn.el ends here