Initial Commit
[packages] / xemacs-packages / semantic / bovine / bovine-grammar.el.upstream
1 ;;; bovine-grammar.el --- Bovine's input grammar mode
2 ;;
3 ;; Copyright (C) 2002, 2003, 2004, 2007 David Ponce
4 ;;
5 ;; Author: David Ponce <david@dponce.com>
6 ;; Maintainer: David Ponce <david@dponce.com>
7 ;; Created: 26 Aug 2002
8 ;; Keywords: syntax
9 ;; X-RCS: $Id: bovine-grammar.el.upstream,v 1.1 2007-11-26 15:11:50 michaels Exp $
10 ;;
11 ;; This file is not part of GNU Emacs.
12 ;;
13 ;; This program is free software; you can redistribute it and/or
14 ;; modify it under the terms of the GNU General Public License as
15 ;; published by the Free Software Foundation; either version 2, or (at
16 ;; your option) any later version.
17 ;;
18 ;; This software 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 GNU
21 ;; 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., 51 Franklin Street, Fifth Floor,
26 ;; Boston, MA 02110-1301, USA.
27
28 ;;; Commentary:
29 ;;
30 ;; Major mode for editing Bovine's input grammar (.by) files.
31
32 ;;; History:
33 ;;
34
35 ;;; Code:
36 (require 'semantic-grammar)
37 (require 'bovine-grammar-macros)
38
39 ;; Cache of macro definitions currently in use.
40 (defvar bovine--grammar-macros nil)
41
42 (defun bovine-grammar-expand-form (form quotemode &optional inplace)
43   "Expand FORM into a new one suitable to the bovine parser.
44 FORM is a list in which we are substituting.
45 Argument QUOTEMODE is non-nil if we are in backquote mode.
46 When non-nil, optional argument INPLACE indicates that FORM is being
47 expanded from elsewhere."
48   (when (eq (car form) 'quote)
49     (setq form (cdr form))
50     (cond
51      ((and (= (length form) 1) (listp (car form)))
52       (insert "\n(append")
53       (bovine-grammar-expand-form (car form) quotemode nil)
54       (insert ")")
55       (setq form nil inplace nil)
56       )
57      ((and (= (length form) 1) (symbolp (car form)))
58       (insert "\n'" (symbol-name (car form)))
59       (setq form nil inplace nil)
60       )
61      (t
62       (insert "\n(list")
63       (setq inplace t)
64       )))
65   (let ((macro (assq (car form) bovine--grammar-macros))
66         inlist first n q x val)
67     (if macro
68         (bovine-grammar-expand-form
69          (apply (cdr macro) (cdr form))
70          quotemode t)
71       (if inplace (insert "\n("))
72       (while form
73         (setq first (car form)
74               form  (cdr form))
75         (cond
76          ((eq first nil)
77           (when (and (not inlist) (not inplace))
78             (insert "\n(list")
79             (setq inlist t))
80           (insert " nil")
81           )
82          ((listp first)
83           ;;(let ((fn (and (symbolp (caar form)) (fboundp (caar form)))))
84           (when (and (not inlist) (not inplace))
85             (insert "\n(list")
86             (setq inlist t))
87           ;;(if (and inplace (not fn) (not (eq (caar form) 'EXPAND)))
88           ;;    (insert " (append"))
89           (bovine-grammar-expand-form
90            first quotemode t) ;;(and fn (not (eq fn 'quote))))
91           ;;(if (and inplace (not fn) (not (eq (caar form) 'EXPAND)))
92           ;;    (insert  ")"))
93           ;;)
94           )
95          ((symbolp first)
96           (setq n (symbol-name first)   ;the name
97                 q quotemode             ;implied quote flag
98                 x nil)                  ;expand flag
99           (if (eq (aref n 0) ?,)
100               (if quotemode
101                   ;; backquote mode needs the @
102                   (if (eq (aref n 1) ?@)
103                       (setq n (substring n 2)
104                             q nil
105                             x t)
106                     ;; non backquote mode behaves normally.
107                     (setq n (substring n 1)
108                           q nil))
109                 (setq n (substring n 1)
110                       x t)))
111           (if (string= n "")
112               (progn
113                 ;; We expand only the next item in place (a list?)
114                 ;; A regular inline-list...
115                 (bovine-grammar-expand-form (car form) quotemode t)
116                 (setq form (cdr form)))
117             (if (and (eq (aref n 0) ?$)
118                      ;; Don't expand $ tokens in implied quote mode.
119                      ;; This acts like quoting in other symbols.
120                      (not q))
121                 (progn
122                   (cond
123                    ((and (not x) (not inlist) (not inplace))
124                     (insert "\n(list"))
125                    ((and x inlist (not inplace))
126                     (insert ")")
127                     (setq inlist nil)))
128                   (insert "\n(nth " (int-to-string
129                                      (1- (string-to-number
130                                           (substring n 1))))
131                           " vals)")
132                   (and (not x) (not inplace)
133                        (setq inlist t)))
134               
135               (when (and (not inlist) (not inplace))
136                 (insert "\n(list")
137                 (setq inlist t))
138               (or (char-equal (char-before) ?\()
139                   (insert " "))
140               (insert (if (or inplace (eq first t))
141                           "" "'")
142                       n))) ;; " "
143           )
144          (t
145           (when (and (not inlist) (not inplace))
146             (insert "\n(list")
147             (setq inlist t))
148           (insert (format "\n%S" first))
149           )
150          ))
151       (if inlist (insert ")"))
152       (if inplace (insert ")")))
153     ))
154
155 (defun bovine-grammar-expand-action (textform quotemode)
156   "Expand semantic action string TEXTFORM into Lisp code.
157 QUOTEMODE is the mode in which quoted symbols are slurred."
158   (if (string= "" textform)
159       nil
160     (let ((sexp (read textform)))
161       ;; We converted the lambda string into a list.  Now write it
162       ;; out as the bovine lambda expression, and do macro-like
163       ;; conversion upon it.
164       (insert "\n")
165       (cond
166        ((eq (car sexp) 'EXPAND)
167         (insert ",(lambda (vals start end)")
168         ;; The EXPAND macro definition is mandatory
169         (bovine-grammar-expand-form
170          (apply (cdr (assq 'EXPAND bovine--grammar-macros)) (cdr sexp))
171          quotemode t)
172         )
173        ((and (listp (car sexp)) (eq (caar sexp) 'EVAL))
174         ;; The user wants to evaluate the following args.
175         ;; Use a simpler expander
176         )
177        (t
178         (insert ",(semantic-lambda")
179         (bovine-grammar-expand-form sexp quotemode)
180         ))
181       (insert ")\n"))))
182
183 (defun bovine-grammar-parsetable-builder ()
184   "Return the parser table expression as a string value.
185 The format of a bovine parser table is:
186
187  ( ( NONTERMINAL-SYMBOL1 MATCH-LIST1 )
188    ( NONTERMINAL-SYMBOL2 MATCH-LIST2 )
189    ...
190    ( NONTERMINAL-SYMBOLn MATCH-LISTn )
191  
192 Where each NONTERMINAL-SYMBOL is an artificial symbol which can appear
193 in any child state.  As a starting place, one of the NONTERMINAL-SYMBOLS
194 must be `bovine-toplevel'.
195
196 A MATCH-LIST is a list of possible matches of the form:
197
198  ( STATE-LIST1
199    STATE-LIST2
200    ...
201    STATE-LISTN )
202
203 where STATE-LIST is of the form:
204   ( TYPE1 [ \"VALUE1\" ] TYPE2 [ \"VALUE2\" ] ... LAMBDA )
205
206 where TYPE is one of the returned types of the token stream.
207 VALUE is a value, or range of values to match against.  For
208 example, a SYMBOL might need to match \"foo\".  Some TYPES will not
209 have matching criteria.
210
211 LAMBDA is a lambda expression which is evaled with the text of the
212 type when it is found.  It is passed the list of all buffer text
213 elements found since the last lambda expression.  It should return a
214 semantic element (see below.)
215
216 For consistency between languages, try to use common return values
217 from your parser.  Please reference the chapter \"Writing Parsers\" in
218 the \"Language Support Developer's Guide -\" in the semantic texinfo
219 manual."
220   (let* ((start      (semantic-grammar-start))
221          (scopestart (semantic-grammar-scopestart))
222          (quotemode  (semantic-grammar-quotemode))
223          (tags       (semantic-find-tags-by-class
224                       'token (current-buffer)))
225          (nterms     (semantic-find-tags-by-class
226                       'nonterminal (current-buffer)))
227          ;; Setup the cache of macro definitions.
228          (bovine--grammar-macros (semantic-grammar-macros))
229          nterm rules items item actn prec tag type regex)
230
231     ;; Check some trivial things
232     (cond
233      ((null nterms)
234       (error "Bad input grammar"))
235      (start
236       (if (cdr start)
237           (message "Extra start symbols %S ignored" (cdr start)))
238       (setq start (symbol-name (car start)))
239       (unless (semantic-find-first-tag-by-name start nterms)
240         (error "start symbol `%s' has no rule" start)))
241      (t
242       ;; Default to the first grammar rule.
243       (setq start (semantic-tag-name (car nterms)))))
244     (when scopestart
245       (setq scopestart (symbol-name scopestart))
246       (unless (semantic-find-first-tag-by-name scopestart nterms)
247         (error "scopestart symbol `%s' has no rule" scopestart)))
248
249     ;; Generate the grammar Lisp form.
250     (with-temp-buffer
251       (erase-buffer)
252       (insert "`(")
253       ;; Insert the start/scopestart rules
254       (insert "\n(bovine-toplevel \n("
255               start
256               ")\n) ;; end bovine-toplevel\n")
257       (when scopestart
258         (insert "\n(bovine-inner-scope \n("
259                 scopestart
260                 ")\n) ;; end bovine-inner-scope\n"))
261       ;; Process each nonterminal
262       (while nterms
263         (setq nterm  (car nterms)
264               ;; We can't use the override form because the current buffer
265               ;; is not the originator of the tag.
266               rules  (semantic-tag-components-semantic-grammar-mode nterm)
267               nterm  (semantic-tag-name nterm)
268               nterms (cdr nterms))
269         (when (member nterm '("bovine-toplevel" "bovine-inner-scope"))
270           (error "`%s' is a reserved internal name" nterm))
271         (insert "\n(" nterm)
272         ;; Process each rule
273         (while rules
274           (setq items (semantic-tag-get-attribute (car rules) :value)
275                 prec  (semantic-tag-get-attribute (car rules) :prec)
276                 actn  (semantic-tag-get-attribute (car rules) :expr)
277                 rules (cdr rules))
278           ;; Process each item
279           (insert "\n(")
280           (if (null items)
281               ;; EMPTY rule
282               (insert ";;EMPTY" (if actn "" "\n"))
283             ;; Expand items
284             (while items
285               (setq item  (car items)
286                     items (cdr items))
287               (if (consp item) ;; mid-rule action
288                   (message "Mid-rule action %S ignored" item)
289                 (or (char-equal (char-before) ?\()
290                     (insert "\n"))
291                 (cond
292                  ((member item '("bovine-toplevel" "bovine-inner-scope"))
293                   (error "`%s' is a reserved internal name" item))
294                  ;; Replace ITEM by its %token definition.
295                  ;; If a '%token TYPE ITEM [REGEX]' definition exists
296                  ;; in the grammar, ITEM is replaced by TYPE [REGEX].
297                  ((setq tag (semantic-find-first-tag-by-name
298                              item tags)
299                         type  (semantic-tag-get-attribute tag :type))
300                   (insert type)
301                   (if (setq regex (semantic-tag-get-attribute tag :value))
302                       (insert (format "\n%S" regex))))
303                  ;; Don't change ITEM
304                  (t
305                   (insert (semantic-grammar-item-text item)))
306                  ))))
307           (if prec
308               (message "%%prec %S ignored" prec))
309           (if actn
310               (bovine-grammar-expand-action actn quotemode))
311           (insert ")"))
312         (insert "\n) ;; end " nterm "\n"))
313       (insert ")\n")
314       (buffer-string))))
315
316 (defun bovine-grammar-setupcode-builder ()
317   "Return the text of the setup code."
318   (format
319    "(setq semantic--parse-table %s\n\
320           semantic-debug-parser-source %S\n\
321           semantic-debug-parser-class 'semantic-bovine-debug-parser
322           semantic-flex-keywords-obarray %s\n\
323           %s)"
324    (semantic-grammar-parsetable)
325    (buffer-name)
326    (semantic-grammar-keywordtable)
327    (let ((mode (semantic-grammar-languagemode)))
328      ;; Is there more than one major mode?
329      (if (and (listp mode) (> (length mode) 1))
330          (format "semantic-equivalent-major-modes '%S\n" mode)
331        ""))))
332
333 (defvar bovine-grammar-menu
334   '("BY Grammar"
335     )
336   "BY mode specific grammar menu.
337 Menu items are appended to the common grammar menu.")
338
339 ;;;###autoload
340 (define-derived-mode bovine-grammar-mode semantic-grammar-mode "BY"
341   "Major mode for editing Bovine grammars."
342   (semantic-grammar-setup-menu bovine-grammar-menu)
343   (semantic-install-function-overrides
344    '((grammar-parsetable-builder . bovine-grammar-parsetable-builder)
345      (grammar-setupcode-builder  . bovine-grammar-setupcode-builder)
346      )))
347
348 ;;;###autoload
349 (add-to-list 'auto-mode-alist '("\\.by$" . bovine-grammar-mode))
350
351 ;;;###autoload
352 (eval-after-load "speedbar"
353   '(speedbar-add-supported-extension ".by"))
354
355 (provide 'bovine-grammar)
356
357 ;;; bovine-grammar.el ends here