diff --git a/project5_testcases/test100/01.in b/project5_testcases/test100/01.in new file mode 100644 index 0000000..395f206 --- /dev/null +++ b/project5_testcases/test100/01.in @@ -0,0 +1 @@ +10 3 diff --git a/project5_testcases/test100/01.out b/project5_testcases/test100/01.out new file mode 100644 index 0000000..bb70277 --- /dev/null +++ b/project5_testcases/test100/01.out @@ -0,0 +1 @@ +13 7 30 3 1 -10 \ No newline at end of file diff --git a/project5_testcases/test100/02.in b/project5_testcases/test100/02.in new file mode 100644 index 0000000..63d7642 --- /dev/null +++ b/project5_testcases/test100/02.in @@ -0,0 +1 @@ +20 5 diff --git a/project5_testcases/test100/02.out b/project5_testcases/test100/02.out new file mode 100644 index 0000000..35abf45 --- /dev/null +++ b/project5_testcases/test100/02.out @@ -0,0 +1 @@ +25 15 100 4 0 -20 \ No newline at end of file diff --git a/project5_testcases/test100/03.in b/project5_testcases/test100/03.in new file mode 100644 index 0000000..0e2a695 --- /dev/null +++ b/project5_testcases/test100/03.in @@ -0,0 +1 @@ +100 7 diff --git a/project5_testcases/test100/03.out b/project5_testcases/test100/03.out new file mode 100644 index 0000000..7fdb0f3 --- /dev/null +++ b/project5_testcases/test100/03.out @@ -0,0 +1 @@ +107 93 700 14 2 -100 \ No newline at end of file diff --git a/project5_testcases/test100/04.in b/project5_testcases/test100/04.in new file mode 100644 index 0000000..f70a163 --- /dev/null +++ b/project5_testcases/test100/04.in @@ -0,0 +1 @@ +50 8 diff --git a/project5_testcases/test100/04.out b/project5_testcases/test100/04.out new file mode 100644 index 0000000..fdbc307 --- /dev/null +++ b/project5_testcases/test100/04.out @@ -0,0 +1 @@ +58 42 400 6 2 -50 \ No newline at end of file diff --git a/project5_testcases/test100/05.in b/project5_testcases/test100/05.in new file mode 100644 index 0000000..0fadabb --- /dev/null +++ b/project5_testcases/test100/05.in @@ -0,0 +1 @@ +-15 4 diff --git a/project5_testcases/test100/05.out b/project5_testcases/test100/05.out new file mode 100644 index 0000000..68df3f0 --- /dev/null +++ b/project5_testcases/test100/05.out @@ -0,0 +1 @@ +-11 -19 -60 -3 -3 15 \ No newline at end of file diff --git a/project5_testcases/test100/Your_own_test_begins_at_100 b/project5_testcases/test100/Your_own_test_begins_at_100 deleted file mode 100644 index 82fa4db..0000000 --- a/project5_testcases/test100/Your_own_test_begins_at_100 +++ /dev/null @@ -1 +0,0 @@ -quq \ No newline at end of file diff --git a/project5_testcases/test100/splc.c b/project5_testcases/test100/splc.c new file mode 100644 index 0000000..2bb6f33 --- /dev/null +++ b/project5_testcases/test100/splc.c @@ -0,0 +1,17 @@ +int readint(); +int writeint(int out); + +// Test 100: Basic arithmetic operations +int main0() { + int a = readint(); + int b = readint(); + + writeint(a + b); + writeint(a - b); + writeint(a * b); + writeint(a / b); + writeint(a % b); + writeint(-a); + + return 0; +} diff --git a/project5_testcases/test101/01.in b/project5_testcases/test101/01.in new file mode 100644 index 0000000..3303b14 --- /dev/null +++ b/project5_testcases/test101/01.in @@ -0,0 +1 @@ +5 3 diff --git a/project5_testcases/test101/01.out b/project5_testcases/test101/01.out new file mode 100644 index 0000000..9d9be13 --- /dev/null +++ b/project5_testcases/test101/01.out @@ -0,0 +1 @@ +1 0 1 0 0 1 1 \ No newline at end of file diff --git a/project5_testcases/test101/02.in b/project5_testcases/test101/02.in new file mode 100644 index 0000000..ac81dc6 --- /dev/null +++ b/project5_testcases/test101/02.in @@ -0,0 +1 @@ +3 3 diff --git a/project5_testcases/test101/02.out b/project5_testcases/test101/02.out new file mode 100644 index 0000000..c924120 --- /dev/null +++ b/project5_testcases/test101/02.out @@ -0,0 +1 @@ +0 0 1 1 1 0 0 \ No newline at end of file diff --git a/project5_testcases/test101/03.in b/project5_testcases/test101/03.in new file mode 100644 index 0000000..c0be89e --- /dev/null +++ b/project5_testcases/test101/03.in @@ -0,0 +1 @@ +2 8 diff --git a/project5_testcases/test101/03.out b/project5_testcases/test101/03.out new file mode 100644 index 0000000..a6e5bec --- /dev/null +++ b/project5_testcases/test101/03.out @@ -0,0 +1 @@ +0 1 0 1 0 1 0 \ No newline at end of file diff --git a/project5_testcases/test101/04.in b/project5_testcases/test101/04.in new file mode 100644 index 0000000..d8d67df --- /dev/null +++ b/project5_testcases/test101/04.in @@ -0,0 +1 @@ +-5 3 diff --git a/project5_testcases/test101/04.out b/project5_testcases/test101/04.out new file mode 100644 index 0000000..a6e5bec --- /dev/null +++ b/project5_testcases/test101/04.out @@ -0,0 +1 @@ +0 1 0 1 0 1 0 \ No newline at end of file diff --git a/project5_testcases/test101/05.in b/project5_testcases/test101/05.in new file mode 100644 index 0000000..b748e2d --- /dev/null +++ b/project5_testcases/test101/05.in @@ -0,0 +1 @@ +0 0 diff --git a/project5_testcases/test101/05.out b/project5_testcases/test101/05.out new file mode 100644 index 0000000..c924120 --- /dev/null +++ b/project5_testcases/test101/05.out @@ -0,0 +1 @@ +0 0 1 1 1 0 0 \ No newline at end of file diff --git a/project5_testcases/test101/splc.c b/project5_testcases/test101/splc.c new file mode 100644 index 0000000..85e4481 --- /dev/null +++ b/project5_testcases/test101/splc.c @@ -0,0 +1,23 @@ +int readint(); +int writeint(int out); + +// Test 101: Comparison and conditional operations +int main0() { + int a = readint(); + int b = readint(); + + writeint(a > b); + writeint(a < b); + writeint(a >= b); + writeint(a <= b); + writeint(a == b); + writeint(a != b); + + if (a > b) { + writeint(1); + } else { + writeint(0); + } + + return 0; +} diff --git a/project5_testcases/test102/01.in b/project5_testcases/test102/01.in new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/project5_testcases/test102/01.in @@ -0,0 +1 @@ +5 diff --git a/project5_testcases/test102/01.out b/project5_testcases/test102/01.out new file mode 100644 index 0000000..fb6bde3 --- /dev/null +++ b/project5_testcases/test102/01.out @@ -0,0 +1 @@ +10 5 \ No newline at end of file diff --git a/project5_testcases/test102/02.in b/project5_testcases/test102/02.in new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/project5_testcases/test102/02.in @@ -0,0 +1 @@ +10 diff --git a/project5_testcases/test102/02.out b/project5_testcases/test102/02.out new file mode 100644 index 0000000..e3ddb46 --- /dev/null +++ b/project5_testcases/test102/02.out @@ -0,0 +1 @@ +45 10 \ No newline at end of file diff --git a/project5_testcases/test102/03.in b/project5_testcases/test102/03.in new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/project5_testcases/test102/03.in @@ -0,0 +1 @@ +1 diff --git a/project5_testcases/test102/03.out b/project5_testcases/test102/03.out new file mode 100644 index 0000000..6635e61 --- /dev/null +++ b/project5_testcases/test102/03.out @@ -0,0 +1 @@ +0 1 \ No newline at end of file diff --git a/project5_testcases/test102/04.in b/project5_testcases/test102/04.in new file mode 100644 index 0000000..573541a --- /dev/null +++ b/project5_testcases/test102/04.in @@ -0,0 +1 @@ +0 diff --git a/project5_testcases/test102/04.out b/project5_testcases/test102/04.out new file mode 100644 index 0000000..856bc0e --- /dev/null +++ b/project5_testcases/test102/04.out @@ -0,0 +1 @@ +0 0 \ No newline at end of file diff --git a/project5_testcases/test102/05.in b/project5_testcases/test102/05.in new file mode 100644 index 0000000..209e3ef --- /dev/null +++ b/project5_testcases/test102/05.in @@ -0,0 +1 @@ +20 diff --git a/project5_testcases/test102/05.out b/project5_testcases/test102/05.out new file mode 100644 index 0000000..30e0de2 --- /dev/null +++ b/project5_testcases/test102/05.out @@ -0,0 +1 @@ +190 20 \ No newline at end of file diff --git a/project5_testcases/test102/splc.c b/project5_testcases/test102/splc.c new file mode 100644 index 0000000..29e852c --- /dev/null +++ b/project5_testcases/test102/splc.c @@ -0,0 +1,19 @@ +int readint(); +int writeint(int out); + +// Test 102: While loop and simple accumulation +int main0() { + int n = readint(); + int sum = 0; + int i = 0; + + while (i < n) { + sum = sum + i; + i = i + 1; + } + + writeint(sum); + writeint(i); + + return 0; +} diff --git a/project5_testcases/test103/01.in b/project5_testcases/test103/01.in new file mode 100644 index 0000000..99e00b5 --- /dev/null +++ b/project5_testcases/test103/01.in @@ -0,0 +1,2 @@ +3 +1 2 3 diff --git a/project5_testcases/test103/01.out b/project5_testcases/test103/01.out new file mode 100644 index 0000000..7b697b8 --- /dev/null +++ b/project5_testcases/test103/01.out @@ -0,0 +1 @@ +1 2 3 4 \ No newline at end of file diff --git a/project5_testcases/test103/02.in b/project5_testcases/test103/02.in new file mode 100644 index 0000000..823123c --- /dev/null +++ b/project5_testcases/test103/02.in @@ -0,0 +1,2 @@ +5 +10 20 30 40 50 diff --git a/project5_testcases/test103/02.out b/project5_testcases/test103/02.out new file mode 100644 index 0000000..2b8d31b --- /dev/null +++ b/project5_testcases/test103/02.out @@ -0,0 +1 @@ +10 20 30 40 50 60 \ No newline at end of file diff --git a/project5_testcases/test103/03.in b/project5_testcases/test103/03.in new file mode 100644 index 0000000..0d5fc37 --- /dev/null +++ b/project5_testcases/test103/03.in @@ -0,0 +1,2 @@ +2 +-5 5 diff --git a/project5_testcases/test103/03.out b/project5_testcases/test103/03.out new file mode 100644 index 0000000..c863ba3 --- /dev/null +++ b/project5_testcases/test103/03.out @@ -0,0 +1 @@ +-5 5 0 \ No newline at end of file diff --git a/project5_testcases/test103/04.in b/project5_testcases/test103/04.in new file mode 100644 index 0000000..99c49ea --- /dev/null +++ b/project5_testcases/test103/04.in @@ -0,0 +1,2 @@ +4 +7 8 9 10 diff --git a/project5_testcases/test103/04.out b/project5_testcases/test103/04.out new file mode 100644 index 0000000..aa4051a --- /dev/null +++ b/project5_testcases/test103/04.out @@ -0,0 +1 @@ +7 8 9 10 17 \ No newline at end of file diff --git a/project5_testcases/test103/05.in b/project5_testcases/test103/05.in new file mode 100644 index 0000000..192e9d9 --- /dev/null +++ b/project5_testcases/test103/05.in @@ -0,0 +1,2 @@ +1 +42 diff --git a/project5_testcases/test103/05.out b/project5_testcases/test103/05.out new file mode 100644 index 0000000..3a204ec --- /dev/null +++ b/project5_testcases/test103/05.out @@ -0,0 +1 @@ +42 84 \ No newline at end of file diff --git a/project5_testcases/test103/splc.c b/project5_testcases/test103/splc.c new file mode 100644 index 0000000..073ad12 --- /dev/null +++ b/project5_testcases/test103/splc.c @@ -0,0 +1,25 @@ +int readint(); +int writeint(int out); + +// Test 103: Array read and write +int arr[10]; + +int main0() { + int n = readint(); + int i = 0; + + while (i < n) { + arr[i] = readint(); + i = i + 1; + } + + i = 0; + while (i < n) { + writeint(arr[i]); + i = i + 1; + } + + writeint(arr[0] + arr[n - 1]); + + return 0; +} diff --git a/project5_testcases/test104/01.in b/project5_testcases/test104/01.in new file mode 100644 index 0000000..3303b14 --- /dev/null +++ b/project5_testcases/test104/01.in @@ -0,0 +1 @@ +5 3 diff --git a/project5_testcases/test104/01.out b/project5_testcases/test104/01.out new file mode 100644 index 0000000..cf58fa6 --- /dev/null +++ b/project5_testcases/test104/01.out @@ -0,0 +1 @@ +8 15 23 \ No newline at end of file diff --git a/project5_testcases/test104/02.in b/project5_testcases/test104/02.in new file mode 100644 index 0000000..0e9a360 --- /dev/null +++ b/project5_testcases/test104/02.in @@ -0,0 +1 @@ +10 7 diff --git a/project5_testcases/test104/02.out b/project5_testcases/test104/02.out new file mode 100644 index 0000000..1422b98 --- /dev/null +++ b/project5_testcases/test104/02.out @@ -0,0 +1 @@ +17 70 87 \ No newline at end of file diff --git a/project5_testcases/test104/03.in b/project5_testcases/test104/03.in new file mode 100644 index 0000000..b748e2d --- /dev/null +++ b/project5_testcases/test104/03.in @@ -0,0 +1 @@ +0 0 diff --git a/project5_testcases/test104/03.out b/project5_testcases/test104/03.out new file mode 100644 index 0000000..ef6b967 --- /dev/null +++ b/project5_testcases/test104/03.out @@ -0,0 +1 @@ +0 0 0 \ No newline at end of file diff --git a/project5_testcases/test104/04.in b/project5_testcases/test104/04.in new file mode 100644 index 0000000..c7a0cd9 --- /dev/null +++ b/project5_testcases/test104/04.in @@ -0,0 +1 @@ +100 50 diff --git a/project5_testcases/test104/04.out b/project5_testcases/test104/04.out new file mode 100644 index 0000000..da8fd92 --- /dev/null +++ b/project5_testcases/test104/04.out @@ -0,0 +1 @@ +150 5000 5150 \ No newline at end of file diff --git a/project5_testcases/test104/05.in b/project5_testcases/test104/05.in new file mode 100644 index 0000000..51a91f6 --- /dev/null +++ b/project5_testcases/test104/05.in @@ -0,0 +1 @@ +-5 8 diff --git a/project5_testcases/test104/05.out b/project5_testcases/test104/05.out new file mode 100644 index 0000000..1fdcf57 --- /dev/null +++ b/project5_testcases/test104/05.out @@ -0,0 +1 @@ +3 -40 -37 \ No newline at end of file diff --git a/project5_testcases/test104/splc.c b/project5_testcases/test104/splc.c new file mode 100644 index 0000000..293d6fa --- /dev/null +++ b/project5_testcases/test104/splc.c @@ -0,0 +1,25 @@ +int readint(); +int writeint(int out); + +// Test 104: Simple function calls +int add(int a, int b) { + return a + b; +} + +int multiply(int a, int b) { + return a * b; +} + +int main0() { + int x = readint(); + int y = readint(); + + int sum = add(x, y); + int prod = multiply(x, y); + + writeint(sum); + writeint(prod); + writeint(add(sum, prod)); + + return 0; +} diff --git a/project5_testcases/test105/01.in b/project5_testcases/test105/01.in new file mode 100644 index 0000000..3303b14 --- /dev/null +++ b/project5_testcases/test105/01.in @@ -0,0 +1 @@ +5 3 diff --git a/project5_testcases/test105/01.out b/project5_testcases/test105/01.out new file mode 100644 index 0000000..c72eca0 --- /dev/null +++ b/project5_testcases/test105/01.out @@ -0,0 +1 @@ +1 0 0 \ No newline at end of file diff --git a/project5_testcases/test105/02.in b/project5_testcases/test105/02.in new file mode 100644 index 0000000..d8d67df --- /dev/null +++ b/project5_testcases/test105/02.in @@ -0,0 +1 @@ +-5 3 diff --git a/project5_testcases/test105/02.out b/project5_testcases/test105/02.out new file mode 100644 index 0000000..7dfd248 --- /dev/null +++ b/project5_testcases/test105/02.out @@ -0,0 +1 @@ +0 1 0 \ No newline at end of file diff --git a/project5_testcases/test105/03.in b/project5_testcases/test105/03.in new file mode 100644 index 0000000..8a0e5b5 --- /dev/null +++ b/project5_testcases/test105/03.in @@ -0,0 +1 @@ +5 -3 diff --git a/project5_testcases/test105/03.out b/project5_testcases/test105/03.out new file mode 100644 index 0000000..7dfd248 --- /dev/null +++ b/project5_testcases/test105/03.out @@ -0,0 +1 @@ +0 1 0 \ No newline at end of file diff --git a/project5_testcases/test105/04.in b/project5_testcases/test105/04.in new file mode 100644 index 0000000..b748e2d --- /dev/null +++ b/project5_testcases/test105/04.in @@ -0,0 +1 @@ +0 0 diff --git a/project5_testcases/test105/04.out b/project5_testcases/test105/04.out new file mode 100644 index 0000000..51d7369 --- /dev/null +++ b/project5_testcases/test105/04.out @@ -0,0 +1 @@ +0 0 1 \ No newline at end of file diff --git a/project5_testcases/test105/05.in b/project5_testcases/test105/05.in new file mode 100644 index 0000000..9bb5239 --- /dev/null +++ b/project5_testcases/test105/05.in @@ -0,0 +1 @@ +-5 -3 diff --git a/project5_testcases/test105/05.out b/project5_testcases/test105/05.out new file mode 100644 index 0000000..7dfd248 --- /dev/null +++ b/project5_testcases/test105/05.out @@ -0,0 +1 @@ +0 1 0 \ No newline at end of file diff --git a/project5_testcases/test105/splc.c b/project5_testcases/test105/splc.c new file mode 100644 index 0000000..85b0ac0 --- /dev/null +++ b/project5_testcases/test105/splc.c @@ -0,0 +1,28 @@ +int readint(); +int writeint(int out); + +// Test 105: Short-circuit evaluation +int main0() { + int a = readint(); + int b = readint(); + + if (a > 0 && b > 0) { + writeint(1); + } else { + writeint(0); + } + + if (a < 0 || b < 0) { + writeint(1); + } else { + writeint(0); + } + + if (a == 0 && b == 0) { + writeint(1); + } else { + writeint(0); + } + + return 0; +} diff --git a/project5_testcases/test106/01.in b/project5_testcases/test106/01.in new file mode 100644 index 0000000..3303b14 --- /dev/null +++ b/project5_testcases/test106/01.in @@ -0,0 +1 @@ +5 3 diff --git a/project5_testcases/test106/01.out b/project5_testcases/test106/01.out new file mode 100644 index 0000000..9b22fc4 --- /dev/null +++ b/project5_testcases/test106/01.out @@ -0,0 +1 @@ +5 3 8 15 \ No newline at end of file diff --git a/project5_testcases/test106/02.in b/project5_testcases/test106/02.in new file mode 100644 index 0000000..ed40cec --- /dev/null +++ b/project5_testcases/test106/02.in @@ -0,0 +1 @@ +10 20 diff --git a/project5_testcases/test106/02.out b/project5_testcases/test106/02.out new file mode 100644 index 0000000..5bcae40 --- /dev/null +++ b/project5_testcases/test106/02.out @@ -0,0 +1 @@ +10 20 30 200 \ No newline at end of file diff --git a/project5_testcases/test106/03.in b/project5_testcases/test106/03.in new file mode 100644 index 0000000..b748e2d --- /dev/null +++ b/project5_testcases/test106/03.in @@ -0,0 +1 @@ +0 0 diff --git a/project5_testcases/test106/03.out b/project5_testcases/test106/03.out new file mode 100644 index 0000000..f6f83b9 --- /dev/null +++ b/project5_testcases/test106/03.out @@ -0,0 +1 @@ +0 0 0 0 \ No newline at end of file diff --git a/project5_testcases/test106/04.in b/project5_testcases/test106/04.in new file mode 100644 index 0000000..51a91f6 --- /dev/null +++ b/project5_testcases/test106/04.in @@ -0,0 +1 @@ +-5 8 diff --git a/project5_testcases/test106/04.out b/project5_testcases/test106/04.out new file mode 100644 index 0000000..f5012b8 --- /dev/null +++ b/project5_testcases/test106/04.out @@ -0,0 +1 @@ +-5 8 3 -40 \ No newline at end of file diff --git a/project5_testcases/test106/05.in b/project5_testcases/test106/05.in new file mode 100644 index 0000000..11c8dd7 --- /dev/null +++ b/project5_testcases/test106/05.in @@ -0,0 +1 @@ +7 7 diff --git a/project5_testcases/test106/05.out b/project5_testcases/test106/05.out new file mode 100644 index 0000000..af0331c --- /dev/null +++ b/project5_testcases/test106/05.out @@ -0,0 +1 @@ +7 7 14 49 \ No newline at end of file diff --git a/project5_testcases/test106/splc.c b/project5_testcases/test106/splc.c new file mode 100644 index 0000000..28c7fd5 --- /dev/null +++ b/project5_testcases/test106/splc.c @@ -0,0 +1,21 @@ +int readint(); +int writeint(int out); + +// Test 106: Simple struct operations +struct Point { + int x; + int y; +}; + +int main0() { + struct Point p; + p.x = readint(); + p.y = readint(); + + writeint(p.x); + writeint(p.y); + writeint(p.x + p.y); + writeint(p.x * p.y); + + return 0; +} diff --git a/project5_testcases/test107/01.in b/project5_testcases/test107/01.in new file mode 100644 index 0000000..9c6f148 --- /dev/null +++ b/project5_testcases/test107/01.in @@ -0,0 +1,3 @@ +2 +1 2 +3 4 diff --git a/project5_testcases/test107/01.out b/project5_testcases/test107/01.out new file mode 100644 index 0000000..765f131 --- /dev/null +++ b/project5_testcases/test107/01.out @@ -0,0 +1 @@ +3 7 \ No newline at end of file diff --git a/project5_testcases/test107/02.in b/project5_testcases/test107/02.in new file mode 100644 index 0000000..635f3a7 --- /dev/null +++ b/project5_testcases/test107/02.in @@ -0,0 +1,4 @@ +3 +5 5 +10 20 +0 0 diff --git a/project5_testcases/test107/02.out b/project5_testcases/test107/02.out new file mode 100644 index 0000000..93190a4 --- /dev/null +++ b/project5_testcases/test107/02.out @@ -0,0 +1 @@ +10 30 0 \ No newline at end of file diff --git a/project5_testcases/test107/03.in b/project5_testcases/test107/03.in new file mode 100644 index 0000000..2e0fe5d --- /dev/null +++ b/project5_testcases/test107/03.in @@ -0,0 +1,2 @@ +1 +100 200 diff --git a/project5_testcases/test107/03.out b/project5_testcases/test107/03.out new file mode 100644 index 0000000..4d534a3 --- /dev/null +++ b/project5_testcases/test107/03.out @@ -0,0 +1 @@ +300 \ No newline at end of file diff --git a/project5_testcases/test107/04.in b/project5_testcases/test107/04.in new file mode 100644 index 0000000..9a7e65d --- /dev/null +++ b/project5_testcases/test107/04.in @@ -0,0 +1,5 @@ +4 +1 1 +2 2 +3 3 +4 4 diff --git a/project5_testcases/test107/04.out b/project5_testcases/test107/04.out new file mode 100644 index 0000000..8f52d54 --- /dev/null +++ b/project5_testcases/test107/04.out @@ -0,0 +1 @@ +2 4 6 8 \ No newline at end of file diff --git a/project5_testcases/test107/05.in b/project5_testcases/test107/05.in new file mode 100644 index 0000000..e7fbb4d --- /dev/null +++ b/project5_testcases/test107/05.in @@ -0,0 +1,3 @@ +2 +-5 10 +8 -3 diff --git a/project5_testcases/test107/05.out b/project5_testcases/test107/05.out new file mode 100644 index 0000000..3bffa35 --- /dev/null +++ b/project5_testcases/test107/05.out @@ -0,0 +1 @@ +5 5 \ No newline at end of file diff --git a/project5_testcases/test107/splc.c b/project5_testcases/test107/splc.c new file mode 100644 index 0000000..7da3f87 --- /dev/null +++ b/project5_testcases/test107/splc.c @@ -0,0 +1,29 @@ +int readint(); +int writeint(int out); + +// Test 107: Struct array and member access +struct Data { + int a; + int b; +}; + +struct Data arr[5]; + +int main0() { + int n = readint(); + int i = 0; + + while (i < n) { + arr[i].a = readint(); + arr[i].b = readint(); + i = i + 1; + } + + i = 0; + while (i < n) { + writeint(arr[i].a + arr[i].b); + i = i + 1; + } + + return 0; +} diff --git a/project5_testcases/test108/01.in b/project5_testcases/test108/01.in new file mode 100644 index 0000000..aab0fad --- /dev/null +++ b/project5_testcases/test108/01.in @@ -0,0 +1,2 @@ +3 +10 20 30 diff --git a/project5_testcases/test108/01.out b/project5_testcases/test108/01.out new file mode 100644 index 0000000..b4ee7e1 --- /dev/null +++ b/project5_testcases/test108/01.out @@ -0,0 +1 @@ +10 20 30 \ No newline at end of file diff --git a/project5_testcases/test108/02.in b/project5_testcases/test108/02.in new file mode 100644 index 0000000..c278a74 --- /dev/null +++ b/project5_testcases/test108/02.in @@ -0,0 +1,2 @@ +2 +5 15 diff --git a/project5_testcases/test108/02.out b/project5_testcases/test108/02.out new file mode 100644 index 0000000..c0c0100 --- /dev/null +++ b/project5_testcases/test108/02.out @@ -0,0 +1 @@ +5 15 \ No newline at end of file diff --git a/project5_testcases/test108/03.in b/project5_testcases/test108/03.in new file mode 100644 index 0000000..18a4d51 --- /dev/null +++ b/project5_testcases/test108/03.in @@ -0,0 +1,2 @@ +4 +1 2 3 4 diff --git a/project5_testcases/test108/03.out b/project5_testcases/test108/03.out new file mode 100644 index 0000000..7b697b8 --- /dev/null +++ b/project5_testcases/test108/03.out @@ -0,0 +1 @@ +1 2 3 4 \ No newline at end of file diff --git a/project5_testcases/test108/04.in b/project5_testcases/test108/04.in new file mode 100644 index 0000000..ace1d56 --- /dev/null +++ b/project5_testcases/test108/04.in @@ -0,0 +1,2 @@ +1 +100 diff --git a/project5_testcases/test108/04.out b/project5_testcases/test108/04.out new file mode 100644 index 0000000..a5879dc --- /dev/null +++ b/project5_testcases/test108/04.out @@ -0,0 +1 @@ +100 \ No newline at end of file diff --git a/project5_testcases/test108/05.in b/project5_testcases/test108/05.in new file mode 100644 index 0000000..0339e6e --- /dev/null +++ b/project5_testcases/test108/05.in @@ -0,0 +1,2 @@ +5 +-5 0 5 10 15 diff --git a/project5_testcases/test108/05.out b/project5_testcases/test108/05.out new file mode 100644 index 0000000..f922e63 --- /dev/null +++ b/project5_testcases/test108/05.out @@ -0,0 +1 @@ +-5 0 5 10 15 \ No newline at end of file diff --git a/project5_testcases/test108/splc.c b/project5_testcases/test108/splc.c new file mode 100644 index 0000000..63b5b13 --- /dev/null +++ b/project5_testcases/test108/splc.c @@ -0,0 +1,33 @@ +int readint(); +int writeint(int out); + +// Test 108: Simple struct pointer operations +struct Item { + int value; +}; + +struct Item items[5]; + +int set_value(struct Item *p, int v) { + p->value = v; + return 0; +} + +int main0() { + int n = readint(); + int i = 0; + + while (i < n) { + int v = readint(); + set_value(&items[i], v); + i = i + 1; + } + + i = 0; + while (i < n) { + writeint(items[i].value); + i = i + 1; + } + + return 0; +} diff --git a/project5_testcases/test109/01.in b/project5_testcases/test109/01.in new file mode 100644 index 0000000..9c6f148 --- /dev/null +++ b/project5_testcases/test109/01.in @@ -0,0 +1,3 @@ +2 +1 2 +3 4 diff --git a/project5_testcases/test109/01.out b/project5_testcases/test109/01.out new file mode 100644 index 0000000..765f131 --- /dev/null +++ b/project5_testcases/test109/01.out @@ -0,0 +1 @@ +3 7 \ No newline at end of file diff --git a/project5_testcases/test109/02.in b/project5_testcases/test109/02.in new file mode 100644 index 0000000..e3ee4d2 --- /dev/null +++ b/project5_testcases/test109/02.in @@ -0,0 +1,4 @@ +3 +5 5 +10 10 +0 0 diff --git a/project5_testcases/test109/02.out b/project5_testcases/test109/02.out new file mode 100644 index 0000000..96958b0 --- /dev/null +++ b/project5_testcases/test109/02.out @@ -0,0 +1 @@ +10 20 0 \ No newline at end of file diff --git a/project5_testcases/test109/03.in b/project5_testcases/test109/03.in new file mode 100644 index 0000000..2e0fe5d --- /dev/null +++ b/project5_testcases/test109/03.in @@ -0,0 +1,2 @@ +1 +100 200 diff --git a/project5_testcases/test109/03.out b/project5_testcases/test109/03.out new file mode 100644 index 0000000..4d534a3 --- /dev/null +++ b/project5_testcases/test109/03.out @@ -0,0 +1 @@ +300 \ No newline at end of file diff --git a/project5_testcases/test109/04.in b/project5_testcases/test109/04.in new file mode 100644 index 0000000..6dc196a --- /dev/null +++ b/project5_testcases/test109/04.in @@ -0,0 +1,5 @@ +4 +-5 10 +8 -3 +0 0 +1 1 diff --git a/project5_testcases/test109/04.out b/project5_testcases/test109/04.out new file mode 100644 index 0000000..6c0eae4 --- /dev/null +++ b/project5_testcases/test109/04.out @@ -0,0 +1 @@ +5 5 0 2 \ No newline at end of file diff --git a/project5_testcases/test109/05.in b/project5_testcases/test109/05.in new file mode 100644 index 0000000..b991c47 --- /dev/null +++ b/project5_testcases/test109/05.in @@ -0,0 +1,3 @@ +2 +50 50 +25 75 diff --git a/project5_testcases/test109/05.out b/project5_testcases/test109/05.out new file mode 100644 index 0000000..d3ff3ef --- /dev/null +++ b/project5_testcases/test109/05.out @@ -0,0 +1 @@ +100 100 \ No newline at end of file diff --git a/project5_testcases/test109/splc.c b/project5_testcases/test109/splc.c new file mode 100644 index 0000000..bc3d7b1 --- /dev/null +++ b/project5_testcases/test109/splc.c @@ -0,0 +1,34 @@ +int readint(); +int writeint(int out); + +// Test 109: Pointer arithmetic and struct pointer +struct Pair { + int first; + int second; +}; + +struct Pair pairs[5]; + +int add_pair(struct Pair *p) { + return p->first + p->second; +} + +int main0() { + int n = readint(); + int i = 0; + + while (i < n) { + pairs[i].first = readint(); + pairs[i].second = readint(); + i = i + 1; + } + + i = 0; + while (i < n) { + struct Pair *p = &pairs[i]; + writeint(add_pair(p)); + i = i + 1; + } + + return 0; +} diff --git a/src/main/java/framework/llvm/Inst.java b/src/main/java/framework/llvm/Inst.java index eadc5bd..6a11824 100644 --- a/src/main/java/framework/llvm/Inst.java +++ b/src/main/java/framework/llvm/Inst.java @@ -162,7 +162,7 @@ public ConversionInst(InstType instType, IRValue result, IRType ty, IRValue valu @Override String toLLVMRep() { return switch(type) { - case InstType.zext -> String.format("%s = zext %s %s to %s", result.llvmName(), ty.llvmName(), value.llvmName(), ty2.llvmName()); + case zext -> String.format("%s = zext %s %s to %s", result.llvmName(), ty.llvmName(), value.llvmName(), ty2.llvmName()); default -> null; }; } diff --git a/src/main/java/impl/Compiler.java b/src/main/java/impl/Compiler.java index 1a2f598..c182cc5 100644 --- a/src/main/java/impl/Compiler.java +++ b/src/main/java/impl/Compiler.java @@ -3,6 +3,7 @@ import framework.AbstractCompiler; import framework.AbstractGrader; import framework.lang.Type; +import framework.llvm.*; import framework.project3.Project3SemanticError; import framework.project4.Project4SemanticError; import framework.project4.Project4Exception; @@ -13,6 +14,7 @@ import org.antlr.v4.runtime.CharStreams; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.Token; +import org.antlr.v4.runtime.misc.Pair; import org.antlr.v4.runtime.tree.ParseTree; import org.antlr.v4.runtime.tree.TerminalNode; @@ -40,18 +42,10 @@ public void start() throws IOException { SemanticAnalyzer analyzer = new SemanticAnalyzer(grader); analyzer.visit(program); - // If we get here, no semantic errors were found (or only Project 4 errors) - // Phase 2: Print global variables and functions only if no errors + // Phase 2: Generate LLVM IR if no semantic errors if (!analyzer.hasSemanticErrors()) { - grader.print("Variables:\n"); - for (Symbol symbol : analyzer.getGlobalVariables()) { - grader.print(symbol.getName() + ": " + symbol.getType().fullPrint() + "\n"); - } - grader.print("\n"); - grader.print("Functions:\n"); - for (Symbol symbol : analyzer.getGlobalFunctions()) { - grader.print(symbol.getName() + ": " + symbol.getType().prettyPrint() + "\n"); - } + IRCodeGenerator codeGen = new IRCodeGenerator(grader); + codeGen.generate(program); } } @@ -1409,4 +1403,1064 @@ private boolean requiresImmediateCompletenessCheck(Type type) { return false; } } + + // ===== LLVM IR Code Generator ===== + + private static class IRCodeGenerator extends SplcBaseVisitor { + private final AbstractGrader grader; + private final IRBuilder ir; + + // Symbol info: address + type + private static class VarInfo { + final IRValue addr; + final Type type; + VarInfo(IRValue addr, Type type) { + this.addr = addr; + this.type = type; + } + } + + // Symbol table for variables (maps variable names to their info) + private final Map globalVariables = new HashMap<>(); + private final Deque> localScopes = new ArrayDeque<>(); + + // Current function context + private FunctionBuilder currentFunction; + private BasicBlockBuilder currentBlock; + + // Struct definitions (maps struct tag to list of (fieldName, fieldType)) + private final Map>> structDefs = new LinkedHashMap<>(); + + // Track struct types for LLVM + private final Map> structIRTypes = new HashMap<>(); + + public IRCodeGenerator(AbstractGrader grader) { + this.grader = grader; + this.ir = new IRBuilder(); + } + + public void generate(SplcParser.ProgramContext program) { + // First pass: collect struct definitions and declare all functions + for (SplcParser.GlobalDefContext globalDef : program.globalDef()) { + preprocessGlobalDef(globalDef); + } + + // Second pass: generate code for all definitions + visit(program); + + // Output the generated IR + grader.printIR(ir); + } + + // First pass: preprocess to collect struct definitions and declare functions + private void preprocessGlobalDef(SplcParser.GlobalDefContext ctx) { + Type specType = buildTypeFromSpecifier(ctx.specifier()); + + // Handle struct definition in specifier + if (ctx.specifier().STRUCT() != null && ctx.specifier().LBRACE() != null) { + String tagName = ctx.specifier().Identifier().getText(); + List> members = new ArrayList<>(); + List irMembers = new ArrayList<>(); + + for (int i = 0; i < ctx.specifier().specifier().size(); i++) { + Type memberSpecType = buildTypeFromSpecifier(ctx.specifier().specifier(i)); + String memberName = extractIdentifierFromVarDec(ctx.specifier().varDec(i)); + Type memberType = buildTypeFromVarDec(ctx.specifier().varDec(i), memberSpecType); + members.add(new Pair<>(memberName, memberType)); + irMembers.add(convertTypeToIR(memberType)); + } + + structDefs.put(tagName, members); + structIRTypes.put(tagName, irMembers); + ir.defineStructure(tagName, irMembers); + } + + // Handle function declaration (without body) + if (ctx.funcArgs() != null && ctx.SEMI() != null && ctx.LBRACE() == null) { + String funcName = ctx.Identifier().getText(); + List> params = new ArrayList<>(); + + if (ctx.funcArgs().specifier() != null && !ctx.funcArgs().specifier().isEmpty()) { + for (int i = 0; i < ctx.funcArgs().specifier().size(); i++) { + Type paramSpecType = buildTypeFromSpecifier(ctx.funcArgs().specifier(i)); + Type paramType = buildTypeFromVarDec(ctx.funcArgs().varDec(i), paramSpecType); + String paramName = extractIdentifierFromVarDec(ctx.funcArgs().varDec(i)); + params.add(new Pair<>(paramName, convertTypeToIR(paramType))); + } + } + + ir.declareFunction(funcName, convertTypeToIR(specType), params); + } + } + + @Override + public Void visitProgram(SplcParser.ProgramContext ctx) { + for (SplcParser.GlobalDefContext globalDef : ctx.globalDef()) { + visitGlobalDef(globalDef); + } + return null; + } + + @Override + public Void visitGlobalDef(SplcParser.GlobalDefContext ctx) { + Type specType = buildTypeFromSpecifier(ctx.specifier()); + + if (ctx.LBRACE() != null) { + // Function definition + String funcName = ctx.Identifier().getText(); + List> params = new ArrayList<>(); + List> paramTypes = new ArrayList<>(); + + if (ctx.funcArgs().specifier() != null && !ctx.funcArgs().specifier().isEmpty()) { + for (int i = 0; i < ctx.funcArgs().specifier().size(); i++) { + Type paramSpecType = buildTypeFromSpecifier(ctx.funcArgs().specifier(i)); + Type paramType = buildTypeFromVarDec(ctx.funcArgs().varDec(i), paramSpecType); + String paramName = extractIdentifierFromVarDec(ctx.funcArgs().varDec(i)); + params.add(new Pair<>(paramName, convertTypeToIR(paramType))); + paramTypes.add(new Pair<>(paramName, paramType)); + } + } + + currentFunction = ir.defineFunction(funcName, convertTypeToIR(specType), params); + currentBlock = currentFunction.rootBlock(); + + // Create local scope for function parameters + localScopes.push(new HashMap<>()); + + // Add parameters to local scope with their types + for (int i = 0; i < paramTypes.size(); i++) { + String paramName = paramTypes.get(i).a; + Type paramType = paramTypes.get(i).b; + IRValue paramAddr = currentFunction.param(paramName); + localScopes.peek().put(paramName, new VarInfo(paramAddr, paramType)); + } + + // Visit function body + for (SplcParser.StatementContext stmt : ctx.statement()) { + visit(stmt); + } + + // If no return statement was reached, add a default return 0 + if (!currentBlock.hasTerminated()) { + currentBlock.ret(IRValue.consti32(0)); + } + + localScopes.pop(); + currentFunction = null; + currentBlock = null; + + } else if (ctx.varDec() != null) { + // Global variable definition + String varName = extractIdentifierFromVarDec(ctx.varDec()); + Type varType = buildTypeFromVarDec(ctx.varDec(), specType); + IRType irType = convertTypeToIR(varType); + + IRValue globalAddr = ir.defineGlobalVar(varName, irType); + globalVariables.put(varName, new VarInfo(globalAddr, varType)); + } + // Skip function declarations (already handled in preprocess) and struct-only declarations + + return null; + } + + @Override + public Void visitBracket(SplcParser.BracketContext ctx) { + localScopes.push(new HashMap<>()); + for (SplcParser.StatementContext stmt : ctx.statement()) { + visit(stmt); + } + localScopes.pop(); + return null; + } + + @Override + public Void visitVarDecStmt(SplcParser.VarDecStmtContext ctx) { + Type specType = buildTypeFromSpecifier(ctx.specifier()); + String varName = extractIdentifierFromVarDec(ctx.varDec()); + Type varType = buildTypeFromVarDec(ctx.varDec(), specType); + IRType irType = convertTypeToIR(varType); + + // Allocate local variable + IRValue varAddr = currentBlock.alloca(irType, varName); + localScopes.peek().put(varName, new VarInfo(varAddr, varType)); + + // Handle initialization + if (ctx.expression() != null) { + IRValue initValue = generateExpression(ctx.expression()); + currentBlock.store(varAddr, irType, initValue); + } + + return null; + } + + @Override + public Void visitIfStmt(SplcParser.IfStmtContext ctx) { + // Evaluate condition + IRValue cond = generateExpression(ctx.expression()); + + // Ensure condition is i1 (bool) + if (!cond.type().isBoolean()) { + // Compare with 0 or null to get boolean + if (cond.type().isPointer()) { + cond = currentBlock.icmp(cond, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + cond = currentBlock.icmp(cond, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + } + + // Create basic blocks + BasicBlockBuilder thenBlock = currentFunction.newBasicBlock("if.then"); + BasicBlockBuilder elseBlock = ctx.statement().size() > 1 ? + currentFunction.newBasicBlock("if.else") : null; + BasicBlockBuilder mergeBlock = currentFunction.newBasicBlock("if.end"); + + // Branch based on condition + if (elseBlock != null) { + currentBlock.condBr(cond, thenBlock, elseBlock); + } else { + currentBlock.condBr(cond, thenBlock, mergeBlock); + } + + // Generate then block + currentBlock = thenBlock; + visit(ctx.statement(0)); + if (!currentBlock.hasTerminated()) { + currentBlock.br(mergeBlock); + } + + // Generate else block if present + if (elseBlock != null) { + currentBlock = elseBlock; + visit(ctx.statement(1)); + if (!currentBlock.hasTerminated()) { + currentBlock.br(mergeBlock); + } + } + + // Continue with merge block + currentBlock = mergeBlock; + + return null; + } + + @Override + public Void visitWhileStmt(SplcParser.WhileStmtContext ctx) { + // Create basic blocks + BasicBlockBuilder condBlock = currentFunction.newBasicBlock("while.cond"); + BasicBlockBuilder bodyBlock = currentFunction.newBasicBlock("while.body"); + BasicBlockBuilder endBlock = currentFunction.newBasicBlock("while.end"); + + // Branch to condition block + currentBlock.br(condBlock); + + // Generate condition block + currentBlock = condBlock; + IRValue cond = generateExpression(ctx.expression()); + + // Ensure condition is i1 (bool) + if (!cond.type().isBoolean()) { + if (cond.type().isPointer()) { + cond = currentBlock.icmp(cond, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + cond = currentBlock.icmp(cond, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + } + + currentBlock.condBr(cond, bodyBlock, endBlock); + + // Generate body block + currentBlock = bodyBlock; + visit(ctx.statement()); + if (!currentBlock.hasTerminated()) { + currentBlock.br(condBlock); + } + + // Continue with end block + currentBlock = endBlock; + + return null; + } + + @Override + public Void visitReturnStmt(SplcParser.ReturnStmtContext ctx) { + IRValue retValue = generateExpression(ctx.expression()); + currentBlock.ret(retValue); + return null; + } + + @Override + public Void visitExprStmt(SplcParser.ExprStmtContext ctx) { + generateExpression(ctx.expression()); + return null; + } + + // ===== Expression Generation ===== + + private IRValue generateExpression(SplcParser.ExpressionContext ctx) { + // Identifier + if (ctx.Identifier() != null && ctx.LPAREN() == null && ctx.DOT() == null && ctx.ARROW() == null) { + String name = ctx.Identifier().getText(); + IRValue addr = lookupVariable(name); + Type varType = lookupVariableType(name); + IRType irType = convertTypeToIR(varType); + + // If it's an array, return the address (arrays decay to pointers) + if (varType instanceof ArrayType) { + return addr; + } + + // Load the value + return currentBlock.load(addr, irType, null); + } + + // Number + if (ctx.Number() != null) { + int value = Integer.parseInt(ctx.Number().getText()); + return IRValue.consti32(value); + } + + // Parenthesized expression + if (ctx.LPAREN() != null && ctx.expression().size() == 1 && ctx.Identifier() == null) { + return generateExpression(ctx.expression(0)); + } + + // Function call + if (ctx.Identifier() != null && ctx.LPAREN() != null) { + String funcName = ctx.Identifier().getText(); + List args = new ArrayList<>(); + + for (SplcParser.ExpressionContext argCtx : ctx.expression()) { + args.add(generateExpression(argCtx)); + } + + return currentBlock.call(IRType.int32(), funcName, args, null); + } + + // Array access: expression LBRACK expression RBRACK + if (ctx.LBRACK() != null) { + Type baseType = getExpressionType(ctx.expression(0)); + IRValue index = generateExpression(ctx.expression(1)); + + IRType elementIRType; + IRValue elementAddr; + + if (baseType instanceof ArrayType) { + // For arrays, we need the address of the array and use 2-index GEP + IRValue baseAddr = generateLvalueAddress(ctx.expression(0)); + elementIRType = convertTypeToIR(((ArrayType) baseType).getElementType()); + IRType gepType = convertTypeToIR(baseType); + elementAddr = currentBlock.gep(baseAddr, gepType, 0, index, null); + } else if (baseType instanceof PointerType) { + // For pointers, evaluate the pointer expression and use 1-index GEP + IRValue ptrValue = generateExpression(ctx.expression(0)); + Type referenced = ((PointerType) baseType).getReferencedType(); + elementIRType = convertTypeToIR(referenced); + elementAddr = currentBlock.gep(ptrValue, elementIRType, index, null); + } else { + throw new RuntimeException("Array access on non-array, non-pointer type"); + } + + return currentBlock.load(elementAddr, elementIRType, null); + } + + // Struct member access: expression DOT Identifier + if (ctx.DOT() != null) { + IRValue structAddr = generateLvalueAddress(ctx.expression(0)); + String memberName = ctx.Identifier().getText(); + Type structType = getExpressionType(ctx.expression(0)); + + if (!(structType instanceof StructType)) { + throw new RuntimeException("DOT access on non-struct type"); + } + + StructType st = (StructType) structType; + int memberIndex = getMemberIndex(st.getTag(), memberName); + Type memberType = getMemberType(st.getTag(), memberName); + IRType irStructType = IRType.structure(st.getTag()); + IRType memberIRType = convertTypeToIR(memberType); + + IRValue memberAddr = currentBlock.gep(structAddr, irStructType, 0, IRValue.consti32(memberIndex), null); + return currentBlock.load(memberAddr, memberIRType, null); + } + + // Pointer member access: expression ARROW Identifier + if (ctx.ARROW() != null) { + IRValue ptrValue = generateExpression(ctx.expression(0)); + String memberName = ctx.Identifier().getText(); + Type ptrType = getExpressionType(ctx.expression(0)); + + if (!(ptrType instanceof PointerType)) { + throw new RuntimeException("ARROW access on non-pointer type"); + } + + Type referencedType = ((PointerType) ptrType).getReferencedType(); + if (!(referencedType instanceof StructType)) { + throw new RuntimeException("ARROW access on non-struct pointer"); + } + + StructType st = (StructType) referencedType; + int memberIndex = getMemberIndex(st.getTag(), memberName); + Type memberType = getMemberType(st.getTag(), memberName); + IRType irStructType = IRType.structure(st.getTag()); + IRType memberIRType = convertTypeToIR(memberType); + + IRValue memberAddr = currentBlock.gep(ptrValue, irStructType, 0, IRValue.consti32(memberIndex), null); + return currentBlock.load(memberAddr, memberIRType, null); + } + + // Postfix increment/decrement + if ((ctx.INC() != null || ctx.DEC() != null) && ctx.expression().size() == 1) { + // Check if it's postfix (expression comes before operator) + if (isPostfixOp(ctx)) { + IRValue addr = generateLvalueAddress(ctx.expression(0)); + Type varType = getExpressionType(ctx.expression(0)); + IRType irType = convertTypeToIR(varType); + + IRValue oldValue = currentBlock.load(addr, irType, null); + IRValue one = IRValue.consti32(1); + + IRValue newValue; + if (varType instanceof PointerType) { + Type ptrElemType = ((PointerType) varType).getReferencedType(); + IRType ptrElemIRType = convertTypeToIR(ptrElemType); + IRValue offset = ctx.INC() != null ? one : currentBlock.sub(IRValue.consti32(0), one, null); + newValue = currentBlock.gep(oldValue, ptrElemIRType, offset, null); + } else { + newValue = ctx.INC() != null ? + currentBlock.add(oldValue, one, null) : + currentBlock.sub(oldValue, one, null); + } + + currentBlock.store(addr, irType, newValue); + return oldValue; + } else { + // Prefix increment/decrement + IRValue addr = generateLvalueAddress(ctx.expression(0)); + Type varType = getExpressionType(ctx.expression(0)); + IRType irType = convertTypeToIR(varType); + + IRValue oldValue = currentBlock.load(addr, irType, null); + IRValue one = IRValue.consti32(1); + + IRValue newValue; + if (varType instanceof PointerType) { + Type ptrElemType = ((PointerType) varType).getReferencedType(); + IRType ptrElemIRType = convertTypeToIR(ptrElemType); + IRValue offset = ctx.INC() != null ? one : currentBlock.sub(IRValue.consti32(0), one, null); + newValue = currentBlock.gep(oldValue, ptrElemIRType, offset, null); + } else { + newValue = ctx.INC() != null ? + currentBlock.add(oldValue, one, null) : + currentBlock.sub(oldValue, one, null); + } + + currentBlock.store(addr, irType, newValue); + return newValue; + } + } + + // Unary operators (prefix) + if (ctx.expression().size() == 1) { + // Unary plus + if (ctx.PLUS() != null) { + return generateExpression(ctx.expression(0)); + } + + // Unary minus + if (ctx.MINUS() != null) { + IRValue operand = generateExpression(ctx.expression(0)); + return currentBlock.sub(IRValue.consti32(0), operand, null); + } + + // Logical NOT + if (ctx.NOT() != null) { + IRValue operand = generateExpression(ctx.expression(0)); + IRValue cmp; + if (operand.type().isBoolean()) { + cmp = currentBlock.icmp(operand, LLVMIcmpPredicate.Equals, IRValue.constFalse(), null); + } else if (operand.type().isPointer()) { + cmp = currentBlock.icmp(operand, LLVMIcmpPredicate.Equals, IRValue.constNull(), null); + } else { + cmp = currentBlock.icmp(operand, LLVMIcmpPredicate.Equals, IRValue.consti32(0), null); + } + return currentBlock.zext(cmp, IRType.int32(), null); + } + + // Dereference + if (ctx.STAR() != null) { + IRValue ptrValue = generateExpression(ctx.expression(0)); + Type ptrType = getExpressionType(ctx.expression(0)); + + if (!(ptrType instanceof PointerType)) { + throw new RuntimeException("Dereference on non-pointer"); + } + + Type referencedType = ((PointerType) ptrType).getReferencedType(); + IRType irType = convertTypeToIR(referencedType); + + return currentBlock.load(ptrValue, irType, null); + } + + // Address-of + if (ctx.AMP() != null) { + return generateLvalueAddress(ctx.expression(0)); + } + } + + // Binary operators + if (ctx.expression().size() == 2) { + // Assignment + if (ctx.ASSIGN() != null) { + IRValue addr = generateLvalueAddress(ctx.expression(0)); + Type lhsType = getExpressionType(ctx.expression(0)); + IRType irType = convertTypeToIR(lhsType); + IRValue value = generateExpression(ctx.expression(1)); + + // Handle null pointer assignment (0 to pointer) + if (irType.isPointer() && value.type().isInteger()) { + // Check if rhs is constant 0 + if (isConstantZero(ctx.expression(1))) { + value = IRValue.constNull(); + } + } + + currentBlock.store(addr, irType, value); + return value; + } + + // Logical AND (short-circuit) + if (ctx.AND() != null) { + return generateShortCircuitAnd(ctx); + } + + // Logical OR (short-circuit) + if (ctx.OR() != null) { + return generateShortCircuitOr(ctx); + } + + IRValue lhs = generateExpression(ctx.expression(0)); + IRValue rhs = generateExpression(ctx.expression(1)); + + // Arithmetic: *, /, % + if (ctx.STAR() != null) { + return currentBlock.mul(lhs, rhs, null); + } + if (ctx.DIV() != null) { + return currentBlock.div(lhs, rhs, null); + } + if (ctx.MOD() != null) { + return currentBlock.rem(lhs, rhs, null); + } + + // Addition/Subtraction (including pointer arithmetic) + if (ctx.PLUS() != null) { + Type lhsType = getExpressionType(ctx.expression(0)); + Type rhsType = getExpressionType(ctx.expression(1)); + + if (lhsType instanceof PointerType && isIntegerType(rhsType)) { + // Pointer + integer + Type ptrElemType = ((PointerType) lhsType).getReferencedType(); + IRType ptrElemIRType = convertTypeToIR(ptrElemType); + return currentBlock.gep(lhs, ptrElemIRType, rhs, null); + } else if (isIntegerType(lhsType) && rhsType instanceof PointerType) { + // Integer + pointer + Type ptrElemType = ((PointerType) rhsType).getReferencedType(); + IRType ptrElemIRType = convertTypeToIR(ptrElemType); + return currentBlock.gep(rhs, ptrElemIRType, lhs, null); + } + return currentBlock.add(lhs, rhs, null); + } + if (ctx.MINUS() != null) { + Type lhsType = getExpressionType(ctx.expression(0)); + Type rhsType = getExpressionType(ctx.expression(1)); + + if (lhsType instanceof PointerType && isIntegerType(rhsType)) { + // Pointer - integer + Type ptrElemType = ((PointerType) lhsType).getReferencedType(); + IRType ptrElemIRType = convertTypeToIR(ptrElemType); + IRValue negRhs = currentBlock.sub(IRValue.consti32(0), rhs, null); + return currentBlock.gep(lhs, ptrElemIRType, negRhs, null); + } + return currentBlock.sub(lhs, rhs, null); + } + + // Comparison operators + LLVMIcmpPredicate pred = null; + if (ctx.LT() != null) pred = LLVMIcmpPredicate.SignedLT; + if (ctx.LE() != null) pred = LLVMIcmpPredicate.SignedLE; + if (ctx.GT() != null) pred = LLVMIcmpPredicate.SignedGT; + if (ctx.GE() != null) pred = LLVMIcmpPredicate.SignedGE; + if (ctx.EQ() != null) pred = LLVMIcmpPredicate.Equals; + if (ctx.NEQ() != null) pred = LLVMIcmpPredicate.NotEquals; + + if (pred != null) { + // Handle pointer-to-null comparisons + Type lhsType = getExpressionType(ctx.expression(0)); + Type rhsType = getExpressionType(ctx.expression(1)); + + // If one side is a pointer and the other is 0, convert 0 to null + if (lhsType instanceof PointerType && isConstantZero(ctx.expression(1))) { + rhs = IRValue.constNull(); + } else if (rhsType instanceof PointerType && isConstantZero(ctx.expression(0))) { + lhs = IRValue.constNull(); + } + + IRValue cmp = currentBlock.icmp(lhs, pred, rhs, null); + return currentBlock.zext(cmp, IRType.int32(), null); + } + } + + throw new RuntimeException("Unsupported expression: " + ctx.getText()); + } + + private IRValue generateShortCircuitAnd(SplcParser.ExpressionContext ctx) { + // Short-circuit AND: if lhs is false, return 0 without evaluating rhs + // We use alloca to store the result since we don't have phi + IRValue resultAddr = currentBlock.alloca(IRType.int32(), "and.result"); + + // Initialize result to 0 (the short-circuit result) + currentBlock.store(resultAddr, IRType.int32(), IRValue.consti32(0)); + + BasicBlockBuilder rhsBlock = currentFunction.newBasicBlock("and.rhs"); + BasicBlockBuilder endBlock = currentFunction.newBasicBlock("and.end"); + + // Evaluate lhs + IRValue lhs = generateExpression(ctx.expression(0)); + IRValue lhsBool; + if (lhs.type().isBoolean()) { + lhsBool = lhs; + } else if (lhs.type().isPointer()) { + lhsBool = currentBlock.icmp(lhs, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + lhsBool = currentBlock.icmp(lhs, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + + // If lhs is true, evaluate rhs; if false, skip to end (result is already 0) + currentBlock.condBr(lhsBool, rhsBlock, endBlock); + + // Evaluate rhs (if we get here, lhs was true) + currentBlock = rhsBlock; + IRValue rhs = generateExpression(ctx.expression(1)); + IRValue rhsBool; + if (rhs.type().isBoolean()) { + rhsBool = rhs; + } else if (rhs.type().isPointer()) { + rhsBool = currentBlock.icmp(rhs, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + rhsBool = currentBlock.icmp(rhs, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + IRValue rhsResult = currentBlock.zext(rhsBool, IRType.int32(), null); + currentBlock.store(resultAddr, IRType.int32(), rhsResult); + currentBlock.br(endBlock); + + currentBlock = endBlock; + return currentBlock.load(resultAddr, IRType.int32(), null); + } + + private IRValue generateShortCircuitOr(SplcParser.ExpressionContext ctx) { + // Short-circuit OR: if lhs is true, return 1 without evaluating rhs + // We use alloca to store the result + IRValue resultAddr = currentBlock.alloca(IRType.int32(), "or.result"); + + // Initialize result to 1 (the short-circuit result) + currentBlock.store(resultAddr, IRType.int32(), IRValue.consti32(1)); + + BasicBlockBuilder rhsBlock = currentFunction.newBasicBlock("or.rhs"); + BasicBlockBuilder endBlock = currentFunction.newBasicBlock("or.end"); + + // Evaluate lhs + IRValue lhs = generateExpression(ctx.expression(0)); + IRValue lhsBool; + if (lhs.type().isBoolean()) { + lhsBool = lhs; + } else if (lhs.type().isPointer()) { + lhsBool = currentBlock.icmp(lhs, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + lhsBool = currentBlock.icmp(lhs, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + + // If lhs is true, skip to end (result is already 1); if false, evaluate rhs + currentBlock.condBr(lhsBool, endBlock, rhsBlock); + + // Evaluate rhs (if we get here, lhs was false) + currentBlock = rhsBlock; + IRValue rhs = generateExpression(ctx.expression(1)); + IRValue rhsBool; + if (rhs.type().isBoolean()) { + rhsBool = rhs; + } else if (rhs.type().isPointer()) { + rhsBool = currentBlock.icmp(rhs, LLVMIcmpPredicate.NotEquals, IRValue.constNull(), null); + } else { + rhsBool = currentBlock.icmp(rhs, LLVMIcmpPredicate.NotEquals, IRValue.consti32(0), null); + } + IRValue rhsResult = currentBlock.zext(rhsBool, IRType.int32(), null); + currentBlock.store(resultAddr, IRType.int32(), rhsResult); + currentBlock.br(endBlock); + + currentBlock = endBlock; + return currentBlock.load(resultAddr, IRType.int32(), null); + } + + // Generate address of an lvalue expression + private IRValue generateLvalueAddress(SplcParser.ExpressionContext ctx) { + // Identifier + if (ctx.Identifier() != null && ctx.LPAREN() == null && ctx.DOT() == null && ctx.ARROW() == null) { + return lookupVariable(ctx.Identifier().getText()); + } + + // Parenthesized expression + if (ctx.LPAREN() != null && ctx.expression().size() == 1 && ctx.Identifier() == null) { + return generateLvalueAddress(ctx.expression(0)); + } + + // Array access + if (ctx.LBRACK() != null) { + Type baseType = getExpressionType(ctx.expression(0)); + + if (baseType instanceof ArrayType) { + // For arrays, we need the address of the array and use 2-index GEP + IRValue baseAddr = generateLvalueAddress(ctx.expression(0)); + IRValue index = generateExpression(ctx.expression(1)); + IRType gepType = convertTypeToIR(baseType); + return currentBlock.gep(baseAddr, gepType, 0, index, null); + } else if (baseType instanceof PointerType) { + // For pointers, evaluate the pointer expression and use 1-index GEP + IRValue ptrValue = generateExpression(ctx.expression(0)); + IRValue index = generateExpression(ctx.expression(1)); + Type referenced = ((PointerType) baseType).getReferencedType(); + IRType elementIRType = convertTypeToIR(referenced); + return currentBlock.gep(ptrValue, elementIRType, index, null); + } + + throw new RuntimeException("Array access on non-array, non-pointer"); + } + + // Struct member access + if (ctx.DOT() != null) { + IRValue structAddr = generateLvalueAddress(ctx.expression(0)); + String memberName = ctx.Identifier().getText(); + Type structType = getExpressionType(ctx.expression(0)); + + if (!(structType instanceof StructType)) { + throw new RuntimeException("DOT access on non-struct"); + } + + StructType st = (StructType) structType; + int memberIndex = getMemberIndex(st.getTag(), memberName); + IRType irStructType = IRType.structure(st.getTag()); + + return currentBlock.gep(structAddr, irStructType, 0, IRValue.consti32(memberIndex), null); + } + + // Pointer member access + if (ctx.ARROW() != null) { + IRValue ptrValue = generateExpression(ctx.expression(0)); + String memberName = ctx.Identifier().getText(); + Type ptrType = getExpressionType(ctx.expression(0)); + + if (!(ptrType instanceof PointerType)) { + throw new RuntimeException("ARROW access on non-pointer"); + } + + Type referencedType = ((PointerType) ptrType).getReferencedType(); + if (!(referencedType instanceof StructType)) { + throw new RuntimeException("ARROW access on non-struct pointer"); + } + + StructType st = (StructType) referencedType; + int memberIndex = getMemberIndex(st.getTag(), memberName); + IRType irStructType = IRType.structure(st.getTag()); + + return currentBlock.gep(ptrValue, irStructType, 0, IRValue.consti32(memberIndex), null); + } + + // Dereference + if (ctx.STAR() != null && ctx.expression().size() == 1) { + return generateExpression(ctx.expression(0)); + } + + throw new RuntimeException("Cannot get address of expression: " + ctx.getText()); + } + + // ===== Helper Methods ===== + + private boolean isPostfixOp(SplcParser.ExpressionContext ctx) { + // In postfix, the operator comes after the expression + // We can check by looking at token positions + if (ctx.expression().size() != 1) return false; + if (ctx.INC() == null && ctx.DEC() == null) return false; + + int exprStart = ctx.expression(0).getStart().getStartIndex(); + int opStart = ctx.INC() != null ? + ctx.INC().getSymbol().getStartIndex() : + ctx.DEC().getSymbol().getStartIndex(); + + return opStart > exprStart; + } + + private boolean isConstantZero(SplcParser.ExpressionContext ctx) { + // Check if expression is directly 0 (optionally wrapped in parentheses) + if (ctx.Number() != null && ctx.Number().getText().equals("0")) { + return true; + } + // Check if it's parenthesized zero + if (ctx.LPAREN() != null && ctx.expression().size() == 1 && ctx.Identifier() == null) { + return isConstantZero(ctx.expression(0)); + } + return false; + } + + private IRValue lookupVariable(String name) { + // Check local scopes first (from innermost to outermost) + for (Map scope : localScopes) { + if (scope.containsKey(name)) { + return scope.get(name).addr; + } + } + + // Check global variables + if (globalVariables.containsKey(name)) { + return globalVariables.get(name).addr; + } + + throw new RuntimeException("Variable not found: " + name); + } + + // Get the type of a variable + private Type lookupVariableType(String name) { + // Check local scopes first (from innermost to outermost) + for (Map scope : localScopes) { + if (scope.containsKey(name)) { + return scope.get(name).type; + } + } + + // Check global variables + if (globalVariables.containsKey(name)) { + return globalVariables.get(name).type; + } + + return new BasicType(BasicType.Kind.INT); // Fallback + } + + // Get the type of an expression (simplified implementation) + private Type getExpressionType(SplcParser.ExpressionContext ctx) { + return getExpressionTypeImpl(ctx); + } + + private Type getExpressionTypeImpl(SplcParser.ExpressionContext ctx) { + // Identifier + if (ctx.Identifier() != null && ctx.LPAREN() == null && ctx.DOT() == null && ctx.ARROW() == null) { + return lookupVariableType(ctx.Identifier().getText()); + } + + // Number + if (ctx.Number() != null) { + return new BasicType(BasicType.Kind.INT); + } + + // Parenthesized + if (ctx.LPAREN() != null && ctx.expression().size() == 1 && ctx.Identifier() == null) { + return getExpressionTypeImpl(ctx.expression(0)); + } + + // Function call + if (ctx.Identifier() != null && ctx.LPAREN() != null) { + return new BasicType(BasicType.Kind.INT); // All functions return int per project spec + } + + // Array access + if (ctx.LBRACK() != null) { + Type baseType = getExpressionTypeImpl(ctx.expression(0)); + if (baseType instanceof ArrayType) { + return ((ArrayType) baseType).getElementType(); + } else if (baseType instanceof PointerType) { + return ((PointerType) baseType).getReferencedType(); + } + } + + // Struct member access + if (ctx.DOT() != null) { + Type structType = getExpressionTypeImpl(ctx.expression(0)); + if (structType instanceof StructType) { + String memberName = ctx.Identifier().getText(); + return getMemberType(((StructType) structType).getTag(), memberName); + } + } + + // Pointer member access + if (ctx.ARROW() != null) { + Type ptrType = getExpressionTypeImpl(ctx.expression(0)); + if (ptrType instanceof PointerType) { + Type referencedType = ((PointerType) ptrType).getReferencedType(); + if (referencedType instanceof StructType) { + String memberName = ctx.Identifier().getText(); + return getMemberType(((StructType) referencedType).getTag(), memberName); + } + } + } + + // Increment/decrement + if (ctx.INC() != null || ctx.DEC() != null) { + return getExpressionTypeImpl(ctx.expression(0)); + } + + // Unary operators + if (ctx.expression().size() == 1) { + if (ctx.PLUS() != null || ctx.MINUS() != null || ctx.NOT() != null) { + return new BasicType(BasicType.Kind.INT); + } + if (ctx.STAR() != null) { + Type ptrType = getExpressionTypeImpl(ctx.expression(0)); + if (ptrType instanceof PointerType) { + return ((PointerType) ptrType).getReferencedType(); + } + } + if (ctx.AMP() != null) { + return new PointerType(getExpressionTypeImpl(ctx.expression(0))); + } + } + + // Binary operators + if (ctx.expression().size() == 2) { + if (ctx.ASSIGN() != null) { + return getExpressionTypeImpl(ctx.expression(0)); + } + if (ctx.PLUS() != null || ctx.MINUS() != null) { + Type lhsType = getExpressionTypeImpl(ctx.expression(0)); + Type rhsType = getExpressionTypeImpl(ctx.expression(1)); + if (lhsType instanceof PointerType) return lhsType; + if (rhsType instanceof PointerType) return rhsType; + return new BasicType(BasicType.Kind.INT); + } + // All other binary ops return int + return new BasicType(BasicType.Kind.INT); + } + + return new BasicType(BasicType.Kind.INT); + } + + private int getMemberIndex(String structTag, String memberName) { + List> members = structDefs.get(structTag); + if (members == null) return 0; + for (int i = 0; i < members.size(); i++) { + if (members.get(i).a.equals(memberName)) { + return i; + } + } + return 0; + } + + private Type getMemberType(String structTag, String memberName) { + List> members = structDefs.get(structTag); + if (members == null) return new BasicType(BasicType.Kind.INT); + for (Pair member : members) { + if (member.a.equals(memberName)) { + return member.b; + } + } + return new BasicType(BasicType.Kind.INT); + } + + private boolean isIntegerType(Type type) { + return type instanceof BasicType && ((BasicType) type).getKind() == BasicType.Kind.INT; + } + + // ===== Type Conversion ===== + + private IRType convertTypeToIR(Type type) { + if (type instanceof BasicType) { + BasicType.Kind kind = ((BasicType) type).getKind(); + if (kind == BasicType.Kind.INT) { + return IRType.int32(); + } + // CHAR not supported per project spec + return IRType.int32(); + } else if (type instanceof ArrayType) { + ArrayType arr = (ArrayType) type; + IRType elemType = convertTypeToIR(arr.getElementType()); + // Build array type with proper dimensions + return buildArrayIRType(arr); + } else if (type instanceof PointerType) { + return IRType.pointer(); + } else if (type instanceof StructType) { + return IRType.structure(((StructType) type).getTag()); + } + return IRType.int32(); + } + + private IRType buildArrayIRType(ArrayType arr) { + // Collect all dimensions + List dims = new ArrayList<>(); + Type current = arr; + while (current instanceof ArrayType) { + dims.add(((ArrayType) current).getLength()); + current = ((ArrayType) current).getElementType(); + } + IRType elemType = convertTypeToIR(current); + int[] dimArray = new int[dims.size()]; + for (int i = 0; i < dims.size(); i++) { + dimArray[i] = dims.get(i); + } + return IRType.array(elemType, dimArray); + } + + // ===== Type Building from AST ===== + + private Type buildTypeFromSpecifier(SplcParser.SpecifierContext ctx) { + if (ctx.INT() != null) { + return new BasicType(BasicType.Kind.INT); + } else if (ctx.STRUCT() != null) { + String tagName = ctx.Identifier().getText(); + if (ctx.LBRACE() != null) { + // Complete struct - build the type with members + List members = new ArrayList<>(); + for (int i = 0; i < ctx.specifier().size(); i++) { + Type memberSpecType = buildTypeFromSpecifier(ctx.specifier(i)); + String memberName = extractIdentifierFromVarDec(ctx.varDec(i)); + Type memberType = buildTypeFromVarDec(ctx.varDec(i), memberSpecType); + members.add(new StructType.Member(memberType, memberName)); + } + return new StructType(tagName, members); + } else { + // Reference to existing struct + List> existingMembers = structDefs.get(tagName); + if (existingMembers != null) { + List members = new ArrayList<>(); + for (Pair m : existingMembers) { + members.add(new StructType.Member(m.b, m.a)); + } + return new StructType(tagName, members); + } + return new StructType(tagName, false); + } + } + return new BasicType(BasicType.Kind.INT); + } + + private String extractIdentifierFromVarDec(SplcParser.VarDecContext ctx) { + if (ctx.Identifier() != null) { + return ctx.Identifier().getText(); + } else if (ctx.varDec() != null) { + return extractIdentifierFromVarDec(ctx.varDec()); + } + return null; + } + + private Type buildTypeFromVarDec(SplcParser.VarDecContext ctx, Type baseType) { + if (ctx.Identifier() != null) { + return baseType; + } else if (ctx.LPAREN() != null && ctx.varDec() != null) { + return buildTypeFromVarDec(ctx.varDec(), baseType); + } else if (ctx.LBRACK() != null) { + int arraySize = Integer.parseInt(ctx.Number().getText()); + Type arrayType = new ArrayType(baseType, arraySize); + return buildTypeFromVarDec(ctx.varDec(), arrayType); + } else if (ctx.STAR() != null) { + Type pointerType = new PointerType(baseType); + return buildTypeFromVarDec(ctx.varDec(), pointerType); + } + return baseType; + } + } } \ No newline at end of file