mirror of
https://github.com/Ed94/gencpp.git
synced 2025-06-15 11:11:46 -07:00
Naive preprocessor support initial implementation (compiles and runs, not heavily tested)
This commit is contained in:
@ -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:
|
||||
|
@ -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 ];
|
||||
|
@ -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 ) \
|
||||
|
@ -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" ) \
|
||||
|
@ -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
|
||||
|
@ -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" )
|
||||
|
@ -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
|
||||
|
@ -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() );
|
||||
|
0
project/components/interface.upfront.bodies.cpp
Normal file
0
project/components/interface.upfront.bodies.cpp
Normal 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user