Управление парсером Stack во время грамматики с действиями

Это второй вопрос, связанный с пользовательскими объектами в действиях ParseKit.

Если бы у меня было правило грамматики, например:

qualifiedTableName  = (databaseName '.')? tableName (('INDEXED' 'BY' indexName) | ('NOT' 'INDEXED'))?;

Правильно ли предположить, что действие не будет вызываться до тех пор, пока не будет найдено правило? Так что в этом случае, когда действие вызывается в стек, может выглядеть так:

possibly:
|'INDEXED'
|'NOT'
or:
|indexName (A custom object possibly)
|'BY'
|'INDEXED

|tableName (for sure will be here)

and possibly these
|'.'            (if this is here I know the database name must be here) if not push last one on?
|databaseName
--------------(perhaps more things from other rules)

Это правильные оценки? Есть ли другая документация о действиях? Я знаю, что это в значительной степени основано на Antlr, но это тонкие различия, которые могут действительно поставить вас в беду.

1 ответ

Решение

Создатель PEGKit здесь.

Действия выполняются сразу после сопоставления предыдущего токена.

Предположим, что этот вход:

mydb.mytable INDEXED BY 'foo'

В вашем примере правило не содержит никаких действий, поэтому я добавлю некоторые. На самом деле гораздо проще добавлять действия, если вы разбиваете свое правило на более мелкие подправила:

qualifiedTableName = name indexOpt
{
    // now stack contains 3 `NSString`s. 
    // ["mydb", "mytable", "foo"]
    NSString *indexName = POP();
    NSString *tableName = POP();
    NSString *dbName = POP();
    // do stuff here
};

databaseName = Word;
tableName = Word;
indexName = QuotedString;

name = (databaseName '.'!)? tableName 
{
    // now stack contains 2 `PKToken`s of type Word
    // [<Word «mydb»>, <Word «mytable»>]
    // pop their string values
    NSString *tableName = POP_STR();
    NSString *dbName = POP_STR();
    PUSH(dbName);
    PUSH(tableName);
};

indexOpt
    = index
    | Empty { PUSH(@""); }
    ;

index
    = ('INDEXED'! 'BY'! indexName)
    { 
        // now top of stack will be a Quoted String `PKToken`
        // […, <Quoted String «"foo"»>]
        // pop its string value
        NSString *indexName = POP_STR();
        // trim quotes
        indexName = [indexName substringWithRange:NSMakeRange(1, [indexName length]-2)];
        // leave it on the stack for later
        PUSH(indexName);
    }
    | ('NOT'! 'INDEXED'!) { PUSH(@""); }
    ;

Обратите внимание, что я отбрасываю все буквальные токены, используя ! директива об отказе Эти литералы являются чистым синтаксисом и не нужны в ваших действиях для дальнейшей обработки.

Также обратите внимание, что в случае несуществующего INDEXED BY выражение или NOT INDEXED выражение, я помещаю пустую строку в стек. Это сделано для того, чтобы вы могли равномерно обрабатывать указанный индекс в qualifiedTableName Действие. В этом действии у вас всегда будет строка в верхней части стека, которая указывает индекс. Если это пустая строка, то индекс отсутствует.

Другие вопросы по тегам