#!/usr/bin/env bash set -euo pipefail if [[ $# -lt 1 || $# -gt 2 ]]; then echo "用法: $0 [output_dir]" >&2 exit 1 fi test_dir=${1%/} out_dir="test/test_result/function/asm" shift while [[ $# -gt 0 ]]; do out_dir="$1" shift done if [[ ! -d "$test_dir" ]]; then echo "测试目录不存在: $test_dir" >&2 exit 1 fi compiler="./build/bin/compiler" if [[ ! -x "$compiler" ]]; then echo "未找到编译器: $compiler ,请先构建。" >&2 exit 1 fi if ! command -v aarch64-linux-gnu-gcc >/dev/null 2>&1; then echo "未找到 aarch64-linux-gnu-gcc,无法汇编/链接。" >&2 exit 1 fi if ! command -v qemu-aarch64 >/dev/null 2>&1; then echo "未找到 qemu-aarch64,无法运行生成的可执行文件。" >&2 exit 1 fi sylib_c="sylib/sylib.c" if [[ ! -f "$sylib_c" ]]; then echo "未找到 sylib: $sylib_c" >&2 exit 1 fi mkdir -p "$out_dir" sylib_obj="$out_dir/sylib.o" aarch64-linux-gnu-gcc -c "$sylib_c" -I sylib -o "$sylib_obj" mapfile -t inputs < <(find "$test_dir" -type f -name '*.sy' | sort) if [[ ${#inputs[@]} -eq 0 ]]; then echo "测试目录下未找到 .sy 文件: $test_dir" >&2 exit 1 fi failures=0 normalize() { # strip CR, then strip a single trailing newline so both files # are comparable regardless of CRLF / trailing-newline differences tr -d '\r' < "$1" | sed -e '${ /^$/d; }' | perl -pe 'chomp if eof' } run_case() { local input=$1 local input_dir base stem rel_path rel_dir case_out_dir asm_file exe local stdin_file expected_file stdout_file actual_file status input_dir=$(dirname "$input") base=$(basename "$input") stem=${base%.sy} rel_path=${input#"$test_dir"/} rel_dir=$(dirname "$rel_path") case_out_dir="$out_dir" if [[ "$rel_dir" != "." ]]; then case_out_dir="$out_dir/$rel_dir" fi mkdir -p "$case_out_dir" asm_file="$case_out_dir/$stem.s" exe="$case_out_dir/$stem" stdin_file="$input_dir/$stem.in" expected_file="$input_dir/$stem.out" stdout_file="$case_out_dir/$stem.stdout" actual_file="$case_out_dir/$stem.actual.out" if ! "$compiler" --emit-asm "$input" > "$asm_file" 2>"$case_out_dir/$stem.err"; then echo "$stem: 编译失败" cat "$case_out_dir/$stem.err" >&2 return 1 fi if ! aarch64-linux-gnu-gcc "$asm_file" "$sylib_obj" -o "$exe" 2>"$case_out_dir/$stem.link.err"; then echo "$stem: 链接失败" cat "$case_out_dir/$stem.link.err" >&2 return 1 fi set +e if [[ -f "$stdin_file" ]]; then qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" < "$stdin_file" > "$stdout_file" else qemu-aarch64 -L /usr/aarch64-linux-gnu "$exe" > "$stdout_file" fi status=$? set -e { cat "$stdout_file" if [[ -s "$stdout_file" ]] && (( $(tail -c 1 "$stdout_file" | wc -l) == 0 )); then printf '\n' fi printf '%s\n' "$status" } > "$actual_file" if [[ -f "$expected_file" ]]; then if diff <(normalize "$expected_file") <(normalize "$actual_file") >/dev/null 2>&1; then echo "$stem: PASS" return 0 else echo "$stem: FAIL (退出码: $status)" diff -u --strip-trailing-cr "$expected_file" "$actual_file" >&2 || true return 1 fi else echo "$stem: SKIP (无预期输出, 退出码: $status)" return 0 fi } for input in "${inputs[@]}"; do if ! run_case "$input"; then ((failures+=1)) fi done total=${#inputs[@]} passed=$((total - failures)) echo "总计: $total, 通过: $passed, 失败: $failures" if (( failures > 0 )); then exit 1 fi