📄 autoupdate.in
字号:
## No big deal for the semantics (unless the macro depends upon $#, which# is bad), but the users would not be happy.## Additionally, we introduced quotes that we not there before, which is# OK in most cases, but could change the semantics of the file.## Cruel dilemma: we do want the auto-quoting definition of `NEW' when# evaluating `OLD', but we don't when we evaluate the second `NEW'.# Back to namespaces?## No.### # Second step: replacement# # ------------------------## No, as announced above, we will work in two steps: in a first step we# compute the updated values, and in a second step we replace them. Our# goal is something like this:## divert(-1)dnl# changequote([, ])# define([OLD], [NEW([1, 2], [3])changequote()])# undefine([dnl])# undefine([m4_eval])# # Some more undefines...# changequote()# divert(0)dnl# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# NEW([0, 0],# 0)## i.e., the new value of `OLD' is precomputed using the auto-quoting# definition of `NEW' and the m4 builtins. We'll see how afterwards,# let's finish with the replacement.## Of course the solution above is wrong: if there were other calls to# `OLD' with different values, we would smash them to the same value.# But it is quite easy to generalize the scheme above:## divert(-1)dnl# changequote([, ])# define([OLD([1],[2])], [NEW([1, 2], [3])])# define([OLD], [defn([OLD($@)])changequote()])# undefine([dnl])# undefine([m4_eval])# # Some more undefines...# changequote()# divert(0)dnl# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# NEW([0, 0],# 0)## i.e., for each call to obsolete macros, we build an array `call =># value', and use a macro to dispatch these values. This results in:## dnl The Unbelievable Truth# NEW([1, 2], [3])# NEW([0, 0],# 0)## In French, we say `Youpi !', which you might roughly translate as# `Yippee!'.### # First step: computation# # -----------------------## Let's study the anatomy of the file, and name its sections:## prologue# divert(-1)dnl# changequote([, ])# values# define([OLD([1],[2])], [NEW([1, 2], [3])])# dispatcher# define([OLD], [defn([OLD($@)])changequote()])# disabler# undefine([dnl])# undefine([m4_eval])# # Some more undefines...# changequote()# divert(0)dnl# input# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# NEW([0, 0],# 0)### # Computing the `values' section# # ..............................## First we need to get the list of all the AU macro uses. To this end,# first get the list of all the AU macros names by tracing `AU_DEFUN' in# the initialization of autoconf. This list is computed in the file# `au.txt' below.## Then use this list to trace all the AU macro uses in the input. The# goal is obtain in the case of our example:## [define([OLD([1],[2])],]@<<@OLD([1],[2])@>>@[)]## This is the file `values.in' below.## We want to evaluate this with only the builtins (in fact m4sugar), the# auto-quoting definitions of the new macros (`new.m4'), and the# definition of the old macros (`old.m4'). Computing these last two# files is easy: it's just a matter of using the right `--trace' option.## So the content of `values.in' is:## include($autoconf_dir/m4sugar.m4)# m4_include(new.m4)# m4_include(old.m4)# divert(0)dnl# [define([OLD([1],[2])],]@<<@OLD([1],[2])@>>@[)]## We run m4 on it, which yields:## define([OLD([1],[2])],@<<@NEW([1, 2], [3])@>>@)## Transform `@<<@' and `@>>@' into quotes and we get## define([OLD([1],[2])],[NEW([1, 2], [3])])## This is `values.m4'.### # Computing the `dispatcher' section# # ..................................## The `prologue', and the `disabler' are simple and need no commenting.## To compute the `dispatcher' (`dispatch.m4'), again, it is a simple# matter of using the right `--trace'.## Finally, the input is not exactly the input file, rather it is the# input file with the added `changequote'. To this end, we build# `quote.sed'.### # Putting it all together# # .......................## We build the file `input.m4' which contains:## divert(-1)dnl# changequote([, ])# include(values.m4)# include(dispatch.m4)# undefine([dnl])# undefine([eval])# # Some more undefines...# changequote()# divert(0)dnl# dnl The Unbelievable Truth# changequote([, ])OLD(1, 2)# NEW([0, 0],# 0)## And we just run m4 on it. Et voila`, Monsieur ! Mais oui, mais oui.## Well, there are a few additional technicalities. For instance, we# rely on `changequote', `ifelse' and `defn', but we don't want to# interpret the changequotes of the user, so we simply use another name:# `_au_changequote' etc.### # Failure of the fourth approach# # ------------------------------## This approach is heavily based on traces, but then there is an obvious# problem: non expanded code will never be seen/ In particular, the body# of a `define' definition is not seen, so on the input## define([idem], [OLD(0, [$1])])## autoupdate would never see the `OLD', and wouldn't have updated it.# Worse yet, if `idem(0)' was used later, then autoupdate sees that# `OLD' is used, computes the result for `OLD(0, 0)' and sets up a# dispatcher for `OLD'. Since there was no computed value for `OLD(0,# [$1])', the dispatcher would have replaced with... nothing, leading# to## define([idem], [])## With some more thinking, you see that the two step approach is wrong,# the namespace approach was much saner.## But you learned a lot, in particular you realized that using traces# can make it possible to simulate namespaces!#### # The fifth implementation: m4 namespaces by files# # ================================================## The fourth implementation demonstrated something unsurprising: you# cannot precompute, i.e., the namespace approach was the right one.# Still, we no longer want them, they're too expensive. Let's have a# look at the way it worked.## When updating## dnl The Unbelievable Truth# OLD(1, 2)# NEW([0, 0], [0])## you evaluate `input.m4':## divert(-1)# changequote([, ])# define([OLD],# [m4_enable()NEW([$1, $2], m4_eval([$1 + $2]))m4_disable()])# ...# m4_disable()# dnl The Unbelievable Truth# OLD(1, 2)# NEW([0, 0], [0])## where `m4_disable' undefines the m4 and m4sugar, and disables the quotes# and comments:## define([m4_disable],# [undefine([__file__])# ...# changecom(#)# changequote()])## `m4_enable' does the converse: reestablish quotes and comments# --easy--, reestablish m4sugar --easy: just load `m4sugar.m4' again-- and# reenable the builtins. This later task requires that you first save# the builtins. And BTW, the definition above of `m4_disable' cannot# work: you undefined `changequote' before using it! So you need to use# your privates copies of the builtins. Let's introduce three files for# this:## `m4save.m4'# moves the m4 builtins into the `_au_' pseudo namespace# `unm4.m4'# undefines the builtins# `m4.m4'# restores them## So `input.m4' is:## divert(-1)# changequote([, ])## include([m4save.m4])## # Import AU.# define([OLD],# [m4_enable()NEW([$1, $2], m4_eval([$1 + $2]))m4_disable()])## define([_au_enable],# [_au_changecom([#])# _au_include([m4.m4])# _au_include(m4sugar.m4)])## define([_au_disable],# [# Disable m4sugar.# # Disable the m4 builtins.# _au_include([unm4.m4])# # 1. Disable special characters.# _au_changequote()# _au_changecom()])## m4_disable()# dnl The Unbelievable Truth# OLD(1, 2)# NEW([0, 0], [0])## Based on what we learned in the fourth implementation we know that we# have to enable the quotes *before* any AU macro, and we know we need# to build autoquoting versions of the AC macros. But the autoquoting# AC definitions must be disabled in the rest of the file, and enabled# inside AU macros.## Using `autoconf --trace' it is easy to build the files## `ac.m4'# define the autoquoting AC fake macros# `disable.m4'# undefine the m4sugar and AC autoquoting macros.# `au.m4'# definitions of the AU macros (such as `OLD' above).## Now, `input.m4' is:## divert(-1)# changequote([, ])## include([m4save.m4])# # Import AU.# include([au.m4])## define([_au_enable],# [_au_changecom([#])# _au_include([m4.m4])# _au_include(m4sugar.m4)# _au_include(ac.m4)])## define([_au_disable],# [_au_include([disable.m4])# _au_include([unm4.m4])# # 1. Disable special characters.# _au_changequote()# _au_changecom()])## m4_disable()# dnl The Unbelievable Truth# _au_changequote([, ])OLD(1, 2)# NEW([0, 0], [0])## Finally, version V is ready.## Well... almost.## There is a slight problem that remains: if an AU macro OUTER includes# an AU macro INNER, then _au_enable will be run when entering OUTER# and when entering INNER (not good, but not too bad yet). But when# getting out of INNER, _au_disable will disable everything while we# were still in OUTER. Badaboom.## Therefore _au_enable and _au_disable have to be written to work by# pairs: each _au_enable pushdef's _au_enabled, and each _au_disable# popdef's _au_enabled. And of course _au_enable and _au_disable are# effective when _au_enabled is *not* defined.## Finally, version V' is ready. And there is much rejoicing. (And I# have free time again. I think. Yeah, right.)### Setup "GNU" style for perl-mode and cperl-mode.## Local Variables:## perl-indent-level: 2## perl-continued-statement-offset: 2## perl-continued-brace-offset: 0## perl-brace-offset: 0## perl-brace-imaginary-offset: 0## perl-label-offset: -2## cperl-indent-level: 2## cperl-brace-offset: 0## cperl-continued-brace-offset: 0## cperl-label-offset: -2## cperl-extra-newline-before-brace: t## cperl-merge-trailing-else: nil## cperl-continued-statement-offset: 2## End:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -