AlgPseudocode and Language Variants¶
Hint
The reST source of this documentation page can be found here.
These lexers are heavily inspired by CTAN’s Algpseudocodex. They recognize all sorts of single- and multi-line comments in addition to expressions and commands that are inspired by Algpseudocodex.
They are used in Sphinx using their aliases. The code block:
.. code-block:: algpseudocode
\PROGRAM {The Pseudoprogram} \IS
\END PROGRAM {The Pseudoprogram}
will be rendered as:
PROGRAM The Pseudoprogram IS
END OF PROGRAM The Pseudoprogram
And the same code block with the german variant
(using .. code-block:: algpseudocode-de as language alias):
PROGRAMM The Pseudoprogram IST
ENDE DES PROGRAMMS The Pseudoprogram
States¶
The AlgPseudocode lexer and its language variants AlgPseudocodeDE and AlgPseudocodeFR basically work in three states (aka modes or contexts): default, expression and text.
In expressions it automatically recognizes:
Strings (single-quote, double-quote, triple-single-quote, triple-double-quote, Python style)
Numbers (also Python style)
(Mathematical) operators and symbols
\TEXT{...}or\T{...}Used to switch to a text-mode that prohibits automatic expression highlighting.
A closing curly brace can be quoted with
\}to not end the text mode prematurely.
\EXPR,\EXPRESSIONor\Eas nested construct
\NAME,\CALLand\GETS
\REMand\REMARKfor remarks (aka comments)Names (Name.Entity)
The default-mode is an extension of expression: in addition to expressions it recognizes all sorts of single- and multi-line comments and commands that are inspired by Algpseudocodex.
In text context it recognizes:
\EXPRESSION,\EXPRor\EUse to switch to expression-mode.
A closing curly brace can be quoted with
\}to not end the expression mode prematurely.
\TEXT(aka\T) as nested construct
\REMand\REMARKfor remarks (aka comments)
Lexer Options¶
- prohibit_raiseonerror_filter
Type:
boolDefault:
NoneIf
Truethe raiseonerror filter is not allowed to be applied by Sphinx whenLexer.add_filter()is called.This setting does not apply to filters that are set by the standard lexer option filters.
- no_end
Type:
boolDefault:
FalseIf
Trueall the\ENDxxxcommands will be skipped and yield no output.
- strict_tokentype
Type::
boolDefault:
TrueControl whether Explicit Token Types yield
pygments.token.Token.Generic.Errortokens (whenTrue, this is the default) or a token type that is synthesized on the fly bypygments.token.string_to_tokentype()(whenFalse).
- gets
Type:
strorNoneDefault:
None(yields⟵)The operator symbol to be printed by the command
\GETS.An often used alternative is
:=.
- remark
Type:
strorNoneDefault:
None(yields▷)The symbol to be printed as when starting comments with
\REMARKor\REM.To use a lexer with non-default options in Sphinx see section Customized Lexers in Sphinx.
Literals¶
Strings and numbers as in Python.
String prefixes u and b are supported—prefixes
r, f and t are not supported.
To have non-string-delimiting single- and double-quotes in the output you
have to escape them using \' or \".
This must be used to typeset something as f'(x) = 0.
0 1234567890 0xdead 0b100001 0o720 2.7 2.7e-54
"A string with an escaped double-quote \" "
'Another string with an escaped single-quote \' '
"""A multiline
string
"""
'''Another multiline string
'''
b"A \x20 byte string"
u'An explicit Unicode \u1234 string'
" a non string
' a non string also
(Mathematical) Symbols and Operators¶
Some ASCII symbol combinations are recognized and replaced by a Unicode symbol:
<=> ⇔
<-> ⟷
<- ⟵
-> ⟶
=> ⇒
<= ≤
>= ≥
<> ≠
!= ≠
:= ∶=
=: =∶
?= ≟
Unicode codepoints with property Sm are recognized as mathematical symbols
and highlighted accordingly.
Punctuation¶
Runs of dots ., .., ..., ...., … are handled
properly in expressions and yield a punctuation token.
They are not replaced by corresponding Unicode symbols.
Commands¶
Start with a backslash character
\Case-insensitive
Yield mostly the
pygments.token.Token.Keywordtoken typeTranslated if a translation is found
Depending on the command—may have required or optional parameters
Parameter handling is as follows:
Parameters are enclosed in curly braces
{and}Escaping within the braces is possible using the backslash
\as escape characterParameters are separated from the keyword/command by a (possibly empty) run of space or TAB characters. This is true for required and optional parameters.
Unrecognized commands typically result in a
pygments.token.Token.Errortoken.
More on escaping rules you can find in this chapter.
Commands With Required Parameters¶
\PROGRAM {A Program} or \PROG {A Program} PROGRAM A Program
\ALGORITHM{An Algorithm} or \ALGO{An Algorithm} ALGORITHM An Algorithm
\PROCEDURE{A Procedure} or \PROC{A Procedure} PROCEDURE A Procedure
\FUNCTION{A Function} or \FUNC{A Function} or \FN{A Function} FUNCTION A Function
\CLASS{A Class} CLASS A Class
\STATEMENT{the expression} \STATE{the expression} \BLOCK{the expression} ◆ the expression
expr1: \EXPRESSION{expression a in b} expr2: \EXPR{expression b in a} expr1: expression a in b expr2: expression b in a
\TEXTSTATEMENT{the text} \TEXTSTATE{the text} \TSTATEMENT{the text} \TSTATE{the text} \TEXTBLOCK{the text} \TBLOCK{the text} ▪ the text
\INPUT{Input 1} Input: Input 1
\INPUTS{Input 2} Inputs: Input 2
\OUTPUT{Output 1} Output: Output 1
\OUTPUTS{Output 2} Outputs: Output 2
\ENSURE{Whatever should be ensured!} Ensure: Whatever should be ensured!
\REQUIRE{Whatever should be required.} Require: Whatever should be required.
\RETURNS{Return 2} Returns: Return 2
\CALL{a function}(p1, p2) a function(p1, p2)
\NAME{an entity name} an entity name
For a special command with two required parameters see Explicit Token Types.
Commands With Optional Parameters¶
Some END-commands have optional parameters:
\ENDPROGRAM \ENDPROG END OF PROGRAM
\ENDALGORITHM \ENDALGO END OF ALGORITHM
\ENDPROCEDURE \ENDPROC END OF PROCEDURE
\ENDFUNCTION \ENDFUNC \ENDFN END OF FUNCTION
\ENDCLASS END OF CLASS
They are used like this:
\CLASS{Foo Bar Class} ... \END CLASS {Foo Bar Class} yields CLASS Foo Bar Class ... END OF CLASS Foo Bar Class
\CLASS{Foo Bar Class} ... \END CLASS yields CLASS Foo Bar Class ... END OF CLASS
See also
For other syntax variants concerning END see also section END-Commands.
Commands Without Parameters¶
“Normal” Commands¶
\IF IF
\THEN THEN
\ELSE ELSE
\ELSEIF or \ELSIF or \ELIF ELSE IF or ELSE IF or ELSE IF
\DO DO
\WHILE WHILE
\FORALL FOR ALL
\FOR FOR
\FROM FROM
\TO TO
\STEP STEP
\IN IN
\LOOP LOOP
\REPEAT REPEAT
\UNTIL UNTIL
\RETURN RETURN
\BEGIN BEGIN
\END END
\IS IS
\WITH WITH
\GETS ⟵
\REMARK or \REM ▷ A comment with a leading symbol
\REMARK or \REM is special: all characters to the end of the
line are taken as comment; curly braces are not needed—in fact:
they are interpreted to be part of the comment.
END-Commands¶
The separator character can be empty, a run of ASCII spaces, a run of
TAB characters, a single underscore _ or a single hyphen -.
All of the following examples are equally valid and result in the same output:
\ENDIF,\END IF,\END-IF,\END_IFor\END IF
\ENDIF END IF ▷ empty
\END IF END IF ▷ a single space
\END IF END IF ▷ two spaces
\END-IF END IF ▷ a single hyphen
\END_IF END IF ▷ a single underscore
\END IF END IF ▷ a single TAB character
The list of END-commands (here always just with - as separator):
\END-PROGRAM \END-PROG END OF PROGRAM
\END-ALGORITHM \END-ALGO END OF ALGORITHM
\END-PROCEDURE \END-PROC END OF PROCEDURE
\END-FUNCTION \END-FUNC \END-FN END OF FUNCTION
\END-CLASS END OF CLASS
\END-IF END IF
\END-WHILE END WHILE
\END-FOR END FOR
\END-FORALL END FOR ALL
\END-LOOP END LOOP
Note
The output of these END-commands can be suppressed by setting the
lexer option no_end to True.
Names and Entities¶
In an expression context all other words are interpreted as entity
names (token type pygments.token.Token.Name.Entity).
Allowed characters in the words follow the corresponding Python rules. As such, many Unicode characters are allowed.
To highlight entity names with whitespace or other “special” characters in it
use the NAME command.
entity_name_1 entity_name_1
entity_name_2 entity_name_2
\NAME{entity-name 3} entity-name 3
München München
Genève Genève
Note
Should you want to change the token type and the associated highlighting you may want to have a look at TokenReplaceFilter.
Explicit Token Types¶
They allow to handle keywords and operators that are not recognized by default. And they allow the user to explicitely highlight some input text with a low-level command.
They are implemented with the \ttX{ARG1}{ARG2} command.
This command has two required parameters:
The content of the first argument ARG1 can be one of
A value in the
pygments.token.STANDARD_TYPESdict.Its corresponding token type (the associated key in this dictionary) will be used as token type for the token.
A string representation of an existing token type without the
Token.prefix (e.g.String,Generic,Generic.EmphStrong,Text,Text.Multiline).
If a corresponding token type is not found the lexer’s behaviour depends on the lexer option
strict_tokentype(see Lexer Options):If
True(the default) the command yields apygments.token.Token.Generic.Errortoken type for the given command’s content.If
Falsethen the Pygments functionpygments.token.string_to_tokentype()will be called. This function returns either an existing token type or synthesizes a new one on the fly. The associated highlighting with freshly created token types in the output may not be well defined.For this argument escaping is neither needed nor supported.
The content of the second argument will given the token type of the first parameter.
Standard Escaping Rules apply to this argument!
Note
The command for explicit token types is case-sensitive.
Examples:
• \ttX{}{token} token ▷ just a base "Token"
• \ttX{kc}{C} C ▷ C as Keyword.Constant
• \ttX{Keyword.Constant}{C} C ▷ C as Keyword.Constant
• \ttX{ow}{∈} ∈ ▷ ∈ as Operator.Word
• \ttX{Operator.Word}{∈} ∈ ▷ ∈ as Operator.Word
• \ttX{kc}{A Constant Keyword} A Constant Keyword ▷ An explicit Keyword.Constant
• \ttX{nv}{A Variable Name} A Variable Name ▷ An explicit Name.Variable
• \ttX{ni}{An Entity*Name} An Entity*Name ▷ An explicit Name.Entity
• \ttX{k}{∈ ∌} ∈ ∌ ▷ ∈ and ∌ as (ordinary) Keywords
• \ttX{o}{∈ ∌} ∈ ∌ ▷ ∈ and ∌ as (ordinary) Operators
/*
* The line below has ∈_∌ as (peculiar) function name.
* Their params are automatic (i.e. a normal expression).
*/
• \ttX{nf}{∈_∌}(p1, p2) ∈_∌(p1, p2)
• \ttX{Name.Function}{∈_∌}(p1, p2) ∈_∌(p1, p2)
/*
* The line below has ∈_∌ as (peculiar) decorator name (as used in Python).
* Their params are automatic (i.e. a normal expression).
*/
• \ttX{nd}{∈_∌}(p1, p2) ∈_∌(p1, p2)
• \ttX{Name.Decorator}{∈_∌}(p1, p2) ∈_∌(p1, p2)
/*
* Normal emphasis ("strong")
*/
• \ttX{gs}{this is strong} this is strong
• \ttX{Generic.Strong}{this is strong} this is strong
/*
* A strong emphasis.
*/
• \ttX{ges}{A Strong Emphasis!} A Strong Emphasis!
• \ttX{Generic.EmphStrong}{A Strong Emphasis!} A Strong Emphasis!
/*
* Escaping is allowed and needed for the closing brace!
* The example token type is a "String".
*/
• \ttX{s}{Escaping brace \} and backslash \\!} Escaping brace } and backslash \!
/*
* This is a non-existing token type:
* by default you get some generic error markup with a Generic.Error
* token and no expansion.
* See also `Lexer Options` and `strict_tokentype`.
*/
• \ttX{NON-EXISTING}{∈_∌}(p1, p2) \ttX{NON-EXISTING}{∈_∌}(p1, p2)
An example with a lexer and strict_tokentype=False
(highlighting obviously is like standard text with the templates used):
• \ttX{Generic.Not.Yet.Existing}{∈_∌}(p1, p2) ∈_∌(p1, p2)
Note
Explicit token types work in all expression and text contexts.
Note
Nesting of explicit token types is not supported.
Escaping Rules¶
The escape character is a backslash \.
A backslash can be escaped with \\ and yields a single backslash token.
Within parameters a closing curly brace } ends the current
parameters environment.
It must be escaped using \} if a closing curly brace is part of the
argument content.
A single backslash yields a pygments.token.Token.Generic.Error
token when in default and expression states
(and also in Explicit Token Types).
Contrary—in text contexts a single backslash character that does not
introduce a command yields a normal text token.
In all contexts a backslash that would normally introduce a known command must be escaped if the content should not recognized as a command.
Single- and double-quotes must be escaped also (\" or \') in
default and expression contexts when they should not introduce a
string token.
Customized Lexers in Sphinx¶
Defining lexers with non-default options in Sphinx can be done in its
configuration file conf.py.
The first option is to apply the Sphinx config value highlight_options
properly. An existing lexer can be customized by options.
A more flexible alternative is to define a new lexer in the Sphinx application. The very same lexer class can be used with different options:
from functools import partial
from pygments_lexer_pseudocode2.lexers.algpseudocode import AlgPseudocodeLexer
def setup(app):
#
# Add a custom lexer: AlgPseudocodeLexer with custom init
# option "no_end".
#
# In modern Sphinx versions given lexer must be callable and may
# not be a lexer instance. So use an indirection with "partial"
# here.
#
app.add_lexer("noend-algpseudocode",
partial(AlgPseudocodeLexer, no_end=True))
Note
Lexers in Sphinx are instantiated with the raiseonerror filter
applied by default.
This is also true for custom lexers that are added by
Sphinx.add_lexer().
Using the filters option the user can associate custom filters
with a lexer.
These filters have precedence over the default raiseonerror
filter.
Lexer instances that are added to
sphinx.highlighting.lexers somehow are taken as is by
Sphinx and are not augmented with any default filters.
See also chapter Filters.
For older Sphinx versions your mileage may vary.
Some Examples¶
Synthetic Example
The first example is a synthetic example with many features.
Its source code is in examples/example-1.pseudocode.
PROGRAM The Pseudocode Lexer IS
/*
* The program is here, but it also could be an \ALGORITHM
*
* /* YES! Nested multi-line comments work! */
*/
PROCEDURE A Procedure name IS
▪ A text block 1
▪ A text block 2 with a nested expression: flag is FALSE
◆
▷ A remark on its own line within a "BLOCK"
END OF PROCEDURE A Procedure name
FUNCTION A Function with {escaped} text IS
(1234567890 ≠ what) or a and b xor (c in d) ▷ this is another remark
◆ foo is not bar
◆ 2 + 6 = 1 (mod 7)
IF a is nil THEN
Set something
ELSE IF
Set some other thing
END IF
END OF FUNCTION A Function with {escaped} text
CLASS A Class IS
// This is a one-line comment
a and b xor (c in d) ▷ this is another remark
# This is another one-line comment
(* Here is a "block" of expressions.
A block has a leading symbol. *)
◆ foo ≟ bar
Bär ≥ Maus
and Bär ≠ Maus
◆ a 1.2 {x in X} c
(* Analogous there is a variant that is in text-mode by default.
It has an other leading symbol. *)
▪ We will compute next a xor b or (set X is Empty) ▷ without c!
or multiply it the \ttx-ges/other/ way.
▪ foo bar ▷ A remark within a text statement until LF!
nextfoo nextbar
nextnextfoo nextnextbar
END OF CLASS A Class
@A_XXX
FOO BAR
END OF PROGRAM
The highlighted output with a customized AlgPseudocodeLexer and its no_end
option set to True:
PROGRAM The Pseudocode Lexer IS
/*
* The program is here, but it also could be an \ALGORITHM
*
* /* YES! Nested multi-line comments work! */
*/
PROCEDURE A Procedure name IS
▪ A text block 1
▪ A text block 2 with a nested expression: flag is FALSE
◆
▷ A remark on its own line within a "BLOCK"
FUNCTION A Function with {escaped} text IS
(1234567890 ≠ what) or a and b xor (c in d) ▷ this is another remark
◆ foo is not bar
◆ 2 + 6 = 1 (mod 7)
IF a is nil THEN
Set something
ELSE IF
Set some other thing
CLASS A Class IS
// This is a one-line comment
a and b xor (c in d) ▷ this is another remark
# This is another one-line comment
(* Here is a "block" of expressions.
A block has a leading symbol. *)
◆ foo ≟ bar
Bär ≥ Maus
and Bär ≠ Maus
◆ a 1.2 {x in X} c
(* Analogous there is a variant that is in text-mode by default.
It has an other leading symbol. *)
▪ We will compute next a xor b or (set X is Empty) ▷ without c!
or multiply it the \ttx-ges/other/ way.
▪ foo bar ▷ A remark within a text statement until LF!
nextfoo nextbar
nextnextfoo nextnextbar
@A_XXX
FOO BAR
Dinic’s Algorithm
The second example is Wikipedia’s description of Dinic’s Algorithm (see https://en.wikipedia.org/wiki/Dinic%27s_algorithm).
Its source code is in examples/algorithm-dinic.pseudocode.
ALGORITHM Dinic's Algorithm WITH
Input: A network G = ((V , E), c, s, t).
Output: An s–t flow f of maximum value.
IS
1. Set f(e) = 0 for each e ∈ E.
2. Construct G_L from G_f of G.
If dist(t) = ∞, stop and output f.
3. Find a blocking flow f' in G_L.
4. Augment flow f by f' and go back to step 2.
END OF ALGORITHM
Ford–Fulkerson Algorithm
The third example is Wikipedia’s pseudocode of the Ford–Fulkerson Algorithm (see https://en.wikipedia.org/wiki/Ford%E2%80%93Fulkerson_algorithm).
Its source code is in
examples/algorithm-ford-fulkerson.pseudocode.
ALGORITHM Ford–Fulkerson WITH
Inputs: Given a network G = (V, E) with flow capacity c, a source node s, and a sink node t
Output: Compute a flow f from s to t of maximum value
IS
1. f(u, v) ⟵ 0 for all edges (u, v)
2. While there is a path p from s to t in G_f,
such that c_f(u, v) > 0 for all edges (u, v) ∈ p:
1. Find c_f(p) = min{c_f(u, v): (u, v) ∈ p}
2. For each edge (u, v) ∈ p
1. f(u, v) ⟵ f(u, v) + c_f(p) ▷ Send flow along the path
2. f(v, u) ⟵ f(v, u) - c_f(p) ▷ The flow might be "returned" later
END OF ALGORITHM Ford–Fulkerson
Edmonds–Karp Algorithm
The fourth example is Wikipedia’s pseudocode of the Edmonds–Karp Algorithm
(see https://en.wikipedia.org/wiki/Edmonds%E2%80%93Karp_algorithm)
with a custom lexer which skips all ENDxxx keywords.
Its source code is in
examples/algorithm-edmonds-karp.pseudocode.
ALGORITHM Edmonds–Karp WITH
Input:
graph: graph[v] should be the list of edges coming out of vertex v in the
original graph and their corresponding constructed reverse edges
which are used for push-back flow.
Each edge should have a capacity cap, flow, source s and sink t
as parameters, as well as a pointer to the reverse edge rev.
s: Source vertex
t: Sink vertex
Output:
flow: Value of maximum flow)
IS
flow ∶= 0
REPEAT
/* Run a breadth-first search (bfs) to find the shortest s-t path.
We use 'pred' to store the edge taken to get to each vertex,
so we can recover the path afterwards. */
q ∶= queue()
q.push(s)
pred ∶= array(graph.length)
WHILE not empty(q) and pred[t] = null DO
cur ∶= q.pop()
FOR Edge e in graph[cur] DO
IF pred[e.t] = null and e.t ≠ s and e.cap > e.flow THEN
pred[e.t] ∶= e
q.push(e.t)
IF not (pred[t] = null) THEN
/* We found an augmenting path.
See how much flow we can send */
df ∶= ∞
FOR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) DO
df ∶= min(df, e.cap - e.flow)
/* And update edges by that amount */
FOR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) DO
e.flow ∶= e.flow + df
e.rev.flow ∶= e.rev.flow - df
flow ∶= flow + df
UNTIL pred[t] = null ▷ i.e., until no augmenting path was found
RETURN flow
And now the Edmonds–Karp Algorithm with french keywords:
ALGORITHME Edmonds–Karp AVEC
Input:
graph: graph[v] should be the list of edges coming out of vertex v in the
original graph and their corresponding constructed reverse edges
which are used for push-back flow.
Each edge should have a capacity cap, flow, source s and sink t
as parameters, as well as a pointer to the reverse edge rev.
s: Source vertex
t: Sink vertex
Output:
flow: Value of maximum flow)
EST
flow ∶= 0
RÉPÉTER
/* Run a breadth-first search (bfs) to find the shortest s-t path.
We use 'pred' to store the edge taken to get to each vertex,
so we can recover the path afterwards. */
q ∶= queue()
q.push(s)
pred ∶= array(graph.length)
TANTQUE not empty(q) and pred[t] = null FAIRE
cur ∶= q.pop()
POUR Edge e in graph[cur] FAIRE
SI pred[e.t] = null and e.t ≠ s and e.cap > e.flow ALORS
pred[e.t] ∶= e
q.push(e.t)
END IF
FIN POUR
FIN TANTQUE
SI not (pred[t] = null) ALORS
/* We found an augmenting path.
See how much flow we can send */
df ∶= ∞
POUR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) FAIRE
df ∶= min(df, e.cap - e.flow)
FIN POUR
/* And update edges by that amount */
POUR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) FAIRE
e.flow ∶= e.flow + df
e.rev.flow ∶= e.rev.flow - df
FIN POUR
flow ∶= flow + df
END IF
JUSQUACEQUE pred[t] = null ▷ i.e., until no augmenting path was found
RENVOYER flow
FIN D'ALGORITHME Edmonds–Karp
And again the Edmonds–Karp Algorithm with german keywords:
ALGORITHMUS Edmonds–Karp MIT
Input:
graph: graph[v] should be the list of edges coming out of vertex v in the
original graph and their corresponding constructed reverse edges
which are used for push-back flow.
Each edge should have a capacity cap, flow, source s and sink t
as parameters, as well as a pointer to the reverse edge rev.
s: Source vertex
t: Sink vertex
Output:
flow: Value of maximum flow)
IST
flow ∶= 0
WIEDERHOLE
/* Run a breadth-first search (bfs) to find the shortest s-t path.
We use 'pred' to store the edge taken to get to each vertex,
so we can recover the path afterwards. */
q ∶= queue()
q.push(s)
pred ∶= array(graph.length)
SOLANGE not empty(q) and pred[t] = null DO
cur ∶= q.pop()
FÜR Edge e in graph[cur] DO
WENN pred[e.t] = null and e.t ≠ s and e.cap > e.flow DANN
pred[e.t] ∶= e
q.push(e.t)
ENDE WENN
ENDE FÜR
ENDE SOLANGE
WENN not (pred[t] = null) DANN
/* We found an augmenting path.
See how much flow we can send */
df ∶= ∞
FÜR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) DO
df ∶= min(df, e.cap - e.flow)
ENDE FÜR
/* And update edges by that amount */
FÜR (e ∶= pred[t]; e ≠ null; e ∶= pred[e.s]) DO
e.flow ∶= e.flow + df
e.rev.flow ∶= e.rev.flow - df
ENDE FÜR
flow ∶= flow + df
ENDE WENN
BIS pred[t] = null ▷ i.e., until no augmenting path was found
RETURN flow
ENDE DES ALGORITHMUS Edmonds–Karp
Comments¶
with the
\REMARKor\REMkeywords (until the end of the line; the output includes a leading symbol, by default▷)multi-line comments with
/* ... */; they can be nestedmulti-line comments with
(* ... *); they can be nestedsingle-line comments with
//or#(until the end of the line)