Add 2011 to FSF/AIST copyright years.
[bpt/emacs.git] / lisp / progmodes / ebnf-yac.el
CommitLineData
e8af40ee 1;;; ebnf-yac.el --- parser for Yacc/Bison
984ae001 2
5df4f04c 3;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
d7a0267c 4;; Free Software Foundation, Inc.
984ae001 5
ac4780a1
VJL
6;; Author: Vinicius Jose Latorre <viniciusjl@ig.com.br>
7;; Maintainer: Vinicius Jose Latorre <viniciusjl@ig.com.br>
ae16d111 8;; Keywords: wp, ebnf, PostScript
3ced5caa 9;; Version: 1.4
984ae001 10
8d9ea7b1 11;; This file is part of GNU Emacs.
984ae001 12
b1fc2b50 13;; GNU Emacs is free software: you can redistribute it and/or modify
984ae001 14;; it under the terms of the GNU General Public License as published by
b1fc2b50
GM
15;; the Free Software Foundation, either version 3 of the License, or
16;; (at your option) any later version.
984ae001 17
8d9ea7b1 18;; GNU Emacs is distributed in the hope that it will be useful,
984ae001
GM
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
b1fc2b50 24;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
984ae001
GM
25
26;;; Commentary:
27
28;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
29;;
30;;
31;; This is part of ebnf2ps package.
32;;
33;; This package defines a parser for Yacc/Bison.
34;;
35;; See ebnf2ps.el for documentation.
36;;
37;;
38;; Yacc/Bison Syntax
39;; -----------------
40;;
41;; YACC = { YACC-Definitions }* "%%" { YACC-Rule }* [ "%%" [ YACC-Code ] ].
42;;
ac4780a1
VJL
43;; YACC-Definitions = ( "%token" | "%left" | "%right" | "%nonassoc" )
44;; [ "<" Name ">" ] Name-List
45;; | "%prec" Name
984ae001
GM
46;; | "any other Yacc definition"
47;; .
48;;
49;; YACC-Code = "any C definition".
50;;
51;; YACC-Rule = Name ":" Alternative ";".
52;;
53;; Alternative = { Sequence || "|" }*.
54;;
55;; Sequence = { Factor }*.
56;;
57;; Factor = Name
58;; | "'" "character" "'"
59;; | "error"
60;; | "{" "C like commands" "}"
61;; .
62;;
63;; Name-List = { Name || "," }*.
64;;
65;; Name = "[A-Za-z][A-Za-z0-9_.]*".
66;;
67;; Comment = "/*" "any character, but the sequence \"*/\"" "*/"
60df7255 68;; | "//" "any character, but the newline \"\\n\"" "\\n".
984ae001
GM
69;;
70;;
ac4780a1
VJL
71;; In other words, a valid Name begins with a letter (upper or lower case)
72;; followed by letters, decimal digits, underscore (_) or point (.). For
73;; example: this_is_a_valid.name, Another_EXAMPLE, mIxEd.CaSe.
74;;
75;;
76;; Acknowledgements
77;; ----------------
78;;
79;; Thanks to Matthew K. Junker <junker@alum.mit.edu> for the suggestion to deal
80;; with %right, %left and %prec pragmas. His suggestion was extended to deal
81;; with %nonassoc pragma too.
82;;
83;;
984ae001
GM
84;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
85
e8af40ee 86;;; Code:
984ae001
GM
87
88
89(require 'ebnf-otz)
90
91
92(defvar ebnf-yac-lex nil
93 "Value returned by `ebnf-yac-lex' function.")
94
95
96(defvar ebnf-yac-token-list nil
97 "List of `%TOKEN' names.")
98
99
100(defvar ebnf-yac-skip-char nil
101 "Non-nil means skip printable characters with no grammatical meaning.")
102
103
104(defvar ebnf-yac-error nil
b373b419 105 "Non-nil means \"error\" occurred.")
984ae001
GM
106
107\f
108;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
f504d516 109;; Syntactic analyzer
984ae001
GM
110
111
112;;; YACC = { YACC-Definitions }* "%%" { YACC-Rule }* [ "%%" [ YACC-Code ] ].
113;;;
114;;; YACC-Code = "any C definition".
115
116(defun ebnf-yac-parser (start)
117 "yacc/Bison parser."
118 (let ((total (+ (- ebnf-limit start) 1))
119 (bias (1- start))
120 (origin (point))
121 syntax-list token rule)
122 (goto-char start)
123 (setq token (ebnf-yac-lex))
124 (and (eq token 'end-of-input)
e8af40ee 125 (error "Invalid Yacc/Bison file format"))
984ae001 126 (or (eq (ebnf-yac-definitions token) 'yac-separator)
e8af40ee 127 (error "Missing `%%%%'"))
984ae001
GM
128 (setq token (ebnf-yac-lex))
129 (while (not (memq token '(end-of-input yac-separator)))
130 (ebnf-message-float
131 "Parsing...%s%%"
132 (/ (* (- (point) bias) 100.0) total))
133 (setq token (ebnf-yac-rule token)
134 rule (cdr token)
135 token (car token))
136 (or (ebnf-add-empty-rule-list rule)
137 (setq syntax-list (cons rule syntax-list))))
138 (goto-char origin)
139 syntax-list))
140
141
ac4780a1
VJL
142;;; YACC-Definitions = ( "%token" | "%left" | "%right" | "%nonassoc" )
143;;; [ "<" Name ">" ] Name-List
144;;; | "%prec" Name
984ae001
GM
145;;; | "any other Yacc definition"
146;;; .
147
148(defun ebnf-yac-definitions (token)
149 (let ((ebnf-yac-skip-char t))
150 (while (not (memq token '(yac-separator end-of-input)))
151 (setq token
152 (cond
ac4780a1
VJL
153 ;; ( "%token" | "%left" | "%right" | "%nonassoc" )
154 ;; [ "<" Name ">" ] Name-List
984ae001
GM
155 ((eq token 'yac-token)
156 (setq token (ebnf-yac-lex))
157 (when (eq token 'open-angle)
158 (or (eq (ebnf-yac-lex) 'non-terminal)
e8af40ee 159 (error "Missing type name"))
984ae001 160 (or (eq (ebnf-yac-lex) 'close-angle)
e8af40ee 161 (error "Missing `>'"))
984ae001
GM
162 (setq token (ebnf-yac-lex)))
163 (setq token (ebnf-yac-name-list token)
164 ebnf-yac-token-list (nconc (cdr token)
165 ebnf-yac-token-list))
166 (car token))
ac4780a1
VJL
167 ;; "%prec" Name
168 ((eq token 'yac-prec)
169 (or (eq (ebnf-yac-lex) 'non-terminal)
170 (error "Missing prec name"))
171 (ebnf-yac-lex))
172 ;; "any other Yacc definition"
984ae001
GM
173 (t
174 (ebnf-yac-lex))
175 )))
176 token))
177
178
179;;; YACC-Rule = Name ":" Alternative ";".
180
181(defun ebnf-yac-rule (token)
182 (let ((header ebnf-yac-lex)
183 (action ebnf-action)
184 body)
185 (setq ebnf-action nil)
186 (or (eq token 'non-terminal)
e8af40ee 187 (error "Invalid rule name"))
984ae001 188 (or (eq (ebnf-yac-lex) 'colon)
e8af40ee 189 (error "Invalid rule: missing `:'"))
984ae001
GM
190 (setq body (ebnf-yac-alternative))
191 (or (eq (car body) 'period)
e8af40ee 192 (error "Invalid rule: missing `;'"))
984ae001
GM
193 (setq body (cdr body))
194 (ebnf-eps-add-production header)
195 (cons (ebnf-yac-lex)
196 (ebnf-make-production header body action))))
197
198
199;;; Alternative = { Sequence || "|" }*.
200
201(defun ebnf-yac-alternative ()
202 (let (body sequence)
203 (while (eq (car (setq sequence (ebnf-yac-sequence)))
204 'alternative)
205 (and (setq sequence (cdr sequence))
206 (setq body (cons sequence body))))
207 (ebnf-token-alternative body sequence)))
208
209
210;;; Sequence = { Factor }*.
211
212(defun ebnf-yac-sequence ()
213 (let (ebnf-yac-error token seq factor)
214 (while (setq token (ebnf-yac-lex)
215 factor (ebnf-yac-factor token))
216 (setq seq (cons factor seq)))
217 (cons token
6411a60a
VJL
218 (if (and ebnf-yac-ignore-error-recovery ebnf-yac-error)
219 ;; ignore error recovery
220 nil
221 (ebnf-token-sequence seq)))))
984ae001
GM
222
223
224;;; Factor = Name
225;;; | "'" "character" "'"
226;;; | "error"
227;;; | "{" "C like commands" "}"
228;;; .
229
230(defun ebnf-yac-factor (token)
231 (cond
232 ;; 'character'
233 ((eq token 'terminal)
234 (ebnf-make-terminal ebnf-yac-lex))
235 ;; Name
236 ((eq token 'non-terminal)
237 (ebnf-make-non-terminal ebnf-yac-lex))
238 ;; "error"
239 ((eq token 'yac-error)
240 (ebnf-make-special ebnf-yac-lex))
241 ;; not a factor
242 (t
243 nil)
244 ))
245
246
247;;; Name-List = { Name || "," }*.
248
249(defun ebnf-yac-name-list (token)
250 (let (names)
251 (when (eq token 'non-terminal)
252 (while (progn
253 (setq names (cons ebnf-yac-lex names)
254 token (ebnf-yac-lex))
255 (eq token 'comma))
256 (or (eq (ebnf-yac-lex) 'non-terminal)
e8af40ee 257 (error "Missing token name"))))
984ae001
GM
258 (cons token names)))
259
260\f
261;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
262;; Lexical analyzer
263
264
265;;; Name = "[A-Za-z][A-Za-z0-9_.]*".
266;;;
267;;; Comment = "/*" "any character, but the sequence \"*/\"" "*/"
268;;; | "//" "any character" "\\n".
269
270(defconst ebnf-yac-token-table
271 ;; control character & 8-bit character are set to `error'
272 (let ((table (make-vector 256 'error)))
273 ;; upper & lower case letters:
5d66fabc 274 (mapc
984ae001
GM
275 #'(lambda (char)
276 (aset table char 'non-terminal))
277 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz")
278 ;; printable characters:
5d66fabc 279 (mapc
984ae001
GM
280 #'(lambda (char)
281 (aset table char 'character))
282 "!#$&()*+-.0123456789=?@[\\]^_`~")
283 ;; Override space characters:
284 (aset table ?\n 'space) ; [NL] linefeed
285 (aset table ?\r 'space) ; [CR] carriage return
286 (aset table ?\t 'space) ; [HT] horizontal tab
287 (aset table ?\ 'space) ; [SP] space
288 ;; Override form feed character:
289 (aset table ?\f 'form-feed) ; [FF] form feed
290 ;; Override other lexical characters:
291 (aset table ?< 'open-angle)
292 (aset table ?> 'close-angle)
293 (aset table ?, 'comma)
294 (aset table ?% 'yac-pragma)
295 (aset table ?/ 'slash)
296 (aset table ?\{ 'yac-code)
297 (aset table ?\" 'string)
298 (aset table ?\' 'terminal)
299 (aset table ?: 'colon)
300 (aset table ?| 'alternative)
301 (aset table ?\; 'period)
302 table)
303 "Vector used to map characters to a lexical token.")
304
305
306(defun ebnf-yac-initialize ()
307 "Initializations for Yacc/Bison parser."
308 (setq ebnf-yac-token-list nil))
309
310
311(defun ebnf-yac-lex ()
f103649a 312 "Lexical analyzer for Yacc/Bison.
984ae001
GM
313
314Return a lexical token.
315
316See documentation for variable `ebnf-yac-lex'."
317 (if (>= (point) ebnf-limit)
318 'end-of-input
319 (let (token)
320 ;; skip spaces, code blocks and comments
321 (while (if (> (following-char) 255)
322 (progn
323 (setq token 'error)
324 nil)
325 (setq token (aref ebnf-yac-token-table (following-char)))
326 (cond
327 ((or (eq token 'space)
328 (and ebnf-yac-skip-char
329 (eq token 'character)))
330 (ebnf-yac-skip-spaces))
331 ((eq token 'yac-code)
332 (ebnf-yac-skip-code))
333 ((eq token 'slash)
334 (ebnf-yac-handle-comment))
335 ((eq token 'form-feed)
336 (forward-char)
337 (setq ebnf-action 'form-feed))
338 (t nil)
339 )))
340 (cond
341 ;; end of input
342 ((>= (point) ebnf-limit)
343 'end-of-input)
344 ;; error
345 ((eq token 'error)
eac9c0ef 346 (error "Invalid character"))
984ae001
GM
347 ;; "string"
348 ((eq token 'string)
349 (setq ebnf-yac-lex (ebnf-get-string))
350 'string)
351 ;; terminal: 'char'
352 ((eq token 'terminal)
353 (setq ebnf-yac-lex (ebnf-string " -&(-~" ?\' "terminal"))
354 'terminal)
355 ;; non-terminal, terminal or "error"
356 ((eq token 'non-terminal)
357 (setq ebnf-yac-lex (ebnf-buffer-substring "0-9A-Za-z_."))
358 (cond ((member ebnf-yac-lex ebnf-yac-token-list)
359 'terminal)
360 ((string= ebnf-yac-lex "error")
361 (setq ebnf-yac-error t)
362 'yac-error)
363 (t
364 'non-terminal)
365 ))
366 ;; %% and Yacc pragmas (%TOKEN, %START, etc).
367 ((eq token 'yac-pragma)
368 (forward-char)
369 (cond
370 ;; Yacc separator
371 ((eq (following-char) ?%)
372 (forward-char)
373 'yac-separator)
ac4780a1
VJL
374 ;; %TOKEN, %RIGHT, %LEFT, %PREC, %NONASSOC
375 ((cdr (assoc (upcase (ebnf-buffer-substring "0-9A-Za-z_"))
376 '(("TOKEN" . yac-token)
377 ("RIGHT" . yac-token)
378 ("LEFT" . yac-token)
379 ("NONASSOC" . yac-token)
380 ("PREC" . yac-prec)))))
984ae001
GM
381 ;; other Yacc pragmas
382 (t
383 'yac-pragma)
384 ))
385 ;; miscellaneous
386 (t
387 (forward-char)
388 token)
389 ))))
390
391
392(defun ebnf-yac-skip-spaces ()
393 (skip-chars-forward
394 (if ebnf-yac-skip-char
395 "\n\r\t !#$&()*+-.0123456789=?@[\\\\]^_`~"
396 "\n\r\t ")
397 ebnf-limit)
398 (< (point) ebnf-limit))
399
400
a1548b10
GM
401;; replace the range "\177-\377" (see `ebnf-range-regexp').
402(defconst ebnf-yac-skip-chars
403 (ebnf-range-regexp "^{}/'\"\000-\010\013\016-\037" ?\177 ?\377))
404
405
984ae001
GM
406(defun ebnf-yac-skip-code ()
407 (forward-char)
408 (let ((pair 1))
409 (while (> pair 0)
a1548b10 410 (skip-chars-forward ebnf-yac-skip-chars ebnf-limit)
984ae001
GM
411 (cond
412 ((= (following-char) ?{)
413 (forward-char)
414 (setq pair (1+ pair)))
415 ((= (following-char) ?})
416 (forward-char)
417 (setq pair (1- pair)))
418 ((= (following-char) ?/)
419 (ebnf-yac-handle-comment))
420 ((= (following-char) ?\")
421 (ebnf-get-string))
422 ((= (following-char) ?\')
423 (ebnf-string " -&(-~" ?\' "character"))
424 (t
eac9c0ef 425 (error "Invalid character"))
984ae001
GM
426 )))
427 (ebnf-yac-skip-spaces))
428
429
430(defun ebnf-yac-handle-comment ()
431 (forward-char)
432 (cond
433 ;; begin comment
434 ((= (following-char) ?*)
435 (ebnf-yac-skip-comment)
436 (ebnf-yac-skip-spaces))
437 ;; line comment
438 ((= (following-char) ?/)
439 (end-of-line)
440 (ebnf-yac-skip-spaces))
441 ;; no comment
442 (t nil)
443 ))
444
445
647a066c
GM
446;; replace the range "\177-\237" (see `ebnf-range-regexp').
447(defconst ebnf-yac-comment-chars
448 (ebnf-range-regexp "^*\000-\010\013\016-\037" ?\177 ?\237))
984ae001
GM
449
450
451(defun ebnf-yac-skip-comment ()
452 (forward-char)
453 (cond
454 ;; open EPS file
455 ((and ebnf-eps-executing (= (following-char) ?\[))
456 (ebnf-eps-add-context (ebnf-yac-eps-filename)))
457 ;; close EPS file
458 ((and ebnf-eps-executing (= (following-char) ?\]))
459 (ebnf-eps-remove-context (ebnf-yac-eps-filename)))
3ced5caa
VJL
460 ;; EPS header
461 ((and ebnf-eps-executing (= (following-char) ?H))
462 (ebnf-eps-header-comment (ebnf-yac-eps-filename)))
463 ;; EPS footer
464 ((and ebnf-eps-executing (= (following-char) ?F))
465 (ebnf-eps-footer-comment (ebnf-yac-eps-filename)))
984ae001
GM
466 ;; any other action in comment
467 (t
468 (setq ebnf-action (aref ebnf-comment-table (following-char))))
469 )
470 (let ((not-end t))
471 (while not-end
472 (skip-chars-forward ebnf-yac-comment-chars ebnf-limit)
473 (cond ((>= (point) ebnf-limit)
e8af40ee 474 (error "Missing end of comment: `*/'"))
984ae001
GM
475 ((= (following-char) ?*)
476 (skip-chars-forward "*" ebnf-limit)
477 (when (= (following-char) ?/)
478 ;; end of comment
479 (forward-char)
480 (setq not-end nil)))
481 (t
eac9c0ef 482 (error "Invalid character"))
984ae001
GM
483 ))))
484
485
486(defun ebnf-yac-eps-filename ()
487 (forward-char)
488 (buffer-substring-no-properties
489 (point)
490 (let ((chars (concat ebnf-yac-comment-chars "\n"))
491 found)
492 (while (not found)
493 (skip-chars-forward chars ebnf-limit)
494 (setq found
495 (cond ((>= (point) ebnf-limit)
496 (point))
497 ((= (following-char) ?*)
498 (skip-chars-forward "*" ebnf-limit)
499 (if (/= (following-char) ?\/)
500 nil
501 (backward-char)
502 (point)))
503 (t
504 (point))
505 )))
506 found)))
507
508\f
509;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
510
511
512(provide 'ebnf-yac)
513
514
cbee283d 515;; arch-tag: 8a96989c-0b1d-42ba-a020-b2901f9a2a4d
984ae001 516;;; ebnf-yac.el ends here