Ирония: Как запретить пространство между 2 жетонами? - PullRequest
6 голосов
/ 21 февраля 2011

Я пытаюсь определить переменные в стиле PHP в Ирония примерно так:

variable.Rule = "$" + identifier;

Прекрасно работает, за исключением того, что вы можете ставить пробелы между $и identifier.Я хочу предотвратить это.Как?

Нужно ли создавать новый настраиваемый терминал?Если да, смогу ли я воспользоваться магией IdentifierTerminal?


Копаться в IdentifierTerminal Я вижу, что на самом деле есть флаг для "NameIncludePrefix", но он используется только в одномместо.Похоже, префикс хранится в этом 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 ..Я предполагаю, что это какое-то динамическое свойство, основанное на текущей позиции предварительного просмотра?То, как в Иронии выполняется синтаксический анализ, кажется немного странным ...

В любом случае, проблема в том, что когда я использую этот VariableTerminal вместо того, как я делал это раньше с "$" + IdentifierTerminal", когда есть синтаксическая ошибка, такая как в этом коде:

p cat

Терминал идентификатора имел обыкновение говорить

Синтаксическая ошибка, ожидаемая: {настоящая строка $ true false ...

Но переменная выдаёт мне эту ошибку вместо:

Недопустимый символ: 'c'

Предыдущая ошибка была более полезной. Iсчитать.Я не очень понимаю, почему он выдает другую ошибку ... как я могу заставить его сказать это вместо этого?

Ответы [ 5 ]

6 голосов
/ 17 марта 2011

для меня ясно, что то, что вы хотите, в настоящее время не поддерживается (проверено в источниках). См. Также обсуждение символа паскаля (само обозначение), которое обозначено как «#number», не допускающее пробела между.

Я не верю, чтобы работать с нетерминалом. Грамматика по своей природе работает так, что между токенами могут быть пробелы. Так что вам действительно нужно следовать советам, данным в проекте вики - раздел Пользовательские терминалы в нижней части страницы, и расширять класс Terminal в соответствии со своими потребностями.

Или самый простой вариант - ввести флаг, который может сделать префикс обязательным. Расширение класса IdentifierTerminal и переопределение метода TryMatch.

Если вы посмотрите на этот метод в классе CompoundTerminalBase, то, что делает метод TryMatch, в основном:

  1. ReadPrefix (но более менее игнорировать, если префикс был найден или нет)
  2. ReadBody (происходит сбой, если тело не было прочитано)
  3. ReadSuffix

Метод ReadPrefix устанавливает флаг details.Prefix, если префикс найден. Поэтому после вызова ReadPrefix вы можете захотеть проверить свой введенный флаг на обязательный префикс, и если он установлен, вы можете проверить, установлен ли также флаг details.Prefix, в противном случае вы выдаете ошибку.

Удачи:)

3 голосов
/ 28 ноября 2011

Я не знаю, какую версию Irony вы используете, но с текущей версией я смог заставить ее работать, используя AllFirstChars:

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

Надеюсь, это поможет

1 голос
/ 21 февраля 2011

Не уверен, может ли это помочь:

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

Я думаю, вы не будете использовать их точно так же, но, возможно, что-то похожее.

0 голосов
/ 18 марта 2011

Я согласен с Яном, что это следует обрабатывать в сканере, а не в синтаксическом анализаторе.

Делает ли включение $ в extraFirstChars то, что вы хотите?

public IdentifierTerminal(string name, string extraChars, string extraFirstChars)
0 голосов
/ 17 марта 2011
var identifier = new IdentifierTerminal("identifier", IdFlags.NameIncludesPrefix);
identifier.AddPrefix("$", IdFlags.None);

должен сделать трюк.

...