# The first line that doesn't start with a '#' should be the compiler command.
# It should read source code from stdin and produce an executable named
# 'test'.
bash -c '(./cflat > test.s && gcc -m32 -c test.s -o test.o && gcc -m32 test.o lib.o -o test)'

After the compiler command, anything not within a test case (surrounded by ...)
is ignored.
The closing ... should be followed by a space and then the desired result of the
test:
* OK if the code should compile,
* BAD if the code shouldn't compile, or
* Any other single line string which the code, when run, should produce.
  Whitespace may be trimmed from the front or back.


   *** Compiling ***
...
main() {
}
... OK

...
main() {
  bad
}
... BAD


   *** Comments ***
...
main() { }
/*
... BAD

...
main() {
  out(1);
  /* out(2); /* out(3); */ // */
  /* garbage */
  out(4); // out(5); garbage
  out(6);
}
... 1 4 6

   *** Variables ***
...
f(a, b) {
  out(a);
  out(b);
}
main() {
  out(a); /* a should be initialized to 0 */
  a = 1;
  b = a;
  out(b);
  out(a+b);
  f(2, 3);
}
... 0 1 2 2 3

...
/* variable can have the same name as a function */
f(f) {
  out(f);
}
main() {
  f = 2;
  f(f);
}
... 2

...
/* local variable discovery */
dummy(a) { }
a() { v; }
b() { !v; }
c() { v++; }
d() { v+0; }
e() { 0+v; }
f() { v+=0; }
g() { v=0; }
h() { dummy(v); }
i() { { v; } }
j() { return v; }
k() { if (v); }
l() { for(v;;); }
m() { for(;v;); }
n() { for(;;v); }
o() { while (v); }
p() { try {} catch(v) {} }
q() { throw v; }
main() { }
... OK


   *** Operators correctness ***
...
main() {
  /* Unop */
  out(-3);
  out(+ - + - + - + 4);
  out(!0);
  out(!2);
  out(!!2);
  out(~10);
  out(~~10);
}
... -3 -4 1 0 1 -11 10

...
main() {
  /* increment and decrement */
  out(a++);
  out(a);
  out(a--);
  out(a);
  out(++a);
  out(a);
  out(--a);
  out(a);
  out(a+++a++);
  out(a);
  out(a--+a--);
  out(a);
}
... 0 1 1 0 1 1 0 0 1 2 3 0

...
main() {
  /* Arithmetic binops */
  out(3+1);
  out(3+-1);
  out(-2+-2);
  out(3-1);
  out(3- -1);
  out(-1- -2);
  out(3*2);
  out(-2*3);
  out(-1*-1);
  out(12/4);
  out(6/-2);
  out(-5/-5);
  out(10%4);
  out(10%-4);
  out(-10%4);
  out(-10%-4);
}
... 4 2 -4 2 4 1 6 -6 1 3 -3 1 2 2 -2 -2

...
main() {
  /* Bitwise binops */
  out(3<<2);
  out(-1<<1);
  out(12>>2);
  out(-1>>1);
  out(1|4);
  out(3&5);
  out(3^5);
}
... 12 -2 3 -1 5 1 6

...
main() {
  /* Assign binops */
  a = 0; a += 2; out(a);
  a = 0; a -= 2; out(a);
  a = 2; a *= 3; out(a);
  a = 6; a /= 2; out(a);
  a = 7; a %= 4; out(a);

  a = 3; a <<= 2; out(a);
  a = 12; a >>= 2; out(a);
  a = 1; a |= 4; out(a);
  a = 3; a &= 5; out(a);
  a = 3; a ^= 5; out(a);
}
... 2 -2 6 3 3 12 3 5 1 6

...
main() {
  /* Logic binops */
  out(-2>-1);
  out(0>-1);
  out(0>0);
  out(1>0);

  out(-2>=-1);
  out(0>=-1);
  out(0>=0);
  out(1>=0);

  out(-1<-2);
  out(-2<0);
  out(1<1);
  out(0<1);

  out(-1<=-2);
  out(-2<=0);
  out(1<=1);
  out(0<=1);

  out(1==1);
  out(1==0);
  out(1!=1);
  out(1!=0);

  out(0&&1);
  out(1&&0);
  out(1&&3);
  out(0&&0);

  out(0||0);
  out(1||0);
  out(0||1);
  out(1||3);
}
... 0 1 0 1 0 1 1 1 0 1 0 1 0 1 1 1 1 0 0 1 0 0 1 0 0 1 1 1


   *** Operator precedence ***
