12

Is it possible to do some TeX magic to get a command \mycmd which takes one argument before the command and one afterwards. So something like <arg1>\mycmd<arg2>. I tried

\documentclass{memoir}
\def#1\mycmd#2{Hello World of #1 and #2}
\begon{document}

{foo}\mycmd{bar}

\end{document}

but obviously failed. Can't say I expected that it would work, anyway.

Gaussler
  • 12,801
  • Why would you want to do that? I guess just for fun :) – Ruben Dec 20 '14 at 17:13
  • 2
    Btw: I'd say it is impossible because TeX by definition isn't capable of reading backwards. – Ruben Dec 20 '14 at 17:14
  • 1
    @ruben Not only for fun, actually. I'm converting an XML document into LaTeX. It uses calligraphic letters, which I'd like to do LaTeX-style with lettrine. Only problem: Sometimes there are quotation marks before the calligraphic letters. lettrine can handle this, provided that I can tell it to. But that requires such a command. – Gaussler Dec 20 '14 at 17:15
  • xml -- and unicode too (the combining diacritics) -- can make life difficult if the order is by definition backwards from what tex expects. since tex existed before either xml or unicode, and before that, typewriters had accents on "dead keys", so the accent came first, my inclination is that tex got it right, but i'm not in charge here. i hope there's some other "trigger" that you can identify to allow you to save the quotes to check when it's time to apply the lettrine. – barbara beeton Dec 20 '14 at 17:55
  • 1
    Something like this should be possible. After all, $a \over b$ and $a \choose b$ are examples of (something pretty close to) what you want. However, I don't know how those are defined. (Yes, I really need to read the TeX-book, but I still haven't had the time for it.) – jmc Dec 20 '14 at 18:02
  • 1
    The situation with \over is very different: first of all it's not a macro, but a primitive. When TeX finds it, it stores whatever is in the current math list, determines the denominator and then builds the Frac atom. With macros it's not possible: TeX strictly expands in the order tokens are created and after expansion or execution it discards the items. – egreg Dec 20 '14 at 18:17
  • 1
    @Gaussler No, it's not possible. TeX is only capable of using the last object from a constructed list, provided it's a skip, a penalty, a kern or a box. – egreg Dec 20 '14 at 18:19
  • egreg's answer is definitive, but perhaps there is some hope if the problem can be more constrained. For example, if <arg1> is always (and only) a quotation mark, for example, then perhaps you could achieve your desired result by making the quotation mark active, and make it look ahead to see if \mycmd follows it or not. – Steven B. Segletes Dec 20 '14 at 19:42
  • @StevenB.Segletes egreg's answer isn't definitive. Compare my answer. But I would do the concrete application (with quotation marks) differently. These marks can be active and they can look to the following token by \futurelet. – wipet Dec 21 '14 at 06:43

3 Answers3

17

The problem has been examined under a different point of view in Is a command with an argument before and after the command possible? but the situation is different: the object that was to be placed before or after the main command is itself a macro.

It's not possible to have a macro that “looks backwards”. TeX is strictly “first in, first out”, after macro expansion. Moreover it tokenizes the input only when needed for supplying arguments to macros or primitives.

After macro expansion, only unexpandable tokens remain and they are executed in the order they are found and removes them. So in a situation such as

{abc}\macro{def}

the {abc} part is already gone when \macro is examined. Trace of it can remain in some of the internal lists, so, for example, TeX is able to execute \unskip which really is a command that, upon execution, removes the last node from the current list, provided it is glue (there are hairy details, but this is basically the truth).

A command that seems to do what you want is \over. However, this is not a macro, but a primitive.

Its work is performed at the level of the internal lists: when TeX finds \over, it executes it, because it's unexpandable. The execution consists in storing whatever is in the current math list in a special place and go on. When the end of the current math list is found, TeX uses it and the stored part to build a Frac atom with the head sublist as numerator and the tail sublist as denominator. But nothing of this happens at the macro expansion level.

