eĿlipsis
a language independent preprocessor
 
Loading...
Searching...
No Matches
directives.c File Reference

Directives implemented by eĿlipsis. More...

Variables

C standard directives
__directive__ define
 The define directive as specified by the C standard.
 
__directive__ elif
 The elif directive as specified by the C standard.
 
__directive__ else
 The else directive as specified by the C standard.
 
__directive__ embed
 The embed directive as specified by the C standard plus extension.
 
__directive__ endif
 The endif directive as specified by the C standard.
 
__directive__ error
 The error directive as specified by the C standard.
 
__directive__ if
 The else directive as specified by the C standard.
 
__directive__ include
 The include directive as specified by the C standard plus extensions.
 
__directive__ line
 The line directive as specified by the C standard.
 
__directive__ undef
 The undef directive as specified by the C standard.
 
__directive__ warning
 The warning directive as specified by the C standard.
 
C standard shortcuts for directives
__directive__ elifdef
 alias for #elif defined
 
__directive__ elifndef
 alias for #elif !defined
 
__directive__ ifdef
 alias for #if defined
 
__directive__ ifndef
 alias for #if !defined
 
EĿlipsis specific variations of directives
__directive__ always
 Always expand the code up to the next #end or #endif.
 
__directive__ bind
 A local equivalent to #define.
 
__directive__ embed_resource
 Embed the data source file but without expanding the token list of the directive.
 
__directive__ environment
 Find an environment variable through the C library call getenv and define a macro of the same name.
 
__directive__ expand
 Expand the remaining tokens on the line and re-interpret the result as a directive.
 
__directive__ include_directives
 Execute only the directives in the given header file.
 
__directive__ include_source
 Include the source file but without expanding the token list of the directive.
 
__directive__ linenumber
 As the #line directive but without expanding the rest of the line.
 
__directive__ never
 Never expand the code up to the next #end or #endif.
 
__directive__ once
 Only expand the code up to the next #end, #endif or the end of the header once.
 
EĿlipsis extensions to handle argument lists

Using recursive inclusion would quickly hit a complexity wall if we are not careful. This is because with "normal" directives we expand a whole argument lists, for example, just to split off the first argument and collect the remainder. This easily makes iterative algorithms quadratic because all the arguments are touched over and over again.

EĿlipsis provides specialized macro assignment directives that avoid this complexity.

__directive__ gather
 Gather token lists into a macro.
 
__directive__ move
 Delete the contents of target and move the contents of source into it.
 
__directive__ scatter
 Scatter comma-separated parts of a token list into other macros.
 
Shortcuts for explicit expansion
__directive__ end
 alias for #endif
 
__directive__ xbind
 alias for #expand __bind__
 
__directive__ xdefine
 alias for #expand __define__
 
__directive__ xembed_resource
 alias for #expand __embed_resource__
 
__directive__ xinclude_source
 alias for #expand __include_source__
 
__directive__ xlinenumber
 alias for #expand __linenumber__
 

Detailed Description

Directives implemented by eĿlipsis.

Warning
This is a file generated by eĿlipsis version 20241112, do not modify

These are only artificially combined into this pseudo-source file for reference.

Some form proper directives of their own, others are just shortcuts (aliases) for some other combination.

Variable Documentation

◆ always

__directive__ always

Always expand the code up to the next #end or #endif.

This can be used for example to ensure that a set of #bind directives is restricted to the lines up to the end of this construct.

#always
...
__directive__ end
alias for #endif
Definition directives.c:548

is the same as

#if false
#else
...
__directive__ endif
The endif directive as specified by the C standard.
Definition directives.c:52
Remarks
This is preferable over #if true because #elif and #else are inhibited.

◆ bind

__directive__ bind

A local equivalent to #define.

