如何自动替换下标并突出显示 GoTo 标签?

如何自动替换下标并突出显示 GoTo 标签?

我必须在整个文档中显示大量自动生成的代码。

生成的代码表示具有显式块标签和gotos 的循环。以下代码将函数f应用于数组的每个元素,从而产生一个新数组(即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}

到处都看到下划线和整数后缀,可读性很差。我更喜欢下面这样:

\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}

格式良好的代码

但是,这需要对每个列表进行繁琐的格式化。我想知道是否有更自动化的解决方案?


我的问题是是否可以在列表中执行以下一项或多项操作:

  1. 自动为下划线后的符号部分添加下标(下面我有部分解决方案)

  2. 自动替换_1_xs_2_ys

  3. 自动标记匹配的字符串,例如制作标签init_1guard_2粗体

如果它能让我更轻松地排版代码,我不介意使用不同的列表包。


我已经在以下帮助下部分解决了问题 1答案但它只适用于常规文本,而不是列表代码:

\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}

答案1

  1. 自动为下划线后的符号部分添加下标

但这可能会导致问题;特别是如果标识符包含下划线怎么办?

  1. 自动替换_1_xs_2_ys

我认为霍斯特绝对是正确的。虽然我不是它的忠实粉丝,但literate在这里,这个关键点还是可以得到很好的利用的。

  1. 自动标记匹配的字符串,例如使标签 init_1、guard_2 变为粗体。

您的意思是“转到标签”?使用“转到标签”自动突出显示这些标签listings是一个更难解决的问题。接下来的内容更像是一种美化的黑客行为,而不是真正的解决方案,但看看它是否适合您。

在此处输入图片描述


解决方案细分

程序包加载

除了你需要这个fixltx2e包(因为它定义了\textsubscript宏)之外,这里没有什么有趣的东西。

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

样式定义

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

列表设置

我们columns=flexible在这里使用 而不是默认的columns=fixed;否则,输出看起来会很丑陋。我们定义一个以 开头的单行分隔符goto␣。最后,我们为下标、两个连续空格和冒号字符定义一些文字替换。

\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

EveryPar

在每个“true”行的开头,我们应用 GoTo 标签的样式并将开关设置为 true。

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

辅助宏

moredelim在这里,我们定义传递给和键的值所使用的宏literate

每次goto␣遇到时,我们都会正常打印它,但我们会触发与 GoTo 标签相关的样式;无需设置开关(它已经在当前行的开头设置了)。

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

每次出现的情况都是同样的想法␣|␣

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

以下宏以相应的样式排版下标,并且仅当设置了开关时才应用 GoTo 标签的颜色。

\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

完整代码

\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}

答案2

如果您使用\lstset,则可以选择用literatelatex 标记或替换下划线(应该回答问题 1 和问题 2)。并使用加粗关键字(如果我明白你的意思)。你可以尝试类似_1_xskeywordstyle

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

文学编程非常注重正确的括号,所以我的例子可能行不通。请参阅 5.4 文学编程http://texdoc.net/texmf-dist/doc/latex/listings/listings.pdf并尝试找到正确的方法。这个论坛也有很多关于它的内容。(它有一个关于括号的错误,请参阅https://tex.stackexchange.com/a/149203

相关内容