我编写了一些命令,旨在简化从形式语法推导的排版。
\documentclass{article}
\usepackage{lmodern}
\usepackage{xparse}
\usepackage{amsmath}
\ExplSyntaxOn
\seq_new:N \l__inft_gr_vars_seq
\seq_new:N \l__inft_gr_alph_seq
\keys_define:nn { inft / gr }
{
variables .code:n = { \seq_set_from_clist:Nn \l__inft_gr_vars_seq { #1 } },
alphabet .code:n = { \seq_set_from_clist:Nn \l__inft_gr_alph_seq { #1 } }
}
\NewDocumentCommand \DefineGrammar { m }
{
\keys_set:nn { inft / gr } { #1 }
}
\NewDocumentCommand \GrammarDrv { m }
{
\inft_grammar_drv:n { #1 }
}
\cs_new:Nn \inft_grammar_drv:n
{
\seq_set_split:Nnn \l_tmpa_seq { => } { #1 }
\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
{ \exp_not:n { \inft_word:nn { \width} { ##1 } } }
\seq_use:Nn \l_tmpb_seq { \Rightarrow }
}
\cs_new:Nn \inft_char:nn
{
\makebox[#1]
{
\str_case_x:nnF { \tl_to_str:n {#2} }
{
{ ## } { \texttt{\#} }
{ \c_underscore_str } { \scalebox{.87}{$\Box$} }
{ \c_tilde_str } { $\varepsilon$ }
{ } { $\varepsilon$ }
}
{ \texttt{#2} }
}
}
\cs_new:Nn \inft_word:nn
{
\tl_if_blank:nTF {#2}
{
\inft_char:nn { #1 } { }
}
{
\tl_set:Nn \l_tempa {#2}
\tl_map_inline:Nn \l_tempa
{
\seq_if_in:NnTF \l__inft_gr_vars_seq ##1
{
\inft_gr_var:n { ##1 }
}
{
\seq_if_in:NnTF \l__inft_gr_alph_seq ##1
{
\inft_char:nn { #1 } { ##1 }
}
{
{ ##1 }
}
}
}
}
}
\cs_new:Nn \inft_gr_var:n
{
\tl_if_single:nTF { #1 }
{ #1 }
{ \mathit{#1} }
}
\ExplSyntaxOff
\begin{document}
\DefineGrammar{variables = {S, X, Y, Z}, alphabet = {a, b, c}}
\par (1) $\GrammarDrv{S => aXYZ}$
\par (2) $\GrammarDrv{S => aXY{{\kern-1.7pt}}Z}$
\par (3) $\GrammarDrv{S => aXY{\kern-1.7pt}Z}$
\end{document}
输出
表明:(1) 只要不实施特定规则,就需要手动调整字距;(2) 如果字距调整命令受到两对括号的“保护”,则该命令可以正常工作;(3) 如果字距调整命令仅被一对括号包围,则该命令会中断。
我该如何修改我的命令使得(3)能够按预期工作?
答案1
这个问题已由曼努埃尔在他上面的评论中。
在第 61 行和第 66 行中,第二个参数##1
必须\seq_if_in:NnTF
用括号括起来,因为它是 类型n
。更正后的版本是
\seq_if_in:NnTF \l__inft_gr_vars_seq { ##1 }
和
\seq_if_in:NnTF \l__inft_gr_alph_seq { ##1 }
分别。