mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 03:51:18 +00:00
Updated the command line parsing a little bit, as well as the README.
This commit is contained in:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -50,4 +50,6 @@ modules.order
|
||||
Module.symvers
|
||||
Mkfile.old
|
||||
dkms.conf
|
||||
cmake-build-debug/
|
||||
cmake-build-debug/
|
||||
|
||||
.idea/
|
||||
20
README.md
20
README.md
@@ -1,7 +1,23 @@
|
||||
# C3 Language
|
||||
|
||||
This is a prototype language branched off C2. It goes further than C2 in several regards, while still embracing the goals of C2.
|
||||
This is a prototype language heavily inspired by C2. It goes further than C2 in several regards, while still embracing the goals of C2.
|
||||
|
||||
### Design Principles
|
||||
- Procedural "get things done"-type of language.
|
||||
- Try to stay close to C - only change where truly needed.
|
||||
- Flawless C integration.
|
||||
- Learning C3 should be easy for a C programmer.
|
||||
- Dare violating the "close to metal" principle if the value is great.
|
||||
- Not an object oriented language.
|
||||
- Avoid "big ideas".
|
||||
- Avoid the kitchen sink language trap.
|
||||
|
||||
### Current status
|
||||
|
||||
As of now, very little code towards the compiler will be added here.
|
||||
|
||||
There is a "work-in-progress" C2 compiler in C called Titanos, which an eventual compiler might be based on.
|
||||
There is a "work-in-progress" C2 compiler in C called Titanos, which an eventual compiler might be based on.
|
||||
|
||||
A design draft can be found here: https://lerno.github.io/c3docs/
|
||||
|
||||
Discuss the language on the r/ProgrammingLanguages Discord server: https://discord.gg/cfu4wdk
|
||||
@@ -3,5 +3,259 @@
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
#include "build_options.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
BuildOptions build_options;
|
||||
#include "../utils/errors.h"
|
||||
|
||||
static const char* DEFAULT_TARGET = "default";
|
||||
|
||||
BuildOptions build_options;
|
||||
static int arg_index;
|
||||
static int arg_count;
|
||||
static const char** args;
|
||||
static const char* current_arg;
|
||||
|
||||
|
||||
#define OUTPUT(string, ...) fprintf(stdout, string "\n", ##__VA_ARGS__)
|
||||
#define FAIL_WITH_ERR(string, ...) do { fprintf(stderr, "Error: " string "\n\n", ##__VA_ARGS__); usage(); exit(EXIT_FAILURE); } while (0)
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
OUTPUT("Usage: %s [<options>] <command> [<args>]", args[0]);
|
||||
OUTPUT("");
|
||||
OUTPUT("Commands:");
|
||||
OUTPUT("");
|
||||
OUTPUT(" compile <file1> [<file2> ...] Compile files without a project into an executable.");
|
||||
OUTPUT(" init <project name> Initialize a new project structure.");
|
||||
OUTPUT(" build [<target>] Build the target in the current project.");
|
||||
OUTPUT(" clean Clean all build files.");
|
||||
OUTPUT(" run [<target>] Run (and build if needed) the target in the current project.");
|
||||
OUTPUT(" dist [<target>] Clean and build a target for distribution.");
|
||||
OUTPUT(" docs [<target>] Generate documentation for the target.");
|
||||
OUTPUT(" bench [<target>] Benchmark a target.");
|
||||
OUTPUT(" clean-run [<target>] Clean, then run the target.");
|
||||
OUTPUT(" compile-run <file1> [<file2> ...] Compile files then immediately run the result.");
|
||||
OUTPUT("");
|
||||
OUTPUT("Options:");
|
||||
OUTPUT(" --lib <dir> - Use this directory as the c3 library path.");
|
||||
OUTPUT(" --path <dir> - Use this as the base directory for the current command.");
|
||||
OUTPUT(" --template <template> - Use a different template: \"lib\", \"staticlib\" or a path.");
|
||||
OUTPUT(" --about - Prints a short description of C3.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
static const char* check_dir(const char *path)
|
||||
{
|
||||
static char *original_path = NULL;
|
||||
if (!original_path)
|
||||
{
|
||||
original_path = getcwd(NULL, 0);
|
||||
}
|
||||
if (chdir(path) == -1) error_exit("The path \"%s\" does not point to a valid directory.", path);
|
||||
int err = chdir(original_path);
|
||||
assert(!err);
|
||||
return path;
|
||||
}
|
||||
|
||||
static inline bool at_end()
|
||||
{
|
||||
return arg_index == arg_count - 1;
|
||||
}
|
||||
|
||||
static inline const char* next_arg()
|
||||
{
|
||||
assert(!at_end());
|
||||
current_arg = args[++arg_index];
|
||||
return current_arg;
|
||||
}
|
||||
|
||||
|
||||
static inline bool next_is_opt()
|
||||
{
|
||||
return args[arg_index + 1][0] == '-';
|
||||
}
|
||||
|
||||
static inline bool match_longopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_arg[2], name) == 0;
|
||||
}
|
||||
|
||||
static inline bool match_shortopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_arg[1], name) == 0;
|
||||
}
|
||||
|
||||
|
||||
void append_file()
|
||||
{
|
||||
if (build_options.file_count == MAX_FILES)
|
||||
{
|
||||
fprintf(stderr, "Max %d files may be specified\n", MAX_FILES);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
build_options.files[build_options.file_count++] = current_arg;
|
||||
}
|
||||
|
||||
static bool arg_match(const char *candidate)
|
||||
{
|
||||
return strcmp(current_arg, candidate) == 0;
|
||||
}
|
||||
|
||||
static void parse_optional_target()
|
||||
{
|
||||
if (at_end() || next_is_opt())
|
||||
{
|
||||
build_options.target = DEFAULT_TARGET;
|
||||
}
|
||||
else
|
||||
{
|
||||
build_options.target = next_arg();
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_command(void)
|
||||
{
|
||||
if (arg_match("init"))
|
||||
{
|
||||
build_options.command = COMMAND_INIT;
|
||||
if (at_end() || next_is_opt()) error_exit("Expected a project name after init");
|
||||
build_options.project_name = next_arg();
|
||||
return;
|
||||
}
|
||||
if (arg_match("compile"))
|
||||
{
|
||||
build_options.command = COMMAND_COMPILE;
|
||||
return;
|
||||
}
|
||||
if (arg_match("build"))
|
||||
{
|
||||
build_options.command = COMMAND_BUILD;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("run"))
|
||||
{
|
||||
build_options.command = COMMAND_RUN;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("compile-run"))
|
||||
{
|
||||
build_options.command = COMMAND_COMPILE_RUN;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("clean-run"))
|
||||
{
|
||||
build_options.command = COMMAND_CLEAN_RUN;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("clean"))
|
||||
{
|
||||
build_options.command = COMMAND_CLEAN;
|
||||
return;
|
||||
}
|
||||
if (arg_match("dist"))
|
||||
{
|
||||
build_options.command = COMMAND_CLEAN_RUN;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("docs"))
|
||||
{
|
||||
build_options.command = COMMAND_DOCS;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
if (arg_match("bench"))
|
||||
{
|
||||
build_options.command = COMMAND_BENCH;
|
||||
parse_optional_target();
|
||||
return;
|
||||
}
|
||||
FAIL_WITH_ERR("Cannot process the unknown command \"%s\".", current_arg);
|
||||
}
|
||||
static void parse_option()
|
||||
{
|
||||
switch (current_arg[1])
|
||||
{
|
||||
case 'h':
|
||||
break;
|
||||
case '-':
|
||||
if (match_longopt("about"))
|
||||
{
|
||||
OUTPUT("The C3 Compiler");
|
||||
OUTPUT("C3 is low level programming language based on C.");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
if (match_longopt("lib"))
|
||||
{
|
||||
if (at_end() || next_is_opt()) error_exit("error: --lib needs a directory.");
|
||||
if (build_options.lib_count == MAX_LIB_DIRS) error_exit("Max %d libraries may be specified.", MAX_LIB_DIRS);
|
||||
build_options.lib_dir[build_options.lib_count++] = check_dir(next_arg());
|
||||
return;
|
||||
}
|
||||
if (match_longopt("path"))
|
||||
{
|
||||
if (at_end() || next_is_opt()) error_exit("error: --path needs a directory.");
|
||||
build_options.path = check_dir(next_arg());
|
||||
return;
|
||||
}
|
||||
if (match_longopt("help"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
FAIL_WITH_ERR("Cannot process the unknown option \"%s\".", current_arg);
|
||||
}
|
||||
|
||||
|
||||
void parse_arguments(int argc, const char *argv[])
|
||||
{
|
||||
if (argc < 2)
|
||||
{
|
||||
usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
build_options.path = ".";
|
||||
build_options.command = COMMAND_MISSING;
|
||||
|
||||
arg_count = argc;
|
||||
args = argv;
|
||||
for (arg_index = 1; arg_index < arg_count; arg_index++)
|
||||
{
|
||||
current_arg = args[arg_index];
|
||||
if (current_arg[0] == '-')
|
||||
{
|
||||
parse_option();
|
||||
continue;
|
||||
}
|
||||
if (build_options.command == COMMAND_MISSING)
|
||||
{
|
||||
parse_command();
|
||||
continue;
|
||||
}
|
||||
if (build_options.command == COMMAND_COMPILE_RUN || build_options.command == COMMAND_COMPILE)
|
||||
{
|
||||
append_file();
|
||||
continue;
|
||||
}
|
||||
FAIL_WITH_ERR("Found the unexpected argument \"%s\".", current_arg);
|
||||
}
|
||||
if (build_options.command == COMMAND_MISSING)
|
||||
{
|
||||
FAIL_WITH_ERR("No command found.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,21 @@
|
||||
#define MAX_LIB_DIRS 1024
|
||||
#define MAX_FILES 2048
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COMMAND_MISSING = 0,
|
||||
COMMAND_COMPILE,
|
||||
COMMAND_INIT,
|
||||
COMMAND_BUILD,
|
||||
COMMAND_COMPILE_RUN,
|
||||
COMMAND_RUN,
|
||||
COMMAND_CLEAN_RUN,
|
||||
COMMAND_CLEAN,
|
||||
COMMAND_DIST,
|
||||
COMMAND_DOCS,
|
||||
COMMAND_BENCH,
|
||||
} CompilerCommand;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
const char* lib_dir[MAX_LIB_DIRS];
|
||||
@@ -14,8 +29,11 @@ typedef struct
|
||||
const char* files[MAX_FILES];
|
||||
int file_count;
|
||||
const char* project_name;
|
||||
const char* target;
|
||||
const char* path;
|
||||
const char* original_path;
|
||||
CompilerCommand command;
|
||||
} BuildOptions;
|
||||
|
||||
extern BuildOptions build_options;
|
||||
extern BuildOptions build_options;
|
||||
|
||||
void parse_arguments(int argc, const char *argv[]);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include "project_creation.h"
|
||||
#include "build_options.h"
|
||||
#include "../utils/string_utils.h"
|
||||
|
||||
189
src/main.c
189
src/main.c
@@ -1,179 +1,30 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include "build/build_options.h"
|
||||
#include "build/project_creation.h"
|
||||
#include "utils/errors.h"
|
||||
|
||||
static void usage(const char* name) {
|
||||
fprintf(stderr, "Usage: %s <options> <target>\n", name);
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " --lib <dir> - use this directory as the c3 library path\n");
|
||||
fprintf(stderr, " --path <dir> - use this as the base directory for the current command\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
COMMAND_COMPILE,
|
||||
COMMAND_NEW,
|
||||
} CompilerCommand;
|
||||
|
||||
static CompilerCommand command;
|
||||
|
||||
static int arg_index;
|
||||
static int arg_count;
|
||||
static const char** args;
|
||||
static const char* current_arg;
|
||||
|
||||
static void select_compiler_command(CompilerCommand new_command)
|
||||
{
|
||||
if (command != COMMAND_COMPILE)
|
||||
{
|
||||
fprintf(stderr, "Please select only one command\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
command = new_command;
|
||||
}
|
||||
|
||||
static const char* check_dir(const char *path)
|
||||
{
|
||||
if (chdir(path) == -1) error_exit("The path \"%s\" does not point to a valid directory.", path);
|
||||
int err = chdir(build_options.original_path);
|
||||
assert(!err);
|
||||
return path;
|
||||
}
|
||||
|
||||
static inline bool at_end()
|
||||
{
|
||||
return arg_index == arg_count - 1;
|
||||
}
|
||||
|
||||
static inline const char* next_arg()
|
||||
{
|
||||
assert(!at_end());
|
||||
current_arg = args[++arg_index];
|
||||
return current_arg;
|
||||
}
|
||||
|
||||
|
||||
static inline bool next_is_arg()
|
||||
{
|
||||
return args[arg_index + 1][0] == '-';
|
||||
}
|
||||
|
||||
static inline bool match_longopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_arg[2], name) == 0;
|
||||
}
|
||||
|
||||
static inline bool match_shortopt(const char* name)
|
||||
{
|
||||
return strcmp(¤t_arg[1], name) == 0;
|
||||
}
|
||||
|
||||
|
||||
void append_file()
|
||||
{
|
||||
if (build_options.file_count == MAX_FILES)
|
||||
{
|
||||
fprintf(stderr, "Max %d files may be specified\n", MAX_FILES);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
build_options.files[build_options.file_count++] = current_arg;
|
||||
}
|
||||
|
||||
static void parse_option()
|
||||
{
|
||||
switch (current_arg[1])
|
||||
{
|
||||
case 'h':
|
||||
break;
|
||||
case 'n':
|
||||
if (match_shortopt("new"))
|
||||
{
|
||||
select_compiler_command(COMMAND_NEW);
|
||||
if (at_end() || next_is_arg()) error_exit("Expected a project name after -new");
|
||||
build_options.project_name = next_arg();
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case '-':
|
||||
if (match_longopt("about"))
|
||||
{
|
||||
fprintf(stderr, "The C3 Compiler\n");
|
||||
fprintf(stderr, "\nC3 is an evolution of C.\n");
|
||||
exit(0);
|
||||
}
|
||||
if (match_longopt("lib"))
|
||||
{
|
||||
if (at_end() || next_is_arg()) error_exit("error: --lib needs a directory.");
|
||||
if (current_arg[0] == '-') error_exit("Expected a directory after --lib.");
|
||||
if (build_options.lib_count == MAX_LIB_DIRS) error_exit("Max %d libraries may be specified.", MAX_LIB_DIRS);
|
||||
build_options.lib_dir[build_options.lib_count++] = check_dir(next_arg());
|
||||
return;
|
||||
}
|
||||
if (match_longopt("path"))
|
||||
{
|
||||
if (at_end() || next_is_arg()) error_exit("error: --path needs a directory.");
|
||||
build_options.path = check_dir(next_arg());
|
||||
return;
|
||||
}
|
||||
if (match_longopt("help"))
|
||||
{
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
||||
}
|
||||
usage(args[0]);
|
||||
}
|
||||
|
||||
static void handle_compile_command()
|
||||
{
|
||||
printf("TODO\n");
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static void parse_arguments()
|
||||
{
|
||||
command = COMMAND_COMPILE;
|
||||
for (arg_index = 1; arg_index < arg_count; arg_index++)
|
||||
{
|
||||
current_arg = args[arg_index];
|
||||
if (current_arg[0] == '-')
|
||||
{
|
||||
parse_option();
|
||||
continue;
|
||||
}
|
||||
append_file();
|
||||
}
|
||||
switch (command)
|
||||
{
|
||||
case COMMAND_NEW:
|
||||
create_project();
|
||||
break;
|
||||
case COMMAND_COMPILE:
|
||||
handle_compile_command();
|
||||
break;
|
||||
default:
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, const char *argv[])
|
||||
{
|
||||
build_options.path = ".";
|
||||
build_options.original_path = getcwd(NULL, 0);
|
||||
arg_count = argc;
|
||||
args = argv;
|
||||
parse_arguments();
|
||||
return EXIT_SUCCESS;
|
||||
parse_arguments(argc, argv);
|
||||
switch (build_options.command)
|
||||
{
|
||||
case COMMAND_INIT:
|
||||
create_project();
|
||||
break;
|
||||
case COMMAND_COMPILE:
|
||||
case COMMAND_COMPILE_RUN:
|
||||
case COMMAND_MISSING:
|
||||
case COMMAND_BUILD:
|
||||
case COMMAND_RUN:
|
||||
case COMMAND_CLEAN_RUN:
|
||||
case COMMAND_CLEAN:
|
||||
case COMMAND_DIST:
|
||||
case COMMAND_DOCS:
|
||||
case COMMAND_BENCH:
|
||||
printf("TODO\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user