2023-11-20 12:09:01 -08:00
|
|
|
#ifdef GEN_INTELLISENSE_DIRECTIVES
|
|
|
|
#pragma once
|
|
|
|
#include "interface.upfront.cpp"
|
|
|
|
#include "gen/etoktype.cpp"
|
|
|
|
#endif
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
GEN_NS_PARSER_BEGIN
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
enum TokFlags : u32
|
|
|
|
{
|
|
|
|
TF_Operator = bit(0),
|
|
|
|
TF_Assign = bit(1),
|
|
|
|
TF_Preprocess = bit(2),
|
|
|
|
TF_Preprocess_Cond = bit(3),
|
|
|
|
TF_Attribute = bit(6),
|
2024-04-17 14:40:32 -07:00
|
|
|
TF_AccessOperator = bit( 7 ),
|
|
|
|
TF_AccessSpecifier = bit( 8 ),
|
|
|
|
TF_Specifier = bit( 9 ),
|
|
|
|
TF_EndDefinition = bit( 10 ), // Either ; or }
|
|
|
|
TF_Formatting = bit( 11 ),
|
|
|
|
TF_Literal = bit( 12 ),
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
TF_Null = 0,
|
|
|
|
};
|
|
|
|
|
|
|
|
struct Token
|
|
|
|
{
|
|
|
|
char const* Text;
|
|
|
|
sptr Length;
|
|
|
|
TokType Type;
|
|
|
|
s32 Line;
|
|
|
|
s32 Column;
|
|
|
|
u32 Flags;
|
2024-12-02 19:25:39 -08:00
|
|
|
};
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
constexpr Token NullToken { nullptr, 0, Tok_Invalid, false, 0, TF_Null };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
AccessSpec to_access_specifier(Token tok)
|
|
|
|
{
|
|
|
|
return scast(AccessSpec, tok.Type);
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
StrC to_str(Token tok)
|
|
|
|
{
|
|
|
|
return { tok.Length, tok.Text };
|
|
|
|
}
|
2024-04-17 14:40:32 -07:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_valid( Token tok )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
return tok.Text && tok.Length && tok.Type != Tok_Invalid;
|
2024-12-02 19:25:39 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_access_operator(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_AccessOperator );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_access_specifier(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_AccessSpecifier );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_attribute(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_Attribute );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_operator(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_Operator );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_preprocessor(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_Preprocess );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_preprocess_cond(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_Preprocess_Cond );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_specifier(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_Specifier );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool is_end_definition(Token tok)
|
|
|
|
{
|
|
|
|
return bitfield_is_equal( u32, tok.Flags, TF_EndDefinition );
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
String to_string(Token tok)
|
|
|
|
{
|
|
|
|
String result = string_make_reserve( GlobalAllocator, kilobytes(4) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
StrC type_str = to_str( tok.Type );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
append_fmt( & result, "Line: %d Column: %d, Type: %.*s Content: %.*s"
|
|
|
|
, tok.Line, tok.Column
|
|
|
|
, type_str.Len, type_str.Ptr
|
|
|
|
, tok.Length, tok.Text
|
|
|
|
);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return result;
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
struct TokArray
|
|
|
|
{
|
2024-12-02 19:25:39 -08:00
|
|
|
Array(Token) Arr;
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 Idx;
|
2024-12-02 19:25:39 -08:00
|
|
|
};
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
bool __eat( TokType type );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token* current(TokArray* self, bool skip_formatting )
|
|
|
|
{
|
|
|
|
if ( skip_formatting )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( self->Arr[self->Idx].Type == Tok_NewLine || self->Arr[self->Idx].Type == Tok_Comment )
|
2024-12-02 19:25:39 -08:00
|
|
|
self->Idx++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return & self->Arr[self->Idx];
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token* previous(TokArray self, bool skip_formatting)
|
|
|
|
{
|
|
|
|
s32 idx = self.Idx;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( skip_formatting )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( self.Arr[idx].Type == Tok_NewLine )
|
2024-12-02 19:25:39 -08:00
|
|
|
idx --;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return & self.Arr[idx];
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return & self.Arr[idx - 1];
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
Token* next(TokArray self, bool skip_formatting)
|
|
|
|
{
|
|
|
|
s32 idx = self.Idx;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
if ( skip_formatting )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
while ( self.Arr[idx].Type == Tok_NewLine )
|
2024-12-02 19:25:39 -08:00
|
|
|
idx++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return & self.Arr[idx + 1];
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
return & self.Arr[idx + 1];
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-05-05 18:53:22 -07:00
|
|
|
global Arena_256KB defines_map_arena;
|
2024-12-02 19:25:39 -08:00
|
|
|
global HashTable(StrC) defines;
|
|
|
|
global Array(Token) Tokens;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
#define current ( * ctx->scanner )
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
#define move_forward() \
|
|
|
|
{ \
|
|
|
|
if ( current == '\n' ) \
|
|
|
|
{ \
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->line++; \
|
|
|
|
ctx->column = 1; \
|
2023-11-20 12:09:01 -08:00
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->column++; \
|
2023-11-20 12:09:01 -08:00
|
|
|
} \
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->left--; \
|
|
|
|
ctx->scanner++; \
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
#define SkipWhitespace() \
|
|
|
|
while ( ctx->left && char_is_space( current ) ) \
|
|
|
|
{ \
|
|
|
|
move_forward(); \
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
#define end_line() \
|
|
|
|
do \
|
|
|
|
{ \
|
|
|
|
while ( ctx->left && current == ' ' ) \
|
|
|
|
{ \
|
|
|
|
move_forward(); \
|
|
|
|
} \
|
|
|
|
if ( ctx->left && current == '\r' ) \
|
|
|
|
{ \
|
|
|
|
move_forward(); \
|
|
|
|
move_forward(); \
|
|
|
|
} \
|
|
|
|
else if ( ctx->left && current == '\n' ) \
|
|
|
|
{ \
|
|
|
|
move_forward(); \
|
|
|
|
} \
|
|
|
|
} \
|
2023-11-20 12:09:01 -08:00
|
|
|
while (0)
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
Lex_Continue,
|
|
|
|
Lex_ReturnNull,
|
|
|
|
};
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
struct LexContext
|
|
|
|
{
|
|
|
|
StrC content;
|
|
|
|
s32 left;
|
|
|
|
char const* scanner;
|
|
|
|
s32 line;
|
|
|
|
s32 column;
|
|
|
|
HashTable(StrC) defines;
|
|
|
|
Token token;
|
|
|
|
};
|
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
forceinline
|
2024-12-02 22:44:01 -08:00
|
|
|
s32 lex_preprocessor_directive( LexContext* ctx )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
char const* hash = ctx->scanner;
|
2024-12-03 06:50:30 -08:00
|
|
|
append( & Tokens, { hash, 1, Tok_Preprocess_Hash, ctx->line, ctx->column, TF_Preprocess } );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
move_forward();
|
|
|
|
SkipWhitespace();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Text = ctx->scanner;
|
|
|
|
while (ctx->left && ! char_is_space(current) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
ctx->token.Type = to_toktype( to_str(ctx->token) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
bool is_preprocessor = ctx->token.Type >= Tok_Preprocess_Define && ctx->token.Type <= Tok_Preprocess_Pragma;
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( ! is_preprocessor )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
ctx->token.Type = Tok_Preprocess_Unsupported;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Its an unsupported directive, skip it
|
|
|
|
s32 within_string = false;
|
|
|
|
s32 within_char = false;
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( ctx->left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '"' && ! within_char )
|
|
|
|
within_string ^= true;
|
|
|
|
|
|
|
|
if ( current == '\'' && ! within_string )
|
|
|
|
within_char ^= true;
|
|
|
|
|
|
|
|
if ( current == '\\' && ! within_string && ! within_char )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
|
|
|
" in preprocessor directive (%d, %d)\n%.100s"
|
2024-12-02 22:44:01 -08:00
|
|
|
, current, ctx->line, ctx->column
|
|
|
|
, ctx->token.Line, ctx->token.Column, ctx->token.Text );
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length = ctx->token.Length + ctx->token.Text - hash;
|
|
|
|
ctx->token.Text = hash;
|
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
return Lex_Continue; // Skip found token, its all handled here.
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ctx->token.Type == Tok_Preprocess_Else || ctx->token.Type == Tok_Preprocess_EndIf )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Flags |= TF_Preprocess_Cond;
|
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
end_line();
|
|
|
|
return Lex_Continue;
|
|
|
|
}
|
2024-12-03 06:50:30 -08:00
|
|
|
else if ( ctx->token.Type >= Tok_Preprocess_If && ctx->token.Type <= Tok_Preprocess_ElIf )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Flags |= TF_Preprocess_Cond;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
SkipWhitespace();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ctx->token.Type == Tok_Preprocess_Define )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
Token name = { ctx->scanner, 0, Tok_Identifier, ctx->line, ctx->column, TF_Preprocess };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
name.Text = ctx->scanner;
|
2023-11-20 12:09:01 -08:00
|
|
|
name.Length = 1;
|
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( ctx->left && ( char_is_alphanumeric(current) || current == '_' ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
name.Length++;
|
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( ctx->left && current == '(' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
name.Length++;
|
|
|
|
}
|
|
|
|
|
2024-12-01 18:59:43 -08:00
|
|
|
append( & Tokens, name );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
u64 key = crc32( name.Text, name.Length );
|
2024-12-02 22:44:01 -08:00
|
|
|
set(& ctx->defines, key, to_str(name) );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
Token preprocess_content = { ctx->scanner, 0, Tok_Preprocess_Content, ctx->line, ctx->column, TF_Preprocess };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ctx->token.Type == Tok_Preprocess_Include )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
preprocess_content.Type = Tok_String;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( current != '"' && current != '<' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
String directive_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 80, ctx->left + preprocess_content.Length ), ctx->token.Text );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
log_failure( "gen::Parser::lex: Expected '\"' or '<' after #include, not '%c' (%d, %d)\n%s"
|
|
|
|
, current
|
|
|
|
, preprocess_content.Line
|
|
|
|
, preprocess_content.Column
|
|
|
|
, directive_str.Data
|
|
|
|
);
|
|
|
|
return Lex_ReturnNull;
|
|
|
|
}
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( ctx->left && current != '"' && current != '>' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( current == '\r' && ctx->scanner[1] == '\n' )
|
2024-05-05 18:53:22 -07:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
else if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
2024-12-01 18:59:43 -08:00
|
|
|
append( & Tokens, preprocess_content );
|
2023-11-20 12:09:01 -08:00
|
|
|
return Lex_Continue; // Skip found token, its all handled here.
|
|
|
|
}
|
|
|
|
|
|
|
|
s32 within_string = false;
|
|
|
|
s32 within_char = false;
|
|
|
|
|
|
|
|
// SkipWhitespace();
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( ctx->left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '"' && ! within_char )
|
|
|
|
within_string ^= true;
|
|
|
|
|
|
|
|
if ( current == '\'' && ! within_string )
|
|
|
|
within_char ^= true;
|
|
|
|
|
|
|
|
if ( current == '\\' && ! within_string && ! within_char )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
String directive_str = string_make_length( GlobalAllocator, ctx->token.Text, ctx->token.Length );
|
|
|
|
String content_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 400, ctx->left + preprocess_content.Length ), preprocess_content.Text );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
log_failure( "gen::Parser::lex: Invalid escape sequence '\\%c' (%d, %d)"
|
|
|
|
" in preprocessor directive '%s' (%d, %d)\n%s"
|
2024-12-02 22:44:01 -08:00
|
|
|
, current, ctx->line, ctx->column
|
2023-11-20 12:09:01 -08:00
|
|
|
, directive_str, preprocess_content.Line, preprocess_content.Column
|
|
|
|
, content_str );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
move_forward();
|
|
|
|
preprocess_content.Length++;
|
|
|
|
}
|
|
|
|
|
2024-12-01 18:59:43 -08:00
|
|
|
append( & Tokens, preprocess_content );
|
2023-11-20 12:09:01 -08:00
|
|
|
return Lex_Continue; // Skip found token, its all handled here.
|
|
|
|
}
|
|
|
|
|
|
|
|
forceinline
|
2024-12-03 06:31:27 -08:00
|
|
|
void lex_found_token( LexContext* ctx )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ctx->token.Type != Tok_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-12-03 10:14:14 -08:00
|
|
|
TokType type = to_toktype( to_str(ctx->token) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if (type <= Tok_Access_Public && type >= Tok_Access_Private )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Flags |= TF_AccessSpecifier;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( type > Tok___Attributes_Start )
|
2024-04-17 14:40:32 -07:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Flags |= TF_Attribute;
|
2024-04-17 14:40:32 -07:00
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( type == Tok_Decl_Extern_Linkage )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
SkipWhitespace();
|
|
|
|
|
|
|
|
if ( current != '"' )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
type = Tok_Spec_Extern;
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Flags |= TF_Specifier;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Type = type;
|
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( ( type <= Tok_Star && type >= Tok_Spec_Alignas)
|
|
|
|
|| type == Tok_Ampersand
|
|
|
|
|| type == Tok_Ampersand_DBL )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Type = type;
|
|
|
|
ctx->token.Flags |= TF_Specifier;
|
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
if ( type != Tok_Invalid )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Type = type;
|
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 key = 0;
|
|
|
|
if ( current == '(')
|
2024-12-02 22:44:01 -08:00
|
|
|
key = crc32( ctx->token.Text, ctx->token.Length + 1 );
|
2023-11-20 12:09:01 -08:00
|
|
|
else
|
2024-12-02 22:44:01 -08:00
|
|
|
key = crc32( ctx->token.Text, ctx->token.Length );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
StrC* define = get(ctx->defines, key );
|
2023-11-20 12:09:01 -08:00
|
|
|
if ( define )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
ctx->token.Type = Tok_Preprocess_Macro;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Want to ignore any arguments the define may have as they can be execution expressions.
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( ctx->left && current == '(' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
s32 level = 0;
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( ctx->left && (current != ')' || level > 0) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '(' )
|
|
|
|
level++;
|
|
|
|
|
|
|
|
else if ( current == ')' && level > 0 )
|
|
|
|
level--;
|
|
|
|
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
ctx->token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( current == '\r' && ctx->scanner[1] == '\n' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
else if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
ctx->token.Type = Tok_Identifier;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, ctx->token );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2023-11-21 17:09:14 -08:00
|
|
|
|
2023-11-20 12:09:01 -08:00
|
|
|
neverinline
|
2023-11-22 11:23:21 -08:00
|
|
|
// TokArray lex( Array<Token> tokens, StrC content )
|
2023-11-20 12:09:01 -08:00
|
|
|
TokArray lex( StrC content )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
LexContext c; LexContext* ctx = & c;
|
|
|
|
c.content = content;
|
|
|
|
c.left = content.Len;
|
|
|
|
c.scanner = content.Ptr;
|
|
|
|
c.defines = defines;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
char const* word = c.scanner;
|
2023-11-20 12:09:01 -08:00
|
|
|
s32 word_length = 0;
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
c.line = 1;
|
|
|
|
c.column = 1;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
SkipWhitespace();
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left <= 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
log_failure( "gen::lex: no tokens found (only whitespace provided)" );
|
2024-12-01 15:50:37 -08:00
|
|
|
return { {}, 0 };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-11-30 15:54:19 -08:00
|
|
|
foreach( StringCached, entry, PreprocessorDefines )
|
2023-11-21 17:09:14 -08:00
|
|
|
{
|
|
|
|
s32 length = 0;
|
|
|
|
char const* scanner = entry.Data;
|
2024-12-01 00:06:30 -08:00
|
|
|
while ( GEN_NS length(entry) > length && (char_is_alphanumeric( *scanner ) || *scanner == '_') )
|
2023-11-21 17:09:14 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.scanner++;
|
2023-11-21 17:09:14 -08:00
|
|
|
length ++;
|
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.scanner[0] == '(' )
|
2023-11-21 17:09:14 -08:00
|
|
|
{
|
|
|
|
length++;
|
|
|
|
}
|
|
|
|
|
|
|
|
u64 key = crc32( entry.Data, length );
|
2024-12-02 22:44:01 -08:00
|
|
|
set(& c.defines, key, (StrC)entry );
|
2023-11-21 17:09:14 -08:00
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-11-30 15:54:19 -08:00
|
|
|
clear(Tokens);
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while (c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (Tokens.num())
|
|
|
|
{
|
|
|
|
log_fmt("\nLastTok: %S", Tokens.back().to_string());
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token = { c.scanner, 0, Tok_Invalid, c.line, c.column, TF_Null };
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
bool is_define = false;
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.column == 1 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '\r')
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 1;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_NewLine;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, c.token );
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 0;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
SkipWhitespace();
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left <= 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
break;
|
|
|
|
|
|
|
|
switch ( current )
|
|
|
|
{
|
|
|
|
case '#':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
s32 result = lex_preprocessor_directive( ctx );
|
2023-11-20 12:09:01 -08:00
|
|
|
switch ( result )
|
|
|
|
{
|
|
|
|
case Lex_Continue:
|
|
|
|
continue;
|
|
|
|
|
|
|
|
case Lex_ReturnNull:
|
2024-12-01 15:50:37 -08:00
|
|
|
return { {}, 0 };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
case '.':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Access_MemberSymbol;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_AccessOperator;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left) {
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '.' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
if( current == '.' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 3;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Varadic_Argument;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Null;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
String context_str = string_fmt_buf( GlobalAllocator, "%s", c.scanner, min( 100, c.left ) );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
log_failure( "gen::lex: invalid varadic argument, expected '...' got '..%c' (%d, %d)\n%s", current, c.line, c.column, context_str );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '&' :
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Ampersand;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags |= TF_Operator;
|
|
|
|
c.token.Flags |= TF_Specifier;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '&' ) // &&
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 2;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Ampersand_DBL;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case ':':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Assign_Classifer;
|
2023-11-20 12:09:01 -08:00
|
|
|
// Can be either a classifier (ParentType, Bitfield width), or ternary else
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_Colon;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == ':' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Access_StaticSymbol;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '{':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_BraceCurly_Open;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '}':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_BraceCurly_Close;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_EndDefinition;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
end_line();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '[':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_BraceSquare_Open;
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == ']' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 2;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case ']':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_BraceSquare_Close;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '(':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Capture_Start;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case ')':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Capture_End;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '\'':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Char;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Literal;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left && current == '\\' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
if ( current == '\'' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && current != '\'' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case ',':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Comma;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '*':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Star;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags |= TF_Specifier;
|
|
|
|
c.token.Flags |= TF_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '=' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
|
|
|
c.token.Flags |= TF_Assign;
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Assign_Multiply;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case ';':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Statement_End;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_EndDefinition;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
end_line();
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '"':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_String;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags |= TF_Literal;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '"' )
|
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\\' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '?':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
|
|
|
// c.token.Type = Tok_Ternary;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '=':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
|
|
|
// c.token.Type = Tok_Assign;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
|
|
|
c.token.Flags |= TF_Assign;
|
|
|
|
|
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '=' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
|
|
|
c.token.Flags = TF_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '+':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Add
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
case '%':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Modulo;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
case '^':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_B_XOr;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
case '~':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Unary_Not;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
case '!':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_L_Not;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
case '<':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Lesser;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
case '>':
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// c.token.Type = Tok_Greater;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
}
|
|
|
|
case '|':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_L_Or;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '=' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
|
|
|
c.token.Flags |= TF_Assign;
|
2023-11-20 12:09:01 -08:00
|
|
|
// token.Flags |= TokFlags::Assignment;
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_Assign_L_Or;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
else while ( c.left && current == *(c.scanner - 1) && c.token.Length < 3 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Dash is unfortunatlly a bit more complicated...
|
|
|
|
case '-':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
|
|
|
// token.Type = Tok_Subtract;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '>' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_Access_PointerToMemberSymbol;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags |= TF_AccessOperator;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '*' )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_Access_PointerToMemberOfPointerSymbol;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( current == '=' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2024-12-03 06:50:30 -08:00
|
|
|
// token.Type = Tok_Assign_Subtract;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags |= TF_Assign;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
else while ( c.left && current == *(c.scanner - 1) && c.token.Length < 3 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left)
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
case '/':
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Operator;
|
|
|
|
// token.Type = Tok_Divide;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Operator;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
if ( current == '=' )
|
|
|
|
{
|
|
|
|
// token.Type = TokeType::Assign_Divide;
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
|
|
|
c.token.Flags = TF_Assign;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
else if ( current == '/' )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Comment;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 2;
|
|
|
|
c.token.Flags = TF_Null;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && current != '\n' && current != '\r' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, c.token );
|
2023-11-20 12:09:01 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if ( current == '*' )
|
|
|
|
{
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Comment;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length = 2;
|
|
|
|
c.token.Flags = TF_Null;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
|
|
|
bool star = current == '*';
|
2024-12-02 22:44:01 -08:00
|
|
|
bool slash = c.scanner[1] == '/';
|
2023-11-20 12:09:01 -08:00
|
|
|
bool at_end = star && slash;
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && ! at_end )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
star = current == '*';
|
2024-12-02 22:44:01 -08:00
|
|
|
slash = c.scanner[1] == '/';
|
2023-11-20 12:09:01 -08:00
|
|
|
at_end = star && slash;
|
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length += 2;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
move_forward();
|
|
|
|
|
|
|
|
if ( current == '\r' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
if ( current == '\n' )
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-12-02 22:44:01 -08:00
|
|
|
append( & Tokens, c.token );
|
2023-11-20 12:09:01 -08:00
|
|
|
// end_line();
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( char_is_alpha( current ) || current == '_' )
|
|
|
|
{
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && ( char_is_alphanumeric(current) || current == '_' ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
else if ( char_is_digit(current) )
|
|
|
|
{
|
|
|
|
// This is a very brute force lex, no checks are done for validity of literal.
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Text = c.scanner;
|
|
|
|
c.token.Length = 1;
|
2024-12-03 06:50:30 -08:00
|
|
|
c.token.Type = Tok_Number;
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Flags = TF_Literal;
|
2023-11-20 12:09:01 -08:00
|
|
|
move_forward();
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left
|
2023-11-20 12:09:01 -08:00
|
|
|
&& ( current == 'x' || current == 'X'
|
|
|
|
|| current == 'b' || current == 'B'
|
|
|
|
|| current == 'o' || current == 'O' )
|
|
|
|
)
|
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && char_is_hex_digit(current) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && char_is_digit(current) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
if ( c.left && current == '.' )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && char_is_digit(current) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
2024-10-24 22:04:17 -07:00
|
|
|
|
|
|
|
// Handle number literal suffixes in a botched way
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left && (
|
2024-10-24 22:04:17 -07:00
|
|
|
current == 'l' || current == 'L' || // long/long long
|
|
|
|
current == 'u' || current == 'U' || // unsigned
|
|
|
|
current == 'f' || current == 'F' || // float
|
|
|
|
current == 'i' || current == 'I' || // imaginary
|
|
|
|
current == 'z' || current == 'Z')) // complex
|
|
|
|
{
|
|
|
|
char prev = current;
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2024-10-24 22:04:17 -07:00
|
|
|
|
|
|
|
// Handle 'll'/'LL' as a special case when we just processed an 'l'/'L'
|
2024-12-02 22:44:01 -08:00
|
|
|
if (c.left && (prev == 'l' || prev == 'L') && (current == 'l' || current == 'L'))
|
2024-10-24 22:04:17 -07:00
|
|
|
{
|
|
|
|
move_forward();
|
2024-12-02 22:44:01 -08:00
|
|
|
c.token.Length++;
|
2024-10-24 22:04:17 -07:00
|
|
|
}
|
|
|
|
}
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
goto FoundToken;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-11-30 15:54:19 -08:00
|
|
|
s32 start = max( 0, num(Tokens) - 100 );
|
2023-11-20 12:09:01 -08:00
|
|
|
log_fmt("\n%d\n", start);
|
2024-11-30 15:54:19 -08:00
|
|
|
for ( s32 idx = start; idx < num(Tokens); idx++ )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
log_fmt( "Token %d Type: %s : %.*s\n"
|
|
|
|
, idx
|
2024-12-03 06:50:30 -08:00
|
|
|
, to_str( Tokens[ idx ].Type ).Ptr
|
2023-11-20 12:09:01 -08:00
|
|
|
, Tokens[ idx ].Length, Tokens[ idx ].Text
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2024-12-02 22:44:01 -08:00
|
|
|
String context_str = string_fmt_buf( GlobalAllocator, "%.*s", min( 100, c.left ), c.scanner );
|
|
|
|
log_failure( "Failed to lex token '%c' (%d, %d)\n%s", current, c.line, c.column, context_str );
|
2023-11-20 12:09:01 -08:00
|
|
|
|
|
|
|
// Skip to next whitespace since we can't know if anything else is valid until then.
|
2024-12-02 22:44:01 -08:00
|
|
|
while ( c.left && ! char_is_space( current ) )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
move_forward();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
FoundToken:
|
2024-12-02 22:44:01 -08:00
|
|
|
lex_found_token( ctx );
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-11-30 15:54:19 -08:00
|
|
|
if ( num(Tokens) == 0 )
|
2023-11-20 12:09:01 -08:00
|
|
|
{
|
|
|
|
log_failure( "Failed to lex any tokens" );
|
2024-12-01 15:50:37 -08:00
|
|
|
return { {}, 0 };
|
2023-11-20 12:09:01 -08:00
|
|
|
}
|
|
|
|
|
2024-11-30 22:39:21 -08:00
|
|
|
clear(defines);
|
2023-11-20 12:09:01 -08:00
|
|
|
// defines_map_arena.free();
|
|
|
|
return { Tokens, 0 };
|
|
|
|
}
|
|
|
|
#undef current
|
|
|
|
#undef move_forward
|
|
|
|
#undef SkipWhitespace
|
|
|
|
|
2024-12-02 19:25:39 -08:00
|
|
|
GEN_NS_PARSER_END
|