update
This commit is contained in:
parent
ab03aa4eb7
commit
e65c1ab9dc
|
@ -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
|
||||||
|
|
21
.travis.yml
21
.travis.yml
|
@ -0,0 +1,21 @@
|
||||||
|
language: c
|
||||||
|
|
||||||
|
os:
|
||||||
|
- linux
|
||||||
|
- osx
|
||||||
|
|
||||||
|
dist: bionic
|
||||||
|
|
||||||
|
compiler:
|
||||||
|
- gcc
|
||||||
|
- clang
|
||||||
|
|
||||||
|
branches:
|
||||||
|
only:
|
||||||
|
- master
|
||||||
|
|
||||||
|
script:
|
||||||
|
- autoreconf --install
|
||||||
|
- ./configure
|
||||||
|
- make
|
||||||
|
- make check
|
41
README.md
41
README.md
|
@ -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`
|
||||||
|
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
|
@ -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));
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue