Function: semantic-lex-spp-token-macro-to-macro-stream
semantic-lex-spp-token-macro-to-macro-stream is a byte-compiled
function defined in lex-spp.el.gz.
Signature
(semantic-lex-spp-token-macro-to-macro-stream VAL BEG END ARGVALUES)
Documentation
Convert lexical macro contents VAL into a macro expansion stream.
Argument VAL is the value of some macro to be converted into a stream. BEG and END are the token bounds of the macro to be expanded that will somehow gain a much longer token stream. ARGVALUES are values for any arg list, or nil. See comments in code for information about how token streams are processed and what valid VAL values are.
Source Code
;; Defined in /usr/src/emacs/lisp/cedet/semantic/lex-spp.el.gz
(defun semantic-lex-spp-token-macro-to-macro-stream (val beg end argvalues)
"Convert lexical macro contents VAL into a macro expansion stream.
Argument VAL is the value of some macro to be converted into a stream.
BEG and END are the token bounds of the macro to be expanded
that will somehow gain a much longer token stream.
ARGVALUES are values for any arg list, or nil.
See comments in code for information about how token streams are processed
and what valid VAL values are."
;; A typical VAL value might be either a stream of tokens.
;; Tokens saved into a macro stream always includes the text from the
;; buffer, since the locations specified probably don't represent
;; that text anymore, or even the same buffer.
;;
;; CASE 1: Simple token stream
;;
;; #define SUPER mysuper::
;; ==>
;;((symbol "mysuper" 480 . 487)
;; (punctuation ":" 487 . 488)
;; (punctuation ":" 488 . 489))
;;
;; CASE 2: Token stream with argument list
;;
;; #define INT_FCN(name) int name (int in)
;; ==>
;; ((spp-arg-list ("name") 558 . 564)
;; (INT "int" 565 . 568)
;; (symbol "name" 569 . 573)
;; (semantic-list "(int in)" 574 . 582))
;;
;; In the second case, a macro with an argument list as the args as the
;; first entry.
;;
;; CASE 3: Symbol text merge
;;
;; #define TMP(a) foo_ ## a
;; ==>
;; ((spp-arg-list ("a") 20 . 23)
;; (spp-symbol-merge ((symbol "foo_" 24 . 28) (symbol "a" 32 . 33))
;; 24 . 33))
;;
;; Usually in conjunction with a macro with an argument, merging symbol
;; parts is a way of fabricating new symbols from pieces inside the macro.
;; These macros use `spp-symbol-merge' tokens whose TEXT part is another
;; token stream. This sub-stream ought to consist of only 2 SYMBOL pieces,
;; though I suppose keywords might be ok. The end result of this example
;; merge symbol would be (symbol "foo_A" 24 . 33) where A is the symbol
;; passed in from the arg list "a".
;;
;; CASE 4: Nested token streams
;;
;; #define FOO(f) f
;; #define BLA bla FOO(foo)
;; ==>
;; ((INT "int" 82 . 85)
;; (symbol "FOO" 86 . 89)
;; (semantic-list "(foo)" 89 . 94))
;;
;; Nested token FOO shows up in the table of macros, and gets replace
;; inline. This is the same as case 2.
;;
;; CASE 5: Macros which open a scope without closing it
;;
;; #define __NAMESPACE_STD namespace std {
;; #define __NAMESPACE_END }
;; ==>
;; ((NAMESPACE "namespace" 140 . 149)
;; (symbol "std" 150 . 153)
;; (open-paren "{" 154 . 155))
;;
;; Note that we get a single 'open-paren' instead of a
;; 'semantic-list', which is because we use
;; 'semantic-lex-spp-paren-or-list' instead of
;; 'semantic-lex-paren-or-list' in our spp-lexer. To keep things
;; reasonably simple, we assume that such an open scope will always
;; be closed by another macro (see
;; `semantic-lex-spp-find-closing-macro'). We generate a
;; 'semantic-list' to this closing macro, and we leave an overlay
;; which contains information how far we got into the macro's
;; stream (since it might open several scopes).
(let* ((arglist (semantic-lex-spp-macro-with-args val))
(argalist nil)
(val-tmp nil)
(v nil)
(sppov (semantic-lex-spp-get-overlay beg))
(sppinfo (when sppov (overlay-get sppov 'semantic-spp))))
;; First, check if we were already here and left information
(when sppinfo
;; Advance in the tokens as far as we got last time
(when (numberp (car sppinfo))
(while (and val
(>= (car sppinfo) (car (last (car val)))))
(setq val (cdr val))))
;; And push an open paren
(semantic-lex-push-token
(semantic-lex-token 'open-paren beg (1+ beg) "{"))
(setq semantic-lex-current-depth (1+ semantic-lex-current-depth))
(unless val
;; We reached the end of this macro, so delete overlay
(delete-overlay sppov)))
;; CASE 2: Dealing with the arg list.
(when (and val arglist)
;; Skip the arg list.
(when (eq (caar val) 'spp-arg-list)
(setq val (cdr val)))
;; Push args into the replacement list.
(let ((AV argvalues))
(dolist (A arglist)
(let* ((argval (car AV)))
(semantic-lex-spp-symbol-push A argval)
(setq argalist (cons (cons A argval) argalist))
(setq AV (cdr AV)))))
)
;; Set val-tmp after stripping arguments.
(setq val-tmp val)
;; CASE 1: Push everything else onto the list.
;; Once the arg list is stripped off, CASE 2 is the same
;; as CASE 1.
(while val-tmp
(setq v (car val-tmp))
(setq val-tmp (cdr val-tmp))
(let* (;; The text of the current lexical token.
(txt (car (cdr v)))
;; Try to convert txt into a macro declaration. If it is
;; not a macro, use nil.
(txt-macro-or-nil (semantic-lex-spp-symbol txt))
;; If our current token is a macro, then pull off the argument
;; list.
(macro-and-args
(when txt-macro-or-nil
(semantic-lex-spp-macro-with-args (symbol-value txt-macro-or-nil)))
)
;; We need to peek at the next token when testing for
;; used macros with arg lists.
(next-tok-class (semantic-lex-token-class (car val-tmp)))
)
(cond
;; CASE 3: Merge symbols together.
((eq (semantic-lex-token-class v) 'spp-symbol-merge)
(let ((newsym (semantic-lex-spp-symbol-merge txt)))
(semantic-lex-push-token
(semantic-lex-token 'symbol beg end newsym))
))
;; CASE 2: Argument replacement. If a discovered symbol is in
;; the active list of arguments, then we need to substitute
;; in the new value.
((and (eq (semantic-lex-token-class v) 'symbol) txt-macro-or-nil
(or (and macro-and-args (eq next-tok-class 'semantic-list))
(not macro-and-args))
)
(let ((AV nil))
(when macro-and-args
(setq AV
(semantic-lex-spp-stream-for-arglist (car val-tmp)))
;; We used up these args. Pull from the stream.
(setq val-tmp (cdr val-tmp))
)
(semantic-lex-with-macro-used txt
;; Don't recurse directly into this same fcn, because it is
;; convenient to have plain string replacements too.
(semantic-lex-spp-macro-to-macro-stream
(symbol-value txt-macro-or-nil)
beg end AV))
))
;; This is a HACK for the C parser. The 'macros text
;; property is some storage so that the parser can do
;; some C specific text manipulations.
((eq (semantic-lex-token-class v) 'semantic-list)
;; Push our arg list onto the semantic list.
(when argalist
(setq txt (concat txt)) ; Copy the text.
(put-text-property 0 1 'macros argalist txt))
(semantic-lex-push-token
(semantic-lex-token (semantic-lex-token-class v) beg end txt))
)
;; CASE 5: Macro which opens a scope
((eq (semantic-lex-token-class v) 'open-paren)
;; We assume that the scope will be closed by another macro.
;; (Everything else would be a terrible idea anyway.)
(let* ((endpoint (semantic-lex-spp-find-closing-macro))
(ov (when endpoint
(or sppov
(make-overlay beg end)))))
(when ov
;; Generate a semantic-list which spans to the end of
;; the closing macro
(semantic-lex-push-token
(semantic-lex-token 'semantic-list beg endpoint))
;; The rest of the current macro's stream will be parsed
;; next time.
(setq val-tmp nil)
;; Store our current state were we are in the macro and
;; the endpoint.
(overlay-put ov 'semantic-spp
(cons (car (last v)) endpoint)))))
((eq (semantic-lex-token-class v) 'close-paren)
;; Macro which closes a scope
;; Just push the close paren, but also decrease depth
(semantic-lex-push-token
(semantic-lex-token 'close-paren beg end txt))
(setq semantic-lex-current-depth (1- semantic-lex-current-depth)))
;; CASE 1: Just another token in the stream.
(t
;; Nothing new.
(semantic-lex-push-token
(semantic-lex-token (semantic-lex-token-class v) beg end txt))
)
)))
;; CASE 2: The arg list we pushed onto the symbol table
;; must now be removed.
(dolist (A arglist)
(semantic-lex-spp-symbol-pop A))
))