# ACD pass description for the ACK and GCC compilers and the C68/C386
# front end.
#
# Pre-set variables.
#   PROGRAM		- Name the compiler driver is called with.
#   ARCH		- Default target architecture.

# Preferred front end and back end if there is a choice.  Use names ack, gnu,
# or ccc.  (Another description file may have defined these already.)
ifndef PREF_FE
	PREF_FE = ack
	PREF_BE = ack

# Library directories search path.
L =	/lib /usr/lib

# ACK Compilers support search path.
A =	$L/ack

# GCC Compiler support search path.
G =	$L/gnu

# C68/C386 front end search path.
C =	$L/ccc

# ARCH must be defined.
ifndef ARCH
	error "\$ARCH is not predefined"

# Remember the architecture we run under.
THIS_ARCH = * $ARCH

# Get ARCH from the environment if set.
import ARCH

# Compiler passes.
ACK_CPP =	$A/cpp.ansi $CPP_F $PREDEF $NOLINENO
ACK_CEM =	$A/em_cemcom.ansi -L $CPP_F $PREDEF \
		    -Vw${W}.${W}i${W}.${W}p${P}.${W}f4.${W}s2.2l4.${W}d8.${W}
ACK_M2 =	$A/em_m2 -I$MOD_INCL -WR \
		    -Vw${W}.${W}i${W}.${W}p${P}.${W}l4.${W}f4.${W}d8.${W}
ACK_PC =	$A/em_pc \
		    -Vw${W}.${W}i${W}.${W}l4.${W}p${P}.${W}f8.${W}S${W}.${W}
MOD_INCL =	$A/m2 +
ACK_DECODE =	$A/em_decode
ACK_ENCODE =	$A/em_encode
ACK_OPT =	$A/em_opt
ACK_EGO =	$A/em_ego -P $A/ego -M$EGO_DESCR
EGO_DESCR =	$A/ego/${ARCH}descr +
ACK_OPT2 =	$A/em_opt2
ACK_CG =	$A/$ARCH/cg
ACK_AS =	$A/$ARCH/as \-
ACK_LED =	$A/em_led -a0:$W -a1:$W -a2:$W -a3:$W
ACK_CV =	$A/cv
GNU_CPP =	$G/cpp -nostdinc -undef -pedantic -trigraphs -\$ -Wall \
			$PREDEF $CPP_F -I/usr/include
GNU_CC1 =	$G/$ARCH/cc1 -quiet -ansi -pedantic -Wall -Wstrict-prototypes
GNU_AS =	$G/$ARCH/as
GNU_LD =	$G/$ARCH/ld
GNU_CV =	$G/$ARCH/gcv
CCC_CC1 =	$C/$ARCH/cc1 -separate -fpret387 -warn=4
ASMCONV =	$L/asmconv
AAL =		/usr/bin/aal
AR =		/usr/bin/ar
RANLIB =	/usr/bin/ranlib

# Minix predefined symbols.
CPP_F =		-D__minix -D__minix_vmd -D__$ARCH -D_BSD_ANSI_LIB_SRC \
			-D_ARCH=$MNX_ARCH -D_VMD_EXT

# Library path.
LIBPATH = $USERLIBPATH $L/$PREF_BE/$ARCH

# Default output "model".
DEF_MODEL = -pal -uzp -sep

# Default optimization level.
OPT_LEVEL = 1

# Call names.
if $PROGRAM = acc
	PREF_FE = ack		# Prefer ack if called as acc.
	PREF_BE = ack
	PROGRAM = cc
if $PROGRAM = apc
	PREF_FE = ack		# Prefer ack if called as apc.
	PREF_BE = ack
	PROGRAM = pc
if $PROGRAM = am2
	PREF_FE = ack		# Prefer ack if called as am2.
	PREF_BE = ack
	PROGRAM = m2
if $PROGRAM = gcc
	PREF_FE = gnu		# Prefer gnu if called as gcc.
	PREF_BE = gnu
	PROGRAM = cc
if $PROGRAM = ccc
	PREF_FE = ccc		# Prefer ccc, use the given back end.
	PROGRAM = cc
if $PROGRAM = kcc
	PROGRAM = cc		# The kernel C compiler.

# Default transformation target.
stop .out

# Select the runtime environment by option or program name.
arg -.c
if $PROGRAM = cc
	ifndef RTSO
		RTSO = -.c
	LIBS = $LIBS + -.c

arg -.mod
if $PROGRAM = m2
	ifndef RTSO
		RTSO = -.mod
	LIBS = $LIBS + -.mod

