Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

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.

share|improve this question

2 Answers 2

up vote 9 down vote accepted

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.

share|improve this answer
    
So the outer one is expanded before the inner one? That's... gross. –  morbusg Aug 9 at 11:27
    
Well how come it works with the \foo then? –  morbusg Aug 9 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 –  David Carlisle Aug 9 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" –  David Carlisle Aug 9 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 ) –  David Carlisle Aug 9 at 21:01

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
}
share|improve this answer
    
Nice, thank you! :-). I guess one needs a \newcount\tmpnum to go with it. –  morbusg Aug 13 at 8:45
    
@morbusg Thanks. I have \tmpnum declared by default. Thus I forgot it. I corrected the code. –  wipet Aug 14 at 11:44

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.