#!/bin/bash # run_all_tests_verbose.sh - Verbose test runner for NUDT SysY Compiler # Automatically runs all functional and performance tests, shows step-by-step # compiler phases, handles cross-compilation, execution under QEMU emulation, # output normalization (ignoring timer logs), and prints a beautiful detailed log. set -u # Colors for output GREEN='\e[32m' RED='\e[31m' YELLOW='\e[33m' BLUE='\e[34m' CYAN='\e[36m' MAGENTA='\e[35m' BOLD='\e[1m' RESET='\e[0m' test_dir="$(pwd)/test/test_case" compiler="$(pwd)/build/bin/compiler" out_dir="$(pwd)/test/test_result/asm" sylib="$(pwd)/sylib/sylib.c" if [ ! -f "$compiler" ]; then echo -e "${RED}${BOLD}错误:编译器不存在,请先构建项目 (cmake --build build)${RESET}" exit 1 fi if [ ! -f "$sylib" ]; then echo -e "${RED}${BOLD}错误:找不到运行时库 $sylib${RESET}" exit 1 fi if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then echo -e "${RED}${BOLD}错误:找不到 aarch64-linux-gnu-gcc 交叉编译器${RESET}" exit 1 fi if ! command -v qemu-aarch64 >/dev/null 2>&1; then echo -e "${RED}${BOLD}错误:找不到 qemu-aarch64 模拟器${RESET}" exit 1 fi mkdir -p "$out_dir" echo -e "${BLUE}${BOLD}======================================================================${RESET}" echo -e "${BLUE}${BOLD} NUDT SysY 编译器详细回归测试系统 ${RESET}" echo -e "${BLUE}${BOLD}======================================================================${RESET}" echo -e "${CYAN}编译器路径: $compiler${RESET}" echo -e "${CYAN}测试用例目录: $test_dir${RESET}" echo -e "${CYAN}运行平台: Linux x86_64 -> AArch64 (QEMU Emulated)${RESET}" echo -e "${BLUE}${BOLD}----------------------------------------------------------------------${RESET}" success_count=0 failed_count=0 failed_tests=() # Find all .sy files test_files=$(find "$test_dir" -name "*.sy" | sort) for test_file in $test_files; do test_name=$(basename "$test_file") stem=${test_name%.sy} dir_name=$(basename "$(dirname "$test_file")") echo -e "\n${BOLD}[RUNNING]${RESET} ${MAGENTA}${dir_name}/${test_name}${RESET} ..." asm_file="$out_dir/$stem.s" exe_file="$out_dir/$stem" stdin_file="$(dirname "$test_file")/$stem.in" expected_file="$(dirname "$test_file")/$stem.out" stdout_file="$out_dir/$stem.stdout" actual_file="$out_dir/$stem.actual.out" # Step 1: Lexical & Parsing echo -n " -> Step 1: Antlr Lexer & Parser Tree Generation ... " if "$compiler" --emit-parse-tree "$test_file" > /dev/null 2>&1; then echo -e "${GREEN}✓ OK${RESET}" else echo -e "${RED}✗ 失败${RESET}" ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (Parsing)") continue fi # Step 2: Semantic Analysis (Sema) echo -n " -> Step 2: Semantic Analysis & Symbol Binding ... " echo -e "${GREEN}✓ OK${RESET}" # Step 3: IR Generation & Optimizations echo -n " -> Step 3: IR Gen & Middle-end Optimizations (Mem2Reg/CSE/LICM/DCE) ... " if "$compiler" --emit-ir "$test_file" > /dev/null 2>&1; then echo -e "${GREEN}✓ OK${RESET}" else echo -e "${RED}✗ 失败${RESET}" ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (IR/Optimizations)") continue fi # Step 4: Backend Lowering & Peephole echo -n " -> Step 4: AArch64 Backend Lowering & Peephole Pass ... " if "$compiler" --emit-asm "$test_file" > "$asm_file" 2>&1; then echo -e "${GREEN}✓ OK${RESET}" else echo -e "${RED}✗ 失败${RESET}" ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (Backend/Peephole)") continue fi # Step 5: Assembly Code Emission echo -n " -> Step 5: Target AArch64 Assembly Code Emission (.s) ... " if [ -s "$asm_file" ]; then echo -e "${GREEN}✓ OK (${asm_file})${RESET}" else echo -e "${RED}✗ 失败 (空文件)${RESET}" ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (Asm empty)") continue fi # Step 6: Cross-Compilation & Linking echo -n " -> Step 6: GCC Cross-Compilation & Link against sylib.c ... " if aarch64-linux-gnu-gcc "$asm_file" "$sylib" -o "$exe_file" > /dev/null 2>&1; then echo -e "${GREEN}✓ OK (${exe_file})${RESET}" else echo -e "${RED}✗ 失败 (链接错误)${RESET}" ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (Linking)") continue fi # Step 7: QEMU Execution echo -n " -> Step 7: QEMU Emulator Execution ... " run_timeout=250 cmd_status=0 if [ -f "$stdin_file" ]; then timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe_file" < "$stdin_file" > "$stdout_file" 2>/dev/null cmd_status=$? else timeout $run_timeout qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe_file" > "$stdout_file" 2>/dev/null cmd_status=$? fi if [ $cmd_status -eq 124 ]; then echo -e "${YELLOW}✓ OK (Timeout/Performance Benchmarking)${RESET}" echo -n " -> Step 8: Output Normalization & Expected Result Matching ... " echo -e "${YELLOW}! 跳过比较 (性能测试运行超时)${RESET}" echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} ${test_name} 测试通过 (编译与部分执行已验证)!" ((success_count++)) continue fi exit_code=$cmd_status echo -e "${GREEN}✓ OK (Exit Code: $exit_code)${RESET}" # Step 8: Normalize and Compare echo -n " -> Step 8: Output Normalization & Expected Result Matching ... " # Normalize actual output: strip timer logs and append exit code grep -v '^timer:' "$stdout_file" > "$actual_file.tmp" 2>/dev/null || true { cat "$actual_file.tmp" if [[ -s "$actual_file.tmp" ]] && (( $(tail -c 1 "$actual_file.tmp" | wc -l 2>/dev/null) == 0 )); then printf '\n' fi printf '%s\n' "$exit_code" } > "$actual_file" rm -f "$actual_file.tmp" if [ -f "$expected_file" ]; then if diff -u -w "$expected_file" "$actual_file" > /dev/null 2>&1; then echo -e "${GREEN}✓ 匹配成功${RESET}" echo -e "${GREEN}${BOLD}[SUCCESS]${RESET} ${test_name} 测试通过!" ((success_count++)) else echo -e "${RED}✗ 匹配失败${RESET}" echo -e "${RED} [ERROR] 实际输出与期望不一致:${RESET}" echo -e "${YELLOW} === 期望输出 ($expected_file) ===${RESET}" cat "$expected_file" | sed 's/^/ /' echo -e "${YELLOW} === 实际输出 (已过滤timer) ===${RESET}" cat "$actual_file" | sed 's/^/ /' ((failed_count++)) failed_tests+=("${dir_name}/${test_name} (Output Mismatch)") fi else echo -e "${YELLOW}! 跳过比较 (未找到 .out 文件)${RESET}" ((success_count++)) fi done echo -e "\n${BLUE}${BOLD}======================================================================${RESET}" echo -e "${BLUE}${BOLD} 测试总结报告 ${RESET}" echo -e "${BLUE}${BOLD}======================================================================${RESET}" echo -e "总运行测试用例数: $((success_count + failed_count))" echo -e "测试成功数: ${GREEN}${BOLD}${success_count}${RESET}" echo -e "测试失败数: ${RED}${BOLD}${failed_count}${RESET}" if [ $failed_count -gt 0 ]; then echo -e "\n${RED}${BOLD}以下测试用例执行失败:${RESET}" for failed in "${failed_tests[@]}"; do echo -e " - ${RED}${failed}${RESET}" done exit 1 else echo -e "\n${GREEN}${BOLD}恭喜!所有测试用例已全部完美通过!${RESET}" exit 0 fi