# Makefile.in for elkhound # see license.txt for copyright and terms of use # I uncomment this temporarily to just build certain modules #tmp: mlsstr # main targets: elkhound, and some examples all: elkhound libelkhound.a forbid.gr.gen.out arith c cc2/cc2.exe @echo BUILD FINISHED # directories of other software SMBASE := @SMBASE@ AST := @AST@ # stuff inside those other directories LIBSMBASE := $(SMBASE)/libsmbase.a LIBAST := $(AST)/libast.a ASTGEN := $(AST)/astgen # external tools PERL := @PERL@ MYFLEX := $(PERL) $(SMBASE)/run-flex.pl # remake the generated Makefile if its inputs have changed Makefile: Makefile.in config.status ./config.status # reconfigure if the configure script has changed config.status: configure.pl $(SMBASE)/sm_config.pm ./config.status -reconfigure # This variable is a parameter that can be passed on the 'make' command # line. It becomes part of the -tr argument to 'elkhound'. By default, # it's set to the flag to generate a debug dump of the LR parse tables. TRGRAMANL := ,lrtable # -------------------- compiler configuration ------------------- # C++ compiler, etc. CXX := @CXX@ # flags for the C and C++ compilers (and preprocessor) # "-Ic" is needed for binaries that use $(support-set) CCFLAGS := @CCFLAGS@ -I$(SMBASE) -I$(AST) -Ic # flags for the linker libraries := $(LIBAST) $(LIBSMBASE) LDFLAGS := -g -Wall $(libraries) # some other tools AR := ar RANLIB := ranlib # compile .cc to .o %.o: %.cc $(CXX) -c -o $@ $< $(CCFLAGS) @perl $(SMBASE)/depend.pl -o $@ $< $(CCFLAGS) >$*.d # ----------------- sets of related object files --------------------- # files needed to represent a grammar in memory grammar-set := \ asockind.o \ grammar.o -include $(grammar-set:.o=.d) # in addition to grammar-set, files needed to parse a grammar description # and emit action code grampar-set := \ emitcode.o \ mlsstr.o \ genml.o \ gramast.ast.gen.o \ gramlex.yy.o \ grampar.o \ grampar.tab.o -include $(grampar-set:.o=.d) # minimal runtime files needed to do GLR parsing; these get # combined to form libelkhound.a, the Elkhound runtime library glr-set := \ cyctimer.o \ glr.o \ parsetables.o \ useract.o -include $(glr-set:.o=.d) # utility modules useful with elkhound, though not necessary util-set := \ ptreenode.o \ ptreeact.o -include $(util-set:.o=.d) # additional modules borrowed from the C parser for the trivial grammars, # and the C++ parser based on the Standard grammar support-set := \ c/cc_lang.o \ c/parssppt.o \ c/lexer1.o \ c/lexer1yy.o \ c/lexer2.o #-include $(support-set:.o=.d) # # The above include is deliberately missing. There is a problem with # the generated .d files when the source lives in a directory other # than the current one, and I have not tracked down precisely when and # why this occurs. Unfortunately, it means that some changes # (especially in smbase) require a 'make clean'... # ---------------------- generic rules ---------------------- # intermediate files for an ast spec # (this have been commented-out and instantiated with the specific # rules for gramast.ast, because I only need once instance, and # because the cygwin version of make-3.80 fails to recognize the # applicability of this pattern for some reason) # .PRECIOUS: %.ast.gen.cc %.ast.gen.h # %.ast.gen.cc %.ast.gen.h: %.ast $(AST)/astgen # rm -f $*.ast.gen.* # $(AST)/astgen -o$*.ast.gen $*.ast # chmod a-w $*.ast.gen.h $*.ast.gen.cc # intermediate files for a grammar # TRGRAMANL: extra trace flags specified by user; starts with "," if defined # ('chmod a-w' is so I don't accidentally edit it) .PRECIOUS: %.gr.gen.cc %.gr.gen.h %.gr.gen.cc %.gr.gen.h %.gr.gen.y: %.gr elkhound rm -f $*.gr.gen.* ./elkhound -v -tr bison,NOconflict$(TRGRAMANL) -o $*.gr.gen $*.gr chmod a-w $*.gr.gen.h $*.gr.gen.cc # bison parser from the a given grammar; the 'sed' is because Bison # already interpretes 0 as EOF, and if my rule names it explicitly # then it gets mad %.y: %.gr.gen.y echo '%{' >$@ echo '#include "trivbison.h"' >>$@ echo '%}' >>$@ sed -e 's/"EOF" {/{/' <$*.gr.gen.y >>$@ # run Bison; the 'sed' command is to silence a spurious warning about # 'yyval' being used uninitialized; I also compile here (instead of # relying on another pattern rule) because I want to control exactly # how the compilation happens (to ensure the Bison-parser is compiled # with flags to make it a fair performance test with my own stuff) %.tab.c %.tab.o %.tab.h: %.y bison -d -v $*.y mv $*.tab.c $*.tab.c.orig sed -e 's/YYSTYPE yyval;/YYSTYPE yyval = 0;/' \ -e 's/__attribute__ ((__unused__))//' \ <$*.tab.c.orig >$*.tab.c rm $*.tab.c.orig g++ -c -g -o $*.tab.o -O2 -DNDEBUG -Wall $(YYDEBUG) $*.tab.c # run the trivial-grammar helper .PRECIOUS: %.gr %.tree.gr %.gr: %.gr.in make-trivparser.pl rm -f $@ perl ./make-trivparser.pl $(notdir $*) <$*.gr.in >$@ chmod a-w $@ %.tree.gr: %.gr.in make-trivparser.pl rm -f $@ perl ./make-trivparser.pl -ptree $(notdir $*) <$*.gr.in >$@ chmod a-w $@ # make a parser for testing some grammar, using trivial lexer trivparse-deps := trivmain.cc trivlex.o libelkhound.a %.gr.exe: %.gr.gen.o $(trivparse-deps) $(libraries) $(CXX) -o $@ -DGRAMMAR_NAME=\"$*.bin\" $(CCFLAGS) $*.gr.gen.o $(support-set) $(trivparse-deps) $(LDFLAGS) # similar, for Bison as the parser-generator trivbison-deps := trivbison.o trivlex.o lexer2.o libelkhound.a %.bison.exe: %.tab.o $(trivbison-deps) $(CXX) -o $@ $*.tab.o $(trivbison-deps) $(LDFLAGS) # ------------------- intermediate files -------------------- # grammar lexer # like in ast/, need to replace forward decl with proper #include gramlex.yy.cc: gramlex.lex $(MYFLEX) -o$@ gramlex.lex # grammar description AST (manual instantiation of above # commented-out pattern rule) .PRECIOUS: gramast.ast.gen.cc gramast.ast.gen.h gramast.ast.gen.cc gramast.ast.gen.h: gramast.ast $(AST)/astgen rm -f gramast.ast.gen.* $(AST)/astgen -ogramast.ast.gen gramast.ast chmod a-w gramast.ast.gen.h gramast.ast.gen.cc # bison implementation of grammar parser. # I have to make some changes to the generated output so it will compile # with a C++ compiler, and want to extract the codes so they're available # separately without having to know about all of the types in YYSTYPE. grampar.tab.cc grampar.tab.h grampar.codes.h: grampar.y bison -d -v grampar.y mv -f grampar.tab.c tmp sed -e 's/typedef union {/typedef union YYSTYPE {/' \ -e 's/__attribute__ ((__unused__))//' \ grampar.tab.cc mv -f grampar.tab.h tmp sed -e 's/typedef union {/typedef union YYSTYPE {/' grampar.tab.h rm tmp grep '# *define' grampar.tab.h >grampar.codes.h # new C++ grammar with treebuilding actions cc2/cc2t.gr.gen.cc cc2/cc2t.gr.gen.h cc2/cc2t.gr.gen.y: cc2/cc2.gr c/c.tok elkhound rm -f cc2/cc2t* sed -e 's/cc2\.gr\.gen\.h/cc2t.gr.gen.h/' cc2/cc2t.gr ./elkhound -v -tr treebuild$(TRGRAMANL) -o cc2/cc2t.gr.gen cc2/cc2t.gr chmod a-w cc2/cc2t.gr* # ----------------- extra dependencies ----------------- # These dependencies ensure that automatically-generated code is # created in time to be used by other build processes which need it. # I had been maintaining the list by hand, but now I've got a script # to build it. The list may need to be rebuilt from time to time; if # you get compile errors after 'make clean' because of missing files # that are automatically generated, rebuild extradep.mk after a full # compilation succeeds. extradep.mk: perl ./find-extra-deps *.d cc2/*.d >$@ -include extradep.mk # --------------------- test programs ---------------------- # grammar lexer test program gramlex-dep := gramlex.yy.cc $(AST)/gramlex.cc gramlex: ../ast/gramlex.h $(gramlex-dep) $(libraries) $(CXX) -o $@ -DTEST_GRAMLEX $(CCFLAGS) $(gramlex-dep) $(LDFLAGS) # cycle timer test cyctimer: cyctimer.cc cyctimer.h $(CXX) -o $@ -DTEST_CYCTIMER $(CCFLAGS) cyctimer.cc $(LDFLAGS) # ML lexical parser mlsstr: mlsstr.cc mlsstr.h $(CXX) -o $@ -DTEST_MLSSTR $(CCFLAGS) mlsstr.cc $(LDFLAGS) # test grammar for 'forbid' (there is no executable for this, I just look # at the Elkhound output) forbid.gr.gen.out: forbid.gr ./elkhound -tr requireExactStats -o forbid.gr.gen forbid.gr # -------------------- exported library ---------------- # glr parsing engine libelkhound.a: $(glr-set) $(util-set) rm -f $@ $(AR) -r $@ $(glr-set) $(util-set) -$(RANLIB) $@ # --------------------- executables --------------------- # reads the grammar and emits C++ code for semantic functions; # this is the main parser generator binary elkhound-dep := gramanl.cc gramexpl.o $(grammar-set) $(grampar-set) parsetables.o elkhound: $(elkhound-dep) grammar.h gramanl.h $(libraries) $(CXX) -o $@ -DGRAMANL_MAIN $(CCFLAGS) $(elkhound-dep) $(LDFLAGS) # C++ parser based on Standard grammar cc2-deps := cc2/cc2main.o cc2/cc2.gr.gen.o libelkhound.a cc2/cc2.exe: $(cc2-deps) $(libraries) $(CXX) -o $@ $(support-set) $(cc2-deps) $(LDFLAGS) # new C++ parser with treebuilding cc2t-deps := cc2/cc2main.o cc2/cc2t.gr.gen.o libelkhound.a cc2/cc2t.exe: $(cc2t-deps) $(libraries) $(CXX) -o $@ $(support-set) $(cc2t-deps) $(LDFLAGS) # ---------------------- Elkhound examples ------------------ .PHONY: c c: elkhound libelkhound.a $(MAKE) -C c c.in/c.in4c: c.in/c.in4b rm -f $@ for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18; do \ cat $< >>$@; \ done c.in/c.in4d: c.in/c.in4c rm -f $@ for n in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18; do \ cat $< >>$@; \ done # stuff in examples directory .PHONY: examples arith arith: elkhound libelkhound.a $(MAKE) -C examples/arith examples: all glrmain.o arith gcom $(MAKE) -C examples/cexp $(MAKE) -C examples/cdecl $(MAKE) -C examples/scannerless .PHONY: ocaml ocaml: $(MAKE) -C ocaml # ---------------------------- gcom ----------------------- # guarded command example from tutorial .PHONY: gcom gcom-clean gcom: $(MAKE) -C examples/gcom1 all check $(MAKE) -C examples/gcom4 all check $(MAKE) -C examples/gcom5 all check $(MAKE) -C examples/gcom all check $(MAKE) -C examples/gcom7 all check gcom-clean: $(MAKE) -C examples/gcom1 clean $(MAKE) -C examples/gcom4 clean $(MAKE) -C examples/gcom5 clean $(MAKE) -C examples/gcom clean $(MAKE) -C examples/gcom7 clean $(MAKE) -C examples/scannerless clean # ----------------------------- EFa ----------------------- # input for EFa triv/efa.in: mkdir $@ perl -e 'foreach $$n (500, 1000, 1500, 2000, 2500, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000) { \ $$name = sprintf("%07d", $$n); \ open(OUT, ">$@/$$name.in") or die $!; \ print OUT "A"; \ for($$i=0; $$i < $$n; $$i++) { \ print OUT ("PA"); \ } \ close(OUT); \ }' EFA_TESTS := triv/efa.perf.txt triv/efa.notree.perf.txt triv/efa.bison.tree.perf.txt triv/efa.bison.notree.perf.txt #.PHONY: $(EFA_TESTS) all-efa # run all the EFa tests; the whole batch runs in less than a minute # (well, they did before I put in the loop from 1 to 5 ...) all-efa: $(EFA_TESTS) # performance test for EFa triv/efa.perf.txt: rm -f $@ for fn in triv/efa.in/*; do \ for count in 1 2 3 4 5; do \ triv/EFa.tree.gr.exe -tr progress -count $$fn 2>&1 | \ sed "s,^,$$fn: ," >> $@ ; \ done; \ done triv/efa.notree.perf.txt: rm -f $@ for fn in triv/efa.in/*; do \ for count in 1 2 3 4 5; do \ triv/EFa.tree.gr.exe -tr progress,trivialActions $$fn 2>&1 | \ sed "s,^,$$fn: ," >> $@ ; \ done; \ done triv/efa.bison.tree.perf.txt: rm -f $@ for fn in triv/efa.in/*; do \ for count in 1 2 3 4 5; do \ triv/EFa.tree.bison.exe $$fn 2>&1 | \ sed "s,^,$$fn: ," >> $@ ; \ done; \ done triv/efa.bison.notree.perf.txt: rm -f $@ for fn in triv/efa.in/*; do \ for count in 1 2 3 4 5; do \ triv/EFa.bison.exe $$fn 2>&1 | \ sed "s,^,$$fn: ," >> $@ ; \ done; \ done %.csv: %.txt cat $^ | grep cycles | \ perl -p -e 's/^[^:]*\D(\d+)\D.*:.*\D(\d+)_(\d+) cycles.*$$/$$1, $$2$$3/' >$@ all-efa-csv: $(EFA_TESTS:.txt=.csv) # --------------------------- EEb ----------------------- # input for EEb triv/eeb.in: mkdir $@ perl -e 'foreach $$n (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 20, 50, 100, 200, 300, 400, 500) { \ open(OUT, ">$@/$$n.in") or die $!; \ print OUT "B"; \ for($$i=0; $$i < $$n; $$i++) { \ print OUT ("PB"); \ } \ close(OUT); \ }' # performance test for EEb triv/eeb.perf.txt: rm -f $@ for n in 10 20 50 100 200 300 400 500; do \ triv/EEb.tree.gr.exe -tr progress -count triv/eeb.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done triv/eeb.notree.perf.txt: rm -f $@ for n in 10 20 50 100 200 300 400 500; do \ triv/EEb.tree.gr.exe -tr progress,trivialActions triv/eeb.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done # --------------------------- SSx ---------------------- # input for SSx triv/ssx.in: mkdir $@ perl -e 'for($$n=1; $$n <= 99; $$n += 2) { \ open(OUT, ">$@/$$n.in") or die $!; \ for($$i=0; $$i < $$n; $$i++) { \ print OUT ("X"); \ } \ close(OUT); \ }' # performance test for SSx triv/ssx.perf.txt: rm -f $@ for n in 15 25 35 45 55 65 75 85 99; do \ triv/SSx.tree.gr.exe -tr progress -count triv/ssx.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done triv/ssx.notree.perf.txt: rm -f $@ for n in 15 25 35 45 55 65 75 85 99; do \ triv/SSx.tree.gr.exe -tr progress,trivialActions triv/ssx.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done # --------------------------- SSSx ---------------------- # input for SSSx triv/sssx.in: mkdir $@ perl -e 'for($$n=1; $$n <= 99; $$n += 1) { \ open(OUT, ">$@/$$n.in") or die $!; \ for($$i=0; $$i < $$n; $$i++) { \ print OUT ("X"); \ } \ close(OUT); \ }' triv/sssx.perf.txt: rm -f $@ for n in 5 10 15 20 25 30 35 40 45 50; do \ triv/SSSx.tree.gr.exe -tr progress -count triv/sssx.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done triv/sssx.notree.perf.txt: rm -f $@ for n in 5 10 15 20 25 30 35 40 45 50; do \ triv/SSSx.tree.gr.exe -tr progress,trivialActions triv/sssx.in/$$n.in 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done # ------------------------ DeclExpr ---------------------- triv/DeclExpr.perf.txt: rm -f $@ for n in 1 10 100 1000 10000; do \ triv/DeclExpr.gr.exe -tr progress,trivialActions triv/DeclExpr.in$$n 2>&1 | \ sed "s/^/$$n: /" >> $@ ; \ done # ------------------------ documentation ----------------------- # directory of generated documentation gendoc: mkdir gendoc # dependencies for 'elkhound', the parser generator executable gendoc/elkhound_dep.dot: perl $(SMBASE)/scan-depends.pl -r -I$(AST) gramanl.cc >$@ # dependencies for 'glr.h', the entry point to the runtime library gendoc/glr.dot: perl $(SMBASE)/scan-depends.pl -r -I$(AST) glr.h >$@ # check to see if they have dot .PHONY: dot dot: @if ! which dot >/dev/null; then \ echo "You don't have the 'dot' tool. You can get it at:"; \ echo "http://www.research.att.com/sw/tools/graphviz/"; \ exit 2; \ fi # use 'dot' to lay out the graph %.ps: %.dot dot dot -Tps <$*.dot >$@ # use 'convert' to make a PNG image with resolution not to exceed # 1000 in X or 700 in Y ('convert' will preserve aspect ratio); this # also antialiases, so it looks very nice (it's hard to reproduce # this using 'gs' alone) %.png: %.ps convert -geometry 1000x700 $^ $@ # glr is much smaller gendoc/glr.png: gendoc/glr.ps convert -geometry 500x400 $^ $@ gendoc/configure.txt: configure ./configure --help >$@ # "make doc" should build whatever we have that needs building .PHONY: doc doc: gendoc gendoc/elkhound_dep.png gendoc/glr.png gendoc/configure.txt @echo "built documentation" # some other random phony targets (I hate this clutter..) .PHONY: clean distclean check # -------------------- clean, check, etc. ------------------ # things to remove from all directories CLEAN_PATTERNS := \ *.o \ *~ \ *.d \ *.exe \ *.gen.* \ *.bin \ *.output \ a.out \ core clean: gcom-clean rm -f $(CLEAN_PATTERNS) rm -f elkhound glr gramlex cyctimer rm -f grampar.output grampar tlexer rm -f gramlex.yy.cc rm -f libelkhound.a rm -f gdb.log gprof.out gmon.out test-bad-tmp.c rm -f examples/crash1.{cc,h} cd cc2; rm -f $(CLEAN_PATTERNS) cd triv; rm -f $(CLEAN_PATTERNS) *.y *.gr for dir in arith cdecl cexp; do \ (cd examples/$$dir; $(MAKE) clean); \ done $(MAKE) -C c clean distclean: clean rm -f Makefile config.status config.summary glrconfig.h *.tmp cd triv; rm -rf sssx.in ssx.in eeb.in $(MAKE) -C c distclean rm -rf gendoc rm -f c.in/c.in4{c,d} # 'clean', plus remove distributed output files from bison toolclean: clean rm -f grampar.tab.cc grampar.tab.h grampar.codes.h $(MAKE) -C examples/arith toolclean $(MAKE) -C c toolclean check: all mlsstr ./mlsstr MAKE=$(MAKE) ./regrtest @echo "" @echo "Regression tests passed." # --------------- random other stuff -------------------- # test for rcptr trcptr: rcptr.h trcptr.cc $(CXX) -o $@ trcptr.cc