我正试图在Irony中定义PHP样式的变量,如下所示:
variable.Rule = "$" + identifier;
效果很好,但允许您在$
和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
标识符终端用于说
语法错误,预期:{real string $ true false ...
但变量给了我这个错误:
无效字符:'c'
我认为前一个错误更有用。我真的不明白为什么它会吐出一个不同的错误......我怎么能这样说呢?
答案 0 :(得分:6)
对我来说,看起来很清楚,目前不支持你想要的东西(在消息来源中查看)。请参阅关于pascal character(非常botoom)的讨论,该讨论被标识为'#number',不允许空格。
与非终端合作不是我相信的方式。语法本质上是你可以在令牌之间有空格。因此,您真正需要的是遵循页面底部project wiki - 自定义终端部分提供的建议,并扩展终端类以满足您的需求。
或者最简单的选择是引入可以强制使用前缀的标志。扩展IdentifierTerminal
类并覆盖TryMatch
方法。
如果您在CompoundTerminalBase
课程中查看此方法,TryMatch
方法的作用基本上是:
如果找到前缀,ReadPrefix
方法会设置details.Prefix
标志。因此,在调用ReadPrefix
之后,您可能需要检查新引入的标志是否有强制性前缀,如果已设置,您可以检查是否也设置了details.Prefix
标志,否则您将发出错误。
答案 1 :(得分:3)
我不知道你使用的是哪个版本的反讽,但是使用当前版本,我能够使用AllFirstChars来实现这一点:
var localVariable = new IdentifierTerminal(NodeType.LocalVariable);
localVariable.AllFirstChars = "$";
希望这有帮助
答案 2 :(得分:1)
不确定这个是否有帮助:
http://irony.codeplex.com/discussions/70460
所以,分享两行:
var identifier = new IdentifierTerminal("Identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix(Strings.AllLatinLetters, IdFlags.None); //[a-zA-Z]([a-zA-Z0-9])
我认为你不会以完全相同的方式使用它们,但也许类似的东西。
答案 3 :(得分:0)
var identifier = new IdentifierTerminal("identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix("$", IdFlags.None);
应该这样做。
答案 4 :(得分:0)
我同意Jan的说法,这应该在扫描仪中处理,而不是在解析器中处理。
包括&#39; $&#39;在extraFirstChars做你想要的吗?
public IdentifierTerminal(string name, string extraChars, string extraFirstChars)