arg -.p
if $PROGRAM = pc
	ifndef RTSO
		RTSO = -.p
	LIBS = $LIBS + -.p

# Omit the runtime startoff, but keep the libraries.
arg -.o
	RTSO =

arg -.$any
	error ".$any: unknown language"

# Select the target architecture.
arg -m$arch
	ARCH = $arch

# Preprocessor directives.
arg -D$name
arg -D $name
	CPP_F = $CPP_F -D$name
arg -U$name
arg -U $name
	CPP_F = $CPP_F -U$name
arg -I$dir
arg -I $dir
	CPP_F = $CPP_F -I$dir
	ACK_M2 = $ACK_M2 -I$dir

# Debugging.
arg -g				# Add debugging info.
	ACK_CEM = $ACK_CEM -g
	ACK_CG = $ACK_CG -gdb

arg -n				# Suppress line numbers.
	ACK_M2 = $ACK_M2 -L
	ACK_PC = $ACK_PC -L
arg -a				# Enable assertions.
arg -R				# Disable runtime checks
arg -A				# Enable array bound checks.
	ACK_M2 = $ACK_M2 $*
	ACK_PC = $ACK_PC $*

# Language checking.
arg -w				# No warnings.
	ACK_CEM = $ACK_CEM $*
	ACK_M2 = $ACK_M2 $*
	ACK_PC = $ACK_PC $*
	GNU_CC1 = $GNU_CC1 - -pedantic -Wall -Wstrict-prototypes
	CCC_CC1 = $CCC_CC1 -warn=1

arg -ws				# No strict warnings.
	ACK_CEM = $ACK_CEM -s
	ACK_M2 = $ACK_M2 -wR
	GNU_CC1 = $GNU_CC1 - -Wstrict-prototypes
	CCC_CC1 = $CCC_CC1 -warn=3

arg -wa				# No warnings and no strict warnings.
	ACK_CEM = $ACK_CEM -a
	ACK_M2 = $ACK_M2 -wR
	GNU_CPP = $GNU_CPP - -pedantic -Wall
	GNU_CC1 = $GNU_CC1 - -pedantic -Wall -Wstrict-prototypes
	CCC_CC1 = $CCC_CC1 -warn=0

arg -wo				# No warnings about old style C (or GNU C).
	ACK_CPP = $ACK_CPP -o
	ACK_CEM = $ACK_CEM -o
	ACK_M2 = $ACK_M2 -wO
	GNU_CPP = $GNU_CPP - -pedantic
	GNU_CC1 = $GNU_CC1 - -ansi -pedantic -Wstrict-prototypes \
			+ -Wno-return-type -Wno-implicit
	CCC_CC1 = $CCC_CC1 -warn=2

arg -3				# Only accept 3rd generation Modula-2.
	ACK_M2 = $ACK_M2 $*

arg -_				# Allow underscores in identifiers.
	ACK_M2 = $ACK_M2 -U
	ACK_PC = $ACK_PC -U

arg -w$any
arg -F
arg -m
	# Ignore strange -w flags, and past and present i86 compiler flags.

# Stop suffix.
arg -c
	stop .o

arg -c.$stop
	stop .$stop

arg -E
	stop .E

arg -P
	CPP_F = $CPP_F -P
	stop .i

arg -S
	stop .s

# Optimization.
arg -O
	OPT_LEVEL = 1

arg -O$n
	numeric $n
	OPT_LEVEL = $n

arg -OS				# Optimize for size.
	ACK_EGO = $ACK_EGO -S
arg -OT				# Optimize for time.
	ACK_EGO = $ACK_EGO -T

# Library search path.
arg -L$dir
arg -L $dir
	USERLIBPATH = $USERLIBPATH $dir/$PREF_BE/$ARCH $dir

# -llib must be searched in $LIBPATH later.
arg -l$lib
arg -l $lib
	$> = $LIBPATH/lib$lib.a

# Software floating point, or no floating point.
arg -f
arg -fp
arg -fsoft
	GNU_CC1 = $GNU_CC1 -msoft-float -mno-fp-ret-in-387
	CCC_CC1 = $CCC_CC1 -nofpu
	LIBS = $LIBS + -fsoft

arg -fnone
	LIBS = $LIBS + -fnone

# Output model.
arg -com			# Common, no tricks.
	DEF_MODEL = ; MODEL = $MODEL - -pal -uzp -sep

