Self-made programming language crowbar (v0.1) allocates memory when building a parser, crowbarv0.1
During the first request for memory in crowbar, the parser is generated:
/* interface.c */
CRB_Interpreter *CRB_create_interpreter(void){ MEM_Storage storage; CRB_Interpreter *interpreter; storage = MEM_open_storage(0); interpreter = MEM_storage_malloc(storage, sizeof(struct CRB_Interpreter_tag)); interpreter->interpreter_storage = storage; interpreter->execute_storage = NULL; interpreter->variable = NULL; interpreter->function_list = NULL; interpreter->statement_list = NULL; interpreter->current_line_number = 1; crb_set_current_interpreter(interpreter); add_native_functions(interpreter); return interpreter;}
First, let's take a look at the MEM_Storage type and declare:
/* MEM.h */typedef struct MEM_Storage_tag *MEM_Storage;
/* MEM/storage.c */struct MEM_Storage_tag { MemoryPageList page_list; int current_page_size;};typedef MemoryPage *MemoryPageList;typedef struct MemoryPage_tag MemoryPage;struct MemoryPage_tag { int cell_num; int use_cell_num; MemoryPageList next; Cell cell[1];};typedef union { long l_dummy; double d_dummy; void *p_dummy;} Cell;
Structure Diagram: (cell is union)
Next let's look at MEM_open_storage (0 ):
/* MEM.h */
#define MEM_open_storage(page_size)(MEM_open_storage_func(MEM_CURRENT_CONTROLLER, __FILE__, __LINE__, page_size))
/* MEM/storage.c */MEM_Storage MEM_open_storage_func(MEM_Controller controller,char *filename, int line, int page_size){ MEM_Storage storage; storage = MEM_malloc_func(controller, filename, line, sizeof(struct MEM_Storage_tag)); storage->page_list = NULL; assert(page_size >= 0); if (page_size > 0) { storage->current_page_size = page_size; } else { storage->current_page_size = DEFAULT_PAGE_SIZE; } return storage;}
The MEM_open_storage function uploads a MEM_CURRENT_CONTROLLER macro. Next, let's take a look at the macro definition:
/* MEM.h */
typedef struct MEM_Controller_tag *MEM_Controller;
extern MEM_Controller mem_default_controller;
#ifdef MEM_CONTROLLER#define MEM_CURRENT_CONTROLLER MEM_CONTROLLER#else /* MEM_CONTROLLER */#define MEM_CURRENT_CONTROLLER mem_default_controller#endif /* MEM_CONTROLLER */
Definition of MEM_Controller_tag:
/* MEM/memory.h */
typedef union Header_tag Header;struct MEM_Controller_tag { FILE *error_fp; MEM_ErrorHandler error_handler; MEM_FailMode fail_mode; Header *block_header;};
/* MEM.h */
typedef void (*MEM_ErrorHandler)(MEM_Controller, char *, int, char *);
typedef enum {
MEM_FAIL_AND_EXIT,
MEM_FAIL_AND_RETURN
} MEM_FailMode;
Header_tag is defined as follows:
/* MEM/memory.c */union Header_tag { HeaderStruct s; Align u[HEADER_ALIGN_SIZE];};
#define MARK_SIZE (4)
#define ALIGN_SIZE (sizeof(Align))#define revalue_up_align(val) ((val) ? (((val) - 1) / ALIGN_SIZE + 1) : 0)#define HEADER_ALIGN_SIZE (revalue_up_align(sizeof(HeaderStruct)))
#define MARK (0xCD)
typedef struct { int size; char *filename; int line; Header *prev; Header *next; unsigned char mark[MARK_SIZE];} HeaderStruct;typedef union { long l_dummy; double d_dummy; void *p_dummy;} Align;
We can see that MEM_malloc_func () and MEM_malloc_func prototype are called in MEM_open_storage_func:
/* MEM/memory.c */
void *MEM_malloc_func(MEM_Controller controller, char *filename, int line, size_t size){ void *ptr; size_t alloc_size;#ifdef DEBUG alloc_size = size + sizeof(Header) + MARK_SIZE;#else alloc_size = size;#endif ptr = malloc(alloc_size); if (ptr == NULL) { error_handler(controller, filename, line, "malloc"); }#ifdef DEBUG memset(ptr, 0xCC, alloc_size); set_header(ptr, size, filename, line); set_tail(ptr, alloc_size); chain_block(controller, (Header*)ptr); ptr = (char*)ptr + sizeof(Header);#endif return ptr;}
The DEBUG code is ignored for the moment. So far, the DEFAULT_PAGE_SIZE (1024) size memory has been applied from the memory to the MEM_Storage storage variable.
Next let's look at interpreter = MEM_storage_malloc (storage, sizeof (struct CRB_Interpreter_tag ));
MEM_storage_malloc prototype:
/* MEM. h */
# Define MEM_storage_malloc (storage, size) (MEM_storage_malloc_func (MEM_CURRENT_CONTROLLER ,__ FILE __, _ LINE __, storage, size ))
/* MEM/storage. c */void * MEM_storage_malloc_func (MEM_Controller controller, char * filename, int line, MEM_Storage storage, size_t size) {int cell_num; MemoryPage * new_page; void * p; cell_num = (size-1)/CELL_SIZE) + 1; /* if the number of cells used in storage plus the number of cells to be allocated is smaller than that of all cells in storage, a cell is retrieved from storage and a result is returned. */if (storage-> page_list! = NULL & (storage-> page_list-> use_cell_num + cell_num <storage-> page_list-> cell_num )) {p = & (storage-> page_list-> cell [storage-> page_list-> use_cell_num]); storage-> page_list-> use_cell_num + = cell_num;
/* Otherwise, apply again from the memory */} else {int alloc_cell_num; alloc_cell_num = larger (cell_num, storage-> current_page_size); new_page = MEM_malloc_func (controller, filename, line, sizeof (MemoryPage) + CELL_SIZE * (alloc_cell_num-1); new_page-> next = storage-> page_list; new_page-> cell_num = alloc_cell_num; storage-> page_list = new_page; p = & (new_page-> cell [0]); new_page-> use_cell_num = cell_num;} return p ;}
Memory allocation has been analyzed during the parser build.