2024-11-15 13:27:39 +00:00
|
|
|
#include "boot-lib.h"
|
|
|
|
|
|
|
|
// lexer
|
|
|
|
|
|
|
|
int is_digit(int ch) {
|
|
|
|
return '0' <= ch && ch <= '9';
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_id_start(int ch) {
|
|
|
|
return 'a' <= ch && ch <= 'z' || 'A' <= ch && ch <= 'Z' || ch == '_';
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_id_cont(int ch) {
|
|
|
|
return is_id_start(ch) || is_digit(ch);
|
|
|
|
}
|
|
|
|
|
|
|
|
int token_state;
|
|
|
|
int token_type;
|
|
|
|
int token_data;
|
|
|
|
|
|
|
|
const int TOKEN_EOF = 0;
|
|
|
|
const int TOKEN_SEMICOLON = 1;
|
|
|
|
const int TOKEN_ADD = 2;
|
|
|
|
const int TOKEN_MINUS = 3;
|
|
|
|
const int TOKEN_STAR = 4;
|
|
|
|
const int TOKEN_DIV = 5;
|
|
|
|
const int TOKEN_REM = 6;
|
|
|
|
const int TOKEN_ASSIGN = 7;
|
|
|
|
const int TOKEN_COMMA = 8;
|
|
|
|
const int TOKEN_DOT = 9;
|
2024-11-16 14:28:00 +00:00
|
|
|
const int TOKEN_LSHIFT = 10;
|
|
|
|
const int TOKEN_RSHIFT = 11;
|
2024-11-15 13:27:39 +00:00
|
|
|
const int TOKEN_AND = 12;
|
|
|
|
const int TOKEN_OR = 13;
|
|
|
|
const int TOKEN_XOR = 14;
|
|
|
|
const int TOKEN_COMPL = 15;
|
|
|
|
const int TOKEN_NOT = 16;
|
|
|
|
const int TOKEN_LAND = 17;
|
|
|
|
const int TOKEN_LOR = 18;
|
|
|
|
const int TOKEN_ELLIPSIS = 19;
|
|
|
|
const int TOKEN_INC = 20;
|
|
|
|
const int TOKEN_DEC = 21;
|
|
|
|
|
|
|
|
const int TOKEN_EQ = 40;
|
|
|
|
const int TOKEN_NE = 41;
|
|
|
|
const int TOKEN_LT = 42;
|
|
|
|
const int TOKEN_GT = 43;
|
|
|
|
const int TOKEN_LE = 44;
|
|
|
|
const int TOKEN_GE = 45;
|
|
|
|
|
|
|
|
const int TOKEN_PAREN_LEFT = 50;
|
|
|
|
const int TOKEN_PAREN_RIGHT = 51;
|
|
|
|
const int TOKEN_BRACKET_LEFT = 52;
|
|
|
|
const int TOKEN_BRACKET_RIGHT = 53;
|
|
|
|
const int TOKEN_BRACE_LEFT = 54;
|
|
|
|
const int TOKEN_BRACE_RIGHT = 55;
|
|
|
|
|
2024-11-17 09:01:18 +00:00
|
|
|
const int TOKEN_STRING = 99;
|
2024-11-15 13:27:39 +00:00
|
|
|
const int TOKEN_NUMBER = 100;
|
|
|
|
const int TOKEN_ID = 101;
|
2024-11-17 09:01:18 +00:00
|
|
|
const int TOKEN_IF = 102;
|
|
|
|
const int TOKEN_ELSE = 103;
|
|
|
|
const int TOKEN_WHILE = 104;
|
|
|
|
const int TOKEN_FOR = 105;
|
|
|
|
const int TOKEN_DO = 106;
|
|
|
|
const int TOKEN_BREAK = 107;
|
|
|
|
const int TOKEN_CONTINUE = 108;
|
|
|
|
const int TOKEN_RETURN = 109;
|
|
|
|
|
|
|
|
const int TOKEN_CONST = 127;
|
|
|
|
const int TOKEN_VOID = 128;
|
|
|
|
const int TOKEN_INT = 129;
|
|
|
|
const int TOKEN_CHAR = 130;
|
|
|
|
|
|
|
|
const int TYPE_VOID = 0;
|
|
|
|
const int TYPE_INT = 1;
|
|
|
|
const int TYPE_CHAR = 2;
|
|
|
|
const int TYPE_VOID_PTR = 16;
|
|
|
|
const int TYPE_INT_PTR = 17;
|
|
|
|
const int TYPE_CHAR_PTR = 18;
|
|
|
|
|
|
|
|
const int TYPE_PTR_MASK = 16;
|
|
|
|
const int TYPE_TOKEN_MASK = 128;
|
2024-11-15 13:27:39 +00:00
|
|
|
|
|
|
|
int parse_int(int ch) {
|
|
|
|
int num = ch - '0';
|
2024-11-16 00:39:45 +00:00
|
|
|
while (is_digit(ch = getchar())) {
|
2024-11-15 13:27:39 +00:00
|
|
|
num = num * 10;
|
|
|
|
num = num + ch - '0';
|
|
|
|
}
|
|
|
|
ungetchar(ch);
|
|
|
|
return num;
|
|
|
|
}
|
|
|
|
|
|
|
|
int get_escaped_char() {
|
|
|
|
int ch = getchar();
|
|
|
|
if (ch == 'n') {
|
|
|
|
ch = '\n';
|
|
|
|
} else if (ch == 't') {
|
|
|
|
ch = '\t';
|
|
|
|
} else if (ch == 'r') {
|
|
|
|
ch = '\r';
|
|
|
|
} else if (ch == '0') {
|
|
|
|
ch = '\0';
|
|
|
|
} else if (ch == '\\') {
|
|
|
|
ch = '\\';
|
|
|
|
} else if (ch == '\'') {
|
|
|
|
ch = '\'';
|
|
|
|
} else if (ch == '\"') {
|
|
|
|
ch = '\"';
|
|
|
|
} else {
|
|
|
|
eprintf("unexpected escaped character: %c\n", ch);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return ch;
|
|
|
|
}
|
|
|
|
|
2024-11-16 00:24:55 +00:00
|
|
|
int streq(const char* s1, const char* s2) {
|
|
|
|
while (*s1 && *s2 && *s1 == *s2) {
|
|
|
|
s1++;
|
|
|
|
s2++;
|
|
|
|
}
|
|
|
|
return *s1 == *s2;
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
|
|
|
|
char string_table[65536];
|
|
|
|
int string_offset;
|
|
|
|
int string_lut[4096];
|
|
|
|
int string_lut_size;
|
|
|
|
int parse_string() {
|
|
|
|
int offset = string_offset;
|
2024-11-15 17:12:39 +00:00
|
|
|
int ch;
|
2024-11-16 00:39:45 +00:00
|
|
|
while ((ch = getchar()) != '"') {
|
|
|
|
if (ch == -1 || ch == '\n') {
|
|
|
|
eprintf("expecting '\"'\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
if (ch == '\\') {
|
|
|
|
ch = get_escaped_char();
|
|
|
|
}
|
2024-11-15 17:12:39 +00:00
|
|
|
string_table[string_offset++] = ch;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-15 17:12:39 +00:00
|
|
|
string_table[string_offset++] = 0;
|
2024-11-15 13:27:39 +00:00
|
|
|
string_lut[string_lut_size] = offset;
|
|
|
|
return string_lut_size++;
|
|
|
|
}
|
|
|
|
|
2024-11-29 03:16:58 +00:00
|
|
|
void rewind_string(int new_data) {
|
|
|
|
string_offset = string_lut[token_data];
|
|
|
|
token_data = new_data;
|
|
|
|
--string_lut_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dedup_string() {
|
|
|
|
int last_string = string_lut_size - 1;
|
|
|
|
char* latest = string_table + string_lut[last_string];
|
|
|
|
for (int i = 0; i < last_string; i++) {
|
|
|
|
char* candidate = string_table + string_lut[i];
|
|
|
|
if (streq(candidate, latest)) {
|
|
|
|
rewind_string(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
char id_table[65536];
|
|
|
|
int id_offset;
|
|
|
|
int id_lut[4096];
|
|
|
|
int id_lut_size;
|
|
|
|
int parse_id(int ch) {
|
|
|
|
int offset = id_offset;
|
2024-11-15 17:12:39 +00:00
|
|
|
id_table[id_offset++] = ch;
|
2024-11-16 00:39:45 +00:00
|
|
|
while (is_id_cont(ch = getchar())) {
|
2024-11-15 17:12:39 +00:00
|
|
|
id_table[id_offset++] = ch;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
ungetchar(ch);
|
2024-11-15 17:12:39 +00:00
|
|
|
id_table[id_offset++] = 0;
|
2024-11-15 13:27:39 +00:00
|
|
|
id_lut[id_lut_size] = offset;
|
|
|
|
return id_lut_size++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void rewind_id(int new_data) {
|
|
|
|
id_offset = id_lut[token_data];
|
|
|
|
token_data = new_data;
|
|
|
|
--id_lut_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
void dedup_id() {
|
2024-11-16 01:34:56 +00:00
|
|
|
int last_id = id_lut_size - 1;
|
|
|
|
char* latest = id_table + id_lut[last_id];
|
|
|
|
for (int i = 0; i < last_id; i++) {
|
|
|
|
char* candidate = id_table + id_lut[i];
|
2024-11-16 00:24:55 +00:00
|
|
|
if (streq(candidate, latest)) {
|
2024-11-15 13:27:39 +00:00
|
|
|
rewind_id(i);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_id_like(int ch) {
|
|
|
|
token_type = TOKEN_ID;
|
|
|
|
token_data = parse_id(ch);
|
2024-11-16 01:34:56 +00:00
|
|
|
char* id = id_table + id_lut[token_data];
|
2024-11-16 00:24:55 +00:00
|
|
|
if (streq(id, "int")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_INT;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "if")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_IF;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "else")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_ELSE;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "while")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_WHILE;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "break")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_BREAK;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "continue")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_CONTINUE;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "return")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_RETURN;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "void")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_VOID;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "const")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_CONST;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "char")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_CHAR;
|
2024-11-16 00:24:55 +00:00
|
|
|
} else if (streq(id, "for")) {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_FOR;
|
2024-11-17 02:52:27 +00:00
|
|
|
} else if (streq(id, "do")) {
|
|
|
|
token_type = TOKEN_DO;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
if (token_type != TOKEN_ID) {
|
|
|
|
rewind_id(0);
|
|
|
|
} else {
|
|
|
|
dedup_id();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void unget_token() {
|
|
|
|
token_state = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void next_token() {
|
|
|
|
if (token_state) {
|
|
|
|
token_state = 0;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int ch = getchar();
|
|
|
|
while (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n') {
|
|
|
|
ch = getchar();
|
|
|
|
}
|
|
|
|
if (ch == -1) {
|
|
|
|
token_type = TOKEN_EOF;
|
|
|
|
} else if (ch == '(') {
|
|
|
|
token_type = TOKEN_PAREN_LEFT;
|
|
|
|
} else if (ch == ')') {
|
|
|
|
token_type = TOKEN_PAREN_RIGHT;
|
|
|
|
} else if (ch == '[') {
|
|
|
|
token_type = TOKEN_BRACKET_LEFT;
|
|
|
|
} else if (ch == ']') {
|
|
|
|
token_type = TOKEN_BRACKET_RIGHT;
|
|
|
|
} else if (ch == '{') {
|
|
|
|
token_type = TOKEN_BRACE_LEFT;
|
|
|
|
} else if (ch == '}') {
|
|
|
|
token_type = TOKEN_BRACE_RIGHT;
|
|
|
|
} else if (ch == '+') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '+') {
|
|
|
|
token_type = TOKEN_INC;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_ADD;
|
|
|
|
}
|
|
|
|
} else if (ch == '-') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '-') {
|
|
|
|
token_type = TOKEN_DEC;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_MINUS;
|
|
|
|
}
|
|
|
|
} else if (ch == '*') {
|
|
|
|
token_type = TOKEN_STAR;
|
|
|
|
} else if (ch == '/') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '/') {
|
2024-11-17 02:52:27 +00:00
|
|
|
do ch = getchar(); while (ch != -1 && ch != '\n');
|
2024-11-15 13:27:39 +00:00
|
|
|
next_token();
|
|
|
|
return;
|
|
|
|
} else if (ch2 == '*') {
|
|
|
|
while (1) {
|
|
|
|
ch = getchar();
|
2024-11-17 02:29:04 +00:00
|
|
|
if (ch == -1) {
|
|
|
|
eprintf("expecting '*/'\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
if (ch == '*') {
|
|
|
|
ch = getchar();
|
|
|
|
if (ch == '/') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next_token();
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_DIV;
|
|
|
|
}
|
|
|
|
} else if (ch == '%') {
|
|
|
|
token_type = TOKEN_REM;
|
|
|
|
} else if (ch == ';') {
|
|
|
|
token_type = TOKEN_SEMICOLON;
|
|
|
|
} else if (ch == ',') {
|
|
|
|
token_type = TOKEN_COMMA;
|
|
|
|
} else if (ch == '<') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '=') {
|
|
|
|
token_type = TOKEN_LE;
|
|
|
|
} else if (ch2 == '<') {
|
|
|
|
token_type = TOKEN_LSHIFT;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_LT;
|
|
|
|
}
|
|
|
|
} else if (ch == '>') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '=') {
|
|
|
|
token_type = TOKEN_GE;
|
|
|
|
} else if (ch2 == '>') {
|
|
|
|
token_type = TOKEN_RSHIFT;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_GT;
|
|
|
|
}
|
|
|
|
} else if (ch == '=') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '=') {
|
|
|
|
token_type = TOKEN_EQ;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_ASSIGN;
|
|
|
|
}
|
|
|
|
} else if (ch == '!') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '=') {
|
|
|
|
token_type = TOKEN_NE;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_NOT;
|
|
|
|
}
|
|
|
|
} else if (ch == '&') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '&') {
|
|
|
|
token_type = TOKEN_LAND;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_AND;
|
|
|
|
}
|
|
|
|
} else if (ch == '|') {
|
|
|
|
int ch2 = getchar();
|
|
|
|
if (ch2 == '|') {
|
|
|
|
token_type = TOKEN_LOR;
|
|
|
|
} else {
|
|
|
|
ungetchar(ch2);
|
|
|
|
token_type = TOKEN_OR;
|
|
|
|
}
|
|
|
|
} else if (ch == '^') {
|
|
|
|
token_type = TOKEN_XOR;
|
|
|
|
} else if (ch == '~') {
|
|
|
|
token_type = TOKEN_COMPL;
|
|
|
|
} else if (ch == '\'') {
|
|
|
|
token_type = TOKEN_NUMBER;
|
|
|
|
token_data = getchar();
|
|
|
|
if (token_data == '\\') {
|
|
|
|
token_data = get_escaped_char();
|
|
|
|
}
|
|
|
|
if (getchar() != '\'') {
|
|
|
|
eprintf("expecting '\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else if (ch == '"') {
|
|
|
|
token_type = TOKEN_STRING;
|
|
|
|
token_data = parse_string();
|
2024-11-29 03:16:58 +00:00
|
|
|
dedup_string();
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (ch == '.') {
|
2024-11-29 08:00:22 +00:00
|
|
|
token_type = 0;
|
|
|
|
if (getchar() == '.') {
|
|
|
|
if (getchar() == '.') {
|
2024-11-15 13:27:39 +00:00
|
|
|
token_type = TOKEN_ELLIPSIS;
|
|
|
|
}
|
2024-11-29 08:00:22 +00:00
|
|
|
}
|
|
|
|
if (token_type != TOKEN_ELLIPSIS) {
|
|
|
|
eprintf("expecting '...'\n");
|
2024-11-15 13:27:39 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
} else if (is_digit(ch)) {
|
|
|
|
token_type = TOKEN_NUMBER;
|
|
|
|
token_data = parse_int(ch);
|
|
|
|
} else if (is_id_start(ch)) {
|
|
|
|
parse_id_like(ch);
|
|
|
|
} else {
|
|
|
|
eprintf("unexpected character: %c(%d)\n", ch, ch);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
eprintf("token: %d\n", token_type);
|
|
|
|
if (token_type == TOKEN_ID) {
|
2024-11-16 01:34:56 +00:00
|
|
|
const char* name = id_table + id_lut[token_data];
|
2024-11-15 13:27:39 +00:00
|
|
|
eprintf(" id: %s\n", name);
|
|
|
|
} else if (token_type == TOKEN_NUMBER) {
|
|
|
|
eprintf(" number: %d\n", token_data);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void expect_token(int expected_type) {
|
|
|
|
next_token();
|
|
|
|
if (token_type != expected_type) {
|
|
|
|
eprintf("unexpected token: %d, should be %d\n", token_type, expected_type);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-17 09:01:18 +00:00
|
|
|
void ignore_const() {
|
2024-11-15 13:27:39 +00:00
|
|
|
if (token_type == TOKEN_CONST) {
|
|
|
|
next_token();
|
|
|
|
}
|
2024-11-17 09:01:18 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int parse_type() {
|
|
|
|
ignore_const();
|
|
|
|
if (token_type == TOKEN_INT || token_type == TOKEN_CHAR || token_type == TOKEN_VOID) {
|
|
|
|
int type = token_type & ~TYPE_TOKEN_MASK;
|
2024-11-15 13:27:39 +00:00
|
|
|
next_token();
|
2024-11-17 09:01:18 +00:00
|
|
|
ignore_const();
|
2024-11-15 13:27:39 +00:00
|
|
|
if (token_type == TOKEN_STAR) {
|
2024-11-30 01:40:52 +00:00
|
|
|
next_token();
|
2024-11-17 09:01:18 +00:00
|
|
|
ignore_const();
|
2024-11-30 01:40:52 +00:00
|
|
|
type = type | TYPE_PTR_MASK;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
unget_token();
|
2024-11-17 09:01:18 +00:00
|
|
|
return type;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-30 01:40:52 +00:00
|
|
|
return -1;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// asm
|
|
|
|
|
|
|
|
int local_table[4096]; // id -> local id
|
2024-11-29 01:49:57 +00:00
|
|
|
int next_local_id = 1;
|
|
|
|
int max_local_id = 1;
|
2024-11-15 13:27:39 +00:00
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
const int MARKER_TEMP = 0;
|
|
|
|
const int MARKER_SCALAR = 1;
|
|
|
|
const int MARKER_ARRAY = 2;
|
2024-11-20 15:44:42 +00:00
|
|
|
const int MARKER_FUNCTION = 3;
|
2024-11-15 13:27:39 +00:00
|
|
|
|
|
|
|
int local_marker[4096];
|
|
|
|
int global_marker[4096];
|
2024-11-15 17:12:39 +00:00
|
|
|
int local_type[4096];
|
|
|
|
int global_type[4096];
|
2024-11-21 12:23:11 +00:00
|
|
|
|
|
|
|
int reg_type[4096];
|
|
|
|
int next_reg_id = 18;
|
|
|
|
int max_reg_id = 18;
|
2024-11-16 14:28:00 +00:00
|
|
|
int indirection[4096];
|
2024-11-21 12:23:11 +00:00
|
|
|
int overflow[4096];
|
|
|
|
|
2024-11-29 08:00:22 +00:00
|
|
|
int const_table[4096]; // id -> value
|
|
|
|
int is_const[4096];
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
const int REG_ZERO = 0;
|
|
|
|
const int REG_RA = 1;
|
|
|
|
const int REG_SP = 2;
|
|
|
|
const int REG_GP = 3;
|
|
|
|
const int REG_TP = 4;
|
|
|
|
const int REG_T0 = 5;
|
|
|
|
const int REG_T1 = 6;
|
|
|
|
const int REG_T2 = 7;
|
|
|
|
const int REG_FP = 8;
|
|
|
|
const int REG_S1 = 9;
|
|
|
|
const int REG_A0 = 10;
|
|
|
|
const int REG_A1 = 11;
|
|
|
|
const int REG_A2 = 12;
|
|
|
|
const int REG_A3 = 13;
|
|
|
|
const int REG_A4 = 14;
|
|
|
|
const int REG_A5 = 15;
|
|
|
|
const int REG_A6 = 16;
|
|
|
|
const int REG_A7 = 17;
|
|
|
|
const int REG_S2 = 18;
|
|
|
|
const int REG_S3 = 19;
|
|
|
|
const int REG_S4 = 20;
|
|
|
|
const int REG_S5 = 21;
|
|
|
|
const int REG_S6 = 22;
|
|
|
|
const int REG_S7 = 23;
|
|
|
|
const int REG_S8 = 24;
|
|
|
|
const int REG_S9 = 25;
|
|
|
|
const int REG_S10 = 26;
|
|
|
|
const int REG_S11 = 27;
|
|
|
|
const int REG_T3 = 28;
|
|
|
|
const int REG_T4 = 29;
|
|
|
|
const int REG_T5 = 30;
|
|
|
|
const int REG_T6 = 31;
|
|
|
|
|
|
|
|
void reset_reg() {
|
|
|
|
next_reg_id = REG_S2;
|
|
|
|
for (int i = 0; i < 4096; ++i) {
|
|
|
|
reg_type[i] = TYPE_VOID;
|
|
|
|
indirection[i] = 0;
|
|
|
|
overflow[i] = 0;
|
|
|
|
}
|
2024-11-29 03:16:58 +00:00
|
|
|
reg_type[REG_ZERO] = TYPE_INT;
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* reg_name(int reg) {
|
|
|
|
if (reg == 0) return "zero";
|
|
|
|
if (reg == 1) return "ra";
|
|
|
|
if (reg == 2) return "sp";
|
|
|
|
if (reg == 3) return "gp";
|
|
|
|
if (reg == 4) return "tp";
|
|
|
|
if (reg == 5) return "t0";
|
|
|
|
if (reg == 6) return "t1";
|
|
|
|
if (reg == 7) return "t2";
|
|
|
|
if (reg == 8) return "fp";
|
|
|
|
// reserved begin
|
|
|
|
if (reg == 9) return "s1";
|
|
|
|
if (reg == 10) return "a0";
|
|
|
|
if (reg == 11) return "a1";
|
|
|
|
if (reg == 12) return "a2";
|
|
|
|
if (reg == 13) return "a3";
|
|
|
|
if (reg == 14) return "a4";
|
|
|
|
if (reg == 15) return "a5";
|
|
|
|
if (reg == 16) return "a6";
|
|
|
|
if (reg == 17) return "a7";
|
|
|
|
// allocation begin
|
|
|
|
if (reg == 18) return "s2";
|
|
|
|
if (reg == 19) return "s3";
|
|
|
|
if (reg == 20) return "s4";
|
|
|
|
if (reg == 21) return "s5";
|
|
|
|
if (reg == 22) return "s6";
|
|
|
|
if (reg == 23) return "s7";
|
|
|
|
if (reg == 24) return "s8";
|
|
|
|
if (reg == 25) return "s9";
|
|
|
|
if (reg == 26) return "s10";
|
|
|
|
if (reg == 27) return "s11";
|
|
|
|
if (reg == 28) return "t3";
|
|
|
|
if (reg == 29) return "t4";
|
|
|
|
if (reg == 30) return "t5";
|
|
|
|
if (reg == 31) return "t6";
|
2024-11-29 02:54:07 +00:00
|
|
|
// overflow begin
|
2024-11-21 12:23:11 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int is_overflow(int reg) {
|
2024-11-29 02:54:07 +00:00
|
|
|
return reg > REG_T6;
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
|
|
|
|
void reset_local() {
|
2024-11-29 01:49:57 +00:00
|
|
|
next_local_id = 1;
|
|
|
|
max_local_id = 1;
|
|
|
|
max_reg_id = REG_S2;
|
2024-11-15 13:27:39 +00:00
|
|
|
for (int i = 0; i < 4096; ++i) {
|
|
|
|
local_table[i] = 0;
|
2024-11-15 17:12:39 +00:00
|
|
|
local_marker[i] = MARKER_TEMP;
|
|
|
|
local_type[i] = TYPE_VOID;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
reset_reg();
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void reset_temp() {
|
2024-11-29 01:49:57 +00:00
|
|
|
while (next_local_id > 1 && local_marker[next_local_id - 1] == MARKER_TEMP) {
|
2024-11-15 13:27:39 +00:00
|
|
|
--next_local_id;
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
reset_reg();
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
int next_local_slot(int type) {
|
|
|
|
int slot = next_local_id++;
|
|
|
|
local_type[slot] = type;
|
2024-11-15 13:27:39 +00:00
|
|
|
if (next_local_id > max_local_id) {
|
|
|
|
max_local_id = next_local_id;
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return slot;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
int declare_local(int id, int type) {
|
2024-11-15 13:27:39 +00:00
|
|
|
if (local_table[id] != 0) return local_table[id];
|
2024-11-21 12:23:11 +00:00
|
|
|
int slot = next_local_slot(type);
|
|
|
|
local_marker[slot] = MARKER_SCALAR;
|
|
|
|
return local_table[id] = slot;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
int declare_local_array(int id, int type, int size) {
|
2024-11-15 13:27:39 +00:00
|
|
|
if (local_table[id] != 0) return local_table[id];
|
2024-11-29 01:49:57 +00:00
|
|
|
int slot = next_local_slot(type);
|
|
|
|
local_marker[slot] = MARKER_ARRAY;
|
|
|
|
for (int i = 1; i < size; ++i) local_marker[next_local_slot(type)] = MARKER_ARRAY;
|
2024-11-21 12:23:11 +00:00
|
|
|
return local_table[id] = slot;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
void declare_global(int id, int marker, int type) {
|
2024-11-15 13:27:39 +00:00
|
|
|
global_marker[id] = marker;
|
2024-11-15 17:12:39 +00:00
|
|
|
global_type[id] = type;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
int next_reg(int type) {
|
|
|
|
int reg = next_reg_id++;
|
|
|
|
if (is_overflow(reg)) {
|
|
|
|
int slot = next_local_slot(type);
|
|
|
|
local_marker[slot] = MARKER_TEMP;
|
|
|
|
overflow[reg] = slot;
|
|
|
|
}
|
|
|
|
reg_type[reg] = type;
|
|
|
|
if (next_reg_id > max_reg_id) {
|
|
|
|
max_reg_id = next_reg_id;
|
|
|
|
}
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// prolog & epilog helpers
|
|
|
|
|
2024-11-15 14:37:36 +00:00
|
|
|
int check_itype_immediate(int value) {
|
|
|
|
return value >= -2048 && value <= 2047;
|
|
|
|
}
|
|
|
|
|
|
|
|
void asm_ld(const char* rd, int imm, const char* rs) {
|
|
|
|
if (check_itype_immediate(imm)) {
|
|
|
|
printf(" ld %s, %d(%s)\n", rd, imm, rs);
|
|
|
|
} else {
|
|
|
|
printf(" li t0, %d\n", imm);
|
|
|
|
printf(" add t0, %s, t0\n", rs);
|
|
|
|
printf(" ld %s, 0(t0)\n", rd);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void asm_sd(const char* rs1, int imm, const char* rs2) {
|
|
|
|
if (check_itype_immediate(imm)) {
|
|
|
|
printf(" sd %s, %d(%s)\n", rs1, imm, rs2);
|
|
|
|
} else {
|
|
|
|
printf(" li t0, %d\n", imm);
|
|
|
|
printf(" add t0, %s, t0\n", rs2);
|
|
|
|
printf(" sd %s, 0(t0)\n", rs1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void asm_addi(const char* rd, const char* rs, int imm) {
|
|
|
|
if (check_itype_immediate(imm)) {
|
|
|
|
printf(" addi %s, %s, %d\n", rd, rs, imm);
|
|
|
|
} else {
|
|
|
|
printf(" li t0, %d\n", imm);
|
|
|
|
printf(" add %s, %s, t0\n", rd, rs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
// assembly helpers
|
|
|
|
|
2024-11-29 01:49:57 +00:00
|
|
|
const char* load_op_of_type(int type) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (type & TYPE_PTR_MASK) {
|
|
|
|
return "ld";
|
|
|
|
} else if (type == TYPE_CHAR) {
|
|
|
|
return "lb";
|
|
|
|
} else { // int
|
|
|
|
return "lw";
|
2024-11-17 13:33:57 +00:00
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
const char* store_op_of_type(int type) {
|
|
|
|
if (type & TYPE_PTR_MASK) {
|
|
|
|
return "sd";
|
|
|
|
} else if (type == TYPE_CHAR) {
|
|
|
|
return "sb";
|
|
|
|
} else { // int
|
|
|
|
return "sw";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-29 16:31:33 +00:00
|
|
|
// address loaders
|
2024-11-21 12:23:11 +00:00
|
|
|
// rd must be one of t0, t1, t2
|
2024-11-29 16:31:33 +00:00
|
|
|
void load_local_address(int rd, int slot_id) {
|
|
|
|
asm_addi(reg_name(rd), "sp", slot_id * 8 - 8);
|
|
|
|
}
|
|
|
|
|
|
|
|
// load a non-trivial register into trivial one
|
|
|
|
void load(int rd, int rs) {
|
|
|
|
const char* op = load_op_of_type(reg_type[rs]);
|
2024-11-21 12:23:11 +00:00
|
|
|
const char* rd_name = reg_name(rd);
|
2024-11-29 16:31:33 +00:00
|
|
|
if (is_overflow(rs)) {
|
|
|
|
load_local_address(rd, overflow[rs]);
|
|
|
|
if (indirection[rs]) {
|
2024-11-21 12:23:11 +00:00
|
|
|
printf(" ld %s, 0(%s)\n", rd_name, rd_name);
|
2024-11-15 14:37:36 +00:00
|
|
|
}
|
2024-11-29 16:31:33 +00:00
|
|
|
rs = rd;
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
2024-11-29 16:31:33 +00:00
|
|
|
printf(" %s %s, 0(%s) # load non-trivial register\n", op, rd_name, reg_name(rs));
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 16:31:33 +00:00
|
|
|
// store a trivial register into a non-trivial one
|
|
|
|
void store(const char* rs, int reg) {
|
2024-11-29 01:49:57 +00:00
|
|
|
const char* op = store_op_of_type(reg_type[reg]);
|
2024-11-21 12:23:11 +00:00
|
|
|
if (is_overflow(reg)) {
|
|
|
|
load_local_address(REG_T2, overflow[reg]);
|
|
|
|
if (indirection[reg]) {
|
|
|
|
printf(" ld t2, 0(t2)\n");
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
reg = REG_T2;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-29 16:31:33 +00:00
|
|
|
printf(" %s %s, 0(%s) # store non-trivial register\n", op, rs, reg_name(reg));
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
int is_nontrivial(int reg) {
|
|
|
|
return is_overflow(reg) || indirection[reg];
|
|
|
|
}
|
|
|
|
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* trivialize(int rs, int t) {
|
|
|
|
if (is_nontrivial(rs)) {
|
|
|
|
load(t, rs);
|
|
|
|
return reg_name(t);
|
|
|
|
}
|
|
|
|
return reg_name(rs);
|
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
void _asm_r(const char* op, int rd, int rs1) {
|
|
|
|
const char* rd_name = reg_name(rd);
|
|
|
|
if (is_nontrivial(rd)) rd_name = "t0";
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
|
|
|
printf(" %s %s, %s\n", op, rd_name, rs1_name);
|
|
|
|
if (is_nontrivial(rd)) {
|
|
|
|
store("t0", rd);
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
2024-11-29 16:31:33 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void asm_mv(int rd, int rs1) {
|
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
2024-11-21 12:23:11 +00:00
|
|
|
if (is_nontrivial(rd)) {
|
2024-11-29 16:31:33 +00:00
|
|
|
store(rs1_name, rd);
|
|
|
|
} else {
|
|
|
|
const char* rd_name = reg_name(rd);
|
|
|
|
if (!streq(rd_name, rs1_name))
|
|
|
|
printf(" mv %s, %s\n", rd_name, rs1_name);
|
2024-11-16 01:34:56 +00:00
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
void _asm_rr(const char* op, int rd, int rs1, int rs2) {
|
|
|
|
const char* rd_name = reg_name(rd);
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
|
|
|
const char* rs2_name = trivialize(rs2, REG_T1);
|
2024-11-21 12:23:11 +00:00
|
|
|
if (is_nontrivial(rd)) rd_name = "t0";
|
|
|
|
printf(" %s %s, %s, %s\n", op, rd_name, rs1_name, rs2_name);
|
|
|
|
if (is_nontrivial(rd)) {
|
2024-11-29 16:31:33 +00:00
|
|
|
store("t0", rd);
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void _asm_ri(const char* op, int rd, int rs1, int imm) {
|
|
|
|
const char* rd_name = reg_name(rd);
|
|
|
|
if (is_nontrivial(rd)) rd_name = "t0";
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
2024-11-21 12:23:11 +00:00
|
|
|
printf(" %s %s, %s, %d\n", op, rd_name, rs1_name, imm);
|
|
|
|
if (is_nontrivial(rd)) {
|
2024-11-29 16:31:33 +00:00
|
|
|
store("t0", rd);
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-30 01:40:52 +00:00
|
|
|
void asm_branch(const char* op, int rs1, int label) {
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
2024-11-21 12:23:11 +00:00
|
|
|
printf(" %s %s, L%d\n", op, rs1_name, label);
|
|
|
|
}
|
|
|
|
|
2024-11-29 01:49:57 +00:00
|
|
|
void _asm_i(const char* op, int rd, const char* prefix1, const char* prefix2, int imm) {
|
|
|
|
const char* rd_name = reg_name(rd);
|
|
|
|
if (is_nontrivial(rd)) rd_name = "t0";
|
|
|
|
printf(" %s %s, %s%s%d\n", op, rd_name, prefix1, prefix2, imm);
|
|
|
|
if (is_nontrivial(rd)) {
|
2024-11-29 16:31:33 +00:00
|
|
|
store("t0", rd);
|
2024-11-29 01:49:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-29 03:16:58 +00:00
|
|
|
int is_not_reusable(int rs1, int expected_type) {
|
|
|
|
return indirection[rs1] || reg_type[rs1] != expected_type || rs1 == REG_ZERO;
|
|
|
|
}
|
|
|
|
|
2024-11-21 12:23:11 +00:00
|
|
|
int asm_r(int type, const char* op, int rs1) {
|
2024-11-29 01:49:57 +00:00
|
|
|
int rd = rs1;
|
2024-11-29 03:16:58 +00:00
|
|
|
if (is_not_reusable(rs1, type)) rd = next_reg(type);
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_r(op, rd, rs1);
|
|
|
|
return rd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int asm_rr(int type, const char* op, int rs1, int rs2) {
|
2024-11-29 01:49:57 +00:00
|
|
|
int rd = rs1;
|
2024-11-29 03:16:58 +00:00
|
|
|
if (is_not_reusable(rs1, type)) rd = rs2;
|
|
|
|
if (is_not_reusable(rs2, type)) rd = next_reg(type);
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_rr(op, rd, rs1, rs2);
|
|
|
|
return rd;
|
|
|
|
}
|
|
|
|
|
2024-11-29 01:49:57 +00:00
|
|
|
void store_into_local(int rs1, int slot) {
|
2024-11-29 16:31:33 +00:00
|
|
|
const char* rs1_name = trivialize(rs1, REG_T0);
|
2024-11-29 01:49:57 +00:00
|
|
|
load_local_address(REG_T2, slot);
|
|
|
|
printf(" %s %s, 0(t2)\n", store_op_of_type(local_type[slot]), rs1_name);
|
2024-11-15 14:37:36 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 01:49:57 +00:00
|
|
|
int materialize_address(int rd, int type, int marker) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (marker == MARKER_ARRAY) {
|
|
|
|
type = type | TYPE_PTR_MASK;
|
|
|
|
}
|
|
|
|
reg_type[rd] = type;
|
|
|
|
indirection[rd] = marker == MARKER_SCALAR;
|
|
|
|
return rd;
|
|
|
|
}
|
|
|
|
|
|
|
|
int lookup_from_slot(int slot) {
|
2024-11-29 16:31:33 +00:00
|
|
|
int rd = next_reg(TYPE_VOID_PTR);
|
|
|
|
if (is_nontrivial(rd)) {
|
2024-11-29 01:49:57 +00:00
|
|
|
load_local_address(REG_T0, slot);
|
2024-11-29 16:31:33 +00:00
|
|
|
asm_mv(rd, REG_T0);
|
2024-11-29 01:49:57 +00:00
|
|
|
} else {
|
2024-11-29 16:31:33 +00:00
|
|
|
load_local_address(rd, slot);
|
2024-11-29 01:49:57 +00:00
|
|
|
}
|
2024-11-29 16:31:33 +00:00
|
|
|
return materialize_address(rd, local_type[slot], local_marker[slot]);
|
2024-11-15 17:12:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-29 08:00:22 +00:00
|
|
|
int load_imm(int imm) {
|
|
|
|
if (imm == 0) return REG_ZERO;
|
|
|
|
int reg = next_reg(TYPE_INT);
|
|
|
|
_asm_i("li", reg, "", "", imm);
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
int lookup(int id) {
|
2024-11-29 08:00:22 +00:00
|
|
|
if (local_table[id]) {
|
|
|
|
return lookup_from_slot(local_table[id]);
|
|
|
|
}
|
|
|
|
if (is_const[id]) {
|
|
|
|
return load_imm(const_table[id]);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-16 01:34:56 +00:00
|
|
|
const char* name = id_table + id_lut[id];
|
2024-11-15 13:27:39 +00:00
|
|
|
if (global_marker[id]) {
|
2024-11-20 15:44:42 +00:00
|
|
|
if (global_marker[id] == MARKER_FUNCTION) {
|
|
|
|
eprintf("function name must not appear outside function call: %s\n", name);
|
|
|
|
exit(1);
|
2024-11-29 16:31:33 +00:00
|
|
|
}
|
|
|
|
int rd = next_reg(TYPE_VOID_PTR);
|
|
|
|
_asm_i("la", rd, name, " # id: ", id);
|
|
|
|
return materialize_address(rd, global_type[id], global_marker[id]);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
eprintf("unresolved identifier: %s\n", name);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
2024-11-18 01:48:28 +00:00
|
|
|
int asm_r_arith(const char* op, int rs1) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (reg_type[rs1] & TYPE_PTR_MASK) {
|
2024-11-18 01:48:28 +00:00
|
|
|
eprintf("pointer cannot be arithmetically operated by %s\n", op);
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_r(TYPE_INT, op, rs1);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-18 01:48:28 +00:00
|
|
|
int asm_rr_arith(const char* op, int rs1, int rs2) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (reg_type[rs1] & TYPE_PTR_MASK || reg_type[rs2] & TYPE_PTR_MASK) {
|
2024-11-18 01:48:28 +00:00
|
|
|
eprintf("pointer cannot be arithmetically operated by %s\n", op);
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_rr(TYPE_INT, op, rs1, rs2);
|
2024-11-18 01:48:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int asm_rr_cmp(const char* op, int rs1, int rs2) {
|
2024-11-21 12:23:11 +00:00
|
|
|
// since NULL is virtually 0, it is considered a valid example of a pointer comparing with an integer
|
|
|
|
return asm_rr(TYPE_INT, op, rs1, rs2);
|
2024-11-18 01:48:28 +00:00
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
void asm_beqz(int rs1, int label) {
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_branch("beqz", rs1, label);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void asm_bnez(int rs1, int label) {
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_branch("bnez", rs1, label);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void asm_j(int label) {
|
|
|
|
printf(" j L%d\n", label);
|
|
|
|
}
|
|
|
|
|
2024-11-29 16:31:33 +00:00
|
|
|
int next_label_id = 0;
|
|
|
|
int next_label() {
|
|
|
|
return next_label_id++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int asm_label(int label) {
|
|
|
|
printf("L%d:\n", label);
|
|
|
|
return label;
|
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
int break_label_stack[4096];
|
|
|
|
int cont_label_stack[4096];
|
|
|
|
int break_label_stack_size;
|
|
|
|
int cont_label_stack_size;
|
|
|
|
|
2024-11-30 01:40:52 +00:00
|
|
|
void asm_break() {
|
|
|
|
if (break_label_stack_size == 0) {
|
|
|
|
eprintf("break without loop\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
asm_j(break_label_stack[break_label_stack_size - 1]);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-30 01:40:52 +00:00
|
|
|
void asm_continue() {
|
|
|
|
if (cont_label_stack_size == 0) {
|
|
|
|
eprintf("continue without loop\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
asm_j(cont_label_stack[cont_label_stack_size - 1]);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void asm_push_label(int break_label, int cont_label) {
|
|
|
|
break_label_stack[break_label_stack_size++] = break_label;
|
|
|
|
cont_label_stack[cont_label_stack_size++] = cont_label;
|
|
|
|
}
|
|
|
|
|
|
|
|
void asm_pop_label() {
|
|
|
|
--break_label_stack_size;
|
|
|
|
--cont_label_stack_size;
|
|
|
|
}
|
|
|
|
|
2024-11-30 01:40:52 +00:00
|
|
|
int epilog_label;
|
|
|
|
|
|
|
|
void asm_return() {
|
|
|
|
asm_j(epilog_label);
|
|
|
|
}
|
|
|
|
|
2024-11-29 16:31:33 +00:00
|
|
|
int log_step_of(int type) {
|
|
|
|
return 2 * (type == TYPE_INT_PTR);
|
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
int step_of(int type) {
|
2024-11-29 16:31:33 +00:00
|
|
|
return 1 << log_step_of(type);
|
2024-11-15 17:12:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-16 01:34:56 +00:00
|
|
|
int asm_add(int lhs, int rhs) {
|
2024-11-21 12:23:11 +00:00
|
|
|
int type1 = reg_type[lhs] & TYPE_PTR_MASK;
|
|
|
|
int type2 = reg_type[rhs] & TYPE_PTR_MASK;
|
2024-11-16 01:34:56 +00:00
|
|
|
if (type1 != type2) {
|
|
|
|
int ptr;
|
|
|
|
int idx;
|
|
|
|
if (type1) {
|
|
|
|
ptr = lhs;
|
|
|
|
idx = rhs;
|
|
|
|
} else {
|
|
|
|
ptr = rhs;
|
|
|
|
idx = lhs;
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
int ptr_type = reg_type[ptr];
|
2024-11-17 13:33:57 +00:00
|
|
|
if (ptr_type == TYPE_VOID_PTR) {
|
|
|
|
eprintf("void pointer cannot be arithmetically operated\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
int offset = next_reg(TYPE_INT);
|
2024-11-29 16:31:33 +00:00
|
|
|
_asm_ri("slli", offset, idx, log_step_of(ptr_type));
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_rr(ptr_type, "add", ptr, offset);
|
2024-11-16 01:34:56 +00:00
|
|
|
}
|
|
|
|
if (type1 && type2) {
|
2024-11-18 01:48:28 +00:00
|
|
|
eprintf("operands of addition cannot be both pointers\n");
|
2024-11-16 01:34:56 +00:00
|
|
|
exit(1);
|
2024-11-15 17:12:39 +00:00
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_rr(TYPE_INT, "add", lhs, rhs);
|
2024-11-15 17:12:39 +00:00
|
|
|
}
|
|
|
|
|
2024-11-16 15:45:57 +00:00
|
|
|
int asm_sub(int lhs, int rhs) {
|
2024-11-21 12:23:11 +00:00
|
|
|
int lhs_type = reg_type[lhs];
|
|
|
|
int rhs_type = reg_type[rhs];
|
2024-11-17 13:33:57 +00:00
|
|
|
int type1 = lhs_type & TYPE_PTR_MASK;
|
|
|
|
int type2 = rhs_type & TYPE_PTR_MASK;
|
2024-11-16 15:45:57 +00:00
|
|
|
if (type1 && type2) {
|
2024-11-17 13:33:57 +00:00
|
|
|
if (lhs_type != rhs_type) {
|
|
|
|
eprintf("pointer type mismatch\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (lhs_type == TYPE_VOID_PTR) {
|
|
|
|
eprintf("void pointer cannot be arithmetically operated\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
int difference = asm_rr(TYPE_INT, "sub", lhs, rhs);
|
2024-11-29 16:31:33 +00:00
|
|
|
_asm_ri("slli", difference, difference, log_step_of(lhs_type));
|
2024-11-29 01:49:57 +00:00
|
|
|
return difference;
|
2024-11-16 15:45:57 +00:00
|
|
|
}
|
|
|
|
if (type1) {
|
2024-11-18 01:48:28 +00:00
|
|
|
int neg = asm_r_arith("neg", rhs);
|
2024-11-16 15:45:57 +00:00
|
|
|
return asm_add(lhs, neg);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_rr_arith("sub", lhs, rhs);
|
|
|
|
}
|
|
|
|
|
|
|
|
int dereference(int reg) {
|
|
|
|
if (indirection[reg]) {
|
|
|
|
load(reg, reg);
|
|
|
|
} else {
|
|
|
|
indirection[reg] = 1;
|
|
|
|
}
|
|
|
|
reg_type[reg] = reg_type[reg] & ~TYPE_PTR_MASK;
|
|
|
|
return reg;
|
|
|
|
}
|
|
|
|
|
|
|
|
int addressof(int reg) {
|
|
|
|
if (indirection[reg] && !(reg_type[reg] & TYPE_PTR_MASK)) {
|
|
|
|
reg_type[reg] = reg_type[reg] | TYPE_PTR_MASK;
|
|
|
|
indirection[reg] = 0;
|
|
|
|
} else {
|
|
|
|
printf("cannot take address of this expression");
|
|
|
|
}
|
|
|
|
return reg;
|
2024-11-16 15:45:57 +00:00
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
// parser
|
2024-11-29 16:31:33 +00:00
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
int parse_expr();
|
|
|
|
|
2024-11-20 15:44:42 +00:00
|
|
|
int parse_function_call(int id) {
|
|
|
|
const char* name = id_table + id_lut[id];
|
|
|
|
if (global_marker[id] != MARKER_FUNCTION) {
|
|
|
|
eprintf("not a function name: %s\n", name);
|
2024-11-15 13:27:39 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-17 13:33:57 +00:00
|
|
|
int arg = 0;
|
|
|
|
int args[8];
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_PAREN_RIGHT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
if (arg >= 8) {
|
|
|
|
eprintf("too many arguments\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
args[arg++] = parse_expr();
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_COMMA) {
|
|
|
|
// continue;
|
|
|
|
} else if (token_type == TOKEN_PAREN_RIGHT) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
eprintf("expecting ',' or ')'\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (int i = 0; i < arg; ++i) {
|
2024-11-21 12:23:11 +00:00
|
|
|
asm_mv(i + REG_A0, args[i]);
|
2024-11-17 13:33:57 +00:00
|
|
|
}
|
2024-11-29 02:54:07 +00:00
|
|
|
for (int i = REG_T3; i <= REG_T6; ++i) {
|
|
|
|
if (i < max_reg_id) {
|
|
|
|
asm_sd(reg_name(i), (REG_S2 - i) * 8 - 24, "fp");
|
|
|
|
}
|
|
|
|
}
|
2024-11-20 15:44:42 +00:00
|
|
|
printf(" call %s\n", name);
|
2024-11-29 02:54:07 +00:00
|
|
|
for (int i = REG_T3; i <= REG_T6; ++i) {
|
|
|
|
if (i < max_reg_id) {
|
|
|
|
asm_ld(reg_name(i), (REG_S2 - i) * 8 - 24, "fp");
|
|
|
|
}
|
|
|
|
}
|
2024-11-20 15:44:42 +00:00
|
|
|
int type = global_type[id];
|
2024-11-17 13:33:57 +00:00
|
|
|
if (type != TYPE_VOID) {
|
2024-11-29 01:49:57 +00:00
|
|
|
int rd = next_reg(type);
|
|
|
|
asm_mv(rd, REG_A0);
|
|
|
|
return rd;
|
2024-11-17 13:33:57 +00:00
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2024-11-20 15:44:42 +00:00
|
|
|
int parse_primary_expr() {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_EOF) {
|
|
|
|
exit(1);
|
|
|
|
} else if (token_type == TOKEN_NUMBER) {
|
2024-11-29 08:00:22 +00:00
|
|
|
return load_imm(token_data);
|
2024-11-20 15:44:42 +00:00
|
|
|
} else if (token_type == TOKEN_ID) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_PAREN_LEFT) {
|
|
|
|
return parse_function_call(token_data);
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
return lookup(token_data);
|
|
|
|
} else if (token_type == TOKEN_STRING) {
|
2024-11-29 01:49:57 +00:00
|
|
|
int reg = next_reg(TYPE_CHAR_PTR);
|
|
|
|
_asm_i("la", reg, ".LC", "", token_data);
|
|
|
|
return reg;
|
2024-11-20 15:44:42 +00:00
|
|
|
} else if (token_type == TOKEN_PAREN_LEFT) {
|
|
|
|
int reg = parse_expr();
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
return reg;
|
|
|
|
} else {
|
|
|
|
eprintf("unexpected token in primary expression: %d\n", token_type);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
int parse_postfix_expr() {
|
|
|
|
int lhs = parse_primary_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_INC) {
|
2024-11-21 12:23:11 +00:00
|
|
|
int type = reg_type[lhs];
|
2024-11-15 17:12:39 +00:00
|
|
|
int reg = next_reg(type);
|
2024-11-21 12:23:11 +00:00
|
|
|
asm_mv(reg, lhs);
|
|
|
|
_asm_ri("addi", lhs, lhs, step_of(type));
|
2024-11-17 02:29:04 +00:00
|
|
|
lhs = reg;
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_DEC) {
|
2024-11-21 12:23:11 +00:00
|
|
|
int type = reg_type[lhs];
|
2024-11-15 17:12:39 +00:00
|
|
|
int reg = next_reg(type);
|
2024-11-21 12:23:11 +00:00
|
|
|
asm_mv(reg, lhs);
|
|
|
|
_asm_ri("addi", lhs, lhs, -step_of(type));
|
2024-11-17 02:29:04 +00:00
|
|
|
lhs = reg;
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_BRACKET_LEFT) {
|
|
|
|
int rhs = parse_expr();
|
|
|
|
expect_token(TOKEN_BRACKET_RIGHT);
|
2024-11-17 13:33:57 +00:00
|
|
|
lhs = dereference(asm_add(lhs, rhs));
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
2024-11-17 02:29:04 +00:00
|
|
|
break;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
}
|
2024-11-17 02:29:04 +00:00
|
|
|
return lhs;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int parse_prefix_expr() {
|
|
|
|
next_token();
|
2024-11-17 13:33:57 +00:00
|
|
|
if (token_type == TOKEN_AND) {
|
2024-11-15 17:12:39 +00:00
|
|
|
int reg = parse_postfix_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
int type = reg_type[reg];
|
2024-11-17 13:33:57 +00:00
|
|
|
if (type & TYPE_PTR_MASK) {
|
|
|
|
eprintf("cannot take address of a pointer\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return addressof(reg);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_STAR) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
int type = reg_type[reg];
|
2024-11-17 13:33:57 +00:00
|
|
|
if (!(type & TYPE_PTR_MASK)) {
|
|
|
|
eprintf("cannot dereference a non-pointer\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
if (type == TYPE_VOID_PTR) {
|
|
|
|
eprintf("cannot dereference void pointer\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
return dereference(reg);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_MINUS) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
return asm_r_arith("neg", reg);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_COMPL) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
return asm_r_arith("not", reg);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_NOT) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
return asm_r(TYPE_INT, "seqz", reg);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_INC) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_ri("addi", reg, reg, step_of(reg_type[reg]));
|
2024-11-15 13:27:39 +00:00
|
|
|
return reg;
|
|
|
|
} else if (token_type == TOKEN_DEC) {
|
|
|
|
int reg = parse_postfix_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_ri("addi", reg, reg, -step_of(reg_type[reg]));
|
2024-11-15 13:27:39 +00:00
|
|
|
return reg;
|
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
return parse_postfix_expr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_mul_expr() {
|
|
|
|
int lhs = parse_prefix_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_STAR) {
|
|
|
|
int rhs = parse_prefix_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("mul", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_DIV) {
|
|
|
|
int rhs = parse_prefix_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("div", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_REM) {
|
|
|
|
int rhs = parse_prefix_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("rem", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_add_expr() {
|
|
|
|
int lhs = parse_mul_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_ADD) {
|
|
|
|
int rhs = parse_mul_expr();
|
2024-11-16 01:34:56 +00:00
|
|
|
lhs = asm_add(lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_MINUS) {
|
|
|
|
int rhs = parse_mul_expr();
|
2024-11-16 15:45:57 +00:00
|
|
|
lhs = asm_sub(lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
2024-11-16 02:23:03 +00:00
|
|
|
int parse_shift_expr() {
|
2024-11-15 13:27:39 +00:00
|
|
|
int lhs = parse_add_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
2024-11-16 02:23:03 +00:00
|
|
|
if (token_type == TOKEN_LSHIFT) {
|
|
|
|
int rhs = parse_add_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("sll", lhs, rhs);
|
2024-11-16 02:23:03 +00:00
|
|
|
} else if (token_type == TOKEN_RSHIFT) {
|
2024-11-15 13:27:39 +00:00
|
|
|
int rhs = parse_add_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("sra", lhs, rhs);
|
2024-11-16 02:23:03 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_cmp_expr() {
|
|
|
|
int lhs = parse_shift_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_LT) {
|
|
|
|
int rhs = parse_shift_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_cmp("slt", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_GT) {
|
2024-11-16 02:23:03 +00:00
|
|
|
int rhs = parse_shift_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_cmp("sgt", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_LE) {
|
2024-11-16 02:23:03 +00:00
|
|
|
int rhs = parse_shift_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
int sgt = asm_rr_cmp("sgt", lhs, rhs);
|
2024-11-21 12:23:11 +00:00
|
|
|
lhs = asm_r(TYPE_INT, "seqz", sgt);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_GE) {
|
2024-11-16 02:23:03 +00:00
|
|
|
int rhs = parse_shift_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
int slt = asm_rr_cmp("slt", lhs, rhs);
|
2024-11-21 12:23:11 +00:00
|
|
|
lhs = asm_r(TYPE_INT, "seqz", slt);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_eq_expr() {
|
|
|
|
int lhs = parse_cmp_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_EQ) {
|
|
|
|
int rhs = parse_cmp_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
int xor0 = asm_rr_cmp("xor", lhs, rhs);
|
2024-11-21 12:23:11 +00:00
|
|
|
lhs = asm_r(TYPE_INT, "seqz", xor0);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_NE) {
|
|
|
|
int rhs = parse_cmp_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
int xor0 = asm_rr_cmp("xor", lhs, rhs);
|
2024-11-21 12:23:11 +00:00
|
|
|
lhs = asm_r(TYPE_INT, "snez", xor0);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_bitwise_and_expr() {
|
|
|
|
int lhs = parse_eq_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_AND) {
|
|
|
|
int rhs = parse_eq_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("and", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int parse_bitwise_xor_expr() {
|
|
|
|
int lhs = parse_bitwise_and_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_XOR) {
|
|
|
|
int rhs = parse_bitwise_and_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("xor", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_bitwise_or_expr() {
|
|
|
|
int lhs = parse_bitwise_xor_expr();
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_OR) {
|
|
|
|
int rhs = parse_bitwise_xor_expr();
|
2024-11-18 01:48:28 +00:00
|
|
|
lhs = asm_rr_arith("or", lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_logical_and_expr() {
|
|
|
|
int lhs = parse_bitwise_or_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
int logical = 0;
|
|
|
|
int label;
|
|
|
|
int result;
|
2024-11-15 13:27:39 +00:00
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_LAND) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (!logical) {
|
|
|
|
logical = 1;
|
|
|
|
label = next_label();
|
|
|
|
result = next_reg(TYPE_INT);
|
|
|
|
_asm_r("snez", result, lhs);
|
|
|
|
}
|
|
|
|
asm_beqz(result, label);
|
2024-11-15 13:27:39 +00:00
|
|
|
int rhs = parse_bitwise_or_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_r("snez", result, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
if (logical) {
|
2024-11-15 13:27:39 +00:00
|
|
|
asm_label(label);
|
2024-11-21 12:23:11 +00:00
|
|
|
return result;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_logical_or_expr() {
|
|
|
|
int lhs = parse_logical_and_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
int logical = 0;
|
|
|
|
int label;
|
|
|
|
int result;
|
2024-11-15 13:27:39 +00:00
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_LOR) {
|
2024-11-21 12:23:11 +00:00
|
|
|
if (!logical) {
|
|
|
|
logical = 1;
|
|
|
|
label = next_label();
|
|
|
|
result = next_reg(TYPE_INT);
|
|
|
|
_asm_r("snez", result, lhs);
|
|
|
|
}
|
|
|
|
asm_bnez(result, label);
|
2024-11-15 13:27:39 +00:00
|
|
|
int rhs = parse_logical_and_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
_asm_r("snez", result, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
if (logical) {
|
2024-11-15 13:27:39 +00:00
|
|
|
asm_label(label);
|
2024-11-21 12:23:11 +00:00
|
|
|
return result;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_assign_expr() {
|
|
|
|
int lhs = parse_logical_or_expr();
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_ASSIGN) {
|
|
|
|
int rhs = parse_assign_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
asm_mv(lhs, rhs);
|
2024-11-15 13:27:39 +00:00
|
|
|
return lhs;
|
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
return lhs;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int parse_expr() {
|
|
|
|
return parse_assign_expr();
|
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
void parse_local_variable(int type) {
|
2024-11-17 09:23:30 +00:00
|
|
|
if (type == TYPE_VOID) {
|
2024-11-29 02:54:07 +00:00
|
|
|
eprintf("variable cannot be of void type\n");
|
2024-11-17 09:23:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
expect_token(TOKEN_ID);
|
|
|
|
int id = token_data;
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_BRACKET_LEFT) {
|
2024-11-16 01:34:56 +00:00
|
|
|
if (type & TYPE_PTR_MASK) {
|
2024-11-29 01:49:57 +00:00
|
|
|
eprintf("array of pointers is not supported\n");
|
2024-11-16 01:34:56 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
expect_token(TOKEN_NUMBER);
|
|
|
|
int size = token_data;
|
|
|
|
expect_token(TOKEN_BRACKET_RIGHT);
|
2024-11-15 17:12:39 +00:00
|
|
|
declare_local_array(id, type, size);
|
2024-11-21 12:23:11 +00:00
|
|
|
return;
|
2024-11-29 16:31:33 +00:00
|
|
|
}
|
2024-11-21 12:23:11 +00:00
|
|
|
int slot = declare_local(id, type);
|
2024-11-15 13:27:39 +00:00
|
|
|
if (token_type == TOKEN_SEMICOLON) {
|
|
|
|
unget_token();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
expect_token(TOKEN_ASSIGN);
|
|
|
|
int reg = parse_expr();
|
2024-11-21 12:23:11 +00:00
|
|
|
if (type != reg_type[reg]) {
|
|
|
|
eprintf("type mismatch in assignment\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-29 01:49:57 +00:00
|
|
|
store_into_local(reg, slot);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void parse_stmt();
|
|
|
|
|
|
|
|
void parse_if() {
|
|
|
|
expect_token(TOKEN_PAREN_LEFT);
|
|
|
|
int cond = parse_expr();
|
|
|
|
int label1 = next_label();
|
|
|
|
int label2 = next_label();
|
|
|
|
asm_beqz(cond, label1);
|
|
|
|
reset_temp();
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
parse_stmt();
|
|
|
|
asm_j(label2);
|
|
|
|
asm_label(label1);
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_ELSE) {
|
|
|
|
parse_stmt();
|
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
}
|
|
|
|
asm_label(label2);
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_while() {
|
|
|
|
expect_token(TOKEN_PAREN_LEFT);
|
|
|
|
int break_label = next_label();
|
|
|
|
int cont_label = next_label();
|
|
|
|
asm_push_label(break_label, cont_label);
|
|
|
|
asm_label(cont_label);
|
|
|
|
int cond = parse_expr();
|
|
|
|
asm_beqz(cond, break_label);
|
|
|
|
reset_temp();
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
parse_stmt();
|
|
|
|
asm_j(cont_label);
|
|
|
|
asm_label(break_label);
|
|
|
|
asm_pop_label();
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_for() {
|
|
|
|
expect_token(TOKEN_PAREN_LEFT);
|
|
|
|
int cont_label = next_label();
|
|
|
|
int break_label = next_label();
|
|
|
|
int cond_label = next_label();
|
|
|
|
int body_label = next_label();
|
|
|
|
asm_push_label(break_label, cont_label);
|
|
|
|
parse_stmt(); // init
|
|
|
|
asm_label(cond_label);
|
|
|
|
int cond = parse_expr();
|
|
|
|
asm_beqz(cond, break_label);
|
|
|
|
asm_j(body_label);
|
|
|
|
reset_temp();
|
|
|
|
expect_token(TOKEN_SEMICOLON);
|
|
|
|
asm_label(cont_label);
|
|
|
|
parse_expr(); // update
|
|
|
|
reset_temp();
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
asm_j(cond_label);
|
|
|
|
asm_label(body_label);
|
|
|
|
parse_stmt(); // body
|
|
|
|
asm_j(cont_label);
|
|
|
|
asm_label(break_label);
|
|
|
|
asm_pop_label();
|
|
|
|
}
|
|
|
|
|
2024-11-17 02:52:27 +00:00
|
|
|
void parse_do_while() {
|
|
|
|
int cont_label = next_label();
|
|
|
|
int break_label = next_label();
|
|
|
|
asm_push_label(break_label, cont_label);
|
|
|
|
asm_label(cont_label);
|
|
|
|
parse_stmt(); // body
|
|
|
|
expect_token(TOKEN_WHILE);
|
|
|
|
expect_token(TOKEN_PAREN_LEFT);
|
|
|
|
int cond = parse_expr();
|
|
|
|
asm_bnez(cond, cont_label);
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
asm_label(break_label);
|
|
|
|
asm_pop_label();
|
|
|
|
}
|
|
|
|
|
2024-11-15 13:27:39 +00:00
|
|
|
void parse_stmt() {
|
|
|
|
next_token();
|
2024-11-15 17:12:39 +00:00
|
|
|
int decl_type;
|
2024-11-15 13:27:39 +00:00
|
|
|
if (token_type == TOKEN_IF) {
|
|
|
|
parse_if();
|
|
|
|
return;
|
|
|
|
} else if (token_type == TOKEN_WHILE) {
|
|
|
|
parse_while();
|
|
|
|
return;
|
|
|
|
} else if (token_type == TOKEN_FOR) {
|
|
|
|
parse_for();
|
|
|
|
return;
|
2024-11-17 02:52:27 +00:00
|
|
|
} else if (token_type == TOKEN_DO) {
|
|
|
|
parse_do_while();
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_BRACE_LEFT) {
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_BRACE_RIGHT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
parse_stmt();
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} else if (token_type == TOKEN_RETURN) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_SEMICOLON) {
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_return();
|
2024-11-15 13:27:39 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
unget_token();
|
2024-11-21 12:23:11 +00:00
|
|
|
int rs1 = parse_expr();
|
|
|
|
asm_mv(REG_A0, rs1);
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_return();
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_BREAK) {
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_break();
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_CONTINUE) {
|
2024-11-30 01:40:52 +00:00
|
|
|
asm_continue();
|
2024-11-15 13:27:39 +00:00
|
|
|
} else if (token_type == TOKEN_SEMICOLON) {
|
|
|
|
unget_token();
|
2024-11-15 17:12:39 +00:00
|
|
|
} else if ((decl_type = parse_type()) >= 0) {
|
|
|
|
parse_local_variable(decl_type);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
|
|
|
unget_token();
|
|
|
|
parse_expr();
|
|
|
|
}
|
|
|
|
expect_token(TOKEN_SEMICOLON);
|
|
|
|
reset_temp();
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_function(const char* name) {
|
|
|
|
reset_local();
|
|
|
|
int arg = 0;
|
|
|
|
int args[8];
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_PAREN_RIGHT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (token_type == TOKEN_ELLIPSIS) {
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
break;
|
|
|
|
}
|
2024-11-17 09:23:30 +00:00
|
|
|
if (token_type == TOKEN_VOID) {
|
|
|
|
if (arg != 0) {
|
|
|
|
eprintf("void should be the only argument\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
expect_token(TOKEN_PAREN_RIGHT);
|
|
|
|
break;
|
|
|
|
}
|
2024-11-17 02:39:58 +00:00
|
|
|
int arg_type = parse_type();
|
2024-11-17 09:23:30 +00:00
|
|
|
if (arg_type < 0 || arg_type == TYPE_VOID) {
|
2024-11-29 16:31:33 +00:00
|
|
|
eprintf("expecting a non-void argument type: %d\n", arg_type);
|
2024-11-17 09:23:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
expect_token(TOKEN_ID);
|
2024-11-17 02:39:58 +00:00
|
|
|
int arg_name = token_data;
|
2024-11-15 13:27:39 +00:00
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_BRACKET_LEFT) {
|
|
|
|
expect_token(TOKEN_BRACKET_RIGHT);
|
|
|
|
next_token();
|
2024-11-17 02:39:58 +00:00
|
|
|
if (arg_type & TYPE_PTR_MASK) {
|
2024-11-29 01:49:57 +00:00
|
|
|
eprintf("array of pointers is not supported\n");
|
2024-11-17 02:39:58 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
arg_type = arg_type | TYPE_PTR_MASK;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
2024-11-29 02:54:07 +00:00
|
|
|
if (arg >= 8) {
|
|
|
|
eprintf("too many arguments\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-17 02:39:58 +00:00
|
|
|
args[arg++] = declare_local(token_data, arg_type);
|
2024-11-15 13:27:39 +00:00
|
|
|
if (token_type == TOKEN_COMMA) {
|
|
|
|
// continue;
|
|
|
|
} else if (token_type == TOKEN_PAREN_RIGHT) {
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
eprintf("expecting ',' or ')'\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_SEMICOLON) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
expect_token(TOKEN_BRACE_LEFT);
|
|
|
|
printf(".text\n");
|
|
|
|
printf(".global %s\n", name);
|
|
|
|
printf("%s:\n", name);
|
|
|
|
int label = next_label();
|
|
|
|
int prolog_label = next_label();
|
|
|
|
epilog_label = next_label();
|
|
|
|
asm_j(prolog_label);
|
|
|
|
asm_label(label);
|
|
|
|
while (1) {
|
|
|
|
next_token();
|
|
|
|
if (token_type == TOKEN_BRACE_RIGHT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
unget_token();
|
|
|
|
parse_stmt();
|
|
|
|
}
|
2024-11-30 01:40:52 +00:00
|
|
|
if (streq(name, "main")) {
|
|
|
|
asm_mv(REG_A0, REG_ZERO);
|
|
|
|
}
|
|
|
|
asm_return();
|
2024-11-29 01:49:57 +00:00
|
|
|
int reg_used = max_reg_id - REG_S2;
|
2024-11-29 02:54:07 +00:00
|
|
|
if (reg_used > 14) reg_used = 14;
|
2024-11-29 01:49:57 +00:00
|
|
|
int frame_size = (max_local_id - 1 + reg_used + 2) * 8;
|
2024-11-29 02:54:07 +00:00
|
|
|
if (reg_used > 10) reg_used = 10;
|
2024-11-17 13:33:57 +00:00
|
|
|
if (frame_size % 16 != 0) {
|
|
|
|
frame_size = frame_size + 8;
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
// prolog
|
|
|
|
asm_label(prolog_label);
|
2024-11-17 13:33:57 +00:00
|
|
|
asm_addi("sp", "sp", -frame_size);
|
|
|
|
asm_sd("ra", frame_size - 8, "sp");
|
|
|
|
asm_sd("fp", frame_size - 16, "sp");
|
2024-11-29 01:49:57 +00:00
|
|
|
for (int i = 0; i < reg_used; ++i) {
|
|
|
|
int reg = REG_S2 + i;
|
|
|
|
asm_sd(reg_name(reg), frame_size - 24 - i * 8, "sp");
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
2024-11-17 13:33:57 +00:00
|
|
|
asm_addi("fp", "sp", frame_size);
|
2024-11-15 13:27:39 +00:00
|
|
|
for (int i = 0; i < arg; ++i) {
|
2024-11-29 01:49:57 +00:00
|
|
|
store_into_local(REG_A0 + i, args[i]);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
asm_j(label);
|
|
|
|
// epilog
|
|
|
|
asm_label(epilog_label);
|
2024-11-17 13:33:57 +00:00
|
|
|
asm_ld("ra", frame_size - 8, "sp");
|
2024-11-21 12:23:11 +00:00
|
|
|
asm_ld("fp", frame_size - 16, "sp");
|
2024-11-29 01:49:57 +00:00
|
|
|
for (int i = 0; i < reg_used; ++i) {
|
|
|
|
int reg = REG_S2 + i;
|
|
|
|
asm_ld(reg_name(reg), frame_size - 24 - i * 8, "sp");
|
2024-11-21 12:23:11 +00:00
|
|
|
}
|
2024-11-17 13:33:57 +00:00
|
|
|
asm_addi("sp", "sp", frame_size);
|
2024-11-15 13:27:39 +00:00
|
|
|
printf(" ret\n");
|
|
|
|
}
|
|
|
|
|
2024-11-15 17:12:39 +00:00
|
|
|
void parse_global_variable(int id, const char* name, int type) {
|
2024-11-17 09:23:30 +00:00
|
|
|
if (type == TYPE_VOID) {
|
2024-11-29 02:54:07 +00:00
|
|
|
eprintf("variable cannot be of void type\n");
|
2024-11-17 09:23:30 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
printf(".data\n");
|
|
|
|
printf(".globl %s\n", name);
|
|
|
|
printf(".align 5\n");
|
|
|
|
printf("%s:\n", name);
|
|
|
|
if (token_type == TOKEN_ASSIGN) {
|
|
|
|
expect_token(TOKEN_NUMBER);
|
|
|
|
printf(" .word %d\n", token_data);
|
|
|
|
} else if (token_type == TOKEN_BRACKET_LEFT) {
|
2024-11-29 01:49:57 +00:00
|
|
|
if (type & TYPE_PTR_MASK) {
|
|
|
|
eprintf("array of pointers is not supported\n");
|
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
expect_token(TOKEN_NUMBER);
|
|
|
|
int size = token_data;
|
|
|
|
expect_token(TOKEN_BRACKET_RIGHT);
|
2024-11-16 01:34:56 +00:00
|
|
|
int array_size = 4 * size;
|
|
|
|
if (type == TYPE_CHAR) {
|
|
|
|
array_size = size;
|
|
|
|
}
|
|
|
|
printf(" .zero %d\n", array_size);
|
2024-11-15 17:12:39 +00:00
|
|
|
declare_global(id, MARKER_ARRAY, type);
|
2024-11-15 13:27:39 +00:00
|
|
|
} else {
|
2024-11-16 01:34:56 +00:00
|
|
|
printf(" .zero %d\n", 4);
|
2024-11-15 13:27:39 +00:00
|
|
|
unget_token();
|
|
|
|
}
|
|
|
|
expect_token(TOKEN_SEMICOLON);
|
|
|
|
}
|
|
|
|
|
2024-11-17 09:01:18 +00:00
|
|
|
void parse_global_declaration() {
|
2024-11-29 08:00:22 +00:00
|
|
|
int is_const_int = 1;
|
|
|
|
if (token_type != TOKEN_CONST) {
|
|
|
|
is_const_int = 0;
|
|
|
|
}
|
2024-11-17 09:01:18 +00:00
|
|
|
int type = parse_type();
|
|
|
|
if (type < 0) {
|
2024-11-17 09:23:30 +00:00
|
|
|
eprintf("expecting type for global declaration\n");
|
2024-11-17 09:01:18 +00:00
|
|
|
exit(1);
|
|
|
|
}
|
2024-11-29 08:00:22 +00:00
|
|
|
if (type != TYPE_INT) {
|
|
|
|
is_const_int = 0;
|
|
|
|
}
|
2024-11-15 13:27:39 +00:00
|
|
|
expect_token(TOKEN_ID);
|
|
|
|
int id = token_data;
|
2024-11-16 01:34:56 +00:00
|
|
|
char* name = id_table + id_lut[id];
|
2024-11-15 13:27:39 +00:00
|
|
|
next_token();
|
2024-11-29 08:00:22 +00:00
|
|
|
if (is_const_int && token_type == TOKEN_ASSIGN) {
|
|
|
|
expect_token(TOKEN_NUMBER);
|
|
|
|
const_table[id] = token_data;
|
|
|
|
is_const[id] = 1;
|
|
|
|
expect_token(TOKEN_SEMICOLON);
|
|
|
|
} else if (token_type == TOKEN_PAREN_LEFT) {
|
2024-11-29 16:31:33 +00:00
|
|
|
declare_global(id, MARKER_FUNCTION, type);
|
2024-11-15 13:27:39 +00:00
|
|
|
parse_function(name);
|
|
|
|
} else {
|
2024-11-29 16:31:33 +00:00
|
|
|
declare_global(id, MARKER_SCALAR, type);
|
2024-11-15 17:12:39 +00:00
|
|
|
parse_global_variable(id, name, type);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void parse_top_level() {
|
|
|
|
next_token();
|
2024-11-17 09:01:18 +00:00
|
|
|
if (token_type == TOKEN_EOF)
|
2024-11-15 13:27:39 +00:00
|
|
|
return;
|
2024-11-17 09:01:18 +00:00
|
|
|
parse_global_declaration();
|
2024-11-16 00:39:45 +00:00
|
|
|
parse_top_level();
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void dump_string_table() {
|
|
|
|
printf(".data\n");
|
|
|
|
for (int i = 0; i < string_lut_size; ++i) {
|
|
|
|
printf(".LC%d: .string \"", i);
|
2024-11-29 16:31:33 +00:00
|
|
|
char* p = string_table + string_lut[i];
|
|
|
|
int ch;
|
|
|
|
while ((ch = *p++) != 0) {
|
2024-11-15 13:27:39 +00:00
|
|
|
if (ch == '\n') {
|
|
|
|
printf("\\n");
|
|
|
|
} else if (ch == '\t') {
|
|
|
|
printf("\\t");
|
|
|
|
} else if (ch == '\r') {
|
|
|
|
printf("\\r");
|
|
|
|
} else if (ch == '\0') {
|
|
|
|
printf("\\0");
|
|
|
|
} else if (ch == '\\') {
|
|
|
|
printf("\\\\");
|
|
|
|
} else if (ch == '\'') {
|
|
|
|
printf("\\'");
|
|
|
|
} else if (ch == '\"') {
|
|
|
|
printf("\\\"");
|
|
|
|
} else {
|
2024-11-16 00:24:55 +00:00
|
|
|
printf("%c", ch);
|
2024-11-15 13:27:39 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
printf("\"\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int main() {
|
2024-11-16 00:39:45 +00:00
|
|
|
parse_top_level();
|
2024-11-15 13:27:39 +00:00
|
|
|
dump_string_table();
|
|
|
|
return 0;
|
|
|
|
}
|