7

I wanted to play with delimiter sizing without using the \delimiterfactor, -shortfall, etc. and made the following:

\newdimen\bigdim  \bigdim  = 1.9743ex
\newdimen\Bigdim  \Bigdim  = 2.671ex
\newdimen\biggdim \biggdim = 3.3678ex
\newdimen\Biggdim \Biggdim = 4.0646ex

\def\fence#1#2#3{
  \setbox0\hbox{$\displaystyle #3$}
  \ifdim\ht0 < .9\bigdim #1\box0 #2\else
  \ifdim\ht0 < .9\Bigdim \bigl#1\box0\bigr#2\else
  \ifdim\ht0 < .9\biggdim \Bigl#1\box0\Bigr#2\else
  \ifdim\ht0 < .9\Biggdim \biggl#1\box0\biggr#2\else
  \ifdim\ht0 < .9\Biggdim \Biggl#1\box0\Biggr#2\else
  \left#1\box0\right#2
  \fi\fi\fi\fi\fi}

\def\args(#1){\fence(){#1}}

$$
  \args(bar\args(baz))
$$

\bye

(before you push that comment-button, I know there should be \mathsurround=0pt and such in there, I just wanted to keep this simple) but this results in an error saying the argument of \args has an extra }.

I thought it would have something to do with macro argument delimiters, so made a quick test:

\def\foo(#1){(#1)}
\foo(bar\foo(baz))
\bye

but that seemed to work just fine. Now I don't know what else could be the issue. Note that if there isn't an \args inside of \args, it works.

2 Answers 2

8

You have

\args(bar\args(baz))

so the argument to the outer \args is

 bar\args(baz

as it stops at the first )

you want

 \args({bar\args(baz)})

in the \foo example, the arguments are interpreted the same way, but it accidentally works.

for the outer \foo '#1 is

bar\foo(baz

so that expands to

(bar\foo(baz)

then the inner \foo expands to

 (baz)

and finally the ) which was never used as a macro delimiter is typeset.

13
  • So the outer one is expanded before the inner one? That's... gross.
    – morbusg
    Commented Aug 9, 2014 at 11:27
  • Well how come it works with the \foo then?
    – morbusg
    Commented Aug 9, 2014 at 11:29
  • @morbusg not expanded, scanned, the arguments are scanned before the macro expands, I'll step through the foo example in a minute Commented Aug 9, 2014 at 11:32
  • 1
    @morbusg not really TeX only has one kind of matching (catcode 1 and 2 so normally { and }) if you delimit an argument as (#1) it will take everything up to the first ) as #1 without matching anything other than {}. You see same in latex's [] delimited optional arguments. as Joseph said xparse will match () if you want but it does it by reading token by token and matching braces "by hand" Commented Aug 9, 2014 at 11:45
  • 1
    @MickG no there is no height to satisfy any condition. The outer \args tries to set its argument in a box so it evaluates \hbox{$\displaystyle bar\args(baz$} and if that box was set its height would be measured but the inner \args fails with a runaway argument error as it has no ) Commented Aug 9, 2014 at 21:01
5

You can use \ensurebalanced macro for another types of parens by the following way:

\def\macro(#1){\ensurebalanced()\macroA{#1}}
\def\macroA#1{the "#1" is balanced here in () meaning}

\macro(abc(de(f))g(hi)) % prints: the "abc(de(f))g(hi)" is balanced here in () meaning.

Or your example:

\def\args(#1){\ensurebalanced(){\fence()}{#1}}

My macro \ensurebalanced looks like this:

\newcount\tmpnum
\def\ensurebalanced#1#2#3#4{%
   \isbalanced#1#2{#4}\iftrue #3{#4}%
   \else
      \def\ensurebalancedA##1##2#2{%
         \isbalanced#1#2{##1#2##2}\iftrue #3{##1#2##2}%
         \else \def\next{\ensurebalancedA{##1#2##2}}\expandafter\next\fi
      }%
      \def\next{\ensurebalancedA{#4}}\expandafter\next\fi
}
\def\isbalanced#1#2#3\iftrue{\tmpnum=0 \isbalancedA#1#2#3\isbalanced}
\def\isbalancedA#1#2#3{%
    \ifx\isbalanced#3\def\next{\csname ifnum\endcsname\tmpnum=0 }%
    \else \def\next{\isbalancedA#1#2}%
          \ifx#3#1\advance\tmpnum by1\fi
          \ifx#3#2\advance\tmpnum by-1\fi
    \fi \next
}
2
  • Nice, thank you! :-). I guess one needs a \newcount\tmpnum to go with it.
    – morbusg
    Commented Aug 13, 2014 at 8:45
  • @morbusg Thanks. I have \tmpnum declared by default. Thus I forgot it. I corrected the code.
    – wipet
    Commented Aug 14, 2014 at 11:44

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .