corpus.sh 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/bin/sh
  2. # Runs the V3 compiler (compiler/M2) over a corpus of standard Modula-2
  3. # sources and reports how many compile cleanly.
  4. #
  5. # Each source is copied into a scratch tree (so its .LST listing never
  6. # touches the corpus) and compiled alone, together with:
  7. # * its sibling DEFINITION (same basename, .def/.DEF) when present, and
  8. # * the DEFINITION of every module it imports, searched in the source
  9. # directory and in the -I-style library dirs listed in $V3_LIBS
  10. # (colon-separated), so cross-module imports resolve.
  11. #
  12. # A file with 0 errors is a pass. Failures are split into CRASH (M2
  13. # died), LIB (an import still unresolved: no .def found) and LANG (a
  14. # real V3 gap).
  15. #
  16. # Usage: ./corpus.sh [corpus-dir ...]
  17. cd "$(dirname "$0")"
  18. ROOT="$(cd ../.. && pwd)"
  19. M2="$ROOT/compiler/M2"
  20. WORK=/tmp/opencode/v3corpus
  21. KNOWN="SYSTEM libc SysIO TextIO Strings Math Conversions RealIO ProgramArgs IOChan Files Storage WholeIO CharClass SysClock"
  22. [ -x "$M2" ] || { echo "compiler/M2 missing -- run compiler/build.sh"; exit 1; }
  23. [ "$#" -gt 0 ] || set -- \
  24. "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/pim/pass" \
  25. "$HOME/Projets/Projets-Modula2/MyWork/gcc-git/gcc/testsuite/gm2/iso/run/pass"
  26. known() { for k in $KNOWN; do [ "$1" = "$k" ] && return 0; done; return 1; }
  27. # find a DEFINITION file for module $1 in the source dir or $V3_LIBS
  28. finddef() {
  29. for d in "$scrdir" $(echo "$V3_LIBS" | tr ':' ' '); do
  30. [ -d "$d" ] || continue
  31. for cand in "$d/$1.def" "$d/$1.DEF" "$d/$(echo "$1" | tr 'A-Z' 'a-z').def"; do
  32. [ -f "$cand" ] && { echo "$cand"; return; }
  33. done
  34. done
  35. }
  36. # extract imported module names from a source
  37. imports() {
  38. { sed -nE 's/^[[:space:]]*FROM[[:space:]]+([A-Za-z][A-Za-z0-9_]*).*/\1/p' "$1"
  39. sed -nE 's/^[[:space:]]*IMPORT[[:space:]]+(.*)/\1/p' "$1" | sed 's/;.*//' | tr ',' '\n'
  40. } | sed -E 's/[[:space:]]//g' | grep -E '^[A-Za-z][A-Za-z0-9_]*$'
  41. }
  42. # Transitively collect the DEFINITION of module $1 (and its own imports)
  43. # into $w, appending each def (dependency order) to $deplist. Sets
  44. # $lib=1 when a needed definition cannot be found. Uses $1 (per-call)
  45. # rather than globals so recursion is safe.
  46. adddef() {
  47. known "$1" && return
  48. case " $seen " in *" $1 "*) return;; esac
  49. if [ -z "$(finddef "$1")" ]; then lib=1; return; fi
  50. seen="$seen $1"
  51. for mm in $(imports "$(finddef "$1")"); do adddef "$mm"; done
  52. adf=$(finddef "$1")
  53. cp "$adf" "$w/$(basename "$adf")"
  54. deplist="$deplist $w/$(basename "$adf")"
  55. }
  56. rm -rf "$WORK"; mkdir -p "$WORK"; : > "$WORK/results.txt"
  57. n=0
  58. for scrdir in "$@"; do
  59. find "$scrdir" -maxdepth 1 \( -iname '*.mod' -o -iname '*.def' \) 2>/dev/null | sort |
  60. while read -r f; do
  61. n=$((n+1))
  62. w="$WORK/f$n"; mkdir -p "$w"; base=$(basename "$f")
  63. cp "$f" "$w/$base"
  64. lib=0; deplist=""; seen=""
  65. # the base file's imports, transitively (dependency order)
  66. for m in $(imports "$w/$base"); do adddef "$m"; done
  67. basedeps="$deplist"; deplist=""
  68. # sibling DEFINITION (same basename) and its own imports
  69. sibfile=""
  70. case "$base" in
  71. *.mod|*.MOD)
  72. sib="$(echo "$base" | sed -E 's/\.[^.]*$/.def/')"
  73. [ -f "$scrdir/$sib" ] || sib="$(echo "$base" | sed -E 's/\.[^.]*$/.DEF/')"
  74. if [ -f "$scrdir/$sib" ]; then
  75. cp "$scrdir/$sib" "$w/$sib"; sibfile="$w/$sib"
  76. for m in $(imports "$sibfile"); do adddef "$m"; done
  77. fi
  78. ;;
  79. esac
  80. files="$basedeps $deplist $sibfile $w/$base"
  81. "$M2" $files >/dev/null 2>&1
  82. rc=$?
  83. lst="$w/$(echo "$base" | sed 's/\.[^.]*$//').LST"
  84. if [ "$rc" -ge 128 ]; then echo "CRASH||$f" >> "$WORK/results.txt"; continue; fi
  85. if [ ! -f "$lst" ]; then echo "LANG|no listing|$f" >> "$WORK/results.txt"; continue; fi
  86. e=$(grep -oE '[0-9]+ errors?' "$lst" | head -1 | grep -oE '[0-9]+')
  87. [ -z "$e" ] && e=-1
  88. if [ "$e" = 0 ]; then echo "OK||$f" >> "$WORK/results.txt"; continue; fi
  89. m=$(grep -E '^\*\*\*\*\*' "$lst" | head -1 | sed -E 's/^\*\*\*\*\* *\^? *//; s/^\*\*\*\*\*//')
  90. if [ "$lib" = 1 ]; then echo "LIB|$m|$f" >> "$WORK/results.txt"
  91. else echo "LANG|$m|$f" >> "$WORK/results.txt"; fi
  92. done
  93. done
  94. total=$(wc -l < "$WORK/results.txt")
  95. cnt() { grep -c "^$1" "$WORK/results.txt" 2>/dev/null || true; }
  96. echo "total : $total"
  97. echo "compile-OK : $(cnt OK)"
  98. echo "CRASH : $(cnt CRASH)"
  99. echo "LIB (unresolved import): $(cnt LIB)"
  100. echo "LANG (V3 gap) : $(cnt LANG)"
  101. echo "=== LANG error kinds (top) ==="
  102. grep '^LANG' "$WORK/results.txt" | cut -d'|' -f2 | sed -E 's/[0-9]+/N/g' | sort | uniq -c | sort -rn | head -15
  103. echo "=== LANG files (first 40) ==="
  104. grep '^LANG' "$WORK/results.txt" | head -40 | sed -E 's/^LANG\|([^|]*)\|/ [\1] /'