From e425464aab7177701541d9ca1ebb22032d5a3ef5 Mon Sep 17 00:00:00 2001 From: Yaossg Date: Mon, 10 Mar 2025 00:46:24 +0800 Subject: [PATCH] colored demo --- .gitignore | 3 +- boot.c | 88 +++++++++++++++++++++++--------------- compile.sh | 4 ++ demo/for.c | 9 ++++ transcript.py | 114 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 183 insertions(+), 35 deletions(-) create mode 100644 compile.sh create mode 100644 demo/for.c create mode 100644 transcript.py diff --git a/.gitignore b/.gitignore index 1762ca8..8c1984e 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,5 @@ cov *.o *.s *.ans -*.elf \ No newline at end of file +*.elf +*.html \ No newline at end of file diff --git a/boot.c b/boot.c index bfab8ac..d5c87ef 100644 --- a/boot.c +++ b/boot.c @@ -20,13 +20,10 @@ void exit(int status); int fprintf(void* file, char* format, ...); int ungetc(int ch, void* file); -void ungetchar(int ch) { - ungetc(ch, stdin); -} - // limitations enum { + ECHO_BUFFER_SIZE = 65536, STRING_TABLE_SIZE = 65536, STRING_LUT_SIZE = 4096, ID_TABLE_SIZE = 65536, @@ -35,6 +32,28 @@ enum { REG_SIZE = 4096, }; +// hooks + +char echo_buffer[ECHO_BUFFER_SIZE]; +int echo_size; + +int readchar() { + int ch = getchar(); + if (ch != '\n') { + echo_buffer[echo_size++] = ch; + } else { + echo_buffer[echo_size++] = 0; + printf("#@%s\n", echo_buffer); + echo_size = 0; + } + return ch; +} + +void ungetchar(int ch) { + --echo_size; + ungetc(ch, stdin); +} + // constants enum { @@ -220,7 +239,7 @@ int is_id_cont(int ch) { int parse_int(int ch) { int num = ch - '0'; - while (is_digit(ch = getchar())) { + while (is_digit(ch = readchar())) { num *= 10; num += ch - '0'; } @@ -229,7 +248,7 @@ int parse_int(int ch) { } int get_escaped_char() { - int ch = getchar(); + int ch = readchar(); if (ch == 'n') return '\n'; if (ch == 't') return '\t'; if (ch == 'r') return '\r'; @@ -252,7 +271,7 @@ int string_lut_size; int parse_string() { int offset = string_offset; int ch; - while ((ch = getchar()) != '"') { + while ((ch = readchar()) != '"') { if (ch == -1 || ch == '\n') { fprintf(stderr, "expecting '\"'\n"); exit(1); @@ -292,7 +311,7 @@ int id_lut_size; int parse_id(int ch) { int offset = id_offset; id_table[id_offset++] = ch; - while (is_id_cont(ch = getchar())) { + while (is_id_cont(ch = readchar())) { id_table[id_offset++] = ch; } ungetchar(ch); @@ -366,9 +385,9 @@ void next_token() { token_state = 0; return; } - int ch = getchar(); + int ch = readchar(); while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') { - ch = getchar(); + ch = readchar(); } if (ch == -1) { token_type = TOKEN_EOF; @@ -385,7 +404,7 @@ void next_token() { } else if (ch == '}') { token_type = TOKEN_BRACE_RIGHT; } else if (ch == '+') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '+') { token_type = TOKEN_INC; } else if (ch2 == '=') { @@ -395,7 +414,7 @@ void next_token() { token_type = TOKEN_ADD; } } else if (ch == '-') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '-') { token_type = TOKEN_DEC; } else if (ch2 == '=') { @@ -405,7 +424,7 @@ void next_token() { token_type = TOKEN_SUB; } } else if (ch == '*') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_MUL_ASSIGN; } else { @@ -413,22 +432,22 @@ void next_token() { token_type = TOKEN_MUL; } } else if (ch == '/') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_DIV_ASSIGN; } else if (ch2 == '/') { - do ch = getchar(); while (ch != -1 && ch != '\n'); + do ch = readchar(); while (ch != -1 && ch != '\n'); next_token(); return; } else if (ch2 == '*') { while (1) { - ch = getchar(); + ch = readchar(); if (ch == -1) { fprintf(stderr, "expecting '*/'\n"); exit(1); } if (ch == '*') { - ch = getchar(); + ch = readchar(); if (ch == '/') { break; } @@ -441,7 +460,7 @@ void next_token() { token_type = TOKEN_DIV; } } else if (ch == '%') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_REM_ASSIGN; } else { @@ -457,11 +476,11 @@ void next_token() { } else if (ch == ',') { token_type = TOKEN_COMMA; } else if (ch == '<') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_LE; } else if (ch2 == '<') { - int ch3 = getchar(); + int ch3 = readchar(); if (ch3 == '=') { token_type = TOKEN_LSHIFT_ASSIGN; } else { @@ -473,11 +492,11 @@ void next_token() { token_type = TOKEN_LT; } } else if (ch == '>') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_GE; } else if (ch2 == '>') { - int ch3 = getchar(); + int ch3 = readchar(); if (ch3 == '=') { token_type = TOKEN_RSHIFT_ASSIGN; } else { @@ -489,7 +508,7 @@ void next_token() { token_type = TOKEN_GT; } } else if (ch == '=') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_EQ; } else { @@ -497,7 +516,7 @@ void next_token() { token_type = TOKEN_ASSIGN; } } else if (ch == '!') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_NE; } else { @@ -505,7 +524,7 @@ void next_token() { token_type = TOKEN_NOT; } } else if (ch == '&') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_AND_ASSIGN; } else if (ch2 == '&') { @@ -515,7 +534,7 @@ void next_token() { token_type = TOKEN_AND; } } else if (ch == '|') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_OR_ASSIGN; } else if (ch2 == '|') { @@ -525,7 +544,7 @@ void next_token() { token_type = TOKEN_OR; } } else if (ch == '^') { - int ch2 = getchar(); + int ch2 = readchar(); if (ch2 == '=') { token_type = TOKEN_XOR_ASSIGN; } else { @@ -536,11 +555,11 @@ void next_token() { token_type = TOKEN_INV; } else if (ch == '\'') { token_type = TOKEN_NUMBER; - token_data = getchar(); + token_data = readchar(); if (token_data == '\\') { token_data = get_escaped_char(); } - if (getchar() != '\'') { + if (readchar() != '\'') { fprintf(stderr, "expecting '\n"); exit(1); } @@ -550,8 +569,8 @@ void next_token() { dedup_string(); } else if (ch == '.') { token_type = 0; - if (getchar() == '.') { - if (getchar() == '.') { + if (readchar() == '.') { + if (readchar() == '.') { token_type = TOKEN_ELLIPSIS; } } @@ -826,7 +845,7 @@ void load(int rd, int rs) { } rs = rd; } - printf(" %s %s, 0(%s) # load non-trivial register\n", op, rd_name, reg_name(rs)); + printf(" %s %s, 0(%s)\n", op, rd_name, reg_name(rs)); } // store a trivial register into a non-trivial one @@ -839,7 +858,7 @@ void store(char* rs, int reg) { } reg = REG_T2; } - printf(" %s %s, 0(%s) # store non-trivial register\n", op, rs, reg_name(reg)); + printf(" %s %s, 0(%s)\n", op, rs, reg_name(reg)); } int is_nontrivial(int reg) { @@ -972,7 +991,7 @@ int lookup(int id) { char* name = id_table + id_lut[id]; if (global_kind[id]) { if (global_kind[id] == KIND_FUNCTION) { - fprintf(stderr, "function name must not appear outside function call: %s\n", name); + fprintf(stderr, "function name can only be directly called: %s\n", name); exit(1); } int rd = next_reg(TYPE_VOID_PTR); @@ -1974,6 +1993,7 @@ void parse_top_level() { } void dump_string_table() { + printf("# string table: \n"); printf(".data\n"); for (int i = 0; i < string_lut_size; ++i) { printf(".LC%d: .string \"", i); diff --git a/compile.sh b/compile.sh new file mode 100644 index 0000000..b59487c --- /dev/null +++ b/compile.sh @@ -0,0 +1,4 @@ +gcc boot.c -o boot.elf && +./boot.elf < $1 > $1.s +python3 transcript.py < $1.s > $1.html +rm boot.elf \ No newline at end of file diff --git a/demo/for.c b/demo/for.c new file mode 100644 index 0000000..31d696c --- /dev/null +++ b/demo/for.c @@ -0,0 +1,9 @@ +int printf(char* format, ...); + +int main() { + int i; + for (i = 0; + i < 10; + ++i) + printf("hello %d\n", i); +} diff --git a/transcript.py b/transcript.py new file mode 100644 index 0000000..d83e8fa --- /dev/null +++ b/transcript.py @@ -0,0 +1,114 @@ +import sys +import html + +src = '' +asm = '' +style = 0 +flip = False + +def decorate(line): + return f'{html.escape(line)}' + +for line in sys.stdin: + if line.startswith("#@"): + line = line.removeprefix("#@") + src += decorate(line) if flip else line + style += 1 + style %= 5 + flip = False + elif line.startswith("# string table: "): + asm += line + break + else: + asm += decorate(line) + flip = True + +for line in sys.stdin: + asm += line + +title = 'RVBTCC Code Gen Demo' + + +template = ''' + + + + + + <%title%> + + + +
+

<%title%>

+
+
+
+

Source Code

+
+<%src%>
+                
+
+ +
+

Assembly

+
+<%asm%>
+                
+
+
+ + +''' + +print(template.replace("<%title%>", title).replace("<%src%>", src).replace("<%asm%>", asm)) \ No newline at end of file