[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: fewer forks in AC_DEFINE [was: Use newer m4_map_args_{w,sep}]

From: Eric Blake
Subject: Re: fewer forks in AC_DEFINE [was: Use newer m4_map_args_{w,sep}]
Date: Thu, 20 Nov 2008 06:39:56 -0700
User-agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv: Gecko/20081105 Thunderbird/ Mnenhy/

Hash: SHA1

According to Ralf Wildenhues on 11/19/2008 11:01 PM:
> Please use appropriate language quoting.  Unlike your code, your readers
> cannot deal well with underquoted parentheses.  IOW, please make the
> above sentence either
>   * lib/m4sugar/m4sugar.m4 (_m4_expand): Tolerate unquoted
>   unbalanced `)'.

Yes, that looks nicer.  I'll rebase the patch accordingly before pushing.

>> +creative shell comments to supply the balance.  Note that you should use
>> +the quadrigraph @samp{@@%:@@} and not a literal @samp{#}, because the
>> +latter hides the @samp{(} inside an m4 comment, and you would still be
>> +presenting m4 with unbalanced parentheses.
> But not the human reader of the macro text!  IIUC then as the code
> is capable, we *can* use `in #(', which is much more readable than
> `in @:@('.  I've never knowingly added the extra opening parenthesis
> in order to help M4, only ever in order to help paren matching
> algorithms in $EDITORs.

Hmm.  Yet it was your message in
that caused Paul to have to do just that in commit e07dd (note that he had
to replace 'case "$ac_try" in #((' with 'case "(($ac_try" in').

Just because m4_expand can handle #( doesn't mean that other macros can;
you still have a bug if you do:

dnl plus: pasteable, balanced in editor, human-readable
dnl minus: broken as m4 argument
m4_define([do_case], [case bar in #(
 *) ;;

But not if you do:

dnl plus: expansion works as m4 argument, balanced in editor
dnl minus: not human-readable, not pasteable
m4_define([do_case], [case bar in @%:@(
 *) ;;

dnl plus: expansion works as m4 argument, human-readable
dnl minus: not balanced in editor, not pasteable
m4_define([do_case], [case bar in
 *[)] ;;

dnl plus: expansion works as m4 argument, human-readable, pasteable
dnl minus: not balanced in editor, no embedded macros allowed
m4_define([do_case], [[case bar in
 *) ;;

So, I will reword this paragraph to mention all of the possibilities, each
with their strengths and drawbacks.

>> In addition to the previously discussed idea of making m4_expand supply and 
>> chomp a trailing newline, in order to handle what would otherwise be an 
>> unterminated comment, I managed to figure out a way to handle underquoted 
>> shell 
>> case statements.  Kudos to you if you manage to figure out my trick on the 
>> first read of the new m4_expand implementation.
> Well yeah, with changequote you tread along the path to the dark side.
> And no, I don't really understand.

Here's a single-stepped example.  The first argument to _m4_expand is
always the original argument, the second is the number of open '(' to add
if an unbalance is detected, the third is supposed to be the expansion of
$1 surrounded in special delimiters, and the fourth is supposed to be a
marker (conveniently matching most of the end delimiter) to detect
problems with the third parameter.  On the first iteration:

'm4_expand([a)), b])' expands to:
  '_m4_expand([a)), b], [(], -=<{(a)), b)}>=-, [}>=-])'
Argument collection stops once the parens are balanced, so this calls
_m4_expand with three arguments:
  '_m4_expand([a)), b], [(], [-=<{(a)])'
and leaves some slop:
  ', b)}>=-, [}>=-])'

The first pass of _m4_expand notes that the marker in $4 is not present,
so it adds an open paren and recurses, by expanding $1 again (yes, this
means that side effects in $1 occur more than once, but only if $1 expands
to unbalanced unquoted `)').  On the second iteration, we have:
  '_m4_expand([a)), b], [((], -=<{((a)), b)}>=-, [}>=-])m4_ignore('

Argument collection again stops at balanced parens, where we call
_m4_expand with four arguments:
  '_m4_expand([a)), b], [((], [-=<{((a))], [b])'
and prepending to the slop:
  '}>=-, [}>=-])m4_ignore('

Oops, [b] is still not the marker, so we go to a third iteration:
  '_m4_expand([a)), b], [(((], -=<{(((a)), b)}>=-, [}>=-])m4_ignore(('
Parentheses are now balanced, so we invoke _m4_expand with the marker as
the fourth argument:
  '_m4_expand([a)), b], [(((], [-=<{(((a)), b)}>=-], [}>=-])'
while prepending to the slop:

Pre-patch, the changequote was always 5 and 5 characters.  But now that we
noted that we had to add extra '(' to get balance in the expansion of $1,
the changequote must consume those extra '('.  Hence, we change quotes to:
  '-=<{(((' and ')}>=-'
at which point $3 is a quoted string, whose contents are the expansion of
the $1 passed to m4_expand.  All that remains is to undo the changequote,
then take care of the slop, which is now:
  'm4_ignore((' '}>=-, [}>=-])m4_ignore(' ', b)}>=-, [}>=-])'

Oddly enough, that is just enough parens and ( to balance out the
leftovers in the failed expansions of $1 in the first and second
iteration.  It is parsed as an inner 'm4_ignore([], [b])' that ignores its
two arguments, then an outer:
  'm4_ignore([(}>=- [}>=-])}>=-], [}>=-])'
that also ignores its two arguments.

Slick, huh?

> I do wonder when quadrigraphs for `(' and `)' will finally be added,
> though.

Already done :(.  In 2.63.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             address@hidden
Version: GnuPG v1.4.9 (Cygwin)
Comment: Public key at
Comment: Using GnuPG with Mozilla -


reply via email to

[Prev in Thread] Current Thread [Next in Thread]