This commit is contained in:
CismonX 2020-02-01 22:45:48 +08:00
parent ab03aa4eb7
commit e65c1ab9dc
No known key found for this signature in database
GPG Key ID: 315D6652268C5007
6 changed files with 55 additions and 41 deletions

6
.gitattributes vendored
View File

@ -1 +1,5 @@
*.h linguist-language=c # Attributes for GitHub Linguist
*.h linguist-language=c
*.1 linguist-documentation
*.ac linguist-detectable=false
*.am linguist-detectable=false

View File

@ -0,0 +1,21 @@
language: c
os:
- linux
- osx
dist: bionic
compiler:
- gcc
- clang
branches:
only:
- master
script:
- autoreconf --install
- ./configure
- make
- make check

View File

@ -6,56 +6,43 @@ Implementation of Unlambda, an esoteric programming language.
## Description ## Description
The u6a project provides a C implementation of the [Unlambda](http://www.madore.org/~david/programs/unlambda/) programming language, where Unlambda source code can be compiled into bytecode and executed in a virtual machine. The u6a project provides a bytecode compiler and a runtime system for the [Unlambda](http://www.madore.org/~david/programs/unlambda/) programming language.
Ideas behind this implementation can be found [here](https://). Ideas behind this implementation can be found [here](https://cismon.net/articles/2020/01/30/1580374678582.html).
## Requirements ## Getting Started
* A POSIX-compliant operating system Building:
* GNU Autotools
* GNU Make
* A C compiler (with C99 support)
## Build
```bash ```bash
# (If not already) Install the required build tools. # (If not already) Install the required build tools.
sudo apt install build-essential automake sudo apt install build-essential automake
# Generate configuration script.
# Generate configure files.
autoreconf --install autoreconf --install
# Execute configuration script with desired options.
# Run configure script with desired options.
./configure --prefix=$HOME ./configure --prefix=$HOME
# Compile source code and generate executables.
# Compile sources and generate executables.
make make
# (Optional) Run tests. # (Optional) Run tests.
make check make check
# (Optional) Install executables and man pages. # (Optional) Install executables and man pages.
make install make install
``` ```
## Usage Usage:
First, compile an Unlambda source file into bytecode.
```bash ```bash
# Compile an Unlambda source file into bytecode.
u6ac -o foo.unl.bc foo.unl u6ac -o foo.unl.bc foo.unl
``` # execute the bytecode file.
Then, execute the bytecode file with the interpreter.
```bash
u6a foo.unl.bc u6a foo.unl.bc
``` ```
See [**u6ac**(1)](man/u6ac.1) and [**u6a**(1)](man/u6a.1) man pages for details. See [**u6ac**(1)](man/u6ac.1) and [**u6a**(1)](man/u6a.1) man pages for details.
## TODOs ## Future Plans
* `u6adb` - An interactive debugger for Unlambda * Interactive debugger: `u6adb`
* More compile-time optimizations * More compile-time optimizations
* More test cases
* LLVM backend for `u6ac`

View File

@ -56,8 +56,8 @@ write_bc_header(FILE* restrict output_stream, uint32_t text_len, uint32_t rodata
.prog_header_size = U6A_BC_PROG_HEADER_SIZE .prog_header_size = U6A_BC_PROG_HEADER_SIZE
}, },
.prog = { .prog = {
.text_size = htonl(text_len * sizeof(uint8_t)), .text_size = htonl(text_len * sizeof(struct u6a_vm_ins)),
.rodata_size = htonl(rodata_len * sizeof(struct u6a_token)) .rodata_size = htonl(rodata_len * sizeof(uint8_t))
} }
}; };
return 1 == fwrite(&header, sizeof(struct u6a_bc_header), 1, output_stream); return 1 == fwrite(&header, sizeof(struct u6a_bc_header), 1, output_stream);
@ -111,9 +111,9 @@ u6a_codegen(struct u6a_ast_node* ast_arr, uint32_t ast_len) {
struct u6a_ast_node* rchild = U6A_AN_RIGHT(node, ast_arr); struct u6a_ast_node* rchild = U6A_AN_RIGHT(node, ast_arr);
if (U6A_AN_FN(lchild) == u6a_tf_app) { if (U6A_AN_FN(lchild) == u6a_tf_app) {
if (U6A_AN_FN(rchild) == u6a_tf_app) { if (U6A_AN_FN(rchild) == u6a_tf_app) {
stack[stack_top++].ins.opcode = u6a_vo_sa; stack[++stack_top].ins.opcode = u6a_vo_sa;
} else { } else {
stack[stack_top++].ins = (struct u6a_vm_ins) { stack[++stack_top].ins = (struct u6a_vm_ins) {
.opcode = u6a_vo_app, .opcode = u6a_vo_app,
.operand.fn.second = rchild->value .operand.fn.second = rchild->value
}; };
@ -122,12 +122,12 @@ u6a_codegen(struct u6a_ast_node* ast_arr, uint32_t ast_len) {
if (U6A_AN_FN(rchild) == u6a_tf_app) { if (U6A_AN_FN(rchild) == u6a_tf_app) {
if (U6A_AN_FN(lchild) == u6a_tf_d) { if (U6A_AN_FN(lchild) == u6a_tf_d) {
text_buffer[text_len].opcode = u6a_vo_del; text_buffer[text_len].opcode = u6a_vo_del;
stack[stack_top++] = (struct ins_with_offset) { stack[++stack_top] = (struct ins_with_offset) {
.ins.opcode = u6a_vo_la, .ins.opcode = u6a_vo_la,
.offset = text_len++ .offset = text_len++
}; };
} else { } else {
stack[stack_top++].ins = (struct u6a_vm_ins) { stack[++stack_top].ins = (struct u6a_vm_ins) {
.opcode = u6a_vo_app, .opcode = u6a_vo_app,
.operand.fn.first = lchild->value .operand.fn.first = lchild->value
}; };

View File

@ -118,7 +118,7 @@ vm_var_fn_free(struct u6a_vm_var_fn var) {
bool bool
u6a_runtime_info(FILE* restrict input_stream, const char* file_name) { u6a_runtime_info(FILE* restrict input_stream, const char* file_name) {
struct u6a_bc_header header; struct u6a_bc_header header;
if (UNLIKELY(read_bc_header(&header, input_stream))) { if (UNLIKELY(!read_bc_header(&header, input_stream))) {
u6a_err_invalid_bc_file(err_runtime, file_name); u6a_err_invalid_bc_file(err_runtime, file_name);
return false; return false;
} }
@ -137,16 +137,18 @@ u6a_runtime_info(FILE* restrict input_stream, const char* file_name) {
bool bool
u6a_runtime_init(struct u6a_runtime_options* options) { u6a_runtime_init(struct u6a_runtime_options* options) {
struct u6a_bc_header header; struct u6a_bc_header header;
if (UNLIKELY(read_bc_header(&header, options->istream))) { if (UNLIKELY(!read_bc_header(&header, options->istream))) {
u6a_err_invalid_bc_file(err_runtime, options->file_name); u6a_err_invalid_bc_file(err_runtime, options->file_name);
return false; return false;
} }
if (UNLIKELY(CHECK_BC_HEADER_VER(header.file))) { if (UNLIKELY(!CHECK_BC_HEADER_VER(header.file))) {
if (!options->force_exec || header.file.prog_header_size != U6A_BC_FILE_HEADER_SIZE) { if (!options->force_exec || header.file.prog_header_size != U6A_BC_FILE_HEADER_SIZE) {
u6a_err_bad_bc_ver(err_runtime, options->file_name, header.file.ver_major, header.file.ver_minor); u6a_err_bad_bc_ver(err_runtime, options->file_name, header.file.ver_major, header.file.ver_minor);
return false; return false;
} }
} }
header.prog.text_size = ntohl(header.prog.text_size);
header.prog.rodata_size = ntohl(header.prog.rodata_size);
text = malloc(header.prog.text_size + sizeof(text_subst)); text = malloc(header.prog.text_size + sizeof(text_subst));
if (UNLIKELY(text == NULL)) { if (UNLIKELY(text == NULL)) {
u6a_err_bad_alloc(err_runtime, header.prog.text_size + sizeof(text_subst)); u6a_err_bad_alloc(err_runtime, header.prog.text_size + sizeof(text_subst));

View File

@ -73,7 +73,7 @@ process_options(struct arg_options* options, int argc, char** argv) {
options->optimize_const = false; options->optimize_const = false;
bool syntax_only = false; bool syntax_only = false;
bool verbose = false; bool verbose = false;
char optimize_level; char optimize_level = '1';
while (true) { while (true) {
int result = getopt_long(argc, argv, "o:O::vHV", long_opts, NULL); int result = getopt_long(argc, argv, "o:O::vHV", long_opts, NULL);
if (result == -1) { if (result == -1) {
@ -88,9 +88,6 @@ process_options(struct arg_options* options, int argc, char** argv) {
break; break;
case 'O': case 'O':
optimize_level = optarg ? optarg[0] : '1'; optimize_level = optarg ? optarg[0] : '1';
if (optimize_level > '0') {
options->optimize_const = true;
}
case 'p': case 'p':
if (UNLIKELY(options->output_file_prefix)) { if (UNLIKELY(options->output_file_prefix)) {
break; break;
@ -177,6 +174,9 @@ process_options(struct arg_options* options, int argc, char** argv) {
} }
} }
} }
if (optimize_level > '0') {
options->optimize_const = true;
}
u6a_logging_verbose(verbose); u6a_logging_verbose(verbose);
return true; return true;
} }