#!/bin/bash
RUN=0
PRIMS=1
TRACE=""
GDB=""
IMP77="0"   # ask for imp77 syntax check before compiling.
IMP80="0"   # ask for imp80 syntax check before compiling.
IMP68K="0"
IMPCHECK="1"
OPT=""
BASE="`dirname $0`/../"
# https://blogs.oracle.com/linux/post/making-code-more-secure-with-gcc-part-2
# use -O0 unless using  -D_FORTIFY_SOURCE=1 -O2 :
# since we make heavy use of arrays declared with dynamic bounds within
# recursive valls, trying option -fsplit-stack to see if it helps with
# some cases where an error has occurred for no apparent reason other
# than the size of the Imp program being compiled.
GCCOPTS=" -Wall -fsplit-stack -Wno-return-type -Wno-comment -g -fsanitize=undefined -fsanitize-undefined-trap-on-error -fno-sanitize-recover=all -frecord-gcc-switches -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -fstack-protector -D_FORTIFY_SOURCE=1 -O2  -ftrapv -grecord-gcc-switches  -ggdb3 "
#GCCOPTS=" -Wall -Wno-return-type -Wno-comment -g -fno-omit-frame-pointer -fsanitize=undefined -fsanitize-undefined-trap-on-error -fno-sanitize-recover=all -frecord-gcc-switches -fsanitize=float-divide-by-zero -fsanitize=float-cast-overflow -ftrapv -grecord-gcc-switches -O2 -ggdb3 "
if [ "$1" = "-np" ]; then
    # no perms/prims
    shift
    PRIMS=0
fi
if [ "$1" = "-r" ]; then
    # compile and run student system
    shift
    RUN=1
fi
if [ "$1" = "--opt" ]; then
    shift
    OPT="-opt" # run binary that was compiled without assertions or array index range checks
fi
if [ "$1" = "--fast" ]; then
    shift
    OPT="-opt" # run binary that was compiled without assertions or array index range checks
fi
if [ "$1" = "--trace" ]; then
    shift
    RUN=1
    TRACE="--trace"
fi
if [ "$1" = "--imp77" ]; then
    shift
    IMP77=1
fi
if [ "$1" = "--imp80" ]; then
    shift
    IMP80=1
fi
if [ "$1" = "--imp68k" ]; then
    shift
    IMP68K=1
fi
if [ "$1" = "--no-check" ]; then
    shift
    IMPCHECK=0
fi
if [ "$1" = "--no-gdb" ]; then
    shift
    RUN=1
    GDB="--no-gdb"
fi
if [ "$1" = "--nogdb" ]; then
    shift
    RUN=1
    GDB="--no-gdb"
fi
if [ "$1" = "--gdb" ]; then
    shift
    RUN=1
    GDB="--gdb"
fi
if [ "$1" = "--trace" ]; then
    shift
    RUN=1
    TRACE="--trace"
