## ---------------- ##
# m4_define_default([b4_lex_param], []) dnl breaks other skeletons
+m4_define_default([b4_pre_prologue], [])
+m4_define_default([b4_post_prologue], [])
m4_define_default([b4_epilogue], [])
m4_define_default([b4_parse_param], [])
b4_define_user_code([stype])
-# b4_check_for_unrecognized_names(WHAT, LIST, [VALID_NAME], [VALID_NAME])
-# -----------------------------------------------------------------------
-# Complain if any name of type WHAT is used in the grammar (as recorded in
-# LIST) but is not a VALID_NAME.
+# b4_check_user_names(WHAT, USER-LIST, SKELETON-NAMESPACE)
+# --------------------------------------------------------
+# Warn if any name of type WHAT is used by the user (as recorded in USER-LIST)
+# but is not used by the skeleton (as recorded by macros in the namespace
+# SKELETON-NAMESPACE).
#
-# LIST must expand to a list specifying all grammar occurrences of all names of
-# type WHAT. Each item in the list is a triplet specifying one occurrence:
-# name, start boundary, and end boundary. Empty string names are fine. An
-# empty list is fine.
+# USER-LIST must expand to a list specifying all grammar occurrences of all
+# names of type WHAT. Each item in the list must be a triplet specifying one
+# occurrence: name, start boundary, and end boundary. Empty string names are
+# fine. An empty list is fine.
#
-# For example, to define b4_foo_list to be used for LIST with three name
-# occurrences and with correct quoting:
+# For example, to define b4_foo_user_names to be used for USER-LIST with three
+# name occurrences and with correct quoting:
#
-# m4_define([b4_foo_list],
+# m4_define([b4_foo_user_names],
# [[[[[[bar]], [[parser.y:1.7]], [[parser.y:1.16]]]],
# [[[[bar]], [[parser.y:5.7]], [[parser.y:5.16]]]],
# [[[[baz]], [[parser.y:8.7]], [[parser.y:8.16]]]]]])
#
-# Each VALID_NAME must expand to a valid name of type WHAT. Multiple
-# occurrences of the same valid name are fine. A VALID_NAME that expands to
-# the empty string will correctly define the empty string as a valid name, but
-# it would be ugly for a Bison skeleton to actually use that.
+# The macro SKELETON-NAMESPACE(bar) must be defined iff the name bar of type
+# WHAT is used in the skeleton. Empty string names are fine, but it would be
+# ugly for a Bison skeleton to actually use one.
#
-# For example, to invoke b4_check_for_unrecognized_names with TYPE foo, with
-# LIST b4_foo_list, with two valid names, and with correct quoting:
+# For example, to use b4_foo_skeleton_names for SKELETON-NAMESPACE and define
+# that the names bar and baz are used in the skeleton:
#
-# b4_check_for_unrecognized_names([[foo]], [b4_foo_list],
-# [[bar]], [[baz]])
+# m4_define([b4_foo_skeleton_names(bar)])
+# m4_define([b4_foo_skeleton_names(baz)])
#
-# Names and valid names must not contain the character `,'.
-m4_define([b4_check_for_unrecognized_names],
-[m4_foreach([b4_occurrence],
- $2,
- [m4_pushdef([b4_occurrence], b4_occurrence)
- m4_pushdef([b4_name], m4_car(b4_occurrence))
- m4_pushdef([b4_start], m4_car(m4_shift(b4_occurrence)))
- m4_pushdef([b4_end], m4_shift(m4_shift(b4_occurrence)))
- m4_if(m4_index(m4_if($#, 2, [],
- [[,]m4_quote(m4_shift(m4_shift($*)))[,]]),
- [,]b4_name[,]),
- [-1],
- [b4_complain_at([b4_start], [b4_end],
- [[`%s' is not a recognized %s]],
- [b4_name], [$1])
- ])
- m4_popdef([b4_occurrence])
- m4_popdef([b4_name])
- m4_popdef([b4_start])
- m4_popdef([b4_end])
- ])
-])
+# To invoke b4_check_user_names with TYPE foo, with USER-LIST
+# b4_foo_user_names, with SKELETON-NAMESPACE b4_foo_skeleton_names, and with
+# correct quoting:
+#
+# b4_check_user_names([[foo]], [b4_foo_user_names],
+# [[b4_foo_skeleton_names]])
+m4_define([b4_check_user_names],
+[m4_foreach([b4_occurrence], $2,
+[m4_pushdef([b4_occurrence], b4_occurrence)dnl
+m4_pushdef([b4_user_name], m4_car(b4_occurrence))dnl
+m4_pushdef([b4_start], m4_car(m4_shift(b4_occurrence)))dnl
+m4_pushdef([b4_end], m4_shift(m4_shift(b4_occurrence)))dnl
+m4_ifndef($3[(]m4_quote(b4_user_name)[)],
+ [b4_warn_at([b4_start], [b4_end],
+ [[%s `%s' is not used]],
+ [$1], [b4_user_name])])[]dnl
+m4_popdef([b4_occurrence])dnl
+m4_popdef([b4_user_name])dnl
+m4_popdef([b4_start])dnl
+m4_popdef([b4_end])dnl
+])])
+
+# b4_percent_define_get(VARIABLE)
+# -------------------------------
+# If the %define variable VARIABLE is defined, emit its value. Also, record
+# the skeleton's usage of VARIABLE by defining
+# b4_percent_define_skeleton_variables(VARIABLE).
+#
+# For example:
+#
+# b4_percent_define_get([[foo]])
+m4_define([b4_percent_define_get],
+[m4_define([b4_percent_define_skeleton_variables(]$1[)])dnl
+m4_ifdef([b4_percent_define(]$1[)], [m4_indir([b4_percent_define(]$1[)])])])
+
+# b4_percent_define_ifdef(VARIABLE, IF-TRUE, [IF-FALSE])
+# ------------------------------------------------------
+# If the %define variable VARIABLE is defined, expand IF-TRUE, else expand
+# IF-FALSE. Also, record the skeleton's usage of VARIABLE by defining
+# b4_percent_define_skeleton_variables(VARIABLE).
+m4_define([b4_percent_define_ifdef],
+[m4_ifdef([b4_percent_define(]$1[)],
+ [m4_define([b4_percent_define_skeleton_variables(]$1[)])$2],
+ [$3])])
+
+# b4_percent_define_flag_if(VARIABLE, IF-TRUE, [IF-FALSE])
+# --------------------------------------------------------
+# If the %define variable VARIABLE is defined to anything but "0" or "false",
+# expand IF-TRUE. If it is defined to "0" or "false", expand IF-FALSE. If
+# it is undefined, raise an error (this macro should be preceded by
+# b4_percent_define_default). Also, record the skeleton's usage of VARIABLE by
+# defining b4_percent_define_skeleton_variables(VARIABLE).
+m4_define([b4_percent_define_flag_if],
+[b4_percent_define_ifdef([$1],
+ [m4_case(b4_percent_define_get([$1]),
+ [0], [$3], [false], [$3],
+ [$2])],
+ [m4_fatal([invalid %define variable passed to b4_percent_define_flag_if: ]$1)])])
+
+# b4_percent_define_default(VARIABLE, DEFAULT)
+# --------------------------------------------
+# If the %define variable VARIABLE is undefined, set its value to DEFAULT.
+#
+# For example:
+#
+# b4_percent_define_default([[foo]], [[default value]])
+m4_define([b4_percent_define_default],
+[m4_ifndef([b4_percent_define(]$1[)],
+ [m4_define([b4_percent_define(]$1[)], [$2])])])
-# b4_check_percent_define_variables([VAILD_VARIABLE], [VALID_VARIABLE], ...)
-# --------------------------------------------------------------------------
-# Wrapper around b4_check_for_unrecognized_names for %define variables.
+# b4_percent_code_get([QUALIFIER])
+# --------------------------------
+# If any %code blocks for QUALIFIER are defined, emit them beginning with a
+# comment and ending with synclines and a newline. If QUALIFIER is not
+# specified or empty, do this for the unqualified %code blocks. Also, record
+# the skeleton's usage of QUALIFIER (if specified) by defining
+# b4_percent_code_skeleton_qualifiers(QUALIFIER).
#
-# b4_used_percent_define_variables must contain a list of all %define variables
-# used in the grammar similar to b4_foo_list from the
-# b4_check_for_unrecognized_names documentation's example. If
-# b4_used_percent_define_variables is undefined, it's treated the same as an
-# empty list.
+# For example, to emit any unqualified %code blocks followed by any %code
+# blocks for the qualifier foo:
#
-# Invoking b4_check_percent_define_variables with empty parens specifies one
-# valid variable that is an empty string. Invoke it without parens to specify
-# that there are no valid variables.
-m4_define([b4_check_percent_define_variables],
-[m4_ifdef([b4_used_percent_define_variables],
-[b4_check_for_unrecognized_names([[%define variable]],
-[b4_used_percent_define_variables]m4_if([$#], [0], [], [, $@]))])])
-
-# b4_check_percent_code_qualifiers([VAILD_QUALIFIER], [VALID_QUALIFIER], ...)
-# ---------------------------------------------------------------------------
-# Same as b4_check_percent_define_variables but for %code qualifiers using
-# b4_used_percent_code_qualifiers.
-m4_define([b4_check_percent_code_qualifiers],
-[m4_ifdef([b4_used_percent_code_qualifiers],
-[b4_check_for_unrecognized_names([[%code qualifier]],
-[b4_used_percent_code_qualifiers]m4_if([$#], [0], [], [, $@]))])])
+# b4_percent_code_get
+# b4_percent_code_get([[foo]])
+m4_define([b4_percent_code_get],
+[m4_pushdef([b4_macro_name], [[b4_percent_code(]$1[)]])dnl
+m4_ifval([$1], [m4_define([b4_percent_code_skeleton_qualifiers(]$1[)])])dnl
+m4_ifdef(b4_macro_name,
+[b4_comment([m4_if([$#], [0], [[Unqualified %code]],
+ [[%code "]$1["]])[ blocks.]])
+b4_user_code([m4_indir(b4_macro_name)])
+])dnl
+m4_popdef([b4_macro_name])])
+
+# b4_percent_code_ifdef(QUALIFIER, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------
+# If any %code blocks for QUALIFIER (or unqualified %code blocks if
+# QUALIFIER is empty) are defined, expand IF-TRUE, else expand IF-FALSE.
+# Also, record the skeleton's usage of QUALIFIER (if specified) by defining
+# b4_percent_code_skeleton_qualifiers(QUALIFIER).
+m4_define([b4_percent_code_ifdef],
+[m4_ifdef([b4_percent_code(]$1[)],
+ [m4_ifval([$1], [m4_define([b4_percent_code_skeleton_qualifiers(]$1[)])])$2],
+ [$3])])
+
+
+## --------------------------------------------------------- ##
+## After processing the skeletons, check that all the user's ##
+## %define variables and %code qualifiers were used. ##
+## --------------------------------------------------------- ##
+
+m4_define([b4_check_user_names_wrap],
+[m4_ifdef([b4_percent_]$1[_user_]$2[s],
+ [b4_check_user_names([[%]$1 $2],
+ [b4_percent_]$1[_user_]$2[s],
+ [[b4_percent_]$1[_skeleton_]$2[s]])])])
+
+m4_wrap([
+b4_check_user_names_wrap([[define]], [[variable]])
+b4_check_user_names_wrap([[code]], [[qualifier]])
+])