40 KiB
Navigation
Parser's Algorithm
gencpp uses a hand-written recursive descent parser. Both the lexer and parser currently handle a full C/C++ file in a single pass.
Notable implementation background
Lexer
File: lexer.cpp
The lex
procedure does the lexical pass of content provided as a Str
type.
The tokens are stored (for now) in Lexer_Tokens
.
Fields:
Array<Token> Arr;
s32 Idx;
What token types are supported can be found in ETokType.csv you can also find the token types in ETokType.h , which is the generated enum from the csv file.
struct Token
{
Str Text;
TokType Type;
s32 Line;
s32 Column;
u32 Flags;
}
Flags is a bitfield made up of TokFlags (Token Flags):
TF_Operator
: Any operator token used in expressionsTF_Assign
- Using statment assignment
- Parameter argument default value assignment
- Variable declaration initialization assignment
TF_Preprocess
: Related to a preprocessing directiveTF_Preprocess_Cond
: A preprocess conditionalTF_Attribute
: An attribute tokenTF_AccessSpecifier
: An accesor operation tokenTF_Specifier
: One of the specifier tokensTF_EndDefinition
: Can be interpreted as an end definition for a scope.TF_Formatting
: Considered a part of the formattingTF_Literal
: Anything considered a literal by C++.TF_Macro_Functional
: Used to indicate macro token is flagged asMF_Functional
.TF_Macro_Expects_Body
: Used to indicate macro token is flagged asMF_Expects_Body
.
Parser
Files:
The parser has a limited user interface, only specific types of definitions or statements are expected to be provided by the user directly when using to construct an AST dynamically. It however does attempt to provide capability to parse a full C/C++ from production codebases.
Each public user interface procedure has the following format:
<code type> parse_<definition type>( Str def )
{
check_parse_args( def );
using namespace Parser;
TokArray toks = lex( def );
if ( toks.Arr == nullptr )
return CodeInvalid;
// Parse the tokens and return a constructed AST using internal procedures
...
}
The most top-level parsing procedure used for C/C++ file parsing is parse_global_body
.
It uses a helper procedure called parse_global_nspace
.
Each internal procedure will have the following format:
internal
<code type> parse_<definition_type>( <empty or contextual params> )
{
push_scope();
...
<code type> result = (<code type>) make_code();
...
Context.pop();
return result;
}
The parsing implementation contains throughut the codeapths to indicate how far their contextual AST node has been resolved.
Example:
internal
CodeFn parser_parse_function()
{
push_scope();
Specifier specs_found[16] = { Spec_NumSpecifiers };
s32 NumSpecifiers = 0;
CodeAttributes attributes = { nullptr };
CodeSpecifiers specifiers = { nullptr };
ModuleFlag mflags = ModuleFlag_None;
if ( check(Tok_Module_Export) ) {
mflags = ModuleFlag_Export;
eat( Tok_Module_Export );
}
// <export>
attributes = parse_attributes();
// <export> <Attributes>
while ( left && tok_is_specifier(currtok) )
{
Specifier spec = str_to_specifier( tok_to_str(currtok) );
switch ( spec )
{
GEN_PARSER_FUNCTION_ALLOWED_SPECIFIER_CASES:
break;
default:
log_failure( "Invalid specifier %S for functon\n%SB", spec_to_str(spec), parser_to_strbuilder(_ctx->parser) );
parser_pop(& _ctx->parser);
return InvalidCode;
}
if ( spec == Spec_Const )
continue;
specs_found[NumSpecifiers] = spec;
NumSpecifiers++;
eat( currtok.Type );
}
if ( NumSpecifiers ) {
specifiers = def_specifiers_arr( NumSpecifiers, specs_found );
}
// <export> <Attributes> <Specifiers>
CodeTypename ret_type = parser_parse_type(parser_not_from_template, nullptr);
if ( cast(Code, ret_type) == Code_Invalid ) {
parser_pop(& _ctx->parser);
return InvalidCode;
}
// <export> <Attributes> <Specifiers> <ReturnType>
Token name = parse_identifier(nullptr);
_ctx->parser.Scope->Name = name.Text;
if ( ! tok_is_valid(name) ) {
parser_pop(& _ctx->parser);
return InvalidCode;
}
// <export> <Attributes> <Specifiers> <ReturnType> <Name>
CodeFn result = parse_function_after_name( mflags, attributes, specifiers, ret_type, name );
// <export> <Attributes> <Specifiers> <ReturnType> <Name> ...
parser_pop(& _ctx->parser);
return result;
}
In the above parse_function
implementation:
// <intutive expression of AST component> ...
Will be conventionlly used where by that point in time for the codepath: <intutive expression of AST component>
should be resolved for the AST.
Outline of parsing codepaths
Below is an outline of the general alogirithim used for these internal procedures. The intention is to provide a basic briefing to aid the user in traversing the actual code definitions. These appear in the same order as they are in the parser.cpp
file
NOTE: This is still heavily in an alpha state. A large swaph of this can change, make sure these docs are up to date before considering them 1:1 with the repo commit your considering.
parse_array_decl
- Push parser scope
- Check for empty array
[]
- Return untyped string with single space if found
- Check for opening bracket
[
- Validate parser not at EOF
- Reject empty array expression
- Capture expression tokens until closing bracket
- Calculate expression span length
- Convert to untyped string
- Validate and consume closing bracket
]
- Handle multi-dimensional case
- If adjacent
[
detected, recursively parse - Link array expressions via Next pointer
- If adjacent
- Pop parser scope
- Return array expression or NullCode on failure
parse_attributes
- Push parser scope and initialize tracking
- Store initial token position
- Initialize length counter
- Process attributes while available
- Handle C++ style attributes
[[...]]
- Consume opening
[[
- Capture content until closing
]]
- Calculate attribute span length
- Consume opening
- Handle GNU style
__attribute__((...))
- Consume
__attribute__
keyword and opening((
- Capture content until closing
))
- Calculate attribute span length
- Consume
- Handle MSVC style
__declspec(...)
- Consume
__declspec
and opening(
- Capture content until closing
)
- Calculate attribute span length
- Consume
- Handle macro-style attributes
- Consume attribute token
- If followed by parentheses
- Handle nested parentheses tracking
- Capture content maintaining paren balance
- Calculate attribute span length
- Handle C++ style attributes
- Generate attribute code if content captured
- Create attribute text span from start position and length
- Strip formatting from attribute text
- Construct Code node
- Set type to
CT_PlatformAttributes
- Cache and set Name and Content fields
- Set type to
- Return as CodeAttributes
- Pop parser scope
- Return NullCode if no attributes found
parse_class_struct
- Validate token type is class or struct
- Return InvalidCode if validation fails
- Initialize class/struct metadata
- Access specifier (default)
- Parent class/struct reference
- Class/struct body
- Attributes
- Module flags
- Parse module export flag if present
- Set ModuleFlag_Export
- Consume export token
- Consume class/struct token
- Parse attributes via
parse_attributes()
- Parse class/struct identifier
- Update parser scope name
- Initialize interface array (4KB arena)
- Parse inheritance/implementation
- If classifier token (
:
) present- Parse access specifier if exists
- Parse parent class/struct name
- Parse additional interfaces
- Separated by commas
- Optional access specifiers
- Store in interface array
- If classifier token (
- Parse class body if present
- Triggered by opening brace
- Parse via
parse_class_struct_body
- Handle statement termination
- Skip for inplace definitions
- Consume semicolon
- Parse inline comment if present
- Construct result node
- Create class definition if Tok_Decl_Class
- Create struct definition if Tok_Decl_Struct
- Attach inline comment if exists
- Cleanup interface array and return result
parse_class_struct_body
- Initialize scope and body structure
- Push parser scope
- Consume opening brace
- Create code node with
CT_Class_Body
orCT_Struct_Body
type
- Parse body members while not at closing brace
- Initialize member parsing state
- Code member (InvalidCode)
- Attributes (null)
- Specifiers (null)
- Function expectation flag
- Handle preprocessor hash if present
- Process member by token type in switch statement
- Statement termination - warn and skip
- Newline - format member
- Comments - parse comment
- Access specifiers -
public/protected/private
- Declarations -
class/enum/struct/union/typedef/using
- Operators -
destructors/casts
- Preprocessor directives -
define/include/conditionals/pragmas
- Preprocessor statement macros
- Report naked preprocossor expression macros detected as an error.
- Static assertions
- Attributes and specifiers
- Parse attributes
- Parse valid member specifiers
- Handle
attribute-specifier-attribute
case
- Identifiers and types
- Check for constructors
- Parse
operator/function/variable
- Default - capture unknown content until closing brace
- Validate member parsing
- Return InvalidCode if member invalid
- Append valid member to body
- Initialize member parsing state
- Finalize body
- Consume closing brace
- Pop parser scope
- Return completed CodeBody
parse_comment
- Just wrap the token into a cached string ( the lexer did the processing )
parse_complicated_definition
- Initialize parsing context
- Push scope
- Set inplace flag false
- Get token array reference
- Scan ahead for statement termination
- Track brace nesting level
- Find first semicolon at level 0
- Handle declaration variants
- Forward declaration case
- Check if only 2 tokens before semicolon
- Parse via
parse_forward_or_definition
- Function with trailing specifiers
- Identify trailing specifiers
- Check for function pattern
- Parse as
operator/function/variable
- Return
InvalidCode
if pattern invalid
- Identifier-based declarations
- Check identifier patterns
- Inplace definition
{...} id;
- Namespace type variable
which id id;
- Enum with class qualifier
Pointer/reference
types
- Inplace definition
- Parse as
operator/function/variable
if valid - Return
InvalidCode
if pattern invalid
- Check identifier patterns
- Basic type declarations
- Validate enum class pattern
- Parse via
parser_parse_enum
- Return
InvalidCode
if invalid
- Direct definitions
- Handle closing brace -
parse_forward_or_definition
- Handle array definitions -
parse_operator_function_or_variable
- Return InvalidCode for unknown patterns
- Handle closing brace -
- Forward declaration case
parse_assignment_expression
- Initialize expression parsing
- Null expression pointer
- Consume assignment operator token
- Capture initial expression token
- Validate expression presence
- Check for immediate termination
- Return
InvalidCode
if missing expression
- Parse balanced expression
- Track nesting level for
- Curly braces
- Parentheses
- Continue until
- End of input, or
- Statement terminator, or
- Unnested comma
- Consume tokens sequentially
- Track nesting level for
- Generate expression code
- Calculate expression span length
- Convert to untyped string
- Return expression node
parse_forward_or_definition
- Declaration type routing
- Class (
Tok_Decl_Class
) ->parser_parse_class
- Enum (
Tok_Decl_Enum
) ->parser_parse_enum
- Struct (
Tok_Decl_Struct
) ->parser_parse_struct
- Union (
Tok_Decl_Union
) ->parser_parse_union
- Class (
- Error handling
- Return
InvalidCode
for unsupported token types - Log failure with parser context
- Return
is_inplace
flag propagates to specialized codepaths to maintain parsing context.
parse_function_after_name
This is needed as a function definition is not easily resolvable early on, as such this function handles resolving a function after its been made ceratin that the type of declaration or definition is indeed for a function signature.
By the point this function is called the following are known : export module flag, attributes, specifiers, return type, & name
- Parameter parsing
- Push scope
- Parse parameter list with parentheses
- Post-parameter specifier processing
- Collect trailing specifiers
- Initialize or append to existing specifiers
- Parse function termination
- Function body case
- Parse body if open brace found
- Validate body type (
CT_Function_Body
orCT_Untyped
)
- Pure virtual case
- Handle "
= 0
" syntax - Append pure specifier
- Handle "
- Forward declaration case
- Consume statement terminator
- Handle inline comments for all cases
- Function body case
- Construct function node
- Strip whitespace from name
- Initialize
CodeFn
with base properties- Name (cached, stripped)
- Module flags
- Set node type
CT_Function
if body presentCT_Function_Fwd
if declaration only
- Attach components
- Attributes if present
- Specifiers if present
- Return type
- Parameters if present
- Inline comment if present
- Cleanup and return
- Pop scope
- Return completed function node
parse_function_body
Currently there is no actual parsing of the function body. Any content with the braces is shoved into an execution AST node. In the future statements and expressions will be parsed.
- Initialize body parsing
- Push scope
- Consume opening brace
- Create CodeBody with CT_Function_Body type
- Capture function content
- Record start token position
- Track brace nesting level
- Consume tokens while
- Input remains AND
- Not at unmatched closing brace
- Update level counters
- Increment on open brace
- Decrement on closing brace when level > 0
- Process captured content
- Calculate content length via pointer arithmetic
- Create execution block if content exists
- Construct string span from start position and length
- Wrap in execution node
- Append to body
- Finalize
- Consume closing brace
- Pop scope
- Return cast body node
parse_global_nspace
- State initialization
- Push parser scope
- Validate namespace type (Global, Namespace, Export, Extern Linkage)
- Consume opening brace for non-global scopes
- Initialize
CodeBody
with specified body type:which
- Member parsing loop (while not at closing brace)
- Reset parse state
- Member code
- Attributes
- Specifiers
- Function expectation flag
- Member type handling
- Declarations
Class/Struct/Union/Enum
viaparse_complicated_definition
Template/Typedef/Using
via dedicated parsersNamespace/Export/Extern
declarations
- Preprocessor directivess
- Include/Define
- Conditionals
(if / ifdef / ifndef / elif / else / endif)
- Pragmas
- Preprocessor statement macros
- Report naked preprocossor expression macros detected as an error.
- Comments/Formatting
- Newlines
- Comments
- Static assertions
- Declarations
- Attributes and specifiers
- Parse attributes if present
- Collect valid specifiers (max 16)
- Handle
consteval
for function expectation
- Identifier resolution
- Check
constructor/destructor
implementation - Look ahead for user defined operator implementation outside of class
- Default to
operator/function/variable
parse
- Check
- Reset parse state
- Member validation/storage
- Validate parsed member
- Append to body if valid
- Return
InvalidCode
on parse failure
- Scope finalization
- Consume closing brace for non-global scopes
- Pop parser scope
- Return completed body
parse_global_nspace_constructor_destructor
- Forward Token Analysis
- Scan for parameter list opening parenthesis
- Template Expression Handling
- Track template nesting depth
- Account for nested parentheses within templates
- Skip until template closure or parameter start
// Valid patterns:
ClassName :: ClassName(...)
ClassName :: ~ClassName(...)
ClassName< T ... > :: ClassName(...)
- Constructor/Destructor Identification
- Token Validation Sequence
- Verify identifier preceding parameters
- Check for destructor indicator (
~
) - Validate scope resolution operator (
::
)
- Left-side Token Analysis
- Process nested template expressions
- Maintain template/capture level tracking
- Locate matching identifier token
- Token Validation Sequence
- Parser Resolution
- Name Pattern Validation
- Compare identifier tokens for exact match
- Specialized Parsing
- Route to
parser_parse_destructor
for '~' prefix - Route to
parser_parse_constructor
for direct match
- Route to
- Apply specifiers to resulting node
- Name Pattern Validation
- Return result (
NullCode
on pattern mismatch)
Implementation Constraints
- Cannot distinguish nested namespaces with identical names
- Return type detection requires parser enhancement
- Template parameter validation is syntax-based only
- Future enhancement: Implement type parsing with rollback capability
parse_identifier
This is going to get heavily changed down the line to have a more broken down "identifier expression" so that the qualifier, template args, etc, can be distinguished between the targeted identifier.
The function can parse all of them, however the AST node compresses them all into a string.
- Initialize identifier context
- Push parser scope
- Capture initial token as name
- Set scope name from token text
- Process initial identifier component
- Consume identifier token
- Parse template arguments if present
- Handle qualified identifiers (loop while
::
found)- Consume static access operator
- Validate token sequence:
- Handle destructor operator (
~
)- Validate destructor parsing context
- Update name span if valid
- Return invalid on context mismatch
- Process member function pointer (
*
)- Set possible_member_function flag if context allows
- Return invalid if pointer unexpected
- Verify identifier token follows
- Handle destructor operator (
- Update identifier span
- Extend name length to include new qualifier
- Consume identifier token
- Parse additional template arguments
- Return completed identifier token
Notes:
- Current implementation treats identifier as single token span
- TODO: Refactor to AST-based identifier representation for:
- Better support for nested symbol resolution
parse_include
- Consume include directive
- Consume the path
parse_operator_after_ret_type
This is needed as a operator definition is not easily resolvable early on, as such this function handles resolving a operator after its been made ceratin that the type of declaration or definition is indeed for a operator signature.
By the point this function is called the following are known : export module flag, attributes, specifiers, and return type
- Initialize operator context
- Push scope
- Parse qualified namespace identifier
- Consume
operator
keyword
- Operator identification
- Validate operator token presence
- Set scope name from operator token
- Map operator token to internal operator enum:
- Arithmetic:
+, -, *, /, %
- Assignment:
+=, -=, *=, /=, %=, =
- Bitwise:
&, |, ^, ~, >>
- Logical:
&&, ||, !, ==
- Comparison:
<, >, <=, >=
- Member access:
->, ->*
- Special:
(), [], new, delete
- Arithmetic:
- Handle array variants for new/delete
- Parameter and specifier processing
- Parse parameter list
- Handle multiply/member-pointer ambiguity
- Collect trailing specifiers
- Merge with existing specifiers
- Function body handling
- Parse implementation if present
- Otherwise consume statement terminator
- Capture inline comments
- Result construction
- Create operator node with:
- Operator type
- Namespace qualification
- Parameters
- Return type
- Implementation body
- Specifiers
- Attributes
- Module flags
- Attach inline comments
- Create operator node with:
- Pop scope
parse_operator_function_or_variable
When this function is called, attribute and specifiers may have been resolved, however what comes next can still be either an operator, function, or variable.
- Initial Type Resolution
- Push parsing scope
- Handle macro definitions via
parse_macro_as_definition
- Parse base type, validate result
- Exit on invalid type
- Declaration Classification
- Scan token stream for
operator
keyword - Track static symbol access
- Branch handling:
- Operator overload: Forward to
parse_operator_after_ret_type
- Function/variable: Parse identifier and analyze context
- Operator overload: Forward to
- Scan token stream for
- Function/Variable Disambiguation
- Parse identifier
- Analyze token patterns:
- Detect parameter capture via parenthesis
- Check for constructor initialization pattern
- Handle variadic argument cases
- Macro Expression Analysis:
- Validate functional macros
- Track parenthesis balance
- Detect comma patterns
- Declaration Parsing
- Function path
- Verify function expectation (
consteval
) - Delegate to
parse_function_after_name
- Verify function expectation (
- Variable path
- Validate against function expectation
- Forward to
parse_variable_after_name
- Function path
parse_macro_as_definition
- Validation
- Check token type (Tok_Preprocess_Macro_Stmt)
- Retrieve macro from lookup
- Verify
MF_Allow_As_Definition
flag
- Macro Processing
- Parse via
parse_simple_preprocess
- Maintain original token categorization
- Parse via
- Definition Construction
- Format components:
- Attributes (if present)
- Specifiers (if present)
- Macro content
- Build unified string representation
- Convert to untyped code node
- Format components:
Notes:
- Early exits return NullCode for non-qualifying macros
- TODO: Pending AST_Macro implementation for proper attribute/specifier support
parse_pragma
- Consume pragma directive
- Process the token content into cached string
parse_params
- Parameter List Initialization
- Delimiter handling based on context
- Parentheses:
(...)
for standard parameters - Angle brackets:
<...>
for template parameters
- Parentheses:
- Early return for empty parameter lists
- Initial parameter component initialization
- Macro reference
- Type information
- Parameter value
- Identifier token
- Delimiter handling based on context
- Primary Parameter Processing
- Handle varadic arguments
- Process preprocessor macros (
UPARAM
style) - Parse parameter sequence
- Type information
- Optional identifier
- Post-name macro expressions
- Default value expressions
- Value expression capture with nested structure tracking
- Template depth counting
- Parentheses balance
- Text span calculation
- Multi-Parameter Handling
- Parse comma-separated entries
- Maintain parameter structure
- Macro context
- Type information
- Identifier caching
- Post-name macro persistence
- Value assignments
- Parameter list construction via
params_append
- Consume params capture termination token & return result.
parse_preprocess_cond
- Parse conditional directive
- Process directive's content expression
parse_simple_preprocess
- Basic Setup
- Push scope
- Capture initial macro token
- Validate macro registration
- Lookup in macro registry
- Skip validation for unsupported macros
- Functional Macro Processing
- Handle macro invocation
- Parse opening parenthesis
- Track nested parenthesis level
- Capture parameter content
- Update macro span length
- Handle macro invocation
- Macro Body Handling
- Process associated block if macro expects body
- Parse curly brace delimited content
- Track nesting level
- Capture body content
- Handle statement termination
- Context-specific semicolon handling
- Process inline comments
- Update macro span
- Process associated block if macro expects body
- Context-Specific Termination
- Special case handling
- Enum context bypass
- Typedef context validation
- Global/class scope handling
- Statement termination rules
- Process semicolons based on context
- Update token span accordingly
- Special case handling
Notes:
- Pending AST_Macro implementation for improved structure
- Current implementation uses simple token span capture
parse_static_assert
- Consume static assert and opening curly brace
- Consume all tokens until the the closing brace is reached.
- Consume curly brace and end statement
- Place all tokens within braces into a content for the assert.
parse_template_args
This will get changed heavily once we have better support for typename expressions
- Consume opening angle bracket
- Consume all tokens until closing angle bracket
- Consme closing angle bracket
- Return the currtok with the ammended length.
parse_variable_after_name
This is needed as a variable definition is not easily resolvable early on, it takes a long evaluation period before its known that the declaration or definition is a variable. As such this function handles resolving a variable.
By the point this function is called the following are known : export module flag, attributes, specifiers, value type, name
- Initialization Processing
- Array dimension parsing
- Expression capture
- Assignment expressions
- Constructor initializations
- Bitfield specifications
- Expression Pattern Handling
- Direct assignment (
=
)- Parse assignment expression
- Brace initialization (
{}
)- Track nested braces
- Capture initialization list
- Constructor initialization (
()
)- Track parenthesis nesting
- Update initialization flag
- Bitfield specification (
:
)- Validate non-empty expression
- Capture bitfield size
- Direct assignment (
- Multi-Variable Processing
- Handle comma-separated declarations
- Statement termination
- Process semicolon
- Capture inline comments
- Link variable chain via NextVar
- AST Node Construction
- Core properties
- Type (
CT_Variable
) - Name caching
- Module flags
- Value type
- Type (
- Optional components
- Array expression
- Bitfield size
- Attributes/Specifiers
- Initialization value
- Constructor flag
- Parent/Next linkage
- Core properties
parse_variable_declaration_list
- Chain Initialization
- Initialize null variable chain head and tail
- Process while comma token present
- Per-Variable Processing
- Specifier Collection
- Validate specifier ordering (const after pointer)
- Handle core specifiers:
ptr, ref, rvalue
- Maintain specifier chain integrity
- Log invalid specifier usage but continue parsing
- Variable Declaration
- Extract identifier name
- Parse remainder via
parse_variable_after_name
- Note: Function pointers unsupported
- Specifier Collection
- Chain Management
- First Variable
- Set as chain head and tail
- Subsequent Variables
- Link to previous via NextVar
- Establish parent reference
- Update tail pointer
- First Variable
Limitations:
- No function pointer support
parser_parse_class
parse_class_struct
parser_parse_constructor
- Core Parse Sequence
- Identifier extraction and parameter list capture
- Handle construction variants:
- Colon-prefixed member initializer lists
- Direct body implementation
- Default/delete assignment forms
- Forward declarations
- Initializer List Processing
- Track nested parentheses balance
- Capture full initializer span
- Convert to untyped string representation
- Implementation Variants
- Body implementation
- Parse full function body
- Set
CT_Constructor
type
- Forward declaration
- Process terminator and comments
- Set
CT_Constructor_Fwd
type
- Special forms
- Handle assignment operator cases
- Capture inline comments for declarations
- Body implementation
- AST Construction
- Core node attributes
- Cached identifier name
- Parameter list linkage
- Specifier chain
- Optional components
- Initializer list
- Implementation body
- Inline comments
- Core node attributes
parser_parse_define
- Token Stream Preparation
- Handle optional preprocessor hash
- Consume define directive
- Validate identifier presence
- Define Node Initialization
- Construct CodeDefine with
CT_Preprocess_Define
type - Cache identifier name
- Update scope context
- Construct CodeDefine with
- Parameter Processing (Functional Macros)
- Initial parameter detection
- Verify macro functionality
- Initialize parameter list node (
CT_Parameters_Define
)
- Parameter chain construction
- Initial parameter detection
- Content Handling
- Content validation
- Verify presence
- Handle empty content case with newline
- Content processing
- Strip formatting
- Preserve line termination
- Create untyped node
- Content validation
parser_parse_destructor
- Context Validation
- Verify parser scope hierarchy
- Check global namespace context
- Process
virtual
specifier if present
- Identifier Resolution
- Parse prefix identifier in global scope
- Validate destructor operator (
~
) - Capture destructor name
- Enforce empty parameter list
- Specifier Processing
- Handle pure virtual case (
= 0
)- Append
Spec_Pure
to specifiers - Set
pure_virtual
flag
- Append
- Process default specifier (= default)
- Parse as assignment expression
- Validate specifier syntax
- Handle pure virtual case (
- Implementation Processing
- Function body (non-pure case)
- Parse complete body
- Set
CT_Destructor
type
- Forward declaration
- Handle statement termination
- Process inline comments
- Set
CT_Destructor_Fwd
type
- Function body (non-pure case)
- AST Construction
- Build destructor node
- Handle qualified names
- Concatenate prefix and identifier
- Attach components
- Specifiers
- Implementation body
- Inline comments
parser_parse_enum
- Declaration Components
- Basic structure processing
- Enum type detection (
enum/enum class
) - Attributes parsing
- Identifier capture
- Enum type detection (
- Underlying type resolution
- Standard type parsing
- Macro-based underlying type handling
- Classifier token validation
- Basic structure processing
- Body Processing
- Entry parsing loop
- Preprocessor directives (
#define, #if, #pragma
) - Enum member declarations
- Comment preservation
- Formatting tokens
- Preprocessor directives (
- Entry value handling
- Assignment expressions
UMETA
macro support- Entry termination (commas)
- Token span calculation for entries
- Entry parsing loop
- AST Construction
- Node type determination
CT_Enum/CT_Enum_Class
for definitionsCT_Enum_Fwd/CT_Enum_Class_Fwd
for declarations
- Component attachment
- Name caching
- Body linkage
- Underlying type/macro
- Attributes
- Inline comments
- Node type determination
parser_parse_export_body
parse_global_nspace
parser_parse_extern_link_body
parse_global_nspace
parser_parse_extern_link
- Consume
Tok_Decl_Extern_Linkage
- Consume the linkage identifier
parse_extern_link_body
parser_parse_friend
- Consume
friend
- Parse specifiers
parse_type
- If the currok is an identifier its a function declaration or definition
parse_function_after_name
- Otherwise its a operator:
parse_operator_after_ret_type
- Consume end statement so long as its not a function definion
- Check for inline comment,
parse_comment
if exists
parser_parse_function
- Check and parse for
export
parse_attributes
- Parse specifiers
parse_type
for return typeparse_identifier
parse_function_after_name
parser_parse_namespace
- Consume namespace declaration
- Parse identifier
parse_global_namespace
parser_parse_operator
- Check for and parse export declaration
parse_attributes
- Parse specifiers
parse_type
parse_operator_after_ret_type
parser_parse_operator_cast
- Look for and parse a qualifier namespace for the cast (in-case this is defined outside the class's scope)
- Consume operator declaration
parse_type
- Consume opening and closing parethesis
- Check for a const qualifiying specifier
- Check to see if this is a definition (
{
)- Consume
{
- Parse body to untyped string (parsing statement and expressions not supported yet)
- Consume
}
- Consume
- Otherwise:
- Consume end statement
- Check for and consume comment :
parse_comment
parser_parse_struct
parse_class_struct
parser_parse_template
- Initial State Configuration
- Module flag handling (
export
keyword) - Template parameter parsing via
parse_params
- Uses specialized template capture mode
- Validates parameter list integrity
- Module flag handling (
- Declaration Type Resolution
- Primary type dispatch
Class/Struct/Union
declarations- Using declarations
- Function/Variable handling
- Attribute collection
- Specifier validation (16 max)
- Function expectation detection
- Primary type dispatch
- Special Case Processing
- Global namespace constructors/destructors
- Context validation
- Delegation to
parse_global_nspace_constructor_destructor
- Operator cast implementations
- Token lookahead for operator detection
- Static symbol access validation
- Cast parsing delegation
- Global namespace constructors/destructors
- AST Construction
- Template node composition
CT_Template
type assignment- Parameter linkage
- Declaration binding
- Module flag preservation
- Template node composition
parser_parse_type
This implementatin will be updated in the future to properly handle functional typename signatures.
Current Algorithm
Anything that is in the qualifier capture of the function typename is treated as an expression abstracted as an untyped string
parse_attributes
- Parse specifiers
- If the
parse_type
was called from a template parse, check to see if class was used instead of typname and consume as name. - This is where things get ugly for each of these depend on what the next token is.
- If its an in-place definition of a class, enum, struct, or union:
- If its a decltype (Not supported yet but draft impl there)
- If its a compound native type expression (unsigned, char, short, long, int, float, dobule, etc )
- If its a typename amcro
- A regular type alias of an identifier
- Parse specifiers (postfix)
- We need to now look ahead to see If we're dealing with a function typename
- If wer're dealing with a function typename:
- Shove the specifiers, and identifier code we have so far into a return type typename's Name (untyped string)
- Reset the specifiers code for the top-level typeanme
- Check to see if the next token is an identifier:
parse_identifier
- Check to see if the next token is capture start and is not the last capture ("qualifier capture"):
- Consume
(
- Consume expresssion between capture
- Consume
)
- Consume
parse_params
- Parse postfix specifiers
- Shove the specifiers, and identifier code we have so far into a return type typename's Name (untyped string)
- Check for varaidic argument (param pack) token:
- Consume varadic argument token
WIP - Alternative Algorithm
Currently wrapped up via macro: GEN_USE_NEW_TYPENAME_PARSING
Anything that is in the qualifier capture of the function typename is treated as an expression abstracted as an untyped string
parse_attributes
- Parse specifiers (prefix)
- This is where things get ugly for each of these depend on what the next token is.
- If its an in-place definition of a class, enum, struct, or union:
- If its a decltype (Not supported yet but draft impl there)
- If its a compound native type expression (unsigned, char, short, long, int, float, dobule, etc )
- If its a typename amcro
- A regular type alias of an identifier
- Parse specifiers (postfix)
- If any specifiers are found populate specifiers code with them.
- We need to now look ahead to see If we're dealing with a function typename
- If wer're dealing with a function typename:
- Shove the specifiers, and identifier code we have so far into a return type typename's Name (untyped string)
- Reset the specifiers code for the top-level typename
- Check to see if the next token is an identifier:
parse_identifier
- Check to see if the next token is capture start and is not the last capture ("qualifier capture"):
- Consume
(
- Parse binding specifiers
parse_identifier
parse_parameters
-> params_nested- Consume
)
- Construct a nested function typename definition for the qualifier
Name
- Consume
parse_params
- > params- Parse postfix specifiers
- Shove the specifiers, and identifier code we have so far into a return type typename's Name (untyped string)
- Check for varaidic argument (param pack) token:
- Consume varadic argument token
Later: Algorithm based on typename expressions
parse_typedef
- Check for export module specifier
- typedef keyword
- If its a preprocess macro: Get the macro name
- Else:
- Check to see if its a complicated definition (in-place enum, class, struct, union)
- If its a complicated definition:
- Perform the look ahead similar to
parse_complicated_definition
's implementation - Check to see if its a forward declaration :
parse_forward_declaration
- If end[-1] is an identifier:
- Its either an in-place, varaible type qualified identifier, or indirection type:
parse_foward_or_definition
- Its either an in-place, varaible type qualified identifier, or indirection type:
- else if end[-1] is a closing curly brace
- Its a definition:
parse_forward_or_definition
- Its a definition:
- else if end[-1] is a closing square brace
2. Its an array definition:
parse_type
- Perform the look ahead similar to
- Else :
parse-type
- Check for identifier : Consume the token
parse_array_decl
- Consume end statement
- Check for inline comment :
parse_comment
parse_union
- Check for export module specifier
- union keyword
parse_attributes
- Check for identifier
- Parse the body (Possible options):
- Newline
- Comment
- Decl_Class
- Decl_Enum
- Decl_Struct
- Decl_Union
- Preprocess_Define
- Preprocess_Conditional (if, ifdef, ifndef, elif, else, endif)
- Preprocess_Macro (
MT_Statement
orMT_Typename
) - Preprocess_Pragma
- Unsupported preprocess directive
- Variable
- If its not an inplace definiton: End Statement
parse_using
- Check for export module specifier
- using keyword
- Check to see if its a using namespace
- Get the identifier
- If its a regular using declaration:
parse_attributes
parse_type
parse_array_decl
- End statement
- Check for inline comment
parse_variable
- Check for export module specifier
parse_attributes
parse specifiers
parse_type
parse_identifier
parse_variable_after_name