The difference is that the macro is undefined (as if by #undef) at the end of the current #if/#elif/#else block or source file.

◆ define

__directive__ define

The define directive as specified by the C standard.

◆ elif

__directive__ elif

The elif directive as specified by the C standard.

◆ elifdef

__directive__ elifdef

alias for #elif defined

◆ elifndef

__directive__ elifndef

alias for #elif !defined

◆ else

__directive__ else

The else directive as specified by the C standard.

◆ embed

__directive__ embed

The embed directive as specified by the C standard plus extension.

See also
extension to directives

◆ embed_resource

__directive__ embed_resource

Embed the data source file but without expanding the token list of the directive.

Other arguments to this directive are not expanded, unless the #expand prefix is applied.

◆ end

◆ endif

__directive__ endif

The endif directive as specified by the C standard.

◆ environment

__directive__ environment

Find an environment variable through the C library call getenv and define a macro of the same name.

The contents of the environment variable is tokenized as if it were given in a #‿define directive. The remaining token list (which may be empty) is the default setting if the environment variable is not found.

Example:

#environment LOOP_DEPTH 4
#environment VALUES 5, 6, 78
#environment QUESTION
#environment HOME

inspects the environment variables and defines the macros LOOP_DEPTH, VALUES, QUESTION and HOME. If there is no such environment variable it is set to the token list as indicated. So if there is no QUESTION environment variable, the replacement list of that macro would be empty.

For HOME most operating systems provide a name of a directory so in general the macro HOME will not be empty. Note thought that eĿlipsis provides the contents of this variable as raw token sequence, not as a string. This allows for more flexibility when you have to compose path names.

#environment HOME
#include <HOME/include/>

Would establish a subdirectory of the user′s home directory as a place to seek for include files.

Or, if you want something like this inside a string

#include __EXPAND_STRING​IFY__(HOME/include/my_favorite.h)
Remarks
A macro such defined cannot be undefined.
As for other macro definitions, redefining an existing macro of the same name is an error if that would result in a different replacement list.

◆ error

__directive__ error

The error directive as specified by the C standard.

◆ expand

__directive__ expand

Expand the remaining tokens on the line and re-interpret the result as a directive.

#expand tokens ...

So, after expansion, the first token in the resulting list should be a directive. Here, the resulting directive may be uglified by appending double underscores in front and back to avoid expansion if that happens to be defined as a macro.

If for example ARRAY(100) is a macro and expands to array_name_100 and VALUE(100) expands to 100*37 the following

#expand __define__ ARRAY(100) VALUE(100)

leads to

__define__ array_name_100 100*37

which is the same as if we had the following directive

#define array_name_100 100*37

which defines a new macro array_name_100 with the indicated expression as expansion.

◆ gather

__directive__ gather

Gather token lists into a macro.

The general form of that directive is

#gather NAME [token₁ [token₂ [... tokenₖ ] ] ]

where NAME is a name of a possibly pre-existing macro, and tokenᵢ are tokens. The difference to #define and similar are

  • If one of the tokenᵢ is a name of a macro, the replacement list of that macro is removed from that macro (so it becomes empty) and spliced in place instead of tokenᵢ. But other than for #define no further expansion takes place.
  • If NAME is not a pre-existing macro, a new macro is defined that has the resulting list as replacement list.
  • If NAME is already a macro, the resulting list is appended to the current replacement list.

Consider the following example that uses three function-like macros

#define A() a , 1
#define B() b
#define C() c , d
#gather C A B

Note that in the #gather line, none of the macros is "invoked", there are no () parenthesis.

After that, the following three source lines

A: A()
B: B()
C: C()

expand to the replacements

A:
B:
C: c , d a , 1 b

That is, C() has the concatenation of the three lists in the order they appear in #gather, and A() and B() are now empty macros that expand to nothing.

For a more complicated example, take the source of the ellipsis-foreach-loop.dirs Xfile, which is the bottom of the recursion of ellipsis-foreach.dirs

# scatter FOREACH_FIR FOREACH_ARGS
# expand gather FOREACH_RESULT BODY(FOREACH_FIR)
# if __ANY__(FOREACH_ARGS)
# if __ANY__(FOREACH_SEPARATOR)
# expand gather FOREACH_RESULT FOREACH_SEPARATOR
# endif
# else
# undef LOOP_TERMINATED
# define LOOP_TERMINATED true
# endif

If we have that

  • FOREACH_RESULT is a function-like macro with no parameter that expands to the tokens "a , b , c"
  • BODY is function-like macro that receives one parameter X and returns the tokens "array [X ]"
  • FOREACH_FIR expands to the single token "100",

the line

# expand gather FOREACH_RESULT BODY(FOREACH_FIR)

First expands the tokens on the line, to maybe result in something like

gather FOREACH_RESULT array [100 ]
__directive__ gather
Gather token lists into a macro.
Definition directives.c:430

Note that gather and FOREACH_RESULT are not expanded. This new token list is then taken as a directive and FOREACH_RESULT now contains a, b, c, array[100]

Remarks
The complexity of this directive is only related to the number of tokens k that are given, not on the lengths of their replacement lists or the length of the existing replacement list of NAME.

◆ if

__directive__ if

The else directive as specified by the C standard.

◆ ifdef

__directive__ ifdef

alias for #if defined

◆ ifndef

__directive__ ifndef

alias for #if !defined

◆ include

__directive__ include

The include directive as specified by the C standard plus extensions.

See also
extension to directives

◆ include_directives

__directive__ include_directives

Execute only the directives in the given header file.

All tokens that would be produced are discarded, only side effects such as macro definitions have an effect on the source that uses this directive.

Other arguments to this directive are not expanded, unless the #expand prefix is applied.

◆ include_source

__directive__ include_source

Include the source file but without expanding the token list of the directive.

Other arguments to this directive are not expanded, unless the #expand prefix is applied.

◆ line

__directive__ line

The line directive as specified by the C standard.

Referenced by ellipsis‿include‿embed(), ellipsis‿tokenize(), and get_a_line().

◆ linenumber

__directive__ linenumber

As the #line directive but without expanding the rest of the line.

◆ move

__directive__ move

Delete the contents of target and move the contents of source into it.

#move target source
Remarks
The complexity of this directive is O(1).

◆ never

__directive__ never

Never expand the code up to the next #end or #endif.

This can be used for example to comment out a set of lines without having to change them individually.

Remarks
This is preferable over #if false because #elif and #else are inhibited.

◆ once

__directive__ once

Only expand the code up to the next #end, #endif or the end of the header once.

In particular this can be used to skip over a whole header file that has already be seen.

The directive receives one optional argument, which is an identifier that helps to identify the source file (or #if construct) in question. If omitted, a hash of the base-name of the current file name is used.

Remarks
This is preferable over #ifdef include guards because it avoid to read over the header, again.
See also
pragma This is also interfaced via the legacy pragma once.

◆ scatter

__directive__ scatter

Scatter comma-separated parts of a token list into other macros.

The general form of that directive is

#scatter [target₁ [target₂ [... targetₖ] ] ] NAME

where NAME is a name of a pre-existing macro, and targetᵢ are identifiers. Here the starting sequence of tokens in NAME up to the first comma is removed from NAME, target1 is made a macro if it was not before, and the replacement sequence of target1 is set to (or replaced by) that starting sequence. Then the now leading comma is also removed from NAME and the procedure is performed in turn for target2 etc. Once all targetᵢ macros are processed, NAME keeps the remaining token list (again without the possible comma).

#define A()
#define B()
#define C() c , d a , 1 b
#scatter A B C

Note that in the #scatter line, none of the macros is "invoked", there are no () parenthesis.

After that, the following three source lines

A: A()
B: B()
C: C()

expand to the replacements

A: c
B: d a
C: 1 b

That is, A() has the tokens up to the first comma, B() those up to the second then C() keeps the remaining list after the second comma.

For a more complicated example, take the source of the ellipsis-foreach-loop.dirs Xfile, which is the bottom of the recursion of ellipsis-foreach.dirs

# scatter FOREACH_FIR FOREACH_ARGS
# expand gather FOREACH_RESULT BODY(FOREACH_FIR)
# if __ANY__(FOREACH_ARGS)
# if __ANY__(FOREACH_SEPARATOR)
# expand gather FOREACH_RESULT FOREACH_SEPARATOR
# endif
# else
# undef LOOP_TERMINATED
# define LOOP_TERMINATED true
# endif

If we have that

  • FOREACH_ARGS is a function-like macro with no parameter that expands to the tokens "17 , 9 , 100"
  • FOREACH_FIR is a function-like macro with no parameter that might have any contents

after the line

# scatter FOREACH_FIR FOREACH_ARGS

the snippet

FOREACH_FIR: FOREACH_FIR()
FOREACH_ARGS: FOREACH_ARGS()

would expand to

FOREACH_FIR: 17
FOREACH_ARGS: 9 , 100
Remarks
The complexity of this directive is only related to the number of targets k that are given and on the length of the corresponding lists in NAME. If n₁, ..., nₖ are the lengths of these lists, the complexity is O(Σᵢ nᵢ). The remaining list in NAME stays otherwise untouched and may be arbitrarily long without influencing the complexity.

◆ undef

__directive__ undef

The undef directive as specified by the C standard.

◆ warning

__directive__ warning

The warning directive as specified by the C standard.

◆ xbind

__directive__ xbind

alias for #expand __bind__

◆ xdefine

__directive__ xdefine

alias for #expand __define__

◆ xembed_resource

__directive__ xembed_resource

alias for #expand __embed_resource__

◆ xinclude_source

__directive__ xinclude_source

alias for #expand __include_source__

◆ xlinenumber

__directive__ xlinenumber

alias for #expand __linenumber__