【发布时间】:2014-11-07 06:43:50
【问题描述】:
我正在尝试编写 VBA 解析器;为了创建ConstantNode,我需要能够匹配Const 声明的所有可能变体。
这些效果很好:
Const foo = 123Const foo$ = "123"Const foo As String = "123"Private Const foo = 123Public Const foo As Integer = 123Global Const foo% = 123
但我有两个问题:
-
如果声明末尾有注释,我会将其作为价值的一部分:
Const foo = 123 'this comment is included as part of the value -
如果在同一条指令中声明了两个或多个常量,我将无法匹配整个指令:
Const foo = 123, bar = 456
这是我正在使用的正则表达式:
/// <summary>
/// Gets a regular expression pattern for matching a constant declaration.
/// </summary>
/// <remarks>
/// Constants declared in class modules may only be <c>Private</c>.
/// Constants declared at procedure scope cannot have an access modifier.
/// </remarks>
public static string GetConstantDeclarationSyntax()
{
return @"^((Private|Public|Global)\s)?Const\s(?<identifier>[a-zA-Z][a-zA-Z0-9_]*)(?<specifier>[%&@!#$])?(?<as>\sAs\s(?<reference>(((?<library>[a-zA-Z][a-zA-Z0-9_]*))\.)?(?<identifier>[a-zA-Z][a-zA-Z0-9_]*)))?\s\=\s(?<value>.*)$";
}
显然这两个问题都是由 (?<value>.*)$ 部分引起的,它匹配 anything 直到行尾。我得到VariableNode 来支持一条指令中的多个声明,方法是将整个模式包含在一个捕获组中并添加一个可选的逗号,但是因为常量有这个value 组,这样做会导致第一个常量将所有以下声明捕获为它的部分价值......这让我回到了问题 #1。
我想知道是否有可能使用正则表达式解决问题 #1,因为该值可能是一个包含撇号的字符串,并且可能是一些转义(双引号)双引号。
我想我可以在ConstantNode 类本身,在Value 的getter 中解决它:
/// <summary>
/// Gets the constant's value. Strings include delimiting quotes.
/// </summary>
public string Value
{
get
{
return RegexMatch.Groups["value"].Value;
}
}
我的意思是,我可以在这里实现一些额外的逻辑,来做我不能用正则表达式做的事情。
如果问题 #1 可以用正则表达式解决,那么我相信问题 #2 也可以解决......还是我在正确的轨道上?我应该放弃[相当复杂的]正则表达式模式并考虑另一种方式吗?我对 greedy subexpressions、backreferences 和其他更高级的正则表达式功能不太熟悉 - 这是否限制了我,或者只是我使用了错误的锤子这个钉子?
注意:模式可能与非法语法匹配并不重要 - 此代码只会针对可编译的 VBA 代码运行。
【问题讨论】:
-
你没有用错钉子的锤子.....你没有钉子,你有螺丝;-)
-
@rolfl 所以...那我搞砸了?
-
我要在这里冒个险,说解析可能应该用解析器来完成;) 解析 VBA 是一个有趣的想法……您可以添加对宏等预处理的支持或添加语法扩展以支持更简单的错误处理,甚至在 VBA 之上创建更简单的语言(就像咖啡脚本之于 javascript)!
-
@Blackhawk 我非常愿意使用经过测试且已经有效的解决方案!您是否知道任何易于使用、免费/开源的 VBA 解析器,可以生成 C# 代码可以使用的语法树?
-
@retailcoder 我没有 :(