4

I have to show a lot of autogenerated code throughout my document.

The generated code represents loops with explicit block labels and gotos. The following code applies function f to each element of an array yielding a new array (i.e. ys = map f xs):

\documentclass{article}
\usepackage{listings}
\begin{document}
\begin{lstlisting}

init_2:
  i_1 = 0
  arr_2 = newArray (length arr_1)
  goto guard_2

guard_2:
  guard i_1 < length arr_1 | done_2
  goto body_2

body_2:
  elt_1 = readArray arr_1 i_1
  elt_2 = f_2 elt_1
  writeArray arr_2 i_1
  i_1 := i_1 + 1
  goto guard_2

done_2:
  return arr_2

\end{lstlisting}
\end{document}

Seeing underscores and integer suffixes everywhere is not very readable. I'd much prefer something like the following:

\documentclass{article}
\usepackage{listings}
\usepackage{xcolor}
\begin{document}
\begin{lstlisting}[mathescape=true, basicstyle=\ttfamily]

$\color{red}{init_{ys}}$:
  i$_{xs}$ = 0
  arr$_{ys}$ = newArray (length arr$_{xs}$)
  goto $\color{red}{guard_{ys}}$

\end{lstlisting}
\end{document}

Nicely formated code

However, this requires tediously formatting each listing individually. I was wondering if there is a more automated solution?


My question is whether it is possible to do one or more of the following in a listing:

  1. Automatically subscript part of the symbol after underscore (I have a partial solution below)

  2. Automatically replace _1 with _xs and _2 with _ys

  3. Automatically markup matching strings, e.g. make labels init_1, guard_2 bold

I don't mind using a different listings package if it lets me typeset code more easily.


I have managed to partially solve question 1 with the help of this answer but it only works for regular text, not listings code:

\documentclass{article}
\usepackage{listings}
\usepackage{fixltx2e}

%% Automatically make code after underscore subscripted
\def\SubscriptWord#1 {\check#1\relax\textsubscript{#1} }
% Check function parses world until space/newline
\def\check#1{%
\ifx\relax#1%
\else
\ifcat a#1%
\else
\typeout{illegal character #1}%
\fi
\expandafter\check
\fi}

\begin{document}

