diff --git a/contrib/cube/Makefile b/contrib/cube/Makefile
index 19fd7dc658f7daa561653d97ffb77ce123341fa7..b5cd5d0f33f69578d0aa6eadf4dfa32561f9f1ce 100644
--- a/contrib/cube/Makefile
+++ b/contrib/cube/Makefile
@@ -27,20 +27,6 @@ endif
 # cubescan is compiled as part of cubeparse
 cubeparse.o: cubescan.c
 
-cubeparse.c: cubeparse.y
-ifdef BISON
-	$(BISON) $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-cubescan.c: cubescan.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
 distprep: cubeparse.c cubescan.c
 
 maintainer-clean:
diff --git a/contrib/seg/Makefile b/contrib/seg/Makefile
index d84934c67fb7dbfc7bbb467b24976b9f1d59b7c0..fb9c5765c34e4ceda4af0ea2194262ac680595fb 100644
--- a/contrib/seg/Makefile
+++ b/contrib/seg/Makefile
@@ -25,20 +25,6 @@ endif
 # segscan is compiled as part of segparse
 segparse.o: segscan.c
 
-segparse.c: segparse.y
-ifdef BISON
-	$(BISON) $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-segscan.c: segscan.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
 distprep: segparse.c segscan.c
 
 maintainer-clean:
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 000bfd772abdb31202809a2e52dcfaa6d33946e1..fbaaaf995bf781841d6300ddedcdac255df12985 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -500,6 +500,22 @@ TAS         = @TAS@
 #
 # Global targets and rules
 
+%.c: %.l
+ifdef FLEX
+	$(FLEX) $(if $(FLEX_NO_BACKUP),-b) $(FLEXFLAGS) -o'$@' $<
+	@$(if $(FLEX_NO_BACKUP),if [ `wc -l <lex.backup` -eq 1 ]; then rm lex.backup; else echo "Scanner requires backup; see lex.backup." 1>&2; exit 1; fi)
+else
+	@$(missing) flex $< '$@'
+endif
+
+%.c: %.y
+	$(if $(BISON_CHECK_CMD),$(BISON_CHECK_CMD))
+ifdef BISON
+	$(BISON) $(BISONFLAGS) -o $@ $<
+else
+	@$(missing) bison $< $@
+endif
+
 %.i: %.c
 	$(CPP) $(CPPFLAGS) -o $@ $<
 
diff --git a/src/backend/bootstrap/Makefile b/src/backend/bootstrap/Makefile
index a77d8648008b52054859454712d69c80341544df..672bc8b6d7b16a3f2362aa6fbf592e90842588e0 100644
--- a/src/backend/bootstrap/Makefile
+++ b/src/backend/bootstrap/Makefile
@@ -16,24 +16,8 @@ OBJS= bootparse.o bootstrap.o
 
 include $(top_srcdir)/src/backend/common.mk
 
-
 # bootscanner is compiled as part of bootparse
 bootparse.o: bootscanner.c
 
-bootparse.c: bootparse.y
-ifdef BISON
-	$(BISON) $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-bootscanner.c: bootscanner.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
-
 # bootparse.c and bootscanner.c are in the distribution tarball, so
 # they are not cleaned here.
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index 1f48e16a76a0f05094d4a690506c2452cc9970f2..0395bd5934afc480a2fa93dd5172cb206ece0197 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -17,8 +17,6 @@ OBJS= analyze.o gram.o keywords.o kwlookup.o parser.o \
       parse_expr.o parse_func.o parse_node.o parse_oper.o parse_param.o \
       parse_relation.o parse_target.o parse_type.o parse_utilcmd.o scansup.o
 
-FLEXFLAGS = -CF -b -p -p
-
 include $(top_srcdir)/src/backend/common.mk
 
 
@@ -40,22 +38,12 @@ endif
 
 gram.h: gram.c ;
 
-gram.c: gram.y
-	$(PERL) $(srcdir)/check_keywords.pl $< $(top_srcdir)/src/include/parser/kwlist.h
-ifdef BISON
-	$(BISON) -d $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
+gram.c: BISONFLAGS += -d
+gram.c: BISON_CHECK_CMD = $(PERL) $(srcdir)/check_keywords.pl $< $(top_srcdir)/src/include/parser/kwlist.h
 
 
-scan.c: scan.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-	@if [ `wc -l <lex.backup` -eq 1 ]; then rm lex.backup; else echo "Scanner requires backup, see lex.backup."; exit 1; fi
-else
-	@$(missing) flex $< $@
-endif
+scan.c: FLEXFLAGS = -CF -p -p
+scan.c: FLEX_NO_BACKUP=yes
 
 
 # Force these dependencies to be known even without dependency info built:
diff --git a/src/backend/replication/Makefile b/src/backend/replication/Makefile
index 1f93ac1e5d1594c89349c35a30f763f03ca7c6a8..2dde0118a47185d6de954725c55abc7007afd20d 100644
--- a/src/backend/replication/Makefile
+++ b/src/backend/replication/Makefile
@@ -22,19 +22,5 @@ include $(top_srcdir)/src/backend/common.mk
 # repl_scanner is compiled as part of repl_gram
 repl_gram.o: repl_scanner.c
 
