slcc/cc.c

318 lines
10 KiB
C

#define TOOL_CPP
#define _CRT_SECURE_NO_WARNINGS
#ifdef _WIN32
#include <process.h>
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
//#include "compile.h"
#define CCB_IMPLEMENTATION
#include "ccb.h"
#define CCBGENERIC_IMPLEMENTATION
#include "ccbgeneric.h"
#ifdef TOOL_CPP
#define CPP_IMPLEMENTATION
#include "cpp.h"
#endif
#ifdef TOOL_MK
#define MK_IMPLEMENTATION
#include "mk.h"
#endif
int sh_main(int argc, char** argv);
void ccb_compile_error_impl(ccb_t* ccb/*, const char* fmt, ...*/) {
fprintf(stderr, "^ Around line %d, column %d of '%s'.\n", ccb->pos.uline, ccb->pos.ucol, ccb->pos.ufile);
fprintf(stderr, " [Around line %d, column %d of preprocessed input]\n", ccb->pos.line, ccb->pos.col);
/*#ifdef _ZCC
fprintf(stderr, "ERROR '%s'\n(TODO: Better formatting!)\n", fmt);
((char*)NULL)[0] = 0; // Trigger debugger
#else
va_list a;
va_start(a, fmt);
vfprintf(stderr, fmt, a);
fprintf(stderr, "\n");
va_end(a);
#endif*/
exit(EXIT_FAILURE);
}
void ccb_compile_warn_impl(ccb_t* ccb/*, const char* fmt, ...*/) {
fprintf(stderr, "^ Around line %d, column %d of '%s'.\n", ccb->pos.uline, ccb->pos.ucol, ccb->pos.ufile);
fprintf(stderr, " [Around line %d, column %d of preprocessed input]\n", ccb->pos.line, ccb->pos.col);
/*#ifdef _ZCC
fprintf(stderr, "WARNING '%s'\n(TODO: Better formatting!)\n", fmt);
#else
va_list a;
va_start(a, fmt);
vfprintf(stderr, fmt, a);
fprintf(stderr, "\n");
va_end(a);
#endif*/
}
static int startcompile(ccb_t* ccb) {
ccb_util_init(ccb);
ccb_target_init(ccb);
ccb_ast_init(ccb);
ccb_list_t* block = ccb_parse_run(ccb);
if (!ccb->dump_ast) {
if (ccb->include_data) {
ccb_target_gen_data_section(ccb);
}
}
/* First run is required to gather externs. TODO: This should be done for any extern data elements too! */
for (ccb_list_iterator_t* it = ccb_list_iterator(block); !ccb_list_iterator_end(it); ) {
if (!ccb->dump_ast) {
if (ccb->include_code) {
ccb_target_gen_declfunction(ccb, ccb_list_iterator_next(it));
}
}
else {
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
}
}
if (ccb->knownexterns != NULL) {
for (ccb_list_iterator_t* it = ccb_list_iterator(ccb->knownexterns); !ccb_list_iterator_end(it); ) {
if (!ccb->dump_ast) {
if (ccb->include_code) {
ccb_target_gen_declextern(ccb, ccb_list_iterator_next(it));
}
}
else {
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
}
}
}
for (ccb_list_iterator_t* it = ccb_list_iterator(block); !ccb_list_iterator_end(it); ) {
if (!ccb->dump_ast) {
if (ccb->include_code) {
ccb_target_gen_function(ccb, ccb_list_iterator_next(it));
}
}
else {
printf("%s", ccb_ast_string(ccb, ccb_list_iterator_next(it)));
}
}
return true;
}
/* Original main program from LICE:
int main(int argc, char **argv) {
argc--;
argv++;
return startcompile(!!(argc && !strcmp(*argv, "--dump-ast")))
? EXIT_SUCCESS
: EXIT_FAILURE;
}
*/
static void usage(int argc, char** argv, int arge) {
//fprintf(stderr, "TODO: Usage!\n");
char* n = argv[0];
fprintf(stderr, "USAGE:\n\n");
fprintf(stderr, " %s [--silent] [--ast-only|--code-only|--data-only|--usage] [TODO --asmfmt fasm|gas] [TODO --binfmt elf|flat] [--input <fname>] [--output|--append <fname>]\n\n", n);
fprintf(stderr, "(This is a simple core compiler designed to be invoked from a more user-friendly frontend.\nArguments must be provided in the above order, defaults to using stdin/stdout.)");
}
int preprocessormain(int argc, char** argv); // Extra definition of the C preprocessor main program
//void mk_main(int argc, char** argv); // Extra definition of the "make" tool main program
/* Zak's new new main program: (frontend) */
#include "frontend.c"
/* Zak's new main program: (backend) */
int backend_main(int argc, char** argv) {
/*int x;
for(x=0;x<argc;x++) {
printf("Got arg '%s'\n", argv[x]);
}*/
//argc = 3;
//argv = (char*[]){"test",/*"--ast-only",*/"--input","C:\\Users\\Zak\\source\\repos\\ZCC\\Debug\\test2.c"};
ccb_t ccb;
ccb.dump_ast = false;
ccb.silent = false;
ccb.input = stdin;
ccb.output = stdout;
ccb.include_code = true;
ccb.include_data = true;
ccb.pos.line = 1;
ccb.pos.col = 1;
ccb.pos.uline = 1;
ccb.pos.ucol = 1;
ccb.pos.ufile = strdup("input");
ccb.default_callconv = 0;
ccb.func_callconv = 0;
ccb.func_name = NULL;
ccb.mod_name = NULL;
ccb.mod_initstmts = NULL;
ccb.sym_prefix = strdup("");
ccb.declarednames = NULL;
ccb.knownexterns = NULL;
ccb.bsscount = 0;
int argi = 1;
if (argc > argi && (!strcmp(argv[argi], "--silent") || !strcmp(argv[argi], "--usage") || !strcmp(argv[argi], "-P") || !strcmp(argv[argi], "-B"))) { // Also skip added notices if using --usage
if (!strcmp(argv[argi], "--silent")) {
argi++;
}
ccb.silent = true;
}
else {
fprintf(stderr, "SecureLang C Compiler backend (CCb), early version\n");
fprintf(stderr, "NOTE: This program generally reads program code from standard input (until EOF) and writes assembly code to standard output.\n");
fprintf(stderr, " It would usually be used from a compiler frontend (preprocessing, assembling and linking must be done separately).\n");
fprintf(stderr, " Use --silent as the first argument to disable these notices or --usage to learn more.\n\n");
}
/* Ignore -B, used to invoke backend. */
if (argc > argi && !strcmp(argv[argi], "-B")) {
argi++;
}
if (argc > argi && !strcmp(argv[argi], "--ast-only")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Will dump AST to output instead of assembly code.\n");
}
ccb.dump_ast = true;
argi++;
}
else if (argc > argi && !strcmp(argv[argi], "--data-only")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Will dump data section only.\n");
}
ccb.include_code = false;
ccb.include_data = true;
argi++;
}
else if (argc > argi && !strcmp(argv[argi], "--code-only")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Will dump code section only.\n");
}
ccb.include_code = true;
ccb.include_data = false;
argi++;
}
#ifdef TOOL_CPP
else if (argc > argi && !strcmp(argv[argi], "-P")) { /* Invoke the built-in preprocessor instead of the backend. */
if (!ccb.silent) {
fprintf(stderr, "NOTE: Invoking the experimental preprocessor.\n");
}
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
return preprocessormain(argc, argv);
}
#endif
#ifdef TOOL_MK
else if (argc > argi && !strcmp(argv[argi], "-M")) { /* Invoke the built-in make tool instead of the backend. */
if (!ccb.silent) {
fprintf(stderr, "NOTE: Invoking the experimental make tool.\n");
}
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
void* tmp = NULL;
mk_main(argc, argv, &tmp);
return -1; // TODO: mk_main returns void but also has some exit calls, this behaviour needs to be checked to return error codes properly
}
#endif
#ifdef TOOL_SH
else if (argc > argi && !strcmp(argv[argi], "-S")) { /* Invoke the built-in make tool instead of the backend. */
if (!ccb.silent) {
fprintf(stderr, "NOTE: Invoking the experimental shell tool.\n");
}
// NOTE: This will only work for argv == 1, and because cppmain ignores the -P flag!
void* tmp = NULL;
return sh_main(argc, argv);
}
#endif
if (argc > argi && !strcmp(argv[argi], "--usage")) {
printf("USAGE?\n");
usage(argc, argv, -1);
return EXIT_SUCCESS;
}
if (argc > argi && !strcmp(argv[argi], "--101")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Using calling convention 101 (__classic_call) by default.\n", argv[argi + 1]);
}
ccb.default_callconv = 101;
argi++;
}
if (argc > argi + 1 && !strcmp(argv[argi], "--mod")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Using module name '%s'.\n", argv[argi + 1]);
}
ccb.mod_name = strdup(argv[argi + 1]);
argi += 2;
}
if (argc > argi + 1 && !strcmp(argv[argi], "--prefix")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Using symbol prefix '%s'.\n", argv[argi + 1]);
}
ccb.sym_prefix = strdup(argv[argi + 1]);
argi += 2;
}
if (argc > argi + 1 && !strcmp(argv[argi], "--input")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Using input from '%s'.\n", argv[argi + 1]);
}
ccb.input = fopen(argv[argi + 1], "r");
ccb.pos.ufile = strdup(argv[argi + 1]);
argi += 2;
}
if (argc > argi + 1 && !strcmp(argv[argi], "--output")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Writing output to '%s'.\n", argv[argi + 1]);
}
ccb.output = fopen(argv[argi + 1], "w");
argi += 2;
}
else if (argc > argi + 1 && !strcmp(argv[argi], "--append")) {
if (!ccb.silent) {
fprintf(stderr, "NOTE: Appending output from '%s'.\n", argv[argi]);
}
ccb.output = fopen(argv[argi + 1], "a");
argi += 2;
}
if (ccb.input == NULL) {
fprintf(stderr, "ERROR: Failed to open input file.\n");
}
if (ccb.output == NULL) {
fprintf(stderr, "ERROR: Failed to open output file.\n");
}
if (argi != argc) {
usage(argc, argv, argi);
return EXIT_FAILURE;
}
int result = startcompile(&ccb);
if (ccb.input != stdin) {
fclose(ccb.input);
}
if (ccb.output != stdout) {
fclose(ccb.output);
}
if (result) {
return EXIT_SUCCESS;
}
else {
return EXIT_FAILURE;
}
}