#!/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 ]]