4 个版本 (2 个重大更新)
0.3.1 | 2023年5月21日 |
---|---|
0.3.0 | 2023年5月18日 |
0.2.0 | 2023年5月2日 |
0.1.0 | 2023年4月10日 |
#1620 in 解析实现
每月47次下载
170KB
2K SLoC
udl-rs
UDL(通用数据语言)的 Rust 解析器。
通用数据语言(UDL)
UDL 是一种文本 元格式,主要用于定义用户读取和手工编写的数据格式。这些格式主要是配置和标记格式,或者两者混合。
UDL 本地支持其他编程语言和格式(如 XML、JSON 和 LaTeX)中找到的通用数据结构。它可以表达结构化数据(字典、序列、层次结构、值)和非结构化数据(文本、标记),并且可以表达由这些数据的任意组合组成的复杂结构。
UDL 是一种注重人类可读性和可写的文本格式。格式良好的 UDL 文档易于阅读、理解和编辑。该格式简洁,语法噪声最小;构建文档所需的字符很少。它便于手工编码,因此作为源格式。因此,该格式适合作为配置和标记格式的基座。
UDL 简单:特殊情况很少,异常很少,保留字符很少。这使得它易于推理、生成和解析。虽然牺牲了可读性,但它可以被压缩。虽然不是为此目的而设计的,但它适合于序列化、数据存储和数据交换,尽管这里其他格式可能更优。
比较
与 XML 相比,UDL 本地支持序列和字典的通用数据结构。 UDL 的标签符号语法基于 XML 的标签符号语法,但进行了一些修改。在 UDL 中,还支持编码命令和操作。
与 JSON 相比,UDL 的语法噪声更少;它不需要将字符串放在引号中。UDL 本地支持标记,并且更重要的是,注释。UDL 的序列和字典语法受 JSON 启发。
与(常规)LaTeX 相比,UDL 支持结构化数据。它们在语法噪声和简洁性方面相似。可以认为 UDL 中的命令符号比 LaTeX 中的命令符号更易读,因为可以从语法中清楚地看到命令适用于哪些参数。此外,命令可以接受结构化数据作为参数,这对于某些应用来说很方便。
示例 & 展示
以下是基于 UDL 的格式和文档的示例。展示了结构化数据和非结构化数据如何共存并形成更复杂的结构,以及如何用于标记和配置。
维基百科文章示例
这是一个基于 UDL 的维基百科文章格式的示例。
此示例展示了由结构化数据(值、字典和序列)和非结构化数据(标记)组成的复杂层次结构。
此示例的目的是展示 UDL 在充分发挥其功能时的能力。特别是,维基百科文章通常包含结构化数据和非结构化数据。因此,这是一个很好的示例,说明 UDL 如何将这两种类型组合成更复杂的层次结构。
此外,此示例展示了 UDL 语法。与其他编码相同数据的格式相比,该格式的可读性、简洁性和简单性。
注意
- 宏应用看起来是这样的:
<macro>:arg1:arg2:...:argN
。参数以冒号附加。 - 宏也可以用标签表示。这是一个带有一个参数的宏:
<+macro>arg<-macro>
。 @
宏插入一个链接。它接受两个参数:第一个参数是要链接的文章,第二个参数是将在文章中出现的链接标签。title
宏不接受任何参数,并用作文章标题。
title: Aluminium;
shortdesc: The <@>:element:{chemical element} aluminium.;
uuid: 0c5aacfe-d828-43c7-a530-12a802af1df4;
type: chemical-element;
tags: [metal; common];
key: aluminium;
chemical-symbol: Al;
atomic-number: 13;
stp-phase: solid;
melting-point: 933.47;
boiling-point: 2743;
density: 2.7;
electron-shells: [2; 8; 3];
# External references
ext-refs: {
wikipedia: "https://en.wikipedia.org/wiki/Aluminium";
snl: "https://snl.no/aluminium";
};
# Intra-wiki references
refs: {
element: 740097ea-10fa-4203-b086-58632f099167;
chemsym: 6e2f634c-f180-407a-b9ce-2138b412b248;
atomnum: 1a5e1974-a78c-4820-afeb-79bef6974814;
react: ab7d8a1f-c028-4466-9bb2-41a39d153241;
aloxide: c1ff08e7-a88f-42d5-83c3-6adc4835a07b;
stab: b3b13474-4fe3-4556-9568-925c066916a5;
purity: 40786551-85c4-461c-ba6e-4d54d5863820;
ion: effd5c7a-da31-4357-a94c-91343e9a05eb;
metal: 84333088-cfcc-4e78-8d3f-7307dcab144b;
};
content: {
<@>:self:<title> is a <@>:element:{chemical element} with
<@>:chemsym:{chemical symbol} <chemsym> and <@>:atomnum:{atomic number}
<atomnum>.
<p>
In <@>:purity:pure form, it is a highly <@>:react:reactive <@>:metal:{metal},
but normally a thin coat of <@>:aloxide:{aluminium oxide} forms on its
surface, keeping it highly <@>:stab:{stable}.
<p>
In nature, it occurs as the <@>:ion:ion <+$>Al^{3+}<-$>. It constitutes 8.2%
of the earth's crust, making it the most common <@>:metal:metal found there.
...
};
HTML 预处理器示例
这是一个基于 UDL 的 HTML 预处理器输入格式的文档示例。预处理器可以将此文档编译为 HTML。
此示例的目的是展示基于 UDL 的标记和类似 XML 的结构的编码。
将此文档与相应的 HTML 文档进行比较。在术语冗长性和语法噪声方面,UDL 允许使用短和长闭合标签。在不同的情况下,两者都很有用。 UDL 不需要在属性值周围使用引号。
注意
- 在此格式中,常规标记标签和特殊宏通过
@
符号区分。宏以@
开头,而常规标签仅由字母组成。 @doctype
宏用<!doctype html>
替换自己。
<@doctype>
<+html> # <+tag> is an opening tag and <-tag> or <-> is a closing tag.
<+head>
<+title><@title><->
<+script src:script.js><->
<-head>
<+body>
<+h1 id:main-heading><@title><->
<+p>Hello world!<-> # These two paragraph notations are equivalent.
<p>:{Hello world!}
<img src:frontpage.jpg>
<+div class:dark-background><+p>
This is a paragraph<br>
with a line break.
<+em class:italic-text>This text is italic.<->
<-><->
<-body>
<-html>
TeX 预处理器示例
这是一个基于 UDL 的 LaTeX 预处理器输入格式的文档示例。预处理器可以将此文档编译为 LaTeX。
此示例的目的是展示基于 UDL 的类似 LaTeX 的标记的编码。
将此文档与相应的 LaTeX 文档进行比较。它们很相似,但 UDL 文档的一个优点是,命令应用的参数可以仅从语法中确定。
作为一个应用,这种编码可能适用于维基百科文章示例。文章可能包含数学符号,而此编码可用于编码 LaTeX-math,该数学符号随后由 MathJax 显示。
注意
- 预处理器宏以
@
开头,而常规命令仅由字母组成。 @tabulate-sq
自动制表一个方格,例如矩阵。它接受一个数字和一系列制表值。
<documentclass>:article
<usepackage>:amsmath
<begin>:document
<section>:Equations
# Define a sum-range command.
<newcommand>:<SumRn>:*:4:{
<sum>_{#1}^{#2 <dots> #3} #4
}
<begin>:math
<SumRn>:k:0:100:k
= 0 + 1 + 2 + <dots> + 99 + 100
= (0 + 100) + (1 + 99) + <dots> (49 + 51) + 50
= 5050
<end>:math
<begin>:math
<SumRn>:k:0:n:k
= 0 + 1 + 2 + <dots> + (n - 1) + n
= n <cfrac>:n:2 + <cfrac>:n:2
= <cfrac>:n^2:2 + <cfrac>:n:2
= n <cdot> <cfrac>:{n + 1}:2
<end>:math
<section>:Matrices
<begin>:math
<mathbf>:X = <begin>:bmatrix <@tabulate-sq>:3:[
1;0;0;
0;1;0;
0;0;1;
] <end>:bmatrix
<end>:math
<end>:document
材料配置示例
这是一个基于 UDL 的配置示例。
本例的目的是展示一个基于 UDL 的配置文件,并将其与相应的 JSON 配置文件进行比较。
在语法噪声方面,相应的 JSON 文档要求所有键周围都要加引号,所有文本值周围也要加引号,不允许注释,并且要求根级别元素用括号括起来。显然,UDL 的语法噪声更少。这两种格式都具有最小的冗余性,并且都很简单。
oak-planks: {
name: Oak planks;
description: Planks made from oak wood.;
tags: [wood];
price: 200;
};
birch-planks: {
name: Birch planks;
description: Planks made from birch wood.;
tags: [wood];
price: 200;
};
stone: {
name: Stone;
description: A solid material, but does not insulate well.;
price: 100;
tags: [heavy; stone];
};
marble: {
name: Marble;
price: 450;
beauty: 2;
tags: [heavy; stone; wealth];
};
# This material is not available yet.
glass: {
disabled;
name: Glass;
price: 400;
};
语法
UDL 文档由表达式组成,而表达式由参数组成。一些参数可能还包含嵌套的表达式。
表达式和参数
表达式 是参数的序列。
示例: arg1 arg2 arg3 ...
。
参数 是表达式的元素。有 6 种参数变体:空、文本、序列、字典、指令 和 复合。
分组
括号 {
}
用于分组和限定参数。
示例: {Text 1} {Text 2}
是一个包含 2 个文本参数的表达式。括号用于限定文本参数,防止它们合并为一个文本参数。
通过分组参数,可以将任意数量的参数作为一个单独的参数给出。一个空分组表示一个空参数。一个参数的分组简单地表示该参数本身。多个(2 个或更多)参数的分组表示一个复合参数。
示例: { arg }
是单个参数的分组。这可能有助于界定文本或界定指令参数。作为参数,arg
等于 { arg }
,这等于 { { arg } }
。确实,将单个参数括在括号中没有结构上的效果,但有时它可以提高可读性。
示例: { arg1 arg2 arg3 }
是 3 个参数的分组,它产生一个包含 3 个参数的复合参数。
空参数
空 参数由括号内的空表达式表示: {}
。
文本参数
文本 参数简单地说是一系列单词或引号文本。
示例: This is a text argument
。
示例: "Text argument 1" Text argument 2 {Text argument 3} {Text argument 4} Text argument 5
是一个由 5 个文本参数组成的表达式。
示例: "引号允许插入任意空白和保留字符,例如 : 或 ]"
。
未引用的文本不能包含保留字符,除非它们被反斜杠 \
转义。
示例: Some 保留字符\: \:, \;, \<, \}, 等.
。
可以使用重复来在未引用的文本中插入冒号 :
。
示例: Some text:: More text
解析为文本 Some text: More text
。
此外,未引用的文本中的任何空白都将缩减为一个空格字符。 UDL 是一个空白等价格式,其中所有空白都等于一个空格字符,除非它被转义或位于引号内。
字典参数
一个 字典 参数是由分号 ;
分隔的键值对序列,用花括号 {
}
括起来。条目中的键和值由冒号 :
分隔。键由一个单词或一个引号给出;它不能由多个单词给出。值是一个表达式。
示例: { k1: v1; "key 2": v2; k3: v3; ... }
。
空字典参数必须包含一个冒号,以区分空表达式。
示例: {:}
是一个空字典。
键后跟分号 ;
表示其值是一个空表达式。
示例: {k1; k2: v2; k3;}
包含键 k1
和 k3
,它们后面跟着分号 ;
。这意味着它们的值是空表达式。
允许尾部分号。
示例: {k1: v1; k2: v2;}
和 {k1: v1; k2: v2}
是相等的。
序列参数
一个 序列 参数是由分号 ;
分隔的表达式序列,用方括号 [
]
括起来。
示例: [expr1; expr2; expr3; ...]
。
示例: []
是一个空序列。
允许尾部分号。
示例: [expr1; expr2;]
和 [expr1; expr2]
是相等的。
指令参数
指令表达式 是应用于多个参数的指令。有两种记法可以生成指令表达式:命令记法和标签记法。
命令记法
在命令记法中,一个 指令表达式 被编码为一个在尖括号内的 指令,后跟应用于它的参数,这些参数以冒号 :
后跟,其中没有周围空白。
示例: <dir>:arg1:arg2:...:argN
是一个具有 N 个参数的指令表达式。
示例: <dir>
是一个没有参数的指令。
示例: <text-weight>:600:{This is bold text}
是应用于 2 个文本参数的指令 text-weight
。
指令,即尖括号内的部分,由一个标签后跟属性组成。标签由一个词或引号给出。在标签之后,可以插入属性。一个属性是一个键值对。键和值由冒号 :
分隔。
示例: <p id:opening class:fancy>
编码了具有属性 id:opening
和 class:fancy
的指令 p
。
允许不跟冒号的属性键。此类属性的值被视为一个空参数。
示例: <input type:checkbox checked>
有标签 input
。它有两个属性:具有值 checkbox
的 type
和具有值 {}
的 checked
。
可以将指令作为参数插入到指令表达式中。在那里,它们被解释为零参数的指令表达式。
示例: 在 <cmd0>:arg1:arg2:<cmd3>:arg4:arg5
中,<cmd3>
是一个零参数的指令表达式。 <cmd0>
是一个具有 5 个参数的指令表达式。
优先运算符 <>
是一个特殊运算符,可以在指令表达式中使用。它将右侧的指令表达式作为参数应用于左侧的指令表达式。
示例: <bold>:<>:<italic>:text
等价于 <bold>:{ <italic>:text }
。
标签符号
在标签符号中,标签用于生成指令表达式。一个开标签以 +
开始,而一个闭标签以 -
开始。
示例: <+tag> content <-tag>
。
标签内的内容是一个表达式,作为最后一个参数附加到标签表示的指令表达式上。
示例: <+math>1 + 2 + 3 + <dots><-math>
等价于 <math>:{1 + 2 + 3 + <dots>}
。
可以使用冒号将参数附加到开标签上。
示例: <+Sum>:k:1:n 3k^2-2k <-Sum>
等价于 <Sum>:k:1:n:{3k^2 - 2k}
。
在闭标签中是否包含指令名是可选的。在某些情况下这很有用,但在其他情况下可能过于冗长。
示例: <+tag>arg<-tag>
等价于 <+tag>arg<->
。
在某些情况下,标签符号可以提高文档的可读性。
示例:在跨越多行的长范围内,可能难以判断哪些括号属于哪个指令,以及每个作用域在哪里结束。标签符号可以在关闭标签中显示作用域的名称,从而解决此问题。 <+html> 多行和多内容... <-html>
。
示例:有时括号放置得太紧凑,难以区分。标签符号通过引入冗余性使区分作用域更容易。 <bold>:{Bold <italic>:{italic <underline>:{underlined <strikethrough>:{strikethrough text}}}}
比<+bold>Bold <+italic>italic <+underline>underlined <+strikethrough>strikethrough text<-><-><-><->
更容易阅读。
复合参数
一个复合参数简单来说就是包含多个(2个或更多)参数的表达式,这些参数用大括号{
}
括起来。
示例: { {Text} Some more text [1; 2; 3] {k1: v1; k2: v2} {} }
是一个包含2个文本参数、1个序列、1个字典以及最后1个空参数的复合参数。
根节点
UDL文档的根节点是一个表达式、一个序列或一个字典。根节点不是一个参数,因此不被括号包围。
保留字符
TODO:将关于保留字符序列的说明写入,而不是保留字符。
括号<
、>
、[
、]
、{
、}
、引号"
、冒号:
和分号;
是保留字符。除非转义,否则它们不能用于文本中。
转义字符
反斜杠 \
是转义字符。紧随其后的字符将作为文本插入,无论该字符是否为保留字符。
示例: \[
解析为文本 [\
。
特殊转义序列
冒号 :
有时用于常规文本,因此如果它们是保留字符,可能会不方便。因此,允许一些特殊的转义序列:::
将冒号作为文本插入,而不是解析为保留字符。
示例: Price:: 300€
解析为文本 Price: 300€
。
空白等价性和重要性
任何空白序列都与单个空格字符等价,除非空白被转义或位于引号内。表达式中的参数之间的空白是重要的,但表达式开头或结尾的空白是不重要的。
示例: arg1{arg2}
不等于 arg1{arg2}
,因为存在重要的空白差异。
示例: arg1{ arg2 }
等于 arg1{arg2}
,因为没有重要的空白差异。
注释
单词开头的数字符号 #
可能会根据其后跟随的字符打开注释。如果其后跟随空白或另一个 #
,则打开一个以下一行结束的注释。否则,如果其后跟随文本符号,该单词将按常规解析为文本。
示例: # This is a comment
是注释,因为 #
后跟空白。
示例: ##### Configuration ###
是注释,因为 #
后跟 #
。
示例: #2
、#0FA60F
和 #elements
不是注释,因为 #
后跟文本符号。
示例: 在 This is text# Is this a comment?
中不会打开注释,因为 #
不是单词的开头。
语义
UDL 规定了表达式和参数的语法,但并未规定它们的语义或数据结构的编码方式。语义,例如指令表达式的有效性、字典键和表达式组合,是在定义基于 UDL 的格式时确定的。这与 XML 和 JSON 作为元语言的方式相似。就它们本身而言,它们仅确定文档是否在语法上正确,但将有效性问题留给了格式实现者。
数据结构可以以许多任意的方式在 UDL 中进行编码。因此,实现者必须为每个数据结构定义特定的编码。实现者还必须定义文档根是表达式、序列还是字典。这可以通过编写文档、使用模式或最好通过在程序中实现反序列化过程来完成。一旦完成这些,就有一个具有良好定义的语法和语义的格式。
尽管关于数据结构应该如何编码没有明确的规则,但在表达和变体表示方面有一些最佳实践。在实现编码时遵循这些实践可以使基于 UDL 的格式更加统一,从而使它们更容易理解。以下描述了关于表达式和参数编码的最佳实践。
表达式和参数语义
表达式以规范或默认方式编码数据结构。表达式由任意数量的参数组成,这些参数提供了表达式所需的信息。从表达式的角度来看,参数可以被视为自身编码一个子结构,该子结构是外部表达式构建的,或者简单地作为提供信息给表达式的普通变体。
以下是参数的可能解释总结以及这样的参数编码的内容。
参数 | 用途 |
---|---|
文本 | 编码原始值。 |
序列 | 编码多个数据结构。 |
字典 | 编码多个命名数据结构。 |
指令 | 以特定方式编码数据结构。 |
表达式/单例/复合/空 | 以规范或默认方式编码数据结构。 |
鉴于某些参数可能有多种解释,假设当基于 UDL 的格式定义时提供了参数的解释。
在定义复杂结构时,必须将数据结构拆分为多个参数,并使用最适合的变体对每个部分进行编码。
指令语义
作为一个数据结构的编码,指令表达式以特定方式编码结构。然而,指令有两个维度
- 首先,指令描述了输入如何编码数据结构。
- 其次,指令描述了输入如何编码一个动作(动作是环境的外部效应、有状态变化或查询)。如果指令不依赖于环境,则它是纯的,否则是不纯的。
据此,指令表达式表示编码的数据结构、编码的动作或两者的混合。指令可以被视为 XML 标签、LaTeX 命令/宏和文本占位符/标记的泛化。
示例:在类似 XML 的标记中,标签用于标记和添加文本的语义。标签不编码任何动作。在 UDL 中,标签可以编码为指令,当应用于文本时,编码语义文本。例如,HTML <span class="italic">text</span>
对应于 UDL <+span class:italic>text<->
。
示例:在 <sender> sent <amount> to <recipient>.
中,指令用于表示占位符。
示例:在类似于 LaTeX 的标记中,命令/宏用于执行替换、计算和状态动作(例如增加章节计数,或包含一个包)。在 UDL 中,命令可以简单地编码为指令。例如,LaTeX 的 \frac{2a}{b}
对应于 UDL 的 <frac>:2a:b
。
示例:<set>:x:100
编码了一个将变量 x
设置为 100
的动作。它编码了一个空的数据结构,因为这纯粹是一个命令。
原始编码
原始值简单地编码为文本。
- 字符串编码为文本。
- 数字(包括布尔值)编码为文本。有效的编码进一步由数字类型确定。
标记编码
标记编码为一个包含任意数量文本和指令表达式参数的表达式。产生语义文本且不表示任何动作的指令可以编码为标签,但这不是必需的。其他可能表示动作的宏类型编码为命令符号。
示例:上述预处理器示例演示了标记编码。
结构/产品类型编码
没有字段的结构编码为空表达式。具有字段的结构编码为字典或序列,具体取决于它们是否命名或位置。可选地,可以包含结构类型。
变体 | 示例 |
---|---|
命名字段 | { x: 10; y: 30; z: 5 } 或 Coordinates { x: 10; y: 30; z: 5 } |
位置字段 | [10; 30; 5] 或 Coordinates [10; 30; 5] |
没有字段 | {} 或 Empty 或 Empty {} |
枚举/求和类型编码
枚举以1或2个参数进行编码。第一个参数是一个文本参数,用于指定枚举变体。如果枚举没有字段,则没有第二个参数。否则,第二个参数是一个序列或字典,这取决于枚举是否有命名或位置字段。可选地,可以包含枚举类型,以下展示了如何编码类型和变体。
变体 | 示例 |
---|---|
命名字段 | Binomial { n: 50; p: 10% } 或 Distribution::Binomial { n: 50; p: 10% } |
位置字段 | Uniform [0; 10] 或 Distribution::Uniform [0; 10] |
没有字段 | StandardNormal 或 Distribution::StandardNormal |
目的
目标是设计一种文本格式,以满足以下要求。同时,也考虑了现有格式如何满足这些要求。最重要的要求是 1、2、6、7、8 和 10,而 9 的要求较低。设计这个新格式的首要原因确实是缺乏满足要求 6 和 10 的格式。请注意,某些要求可能是主观的。
目标 | JSON | XML&HTML | YAML | TOML |
---|---|---|---|---|
1 格式是可读的。假设遵循最佳格式化实践,该格式应易于阅读和理解。 | ✔️ | ✔️ | ✔️ | ✔️ |
2 格式是可写的。在这里,不考虑写作的便利性或方便性。 | ✔️️ | ✔️ | ✔️ | ✔️ |
3 格式简单。特殊案例很少。简单格式的优点是它更容易解析。 | ✔️ | ✔️ 有时会对是否将数据编码为标签或属性存在一些小的困惑。 | ❌ YAML 复杂。有许多特殊案例,并且某些值可能会产生令人惊讶的结果。 | ✔️ |
4 格式简洁,包含最少的语法噪音。 | ➖ JSON 简洁,但并不最小化语法噪音。即使在没有歧义的情况下,它也要求在键周围使用引号。 | ❌ XML 不最小化语法噪音。它非常冗长。 | ✔️ | ✔️ |
5 格式有注释。 | ❌ | ✔️ | ✔️ | ✔️ |
6 格式可以原生地表达结构和非结构化数据,例如
|
❌ JSON 不支持标记,并且关于如何表示求和类型并不完全清楚。 | ➖️ XML 可以通过其灵活性表示这些结构,但它没有原生支持序列和字典。然而,显然可以如何建模它们。 | ❌ YAML 不支持标记,并且关于如何表示求和类型并不完全清楚。 | ❌ TOML不支持标记,而且表示联合类型的方式并不完全明确。 |
7 该格式适合用于标记。 | ❌ | ✔️ | ❌ | ❌ |
8 该格式适合用于配置。 | ➖️ JSON可以用于配置,但它缺少注释,这是一个很大的缺点。 | ➖️ XML可以用于配置,但其冗长使其作为通用配置格式不太方便。 | ✔️ | ✔️ |
9 该格式适用于序列化、数据存储和数据交换。 | ✔️ | ✔️ | ➖️ YAML可以用于序列化,但不是最佳选择。 | ❌ TOML不适合用于序列化。 |
10 该格式适合手动编码。它非常适合作为源格式。它可以方便地编码结构化数据和标记。 | ➖️️ JSON易于手动编码,但它的注释缺失使其作为源格式不太实用。 | ❌️ XML由于其冗长不适合作为源格式。 | ✔️ 在大多数情况下,YAML易于手动编码,但当YAML文档变得很大或复杂时,它们可能很难管理,尤其是在空格缩进的情况下。 | ✔️ |
设计
以下是在设计过程中做出的部分决策。这些决策背后的原因可能具有主观性。
空格等价性
空格等价性使用户可以按照自己的喜好格式化文档。对于简单的表达式,这种灵活性是不必要的,但对于跨越多行的复杂表达式,这种灵活性是受欢迎的。
空格缩进
空格缩进简单且在表达式跨越单行时表现良好。在许多使用空格缩进的格式和语言中,这种情况占大多数。然而,当表达式需要跨越多行时,空格缩进需要复杂的规则,这些规则对用户来说感觉像是特殊情况。跟踪空格和缩进级别也增加了解析器的复杂性。因此,决定坚持使用括号分隔的作用域。
参数变体
观察现代编程语言和普遍使用的格式,如JSON、XML和LaTeX,以下结构被普遍使用:数字、文本、结构/产品类型、枚举/联合类型、字典、序列以及由文本和命令/标签组成的标记。
实现的参数变体能够以简洁方便的语法原生地支持这些结构。
元格式
采用了XML方法,即文档的语义(如包含表达式的类型)必须在外部定义。用户必须通过使用模式、编写文档或在一个程序中实现序列化/反序列化过程来定义语义。
采取这种方法仅仅是因为它给格式实现者提供了很大的灵活性。此外,通常文档不是盲目地读取。用户或程序已经对编码表达式的类型有所预期。因此,没有必要添加语法类型表达式。