Naive preprocessor support initial implementation (compiles and runs, not heavily tested)

This commit is contained in:
2023-07-30 01:21:04 -04:00
parent 3d7cb85e71
commit bfbfae466f
19 changed files with 641 additions and 199 deletions

View File

@ -489,8 +489,40 @@ String AST::to_string()
}
break;
case Preprocessor_Include:
result.append_fmt( "#include \"%s\"", Name );
case Preprocess_Define:
result.append_fmt( "#define %s %s", Name, Content );
break;
case Preprocess_If:
result.append_fmt( "#if %s", Content );
break;
case Preprocess_IfDef:
result.append_fmt( "#ifdef %s", Content );
break;
case Preprocess_IfNotDef:
result.append_fmt( "#ifndef %s", Content );
break;
case Preprocess_Include:
result.append_fmt( "#include \"%s\"", Content );
break;
case Preprocess_ElIf:
result.append_fmt( "#elif %s", Content );
break;
case Preprocess_Else:
result.append_fmt( "#else" );
break;
case Preprocess_EndIf:
result.append_fmt( "#endif" );
break;
case Preprocess_Pragma:
result.append_fmt( "#pragma %s", Content );
break;
case Specifiers:

View File

@ -12,6 +12,7 @@ struct AST_Body;
struct AST_Attributes;
struct AST_Comment;
struct AST_Class;
struct AST_Define;
struct AST_Enum;
struct AST_Exec;
struct AST_Extern;
@ -23,6 +24,8 @@ struct AST_Namespace;
struct AST_Operator;
struct AST_OpCast;
struct AST_Param;
struct AST_Pragma;
struct AST_PreprocessCond;
struct AST_Specifiers;
struct AST_Struct;
struct AST_Template;
@ -38,6 +41,7 @@ struct CodeBody;
struct CodeAttributes;
struct CodeComment;
struct CodeClass;
struct CodeDefine;
struct CodeEnum;
struct CodeExec;
struct CodeExtern;
@ -49,6 +53,8 @@ struct CodeNamespace;
struct CodeOperator;
struct CodeOpCast;
struct CodeParam;
struct CodePreprocessCond;
struct CodePragma;
struct CodeSpecifiers;
struct CodeStruct;
struct CodeTemplate;
@ -115,6 +121,7 @@ struct Code
operator CodeAttributes() const;
operator CodeComment() const;
operator CodeClass() const;
operator CodeDefine() const;
operator CodeExec() const;
operator CodeEnum() const;
operator CodeExtern() const;
@ -126,6 +133,8 @@ struct Code
operator CodeOperator() const;
operator CodeOpCast() const;
operator CodeParam() const;
operator CodePragma() const;
operator CodePreprocessCond() const;
operator CodeSpecifiers() const;
operator CodeStruct() const;
operator CodeTemplate() const;
@ -175,6 +184,7 @@ struct AST
operator CodeAttributes();
operator CodeComment();
operator CodeClass();
operator CodeDefine();
operator CodeEnum();
operator CodeExec();
operator CodeExtern();
@ -186,6 +196,8 @@ struct AST
operator CodeOperator();
operator CodeOpCast();
operator CodeParam();
operator CodePragma();
operator CodePreprocessCond();
operator CodeSpecifiers();
operator CodeStruct();
operator CodeTemplate();
@ -378,6 +390,7 @@ struct CodeBody
Define_CodeType( Attributes );
Define_CodeType( Comment );
Define_CodeType( Define );
Define_CodeType( Enum );
Define_CodeType( Exec );
Define_CodeType( Extern );
@ -388,6 +401,8 @@ Define_CodeType( Module );
Define_CodeType( Namespace );
Define_CodeType( Operator );
Define_CodeType( OpCast );
Define_CodeType( Pragma );
Define_CodeType( PreprocessCond );
Define_CodeType( Template );
Define_CodeType( Type );
Define_CodeType( Typedef );
@ -631,6 +646,21 @@ struct AST_Class
};
static_assert( sizeof(AST_Class) == sizeof(AST), "ERROR: AST_Class is not the same size as AST");
struct AST_Define
{
union {
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
StringCached Content;
};
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Define) == sizeof(AST), "ERROR: AST_Define is not the same size as AST");
struct AST_Enum
{
union {
@ -847,6 +877,36 @@ struct AST_Param
};
static_assert( sizeof(AST_Param) == sizeof(AST), "ERROR: AST_Param is not the same size as AST");
struct AST_Pragma
{
union {
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
StringCached Content;
};
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_Pragma) == sizeof(AST), "ERROR: AST_Pragma is not the same size as AST");
struct AST_PreprocessCond
{
union {
char _PAD_[ sizeof(SpecifierT) * AST::ArrSpecs_Cap ];
StringCached Content;
};
Code Prev;
Code Next;
Code Parent;
StringCached Name;
CodeT Type;
char _PAD_UNUSED_[ sizeof(ModuleFlag) + sizeof(u32) ];
};
static_assert( sizeof(AST_PreprocessCond) == sizeof(AST), "ERROR: AST_PreprocessCond is not the same size as AST");
struct AST_Specifiers
{
SpecifierT ArrSpecs[ AST::ArrSpecs_Cap ];

View File

@ -37,7 +37,15 @@ namespace ECode
Entry( Operator_Cast ) \
Entry( Operator_Cast_Fwd ) \
Entry( Parameters ) \
Entry( Preprocessor_Include ) \
Entry( Preprocess_Define ) \
Entry( Preprocess_If ) \
Entry( Preprocess_IfDef ) \
Entry( Preprocess_IfNotDef ) \
Entry( Preprocess_ElIf ) \
Entry( Preprocess_Else ) \
Entry( Preprocess_EndIf ) \
Entry( Preprocess_Include ) \
Entry( Preprocess_Pragma ) \
Entry( Specifiers ) \
Entry( Struct ) \
Entry( Struct_Fwd ) \

View File

@ -15,7 +15,7 @@ namespace Parser
Entry( API_Import, "GEN_API_Import_Code" )
#endif
# define Define_TokType \
# define Define_TokType \
Entry( Invalid, "INVALID" ) \
Entry( Access_Private, "private" ) \
Entry( Access_Protected, "protected" ) \
@ -37,7 +37,7 @@ namespace Parser
Entry( Char, "character" ) \
Entry( Comma, "," ) \
Entry( Decl_Class, "class" ) \
Entry( Decl_GNU_Attribute, "__attribute__" ) \
Entry( Decl_GNU_Attribute, "__attribute__" ) \
Entry( Decl_MSVC_Attribute, "__declspec" ) \
Entry( Decl_Enum, "enum" ) \
Entry( Decl_Extern_Linkage, "extern" ) \
@ -56,11 +56,15 @@ namespace Parser
Entry( Number, "number" ) \
Entry( Operator, "operator" ) \
Entry( Preprocess_Define, "#define") \
Entry( Preproces_Include, "include" ) \
Entry( Preprocess_Include, "include" ) \
Entry( Preprocess_If, "#if") \
Entry( Preprocess_Elif, "#elif") \
Entry( Preprocess_IfDef, "#if") \
Entry( Preprocess_IfNotDef, "#ifndef") \
Entry( Preprocess_ElIf, "#elif") \
Entry( Preprocess_Else, "#else") \
Entry( Preprocess_EndIf, "#endif") \
Entry( Preprocess_Pragma, "#pragma") \
Entry( Preprocess_Content, "macro content") \
Entry( Spec_Alignas, "alignas" ) \
Entry( Spec_Const, "const" ) \
Entry( Spec_Consteval, "consteval" ) \

View File

@ -162,6 +162,7 @@ Define_CodeImpl( CodeBody );
Define_CodeImpl( CodeAttributes );
Define_CodeImpl( CodeComment );
Define_CodeImpl( CodeClass );
Define_CodeImpl( CodeDefine );
Define_CodeImpl( CodeEnum );
Define_CodeImpl( CodeExec );
Define_CodeImpl( CodeExtern );
@ -173,6 +174,8 @@ Define_CodeImpl( CodeNamespace );
Define_CodeImpl( CodeOperator );
Define_CodeImpl( CodeOpCast );
Define_CodeImpl( CodeParam );
Define_CodeImpl( CodePragma );
Define_CodeImpl( CodePreprocessCond );
Define_CodeImpl( CodeSpecifiers );
Define_CodeImpl( CodeStruct );
Define_CodeImpl( CodeTemplate );
@ -193,6 +196,7 @@ Define_AST_Cast( Body );
Define_AST_Cast( Attributes );
Define_AST_Cast( Comment );
Define_AST_Cast( Class );
Define_AST_Cast( Define );
Define_AST_Cast( Enum );
Define_AST_Cast( Exec );
Define_AST_Cast( Extern );
@ -204,6 +208,8 @@ Define_AST_Cast( Namespace );
Define_AST_Cast( Operator );
Define_AST_Cast( OpCast );
Define_AST_Cast( Param );
Define_AST_Cast( Pragma );
Define_AST_Cast( PreprocessCond );
Define_AST_Cast( Struct );
Define_AST_Cast( Specifiers );
Define_AST_Cast( Template );
@ -223,6 +229,7 @@ Code::operator Code ## type() const \
Define_CodeCast( Attributes );
Define_CodeCast( Comment );
Define_CodeCast( Class );
Define_CodeCast( Define );
Define_CodeCast( Exec );
Define_CodeCast( Enum );
Define_CodeCast( Extern );
@ -234,6 +241,8 @@ Define_CodeCast( Namespace );
Define_CodeCast( Operator );
Define_CodeCast( OpCast );
Define_CodeCast( Param );
Define_CodeCast( Pragma );
Define_CodeCast( PreprocessCond );
Define_CodeCast( Specifiers );
Define_CodeCast( Struct );
Define_CodeCast( Template );
@ -368,28 +377,6 @@ StrC token_fmt_impl( sw num, ... )
#pragma region Constants
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
// Predefined typename codes. Are set to readonly and are setup during gen::init()
extern CodeType t_b32;
extern CodeType t_s8;
extern CodeType t_s16;
extern CodeType t_s32;
extern CodeType t_s64;
extern CodeType t_u8;
extern CodeType t_u16;
extern CodeType t_u32;
extern CodeType t_u64;
extern CodeType t_sw;
extern CodeType t_uw;
extern CodeType t_f32;
extern CodeType t_f64;
#endif
#ifndef GEN_GLOBAL_BUCKET_SIZE
# define GEN_GLOBAL_BUCKET_SIZE megabytes(10)
#endif
@ -437,29 +424,22 @@ constexpr s32 TokenFmt_TokenMap_MemSize = GEN_TOKEN_FMT_TOKEN_MAP_MEM_SIZE;
constexpr s32 LexAllocator_Size = GEN_LEX_ALLOCATOR_SIZE;
constexpr s32 Builder_StrBufferReserve = GEN_BUILDER_STR_BUFFER_RESERVE;
extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
extern CodeType t_auto;
extern CodeType t_void;
extern CodeType t_int;
extern CodeType t_bool;
extern CodeType t_char;
extern CodeType t_wchar_t;
extern CodeType t_class;
extern CodeType t_typename;
extern CodeParam param_varadic;
extern CodeAttributes attrib_api_export;
extern CodeAttributes attrib_api_import;
extern Code access_public;
extern Code access_protected;
extern Code access_private;
extern CodeAttributes attrib_api_export;
extern CodeAttributes attrib_api_import;
extern Code module_global_fragment;
extern Code module_private_fragment;
extern Code pragma_once;
extern CodePragma pragma_once;
extern CodeParam param_varadic;
extern CodePreprocessCond preprocess_else;
extern CodePreprocessCond preprocess_endif;
extern CodeSpecifiers spec_const;
extern CodeSpecifiers spec_consteval;
@ -482,6 +462,38 @@ extern CodeSpecifiers spec_thread_local;
extern CodeSpecifiers spec_virtual;
extern CodeSpecifiers spec_volatile;
extern CodeType t_empty; // Used with varaidc parameters. (Exposing just in case its useful for another circumstance)
extern CodeType t_auto;
extern CodeType t_void;
extern CodeType t_int;
extern CodeType t_bool;
extern CodeType t_char;
extern CodeType t_wchar_t;
extern CodeType t_class;
extern CodeType t_typename;
#ifdef GEN_DEFINE_LIBRARY_CODE_CONSTANTS
// Predefined typename codes. Are set to readonly and are setup during gen::init()
extern CodeType t_b32;
extern CodeType t_s8;
extern CodeType t_s16;
extern CodeType t_s32;
extern CodeType t_s64;
extern CodeType t_u8;
extern CodeType t_u16;
extern CodeType t_u32;
extern CodeType t_u64;
extern CodeType t_sw;
extern CodeType t_uw;
extern CodeType t_f32;
extern CodeType t_f64;
#endif
#pragma endregion Constants
#pragma region Macros

View File

@ -71,6 +71,59 @@ void define_constants()
Code::Invalid = make_code();
Code::Invalid.set_global();
access_private = make_code();
access_private->Type = ECode::Access_Private;
access_private->Name = get_cached_string( txt_StrC("private:") );
access_private.set_global();
access_protected = make_code();
access_protected->Type = ECode::Access_Protected;
access_protected->Name = get_cached_string( txt_StrC("protected:") );
access_protected.set_global();
access_public = make_code();
access_public->Type = ECode::Access_Public;
access_public->Name = get_cached_string( txt_StrC("public:") );
access_public.set_global();
attrib_api_export = def_attributes( code(GEN_API_Export_Code));
attrib_api_export.set_global();
attrib_api_import = def_attributes( code(GEN_API_Import_Code));
attrib_api_import.set_global();
module_global_fragment = make_code();
module_global_fragment->Type = ECode::Untyped;
module_global_fragment->Name = get_cached_string( txt_StrC("module;") );
module_global_fragment->Content = module_global_fragment->Name;
module_global_fragment.set_global();
module_private_fragment = make_code();
module_private_fragment->Type = ECode::Untyped;
module_private_fragment->Name = get_cached_string( txt_StrC("module : private;") );
module_private_fragment->Content = module_private_fragment->Name;
module_private_fragment.set_global();
pragma_once = (CodePragma) make_code();
pragma_once->Type = ECode::Untyped;
pragma_once->Name = get_cached_string( txt_StrC("once") );
pragma_once->Content = pragma_once->Name;
pragma_once.set_global();
param_varadic = (CodeType) make_code();
param_varadic->Type = ECode::Parameters;
param_varadic->Name = get_cached_string( txt_StrC("...") );
param_varadic->ValueType = t_empty;
param_varadic.set_global();
preprocess_else = (CodePreprocessCond) make_code();
preprocess_else->Type = ECode::Preprocess_Else;
preprocess_else.set_global();
preprocess_endif = (CodePreprocessCond) make_code();
preprocess_endif->Type = ECode::Preprocess_EndIf;
preprocess_endif.set_global();
# define def_constant_code_type( Type_ ) \
t_##Type_ = def_type( name(Type_) ); \
t_##Type_.set_global();
@ -110,51 +163,6 @@ void define_constants()
t_empty->Name = get_cached_string( txt_StrC("") );
t_empty.set_global();
param_varadic = (CodeType) make_code();
param_varadic->Type = ECode::Parameters;
param_varadic->Name = get_cached_string( txt_StrC("...") );
param_varadic->ValueType = t_empty;
param_varadic.set_global();
attrib_api_export = def_attributes( code(GEN_API_Export_Code));
attrib_api_export.set_global();
attrib_api_import = def_attributes( code(GEN_API_Import_Code));
attrib_api_import.set_global();
access_private = make_code();
access_private->Type = ECode::Access_Private;
access_private->Name = get_cached_string( txt_StrC("private:") );
access_private.set_global();
access_protected = make_code();
access_protected->Type = ECode::Access_Protected;
access_protected->Name = get_cached_string( txt_StrC("protected:") );
access_protected.set_global();
access_public = make_code();
access_public->Type = ECode::Access_Public;
access_public->Name = get_cached_string( txt_StrC("public:") );
access_public.set_global();
module_global_fragment = make_code();
module_global_fragment->Type = ECode::Untyped;
module_global_fragment->Name = get_cached_string( txt_StrC("module;") );
module_global_fragment->Content = module_global_fragment->Name;
module_global_fragment.set_global();
module_private_fragment = make_code();
module_private_fragment->Type = ECode::Untyped;
module_private_fragment->Name = get_cached_string( txt_StrC("module : private;") );
module_private_fragment->Content = module_private_fragment->Name;
module_private_fragment.set_global();
pragma_once = make_code();
pragma_once->Type = ECode::Untyped;
pragma_once->Name = get_cached_string( txt_StrC("#pragma once") );
pragma_once->Content = pragma_once->Name;
pragma_once.set_global();
# pragma push_macro( "global" )
# pragma push_macro( "internal" )
# pragma push_macro( "local_persist" )

View File

@ -45,6 +45,8 @@ CodeClass def_class( StrC name
, ModuleFlag mflags = ModuleFlag::None
, CodeType* interfaces = nullptr, s32 num_interfaces = 0 );
CodeDefine def_define( StrC name, StrC content );
CodeEnum def_enum( StrC name
, Code body = NoCode, CodeType type = NoCode
, EnumT specifier = EnumRegular, CodeAttributes attributes = NoCode
@ -70,7 +72,11 @@ CodeOperator def_operator( OperatorT op
CodeOpCast def_operator_cast( CodeType type, Code body = NoCode, CodeSpecifiers specs = NoCode );
CodeParam def_param ( CodeType type, StrC name, Code value = NoCode );
CodeParam def_param ( CodeType type, StrC name, Code value = NoCode );
CodePragma def_pragma( StrC directive );
CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC content );
CodeSpecifiers def_specifier( SpecifierT specifier );
CodeStruct def_struct( StrC name

View File

@ -36,7 +36,12 @@ namespace Parser
bool is_preprocessor()
{
return Type >= TokType::Preprocess_Define && Type <= TokType::Preprocess_EndIf;
return Type >= TokType::Preprocess_Define && Type <= TokType::Preprocess_Pragma;
}
bool is_preprocess_cond()
{
return Type >= TokType::Preprocess_If && Type <= TokType::Preprocess_EndIf;
}
bool is_specifier()
@ -163,7 +168,13 @@ namespace Parser
{
String token_str = String::make( GlobalAllocator, { Arr[Idx].Length, Arr[Idx].Text } );
log_failure( "Parse Error, TokArray::eat, Expected: %s, not '%s' (%d, %d)`\n%s", ETokType::to_str(type), token_str, current().Line, current().Column, Context.to_string() );
log_failure( "Parse Error, TokArray::eat, Expected: %s, not '%s' (%d, %d)`\n%s"
, ETokType::to_str(type)
, token_str
, current().Line
, current().Column
, Context.to_string()
);
return false;
}
@ -177,7 +188,7 @@ namespace Parser
IsAssign = bit(0),
};
TokArray lex( StrC content, bool keep_preprocess_directives = true )
TokArray lex( StrC content )
{
# define current ( * scanner )
@ -202,17 +213,6 @@ namespace Parser
move_forward(); \
}
# define SkipWhitespace_Checked( Context_, Msg_, ... ) \
while ( left && char_is_space( current ) ) \
{ \
move_forward(); \
} \
if ( left <= 0 ) \
{ \
log_failure( "gen::" txt(Context_) ": " Msg_, __VA_ARGS__ ); \
return { 0, nullptr }; \
}
local_persist thread_local
Array<Token> Tokens = { nullptr };
@ -249,34 +249,93 @@ namespace Parser
switch ( current )
{
// TODO : Need to handle the preprocessor as a separate pass.
case '#':
{
token.Text = scanner;
token.Length = 1;
move_forward();
while (left && current != '\n' )
while (left && current != ' ' )
{
if ( token.Type == ETokType::Invalid && current == ' ' )
{
token.Type = ETokType::to_type( token );
}
if ( current == '\\' )
{
move_forward();
if ( current != '\n' && keep_preprocess_directives )
{
log_failure( "gen::lex: invalid preprocessor directive, will still grab but will not compile %s", token.Text );
}
}
move_forward();
token.Length++;
}
goto FoundToken;
token.Type = ETokType::to_type( token );
Tokens.append( token );
Token content = { scanner, 0, TokType::Preprocess_Content, false, line, column };
if ( token.Type == TokType::Preprocess_Include )
{
content.Type = TokType::String;
SkipWhitespace();
if ( current != '"' )
{
log_failure( "gen::Parser::lex: Expected '\"' after #include, not '%c' (%d, %d)\n%s"
, current
, token.Line
, token.Column
, Context.to_string()
);
return { { nullptr }, 0 };
}
while ( left && current != '"' )
{
move_forward();
content.Length++;
}
move_forward();
content.Length++;
Tokens.append( content );
continue; // Skip found token, its all handled here.
}
while ( left )
{
if ( current == '\\' )
{
move_forward();
content.Length++;
if ( current == '\n' )
{
move_forward();
content.Length++;
continue;
}
else
{
String directive_str = String::fmt_buf( GlobalAllocator, "%s", token.Text, token.Length );
String content_str = String::fmt_buf( GlobalAllocator, "%s", content, min( 40, left + content.Length ) );
log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
" in preprocessor directive '%.*s' (%d, %d)\n"
"will continue parsing, but compiliation will fail (if using non-fatal failures).\n"
, content_str, line, column
, directive_str, token.Line, token.Column );
break;
}
}
if ( current == '\n' )
{
move_forward();
content.Length++;
break;
}
move_forward();
content.Length++;
}
Tokens.append( content );
continue; // Skip found token, its all handled here.
}
case '.':
token.Text = scanner;
token.Length = 1;
@ -297,7 +356,9 @@ namespace Parser
}
else
{
log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c'", current );
String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) );
log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)", context_str, line, column );
}
}
@ -669,7 +730,7 @@ namespace Parser
{
String context_str = String::fmt_buf( GlobalAllocator, "%s", scanner, min( 100, left ) );
log_failure( "Failed to lex token %s", context_str );
log_failure( "Failed to lex token %s (%d, %d)", context_str, line, column );
// Skip to next whitespace since we can't know if anything else is valid until then.
while ( left && ! char_is_space( current ) )
@ -682,9 +743,6 @@ namespace Parser
if ( token.Type != TokType::Invalid )
{
if ( token.is_preprocessor() && keep_preprocess_directives == false )
continue;
Tokens.append( token );
continue;
}
@ -708,22 +766,21 @@ namespace Parser
# undef current
# undef move_forward
# undef SkipWhitespace
# undef SkipWhitespace_Checked
}
}
#pragma region Helper Macros
# define check_parse_args( def ) \
if ( def.Len <= 0 ) \
{ \
# define check_parse_args( def ) \
if ( def.Len <= 0 ) \
{ \
log_failure( "gen::" stringize(__func__) ": length must greater than 0" ); \
return CodeInvalid; \
} \
if ( def.Ptr == nullptr ) \
{ \
return CodeInvalid; \
} \
if ( def.Ptr == nullptr ) \
{ \
log_failure( "gen::" stringize(__func__) ": def was null" ); \
return CodeInvalid; \
return CodeInvalid; \
}
# define nexttok Context.Tokens.next()
@ -734,7 +791,7 @@ if ( def.Ptr == nullptr )
# define check( Type_ ) ( left && currtok.Type == Type_ )
# define push_scope() \
# define push_scope() \
StackNode scope { nullptr, currtok, NullToken, txt_StrC( __func__ ) }; \
Context.push( & scope )
@ -760,6 +817,115 @@ internal CodeTypedef parse_typedef ();
internal CodeUnion parse_union ();
internal CodeUsing parse_using ();
internal inline
CodeDefine parse_define()
{
using namespace Parser;
push_scope();
eat( TokType::Preprocess_Define );
CodeDefine
define = (CodeDefine) make_code();
define->Type = ECode::Preprocess_Define;
if ( ! check( TokType::Identifier ) )
{
log_failure( "Error, expected identifier after #define\n%s", Context.to_string() );
return CodeInvalid;
}
define->Name = get_cached_string( currtok );
eat( TokType::Identifier );
if ( ! check( TokType::Preprocess_Content ))
{
log_failure( "Error, expected content after #define %s\n%s", define->Name, Context.to_string() );
return CodeInvalid;
}
define->Content = get_cached_string( currtok );
eat( TokType::Preprocess_Content );
Context.pop();
return define;
}
internal inline
CodePreprocessCond parse_preprocess_cond()
{
using namespace Parser;
push_scope();
if ( ! currtok.is_preprocess_cond() )
{
log_failure( "Error, expected preprocess conditional\n%s", Context.to_string() );
return CodeInvalid;
}
CodePreprocessCond
cond = (CodePreprocessCond) make_code();
cond->Type = scast(CodeT, currtok.Type - (ETokType::Preprocess_If - ECode::Preprocess_If) );
eat( currtok.Type );
if ( ! check( TokType::Preprocess_Content ))
{
log_failure( "Error, expected content after #define\n%s", Context.to_string() );
return CodeInvalid;
}
cond->Content = get_cached_string( currtok );
eat( TokType::Preprocess_Content );
Context.pop();
return cond;
}
internal inline
CodeInclude parse_include()
{
using namespace Parser;
push_scope();
CodeInclude
include = (CodeInclude) make_code();
include->Type = ECode::Preprocess_Include;
if ( ! check( TokType::String ))
{
log_failure( "Error, expected include string after #include\n%s", Context.to_string() );
return CodeInvalid;
}
include->Content = get_cached_string( currtok );
eat( TokType::String );
Context.pop();
return include;
}
internal inline
CodePragma parse_pragma()
{
using namespace Parser;
push_scope();
CodePragma
pragma = (CodePragma) make_code();
pragma->Type = ECode::Preprocess_Pragma;
if ( ! check( TokType::Preprocess_Content ))
{
log_failure( "Error, expected content after #define\n%s", Context.to_string() );
return CodeInvalid;
}
pragma->Content = get_cached_string( currtok );
eat( TokType::Preprocess_Content );
Context.pop();
return pragma;
}
internal inline
Code parse_array_decl()
{
@ -1677,6 +1843,33 @@ CodeBody parse_class_struct_body( Parser::TokType which )
member = parse_using();
break;
case TokType::Preprocess_Define:
member = parse_define();
break;
case TokType::Preprocess_Include:
member = parse_include();
break;
case TokType::Preprocess_If:
case TokType::Preprocess_IfDef:
case TokType::Preprocess_IfNotDef:
case TokType::Preprocess_ElIf:
member = parse_preprocess_cond();
break;
case TokType::Preprocess_Pragma:
member = parse_pragma();
break;
case TokType::Preprocess_Else:
member = preprocess_else;
break;
case TokType::Preprocess_EndIf:
member = preprocess_endif;
break;
case TokType::Attribute_Open:
case TokType::Decl_GNU_Attribute:
case TokType::Decl_MSVC_Attribute:
@ -1966,6 +2159,33 @@ CodeBody parse_global_nspace( CodeT which )
member = parse_using();
break;
case TokType::Preprocess_Define:
member = parse_define();
break;
case TokType::Preprocess_Include:
member = parse_include();
break;
case TokType::Preprocess_If:
case TokType::Preprocess_IfDef:
case TokType::Preprocess_IfNotDef:
case TokType::Preprocess_ElIf:
member = parse_preprocess_cond();
break;
case TokType::Preprocess_Pragma:
member = parse_pragma();
break;
case TokType::Preprocess_Else:
member = preprocess_else;
break;
case TokType::Preprocess_EndIf:
member = preprocess_endif;
break;
case TokType::Module_Export:
if ( which == Export_Body )
log_failure( "Nested export declaration\n%s", Context.to_string() );

View File

@ -489,6 +489,26 @@ CodeClass def_class( StrC name
return result;
}
CodeDefine def_define( StrC name, StrC content )
{
using namespace ECode;
name_check( def_define, name );
if ( content.Len <= 0 || content.Ptr == nullptr )
{
log_failure( "gen::def_define: Invalid value provided" );
return CodeInvalid;
}
CodeDefine
result = (CodeDefine) make_code();
result->Name = get_cached_string( name );
result->Content = get_cached_string( content );
return result;
}
CodeEnum def_enum( StrC name
, Code body, CodeType type
, EnumT specifier, CodeAttributes attributes
@ -719,7 +739,7 @@ CodeInclude def_include ( StrC path )
Code
result = make_code();
result->Type = ECode::Preprocessor_Include;
result->Type = ECode::Preprocess_Include;
result->Name = get_cached_string( path );
result->Content = result->Name;
@ -910,6 +930,53 @@ CodeParam def_param( CodeType type, StrC name, Code value )
return result;
}
CodePragma def_pragma( StrC directive )
{
using namespace ECode;
if ( directive.Len <= 0 || directive.Ptr == nullptr )
{
log_failure( "gen::def_comment: Invalid comment provided:" );
return CodeInvalid;
}
CodePragma
result = (CodePragma) make_code();
result->Type = Preprocess_Pragma;
result->Content = get_cached_string( directive );
return result;
}
CodePreprocessCond def_preprocess_cond( EPreprocessCond type, StrC expr )
{
using namespace ECode;
if ( expr.Len <= 0 || expr.Ptr == nullptr )
{
log_failure( "gen::def_comment: Invalid comment provided:" );
return CodeInvalid;
}
CodePreprocessCond
result = (CodePreprocessCond) make_code();
result->Content = get_cached_string( expr );
switch (type)
{
case EPreprocessCond::If:
result->Type = ECode::Preprocess_If;
case EPreprocessCond::IfDef:
result->Type = Preprocess_IfDef;
case EPreprocessCond::IfNotDef:
result->Type = Preprocess_IfNotDef;
case EPreprocessCond::ElIf:
result->Type = Preprocess_ElIf;
}
return result;
}
CodeSpecifiers def_specifier( SpecifierT spec )
{
CodeSpecifiers

View File

@ -22,6 +22,44 @@ global AllocatorInfo Allocator_TypeTable = heap();
#pragma region Constants
global Code access_public;
global Code access_protected;
global Code access_private;
global CodeAttributes attrib_api_export;
global CodeAttributes attrib_api_import;
global Code module_global_fragment;
global Code module_private_fragment;
global CodeParam param_varadic;
global CodePragma pragma_once;
global CodePreprocessCond preprocess_else;
global CodePreprocessCond preprocess_endif;
global CodeSpecifiers spec_const;
global CodeSpecifiers spec_consteval;
global CodeSpecifiers spec_constexpr;
global CodeSpecifiers spec_constinit;
global CodeSpecifiers spec_extern_linkage;
global CodeSpecifiers spec_final;
global CodeSpecifiers spec_global;
global CodeSpecifiers spec_inline;
global CodeSpecifiers spec_internal_linkage;
global CodeSpecifiers spec_local_persist;
global CodeSpecifiers spec_mutable;
global CodeSpecifiers spec_override;
global CodeSpecifiers spec_ptr;
global CodeSpecifiers spec_ref;
global CodeSpecifiers spec_register;
global CodeSpecifiers spec_rvalue;
global CodeSpecifiers spec_static_member;
global CodeSpecifiers spec_thread_local;
global CodeSpecifiers spec_virtual;
global CodeSpecifiers spec_volatile;
global CodeType t_empty;
global CodeType t_auto;
global CodeType t_void;
@ -52,39 +90,4 @@ global CodeType t_f32;
global CodeType t_f64;
#endif
global CodeParam param_varadic;
global CodeAttributes attrib_api_export;
global CodeAttributes attrib_api_import;
global Code access_public;
global Code access_protected;
global Code access_private;
global Code module_global_fragment;
global Code module_private_fragment;
global Code pragma_once;
global CodeSpecifiers spec_const;
global CodeSpecifiers spec_consteval;
global CodeSpecifiers spec_constexpr;
global CodeSpecifiers spec_constinit;
global CodeSpecifiers spec_extern_linkage;
global CodeSpecifiers spec_final;
global CodeSpecifiers spec_global;
global CodeSpecifiers spec_inline;
global CodeSpecifiers spec_internal_linkage;
global CodeSpecifiers spec_local_persist;
global CodeSpecifiers spec_mutable;
global CodeSpecifiers spec_override;
global CodeSpecifiers spec_ptr;
global CodeSpecifiers spec_ref;
global CodeSpecifiers spec_register;
global CodeSpecifiers spec_rvalue;
global CodeSpecifiers spec_static_member;
global CodeSpecifiers spec_thread_local;
global CodeSpecifiers spec_virtual;
global CodeSpecifiers spec_volatile;
#pragma endregion Constants

View File

@ -8,16 +8,6 @@ using LogFailType = sw(*)(char const*, ...);
constexpr LogFailType log_failure = fatal;
#endif
// Used to indicate if enum definitoin is an enum class or regular enum.
enum class EnumT : u8
{
Regular,
Class
};
constexpr EnumT EnumClass = EnumT::Class;
constexpr EnumT EnumRegular = EnumT::Regular;
enum class AccessSpec : u32
{
Default,
@ -46,6 +36,17 @@ char const* to_str( AccessSpec type )
return lookup[ (u32)type ];
}
// Used to indicate if enum definitoin is an enum class or regular enum.
enum class EnumT : u8
{
Regular,
Class
};
constexpr EnumT EnumClass = EnumT::Class;
constexpr EnumT EnumRegular = EnumT::Regular;
enum class ModuleFlag : u32
{
None = 0,
@ -62,6 +63,19 @@ ModuleFlag operator|( ModuleFlag A, ModuleFlag B)
return (ModuleFlag)( (u32)A | (u32)B );
}
enum class EPreprocessCond : u32
{
If,
IfDef,
IfNotDef,
ElIf
};
constexpr EPreprocessCond PreprocessCond_If = EPreprocessCond::If;
constexpr EPreprocessCond PreprocessCond_IfDef = EPreprocessCond::IfDef;
constexpr EPreprocessCond PreprocessCond_IfNotDef = EPreprocessCond::IfNotDef;
constexpr EPreprocessCond PreprocessCond_ElIf = EPreprocessCond::ElIf;
/*
Predefined attributes
Used for the parser constructors to identify non-standard attributes