diff --git a/CHANGELOG.md b/CHANGELOG.md index 3e4c781..d1e228a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. See [Keep a ### Added +- RND (`$`) now works in compiled programs, though backed by a different source of randomness. - GDT and GTM (`D` and `T`) now work in compiled programs. ## [1.6.2] - 2023-11-21 diff --git a/README.md b/README.md index cad6f99..6575b38 100644 --- a/README.md +++ b/README.md @@ -212,8 +212,6 @@ When using the `-c` flag, the input program will be translated into C code. The If the `-a` flag is additionally specified, the output program will use `getchar` and `putchar` for the `GTC` and `PTC` opcodes respectively. Otherwise, the output program will convert between UTF-8 and UTF-32 the same way the interpreter does. -Compiled programs cannot use multiple threads, and at this time cannot use the `RND`, `GTM`, and `GDT` opcodes. - ## Sample programs Here are some simple programs I've written. diff --git a/src/compiler.cpp b/src/compiler.cpp index d0c6532..fd6aa14 100644 --- a/src/compiler.cpp +++ b/src/compiler.cpp @@ -14,6 +14,14 @@ void compiler::write_state(std::ostream& os) { os << header; + if (std::any_of(m_fragments->cbegin(), m_fragments->cend(), [](const auto& v) { + return std::any_of(v->begin(), v->end(), [](const auto& i) { + return i.m_op == instruction::operation::RND; + }); + })) { + os << "srand(time(NULL));"; + } + for (size_t i = 0; i < m_fragments->size(); ++i) { const std::vector& frag = *m_fragments->at(i); for (size_t j = 0; j < frag.size(); ++j) { @@ -138,8 +146,8 @@ void compiler::get_c_code(const instruction& i, std::ostream& os, bool assume_as return; } case op::RND: - cerr << "Random number generation is not yet supported for compiled programs." << endl; - exit(EXIT_FAILURE); + os << "lws_push(stack, rand24());"; + return; case op::GDT: os << "lws_push(stack, get_date());"; return; diff --git a/src/compiler/lightweight_stack.h b/src/compiler/lightweight_stack.h index 08488bd..fd5f6ce 100644 --- a/src/compiler/lightweight_stack.h +++ b/src/compiler/lightweight_stack.h @@ -127,4 +127,36 @@ static inline int32_t get_date() { time_t t = time(NULL); return (int32_t)(t / SECS_PER_DAY); } + +static inline int32_t rand24() { +#if RAND_MAX >= 0x00ffffff +#if (RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX + return (int32_t)(rand() << 8) >> 8; +#else + // Unlikely, but not difficult + int x; + do { + x = rand(); + } while (x > 0x00ffffff); + return (int32_t)(x << 8) >> 8; +#endif +#else + // RAND_MAX is [0x00007fff, 0x00ffffff) + // Uhh just use twelve bits from each call +#if (RAND_MAX | (RAND_MAX >> 1)) == RAND_MAX + int lowTwelve = rand() & 0x0fff; + int highTwelve = rand() & 0x0fff; +#else + // :( + int lowTwelve, highTwelve; + do { + lowTwelve = rand(); + } while (lowTwelve > 0x0fff); + do { + highTwelve = rand(); + } while (highTwelve > 0x0fff); +#endif + return (((int32_t)highTwelve << 20) | ((int32_t)lowTwelve << 8)) >> 8; +#endif +} //)"