From 1ac5bb6eee99f59ee2cf3877e4bfc1466baf79b0 Mon Sep 17 00:00:00 2001 From: Sanne Wouda Date: Sun, 10 Jan 2021 09:32:42 -0500 Subject: [PATCH] Initial import of functionality from M2-Planet --- .gitignore | 26 ++ cc.c | 138 ++++++++++ cc.h | 83 ++++++ cc_core.c | 61 +++++ cc_globals.c | 46 ++++ cc_globals.h | 49 ++++ cc_macro.c | 530 ++++++++++++++++++++++++++++++++++++ cc_reader.c | 301 ++++++++++++++++++++ functions/in_set.c | 32 +++ functions/match.c | 35 +++ functions/numerate_number.c | 177 ++++++++++++ functions/require.c | 29 ++ functions/string.c | 37 +++ gcc_req.h | 21 ++ makefile | 95 +++++++ 15 files changed, 1660 insertions(+) create mode 100644 .gitignore create mode 100644 cc.c create mode 100644 cc.h create mode 100644 cc_core.c create mode 100644 cc_globals.c create mode 100644 cc_globals.h create mode 100644 cc_macro.c create mode 100644 cc_reader.c create mode 100644 functions/in_set.c create mode 100644 functions/match.c create mode 100644 functions/numerate_number.c create mode 100644 functions/require.c create mode 100644 functions/string.c create mode 100644 gcc_req.h create mode 100644 makefile diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f0435dc --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +## Copyright (C) 2017 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 . + +# Generated files +tape_01 +tape_02 + +# Directories storing data that should be ignored +bin/ +temp/ +test/scratch/ +scratch/ + diff --git a/cc.c b/cc.c new file mode 100644 index 0000000..254bc78 --- /dev/null +++ b/cc.c @@ -0,0 +1,138 @@ +/* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2020 deesix + * 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 +#include"cc.h" + +/* The core functions */ +void initialize_types(); +struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename); +struct token_list* reverse_list(struct token_list* head); + +struct token_list* remove_line_comments(struct token_list* head); +struct token_list* remove_line_comment_tokens(struct token_list* head); +struct token_list* remove_preprocessor_directives(struct token_list* head); + +void eat_newline_tokens(); +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 main(int argc, char** argv) +{ + MAX_STRING = 4096; + BOOTSTRAP_MODE = FALSE; + PREPROCESSOR_MODE = FALSE; + FILE* in = stdin; + FILE* destination_file = stdout; + Architecture = KNIGHT_NATIVE; /* Assume Knight-native */ + char* name; + + int i = 1; + while(i <= argc) + { + if(NULL == argv[i]) + { + i = i + 1; + } + else if(match(argv[i], "-f") || match(argv[i], "--file")) + { + if(NULL == hold_string) + { + hold_string = calloc(MAX_STRING, sizeof(char)); + require(NULL != hold_string, "Impossible Exhustion has occured\n"); + } + + name = argv[i + 1]; + in = fopen(name, "r"); + if(NULL == in) + { + fputs("Unable to open for reading file: ", stderr); + fputs(name, stderr); + fputs("\n Aborting to avoid problems\n", stderr); + exit(EXIT_FAILURE); + } + global_token = read_all_tokens(in, global_token, name); + fclose(in); + i = i + 2; + } + else if(match(argv[i], "-o") || match(argv[i], "--output")) + { + destination_file = fopen(argv[i + 1], "w"); + if(NULL == destination_file) + { + fputs("Unable to open for writing file: ", stderr); + fputs(argv[i + 1], stderr); + fputs("\n Aborting to avoid problems\n", stderr); + exit(EXIT_FAILURE); + } + i = i + 2; + } + else if(match(argv[i], "--max-string")) + { + MAX_STRING = numerate_string(argv[i+1]); + require(0 < MAX_STRING, "Not a valid string size\nAbort and fix your --max-string\n"); + i = i + 2; + } + else if(match(argv[i], "-h") || match(argv[i], "--help")) + { + fputs(" -f input file\n -o output file\n --help for this message\n --version for file version\n", stdout); + exit(EXIT_SUCCESS); + } + else if(match(argv[i], "-V") || match(argv[i], "--version")) + { + fputs("M2-Mesoplanet v1.7.0\n", stderr); + exit(EXIT_SUCCESS); + } + else + { + fputs("UNKNOWN ARGUMENT\n", stdout); + exit(EXIT_FAILURE); + } + } + + /* Deal with special case of wanting to read from standard input */ + if(stdin == in) + { + hold_string = calloc(MAX_STRING, sizeof(char)); + require(NULL != hold_string, "Impossible Exhustion has occured\n"); + global_token = read_all_tokens(in, global_token, "STDIN"); + } + + if(NULL == global_token) + { + fputs("Either no input files were given or they were empty\n", stderr); + exit(EXIT_FAILURE); + } + global_token = reverse_list(global_token); + + global_token = remove_line_comments(global_token); + preprocess(); + + fputs("\n/* Preprocessed source */\n", destination_file); + output_tokens(global_token, destination_file); + + if (destination_file != stdout) + { + fclose(destination_file); + } + return EXIT_SUCCESS; +} diff --git a/cc.h b/cc.h new file mode 100644 index 0000000..8166265 --- /dev/null +++ b/cc.h @@ -0,0 +1,83 @@ +/* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2020 deesix + * 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 + +// CONSTANT FALSE 0 +#define FALSE 0 +// CONSTANT TRUE 1 +#define TRUE 1 + +// CONSTANT KNIGHT_NATIVE 0 +#define KNIGHT_NATIVE 0 +// CONSTANT KNIGHT_POSIX 1 +#define KNIGHT_POSIX 1 +// CONSTANT X86 2 +#define X86 2 +// CONSTANT AMD64 3 +#define AMD64 3 +// CONSTANT ARMV7L 4 +#define ARMV7L 4 +// CONSTANT AARCH64 5 +#define AARCH64 5 + + +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); +void reset_hold_string(); + + +struct type +{ + struct type* next; + int size; + int offset; + int is_signed; + struct type* indirect; + struct type* members; + struct type* type; + char* name; +}; + +struct token_list +{ + struct token_list* next; + union + { + struct token_list* locals; + struct token_list* prev; + }; + char* s; + union + { + struct type* type; + char* filename; + }; + union + { + struct token_list* arguments; + int depth; + int linenumber; + }; +}; + +#include "cc_globals.h" diff --git a/cc_core.c b/cc_core.c new file mode 100644 index 0000000..0d66803 --- /dev/null +++ b/cc_core.c @@ -0,0 +1,61 @@ +/* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2018 Jan (janneke) Nieuwenhuizen + * Copyright (C) 2020 deesix + * 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 "cc.h" +#include "gcc_req.h" +#include + +char* numerate_number(int a); + +void line_error_token(struct token_list *token) +{ + require(NULL != token, "EOF reached inside of line_error\n"); + fputs(token->filename, stderr); + fputs(":", stderr); + fputs(numerate_number(token->linenumber), stderr); + fputs(":", stderr); +} + +void line_error() +{ + line_error_token(global_token); +} + +void require_match(char* message, char* required) +{ + require(NULL != global_token, "EOF reached inside of require match\n"); + if(!match(global_token->s, required)) + { + line_error(); + fputs(message, stderr); + exit(EXIT_FAILURE); + } + global_token = global_token->next; + require(NULL != global_token, "EOF after require match occurred\n"); +} + +void output_tokens(struct token_list *i, FILE* out) +{ + while(NULL != i) + { + fputs(i->s, out); + fputs(" ", out); + i = i->next; + } +} diff --git a/cc_globals.c b/cc_globals.c new file mode 100644 index 0000000..13f0036 --- /dev/null +++ b/cc_globals.c @@ -0,0 +1,46 @@ +/* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2020 deesix + * 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 . + */ + +/* What types we have */ +struct type* global_types; +struct type* prim_types; + +/* What we are currently working on */ +struct token_list* global_token; + +/* Output reorder collections*/ +struct token_list* output_list; +struct token_list* strings_list; +struct token_list* globals_list; + +/* Make our string collection more efficient */ +char* hold_string; +int string_index; + +/* Our Target Architecture */ +int Architecture; +int register_size; + +int MAX_STRING; +struct type* integer; + +/* enable bootstrap-mode */ +int BOOTSTRAP_MODE; + +/* enable preprocessor-only mode */ +int PREPROCESSOR_MODE; diff --git a/cc_globals.h b/cc_globals.h new file mode 100644 index 0000000..cdac985 --- /dev/null +++ b/cc_globals.h @@ -0,0 +1,49 @@ +/* Copyright (C) 2016 Jeremiah Orians + * Copyright (C) 2020 deesix + * 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 . + */ + +/* What types we have */ +extern struct type* global_types; +extern struct type* prim_types; + +/* What we are currently working on */ +extern struct token_list* global_token; + +/* Output reorder collections*/ +extern struct token_list* output_list; +extern struct token_list* strings_list; +extern struct token_list* globals_list; + +/* Make our string collection more efficient */ +extern char* hold_string; +extern int string_index; + +/* Our Target Architecture */ +extern int Architecture; +extern int register_size; + +/* Allow us to have a single settable max string */ +extern int MAX_STRING; + +/* make default type integer */ +extern struct type* integer; + +/* enable bootstrap-mode */ +extern int BOOTSTRAP_MODE; + +/* enable preprocessor-only mode */ +extern int PREPROCESSOR_MODE; diff --git a/cc_macro.c b/cc_macro.c new file mode 100644 index 0000000..57e6d48 --- /dev/null +++ b/cc_macro.c @@ -0,0 +1,530 @@ +/* Copyright (C) 2021 Sanne Wouda + * 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 "cc.h" +#include "gcc_req.h" + +void require(int bool, char* error); +int numerate_string(char* a); +void line_error_token(struct token_list* list); +struct token_list* eat_token(struct token_list* head); + +struct conditional_inclusion +{ + struct conditional_inclusion* prev; + int include; /* 1 == include, 0 == skip */ + int previous_condition_matched; /* 1 == all subsequent conditions treated as FALSE */ +}; + +struct macro_list +{ + struct macro_list* next; + char* symbol; + struct token_list* expansion; +}; + +struct macro_list* macro_env; +struct conditional_inclusion* conditional_inclusion_top; + +/* point where we are currently modifying the global_token list */ +struct token_list* macro_token; + +void eat_current_token() +{ + int update_global_token = FALSE; + if (macro_token == global_token) + update_global_token = TRUE; + + macro_token = eat_token(macro_token); + + if(update_global_token) + global_token = macro_token; +} + +void eat_newline_tokens() +{ + macro_token = global_token; + + while(TRUE) + { + if(NULL == macro_token) return; + + if(match("\n", macro_token->s)) + { + eat_current_token(); + } + else + { + macro_token = macro_token->next; + } + } +} + +/* returns the first token inserted; inserts *before* point */ +struct token_list* insert_tokens(struct token_list* point, struct token_list* token) +{ + struct token_list* copy; + struct token_list* first = NULL; + + while (NULL != token) + { + copy = calloc(1, sizeof(struct token_list)); + copy->s = token->s; + copy->filename = token->filename; + copy->linenumber = token->linenumber; + + if(NULL == first) + { + first = copy; + } + + copy->next = point; + + if (NULL != point) + { + copy->prev = point->prev; + + if(NULL != point->prev) + { + point->prev->next = copy; + } + + point->prev = copy; + } + + token = token->next; + } + + return first; +} + +struct macro_list* lookup_macro(struct token_list* token) +{ + struct macro_list* hold = macro_env; + + while (NULL != hold) + { + if (match(token->s, hold->symbol)) + { + /* found! */ + return hold; + } + + hold = hold->next; + } + + /* not found! */ + return NULL; +} + +int macro_expression(); +int macro_variable() +{ + eat_current_token(); + return 0; +} +int macro_number() +{ + int result = numerate_string(macro_token->s); + eat_current_token(); + return result; +} + +int macro_primary_expr() +{ + int defined_has_paren = FALSE; + int hold; + require(NULL != macro_token, "got an EOF terminated macro primary expression\n"); + + if('-' == macro_token->s[0]) + { + eat_current_token(); + return -macro_primary_expr(); + } + else if('!' == macro_token->s[0]) + { + eat_current_token(); + return !macro_primary_expr(); + } + else if('(' == macro_token->s[0]) + { + eat_current_token(); + return macro_expression(); + } + else if(match("defined", macro_token->s)) + { + eat_current_token(); + + require(NULL != macro_token, "got an EOF terminated macro defined expression\n"); + + if('(' == macro_token->s[0]) + { + defined_has_paren = TRUE; + eat_current_token(); + } + + if (NULL != lookup_macro(macro_token)) + { + hold = TRUE; + } + else + { + hold = FALSE; + } + eat_current_token(); + + if(TRUE == defined_has_paren) + { + require(')' == macro_token->s[0], "missing close parenthesis for defined()\n"); + eat_current_token(); + } + + return hold; + } + else if(in_set(macro_token->s[0], "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_")) + { + return macro_variable(); + } + else if(in_set(macro_token->s[0], "0123456789")) + { + return macro_number(); + } + else + { + return 0; /* FIXME: error handling */ + } +} + +int macro_additive_expr() +{ + int lhs = macro_primary_expr(); + int hold; + + require(NULL != macro_token, "got an EOF terminated macro additive expression\n"); + if(match("+", macro_token->s)) + { + eat_current_token(); + return lhs + macro_additive_expr(); + } + else if(match("-", macro_token->s)) + { + eat_current_token(); + return lhs - macro_additive_expr(); + } + else if(match("*", macro_token->s)) + { + eat_current_token(); + return lhs * macro_additive_expr(); + } + else if(match("/", macro_token->s)) + { + eat_current_token(); + hold = macro_additive_expr(); + require(0 != hold, "divide by zero not valid even in C macros\n"); + return lhs / hold; + } + else if(match("%", macro_token->s)) + { + eat_current_token(); + hold = macro_additive_expr(); + require(0 != hold, "modulus by zero not valid even in C macros\n"); + return lhs % hold; + } + else if(match(">>", macro_token->s)) + { + eat_current_token(); + return lhs >> macro_additive_expr(); + } + else if(match("<<", macro_token->s)) + { + eat_current_token(); + return lhs << macro_additive_expr(); + } + else + { + return lhs; + } +} + +int macro_relational_expr() +{ + int lhs = macro_additive_expr(); + + if(match("<", macro_token->s)) + { + eat_current_token(); + return lhs < macro_relational_expr(); + } + else if(match("<=", macro_token->s)) + { + eat_current_token(); + return lhs <= macro_relational_expr(); + } + else if(match(">=", macro_token->s)) + { + eat_current_token(); + return lhs >= macro_relational_expr(); + } + else if(match(">", macro_token->s)) + { + eat_current_token(); + return lhs > macro_relational_expr(); + } + else if(match("==", macro_token->s)) + { + eat_current_token(); + return lhs == macro_relational_expr(); + } + else if(match("!=", macro_token->s)) + { + eat_current_token(); + return lhs != macro_relational_expr(); + } + else + { + return lhs; + } +} + +int macro_bitwise_expr() +{ + int rhs; + int lhs = macro_relational_expr(); + + if(match("&", macro_token->s)) + { + eat_current_token(); + return lhs & macro_bitwise_expr(); + } + else if(match("&&", macro_token->s)) + { + eat_current_token(); + rhs = macro_bitwise_expr(); + return lhs && rhs; + } + else if(match("|", macro_token->s)) + { + eat_current_token(); + rhs = macro_bitwise_expr(); + return lhs | rhs; + } + else if(match("||", macro_token->s)) + { + eat_current_token(); + rhs = macro_bitwise_expr(); + return lhs || rhs; + } + else if(match("^", macro_token->s)) + { + eat_current_token(); + rhs = macro_bitwise_expr(); + return lhs ^ rhs; + } + else + { + return lhs; + } +} + +int macro_expression() +{ + return macro_bitwise_expr(); +} + +void handle_define() +{ + struct macro_list* hold; + struct token_list* expansion_end; + + eat_current_token(); + + require(NULL != macro_token, "got an EOF terminated #define\n"); + require('\n' != macro_token->s[0], "unexpected newline after #define\n"); + + /* insert new macro */ + hold = calloc(1, sizeof(struct macro_list)); + hold->symbol = macro_token->s; + hold->next = macro_env; + macro_env = hold; + + /* discard the macro name */ + eat_current_token(); + + while (TRUE) + { + require(NULL != macro_token, "got an EOF terminated #define\n"); + + if ('\n' == macro_token->s[0]) + { + expansion_end->next = NULL; + return; + } + + expansion_end = macro_token; + + /* in the first iteration, we set the first token of the expansion, if + it exists */ + if (NULL == hold->expansion) + { + hold->expansion = macro_token; + } + + eat_current_token(); + } + +} + +void macro_directive() +{ + struct conditional_inclusion *t; + int result; + + /* FIXME: whitespace is allowed between "#"" and "if" */ + if(match("#if", macro_token->s)) + { + eat_current_token(); + /* evaluate constant integer expression */ + result = macro_expression(); + /* 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(); + result = macro_expression(); + require(NULL != conditional_inclusion_top, "#elif without leading #if\n"); + conditional_inclusion_top->include = result && !conditional_inclusion_top->previous_condition_matched; + conditional_inclusion_top->previous_condition_matched = + conditional_inclusion_top->previous_condition_matched || conditional_inclusion_top->include; + } + else if(match("#else", macro_token->s)) + { + eat_current_token(); + require(NULL != conditional_inclusion_top, "#else without leading #if\n"); + conditional_inclusion_top->include = !conditional_inclusion_top->previous_condition_matched; + } + else if(match("#endif", macro_token->s)) + { + if(NULL == conditional_inclusion_top) + { + line_error_token(macro_token); + fputs("unexpected #endif\n", stderr); + exit(EXIT_FAILURE); + } + + eat_current_token(); + /* pop conditional inclusion */ + t = conditional_inclusion_top; + conditional_inclusion_top = conditional_inclusion_top->prev; + free(t); + } + else if(match("#define", macro_token->s)) + { + handle_define(); + } + else + { + /* unhandled macro directive; let's eat until a newline; om nom nom */ + while(TRUE) + { + if(NULL == macro_token) + { + return; + } + + if('\n' == macro_token->s[0]) + { + return; + } + + eat_current_token(); + } + } +} + +struct token_list* maybe_expand(struct token_list* token) +{ + struct macro_list* hold = lookup_macro(token); + struct token_list* hold2; + if (NULL == hold) + { + return token->next; + } + + token = eat_token(token); + hold2 = insert_tokens(token, hold->expansion); + + return hold2->next; +} + +void preprocess() +{ + int start_of_line = TRUE; + macro_token = global_token; + + while(NULL != macro_token) + { + if(start_of_line && '#' == macro_token->s[0]) + { + macro_directive(); + + if(macro_token) + { + if('\n' != macro_token->s[0]) + { + line_error_token(macro_token); + fputs("newline expected at end of macro directive\n", stderr); + fputs("found: '", stderr); + fputs(macro_token->s, stderr); + fputs("'\n", stderr); + exit(EXIT_FAILURE); + } + } + } + else if('\n' == macro_token->s[0]) + { + start_of_line = TRUE; + macro_token = macro_token->next; + } + else + { + start_of_line = FALSE; + if(NULL == conditional_inclusion_top) + { + macro_token = maybe_expand(macro_token); + } + else if(!conditional_inclusion_top->include) + { + /* rewrite the token stream to exclude the current token */ + eat_current_token(); + } + else + { + macro_token = maybe_expand(macro_token); + } + } + } +} diff --git a/cc_reader.c b/cc_reader.c new file mode 100644 index 0000000..9118e05 --- /dev/null +++ b/cc_reader.c @@ -0,0 +1,301 @@ +/* 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 "cc.h" + +/* Globals */ +FILE* input; +struct token_list* token; +int line; +char* file; + +int clearWhiteSpace(int c) +{ + if((32 == c) || (9 == c)) return clearWhiteSpace(fgetc(input)); + return c; +} + +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); +} + +int preserve_string(int c) +{ + int frequent = c; + int escape = FALSE; + do + { + if(!escape && '\\' == c ) escape = TRUE; + else escape = FALSE; + c = consume_byte(c); + require(EOF != c, "Unterminated string\n"); + } while(escape || (c != frequent)); + return fgetc(input); +} + + void fixup_label() +{ + int hold = ':'; + int prev; + int i = 0; + do + { + prev = hold; + hold = hold_string[i]; + hold_string[i] = prev; + i = i + 1; + } while(0 != hold); +} + +int preserve_keyword(int c, char* S) +{ + while(in_set(c, S)) + { + c = consume_byte(c); + } + return c; +} + +void reset_hold_string() +{ + int i = string_index + 2; + while(0 != i) + { + hold_string[i] = 0; + i = i - 1; + } +} + +/* note if this is the first token in the list, head needs fixing up */ +struct token_list* eat_token(struct token_list* token) +{ + if(NULL != token->prev) + { + token->prev->next = token->next; + } + + /* update backlinks */ + if(NULL != token->next) + { + token->next->prev = token->prev; + } + + return token->next; +} + +struct token_list* eat_until_newline(struct token_list* head) +{ + while (NULL != head) + { + if('\n' == head->s[0]) + { + return head; + } + else + { + head = eat_token(head); + } + } + + return NULL; +} + +struct token_list* remove_line_comments(struct token_list* head) +{ + struct token_list* first = NULL; + + while (NULL != head) + { + if(match("//", head->s)) + { + head = eat_until_newline(head); + } + else + { + if(NULL == first) + { + first = head; + } + head = head->next; + } + } + + return first; +} + +struct token_list* remove_line_comment_tokens(struct token_list* head) +{ + struct token_list* first = NULL; + + while (NULL != head) + { + if(match("//", head->s)) + { + head = eat_token(head); + } + else + { + if(NULL == first) + { + first = head; + } + head = head->next; + } + } + + return first; +} + +struct token_list* remove_preprocessor_directives(struct token_list* head) +{ + struct token_list* first = NULL; + + while (NULL != head) + { + if('#' == head->s[0]) + { + head = eat_until_newline(head); + } + else + { + if(NULL == first) + { + first = head; + } + head = head->next; + } + } + + return first; +} + + +int get_token(int c) +{ + struct token_list* current = calloc(1, sizeof(struct token_list)); + require(NULL != current, "Exhausted memory while getting token\n"); + +reset: + reset_hold_string(); + string_index = 0; + + c = clearWhiteSpace(c); + if(c == EOF) + { + free(current); + return c; + } + else if('#' == c) + { + c = consume_byte(c); + c = preserve_keyword(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); + } + else if(in_set(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_")) + { + c = preserve_keyword(c, "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"); + if(':' == c) + { + fixup_label(); + c = ' '; + } + } + else if(in_set(c, "<=>|&!-")) + { + c = preserve_keyword(c, "<=>|&!-"); + } + else if(in_set(c, "'\"")) + { + c = preserve_string(c); + } + else if(c == '/') + { + c = consume_byte(c); + if(c == '*') + { + c = fgetc(input); + while(c != '/') + { + while(c != '*') + { + c = fgetc(input); + require(EOF != c, "Hit EOF inside of block comment\n"); + if('\n' == c) line = line + 1; + } + c = fgetc(input); + require(EOF != c, "Hit EOF inside of block comment\n"); + if('\n' == c) line = line + 1; + } + c = fgetc(input); + goto reset; + } + else if(c == '/') + { + c = consume_byte(c); + } + } + else if (c == '\n') + { + line = line + 1; + c = consume_byte(c); + } + else + { + c = consume_byte(c); + } + + /* 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"); + copy_string(current->s, hold_string, MAX_STRING); + + current->prev = token; + current->next = token; + current->linenumber = line; + current->filename = file; + token = current; + return c; +} + +struct token_list* reverse_list(struct token_list* head) +{ + struct token_list* root = NULL; + struct token_list* next; + while(NULL != head) + { + next = head->next; + head->next = root; + root = head; + head = next; + } + return root; +} + +struct token_list* read_all_tokens(FILE* a, struct token_list* current, char* filename) +{ + input = a; + line = 1; + file = filename; + token = current; + int ch =fgetc(input); + while(EOF != ch) ch = get_token(ch); + + return token; +} diff --git a/functions/in_set.c b/functions/in_set.c new file mode 100644 index 0000000..e7e989e --- /dev/null +++ b/functions/in_set.c @@ -0,0 +1,32 @@ +/* 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 new file mode 100644 index 0000000..3eb0b22 --- /dev/null +++ b/functions/match.c @@ -0,0 +1,35 @@ +/* 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 new file mode 100644 index 0000000..bd07975 --- /dev/null +++ b/functions/numerate_number.c @@ -0,0 +1,177 @@ +/* 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 new file mode 100644 index 0000000..c16f8f9 --- /dev/null +++ b/functions/require.c @@ -0,0 +1,29 @@ +/* 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 new file mode 100644 index 0000000..edd441c --- /dev/null +++ b/functions/string.c @@ -0,0 +1,37 @@ +/* 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/gcc_req.h b/gcc_req.h new file mode 100644 index 0000000..dd12bb2 --- /dev/null +++ b/gcc_req.h @@ -0,0 +1,21 @@ +/* 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 . + */ + +// Exists only because gcc doesn't support naked Function pointers +// And thus adds just enough support that M2-Plant can leverage the feature +// in its self-host +typedef void (*FUNCTION) (); diff --git a/makefile b/makefile new file mode 100644 index 0000000..0a1cd92 --- /dev/null +++ b/makefile @@ -0,0 +1,95 @@ +## Copyright (C) 2017 Jeremiah Orians +## Copyright (C) 2020 deesix +## This file is part of M2-Mesoplanet. +## +## M2-Mesoplanet 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-Mesoplanet 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-Mesoplanet. If not, see . + +# Prevent rebuilding +VPATH = bin:test:test/results +PACKAGE = m2-planet + +# C compiler settings +CC?=gcc +CFLAGS:=$(CFLAGS) -D_GNU_SOURCE -O0 -std=c99 -ggdb + +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 \ + cc_reader.c \ + cc_core.c \ + cc_macro.c \ + cc.c \ + cc.h \ + cc_globals.c \ + gcc_req.h \ + -o bin/M2-Mesoplanet + +# Clean up after ourselves +.PHONY: clean +clean: + rm -rf bin/ test/results/ +# ./test/test0000/cleanup.sh + +# Directories +bin: + mkdir -p bin + +results: + mkdir -p test/results + +# tests +test: aarch64-tests amd64-tests knight-posix-tests knight-native-tests armv7l-tests x86-tests | results + sha256sum -c test/test.answers + + +# Generate test answers +.PHONY: Generate-test-answers +Generate-test-answers: + sha256sum test/results/* >| test/test.answers + +DESTDIR:= +PREFIX:=/usr/local +bindir:=$(DESTDIR)$(PREFIX)/bin +.PHONY: install +install: M2-Mesoplanet + mkdir -p $(bindir) + cp $^ $(bindir) + +### dist +.PHONY: dist + +COMMIT=$(shell git describe --dirty) +TARBALL_VERSION=$(COMMIT:Release_%=%) +TARBALL_DIR:=$(PACKAGE)-$(TARBALL_VERSION) +TARBALL=$(TARBALL_DIR).tar.gz +# Be friendly to Debian; avoid using EPOCH +MTIME=$(shell git show HEAD --format=%ct --no-patch) +# Reproducible tarball +TAR_FLAGS=--sort=name --mtime=@$(MTIME) --owner=0 --group=0 --numeric-owner --mode=go=rX,u+rw,a-s + +$(TARBALL): + (git ls-files \ + --exclude=$(TARBALL_DIR); \ + echo $^ | tr ' ' '\n') \ + | tar $(TAR_FLAGS) \ + --transform=s,^,$(TARBALL_DIR)/,S -T- -cf- \ + | gzip -c --no-name > $@ + +dist: $(TARBALL)