3

我正在设计和实现一种脚本语言,在“阅读”阶段,我采用了久经考验且直接的方法,将代码拆分为标记(词法分析),然后使用基于堆栈的 AST 生成器进行压缩令牌流之外的句法结构(解析)。但是,我遇到了字符串、注释以及它们如何交互的问题。

(作为参考,我的语言中的代码~用于开始评论)

这可能是错误的方法,但我正在使用正则表达式执行词法分析步骤。对于n各种标记,我n在我的代码上运行标记化传递,每次传递都查找与给定正则表达式匹配的子字符串并“标记”它们,直到最终标记每个字符。每个正则表达式都会忽略已标记的源代码部分中的匹配项,只标记无人认领的土地。这很有用,因为您不希望,例如,一个number令牌渗入像translate3d.

我遇到的问题是嵌入在字符串中的注释和嵌入在注释中的字符串。我不知道如何同时使这个

"The ~ is my favorite character!  It's so happy-looking!"

被标记为一个字符串,并有这个

~ "handles" the Exception (just logs it to a file nobody ever reads and moves on)

被标记为评论。似乎无论哪种方式,您都必须对词法分析的传递进行一些排序,并且注释或字符串传递将“获胜”并标记它没有业务标记的子字符串。例如,字符串被标记如下:(我使用 XML 表示法,因为它是表示文本标记区域的好方法。XML 在任何时候实际上都没有在我的程序中使用)

"The <comment>~ is my favorite character!  It's so happy-looking!"</comment>

或评论标记如下:

<comment>~ </comment><string>"handles"</string>the Exception (just logs it to a file and moves on)

假设一个字符串从注释的中间开始,或者一个注释从一个字符串的中间开始。

奇怪的是,这个正则表达式系统似乎传递标记子字符串正是文本编辑器上的语法突出显示所做的,并且注释和字符串在那里工作正常。我已经为我的语言开发了 textmate/submlimime text 2 语法定义,我所要做的就是(在所用实际格式的简化版本中)

<syntax>
    <color>
        string_color
    </color>
    <pattern>
        "[^"]*"
    </pattern>
</syntax>
<syntax>
    <color>
        comment_color
    </color>
    <pattern>
        ~.*
    </pattern>
</syntax>

当我编写示例代码时,一切正常。然而,当我试图模仿我想象的文本编辑器的行为时,我遇到了上面提到的问题。如何解决这个问题,最好以最优雅的方式解决?显然,可以添加特殊处理,在进行任何词法分析之前从源代码中删除所有注释,字符串中的注释除外(这需要阅读器(在这种情况下,阅读器是机器,而不是人类)检测哪些部分的代码是字符串两次),但我相信一定有更好的方法,仅仅是因为崇高的文本只知道用于指定两种代码区域的正则表达式,并且只有这些信息它的行为完全符合预期.

4

1 回答 1

2

我建议您放弃标记,只使用一个正则表达式一次性标记代码,而不是在标记源代码之前先标记它,然后使用多次传递来这样做。

如果您构建一个包罗万象的正则表达式,其中包含用于匹配和捕获每个标记的子模式,那么您可以全局匹配并通过检查捕获组内容来确定标记类型。

在简单的示例中,如果您有一个正则表达式,例如

"([^"]*)"|~([^\n]*)|(\d+(?:.\d+)?)

要匹配字符串、注释或数字,则如果匹配字符串,则第一个捕获组()将包含它,而所有其他捕获组将为空。

因此,在您的for each循环(D 语言正则表达式)中,您将使用条件语句和匹配对象的捕获组内容来确定要添加的下一个标记。

而且您不必只使用一个大的正则表达式,您可以在一个捕获组中匹配多个令牌类型,然后在for each块内对捕获组内容应用进一步的正则表达式(或indexOf等)以确定令牌。

于 2013-04-15T23:08:08.713 回答