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
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
* GNU Autotools
* GNU Make
* A C compiler (with C99 support)
## Build
Building:
```bash
# (If not already) Install the required build tools.
sudo apt install build-essential automake
# Generate configure files.
# Generate configuration script.
autoreconf --install
# Run configure script with desired options.
# Execute configuration script with desired options.
./configure --prefix=$HOME
# Compile sources and generate executables.
# Compile source code and generate executables.
make
# (Optional) Run tests.
make check
# (Optional) Install executables and man pages.
make install
```
## Usage
First, compile an Unlambda source file into bytecode.
Usage:
```bash
# Compile an Unlambda source file into bytecode.
u6ac -o foo.unl.bc foo.unl
```
Then, execute the bytecode file with the interpreter.
```bash
# execute the bytecode file.
u6a foo.unl.bc
```
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 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 = {
.text_size = htonl(text_len * sizeof(uint8_t)),
.rodata_size = htonl(rodata_len * sizeof(struct u6a_token))
.text_size = htonl(text_len * sizeof(struct u6a_vm_ins)),
.rodata_size = htonl(rodata_len * sizeof(uint8_t))
}
};
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);
if (U6A_AN_FN(lchild) == 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 {
stack[stack_top++].ins = (struct u6a_vm_ins) {
stack[++stack_top].ins = (struct u6a_vm_ins) {
.opcode = u6a_vo_app,
.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(lchild) == u6a_tf_d) {
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,
.offset = text_len++
};
} else {
stack[stack_top++].ins = (struct u6a_vm_ins) {
stack[++stack_top].ins = (struct u6a_vm_ins) {
.opcode = u6a_vo_app,
.operand.fn.first = lchild->value
};

View File

@ -118,7 +118,7 @@ vm_var_fn_free(struct u6a_vm_var_fn var) {
bool
u6a_runtime_info(FILE* restrict input_stream, const char* file_name) {
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);
return false;
}
@ -137,16 +137,18 @@ u6a_runtime_info(FILE* restrict input_stream, const char* file_name) {
bool
u6a_runtime_init(struct u6a_runtime_options* options) {
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);
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) {
u6a_err_bad_bc_ver(err_runtime, options->file_name, header.file.ver_major, header.file.ver_minor);
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));
if (UNLIKELY(text == NULL)) {
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;
bool syntax_only = false;
bool verbose = false;
char optimize_level;
char optimize_level = '1';
while (true) {
int result = getopt_long(argc, argv, "o:O::vHV", long_opts, NULL);
if (result == -1) {
@ -88,9 +88,6 @@ process_options(struct arg_options* options, int argc, char** argv) {
break;
case 'O':
optimize_level = optarg ? optarg[0] : '1';
if (optimize_level > '0') {
options->optimize_const = true;
}
case 'p':
if (UNLIKELY(options->output_file_prefix)) {
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);
return true;
}