|
|
|
@@ -1,7 +1,17 @@ |
|
|
|
proc visualize_lisp_machine() -> void { |
|
|
|
const int padding = 30; |
|
|
|
fprintf(stderr, "Drawing visualization..."); |
|
|
|
defer { |
|
|
|
fprintf(stderr, "Done!\n"); |
|
|
|
}; |
|
|
|
|
|
|
|
const int padding = 40; |
|
|
|
const int margin = 20; |
|
|
|
|
|
|
|
const char* draw_text_template = " <text x='%d' y='%d' font-size='20' font-family='monospace'>\n %s\n </text>\n"; |
|
|
|
const char* draw_integer_template = " <text x='%d' y='%d' font-size='20' font-family='monospace'>\n %d\n </text>\n"; |
|
|
|
const char* draw_float_template = " <text x='%d' y='%d' font-size='20' font-family='monospace'>\n %012.6f\n </text>\n"; |
|
|
|
|
|
|
|
|
|
|
|
FILE *f = fopen("visualization.svg", "w"); |
|
|
|
defer { |
|
|
|
fclose(f); |
|
|
|
@@ -18,27 +28,293 @@ proc visualize_lisp_machine() -> void { |
|
|
|
write_x = 0, |
|
|
|
write_y = 0; |
|
|
|
|
|
|
|
|
|
|
|
proc draw_margin = [&](int count = 1) { |
|
|
|
write_x += margin * count; |
|
|
|
}; |
|
|
|
proc draw_new_line = [&](int count = 1) { |
|
|
|
write_x = 0; |
|
|
|
write_y += 25 * count; |
|
|
|
}; |
|
|
|
proc draw_text = [&](const char* text) { |
|
|
|
int text_width = 12 * strlen(text); |
|
|
|
int text_height = 12; |
|
|
|
// take care of escaping sensitive chars |
|
|
|
int text_length = 0; |
|
|
|
int extra_needed_chars = 0; |
|
|
|
char* new_text; |
|
|
|
|
|
|
|
char source; |
|
|
|
while ((source = text[text_length++]) != '\0') { |
|
|
|
switch (source) { |
|
|
|
case '<': |
|
|
|
case '>': |
|
|
|
extra_needed_chars += 3; |
|
|
|
break; |
|
|
|
case '&': |
|
|
|
extra_needed_chars += 4; |
|
|
|
break; |
|
|
|
case '\'': |
|
|
|
case '"': |
|
|
|
extra_needed_chars += 5; |
|
|
|
} |
|
|
|
} |
|
|
|
// if we need to replace some chars |
|
|
|
if (extra_needed_chars > 0) { |
|
|
|
new_text = (char*)malloc((text_length + extra_needed_chars) * sizeof(char)); |
|
|
|
|
|
|
|
int index_in_text = 0, |
|
|
|
index_in_new_text = 0; |
|
|
|
|
|
|
|
char source; |
|
|
|
while ((source = text[index_in_text++]) != '\0') { |
|
|
|
switch (source) { |
|
|
|
case '<': |
|
|
|
new_text[index_in_new_text++] = '&'; |
|
|
|
new_text[index_in_new_text++] = 'l'; |
|
|
|
new_text[index_in_new_text++] = 't'; |
|
|
|
new_text[index_in_new_text++] = ';'; |
|
|
|
break; |
|
|
|
case '>': |
|
|
|
new_text[index_in_new_text++] = '&'; |
|
|
|
new_text[index_in_new_text++] = 'g'; |
|
|
|
new_text[index_in_new_text++] = 't'; |
|
|
|
new_text[index_in_new_text++] = ';'; |
|
|
|
break; |
|
|
|
case '&': |
|
|
|
new_text[index_in_new_text++] = '&'; |
|
|
|
new_text[index_in_new_text++] = 'a'; |
|
|
|
new_text[index_in_new_text++] = 'm'; |
|
|
|
new_text[index_in_new_text++] = 'p'; |
|
|
|
new_text[index_in_new_text++] = ';'; |
|
|
|
break; |
|
|
|
case '"': |
|
|
|
new_text[index_in_new_text++] = '&'; |
|
|
|
new_text[index_in_new_text++] = 'q'; |
|
|
|
new_text[index_in_new_text++] = 'u'; |
|
|
|
new_text[index_in_new_text++] = 'o'; |
|
|
|
new_text[index_in_new_text++] = 't'; |
|
|
|
new_text[index_in_new_text++] = ';'; |
|
|
|
break; |
|
|
|
case '\'': |
|
|
|
new_text[index_in_new_text++] = '&'; |
|
|
|
new_text[index_in_new_text++] = 'a'; |
|
|
|
new_text[index_in_new_text++] = 'p'; |
|
|
|
new_text[index_in_new_text++] = 'o'; |
|
|
|
new_text[index_in_new_text++] = 's'; |
|
|
|
new_text[index_in_new_text++] = ';'; |
|
|
|
break; |
|
|
|
default: |
|
|
|
new_text[index_in_new_text++] = source; |
|
|
|
} |
|
|
|
} |
|
|
|
new_text[index_in_new_text] = '\0'; |
|
|
|
} |
|
|
|
|
|
|
|
int text_width = 12 * text_length; |
|
|
|
|
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
|
|
|
|
fprintf(f, |
|
|
|
" <text x='%d' y='%d' font-size='20' " |
|
|
|
"font-family='monospace'>\n" |
|
|
|
" %s" |
|
|
|
"\n </text>\n", write_x, write_y, text); |
|
|
|
if (extra_needed_chars) { |
|
|
|
fprintf(f, draw_text_template, write_x, write_y, new_text); |
|
|
|
free(new_text); |
|
|
|
} else { |
|
|
|
fprintf(f, draw_text_template, write_x, write_y, text); |
|
|
|
} |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
}; |
|
|
|
proc draw_integer = [&](int number) { |
|
|
|
int text_width = 12 * ((int)log10(number)+1); |
|
|
|
|
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
|
|
|
|
fprintf(f, draw_integer_template, write_x, write_y, number); |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
}; |
|
|
|
proc draw_float = [&](float number) { |
|
|
|
int text_width = 12 * 12; |
|
|
|
|
|
|
|
if (write_x + text_width > max_x) max_x = write_x + text_width; |
|
|
|
if (write_y > max_y) max_y = write_y; |
|
|
|
|
|
|
|
fprintf(f, draw_float_template, write_x, write_y, number); |
|
|
|
|
|
|
|
write_x += text_width; |
|
|
|
}; |
|
|
|
|
|
|
|
proc draw_header = [&]() { |
|
|
|
proc draw_separator = [&]() { |
|
|
|
draw_margin(); |
|
|
|
draw_text("|"); |
|
|
|
draw_margin(); |
|
|
|
}; |
|
|
|
|
|
|
|
time_t t = time(NULL); |
|
|
|
struct tm tm = *localtime(&t); |
|
|
|
|
|
|
|
proc draw_header = [&](){ |
|
|
|
write_y = 12; |
|
|
|
// draw_text("ASD"); |
|
|
|
// write_x += margin; |
|
|
|
draw_text("doeun"); |
|
|
|
|
|
|
|
// ------------------- |
|
|
|
// Date |
|
|
|
// ------------------- |
|
|
|
char date[12]; |
|
|
|
snprintf(date, 12, "%02d.%02d.%d", tm.tm_mday, tm.tm_mon + 1, tm.tm_year + 1900); |
|
|
|
|
|
|
|
draw_text("Date: "); |
|
|
|
draw_text(date); |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
// ------------------- |
|
|
|
// Time |
|
|
|
// ------------------- |
|
|
|
char time[12]; |
|
|
|
snprintf(time, 12, "%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); |
|
|
|
|
|
|
|
draw_text("Time: "); |
|
|
|
draw_text(time); |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
// ------------------- |
|
|
|
// String Memory |
|
|
|
// ------------------- |
|
|
|
draw_new_line(); |
|
|
|
|
|
|
|
int free_string_memory = Memory::next_free_spot_in_string_memory - Memory::string_memory; |
|
|
|
for (int i = 0; i < Memory::free_spots_in_string_memory->next_index; ++i) { |
|
|
|
free_string_memory += ((String*)(Memory::free_spots_in_string_memory->data[i]))->length; |
|
|
|
} |
|
|
|
int used_string_memory = Memory::string_memory_size - free_string_memory; |
|
|
|
|
|
|
|
draw_text("String Memory:"); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[allocated chars] "); |
|
|
|
draw_integer(Memory::string_memory_size); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[free] "); |
|
|
|
draw_integer(free_string_memory); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[used] "); |
|
|
|
draw_integer(used_string_memory); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%free] "); |
|
|
|
draw_float(100.0f * free_string_memory / Memory::string_memory_size); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%used] "); |
|
|
|
draw_float(100.0f * used_string_memory / Memory::string_memory_size); |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
draw_new_line(); |
|
|
|
|
|
|
|
// ------------------- |
|
|
|
// Object Memory |
|
|
|
// ------------------- |
|
|
|
|
|
|
|
int free_object_memory_cells = Memory::object_memory_size - (Memory::next_index_in_object_memory - Memory::free_spots_in_object_memory->next_index); |
|
|
|
int used_object_memory_cells = Memory::next_index_in_object_memory - Memory::free_spots_in_object_memory->next_index; |
|
|
|
|
|
|
|
draw_text("Object Memory:"); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#allocated] "); |
|
|
|
draw_integer(Memory::object_memory_size); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#free] "); |
|
|
|
draw_integer(free_object_memory_cells); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[#used] "); |
|
|
|
draw_integer(used_object_memory_cells); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%free] "); |
|
|
|
draw_float(100.0f * free_object_memory_cells / Memory::object_memory_size); |
|
|
|
draw_margin(); |
|
|
|
draw_text("[%used] "); |
|
|
|
draw_float(100.0f * used_object_memory_cells / Memory::object_memory_size); |
|
|
|
|
|
|
|
draw_separator(); |
|
|
|
|
|
|
|
draw_new_line(); |
|
|
|
draw_new_line(); |
|
|
|
draw_new_line(); |
|
|
|
}; |
|
|
|
proc draw_symbols_keywords_and_numbers = [&]() { |
|
|
|
Lisp_Object_Array_List* symbols = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* keywords = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* numbers = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* strings = create_Lisp_Object_array_list(); |
|
|
|
Lisp_Object_Array_List* pairs = create_Lisp_Object_array_list(); |
|
|
|
|
|
|
|
// loop over all used memory |
|
|
|
for (int i = 0; i < Memory::next_index_in_object_memory; ++i) { |
|
|
|
for (int j = 0; j < Memory::free_spots_in_object_memory->next_index; ++j) { |
|
|
|
if (i == Memory::free_spots_in_object_memory->data[j]) |
|
|
|
goto next; |
|
|
|
} |
|
|
|
|
|
|
|
switch (Memory::get_type(Memory::object_memory+i)) { |
|
|
|
case Lisp_Object_Type::Symbol: append_to_array_list(symbols, Memory::object_memory+i); break; |
|
|
|
case Lisp_Object_Type::String: append_to_array_list(strings, Memory::object_memory+i); break; |
|
|
|
case Lisp_Object_Type::Keyword: append_to_array_list(keywords, Memory::object_memory+i); break; |
|
|
|
case Lisp_Object_Type::Number : append_to_array_list(numbers, Memory::object_memory+i); break; |
|
|
|
case Lisp_Object_Type::Pair : append_to_array_list(pairs, Memory::object_memory+i); break; |
|
|
|
} |
|
|
|
|
|
|
|
next: ; |
|
|
|
} |
|
|
|
|
|
|
|
draw_text("Memory Contents:"); |
|
|
|
draw_new_line(); |
|
|
|
draw_new_line(); |
|
|
|
|
|
|
|
int start_x = write_x, |
|
|
|
start_y = write_y; |
|
|
|
|
|
|
|
draw_text("Symbols: "); |
|
|
|
draw_integer(symbols->next_index); |
|
|
|
|
|
|
|
for (int i = 0; i < symbols->next_index; ++i) { |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x; |
|
|
|
|
|
|
|
draw_text(&symbols->data[i]->value.identifier->data); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
write_x = start_x + 300; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Keywords: "); |
|
|
|
draw_integer(keywords->next_index); |
|
|
|
|
|
|
|
for (int i = 0; i < keywords->next_index; ++i) { |
|
|
|
draw_new_line(); |
|
|
|
write_x = start_x + 300; |
|
|
|
|
|
|
|
draw_text(":"); |
|
|
|
draw_text(&keywords->data[i]->value.identifier->data); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
write_x = start_x + 600; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Numbers: "); |
|
|
|
draw_integer(numbers->next_index); |
|
|
|
|
|
|
|
write_x = start_x + 900; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Strings: "); |
|
|
|
draw_integer(strings->next_index); |
|
|
|
|
|
|
|
write_x = start_x + 1200; |
|
|
|
write_y = start_y; |
|
|
|
|
|
|
|
draw_text("Pairs: "); |
|
|
|
draw_integer(pairs->next_index); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
@@ -50,6 +326,7 @@ proc visualize_lisp_machine() -> void { |
|
|
|
">\n\n", -padding, -padding, 0, 0); |
|
|
|
|
|
|
|
draw_header(); |
|
|
|
draw_symbols_keywords_and_numbers(); |
|
|
|
|
|
|
|
fprintf(f, "\n\n</svg>"); |
|
|
|
|
|
|
|
|