代码之家  ›  专栏  ›  技术社区  ›  John Leidegren

词法分析器歧义

  •  4
  • John Leidegren  · 技术社区  · 14 年前

    /*/*/
    

    为什么它不只是说,哦,是的,这是一个多行注释的开始,然后是另一个多行注释。

    一个贪婪的lexer会不会仅仅返回以下代币?

    • /*
    • /

    我正在为CSS编写一个shift-reduce解析器,但是这个简单的注释问题妨碍了我。你可以阅读 this question 如果你不想了解更多的背景资料。

    更新

    很抱歉一开始就漏掉了这个。我计划在这个表单中为CSS语言添加扩展 /* @ func ( args, ... ) */ 但我不想把一个理解CSS但不理解我的扩展注释的编辑器弄糊涂。这就是为什么lexer不能忽略评论。

    6 回复  |  直到 7 年前
        1
  •  9
  •   rici    7 年前

    一种方法是lexer在遇到第一个lexer时进入一个不同的内部状态 /* . 例如, flex 这叫什么 "start conditions" (匹配的C样式注释是该页上的示例之一)。

        2
  •  6
  •   Amber    14 年前

    最简单的方法可能是将注释作为一个标记来使用,也就是说,不要发出“START comment”标记,而是继续读取输入,直到可以发出一个包含整个注释的“comment BLOCK”标记 /*(anything)*/

        3
  •  3
  •   mjv    14 年前

    在大多数语言中,这并不含糊:第一个斜杠和星号是 消耗 生成“多行注释开始”标记。它后面是一个斜杠,在注释中是纯“content”,最后两个字符是“多行注释结尾”标记。

    由于使用了前2个字符,因此第一个asterix也不能用于生成注释结束标记。我注意到它可以产生第二个“评论开始”标记。。。哦,这可能是个问题,这取决于解析器可用的上下文数量。

    这里我讲的是标记,假设解析器级别处理注释。但这同样适用于lexer,其基本规则是从 '/*' 然后直到 '*/' 找到了。实际上,lexer级别对整个评论的处理不会被第二个“评论开始”混淆。

        4
  •  0
  •   Ming-Tang    14 年前

    使用regexp的算法,从字符串的开头搜索工作方式回到当前位置。

    if (chars[currentLocation] == '/' and chars[currentLocation - 1] == '*') {
      for (int i = currentLocation - 2; i >= 0; i --) {
        if (chars[i] == '/' && chars[i + 1] == '*') {
          // .......
        }
      }
    }
    

    /\*([^\*]|\*[^\/])\*/

        5
  •  0
  •   Cam    14 年前

    解决这个问题的一个方法是让你的lexer返回:

    /
    *
    /
    *
    /
    

    对于大多数编程语言 ,因为/'和*'也可以用于乘法和其他类似的事情,这对于lexer来说太复杂了。雷克瑟真的应该回来了 .

    如果令牌开始太依赖于上下文,那么您要寻找的很可能是一个更简单的令牌。

    也就是说,CSS不是一种编程语言,所以/'和*'不能重载。真的很抱歉,除了评论,它们不能用于其他任何东西。所以我很想把整件事作为一个评论标记传递出去,除非你有充分的理由不这样做: /\*.*\*/

        6
  •  0
  •   Bakuriu    9 年前

    因为CSS不支持嵌套的注释,所以您的示例通常会解析为单个标记, COMMENT . 也就是说,雷克瑟会看到 /* 作为开始注释标记,然后使用 */ 顺序。