LANGUAGE := c
EXT := c
# LANGUAGE := project-name      # replace with your own language to be compiled
# EXT := ext

# setting CC to gcc or clang explicitly should be OK.
CC=cc 

REMAKE=-f Makefile-$(LANGUAGE)
# Pick one:
#SAFEOPTS=-Ofast -DFAST   # for a factor of 3 speedup.
SAFEOPTS=-DSUPPLY_DEFAULT_WALK_AST -g -Wall -Wno-unused-but-set-variable 

# Pick one: (Note that two programs fail with runtime-checking options on, so those always use SAFEOPTS )
#OPTS=$(SAFEOPTS)
OPTS=-DSUPPLY_DEFAULT_WALK_AST -Wall -Wno-return-type -Wno-comment -Wno-unused-but-set-variable -Wno-maybe-uninitialized -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 -O2  -ftrapv -grecord-gcc-switches  -ggdb3 # -fsanitize=address - always fails in getwc.

all: $(LANGUAGE:%=%) regen Makefile $(LANGUAGE:%=%.ng)  # mnemalyse
	@echo All up to date.


$(LANGUAGE:%=%): $(LANGUAGE:%=%.h) Makefile ../../regexp-lexer.o ../../flex.o ../../uparse.o ../../symtab.o # mnemosyne.o 
	@echo LINK $(LANGUAGE:%=%)
	@$(CC) $(OPTS) -o $(LANGUAGE:%=%) ../../uparse.o ../../regexp-lexer.o ../../flex.o ../../symtab.o # mnemosyne.o 
	@# can't use gdb with gzexe binaries
	@# which gzexe && gzexe $(LANGUAGE:%=%) || exit 0

../../symtab.o: ../../symtab.c ../../symtab.h ../../symtab_priv.h
	$(CC) $(OPTS) -o ../../symtab.o -I../.. -c ../../symtab.c

# This regenerates the skeleton compiler code (CST to AST conversion - just the switch on G_*) from the grammar.
$(LANGUAGE:%=%-ast.h): regen
	@echo regen $(LANGUAGE:%=%-ast.h)
	@./regen > $(LANGUAGE:%=%-ast.h)

# This regenerates the skeleton compiler code (AST to application conversion) from the grammar.
$(LANGUAGE:%=%-comp.h): gencomp
	@echo gencomp $(LANGUAGE:%=%-comp.h)
	@./gencomp > $(LANGUAGE:%=%-comp.h)

# This builds the tool to regenerate the skeleton compiler code from the grammar.
# It currently only builds the CST to AST conversion.
# -I. below is because regen.c includes $(LANGUAGE).h and gcc does not treat it as relative to gencomp.c's directory...
regen: ../../regen.c $(LANGUAGE:%=%.h) ../../parser.h ../../flex.o Makefile
	@echo CC regen.c
	@$(CC) $(SAFEOPTS) -Wno-unused-variable -o regen -I. -DGRAMMAR=\"$(LANGUAGE:%=%.h)\" ../../regen.c ../../flex.o

# This builds the tool to regenerate the skeleton compiler code from the grammar.
# It currently only builds the CST to AST conversion.
# -I.. below is because gencomp.c includes parser.h and gcc does not treat it as relative to gencomp.c's directory...
gencomp: ../../gencomp.c $(LANGUAGE:%=%.h) ../../parser.h ../../flex.o Makefile
	@echo CC gencomp.c
	@$(CC) $(SAFEOPTS) -Wno-unused-variable -o gencomp -I../.. -I. -DGRAMMAR=\"$(LANGUAGE:%=%.h)\" ../../gencomp.c ../../flex.o

# This is a backup of the grammar extracted from the grammar tables.
# Only the basic rules are saved. Comments and some grammar extensions are dropped.
# It may be useful when making changes to the grammar after the compiler code is written.
# NOTE!!! Does not correctly escape "\\" in strings.
$(LANGUAGE:%=%.ng): $(LANGUAGE:%=%-ast.h)
	@sed -ne 's|\(.*\)//\\\\ \(.*\)|\2|gp' $(LANGUAGE:%=%-ast.h) > $(LANGUAGE:%=%.ng)