arg -sep			# Separate I&D.
arg -pal			# Page aligned (header in text).
arg -uzp			# Unmapped zero page (trap null-dereferences.)
	DEF_MODEL = ; MODEL = $MODEL + $*

arg -i				# Traditional sep I&D flag.
	MODEL = $MODEL + -sep

arg -r				# Relocatable object (combined .o)
	MODEL = -r

# Strip executable.
arg -s
	ACK_LED = $ACK_LED -s
	GNU_LD = $GNU_LD -s

# Size of heap+stack.
arg -stack $size
	ACK_CV = $ACK_CV -S $size
	GNU_CV = $GNU_CV -S $size

# Change output file.
arg -o$out
arg -o $out
	OUT = $out

# Complain about just -D, -U, -I, ...
arg -D; arg -U; arg -I; arg -L; arg -l; arg -o; arg -stack
	error "argument expected after '$*'"

arg -R$pass-$flag		# The ACK way of passing options to passes.
arg -Wack-R$pass-$flag		# The ACD way.
	if $pass = cpp
		ACK_CPP = $ACK_CPP -$flag
	if $pass = cem
		ACK_CEM = $ACK_CEM -$flag
	if $pass = m2
		ACK_M2 = $ACK_M2 -$flag
	if $pass = pc
		ACK_PC = $ACK_PC -$flag
	if $pass = opt
		ACK_OPT = $ACK_OPT -$flag
	if $pass = ego
		ACK_EGO = $ACK_EGO -$flag
	if $pass = opt2
		ACK_OPT2 = $ACK_OPT2 -$flag
	if $pass = cg
		ACK_CG = $ACK_CG -$flag
	if $pass = as
		ACK_AS = $ACK_AS -$flag
	if $pass = led
		ACK_LED = $ACK_LED -$flag

arg -Wgcc-$opt			# Let gcc-cc1 deal with this.
	GNU_CC1 = $GNU_CC1 -$opt

arg -Wccc-$opt			# C68/C386 special option.
	CCC_CC1 = $CCC_CC1 -$opt

arg -Was-$dialect		# Default assembly dialect.
	ASDIALECT = $dialect

arg -Wacd-nortso		# Omit the runtime startoff.
	RTSO =

arg -Wacd-nolibs		# Omit the libraries.
	LIBS = -nolibs

arg -W$any
	# Ignore any other -W options.

# Complain about unknown options, don't give them to the loader.
arg -$any
	error "$*: unknown option"

# Do the scanning phase early, we need to know the architecture.
scan

# Not all compilers can compile for the i86.  Replace by one that can.
if $PREF_FE = gnu
if $PREF_FE = ccc
	if (i86 - $THIS_ARCH $ARCH) = ()
		PREF_FE = ack
		PREF_BE = ack

# The word and pointer sizes of the target.
if $ARCH = i86
	W = 2; P = 2; MNX_ARCH = _IBM_PC
if $ARCH = i386
	W = 4; P = 4; MNX_ARCH = _IBM_386_VM

ifndef W
	error "$ARCH: unsupported architecture"

# How to optimize?
if $OPT_LEVEL = 0
	CCC_CC1 = $CCC_CC1 -noopt

if $OPT_LEVEL = 1
	GNU_CC1 = $GNU_CC1 -O
	CCC_CC1 = $CCC_CC1 -O

if (0 1 - $OPT_LEVEL) = (0 1)
	ACK_EGO = $ACK_EGO -O$OPT_LEVEL
	ACK_OPT = $ACK_OPT -m0	# Leave multiplication optimization to opt2.
	if $PREF_FE = ack
		prefer .m .gk
	GNU_CC1 = $GNU_CC1 -O$OPT_LEVEL
	CCC_CC1 = $CCC_CC1 -O
	if $PREF_FE:$PREF_BE = ccc:gnu
		PREF_FE = gnu	# Use gcc with high optimization levels.

# Tell cem to reverse bitfields on the i386 to be compatible with gcc.
if $ARCH = i386
	ACK_CEM = $ACK_CEM -Vr

# Predefined preprocessor flags.
if $PREF_FE = ack
	PREDEF = -D_EM_WSIZE=$W -D_EM_PSIZE=$P -D_EM_SSIZE=2 -D_EM_LSIZE=4 \
		 -D_EM_FSIZE=4 -D_EM_DSIZE=8 -D__ACK__ -D__ACK
if $PREF_FE = gnu
	PREDEF = -D__GNUC__=2 -D__GNUC_MINOR__=7
if $PREF_FE = ccc
	PREDEF = -D__CCC__