\catcode`\_=\active
\def_{\SubscriptWord}

normal_foo

\begin{lstlisting}
listing_bar
\end{lstlisting}

\end{document}
  • I think you are after \lstset{...}, setting all options to \begin{lstlisting} only once and they will apply as long you override them locally or use another \lstset – user31729 Sep 11 '14 at 6:46
  • 2
    Welcome to TeX.SX -- you have multiple questions in your posts. This makes it a little bit difficult the answer them all in a row – user31729 Sep 11 '14 at 6:47
  • The closest I got with \lstset was this: \lstset{moredelim=[is][\textsubscript]{\_}{\ }}. It doesn't always work and is (unsurprisingly) very picky about trailing spaces. – roldugin Sep 11 '14 at 7:18
  • While it might be a good training to implement this in TeX: With respect to time-to-results I would also consider a pearl/python/sed script that does the "tediously formatting each listing" for you. – Daniel Sep 11 '14 at 8:06
  • @Daniel If not for Jubobs answer I would've probably resorted to that. However, I really didn't want to modify the listings in tex sources, because it makes them so much harder to read and maintain. – roldugin Sep 17 '14 at 15:16
3
  1. Automatically subscript part of the symbol after underscore

That could lead to problems, though; in particular, what if an identifier contains an underscore?

  1. Automatically replace _1 with _xs and _2 with _ys

I think Horst is definitely on the right track. Even though I'm not a big fan of it, the literate key can be put to good use, here.

  1. Automatically markup matching strings, e.g. make labels init_1, guard_2 bold.

Do you mean "Goto labels"? Highlighting those automatically with listings is a tougher nut to crack. What follows is more of a glorified hack than a proper solution, but see if it works for you.

enter image description here


Breakdown of the solution

Package loading

Nothing very interesting here, aside from the fact that you need the fixltx2e package (because it defines the \textsubscript macro).

\usepackage{fixltx2e}
\usepackage{listings}
\usepackage{xcolor}

Style definitions

\colorlet{gotolabel}{red}
\newcommand\lstsubstyle{\itshape\rmfamily}
\newcommand\gotolabelstyle{\itshape\rmfamily\color{gotolabel}}

Listing settings

We use columns=flexible here instead of the default columns=fixed; otherwise, the output looks quite ugly. We define a one-line delimiter starting by goto␣. Finally, we define a number of literate replacements for subscripts, for two consecutive spaces, and for the colon character.

\lstset{
  basicstyle=\ttfamily\upshape\color{black},
  columns=fullflexible,
  moredelim=**[il][\processgoto]{goto\ },
  moredelim=**[il][\processpipe]{\ |\ },
  literate={_1}{{\lstsub{xs}}}1
           {_2}{{\lstsub{ys}}}1
           {\ \ }{\processtwospaces}2
           {:}{\processcolon}1,
}

Switch

The following switch will be used as state variable and will tell us when to activate/deactivate certain styles.

\newif\ifgotolabel

EveryPar hook

At the beginning of every "true" line, we apply the style of GoTo labels and we set the switch to true.

\makeatletter
\lst@AddToHook{EveryPar}{%
  \let\lst@thestyle\gotolabelstyle%
  \global\gotolabeltrue%
}

Helper macros

Here, we define the macros used in the values passed to the moredelim and literate keys.

Every time goto␣ is encountered, we print it normally, but we trigger the style associated to GoTo labels; no need to set the switch (it was already set at the beginning of the current line).

\newcommand\processgoto{%
  \lst@CalcLostSpaceAndOutput%
  {\lst@basicstyle goto\ }\gotolabelstyle%
}

Same idea for every occurence of ␣|␣:

\newcommand\processpipe{%
  \lst@CalcLostSpaceAndOutput%
  {\lst@basicstyle\ |\ }\gotolabelstyle%
}

The following macro typesets subscripts in the corresponding style and applies the color of GoTo labels only if the switch is set.

\newcommand\lstsub[1]{%
  \textsubscript{%
    \ifgotolabel%
      \color{gotolabel}%
    \fi
    \lstsubstyle #1%
  }%
}

The following macro leaves two consecutive spaces occuring in "processing mode" unchanged, but reactivates the basic style and unset the switch. In particular, it is invoked at the beginning of each line that is indented by two spaces.

\newcommand\processtwospaces{%
  \ifnum\lst@mode=\lst@Pmode%
    \lst@basicstyle%
    \global\gotolabelfalse%
  \fi
  \ \ %
}

Same idea here, but for the colon character.

\newcommand\processcolon{%
  \ifnum\lst@mode=\lst@Pmode%
    \lst@basicstyle%
    \global\gotolabelfalse%
  \fi
  :%
}

\makeatother

Complete code

\documentclass{article}

\usepackage{fixltx2e}
\usepackage{listings}
\usepackage{xcolor}

% Define styles for GoTo labels and subscripts
\colorlet{gotolabel}{red}
\newcommand\lstsubstyle{\itshape\rmfamily}
\newcommand\gotolabelstyle{\itshape\rmfamily\color{gotolabel}}


% 
\lstset{
  basicstyle=\ttfamily\upshape\color{black},
  columns=fullflexible,
  moredelim=**[il][\processgoto]{goto\ },
  moredelim=**[il][\processpipe]{\ |\ },
  literate={_1}{{\lstsub{xs}}}1
           {_2}{{\lstsub{ys}}}1
           {\ \ }{\processtwospaces}2
           {:}{\processcolon}1,
}

\newif\ifgotolabel

\makeatletter

\lst@AddToHook{EveryPar}{%
  \let\lst@thestyle\gotolabelstyle%
  \global\gotolabeltrue%
}

\newcommand\processgoto{%
  \lst@CalcLostSpaceAndOutput%
  {\lst@basicstyle goto\ }\gotolabelstyle%
}

\newcommand\processpipe{%
  \lst@CalcLostSpaceAndOutput%
  {\lst@basicstyle\ |\ }\gotolabelstyle%
}

\newcommand\lstsub[1]{%
  \textsubscript{%
    \ifgotolabel%
      \color{gotolabel}%
    \fi
    \lstsubstyle #1%
  }%
}

\newcommand\processtwospaces{%
  \ifnum\lst@mode=\lst@Pmode%
    \lst@basicstyle%
    \global\gotolabelfalse%
  \fi
  \ \ %
}

\newcommand\processcolon{%
  \ifnum\lst@mode=\lst@Pmode%
    \lst@basicstyle%
    \global\gotolabelfalse%
  \fi
  :%
}

\makeatother


\begin{document}
\begin{lstlisting}

init_2:
  i_1 = 0
  arr_2 = newArray (length arr_1)
  goto guard_2

guard_2:
  guard i_1 < length arr_1 | done_2
  goto body_2

body_2:
  elt_1 = readArray arr_1 i_1
  elt_2 = f_2 elt_1
  writeArray arr_2 i_1
  i_1 := i_1 + 1
  goto guard_2

done_2:
  return arr_2
\end{lstlisting}
\end{document}
|improve this answer|||||
  • This is an amazingly detailed answer, thank you so much for your efforts. The solution almost gets me there, I only needed to add extra code to match labels after | (see guard block). – roldugin Sep 17 '14 at 14:39
  • @roldugin Could you edit your question to better illustrate what's missing from my answer? – jub0bs Sep 17 '14 at 14:42
  • I just meant that done_2 of the line guard i_1 < length arr_1 | done_2 needs to be typeset as label as well. – roldugin Sep 17 '14 at 14:47
  • @roldugin Just to clarify, is the rest of the line after a | always a GoTo label? – jub0bs Sep 17 '14 at 14:48
  • 1
    Yes, time is of essence and I'm happy to go ahead with this result. Thank you for help and the prompt replies! – roldugin Sep 17 '14 at 15:11
2

If you use \lstset, there is the option literate to replace underscores with the latex-markup or _1 with _xs (should answer both Q1 and Q2). And use keywordstyle to bold keywords (if I got your point).You could try something like

\lstset{%
    keywordstyle=\bfseries
    literate=*{_}{\_}1
        {_1}{\_{xs}}2
        {_2}{\_{ys}}2    
}

Literate is very about correct brackets, so my example will not work, I suppose. Read the section 5.4 Literate programming in http://texdoc.net/texmf-dist/doc/latex/listings/listings.pdf and maybe try to find the right way. This forum has also a lot about it. (And it has a bug about brackets, see https://tex.stackexchange.com/a/149203)

|improve this answer|||||
  • Welcome to TeX.SX! – jub0bs Sep 12 '14 at 18:12
  • Thanks! I played around with it before studying Jubobs answer and after a lille fiddling it did indeed solve Q1 and Q2! literate={_1}{{\textsubscript{$xs$}}}2 – roldugin Sep 17 '14 at 14:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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