ebnf-ebx.el 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672
  1. ;;; ebnf-ebx.el --- parser for EBNF used to specify XML (EBNFX)
  2. ;; Copyright (C) 2001-2012 Free Software Foundation, Inc.
  3. ;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
  4. ;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
  5. ;; Keywords: wp, ebnf, PostScript
  6. ;; Version: 1.2
  7. ;; Package: ebnf2ps
  8. ;; This file is part of GNU Emacs.
  9. ;; GNU Emacs is free software: you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation, either version 3 of the License, or
  12. ;; (at your option) any later version.
  13. ;; GNU Emacs is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  21. ;;
  22. ;;
  23. ;; This is part of ebnf2ps package.
  24. ;;
  25. ;; This package defines a parser for EBNF used to specify XML (EBNFX).
  26. ;;
  27. ;; See ebnf2ps.el for documentation.
  28. ;;
  29. ;;
  30. ;; EBNFX Syntax
  31. ;; ------------
  32. ;;
  33. ;; See the URL:
  34. ;; `http://www.w3.org/TR/2004/REC-xml-20040204/#sec-notation'
  35. ;; (Extensible Markup Language (XML) 1.0 (Third Edition))
  36. ;;
  37. ;;
  38. ;; rule ::= symbol '::=' expression
  39. ;; /* rules are separated by at least one blank line. */
  40. ;;
  41. ;; expression ::= concatenation ('|' concatenation)*
  42. ;;
  43. ;; concatenation ::= exception*
  44. ;;
  45. ;; exception ::= term ('-' term)?
  46. ;;
  47. ;; term ::= factor ('*' | '+' | '?')?
  48. ;;
  49. ;; factor ::= hex-char+
  50. ;; | '[' '^'? ( char ( '-' char )? )+ ']'
  51. ;; | '"' 'string' '"'
  52. ;; | "'" "string" "'"
  53. ;; | '(' expression ')'
  54. ;; | symbol
  55. ;;
  56. ;; symbol ::= 'upper or lower case letter'
  57. ;; ('upper or lower case letter' | '-' | '_')*
  58. ;; /* upper and lower 8-bit accentuated characters are included */
  59. ;;
  60. ;; hex-char ::= '#x' [0-9A-Fa-f]+
  61. ;;
  62. ;; char ::= hex-char | 'any character except control characters'
  63. ;; /* 8-bit accentuated characters are included */
  64. ;;
  65. ;; any-char ::= char | 'newline' | 'tab'
  66. ;;
  67. ;; ignore ::= '[' ('wfc' | 'WFC' | 'vc' | 'VC') ':' ( any-char - ']' )* ']'
  68. ;;
  69. ;; comment ::= '/*' ( any-char - '*/' ) '*/'
  70. ;;
  71. ;;
  72. ;; Below is the Notation section extracted from the URL cited above.
  73. ;;
  74. ;; 6 Notation
  75. ;;
  76. ;; The formal grammar of XML is given in this specification using a simple
  77. ;; Extended Backus-Naur Form (EBNF) notation. Each rule in the grammar defines
  78. ;; one symbol, in the form
  79. ;;
  80. ;; symbol ::= expression
  81. ;;
  82. ;; Symbols are written with an initial capital letter if they are the start
  83. ;; symbol of a regular language, otherwise with an initial lowercase letter.
  84. ;; Literal strings are quoted.
  85. ;;
  86. ;; Within the expression on the right-hand side of a rule, the following
  87. ;; expressions are used to match strings of one or more characters:
  88. ;;
  89. ;; #xN
  90. ;;
  91. ;; where N is a hexadecimal integer, the expression matches the character
  92. ;; whose number (code point) in ISO/IEC 10646 is N. The number of leading
  93. ;; zeros in the #xN form is insignificant.
  94. ;;
  95. ;; [a-zA-Z], [#xN-#xN]
  96. ;;
  97. ;; matches any Char with a value in the range(s) indicated (inclusive).
  98. ;;
  99. ;; [abc], [#xN#xN#xN]
  100. ;;
  101. ;; matches any Char with a value among the characters enumerated.
  102. ;; Enumerations and ranges can be mixed in one set of brackets.
  103. ;;
  104. ;; [^a-z], [^#xN-#xN]
  105. ;;
  106. ;; matches any Char with a value outside the range indicated.
  107. ;;
  108. ;; [^abc], [^#xN#xN#xN]
  109. ;;
  110. ;; matches any Char with a value not among the characters given.
  111. ;; Enumerations and ranges of forbidden values can be mixed in one set of
  112. ;; brackets.
  113. ;;
  114. ;; "string"
  115. ;;
  116. ;; matches a literal string matching that given inside the double quotes.
  117. ;;
  118. ;; 'string'
  119. ;;
  120. ;; matches a literal string matching that given inside the single quotes.
  121. ;;
  122. ;; These symbols may be combined to match more complex patterns as follows,
  123. ;; where A and B represent simple expressions:
  124. ;;
  125. ;; (expression)
  126. ;;
  127. ;; expression is treated as a unit and may be combined as described in this
  128. ;; list.
  129. ;;
  130. ;; A?
  131. ;;
  132. ;; matches A or nothing; optional A.
  133. ;;
  134. ;; A B
  135. ;;
  136. ;; matches A followed by B. This operator has higher precedence than
  137. ;; alternation; thus A B | C D is identical to (A B) | (C D).
  138. ;;
  139. ;; A | B
  140. ;;
  141. ;; matches A or B.
  142. ;;
  143. ;; A - B
  144. ;;
  145. ;; matches any string that matches A but does not match B.
  146. ;;
  147. ;; A+
  148. ;;
  149. ;; matches one or more occurrences of A. Concatenation has higher
  150. ;; precedence than alternation; thus A+ | B+ is identical to (A+) | (B+).
  151. ;;
  152. ;; A*
  153. ;;
  154. ;; matches zero or more occurrences of A. Concatenation has higher
  155. ;; precedence than alternation; thus A* | B* is identical to (A*) | (B*).
  156. ;;
  157. ;; Other notations used in the productions are:
  158. ;;
  159. ;; /* ... */
  160. ;;
  161. ;; comment.
  162. ;;
  163. ;; [ wfc: ... ]
  164. ;;
  165. ;; well-formedness constraint; this identifies by name a constraint on
  166. ;; well-formed documents associated with a production.
  167. ;;
  168. ;; [ vc: ... ]
  169. ;;
  170. ;; validity constraint; this identifies by name a constraint on valid
  171. ;; documents associated with a production.
  172. ;;
  173. ;;
  174. ;; Differences Between EBNFX And ebnf2ps EBNFX
  175. ;; -------------------------------------------
  176. ;;
  177. ;; Besides the characters that EBNFX accepts, ebnf2ps EBNFX accepts also the
  178. ;; underscore (_) and minus (-) for rule name and european 8-bit accentuated
  179. ;; characters (from \240 to \377) for rule name, string and comment. Also
  180. ;; rule name can start with upper case letter.
  181. ;;
  182. ;;
  183. ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  184. ;;; Code:
  185. (require 'ebnf-otz)
  186. (defvar ebnf-ebx-lex nil
  187. "Value returned by `ebnf-ebx-lex' function.")
  188. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  189. ;; Syntactic analyzer
  190. ;;; rulelist ::= rule+
  191. (defun ebnf-ebx-parser (start)
  192. "EBNFX parser."
  193. (let ((total (+ (- ebnf-limit start) 1))
  194. (bias (1- start))
  195. (origin (point))
  196. rule-list token rule)
  197. (goto-char start)
  198. (setq token (ebnf-ebx-lex))
  199. (and (eq token 'end-of-input)
  200. (error "Invalid EBNFX file format"))
  201. (and (eq token 'end-of-rule)
  202. (setq token (ebnf-ebx-lex)))
  203. (while (not (eq token 'end-of-input))
  204. (ebnf-message-float
  205. "Parsing...%s%%"
  206. (/ (* (- (point) bias) 100.0) total))
  207. (setq token (ebnf-ebx-rule token)
  208. rule (cdr token)
  209. token (car token))
  210. (or (ebnf-add-empty-rule-list rule)
  211. (setq rule-list (cons rule rule-list))))
  212. (goto-char origin)
  213. rule-list))
  214. ;;; rule ::= symbol '::=' expression
  215. (defun ebnf-ebx-rule (token)
  216. (let ((name ebnf-ebx-lex)
  217. (action ebnf-action)
  218. elements)
  219. (setq ebnf-action nil)
  220. (or (eq token 'non-terminal)
  221. (error "Invalid rule name"))
  222. (setq token (ebnf-ebx-lex))
  223. (or (eq token 'production)
  224. (error "Invalid rule: missing `::='"))
  225. (setq elements (ebnf-ebx-expression))
  226. (or (memq (car elements) '(end-of-rule end-of-input))
  227. (error "Invalid rule: there is no end of rule"))
  228. (setq elements (cdr elements))
  229. (ebnf-eps-add-production name)
  230. (cons (ebnf-ebx-lex)
  231. (ebnf-make-production name elements action))))
  232. ;; expression ::= concatenation ('|' concatenation)*
  233. (defun ebnf-ebx-expression ()
  234. (let (body concatenation)
  235. (while (eq (car (setq concatenation
  236. (ebnf-ebx-concatenation (ebnf-ebx-lex))))
  237. 'alternative)
  238. (setq body (cons (cdr concatenation) body)))
  239. (ebnf-token-alternative body concatenation)))
  240. ;; concatenation ::= exception*
  241. (defun ebnf-ebx-concatenation (token)
  242. (let ((term (ebnf-ebx-exception token))
  243. seq)
  244. (or (setq token (car term)
  245. term (cdr term))
  246. (error "Empty element"))
  247. (setq seq (cons term seq))
  248. (while (setq term (ebnf-ebx-exception token)
  249. token (car term)
  250. term (cdr term))
  251. (setq seq (cons term seq)))
  252. (cons token
  253. (ebnf-token-sequence seq))))
  254. ;;; exception ::= term ('-' term)?
  255. (defun ebnf-ebx-exception (token)
  256. (let ((term (ebnf-ebx-term token)))
  257. (if (eq (car term) 'exception)
  258. (let ((except (ebnf-ebx-term (ebnf-ebx-lex))))
  259. (cons (car except)
  260. (ebnf-make-except (cdr term) (cdr except))))
  261. term)))
  262. ;;; term ::= factor ('*' | '+' | '?')?
  263. (defun ebnf-ebx-term (token)
  264. (let ((factor (ebnf-ebx-factor token)))
  265. (when factor
  266. (setq token (ebnf-ebx-lex))
  267. (cond ((eq token 'zero-or-more)
  268. (setq factor (ebnf-make-zero-or-more factor)
  269. token (ebnf-ebx-lex)))
  270. ((eq token 'one-or-more)
  271. (setq factor (ebnf-make-one-or-more factor)
  272. token (ebnf-ebx-lex)))
  273. ((eq token 'optional)
  274. (setq factor (ebnf-token-optional factor)
  275. token (ebnf-ebx-lex)))))
  276. (cons token factor)))
  277. ;;; factor ::= hex-char+
  278. ;;; | '[' '^'? ( char ( '-' char )? )+ ']'
  279. ;;; | '"' 'string' '"'
  280. ;;; | "'" "string" "'"
  281. ;;; | '(' expression ')'
  282. ;;; | symbol
  283. ;;;
  284. ;;; symbol ::= 'upper or lower case letter'
  285. ;;; ('upper or lower case letter' | '-' | '_')*
  286. ;;; /* upper and lower 8-bit accentuated characters are included */
  287. ;;;
  288. ;;; hex-char ::= '#x' [0-9A-Fa-f]+
  289. ;;;
  290. ;;; char ::= hex-char | 'any character except control characters'
  291. ;;; /* 8-bit accentuated characters are included */
  292. ;;;
  293. ;;; any-char ::= char | 'newline' | 'tab'
  294. (defun ebnf-ebx-factor (token)
  295. (cond
  296. ;; terminal
  297. ((eq token 'terminal)
  298. (ebnf-make-terminal ebnf-ebx-lex))
  299. ;; non-terminal
  300. ((eq token 'non-terminal)
  301. (ebnf-make-non-terminal ebnf-ebx-lex))
  302. ;; group
  303. ((eq token 'begin-group)
  304. (let ((body (ebnf-ebx-expression)))
  305. (or (eq (car body) 'end-group)
  306. (error "Missing `)'"))
  307. (cdr body)))
  308. ;; no element
  309. (t
  310. nil)
  311. ))
  312. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  313. ;; Lexical analyzer
  314. (defconst ebnf-ebx-token-table (make-vector 256 'error)
  315. "Vector used to map characters to a lexical token.")
  316. (defun ebnf-ebx-initialize ()
  317. "Initialize EBNFX token table."
  318. ;; control character & control 8-bit character are set to `error'
  319. (let ((char ?\101))
  320. ;; printable character: A-Z
  321. (while (< char ?\133)
  322. (aset ebnf-ebx-token-table char 'non-terminal)
  323. (setq char (1+ char)))
  324. ;; printable character: a-z
  325. (setq char ?\141)
  326. (while (< char ?\173)
  327. (aset ebnf-ebx-token-table char 'non-terminal)
  328. (setq char (1+ char)))
  329. ;; European 8-bit accentuated characters:
  330. (setq char ?\240)
  331. (while (< char ?\400)
  332. (aset ebnf-ebx-token-table char 'non-terminal)
  333. (setq char (1+ char)))
  334. ;; Override end of line characters:
  335. (aset ebnf-ebx-token-table ?\n 'end-of-rule) ; [NL] linefeed
  336. (aset ebnf-ebx-token-table ?\r 'end-of-rule) ; [CR] carriage return
  337. ;; Override space characters:
  338. (aset ebnf-ebx-token-table ?\013 'space) ; [VT] vertical tab
  339. (aset ebnf-ebx-token-table ?\t 'space) ; [HT] horizontal tab
  340. (aset ebnf-ebx-token-table ?\ 'space) ; [SP] space
  341. ;; Override form feed character:
  342. (aset ebnf-ebx-token-table ?\f 'form-feed) ; [FF] form feed
  343. ;; Override other lexical characters:
  344. (aset ebnf-ebx-token-table ?# 'hash)
  345. (aset ebnf-ebx-token-table ?\" 'double-quote)
  346. (aset ebnf-ebx-token-table ?\' 'single-quote)
  347. (aset ebnf-ebx-token-table ?\( 'begin-group)
  348. (aset ebnf-ebx-token-table ?\) 'end-group)
  349. (aset ebnf-ebx-token-table ?- 'exception)
  350. (aset ebnf-ebx-token-table ?: 'colon)
  351. (aset ebnf-ebx-token-table ?\[ 'begin-square)
  352. (aset ebnf-ebx-token-table ?| 'alternative)
  353. (aset ebnf-ebx-token-table ?* 'zero-or-more)
  354. (aset ebnf-ebx-token-table ?+ 'one-or-more)
  355. (aset ebnf-ebx-token-table ?\? 'optional)
  356. ;; Override comment character:
  357. (aset ebnf-ebx-token-table ?/ 'comment)))
  358. ;; replace the range "\240-\377" (see `ebnf-range-regexp').
  359. (defconst ebnf-ebx-non-terminal-chars
  360. (ebnf-range-regexp "-_A-Za-z" ?\240 ?\377))
  361. (defconst ebnf-ebx-non-terminal-letter-chars
  362. (ebnf-range-regexp "A-Za-z" ?\240 ?\377))
  363. (defun ebnf-ebx-lex ()
  364. "Lexical analyzer for EBNFX.
  365. Return a lexical token.
  366. See documentation for variable `ebnf-ebx-lex'."
  367. (if (>= (point) ebnf-limit)
  368. 'end-of-input
  369. (let (token)
  370. ;; skip spaces and comments
  371. (while (if (> (following-char) 255)
  372. (progn
  373. (setq token 'error)
  374. nil)
  375. (setq token (aref ebnf-ebx-token-table (following-char)))
  376. (cond
  377. ((eq token 'space)
  378. (skip-chars-forward " \013\t" ebnf-limit)
  379. (< (point) ebnf-limit))
  380. ((eq token 'comment)
  381. (ebnf-ebx-skip-comment))
  382. ((eq token 'form-feed)
  383. (forward-char)
  384. (setq ebnf-action 'form-feed))
  385. ((eq token 'end-of-rule)
  386. (ebnf-ebx-skip-end-of-rule))
  387. ((and (eq token 'begin-square)
  388. (let ((case-fold-search t))
  389. (looking-at "\\[\\(wfc\\|vc\\):")))
  390. (ebnf-ebx-skip-constraint))
  391. (t nil)
  392. )))
  393. (cond
  394. ;; end of input
  395. ((>= (point) ebnf-limit)
  396. 'end-of-input)
  397. ;; error
  398. ((eq token 'error)
  399. (error "Invalid character"))
  400. ;; end of rule
  401. ((eq token 'end-of-rule)
  402. 'end-of-rule)
  403. ;; terminal: #x [0-9A-Fa-f]+
  404. ((eq token 'hash)
  405. (setq ebnf-ebx-lex (ebnf-ebx-character))
  406. 'terminal)
  407. ;; terminal: "string"
  408. ((eq token 'double-quote)
  409. (setq ebnf-ebx-lex (ebnf-ebx-string ?\"))
  410. 'terminal)
  411. ;; terminal: 'string'
  412. ((eq token 'single-quote)
  413. (setq ebnf-ebx-lex (ebnf-ebx-string ?\'))
  414. 'terminal)
  415. ;; terminal: [ ^? ( char ( - char )? )+ ]
  416. ((eq token 'begin-square)
  417. (setq ebnf-ebx-lex (ebnf-ebx-range))
  418. 'terminal)
  419. ;; non-terminal: NAME
  420. ((eq token 'non-terminal)
  421. (setq ebnf-ebx-lex
  422. (ebnf-buffer-substring ebnf-ebx-non-terminal-chars))
  423. 'non-terminal)
  424. ;; colon: ::=
  425. ((eq token 'colon)
  426. (or (looking-at "::=")
  427. (error "Missing `::=' token"))
  428. (forward-char 3)
  429. 'production)
  430. ;; miscellaneous: (, ), *, +, ?, |, -
  431. (t
  432. (forward-char)
  433. token)
  434. ))))
  435. ;; replace the range "\177-\237" (see `ebnf-range-regexp').
  436. (defconst ebnf-ebx-constraint-chars
  437. (ebnf-range-regexp "^\000-\010\016-\037]" ?\177 ?\237))
  438. (defun ebnf-ebx-skip-constraint ()
  439. (or (> (skip-chars-forward ebnf-ebx-constraint-chars ebnf-limit) 0)
  440. (error "Invalid character"))
  441. (or (= (following-char) ?\])
  442. (error "Missing end of constraint `]'"))
  443. (forward-char)
  444. t)
  445. (defun ebnf-ebx-skip-end-of-rule ()
  446. (let (eor-p)
  447. (while (progn
  448. ;; end of rule ==> 2 or more consecutive end of lines
  449. (setq eor-p (or (> (skip-chars-forward "\r\n" ebnf-limit) 1)
  450. eor-p))
  451. ;; skip spaces
  452. (skip-chars-forward " \013\t" ebnf-limit)
  453. ;; skip comments
  454. (and (= (following-char) ?/)
  455. (ebnf-ebx-skip-comment))))
  456. (not eor-p)))
  457. ;; replace the range "\177-\237" (see `ebnf-range-regexp').
  458. (defconst ebnf-ebx-comment-chars
  459. (ebnf-range-regexp "^\000-\010\016-\037\\*" ?\177 ?\237))
  460. (defconst ebnf-ebx-filename-chars
  461. (ebnf-range-regexp "^\000-\037\\*" ?\177 ?\237))
  462. (defun ebnf-ebx-skip-comment ()
  463. (forward-char)
  464. (or (= (following-char) ?*)
  465. (error "Invalid beginning of comment"))
  466. (forward-char)
  467. (cond
  468. ;; open EPS file
  469. ((and ebnf-eps-executing (= (following-char) ?\[))
  470. (ebnf-eps-add-context (ebnf-ebx-eps-filename)))
  471. ;; close EPS file
  472. ((and ebnf-eps-executing (= (following-char) ?\]))
  473. (ebnf-eps-remove-context (ebnf-ebx-eps-filename)))
  474. ;; EPS header
  475. ((and ebnf-eps-executing (= (following-char) ?H))
  476. (ebnf-eps-header-comment (ebnf-ebx-eps-filename)))
  477. ;; EPS footer
  478. ((and ebnf-eps-executing (= (following-char) ?F))
  479. (ebnf-eps-footer-comment (ebnf-ebx-eps-filename)))
  480. ;; any other action in comment
  481. (t
  482. (setq ebnf-action (aref ebnf-comment-table (following-char))))
  483. )
  484. (while (progn
  485. (skip-chars-forward ebnf-ebx-comment-chars ebnf-limit)
  486. (or (= (following-char) ?*)
  487. (error "Missing end of comment"))
  488. (forward-char)
  489. (and (/= (following-char) ?/)
  490. (< (point) ebnf-limit))))
  491. ;; check for a valid end of comment
  492. (and (>= (point) ebnf-limit)
  493. (error "Missing end of comment"))
  494. (forward-char)
  495. t)
  496. (defun ebnf-ebx-eps-filename ()
  497. (forward-char)
  498. (let (fname nchar)
  499. (while (progn
  500. (setq fname
  501. (concat fname
  502. (ebnf-buffer-substring ebnf-ebx-filename-chars)))
  503. (and (< (point) ebnf-limit)
  504. (> (setq nchar (skip-chars-forward "*" ebnf-limit)) 0)
  505. (< (point) ebnf-limit)
  506. (/= (following-char) ?/)))
  507. (setq fname (concat fname (make-string nchar ?*))
  508. nchar nil))
  509. (if (or (not nchar) (= nchar 0))
  510. fname
  511. (and (< (point) ebnf-limit)
  512. (= (following-char) ?/)
  513. (setq nchar (1- nchar)))
  514. (concat fname (make-string nchar ?*)))))
  515. ;; replace the range "\240-\377" (see `ebnf-range-regexp').
  516. (defconst ebnf-ebx-double-string-chars
  517. (ebnf-range-regexp "\t -!#-~" ?\240 ?\377))
  518. (defconst ebnf-ebx-single-string-chars
  519. (ebnf-range-regexp "\t -&(-~" ?\240 ?\377))
  520. (defun ebnf-ebx-string (delim)
  521. (buffer-substring-no-properties
  522. (progn
  523. (forward-char)
  524. (point))
  525. (progn
  526. (skip-chars-forward (if (= delim ?\")
  527. ebnf-ebx-double-string-chars
  528. ebnf-ebx-single-string-chars)
  529. ebnf-limit)
  530. (or (= (following-char) delim)
  531. (error "Missing string delimiter `%c'" delim))
  532. (prog1
  533. (point)
  534. (forward-char)))))
  535. (defun ebnf-ebx-character ()
  536. ;; #x [0-9A-Fa-f]+
  537. (buffer-substring-no-properties
  538. (point)
  539. (progn
  540. (ebnf-ebx-hex-character)
  541. (point))))
  542. (defun ebnf-ebx-range ()
  543. ;; [ ^? ( char ( - char )? )+ ]
  544. (buffer-substring-no-properties
  545. (point)
  546. (progn
  547. (forward-char)
  548. (and (= (following-char) ?^)
  549. (forward-char))
  550. (and (= (following-char) ?-)
  551. (forward-char))
  552. (while (progn
  553. (ebnf-ebx-any-character)
  554. (when (= (following-char) ?-)
  555. (forward-char)
  556. (ebnf-ebx-any-character))
  557. (and (/= (following-char) ?\])
  558. (< (point) ebnf-limit))))
  559. (and (>= (point) ebnf-limit)
  560. (error "Missing end of character range `]'"))
  561. (forward-char)
  562. (point))))
  563. (defun ebnf-ebx-any-character ()
  564. (let ((char (following-char)))
  565. (cond ((= char ?#)
  566. (ebnf-ebx-hex-character t))
  567. ((or (and (<= ?\ char) (<= char ?\")) ; #
  568. (and (<= ?$ char) (<= char ?,)) ; -
  569. (and (<= ?. char) (<= char ?\\)) ; ]
  570. (and (<= ?^ char) (<= char ?~))
  571. (and (<= ?\240 char) (<= char ?\377)))
  572. (forward-char))
  573. (t
  574. (error "Invalid character `%c'" char)))))
  575. (defun ebnf-ebx-hex-character (&optional no-error)
  576. ;; #x [0-9A-Fa-f]+
  577. (forward-char)
  578. (if (/= (following-char) ?x)
  579. (or no-error
  580. (error "Invalid hexadecimal character"))
  581. (forward-char)
  582. (or (> (skip-chars-forward "0-9A-Fa-f" ebnf-limit) 0)
  583. (error "Invalid hexadecimal character"))))
  584. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  585. (provide 'ebnf-ebx)
  586. ;;; ebnf-ebx.el ends here