variable.Rule = "$" + identifier;
工作得很好,除了你被允许在$和标识符之间放置空格.我想防止这种情况.怎么样?
我是否必须创建一个新的定制终端?如果是这样,我还能利用IdentifierTerminal魔法吗?
在IdentifierTerminal中挖掘我看到实际上有一个“NameIncludesPrefix”的标志,但它只在一个地方使用.看起来前缀存储在这个CompoundTokenDetails对象中……我不知道如何使用它.编辑:没关系,这是一个死胡同.这些标志用于为变量的行为添加修饰符.
这有点……
class VariableTerminal : Terminal { public VariableTerminal(string name) : base(name) { } public override IList<string> GetFirsts() { return new[] { "$" }; } public override Token TryMatch(ParsingContext context,ISourceStream source) { if (source.PreviewChar != '$') return null; do { source.PreviewPosition++; } while (!source.EOF() && char.IsLetter(source.PreviewChar)); var token = source.CreateToken(OutputTerminal); return token; } }
我不太确定OuputTerminal是什么..我猜这是基于当前预览位置的某种动态属性?解析在Irony中完成的方式我认为有点奇怪……
无论如何,当我使用这个VariableTerminal而不是我之前使用“$”IdentifierTerminal“时,当出现语法错误时,例如在此代码中:
p cat
标识符终端用来说
Syntax error,expected: { real string $true false …
但变量给了我这个错误:
Invalid character: ‘c’
解决方法
与非终端一起去并不是我相信的方式.语法本质上是你可以在令牌之间有空格.因此,您真正需要的是遵循project wiki上给出的建议 – 页面底部的自定义终端部分,并扩展终端类以满足您的需求.
或者最简单的选择是引入可以使前缀成为必需的标志.扩展IdentifierTerminal类并重写TryMatch方法.
如果你在CompoundTerminalBase类中查看这个方法,TryMatch方法的作用基本上是:
> ReadPrefix(但如果找到前缀,则更少忽略)
> ReadBody(如果未读取正文,则会失败)
> ReadSuffix
如果找到前缀,则ReadPrefix方法设置details.Prefix标志.因此,在调用ReadPrefix之后,您可能需要检查新引入的标志是否为强制性前缀,如果已设置,您可以检查是否设置了details.Prefix标志,否则您将发出错误.
祝好运 :)