Commit | Line | Data |
---|---|---|
994e5cea | 1 | ;;; lex-spp.el --- Semantic Lexical Pre-processor |
7a0e7d33 | 2 | |
9bf6c65c | 3 | ;; Copyright (C) 2006, 2007, 2008, 2009 Free Software Foundation, Inc. |
7a0e7d33 CY |
4 | |
5 | ;; Author: Eric M. Ludlam <zappo@gnu.org> | |
6 | ||
7 | ;; This file is part of GNU Emacs. | |
8 | ||
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 | ||
14 | ;; GNU Emacs 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. If not, see <http://www.gnu.org/licenses/>. | |
21 | ||
22 | ;;; Commentary: | |
23 | ;; | |
24 | ;; The Semantic Preprocessor works with semantic-lex to provide a phase | |
25 | ;; during lexical analysis to do the work of a pre-processor. | |
26 | ;; | |
27 | ;; A pre-processor identifies lexical syntax mixed in with another language | |
28 | ;; and replaces some keyword tokens with streams of alternate tokens. | |
29 | ;; | |
30 | ;; If you use SPP in your language, be sure to specify this in your | |
31 | ;; semantic language setup function: | |
32 | ;; | |
33 | ;; (add-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook nil t) | |
34 | ;; | |
35 | ;; | |
36 | ;; Special Lexical Tokens: | |
37 | ;; | |
38 | ;; There are several special lexical tokens that are used by the | |
39 | ;; Semantic PreProcessor lexer. They are: | |
40 | ;; | |
41 | ;; Declarations: | |
42 | ;; spp-macro-def - A definition of a lexical macro. | |
43 | ;; spp-macro-undef - A removal of a definition of a lexical macro. | |
44 | ;; spp-system-include - A system level include file | |
45 | ;; spp-include - An include file | |
46 | ;; spp-concat - A lexical token representing textual concatenation | |
47 | ;; of symbol parts. | |
48 | ;; | |
49 | ;; Operational tokens: | |
50 | ;; spp-arg-list - Represents an argument list to a macro. | |
51 | ;; spp-symbol-merge - A request for multiple symbols to be textually merged. | |
52 | ;; | |
53 | ;;; TODO: | |
54 | ;; | |
55 | ;; Use `semantic-push-parser-warning' for situations where there are likely | |
56 | ;; macros that are undefined unexpectedly, or other problem. | |
57 | ;; | |
58 | ;; TODO: | |
59 | ;; | |
60 | ;; Try to handle the case of: | |
61 | ;; | |
62 | ;; #define NN namespace nn { | |
63 | ;; #define NN_END } | |
64 | ;; | |
65 | ;; NN | |
66 | ;; int mydecl() {} | |
67 | ;; NN_END | |
68 | ;; | |
69 | ||
55b522b2 | 70 | (require 'semantic) |
7a0e7d33 CY |
71 | (require 'semantic/lex) |
72 | ||
73 | ;;; Code: | |
74 | (defvar semantic-lex-spp-macro-symbol-obarray nil | |
75 | "Table of macro keywords used by the Semantic Preprocessor. | |
76 | These symbols will be used in addition to those in | |
77 | `semantic-lex-spp-dynamic-macro-symbol-obarray'.") | |
78 | (make-variable-buffer-local 'semantic-lex-spp-macro-symbol-obarray) | |
79 | ||
80 | (defvar semantic-lex-spp-project-macro-symbol-obarray nil | |
81 | "Table of macro keywords for this project. | |
82 | These symbols will be used in addition to those in | |
83 | `semantic-lex-spp-dynamic-macro-symbol-obarray'.") | |
84 | (make-variable-buffer-local 'semantic-lex-spp-project-macro-symbol-obarray) | |
85 | ||
86 | (defvar semantic-lex-spp-dynamic-macro-symbol-obarray nil | |
87 | "Table of macro keywords used during lexical analysis. | |
88 | Macros are lexical symbols which are replaced by other lexical | |
89 | tokens during lexical analysis. During analysis symbols can be | |
90 | added and removed from this symbol table.") | |
91 | (make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray) | |
92 | ||
93 | (defvar semantic-lex-spp-dynamic-macro-symbol-obarray-stack nil | |
9bf6c65c | 94 | "A stack of obarrays for temporarily scoped macro values.") |
7a0e7d33 CY |
95 | (make-variable-buffer-local 'semantic-lex-spp-dynamic-macro-symbol-obarray-stack) |
96 | ||
97 | (defvar semantic-lex-spp-expanded-macro-stack nil | |
98 | "The stack of lexical SPP macros we have expanded.") | |
99 | ;; The above is not buffer local. Some macro expansions need to be | |
100 | ;; dumped into a secondary buffer for re-lexing. | |
101 | ||
102 | ;;; NON-RECURSIVE MACRO STACK | |
103 | ;; C Pre-processor does not allow recursive macros. Here are some utils | |
104 | ;; for managing the symbol stack of where we've been. | |
105 | ||
106 | (defmacro semantic-lex-with-macro-used (name &rest body) | |
107 | "With the macro NAME currently being expanded, execute BODY. | |
108 | Pushes NAME into the macro stack. The above stack is checked | |
109 | by `semantic-lex-spp-symbol' to not return true for any symbol | |
110 | currently being expanded." | |
111 | `(unwind-protect | |
112 | (progn | |
113 | (push ,name semantic-lex-spp-expanded-macro-stack) | |
114 | ,@body) | |
115 | (pop semantic-lex-spp-expanded-macro-stack))) | |
116 | (put 'semantic-lex-with-macro-used 'lisp-indent-function 1) | |
117 | ||
118 | (add-hook | |
119 | 'edebug-setup-hook | |
120 | #'(lambda () | |
121 | ||
122 | (def-edebug-spec semantic-lex-with-macro-used | |
123 | (symbolp def-body) | |
124 | ) | |
125 | ||
126 | )) | |
127 | ||
128 | ;;; MACRO TABLE UTILS | |
129 | ;; | |
130 | ;; The dynamic macro table is a buffer local variable that is modified | |
131 | ;; during the analysis. OBARRAYs are used, so the language must | |
132 | ;; have symbols that are compatible with Emacs Lisp symbols. | |
133 | ;; | |
134 | (defsubst semantic-lex-spp-symbol (name) | |
135 | "Return spp symbol with NAME or nil if not found. | |
9bf6c65c | 136 | The search priority is: |
7a0e7d33 CY |
137 | 1. DYNAMIC symbols |
138 | 2. PROJECT specified symbols. | |
139 | 3. SYSTEM specified symbols." | |
140 | (and | |
141 | ;; Only strings... | |
142 | (stringp name) | |
143 | ;; Make sure we don't recurse. | |
144 | (not (member name semantic-lex-spp-expanded-macro-stack)) | |
145 | ;; Do the check of the various tables. | |
146 | (or | |
147 | ;; DYNAMIC | |
148 | (and (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray) | |
149 | (intern-soft name semantic-lex-spp-dynamic-macro-symbol-obarray)) | |
150 | ;; PROJECT | |
151 | (and (arrayp semantic-lex-spp-project-macro-symbol-obarray) | |
152 | (intern-soft name semantic-lex-spp-project-macro-symbol-obarray)) | |
153 | ;; SYSTEM | |
154 | (and (arrayp semantic-lex-spp-macro-symbol-obarray) | |
155 | (intern-soft name semantic-lex-spp-macro-symbol-obarray)) | |
156 | ;; ... | |
157 | ))) | |
158 | ||
159 | (defsubst semantic-lex-spp-symbol-p (name) | |
160 | "Return non-nil if a keyword with NAME exists in any keyword table." | |
161 | (if (semantic-lex-spp-symbol name) | |
162 | t)) | |
163 | ||
164 | (defsubst semantic-lex-spp-dynamic-map () | |
165 | "Return the dynamic macro map for the current buffer." | |
166 | (or semantic-lex-spp-dynamic-macro-symbol-obarray | |
167 | (setq semantic-lex-spp-dynamic-macro-symbol-obarray | |
168 | (make-vector 13 0)))) | |
169 | ||
170 | (defsubst semantic-lex-spp-dynamic-map-stack () | |
171 | "Return the dynamic macro map for the current buffer." | |
172 | (or semantic-lex-spp-dynamic-macro-symbol-obarray-stack | |
173 | (setq semantic-lex-spp-dynamic-macro-symbol-obarray-stack | |
174 | (make-vector 13 0)))) | |
175 | ||
176 | (defun semantic-lex-spp-symbol-set (name value &optional obarray-in) | |
177 | "Set value of spp symbol with NAME to VALUE and return VALUE. | |
178 | If optional OBARRAY-IN is non-nil, then use that obarray instead of | |
179 | the dynamic map." | |
180 | (if (and (stringp value) (string= value "")) (setq value nil)) | |
181 | (set (intern name (or obarray-in | |
182 | (semantic-lex-spp-dynamic-map))) | |
183 | value)) | |
184 | ||
185 | (defsubst semantic-lex-spp-symbol-remove (name &optional obarray) | |
186 | "Remove the spp symbol with NAME. | |
187 | If optional OBARRAY is non-nil, then use that obarray instead of | |
188 | the dynamic map." | |
189 | (unintern name (or obarray | |
190 | (semantic-lex-spp-dynamic-map)))) | |
191 | ||
192 | (defun semantic-lex-spp-symbol-push (name value) | |
193 | "Push macro NAME with VALUE into the map. | |
194 | Reverse with `semantic-lex-spp-symbol-pop'." | |
195 | (let* ((map (semantic-lex-spp-dynamic-map)) | |
196 | (stack (semantic-lex-spp-dynamic-map-stack)) | |
197 | (mapsym (intern name map)) | |
198 | (stacksym (intern name stack)) | |
199 | (mapvalue (when (boundp mapsym) (symbol-value mapsym))) | |
200 | ) | |
201 | (when (boundp mapsym) | |
202 | ;; Make sure there is a stack | |
203 | (if (not (boundp stacksym)) (set stacksym nil)) | |
204 | ;; If there is a value to push, then push it. | |
205 | (set stacksym (cons mapvalue (symbol-value stacksym))) | |
206 | ) | |
207 | ;; Set our new value here. | |
208 | (set mapsym value) | |
209 | )) | |
210 | ||
211 | (defun semantic-lex-spp-symbol-pop (name) | |
212 | "Pop macro NAME from the stackmap into the orig map. | |
213 | Reverse with `semantic-lex-spp-symbol-pop'." | |
214 | (let* ((map (semantic-lex-spp-dynamic-map)) | |
215 | (stack (semantic-lex-spp-dynamic-map-stack)) | |
216 | (mapsym (intern name map)) | |
217 | (stacksym (intern name stack)) | |
218 | (oldvalue nil) | |
219 | ) | |
220 | (if (or (not (boundp stacksym) ) | |
221 | (= (length (symbol-value stacksym)) 0)) | |
222 | ;; Nothing to pop, remove it. | |
223 | (unintern name map) | |
224 | ;; If there is a value to pop, then add it to the map. | |
225 | (set mapsym (car (symbol-value stacksym))) | |
226 | (set stacksym (cdr (symbol-value stacksym))) | |
227 | ))) | |
228 | ||
229 | (defsubst semantic-lex-spp-symbol-stream (name) | |
230 | "Return replacement stream of macro with NAME." | |
231 | (let ((spp (semantic-lex-spp-symbol name))) | |
232 | (if spp | |
233 | (symbol-value spp)))) | |
234 | ||
235 | (defun semantic-lex-make-spp-table (specs) | |
236 | "Convert spp macro list SPECS into an obarray and return it. | |
237 | SPECS must be a list of (NAME . REPLACEMENT) elements, where: | |
238 | ||
239 | NAME is the name of the spp macro symbol to define. | |
240 | REPLACEMENT a string that would be substituted in for NAME." | |
241 | ||
242 | ;; Create the symbol hash table | |
243 | (let ((semantic-lex-spp-macro-symbol-obarray (make-vector 13 0)) | |
244 | spec) | |
245 | ;; fill it with stuff | |
246 | (while specs | |
247 | (setq spec (car specs) | |
248 | specs (cdr specs)) | |
249 | (semantic-lex-spp-symbol-set | |
250 | (car spec) | |
251 | (cdr spec) | |
252 | semantic-lex-spp-macro-symbol-obarray)) | |
253 | semantic-lex-spp-macro-symbol-obarray)) | |
254 | ||
255 | (defun semantic-lex-spp-save-table () | |
256 | "Return a list of spp macros and values. | |
257 | The return list is meant to be saved in a semanticdb table." | |
258 | (let (macros) | |
259 | (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray) | |
260 | (mapatoms | |
261 | #'(lambda (symbol) | |
262 | (setq macros (cons (cons (symbol-name symbol) | |
263 | (symbol-value symbol)) | |
264 | macros))) | |
265 | semantic-lex-spp-dynamic-macro-symbol-obarray)) | |
266 | macros)) | |
267 | ||
268 | (defun semantic-lex-spp-macros () | |
269 | "Return a list of spp macros as Lisp symbols. | |
270 | The value of each symbol is the replacement stream." | |
271 | (let (macros) | |
272 | (when (arrayp semantic-lex-spp-macro-symbol-obarray) | |
273 | (mapatoms | |
274 | #'(lambda (symbol) | |
275 | (setq macros (cons symbol macros))) | |
276 | semantic-lex-spp-macro-symbol-obarray)) | |
277 | (when (arrayp semantic-lex-spp-project-macro-symbol-obarray) | |
278 | (mapatoms | |
279 | #'(lambda (symbol) | |
280 | (setq macros (cons symbol macros))) | |
281 | semantic-lex-spp-project-macro-symbol-obarray)) | |
282 | (when (arrayp semantic-lex-spp-dynamic-macro-symbol-obarray) | |
283 | (mapatoms | |
284 | #'(lambda (symbol) | |
285 | (setq macros (cons symbol macros))) | |
286 | semantic-lex-spp-dynamic-macro-symbol-obarray)) | |
287 | macros)) | |
288 | ||
289 | (defun semantic-lex-spp-set-dynamic-table (new-entries) | |
290 | "Set the dynamic symbol table to NEW-ENTRIES. | |
291 | For use with semanticdb restoration of state." | |
292 | (dolist (e new-entries) | |
293 | ;; Default obarray for below is the dynamic map. | |
294 | (semantic-lex-spp-symbol-set (car e) (cdr e)))) | |
295 | ||
296 | (defun semantic-lex-spp-reset-hook (start end) | |
297 | "Reset anything needed by SPP for parsing. | |
298 | In this case, reset the dynamic macro symbol table if | |
299 | START is (point-min). | |
300 | END is not used." | |
301 | (when (= start (point-min)) | |
302 | (setq semantic-lex-spp-dynamic-macro-symbol-obarray nil | |
303 | semantic-lex-spp-dynamic-macro-symbol-obarray-stack nil | |
304 | ;; This shouldn't not be nil, but reset just in case. | |
305 | semantic-lex-spp-expanded-macro-stack nil) | |
306 | )) | |
307 | ||
308 | ;;; MACRO EXPANSION: Simple cases | |
309 | ;; | |
310 | ;; If a user fills in the table with simple strings, we can | |
311 | ;; support that by converting them into tokens with the | |
312 | ;; various analyzers that are available. | |
313 | ||
314 | (defun semantic-lex-spp-extract-regex-and-compare (analyzer value) | |
315 | "Extract a regexp from an ANALYZER and use to match VALUE. | |
316 | Return non-nil if it matches" | |
317 | (let* ((condition (car analyzer)) | |
318 | (regex (cond ((eq (car condition) 'looking-at) | |
319 | (nth 1 condition)) | |
320 | (t | |
321 | nil)))) | |
322 | (when regex | |
323 | (string-match regex value)) | |
324 | )) | |
325 | ||
326 | (defun semantic-lex-spp-simple-macro-to-macro-stream (val beg end argvalues) | |
327 | "Convert lexical macro contents VAL into a macro expansion stream. | |
328 | These are for simple macro expansions that a user may have typed in directly. | |
329 | As such, we need to analyze the input text, to figure out what kind of real | |
330 | lexical token we should be inserting in its place. | |
331 | ||
332 | Argument VAL is the value of some macro to be converted into a stream. | |
333 | BEG and END are the token bounds of the macro to be expanded | |
334 | that will somehow gain a much longer token stream. | |
335 | ARGVALUES are values for any arg list, or nil." | |
336 | (cond | |
337 | ;; We perform a replacement. Technically, this should | |
338 | ;; be a full lexical step over the "val" string, but take | |
339 | ;; a guess that its just a keyword or existing symbol. | |
340 | ;; | |
341 | ;; Probably a really bad idea. See how it goes. | |
342 | ((semantic-lex-spp-extract-regex-and-compare | |
343 | semantic-lex-symbol-or-keyword val) | |
344 | (semantic-lex-push-token | |
345 | (semantic-lex-token (or (semantic-lex-keyword-p val) 'symbol) | |
346 | beg end | |
347 | val))) | |
348 | ||
349 | ;; Ok, the rest of these are various types of syntax. | |
350 | ;; Conveniences for users that type in their symbol table. | |
351 | ((semantic-lex-spp-extract-regex-and-compare | |
352 | semantic-lex-punctuation val) | |
353 | (semantic-lex-token 'punctuation beg end val)) | |
354 | ((semantic-lex-spp-extract-regex-and-compare | |
355 | semantic-lex-number val) | |
356 | (semantic-lex-token 'number beg end val)) | |
357 | ((semantic-lex-spp-extract-regex-and-compare | |
358 | semantic-lex-paren-or-list val) | |
359 | (semantic-lex-token 'semantic-list beg end val)) | |
360 | ((semantic-lex-spp-extract-regex-and-compare | |
361 | semantic-lex-string val) | |
362 | (semantic-lex-token 'string beg end val)) | |
363 | (t nil) | |
364 | )) | |
365 | ||
366 | ;;; MACRO EXPANSION : Lexical token replacement | |
367 | ;; | |
368 | ;; When substituting in a macro from a token stream of formatted | |
369 | ;; semantic lex tokens, things can be much more complicated. | |
370 | ;; | |
371 | ;; Some macros have arguments that get set into the dynamic macro | |
372 | ;; table during replacement. | |
373 | ;; | |
374 | ;; In general, the macro tokens are substituted into the regular | |
375 | ;; token stream, but placed under the characters of the original | |
376 | ;; macro symbol. | |
377 | ;; | |
378 | ;; Argument lists are saved as a lexical token at the beginning | |
379 | ;; of a replacement value. | |
380 | ||
a6d7d3ef | 381 | (defun semantic-lex-spp-one-token-to-txt (tok &optional blocktok) |
7a0e7d33 CY |
382 | "Convert the token TOK into a string. |
383 | If TOK is made of multiple tokens, convert those to text. This | |
384 | conversion is needed if a macro has a merge symbol in it that | |
385 | combines the text of two previously distinct symbols. For | |
9bf6c65c | 386 | example, in c: |
7a0e7d33 | 387 | |
a6d7d3ef CY |
388 | #define (a,b) a ## b; |
389 | ||
390 | If optional string BLOCKTOK matches the expanded value, then do not | |
391 | continue processing recursively." | |
7a0e7d33 CY |
392 | (let ((txt (semantic-lex-token-text tok)) |
393 | (sym nil) | |
394 | ) | |
a6d7d3ef CY |
395 | (cond |
396 | ;; Recursion prevention | |
397 | ((and (stringp blocktok) (string= txt blocktok)) | |
398 | blocktok) | |
399 | ;; A complex symbol | |
400 | ((and (eq (car tok) 'symbol) | |
401 | (setq sym (semantic-lex-spp-symbol txt)) | |
402 | (not (semantic-lex-spp-macro-with-args (symbol-value sym))) | |
403 | ) | |
404 | ;; Now that we have a symbol, | |
405 | (let ((val (symbol-value sym))) | |
406 | (cond | |
407 | ;; This is another lexical token. | |
408 | ((and (consp val) | |
409 | (symbolp (car val))) | |
410 | (semantic-lex-spp-one-token-to-txt val txt)) | |
411 | ;; This is a list of tokens. | |
412 | ((and (consp val) | |
413 | (consp (car val)) | |
414 | (symbolp (car (car val)))) | |
415 | (mapconcat (lambda (subtok) | |
416 | (semantic-lex-spp-one-token-to-txt subtok)) | |
417 | val | |
418 | "")) | |
419 | ;; If val is nil, that's probably wrong. | |
420 | ;; Found a system header case where this was true. | |
421 | ((null val) "") | |
422 | ;; Debug wierd stuff. | |
423 | (t (debug))) | |
424 | )) | |
425 | ((stringp txt) | |
426 | txt) | |
427 | (t nil)) | |
7a0e7d33 CY |
428 | )) |
429 | ||
430 | (defun semantic-lex-spp-macro-with-args (val) | |
431 | "If the macro value VAL has an argument list, return the arglist." | |
432 | (when (and val (consp val) (consp (car val)) | |
433 | (eq 'spp-arg-list (car (car val)))) | |
434 | (car (cdr (car val))))) | |
435 | ||
436 | (defun semantic-lex-spp-token-macro-to-macro-stream (val beg end argvalues) | |
437 | "Convert lexical macro contents VAL into a macro expansion stream. | |
438 | Argument VAL is the value of some macro to be converted into a stream. | |
439 | BEG and END are the token bounds of the macro to be expanded | |
440 | that will somehow gain a much longer token stream. | |
441 | ARGVALUES are values for any arg list, or nil. | |
442 | See comments in code for information about how token streams are processed | |
443 | and what valid VAL values are." | |
444 | ||
445 | ;; A typical VAL value might be either a stream of tokens. | |
446 | ;; Tokens saved into a macro stream always includes the text from the | |
447 | ;; buffer, since the locations specified probably don't represent | |
448 | ;; that text anymore, or even the same buffer. | |
449 | ;; | |
450 | ;; CASE 1: Simple token stream | |
451 | ;; | |
452 | ;; #define SUPER mysuper:: | |
453 | ;; ==> | |
454 | ;;((symbol "mysuper" 480 . 487) | |
455 | ;; (punctuation ":" 487 . 488) | |
456 | ;; (punctuation ":" 488 . 489)) | |
457 | ;; | |
458 | ;; CASE 2: Token stream with argument list | |
459 | ;; | |
460 | ;; #define INT_FCN(name) int name (int in) | |
461 | ;; ==> | |
462 | ;; ((spp-arg-list ("name") 558 . 564) | |
463 | ;; (INT "int" 565 . 568) | |
464 | ;; (symbol "name" 569 . 573) | |
465 | ;; (semantic-list "(int in)" 574 . 582)) | |
466 | ;; | |
467 | ;; In the second case, a macro with an argument list as the a rgs as the | |
468 | ;; first entry. | |
469 | ;; | |
470 | ;; CASE 3: Symbol text merge | |
471 | ;; | |
472 | ;; #define TMP(a) foo_ ## a | |
473 | ;; ==> | |
474 | ;; ((spp-arg-list ("a") 20 . 23) | |
475 | ;; (spp-symbol-merge ((symbol "foo_" 24 . 28) (symbol "a" 32 . 33)) | |
476 | ;; 24 . 33)) | |
477 | ;; | |
478 | ;; Usually in conjunction with a macro with an argument, merging symbol | |
479 | ;; parts is a way of fabricating new symbols from pieces inside the macro. | |
480 | ;; These macros use `spp-symbol-merge' tokens whose TEXT part is another | |
481 | ;; token stream. This sub-stream ought to consist of only 2 SYMBOL pieces, | |
482 | ;; though I suppose keywords might be ok. The end result of this example | |
483 | ;; merge symbol would be (symbol "foo_A" 24 . 33) where A is the symbol | |
484 | ;; passed in from the arg list "a". | |
485 | ;; | |
486 | ;; CASE 4: Nested token streams | |
487 | ;; | |
488 | ;; #define FOO(f) f | |
489 | ;; #define BLA bla FOO(foo) | |
490 | ;; ==> | |
491 | ;; ((INT "int" 82 . 85) | |
492 | ;; (symbol "FOO" 86 . 89) | |
493 | ;; (semantic-list "(foo)" 89 . 94)) | |
494 | ;; | |
495 | ;; Nested token FOO shows up in the table of macros, and gets replace | |
496 | ;; inline. This is the same as case 2. | |
497 | ||
498 | (let ((arglist (semantic-lex-spp-macro-with-args val)) | |
499 | (argalist nil) | |
500 | (val-tmp nil) | |
501 | (v nil) | |
502 | ) | |
503 | ;; CASE 2: Dealing with the arg list. | |
504 | (when arglist | |
505 | ;; Skip the arg list. | |
506 | (setq val (cdr val)) | |
507 | ||
508 | ;; Push args into the replacement list. | |
509 | (let ((AV argvalues)) | |
510 | (dolist (A arglist) | |
511 | (let* ((argval (car AV))) | |
512 | ||
513 | (semantic-lex-spp-symbol-push A argval) | |
514 | (setq argalist (cons (cons A argval) argalist)) | |
515 | (setq AV (cdr AV))))) | |
516 | ) | |
517 | ||
518 | ;; Set val-tmp after stripping arguments. | |
519 | (setq val-tmp val) | |
520 | ||
521 | ;; CASE 1: Push everything else onto the list. | |
522 | ;; Once the arg list is stripped off, CASE 2 is the same | |
523 | ;; as CASE 1. | |
524 | (while val-tmp | |
525 | (setq v (car val-tmp)) | |
526 | (setq val-tmp (cdr val-tmp)) | |
527 | ||
528 | (let* (;; The text of the current lexical token. | |
529 | (txt (car (cdr v))) | |
530 | ;; Try to convert txt into a macro declaration. If it is | |
531 | ;; not a macro, use nil. | |
532 | (txt-macro-or-nil (semantic-lex-spp-symbol txt)) | |
533 | ;; If our current token is a macro, then pull off the argument | |
534 | ;; list. | |
535 | (macro-and-args | |
536 | (when txt-macro-or-nil | |
537 | (semantic-lex-spp-macro-with-args (symbol-value txt-macro-or-nil))) | |
538 | ) | |
539 | ;; We need to peek at the next token when testing for | |
540 | ;; used macros with arg lists. | |
541 | (next-tok-class (semantic-lex-token-class (car val-tmp))) | |
542 | ) | |
543 | ||
544 | (cond | |
545 | ;; CASE 3: Merge symbols together. | |
546 | ((eq (semantic-lex-token-class v) 'spp-symbol-merge) | |
547 | ;; We need to merge the tokens in the 'text segement together, | |
548 | ;; and produce a single symbol from it. | |
549 | (let ((newsym | |
550 | (mapconcat (lambda (tok) | |
551 | (semantic-lex-spp-one-token-to-txt tok)) | |
552 | txt | |
553 | ""))) | |
554 | (semantic-lex-push-token | |
555 | (semantic-lex-token 'symbol beg end newsym)) | |
556 | )) | |
557 | ||
558 | ;; CASE 2: Argument replacement. If a discovered symbol is in | |
559 | ;; the active list of arguments, then we need to substitute | |
560 | ;; in the new value. | |
561 | ((and (eq (semantic-lex-token-class v) 'symbol) txt-macro-or-nil | |
562 | (or (and macro-and-args (eq next-tok-class 'semantic-list)) | |
563 | (not macro-and-args)) | |
564 | ) | |
565 | (let ((AV nil)) | |
566 | (when macro-and-args | |
567 | (setq AV | |
568 | (semantic-lex-spp-stream-for-arglist (car val-tmp))) | |
569 | ;; We used up these args. Pull from the stream. | |
570 | (setq val-tmp (cdr val-tmp)) | |
571 | ) | |
572 | ||
573 | (semantic-lex-with-macro-used txt | |
574 | ;; Don't recurse directly into this same fcn, because it is | |
575 | ;; convenient to have plain string replacements too. | |
576 | (semantic-lex-spp-macro-to-macro-stream | |
577 | (symbol-value txt-macro-or-nil) | |
578 | beg end AV)) | |
579 | )) | |
580 | ||
581 | ;; This is a HACK for the C parser. The 'macros text | |
582 | ;; property is some storage so that the parser can do | |
583 | ;; some C specific text manipulations. | |
584 | ((eq (semantic-lex-token-class v) 'semantic-list) | |
585 | ;; Push our arg list onto the semantic list. | |
586 | (when argalist | |
587 | (setq txt (concat txt)) ; Copy the text. | |
588 | (put-text-property 0 1 'macros argalist txt)) | |
589 | (semantic-lex-push-token | |
590 | (semantic-lex-token (semantic-lex-token-class v) beg end txt)) | |
591 | ) | |
592 | ||
593 | ;; CASE 1: Just another token in the stream. | |
594 | (t | |
595 | ;; Nothing new. | |
596 | (semantic-lex-push-token | |
597 | (semantic-lex-token (semantic-lex-token-class v) beg end txt)) | |
598 | ) | |
599 | ))) | |
600 | ||
601 | ;; CASE 2: The arg list we pushed onto the symbol table | |
602 | ;; must now be removed. | |
603 | (dolist (A arglist) | |
604 | (semantic-lex-spp-symbol-pop A)) | |
605 | )) | |
606 | ||
607 | ;;; Macro Merging | |
608 | ;; | |
609 | ;; Used when token streams from different macros include eachother. | |
610 | ;; Merged macro streams perform in place replacements. | |
611 | ||
612 | (defun semantic-lex-spp-merge-streams (raw-stream) | |
613 | "Merge elements from the RAW-STREAM together. | |
614 | Handle spp-concat symbol concatenation. | |
615 | Handle Nested macro replacements. | |
616 | Return the cooked stream." | |
617 | (let ((cooked-stream nil)) | |
618 | ;; Merge the stream | |
619 | (while raw-stream | |
620 | (cond ((eq (semantic-lex-token-class (car raw-stream)) 'spp-concat) | |
621 | ;; handle hashhash, by skipping it. | |
622 | (setq raw-stream (cdr raw-stream)) | |
623 | ;; Now merge the symbols. | |
624 | (let ((prev-tok (car cooked-stream)) | |
625 | (next-tok (car raw-stream))) | |
626 | (setq cooked-stream (cdr cooked-stream)) | |
627 | (push (semantic-lex-token | |
628 | 'spp-symbol-merge | |
629 | (semantic-lex-token-start prev-tok) | |
630 | (semantic-lex-token-end next-tok) | |
631 | (list prev-tok next-tok)) | |
632 | cooked-stream) | |
633 | )) | |
634 | (t | |
635 | (push (car raw-stream) cooked-stream)) | |
636 | ) | |
637 | (setq raw-stream (cdr raw-stream)) | |
638 | ) | |
639 | ||
640 | (nreverse cooked-stream)) | |
641 | ) | |
642 | ||
643 | ;;; MACRO EXPANSION | |
644 | ;; | |
645 | ;; There are two types of expansion. | |
646 | ;; | |
647 | ;; 1. Expansion using a value made up of lexical tokens. | |
648 | ;; 2. User input replacement from a plain string. | |
649 | ||
650 | (defun semantic-lex-spp-macro-to-macro-stream (val beg end argvalues) | |
651 | "Convert lexical macro contents VAL into a macro expansion stream. | |
652 | Argument VAL is the value of some macro to be converted into a stream. | |
653 | BEG and END are the token bounds of the macro to be expanded | |
654 | that will somehow gain a much longer token stream. | |
655 | ARGVALUES are values for any arg list, or nil." | |
656 | (cond | |
657 | ;; If val is nil, then just skip it. | |
658 | ((null val) t) | |
659 | ;; If it is a token, then return that token rebuilt. | |
660 | ((and (consp val) (car val) (symbolp (car val))) | |
661 | (semantic-lex-push-token | |
662 | (semantic-lex-token (car val) beg end (semantic-lex-token-text val)))) | |
663 | ;; Test for a token list. | |
664 | ((and (consp val) (consp (car val)) (car (car val)) | |
665 | (symbolp (car (car val)))) | |
666 | (semantic-lex-spp-token-macro-to-macro-stream val beg end argvalues)) | |
667 | ;; Test for miscellaneous strings. | |
668 | ((stringp val) | |
669 | (semantic-lex-spp-simple-macro-to-macro-stream val beg end argvalues)) | |
670 | )) | |
671 | ||
672 | ;;; -------------------------------------------------------- | |
673 | ;;; | |
674 | ;;; ANALYZERS: | |
675 | ;;; | |
676 | ||
677 | ;;; Symbol Is Macro | |
678 | ;; | |
679 | ;; An analyser that will push tokens from a macro in place | |
680 | ;; of the macro symbol. | |
681 | ;; | |
682 | (defun semantic-lex-spp-anlyzer-do-replace (sym val beg end) | |
683 | "Do the lexical replacement for SYM with VAL. | |
684 | Argument BEG and END specify the bounds of SYM in the buffer." | |
685 | (if (not val) | |
686 | (setq semantic-lex-end-point end) | |
687 | (let ((arg-in nil) | |
688 | (arg-parsed nil) | |
689 | (arg-split nil) | |
690 | ) | |
691 | ||
692 | ;; Check for arguments. | |
693 | (setq arg-in (semantic-lex-spp-macro-with-args val)) | |
694 | ||
695 | (when arg-in | |
696 | (save-excursion | |
697 | (goto-char end) | |
698 | (setq arg-parsed | |
699 | (semantic-lex-spp-one-token-and-move-for-macro | |
8d106ea0 CY |
700 | ;; NOTE: This used to be (point-at-eol), but |
701 | ;; that was too close for multi-line arguments | |
702 | ;; to a macro. Point max may be too far if there | |
703 | ;; is a typo in the buffer. | |
704 | ;; | |
705 | ;; Look here for performance issues while a user is typing | |
706 | ;; incomplete code. | |
707 | (point-max))) | |
7a0e7d33 CY |
708 | (setq end (semantic-lex-token-end arg-parsed)) |
709 | ||
710 | (when (and (listp arg-parsed) (eq (car arg-parsed) 'semantic-list)) | |
711 | (setq arg-split | |
712 | ;; Use lex to split up the contents of the argument list. | |
713 | (semantic-lex-spp-stream-for-arglist arg-parsed) | |
714 | )) | |
715 | )) | |
716 | ||
717 | ;; if we have something to sub in, then do it. | |
718 | (semantic-lex-spp-macro-to-macro-stream val beg end arg-split) | |
719 | (setq semantic-lex-end-point end) | |
720 | ) | |
721 | )) | |
722 | ||
723 | (defvar semantic-lex-spp-replacements-enabled t | |
724 | "Non-nil means do replacements when finding keywords. | |
725 | Disable this only to prevent recursive expansion issues.") | |
726 | ||
727 | (defun semantic-lex-spp-analyzer-push-tokens-for-symbol (str beg end) | |
728 | "Push lexical tokens for the symbol or keyword STR. | |
729 | STR occurs in the current buffer between BEG and END." | |
55b522b2 | 730 | (let (sym val count) |
7a0e7d33 CY |
731 | (cond |
732 | ;; | |
733 | ;; It is a macro. Prepare for a replacement. | |
734 | ((and semantic-lex-spp-replacements-enabled | |
735 | (semantic-lex-spp-symbol-p str)) | |
736 | (setq sym (semantic-lex-spp-symbol str) | |
737 | val (symbol-value sym) | |
738 | count 0) | |
739 | ||
740 | (let ((semantic-lex-spp-expanded-macro-stack | |
741 | semantic-lex-spp-expanded-macro-stack)) | |
742 | ||
743 | (semantic-lex-with-macro-used str | |
744 | ;; Do direct replacements of single value macros of macros. | |
745 | ;; This solves issues with a macro containing one symbol that | |
746 | ;; is another macro, and get arg lists passed around. | |
747 | (while (and val (consp val) | |
748 | (semantic-lex-token-p (car val)) | |
749 | (eq (length val) 1) | |
750 | (eq (semantic-lex-token-class (car val)) 'symbol) | |
751 | (semantic-lex-spp-symbol-p (semantic-lex-token-text (car val))) | |
752 | (< count 10) | |
753 | ) | |
754 | (setq str (semantic-lex-token-text (car val))) | |
755 | (setq sym (semantic-lex-spp-symbol str) | |
756 | val (symbol-value sym)) | |
757 | ;; Prevent recursion | |
758 | (setq count (1+ count)) | |
759 | ;; This prevents a different kind of recursion. | |
760 | (push str semantic-lex-spp-expanded-macro-stack) | |
761 | ) | |
762 | ||
763 | (semantic-lex-spp-anlyzer-do-replace sym val beg end)) | |
764 | ||
765 | )) | |
766 | ;; Anything else. | |
767 | (t | |
768 | ;; A regular keyword. | |
769 | (semantic-lex-push-token | |
770 | (semantic-lex-token (or (semantic-lex-keyword-p str) 'symbol) | |
771 | beg end)))) | |
772 | )) | |
773 | ||
774 | (define-lex-regex-analyzer semantic-lex-spp-replace-or-symbol-or-keyword | |
775 | "Like 'semantic-lex-symbol-or-keyword' plus preprocessor macro replacement." | |
776 | "\\(\\sw\\|\\s_\\)+" | |
777 | (let ((str (match-string 0)) | |
778 | (beg (match-beginning 0)) | |
779 | (end (match-end 0))) | |
780 | (semantic-lex-spp-analyzer-push-tokens-for-symbol str beg end))) | |
781 | ||
782 | ;;; ANALYZERS FOR NEW MACROS | |
783 | ;; | |
784 | ;; These utilities and analyzer declaration function are for | |
785 | ;; creating an analyzer which produces new macros in the macro table. | |
786 | ;; | |
787 | ;; There are two analyzers. One for new macros, and one for removing | |
788 | ;; a macro. | |
789 | ||
790 | (defun semantic-lex-spp-first-token-arg-list (token) | |
791 | "If TOKEN is a semantic-list, turn it into a an SPP ARG LIST." | |
792 | (when (and (consp token) | |
793 | (symbolp (car token)) | |
794 | (eq 'semantic-list (car token))) | |
795 | ;; Convert TOKEN in place. | |
55b522b2 CY |
796 | (let ((argsplit (split-string (semantic-lex-token-text token) |
797 | "[(), ]" t))) | |
7a0e7d33 CY |
798 | (setcar token 'spp-arg-list) |
799 | (setcar (nthcdr 1 token) argsplit)) | |
800 | )) | |
801 | ||
802 | (defun semantic-lex-spp-one-token-and-move-for-macro (max) | |
803 | "Lex up one token, and move to end of that token. | |
804 | Don't go past MAX." | |
805 | (let ((ans (semantic-lex (point) max 0 0))) | |
806 | (if (not ans) | |
807 | (progn (goto-char max) | |
808 | nil) | |
809 | (when (> (semantic-lex-token-end (car ans)) max) | |
810 | (let ((bounds (semantic-lex-token-bounds (car ans)))) | |
811 | (setcdr bounds max))) | |
812 | (goto-char (semantic-lex-token-end (car ans))) | |
813 | (car ans)) | |
814 | )) | |
815 | ||
816 | (defun semantic-lex-spp-stream-for-arglist (token) | |
817 | "Lex up the contents of the arglist TOKEN. | |
818 | Parsing starts inside the parens, and ends at the end of TOKEN." | |
819 | (let ((end (semantic-lex-token-end token)) | |
820 | (fresh-toks nil) | |
821 | (toks nil)) | |
822 | (save-excursion | |
823 | ||
824 | (if (stringp (nth 1 token)) | |
825 | ;; If the 2nd part of the token is a string, then we have | |
826 | ;; a token specifically extracted from a buffer. Possibly | |
827 | ;; a different buffer. This means we need to do something | |
828 | ;; nice to parse its contents. | |
829 | (let ((txt (semantic-lex-token-text token))) | |
830 | (semantic-lex-spp-lex-text-string | |
831 | (substring txt 1 (1- (length txt))))) | |
832 | ||
833 | ;; This part is like the original | |
834 | (goto-char (semantic-lex-token-start token)) | |
835 | ;; A cheat for going into the semantic list. | |
836 | (forward-char 1) | |
837 | (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end))) | |
838 | (dolist (tok fresh-toks) | |
839 | (when (memq (semantic-lex-token-class tok) '(symbol semantic-list)) | |
840 | (setq toks (cons tok toks)))) | |
841 | ||
842 | (nreverse toks))))) | |
843 | ||
a964f5e5 CY |
844 | (defvar semantic-lex-spp-hack-depth 0 |
845 | "Current depth of recursive calls to `semantic-lex-spp-lex-text-string'.") | |
846 | ||
7a0e7d33 CY |
847 | (defun semantic-lex-spp-lex-text-string (text) |
848 | "Lex the text string TEXT using the current buffer's state. | |
849 | Use this to parse text extracted from a macro as if it came from | |
850 | the current buffer. Since the lexer is designed to only work in | |
851 | a buffer, we need to create a new buffer, and populate it with rules | |
852 | and variable state from the current buffer." | |
a964f5e5 CY |
853 | (let* ((semantic-lex-spp-hack-depth (1+ semantic-lex-spp-hack-depth)) |
854 | (buf (get-buffer-create (format " *SPP parse hack %d*" | |
855 | semantic-lex-spp-hack-depth))) | |
7a0e7d33 CY |
856 | (mode major-mode) |
857 | (fresh-toks nil) | |
858 | (toks nil) | |
859 | (origbuff (current-buffer)) | |
860 | (important-vars '(semantic-lex-spp-macro-symbol-obarray | |
861 | semantic-lex-spp-project-macro-symbol-obarray | |
862 | semantic-lex-spp-dynamic-macro-symbol-obarray | |
863 | semantic-lex-spp-dynamic-macro-symbol-obarray-stack | |
864 | semantic-lex-spp-expanded-macro-stack | |
865 | )) | |
866 | ) | |
0816d744 | 867 | (with-current-buffer buf |
a6d7d3ef CY |
868 | (erase-buffer) |
869 | ;; Below is a painful hack to make sure everything is setup correctly. | |
870 | (when (not (eq major-mode mode)) | |
1eac105a | 871 | (save-match-data |
29e1a603 CY |
872 | |
873 | ;; Protect against user-hooks that throw errors. | |
874 | (condition-case nil | |
875 | (funcall mode) | |
876 | (error nil)) | |
877 | ||
1eac105a CY |
878 | ;; Hack in mode-local |
879 | (activate-mode-local-bindings) | |
880 | ;; CHEATER! The following 3 lines are from | |
881 | ;; `semantic-new-buffer-fcn', but we don't want to turn | |
882 | ;; on all the other annoying modes for this little task. | |
883 | (setq semantic-new-buffer-fcn-was-run t) | |
884 | (semantic-lex-init) | |
885 | (semantic-clear-toplevel-cache) | |
886 | (remove-hook 'semantic-lex-reset-hooks 'semantic-lex-spp-reset-hook | |
887 | t) | |
888 | )) | |
a6d7d3ef | 889 | |
1eac105a | 890 | ;; Second Cheat: copy key variables regarding macro state from the |
a6d7d3ef CY |
891 | ;; the originating buffer we are parsing. We need to do this every time |
892 | ;; since the state changes. | |
7a0e7d33 CY |
893 | (dolist (V important-vars) |
894 | (set V (semantic-buffer-local-value V origbuff))) | |
a6d7d3ef CY |
895 | (insert text) |
896 | (goto-char (point-min)) | |
897 | ||
898 | (setq fresh-toks (semantic-lex-spp-stream-for-macro (point-max)))) | |
7a0e7d33 | 899 | |
7a0e7d33 CY |
900 | (dolist (tok fresh-toks) |
901 | (when (memq (semantic-lex-token-class tok) '(symbol semantic-list)) | |
902 | (setq toks (cons tok toks)))) | |
903 | ||
904 | (nreverse toks))) | |
905 | ||
906 | ;;;; FIRST DRAFT | |
907 | ;; This is the fist version of semantic-lex-spp-stream-for-arglist | |
908 | ;; that worked pretty well. It doesn't work if the TOKEN was derived | |
909 | ;; from some other buffer, in which case it can get the wrong answer | |
910 | ;; or throw an error if the token location in the originating buffer is | |
911 | ;; larger than the current buffer. | |
912 | ;;(defun semantic-lex-spp-stream-for-arglist-orig (token) | |
913 | ;; "Lex up the contents of the arglist TOKEN. | |
914 | ;; Parsing starts inside the parens, and ends at the end of TOKEN." | |
915 | ;; (save-excursion | |
916 | ;; (let ((end (semantic-lex-token-end token)) | |
917 | ;; (fresh-toks nil) | |
918 | ;; (toks nil)) | |
919 | ;; (goto-char (semantic-lex-token-start token)) | |
920 | ;; ;; A cheat for going into the semantic list. | |
921 | ;; (forward-char 1) | |
922 | ;; (setq fresh-toks (semantic-lex-spp-stream-for-macro (1- end))) | |
923 | ;; (dolist (tok fresh-toks) | |
924 | ;; (when (memq (semantic-lex-token-class tok) '(symbol semantic-list)) | |
925 | ;; (setq toks (cons tok toks)))) | |
926 | ;; (nreverse toks)) | |
927 | ;; )) | |
928 | ||
929 | ;;;; USING SPLIT | |
930 | ;; This doesn't work, because some arguments passed into a macro | |
931 | ;; might contain non-simple symbol words, which this doesn't handle. | |
932 | ;; | |
933 | ;; Thus, you need a full lex to occur. | |
934 | ;; (defun semantic-lex-spp-stream-for-arglist-split (token) | |
935 | ;; "Lex up the contents of the arglist TOKEN. | |
936 | ;; Parsing starts inside the parens, and ends at the end of TOKEN." | |
937 | ;; (let* ((txt (semantic-lex-token-text token)) | |
938 | ;; (split (split-string (substring txt 1 (1- (length txt))) | |
939 | ;; "(), " t)) | |
940 | ;; ;; Hack for lexing. | |
941 | ;; (semantic-lex-spp-analyzer-push-tokens-for-symbol nil)) | |
942 | ;; (dolist (S split) | |
943 | ;; (semantic-lex-spp-analyzer-push-tokens-for-symbol S 0 1)) | |
944 | ;; (reverse semantic-lex-spp-analyzer-push-tokens-for-symbol))) | |
945 | ||
946 | ||
947 | (defun semantic-lex-spp-stream-for-macro (eos) | |
948 | "Lex up a stream of tokens for a #define statement. | |
949 | Parsing starts at the current point location. | |
950 | EOS is the end of the stream to lex for this macro." | |
951 | (let ((stream nil)) | |
952 | (while (< (point) eos) | |
953 | (let* ((tok (semantic-lex-spp-one-token-and-move-for-macro eos)) | |
954 | (str (when tok | |
955 | (semantic-lex-token-text tok))) | |
956 | ) | |
957 | (if str | |
958 | (push (semantic-lex-token (semantic-lex-token-class tok) | |
959 | (semantic-lex-token-start tok) | |
960 | (semantic-lex-token-end tok) | |
961 | str) | |
962 | stream) | |
963 | ;; Nothing to push. | |
964 | nil))) | |
965 | (goto-char eos) | |
966 | ;; Fix the order | |
967 | (nreverse stream) | |
968 | )) | |
969 | ||
970 | (defmacro define-lex-spp-macro-declaration-analyzer (name doc regexp tokidx | |
971 | &rest valform) | |
972 | "Define a lexical analyzer for defining new MACROS. | |
973 | NAME is the name of the analyzer. | |
974 | DOC is the documentation for the analyzer. | |
975 | REGEXP is a regular expression for the analyzer to match. | |
976 | See `define-lex-regex-analyzer' for more on regexp. | |
977 | TOKIDX is an index into REGEXP for which a new lexical token | |
978 | of type `spp-macro-def' is to be created. | |
979 | VALFORM are forms that return the value to be saved for this macro, or nil. | |
980 | When implementing a macro, you can use `semantic-lex-spp-stream-for-macro' | |
981 | to convert text into a lexical stream for storage in the macro." | |
982 | (let ((start (make-symbol "start")) | |
983 | (end (make-symbol "end")) | |
984 | (val (make-symbol "val")) | |
985 | (startpnt (make-symbol "startpnt")) | |
986 | (endpnt (make-symbol "endpnt"))) | |
987 | `(define-lex-regex-analyzer ,name | |
988 | ,doc | |
989 | ,regexp | |
990 | (let ((,start (match-beginning ,tokidx)) | |
991 | (,end (match-end ,tokidx)) | |
992 | (,startpnt semantic-lex-end-point) | |
993 | (,val (save-match-data ,@valform)) | |
994 | (,endpnt semantic-lex-end-point)) | |
995 | (semantic-lex-spp-symbol-set | |
996 | (buffer-substring-no-properties ,start ,end) | |
997 | ,val) | |
998 | (semantic-lex-push-token | |
999 | (semantic-lex-token 'spp-macro-def | |
1000 | ,start ,end)) | |
1001 | ;; Preserve setting of the end point from the calling macro. | |
1002 | (when (and (/= ,startpnt ,endpnt) | |
1003 | (/= ,endpnt semantic-lex-end-point)) | |
1004 | (setq semantic-lex-end-point ,endpnt)) | |
1005 | )))) | |
1006 | ||
1007 | (defmacro define-lex-spp-macro-undeclaration-analyzer (name doc regexp tokidx) | |
1008 | "Undefine a lexical analyzer for defining new MACROS. | |
1009 | NAME is the name of the analyzer. | |
1010 | DOC is the documentation for the analyzer. | |
1011 | REGEXP is a regular expression for the analyzer to match. | |
1012 | See `define-lex-regex-analyzer' for more on regexp. | |
1013 | TOKIDX is an index into REGEXP for which a new lexical token | |
1014 | of type `spp-macro-undef' is to be created." | |
1015 | (let ((start (make-symbol "start")) | |
1016 | (end (make-symbol "end"))) | |
1017 | `(define-lex-regex-analyzer ,name | |
1018 | ,doc | |
1019 | ,regexp | |
1020 | (let ((,start (match-beginning ,tokidx)) | |
1021 | (,end (match-end ,tokidx)) | |
1022 | ) | |
1023 | (semantic-lex-spp-symbol-remove | |
1024 | (buffer-substring-no-properties ,start ,end)) | |
1025 | (semantic-lex-push-token | |
1026 | (semantic-lex-token 'spp-macro-undef | |
1027 | ,start ,end)) | |
1028 | )))) | |
1029 | ||
1030 | ;;; INCLUDES | |
1031 | ;; | |
1032 | ;; These analyzers help a language define how include files | |
1033 | ;; are identified. These are ONLY for languages that perform | |
1034 | ;; an actual textual includesion, and not for imports. | |
1035 | ;; | |
1036 | ;; This section is supposed to allow the macros from the headers to be | |
1037 | ;; added to the local dynamic macro table, but that hasn't been | |
1038 | ;; written yet. | |
1039 | ;; | |
1040 | (defcustom semantic-lex-spp-use-headers-flag nil | |
1041 | "*Non-nil means to pre-parse headers as we go. | |
1042 | For languages that use the Semantic pre-processor, this can | |
1043 | improve the accuracy of parsed files where include files | |
1044 | can change the state of what's parsed in the current file. | |
1045 | ||
1046 | Note: Note implemented yet" | |
1047 | :group 'semantic | |
1048 | :type 'boolean) | |
1049 | ||
1050 | (defun semantic-lex-spp-merge-header (name) | |
1051 | "Extract and merge any macros from the header with NAME. | |
1052 | Finds the header file belonging to NAME, gets the macros | |
1053 | from that file, and then merge the macros with our current | |
1054 | symbol table." | |
1055 | (when semantic-lex-spp-use-headers-flag | |
1056 | ;; @todo - do this someday, ok? | |
1057 | )) | |
1058 | ||
1059 | (defmacro define-lex-spp-include-analyzer (name doc regexp tokidx | |
1060 | &rest valform) | |
1061 | "Define a lexical analyzer for defining a new INCLUDE lexical token. | |
1062 | Macros defined in the found include will be added to our running table | |
1063 | at the time the include statement is found. | |
1064 | NAME is the name of the analyzer. | |
1065 | DOC is the documentation for the analyzer. | |
1066 | REGEXP is a regular expression for the analyzer to match. | |
1067 | See `define-lex-regex-analyzer' for more on regexp. | |
1068 | TOKIDX is an index into REGEXP for which a new lexical token | |
1069 | of type `spp-macro-include' is to be created. | |
1070 | VALFORM are forms that return the name of the thing being included, and the | |
1071 | type of include. The return value should be of the form: | |
1072 | (NAME . TYPE) | |
1073 | where NAME is the name of the include, and TYPE is the type of the include, | |
1074 | where a valid symbol is 'system, or nil." | |
1075 | (let ((start (make-symbol "start")) | |
1076 | (end (make-symbol "end")) | |
1077 | (val (make-symbol "val")) | |
1078 | (startpnt (make-symbol "startpnt")) | |
1079 | (endpnt (make-symbol "endpnt"))) | |
1080 | `(define-lex-regex-analyzer ,name | |
1081 | ,doc | |
1082 | ,regexp | |
1083 | (let ((,start (match-beginning ,tokidx)) | |
1084 | (,end (match-end ,tokidx)) | |
1085 | (,startpnt semantic-lex-end-point) | |
1086 | (,val (save-match-data ,@valform)) | |
1087 | (,endpnt semantic-lex-end-point)) | |
1088 | ;;(message "(car ,val) -> %S" (car ,val)) | |
1089 | (semantic-lex-spp-merge-header (car ,val)) | |
1090 | (semantic-lex-push-token | |
1091 | (semantic-lex-token (if (eq (cdr ,val) 'system) | |
1092 | 'spp-system-include | |
1093 | 'spp-include) | |
1094 | ,start ,end | |
1095 | (car ,val))) | |
1096 | ;; Preserve setting of the end point from the calling macro. | |
1097 | (when (and (/= ,startpnt ,endpnt) | |
1098 | (/= ,endpnt semantic-lex-end-point)) | |
1099 | (setq semantic-lex-end-point ,endpnt)) | |
1100 | )))) | |
1101 | ||
1102 | ;;; EIEIO USAGE | |
1103 | ;; | |
1104 | ;; Semanticdb can save off macro tables for quick lookup later. | |
1105 | ;; | |
1106 | ;; These routines are for saving macro lists into an EIEIO persistent | |
1107 | ;; file. | |
1108 | (defvar semantic-lex-spp-macro-max-length-to-save 200 | |
1109 | "*Maximum length of an SPP macro before we opt to not save it.") | |
1110 | ||
b90caf50 | 1111 | ;;;###autoload |
7a0e7d33 CY |
1112 | (defun semantic-lex-spp-table-write-slot-value (value) |
1113 | "Write out the VALUE of a slot for EIEIO. | |
1114 | The VALUE is a spp lexical table." | |
1115 | (if (not value) | |
1116 | (princ "nil") | |
1117 | (princ "\n '(") | |
1118 | ;(princ value) | |
1119 | (dolist (sym value) | |
1120 | (princ "(") | |
1121 | (prin1 (car sym)) | |
1122 | (let* ((first (car (cdr sym))) | |
1123 | (rest (cdr sym))) | |
1124 | (when (not (listp first)) | |
1125 | (error "Error in macro \"%s\"" (car sym))) | |
1126 | (when (eq (car first) 'spp-arg-list) | |
1127 | (princ " ") | |
1128 | (prin1 first) | |
1129 | (setq rest (cdr rest)) | |
1130 | ) | |
1131 | ||
1132 | (when rest | |
1133 | (princ " . ") | |
1134 | (let ((len (length (cdr rest)))) | |
1135 | (cond ((< len 2) | |
1136 | (condition-case nil | |
1137 | (prin1 rest) | |
1138 | (error | |
1139 | (princ "nil ;; Error writing macro\n")))) | |
1140 | ((< len semantic-lex-spp-macro-max-length-to-save) | |
1141 | (princ "\n ") | |
1142 | (condition-case nil | |
1143 | (prin1 rest) | |
1144 | (error | |
1145 | (princ "nil ;; Error writing macro\n "))) | |
1146 | ) | |
1147 | (t ;; Too Long! | |
1148 | (princ "nil ;; Too Long!\n ") | |
1149 | )))) | |
1150 | ) | |
1151 | (princ ")\n ") | |
1152 | ) | |
1153 | (princ ")\n")) | |
1154 | ) | |
1155 | ||
7a0e7d33 CY |
1156 | ;;; MACRO TABLE DEBUG |
1157 | ;; | |
1158 | (defun semantic-lex-spp-describe (&optional buffer) | |
1159 | "Describe the current list of spp macros for BUFFER. | |
1160 | If BUFFER is not provided, use the current buffer." | |
1161 | (interactive) | |
1162 | (let ((syms (save-excursion | |
1163 | (if buffer (set-buffer buffer)) | |
1164 | (semantic-lex-spp-macros))) | |
1165 | (sym nil)) | |
1166 | (with-output-to-temp-buffer "*SPP MACROS*" | |
1167 | (princ "Macro\t\tValue\n") | |
1168 | (while syms | |
1169 | (setq sym (car syms) | |
1170 | syms (cdr syms)) | |
1171 | (princ (symbol-name sym)) | |
1172 | (princ "\t") | |
1173 | (if (< (length (symbol-name sym)) 8) | |
1174 | (princ "\t")) | |
1175 | (prin1 (symbol-value sym)) | |
1176 | (princ "\n") | |
1177 | )))) | |
1178 | ||
1179 | ;;; EDEBUG Handlers | |
1180 | ;; | |
1181 | (add-hook | |
1182 | 'edebug-setup-hook | |
1183 | #'(lambda () | |
1184 | ||
1185 | (def-edebug-spec define-lex-spp-macro-declaration-analyzer | |
1186 | (&define name stringp stringp form def-body) | |
1187 | ) | |
1188 | ||
1189 | (def-edebug-spec define-lex-spp-macro-undeclaration-analyzer | |
1190 | (&define name stringp stringp form) | |
1191 | ) | |
1192 | ||
1193 | (def-edebug-spec define-lex-spp-include-analyzer | |
b90caf50 | 1194 | (&define name stringp stringp form def-body)))) |
7a0e7d33 CY |
1195 | |
1196 | (provide 'semantic/lex-spp) | |
1197 | ||
b90caf50 CY |
1198 | ;; Local variables: |
1199 | ;; generated-autoload-file: "loaddefs.el" | |
1200 | ;; generated-autoload-feature: semantic/loaddefs | |
1201 | ;; generated-autoload-load-name: "semantic/lex-spp" | |
1202 | ;; End: | |
1203 | ||
3999968a | 1204 | ;; arch-tag: 8877d83e-07ea-4d86-a960-e3562138d8a5 |
7a0e7d33 | 1205 | ;;; semantic-lex-spp.el ends here |