Remove non-free old and crusty clearcase pkg
[packages] / xemacs-packages / semantic / semantic-lex-spp.el
1 ;;; semantic-lex-spp.el --- Semantic Lexical Pre-processor
2
3 ;;; Copyright (C) 2006, 2007 Eric M. Ludlam
4
5 ;; X-CVS: $Id: semantic-lex-spp.el,v 1.1 2007-11-26 15:10:40 michaels Exp $
6
7 ;; This file is not part of GNU Emacs.
8
9 ;; Semantic 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 2, or (at your option)
12 ;; any later version.
13
14 ;; This software is distributed in the hope that it will be useful,
15 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
16 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 ;; GNU General Public License for more details.
18
19 ;; You should have received a copy of the GNU General Public License
20 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
21 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 ;; Boston, MA 02110-1301, USA.
23
24 ;;; Commentary:
25 ;;
26 ;; The Semantic Preprocessor works with semantic-lex to provide a phase
27 ;; during lexical analysis to do the work of a pre-processor.
28 ;;
29 ;; A pre-processor identifies lexical syntax mixed in with another language
30 ;; and replaces some keyword tokens with streams of alternate tokens.
31 ;; 
32 ;; If you use SPP in your language, be sure to specify this in your
33 ;; semantic language setup function:
34 ;;
35 ;; (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t)
36 ;;
37 ;;; TODO:
38 ;;
39 ;; Use `semantic-push-parser-warning' for situations where there are likely
40 ;; macros that are undefined unexpectedly, or other problem.
41
42 (require 'semantic-lex)
43
44 ;;; Code:
45 (defvar semantic-lex-spp-macro-symbol-obarray nil
46   "Table of macro keywords used by the Semantic Macro.")
47 (make-variable-buffer-local 'semantic-lex-spp-macro-symbol-obarray)
48
49 (defvar semantic-lex-spp-dynamic-macro-symbol-obarray nil
50   "Table of macro keywords found during lexical analysis.
51 This table is then used by the macro during the lexical analysis
52 step.")
53 (make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray)
54
55 ;;; MACRO TABLE UTILS
56 ;;
57 (defun semantic-lex-spp-symbol-replacement (name)
58   "Return an SPP replacement stream for NAME.
59 nil is a valid return.  Use `semantic-lex-spp-symbol-l\p' to determine
60 if the symbol is in the table."
61   )
62
63 (defsubst semantic-lex-spp-symbol (name)
64   "Return spp symbol with NAME or nil if not found."
65   (and
66    (stringp name)
67    (or (and (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
68             (intern-soft name semantic-lex-spp-dynamic-macro-symbol-obarray))
69        (and (arrayp semantic-lex-spp-macro-symbol-obarray)
70             (intern-soft name semantic-lex-spp-macro-symbol-obarray)))))
71
72 (defsubst semantic-lex-spp-symbol-p (name)
73   "Return non-nil if a keyword with NAME exists in any keyword table."
74   (if (semantic-lex-spp-symbol name)
75       t))
76
77 (defsubst semantic-lex-spp-dynamic-map ()
78   "Return the dynamic macro map for the current buffer."
79   (or semantic-lex-spp-dynamic-macro-symbol-obarray
80       (setq semantic-lex-spp-dynamic-macro-symbol-obarray
81             (make-vector 13 0))))
82
83 (defsubst semantic-lex-spp-symbol-set (name value &optional obarray)
84   "Set value of spp symbol with NAME to VALUE and return VALUE.
85 If optional OBARRAY is non-nil, then use that obarray instead of
86 the dynamic map."
87   (if (string= value "") (setq value nil))
88   (set (intern name (or obarray
89                         (semantic-lex-spp-dynamic-map)))
90        value))
91
92 (defsubst semantic-lex-spp-symbol-remove (name &optional obarray)
93   "Remove the spp symbol with NAME.
94 If optional OBARRAY is non-nil, then use that obarray instead of
95 the dynamic map."
96   (unintern name (or obarray
97                      (semantic-lex-spp-dynamic-map))))
98
99 (defsubst semantic-lex-spp-symbol-stream (name)
100   "Return replacement stream of macro with NAME."
101   (let ((spp (semantic-lex-spp-symbol name)))
102     (if spp
103         (symbol-value spp))))
104
105 (defun semantic-lex-make-spp-table (specs)
106   "Convert spp macro list SPECS into an obarray and return it.
107 SPECS must be a list of (NAME . REPLACEMENT) elements, where:
108
109 NAME is the name of the spp macro symbol to define.
110 REPLACEMENT a string that would be substituted in for NAME."
111
112   ;; Create the symbol hash table
113   (let ((semantic-lex-spp-macro-symbol-obarray (make-vector 13 0))
114         spec)
115     ;; fill it with stuff
116     (while specs
117       (setq spec  (car specs)
118             specs (cdr specs))
119       (semantic-lex-spp-symbol-set
120        (car spec) 
121        (cdr spec)
122        semantic-lex-spp-macro-symbol-obarray))
123     semantic-lex-spp-macro-symbol-obarray))
124
125 (defun semantic-lex-spp-macros ()
126   "Return a list of spp macros as Lisp symbols.
127 The value of each symbol is the replacement stream."
128   (let (macros)
129     (when (arrayp semantic-lex-spp-macro-symbol-obarray)
130       (mapatoms
131        #'(lambda (symbol)
132            (setq macros (cons symbol macros)))
133        semantic-lex-spp-macro-symbol-obarray))
134     (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
135       (mapatoms
136        #'(lambda (symbol)
137            (setq macros (cons symbol macros)))
138        semantic-lex-spp-dynamic-macro-symbol-obarray))
139     macros))
140
141 (defun semantic-lex-spp-reset-dynamic-table ()
142   "Reset the dynamic spp symbol table.
143 This should be done before any new parsing step."
144   (setq semantic-lex-spp-dynamic-macro-symbol-obarray nil))
145
146 (defun semantic-lex-spp-reset-hook (start end)
147   "Reset anything needed by SPP for parsing.
148 In this case, reset the dynamic macro symbol table if
149 START recons the entire buffer.
150 END is not used."
151   (if (= start (point-min))
152       (setq semantic-lex-spp-dynamic-macro-symbol-obarray nil)))
153
154 ;;; MACRO EXPANSION PARSING
155 ;;
156 (defun semantic-lex-spp-string-to-macro-stream (val beg end)
157   "Convert string VAL into a macro expansion stream.
158 Argument VAL is the value of some macro to be converted into a stream.
159 BEG and END are the token bounds of the macro to be expanded
160 that will somehow gain a much longer token stream."
161   ;; NOTE: Must write this function!!!!!
162
163   ;; We perform a replacement.  Technically, this should
164   ;; be a full lexical step over the "val" string, but take
165   ;; a guess that its just a keyword or existing symbol.
166   ;;
167   ;; Probably a really bad idea.  See how it goes.
168   (semantic-lex-push-token
169    (semantic-lex-token (or (semantic-lex-keyword-p val) 'symbol)
170                        beg end
171                        val))
172   )
173
174
175 ;;; MACRO TABLE DEBUG
176 ;;
177 (defun semantic-lex-spp-describe (&optional buffer)
178   "Describe the current list of spp macros for BUFFER.
179 If BUFFER is not provided, use the current buffer."
180   (interactive)
181   (let ((syms (save-excursion
182                 (if buffer (set-buffer buffer))
183                 (semantic-lex-spp-macros)))
184         (sym nil))
185     (with-output-to-temp-buffer "*SPP MACROS*"
186       (princ "Macro\t\tValue\n")
187       (while syms
188         (setq sym (car syms)
189               syms (cdr syms))
190         (princ (symbol-name sym))
191         (princ "\t")
192         (if (< (length (symbol-name sym)) 8)
193             (princ "\t"))
194         (prin1 (symbol-value sym))
195         (princ "\n")
196         ))))
197
198
199 ;;; Analyzers
200 ;;
201 (define-lex-regex-analyzer semantic-lex-spp-replace-or-symbol-or-keyword
202   "Like 'semantic-lex-symbol-or-keyword' plus preprocessor macro replacement."
203   "\\(\\sw\\|\\s_\\)+"
204   (let ((str (match-string 0))
205         (beg (match-beginning 0))
206         (end (match-end 0)))
207     (if (semantic-lex-spp-symbol-p str)
208         ;; It is a macro.  Prepare for a replacement.
209         (let* ((sym (semantic-lex-spp-symbol str))
210                (val (symbol-value sym)))
211           (if (not val)
212               (setq semantic-lex-end-point end)
213             (semantic-lex-spp-string-to-macro-stream val beg end)
214             ))
215       ;; A regular keyword.
216       (semantic-lex-push-token
217        (semantic-lex-token (or (semantic-lex-keyword-p str) 'symbol)
218                            beg end)))))
219
220 (defmacro define-lex-spp-macro-declaration-analyzer (name doc regexp tokidx
221                                                           &rest valform)
222   "Define a lexical analyzer for defining new MACROS.
223 NAME is the name of the analyzer.
224 DOC is the documentation for the analyzer.
225 REGEXP is a regular expression for the analyzer to match.
226 See `define-lex-regex-analyzer' for more on regexp.
227 TOKIDX is an index into REGEXP for which a new lexical token
228 of type `spp-macro-def' is to be created.
229 Optional VALFORM are forms that return the value to be saved for
230 this macro, or nil."
231   (let ((start (make-symbol "start"))
232         (end (make-symbol "end"))
233         (val (make-symbol "val"))
234         (startpnt (make-symbol "startpnt"))
235         (endpnt (make-symbol "endpnt")))
236     `(define-lex-regex-analyzer ,name
237        ,doc
238        ,regexp
239        (let ((,start (match-beginning ,tokidx))
240              (,end (match-end ,tokidx))
241              (,startpnt semantic-lex-end-point)
242              (,val (save-match-data ,@valform))
243              (,endpnt semantic-lex-end-point))
244          (semantic-lex-spp-symbol-set
245           (buffer-substring-no-properties ,start ,end)
246           ,val)
247          (semantic-lex-push-token
248           (semantic-lex-token 'spp-macro-def
249                               ,start ,end))
250          ;; Preserve setting of the end point from the calling macro.
251          (when (and (/= ,startpnt ,endpnt)
252                     (/= ,endpnt semantic-lex-end-point))
253            (setq semantic-lex-end-point ,endpnt))
254          ))))
255
256 (defmacro define-lex-spp-macro-undeclaration-analyzer (name doc regexp tokidx)
257   "Undefine a lexical analyzer for defining new MACROS.
258 NAME is the name of the analyzer.
259 DOC is the documentation for the analyzer.
260 REGEXP is a regular expression for the analyzer to match.
261 See `define-lex-regex-analyzer' for more on regexp.
262 TOKIDX is an index into REGEXP for which a new lexical token
263 of type `spp-macro-undef' is to be created."
264   (let ((start (make-symbol "start"))
265         (end (make-symbol "end")))
266     `(define-lex-regex-analyzer ,name
267        ,doc
268        ,regexp
269        (let ((,start (match-beginning ,tokidx))
270              (,end (match-end ,tokidx)))
271          (semantic-lex-spp-symbol-remove
272           (buffer-substring-no-properties ,start ,end))
273          (semantic-lex-push-token
274           (semantic-lex-token 'spp-macro-undef
275                               ,start ,end))
276          ))))
277
278 (add-hook
279  'edebug-setup-hook
280  #'(lambda ()
281      
282      (def-edebug-spec define-lex-spp-macro-declaration-analyzer
283        (&define name stringp stringp form def-body)
284        )
285
286      (def-edebug-spec define-lex-spp-macro-undeclaration-analyzer
287        (&define name stringp stringp form def-body)
288        )
289      ))
290
291   
292 (provide 'semantic-lex-spp)
293
294 ;;; semantic-lex-spp.el ends here