diff --git a/Makefile b/Makefile
index 9ac311c8caef4bb441cb7016992064cf3cb3cfb7..167e458ce8bd53905c9d07727a94f43aad1dd308 100644
--- a/Makefile
+++ b/Makefile
@@ -276,6 +276,8 @@ DISTRIB_FILES:=\
       share/analysis-scripts/prologue.mk                                \
       share/analysis-scripts/README.md                                  \
       share/analysis-scripts/results_display.py                         \
+      share/analysis-scripts/script_for_creduce_fatal.sh                \
+      share/analysis-scripts/script_for_creduce_non_fatal.sh            \
       share/analysis-scripts/summary.py                                 \
       share/analysis-scripts/template.mk                                \
       $(wildcard share/emacs/*.el) share/autocomplete_frama-c           \
@@ -1943,6 +1945,8 @@ install:: install-lib-$(OCAMLBEST)
 	  share/analysis-scripts/prologue.mk \
 	  share/analysis-scripts/README.md \
 	  share/analysis-scripts/results_display.py \
+	  share/analysis-scripts/script_for_creduce_fatal.sh \
+	  share/analysis-scripts/script_for_creduce_non_fatal.sh \
 	  share/analysis-scripts/summary.py \
 	  share/analysis-scripts/template.mk \
 	  $(FRAMAC_DATADIR)/analysis-scripts
diff --git a/bin/frama-c-script b/bin/frama-c-script
index 022f9b140965db5b7d07cff1ccfba1ff712386b2..a85fadf00fe3f4adbdc6816b343ad0e2b3056f6e 100755
--- a/bin/frama-c-script
+++ b/bin/frama-c-script
@@ -37,6 +37,11 @@ usage() {
    echo "      and non-POSIX external libraries."
    echo "      (run 'frama-c -machdep help' to get the list of machdeps)."
    echo ""
+   echo "  - creduce <args>"
+   echo "      Use the external tool C-Reduce to minimize C files when"
+   echo "      debugging crashes and fatal errors. Run without arguments for"
+   echo "      more details."
+   echo ""
    echo "  - estimate-difficulty file..."
    echo "      Applies several heuristics to try and estimate the difficulty"
    echo "      of analyzing the specified files with Frama-C."
@@ -259,6 +264,10 @@ case "$command" in
         shift;
         "${FRAMAC_SHARE}"/analysis-scripts/normalize_jcdb.py "$@";
         ;;
+    "creduce")
+        shift;
+        ${FRAMAC_SHARE}/analysis-scripts/creduce.sh "$@";
+        ;;
     *)
         echo "error: unrecognized command: $command";
         exit 1
diff --git a/headers/header_spec.txt b/headers/header_spec.txt
index fefab89f71c3fecec85cc19c091c4b28258040b3..edc62ce1b07b9d89a55f7639b95a6ed543bdc6f7 100644
--- a/headers/header_spec.txt
+++ b/headers/header_spec.txt
@@ -134,6 +134,8 @@ share/analysis-scripts/parse-coverage.sh: .ignore
 share/analysis-scripts/prologue.mk: CEA_LGPL
 share/analysis-scripts/README.md: .ignore
 share/analysis-scripts/results_display.py: CEA_LGPL
+share/analysis-scripts/script_for_creduce_fatal.sh: .ignore
+share/analysis-scripts/script_for_creduce_non_fatal.sh: .ignore
 share/analysis-scripts/summary.py: CEA_LGPL
 share/analysis-scripts/template.mk: .ignore
 share/compliance/c11_functions.json: .ignore
diff --git a/share/analysis-scripts/creduce.sh b/share/analysis-scripts/creduce.sh
index 94ddd8ef10f33cd5aa676f17957842b19c057d7b..d35a3fc6f4f23fafb192066cb8be8ae494eac4b9 100755
--- a/share/analysis-scripts/creduce.sh
+++ b/share/analysis-scripts/creduce.sh
@@ -21,52 +21,93 @@
 #                                                                        #
 ##########################################################################
 
-# Script to run C-Reduce (https://embed.cs.utah.edu/creduce) when debugging
-# Frama-C crashes with a 'fatal' error, which produces a stack trace and
-# a message "Please report".
+usage="
+Script to run C-Reduce (https://embed.cs.utah.edu/creduce) when debugging
+Frama-C, or when minimizing test cases resulting in a Frama-C error.
 
-### Requirements
-#
-# - C-Reduce installed in the PATH, or its path given in the
-#   environment variable CREDUCE;
-#
-# - GCC, or the path to a compiler with compatible options given in the
-#   environment variable CC;
-#
-# - Frama-C installed in the PATH, or its path given in the environment
-#   variable FRAMAC;
-#
-# - a source file + a command line which causes Frama-C to crash with
-#   a 'fatal' error (producing a stack trace).
+# Requirements
 
-### How it works
-#
-#   creduce.sh <file.c> <command line options>
+- C-Reduce installed in the PATH, or its path in environment variable CREDUCE;
+- Frama-C installed in the PATH, or the path to its 'bin' directory in
+   environment variable FRAMAC_BIN;
+- a source file + a command line which causes Frama-C to crash with
+  a 'fatal' error (producing a stack trace); can also be used when
+  Frama-C reports other errors, but in this case a separate script must be
+  completed by the user.
+
+# Basic usage
+
+  arguments: <script options> <file> <Frama-C command line options>
+
+This script creates a temporary directory named 'creducing'. It copies <file>
+inside it, then runs creduce with 'frama-c <command line options>'
+on the copied file, modifying it to make it smaller while still crashing.
+
+When done, you need to copy the reduced file and erase directory 'creducing'.
+
+# Script options
+
+Note: these options must be placed _before_ all other arguments.
+
+--help: show this help message.
+
+--ignore-parsability: do not check that each reduced program conforms to
+                      a gcc parsability check; helps avoid issues due to
+                      preprocessing flags.
+
+# Advanced usage
+
+- if <file> is not a preprocessed (.i) source, this script
+  will retrieve the preprocessing arguments from Frama-C. It will try to
+  preprocess the file in GCC to make sure it is parseable during reduction.
+  This may cause some issues; use a preprocessed file if you can.
+
+- For 'fatal' crashes (with stack trace and 'Please report...' message),
+  this script should work automatically. For other crashes (e.g. invalid
+  input), this script will copy a template to the current directory and you
+  need to fill it so that creduce will work. This usage mode requires knowing
+  how C-Reduce works.
+"
+
+#### Command-line and environment validation
 #
-# This script creates a temporary directory named 'creducing'.
-# It copies <file.c> inside it, then runs creduce.
-# creduce runs "frama-c <command line options>" on the copied file,
-# modifying it to make it smaller while still crashing.
 #
-# When done, copy the reduced file and erase directoy 'creducing'.
+
+ignore_parsability=0
+while [ $# -ge 1 ]; do
+    case "$1" in
+        --help) echo "$usage"; exit;;
+        --h) echo "$usage"; exit;;
+        -help) echo "$usage"; exit;;
+        -h) echo "$usage"; exit;;
+        --ignore-parsability)
+            ignore_parsability=1
+            shift
+            ;;
+        *) break;;
+    esac
+done
 
 if [ $# -lt 1 ]; then
-    echo "usage: $0 file.c [Frama-C options that cause a crash]"
-    exit 1
+    echo "$usage"
+    exit
 fi
 
 file="$1"
 base=$(basename "$file")
 shift
-options="$@"
+
 dir_for_reduction="creducing"
 
+script_for_creduce="./script_for_creduce.sh"
+
 if [ -z "$CREDUCE" ]; then
     CREDUCE="creduce"
 fi
 
 if ! command -v "$CREDUCE" 2>&1 >/dev/null; then
-    echo "creduce not found, put it in PATH or in environment variable CREDUCE."
+    echo "creduce not found; install it in the PATH or"
+    echo "put it in environment variable CREDUCE."
     exit 1
 fi
 
@@ -75,12 +116,57 @@ if [[ ! -f "$file" ]]; then
     exit 1
 fi
 
-if [[ $(dirname "$file") -eq "$dir_for_reduction" ]]; then
+too_many_sources=""
+for f in "$@"; do
+    if [ -e "$f" ]; then
+        too_many_sources+=" $f"
+    fi
+done
+if [ ! -z "$too_many_sources" ]; then
+    echo "error: too many sources; only the first argument must be a file: $file"
+    echo "       remove these from the command-line:$too_many_sources"
+    exit 1
+fi
+
+if [[ $(dirname "$file") = "$dir_for_reduction" ]]; then
     echo "error: cannot reduce a file inside the directory used for reduction,"
     echo "       $dir_for_reduction"
     exit 1
 fi
 
+if [ -z "$FRAMAC_BIN" ]; then
+    if ! command -v "frama-c" >/dev/null; then
+        echo "error: frama-c must be in the PATH, or FRAMAC_BIN must point to"
+        echo "       the directory containing the frama-c binary"
+        exit 1
+    fi
+    FRAMAC="frama-c"
+else
+    FRAMAC="$FRAMAC_BIN/frama-c"
+fi
+echo "[info] using FRAMAC: $FRAMAC"
+
+if [ -z "$FRAMAC_SHARE" ]; then
+    FRAMAC_SHARE="$("$FRAMAC" -print-share-path)"
+fi
+
+if ! sed --version >/dev/null 2>&1; then
+    echo "[info] sed is not GNU, trying gsed..."
+    if command -v gsed >/dev/null; then
+        echo "[info] gsed found, using it."
+        SED="gsed"
+    else
+        echo "error: GNU sed is required but was not found (neither sed nor gsed)"
+        exit 1
+    fi
+else
+    SED="sed"
+fi
+
+#
+#
+#### End of command-line and environment validation
+
 if [[ ! "$options" =~ no-autoload-plugins ]]; then
     echo "********************************************************************"
     echo "Hint: consider using -no-autoload-plugins -load-module [modules]"
@@ -93,69 +179,106 @@ if [[ "$base" =~ \.c$ ]]; then
     echo "Hint: consider passing a preprocessed (.i) file if possible,"
     echo "      otherwise #includes may prevent further reduction"
     echo "********************************************************************"
+    # TODO: check for libc includes and suggest -print-libc
 fi
 
-mkdir -p "$dir_for_reduction"
-
-if [ -z "$FRAMAC" ]; then
-    SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
-    FRAMAC=$(realpath "$SCRIPT_DIR/../../bin/frama-c")
-    echo "[info] FRAMAC not set, using binary at: $FRAMAC"
+# Obtain cpp flags by running Frama-C with `-kernel-msg-key pp`
+if [[ "$base" =~ \.i$ ]]; then
+    # Preprocessed file: no need to get preprocessing flags
+    # TODO: check for '-machdep' option and add/remove flags accordingly
+    CPP="gcc -fsyntax-only"
 else
-    echo "[info] using FRAMAC: $FRAMAC"
+    set +e
+    cpp_output=$("$FRAMAC" -print-cpp-commands "$@" "$file" 2>/dev/null)
+    cpp_retcode=$?
+    set -e
+    if [ $cpp_retcode -ne 0 ]; then
+        echo "error trying to get preprocessing flags (exit code: $cpp_retcode): $FRAMAC -print-cpp-commands $@ $file"
+        exit $cpp_retcode
+    fi
+    CPP=$(echo "$cpp_output" | \
+          "$SED" -n '/Preprocessing command:/{n;p;}' | "$SED" "s|'.*' -o '.*'||")
+    if [[ "$CPP" = "" ]]; then
+        echo "[info] Could not get preprocessing flags when running Frama-C,"
+        echo "       using default flags"
+        # TODO: check for '-machdep' option and add/remove flags accordingly
+        CPP="gcc -fsyntax-only -m32"
+    else
+        # Replace -E with -fsyntax-only to force GCC to try parsing the file;
+        # also remove Frama-C's libc; use the standard system libraries.
+        CPP=$(echo $CPP | \
+                  "$SED" 's| -E | -fsyntax-only |' | \
+                  "$SED" 's| -nostdinc | |' | \
+                  "$SED" 's| -I[^ ]\+/libc | |' )
+    fi
 fi
 
-if [ -z "$FRAMAC_SHARE" ]; then
-    FRAMAC_SHARE="$("$FRAMAC" -print-share-path)"
+if [ ! -e "$script_for_creduce" ]; then
+    echo "[info] $script_for_creduce not found."
+    echo "Which kind of error are you reducing for?"
+    echo "1. Fatal crash (error message with stacktrace)"
+    echo "2. Non-fatal error"
+    read -p "Please enter 1 or 2: " errorkind
+    case $errorkind in
+        1)
+            cp "$FRAMAC_SHARE/analysis-scripts/script_for_creduce_fatal.sh" "$script_for_creduce"
+            ;;
+        2)
+            cp "$FRAMAC_SHARE/analysis-scripts/script_for_creduce_non_fatal.sh" "$script_for_creduce"
+            echo "Script copied. Please edit $script_for_creduce and re-run this script."
+            exit 0
+            ;;
+        *)
+            echo "Invalid choice, aborting."
+            exit 0
+            ;;
+    esac
 fi
 
-if [ -z "$CC" ]; then
-    CC=gcc
-    CFLAGS+="-fsyntax-only -I\"$FRAMAC_SHARE\"/libc -D__FC_MACHDEP_X86_32 -m32"
+if [ "$ignore_parsability" -eq 0 ]; then
+    echo "[info] the following command will be used to check for syntactic validity during reduction:"
+    echo "    $CPP"
 fi
 
-echo "[info] checking syntactic validity with: $CC $CFLAGS"
-
+mkdir -p "$dir_for_reduction"
 cp "$file" "$dir_for_reduction"
+cp "$script_for_creduce" "$dir_for_reduction"
 cd "$dir_for_reduction"
 
-cat <<EOF > script_for_creduce.sh
-#!/bin/bash -e
-
-# This script is given to creduce to reduce a Frama-C crashing test case
-# (where "crashing" means a 'fatal' exception, with stack trace).
-
-set +e
-$CC $CFLAGS "$base"
-if [ \$? -ne 0 ]; then
-   exit 1
-fi
-"$FRAMAC" "$base" $options
-retcode=\$?
-# see cmdline.ml for the different exit codes returned by Frama-C
-if [ \$retcode -eq 125 -o \$retcode -eq 4 ]; then
-    exit 0
+if [ "$ignore_parsability" -eq 0 ]; then
+    "$SED" -i "s|@CPP@|$CPP|g" "$script_for_creduce"
 else
-    exit 1
+    "$SED" -i "s|^.*@CPP@.*$||g" "$script_for_creduce"
 fi
-set -e
-
-EOF
-
-chmod u+x script_for_creduce.sh
+"$SED" -i "s|@FRAMAC@|$FRAMAC|g" "$script_for_creduce"
+"$SED" -i "s|@BASE@|$base|g" "$script_for_creduce"
+"$SED" -i "s|@FCFLAGS@|$(echo $@ | tr "'" "\\'")|g" "$script_for_creduce"
+chmod u+x "$script_for_creduce"
 
-trap "{ echo \"Creduce interrupted!\"; echo \"\"; echo \"(partially) reduced file: $dir_for_reduction/$base\"; exit 0; }" SIGINT
+trap '{ echo "Creduce interrupted!"; echo ""; echo "(partially) reduced file: $dir_for_reduction/$base"; exit 0; }' SIGINT
 
+echo ""
 echo "File being reduced: $dir_for_reduction/$base (press Ctrl+C to stop at any time)"
 
 set +e
-./script_for_creduce.sh 2>&1 >/tmp/script_for_creduce.out
+rm -rf /tmp/script_for_creduce.out
+$script_for_creduce >>/tmp/script_for_creduce.out 2>&1
 if [ $? -ne 0 ]; then
-    echo "error: script did not produce a Frama-C 'fatal' crash."
-    echo "       check the options given to Frama-C to ensure they make Frama-C crash."
+    # TODO: check if -cpp-extra-args exists and contains relative paths,
+    # and if so, warn about them
+    echo "#################################################"
+    echo "ERROR: script did not produce the expected error."
+    echo "       check the options given to Frama-C."
+    echo "       If you edited '$script_for_creduce', check it as well."
     echo ""
-    echo "Script output:"
-    cat /tmp/script_for_creduce.out
+    if [ $(wc -l /tmp/script_for_creduce.out | cut -d' ' -f1) -gt 20 ]; then
+        echo "# Script output (first 20 lines):"
+        head -n 20 /tmp/script_for_creduce.out
+        echo "(...) [truncated; full output in /tmp/script_for_creduce.out]"
+    else
+        echo "# Script output:"
+        cat /tmp/script_for_creduce.out
+    fi
     exit 1
 fi
 set -e
@@ -163,3 +286,4 @@ set -e
 "$CREDUCE" script_for_creduce.sh "$base"
 
 echo "Finished reducing file: $dir_for_reduction/$base"
+echo "Remember to remove 'script_for_creduce.sh' after you are done."
diff --git a/share/analysis-scripts/script_for_creduce_fatal.sh b/share/analysis-scripts/script_for_creduce_fatal.sh
new file mode 100644
index 0000000000000000000000000000000000000000..a0fc2ba7b9574f959ac738261ec7486cc5850c52
--- /dev/null
+++ b/share/analysis-scripts/script_for_creduce_fatal.sh
@@ -0,0 +1,17 @@
+#!/bin/bash -e
+
+# Script to reduce a Frama-C crashing test case.
+
+# This script requires no modification.
+# Names between '@'s will be replaced by creduce.sh.
+
+set +e
+"@FRAMAC@" "@BASE@" @FCFLAGS@
+retcode=$?
+# see cmdline.ml for the different exit codes returned by Frama-C
+if [ $retcode -eq 125 -o $retcode -eq 4 ]; then
+    exit 0
+else
+    exit 1
+fi
+set -e
diff --git a/share/analysis-scripts/script_for_creduce_non_fatal.sh b/share/analysis-scripts/script_for_creduce_non_fatal.sh
new file mode 100644
index 0000000000000000000000000000000000000000..d886aeaba29099358e77597529d56ed6ff25dbad
--- /dev/null
+++ b/share/analysis-scripts/script_for_creduce_non_fatal.sh
@@ -0,0 +1,51 @@
+#!/bin/bash -e
+
+# Script to reduce a Frama-C non-crashing test case.
+
+# This script must be completed by the user.
+# Names between '@'s will be replaced by creduce.sh.
+# See the Frama-C User Manual for more details.
+
+cc_out=$(mktemp creduce_cc_XXXXXX.log)
+fc_out=$(mktemp creduce_fc_XXXXXX.log)
+
+# We always check that the reduced file remains valid C code.
+set -o pipefail
+@CPP@ "@BASE@" 2>&1 | tee $cc_out
+set +o pipefail
+
+### Examples of conditions to be maintained by C-Reduce; copy and adapt
+#
+# Ensure that the C file contains <expr>
+# grep -q expr "@BASE@"
+#
+# Ensure that the compiler output contains <expr>
+# grep -q <expr> "$cc_out"
+#
+###
+
+########## INSERT CONDITION(S) RELATED TO THE SOURCE HERE ##########
+
+##########
+
+set -o pipefail
+"@FRAMAC@" "@BASE@" @FCFLAGS@ 2>&1 | tee $fc_out
+fc_retcode=$(echo ${PIPESTATUS[0]})
+set +o pipefail
+
+### Examples of conditions to be maintained by C-Reduce; copy and adapt
+#
+# Ensure that Frama-C emits <expr>
+# grep -q <expr> "$fc_out"
+#
+# Ensure that the exit code of Frama_C is <rc>
+# test $fc_retcode -eq <rc>
+#
+###
+
+########## INSERT CONDITION(S) RELATED TO FRAMA-C HERE ##########
+
+##########
+
+### Cleanup
+rm -f $cc_out $fc_out