2012-04-03 8 views
4

Ich fragte mich, ob es einen Weg gab, um zurückzukommen, wie weit in einer Assembly ein PKParser analysiert hat, bevor ein Syntaxfehler auftritt.Wie Parsing-Fehler mit ParseKit-Framework zu finden

Referenz: http://parsekit.com/

ich eine Grammatik bin mit, die im Grunde eine Ausdruckssprache Präfixnotation beschreibt.

Zum Beispiel:

Ihre Standard Präfixnotation Ausdruck Grammatik und ein String "(+ a - bc))" Ich möchte, dass abzurufen [(, +, a], wo abgestimmt, so dass ich kann dem Benutzer eine Idee geben, wo er nachsehen muss, um seinen Fehler zu beheben, aber das completeMatchFor und bestMatchFor geben nichts zurück, was ich verwenden kann, um diese Informationen zu finden.

Idealerweise würde ich gerne sagen, dass ein '(' war erwartet, aber es ist nicht notwendig für eine Grammatik so einfach wie das, was ich verwende ..

Aus dem Buch als Benutzerhandbuch erwähnt, schien es als wenn ich dafür einen eigenen Parser erstellen müsste, aber ich hatte gehofft, dass ich vielleicht etwas im Framework verpasst hätte.

Gedanken?

Antwort

3

Entwickler von ParseKit hier.

Es gibt zwei Funktionen in ParseKit, die verwendet werden können, um benutzerlesbare Hinweise zur Beschreibung von Syntaxfehlern zu liefern, die bei der Eingabe auftreten.

  1. -[PKParser bestMatchFor:]
  2. Die PKTrack Klasse

Es klingt wie Sie sich der -bestMatchFor: Methode sind, auch wenn es nicht tut, was Sie in diesem Fall erwarten.

Ich denke, die PKTrack Klasse wird hier hilfreicher sein. Wie in Metsker's book beschrieben, ist PKTrack genau wie PKSequence, außer dass seine Unterparser benötigt werden, und ein Fehler wird ausgelöst (mit einer hilfreichen Fehlermeldung), wenn alle Subparser nicht übereinstimmen.

hier ist also eine Grammatik für Ihr Beispiel Eingabe:

@start   = '(' expr ')' | expr; 
expr   = ('+' | '-') term term; 
term   = '(' expr ')' | Word; 

Alle aneinander angrenzend aufgeführten Produktionen sind eine Folge - aber könnte stattdessen eine Spur sein.

Der Vorteil des Änderns dieser Sequenzen in Tracks besteht darin, dass ein NSException mit einer für Menschen lesbaren Analysefehlermeldung ausgelöst wird, wenn die Eingabe nicht übereinstimmt. Der Nachteil besteht darin, dass Sie jetzt alle Verwendungen Ihres in der Factory generierten Parsers in einen try/catch-Block einschließen müssen, um diese Track-Ausnahmen zu erfassen.

Das Problem zur Zeit (oder vor jetzt, zumindest) ist, dass die PKParserFactory nie einen Parser mit Tracks produziert. Stattdessen würde es immer Sequenzen verwenden.

So habe ich nur eine neue Option in Kopf des Rumpfes um Google Code hinzugefügt (Sie müssen udpate).

#define USE_TRACK 0 

in

PKParserFactory.m 

Es ist 0 standardmäßig. Wenn Sie diese Definition zu 1 ändern, werden Spuren anstelle von Sequenzen verwendet. So angesichts der Grammatik oben und ungültige Eingabe wie folgt aus:

(+ a - b c)) 

und dieser Client-Code:

NSString *g = // fetch grammar above 
PKParser *p = [[PKParserFactory factory] parserFromGrammar:g assembler:self]; 
NSString *s = @"(+ a - b c))"; 

@try { 
    PKAssembly *res = [p parse:s]; 
    NSLog(@"res %@", res); 
} 
@catch (NSException *exception) { 
    NSLog(@"Parse Error:%@", exception); 
} 

Sie einen schönen ish Menschen lesbare Fehlermeldung erhalten:

Parse Error: 

After : (+ a 
Expected : Alternation (term) 
Found : - 

Hoffnung das hilft.

3

Ich ringe auch mit diesem Problem. Damit -bestMatchFor: zur Identifizierung von Fehlerzuständen nützlich sein kann, sollten Methoden in der öffentlichen Schnittstelle PKAssembly vorhanden sein, die angeben, ob weitere Token/Zeichen analysiert werden müssen. -completeMatchFor: kann den Fehlerstatus ermitteln, da er Zugriff auf die private -hasMore-Methode hat. Vielleicht PKAssembly 's -hasMore Methode sollte öffentlich sein.

Ich schaute auf PKTrack, aber da ich programmatisch mit Fehlern umgehen will, war es nicht nützlich für mich.

Meine Schlussfolgerung ist, ich schreibe entweder meine eigenen benutzerdefinierten Track-Parser oder ich ändere das Framework und expose -hasMore. Gibt es andere Möglichkeiten, mit Fehlern umzugehen?

Bis ich einen besseren Weg finden, um Fehler zu erkennen, ich habe folgendes in die Datei enthält die Implementierung meiner benutzerdefinierten Parser hinzugefügt:

@interface PKAssembly() 
- (BOOL)hasMore; 
- (id)peek; 
@end 

@implementation PMParser 
... 
@end 

In meiner Parse-Methode:

PKAssembly*  a  = [PKTokenAssembly assemblyWithString:s]; 
PKAssembly*  best = [self bestMatchFor:a]; 
PMParseNode* node = nil; 
BOOL   error = NO; 
NSUInteger  errorOffset = 0; 

if (best == nil) // Anything recognized? 
{ 
    error = YES; 
} 
else 
{ 
    if ([best hasMore]) // Partial recognition? 
    { 
     PKToken* t = [best peek]; 

     error  = YES; 
     errorOffset = t.offset; 
    } 

    node = [best pop]; 
} 

Wenn ein Fehler aufgetreten ist, enthält errorOffset den Speicherort des nicht erkannten Tokens.