# This is the body of the ../../parser.  It requires the grammar to have been converted to table form.
../../uparse.o: ../../uparse.c ../../uparse-main.c $(LANGUAGE)-compile.h $(LANGUAGE)-switch.h ../../parser.h ../../flex.h Makefile $(LANGUAGE:%=%-ast.h) $(LANGUAGE:%=%-comp.h) # $(LANGUAGE:%=%.c) $(LANGUAGE:%=%-indent.c)
	@echo CC uparse.c
	$(CC) $(OPTS) -I../.. -I. \
	              -DAPPMODULE=\"$(LANGUAGE)-compile.h\" \
	              -DAPPCOMMAND=compile \
	              -DGRAMMAR=\"$(LANGUAGE:%=%.h)\" \
	              -DCST2AST=\"$(LANGUAGE:%=%-ast.h)\" \
	              -Wno-unused-variable \
	              -c -o ../../uparse.o ../../uparse.c

#	              -DCOMPILER=\"$(LANGUAGE:%=%.c)\" \


# This converts the grammar to table form.  Executing in a pipe was bad because errorcode set to that of whole pipe, ignoring return from ../../takeon.
$(LANGUAGE:%=%.h): $(LANGUAGE:%=%.g) ../../takeon Makefile
	@echo ../../takeon $(LANGUAGE:%=%.g)
	@../../takeon $(LANGUAGE:%=%.g) > $(LANGUAGE:%=%.h)


# This converts the grammar to table form.
$(LANGUAGE:%=%-switch.h): $(LANGUAGE:%=%-comp.h)
	@ecce $(LANGUAGE:%=%-comp.h) $(LANGUAGE:%=%-switch.h)  --command "u0.  switch (op).km0f-.//\\\\ E.mk0;%c" > /dev/null 2>/dev/null

# This builds the utility which converts the grammar to table form.
# NOTE: -fsanitize=address causes erroneous trap when running ../../takeon.  Do not use that option here.
../../takeon: ../../takeon.c ../../takeon-output.c ../../takeon-checks.c ../../flex.h Makefile ../../flex.o
	@echo CC takeon.c
	@$(CC) $(SAFEOPTS) -o ../../takeon ../../takeon.c ../../flex.o

# This is a utility used in much of the code to support ../../flex arrays, i.e. arrays
# which extend their allocated space as more elements are accessed.  It also
# supplies some checks on array bounds and unassigned variables.  These are
# relatively cheap to implement - the runtime of a program using ../../flex arrays
# and checking is about 3 times that of the same program with static arrays
# and no checks.  Use the "-DFAST" option at the head of this file for a
# faster executable but only once the code is stable and ready for release testing.
../../flex.o: ../../flex.c ../../flex.h Makefile
	@echo CC flex.c
	@$(CC) $(SAFEOPTS) -o ../../flex.o -c ../../flex.c

# This is an internal regular expression matcher which has been modified
# to support Unicode characters.
../../regexp-lexer.o: ../../regexp-lexer.c Makefile ../../parser.h # ../../tools/mnemosyne.h 
	@echo CC regexp-lexer.c
	@$(CC) $(OPTS) -o ../../regexp-lexer.o -c ../../regexp-lexer.c -I../../tools

# This is an old memory leak utility I used to use in the 80's - you can get
# equally good results nowadays by using valgrind instead.  It is off by default.
mnemosyne.o: ../../tools/mnemosyne.c ../../tools/mnemosyne.h Makefile
	$(CC) $(OPTS) -Wno-unused-variable -Wno-pointer-to-int-cast -c ../../tools/mnemosyne.c -I../../tools

# The post-execution analyzer for mnemosyne (the Greek Goddess of memory)
mnemalyse: ../../tools/mnemalyse.c ../../tools/mnemosyne.h Makefile
	$(CC) $(OPTS) -o mnemalyse ../../tools/mnemalyse.c -I../../tools

