Parsing PEGKit组合堆栈上的匹配符号

Parsing PEGKit组合堆栈上的匹配符号,parsing,pegkit,Parsing,Pegkit,我正在为PEGKit编写语法来解析一个Twee文件。这是我第一次使用PEGKit,我正在努力掌握它的工作原理 我有一个我正在解析的twee源文件 :: Passage One P1 Line One P1 Line Two :: Passage Two P2 Line One P2 Line Two 目前,我已经解决了如何使用以下语法解析上述内容 @before { PKTokenizer *t = self.tokenizer; [t.symbolState add:@":

我正在为PEGKit编写语法来解析一个Twee文件。这是我第一次使用PEGKit,我正在努力掌握它的工作原理

我有一个我正在解析的twee源文件

:: Passage One
P1 Line One
P1 Line Two

:: Passage Two
P2 Line One
P2 Line Two
目前,我已经解决了如何使用以下语法解析上述内容

@before {
    PKTokenizer *t = self.tokenizer;
    [t.symbolState add:@"::"];
    [t.commentState addSingleLineStartMarker:@"::"];

    // New lines as symbols
    [t.whitespaceState setWhitespaceChars:NO from:'\n' to:'\n'];
    [t.whitespaceState setWhitespaceChars:NO from:'\r' to:'\r'];
    [t setTokenizerState:t.symbolState from:'\n' to:'\n'];
    [t setTokenizerState:t.symbolState from:'\r' to:'\r'];
}

start                   = passage+;
passage                 = passageTitle contentLine*;
passageTitle            = passageStart Word+ eol+;
contentLine             = singleLine eol+;
singleLine              = Word+;
passageStart            = '::'!;
eol                     = '\n'! | '\r'!;
我得到的结果是

[Passage, One, P1, Line, One, P1, Line, Two, Passage, Two, P2, Line, One, P2, Line, Two]::/Passage/One/
/P1/Line/One/
/P1/Line/Two/
/
/::/Passage/Two/
/P2/Line/One/
/P2/Line/Two/
^
理想情况下,我希望解析器将与
passageTitle
匹配的单词组合成一个字符串,类似于内置的PEGKit
QuotedString
语法的工作方式。我还希望将与
内容行
匹配的单词也组合起来

所以,最终,我会把它放在堆栈上

[Passage One, P1 Line One, P1 Line Two, Passage Two, P2 Line One, P2 Line Two]
任何关于如何实现这一目标的想法都将不胜感激。

这里的创建者

我理解您的最终策略(将行收集/组合为单个字符串对象),并同意这是有意义的,但是,我不同意您提出的实现这一点的策略(改变标记化,尝试将本质上是多个单独的标记组合为单个标记)

将行组合成方便的字符串对象是有意义的,但改变标记化以实现这一点在IMO(至少对于递归下降分析工具包PEGKit)中没有意义,因为所讨论的行没有明显的“括号”字符,如引号或括号

您可以将以
::
开头的
passageTitle
行视为单行
Comment
标记,但我可能不会,因为我认为它们在语义上不是注释

因此,您不应该通过标记器合并多个标记,而应该在解析器委托回调中以更自然的方式为PEGKit:合并多个标记

我们在这里要处理两种不同的情况:

  • passageTitle
  • 内容行
  • 在您的语法中,删除这一行,这样我们就不会将
    passageTitle
    s视为
    Comment
    token(无论如何,您没有完全正确地配置它,但别介意):

    在语法中,删除
    passagetart
    规则中选择code>,以便这些令牌不会被丢弃:

    passageStart            = '::';
    
    语法就这些。现在,在解析器委托回调中,为标题行和内容行实现两种必要的回调方法。在每个回调中,从
    PKAssembly
    的堆栈中取出所有必要的标记,并将它们合并为一个字符串(相反)

    我收到以下输出:

    Title: Passage One
    Content: P1 Line One
    Content: P1 Line Two
    Title: Passage Two
    Content: P2 Line One
    Content: P2 Line Two
    
    至于创建这些字符串后如何处理它们,我将留给您:)。希望有帮助

    @interface TweeDelegate : NSObject
    @end
    
    @implementation TweeDelegate
    
    - (void)parser:(PKParser *)p didMatchPassageTitle:(PKAssembly *)a {
        NSArray *toks = [a objectsAbove:[PKToken tokenWithTokenType:PKTokenTypeSymbol stringValue:@"::" doubleValue:0.0]];
        [a pop]; // discard `::`
    
        NSMutableString *buf = [NSMutableString string];
    
        for (PKToken *tok in [toks reverseObjectEnumerator]) {
            [buf appendFormat:@"%@ ", tok.stringValue];
        }
    
        CFStringTrimWhitespace((CFMutableStringRef)buf);
    
        NSLog(@"Title: %@", buf); // Passage One
    }
    
    - (void)parser:(PKParser *)p didMatchContentLine:(PKAssembly *)a {
        NSArray *toks = [a objectsAbove:nil];
    
        NSMutableString *buf = [NSMutableString string];
    
        for (PKToken *tok in [toks reverseObjectEnumerator]) {
            [buf appendFormat:@"%@ ", tok.stringValue];
        }
    
        CFStringTrimWhitespace((CFMutableStringRef)buf);
    
        NSLog(@"Content: %@", buf); // P1 Line One
    }
    
    @end
    
    Title: Passage One
    Content: P1 Line One
    Content: P1 Line Two
    Title: Passage Two
    Content: P2 Line One
    Content: P2 Line Two