MacroEnv

This an environment of macro declarations

It implements ISO/IEC 9899:1999(E) section 6 (aka ‘C’) and ISO/IEC 14882:1998(E) section 16 (aka ‘C++’)

exception cpip.core.MacroEnv.ExceptionMacroEnv

Exception when handling MacroEnv object.

exception cpip.core.MacroEnv.ExceptionMacroEnvInvalidRedefinition

Exception for a invalid redefinition of a macro. NOTE: Under C rules (C Rationale 6.10.3) callers should merely issue a suitable diagnostic.

exception cpip.core.MacroEnv.ExceptionMacroEnvNoMacroDefined

Exception when trying to access a PpDefine that is not currently defined.

exception cpip.core.MacroEnv.ExceptionMacroIndexError

Exception when an access to a PpDefine that generates a IndexError.

exception cpip.core.MacroEnv.ExceptionMacroReplacementInit

Exception in the constructor.

exception cpip.core.MacroEnv.ExceptionMacroReplacementPredefinedRedefintion

Exception for a redefinition of a macro id that is predefined.

class cpip.core.MacroEnv.MacroEnv(enableTrace=False, stdPredefMacros=None)

Represents a set of #define directives that represent a macro processing environment. This provides support for #define and #undef directives. It also provides support for macro replacement see: ISO/IEC 9899:1999 (E) 6.10.3 Macro replacement.

enableTrace
Allows calls to _debugTokenStream() that may or may not produce log output (depending on logging level). If True this makes this code run slower, typically 3x slower
stdPredefMacros

If present should be a dictionary of: {identifier : replacement_string_\n_terminated, ...} For example:

{
    '__DATE__' : 'First of June\n',
    '__TIME__' : 'Just before lunchtime.\n',
}

Each identifier must be in STD_PREDEFINED_NAMES

_MacroEnv__define(ppD)

Takes a cpip.core.PpDefine.PpDefine object and adds it to the map of objects. Does not check if it is a redefinition of a predefined macro. Does check if it is a valid redefinition.

On success it returns the identifier of the macro.

The insertion is stable i.e. a valid re-definition does not replace the existing definition so that the definition file, line and reference count are preserved.

Parameters:ppD (cpip.core.PpDefine.PpDefine) – Macro definition.
Returns:str – Macro identifier.
_MacroEnv__setString(theStr)

Takes a string 'identifier replacement\n' and sets the macro map. This uses __define() so only a redefinition exception is raised.

Parameters:theStr (str) – Replacement string.
Returns:NoneType
__init__(enableTrace=False, stdPredefMacros=None)

Constructor.

A ‘reference’ is defined as: replacement or if defined. So:

Parameters:
  • enableTrace (bool) – If True allows calls to _debugTokenStream() that may or may not produce log output (depending on logging level).
  • stdPredefMacros (dict({str : [str]})) –

    If present should be a dictionary of: {identifier : replacement_string_\n_terminated, ...}

    These identifiers are not permitted to be redefined.

    This also increments the count is the number of times that the identifier has been referenced in the lifetime of me.

Returns:

NoneType

__weakref__

list of weak references to the object (if defined)

_assertDefineMapIntegrity()

Returns True if dynamic tests on self._defineMap and self._expandedSet pass. i.e. every entry in self._expandedSet must be in self._defineMap.keys().

Returns:bool – False on failure.
_debugTokenStream(thePrefix, theArg='')

Writes to logging.debug() an interpretation of the token stream provided by theList. It will be preceded by the debugMarker value (if set) and that will always be cleared.

_expand(theTtt, theGen, theFileLineCol)

Recursive call to expand macro symbols.

theFileLineCol
Is a FileLocation.FileLineCol object.
_hasExpanded(theTtt)

Returns True if theTok represents a macro name that has already been expanded.

_reset()

Initialises the dynamic values.

Returns:NoneType
_staticMacroDependencies(theIdentifier)

Returns the immediate dependencies as a list of strings for a macro identified by the string.

Parameters:theIdentifier (str) – Macro name.
Returns:list([]),list([str]) – List of macro names.
allStaticMacroDependencies()

Returns a DuplexAdjacencyList() of macro dependencies for the Macro environment. All objects in the cpip.util.Tree.DuplexAdjacencyList are macro identifiers as strings.

A cpip.util.Tree.DuplexAdjacencyList can be converted to a cpip.util.Tree.Tree and that can be converted to a cpip.util.DictTree.DictTree

Returns:cpip.util.Tree.DuplexAdjacencyList – The dependencies.
clear()

Clears the macro environment.

define(theGen, theFile, theLine)

Defines a macro. theGen should be in the state immediately after the #define i.e. this will consume leading whitespace and the trailing newline.

Will raise a ExceptionMacroEnvInvalidRedefinition if the redefinition is not valid. May raise a PpDefine.ExceptionCpipDefineInit (or sub class) on failure.