if $PREF_FE = ack
if $PREF_FE:$PREF_BE = ccc:ack
	# ACK front end rules.

	# Preprocess C source.
	transform .c .i
		$ACK_CPP $* > $>

	# Preprocess any type of file and send it to standard output or $OUT.
	transform "" .E
		if $* = "-"
			file =		# Standard input.
		else
			file = $*
		ifndef OUT
			$ACK_CPP $file
		else
			$ACK_CPP $file > $OUT

	# Compile C source to EM-code.
	transform .c .k
	transform .i .k
		$ACK_CEM $* $>
		ifndef RTSO
			RTSO = -.c
		LIBS = $LIBS + -.c

	# Compile Modula-2 source to EM-code.
	transform .mod .k
		ifhash $*
			apply .c .i
		$ACK_M2 $* $>
		ifndef RTSO
			RTSO = -.mod
		LIBS = $LIBS + -.mod

	# Compile Pascal source to EM-code.
	transform .p .k
		ifhash $*
			apply .c .i
		$ACK_PC $* $>
		ifndef RTSO
			RTSO = -.p
		LIBS = $LIBS + -.p

	# Compact EM to readable EM.
	transform .k .e
	transform .m .e
	transform .gk .e
	transform .g .e
		$ACK_DECODE $* > $>

	# Readable EM to compact EM.
	transform .e .k
		ifhash $*
			NOLINENO = -P	# Encode chokes on cpp line directives.
			apply .c .i
			unset NOLINENO
		$ACK_ENCODE $* > $>

	# Peephole optimization.
	transform .k .m
		$ACK_OPT $* > $>

	# Global optimization.
	transform .m .gk
		$ACK_EGO $* > $>

	# Second peephole optimization after global optimization.
	transform .gk .g
		$ACK_OPT2 $* > $>

	# EM-code to target machine assembly.
	transform .m .ack.s
	transform .g .ack.s
	transform .m .s
	transform .g .s
		$ACK_CG $* > $>

	if $PREF_FE = ccc
		# Prefer ccc over ack.
		prefer .i .bas.s
		transform .i .bas.s
			$CCC_CC1 -bas386 $* > $>
			ifndef RTSO
				RTSO = -.c
			LIBS = $LIBS + -.c

	# How to treat plain .s?
	ifndef ASDIALECT
		transform .s .ack.s
			$> = $*

	# Assembly to object file.
	transform .ack.s .o
		ifhash $*
			apply .c .i
		if $> = $<.o
			ifdef OUT
				$> = $OUT
		$ACK_AS -o $> $*

if $PREF_BE = ack
	# Combine object files and libraries to an executable.
	combine (.o .a) .out
		MODEL = $MODEL + $DEF_MODEL
		if $ARCH = i86
			MODEL = $MODEL - (-pal -uzp)
		if $MODEL = ()
			model = -b0:0
		if $MODEL = (-sep)
			model = -b0:0 -b1:0
		if $MODEL = (-uzp)
			model = -b0:4096
		if $MODEL = (-uzp -sep)
			model = -b0:4096 -b1:4096
		if $MODEL = (-pal)
			model = -b0:32
		if $MODEL = (-pal -sep)
			model = -b0:32 -b1:0
		if $MODEL = (-pal -uzp)
			model = -b0:4128
		if $MODEL = (-pal -uzp -sep)
			model = -b0:4128 -b1:4096
		rtso =
		if $RTSO = -.c
			rtso = $A/$ARCH/crtso.o
		if $RTSO = -.mod
			rtso = $A/$ARCH/m2rtso.o
		if $RTSO = -.p
			rtso = $A/$ARCH/prtso.o
		libm2 = ; libp = ; libnofp = ; libc =
		if (-.mod - $LIBS) = ()
			libm2 = $A/$ARCH/libm2.a
			libc = $A/$ARCH/libc.a
		if (-.p - $LIBS) = ()
			libp = $A/$ARCH/libp.a
			libc = $A/$ARCH/libc.a
		if (-fnone - $LIBS) = ()
			libnofp = $A/$ARCH/libnofp.a
		if (-.c - $LIBS) = ()
			libc = $A/$ARCH/libc.a
		libs = $libm2 $libp $libnofp $libc
		if (-nolibs - $LIBS) = ()
			libs =
		ifndef OUT
			OUT = a.out
		if (-r - $MODEL) = ()
			# Combine to an object file.
			$ACK_LED -r -o $OUT $*
		else
			# Combine to an executable.
			mktemp EXE
			$ACK_LED $model -o $EXE $rtso $* $libs $A/$ARCH/end.a
			$ACK_CV -m$ARCH $EXE $OUT

	# Add object files to a library.
	combine (.o) .a
		if $> = $<.a
			ifdef OUT
				$> = $OUT
		$AAL cr $> $*

