added doxygen and added new compiler module
This commit is contained in:
parent
01f5ef953d
commit
fcbfb548c3
|
@ -0,0 +1,255 @@
|
|||
//
|
||||
// Created by servostar on 6/2/24.
|
||||
//
|
||||
|
||||
#include <compiler.h>
|
||||
#include <ast/ast.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/log.h>
|
||||
#include <yacc/parser.tab.h>
|
||||
#include <lex/util.h>
|
||||
#include <io/files.h>
|
||||
#include <assert.h>
|
||||
#include <cfg/opt.h>
|
||||
|
||||
extern void yyrestart(FILE *);
|
||||
|
||||
// Module AST node used by the parser for AST construction.
|
||||
[[maybe_unused]]
|
||||
AST_NODE_PTR root;
|
||||
// Current file which gets compiled the parser.
|
||||
// NOTE: due to global state no concurrent compilation is possible
|
||||
// on parser level.
|
||||
[[maybe_unused]]
|
||||
ModuleFile *current_file;
|
||||
|
||||
/**
|
||||
* @brief Compile the specified file into AST
|
||||
* @param ast Initialized AST module node to build program rules
|
||||
* @param file The file to be processed
|
||||
* @return EXIT_SUCCESS in case the parsing was success full anything lese if not
|
||||
*/
|
||||
[[nodiscard("AST may be in invalid state")]]
|
||||
[[gnu::nonnull(1), gnu::nonnull(1)]]
|
||||
static int compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
|
||||
assert(file->path != NULL);
|
||||
assert(ast != NULL);
|
||||
|
||||
file->handle = fopen(file->path, "r");
|
||||
|
||||
if (file->handle == NULL) {
|
||||
INFO("unable to open file: %s", file->path);
|
||||
print_message(Error, "Cannot open file %s: %s", file->path, strerror(errno));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
DEBUG("parsing file: %s", file->path);
|
||||
// setup global state
|
||||
root = ast;
|
||||
current_file = file;
|
||||
yyin = file->handle;
|
||||
yyrestart(yyin);
|
||||
lex_reset();
|
||||
|
||||
yyparse();
|
||||
|
||||
// clean up global state
|
||||
// current_file = NULL;
|
||||
root = NULL;
|
||||
yyin = NULL;
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Setup the environment of the target.
|
||||
* @param target
|
||||
* @return EXIT_SUCCESS if successful EXIT_FAILURE otherwise
|
||||
*/
|
||||
static int setup_target_environment(const TargetConfig *target) {
|
||||
DEBUG("setting up environment for target: %s", target->name);
|
||||
|
||||
assert(target->output_directory != NULL);
|
||||
assert(target->archive_directory != NULL);
|
||||
|
||||
int result;
|
||||
|
||||
result = create_directory(target->archive_directory);
|
||||
if (result != 0 && errno != EEXIST) {
|
||||
const char *message = get_last_error();
|
||||
assert(message != NULL);
|
||||
|
||||
print_message(Error, "Unable to create directory: %s: %s", target->archive_directory, message);
|
||||
free((void *) message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
result = create_directory(target->output_directory);
|
||||
if (result != 0 && errno != EEXIST) {
|
||||
const char *message = get_last_error();
|
||||
assert(message != NULL);
|
||||
|
||||
print_message(Error, "Unable to create directory: %s: %s", target->output_directory, message);
|
||||
free((void *) message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Print the supplied AST of the specified target to a graphviz ".gv" file
|
||||
* @param ast
|
||||
* @param target
|
||||
*/
|
||||
static void print_ast_to_file(AST_NODE_PTR ast, TargetConfig *target) {
|
||||
assert(ast != NULL);
|
||||
assert(target != NULL);
|
||||
|
||||
if (!target->print_ast)
|
||||
return;
|
||||
|
||||
// create file path to write graphviz to
|
||||
const char *path = make_file_path(1, target->name, ".gv", target->archive_directory);
|
||||
|
||||
FILE *output = fopen((const char *) path, "w");
|
||||
if (output == NULL) {
|
||||
const char *message = get_last_error();
|
||||
print_message(Error, "Unable to open file for syntax tree at: %s: %s", path, message);
|
||||
free((void *) message);
|
||||
} else {
|
||||
|
||||
AST_fprint_graphviz(output, ast);
|
||||
|
||||
fclose(output);
|
||||
}
|
||||
|
||||
free((void *) path);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build the given target
|
||||
* @param unit
|
||||
* @param target
|
||||
*/
|
||||
static void build_target(ModuleFileStack *unit, TargetConfig *target) {
|
||||
print_message(Info, "Building target: %s", target->name);
|
||||
|
||||
AST_NODE_PTR ast = AST_new_node(empty_location(), AST_Module, NULL);
|
||||
ModuleFile *file = push_file(unit, target->root_module);
|
||||
|
||||
if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) {
|
||||
if (setup_target_environment(target) == 0) {
|
||||
|
||||
print_ast_to_file(ast, target);
|
||||
|
||||
// TODO: parse AST to semantic values
|
||||
// TODO: backend codegen
|
||||
}
|
||||
}
|
||||
|
||||
AST_delete_node(ast);
|
||||
|
||||
print_file_statistics(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Compile a single file.
|
||||
* Creates a single target by the given command line arguments.
|
||||
* @param unit
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
static void compile_file(ModuleFileStack *unit, int argc, char *argv[]) {
|
||||
INFO("compiling basic files...");
|
||||
|
||||
TargetConfig *target = default_target_config_from_args(argc, argv);
|
||||
|
||||
if (target->root_module == NULL) {
|
||||
print_message(Error, "No input file specified.");
|
||||
delete_target_config(target);
|
||||
return;
|
||||
}
|
||||
|
||||
build_target(unit, target);
|
||||
|
||||
delete_target_config(target);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build all project targets specified by the command line arguments.
|
||||
* @param unit
|
||||
* @param config
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
static void build_project_targets(ModuleFileStack *unit, ProjectConfig *config, int argc, char *argv[]) {
|
||||
if (argc == 1 && strcmp(argv[0], "all") == 0) {
|
||||
// build all targets in the project
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init(&iter, config->targets);
|
||||
|
||||
char *key;
|
||||
TargetConfig *val;
|
||||
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
|
||||
build_target(unit, val);
|
||||
}
|
||||
} else {
|
||||
// build all targets given in the arguments
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *target_name = argv[i];
|
||||
if (g_hash_table_contains(config->targets, target_name)) {
|
||||
build_target(unit, g_hash_table_lookup(config->targets, target_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Build targets from project. Configuration is provided by command line arguments.
|
||||
* @param unit File storage
|
||||
* @param argc Number of arguments
|
||||
* @param argv Array of Arguments
|
||||
*/
|
||||
static void build_project(ModuleFileStack *unit, int argc, char *argv[]) {
|
||||
if (argc <= 0) {
|
||||
print_message(Error, "No targets specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectConfig *config = default_project_config();
|
||||
int err = load_project_config(config);
|
||||
|
||||
if (err == PROJECT_OK) {
|
||||
build_project_targets(unit, config, argc, argv);
|
||||
}
|
||||
|
||||
delete_project_config(config);
|
||||
}
|
||||
|
||||
void run_compiler(int argc, char *argv[]) {
|
||||
if (argc <= 0) {
|
||||
INFO("no arguments provided");
|
||||
print_help();
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleFileStack files = new_file_stack();
|
||||
|
||||
if (strcmp(argv[0], "build") == 0) {
|
||||
build_project(&files, argc - 1, &argv[1]);
|
||||
} else if (strcmp(argv[0], "compile") == 0) {
|
||||
compile_file(&files, argc - 1, &argv[1]);
|
||||
} else {
|
||||
print_message(Error, "Invalid mode of operation. Rerun with --help.");
|
||||
}
|
||||
|
||||
if (files.files == NULL) {
|
||||
print_message(Error, "No input files, nothing to do.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print_unit_statistics(&files);
|
||||
delete_files(&files);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
//
|
||||
// Created by servostar on 6/2/24.
|
||||
//
|
||||
|
||||
#ifndef GEMSTONE_COMPILER_H
|
||||
#define GEMSTONE_COMPILER_H
|
||||
|
||||
/**
|
||||
* @brief Run the gemstone compiler with the provided command arguments.
|
||||
* @param argc
|
||||
* @param argv
|
||||
*/
|
||||
void run_compiler(int argc, char *argv[]);
|
||||
|
||||
#endif //GEMSTONE_COMPILER_H
|
|
@ -6,6 +6,28 @@
|
|||
#include <sys/log.h>
|
||||
#include <assert.h>
|
||||
#include <sys/col.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __unix__
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#define MAX_PATH_BYTES PATH_MAX
|
||||
|
||||
#elif defined(_WIN32) || defined(WIN32)
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#define MAX_PATH_BYTES _MAX_PATH
|
||||
|
||||
#endif
|
||||
|
||||
ModuleFileStack new_file_stack() {
|
||||
ModuleFileStack stack;
|
||||
stack.files = NULL;
|
||||
|
||||
return stack;
|
||||
}
|
||||
|
||||
ModuleFile *push_file(ModuleFileStack *stack, const char *path) {
|
||||
assert(stack != NULL);
|
||||
|
@ -92,12 +114,13 @@ void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, c
|
|||
break;
|
||||
}
|
||||
|
||||
char absolute_path[PATH_MAX];
|
||||
realpath(file->path, absolute_path);
|
||||
const char *absolute_path = get_absolute_path(file->path);
|
||||
|
||||
printf("%s%s:%ld:%s %s%s:%s %s\n", BOLD, absolute_path, location->line_start, RESET, accent_color, kind_text, RESET,
|
||||
message);
|
||||
|
||||
free((void *) absolute_path);
|
||||
|
||||
size_t lines = location->line_end - location->line_start + 1;
|
||||
|
||||
for (size_t l = 0; l < lines; l++) {
|
||||
|
@ -261,7 +284,73 @@ void print_message(Message kind, const char *fmt, ...) {
|
|||
|
||||
printf("%s%s:%s ", accent_color, kind_text, RESET);
|
||||
vprintf(fmt, args);
|
||||
printf("\n\n");
|
||||
printf("\n");
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
int create_directory(const char *path) {
|
||||
assert(path != NULL);
|
||||
|
||||
DEBUG("creating directory: %s", path);
|
||||
|
||||
int result;
|
||||
#ifdef __unix__
|
||||
result = mkdir(path, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH);
|
||||
#elif defined(_WIN32) || defined(WIN32)
|
||||
result = _mkdir(path);
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *get_last_error() {
|
||||
return strdup(strerror(errno));
|
||||
}
|
||||
|
||||
const char *get_absolute_path(const char *path) {
|
||||
assert(path != NULL);
|
||||
|
||||
DEBUG("resolving absolute path of: %s", path);
|
||||
|
||||
#ifdef __unix__
|
||||
// use unix specific function
|
||||
char absolute_path[MAX_PATH_BYTES];
|
||||
realpath(path, absolute_path);
|
||||
#elif defined(_WIN32) || defined(WIN32)
|
||||
// use Windows CRT specific function
|
||||
char absolute_path[MAX_PATH_BYTES];
|
||||
_fullpath(path, absolute_path, _MAX_PATH);
|
||||
#endif
|
||||
|
||||
return strdup(absolute_path);
|
||||
}
|
||||
|
||||
const char* make_file_path(int count, const char* name, const char* ext, ...) {
|
||||
DEBUG("building file path...");
|
||||
|
||||
va_list args;
|
||||
va_start(args, count); // Initialize the va_list with the first variadic argument
|
||||
|
||||
char* path = calloc(MAX_PATH_BYTES, sizeof(char));
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
const char* arg = va_arg(args, const char*);
|
||||
assert(arg != NULL);
|
||||
|
||||
strcat(path, arg);
|
||||
strcat(path, PATH_SEPARATOR);
|
||||
}
|
||||
|
||||
va_end(args); // Clean up the va_list
|
||||
|
||||
if (name != NULL) {
|
||||
strcat(path, name);
|
||||
}
|
||||
|
||||
if (name != NULL) {
|
||||
strcat(path, ext);
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,12 @@
|
|||
#include <stdio.h>
|
||||
#include <glib.h>
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32)
|
||||
#define PATH_SEPARATOR "\\"
|
||||
#else
|
||||
#define PATH_SEPARATOR "/"
|
||||
#endif
|
||||
|
||||
typedef struct FileDiagnosticStatistics_t {
|
||||
size_t error_count;
|
||||
size_t warning_count;
|
||||
|
@ -37,6 +43,12 @@ typedef struct TokenLocation_t {
|
|||
unsigned long int col_end;
|
||||
} TokenLocation;
|
||||
|
||||
/**
|
||||
* @brief Create a new, empty file stack.
|
||||
* @return
|
||||
*/
|
||||
ModuleFileStack new_file_stack();
|
||||
|
||||
/**
|
||||
* @brief Add a new file to the file stack.
|
||||
* @attention The file handle returned will be invalid
|
||||
|
@ -65,18 +77,80 @@ void delete_files(ModuleFileStack *stack);
|
|||
TokenLocation new_location(unsigned long int line_start, unsigned long int col_start, unsigned long int line_end,
|
||||
unsigned long int col_end);
|
||||
|
||||
/**
|
||||
* @brief Create a new empty location with all of its contents set to zero
|
||||
* @return
|
||||
*/
|
||||
TokenLocation empty_location(void);
|
||||
|
||||
/**
|
||||
* @brief Prints some diagnostic message to stdout.
|
||||
* This also print the token group and the attached source as context.
|
||||
* @param file
|
||||
* @param location
|
||||
* @param kind
|
||||
* @param message
|
||||
*/
|
||||
[[gnu::nonnull(1), gnu::nonnull(2)]]
|
||||
void print_diagnostic(ModuleFile *file, TokenLocation *location, Message kind, const char *message);
|
||||
|
||||
[[gnu::nonnull(2)]]
|
||||
/**
|
||||
* @brief Print a general message to stdout. Provides no source context like print_diagnostic()
|
||||
* @param kind
|
||||
* @param fmt
|
||||
* @param ...
|
||||
*/
|
||||
void print_message(Message kind, const char *fmt, ...);
|
||||
|
||||
/**
|
||||
* @brief Print statistics about a specific file.
|
||||
* Will print the amount of infos, warning and errors emitted during compilation.
|
||||
* @param file
|
||||
*/
|
||||
[[gnu::nonnull(1)]]
|
||||
void print_file_statistics(ModuleFile *file);
|
||||
|
||||
/**
|
||||
* @brief Print statistics of all files in the module stack.
|
||||
* @param file_stack
|
||||
*/
|
||||
[[gnu::nonnull(1)]]
|
||||
void print_unit_statistics(ModuleFileStack *file_stack);
|
||||
|
||||
/**
|
||||
* @brief Create a new directory. Will return EEXISTS in case the directory already exists.
|
||||
* @param path
|
||||
* @return 0 if successful, anything else otherwise
|
||||
*/
|
||||
[[gnu::nonnull(1)]]
|
||||
int create_directory(const char* path);
|
||||
|
||||
/**
|
||||
* @brief Get a string describing the last error set by errno.
|
||||
* @return a string that must be freed
|
||||
*/
|
||||
[[nodiscard("pointer must be freed")]]
|
||||
const char* get_last_error();
|
||||
|
||||
/**
|
||||
* @brief Resolve the absolute path from a given relative path.
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
[[gnu::nonnull(1)]]
|
||||
[[nodiscard("pointer must be freed")]]
|
||||
const char* get_absolute_path(const char* path);
|
||||
|
||||
/**
|
||||
* @brief Create a file path from a base name, extension a variable amount of directory path segments.
|
||||
* @param count Amount of path segments to prepend to the basename
|
||||
* @param name Basename of the file
|
||||
* @param ext Extension of the file
|
||||
* @param ... Path segments without path separator
|
||||
* @return A relative path of a file
|
||||
*/
|
||||
[[nodiscard("pointer must be freed")]]
|
||||
const char* make_file_path(int count, const char* name, const char* ext, ...);
|
||||
|
||||
#endif //GEMSTONE_FILES_H
|
||||
|
|
176
src/main.c
176
src/main.c
|
@ -1,58 +1,10 @@
|
|||
#include <ast/ast.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/log.h>
|
||||
#include <yacc/parser.tab.h>
|
||||
#include <sys/col.h>
|
||||
#include <lex/util.h>
|
||||
#include <io/files.h>
|
||||
#include <assert.h>
|
||||
#include <cfg/opt.h>
|
||||
|
||||
extern void yyrestart(FILE *);
|
||||
|
||||
[[maybe_unused]]
|
||||
AST_NODE_PTR root;
|
||||
[[maybe_unused]]
|
||||
ModuleFile *current_file;
|
||||
|
||||
/**
|
||||
* @brief Compile the specified file into AST
|
||||
* @param ast
|
||||
* @param file
|
||||
* @return EXIT_SUCCESS in case the parsing was success full anything lese if not
|
||||
*/
|
||||
[[nodiscard("AST may be in invalid state")]]
|
||||
[[gnu::nonnull(1), gnu::nonnull(1)]]
|
||||
|
||||
static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
|
||||
assert(file->path != NULL);
|
||||
assert(ast != NULL);
|
||||
|
||||
file->handle = fopen(file->path, "r");
|
||||
|
||||
if (file->handle == NULL) {
|
||||
INFO("unable to open file: %s", file->path);
|
||||
print_message(Error, "Cannot open file %s: %s", file->path, strerror(errno));
|
||||
return 1;
|
||||
}
|
||||
|
||||
DEBUG("parsing file: %s", file->path);
|
||||
// setup global state
|
||||
root = ast;
|
||||
current_file = file;
|
||||
yyin = file->handle;
|
||||
yyrestart(yyin);
|
||||
lex_reset();
|
||||
|
||||
yyparse();
|
||||
|
||||
// clean up global state
|
||||
// current_file = NULL;
|
||||
root = NULL;
|
||||
yyin = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
#include <compiler.h>
|
||||
|
||||
/**
|
||||
* @brief Log a debug message to inform about beginning exit procedures
|
||||
|
@ -60,17 +12,6 @@ static size_t compile_file_to_ast(AST_NODE_PTR ast, ModuleFile *file) {
|
|||
*/
|
||||
void notify_exit(void) { DEBUG("Exiting gemstone..."); }
|
||||
|
||||
/**
|
||||
* @brief Closes File after compiling.
|
||||
*
|
||||
*/
|
||||
|
||||
void close_file(void) {
|
||||
if (NULL != yyin) {
|
||||
fclose(yyin);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Run compiler setup here
|
||||
*
|
||||
|
@ -95,123 +36,12 @@ void setup(void) {
|
|||
DEBUG("finished starting up gemstone...");
|
||||
}
|
||||
|
||||
static void setup_target_environment(const TargetConfig* target) {
|
||||
if (target->output_directory) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void build_target(ModuleFileStack *unit, TargetConfig *target) {
|
||||
print_message(Info, "Compiling file: %s", target->root_module);
|
||||
|
||||
TokenLocation location = new_location(0,0,0,0);
|
||||
AST_NODE_PTR ast = AST_new_node(location, AST_Module, NULL);
|
||||
ModuleFile *file = push_file(unit, target->root_module);
|
||||
|
||||
if (compile_file_to_ast(ast, file) == EXIT_SUCCESS) {
|
||||
setup_target_environment(target);
|
||||
|
||||
if (target->print_ast) {
|
||||
|
||||
}
|
||||
|
||||
// TODO: parse AST to semantic values
|
||||
// TODO: backend codegen
|
||||
}
|
||||
|
||||
AST_delete_node(ast);
|
||||
|
||||
print_file_statistics(file);
|
||||
}
|
||||
|
||||
void compile_file(ModuleFileStack *unit, int argc, char *argv[]) {
|
||||
INFO("compiling basic files...");
|
||||
|
||||
TargetConfig *target = default_target_config_from_args(argc, argv);
|
||||
|
||||
if (target->root_module == NULL) {
|
||||
print_message(Error, "No input file specified.");
|
||||
delete_target_config(target);
|
||||
return;
|
||||
}
|
||||
|
||||
build_target(unit, target);
|
||||
|
||||
delete_target_config(target);
|
||||
}
|
||||
|
||||
void build_project_targets(ModuleFileStack *unit, ProjectConfig *config, int argc, char *argv[]) {
|
||||
if (argc == 1 && strcmp(argv[0], "all") == 0) {
|
||||
GHashTableIter iter;
|
||||
|
||||
g_hash_table_iter_init(&iter, config->targets);
|
||||
|
||||
char *key;
|
||||
TargetConfig *val;
|
||||
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
|
||||
build_target(unit, val);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < argc; i++) {
|
||||
char *target_name = argv[i];
|
||||
if (g_hash_table_contains(config->targets, target_name)) {
|
||||
build_target(unit, g_hash_table_lookup(config->targets, target_name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void build_project(ModuleFileStack *unit, int argc, char *argv[]) {
|
||||
if (argc <= 0) {
|
||||
print_message(Error, "No targets specified.");
|
||||
return;
|
||||
}
|
||||
|
||||
ProjectConfig *config = default_project_config();
|
||||
int err = load_project_config(config);
|
||||
|
||||
if (err == PROJECT_OK) {
|
||||
build_project_targets(unit, config, argc, argv);
|
||||
}
|
||||
|
||||
delete_project_config(config);
|
||||
}
|
||||
|
||||
void configure_run_mode(int argc, char *argv[]) {
|
||||
if (argc <= 0) {
|
||||
INFO("no arguments provided");
|
||||
print_help();
|
||||
return;
|
||||
}
|
||||
|
||||
ModuleFileStack files;
|
||||
files.files = NULL;
|
||||
|
||||
if (strcmp(argv[0], "build") == 0) {
|
||||
build_project(&files, argc - 1, &argv[1]);
|
||||
} else if (strcmp(argv[0], "compile") == 0) {
|
||||
compile_file(&files, argc - 1, &argv[1]);
|
||||
} else {
|
||||
print_message(Error, "Invalid mode of operation. Rerun with --help.");
|
||||
}
|
||||
|
||||
if (files.files == NULL) {
|
||||
print_message(Error, "No input files, nothing to do.");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
print_unit_statistics(&files);
|
||||
delete_files(&files);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
setup();
|
||||
atexit(close_file);
|
||||
|
||||
print_message(Info, "running GSC version %s", GSC_VERSION);
|
||||
print_message(Info, "Running GSC version %s", GSC_VERSION);
|
||||
|
||||
configure_run_mode(argc - 1, &argv[1]);
|
||||
run_compiler(argc - 1, &argv[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue