2009-12-01 8 views
16

Ich baue einen Parser für eine imaginäre Programmiersprache namens C-- (nicht die eigentliche C - Sprache). Ich bin auf die Stufe gekommen, wo ich die Grammatik der Sprache in etwas übersetzen muss, was Pyparsing akzeptieren kann. Leider, wenn ich komme, um meine Eingabe-Zeichenfolge zu analysieren (die korrekt ist und sollte nicht verursachen, dass Pyparsing zu Fehler) wird nicht ordnungsgemäß analysiert. Ich befürchte, dass dies auf Fehler in meiner Grammatik zurückzuführen ist, aber als ich zum ersten Mal mit Pyparsing anfange, kann ich nicht erkennen, wo ich falsch liege.Debugging Pyparsing Grammatik

Ich habe die Grammatik, die ich übersetze, von here hochgeladen, damit die Leute sie lesen können.

EDIT: Mit dem Rat von Paul aktualisiert.

Dies ist grammer ich zur Zeit habe (die beiden oberen Zeilen der Syntax-Definition sind furchtbar schlecht von mir, ich weiß):

# Lexical structure definition 
ifS = Keyword('if') 
elseS = Keyword('else') 
whileS = Keyword('while') 
returnS = Keyword('return') 
intVar = Keyword('int') 
voidKeyword = Keyword('void') 
sumdiff = Literal('+') | Literal('-') 
prodquot = Literal('*') | Literal('/') 
relation = Literal('<=') | Literal('<') | Literal('==') | \ 
      Literal('!=') | Literal('>') | Literal('=>') 
lbrace = Literal('{') 
rbrace = Literal('}') 
lparn = Literal('(') 
rparn = Literal(')') 
semi = Literal(';') 
comma = Literal(',') 
number = Word(nums) 
identifier = Word(alphas, alphanums) 

# Syntax definition 
term = '' 
statement = '' 
variable = intVar + identifier + semi 
locals  = ZeroOrMore(variable) 
expr  = term | OneOrMore(Group(sumdiff + term)) 
args  = ZeroOrMore(OneOrMore(Group(expr + comma)) | expr) 
funccall = Group(identifier + lparn + args + rparn) 
factor  = Group(lparn + expr + rparn) | identifier | funccall | number 
term  = factor | OneOrMore(prodquot + factor) 
cond  = Group(lparn + expr + relation + expr + rparn) 
returnState = Group(returnS + semi) | Combine(returnS + expr + semi) 
assignment = Group(identifier + '=' + expr + semi) 
proccall = Group(identifier + lparn + args + rparn + semi) 
block  = Group(lbrace + locals + statement + rbrace) 
iteration = Group(whileS + cond + block) 
selection = Group(ifS + cond + block) | Group(ifS + cond + block + elseS + block) 
statement = OneOrMore(proccall | assignment | selection | iteration | returnState) 
param  = Group(intVar + identifier) 
paramlist = OneOrMore(Combine(param + comma)) | param 
params  = paramlist | voidKeyword 
procedure = Group(voidKeyword + identifier + lparn + params + rparn + block) 
function = Group(intVar + identifier + lparn + params + rparn + block) 
declaration = variable | function | procedure 
program  = OneOrMore(declaration) 

Ich mag gerne wissen, ob es irgendwelche Fehler sind ich Ich habe die Übersetzung der Grammatik gemacht und welche Verbesserungen ich machen könnte, um es zu vereinfachen, während ich mich an die Grammatik halte, die mir gegeben wurde.

EDIT 2: Aktualisiert, um den neuen Fehler zu enthalten. Hier

ist die Eingabezeichenfolge Ich bin Parsen:

int larger (int first , int second) { 
if (first > second) { 
return first ; 
} else { 
return second ; 
} 
} 

void main (void) { 
int count ; 
int sum ; 
int max ; 
int x ; 

x = input () ; 
max = x ; 
sum = 0 ; 
count = 0 ; 

while (x != 0) { 
count = count + 1 ; 
sum = sum + x ; 
max = larger (max , x) ; 
x = input () ; 
} 

output (count) ; 
output (sum) ; 
output (max) ; 
} 

Und das ist die Fehlermeldung erhalte ich, wenn mein Programm vom Terminal ausgeführt wird:

/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1156: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
/Users/Joe/Documents/Eclipse Projects/Parser/src/pyparsing.py:1258: SyntaxWarning: null string passed to Literal; use Empty() instead 
other = Literal(other) 
Expected ")" (at char 30), (line:6, col:26) 
None 
+0

