#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <assert.h>
#include <string.h>

#include <string>
#include <array>
#include <random>
#include <chrono>

static std::mt19937 rand_generator(std::chrono::system_clock::now().time_since_epoch().count());

#define RANDFLOAT ((float)(rand_generator() % (1<<30)) / (float)(1<<30))
static std::string do_gen_rand_expr(int depth) {
  if(depth > 64) {
    return std::to_string(rand() % 100);
  }
  if(RANDFLOAT < 0.4) {
    auto op = std::array<std::string, 16> {"+", "-", "*", "==", "!=", "&&"} [rand() % 6];
    return do_gen_rand_expr(depth+1) + op + do_gen_rand_expr(depth+1);
  }
  if(RANDFLOAT < 0.4) {
    return "(" + do_gen_rand_expr(depth+1) + ")";
  }
  if(RANDFLOAT < 0.2) {
    auto tmp = do_gen_rand_expr(depth+1);
    if(tmp[0] != '-') tmp = '-' + tmp;
    return tmp;
  }
  return std::to_string(rand() % 10000);
}
#undef RANDFLOAT

// this should be enough
static char buf[65536];
static inline void gen_rand_expr() {
  auto res = do_gen_rand_expr(0);
  while(res.size() > 512 || res.size() < 16)
    res = do_gen_rand_expr(0);
  strcpy(buf, res.c_str());
}

static char code_buf[65536];
static const char *code_format =
"#include <stdio.h>\n"
"int main() { "
"  unsigned result = %s; "
"  printf(\"%%u\", result); "
"  return 0; "
"}";

int main(int argc, char *argv[]) {
  int loop = 1;
  if (argc > 1) {
    sscanf(argv[1], "%d", &loop);
  }
  int i;
  for (i = 0; i < loop; i ++) {
    gen_rand_expr();

    sprintf(code_buf, code_format, buf);

    FILE *fp = fopen(".code.c", "w");
    assert(fp != NULL);
    fputs(code_buf, fp);
    fclose(fp);

    // One test one compile: extremely slow, unusable.
    int ret = system("gcc .code.c -o .expr");
    if (ret != 0) continue;

    fp = popen("./.expr", "r");
    assert(fp != NULL);

    int result;
    fscanf(fp, "%d", &result);
    pclose(fp);

    printf("%u %s\n", result, buf);
  }
  return 0;
}
