1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
# -*- 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),
'print': Token(Tag.PRINT),
'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))
|