From e65c1ab9dc9bc04535b1aba3462c93ff830bb546 Mon Sep 17 00:00:00 2001 From: CismonX Date: Sat, 1 Feb 2020 22:45:48 +0800 Subject: [PATCH] update --- .gitattributes | 6 +++++- .travis.yml | 21 +++++++++++++++++++++ README.md | 41 ++++++++++++++--------------------------- src/codegen.c | 12 ++++++------ src/runtime.c | 8 +++++--- src/u6ac.c | 8 ++++---- 6 files changed, 55 insertions(+), 41 deletions(-) diff --git a/.gitattributes b/.gitattributes index 5170675..d5fb949 100644 --- a/.gitattributes +++ b/.gitattributes @@ -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 diff --git a/.travis.yml b/.travis.yml index e69de29..2ead638 100644 --- a/.travis.yml +++ b/.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 diff --git a/README.md b/README.md index 47615c1..aee4c92 100644 --- a/README.md +++ b/README.md @@ -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` diff --git a/src/codegen.c b/src/codegen.c index 4b6e2fb..c7af705 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -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 }; diff --git a/src/runtime.c b/src/runtime.c index 7dd0755..8679200 100644 --- a/src/runtime.c +++ b/src/runtime.c @@ -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)); diff --git a/src/u6ac.c b/src/u6ac.c index 64cab8b..702444c 100644 --- a/src/u6ac.c +++ b/src/u6ac.c @@ -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; }