Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
fja
eval
Commits
e7408f3b
Commit
e7408f3b
authored
Feb 28, 2020
by
Kateřina Sloupová
Browse files
split regular grammars and finite automata
parent
9932bacd
Pipeline
#54103
passed with stage
in 22 seconds
Changes
4
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
demo.py
View file @
e7408f3b
from
parser
import
Parser
from
objects
import
Character
,
Terminal
,
Nonterminal
,
State
,
DFA
,
REG
,
NFA
from
objects
import
Composition
as
comp
from
typing
import
Set
,
Dict
,
Tuple
from
reg_automata
import
Character
,
State
,
DFA
,
NFA
from
reg_automata
import
Composition
as
comp
from
reg_grammars
import
REG
,
Terminal
,
Nonterminal
from
typing
import
Set
,
Dict
,
Tuple
,
Union
def
make_dfa
(
states
:
Set
[
str
],
characters
:
Set
[
str
],
...
...
@@ -38,7 +39,7 @@ def reg_1():
nonterminals
=
{
S
,
A
}
init
=
S
terminals
=
{
a
}
rules
=
dict
()
rules
:
Dict
[
Nonterminal
,
Set
[
Union
[
Terminal
,
Tuple
[
Terminal
,
Nonterminal
]]]]
=
dict
()
rules
[
S
]
=
{(
a
,
S
),
(
a
)}
rules
[
A
]
=
{(
a
)}
reg
=
REG
(
nonterminals
,
terminals
,
rules
,
init
)
...
...
@@ -52,7 +53,7 @@ def reg_2():
nonterminals
=
{
S
,
A
}
init
=
S
terminals
=
{
a
}
rules
=
dict
()
rules
:
Dict
[
Nonterminal
,
Set
[
Union
[
Terminal
,
Tuple
[
Terminal
,
Nonterminal
]]]]
=
dict
()
reg
=
REG
(
nonterminals
,
terminals
,
rules
,
init
)
return
reg
...
...
@@ -60,7 +61,7 @@ def nfa_1():
q0
=
State
(
"q0"
)
q1
=
State
(
"q1"
)
q2
=
State
(
"q2"
)
a
=
Terminal
(
"a"
)
a
=
Character
(
"a"
)
transition
=
{(
q0
,
a
):
{
q1
,
q2
},
(
q1
,
a
):
{
q1
},
(
q2
,
a
):
{
q2
}}
nfa
=
NFA
({
q0
,
q1
,
q2
},
{
a
},
transition
,
q0
,
{
q1
,
q2
})
return
nfa
...
...
parser.py
View file @
e7408f3b
from
typing
import
List
,
Dict
,
Tuple
,
Optional
import
re
from
objects
import
REG
,
DFA
,
NFA
,
Terminal
from
reg_automata
import
DFA
,
NFA
from
reg_grammars
import
REG
,
Terminal
# TODO ask: commas at the ends of lines or not?
...
...
@@ -28,7 +29,7 @@ class Parser:
return
out
# TODO ask: import rules
def
rules_to_str
(
self
,
rules
:
REG
.
Rules
):
def
rules_to_str
(
self
,
rules
:
REG
.
Rules
)
->
str
:
out
=
""
for
rule
in
rules
:
out
=
out
[:
-
1
]
+
(
",
\n
"
)
...
...
objects
.py
→
reg_automata
.py
View file @
e7408f3b
from
__future__
import
annotations
from
typing
import
Set
,
FrozenSet
,
List
,
Dict
,
Union
,
Tuple
,
Deque
,
Optional
,
TypeVar
from
typing
import
Set
,
FrozenSet
,
List
,
Dict
,
Union
,
Tuple
,
Deque
,
Optional
,
TypeVar
,
Any
from
enum
import
Enum
import
enum
from
copy
import
deepcopy
...
...
@@ -12,19 +12,6 @@ class Composition(Enum):
Subtraction
=
enum
.
auto
()
class
Terminal
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
def
__eq__
(
self
,
obj
):
if
isinstance
(
obj
,
Terminal
):
return
obj
.
name
==
self
.
name
return
False
def
__hash__
(
self
):
return
hash
(
self
.
name
)
class
Character
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
...
...
@@ -42,19 +29,6 @@ class Eps:
pass
class
Nonterminal
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
def
__eq__
(
self
,
obj
):
if
isinstance
(
obj
,
Nonterminal
):
return
obj
.
name
==
self
.
name
return
False
def
__hash__
(
self
):
return
hash
(
self
.
name
)
class
State
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
...
...
@@ -68,90 +42,6 @@ class State:
return
hash
(
self
.
name
)
class
REG
:
Rules
=
Dict
[
Nonterminal
,
Set
[
Union
[
Terminal
,
Tuple
[
Terminal
,
Nonterminal
]]]]
type_var
=
TypeVar
(
'type_var'
)
# TODO should accept init -> epsilon
def
__init__
(
self
,
nonterminals
:
Set
[
Nonterminal
],
terminals
:
Set
[
Terminal
],
rules
:
Rules
,
init
:
Nonterminal
):
self
.
nonterminals
=
nonterminals
self
.
terminals
=
terminals
self
.
rules
=
rules
self
.
init
=
init
assert
self
.
check
# TODO ask about concept
def
check
(
self
)
->
bool
:
# scheme of grammar - empty sets and dicts are implemention only variant
if
len
(
self
.
nonterminals
)
==
0
:
assert
len
(
self
.
terminals
)
==
0
and
len
(
self
.
rules
)
==
0
and
self
.
init
==
None
,
"nonempty scheme of grammar"
return
True
nonterminal_names
=
set
(
map
(
lambda
x
:
x
.
name
,
self
.
nonterminals
))
terminal_names
=
set
(
map
(
lambda
x
:
x
.
name
,
self
.
terminals
))
assert
len
(
nonterminal_names
.
intersection
(
terminal_names
))
==
0
,
"name conflict"
for
nonterminal
in
self
.
rules
:
assert
nonterminal
in
self
.
nonterminals
,
"unknown nonterminal "
+
nonterminal
.
name
for
rule
in
self
.
rules
[
nonterminal
]:
if
isinstance
(
rule
,
Terminal
):
assert
rule
in
self
.
terminals
,
"unknown terminal "
+
rule
.
name
else
:
assert
rule
[
0
]
in
self
.
terminals
,
"unknown terminal "
+
rule
[
0
].
name
assert
rule
[
1
]
in
self
.
nonterminals
,
"unknown nonterminal "
+
rule
[
1
].
name
assert
self
.
init
in
self
.
nonterminals
,
"init not in nonterminals"
return
True
def
reg_to_nfa
(
self
)
->
NFA
:
init
=
State
(
self
.
init
.
name
)
states
:
Set
[
State
]
=
set
()
for
nonterminal
in
self
.
nonterminals
:
state
=
State
(
nonterminal
.
name
)
states
.
add
(
state
)
characters
:
Set
[
Character
]
=
set
()
for
terminal
in
self
.
terminals
:
character
=
Character
(
terminal
.
name
)
characters
.
add
(
character
)
final
=
State
(
"new_final"
)
# TODO assert that name is unique, as for hell in make_total
states
.
add
(
final
)
transition
:
Dict
[
Tuple
[
State
,
Character
],
Set
[
State
]]
=
dict
()
for
nonterminal
in
self
.
rules
:
state
=
State
(
nonterminal
.
name
)
for
rule
in
self
.
rules
[
nonterminal
]:
# rule A -> a becomes d(A, a) = final
if
isinstance
(
rule
,
Terminal
):
# TODO and a is not \eps
character
=
Character
(
rule
.
name
)
if
(
state
,
character
)
in
transition
:
transition
[
state
,
character
].
add
(
final
)
else
:
transition
[
state
,
character
]
=
{
final
}
# rule A -> aB becomes d(A, a) = B
elif
(
state
,
rule
[
0
])
in
transition
:
character
=
Character
(
rule
[
0
].
name
)
move
=
State
(
rule
[
1
].
name
)
transition
[
state
,
character
].
add
(
move
)
else
:
character
=
Character
(
rule
[
0
].
name
)
move
=
State
(
rule
[
1
].
name
)
transition
[
state
,
character
]
=
{
move
}
# TODO if init -> \eps: nfa.final.add(nfa.init)
# I need to know how to treat \eps
nfa
=
NFA
(
states
,
characters
,
transition
,
init
,
{
final
})
return
nfa
class
DFA
:
Transition
=
Dict
[
Tuple
[
State
,
Character
],
State
]
type_var
=
TypeVar
(
'type_var'
)
...
...
@@ -173,7 +63,7 @@ class DFA:
self
.
transition
=
self
.
dict_or_none
(
transition
)
self
.
init
=
init
self
.
final
=
self
.
set_or_none
(
final
)
assert
self
.
check
assert
self
.
check
()
def
check
(
self
)
->
bool
:
# # scheme of automaton - empty sets and dicts are implemention only variant
...
...
@@ -439,7 +329,9 @@ class DFA:
i
+=
1
return
dfa
def
dfa_to_reg
(
self
)
->
REG
:
def
dfa_to_reg
(
self
)
->
Any
:
from
reg_grammars
import
REG
,
Terminal
,
Nonterminal
nonterminals
:
Set
[
Nonterminal
]
=
set
()
terminals
:
Set
[
Terminal
]
=
set
()
rules
:
Dict
[
Nonterminal
,
Set
[
Union
[
Terminal
,
Tuple
[
Terminal
,
Nonterminal
]]]]
=
dict
()
...
...
@@ -484,10 +376,9 @@ class DFA:
return
reg
def
is_empty
(
self
)
->
bool
:
reached
:
Deque
[
State
]
=
deque
()
reached
.
append
(
self
.
init
)
# TODO ask: I need to do it like this bc State is not iterable - shall it be?
reachable
:
Set
[
State
]
=
set
()
reachable
.
add
(
self
.
init
)
reached
:
Deque
[
State
]
=
deque
([
self
.
init
])
reachable
:
Set
[
State
]
=
{
self
.
init
}
while
len
(
reached
)
>
0
:
actual
=
reached
.
popleft
()
for
character
in
self
.
characters
:
...
...
reg_grammars.py
0 → 100644
View file @
e7408f3b
from
__future__
import
annotations
from
typing
import
Set
,
Dict
,
Union
,
Tuple
,
TypeVar
from
reg_automata
import
Character
,
State
,
NFA
class
Terminal
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
def
__eq__
(
self
,
obj
):
if
isinstance
(
obj
,
Terminal
):
return
obj
.
name
==
self
.
name
return
False
def
__hash__
(
self
):
return
hash
(
self
.
name
)
class
Eps
:
pass
class
Nonterminal
:
def
__init__
(
self
,
name
:
str
):
self
.
name
=
name
def
__eq__
(
self
,
obj
):
if
isinstance
(
obj
,
Nonterminal
):
return
obj
.
name
==
self
.
name
return
False
def
__hash__
(
self
):
return
hash
(
self
.
name
)
class
REG
:
Rules
=
Dict
[
Nonterminal
,
Set
[
Union
[
Terminal
,
Tuple
[
Terminal
,
Nonterminal
]]]]
type_var
=
TypeVar
(
'type_var'
)
# TODO should accept init -> epsilon
def
__init__
(
self
,
nonterminals
:
Set
[
Nonterminal
],
terminals
:
Set
[
Terminal
],
rules
:
Rules
,
init
:
Nonterminal
):
self
.
nonterminals
=
nonterminals
self
.
terminals
=
terminals
self
.
rules
=
rules
self
.
init
=
init
assert
self
.
check
# TODO ask about concept
def
check
(
self
)
->
bool
:
# scheme of grammar - empty sets and dicts are implemention only variant
if
len
(
self
.
nonterminals
)
==
0
:
assert
len
(
self
.
terminals
)
==
0
and
len
(
self
.
rules
)
==
0
and
self
.
init
==
None
,
"nonempty scheme of grammar"
return
True
nonterminal_names
=
set
(
map
(
lambda
x
:
x
.
name
,
self
.
nonterminals
))
terminal_names
=
set
(
map
(
lambda
x
:
x
.
name
,
self
.
terminals
))
assert
len
(
nonterminal_names
.
intersection
(
terminal_names
))
==
0
,
"name conflict"
for
nonterminal
in
self
.
rules
:
assert
nonterminal
in
self
.
nonterminals
,
"unknown nonterminal "
+
nonterminal
.
name
for
rule
in
self
.
rules
[
nonterminal
]:
if
isinstance
(
rule
,
Terminal
):
assert
rule
in
self
.
terminals
,
"unknown terminal "
+
rule
.
name
else
:
assert
rule
[
0
]
in
self
.
terminals
,
"unknown terminal "
+
rule
[
0
].
name
assert
rule
[
1
]
in
self
.
nonterminals
,
"unknown nonterminal "
+
rule
[
1
].
name
assert
self
.
init
in
self
.
nonterminals
,
"init not in nonterminals"
return
True
def
reg_to_nfa
(
self
)
->
NFA
:
init
=
State
(
self
.
init
.
name
)
states
:
Set
[
State
]
=
set
()
for
nonterminal
in
self
.
nonterminals
:
state
=
State
(
nonterminal
.
name
)
states
.
add
(
state
)
characters
:
Set
[
Character
]
=
set
()
for
terminal
in
self
.
terminals
:
character
=
Character
(
terminal
.
name
)
characters
.
add
(
character
)
final
=
State
(
"new_final"
)
# TODO assert that name is unique, as for hell in make_total
states
.
add
(
final
)
transition
:
Dict
[
Tuple
[
State
,
Character
],
Set
[
State
]]
=
dict
()
for
nonterminal
in
self
.
rules
:
state
=
State
(
nonterminal
.
name
)
for
rule
in
self
.
rules
[
nonterminal
]:
# rule A -> a becomes d(A, a) = final
if
isinstance
(
rule
,
Terminal
):
# TODO and a is not \eps
character
=
Character
(
rule
.
name
)
if
(
state
,
character
)
in
transition
:
transition
[
state
,
character
].
add
(
final
)
else
:
transition
[
state
,
character
]
=
{
final
}
# rule A -> aB becomes d(A, a) = B
elif
(
state
,
rule
[
0
])
in
transition
:
character
=
Character
(
rule
[
0
].
name
)
move
=
State
(
rule
[
1
].
name
)
transition
[
state
,
character
].
add
(
move
)
else
:
character
=
Character
(
rule
[
0
].
name
)
move
=
State
(
rule
[
1
].
name
)
transition
[
state
,
character
]
=
{
move
}
# TODO if init -> \eps: nfa.final.add(nfa.init)
# I need to know how to treat \eps
nfa
=
NFA
(
states
,
characters
,
transition
,
init
,
{
final
})
return
nfa
\ No newline at end of file
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment