讽刺:如何禁止两个标记之间有空格?

发布于 2024-10-18 05:46:49 字数 1607 浏览 4 评论 0原文

我正在尝试在 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

清旖 2024-10-25 05:46:49

对我来说,很明显,当前不支持您想要的内容(在来源中检查)。请参阅关于 pascal 字符(最底部)的讨论,该字符被标识为“#number” ' 之间不允许有空格。

我认为使用非终端并不是一种方法。语法的本质是在标记之间可以有空格。因此,您真正需要的是遵循 项目 wiki 上给出的建议 -页面底部的自定义终端部分,并扩展终端类以满足您的需求。

或者最简单的选择是引入可以强制使用前缀的标志。扩展 IdentifierTerminal 类并重写 TryMatch 方法。

如果您在 CompoundTerminalBase 类中查看此方法,TryMatch 方法的作用基本上是:

  1. ReadPrefix(但更不用说忽略是否找到前缀)
  2. ReadBody(如果找到则失败)正文未读取)
  3. ReadSuffix

如果找到前缀,则 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 overriding TryMatch method.

If you look on this method in CompoundTerminalBase class what the TryMatch method does is basically:

  1. ReadPrefix (but more less ignore if the prefix was found or not)
  2. ReadBody (fails if the body wasn't read)
  3. ReadSuffix

The ReadPrefix method sets a details.Prefix flag if a prefix is found. So after calling ReadPrefix you may want to check your newly introduced flag for mandatory prefix and if it is set you can check if the details.Prefix flag is set as well, otherwise you emit an error.

Good luck :)

黄昏下泛黄的笔记 2024-10-25 05:46:49

我不知道您使用的是哪个版本的 Irony,但是在当前版本中,我能够使用 AllFirstChars 来实现该功能:

        var localVariable = new IdentifierTerminal(NodeType.LocalVariable);
        localVariable.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:

        var localVariable = new IdentifierTerminal(NodeType.LocalVariable);
        localVariable.AllFirstChars = "$";

Hope this helps

夜光 2024-10-25 05:46:49

不确定这是否有帮助:

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])

我认为您不会以完全相同的方式使用它们,但可能会类似。

Not sure if this one might help:

http://irony.codeplex.com/discussions/70460

So, sharing it for the 2 lines:

  var identifier = new IdentifierTerminal("Identifier", IdFlags.NameIncludesPrefix);
  identifier.AddPrefix(Strings.AllLatinLetters, IdFlags.None);   //[a-zA-Z]([a-zA-Z0-9])

I think you won't be using them in the same way exactly, but maybe something similar.

追星践月 2024-10-25 05:46:49
var identifier = new IdentifierTerminal("identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix("$", IdFlags.None);

应该可以解决问题。

var identifier = new IdentifierTerminal("identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix("$", IdFlags.None);

should do the trick.

如果没有 2024-10-25 05:46:49

我同意 Jan 的观点,这应该在扫描器中处理,而不是在解析器中处理。

在 extraFirstChars 中包含“$”是否符合您的要求?

public IdentifierTerminal(string name, string extraChars, string 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?

public IdentifierTerminal(string name, string extraChars, string extraFirstChars)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文