summaryrefslogblamecommitdiffstats
path: root/src/front/lexer.py
blob: e6eb1722156f4f6d88287728f207ec38c8ed525b (plain) (tree)
1
2
3
4
5
6
7
8
9



                       
            
                               
                                                  

                             
                                  
                             
 
                                            









                                                              
                                                      

                                                    

              

                                        

              
                   


                                                   
                                                       
                                      
                                                        
                                     
                           
 



                                                


                                          
 

                                      
 




                                                  
                                   



                                                   
                                    













                                                                                                                                  
                                                         




                                                                                
                                                      




                                                                      
                                                    





                                                   
                                        



                                                                                            
# -*- coding: utf-8 -*-
import re
from token import *

class Lexer:
    def __init__(self, source):
        self.source = (source + "\n").splitlines()
        self.source.reverse()
        self.line = 0
        self.lastWasNewline = True
        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):
        # leerzeichen entfernen
        self.currentLine = self.currentLine.strip()

        # 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()

            # nur ein newline zurückgeben
            if self.lastWasNewline:
                return self.scan()

            self.lastWasNewline = True
            return Token(Tag.NEWLINE)

        # bei Kommentar, Rest der Zeile ignorieren
        if self.currentLine.startswith('#'):
            self.currentLine = ''
            return self.scan()

        self.lastWasNewline = False

        # 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))