diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..b67fb1a --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "M2libc"] + path = M2libc + url = https://github.com/oriansj/M2libc.git diff --git a/M2libc b/M2libc new file mode 160000 index 0000000..818fcfb --- /dev/null +++ b/M2libc @@ -0,0 +1 @@ +Subproject commit 818fcfb333d73fbe0293b97b769718f0945e22dc diff --git a/cc.c b/cc.c index 254bc78..88feeaf 100644 --- a/cc.c +++ b/cc.c @@ -34,7 +34,7 @@ void preprocess(); void program(); void recursive_output(struct token_list* i, FILE* out); void output_tokens(struct token_list *i, FILE* out); -int numerate_string(char *a); +int strtoint(char *a); int main(int argc, char** argv) { @@ -45,6 +45,7 @@ int main(int argc, char** argv) FILE* destination_file = stdout; Architecture = KNIGHT_NATIVE; /* Assume Knight-native */ char* name; + char* hold; int i = 1; while(i <= argc) @@ -88,7 +89,13 @@ int main(int argc, char** argv) } else if(match(argv[i], "--max-string")) { - MAX_STRING = numerate_string(argv[i+1]); + hold = argv[i+1]; + if(NULL == hold) + { + fputs("--max-string requires a numeric argument\n", stderr); + exit(EXIT_FAILURE); + } + MAX_STRING = strtoint(hold); require(0 < MAX_STRING, "Not a valid string size\nAbort and fix your --max-string\n"); i = i + 2; } diff --git a/cc.h b/cc.h index 8166265..b448e07 100644 --- a/cc.h +++ b/cc.h @@ -37,9 +37,10 @@ #define ARMV7L 4 // CONSTANT AARCH64 5 #define AARCH64 5 +// CONSTANT RISCV64 6 +#define RISCV64 6 -void copy_string(char* target, char* source, int max); int in_set(int c, char* s); int match(char* a, char* b); void require(int bool, char* error); diff --git a/cc_core.c b/cc_core.c index 0d66803..c7a9088 100644 --- a/cc_core.c +++ b/cc_core.c @@ -21,14 +21,20 @@ #include "gcc_req.h" #include -char* numerate_number(int a); +/* Imported functions */ +char* int2str(int x, int base, int signed_p); void line_error_token(struct token_list *token) { - require(NULL != token, "EOF reached inside of line_error\n"); + if(NULL == token) + { + fputs("EOF reached inside of line_error\n", stderr); + fputs("problem at end of file\n", stderr); + return; + } fputs(token->filename, stderr); fputs(":", stderr); - fputs(numerate_number(token->linenumber), stderr); + fputs(int2str(token->linenumber, 10, TRUE), stderr); fputs(":", stderr); } diff --git a/cc_macro.c b/cc_macro.c index 57e6d48..2df09cf 100644 --- a/cc_macro.c +++ b/cc_macro.c @@ -1,4 +1,5 @@ /* Copyright (C) 2021 Sanne Wouda + * Copyright (C) 2021 Andrius Štikonas * This file is part of M2-Planet. * * M2-Planet is free software: you can redistribute it and/or modify @@ -18,7 +19,7 @@ #include "gcc_req.h" void require(int bool, char* error); -int numerate_string(char* a); +int strtoint(char* a); void line_error_token(struct token_list* list); struct token_list* eat_token(struct token_list* head); @@ -42,6 +43,18 @@ struct conditional_inclusion* conditional_inclusion_top; /* point where we are currently modifying the global_token list */ struct token_list* macro_token; +void init_macro_env(char* sym, char* value, char* source, int num) +{ + struct macro_list* hold = macro_env; + macro_env = calloc(1, sizeof(struct macro_list)); + macro_env->symbol = sym; + macro_env->next = hold; + macro_env->expansion = calloc(1, sizeof(struct token_list)); + macro_env->expansion->s = value; + macro_env->expansion->filename = source; + macro_env->expansion->linenumber = num; +} + void eat_current_token() { int update_global_token = FALSE; @@ -113,6 +126,13 @@ struct token_list* insert_tokens(struct token_list* point, struct token_list* to struct macro_list* lookup_macro(struct token_list* token) { + if(NULL == token) + { + line_error_token(macro_token); + fputs("null token received in lookup_macro\n", stderr); + exit(EXIT_FAILURE); + } + struct macro_list* hold = macro_env; while (NULL != hold) @@ -130,15 +150,65 @@ struct macro_list* lookup_macro(struct token_list* token) return NULL; } +void remove_macro(struct token_list* token) +{ + if(NULL == token) + { + line_error_token(macro_token); + fputs("received a null in remove_macro\n", stderr); + exit(EXIT_FAILURE); + } + + struct macro_list* hold = macro_env; + struct macro_list* temp; + + /* Deal with the first element */ + if (match(token->s, hold->symbol)) { + macro_env = hold->next; + free(hold); + return; + } + + /* Remove element form the middle of linked list */ + while (NULL != hold->next) + { + if (match(token->s, hold->next->symbol)) + { + temp = hold->next; + hold->next = hold->next->next; + free(temp); + return; + } + + hold = hold->next; + } + + /* nothing to undefine */ + return; +} + int macro_expression(); int macro_variable() { + int value = 0; + struct macro_list* hold = lookup_macro(macro_token); + if (NULL != hold) + { + if(NULL == hold->expansion) + { + line_error_token(macro_token); + fputs("hold->expansion is a null\n", stderr); + exit(EXIT_FAILURE); + } + value = strtoint(hold->expansion->s); + } eat_current_token(); - return 0; + return value; } + int macro_number() { - int result = numerate_string(macro_token->s); + int result = strtoint(macro_token->s); eat_current_token(); return result; } @@ -188,6 +258,12 @@ int macro_primary_expr() if(TRUE == defined_has_paren) { + if(NULL == macro_token) + { + line_error_token(macro_token); + fputs("unterminated define ( statement\n", stderr); + exit(EXIT_FAILURE); + } require(')' == macro_token->s[0], "missing close parenthesis for defined()\n"); eat_current_token(); } @@ -347,7 +423,17 @@ int macro_expression() void handle_define() { struct macro_list* hold; - struct token_list* expansion_end; + struct token_list* expansion_end = NULL; + + /* don't use #define statements from non-included blocks */ + int conditional_define = TRUE; + if(NULL != conditional_inclusion_top) + { + if(FALSE == conditional_inclusion_top->include) + { + conditional_define = FALSE; + } + } eat_current_token(); @@ -358,7 +444,8 @@ void handle_define() hold = calloc(1, sizeof(struct macro_list)); hold->symbol = macro_token->s; hold->next = macro_env; - macro_env = hold; + /* provided it isn't in a non-included block */ + if(conditional_define) macro_env = hold; /* discard the macro name */ eat_current_token(); @@ -369,10 +456,18 @@ void handle_define() if ('\n' == macro_token->s[0]) { + if(NULL == expansion_end) + { + hold->expansion = NULL; + expansion_end = macro_token; + return; + } expansion_end->next = NULL; return; } + require(NULL != hold, "#define got something it can't handle\n"); + expansion_end = macro_token; /* in the first iteration, we set the first token of the expansion, if @@ -382,9 +477,60 @@ void handle_define() hold->expansion = macro_token; } + /* throw away if not used */ + if(!conditional_define && (NULL != hold)) + { + free(hold); + hold = NULL; + } + eat_current_token(); } +} +void handle_undef() +{ + eat_current_token(); + remove_macro(macro_token); + eat_current_token(); +} + +void handle_error() +{ + /* don't use #error statements from non-included blocks */ + int conditional_error = TRUE; + if(NULL != conditional_inclusion_top) + { + if(FALSE == conditional_inclusion_top->include) + { + conditional_error = FALSE; + } + } + eat_current_token(); + /* provided it isn't in a non-included block */ + if(conditional_error) + { + line_error_token(macro_token); + fputs(" error: #error ", stderr); + while (TRUE) + { + if ('\n' == macro_token->s[0]) break; + fputs(macro_token->s, stderr); + macro_token = macro_token->next; + fputs(" ", stderr); + } + fputs("\n", stderr); + exit(EXIT_FAILURE); + } + while (TRUE) + { + /* discard the error */ + if ('\n' == macro_token->s[0]) + { + return; + } + eat_current_token(); + } } void macro_directive() @@ -411,6 +557,60 @@ void macro_directive() t->previous_condition_matched = t->include; } + else if(match("#ifdef", macro_token->s)) + { + eat_current_token(); + require(NULL != macro_token, "got an EOF terminated macro defined expression\n"); + if (NULL != lookup_macro(macro_token)) + { + result = TRUE; + } + else + { + result = FALSE; + } + eat_current_token(); + + /* push conditional inclusion */ + t = calloc(1, sizeof(struct conditional_inclusion)); + t->prev = conditional_inclusion_top; + conditional_inclusion_top = t; + t->include = TRUE; + + if(FALSE == result) + { + t->include = FALSE; + } + + t->previous_condition_matched = t->include; + } + else if(match("#ifndef", macro_token->s)) + { + eat_current_token(); + require(NULL != macro_token, "got an EOF terminated macro defined expression\n"); + if (NULL != lookup_macro(macro_token)) + { + result = FALSE; + } + else + { + result = TRUE; + } + eat_current_token(); + + /* push conditional inclusion */ + t = calloc(1, sizeof(struct conditional_inclusion)); + t->prev = conditional_inclusion_top; + conditional_inclusion_top = t; + t->include = TRUE; + + if(FALSE == result) + { + t->include = FALSE; + } + + t->previous_condition_matched = t->include; + } else if(match("#elif", macro_token->s)) { eat_current_token(); @@ -445,8 +645,26 @@ void macro_directive() { handle_define(); } + else if(match("#undef", macro_token->s)) + { + handle_undef(); + } + else if(match("#error", macro_token->s)) + { + handle_error(); + } else { + if(!match("#include", macro_token->s)) + { + /* Put a big fat warning but see if we can just ignore */ + fputs(">>WARNING<<\n>>WARNING<<\n", stderr); + line_error_token(macro_token); + fputs("feature: ", stderr); + fputs(macro_token->s, stderr); + fputs(" unsupported in M2-Planet\nIgnoring line, may result in bugs\n>>WARNING<<\n>>WARNING<<\n\n", stderr); + } + /* unhandled macro directive; let's eat until a newline; om nom nom */ while(TRUE) { @@ -467,14 +685,35 @@ void macro_directive() struct token_list* maybe_expand(struct token_list* token) { + if(NULL == token) + { + line_error_token(macro_token); + fputs("maybe_expand passed a null token\n", stderr); + exit(EXIT_FAILURE); + } + struct macro_list* hold = lookup_macro(token); struct token_list* hold2; + if(NULL == token->next) + { + line_error_token(macro_token); + fputs("we can't expand a null token: ", stderr); + fputs(token->s, stderr); + fputc('\n', stderr); + exit(EXIT_FAILURE); + } + if (NULL == hold) { return token->next; } token = eat_token(token); + + if (NULL == hold->expansion) + { + return token->next; + } hold2 = insert_tokens(token, hold->expansion); return hold2->next; diff --git a/cc_reader.c b/cc_reader.c index 9118e05..798c3ec 100644 --- a/cc_reader.c +++ b/cc_reader.c @@ -1,4 +1,5 @@ /* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2021 Andrius Štikonas * This file is part of M2-Planet. * * M2-Planet is free software: you can redistribute it and/or modify @@ -23,9 +24,16 @@ struct token_list* token; int line; char* file; +int grab_byte() +{ + int c = fgetc(input); + if(10 == c) line = line + 1; + return c; +} + int clearWhiteSpace(int c) { - if((32 == c) || (9 == c)) return clearWhiteSpace(fgetc(input)); + if((32 == c) || (9 == c)) return clearWhiteSpace(grab_byte()); return c; } @@ -34,7 +42,7 @@ int consume_byte(int c) hold_string[string_index] = c; string_index = string_index + 1; require(MAX_STRING > string_index, "Token exceeded MAX_STRING char limit\nuse --max-string number to increase\n"); - return fgetc(input); + return grab_byte(); } int preserve_string(int c) @@ -48,10 +56,23 @@ int preserve_string(int c) c = consume_byte(c); require(EOF != c, "Unterminated string\n"); } while(escape || (c != frequent)); - return fgetc(input); + return grab_byte(); } - void fixup_label() + +void copy_string(char* target, char* source, int max) +{ + int i = 0; + while(0 != source[i]) + { + target[i] = source[i]; + i = i + 1; + if(i == max) break; + } +} + + +void fixup_label() { int hold = ':'; int prev; @@ -217,9 +238,9 @@ reset: c = ' '; } } - else if(in_set(c, "<=>|&!-")) + else if(in_set(c, "<=>|&!^%")) { - c = preserve_keyword(c, "<=>|&!-"); + c = preserve_keyword(c, "<=>|&!^%"); } else if(in_set(c, "'\"")) { @@ -230,32 +251,69 @@ reset: c = consume_byte(c); if(c == '*') { - c = fgetc(input); + c = grab_byte(); while(c != '/') { while(c != '*') { - c = fgetc(input); + c = grab_byte(); require(EOF != c, "Hit EOF inside of block comment\n"); - if('\n' == c) line = line + 1; } - c = fgetc(input); + c = grab_byte(); require(EOF != c, "Hit EOF inside of block comment\n"); - if('\n' == c) line = line + 1; } - c = fgetc(input); + c = grab_byte(); goto reset; } else if(c == '/') { c = consume_byte(c); } + else if(c == '=') + { + c = consume_byte(c); + } } else if (c == '\n') { - line = line + 1; c = consume_byte(c); } + else if(c == '*') + { + c = consume_byte(c); + if(c == '=') + { + c = consume_byte(c); + } + } + else if(c == '+') + { + c = consume_byte(c); + if(c == '=') + { + c = consume_byte(c); + } + if(c == '+') + { + c = consume_byte(c); + } + } + else if(c == '-') + { + c = consume_byte(c); + if(c == '=') + { + c = consume_byte(c); + } + if(c == '>') + { + c = consume_byte(c); + } + if(c == '-') + { + c = consume_byte(c); + } + } else { c = consume_byte(c); @@ -263,7 +321,7 @@ reset: /* More efficiently allocate memory for string */ current->s = calloc(string_index + 2, sizeof(char)); - require(NULL != current->s, "Exhusted memory while trying to copy a token\n"); + require(NULL != current->s, "Exhausted memory while trying to copy a token\n"); copy_string(current->s, hold_string, MAX_STRING); current->prev = token; @@ -294,7 +352,7 @@ struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* fi line = 1; file = filename; token = current; - int ch =fgetc(input); + int ch = grab_byte(); while(EOF != ch) ch = get_token(ch); return token; diff --git a/functions/in_set.c b/functions/in_set.c deleted file mode 100644 index e7e989e..0000000 --- a/functions/in_set.c +++ /dev/null @@ -1,32 +0,0 @@ -/* Copyright (C) 2016 Jeremiah Orians - * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen - * This file is part of M2-Planet. - * - * M2-Planet is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * M2-Planet is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with M2-Planet. If not, see . - */ - -#define FALSE 0 -// CONSTANT FALSE 0 -#define TRUE 1 -// CONSTANT TRUE 1 - -int in_set(int c, char* s) -{ - while(0 != s[0]) - { - if(c == s[0]) return TRUE; - s = s + 1; - } - return FALSE; -} diff --git a/functions/match.c b/functions/match.c deleted file mode 100644 index 3eb0b22..0000000 --- a/functions/match.c +++ /dev/null @@ -1,35 +0,0 @@ -/* Copyright (C) 2016 Jeremiah Orians - * This file is part of M2-Planet. - * - * M2-Planet is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * M2-Planet is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with M2-Planet. If not, see . - */ - -#define FALSE 0 -// CONSTANT FALSE 0 -#define TRUE 1 -// CONSTANT TRUE 1 - -int match(char* a, char* b) -{ - int i = -1; - do - { - i = i + 1; - if(a[i] != b[i]) - { - return FALSE; - } - } while((0 != a[i]) && (0 !=b[i])); - return TRUE; -} diff --git a/functions/numerate_number.c b/functions/numerate_number.c deleted file mode 100644 index bd07975..0000000 --- a/functions/numerate_number.c +++ /dev/null @@ -1,177 +0,0 @@ -/* Copyright (C) 2016 Jeremiah Orians - * This file is part of M2-Planet. - * - * M2-Planet is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * M2-Planet is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with M2-Planet. If not, see . - */ - -#include -#include -#include -// void* calloc(int count, int size); -#define TRUE 1 -//CONSTANT TRUE 1 -#define FALSE 0 -//CONSTANT FALSE 0 -int in_set(int c, char* s); - - -char* numerate_number(int a) -{ - char* result = calloc(16, sizeof(char)); - if(NULL == result) - { - fputs("calloc failed in numerate_number\n", stderr); - exit(EXIT_FAILURE); - } - int i = 0; - - /* Deal with Zero case */ - if(0 == a) - { - result[0] = '0'; - return result; - } - - /* Deal with negatives */ - if(0 > a) - { - result[0] = '-'; - i = 1; - a = a * -1; - } - - /* Using the largest 10^n number possible in 32bits */ - int divisor = 0x3B9ACA00; - /* Skip leading Zeros */ - while(0 == (a / divisor)) divisor = divisor / 10; - - /* Now simply collect numbers until divisor is gone */ - while(0 < divisor) - { - result[i] = ((a / divisor) + 48); - a = a % divisor; - divisor = divisor / 10; - i = i + 1; - } - - return result; -} - -int char2hex(int c) -{ - if (c >= '0' && c <= '9') return (c - 48); - else if (c >= 'a' && c <= 'f') return (c - 87); - else if (c >= 'A' && c <= 'F') return (c - 55); - else return -1; -} - -int hex2char(int c) -{ - if((c >= 0) && (c <= 9)) return (c + 48); - else if((c >= 10) && (c <= 15)) return (c + 55); - else return -1; -} - -int char2dec(int c) -{ - if (c >= '0' && c <= '9') return (c - 48); - else return -1; -} - -int dec2char(int c) -{ - if((c >= 0) && (c <= 9)) return (c + 48); - else return -1; -} - -int index_number(char* s, char c) -{ - int i = 0; - while(s[i] != c) - { - i = i + 1; - if(0 == s[i]) return -1; - } - return i; -} - -int toupper(int c) -{ - if(in_set(c, "abcdefghijklmnopqrstuvwxyz")) return (c & 0xDF); - return c; -} - -int set_reader(char* set, int mult, char* input) -{ - int n = 0; - int i = 0; - int hold; - int negative_p = FALSE; - - if(input[0] == '-') - { - negative_p = TRUE; - i = i + 1; - } - - while(in_set(input[i], set)) - { - n = n * mult; - hold = index_number(set, toupper(input[i])); - - /* Input managed to change between in_set and index_number */ - if(-1 == hold) return 0; - n = n + hold; - i = i + 1; - } - - /* loop exited before NULL and thus invalid input */ - if(0 != input[i]) return 0; - - if(negative_p) - { - n = 0 - n; - } - - return n; -} - -int numerate_string(char *a) -{ - /* If NULL string */ - if(0 == a[0]) - { - return 0; - } - /* Deal with binary*/ - else if ('0' == a[0] && 'b' == a[1]) - { - return set_reader("01", 2, a+2); - } - /* Deal with hex */ - else if ('0' == a[0] && 'x' == a[1]) - { - return set_reader("0123456789ABCDEFabcdef", 16, a+2); - } - /* Deal with octal */ - else if('0' == a[0]) - { - return set_reader("01234567", 8, a+1); - } - /* Deal with decimal */ - else - { - return set_reader("0123456789", 10, a); - } -} diff --git a/functions/require.c b/functions/require.c deleted file mode 100644 index c16f8f9..0000000 --- a/functions/require.c +++ /dev/null @@ -1,29 +0,0 @@ -/* Copyright (C) 2016 Jeremiah Orians - * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen - * This file is part of M2-Planet. - * - * M2-Planet is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * M2-Planet is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with M2-Planet. If not, see . - */ - -#include -#include - -void require(int bool, char* error) -{ - if(!bool) - { - fputs(error, stderr); - exit(EXIT_FAILURE); - } -} diff --git a/functions/string.c b/functions/string.c deleted file mode 100644 index edd441c..0000000 --- a/functions/string.c +++ /dev/null @@ -1,37 +0,0 @@ -/* Copyright (C) 2016 Jeremiah Orians - * This file is part of M2-Planet. - * - * M2-Planet is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * M2-Planet is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with M2-Planet. If not, see . - */ - -#include -#include - -void copy_string(char* target, char* source, int max) -{ - int i = 0; - while(0 != source[i]) - { - target[i] = source[i]; - i = i + 1; - if(i == max) break; - } -} - -int string_length(char* a) -{ - int i = 0; - while(0 != a[i]) i = i + 1; - return i; -} diff --git a/makefile b/makefile index 0a1cd92..39f34d2 100644 --- a/makefile +++ b/makefile @@ -27,11 +27,7 @@ all: M2-Mesoplanet M2-Mesoplanet: bin results cc.h cc_reader.c cc_core.c cc.c cc_globals.c cc_globals.h $(CC) $(CFLAGS) \ - functions/match.c \ - functions/in_set.c \ - functions/numerate_number.c \ - functions/string.c \ - functions/require.c \ + M2libc/bootstrappable.c \ cc_reader.c \ cc_core.c \ cc_macro.c \