1 ;;; semantic-lex-spp.el --- Semantic Lexical Pre-processor
3 ;;; Copyright (C) 2006, 2007 Eric M. Ludlam
5 ;; X-CVS: $Id: semantic-lex-spp.el,v 1.1 2007-11-26 15:10:40 michaels Exp $
7 ;; This file is not part of GNU Emacs.
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)
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.
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.
26 ;; The Semantic Preprocessor works with semantic-lex to provide a phase
27 ;; during lexical analysis to do the work of a pre-processor.
29 ;; A pre-processor identifies lexical syntax mixed in with another language
30 ;; and replaces some keyword tokens with streams of alternate tokens.
32 ;; If you use SPP in your language, be sure to specify this in your
33 ;; semantic language setup function:
35 ;; (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t)
39 ;; Use `semantic-push-parser-warning' for situations where there are likely
40 ;; macros that are undefined unexpectedly, or other problem.
42 (require 'semantic-lex)
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)
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
53 (make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray)
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."
63 (defsubst semantic-lex-spp-symbol (name)
64 "Return spp symbol with NAME or nil if not found."
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)))))
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)
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
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
87 (if (string= value "") (setq value nil))
88 (set (intern name (or obarray
89 (semantic-lex-spp-dynamic-map)))
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
96 (unintern name (or obarray
97 (semantic-lex-spp-dynamic-map))))
99 (defsubst semantic-lex-spp-symbol-stream (name)
100 "Return replacement stream of macro with NAME."
101 (let ((spp (semantic-lex-spp-symbol name)))
103 (symbol-value spp))))
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:
109 NAME is the name of the spp macro symbol to define.
110 REPLACEMENT a string that would be substituted in for NAME."
112 ;; Create the symbol hash table
113 (let ((semantic-lex-spp-macro-symbol-obarray (make-vector 13 0))
115 ;; fill it with stuff
117 (setq spec (car specs)
119 (semantic-lex-spp-symbol-set
122 semantic-lex-spp-macro-symbol-obarray))
123 semantic-lex-spp-macro-symbol-obarray))
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."
129 (when (arrayp semantic-lex-spp-macro-symbol-obarray)
132 (setq macros (cons symbol macros)))
133 semantic-lex-spp-macro-symbol-obarray))
134 (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray)
137 (setq macros (cons symbol macros)))
138 semantic-lex-spp-dynamic-macro-symbol-obarray))
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))
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.
151 (if (= start (point-min))
152 (setq semantic-lex-spp-dynamic-macro-symbol-obarray nil)))
154 ;;; MACRO EXPANSION PARSING
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!!!!!
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.
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)
175 ;;; MACRO TABLE DEBUG
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."
181 (let ((syms (save-excursion
182 (if buffer (set-buffer buffer))
183 (semantic-lex-spp-macros)))
185 (with-output-to-temp-buffer "*SPP MACROS*"
186 (princ "Macro\t\tValue\n")
190 (princ (symbol-name sym))
192 (if (< (length (symbol-name sym)) 8)
194 (prin1 (symbol-value sym))
201 (define-lex-regex-analyzer semantic-lex-spp-replace-or-symbol-or-keyword
202 "Like 'semantic-lex-symbol-or-keyword' plus preprocessor macro replacement."
204 (let ((str (match-string 0))
205 (beg (match-beginning 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)))
212 (setq semantic-lex-end-point end)
213 (semantic-lex-spp-string-to-macro-stream val beg end)
215 ;; A regular keyword.
216 (semantic-lex-push-token
217 (semantic-lex-token (or (semantic-lex-keyword-p str) 'symbol)
220 (defmacro define-lex-spp-macro-declaration-analyzer (name doc regexp tokidx
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
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
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)
247 (semantic-lex-push-token
248 (semantic-lex-token 'spp-macro-def
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))
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
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
282 (def-edebug-spec define-lex-spp-macro-declaration-analyzer
283 (&define name stringp stringp form def-body)
286 (def-edebug-spec define-lex-spp-macro-undeclaration-analyzer
287 (&define name stringp stringp form def-body)
292 (provide 'semantic-lex-spp)
294 ;;; semantic-lex-spp.el ends here