2012-03-31 16 views
2

Ich schreibe einen Compiler in Python, und ich habe einen handgeschriebenen Lexer erstellt, weil ich nicht herausfinden kann, wie Einrückung in PLY zu parsen. Auch mein Lexer einige yield Aussagen verwendet wie folgt:Wie schreibe ich eine PLY-Schnittstelle für handgeschriebene Lexer?

def scan(): 
... 
    for i in tokens: 
     if i[0]: yield Token(self.line, i[0] if i[0] in keywords else "ident", i[0]) 
      elif i[1]: 
       if "e" in i[1]: 
        base, exp = i[1].split("e") 
        val = float(base) * 10 ** int(exp) 
       else: val = float(i[1]) 
       yield Token(self.line, "float", val) 
     ... other cases ... 

jedoch erkannte ich, dass die PLY Parser eine token Methode erfordert, also machte ich eine, die wie folgt aussieht:

def token(self): 
    return next(self.scan()) 

Die tatsächliche Scan Die Verwendung von scan() dauert nach meinen Tests im Durchschnitt 124 ms, aber wenn ich den PLY-Parser verwende, beginnt das Parsing nicht nach ein paar Minuten. Es scheint, dass meine Methode ein Problem hat.

Auch ich habe versucht, die scan() Methode umzubenennen, so dass es könnte die Schnittstelle werden. Python gibt so etwas wie

AttributeError: 'generator' object has no attribute 'type' 

So scheint es, dass PLY ein Verfahren benötigt, die ein einzelnes Zeichen in einer Zeit zurückkehren werden.

Gibt es eine Möglichkeit, die Methode so umzuschreiben, dass es die nächste Iteration von scan() zurückgeben würde und nicht so langsam?

+0

Übrigens können Sie PLY für die meisten Lexing verwenden, auch wenn Sie Einrückung analysieren möchten. Führen Sie einfach alle (führenden?) Whitespace-Zeilenumbrüche durch den Lexer und bearbeiten Sie den Token-Stream nach, um richtige INDENT/DEDENT-Token einzufügen. Als ich das gemacht habe, habe ich PLY nicht für den Parsing-Schritt verwendet, also musste ich es nicht integrieren und kann daher diese Frage nicht beantworten. Aber es macht das Schreiben des Lexiers einfacher IMHO. – delnan

+0

@delnan Das könnte _probably_ funktionieren, aber was ich auch nicht herausfinden kann ist, wie man mehrere Tokens für diese eine Regel zurückgibt, um den Einzug zu verarbeiten. Den Rest konnte ich schon programmieren. –

Antwort

0

Sie benötigen Generator irgendwo zu speichern, wie:

def start(...): 
    self.lexer = self.scan() 

def token(...): 
    return next(self.lexer) 

Haftungsausschluss: Ich weiß nichts über PLY.

+0

Es funktioniert, aber es macht das Programm definitiv etwas langsamer, etwa 5 ms. Aber das stört mich nicht wirklich. Vielen Dank! –

Verwandte Themen