#!/bin/sh # Runs the V3 compiler (compiler/M2) over a corpus of standard Modula-2 # sources and reports how many compile cleanly. # # Each source is copied into a scratch tree (so its .LST listing never # touches the corpus) and compiled alone, together with: # * its sibling DEFINITION (same basename, .def/.DEF) when present, and # * the DEFINITION of every module it imports, searched in the source # directory and in the -I-style library dirs listed in $V3_LIBS # (colon-separated), so cross-module imports resolve. # # A file with 0 errors is a pass. Failures are split into CRASH (M2 # died), LIB (an import still unresolved: no .def found) and LANG (a # real V3 gap). # # Usage: ./corpus.sh [corpus-dir ...] cd "$(dirname "$0")" ROOT="$(cd ../.. && pwd)" M2="$ROOT/compiler/M2" WORK=/tmp/opencode/v3corpus KNOWN="SYSTEM libc SysIO TextIO Strings Math Conversions RealIO ProgramArgs IOChan Files Storage WholeIO CharClass SysClock" [ -x "$M2" ] || { echo "compiler/M2 missing -- run compiler/build.sh"; exit 1; } [ "$#" -gt 0 ] || set -- \ "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/pim/pass" \ "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/iso/run/pass" known() { for k in $KNOWN; do [ "$1" = "$k" ] && return 0; done; return 1; } # find a DEFINITION file for module $1 in the source dir or $V3_LIBS finddef() { for d in "$scrdir" $(echo "$V3_LIBS" | tr ':' ' '); do [ -d "$d" ] || continue for cand in "$d/$1.def" "$d/$1.DEF" "$d/$(echo "$1" | tr 'A-Z' 'a-z').def"; do [ -f "$cand" ] && { echo "$cand"; return; } done done } # extract imported module names from a source imports() { { sed -nE 's/^[[:space:]]*FROM[[:space:]]+([A-Za-z][A-Za-z0-9_]*).*/\1/p' "$1" sed -nE 's/^[[:space:]]*IMPORT[[:space:]]+(.*)/\1/p' "$1" | sed 's/;.*//' | tr ',' '\n' } | sed -E 's/[[:space:]]//g' | grep -E '^[A-Za-z][A-Za-z0-9_]*$' } rm -rf "$WORK"; mkdir -p "$WORK"; : > "$WORK/results.txt" n=0 for scrdir in "$@"; do find "$scrdir" -maxdepth 1 \( -iname '*.mod' -o -iname '*.def' \) 2>/dev/null | sort | while read -r f; do n=$((n+1)) w="$WORK/f$n"; mkdir -p "$w"; base=$(basename "$f") cp "$f" "$w/$base" files="$w/$base" # sibling DEFINITION first case "$base" in *.mod|*.MOD) sib="$(echo "$base" | sed -E 's/\.[^.]*$/.def/')" [ -f "$scrdir/$sib" ] || sib="$(echo "$base" | sed -E 's/\.[^.]*$/.DEF/')" if [ -f "$scrdir/$sib" ]; then cp "$scrdir/$sib" "$w/$sib"; files="$w/$sib $files"; fi ;; esac # imported DEFINITIONs (for the LIB classification and for resolution) lib=0 for m in $(imports "$w/$base"); do known "$m" && continue df=$(finddef "$m") if [ -n "$df" ]; then cp "$df" "$w/$(basename "$df")"; files="$w/$(basename "$df") $files" else lib=1 fi done "$M2" $files >/dev/null 2>&1 rc=$? lst="$w/$(echo "$base" | sed 's/\.[^.]*$//').LST" if [ "$rc" -ge 128 ]; then echo "CRASH||$f" >> "$WORK/results.txt"; continue; fi if [ ! -f "$lst" ]; then echo "LANG|no listing|$f" >> "$WORK/results.txt"; continue; fi e=$(grep -oE '[0-9]+ errors?' "$lst" | head -1 | grep -oE '[0-9]+') [ -z "$e" ] && e=-1 if [ "$e" = 0 ]; then echo "OK||$f" >> "$WORK/results.txt"; continue; fi m=$(grep -E '^\*\*\*\*\*' "$lst" | head -1 | sed -E 's/^\*\*\*\*\* *\^? *//; s/^\*\*\*\*\*//') if [ "$lib" = 1 ]; then echo "LIB|$m|$f" >> "$WORK/results.txt" else echo "LANG|$m|$f" >> "$WORK/results.txt"; fi done done total=$(wc -l < "$WORK/results.txt") cnt() { grep -c "^$1" "$WORK/results.txt" 2>/dev/null || true; } echo "total : $total" echo "compile-OK : $(cnt OK)" echo "CRASH : $(cnt CRASH)" echo "LIB (unresolved import): $(cnt LIB)" echo "LANG (V3 gap) : $(cnt LANG)" echo "=== LANG error kinds (top) ===" grep '^LANG' "$WORK/results.txt" | cut -d'|' -f2 | sed -E 's/[0-9]+/N/g' | sort | uniq -c | sort -rn | head -15 echo "=== LANG files (first 40) ===" grep '^LANG' "$WORK/results.txt" | head -40 | sed -E 's/^LANG\|([^|]*)\|/ [\1] /'