#!/usr/bin/env bash set -euo pipefail ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" COMPILER="$ROOT_DIR/build/bin/compiler" TMP_DIR="$ROOT_DIR/build/test_compiler" TEST_DIRS=("$ROOT_DIR/test/test_case/functional" "$ROOT_DIR/test/test_case/performance") if [[ ! -x "$COMPILER" ]]; then echo "未找到编译器: $COMPILER" echo "请先构建编译器,例如: mkdir -p build && cd build && cmake .. && make -j" exit 1 fi mkdir -p "$TMP_DIR" ir_total=0 ir_pass=0 result_total=0 result_pass=0 ir_failures=() result_failures=() function normalize_file() { sed 's/\r$//' "$1" } for test_dir in "${TEST_DIRS[@]}"; do if [[ ! -d "$test_dir" ]]; then echo "跳过不存在的测试目录: $test_dir" continue fi shopt -s nullglob for input in "$test_dir"/*.sy; do ir_total=$((ir_total+1)) base=$(basename "$input") stem=${base%.sy} out_dir="$TMP_DIR/$(basename "$test_dir")" mkdir -p "$out_dir" ll_file="$out_dir/$stem.ll" stdout_file="$out_dir/$stem.stdout" expected_file="$test_dir/$stem.out" stdin_file="$test_dir/$stem.in" echo "[TEST] $input" # 编译并捕获所有输出 compiler_status=0 compiler_output="" compiler_output=$("$COMPILER" --emit-ir "$input" 2>&1) || compiler_status=$? # 临时文件存储原始输出 raw_ll="$out_dir/$stem.raw.ll" printf '%s\n' "$compiler_output" > "$raw_ll" # 检查编译是否成功 if [[ $compiler_status -ne 0 ]]; then echo " [IR] 编译失败: 返回码 $compiler_status" ir_failures+=("$input: compiler failed ($compiler_status)") # 失败:保留原始输出(包含所有调试信息) cp "$raw_ll" "$ll_file" rm -f "$raw_ll" continue fi # 检查是否生成了有效的函数定义(在过滤后的内容中检查) # 先过滤一下看看是否有define filtered_content=$(sed -E '/^\[DEBUG\]|^SymbolTable::|^Check|^绑定|^保存|^dim_count:/d' "$raw_ll") if ! echo "$filtered_content" | grep -qE '^define '; then echo " [IR] 失败: 未生成有效函数定义" ir_failures+=("$input: invalid IR output") # 失败:保留原始输出 cp "$raw_ll" "$ll_file" rm -f "$raw_ll" continue fi # 编译成功:过滤掉所有调试输出,只保留IR # 过滤规则: # 1. 以 [DEBUG] 开头的行 # 2. SymbolTable:: 开头的行 # 3. CheckLValue: 开头的行 # 4. 绑定变量: 开头的行 # 5. dim_count: 开头的行 # 6. 空行(可选) sed -E '/^(\[DEBUG|SymbolTable::|Check|绑定|保存|dim_)/d' "$raw_ll" > "$ll_file" # 可选:删除多余的空行 sed -i '/^$/N;/\n$/D' "$ll_file" rm -f "$raw_ll" ir_pass=$((ir_pass+1)) echo " [IR] 生成成功 (IR已保存到: $ll_file)" # 运行测试 if [[ -f "$expected_file" ]]; then result_total=$((result_total+1)) # 运行LLVM IR run_status=0 if [[ -f "$stdin_file" ]]; then lli "$ll_file" < "$stdin_file" > "$stdout_file" 2>&1 || run_status=$? else lli "$ll_file" > "$stdout_file" 2>&1 || run_status=$? fi # 读取预期返回值 expected=$(normalize_file "$expected_file") # 比较返回值 if [[ "$run_status" -eq "$expected" ]]; then result_pass=$((result_pass+1)) echo " [RUN] 返回值匹配: $run_status" # 成功:保留已清理的.ll文件,删除输出文件 rm -f "$stdout_file" else echo " [RUN] 返回值不匹配: got $run_status, expected $expected" result_failures+=("$input: exit code mismatch (got $run_status, expected $expected)") # 失败:.ll文件已经保留,输出文件也保留用于调试 fi else echo " [RUN] 未找到预期返回值文件 $expected_file,跳过结果验证" fi done shopt -u nullglob done # 输出统计 cat <