Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
general
stups
prob-teaching-notebooks
Commits
be48016d
Commit
be48016d
authored
Nov 17, 2020
by
Christopher Happe
Browse files
LOOP-Interpreter zu Klasse gemacht
parent
d5d1fc95
Changes
4
Hide whitespace changes
Inline
Side-by-side
info4/kapitel-8/Interpreter/loop_interpreter.py
deleted
100644 → 0
View file @
d5d1fc95
import
lexer
import
sys
import
operator
import
re
regex_to_token
=
[(
re
.
compile
(
r
'\d+'
),
'NUMBER'
),
(
re
.
compile
(
r
'x\d+'
),
'IDENTIFIER'
),
(
re
.
compile
(
r
'\+'
),
'PLUS'
),
(
re
.
compile
(
r
'-'
),
'MINUS'
),
(
re
.
compile
(
r
':=|≔'
),
'EQUALS'
),
(
re
.
compile
(
r
'LOOP'
),
'LOOP'
),
(
re
.
compile
(
r
'DO'
),
'DO'
),
(
re
.
compile
(
r
'END'
),
'END'
),
(
re
.
compile
(
r
';'
),
'SEMICOLON'
),
(
re
.
compile
(
r
'BREAK'
),
'BREAK'
),
(
re
.
compile
(
r
'\n'
,
re
.
MULTILINE
),
'LINEBREAK'
),
(
re
.
compile
(
r
'\s+'
),
'WHITESPACE'
),
(
re
.
compile
(
r
'[^\n]*'
),
'UNKNOWN'
)]
global
error_handler
,
lex
,
values
class
ErrorHandler
:
def
__init__
(
self
,
program
):
sys
.
tracebacklimit
=
0
self
.
program
=
program
self
.
line_number
=
0
def
handle_error
(
self
,
message
):
msg
=
[
"Fehler in Zeile "
+
str
(
self
.
line_number
+
1
),
self
.
program
.
split
(
"
\n
"
)[
self
.
line_number
],
message
]
raise
SyntaxError
(
"
\n
"
.
join
(
msg
))
from
None
def
increase_line
(
self
):
self
.
line_number
+=
1
def
handle_break
(
self
):
print
(
"BREAK in Zeile "
+
str
(
self
.
line_number
))
print
(
"Aktueller Zustand:"
)
for
k
,
v
in
values
.
items
():
print
(
"Variable "
+
k
+
": "
+
str
(
v
))
user_input
=
input
(
"Drücke ENTER zum Fotfahren oder schreibe EXIT zum Beenden:"
)
if
user_input
.
lower
()
==
'exit'
:
raise
KeyboardInterrupt
def
process_assignment
(
forbidden_identifiers
,
identifier_token_1
):
global
values
identifier_1
=
identifier_token_1
.
v
if
identifier_1
in
forbidden_identifiers
:
error_handler
.
handle_error
(
"Identifier "
+
identifier_1
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
next_nonempty_token
(
"Zuweisung"
,
":="
).
k
==
'EQUALS'
:
error_handler
.
handle_error
(
":= in Zuweisung erwartet."
)
identifier_token_2
=
next_nonempty_token
(
"Zuweisung"
,
"IDENTIFIER (x0, x1, ...) oder NUMBER"
)
if
identifier_token_2
.
k
==
'NUMBER'
:
value_1
=
int
(
identifier_token_2
.
v
)
values
.
update
({
identifier_token_1
.
v
:
value_1
})
return
next_token
()
if
not
identifier_token_2
.
k
==
'IDENTIFIER'
:
error_handler
.
handle_error
(
"IDENTIFIER in Zuweisung erwartet."
)
identifier_2
=
identifier_token_2
.
v
if
identifier_2
in
forbidden_identifiers
:
error_handler
.
handle_error
(
"Identifier "
+
identifier_2
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
identifier_2
in
values
:
value_2
=
values
.
get
(
identifier_2
)
else
:
value_2
=
0
operator_token
=
next_nonempty_token
(
"Zuweisung"
,
"+ oder -"
)
op
=
None
if
operator_token
.
k
==
'PLUS'
:
op
=
operator
.
__add__
elif
operator_token
.
k
==
'MINUS'
:
op
=
operator
.
__sub__
else
:
error_handler
.
handle_error
(
"+ oder - in Zuweisung erwartet."
)
number_token
=
next_nonempty_token
(
"Zuweisung"
,
"NUMBER"
)
if
not
number_token
.
k
==
'NUMBER'
:
error_handler
.
handle_error
(
"NUMBER in Zuweisung erwartet."
)
value_1
=
max
(
0
,
op
(
value_2
,
int
(
number_token
.
v
)))
values
.
update
({
identifier_1
:
value_1
})
return
next_token
()
def
verify_assignment
(
forbidden_identifiers
,
identifier_token_1
):
identifier_1
=
identifier_token_1
.
v
if
identifier_1
in
forbidden_identifiers
:
error_handler
.
handle_error
(
"Identifier "
+
identifier_1
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
next_nonempty_token
(
"Zuweisung"
,
":="
).
k
==
'EQUALS'
:
error_handler
.
handle_error
(
":= in Zuweisung erwartet."
)
identifier_token_2
=
next_nonempty_token
(
"Zuweisung"
,
"IDENTIFIER (x0, x1, ...) oder NUMBER"
)
if
identifier_token_2
.
k
==
'NUMBER'
:
return
next_token
()
if
not
identifier_token_2
.
k
==
'IDENTIFIER'
:
error_handler
.
handle_error
(
"IDENTIFIER in Zuweisung erwartet."
)
identifier_2
=
identifier_token_2
.
v
if
identifier_2
in
forbidden_identifiers
:
error_handler
.
handle_error
(
"Identifier "
+
identifier_2
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
next_nonempty_token
(
"Zuweisung"
,
"+ oder -"
).
k
not
in
[
'PLUS'
,
'MINUS'
]:
error_handler
.
handle_error
(
"+ oder - in Zuweisung erwartet."
)
if
not
next_nonempty_token
(
"Zuweisung"
,
"NUMBER"
).
k
==
'NUMBER'
:
error_handler
.
handle_error
(
"NUMBER in Zuweisung erwartet."
)
return
next_token
()
def
process_loop
(
forbidden_identifiers
,
loop_token
):
global
values
identifier_token
=
next_nonempty_token
(
'LOOP'
,
'IDENTIFIER (x0, x1, ...)'
)
if
not
identifier_token
.
k
==
'IDENTIFIER'
:
error_handler
.
handle_error
(
'IDENTIFIER in LOOP erwartet.'
)
if
identifier_token
.
v
in
forbidden_identifiers
:
error_handler
.
handle_error
(
'Identifier '
+
identifier_token
.
v
+
' ist bereits in Loop vorhanden und darf nicht verwendet werden.'
)
if
not
next_nonempty_token
(
"LOOP"
,
"DO"
).
k
==
'DO'
:
error_handler
.
handle_error
(
'DO in LOOP erwartet.'
)
if
identifier_token
.
v
in
values
:
number_of_loops
=
int
(
values
.
get
(
identifier_token
.
v
))
else
:
number_of_loops
=
0
saved_position
=
lex
.
current_position
saved_line
=
error_handler
.
line_number
forbidden_identifiers
.
append
(
identifier_token
.
v
)
if
number_of_loops
==
0
:
end_found
=
False
while
not
end_found
:
token
=
verify_program
(
forbidden_identifiers
,
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
for
index
in
range
(
number_of_loops
):
lex
.
current_position
=
saved_position
error_handler
.
line_number
=
saved_line
end_found
=
False
while
not
end_found
:
token
=
process_program
(
forbidden_identifiers
,
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
forbidden_identifiers
.
remove
(
identifier_token
.
v
)
return
next_token
()
def
verify_loop
(
forbidden_identifiers
,
loop_token
):
identifier_token
=
next_nonempty_token
(
"LOOP"
,
"IDENTIFIER"
)
if
not
identifier_token
.
k
==
'IDENTIFIER'
:
error_handler
.
handle_error
(
'IDENTIFIER in LOOP erwartet.'
)
if
identifier_token
.
v
in
forbidden_identifiers
:
error_handler
.
handle_error
(
"Identifier "
+
identifier_token
.
v
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
next_nonempty_token
(
"LOOP"
,
"DO"
).
k
==
'DO'
:
error_handler
.
handle_error
(
'DO in LOOP erwartet.'
)
forbidden_identifiers
.
append
(
identifier_token
.
v
)
end_found
=
False
while
not
end_found
:
token
=
verify_program
(
forbidden_identifiers
,
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
forbidden_identifiers
.
remove
(
identifier_token
.
v
)
return
next_token
()
def
process_program
(
forbidden_identifiers
,
current_token
):
if
current_token
is
None
or
current_token
.
k
not
in
[
'IDENTIFIER'
,
'LOOP'
]:
error_handler
.
handle_error
(
"Keine passende Anweisung gefunden
\n
"
+
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP"
)
elif
current_token
.
k
==
'IDENTIFIER'
:
current_token
=
process_assignment
(
forbidden_identifiers
,
current_token
)
elif
current_token
.
k
==
'LOOP'
:
current_token
=
process_loop
(
forbidden_identifiers
,
current_token
)
return
current_token
def
verify_program
(
forbidden_identifiers
,
current_token
):
if
current_token
is
None
or
current_token
.
k
not
in
[
'IDENTIFIER'
,
'LOOP'
]:
error_handler
.
handle_error
(
"Keine passende Anweisung gefunden
\n
"
+
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP"
)
elif
current_token
.
k
==
'IDENTIFIER'
:
current_token
=
verify_assignment
(
forbidden_identifiers
,
current_token
)
elif
current_token
.
k
==
'LOOP'
:
current_token
=
verify_loop
(
forbidden_identifiers
,
current_token
)
return
current_token
def
next_token
():
new_token
=
lex
.
next
()
if
new_token
is
None
:
return
None
elif
new_token
.
k
==
'BREAK'
:
error_handler
.
handle_break
()
return
next_token
()
elif
new_token
.
k
==
'LINEBREAK'
:
error_handler
.
increase_line
()
return
next_token
()
elif
new_token
.
k
==
'WHITESPACE'
:
return
next_token
()
else
:
return
new_token
def
next_nonempty_token
(
current_function
,
expected_token
):
token
=
next_token
()
if
token
is
None
:
error_handler
.
handle_error
(
"Frühzeitiges Ende von "
+
current_function
+
"
\n
"
+
"Erwartet: "
+
expected_token
)
return
token
def
interpret
(
program
):
try
:
global
error_handler
,
lex
,
values
lex
=
lexer
.
Lexer
(
regex_to_token
,
program
)
error_handler
=
ErrorHandler
(
program
)
values
=
{}
forbidden_identifiers
=
[]
current_token
=
next_token
()
while
current_token
is
not
None
:
current_token
=
process_program
(
forbidden_identifiers
,
current_token
)
if
current_token
is
not
None
:
if
not
current_token
.
k
==
'SEMICOLON'
:
error_handler
.
handle_error
(
"Semicolon erwartet"
)
current_token
=
next_token
()
if
current_token
is
None
:
error_handler
.
handle_error
(
"Semikolons werden nur zur Trennung und nicht zum "
+
"Abschluss von Programmen verwendet"
)
if
"x0"
in
values
:
return
values
.
get
(
"x0"
)
return
0
except
KeyboardInterrupt
:
return
-
1
info4/kapitel-8/Interpreter/loopinterpreter.py
0 → 100644
View file @
be48016d
import
lexer
import
sys
import
operator
import
re
class
ErrorHandler
:
def
__init__
(
self
,
program
,
interpreter
):
sys
.
tracebacklimit
=
0
self
.
program
=
program
self
.
line_number
=
0
self
.
interpreter
=
interpreter
def
handle_error
(
self
,
message
):
msg
=
[
"Fehler in Zeile "
+
str
(
self
.
line_number
+
1
),
self
.
program
.
split
(
"
\n
"
)[
self
.
line_number
],
message
]
raise
SyntaxError
(
"
\n
"
.
join
(
msg
))
from
None
def
increase_line
(
self
):
self
.
line_number
+=
1
def
handle_break
(
self
):
print
(
"BREAK in Zeile "
+
str
(
self
.
line_number
))
print
(
"Aktueller Zustand:"
)
for
k
,
v
in
self
.
interpreter
.
values
.
items
():
print
(
"Variable "
+
k
+
": "
+
str
(
v
))
user_input
=
input
(
"Drücke ENTER zum Fotfahren oder schreibe EXIT zum Beenden:"
)
if
user_input
.
lower
()
==
'exit'
:
raise
KeyboardInterrupt
class
LOOPInterpreter
:
def
__init__
(
self
):
self
.
regex_to_token
=
[(
re
.
compile
(
r
'\d+'
),
'NUMBER'
),
(
re
.
compile
(
r
'x\d+'
),
'IDENTIFIER'
),
(
re
.
compile
(
r
'\+'
),
'PLUS'
),
(
re
.
compile
(
r
'-'
),
'MINUS'
),
(
re
.
compile
(
r
':=|≔'
),
'EQUALS'
),
(
re
.
compile
(
r
'LOOP'
),
'LOOP'
),
(
re
.
compile
(
r
'DO'
),
'DO'
),
(
re
.
compile
(
r
'END'
),
'END'
),
(
re
.
compile
(
r
';'
),
'SEMICOLON'
),
(
re
.
compile
(
r
'BREAK'
),
'BREAK'
),
(
re
.
compile
(
r
'\n'
,
re
.
MULTILINE
),
'LINEBREAK'
),
(
re
.
compile
(
r
'\s+'
),
'WHITESPACE'
),
(
re
.
compile
(
r
'[^\n]*'
),
'UNKNOWN'
)]
self
.
values
=
{}
self
.
lex
=
None
self
.
error_handler
=
None
def
process_assignment
(
self
,
forbidden_identifiers
,
identifier_token_1
):
identifier_1
=
identifier_token_1
.
v
if
identifier_1
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
"Identifier "
+
identifier_1
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
self
.
next_nonempty_token
(
"Zuweisung"
,
":="
).
k
==
'EQUALS'
:
self
.
error_handler
.
handle_error
(
":= in Zuweisung erwartet."
)
identifier_token_2
=
self
.
next_nonempty_token
(
"Zuweisung"
,
"IDENTIFIER (x0, x1, ...) oder NUMBER"
)
if
identifier_token_2
.
k
==
'NUMBER'
:
value_1
=
int
(
identifier_token_2
.
v
)
self
.
values
.
update
({
identifier_token_1
.
v
:
value_1
})
return
self
.
next_token
()
if
not
identifier_token_2
.
k
==
'IDENTIFIER'
:
self
.
error_handler
.
handle_error
(
"IDENTIFIER in Zuweisung erwartet."
)
identifier_2
=
identifier_token_2
.
v
if
identifier_2
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
"Identifier "
+
identifier_2
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
identifier_2
in
self
.
values
:
value_2
=
self
.
values
.
get
(
identifier_2
)
else
:
value_2
=
0
operator_token
=
self
.
next_nonempty_token
(
"Zuweisung"
,
"+ oder -"
)
op
=
None
if
operator_token
.
k
==
'PLUS'
:
op
=
operator
.
__add__
elif
operator_token
.
k
==
'MINUS'
:
op
=
operator
.
__sub__
else
:
self
.
error_handler
.
handle_error
(
"+ oder - in Zuweisung erwartet."
)
number_token
=
self
.
next_nonempty_token
(
"Zuweisung"
,
"NUMBER"
)
if
not
number_token
.
k
==
'NUMBER'
:
self
.
error_handler
.
handle_error
(
"NUMBER in Zuweisung erwartet."
)
value_1
=
max
(
0
,
op
(
value_2
,
int
(
number_token
.
v
)))
self
.
values
.
update
({
identifier_1
:
value_1
})
return
self
.
next_token
()
def
verify_assignment
(
self
,
forbidden_identifiers
,
identifier_token_1
):
identifier_1
=
identifier_token_1
.
v
if
identifier_1
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
"Identifier "
+
identifier_1
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
self
.
next_nonempty_token
(
"Zuweisung"
,
":="
).
k
==
'EQUALS'
:
self
.
error_handler
.
handle_error
(
":= in Zuweisung erwartet."
)
identifier_token_2
=
self
.
next_nonempty_token
(
"Zuweisung"
,
"IDENTIFIER (x0, x1, ...) oder NUMBER"
)
if
identifier_token_2
.
k
==
'NUMBER'
:
return
self
.
next_token
()
if
not
identifier_token_2
.
k
==
'IDENTIFIER'
:
self
.
error_handler
.
handle_error
(
"IDENTIFIER in Zuweisung erwartet."
)
identifier_2
=
identifier_token_2
.
v
if
identifier_2
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
"Identifier "
+
identifier_2
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
self
.
next_nonempty_token
(
"Zuweisung"
,
"+ oder -"
).
k
not
in
[
'PLUS'
,
'MINUS'
]:
self
.
error_handler
.
handle_error
(
"+ oder - in Zuweisung erwartet."
)
if
not
self
.
next_nonempty_token
(
"Zuweisung"
,
"NUMBER"
).
k
==
'NUMBER'
:
self
.
error_handler
.
handle_error
(
"NUMBER in Zuweisung erwartet."
)
return
self
.
next_token
()
def
process_loop
(
self
,
forbidden_identifiers
,
loop_token
):
identifier_token
=
self
.
next_nonempty_token
(
'LOOP'
,
'IDENTIFIER (x0, x1, ...)'
)
if
not
identifier_token
.
k
==
'IDENTIFIER'
:
self
.
error_handler
.
handle_error
(
'IDENTIFIER in LOOP erwartet.'
)
if
identifier_token
.
v
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
'Identifier '
+
identifier_token
.
v
+
' ist bereits in Loop vorhanden und darf nicht verwendet werden.'
)
if
not
self
.
next_nonempty_token
(
"LOOP"
,
"DO"
).
k
==
'DO'
:
self
.
error_handler
.
handle_error
(
'DO in LOOP erwartet.'
)
if
identifier_token
.
v
in
self
.
values
:
number_of_loops
=
int
(
self
.
values
.
get
(
identifier_token
.
v
))
else
:
number_of_loops
=
0
saved_position
=
self
.
lex
.
current_position
saved_line
=
self
.
error_handler
.
line_number
forbidden_identifiers
.
append
(
identifier_token
.
v
)
if
number_of_loops
==
0
:
end_found
=
False
while
not
end_found
:
token
=
self
.
verify_program
(
forbidden_identifiers
,
self
.
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
self
.
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
for
index
in
range
(
number_of_loops
):
self
.
lex
.
current_position
=
saved_position
self
.
error_handler
.
line_number
=
saved_line
end_found
=
False
while
not
end_found
:
token
=
self
.
process_program
(
forbidden_identifiers
,
self
.
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
self
.
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
forbidden_identifiers
.
remove
(
identifier_token
.
v
)
return
self
.
next_token
()
def
verify_loop
(
self
,
forbidden_identifiers
,
loop_token
):
identifier_token
=
self
.
next_nonempty_token
(
"LOOP"
,
"IDENTIFIER"
)
if
not
identifier_token
.
k
==
'IDENTIFIER'
:
self
.
error_handler
.
handle_error
(
'IDENTIFIER in LOOP erwartet.'
)
if
identifier_token
.
v
in
forbidden_identifiers
:
self
.
error_handler
.
handle_error
(
"Identifier "
+
identifier_token
.
v
+
" ist bereits in Loop vorhanden und darf nicht verwendet werden."
)
if
not
self
.
next_nonempty_token
(
"LOOP"
,
"DO"
).
k
==
'DO'
:
self
.
error_handler
.
handle_error
(
'DO in LOOP erwartet.'
)
forbidden_identifiers
.
append
(
identifier_token
.
v
)
end_found
=
False
while
not
end_found
:
token
=
self
.
verify_program
(
forbidden_identifiers
,
self
.
next_token
())
if
token
is
None
or
token
.
k
not
in
[
'SEMICOLON'
,
'END'
]:
self
.
error_handler
.
handle_error
(
"SEMICOLON oder END in LOOP erwartet."
)
elif
token
.
k
==
'SEMICOLON'
:
continue
elif
token
.
k
==
'END'
:
end_found
=
True
forbidden_identifiers
.
remove
(
identifier_token
.
v
)
return
self
.
next_token
()
def
process_program
(
self
,
forbidden_identifiers
,
current_token
):
if
current_token
is
None
or
current_token
.
k
not
in
[
'IDENTIFIER'
,
'LOOP'
]:
self
.
error_handler
.
handle_error
(
"Keine passende Anweisung gefunden
\n
"
+
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP"
)
elif
current_token
.
k
==
'IDENTIFIER'
:
current_token
=
self
.
process_assignment
(
forbidden_identifiers
,
current_token
)
elif
current_token
.
k
==
'LOOP'
:
current_token
=
self
.
process_loop
(
forbidden_identifiers
,
current_token
)
return
current_token
def
verify_program
(
self
,
forbidden_identifiers
,
current_token
):
if
current_token
is
None
or
current_token
.
k
not
in
[
'IDENTIFIER'
,
'LOOP'
]:
self
.
error_handler
.
handle_error
(
"Keine passende Anweisung gefunden
\n
"
+
"Erwartet: IDENTIFIER (x0, x1, ...) oder LOOP"
)
elif
current_token
.
k
==
'IDENTIFIER'
:
current_token
=
self
.
verify_assignment
(
forbidden_identifiers
,
current_token
)
elif
current_token
.
k
==
'LOOP'
:
current_token
=
self
.
verify_loop
(
forbidden_identifiers
,
current_token
)
return
current_token
def
next_token
(
self
):
new_token
=
self
.
lex
.
next
()
if
new_token
is
None
:
return
None
elif
new_token
.
k
==
'BREAK'
:
self
.
error_handler
.
handle_break
()
return
self
.
next_token
()
elif
new_token
.
k
==
'LINEBREAK'
:
self
.
error_handler
.
increase_line
()
return
self
.
next_token
()
elif
new_token
.
k
==
'WHITESPACE'
:
return
self
.
next_token
()
else
:
return
new_token
def
next_nonempty_token
(
self
,
current_function
,
expected_token
):
token
=
self
.
next_token
()
if
token
is
None
:
self
.
error_handler
.
handle_error
(
"Frühzeitiges Ende von "
+
current_function
+
"
\n
"
+
"Erwartet: "
+
expected_token
)
return
token
def
interpret
(
self
,
program
):
try
:
self
.
lex
=
lexer
.
Lexer
(
self
.
regex_to_token
,
program
)
self
.
error_handler
=
ErrorHandler
(
program
,
self
)
self
.
values
=
{}
forbidden_identifiers
=
[]
current_token
=
self
.
next_token
()
while
current_token
is
not
None
:
current_token
=
self
.
process_program
(
forbidden_identifiers
,
current_token
)
if
current_token
is
not
None
:
if
not
current_token
.
k
==
'SEMICOLON'
:
self
.
error_handler
.
handle_error
(
"Semicolon erwartet"
)
current_token
=
self
.
next_token
()
if
current_token
is
None
:
self
.
error_handler
.
handle_error
(
"Semikolons werden nur zur Trennung und nicht zum "
+
"Abschluss von Programmen verwendet"
)
if
"x0"
in
self
.
values
:
return
self
.
values
.
get
(
"x0"
)
return
0
except
KeyboardInterrupt
:
return
-
1
def
interpret
(
program
):
interpreter
=
LOOPInterpreter
()
return
interpreter
.
interpret
(
program
)
info4/kapitel-8/Interpreter/test_loop_interpreter.py
View file @
be48016d
from
loop
_
interpreter
import
interpret
from
loopinterpreter
import
interpret
import
unittest
from
unittest
import
mock
def
input_exit
(
prompt
):
return
"EXIT"
def
input_continue
(
prompt
):
return
""
def
init_without_tokens
(
self
,
regex_to_token
,
program
):
self
.
regex_to_token
=
{}
self
.
program
=
program
self
.
current_position
=
0
class
InterpreterTest
(
unittest
.
TestCase
):
class
LOOPInterpreterTest
(
unittest
.
TestCase
):
def
test_assignment_default_zero
(
self
):
self
.
assertEqual
(
interpret
(
'x0:=x0 + 0'
),
0
)
self
.
assertEqual
(
interpret
(
'x0:=x1 + 0'
),
0
)
...
...
@@ -219,12 +223,12 @@ class InterpreterTest(unittest.TestCase):
x0:=x2+2'''
),
5
)
self
.
assertEqual
(
interpret
(
'x1:=x1-2;
\n
x0:=x1+2'
),
2
)
@
mock
.
patch
(
'interpreter.input'
,
side_effect
=
input_exit
)
@
mock
.
patch
(
'
loop
interpreter.input'
,
side_effect
=
input_exit
)
def
test_break_exit
(
self
,
input
):
self
.
assertEqual
(
interpret
(
'x1:=2; BREAK x0:=2'
),
-
1
)
self
.
assertEqual
(
interpret
(
'LOOP x1 DO BREAK x2:= 2 END'
),
-
1
)
@
mock
.
patch
(
'interpreter.input'
,
side_effect
=
input_continue
)
@
mock
.
patch
(
'
loop
interpreter.input'
,
side_effect
=
input_continue
)
def
test_break_continue
(
self
,
input
):
self
.
assertEqual
(
interpret
(
'x1:=2; LOOP x1 DO x0:=x0+2 BREAK END'
),
4
)
...
...
info4/kapitel-8/LOOP-Programme.ipynb
View file @
be48016d
...
...
@@ -42,12 +42,12 @@
},
"outputs": [],
"source": [
"%run Interpreter/interpreter.py"
"%run Interpreter/
loop_
interpreter.py"
]
},
{
"cell_type": "code",
"execution_count":
5
,
"execution_count":
2
,
"metadata": {},
"outputs": [
{
...
...
@@ -56,7 +56,7 @@
"9"
]
},
"execution_count":
5
,
"execution_count":
2
,
"metadata": {},
"output_type": "execute_result"
}
...
...
@@ -66,8 +66,9 @@
"x1:=3;\n",
"x2:=6;\n",
"LOOP x1 DO\n",
" x0≔ x0 + 1\n",
"END''')"
" x2≔ x2 + 1\n",
"END;\n",
"x0≔ x2 + 0''')"