1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
|
% Copyright 2019 by Till Tantau
% Copyright 2019 by Jonathan P. Spratte
%
% This file may be distributed and/or modified
%
% 1. under the LaTeX Project Public License and/or
% 2. under the GNU Free Documentation License.
%
% See the file doc/generic/pgf/licenses/LICENSE for more details.
\section{Parser Module}%
\label{section-module-parser}%
\begin{pgfmodule}{parser}%
This module defines some commands for creating a simple letter-by-letter
parser.
\end{pgfmodule}
\begin{package}{pgfparser}
Because the parser module is almost independent of the rest of \pgfname, it
can also be used as a standalone package with minimal dependencies.
\end{package}
This module provides commands for defining a parser that scans some given text
letter-by-letter. For each letter, some code is executed and, possibly a
state-switch occurs. The code for each letter might take mandatory or optional
arguments. The parsing process ends when a final state has been reached, and
optionally some code is executed afterwards.
\begin{command}{\pgfparserparse\marg{parser name}\meta{text}}%
This command is used to parse the \meta{text} using the (previously defined)
parser named \meta{parser name}.
The \meta{text} is not contained in curly braces, rather it is all the text
that follows. The end of the text is determined implicitly, namely when the
final state of the parser has been reached. If you defined a final action for
the parser using |\pgfparserdeffinal| it is executed now.
The parser works as follows: At any moment, it is in a certain
\emph{state}, initially this state is called |initial|. Then, the first
letter of the \meta{text} is examined (using the |\futurlet| command). For
each possible state and each possible letter, some action code is stored in
the parser in a table. This code is then executed. This code may, but need
not, trigger a \emph{state switch}, causing a new state to be set. The
parser then moves on to the next character of the text and repeats the
whole procedure, unless it is in the state |final|, which causes the
parsing process to stop immediately.
In the following example, the parser counts the number of |a|'s in the
\text{text}, ignoring any |b|'s. The \meta{text} ends with the first~|c|.
%
\begin{codeexample}[preamble={\usepgfmodule{parser}}]
\newcount\mycount
\pgfparserdef{myparser}{initial}{the letter a}%
{\advance\mycount by 1\relax}%
\pgfparserdef{myparser}{initial}{the letter b}%
{} % do nothing
\pgfparserdef{myparser}{initial}{the letter c}%
{\pgfparserswitch{final}}% done!
\pgfparserparse{myparser}aabaabababbbbbabaabcccc
There are \the\mycount\ a's.
\end{codeexample}%
%
\end{command}%
\begin{command}%
{%
\pgfparserdef\marg{parser name}\marg{state}\meta{symbol meaning}%
\oarg{arguments}\marg{action}%
}%
This command should be used repeatedly to define a parser named
\meta{parser name}. With a call to this command you specify that the
\meta{parser name} should do the following: When it is in state \meta{state}%
and reads the letter \meta{symbol meaning}, perform the code stored in
\meta{action}.
The \meta{symbol meaning} must be the text that results from applying the
\TeX\ command |\meaning| to the given character. For instance, |\meaning a|
yields |the letter a|, while |\meaning 1| yields |the character 1|. A space
yields |blank space|. Alternatively you can give the symbol you want without
surrounding it in braces. So both
|\pgfparserdef{myparser}{initial}{the letter a}{foo}|
and
|\pgfparserdef{myparser}{initial}a{foo}|
define an \meta{action} for |the letter a|.
The \meta{action} might require arguments which you can specify in the
optional \meta{arguments} string. The argument string can contain up to nine
argument specifications of the following types:
\begingroup
\def\argdesc#1#2%
{%
\par
\begingroup
\setbox0\hbox{\texttt #1}\makebox[1.5em][l]{\usebox0}%
\ifdim\wd0>1.5em\\\null\hspace{1.5em}\fi
\parbox[t]{\dimexpr\linewidth-1.5em\relax}{#2}%
\endgroup
}%
\argdesc{m}%
{a normal mandatory argument}%
\argdesc{r\meta{delim}}%
{a mandatory argument which is read up to the \meta{delim}}%
\argdesc{o}%
{an optional argument in |[]| defaulting to a special mark}%
\argdesc{O\marg{default}}%
{like |o| but defaulting to \meta{default}}%
\argdesc{d\meta{delim1}\meta{delim2}}%
{%
an optional argument in \meta{delim1} and \meta{delim2} defaulting to a
special mark%
}%
\argdesc{D\meta{delim1}\meta{delim2}\marg{default}}%
{like |d| but defaulting to \meta{default}}%
\argdesc{t\meta{token}}%
{%
tests whether the next letter is \meta{token}, if so gobbles it and
the argument is set to a special mark.%
}%
\endgroup
So if you want to define an \meta{action} that takes two mandatory arguments
you use |[mm]|, if it should take an optional star, one optional argument in
brackets that returns a marker if it's not used, one mandatory and finally an
optional argument in parentheses that defaults to |something| you use
|[t*omD(){something}]| as the argument string. If the argument should be
anything up to a semicolon, you use |[r;]|. Spaces before argument
specifications in the string are ignored. So |[r m]| will be one argument and
read anything up to an |m|. Also spaces before any argument in the parsed
letters are ignored, so if |a| was setup to take an optional argument the
argument would be detected in |a []|. Like with normal \LaTeXe\ optional
arguments you have to protect nested brackets: |[a[bc]d]| would be read as
|a[bc| with a trailing |d]|, \emph{not} as |a[bc]d|. You'd have to use
|[{a[bc]d}]| to get it correct.
Inside the \meta{action} you can perform almost any kind of code. This code
will not be surrounded by a scope, so its effect persists after the parsing
is done. However, each time after the \meta{action} is executed, control
goes back to the parser. You should not launch a parser inside the
\meta{action} code, unless you put it in a scope.
When you set the \meta{state} to |all|, the state \meta{action} is performed
in all states as a fallback, whenever \meta{symbol meaning} is encountered.
This means that when you do not specify anything explicitly for a state and a
letter, but you do specify something for |all| and this letter, then the
specified \meta{action} will be used.
When the parser encounters a letter for which nothing is specified in the
current state (neither directly nor indirectly via |all|), an error occurs.
Additionally you can specify an action that is executed after the error is
thrown using |\pgfparserdefunknown|.
\end{command}%
\begin{command}%
{%
\pgfparserlet
\marg{parser name 1}\marg{state 1}\meta{symbol meaning 1}%
\oarg{opt 1}\oarg{opt 2}\meta{symbol meaning 2}%
}%
If none of the optional arguments are given in the following \meta{parser
name 2} and \meta{state 2} are the same as \meta{parser name 1} and
\meta{state 1}. If only the first is given \meta{state 2} equals
\meta{opt 1}. If both are given \meta{parser name 2} equals \meta{opt 1} and
\meta{state 2} equals \meta{opt 2}.
Defines an action for \meta{parser name 1} in \meta{state 1} for the
\meta{symbol meaning 1} to do the same as the action of \meta{parser name 2}
in \meta{state 2} for the \meta{symbol meaning 2}. For \meta{symbol meaning 1}
and \meta{symbol meaning 2} the same parsing rules apply as for \meta{symbol
meaning} in |\pgfparserdef| so you either give the meaning in braces or just
the symbol.
\end{command}%
\begin{command}{\pgfparserdefunknown\marg{parser name}\marg{state}\marg{action}}%
With this macro you can define an \meta{action} for the \meta{parser name}
parser in \meta{state} if the letter which was encountered was undefined.
\end{command}%
\begin{command}{\pgfparserdeffinal\marg{parser name}\marg{action}}%
Every parser can call a final \meta{action} after the state was switched to
|final|. This \meta{action} is executed after everything else, so you can use
something that grabs more arguments if you want to.
\end{command}%
\begin{command}{\pgfparserswitch\marg{state}}%
This command can be called inside the action code of a parser to cause a
state switch to \meta{state}.
\end{command}%
\begin{command}{\pgfparserifmark\marg{arg}\marg{true}\marg{false}}%
Remember that some of the optional argument types set special marks? With
|\pgfparserifmark| you can test whether \meta{arg} is such a mark. So if
there was no optional argument for the argument types |o| and |d| the
\meta{true} branch will be executed, else the \meta{false} branch. For the |t|
type argument the \meta{true} branch is executed if the token was encountered.
\end{command}%
\begin{command}{\pgfparserreinsert}%
You can use this as the final macro in an action of |\pgfparserdef| or
|\pgfparserdefunknown|. This has the effect that the letter which was parsed
in this action will be parsed again after this action (and after any arguments
were read).
\end{command}%
\begin{command}{\pgfparserstate}%
Expands to the current state of the parser.
\end{command}%
\begin{command}{\pgfparsertoken}%
This is the macro which is let to the following token with |\futurelet|. You
can use it inside an action code.
\end{command}%
\begin{command}{\pgfparserletter}%
This macro stores the letter to which |\pgfparsertoken| was let. So if
you'd use |\pgfparserparse{foo}a| this macro would be defined with
|\def\pgfparserletter{a}|. This definition is done before any action code is
executed. There are four special cases: If the next token is of category code
1, 2, 6, or 10, so with standard category codes the tokens |{|, |}|, |#|, and
\textvisiblespace\ (a space) would be treated differently. In those cases this
macro expands to |\bgroup|, |\egroup|, |##|, and \textvisiblespace\ for the
categories 1, 2, 6, and 10, respectively.
\end{command}%
\begin{command}{\pgfparserset\marg{key list}}%
The |pgfparser| module has a few keys you can access through this macro. It
is just a shortcut for |\pgfset{/pgfparser/.cd,#1}|. The available keys are
listed in subsection~\ref{sec:parser:keys}.
\end{command}%
\subsection{Keys of the Parser Module}
\label{sec:parser:keys}
\begin{key}{/pgfparser/silent=\meta{boolean} (initially false)}%
If |true| then no error will be thrown when a letter is parsed for which no
action is specified, silently ignoring it. This holds true for every parser.
\end{key}%
\begin{key}{/pgfparser/status=\meta{boolean} (initially false)}%
If |true| every parser prints a status message for every action executed. This
might help in debugging and understanding what the parser does.
\end{key}%
Additionally to those keys for every \meta{parser name} for which
|\pgfparserdef|, |\pgfparserdefunknown| or |\pgfparserlet| was run at least once
the following will be defined:
\begin{key}{/pgfparser/\meta{parser name}/silent=\meta{boolean} (initially false)}%
If |true| the parser \meta{parser name} will silently ignore undefined
letters. This is an individual equivalent of |/pgfparser/silent| for each
defined parser.
\end{key}%
\subsection{Examples}
The following example counts the different letters appearing in a more or less
random string of letters. Every letter is counted only once, this is achieved
by defining a new action for every encountered unknown letter that does
nothing. We can define such rule without knowing which letter is used, because
|\pgfparsertoken| has the same meaning as that letter.
%
\begin{codeexample}[
preamble={\usepgfmodule{parser}},
pre={\newcount\mycount},
]
\mycount=0
% using the shortcut syntax of just placing ; after the state
\pgfparserdef{different letters}{all};{\pgfparserswitch{final}}%
\pgfparserdefunknown{different letters}{all}%
{\pgfparserdef{different letters}{all}\pgfparsertoken{}\advance\mycount1}%
\pgfparserdeffinal{different letters}%
{\the\mycount\ different letters found}%
% don't throw errors for unknown letters
\pgfparserset{different letters/silent=true}%
\pgfparserparse{different letters}udiaternxqlchudiea;
\end{codeexample}%
Next we want to try something that uses some of the different argument types
available.
%
\begin{codeexample}[preamble={\usepgfmodule{parser}}]
% using the same syntax as \pgfparserdef
\pgfparserdef{arguments}{initial}{the letter a}[d()]
{\pgfparserifmark{#1}{\textcolor{red}{\textit{use}}}{\textbf{#1}} }%
% using the shortcut syntax
\pgfparserdef{arguments}{initial}t[m]{\texttt{#1} }%
\pgfparserdef{arguments}{initial}c[t*O{blue}m]
{\pgfparserifmark{#1}{#3}{\textcolor{#2}{#3}}}%
\pgfparserdef{arguments}{all};{\pgfparserswitch{final}}%
\pgfparserparse{arguments}t{nobody}a(will)ac[green]{P}c*{arse}c{r};
\end{codeexample}%
|