|
|
#!/usr/bin/env bash
|
|
|
# Lab1 自动化构建 + 解析测评脚本(使用 COMPILER_PARSE_ONLY 构建)
|
|
|
# 用法:
|
|
|
# bash scripts/lab1_build_test.sh [--save-tree] [测试目录...]
|
|
|
#
|
|
|
# 选项:
|
|
|
# --save-tree 保存每个测试用例的语法树到 build/trees/ 目录
|
|
|
# 默认只进行通过/失败统计,不保存语法树
|
|
|
#
|
|
|
# 退出码:
|
|
|
# 0 全部用例解析通过
|
|
|
# 1 存在解析失败用例
|
|
|
|
|
|
set -euo pipefail
|
|
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
|
REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
|
COMPILER="$REPO_ROOT/build/bin/compiler"
|
|
|
ANTLR_JAR="$REPO_ROOT/third_party/antlr-4.13.2-complete.jar"
|
|
|
|
|
|
# 颜色输出
|
|
|
RED='\033[0;31m'
|
|
|
GREEN='\033[0;32m'
|
|
|
YELLOW='\033[1;33m'
|
|
|
NC='\033[0m'
|
|
|
|
|
|
# 默认不保存语法树
|
|
|
SAVE_TREE=false
|
|
|
|
|
|
# 解析命令行参数
|
|
|
TEST_DIRS=()
|
|
|
while [[ $# -gt 0 ]]; do
|
|
|
case "$1" in
|
|
|
--save-tree)
|
|
|
SAVE_TREE=true
|
|
|
shift
|
|
|
;;
|
|
|
*)
|
|
|
TEST_DIRS+=("$1")
|
|
|
shift
|
|
|
;;
|
|
|
esac
|
|
|
done
|
|
|
|
|
|
# 如果没有指定测试目录,使用默认
|
|
|
if [[ ${#TEST_DIRS[@]} -eq 0 ]]; then
|
|
|
TEST_DIRS=(
|
|
|
"$REPO_ROOT/test/test_case/functional"
|
|
|
"$REPO_ROOT/test/test_case/performance"
|
|
|
)
|
|
|
fi
|
|
|
|
|
|
# ─── Step 1:生成 ANTLR Lexer/Parser ────────────────────────────────────────────────
|
|
|
echo "==> [1/3] 生成 ANTLR Lexer/Parser ..."
|
|
|
mkdir -p "$REPO_ROOT/build/generated/antlr4"
|
|
|
java -jar "$ANTLR_JAR" \
|
|
|
-Dlanguage=Cpp \
|
|
|
-visitor -no-listener \
|
|
|
-Xexact-output-dir \
|
|
|
-o "$REPO_ROOT/build/generated/antlr4" \
|
|
|
"$REPO_ROOT/src/antlr4/SysY.g4"
|
|
|
echo " Lexer/Parser 生成完毕"
|
|
|
|
|
|
# ─── Step 2:CMake 构建(使用 COMPILER_PARSE_ONLY)────────────────────────────────
|
|
|
echo "==> [2/3] CMake 构建(COMPILER_PARSE_ONLY=ON)..."
|
|
|
cmake -S "$REPO_ROOT" -B "$REPO_ROOT/build" \
|
|
|
-DCMAKE_BUILD_TYPE=Release \
|
|
|
-DCOMPILER_PARSE_ONLY=ON \
|
|
|
> /dev/null
|
|
|
|
|
|
cmake --build "$REPO_ROOT/build" -j "$(nproc)" 2>&1 | grep -E "error:|warning:|Built target|Linking" || true
|
|
|
echo " 构建完毕:$COMPILER"
|
|
|
|
|
|
# ─── Step 3:批量解析测试 ─────────────────────────────────────────────────────
|
|
|
echo "==> [3/3] 批量解析测试 ..."
|
|
|
|
|
|
# 如果需要保存语法树,创建输出目录
|
|
|
if $SAVE_TREE; then
|
|
|
TREE_OUTPUT_DIR="$REPO_ROOT/build/trees"
|
|
|
mkdir -p "$TREE_OUTPUT_DIR"
|
|
|
echo " 语法树将保存到: $TREE_OUTPUT_DIR"
|
|
|
fi
|
|
|
|
|
|
PASS=0
|
|
|
FAIL=0
|
|
|
FAIL_LIST=()
|
|
|
|
|
|
for TEST_DIR in "${TEST_DIRS[@]}"; do
|
|
|
if [[ ! -d "$TEST_DIR" ]]; then
|
|
|
echo -e " ${YELLOW}警告:目录不存在,跳过:$TEST_DIR${NC}"
|
|
|
continue
|
|
|
fi
|
|
|
|
|
|
while IFS= read -r -d '' sy_file; do
|
|
|
rel="$(realpath --relative-to="$REPO_ROOT" "$sy_file")"
|
|
|
|
|
|
if $SAVE_TREE; then
|
|
|
# 将路径中的 '/' 替换为 '_',避免子目录冲突
|
|
|
safe_name="${rel//\//_}"
|
|
|
tree_file="$TREE_OUTPUT_DIR/${safe_name}.tree"
|
|
|
# 运行编译器并保存输出
|
|
|
if "$COMPILER" --emit-parse-tree "$sy_file" > "$tree_file" 2>&1; then
|
|
|
echo -e " ${GREEN}PASS${NC} $rel (tree saved to $tree_file)"
|
|
|
((PASS++)) || true
|
|
|
else
|
|
|
echo -e " ${RED}FAIL${NC} $rel"
|
|
|
FAIL_LIST+=("$rel")
|
|
|
((FAIL++)) || true
|
|
|
fi
|
|
|
else
|
|
|
if "$COMPILER" --emit-parse-tree "$sy_file" > "./output/lab1/$(basename "$sy_file" .sy).tree" 2>&1; then
|
|
|
echo -e " ${GREEN}PASS${NC} $rel"
|
|
|
((PASS++)) || true
|
|
|
else
|
|
|
echo -e " ${RED}FAIL${NC} $rel"
|
|
|
FAIL_LIST+=("$rel")
|
|
|
((FAIL++)) || true
|
|
|
fi
|
|
|
fi
|
|
|
done < <(find "$TEST_DIR" -name "*.sy" -print0 | sort -z)
|
|
|
done
|
|
|
|
|
|
# ─── 汇总 ─────────────────────────────────────────────────────────────────────
|
|
|
echo ""
|
|
|
echo "──────────────────────────────────────────"
|
|
|
echo -e " 测试结果:${GREEN}${PASS} PASS${NC} / ${RED}${FAIL} FAIL${NC} / 总计 $((PASS + FAIL))"
|
|
|
if [[ ${#FAIL_LIST[@]} -gt 0 ]]; then
|
|
|
echo ""
|
|
|
echo " 失败用例:"
|
|
|
for f in "${FAIL_LIST[@]}"; do
|
|
|
echo -e " ${RED}- $f${NC}"
|
|
|
done
|
|
|
fi
|
|
|
echo "──────────────────────────────────────────"
|
|
|
|
|
|
[[ $FAIL -eq 0 ]] |