Mercurial > emacs
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 |