...
op(expr, wanted, not_wanted) {
  out((expr == wanted) && (wanted != not_wanted));
}
main() {
   /* left assoc test */
  out(2) * out(3) * out(4);

  /* precedence test */
  op(~2*3,    (~2)*3,    ~(2*3));
  op(1+2*3,   1+(2*3),   (1+2)*3);
  op(1<<2+3,  1<<(2+3),  (1<<2)+3);
  op(1<2+3,   1<(2+3),   (1<2)+3);
  op(1==2<1,  1==(2<1),  (1==2)<1);
  op(2&2==2,  2&(2==2),  (2&2)==2);
  op(1^2&3,   1^(2&2),   (1^2)&2);
  op(3|2^3,   3|(2^2),   (3|2)^2);
  op(0&&2|1,  0&&(2|1),  (0&&2)|1);
  op(1||2&&0, 1||(2&&0), (1||2)&&0);

  /* right assoc test */
  a = 1; b = 2; c = 3;
  a = b = c;
  out(a); out(b); out(c);
}
... 2 3 4 1 1 1 1 1 1 1 1 1 1 3 3 3


   *** Function test ***
...
/* should compile, number of argument are not checked */
f(a,b,c) { }
main() { f(a); }
... OK

...
/* duplicate function */
f() {}
f() {}
main() {}
... BAD

...
/* duplicate formals */
f(a,b,a) {}
main() {}
... BAD

...
/* Function call evaluation order */
f(a, b, c) { out(a); out(b); out(c); }
g(a, b, c) { }
main() {
  f(1, 2, 3);
  g(out(4), out(5), out(6));
}
... 1 2 3 4 5 6

...
/* Recursive call test */
fib(x) {
        if (x < 3) return 1;
        return fib(x-1) + fib(x-2);
}
main() {
        out(fib(10));
}
... 55

...
main() {
  f(); /* will fail at linking stage */
}
... BAD


   *** if/else ***
...
main() {
  if (1) out(1);
  else   out(2);

  if (0) out(3);
  else   out(4);

  if (0)      out(5);
  else if (1) out(6);
  else        out(7);

  if (1)
    if (0)      out(8);
    else        out(9);
  else        out(10);

  if (1)    out(11);
  if (0)    out(12);
  else      out(13);
}
... 1 4 6 9 11 13


   *** Simple loop test ***
...
main() {
  sum = 0;
  for (i = 0; i <= 10; i++)
    sum += i;
  out(sum);
}
... 55

...
func(a) {
  return a-1;
}
main() {
  a = 10;
  while(func(a))
    a = func(a);
  out(a);
}
... 1

...
/* empty condition */
main() {
  for (;;) break;
  for (;;i++) {
    if (i == 3)
      break;
    out(i);
  }
}
... 0 1 2

...
main() {
  while () { }
}
... BAD

   *** Nested for/while ***
...
main() {
  for (i = 0; i < 2; i++) {
    while (0) { }
    for (j = 0; j < 2; j++)
      out (i + j);
  }
}
... 0 1 1 2


   *** break/continue tests ***
...
main() {
  if (1) {
    break;
  }
}
... BAD

...
main() {
  continue;
}
... BAD

...
/* multi level break/continue */
main() {
  for (i = 0; i < 5; i++) {
    for (j = 0; j < 5; j++) {
      if (j == 1)
        continue;
      else if (j == 3)
        break;
      out(i);
      out(j);
    }
    if (i == 2)
      break;
  }
}
... 0 0 0 2 1 0 1 2 2 0 2 2


   *** Exceptions ***
...
/* nested try/catch across functions */
g() {
  throw 4;
}
f() {
  try {
    g();
  } catch (b) {
    out(b);
    throw b-1;
  }
}
main() {
  out(1);
  try {
    f();
    out(2);
  } catch (a) {
    out(a);
  }
  out(5);
}
... 1 4 3 5

...
/* exceptions in recursive functions caught outside */
f(x) {
  if (x == 0) {
    throw -1;
  } else {
    out(x);
    f(x-1);
  }
}
main() {
  try {
    f(3);
  } catch(e) {
    out(e);
  }
}
... 3 2 1 -1

...
/* exceptions in recursive functions caught inside */
f(x) {
  try {
    if (x == 0) {
      throw -1;
    } else {
      out(x);
      f(x-1);
    }
  } catch(e) {
    out(e);
  }
}
main() {
  f(3);
}
... 3 2 1 -1

...
/* continue/break in a loop */
main() {
  for (i=0; i < 5; i++) {
    try {
      try {
        if (i == 4)
          throw 2;
      } catch {
        break;
      }
      if (i == 2)
        continue;
    } catch { }
    out(i);
  }
  out(-1);
}
... 0 1 3 -1

...
/* return within a try */
f() {
  try {
    return 0;
  } catch {
  }
}

main() {
  try {
    f();
    throw 1;
  } catch (a) {
    out(a);
  }
  out(2);
}
... 1 2

...
/* not catching an exception */
main() {
  throw 1;
}
... uncaught exception: 1