fi
last=${@:$#}     # last parameter is always the .imp file
other=${*%${!#}} # all parameters except the last (i.e. all options)
if [ ! -f $last ] ; then
    echo $last does not exist.
    exit 1
fi
if [ "$last" = "" ] ; then
    echo "Syntax: imps [-r] [-np] file.imp"
    exit 0
fi
if  [ $PRIMS = 1 ]; then
  cat ${BASE}include/imp/perms.inc $last > /tmp/$$.imp
  if  [ $IMPCHECK = 1 ]; then
    if  [ $IMP77 = 1 ]; then
      #echo /usr/local/bin/pass1 $last,/home/gtoal/src/compilers101/new-parser/imps/perms.inc=/dev/null,/tmp/$$.lis
      /usr/local/bin/pass1 $last,${BASE}include/imp/perms.inc=/dev/null,/tmp/$$.lis 1>&2
      if [ $? -ne 0 ] ; then
          exit $?
      fi
    elif  [ $IMP80 = 1 ]; then
      # case 'a':       /* NOARRAY */
      # case 'c':       /* CODE */
      # case 'D':       /* DYNAMIC */
      # case 'd':       /* NODIAG */
      # case 'f':       /* NOFREE */
      # case 'g':       /* DEBUG */
      # case 'h':       /* display help */
      # case 'i':       /* LET */
      # case 'k':       /* NOCHECK */
      # case 'l':       /* listing file */
      # case 'm':       /* MAXDICT */
      # case 'n':       /* NOLINE */
      # case 'O':       /* OPT */
      # case 'o':       /* object file */
      # case 'p':       /* PROFILE */
      # case 's':       /* STACK */
      # case 't':       /* NOTRACE */
      # case 'w':       /* workfile size */
      # case 'v':       /* verbose option */
      # case 'x':       /* PARMX */
      # case 'y':       /* PARMY */
      # case 'z':       /* PARMZ */
                                                                                                                      
      # /home/gtoal/src/compilers101/new-parser/imps/imp80/compiler/imp80 -l /tmp/$$ $last
      /home/gtoal/src/compilers101/new-parser/imps/imp80/compiler/imp80 -l /tmp/$$ $last
      if [ $? -ne 0 ] ; then
          exit $?
      fi
    elif  [ $IMP68K = 1 ]; then
      /home/gtoal/bin/check68k $last
      if [ $? -ne 0 ] ; then
          exit $?
      fi
    else
      : # check wanted but specific variant not mentioned
    fi
  fi
else
  cat $last > /tmp/$$.imp
  if  [ $IMPCHECK = 1 ]; then
    if  [ $IMP77 = 1 ]; then
      #echo /usr/local/bin/pass1 /tmp/$$.imp,/home/gtoal/src/compilers101/new-parser/imps/nullperms.inc=/dev/null,/tmp/$$.lis
      /usr/local/bin/pass1 /tmp/$$.imp,/home/gtoal/src/compilers101/new-parser/imps/nullperms.inc=/dev/null,/tmp/$$.lis 1>&2
      if [ $? -ne 0 ] ; then
          exit $?
      fi
    elif  [ $IMP80 = 1 ]; then
      # /home/gtoal/src/compilers101/new-parser/imps/imp80/compiler/imp80 -l /tmp/$$ $last
      /home/gtoal/src/compilers101/new-parser/imps/imp80/compiler/imp80 -l /tmp/$$ $last
      if [ $? -ne 0 ] ; then
          exit $?
      fi
    else
      : # check wanted but specific variant not mentioned
    fi
  fi
fi

${BASE}imps$OPT $other /tmp/$$.imp > /tmp/$$.c
gprof ${BASE}imps$OPT gmon.out > imps.profile
# As a backup in case the user doesn't have clang-format or uncrustify,
# I supply a source for 'cb' (the ancient 'C Beautifier')

cp ${BASE}.clang-format . > /dev/null 2>&1
cat /tmp/$$.c| \
    tr -d "\r" | clang-format -style=file > /tmp/$$_c3
    if [ $RUN = 1 ]; then
        rm -f /tmp/temptest
        cp /tmp/$$_c3 /tmp/temptest.c
        cc -o /tmp/temptest \
           -I ${BASE}include/c/ \
           $GCCOPTS \
           /tmp/temptest.c ${BASE}runtime/perms.c \
           -lm
        if [ "$GDB" = "--gdb" ]; then
            /tmp/temptest $GDB $TRACE
        else
           # normal run doesn't want gdb messages on stdout or stderr
            ( /tmp/temptest $GDB $TRACE \
               | sed  "s/\[Thread debugging using libthread_db enabled\]//g" \
               | sed  "s/Using host libthread_db library \"\/lib\/i386-linux-gnu\/libthread_db\.so\.1\"\.//g" \
               | sed  "s/^\[Inferior 1 (process [0-9][0-9]*) exited normally\]$//p" \
             ) 3>&1 1>&2 2>&3 \
               | sed  "s/^No stack\.$//g" \
               3>&1 1>&2 2>&3
        fi
    else
      cat /tmp/$$_c3
    fi
exit 0