-repl_gram.c: repl_gram.y
-ifdef BISON
-	$(BISON) $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-repl_scanner.c: repl_scanner.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
 # repl_gram.c and repl_scanner.c are in the distribution tarball, so
 # they are not cleaned here.
diff --git a/src/backend/utils/misc/Makefile b/src/backend/utils/misc/Makefile
index 08be3bd699d9aa450b08e2eacff2ac084178ba0b..c7b745e51319468954749dd317622561e1c07a4e 100644
--- a/src/backend/utils/misc/Makefile
+++ b/src/backend/utils/misc/Makefile
@@ -28,13 +28,6 @@ include $(top_srcdir)/src/backend/common.mk
 # guc-file is compiled as part of guc
 guc.o: guc-file.c
 
-guc-file.c: guc-file.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
 # Note: guc-file.c is not deleted by 'make clean',
 # since we want to ship it in distribution tarballs.
 clean:
diff --git a/src/bin/psql/Makefile b/src/bin/psql/Makefile
index 771fd712e468eb91fecd7f7b905195d760f4a510..9a6776ae83a1d53b8e7d82958285cd285ebf8e09 100644
--- a/src/bin/psql/Makefile
+++ b/src/bin/psql/Makefile
@@ -26,8 +26,6 @@ OBJS=	command.o common.o help.o input.o stringutils.o mainloop.o copy.o \
 	sql_help.o \
 	$(WIN32RES)
 
-FLEXFLAGS = -Cfe -b -p -p
-
 
 all: psql
 
@@ -49,13 +47,8 @@ sql_help.h: create_help.pl $(wildcard $(REFDOCDIR)/*.sgml)
 # psqlscan is compiled as part of mainloop
 mainloop.o: psqlscan.c
 
-psqlscan.c: psqlscan.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-	@if [ `wc -l <lex.backup` -eq 1 ]; then rm lex.backup; else echo "Scanner requires backup, see lex.backup."; exit 1; fi
-else
-	@$(missing) flex $< $@
-endif
+psqlscan.c: FLEXFLAGS = -Cfe -p -p
+psqlscan.c: FLEX_NO_BACKUP=yes
 
 distprep: sql_help.h psqlscan.c
 
diff --git a/src/interfaces/ecpg/preproc/Makefile b/src/interfaces/ecpg/preproc/Makefile
index dec425e553d46faff9075eb68ca0a081b39fe1f0..6e117d49c76b2541c1938b9d864d808e77b2d659 100644
--- a/src/interfaces/ecpg/preproc/Makefile
+++ b/src/interfaces/ecpg/preproc/Makefile
@@ -42,20 +42,7 @@ ecpg: $(OBJS) | submake-libpgport
 preproc.o: pgc.c
 
 preproc.h: preproc.c ;
-
-preproc.c: preproc.y
-ifdef BISON
-	$(BISON) -d $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-pgc.c: pgc.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
+preproc.c: BISONFLAGS += -d
 
 preproc.y: ../../../backend/parser/gram.y parse.pl ecpg.addons ecpg.header ecpg.tokens ecpg.trailer ecpg.type
 	$(PERL) $(srcdir)/parse.pl $(srcdir) < $< > $@
diff --git a/src/pl/plpgsql/src/Makefile b/src/pl/plpgsql/src/Makefile
index 0db0dc56929f6ccc8bf3612fe7a3123ee7300541..852b0c7ae4928d1e12e85d5b43cd228839014af8 100644
--- a/src/pl/plpgsql/src/Makefile
+++ b/src/pl/plpgsql/src/Makefile
@@ -55,15 +55,8 @@ uninstall-headers:
 pl_gram.o pl_handler.o pl_comp.o pl_exec.o pl_funcs.o pl_scanner.o: plpgsql.h pl_gram.h plerrcodes.h
 
 # See notes in src/backend/parser/Makefile about the following two rules
-
 pl_gram.h: pl_gram.c ;
-
-pl_gram.c: pl_gram.y
-ifdef BISON
-	$(BISON) -d $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
+pl_gram.c: BISONFLAGS += -d
 
 # generate plerrcodes.h from src/backend/utils/errcodes.txt
 plerrcodes.h: $(top_srcdir)/src/backend/utils/errcodes.txt generate-plerrcodes.pl
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index 482ac3ecb944258880bdba0b85e31d5e0d516d66..6579be148c1b6d16fcd0c894c904007a85afbac7 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -43,20 +43,6 @@ specparse.h: specparse.c ;
 # specscanner is compiled as part of specparse
 specparse.o: specscanner.c
 
-specparse.c: specparse.y
-ifdef BISON
-	$(BISON) $(BISONFLAGS) -o $@ $<
-else
-	@$(missing) bison $< $@
-endif
-
-specscanner.c: specscanner.l
-ifdef FLEX
-	$(FLEX) $(FLEXFLAGS) -o'$@' $<
-else
-	@$(missing) flex $< $@
-endif
-
 # specparse.c and specscanner.c are in the distribution tarball,
 # so do not clean them here
 clean distclean: