parent
5ce6b687a3
commit
018a020aae
@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
# 实验 2 全量测试脚本 (改进版)
|
||||
# 逻辑参考 verify_ir.sh 与 verify_asm.sh
|
||||
# 增加了批量测试与统计功能,并确保链接 SysY 运行库 (sylib.c)
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
COMPILER="$PROJECT_ROOT/build/bin/compiler"
|
||||
SYLIB="$PROJECT_ROOT/sylib/sylib.c"
|
||||
RESULT_DIR="$PROJECT_ROOT/test/test_result/lab2_full"
|
||||
|
||||
# 检查依赖
|
||||
if [[ ! -x "$COMPILER" ]]; then
|
||||
echo "错误:编译器不存在,请先构建项目。"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -f "$SYLIB" ]]; then
|
||||
echo "错误:未找到运行库 $SYLIB"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# 颜色输出
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m'
|
||||
|
||||
mkdir -p "$RESULT_DIR"
|
||||
|
||||
total=0
|
||||
passed=0
|
||||
failed=0
|
||||
|
||||
run_test() {
|
||||
local input=$1
|
||||
local base=$(basename "$input")
|
||||
local stem=${base%.sy}
|
||||
local input_dir=$(dirname "$input")
|
||||
|
||||
local out_file="$RESULT_DIR/$stem.ll"
|
||||
local obj_file="$RESULT_DIR/$stem.o"
|
||||
local exe_file="$RESULT_DIR/$stem"
|
||||
local stdin_file="$input_dir/$stem.in"
|
||||
local expected_file="$input_dir/$stem.out"
|
||||
local actual_file="$RESULT_DIR/$stem.actual.out"
|
||||
local stdout_file="$RESULT_DIR/$stem.stdout"
|
||||
|
||||
((total++)) || true
|
||||
echo -n "[$total] 测试 $base ... "
|
||||
|
||||
# 1. 生成 IR
|
||||
if ! "$COMPILER" --emit-ir "$input" > "$out_file" 2>&1; then
|
||||
echo -e "${RED}IR 生成失败${NC}"
|
||||
((failed++)) || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 2. 编译 IR 到对象文件 (llc)
|
||||
if ! llc -filetype=obj "$out_file" -o "$obj_file" > /dev/null 2>&1; then
|
||||
echo -e "${RED}LLVM 编译失败 (llc)${NC}"
|
||||
((failed++)) || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 3. 链接运行库 (借鉴 verify_asm.sh 逻辑,但明确包含 sylib.c)
|
||||
if ! clang "$obj_file" "$SYLIB" -o "$exe_file" > /dev/null 2>&1; then
|
||||
echo -e "${RED}链接失败 (clang)${NC}"
|
||||
((failed++)) || true
|
||||
return 1
|
||||
fi
|
||||
|
||||
# 4. 运行程序并捕获输出与退出码 (增加栈空间限制)
|
||||
local status=0
|
||||
ulimit -s unlimited 2>/dev/null || true
|
||||
if [[ -f "$stdin_file" ]]; then
|
||||
"$exe_file" < "$stdin_file" > "$stdout_file" 2>/dev/null || status=$?
|
||||
else
|
||||
"$exe_file" > "$stdout_file" 2>/dev/null || status=$?
|
||||
fi
|
||||
|
||||
# 格式化实际输出 (借鉴 verify_ir.sh 格式)
|
||||
{
|
||||
cat "$stdout_file"
|
||||
if [[ -s "$stdout_file" ]] && [[ "$(tail -c 1 "$stdout_file" | wc -l)" -eq 0 ]]; then
|
||||
printf '\n'
|
||||
fi
|
||||
printf '%s\n' "$status"
|
||||
} > "$actual_file"
|
||||
|
||||
# 5. 比对结果
|
||||
if [[ -f "$expected_file" ]]; then
|
||||
# 忽略空格差异 (-b -w)
|
||||
if diff -q -b -w "$expected_file" "$actual_file" > /dev/null 2>&1; then
|
||||
echo -e "${GREEN}✓ 通过${NC}"
|
||||
((passed++)) || true
|
||||
else
|
||||
echo -e "${RED}✗ 输出不匹配${NC}"
|
||||
((failed++)) || true
|
||||
fi
|
||||
else
|
||||
echo -e "${YELLOW}! 缺少预期输出文件${NC}"
|
||||
((passed++)) || true
|
||||
fi
|
||||
}
|
||||
|
||||
# 批量运行
|
||||
echo "========================================="
|
||||
echo "实验 2 全量测试开始 (IR 语义验证)"
|
||||
echo "========================================="
|
||||
echo ""
|
||||
|
||||
run_batch() {
|
||||
local dir=$1
|
||||
if [[ ! -d "$dir" ]]; then return; fi
|
||||
echo "正在测试目录: $dir"
|
||||
for sy_file in $(ls "$dir"/*.sy | sort); do
|
||||
run_test "$sy_file"
|
||||
done
|
||||
echo ""
|
||||
}
|
||||
|
||||
run_batch "$PROJECT_ROOT/test/test_case/functional"
|
||||
run_batch "$PROJECT_ROOT/test/test_case/performance"
|
||||
|
||||
echo "========================================="
|
||||
echo "测试结果统计"
|
||||
echo "========================================="
|
||||
echo -e "总数:$total"
|
||||
echo -e "通过:${GREEN}$passed${NC}"
|
||||
echo -e "失败:${RED}$failed${NC}"
|
||||
echo ""
|
||||
|
||||
if [[ $failed -eq 0 ]]; then
|
||||
echo -e "${GREEN}🎉 所有测试通过!实验 2 任务完成。${NC}"
|
||||
exit 0
|
||||
else
|
||||
echo -e "${RED}✗ 有 $failed 个测试失败,请检查逻辑。${NC}"
|
||||
exit 1
|
||||
fi
|
||||
@ -1,4 +1,49 @@
|
||||
// SysY 运行库实现:
|
||||
// - 按实验/评测规范提供 I/O 等函数实现
|
||||
// - 与编译器生成的目标代码链接,支撑运行时行为
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
/* Input functions */
|
||||
int getint() { int t; scanf("%d", &t); return t; }
|
||||
int getch() { char t; scanf("%c", &t); return (int)t; }
|
||||
float getfloat() { float t; scanf("%f", &t); return t; }
|
||||
|
||||
int getarray(int a[]) {
|
||||
int n;
|
||||
scanf("%d", &n);
|
||||
for (int i = 0; i < n; i++) scanf("%d", &a[i]);
|
||||
return n;
|
||||
}
|
||||
|
||||
int getfarray(float a[]) {
|
||||
int n;
|
||||
scanf("%d", &n);
|
||||
for (int i = 0; i < n; i++) scanf("%f", &a[i]);
|
||||
return n;
|
||||
}
|
||||
|
||||
/* Output functions */
|
||||
void putint(int a) { printf("%d", a); }
|
||||
void putch(int a) { printf("%c", (char)a); }
|
||||
void putfloat(float a) { printf("%a", a); }
|
||||
|
||||
void putarray(int n, int a[]) {
|
||||
printf("%d:", n);
|
||||
for (int i = 0; i < n; i++) printf(" %d", a[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void putfarray(int n, float a[]) {
|
||||
printf("%d:", n);
|
||||
for (int i = 0; i < n; i++) printf(" %a", a[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
/* Timing functions */
|
||||
struct timeval _sysy_start, _sysy_end;
|
||||
void starttime() { gettimeofday(&_sysy_start, NULL); }
|
||||
void stoptime() {
|
||||
gettimeofday(&_sysy_end, NULL);
|
||||
int millis = (_sysy_end.tv_sec - _sysy_start.tv_sec) * 1000 +
|
||||
(_sysy_end.tv_usec - _sysy_start.tv_usec) / 1000;
|
||||
fprintf(stderr, "Timer: %d ms\n", millis);
|
||||
}
|
||||
|
||||
Loading…
Reference in new issue