Haben Sie irgendwelche Hinweise für uns, z. B. welche Fehlermeldung Sie erhalten (falls vorhanden)? Du sagst "es wird nicht korrekt analysiert", aber woher weißt du das? Gibt es einen Fehler? Generiert es eine falsche AST? Weitere Informationen sind erforderlich. –

+0

Entschuldigung. Ich habe meine Frage mit der Eingabezeichenfolge, die ich analysieren möchte, und den Fehlermeldungen, die ich in Terminal erhalte, aktualisiert. – greenie

Antwort

31

1) Ändern Sie Literal("if")-Keyword("if") (und usw., bis Literal("void")), um zu verhindern, dass das führende "if" einer Variablen mit dem Namen "ifactor" übereinstimmt.

2) nums, alphas und alphanums sind keine Ausdrücke, sie sind Strings, die mit der Wortklasse verwendet werden können, einige typische Sätze von Zeichen zu definieren, bei der Definition von „Wörtern“ wie „eine Zahl ein Wort up gemacht ist nums "oder" ein Bezeichner ist ein Wort, das mit einem Alpha beginnt, gefolgt von null oder mehr Alphanums. " Anstatt also:

number = nums 
identifier = alphas + OneOrMore(alphanums) 

Sie

wollen
number = Word(nums) 
identifier = Word(alphas, alphanums) 

3) Statt Combine, ich glaube, Sie Group wollen. Verwenden Sie Combine, wenn die übereinstimmenden Tokens zusammenhängend sein sollen und keine Leerstellen enthalten sein sollen, und verketten die Token und geben sie als einzelne Zeichenfolge zurück. Combine wird häufig in Fällen wie diesem verwendet:

realnum = Combine(Word(nums) + "." + Word(nums)) 

Ohne Combine, "3.14" Parsen der Liste von Strings ['3', '.', '14'] zurückkehren würde, also fügen wir Combine, so dass das analysierte Ergebnis für realnum '3.14' ist (die Sie dann zu einem passieren konnte Aktion analysieren, um den tatsächlichen Gleitkommawert zu konvertieren 3.14). Combine s Erzwingen von intervenierenden Whitespaces verhindert auch, dass wir versehentlich 'The answer is 3. 10 is too much.' analysieren und denken, dass "3. 10" eine reelle Zahl darstellt.

4) Dies sollte nicht Ihren Fehler verursachen, aber Ihre Eingabezeichenfolge hat Lose von zusätzlichen Leerzeichen. Wenn Sie Ihre Grammatik zum Laufen bringen, sollten Sie "int x;" genauso gut wie "int x ;" parsen können.

Hoffe, dass einige dieser Hinweise dich in Gang bringen. Hast du irgendwelche Online-Artikel oder Tutorials gelesen? Und schau dir bitte die Online-Beispiele an. Sie müssen sich ein gutes Bild davon machen, wie Word, Literal, Combine usw. ihre individuellen Analyseaufgaben ausführen.

5) Sie haben die rekursiven Definitionen für Term und Anweisung falsch implementiert. Stattdessen '' ihnen zuzuweisen, schreiben Sie:

term = Forward() 
statement = Forward() 

Dann, wenn Sie gehen, um tatsächlich sie mit ihren rekursiven Definitionen zu definieren, verwenden Sie die << Operator (und sicher sein, die RHS in () ‚s einzuschließen).

term << (... term definition ...) 
statement << (... statement definition ...) 

Sie können ein Beispiel für einen rekursive Parser here und eine Präsentation zu dem grundlegenden pyparsing Nutzung here finden - siehe den Abschnitt mit dem Titel „Parsing-Liste“ nach Schritt-für-Schritt, wie die Rekursion behandelt wird.

+0

Danke Paul. Ich habe alle Instanzen von Kombinieren mit Gruppe ersetzt und jetzt erhalte ich verschiedene Fehler, von denen ich denke, dass sie eher mit der Schreibweise meiner Regeln zusammenhängen als mit der Syntax, die ich verwendet habe. Ich habe meinen ursprünglichen Beitrag aktualisiert, um die von Ihnen vorgeschlagenen Änderungen und den neuen Fehler zu berücksichtigen. – greenie

+0

Excellent Paul, vielen Dank. Ich wünschte ich könnte dir mehr sagen :) – greenie