# # Builds the Test2 compiler (SimpleMod2 scalar subset -> QBE backend) # and runs the end-to-end tests. # Requires GNU Modula-2 (gm2), the CR binary, qbe and cc. # # Usage: ./build_qbe.sh (from the Test2 directory) # # Pipeline per test: SimpleQ tests/.mod -> gen_qbe/.ssa # -> qbe -> cc -> ./ ; exit code must match the expectation below. # Test convention: a global VAR ExitCode : INTEGER selects the process # exit code; without it the program returns 0. # pass=0 fail=0 expect_run() { # $1 = test file (no dir), $2 = expected exit code name="$1" want="$2" mod="$(basename "$name" .mod)" # The backend names the .ssa after the MODULE name; the newest .ssa # is the one just produced (tests run sequentially, names unique). out=$(./SimpleQ "tests/$name" 2>&1) case "$out" in *"Parsed correctly"*) ;; *) echo "FAIL $name: SimpleQ rejected it: $out"; fail=$((fail+1)); return ;; esac ssa=$(ls -t gen_qbe/*.ssa 2>/dev/null | head -n 1) if [ -z "$ssa" ]; then echo "FAIL $name: no .ssa produced"; fail=$((fail+1)); return fi base=$(basename "$ssa" .ssa) if ! qbe -o "gen_qbe/$base.s" "$ssa" 2> "gen_qbe/$base.qbeerr"; then echo "FAIL $name: qbe rejected $ssa:"; cat "gen_qbe/$base.qbeerr"; fail=$((fail+1)); return fi if ! cc "gen_qbe/$base.s" -o "gen_qbe/$base" 2> "gen_qbe/$base.ccerr"; then echo "FAIL $name: cc failed:"; cat "gen_qbe/$base.ccerr"; fail=$((fail+1)); return fi "gen_qbe/$base" > /dev/null 2>&1 got=$? if [ "$got" = "$want" ]; then echo "ok $name -> exit $got" pass=$((pass+1)) else echo "FAIL $name: exit $got, expected $want" fail=$((fail+1)) fi } expect_fail() { # $1 = test file, $2 = message text that must appear in the .LST # (listings show messages, not numeric codes) name="$1" want="$2" out=$(./SimpleQ "tests/$name" 2>&1) case "$out" in *"Incorrect source"*) ;; *) echo "FAIL $name: expected rejection, got: $out"; fail=$((fail+1)); return ;; esac lst="tests/$(basename "$name" .mod).LST" if grep -q "$want" "$lst" 2>/dev/null; then echo "ok $name rejected with $want" pass=$((pass+1)) else echo "FAIL $name: $want not found in $lst" fail=$((fail+1)) fi } echo "=== Regenerating SimpleQS / SimpleQP / SimpleQ from SimpleQ.atg ===" CRFRAMES="$(pwd)" ../CR -m -C SimpleQ.atg || exit 1 echo "=== Deleting all o files ===" rm -f ./*.o echo "=== Compiling the needed modules ===" for m in FileIO SymTab QbeGen SimpleQS SimpleQP SimpleQ; do gm2 -fiso -c "$m.mod" || exit 1 done echo "=== Phase 1: generating the module list ===" gm2 -fiso -fgen-module-list=modules.lst -o /dev/null \ SimpleQS.o SimpleQP.o FileIO.o SymTab.o QbeGen.o SimpleQ.mod || exit 1 echo "=== Phase 2: compiling main module and linking using the module list ===" gm2 -fiso -fuse-list=modules.lst -o SimpleQ \ SimpleQS.o SimpleQP.o FileIO.o SymTab.o QbeGen.o SimpleQ.mod || exit 1 echo "=== SimpleQ built ===" mkdir -p gen_qbe tests echo "=== Positive tests (compile + qbe + cc + run) ===" expect_run q_minimal.mod 0 expect_run q_arith.mod 7 expect_run q_const.mod 15 expect_run q_bool.mod 42 expect_run q_if.mod 20 expect_run q_case.mod 103 expect_run q_while.mod 55 expect_run q_repeat.mod 55 expect_run q_loop.mod 7 expect_run q_for.mod 85 expect_run q_real.mod 31 expect_run q_char.mod 97 expect_run q_enum.mod 1 expect_run q_full.mod 74 echo "=== Negative tests (must be rejected) ===" expect_fail q_bad_array.mod "qbe backend" expect_fail q_bad_with.mod "qbe backend" expect_fail q_bad_set.mod "qbe backend" expect_fail q_bad_exit.mod "qbe backend" expect_fail q_bad_const.mod "qbe backend" expect_fail q_bad_asn.mod "incompatible assignment" echo "=== $pass passed, $fail failed ===" test "$fail" = 0