我正在编写SVG解析器,主要是作为学习如何使用Parsec的练习。目前我使用以下数据类型来表示我的SVG文件:
data SVG = Element String [Attribute] [SVG]
| SelfClosingTag [Attribute]
| Body String
| Comment String
| XMLDecl String
这很有效,但我不确定数据类型的Element String [Attribute] [SVG]
部分。
由于SVG的潜在tags数量有限,我考虑使用类型来表示SVG元素而不是使用String。像这样:
data SVG = Element TagName [Attribute] [SVG]
| ...
data TagName = A
| AltGlyph
| AltGlyphDef
...
| View
| Vkern
这是个好主意吗?如果有的话,这样做有什么好处? 有更优雅的解决方案吗?
答案 0 :(得分:4)
我个人更喜欢枚举所有可能TagName
的方法。这样,如果你犯了任何粗心的错误,编译器会给你错误和警告。例如,如果我想编写一个涵盖每种可能类型的Element
的函数,那么如果在ADT中枚举每个类型,编译器可以为您提供非详尽的匹配警告。如果将其表示为字符串,则无法实现。另外,如果我想匹配特定类型的Element
,并且我不小心拼错TagName
,编译器将捕获它。第三个原因,这可能并不适用于此,但值得注意的是,如果我后来决定添加或删除TagName
的变体,那么编译器会告诉我每个需要的地方改性。我怀疑SVG标签名称会发生这种情况,但总的来说,这是值得记住的。
答案 1 :(得分:4)
回答您的问题:
您可以采用这种方式执行此操作,具体取决于您在解析树之后要执行的操作。
如果您只关心SVG解析器是描述SGV数据的形状,那么您只需要一个字符串。
另一方面,如果你想以某种方式将SVG数据转换为类似图形的东西(你预期会评估你的AST),你会发现最好在类型系统中表示所有语义信息。它将使下一步更容易。
我心中的问题是解析通道是否恰好是实现这一目标的地方。 (完全披露,我对SVG只是熟悉了。)我怀疑只有一个平坦的标签列表,你最好用Element
各自拥有它自己的必需和可选属性集。如果此转换“在程序中稍后发生”,则无需创建TagName
数据类型。您可以在将属性合并到Element
s。
另一方面,可以做一个很好的论证直接解析成一个完整的Element树,在这种情况下,我会删除[Attribute]
的通用[SVG]
和Element
字段构造函数,而是在TagName
构造函数中创建适当的字段。
您没有问过的问题的另一个答案:
尽早将源代码位置放入您的解析树中。从个人经历来看,我可以告诉你,你的程序越大越难。