2059 lines
72 KiB
C++
2059 lines
72 KiB
C++
|
|
// TOP
|
|
|
|
// TODO(allen):
|
|
// error check the body of macros as they are first read in
|
|
// (as in, check the thing after # is a parameter, and that ## is not on one of the ends)
|
|
|
|
#define _Assert Assert
|
|
#define _TentativeAssert TentativeAssert
|
|
|
|
enum Cpp_Def_Type{
|
|
CPP_DEFTYPE_ERROR,
|
|
CPP_DEFTYPE_FILE,
|
|
CPP_DEFTYPE_MACRO,
|
|
CPP_DEFTYPE_COUNT
|
|
};
|
|
|
|
struct Table_Entry{
|
|
String name;
|
|
Cpp_Def_Type type;
|
|
fcpp_u32 hash;
|
|
int index;
|
|
};
|
|
|
|
struct Table{
|
|
Table_Entry *table;
|
|
int size, max_size;
|
|
};
|
|
|
|
internal fcpp_u32
|
|
get_hash(String name, Cpp_Def_Type type){
|
|
fcpp_u32 x = 5381;
|
|
int i = 0;
|
|
char c;
|
|
while (i < name.size){
|
|
c = name.str[i++];
|
|
x = ((x << 5) + x) + c;
|
|
}
|
|
x += (fcpp_u32)(type)*13;
|
|
return x;
|
|
}
|
|
|
|
internal bool
|
|
table_insert(Table *table, Table_Entry info){
|
|
Table_Entry entry;
|
|
int index;
|
|
|
|
info.hash = get_hash(info.name, info.type);
|
|
index = info.hash % table->max_size;
|
|
while ((entry = table->table[index]).name.str && entry.index != -1){
|
|
if (entry.hash == info.hash && entry.type == info.type && match(entry.name, info.name)){
|
|
return 1;
|
|
}
|
|
index = (index + 1) % table->max_size;
|
|
}
|
|
table->table[index] = info;
|
|
++table->size;
|
|
return 0;
|
|
}
|
|
|
|
internal bool
|
|
table_find_entry(Table *table, String name, Cpp_Def_Type type, int *index_out){
|
|
fcpp_u32 hash = get_hash(name, type);
|
|
int index = hash % table->max_size;
|
|
Table_Entry entry;
|
|
while ((entry = table->table[index]).name.str){
|
|
if (entry.index != -1 && entry.hash == hash && entry.type == type && match(entry.name, name)){
|
|
*index_out = index;
|
|
return 1;
|
|
}
|
|
index = (index + 1) % table->max_size;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
internal bool
|
|
table_find(Table *table, String name, Cpp_Def_Type type, int *index_out){
|
|
bool result;
|
|
int entry_index;
|
|
result = table_find_entry(table, name, type, &entry_index);
|
|
if (result){
|
|
*index_out = table->table[entry_index].index;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal bool
|
|
table_drop(Table *table, String name, Cpp_Def_Type type){
|
|
bool result;
|
|
int entry_index;
|
|
result = table_find_entry(table, name, type, &entry_index);
|
|
if (result){
|
|
table->table[entry_index].index = -1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
table_copy(Table *table_src, Table *table_dst){
|
|
Table_Entry entry;
|
|
int i;
|
|
for (i = 0; i < table_src->max_size; ++i){
|
|
entry = table_src->table[i];
|
|
if (entry.name.str){
|
|
table_insert(table_dst, entry);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO(allen): File_Data not Parse_File
|
|
struct Cpp_Parse_File{
|
|
Cpp_File file;
|
|
Cpp_Token_Stack tokens;
|
|
String filename;
|
|
};
|
|
|
|
struct Cpp_Macro_Data{
|
|
int file_index;
|
|
int token_index;
|
|
int param_count;
|
|
int first_param_index;
|
|
int body_start_index;
|
|
int body_end_index;
|
|
};
|
|
|
|
union Cpp_Def_Slot{
|
|
Cpp_Parse_File file;
|
|
Cpp_Macro_Data macro;
|
|
};
|
|
|
|
struct Cpp_Loose_Token{
|
|
int file_index;
|
|
int token_index;
|
|
int blocked;
|
|
};
|
|
|
|
struct Cpp_Loose_Token_Stack{
|
|
Cpp_Loose_Token *tokens;
|
|
int count, max;
|
|
};
|
|
|
|
struct Cpp_Parse_Context{
|
|
int preserve_chunk_size;
|
|
};
|
|
|
|
struct Cpp_Parse_Definitions{
|
|
Table table;
|
|
Cpp_Def_Slot *slots;
|
|
int count, max;
|
|
|
|
int string_file_index;
|
|
int string_write_pos;
|
|
|
|
Cpp_Loose_Token eof_token;
|
|
Cpp_Loose_Token va_args_token;
|
|
};
|
|
|
|
struct Cpp_Visit{
|
|
int file_index;
|
|
int token_index;
|
|
int blocked;
|
|
};
|
|
|
|
struct Cpp_Expansion{
|
|
int position;
|
|
int end_position;
|
|
int file_index;
|
|
int macro_index;
|
|
int stack_base;
|
|
int stack_pop_pos;
|
|
int out_rule;
|
|
int out_type;
|
|
int param_info_base;
|
|
int invoking_file_index;
|
|
int invoking_token_index;
|
|
|
|
bool pop_and_drop;
|
|
bool may_have_pp;
|
|
bool is_file_level;
|
|
};
|
|
|
|
struct Cpp_Macro_Reading_Vars{
|
|
int name_index;
|
|
int first_param_index;
|
|
int param_count;
|
|
int body_start_index;
|
|
};
|
|
|
|
struct Cpp_Macro_Invoking_Vars{
|
|
int file_index;
|
|
int token_index;
|
|
int invoking_file_index;
|
|
int invoking_token_index;
|
|
int macro_index;
|
|
int param_count;
|
|
int paren_level;
|
|
int stack_base;
|
|
int param_info_base;
|
|
int variadic;
|
|
};
|
|
|
|
struct Cpp_Token_Range{
|
|
int start, end;
|
|
};
|
|
|
|
struct Cpp_Preproc_State{
|
|
Cpp_Expansion expansions[256];
|
|
Cpp_Token_Range param_info[192];
|
|
int expansion_level;
|
|
int param_info_used;
|
|
|
|
Cpp_Loose_Token_Stack tokens;
|
|
|
|
int state;
|
|
|
|
Cpp_Macro_Reading_Vars mac_read;
|
|
Cpp_Macro_Invoking_Vars mac_inv;
|
|
|
|
char *spare_string;
|
|
int spare_string_write_pos;
|
|
int spare_string_size;
|
|
|
|
bool resizing_slots;
|
|
bool finished;
|
|
};
|
|
|
|
enum Memory_Request_Purpse{
|
|
MEMPURP_NONE,
|
|
MEMPURP_SPARE_STRING,
|
|
MEMPURP_PRESERVE_FILE,
|
|
MEMPURP_TOKEN_STACK,
|
|
MEMPURP_DEFINITION_SLOTS
|
|
};
|
|
|
|
struct Cpp_Preproc_Result{
|
|
int file_index;
|
|
int token_index;
|
|
int blocked;
|
|
|
|
int invoking_file_index;
|
|
int invoking_token_index;
|
|
|
|
int error_code;
|
|
int memory_request;
|
|
Memory_Request_Purpse memory_purpose;
|
|
bool emit;
|
|
bool from_macro;
|
|
bool file_request;
|
|
};
|
|
|
|
struct Cpp_Memory_Request{
|
|
Cpp_Preproc_State *state;
|
|
Cpp_Parse_Definitions *definitions;
|
|
int size;
|
|
Memory_Request_Purpse purpose;
|
|
};
|
|
|
|
struct Cpp_File_Request{
|
|
String filename;
|
|
};
|
|
|
|
internal int
|
|
cpp_defs_add(Cpp_Parse_Definitions *defs, String name, Cpp_Def_Type type){
|
|
int result;
|
|
_Assert(defs->count < defs->max);
|
|
result = defs->count++;
|
|
defs->slots[result] = {};
|
|
|
|
if (name.str != 0){
|
|
_Assert(defs->table.size * 7 < defs->table.max_size * 8);
|
|
Table_Entry entry;
|
|
entry.name = name;
|
|
entry.type = type;
|
|
entry.index = result;
|
|
table_insert(&defs->table, entry);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal Cpp_Memory_Request
|
|
cpp_get_memory_request(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_Preproc_Result result){
|
|
Cpp_Memory_Request request = {};
|
|
request.state = state;
|
|
request.definitions = definitions;
|
|
request.size = result.memory_request;
|
|
request.purpose = result.memory_purpose;
|
|
return request;
|
|
}
|
|
|
|
internal Cpp_Parse_File*
|
|
cpp_get_parse_file(Cpp_Parse_Definitions *definitions, int file_index){
|
|
return &definitions->slots[file_index].file;
|
|
}
|
|
|
|
internal void
|
|
cpp_set_parse_file(Cpp_Parse_Definitions *definitions, int file_index, Cpp_Parse_File file){
|
|
definitions->slots[file_index].file = file;
|
|
}
|
|
|
|
internal Cpp_Macro_Data*
|
|
cpp_get_macro_data(Cpp_Parse_Definitions *definitions, int macro_index){
|
|
return &definitions->slots[macro_index].macro;
|
|
}
|
|
|
|
internal void
|
|
cpp_set_macro_data(Cpp_Parse_Definitions *definitions, int macro_index, Cpp_Macro_Data macro){
|
|
definitions->slots[macro_index].macro = macro;
|
|
}
|
|
|
|
internal void*
|
|
cpp_provide_memory(Cpp_Memory_Request request, void *memory){
|
|
void *result = 0;
|
|
switch (request.purpose){
|
|
case MEMPURP_SPARE_STRING:
|
|
{
|
|
Cpp_Preproc_State *state = request.state;
|
|
result = state->spare_string;
|
|
memcpy(memory, result, state->spare_string_size);
|
|
state->spare_string_size = request.size;
|
|
state->spare_string = (char*)memory;
|
|
}break;
|
|
|
|
case MEMPURP_PRESERVE_FILE:
|
|
{
|
|
persist String string_filename = make_lit_string("~ string space");
|
|
|
|
Cpp_Parse_Definitions *definitions = request.definitions;
|
|
int size = request.size >> 1;
|
|
Cpp_Parse_File new_file = {};
|
|
new_file.tokens.tokens = (Cpp_Token*)memory;
|
|
new_file.tokens.max_count = size / sizeof(Cpp_Token);
|
|
new_file.file.data = ((char*)memory) + size;
|
|
new_file.file.size = size;
|
|
new_file.filename = string_filename;
|
|
|
|
int string_index = cpp_defs_add(definitions, {}, CPP_DEFTYPE_FILE);
|
|
definitions->string_write_pos = 0;
|
|
definitions->string_file_index = string_index;
|
|
cpp_set_parse_file(definitions, string_index, new_file);
|
|
}break;
|
|
|
|
case MEMPURP_TOKEN_STACK:
|
|
{
|
|
Cpp_Preproc_State *state = request.state;
|
|
result = state->tokens.tokens;
|
|
memcpy(memory, result, sizeof(Cpp_Loose_Token)*state->tokens.count);
|
|
state->tokens.max = request.size / sizeof(Cpp_Loose_Token);
|
|
state->tokens.tokens = (Cpp_Loose_Token*)memory;
|
|
}break;
|
|
|
|
case MEMPURP_DEFINITION_SLOTS:
|
|
{
|
|
Cpp_Preproc_State *state = request.state;
|
|
Cpp_Parse_Definitions *definitions = request.definitions;
|
|
if (state->resizing_slots){
|
|
result = definitions->slots;
|
|
memcpy(memory, result, sizeof(Cpp_Def_Slot)*(definitions->count));
|
|
definitions->slots = (Cpp_Def_Slot*)memory;
|
|
definitions->max = request.size / sizeof(Cpp_Def_Slot);
|
|
}
|
|
else{
|
|
result = definitions->table.table;
|
|
Table new_table;
|
|
new_table.table = (Table_Entry*)memory;
|
|
new_table.size = 0;
|
|
new_table.max_size = request.size / sizeof(Table_Entry);
|
|
memset(new_table.table, 0, request.size);
|
|
table_copy(&definitions->table, &new_table);
|
|
definitions->table = new_table;
|
|
}
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
_Assert(!"unrecognized memory request");
|
|
}break;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
internal Cpp_File_Request
|
|
cpp_get_file_request(Cpp_Preproc_State *state, Cpp_Preproc_Result result){
|
|
Cpp_File_Request request = {};
|
|
return request;
|
|
}
|
|
|
|
internal bool
|
|
cpp_has_more_files(Cpp_File_Request *request){
|
|
return 0;
|
|
}
|
|
|
|
internal void
|
|
cpp_get_next_file(Cpp_File_Request *request){
|
|
}
|
|
|
|
internal bool
|
|
cpp_try_reuse_file(Cpp_File_Request *request){
|
|
return 0;
|
|
}
|
|
|
|
internal void
|
|
cpp_provide_file(Cpp_File_Request *request, Cpp_File new_file, Cpp_Token_Stack new_tokens){
|
|
}
|
|
|
|
enum Preproc_Error_Code{
|
|
PPERR_NO_ERROR,
|
|
PPERR_UNFINISHED_DEFINE,
|
|
PPERR_DEFINE_EXPECTED_IDENTIFIER,
|
|
PPERR_MACRO_NONIDENTIFIER_ARG,
|
|
PPERR_MACRO_INCOMPLETE_PARAMS,
|
|
PPERR_MACRO_EXPECTED_COMMA,
|
|
PPERR_MACRO_MORE_AFTER_ELLIPSIS,
|
|
PPERR_MACROINV_TOO_FEW_PARAMS,
|
|
PPERR_MACROINV_TOO_MANY_PARAMS,
|
|
PPERR_EXPANSION_OVERRUN,
|
|
PPERR_INCOMPLETE_MACROINV
|
|
};
|
|
|
|
internal String
|
|
cpp_get_error(int error_code){
|
|
String error = {};
|
|
switch (error_code){
|
|
case PPERR_NO_ERROR:
|
|
error = make_lit_string("no error"); break;
|
|
|
|
case PPERR_UNFINISHED_DEFINE:
|
|
error = make_lit_string("define directive is unfinished"); break;
|
|
|
|
case PPERR_DEFINE_EXPECTED_IDENTIFIER:
|
|
error = make_lit_string("define expected identifier for name"); break;
|
|
|
|
case PPERR_MACRO_NONIDENTIFIER_ARG:
|
|
error = make_lit_string("macro argument must be an identifier"); break;
|
|
|
|
case PPERR_MACRO_INCOMPLETE_PARAMS:
|
|
error = make_lit_string("macro incomplete parameters"); break;
|
|
|
|
case PPERR_MACRO_EXPECTED_COMMA:
|
|
error = make_lit_string("macro expected comma between parameters"); break;
|
|
|
|
case PPERR_MACRO_MORE_AFTER_ELLIPSIS:
|
|
error = make_lit_string("should not have more after the ellipsis"); break;
|
|
|
|
case PPERR_EXPANSION_OVERRUN:
|
|
error = make_lit_string("nested expansion of files and macros ran too deep"); break;
|
|
|
|
case PPERR_MACROINV_TOO_FEW_PARAMS:
|
|
error = make_lit_string("not enough arguments to macro invokation"); break;
|
|
|
|
case PPERR_MACROINV_TOO_MANY_PARAMS:
|
|
error = make_lit_string("too many arguments to macro invokation"); break;
|
|
|
|
case PPERR_INCOMPLETE_MACROINV:
|
|
error = make_lit_string("unexpected end of file in macro expansion"); break;
|
|
}
|
|
return error;
|
|
}
|
|
|
|
internal bool
|
|
cpp_recommend_termination(int error_code){
|
|
bool result = 0;
|
|
switch (error_code){
|
|
case PPERR_EXPANSION_OVERRUN:
|
|
result = 1;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
struct Spare_String_Checkpoint{
|
|
int write_pos_start;
|
|
int memory_overrun;
|
|
};
|
|
|
|
internal Spare_String_Checkpoint
|
|
cpp__checkpoint_spare_string(Cpp_Preproc_State *state){
|
|
Spare_String_Checkpoint result = {};
|
|
result.write_pos_start = state->spare_string_write_pos;
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__spare_write(Spare_String_Checkpoint *check, Cpp_Preproc_State *state, char c){
|
|
if (state->spare_string_write_pos < state->spare_string_size){
|
|
state->spare_string[state->spare_string_write_pos++] = c;
|
|
}
|
|
else{
|
|
++check->memory_overrun;
|
|
}
|
|
}
|
|
|
|
internal void
|
|
cpp__spare_write(Spare_String_Checkpoint *check, Cpp_Preproc_State *state, String str){
|
|
if (state->spare_string_write_pos + str.size <= state->spare_string_size){
|
|
memcpy(state->spare_string + state->spare_string_write_pos, str.str, str.size);
|
|
state->spare_string_write_pos += str.size;
|
|
}
|
|
else{
|
|
check->memory_overrun += str.size;
|
|
}
|
|
}
|
|
|
|
internal void
|
|
cpp__restore_spare_string(Cpp_Preproc_State *state, Spare_String_Checkpoint check){
|
|
state->spare_string_write_pos = check.write_pos_start;
|
|
}
|
|
|
|
struct Preserve_Checkpoint{
|
|
int start_write_pos;
|
|
int start_token_count;
|
|
bool out_of_memory;
|
|
};
|
|
|
|
internal Preserve_Checkpoint
|
|
cpp__checkpoint_preserve_write(Cpp_Parse_Definitions *definitions){
|
|
Cpp_Parse_File *file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
Preserve_Checkpoint check;
|
|
check.start_write_pos = definitions->string_write_pos;
|
|
check.start_token_count = file->tokens.count;
|
|
check.out_of_memory = 0;
|
|
return check;
|
|
}
|
|
|
|
internal void
|
|
cpp__restore_preserve_write(Cpp_Parse_Definitions *definitions, Preserve_Checkpoint check){
|
|
Cpp_Parse_File *file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
definitions->string_write_pos = check.start_write_pos;
|
|
file->tokens.count = check.start_token_count;
|
|
}
|
|
|
|
internal void
|
|
cpp__preserve_string(Cpp_Parse_Definitions *definitions, String string){
|
|
Cpp_Parse_File *string_file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
_Assert(string_file->file.size - definitions->string_write_pos >= string.size);
|
|
copy_fast_unsafe(string_file->file.data + definitions->string_write_pos, string);
|
|
definitions->string_write_pos += string.size;
|
|
}
|
|
|
|
internal Cpp_Loose_Token
|
|
cpp__preserve_token(Cpp_Parse_Definitions *definitions, Cpp_Token token){
|
|
Cpp_Parse_File *string_file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
_Assert(string_file->tokens.count < string_file->tokens.max_count);
|
|
Cpp_Loose_Token loose;
|
|
loose.file_index = definitions->string_file_index;
|
|
loose.token_index = string_file->tokens.count;
|
|
loose.blocked = 0;
|
|
string_file->tokens.tokens[string_file->tokens.count++] = token;
|
|
return loose;
|
|
}
|
|
|
|
internal void
|
|
cpp__preserve_string(Preserve_Checkpoint *check, Cpp_Parse_Definitions *definitions, String string){
|
|
if (!check->out_of_memory){
|
|
Cpp_Parse_File *string_file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
if (string_file->file.size - definitions->string_write_pos >= string.size){
|
|
copy_fast_unsafe(string_file->file.data + definitions->string_write_pos, string);
|
|
definitions->string_write_pos += string.size;
|
|
}
|
|
else{
|
|
check->out_of_memory = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
internal Cpp_Loose_Token
|
|
cpp__preserve_token(Preserve_Checkpoint *check, Cpp_Parse_Definitions *definitions, Cpp_Token token){
|
|
Cpp_Loose_Token loose = {};
|
|
if (!check->out_of_memory){
|
|
Cpp_Parse_File *string_file = cpp_get_parse_file(definitions, definitions->string_file_index);
|
|
if (string_file->tokens.count < string_file->tokens.max_count){
|
|
loose.file_index = definitions->string_file_index;
|
|
loose.token_index = string_file->tokens.count;
|
|
loose.blocked = 0;
|
|
string_file->tokens.tokens[string_file->tokens.count++] = token;
|
|
}
|
|
else{
|
|
check->out_of_memory = 1;
|
|
}
|
|
}
|
|
return loose;
|
|
}
|
|
|
|
internal bool
|
|
cpp__can_push_loose_token(Cpp_Preproc_State *state, int count){
|
|
return (state->tokens.count + count <= state->tokens.max);
|
|
}
|
|
|
|
internal void
|
|
cpp__push_loose_token(Cpp_Preproc_State *state, int file_index, int token_index, int blocked){
|
|
_Assert(state->tokens.count < state->tokens.max);
|
|
state->tokens.tokens[state->tokens.count++] = {file_index, token_index, blocked};
|
|
}
|
|
|
|
struct Token_Stack_Checkpoint{
|
|
int start_count;
|
|
int memory_overrun;
|
|
};
|
|
|
|
internal Token_Stack_Checkpoint
|
|
cpp__checkpoint_token_stack(Cpp_Preproc_State *state){
|
|
Token_Stack_Checkpoint result = {};
|
|
result.start_count = state->tokens.count;
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__restore_token_stack(Cpp_Preproc_State *state, Token_Stack_Checkpoint checkpoint){
|
|
state->tokens.count = checkpoint.start_count;
|
|
}
|
|
|
|
internal void
|
|
cpp__push_loose_token(Token_Stack_Checkpoint *checkpoint, Cpp_Preproc_State *state,
|
|
int file_index, int token_index, int blocked){
|
|
if (state->tokens.count < state->tokens.max){
|
|
cpp__push_loose_token(state, file_index, token_index, blocked);
|
|
}
|
|
else{
|
|
++checkpoint->memory_overrun;
|
|
}
|
|
}
|
|
|
|
internal void
|
|
cpp__finish_macro(Cpp_Parse_Definitions *definitions, String name,
|
|
int file_index, int token_index,
|
|
int param_count, int first_param_index,
|
|
int body_start_index, int body_end_index){
|
|
Cpp_Macro_Data macro;
|
|
macro.file_index = file_index;
|
|
macro.token_index = token_index;
|
|
macro.param_count = param_count;
|
|
macro.first_param_index = first_param_index;
|
|
macro.body_start_index = body_start_index;
|
|
macro.body_end_index = body_end_index;
|
|
|
|
int macro_index = cpp_defs_add(definitions, name, CPP_DEFTYPE_MACRO);
|
|
cpp_set_macro_data(definitions, macro_index, macro);
|
|
}
|
|
|
|
enum Cpp_Expansion_Type{
|
|
EXPAN_FILE,
|
|
EXPAN_MACRO,
|
|
EXPAN_ARG,
|
|
EXPAN_PMACRO_BODY
|
|
};
|
|
|
|
enum Cpp_Expansion_Out_Type{
|
|
EXPAN_NORMAL,
|
|
EXPAN_BIG_PROCESS_ARGS,
|
|
EXPAN_BIG_PROCESS_BODY,
|
|
EXPAN_BIG_DIRECT_OUT,
|
|
EXPAN_EOF_FLUSH,
|
|
EXPAN_STRFY
|
|
};
|
|
|
|
internal Cpp_Expansion*
|
|
cpp__push_expansion_raw(Cpp_Preproc_State *state, Cpp_Expansion *expansion){
|
|
if (state->expansion_level == ArrayCount(state->expansions)){
|
|
return 0;
|
|
}
|
|
|
|
++state->expansion_level;
|
|
Cpp_Expansion *result = state->expansions + state->expansion_level;
|
|
*result = *expansion;
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__set_expansion(Cpp_Preproc_State *state, Cpp_Expansion *expansion, Cpp_Expansion_Type type,
|
|
int file_index, int start, int end, int out_rule,
|
|
int invoking_file_index, int invoking_token_index){
|
|
expansion->position = start;
|
|
expansion->end_position = end;
|
|
expansion->file_index = file_index;
|
|
expansion->macro_index = 0;
|
|
expansion->out_rule = out_rule;
|
|
expansion->out_type = EXPAN_NORMAL;
|
|
expansion->invoking_file_index = invoking_file_index;
|
|
expansion->invoking_token_index = invoking_token_index;
|
|
if (state->expansion_level >= 1){
|
|
expansion->stack_base = state->expansions[state->expansion_level-1].stack_base;
|
|
}
|
|
else{
|
|
expansion->stack_base = 0;
|
|
}
|
|
|
|
switch (type){
|
|
case EXPAN_FILE:
|
|
expansion->may_have_pp = 1;
|
|
expansion->is_file_level = 1;
|
|
expansion->pop_and_drop = 0;
|
|
break;
|
|
|
|
case EXPAN_MACRO:
|
|
expansion->may_have_pp = 0;
|
|
expansion->is_file_level = 0;
|
|
expansion->pop_and_drop = 0;
|
|
break;
|
|
|
|
case EXPAN_ARG:
|
|
expansion->may_have_pp = 0;
|
|
expansion->is_file_level = 1;
|
|
expansion->pop_and_drop = 0;
|
|
break;
|
|
|
|
case EXPAN_PMACRO_BODY:
|
|
expansion->may_have_pp = 0;
|
|
expansion->is_file_level = 0;
|
|
expansion->pop_and_drop = 1;
|
|
expansion->stack_pop_pos = state->tokens.count;
|
|
break;
|
|
}
|
|
}
|
|
|
|
internal Cpp_Expansion*
|
|
cpp__push_expansion(Cpp_Preproc_State *state, Cpp_Expansion_Type type,
|
|
int file_index, int start, int end, int out_rule,
|
|
int invoking_file_index, int invoking_token_index){
|
|
_Assert(start < end);
|
|
if (state->expansion_level == ArrayCount(state->expansions)){
|
|
return 0;
|
|
}
|
|
|
|
++state->expansion_level;
|
|
Cpp_Expansion *result = state->expansions + state->expansion_level;
|
|
cpp__set_expansion(state, result, type, file_index, start, end, out_rule,
|
|
invoking_file_index, invoking_token_index);
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__set_strfy_expansion(Cpp_Preproc_State *state, Cpp_Expansion *expansion,
|
|
int start, int end, int out_rule,
|
|
int invoking_file_index, int invoking_token_index){
|
|
expansion->position = start;
|
|
expansion->end_position = end;
|
|
expansion->file_index = -1;
|
|
expansion->macro_index = 0;
|
|
expansion->out_rule = out_rule;
|
|
expansion->out_type = EXPAN_STRFY;
|
|
expansion->invoking_file_index = invoking_file_index;
|
|
expansion->invoking_token_index = invoking_token_index;
|
|
|
|
expansion->may_have_pp = 0;
|
|
expansion->is_file_level = 0;
|
|
expansion->pop_and_drop = 0;
|
|
|
|
if (state->expansion_level >= 1){
|
|
expansion->stack_base = state->expansions[state->expansion_level-1].stack_base;
|
|
}
|
|
else{
|
|
expansion->stack_base = 0;
|
|
}
|
|
}
|
|
|
|
internal Cpp_Expansion*
|
|
cpp__push_strfy_expansion(Cpp_Preproc_State *state, int start, int end, int out_rule,
|
|
int invoking_file_index, int invoking_token_index){
|
|
_Assert(start < end);
|
|
if (state->expansion_level == ArrayCount(state->expansions)){
|
|
return 0;
|
|
}
|
|
|
|
++state->expansion_level;
|
|
Cpp_Expansion *result = state->expansions + state->expansion_level;
|
|
cpp__set_strfy_expansion(state, result, start, end, out_rule,
|
|
invoking_file_index, invoking_token_index);
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__set_big_expansion(Cpp_Expansion *expansion, int macro_index, int stack_base,
|
|
int param_info_base, int out_rule,
|
|
int invoking_file_index, int invoking_token_index){
|
|
expansion->stack_base = stack_base;
|
|
expansion->file_index = macro_index;
|
|
expansion->macro_index = 0;
|
|
expansion->out_rule = out_rule;
|
|
expansion->out_type = EXPAN_BIG_PROCESS_ARGS;
|
|
expansion->param_info_base = param_info_base;
|
|
expansion->invoking_file_index = invoking_file_index;
|
|
expansion->invoking_token_index = invoking_token_index;
|
|
expansion->pop_and_drop = 0;
|
|
expansion->may_have_pp = 0;
|
|
expansion->is_file_level = 0;
|
|
}
|
|
|
|
internal Cpp_Expansion*
|
|
cpp__push_big_expansion(Cpp_Preproc_State *state, int macro_index, int stack_base, int param_info_base,
|
|
int out_rule, int invoking_file_index, int invoking_token_index){
|
|
if (state->expansion_level == ArrayCount(state->expansions)){
|
|
return 0;
|
|
}
|
|
++state->expansion_level;
|
|
Cpp_Expansion *result = state->expansions + state->expansion_level;
|
|
cpp__set_big_expansion(result, macro_index, stack_base, param_info_base, out_rule,
|
|
invoking_file_index, invoking_token_index);
|
|
return result;
|
|
}
|
|
|
|
internal int
|
|
cpp__alloc_param_table(Cpp_Preproc_State *state, int param_count){
|
|
_Assert(state->param_info_used + param_count * 3 <= ArrayCount(state->param_info));
|
|
int result = state->param_info_used;
|
|
state->param_info_used += param_count * 3;
|
|
memset(state->param_info + result, 0, sizeof(Cpp_Token_Range)*param_count*3);
|
|
return result;
|
|
}
|
|
|
|
internal void
|
|
cpp__free_param_table(Cpp_Preproc_State *state, int param_count){
|
|
_Assert(state->param_info_used >= param_count * 3);
|
|
state->param_info_used -= param_count * 3;
|
|
}
|
|
|
|
enum Param_Info_Position{
|
|
RAW_START,
|
|
RAW_END,
|
|
STRFY_START,
|
|
STRFY_END,
|
|
EXPANDED_START,
|
|
EXPANDED_END
|
|
};
|
|
|
|
enum Param_Info_Range_Position{
|
|
RAW,
|
|
STRFY,
|
|
EXPANDED
|
|
};
|
|
|
|
internal Cpp_Token_Range
|
|
cpp__param_info_get(Cpp_Preproc_State *state, int base, int arg_index, Param_Info_Range_Position pos){
|
|
Cpp_Token_Range *range = state->param_info + (base + arg_index*3);
|
|
range += pos;
|
|
return *range;
|
|
}
|
|
|
|
internal void
|
|
cpp__param_info_set(Cpp_Preproc_State *state, int base, int arg_index, Param_Info_Position pos, int val){
|
|
Cpp_Token_Range *range = state->param_info + (base + arg_index*3);
|
|
range += (pos >> 1);
|
|
*( ((int*)range) + (pos & 1) ) = val;
|
|
}
|
|
|
|
internal void
|
|
cpp_set_target(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_File file, Cpp_Token_Stack tokens, String filename){
|
|
int target_index;
|
|
target_index = cpp_defs_add(definitions, filename, CPP_DEFTYPE_FILE);
|
|
cpp_set_parse_file(definitions, target_index, {file, tokens, filename});
|
|
state->expansion_level = -1;
|
|
cpp__push_expansion(state, EXPAN_FILE, target_index, 0, tokens.count, 0, -1, -1);
|
|
}
|
|
|
|
internal void
|
|
cpp__preproc_pop_expansion(Cpp_Preproc_State *state, Cpp_Expansion *expansion){
|
|
if (expansion->is_file_level){
|
|
_Assert(expansion->out_type != EXPAN_EOF_FLUSH);
|
|
expansion->out_type = EXPAN_EOF_FLUSH;
|
|
}
|
|
|
|
else{
|
|
if (expansion->pop_and_drop){
|
|
Cpp_Loose_Token *tokens = state->tokens.tokens;
|
|
int count = state->tokens.count - expansion->stack_pop_pos;
|
|
memmove(tokens + expansion->stack_base, tokens + expansion->stack_pop_pos,
|
|
sizeof(Cpp_Loose_Token)*count);
|
|
state->tokens.count = expansion->stack_base + count;
|
|
state->mac_inv.stack_base -= (expansion->stack_pop_pos - expansion->stack_base);
|
|
}
|
|
|
|
if (state->expansion_level == 0){
|
|
state->finished = 1;
|
|
}
|
|
else{
|
|
--state->expansion_level;
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Preproc_State{
|
|
PPS_DEFAULT,
|
|
PPS_MACRO_NAME,
|
|
PPS_MACRO_PARAM_OR_CLOSE,
|
|
PPS_MACRO_BODY,
|
|
PPS_MACRO_COMMA_OR_CLOSE,
|
|
PPS_MACRO_PARAM,
|
|
PPS_MACRO_CLOSE,
|
|
PPS_MACRO_BODY_OR_PARAM_OPEN,
|
|
PPS_MACRO_ERROR,
|
|
PPS_MACROINV_OPEN,
|
|
PPS_MACROINV_PARAMS
|
|
};
|
|
|
|
internal Cpp_Preproc_Result
|
|
cpp__preproc_normal_step_nonalloc(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_Parse_Context *context){
|
|
Cpp_Preproc_Result result = {};
|
|
Cpp_Expansion to_push_later = {};
|
|
int do_push_later = 0;
|
|
Cpp_Expansion *expansion = state->expansions + state->expansion_level;
|
|
|
|
if (expansion->position == expansion->end_position && expansion->out_type == EXPAN_NORMAL){
|
|
cpp__preproc_pop_expansion(state, expansion);
|
|
result = {};
|
|
return result;
|
|
}
|
|
|
|
if (!cpp__can_push_loose_token(state, 1)){
|
|
result.memory_request = sizeof(Cpp_Loose_Token)*((state->tokens.count*2) + 1);
|
|
result.memory_purpose = MEMPURP_TOKEN_STACK;
|
|
return result;
|
|
}
|
|
|
|
Cpp_Visit visit = {};
|
|
Cpp_Parse_File visit_file;
|
|
Cpp_Token visit_token;
|
|
|
|
if (expansion->out_type == EXPAN_NORMAL){
|
|
if (expansion->file_index >= 0){
|
|
visit.file_index = expansion->file_index;
|
|
visit.token_index = expansion->position;
|
|
visit.blocked = 0;
|
|
}
|
|
else{
|
|
Cpp_Loose_Token loose_token = state->tokens.tokens[expansion->position];
|
|
visit.file_index = loose_token.file_index;
|
|
visit.token_index = loose_token.token_index;
|
|
visit.blocked = loose_token.blocked;
|
|
}
|
|
}
|
|
else if (expansion->out_type == EXPAN_EOF_FLUSH){
|
|
visit.file_index = definitions->eof_token.file_index;
|
|
visit.token_index = definitions->eof_token.token_index;
|
|
visit.blocked = 0;
|
|
}
|
|
|
|
visit_file = *cpp_get_parse_file(definitions, visit.file_index);
|
|
visit_token = visit_file.tokens.tokens[visit.token_index];
|
|
|
|
result.file_index = visit.file_index;
|
|
result.token_index = visit.token_index;
|
|
result.blocked = visit.blocked;
|
|
result.invoking_file_index = expansion->invoking_file_index;
|
|
result.invoking_token_index = expansion->invoking_token_index;
|
|
result.from_macro = !expansion->is_file_level;
|
|
|
|
bool step_forward = 1;
|
|
switch (state->state){
|
|
case PPS_MACRO_NAME:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_IDENTIFIER:
|
|
{
|
|
state->mac_read.name_index = visit.token_index;
|
|
state->state = PPS_MACRO_BODY_OR_PARAM_OPEN;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.error_code = PPERR_DEFINE_EXPECTED_IDENTIFIER;
|
|
state->state = PPS_MACRO_ERROR;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
result.error_code = PPERR_UNFINISHED_DEFINE;
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_BODY_OR_PARAM_OPEN:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_OPEN:
|
|
{
|
|
state->state = PPS_MACRO_PARAM_OR_CLOSE;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
state->mac_read.param_count = -1;
|
|
state->mac_read.body_start_index = visit.token_index;
|
|
state->state = PPS_MACRO_BODY;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
Cpp_Token token = visit_file.tokens.tokens[state->mac_read.name_index];
|
|
String name = make_string(visit_file.file.data + token.start, token.size);
|
|
cpp__finish_macro(definitions, name, visit.file_index, state->mac_read.name_index, -1, 0, 0, 0);
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_BODY:
|
|
{
|
|
if (!(visit_token.flags & CPP_TFLAG_PP_BODY)){
|
|
Cpp_Token token = visit_file.tokens.tokens[state->mac_read.name_index];
|
|
String name = make_string(visit_file.file.data + token.start, token.size);
|
|
cpp__finish_macro(definitions, name,
|
|
visit.file_index, state->mac_read.name_index,
|
|
state->mac_read.param_count, state->mac_read.first_param_index,
|
|
state->mac_read.body_start_index, visit.token_index);
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_PARAM_OR_CLOSE:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
{
|
|
state->mac_read.body_start_index = visit.token_index + 1;
|
|
state->state = PPS_MACRO_BODY;
|
|
}break;
|
|
|
|
case CPP_TOKEN_IDENTIFIER:
|
|
{
|
|
state->mac_read.first_param_index = visit.token_index;
|
|
++state->mac_read.param_count;
|
|
state->state = PPS_MACRO_COMMA_OR_CLOSE;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.error_code = PPERR_MACRO_NONIDENTIFIER_ARG;
|
|
state->state = PPS_MACRO_ERROR;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
result.error_code = PPERR_MACRO_INCOMPLETE_PARAMS;
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_COMMA_OR_CLOSE:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
{
|
|
state->mac_read.body_start_index = visit.token_index + 1;
|
|
state->state = PPS_MACRO_BODY;
|
|
}break;
|
|
|
|
case CPP_TOKEN_COMMA:
|
|
{
|
|
state->state = PPS_MACRO_PARAM;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.error_code = PPERR_MACRO_EXPECTED_COMMA;
|
|
state->state = PPS_MACRO_ERROR;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
result.error_code = PPERR_MACRO_INCOMPLETE_PARAMS;
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_PARAM:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_IDENTIFIER:
|
|
{
|
|
++state->mac_read.param_count;
|
|
state->state = PPS_MACRO_COMMA_OR_CLOSE;
|
|
}break;
|
|
|
|
case CPP_TOKEN_ELLIPSIS:
|
|
{
|
|
++state->mac_read.param_count;
|
|
state->state = PPS_MACRO_CLOSE;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.error_code = PPERR_MACRO_NONIDENTIFIER_ARG;
|
|
state->state = PPS_MACRO_ERROR;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
result.error_code = PPERR_MACRO_INCOMPLETE_PARAMS;
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_CLOSE:
|
|
{
|
|
if (visit_token.flags & CPP_TFLAG_PP_BODY){
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
{
|
|
state->mac_read.body_start_index = visit.token_index + 1;
|
|
state->state = PPS_MACRO_BODY;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.error_code = PPERR_MACRO_MORE_AFTER_ELLIPSIS;
|
|
state->state = PPS_MACRO_ERROR;
|
|
}break;
|
|
}
|
|
}
|
|
else{
|
|
result.error_code = PPERR_MACRO_INCOMPLETE_PARAMS;
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACRO_ERROR:
|
|
{
|
|
if (!(visit_token.flags & CPP_TFLAG_PP_BODY)){
|
|
state->state = PPS_DEFAULT;
|
|
step_forward = 0;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACROINV_OPEN:
|
|
{
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_OPEN:
|
|
{
|
|
Cpp_Macro_Data *macro = cpp_get_macro_data(definitions, state->mac_inv.macro_index);
|
|
state->mac_inv.param_info_base = cpp__alloc_param_table(state, macro->param_count);
|
|
state->state = PPS_MACROINV_PARAMS;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
state->tokens.count = state->mac_inv.stack_base;
|
|
|
|
result.file_index = state->mac_inv.file_index;
|
|
result.token_index = state->mac_inv.token_index;
|
|
result.blocked = 0;
|
|
result.invoking_file_index = state->mac_inv.invoking_file_index;
|
|
result.invoking_token_index = state->mac_inv.invoking_token_index;
|
|
result.from_macro = (result.invoking_file_index != -1);
|
|
result.emit = 1;
|
|
|
|
step_forward = 0;
|
|
|
|
state->state = PPS_DEFAULT;
|
|
}break;
|
|
}
|
|
}break;
|
|
|
|
case PPS_MACROINV_PARAMS:
|
|
{
|
|
enum Macroinv_Params_Action{
|
|
MIA_NONE,
|
|
MIA_EXTEND_PARAM,
|
|
MIA_NEXT_PARAM,
|
|
MIA_FINISH,
|
|
MIA_CLEANUP
|
|
};
|
|
|
|
Macroinv_Params_Action action = MIA_NONE;
|
|
Cpp_Macro_Data macro = *cpp_get_macro_data(definitions, state->mac_inv.macro_index);
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_OPEN:
|
|
{
|
|
action = MIA_EXTEND_PARAM;
|
|
++state->mac_inv.paren_level;
|
|
}break;
|
|
|
|
case CPP_TOKEN_PARENTHESE_CLOSE:
|
|
{
|
|
if (state->mac_inv.paren_level == 0){
|
|
action = MIA_FINISH;
|
|
}
|
|
else{
|
|
--state->mac_inv.paren_level;
|
|
action = MIA_EXTEND_PARAM;
|
|
}
|
|
}break;
|
|
|
|
case CPP_TOKEN_COMMA:
|
|
{
|
|
if (state->mac_inv.paren_level != 0 ||
|
|
(state->mac_inv.variadic &&
|
|
(state->mac_inv.param_count == macro.param_count ||
|
|
macro.param_count == 1))){
|
|
action = MIA_EXTEND_PARAM;
|
|
}
|
|
else{
|
|
action = MIA_NEXT_PARAM;
|
|
}
|
|
}break;
|
|
|
|
case CPP_TOKEN_EOF:
|
|
{
|
|
action = MIA_CLEANUP;
|
|
result.error_code = PPERR_INCOMPLETE_MACROINV;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
action = MIA_EXTEND_PARAM;
|
|
}break;
|
|
}
|
|
|
|
switch (action){
|
|
case MIA_EXTEND_PARAM:
|
|
{
|
|
if (state->mac_inv.param_count == 0){
|
|
state->mac_inv.param_count = 1;
|
|
cpp__param_info_set(state, state->mac_inv.param_info_base,
|
|
0, RAW_START, state->tokens.count);
|
|
}
|
|
// NOTE(allen): this function gaurantees at the head end that there is
|
|
// room for at least one token
|
|
cpp__push_loose_token(state, visit.file_index, visit.token_index, 0);
|
|
}break;
|
|
|
|
case MIA_NEXT_PARAM:
|
|
{
|
|
if (state->mac_inv.param_count == 0){
|
|
state->mac_inv.param_count = 1;
|
|
cpp__param_info_set(state, state->mac_inv.param_info_base,
|
|
0, RAW_START, state->tokens.count);
|
|
}
|
|
|
|
if (state->mac_inv.param_count <= macro.param_count){
|
|
cpp__param_info_set(state, state->mac_inv.param_info_base,
|
|
state->mac_inv.param_count - 1, RAW_END, state->tokens.count);
|
|
++state->mac_inv.param_count;
|
|
cpp__param_info_set(state, state->mac_inv.param_info_base,
|
|
state->mac_inv.param_count - 1, RAW_START, state->tokens.count);
|
|
}
|
|
else{
|
|
++state->mac_inv.param_count;
|
|
}
|
|
}break;
|
|
|
|
case MIA_FINISH:
|
|
{
|
|
if (state->mac_inv.param_count != 0 && state->mac_inv.param_count <= macro.param_count){
|
|
cpp__param_info_set(state, state->mac_inv.param_info_base,
|
|
state->mac_inv.param_count - 1, RAW_END, state->tokens.count);
|
|
}
|
|
if (state->mac_inv.param_count != macro.param_count){
|
|
if (state->mac_inv.param_count < macro.param_count){
|
|
result.error_code = PPERR_MACROINV_TOO_FEW_PARAMS;
|
|
}
|
|
else{
|
|
result.error_code = PPERR_MACROINV_TOO_MANY_PARAMS;
|
|
}
|
|
}
|
|
state->state = PPS_DEFAULT;
|
|
|
|
do_push_later = 2;
|
|
cpp__set_big_expansion(&to_push_later, state->mac_inv.macro_index,
|
|
state->mac_inv.stack_base, state->mac_inv.param_info_base,
|
|
expansion->out_rule, visit.file_index, visit.token_index);
|
|
}break;
|
|
|
|
case MIA_CLEANUP:
|
|
{
|
|
state->tokens.count = state->mac_inv.stack_base;
|
|
cpp__free_param_table(state, state->mac_inv.param_count);
|
|
}break;
|
|
}
|
|
}break;
|
|
|
|
case PPS_DEFAULT:
|
|
{
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:
|
|
case CPP_TOKEN_EOF:break;
|
|
|
|
case CPP_PP_DEFINE:
|
|
{
|
|
state->mac_read = {};
|
|
state->state = PPS_MACRO_NAME;
|
|
}break;
|
|
|
|
case CPP_TOKEN_IDENTIFIER:
|
|
{
|
|
String name = make_string(visit_file.file.data + visit_token.start, visit_token.size);
|
|
int macro_index;
|
|
if (table_find(&definitions->table, name, CPP_DEFTYPE_MACRO, ¯o_index)){
|
|
bool blocked = (visit.blocked != 0);
|
|
if (!blocked){
|
|
for (int i = state->expansion_level; i >= 0; --i){
|
|
if (macro_index == state->expansions[i].macro_index){
|
|
blocked = 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!blocked){
|
|
Cpp_Macro_Data *macro = cpp_get_macro_data(definitions, macro_index);
|
|
if (macro->param_count == -1){
|
|
if (macro->body_start_index < macro->body_end_index){
|
|
do_push_later = 1;
|
|
cpp__set_expansion(state, &to_push_later, EXPAN_MACRO, macro->file_index,
|
|
macro->body_start_index, macro->body_end_index,
|
|
expansion->out_rule, visit.file_index, visit.token_index);
|
|
to_push_later.macro_index = macro_index;
|
|
}
|
|
}
|
|
|
|
else{
|
|
int stack_start = state->tokens.count;
|
|
// NOTE(allen): luckily the number of tokens about to be pushed is known
|
|
// up front in this case. No states have been changed yet so it's okay
|
|
// allowing a memory request to be issued from here.
|
|
if (cpp__can_push_loose_token(state, macro->param_count)){
|
|
bool variadic = 0;
|
|
if (macro->param_count != 0){
|
|
int macro_file_index = macro->file_index;
|
|
Cpp_Parse_File file = *cpp_get_parse_file(definitions, macro_file_index);
|
|
int i = macro->first_param_index;
|
|
Cpp_Token token = file.tokens.tokens[i];
|
|
for (;;){
|
|
if (token.type == CPP_TOKEN_IDENTIFIER){
|
|
cpp__push_loose_token(state, macro_file_index, i, 0);
|
|
}
|
|
if (token.type == CPP_TOKEN_ELLIPSIS){
|
|
Cpp_Loose_Token va_args = definitions->va_args_token;
|
|
cpp__push_loose_token(state, va_args.file_index,
|
|
va_args.token_index, 0);
|
|
variadic = 1;
|
|
}
|
|
|
|
++i;
|
|
if (i >= file.tokens.count){
|
|
break;
|
|
}
|
|
token = file.tokens.tokens[i];
|
|
if (token.type == CPP_TOKEN_PARENTHESE_CLOSE){
|
|
break;
|
|
}
|
|
}
|
|
_Assert(state->tokens.count - stack_start == macro->param_count);
|
|
}
|
|
|
|
state->mac_inv.file_index = visit.file_index;
|
|
state->mac_inv.token_index = visit.token_index;
|
|
|
|
state->mac_inv.invoking_file_index = result.invoking_file_index;
|
|
state->mac_inv.invoking_token_index = result.invoking_token_index;
|
|
|
|
state->mac_inv.macro_index = macro_index;
|
|
state->mac_inv.param_count = 0;
|
|
state->mac_inv.paren_level = 0;
|
|
state->mac_inv.stack_base = stack_start;
|
|
state->mac_inv.variadic = variadic;
|
|
|
|
state->state = PPS_MACROINV_OPEN;
|
|
}
|
|
else{
|
|
result.memory_request = sizeof(Cpp_Loose_Token)*
|
|
((state->tokens.max*2) + macro->param_count);
|
|
result.memory_purpose = MEMPURP_TOKEN_STACK;
|
|
step_forward = 0;
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
result.emit = 1;
|
|
result.blocked = 1;
|
|
}
|
|
}
|
|
else{
|
|
result.emit = 1;
|
|
}
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
result.emit = 1;
|
|
}break;
|
|
}
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
_Assert(!"bad state->state");
|
|
}break;
|
|
}
|
|
|
|
if (expansion->out_rule != 0 && result.emit){
|
|
cpp__push_loose_token(state, result.file_index, result.token_index, result.blocked);
|
|
result.emit = 0;
|
|
if (expansion->out_rule > 0){
|
|
if (state->param_info[expansion->out_rule].start == 0){
|
|
state->param_info[expansion->out_rule].start = state->tokens.count - 1;
|
|
}
|
|
state->param_info[expansion->out_rule].end = state->tokens.count;
|
|
}
|
|
}
|
|
|
|
if (expansion->out_type == EXPAN_NORMAL){
|
|
if (step_forward){
|
|
++expansion->position;
|
|
if (expansion->position == expansion->end_position && do_push_later == 0){
|
|
cpp__preproc_pop_expansion(state, expansion);
|
|
}
|
|
}
|
|
}
|
|
else{
|
|
if (state->expansion_level == 0){
|
|
state->finished = 1;
|
|
}
|
|
else{
|
|
--state->expansion_level;
|
|
}
|
|
}
|
|
|
|
if (do_push_later){
|
|
cpp__push_expansion_raw(state, &to_push_later);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal int
|
|
cpp__get_parameter_i(Cpp_Preproc_State *state, Cpp_Parse_Definitions * definitions,
|
|
Cpp_Parse_File *macro_file, Cpp_Token token, int param_start, int param_count){
|
|
int param_i = -1;
|
|
if (token.type == CPP_TOKEN_IDENTIFIER){
|
|
String token_str = make_string(macro_file->file.data + token.start, token.size);
|
|
for (int j = 0; j < param_count; ++j){
|
|
Cpp_Loose_Token param_loose = state->tokens.tokens[j + param_start];
|
|
Cpp_Parse_File *file = cpp_get_parse_file(definitions, param_loose.file_index);
|
|
Cpp_Token param_token = file->tokens.tokens[param_loose.token_index];
|
|
String param_str = make_string(file->file.data + param_token.start, param_token.size);
|
|
if (match(token_str, param_str)){
|
|
param_i = j;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return param_i;
|
|
}
|
|
|
|
internal Cpp_Preproc_Result
|
|
cpp__preproc_big_step_nonalloc(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_Parse_Context *context){
|
|
Cpp_Preproc_Result result = {};
|
|
Cpp_Expansion *expansion = state->expansions + state->expansion_level;
|
|
|
|
Cpp_Macro_Data macro = *cpp_get_macro_data(definitions, expansion->file_index);
|
|
Cpp_Parse_File *macro_file = cpp_get_parse_file(definitions, macro.file_index);
|
|
switch (expansion->out_type){
|
|
case EXPAN_BIG_PROCESS_ARGS:
|
|
{
|
|
bool expand_arg[64];
|
|
bool strfy_arg[64];
|
|
_Assert(macro.param_count < 64);
|
|
memset(expand_arg, 0, macro.param_count);
|
|
memset(strfy_arg, 0, macro.param_count);
|
|
|
|
bool prev_was_paste = 0;
|
|
bool next_is_paste = 0;
|
|
bool prev_was_strfy = 0;
|
|
Cpp_Token token;
|
|
int param_i;
|
|
for (int i = macro.body_start_index; i < macro.body_end_index; ++i){
|
|
token = macro_file->tokens.tokens[i];
|
|
param_i = cpp__get_parameter_i(state, definitions, macro_file, token,
|
|
expansion->stack_base, macro.param_count);
|
|
|
|
next_is_paste = (i+1 < macro.body_end_index &&
|
|
macro_file->tokens.tokens[i+1].type == CPP_PP_CONCAT);
|
|
|
|
if (param_i != -1){
|
|
if (prev_was_strfy){
|
|
strfy_arg[param_i] = 1;
|
|
}
|
|
else if (!prev_was_paste && !next_is_paste){
|
|
expand_arg[param_i] = 1;
|
|
}
|
|
}
|
|
|
|
prev_was_strfy = (token.type == CPP_PP_STRINGIFY);
|
|
prev_was_paste = (token.type == CPP_PP_CONCAT && i != macro.body_start_index);
|
|
}
|
|
|
|
int param_info_base = expansion->param_info_base;
|
|
for (int i = 0; i < macro.param_count; ++i){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, param_info_base, i, RAW);
|
|
|
|
if (strfy_arg[i]){
|
|
Cpp_Expansion *new_expansion =
|
|
cpp__push_strfy_expansion(state, range.start, range.end,
|
|
param_info_base + i*3 + 1,
|
|
expansion->invoking_file_index,
|
|
expansion->invoking_token_index);
|
|
if (new_expansion == 0){
|
|
result.error_code = PPERR_EXPANSION_OVERRUN;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (expand_arg[i]){
|
|
if (range.start < range.end){
|
|
Cpp_Expansion *new_expansion =
|
|
cpp__push_expansion(state, EXPAN_ARG, -1, range.start, range.end,
|
|
param_info_base + i*3 + 2,
|
|
expansion->invoking_file_index,
|
|
expansion->invoking_token_index);
|
|
if (new_expansion == 0){
|
|
result.error_code = PPERR_EXPANSION_OVERRUN;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
expansion->out_type = EXPAN_BIG_PROCESS_BODY;
|
|
}break;
|
|
|
|
case EXPAN_BIG_PROCESS_BODY:
|
|
{
|
|
int start_pos = state->tokens.count;
|
|
|
|
// TODO(allen): because it is possible that this be used more than once, it is possible that
|
|
// all of this code happens any number of times before it finally runs through with enough
|
|
// memory. Perhaps loft this checkpoint out and try the whole thing in one big checkpoint?
|
|
// Some sort of way of determining the max size needed in spare string?
|
|
Spare_String_Checkpoint str_checkpoint = {};
|
|
Preserve_Checkpoint pres_checkpoint = cpp__checkpoint_preserve_write(definitions);
|
|
Token_Stack_Checkpoint checkpoint = cpp__checkpoint_token_stack(state);
|
|
bool next_is_paste = 0;
|
|
for (int i = macro.body_start_index; i < macro.body_end_index; ++i){
|
|
Cpp_Token token = macro_file->tokens.tokens[i];
|
|
|
|
next_is_paste = (i+1 < macro.body_end_index &&
|
|
macro_file->tokens.tokens[i+1].type == CPP_PP_CONCAT);
|
|
|
|
enum Body_Builder_Action{
|
|
BBA_NONE,
|
|
BBA_NORMAL,
|
|
BBA_STRFY,
|
|
BBA_PASTE
|
|
};
|
|
|
|
int action = BBA_NONE;
|
|
int param_i = -1;
|
|
int i2 = -1;
|
|
|
|
if (token.type == CPP_PP_STRINGIFY){
|
|
i += 1;
|
|
if (i < macro.body_end_index){
|
|
action = BBA_STRFY;
|
|
}
|
|
else{
|
|
i -= 1;
|
|
action = BBA_NONE;
|
|
}
|
|
}
|
|
else if (next_is_paste){
|
|
i2 = i + 2;
|
|
if (i2 < macro.body_end_index){
|
|
action = BBA_PASTE;
|
|
}
|
|
else{
|
|
action = BBA_NORMAL;
|
|
}
|
|
}
|
|
else if (token.type == CPP_PP_CONCAT){
|
|
action = BBA_NONE;
|
|
}
|
|
else{
|
|
action = BBA_NORMAL;
|
|
}
|
|
|
|
// NOTE(allen): loose token pushes here are managed by checkpoint
|
|
switch (action){
|
|
case BBA_NONE:break;
|
|
|
|
case BBA_NORMAL:
|
|
{
|
|
param_i = cpp__get_parameter_i(state, definitions, macro_file, token,
|
|
expansion->stack_base, macro.param_count);
|
|
if (param_i != -1){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, expansion->param_info_base, param_i, EXPANDED);
|
|
for (int j = range.start; j < range.end; ++j){
|
|
Cpp_Loose_Token loose = state->tokens.tokens[j];
|
|
cpp__push_loose_token(&checkpoint, state, loose.file_index, loose.token_index, loose.blocked);
|
|
}
|
|
}
|
|
else{
|
|
cpp__push_loose_token(&checkpoint, state, macro.file_index, i, 0);
|
|
}
|
|
}break;
|
|
|
|
case BBA_STRFY:
|
|
{
|
|
token = macro_file->tokens.tokens[i];
|
|
param_i = cpp__get_parameter_i(state, definitions, macro_file, token,
|
|
expansion->stack_base, macro.param_count);
|
|
if (param_i != -1){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, expansion->param_info_base, param_i, STRFY);
|
|
Cpp_Loose_Token loose = state->tokens.tokens[range.start];
|
|
cpp__push_loose_token(&checkpoint, state, loose.file_index, loose.token_index, loose.blocked);
|
|
}
|
|
else{
|
|
cpp__push_loose_token(&checkpoint, state, macro.file_index, i, 0);
|
|
}
|
|
}break;
|
|
|
|
case BBA_PASTE:
|
|
{
|
|
Cpp_Token token2;
|
|
int param_i2;
|
|
|
|
param_i = cpp__get_parameter_i(state, definitions, macro_file, token,
|
|
expansion->stack_base, macro.param_count);
|
|
token2 = macro_file->tokens.tokens[i2];
|
|
param_i2 = cpp__get_parameter_i(state, definitions, macro_file, token2,
|
|
expansion->stack_base, macro.param_count);
|
|
|
|
str_checkpoint = cpp__checkpoint_spare_string(state);
|
|
if (param_i != -1){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, expansion->param_info_base, param_i, RAW);
|
|
range.end -= 1;
|
|
if (range.start <= range.end){
|
|
int j;
|
|
for (j = range.start; j < range.end; ++j){
|
|
Cpp_Loose_Token loose = state->tokens.tokens[j];
|
|
cpp__push_loose_token(&checkpoint, state, loose.file_index, loose.token_index, loose.blocked);
|
|
}
|
|
Cpp_Loose_Token loose = state->tokens.tokens[j];
|
|
Cpp_Parse_File *end_file = cpp_get_parse_file(definitions, loose.file_index);
|
|
Cpp_Token end_token = end_file->tokens.tokens[loose.token_index];
|
|
String end_string = make_string(end_file->file.data + end_token.start, end_token.size);
|
|
cpp__spare_write(&str_checkpoint, state, end_string);
|
|
}
|
|
}
|
|
else{
|
|
String end_string = make_string(macro_file->file.data + token.start, token.size);
|
|
cpp__spare_write(&str_checkpoint, state, end_string);
|
|
}
|
|
|
|
if (param_i2 != -1){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, expansion->param_info_base, param_i2, RAW);
|
|
if (range.start < range.end){
|
|
int j = range.start;
|
|
Cpp_Loose_Token loose = state->tokens.tokens[j];
|
|
Cpp_Parse_File *start_file = cpp_get_parse_file(definitions, loose.file_index);
|
|
Cpp_Token start_token = start_file->tokens.tokens[loose.token_index];
|
|
String start_string = make_string(start_file->file.data + start_token.start, start_token.size);
|
|
cpp__spare_write(&str_checkpoint, state, start_string);
|
|
}
|
|
}
|
|
else{
|
|
String start_string = make_string(macro_file->file.data + token2.start, token2.size);
|
|
cpp__spare_write(&str_checkpoint, state, start_string);
|
|
}
|
|
|
|
if (!str_checkpoint.memory_overrun){
|
|
Cpp_Token _tokens[3];
|
|
Cpp_Token_Stack tokens;
|
|
tokens.tokens = _tokens;
|
|
tokens.max_count = ArrayCount(_tokens);
|
|
tokens.count = 0;
|
|
|
|
Cpp_File paste_file;
|
|
paste_file.data = state->spare_string;
|
|
paste_file.size = state->spare_string_write_pos;
|
|
|
|
cpp_lex_file_nonalloc(paste_file, &tokens);
|
|
_Assert(tokens.count <= 2);
|
|
|
|
// TODO(allen): protect these preserves
|
|
String paste_string = make_string(state->spare_string, state->spare_string_write_pos);
|
|
cpp__preserve_string(&pres_checkpoint, definitions, paste_string);
|
|
int start_pos = definitions->string_write_pos - paste_string.size;
|
|
for (int k = 0; k < tokens.count; ++k){
|
|
tokens.tokens[k].start += start_pos;
|
|
}
|
|
for (int k = 0; k < tokens.count; ++k){
|
|
Cpp_Loose_Token loose = cpp__preserve_token(&pres_checkpoint, definitions, tokens.tokens[k]);
|
|
cpp__push_loose_token(&checkpoint, state, loose.file_index, loose.token_index, loose.blocked);
|
|
}
|
|
|
|
i = i2;
|
|
}
|
|
else{
|
|
i = macro.body_end_index;
|
|
}
|
|
|
|
state->spare_string_write_pos = 0;
|
|
|
|
if (param_i2 != -1){
|
|
Cpp_Token_Range range = cpp__param_info_get(state, expansion->param_info_base, param_i2, RAW);
|
|
range.start += 1;
|
|
for (int j = range.start; j < range.end; ++j){
|
|
Cpp_Loose_Token loose = state->tokens.tokens[j];
|
|
cpp__push_loose_token(&checkpoint, state, loose.file_index, loose.token_index, loose.blocked);
|
|
}
|
|
}
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
_Assert(!"unknown action");
|
|
}break;
|
|
}
|
|
}
|
|
|
|
if (pres_checkpoint.out_of_memory){
|
|
cpp__restore_token_stack(state, checkpoint);
|
|
cpp__restore_preserve_write(definitions, pres_checkpoint);
|
|
result.memory_request = context->preserve_chunk_size;
|
|
result.memory_purpose = MEMPURP_PRESERVE_FILE;
|
|
}
|
|
else if (str_checkpoint.memory_overrun){
|
|
cpp__restore_token_stack(state, checkpoint);
|
|
cpp__restore_preserve_write(definitions, pres_checkpoint);
|
|
result.memory_request = (state->spare_string_size * 2) + str_checkpoint.memory_overrun;
|
|
result.memory_purpose = MEMPURP_SPARE_STRING;
|
|
}
|
|
else if (checkpoint.memory_overrun){
|
|
cpp__restore_token_stack(state, checkpoint);
|
|
cpp__restore_preserve_write(definitions, pres_checkpoint);
|
|
result.memory_request = sizeof(Cpp_Loose_Token)*((state->tokens.max*2) + checkpoint.memory_overrun);
|
|
result.memory_purpose = MEMPURP_TOKEN_STACK;
|
|
}
|
|
else{
|
|
expansion->position = expansion->stack_base;
|
|
expansion->out_type = EXPAN_BIG_DIRECT_OUT;
|
|
|
|
if (start_pos < state->tokens.count){
|
|
Cpp_Expansion *new_expansion =
|
|
cpp__push_expansion(state, EXPAN_PMACRO_BODY, -1, start_pos, state->tokens.count,
|
|
-1, expansion->invoking_file_index,
|
|
expansion->invoking_token_index);
|
|
new_expansion->macro_index = expansion->file_index;
|
|
if (new_expansion == 0){
|
|
result.error_code = PPERR_EXPANSION_OVERRUN;
|
|
}
|
|
}
|
|
}
|
|
}break;
|
|
|
|
case EXPAN_BIG_DIRECT_OUT:
|
|
{
|
|
if (expansion->out_rule == -1){
|
|
--state->expansion_level;
|
|
_Assert(state->expansion_level != -1);
|
|
cpp__free_param_table(state, macro.param_count);
|
|
}
|
|
else if (expansion->out_rule != 0){
|
|
if (state->param_info[expansion->out_rule].start == 0){
|
|
state->param_info[expansion->out_rule].start = expansion->position;
|
|
}
|
|
state->param_info[expansion->out_rule].end = state->tokens.count;
|
|
--state->expansion_level;
|
|
_Assert(state->expansion_level != -1);
|
|
cpp__free_param_table(state, macro.param_count);
|
|
}
|
|
else{
|
|
Cpp_Visit visit;
|
|
Cpp_Loose_Token loose_token = state->tokens.tokens[expansion->position];
|
|
visit.file_index = loose_token.file_index;
|
|
visit.token_index = loose_token.token_index;
|
|
|
|
result.file_index = visit.file_index;
|
|
result.token_index = visit.token_index;
|
|
result.invoking_file_index = expansion->invoking_file_index;
|
|
result.invoking_token_index = expansion->invoking_token_index;
|
|
result.from_macro = 1;
|
|
result.emit = 1;
|
|
|
|
++expansion->position;
|
|
if (expansion->position == state->tokens.count){
|
|
state->mac_inv.stack_base -= (state->tokens.count - expansion->stack_base);
|
|
state->tokens.count = expansion->stack_base;
|
|
--state->expansion_level;
|
|
_Assert(state->expansion_level != -1);
|
|
cpp__free_param_table(state, macro.param_count);
|
|
}
|
|
}
|
|
}break;
|
|
|
|
default:
|
|
_Assert(!"only meant to be used with one of the big expan types");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal Cpp_Preproc_Result
|
|
cpp__preproc_strfy_step_nonalloc(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_Parse_Context *context){
|
|
Cpp_Preproc_Result result = {};
|
|
Cpp_Expansion *expansion = state->expansions + state->expansion_level;
|
|
|
|
if (!cpp__can_push_loose_token(state, 1)){
|
|
result.memory_request = sizeof(Cpp_Loose_Token)*((state->tokens.max*2) + 1);
|
|
result.memory_purpose = MEMPURP_TOKEN_STACK;
|
|
return result;
|
|
}
|
|
|
|
Cpp_Visit visit = {};
|
|
|
|
bool do_body = 1;
|
|
if (expansion->position == expansion->end_position + 1){
|
|
do_body = 0;
|
|
--expansion->position;
|
|
}
|
|
else if (expansion->position == expansion->end_position){
|
|
visit.file_index = definitions->eof_token.file_index;
|
|
visit.token_index = definitions->eof_token.token_index;
|
|
}
|
|
else{
|
|
_Assert(expansion->file_index == -1);
|
|
Cpp_Loose_Token loose = state->tokens.tokens[expansion->position];
|
|
visit.file_index = loose.file_index;
|
|
visit.token_index = loose.token_index;
|
|
}
|
|
|
|
Spare_String_Checkpoint checkpoint = cpp__checkpoint_spare_string(state);
|
|
|
|
if (do_body){
|
|
Cpp_Parse_File visit_file;
|
|
Cpp_Token visit_token;
|
|
|
|
visit_file = *cpp_get_parse_file(definitions, visit.file_index);
|
|
visit_token = visit_file.tokens.tokens[visit.token_index];
|
|
|
|
result.file_index = visit.file_index;
|
|
result.token_index = visit.token_index;
|
|
result.invoking_file_index = expansion->invoking_file_index;
|
|
result.invoking_token_index = expansion->invoking_token_index;
|
|
result.from_macro = 1;
|
|
result.emit = 0;
|
|
|
|
if (state->spare_string_write_pos == 0){
|
|
cpp__spare_write(&checkpoint, state, '"');
|
|
expansion->param_info_base = visit_token.start + visit_token.size;
|
|
}
|
|
|
|
switch (visit_token.type){
|
|
case CPP_TOKEN_COMMENT:
|
|
case CPP_TOKEN_JUNK:break;
|
|
|
|
case CPP_TOKEN_EOF:
|
|
{
|
|
cpp__spare_write(&checkpoint, state, '"');
|
|
}break;
|
|
|
|
case CPP_TOKEN_STRING_CONSTANT:
|
|
{
|
|
if (visit_token.start > expansion->param_info_base){
|
|
cpp__spare_write(&checkpoint, state, ' ');
|
|
}
|
|
|
|
int i = visit_token.start;
|
|
char c = visit_file.file.data[i];
|
|
while (c != '"'){
|
|
cpp__spare_write(&checkpoint, state, c);
|
|
++i;
|
|
c = visit_file.file.data[i];
|
|
}
|
|
|
|
cpp__spare_write(&checkpoint, state, '\\');
|
|
cpp__spare_write(&checkpoint, state, '"');
|
|
++i;
|
|
|
|
int end_pos = visit_token.start + visit_token.size - 1;
|
|
for (; i < end_pos; ++i){
|
|
c = visit_file.file.data[i];
|
|
switch (c){
|
|
case '\\':
|
|
cpp__spare_write(&checkpoint, state, '\\');
|
|
|
|
default:
|
|
cpp__spare_write(&checkpoint, state, c);
|
|
}
|
|
}
|
|
|
|
cpp__spare_write(&checkpoint, state, '\\');
|
|
cpp__spare_write(&checkpoint, state, '"');
|
|
|
|
expansion->param_info_base = visit_token.start + visit_token.size;
|
|
}break;
|
|
|
|
case CPP_TOKEN_CHARACTER_CONSTANT:
|
|
{
|
|
if (visit_token.start > expansion->param_info_base){
|
|
cpp__spare_write(&checkpoint, state, ' ');
|
|
}
|
|
|
|
int i = visit_token.start;
|
|
char c = visit_file.file.data[i];
|
|
while (c != '\''){
|
|
cpp__spare_write(&checkpoint, state, c);
|
|
++i;
|
|
c = visit_file.file.data[i];
|
|
}
|
|
|
|
int end_pos = visit_token.start + visit_token.size;
|
|
for (; i < end_pos; ++i){
|
|
c = visit_file.file.data[i];
|
|
switch (c){
|
|
case '\\':
|
|
cpp__spare_write(&checkpoint, state, '\\');
|
|
|
|
default:
|
|
cpp__spare_write(&checkpoint, state, c);
|
|
}
|
|
}
|
|
|
|
expansion->param_info_base = visit_token.start + visit_token.size;
|
|
}break;
|
|
|
|
default:
|
|
{
|
|
if (visit_token.start > expansion->param_info_base){
|
|
cpp__spare_write(&checkpoint, state, ' ');
|
|
}
|
|
|
|
int end_pos = visit_token.start + visit_token.size;
|
|
for (int i = visit_token.start; i < end_pos; ++i){
|
|
char c = visit_file.file.data[i];
|
|
cpp__spare_write(&checkpoint, state, c);
|
|
}
|
|
|
|
expansion->param_info_base = visit_token.start + visit_token.size;
|
|
}break;
|
|
}
|
|
}
|
|
|
|
if (checkpoint.memory_overrun){
|
|
cpp__restore_spare_string(state, checkpoint);
|
|
result.memory_request = (state->spare_string_size*2) + checkpoint.memory_overrun;
|
|
result.memory_purpose = MEMPURP_SPARE_STRING;
|
|
}
|
|
else{
|
|
if (expansion->position == expansion->end_position){
|
|
Preserve_Checkpoint preserve_checkpoint = cpp__checkpoint_preserve_write(definitions);
|
|
|
|
String string = make_string(state->spare_string, state->spare_string_write_pos);
|
|
Cpp_Token token = {};
|
|
token.type = CPP_TOKEN_STRING_CONSTANT;
|
|
token.start = definitions->string_write_pos;
|
|
token.size = string.size;
|
|
|
|
cpp__preserve_string(&preserve_checkpoint, definitions, string);
|
|
Cpp_Loose_Token loose = cpp__preserve_token(&preserve_checkpoint, definitions, token);
|
|
|
|
if (preserve_checkpoint.out_of_memory){
|
|
cpp__restore_preserve_write(definitions, preserve_checkpoint);
|
|
result.memory_request = context->preserve_chunk_size;
|
|
result.memory_purpose = MEMPURP_PRESERVE_FILE;
|
|
}
|
|
else{
|
|
_Assert(expansion->out_rule > 0);
|
|
// NOTE(allen): this function gaurantees there is at least room
|
|
// for one token at the head end
|
|
cpp__push_loose_token(state, loose.file_index, loose.token_index, loose.blocked);
|
|
state->param_info[expansion->out_rule].start = state->tokens.count - 1;
|
|
state->param_info[expansion->out_rule].end = state->tokens.count;
|
|
--state->expansion_level;
|
|
state->spare_string_write_pos = 0;
|
|
}
|
|
}
|
|
++expansion->position;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
internal Cpp_Preproc_Result
|
|
cpp_preproc_step_nonalloc(Cpp_Preproc_State *state, Cpp_Parse_Definitions *definitions,
|
|
Cpp_Parse_Context *context){
|
|
Cpp_Preproc_Result result;
|
|
|
|
if (state->resizing_slots){
|
|
result = {};
|
|
result.memory_request = sizeof(Table_Entry)*(definitions->table.max_size*2);
|
|
result.memory_purpose = MEMPURP_DEFINITION_SLOTS;
|
|
state->resizing_slots = 0;
|
|
return result;
|
|
}
|
|
if (definitions->count * 8 >= definitions->max * 7){
|
|
result = {};
|
|
result.memory_request = sizeof(Cpp_Def_Slot)*(definitions->max*2);
|
|
result.memory_purpose = MEMPURP_DEFINITION_SLOTS;
|
|
state->resizing_slots = 1;
|
|
return result;
|
|
}
|
|
|
|
Cpp_Expansion *expansion = state->expansions + state->expansion_level;
|
|
switch (expansion->out_type){
|
|
case EXPAN_NORMAL:
|
|
case EXPAN_EOF_FLUSH:
|
|
result = cpp__preproc_normal_step_nonalloc(state, definitions, context);
|
|
break;
|
|
|
|
case EXPAN_BIG_PROCESS_ARGS:
|
|
case EXPAN_BIG_PROCESS_BODY:
|
|
case EXPAN_BIG_DIRECT_OUT:
|
|
result = cpp__preproc_big_step_nonalloc(state, definitions, context);
|
|
break;
|
|
|
|
case EXPAN_STRFY:
|
|
result = cpp__preproc_strfy_step_nonalloc(state, definitions, context);
|
|
break;
|
|
|
|
default:
|
|
result = {};
|
|
_Assert(!"unknown expansion->out_type");
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// BOTTOM
|
|
|