【问题标题】:Should lexer distinguish different types of string tokens?词法分析器应该区分不同类型的字符串标记吗?
【发布时间】:2019-05-07 07:36:12
【问题描述】:

我正在编写一种可以转译为 html 的类似玉器的语言。下面是标签定义的样子:

section #mainWrapper .container

这转换为:

<section id="mainWrapper" class="container">

词法分析器应该区分 class 和 id 还是应该只吐出带有名称的特殊字符?

换句话说,令牌数组应该是这样的:

[
    {type: 'tag', value: 'section'},
    {type: 'id', value: 'mainWrapper'},
    {type: 'class', value: 'container'}
]

然后解析器只是将它们组装成一棵树

或者词法分析器应该非常原始并且只返回匹配的字符串,然后解析器负责区分它们?:

[
    {type: 'name', value: 'section'},
    {type: 'name', value: '#mainWrapper'},
    {type: 'name', value: '.container'}
]

【问题讨论】:

    标签: html parsing token lexer transpiler


    【解决方案1】:

    根据经验,分词器不应该解析,解析器也不应该分词。

    在这个具体的案例中,在我看来,每次使用类似名称的令牌(例如section)都不太可能必然是tagsection 更有可能是一个标签,因为它的语法上下文。如果分词器尝试将其标记为tag,则分词器正在跟踪句法上下文,这意味着它正在解析。

    符号.# 不太明确。您可以将它们视为单字符标记(语法将坚持在其后跟一个名称),或者您可以将它们视为特殊类型字符串的第一个字符。有些事情可能会左右你:

    • 可以用空格将印记与以下名称分开吗? (# mainWrapper)。如果是这样,印记可能是一个令牌。

    • 类或 id 的词法形式是否与名称不同?例如,考虑使用特殊字符。如果您在不知道它之前有什么印记(如果有)的情况下无法准确识别该物体,那么最好将其视为单个标记。

    • 还有其他方法可以表示class 名称。例如,您如何表示多个类?我想到了一些可能性:

      #classA #classB
      #(classA classB)
      #"classA classB"
      class = "classA classB"
      

      如果除第一个选项之外的任何选项都有效,您可能应该只将# 设为令牌。但是正确处理引用的字符串可能会产生其他挑战。特别是,它可能需要重新标记字符串文字的内容,这将违反解析器不应标记的启发式。幸运的是,这些不是绝对规则。有时需要重新标记。但请尽量减少。

    词法分析和句法分析的分离不应该是束手无策的。这是一种代码组织技术,旨在使各个部分更易于编写、理解、调试和记录。通常(但不总是)这种分离使您的语言的用户更容易理解语法,这也很重要。但它并不适合每一个解析任务,精确的边界是灵活的(但不是多孔的:你可以把边界放在最方便的地方,但一旦放置,不要试图把东西从裂缝里塞进去。)

    如果您发现这种关注点分离对您的项目来说太难了,您应该重新考虑您的语言设计或尝试无扫描仪解析。

    【讨论】:

    • 谢谢,我会坚持将印记和字符串视为一个名称。因此,如果我对您的理解正确,给定 param=value 对,我应该将 paramvalue 视为名称,将 = 视为特殊字符标记,对吧?中间可能有空格
    • @mateusz:是的,基本上。我希望属性值(数字、列表、带引号的字符串,甚至可能是表达式)还有其他可能性,但理想情况下,标记器可以只生成标记并让解析器弄清楚。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-14
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多