On success it returns the identifier of the macro as a string.. The insertion is stable i.e. a valid re-definition does not replace the existing definition so that the existing state of the macro definition (file, line, reference count etc. are preserved.

Parameters:
  • theGen (generator) – Token generator.
  • theFile (str) – File identifier such as the path.
  • theLine (int) – Line number.
Returns:

str – Macro name.

defined(theTtt, flagInvert, theFileLineCol=None)

If the PpToken theTtt is an identifier that is currently defined then this returns 1 as a PpToken, 0 as a PpToken otherwise. If the macro exists in the environment its reference count is incremented.

theFileLineCol
Is a FileLocation.FileLineCol object.

See: ISO/IEC 9899:1999 (E) 6.10.1.

Parameters:
  • theTtt (cpip.core.PpToken.PpToken) – The token.
  • flagInvert (bool) – Invert the test.
  • theFileLineCol (cpip.core.FileLocation.FileLineCol([str, int, int])) – File location.
Returns:

cpip.core.PpToken.PpToken – A token that is either 0 or 1.

Raises:

KeyError

genMacros(theIdentifier=None)

Generates PpDefine objects encountered during my existence. Macros that have been undefined will be generated first in order of un-definition followed by the currently defined macros in identifier order.

Macros that have been #undef’d will have the attribute isCurrentlyDefined as False.

genMacrosInScope(theIdent=None)

Generates PpDefine objects encountered during my existence and still in scope i.e. not yet un-defined.

If theIdent is not None then only that named macros will be yielded.

Parameters:theIdent (NoneType) – Optionally the macro name.
Returns:cpip.core.PpDefine.PpDefine – Yields macro definitions.
genMacrosOutOfScope(theIdent=None)

Generates PpDefine objects encountered during my existence but then undefined in the order of un-definition.

If theIdent is not None then only that named macros will be yielded.

Parameters:theIdent (NoneType) – Optionally the macro name.
Returns:cpip.core.PpDefine.PpDefine – Yields macro definitions.
getUndefMacro(theIdx)

Returns the PpDefine object from the undef list for the given index. Will raise an ExceptionMacroIndexError if the index is out of range.

hasMacro(theIdentifier)

Returns True if the environment has the macro.

Note

This does not increment the reference count so should not be used when processing #ifdef ..., #if defined ... or #if !defined ... for those use isDefined() and defined() instead.

Parameters:theIdentifier (str) – Macro name.
Returns:bool – True if the macro is currently defined.
isDefined(theTtt, theFileLineCol=None)

Returns True theTtt is an identifier that is currently defined, False otherwise. If True this increments the macro reference.

theFileLineCol
Is a FileLocation.FileLineCol object.

See: ISO/IEC 9899:1999 (E) 6.10.1.

macro(theIdentifier)

Returns the macro identified by the identifier. Will raise a ExceptionMacroEnvNoMacroDefined is undefined.

Parameters:theIdentifier (str) – Macro name.
Returns:cpip.core.PpDefine.PpDefine – The macro.
macroHistory(incEnv=True, onlyRef=True)

Returns the macro history as a multi-line string

macroHistoryMap()

Returns a map of {ident : ([ints, ...], True/False), ...} Where the macro identifier is mapped to a pair where: pair[0] is a list of indexes into getUndefMacro(). pair[1] is boolean, True if the identifier is currently defined i.e. it is the value ofself.hasMacro(ident). The macro can be obtained by self.macro().

macroNotDefinedDependencies()

Returns a map of {identifier : [class FileLineColumn, ...], ...} where there has been an #ifdef and nothing is defined. Thus these macros, if present, could alter the outcome i.e. it is dependency on them NOT being defined.

macroNotDefinedDependencyNames()

Returns an unsorted list of identifies where there has been an #ifdef and nothing is defined. Thus these macros, if present, could alter the outcome i.e. it is dependency on them NOT being defined.

Returns:list([str]) – List of macro names.
macroNotDefinedDependencyReferences(theIdentifier)

Returns an ordered list of cpip.core.FileLocation.FileLineCol`for an identifier where there has been an ``#ifdef` and nothing is defined. Thus these macros, if present, could alter the outcome i.e. it is dependency on them NOT being defined.

Parameters:theIdentifier (str) – Macro name.
Returns:list([cpip.core.FileLocation.FileLineCol([str, int, int])]) – List of locations.
macros()

Returns and unsorted list of strings of current macro identifiers.

Returns:list([str]) – Macro names.
mightReplace(theTtt)

Returns True if theTok might be able to be expanded. ‘Might’ is not ‘can’ or ‘will’ because of this:

#define FUNC(a,b) a-b
FUNC FUNC(45,3)

Becomes:

FUNC 45 -3

Thus mightReplace('FUNC', ...) is True in both cases but actual replacement only occurs once for the second FUNC.

Parameters:theTtt (cpip.core.PpToken.PpToken) – The token.
Returns:bool – True if this might be replaceable.
referencedMacroIdentifiers(sortedByRefcount=False)

Returns an unsorted list of macro identifiers that have a reference count > 0. If sortedByRefcount is True the list will be in increasing order of reference count then by name. Use reverse() on the result to get decreasing order. If sortedByRefcount is False the return value is unsorted.

replace(theTtt, theGen, theFileLineCol=None)

Given a PpToken this returns the replacement as a list of [class PpToken, ...] that is the result of the substitution of macro definitions.

theGen
Is a generator that might be used in the case of function-like macros to consume their argument lists.
theFileLineCol
Is a FileLocation.FileLineCol object.
set__FILE__(theStr)

This sets the __FILE__ macro directly.

set__LINE__(theStr)

This sets the __LINE__ macro directly.

undef(theGen, theFile, theLine)

Removes a definition from the map and adds the PpDefine to self._undefS. It returns None. If no definition exists this has no side-effects on the internal representation.