反讽:如何禁止2个代币之间的空格?

时间:2011-02-21 01:54:10

标签: c# grammar irony

我正试图在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'

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

5 个答案:

答案 0 :(得分:6)

对我来说,看起来很清楚,目前不支持你想要的东西(在消息来源中查看)。请参阅关于pascal character(非常botoom)的讨论,该讨论被标识为'#number',不允许空格。

与非终端合作不是我相信的方式。语法本质上是你可以在令牌之间有空格。因此,您真正需要的是遵循页面底部project wiki - 自定义终端部分提供的建议,并扩展终端类以满足您的需求。

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

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

  1. ReadPrefix(但如果找不到前缀则更少忽略)
  2. ReadBody(如果未读取正文则会失败)
  3. ReadSuffix
  4. 如果找到前缀,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)