如何自动生成 PostScript 表达式的堆栈图?

如何自动生成 PostScript 表达式的堆栈图?

下图逐步显示了 PostScript 表达式及其堆栈图。是否有任何包可以开箱即用地生成它?如果没有这样的包,如何为任何 PostScript 表达式自动生成它?我肯定不想编写自己的解释器。

在此处输入图片描述

欢迎使用任何方法。

答案1

使用 TikZ 只是为了好玩(或者打字练习或者其他什么)。

它还不完整,但实现剩余的 postscript 堆栈命令应该很简单。

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}


\makeatletter
\newcount\stacktop
\def\stackclear{\global\stacktop=0\relax}

\def\stackpush#1{%
  \global\advance\stacktop by1\relax
  \expandafter\xdef\csname stack@item@\the\stacktop\endcsname{#1}%
}
\def\stackpeek#1#2{%
  \pgfmathparse{int(#1)}%
  \edef#2{\csname stack@item@\pgfmathresult\endcsname}%
}
\def\stackpop#1{%
  \ifnum\stacktop>0\relax
    \edef#1{\csname stack@item@\the\stacktop\endcsname}%
    \global\advance\stacktop by-1\relax
  \fi%
}

\def\stackswap#1#2{%
  \pgfmathparse{int(#1)}\let\a=\pgfmathresult
  \pgfmathparse{int(#2)}\let\b=\pgfmathresult
  \edef\tmp{\csname stack@item@\a\endcsname}%
  \expandafter\xdef\csname stack@item@\a\endcsname{\csname stack@item@\b\endcsname}%
  \expandafter\xdef\csname stack@item@\b\endcsname{\tmp}%
}

\def\stackroll{%
  \stackpop\R%
  \stackpop\r%
  \pgfmathparse{int(\R < 0 ? -\R : \R)}\let\RR=\pgfmathresult 
  \pgfmathloop%
  \ifnum\pgfmathcounter>\RR\relax
  \else%
    \ifnum\R<0\relax%
      \stackrollneg%
    \else%
      \stackrollpos%
    \fi%
  \repeatpgfmathloop%
}

\def\stackrollpos{%
  \begingroup%
    \pgfmathloop%
    \ifnum\pgfmathcounter=\r
    \else%
      \stackswap{\stacktop-\pgfmathcounter+1}{\stacktop-\pgfmathcounter}%
    \repeatpgfmathloop%
  \endgroup%
}

\def\stackrollneg{%
  \begingroup%
    \pgfmathloop%
    \ifnum\pgfmathcounter=\r
    \else%
      \stackswap{\stacktop-\r+\pgfmathcounter+1}{\stacktop-\r+\pgfmathcounter}%
    \repeatpgfmathloop%
  \endgroup%
}

\def\at{@}

\def\stackmathparse#1{%
  \pgfmathparse{(#1) == int(#1) ? int(#1) : (#1)}%
}
\tikzset{%
  postscript parse/.code={%
    \stackclear%
    \tikzset{ps/parse={#1 @}}%
  },
  ps/.cd,
  parse/.code args={#1 #2}{%
    \def\rest{#2}%
    \def\current{#1}%
    \tikzset{ps/commands/#1={#2}}%
    \tikzset{xshift=1cm}
    \node at (0,.75) {#1};
    \foreach \i [evaluate={\j=int(\stacktop-\i);}] in {0,...,5}
      \node [draw, minimum width=.75cm, minimum height=0.5cm] at (0,-\i/2) {\stackpeek{\j}{\x}\x};
    \ifx\rest\at%
    \else
     \tikzset{ps/parse={#2}}%
    \fi%
  },
  commands/.cd,
    .unknown/.code={\stackpush{\current}},
    exch/.code={\stackswap{\stacktop}{\stacktop-1}},
    roll/.code={\stackroll},
    dup/.code={\stackpeek{\stacktop}{\x}\stackpush{\x}},
    mul/.code={\stackpop{\x}\stackpop{\y}\stackmathparse{\y*\x}\stackpush{\pgfmathresult}},
    add/.code={\stackpop{\x}\stackpop{\y}\stackmathparse{\y+\x}\stackpush{\pgfmathresult}},
    sub/.code={\stackpop{\x}\stackpop{\y}\stackmathparse{\y-\x}\stackpush{\pgfmathresult}},
    div/.code={\stackpop{\x}\stackpop{\y}\stackmathparse{\y/\x}\stackpush{\pgfmathresult}}
}

\begin{document}
\begin{tabular}{l}
\begin{tikzpicture}
\tikzset{postscript parse={4 2 1 exch add 1 sub add}}
\end{tikzpicture}
\\[0.25in]
\begin{tikzpicture}
\tikzset{postscript parse={4 3 2 1 3 1 roll 3 -1 roll}}
\end{tikzpicture}
\\[0.25in]
\begin{tikzpicture}
\tikzset{postscript parse={3 2 dup mul 5 add exch div}}
\end{tikzpicture}
\end{tabular}
\end{document}

在此处输入图片描述

答案2

使用 bash 或类似的命令行,执行

s="";for i in 4  2  1 add 1 sub add ; do  s="$s $i"; echo " $s pstack" | gs -q -sDEVICE=pbm  | sed -e "s/GS>/\\\\foo{$i}{/" -e "s/GS<[0-9]*>/}/" ; done

生产

\foo{4}{4
}\foo{2}{2
4
}\foo{1}{1
2
4
}\foo{add}{3
4
}\foo{1}{1
3
4
}\foo{sub}{2
4
}\foo{add}{6
}

然后用乳胶包裹它:

\documentclass{article}

\def\foo#1#2{%
\parbox[t]{3em}{\centering
\textbf{#1}%
\xfoo#2\$ }}

\def\xfoo#1 {\ifx\$#1\else\\#1 \expandafter\xfoo\fi}

\begin{document}

% s="";for i in 4  2  1 add 1 sub add ; do  s="$s $i"; echo " $s pstack" | gs -q -sDEVICE=pbm  | sed -e "s/GS>/\\\\foo{$i}{/" -e "s/GS<[0-9]*>/}/" ; done


\foo{4}{4
}\foo{2}{2
4
}\foo{1}{1
2
4
}\foo{add}{3
4
}\foo{1}{1
3
4
}\foo{sub}{2
4
}\foo{add}{6
}

\end{document}

你得到

在此处输入图片描述

答案3

为了渲染这样的堆栈,我提供了下面的解决方案。但正如杰克指出的那样,它没有消化生的后记表达式。但是,请参阅本答案的结尾,了解我如何消化 David 的 bash 输出。

这里我使用了一堆嵌套堆栈。\psdepth(堆栈管深度)、\pswidth(堆栈管宽度)和\psrule(堆栈规则厚度)都可以调整。

重新编辑以使输入语法更简单。堆栈深度没有限制,就像之前的编辑一样。

\documentclass{article}
\usepackage[usestackEOL]{stackengine}
\usepackage{readarray}
\usepackage{ifthen}
\def\psdepth{2cm}
\def\pswidth{.5cm}
\def\psrule{.15ex}
\def\psbar{\rule[-\psdepth]{\psrule}{\psdepth}}
\def\pspipe{\psbar\kern\pswidth\psbar}
\def\pscell#1{\stackunder{\footnotesize#1}{\rule{\pswidth}{\psrule}}}
\newcounter{index}
\makeatletter
\newcommand\psstack[2]{%
  \getargsC{#2}%
  \setcounter{index}{0}%
  \def\psstackdata{}%
  \whiledo{\theindex<\narg}{%
    \stepcounter{index}%
    \protected@edef\thisarg{\csname arg\romannumeral\theindex\endcsname}%
    \protected@edef\psstackdata{%
      \psstackdata\protect\pscell{\thisarg}}%
    \ifthenelse{\theindex<\narg}{\protected@edef\psstackdata{%
      \psstackdata \\}}{}%
  }%
  \sffamily\def\stacktype{L}%
  \stackunder{%
    \def\stacktype{S}\stackunder{#1}{\pspipe}%
   }{%
    \def\stacktype{S}\setstackgap{S}{3pt}\expandafter%
      \Shortunderstack\expandafter{\psstackdata}%
   }%
 \hspace{1ex}%
}
\makeatother
\begin{document}
\psstack{4}{4}
\psstack{2}{2 4}
\psstack{1}{1 2 4}
\psstack{exch}{2 1 4}
\psstack{add}{3 4}
\psstack{1}{1 3 4}
\psstack{sub}{2 4}
\psstack{add}{6}
\end{document}

在此处输入图片描述


定义\foo

\newcommand\foo[2]{%
  \getargsC{#2}%
  \setcounter{index}{0}%
  \def\psstackdata{}%
  \whiledo{\theindex<\numexpr\narg-1}{%
    \stepcounter{index}%
    \protected@edef\thisarg{\csname arg\romannumeral\theindex\endcsname}%
    \protected@edef\psstackdata{%
      \psstackdata\protect\pscell{\thisarg}}%
    \ifthenelse{\theindex<\narg}{\protected@edef\psstackdata{%
      \psstackdata \\}}{}%
  }%
  \sffamily\def\stacktype{L}%
  \stackunder{%
    \def\stacktype{S}\stackunder{#1}{\pspipe}%
   }{%
    \def\stacktype{S}\setstackgap{S}{3pt}\expandafter%
      \Shortunderstack\expandafter{\psstackdata}%
   }%
 \hspace{1.85ex}%
}

在我的语法中,允许人们消化 David 的 bash 输出并将其与我的渲染一起呈现。

答案4

至于生成堆栈图片的内容,我受到这个问题的启发,清理了一些旧代码,现在我们可以为任意后记生成漂亮的痕迹。

该计划已发布至github(以及一些早期的草稿计算机语言后记),因为剪切粘贴有点长。它也是一个分步调试器,接受可执行文件名称、字符串、数组或文件。除和之外,代码大部分都是 1 级后记,<<可以>>向下移植以在 1 级解释器上运行,但它非常浪费内存,并且在没有垃圾收集器的内存受限环境中可能不实用。

对于这些代码片段:

1 2 3 add add 
6 eq { 8 9 add = } { 9 10 add = } ifelse

和:

 1 2 3 add add 
  6 eq { 7 } if

 9 { 
     5   
     count 4 gt {
         exit
     } if
 } repeat

  { 55 exit } loop

    (continuation) =

    0 1 10 {
        dup 5 eq {exit} if
    } for 

我得到以下堆栈跟踪输出:

GPL Ghostscript 9.06 (2012-08-08)
Copyright (C) 2012 Artifex Software, Inc.  All rights reserved.
This software comes with NO WARRANTY: see the file PUBLIC for details.
 %|- 
1  %|- 1 
2  %|- 1 2 
3  %|- 1 2 3 
add  %|- 1 5 
add  %|- 6 
6  %|- 6 6 
eq  %|- true 
{8 9 add =}  %|- true {8 9 add =} 
{9 10 add =}  %|- true {8 9 add =} {9 10 add =} 
ifelse  %|- 
8  %|- 8 
9  %|- 8 9 
add  %|- 17 
= 17

 %|- 
1  %|- 1 
2  %|- 1 2 
3  %|- 1 2 3 
add  %|- 1 5 
add  %|- 6 
6  %|- 6 6 
eq  %|- true 
{7}  %|- true {7} 
if  %|- 
7  %|- 7 
9  %|- 7 9 
{5 count 4 gt {exit} if}  %|- 7 9 {5 count 4 gt {exit} if} 
repeat  %|- 7 
5  %|- 7 5 
count  %|- 7 5 2 
4  %|- 7 5 2 4 
gt  %|- 7 5 false 
{exit}  %|- 7 5 false {exit} 
if  %|- 7 5 
8  %|- 7 5 8 
{5 count 4 gt {exit} if}  %|- 7 5 8 {5 count 4 gt {exit} if} 
repeat  %|- 7 5 
5  %|- 7 5 5 
count  %|- 7 5 5 3 
4  %|- 7 5 5 3 4 
gt  %|- 7 5 5 false 
{exit}  %|- 7 5 5 false {exit} 
if  %|- 7 5 5 
7  %|- 7 5 5 7 
{5 count 4 gt {exit} if}  %|- 7 5 5 7 {5 count 4 gt {exit} if} 
repeat  %|- 7 5 5 
5  %|- 7 5 5 5 
count  %|- 7 5 5 5 4 
4  %|- 7 5 5 5 4 4 
gt  %|- 7 5 5 5 false 
{exit}  %|- 7 5 5 5 false {exit} 
if  %|- 7 5 5 5 
6  %|- 7 5 5 5 6 
{5 count 4 gt {exit} if}  %|- 7 5 5 5 6 {5 count 4 gt {exit} if} 
repeat  %|- 7 5 5 5 
5  %|- 7 5 5 5 5 
count  %|- 7 5 5 5 5 5 
4  %|- 7 5 5 5 5 5 4 
gt  %|- 7 5 5 5 5 true 
{exit}  %|- 7 5 5 5 5 true {exit} 
if  %|- 7 5 5 5 5 
exit  %|- 7 5 5 5 5 
{55 exit}  %|- 7 5 5 5 5 {55 exit} 
loop  %|- 7 5 5 5 5 
55  %|- 7 5 5 5 5 55 
exit  %|- 7 5 5 5 5 55 
(continuation)  %|- 7 5 5 5 5 55 (continuation) 
= continuation
 %|- 7 5 5 5 5 55 
0  %|- 7 5 5 5 5 55 0 
1  %|- 7 5 5 5 5 55 0 1 
10  %|- 7 5 5 5 5 55 0 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 
dup  %|- 7 5 5 5 5 55 0 0 
5  %|- 7 5 5 5 5 55 0 0 5 
eq  %|- 7 5 5 5 5 55 0 false 
{exit}  %|- 7 5 5 5 5 55 0 false {exit} 
if  %|- 7 5 5 5 5 55 0 
1  %|- 7 5 5 5 5 55 0 1 
1  %|- 7 5 5 5 5 55 0 1 1 
10  %|- 7 5 5 5 5 55 0 1 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 1 
dup  %|- 7 5 5 5 5 55 0 1 1 
5  %|- 7 5 5 5 5 55 0 1 1 5 
eq  %|- 7 5 5 5 5 55 0 1 false 
{exit}  %|- 7 5 5 5 5 55 0 1 false {exit} 
if  %|- 7 5 5 5 5 55 0 1 
2  %|- 7 5 5 5 5 55 0 1 2 
1  %|- 7 5 5 5 5 55 0 1 2 1 
10  %|- 7 5 5 5 5 55 0 1 2 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 2 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 1 2 
dup  %|- 7 5 5 5 5 55 0 1 2 2 
5  %|- 7 5 5 5 5 55 0 1 2 2 5 
eq  %|- 7 5 5 5 5 55 0 1 2 false 
{exit}  %|- 7 5 5 5 5 55 0 1 2 false {exit} 
if  %|- 7 5 5 5 5 55 0 1 2 
3  %|- 7 5 5 5 5 55 0 1 2 3 
1  %|- 7 5 5 5 5 55 0 1 2 3 1 
10  %|- 7 5 5 5 5 55 0 1 2 3 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 2 3 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 1 2 3 
dup  %|- 7 5 5 5 5 55 0 1 2 3 3 
5  %|- 7 5 5 5 5 55 0 1 2 3 3 5 
eq  %|- 7 5 5 5 5 55 0 1 2 3 false 
{exit}  %|- 7 5 5 5 5 55 0 1 2 3 false {exit} 
if  %|- 7 5 5 5 5 55 0 1 2 3 
4  %|- 7 5 5 5 5 55 0 1 2 3 4 
1  %|- 7 5 5 5 5 55 0 1 2 3 4 1 
10  %|- 7 5 5 5 5 55 0 1 2 3 4 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 2 3 4 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 1 2 3 4 
dup  %|- 7 5 5 5 5 55 0 1 2 3 4 4 
5  %|- 7 5 5 5 5 55 0 1 2 3 4 4 5 
eq  %|- 7 5 5 5 5 55 0 1 2 3 4 false 
{exit}  %|- 7 5 5 5 5 55 0 1 2 3 4 false {exit} 
if  %|- 7 5 5 5 5 55 0 1 2 3 4 
5  %|- 7 5 5 5 5 55 0 1 2 3 4 5 
1  %|- 7 5 5 5 5 55 0 1 2 3 4 5 1 
10  %|- 7 5 5 5 5 55 0 1 2 3 4 5 1 10 
{dup 5 eq {exit} if}  %|- 7 5 5 5 5 55 0 1 2 3 4 5 1 10 {dup 5 eq {exit} if} 
for  %|- 7 5 5 5 5 55 0 1 2 3 4 5 
dup  %|- 7 5 5 5 5 55 0 1 2 3 4 5 5 
5  %|- 7 5 5 5 5 55 0 1 2 3 4 5 5 5 
eq  %|- 7 5 5 5 5 55 0 1 2 3 4 5 true 
{exit}  %|- 7 5 5 5 5 55 0 1 2 3 4 5 true {exit} 
if  %|- 7 5 5 5 5 55 0 1 2 3 4 5 
exit GS<12>

相关内容