我正在设计和实现脚本语言,在“阅读”阶段,我采用经过时间考验的直接方法将代码分解为标记(词法分析),然后使用基于堆栈的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 / submlime text 2语法定义,我所要做的就是(使用实际格式的简化版本)
<syntax>
<color>
string_color
</color>
<pattern>
"[^"]*"
</pattern>
</syntax>
<syntax>
<color>
comment_color
</color>
<pattern>
~.*
</pattern>
</syntax>
当我编写示例代码时,一切正常。当我试图模仿我想象的文本编辑器的行为时,我遇到了上面提到的问题。如何解决这个问题,最好以最优雅的方式解决?显然,可以添加特殊处理,在完成任何词法分析之前从源代码中删除所有注释,除了字符串内的注释(这需要读者(在这种情况下读者是机器,而不是人)来检测哪些部分代码是字符串两次),但我确信必须有更好的方法,因为sublime文本只知道用于指定两种代码区域的正则表达式,并且只有该信息的行为完全符合预期。
答案 0 :(得分:1)
我建议您放弃标记,然后使用一个正则表达式在一次传递中对代码进行标记,而不是在对代码进行标记之前首先对其进行标记,并使用多个传递来进行标记。
如果构建一个包含子模式以匹配和捕获每个标记的无包容正则表达式,则可以全局匹配并通过检查捕获组内容来确定标记类型。
在简单示例中,如果您有正则表达式,例如
"([^"]*)"|~([^\n]*)|(\d+(?:.\d+)?)
匹配字符串,注释或数字,然后如果匹配字符串,则第一个捕获组()
将包含它,并且所有其他捕获组将为空。
因此,在for each
循环(D Language Regular expressons)中,您将使用条件语句和匹配对象的捕获组内容来确定要添加的下一个标记。
并且您不一定只需要使用一个大型正则表达式,您可以在一个捕获组中匹配多个令牌类型,然后在for each
块内应用另一个正则表达式(或indexOf
等。 )在捕获组内容上确定令牌。