我的问题背景

我的问题背景

我的问题背景

我正在开发比斯蒙暂时的名称),某种用于静态源代码分析的持久领域特定语言,与 GCC 绑定(成为我已故的GCC 熔化)这里的细节并不重要,但好奇的人可能会看看它的自述文件.md在 github 上。

就这个问题而言,比斯蒙可以看作是某种动态类型的 Scheme 或 Lua 类语言(即使它实际上不是)。我完全控制它,我可以调整它,使它更像那样。所以对于这个问题,我们可以假装它bismon是一些类似 Scheme 的东西,比如诡计

我需要开始写一些关于它的文档(在 GCC MELT 中已经是这样了,我.texi为 texinfo 生成了文件),其中一些文档(希望越来越多)将由比斯蒙本身(即使显然不是)

我在 Linux/Debian 上运行所有这些,我不关心其他操作系统。我有 texlive,所以 lualatex(版本 1.07),还有橡胶树。我精通 Linux 和 Ocaml(以及某种程度上的 Lua),并且一点点黑客攻击对我来说不是什么问题(例如hevea在 Ocaml 中稍微修补,或编写简单的lua脚本)。

我需要生成一份 PDF 报告(其中包含一些超链接)和一些 HTML5 格式的报告(即一组 HTML5 和其他文件,可以通过最近的浏览器很好地查看)。当然,我正在考虑使用 lualatex 和 hevea(但我可以选择其他方法,只要它们基于免费软件,最好是在 Debian 上打包的)。

理想情况下,我希望有一些文档生成,因为显示实际的输出。其中一些可能发生在相同的在整个文档处理过程中运行的进程(例如 Guile 进程)。

对我来说很重要产生一些文档,包括示例“输入”和“输出”(这确保文档符合当前状态bismon)。

所以我梦想能够排版类似

Here is the factorial in Scheme:
\begin{myguilecode}
 (define (fact n) (if (< n 1) 1 (* n (fact (- n 1)))))
\end{myguilecode}

在同一文档的后面,我梦想着

When we ask about \texttt{fact}, our Scheme interpeter shows that 
it is some function:
\begin{runguilecode}
fact
\end{runguilecode}
Of course, we can compute the factorial of 5:
\begin{runguilecode}
(fact 5)
\end{runguilecode}

此时,我梦见代码和它的输出完美地出现了。请注意,我需要相同的 guile过程(概念上)与 LaTeX 过程共存。因此,也许效果类似于生成的LaTeX

When we ask about \texttt{fact}, our Scheme interpeter shows that 
it is some function:
\begin{alltt}
fact
\end{alltt}
$\Rightarrow$
\begin{alltt}
\$1 = #<procedure fact (n)>
\end{alltt}
Of course, we can compute the factorial of 5:
\begin{alltt}
(fact 5)
\end{alltt}
$\Rightarrow$
\begin{alltt}
\$2 = 120
\end{alltt}

例如Ocaml 手册有售HTMLPDF格式并生成其中的某些部分。

在两种(半)方法之间进行选择。

  • 我可以使用一些预处理,也许是“文学编程”之类的技术,即生成 LaTeX.tex文件。例如,我会编写(也许在 GPP 中)一些可预处理的内容,这些内容会扩展为 LaTeX 代码,例如生成一个包含以下内容的巨大 LaTeX 文件生成的LaTeX

  • 我可以使用一些解释技术,即为luaLuaLaTeX 编写一些脚本,运行 Guile(在某处)并读取其输出。基本上类似于一些 \input 执行的操作弹出(3)(或者甚至在 Lua 中计算一些),而不是打开(3). 对于 HeVeA 来说,这可能更棘手。

  • 我可能会考虑从内部生成所有的 LaTeX bismon,但我现在不太愿意接受这个想法。我觉得更合理的做法是让我在emacs

我目前倾向于第二种方法。

欢迎您的评论。

答案1

在 LuaTeX 中这不是问题。借助 FFI(需要 LuaJITTeX 或 LuaTeX ≥ 1.0.3),您可以调用任意 C 函数。由于 Guile 是一种嵌入式语言,因此它带有丰富的 C-API,可以在 LuaTeX 中轻松使用。我只是从 C 头文件中复制了函数声明并将其粘贴到ffi.cdef.

这是--shell-escape因为 FFI 被认为是不安全的,但实际上不会调用任何外部程序。

下面的代码示例当然是特定于 Guile 的,但既然您是 bismon 的开发人员,您可以提供这样的功能,将 bismon 编译为动态链接库并将其加载到 Lua 中以执行类似的任务。

\documentclass{article}
\usepackage{luacode}
\begin{luacode}
local ffi = assert(require("ffi"))

local SCM = assert(ffi.load("libguile-2.2.so"))

ffi.cdef[[
typedef struct scm_unused_struct *SCM;
void scm_init_guile (void);
SCM scm_c_eval_string (const char *expr);
SCM scm_c_lookup (const char *name);
SCM scm_variable_ref (SCM var);
SCM scm_object_to_string (SCM obj, SCM printer);
char *scm_to_locale_string (SCM str);
void scm_dynwind_free (void *mem);
]]

SCM.scm_init_guile()
function guile_eval_string(expr)
    local object = SCM.scm_c_eval_string(expr);
    local display = SCM.scm_variable_ref(SCM.scm_c_lookup("display"))
    local result = SCM.scm_object_to_string(object, display);
    local c_str = SCM.scm_to_locale_string(result)
    local str = ffi.string(c_str)
    SCM.scm_dynwind_free(c_str)
    return str
end
\end{luacode}

% Run guile code
\newcommand\guile[1]{\directlua{guile_eval_string("\luaescapestring{#1}")}}

% Run guile code and typeset its output using verbatim catcodes
\newcommand\guilerun[1]{\directlua{tex.sprint(-2,guile_eval_string("\luaescapestring{#1}"))}}

\usepackage{alltt}
\usepackage{environ}

\NewEnviron{myguilecode}{%
  % Typeset ...
  \begin{alltt}
    \BODY
  \end{alltt}
  % ... and run!
  \guile{\BODY}%
}

\NewEnviron{runguilecode}{%
  % Typeset ...
  \begin{alltt}
    \BODY
  \end{alltt}
  $\Rightarrow$
  % ... and run and typeset result
  \begin{alltt}
    \guilerun{\BODY}
  \end{alltt}
}

\begin{document}

Here is the factorial in Scheme:
\begin{myguilecode}
(define (fact n) (if (< n 1) 1 (* n (fact (- n 1)))))
\end{myguilecode}
When we ask about \texttt{fact}, our Scheme interpeter shows that 
it is some function:
\begin{runguilecode}
fact
\end{runguilecode}
Of course, we can compute the factorial of 5:
\begin{runguilecode}
(fact 5)
\end{runguilecode}

\end{document}

在此处输入图片描述

相关内容