讽刺:如何禁止两个标记之间有空格?
我正在尝试在 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'
我认为前一个错误更有用。我真的不明白为什么它会吐出不同的错误......我怎样才能让它这么说呢?
I'm trying to define PHP-style variables in Irony like so:
variable.Rule = "$" + identifier;
Works great, except that you're allowed to put spaces between the $
and the identifier
. I want to prevent that. How?
Do I have to create a new customized terminal? If so, will I still be able to take advantage of the IdentifierTerminal
magic?
Digging around in IdentifierTerminal
I see there's actually a flag for "NameIncludesPrefix", but it's only used in one place. Looks like the prefix is stored in this CompoundTokenDetails
object... which I'm not sure how to use. Edit: Nevermind, this was a dead-end. Those flags are for adding modifiers to how the variable behaves.
This kinda works...
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 != '
I'm not really sure what OuputTerminal
is though.. I guess it's some kind of dynamic property based on the current preview position? The way parsing is done in Irony is a little strange I think...
Anyway, the problem with this is what when I use this VariableTerminal
, instead of how I was doing it before with "$" + IdentifierTerminal"
, when there's a syntax error, such as in this code:
p cat
The identifier terminal used to say
Syntax error, expected: { real string $ true false ...
But the variable gives me this error instead:
Invalid character: 'c'
The former error was more useful I think. I don't really understand why it's spitting out a different error...how can I get it to say that instead?
) return null;
do
{
source.PreviewPosition++;
} while (!source.EOF() && char.IsLetter(source.PreviewChar));
var token = source.CreateToken(OutputTerminal);
return token;
}
}
I'm not really sure what OuputTerminal
is though.. I guess it's some kind of dynamic property based on the current preview position? The way parsing is done in Irony is a little strange I think...
Anyway, the problem with this is what when I use this VariableTerminal
, instead of how I was doing it before with "$" + IdentifierTerminal"
, when there's a syntax error, such as in this code:
The identifier terminal used to say
Syntax error, expected: { real string $ true false ...
But the variable gives me this error instead:
Invalid character: 'c'
The former error was more useful I think. I don't really understand why it's spitting out a different error...how can I get it to say that instead?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
对我来说,很明显,当前不支持您想要的内容(在来源中检查)。请参阅关于 pascal 字符(最底部)的讨论,该字符被标识为“#number” ' 之间不允许有空格。
我认为使用非终端并不是一种方法。语法的本质是在标记之间可以有空格。因此,您真正需要的是遵循 项目 wiki 上给出的建议 -页面底部的自定义终端部分,并扩展终端类以满足您的需求。
或者最简单的选择是引入可以强制使用前缀的标志。扩展
IdentifierTerminal
类并重写TryMatch
方法。如果您在
CompoundTerminalBase
类中查看此方法,TryMatch
方法的作用基本上是:如果找到前缀,则
ReadPrefix
方法会设置details.Prefix
标志。因此,在调用ReadPrefix
后,您可能需要检查新引入的标志是否有强制前缀,如果已设置,您可以检查details.Prefix
标志是否也已设置,否则你发出一个错误。祝你好运 :)
for me it looks clear that what you want is currently not supported (checked in the sources). See the discussion on the pascal character (the very botoom) as well which is identified as '#number' not allowing space between.
To go with non-terminal is not a way I believe. Grammars work by nature that you can have whitespaces between tokens. So what you really need is to follow advice given on the project wiki - section Custom Terminals on the bottom of the page and extend the Terminal class to fit your needs.
Or the easiest option would be to introduce flag which can make the prefix mandatory. Extending the
IdentifierTerminal
class and overridingTryMatch
method.If you look on this method in
CompoundTerminalBase
class what theTryMatch
method does is basically:The
ReadPrefix
method sets adetails.Prefix
flag if a prefix is found. So after callingReadPrefix
you may want to check your newly introduced flag for mandatory prefix and if it is set you can check if thedetails.Prefix
flag is set as well, otherwise you emit an error.Good luck :)
我不知道您使用的是哪个版本的 Irony,但是在当前版本中,我能够使用 AllFirstChars 来实现该功能:
希望这会有所帮助
I don't know wich version of Irony you use, but with the current version I was able to get that working using AllFirstChars:
Hope this helps
不确定这是否有帮助:
http://irony.codeplex.com/discussions/70460
因此,分享这两行:
我认为您不会以完全相同的方式使用它们,但可能会类似。
Not sure if this one might help:
http://irony.codeplex.com/discussions/70460
So, sharing it for the 2 lines:
I think you won't be using them in the same way exactly, but maybe something similar.
应该可以解决问题。
should do the trick.
我同意 Jan 的观点,这应该在扫描器中处理,而不是在解析器中处理。
在 extraFirstChars 中包含“$”是否符合您的要求?
I agree with Jan that this should be handled in the scanner, not in the parser.
Does including '$' in extraFirstChars do what you want?