7

我正在尝试在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 中的解析方式有点奇怪......

无论如何,问题在于当我使用 this 时VariableTerminal,而不是我之前使用 with"$" + IdentifierTerminal"时的做法,当出现语法错误时,例如在这段代码中:

p cat

标识符终端曾经说过

语法错误,预期:{ 真正的字符串 $ 真假 ...

但是变量给了我这个错误:

无效字符:'c'

我认为前一个错误更有用。我真的不明白为什么它会吐出一个不同的错误......我怎样才能让它这么说呢?

4

5 回答 5

6

对我来说,很明显你想要的东西目前不受支持(在源代码中检查)。另请参阅关于帕斯卡字符(非常底部)的讨论,该字符被标识为“#number”,不允许有空格。

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

或者最简单的选择是引入可以强制前缀的标志。扩展IdentifierTerminal类和覆盖TryMatch方法。

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

  1. ReadPrefix(但如果找到前缀,则忽略更多)
  2. ReadBody(如果没有读取正文则失败)
  3. 读后缀

如果找到前缀,该ReadPrefix方法设置一个标志。details.Prefix因此,在调用之后,ReadPrefix您可能需要检查新引入的标志是否有强制前缀,如果已设置,您可以检查details.Prefix标志是否也已设置,否则会发出错误。

祝你好运 :)

于 2011-03-17T13:10:23.547 回答
3

我不知道您使用的是哪个版本的 Irony,但在当前版本中,我能够使用 AllFirstChars 使其正常工作:

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

希望这可以帮助

于 2011-11-28T15:51:11.827 回答
1

不确定这个是否有帮助:

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

因此,将其共享为 2 行:

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

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

于 2011-02-21T02:29:41.517 回答
0
var identifier = new IdentifierTerminal("identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix("$", IdFlags.None);

应该做的伎俩。

于 2011-03-17T13:12:04.240 回答
0

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

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

public IdentifierTerminal(string name, string extraChars, string extraFirstChars)
于 2011-03-18T19:18:53.483 回答