if $PREF_FE = gnu
if $PREF_FE:$PREF_BE = ccc:gnu
	# GCC front end rules.

	# Preprocess C source.
	transform .c .i
		$GNU_CPP $* > $>

	# Preprocess any type of file and send it to standard output or $OUT.
	# GNU cpp understands "-".
	transform "" .E
		ifndef OUT
			$GNU_CPP $*
		else
			$GNU_CPP $* > $OUT

	# Compile C source to assembly.
	transform .i .gnu.s
	transform .i .s
		if $PREF_FE = gnu
			$GNU_CC1 -dumpbase $<.c -o $> $*
		else
			$CCC_CC1 -gas386 $* > $>
		ifndef GNU_RTSO
			GNU_RTSO = $GNU_CRTSO
		ifndef GNU_LIB
			GNU_LIB = $GNU_CLIB

	# How to treat plain .s?
	ifndef ASDIALECT
		transform .s .gnu.s
			$> = $*

	# Assembly to object file.
	transform .gnu.s .o
		ifhash $*
			apply .c .i
		if $> = $<.o
			ifdef OUT
				$> = $OUT
		$GNU_AS -o $> $*

if $PREF_BE = gnu
	# Combine object files and libraries to an executable.
	combine (.o .a) .out
		MODEL = $MODEL + $DEF_MODEL
		if $MODEL = ()
			model = -N -Ttext 0
		if $MODEL = (-sep)
			model = -N -Ttext 0 -Tdata 0
		if $MODEL = (-uzp)
			model = -N -Ttext 1000
		if $MODEL = (-uzp -sep)
			model = -N -Ttext 1000 -Tdata 1000
		if $MODEL = (-pal)
			model = -N -Ttext 20
		if $MODEL = (-pal -sep)
			model = -N -Ttext 20 -Tdata 0
		if $MODEL = (-pal -uzp)
			model = -N -Ttext 1020
		if $MODEL = (-pal -uzp -sep)
			model = -N -Ttext 1020 -Tdata 1000
		rtso =
		if $RTSO = -.c
			rtso = $G/$ARCH/crtso.o
		libnofp = ; libsoft = ; libc =
		if (-fnone - $LIBS) = ()
			libnofp = $G/$ARCH/libnofp.a
		if (-fsoft - $LIBS) = ()
			libsoft = $G/$ARCH/libsoft.a
		if (-.c - $LIBS) = ()
			libc = $G/$ARCH/libc.a
		libs = $libnofp $libsoft $libc
		if (-nolibs - $LIBS) = ()
			libs =
		ifndef OUT
			OUT = a.out
		if (-r - $MODEL) = ()
			# Combine to an object file.
			$GNU_LD -r -o $OUT $*
		else
			# Combine to an executable.
			mktemp EXE
			$GNU_LD $model -o $EXE $rtso $* $libs $G/$ARCH/libgcc.a
			$GNU_CV $MODEL $EXE $OUT

if $PREF_BE = gnu
	# Add object files to a library.
	combine (.o) .a
		if $> = $<.a
			ifdef OUT
				$> = $OUT
		$AR crT $> $*
		if $PREF_BE = gnu
			$RANLIB $>

# Assembly conversions.

# ACK assembly to ACK Xenix assembly.
transform .ack.s .ncc.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH ack ncc $* $>

# ACK assembly to GNU assembly.
transform .ack.s .gnu.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH ack gnu $* $>

# ACK Xenix assembly to ACK assembly.
transform .ncc.s .ack.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH ncc ack $* $>

# ACK Xenix assembly to GNU assembly.
transform .ncc.s .gnu.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH ncc gnu $* $>

# BCC assembly to ACK assembly.
transform .bas.s .ack.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH bas ack $* $>

# BCC assembly to ACK Xenix assembly.
transform .bas.s .ncc.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH bas ncc $* $>

# BCC assembly to GNU assembly.
transform .bas.s .gnu.s
	ifhash $*
		apply .c .i
	$ASMCONV -m$ARCH bas gnu $* $>

#ifdef ASDIALECT
	# Treat plain .s as being in the given dialect.
	transform .s .$ASDIALECT.s
		$> = $*
