# -*- coding: utf-8 -*- import re from token import * class Lexer: def __init__(self, source): self.source = (source + "\n\n").splitlines() self.source.reverse() self.line = 0 self.doubleNewlineCheck = False self.currentLine = '' # reservierte Wörter initialisieren self.reservedWords = {'True': Token(Tag.BOOL, True), 'False': Token(Tag.BOOL, False), '[': Token(Tag.LBRAK), ']': Token(Tag.RBRAK), '(': Token(Tag.LPAREN), ')': Token(Tag.RPAREN), ',': Token(Tag.COMMA), 'while': Token(Tag.WHILE), 'if': Token(Tag.IF), 'else': Token(Tag.ELSE), 'call': Token(Tag.CALL), 'fun': Token(Tag.FUN), 'end': Token(Tag.END)} return def reserve(self, word, token): self.reservedWords[word] = token return def scan(self): # wenn in der aktuellen Zeile nichts mehr steht if (len(self.currentLine) == 0): # wenn source zuende, dann None zurückgeben if (len(self.source) <= 0): return None # nächste Zeile auslesen self.line = self.line + 1 self.currentLine = self.source.pop() # newline zurückgeben if self.doubleNewlineCheck: self.doubleNewlineCheck = False return Token(Tag.NEWLINE) # leerzeichen entfernen self.currentLine = self.currentLine.strip() # bei Kommentar, Rest der Zeile ignorieren if self.currentLine.startswith('#'): self.currentLine = '' return self.scan() # keine doppelten Newlines self.doubleNewlineCheck = True # Token parsen if self.currentLine.startswith('@'): self.currentLine = self.currentLine[1:] return Token(Tag.RETURN) # reservierte Wörter (da stehen auch schon erkannte Identifyer drine) for reservedWord, token in self.reservedWords.iteritems(): if self.currentLine.startswith(reservedWord): length = len(reservedWord) if len(self.currentLine) <= length or not self.currentLine[0].isalnum() or not self.currentLine[length].isalnum(): self.currentLine = self.currentLine[length:] return token # zahlen matchen match = re.match(r"^([0-9]+)", self.currentLine) if match: self.currentLine = self.currentLine[match.end(0):] return Token(Tag.NUMBER, int(match.group(0))) # operatoren matchen match = re.match(r"^(<=|==|>=|&&|\|\||<|>|\+|-|\*|/)", self.currentLine) if match: self.currentLine = self.currentLine[match.end(0):] return Token(Tag.OPERATOR, match.group(0)) # idents matchen match = re.match(r"^([a-zA-Z][a-zA-Z0-9]*)", self.currentLine) if match: self.currentLine = self.currentLine[match.end(0):] token = Token(Tag.IDENT, match.group(0)) self.reserve(match.group(0), token) return token # assignments if self.currentLine.startswith('='): self.currentLine = self.currentLine[1:] return Token(Tag.ASSIGNMENT) # wenn die programmausführung hier ist, # ist ein syntaxfehler aufgetreten raise Exception("Syntax Error in line: %d at: '%s'" % (self.line, self.currentLine))