You can have a macro \first that looks ahead after its argument to see if a macro \second comes along and then take appropriate decisions about what to do.

Even LuaTeX can't do it, unless you modify the macro processor, because it can examine and manage all types of nodes in the current list, while TeX abilities are more limited (only penalties, glues, kerns and boxes and not in every situation).

egreg
  • 1,121,712
14

Your requirement is possible for example with encTeX. Try the following code compiled by csplain format:

\mubyte \phantomcmd #1 {\endmubyte

\mubytein=0
\def\phantomcmd#1\mycmd#2{1=#1, 2=#2}
\def\mycmd{my}
\def\normalcmd#1{normal=#1}

\mubytein=1

\normalcmd{hello}    % gives: normal=hello 
...{foo}\mycmd{bar}  % gives: ...1=foo, 2=bar

\bye

When \mubytein=1 then special input is activated: The \phantomcmd is inserted before each occurrence of the { character. This is done before token and expand processor. But there is an exception: if the { immediately follows after control sequence tokenized by token procesor then the \phantomcmd isn't inserted. So both examples work: \normalcmd{hello} and {foo}\cmd{bar}. The second one internally works as:

\phantomcmd{foo}\mycmd{bar}

and this is expanded as desired. But this technique is very fragile, because each occurrence of { which is not immediately after control sequence, is automaticaly preceded by \phantomcmd (when \mybytein=1). For example this crashes:

\normalcmd {hello}   % this is transformed to \normalcmd\phantomcmd{hello}
bb {foo}\mycmd{bar}  % 

Note the difference between this and previous example: the space immediately after \normalcmd.

If you don't be afraid from this fragility, you can define \pfantomcmd which processes the various \mycmds:

\mubyte \phantomcmd #1 {\endmubyte
\mubytein=0
\def\phantomcmd#1{\def\tmp{#1}}
\def\mycmdA#1{I am A. before: \tmp, after: #1}
\def\mycmdB#1{I am B. before: \tmp, after: #1}
\mubytein=1
... {a}\mycmdA{b} ... {x}\mycmdB{y}
\bye
wipet
  • 74,238
  • Interesting. Maybe you should change “is immediately followed“ by “immediately follows”, as this seems to reflect the described behavior. – egreg Dec 21 '14 at 11:16
  • Do I get it right that this only allows you to define one command with an argument before it? – Hendrik Vogt Dec 22 '14 at 07:57
6

In a comment made by the OP, mention was made that the application was one of predetermining quotes prior to a calligraphic letter. As I said in my comment reply, perhaps there is some hope if the problem can be more constrained. For example, if <arg1> is always (and only) a single glyph from a limited set of catcode 12 possibilities, then you could achieve your desired result by making those glyphs \active, and make it look ahead to see if \mycmd follows them or not.

This approach could be used unless the <arg1> possibilities were needed inside other macros, like the period . for example, would not work well for <arg1>, since it is frequently used to specify dimensions via a decimal point.

In the MWE, <arg1>\mycmd<arg2> will print out a Huge \fbox{<arg1><arg2>}. I have it only set up to intercept a double quote or a question mark for <arg1>, though other catcode 12 <arg1> glyphs could be added.

EDITED to ignore calls with "illegal" values of <arg1>.

\documentclass{article}
\let\precommand\relax
\let\mycmd\relax
\def\testnext#1#2{\ifx#1\mycmd\myactualcmd\precommand{#2}\else\precommand#1#2\fi}
\def\myactualcmd#1#2{\if#1\precommand\fbox{\Huge#1#2}\else#1#2\fi}
\let\svquote"
\catcode`"=\active
\def"{\let\precommand\svquote\testnext}
\let\svqmark?
\catcode`?=\active
\def?{\let\precommand\svqmark\testnext}

\begin{document}
Is this is a "test"\textbf{?}  This is a "\mycmd{BIG} test?\mycmd{!}

Here mycmd is used with illegal precommand =\mycmd{which} is ignored.
\end{document}

enter image description here