web:
	make $(REMAKE) clean
	cc -o grammar2html ../../tools/grammar2html.c
	cc -o ctohtml ../../tools/ctohtml.c
	./grammar2html $(LANGUAGE:%=%.g) > $(LANGUAGE:%=%.g.html)
	./ctohtml ../../takeon.c > ../../takeon.c.html
	./ctohtml ../../uparse.c > ../../uparse.c.html
	./ctohtml $(LANGUAGE:%=%.h) > $(LANGUAGE:%=%.h.html)
	./ctohtml ../../regexp-lexer.c > ../../regexp-lexer.c.html
	./ctohtml ../../regexp-lexer.h > ../../regexp-lexer.h.html
	./ctohtml ../../flex.c > ../../flex.c.html
	./ctohtml ../../flex.h > ../../flex.h.html
	./ctohtml ../../parser.h > ../../parser.h.html
	./ctohtml ../../regen.c > ../../regen.c.html
	./ctohtml ../../gencomp.c > ../../gencomp.c.html
	./ctohtml $(LANGUAGE:%=%-ast.h) > $(LANGUAGE:%=%-ast.h.html)
	./ctohtml $(LANGUAGE:%=%-comp.h) > $(LANGUAGE:%=%-comp.h.html)
	# ./ctohtml $(LANGUAGE:%=%-indent.c) > $(LANGUAGE:%=%-indent.c.html)
	rm -f grammar2html ctohtml

# Only for the author. These won't work for anyone else.
upload:
	make web
	tar -cvf $(LANGUAGE:%=%.tar) *.[cgh] *.ng Makefile *.sh README.html ../../tools/mnem*.[ch] ../../tools/grammar2html.c ../../tools/ctohtml.c tests-$(LANGUAGE)/*.$(EXT) *.[chg].html
	make $(REMAKE) clean
	scp Makefile $(LANGUAGE:%=%.tar) gtoal@gtoal.com:gtoal.com/languages/$(LANGUAGE:%=%)/new-unicode-parser/
	ssh gtoal@gtoal.com "( cd gtoal.com/languages/$(LANGUAGE:%=%)/new-unicode-parser ; make $(REMAKE) clean )"
	ssh gtoal@gtoal.com "( cd gtoal.com/languages/$(LANGUAGE:%=%)/new-unicode-parser ; tar -xvf $(LANGUAGE:%=%.tar) )"

# Parse test files
regression-$(LANGUAGE):
	find tests-$(LANGUAGE) -name '*.$(EXT)' |sort > REGRESSION-TESTS-$(LANGUAGE).sh
	# Oops. Does require ecce. Need to avoid that. Use sed instead?
	ecce REGRESSION-TESTS-$(LANGUAGE).sh -command "(rli=./$(LANGUAGE:%=%) =r0i. 2>/dev/null | gtcpp -P | clang-format | ecce - - -command \"f/int _imp_mainep/(v-/ /e-)0m0r0i/-/79b;m-0((v/ /r)0v/;/(v-/ /e-)0m,m)0; m-0(v/\t;/em,m)0; (m-0 (v/;/j-m,m)0)2;%c\" 2> /dev/null.m)0m-0i.#!/bin/sh.b;%c"
	chmod +x REGRESSION-TESTS-$(LANGUAGE).sh
	./REGRESSION-TESTS-$(LANGUAGE).sh -x
#|ecce - - -command '(v/#define/ei/$$/m,m)0;%c' 2>/dev/null | gtcpp

# Mr Sheen.
clean:
	rm -f *~ *.o $(LANGUAGE:%=%) mnemalyse ../../takeon regen gencomp ctohtml grammar2html \#*\# [a-z]*.[chg].html $(LANGUAGE)-ast.h $(LANGUAGE)-comp.h

tidy:
	rm -f *~ *.o $(LANGUAGE:%=%) mnemalyse ../../takeon regen gencomp ctohtml grammar2html \#*\# 
