Commit 47886040 authored by Kateřina Sloupová's avatar Kateřina Sloupová
Browse files

thesis submitted: fixes in CFG parsing, update of user reference, website tweaks and cleanup

parent 8197cb07
Pipeline #62615 passed with stage
in 51 seconds
from lib.parsing.parser import Parser
from lib.common import State, Character, Eps, Terminal, Nonterminal
from lib.dfa import Composition as comp
from typing import Set, Dict, Tuple, Union
from copy import deepcopy
from antlr4 import RecognitionException
from lib.reg import RegGrammar, DFA, NFA, RegEx
from evalweb.web_checker import WebChecker
def make_dfa(states: Set[str], characters: Set[str],
transition: Dict[Tuple[str, str], str], init: str, final: Set[str]):
new_init = State(init)
new_states: Set[State] = set()
new_states.add(new_init)
dfa = DFA(new_states, set(), {}, new_init, set())
for name in states:
state = State(name)
dfa.states.add(state)
for name in characters:
character = Character(name)
dfa.characters.add(character)
for name in final:
state = State(name)
dfa.final.add(state)
for x, y in transition:
state = State(x)
character = Character(y)
move = State(transition[x, y])
dfa.transition[state, character] = move
dfa.check()
return dfa
def reg_1():
S = Nonterminal("S")
A = Nonterminal("A")
a = Terminal("a")
nonterminals = {S, A}
init = S
terminals = {a}
rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict()
rules[S] = {(a, S), (a)}
rules[A] = {(a)}
reg = RegGrammar(nonterminals, terminals, rules, init)
return reg
def reg_2():
S = Nonterminal("S")
A = Nonterminal("A")
a = Terminal("a")
nonterminals = {S, A}
init = S
terminals = {a}
rules : Dict[Nonterminal, Set[Union[Terminal, Tuple[Terminal, Nonterminal]]]] = dict()
reg = RegGrammar(nonterminals, terminals, rules, init)
return reg
def nfa_1():
q0 = State("q0")
q1 = State("q1")
q2 = State("q2")
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
def nfa_e():
q0 = State("q0")
q1 = State("q1")
q2 = State("q2")
q3 = State("q3")
q4 = State("q4")
a = Character("a")
b = Character("b")
c = Character("c")
d = Character("d")
e = Eps()
transition: Dict[Tuple[State, Union[Character, Eps]], Set[State]] = \
{(q0, e): {q1}, (q1, a): {q0}, (q1, d): {q3}, (q1, e): {q2},
(q2, a): {q3}, (q3, e): {q4}, (q4, b): {q3}, (q4, c): {q2}}
nfae = NFA({q0, q1, q2, q3, q4}, {a, b, c, d}, transition, q0, {q2})
return nfae
def dfa_eq(str1, str2):
try:
parser = Parser()
dfa1 = parser.str_to_dfa(str1)
print(parser.dfa_to_str(dfa1))
dfa2 = parser.str_to_dfa(str2)
print(parser.dfa_to_str(dfa2))
return DFA.is_equivalent(dfa1, dfa2)
except RecognitionException as re:
print(re)
def regex_test(str):
parser = Parser()
ast = parser.str_to_regex(str)
str1 = parser.regex_to_str(ast)
#ast1 = parser.str_to_reg(str1)
print(str)
print(str1)
#print(parser.reg_to_str(ast1))
efa = ast.regex_to_efa()
print(parser.nfa_to_str(efa))
print()
def grammar_test(str):
parser = Parser()
gra = parser.str_to_cfg(str)
str1 = parser.cfg_to_str(gra, True)
#ast1 = parser.str_to_reg(str1)
print(str)
print(str1)
print("is regular?", gra.is_regular())
#gra.cfg_to_reggrammar()
print()
def web_conv(str, type, task):
try:
web = WebChecker(str, task)
print(web.convert(type))
except RecognitionException as re:
print(re)
def main():
dfa_1 = make_dfa({"q0", "q1"}, {"a"}, {("q0", "a"): "q1", ("q1", "a"): "q1"}, "q0", {"q1"})
dfa_2 = make_dfa({"r_0", "r_1", "r_2"}, {"a", "b"}, {("r_0", "a"): "r_1", ("r_0", "b"): "r_1",
("r_1", "a"): "r_2", ("r_1", "b"): "r_2"}, "r_0", {"r_2"})
dfa_3 = make_dfa({"1", "2", "3", "4", "5", "6", "7"}, {"a", "b"}, {("1", "a"): "2", ("2", "a"): "3", ("2", "b"): "4",
("3", "a"): "6", ("3", "b"): "5", ("4", "a"): "3", ("4", "b"): "2", ("5", "a"): "6", ("5", "b"): "3",
("6", "a"): "2", ("7", "a"): "6", ("7", "b"): "1", }, "1", {"3", "5", "6"})
reg1 = reg_1()
reg2 = reg_2()
nfa1 = nfa_1()
parser = Parser()
print("parser.dfa_to_str():")
print("String representation of DFA, simple/full.")
print()
print(parser.dfa_to_str(dfa_1))
print()
print(parser.dfa_to_str(dfa_1, True))
print()
print("______________")
print("DFA.accepts():")
print("Test of DFA accepting given word:")
print("dfa_1.accepts('a'):", dfa_1.accepts("a"))
print("dfa_1.accepts('ab'):", dfa_1.accepts("ab"))
print()
print("________________________________")
print("DFA.make_total(), DFA.is_total()")
print("Add new terminal for DFA, check its totality, then make total.")
print()
b = Terminal("b")
dfa_1.characters.add(b)
print("dfa_1.terminals.add(b), dfa_1.is_total():", dfa_1.is_total())
print()
total_dfa = dfa_1.total()
print("dfa_1.total(), total_dfa.is_total():", total_dfa.is_total())
print()
print(parser.dfa_to_str(total_dfa, True))
print()
print("________________")
print("DFA.complement()")
print("Complement of DFA.")
compl_dfa = dfa_1.complement()
print(parser.dfa_to_str(compl_dfa, True))
print()
print("_________________")
print("DFA.composition()")
print("Composition makes union, intersection and subtraction of two DFAs.")
print()
print("second DFA:")
print(parser.dfa_to_str(dfa_2, True))
print()
print("Composition:")
union = dfa_1.union(dfa_1, dfa_2)
print(parser.dfa_to_str(union, True))
print()
print("Intersection:")
intersection = dfa_1.intersection(dfa_1, dfa_2)
print(parser.dfa_to_str(intersection, True))
print()
print("___________________________")
print("DFA.eliminate_unreachable()")
print("Add new state (also to transition) and eliminate unreachable states.")
dfa_x = deepcopy(dfa_1)
q_x = State("q_x")
a = Terminal("a")
dfa_x.states.add(q_x)
dfa_x.final.add(q_x)
dfa_x.transition[q_x, a] = q_x
print()
print("DFA with new state:")
print(parser.dfa_to_str(dfa_x, True))
print()
print("DFA without unreachable states:")
eliminated = dfa_x.eliminate_unreachable()
print(parser.dfa_to_str(eliminated, True))
print()
print("______________")
print("DFA.minimize()")
print("Minimization of DFA from slides:")
print()
print(parser.dfa_to_str(dfa_3, True))
print()
print("Minimal DFA:")
minimal = dfa_3.minimize()
print(parser.dfa_to_str(minimal, True))
print()
print("______________")
print("DFA.canonize()")
print("Canonization of previous minimized DFA.")
print()
canonical = minimal.canonize()
print(parser.dfa_to_str(canonical, True))
print()
print("__________________________________")
print("DFA.dfa_to_reg(), REG.reg_to_nfa()")
print("Transformation of DFA to REG and REG to NFA")
print("plus string representation of REG and NFA.")
print()
print("Original DFA:")
dfa_4 = make_dfa({"q0", "q1"}, {"a"}, {("q0", "a"): "q1", ("q1", "a"): "q1"}, "q0", {"q1"})
print(parser.dfa_to_str(dfa_4, True))
print()
dfareg = dfa_4.dfa_to_nfa().nfa_to_reggrammar()
print("DFA transformed to REG:")
print(parser.reggrammar_to_str(dfareg, True))
print()
regdfa = dfareg.reggrammar_to_nfa()
print("REG transformed to NFA:")
print(parser.nfa_to_str(regdfa, True))
print()
print(dfa_eq(parser.dfa_to_str(regdfa.determinize()),parser.dfa_to_str(dfa_4)).left_counterexample,
dfa_eq(parser.dfa_to_str(regdfa.determinize()),parser.dfa_to_str(dfa_4)).right_counterexample)
print("__________________________________")
print("DFA.is_empty(), DFA.is_equivalent()")
print("Emptiness with counterexample and equivalence \n"
"of DFA through intersections with complements.")
print()
print(parser.dfa_to_str(dfa_3))
result = dfa_3.is_empty()
print("is dfa3 empty?", result)
print("dfa3 and canonical dfa3: ", DFA.is_equivalent(dfa_3, canonical), ", should be True")
if not result:
print(result.counterexample)
print()
print("__________________________________")
print("NFA.determinize()")
print("Determinization of NFA to DFA:")
det = nfa1.determinize()
print(parser.nfa_to_str(nfa1, True))
print()
print(parser.dfa_to_str(det, True))
print("__________________________________")
print("NFA.eliminate_epsilon()")
print("Elimination of epsilon steps in NFA.")
nfae = nfa_e()
print(parser.nfa_to_str(nfae))
print()
nfa_elim = nfae.eliminate_epsilon()
print(parser.nfa_to_str(nfa_elim))
print("__________________________________")
print("Testing parsers")
print("Input of parser.str_to_dfa:")
print("init=0 (0,x)=1 (0,y)=2 (1,x)=1 (1,y)=1 (2,x)=0 (2,y)=4 (3,x)=2 (3,y)=5 (4,x)=3 (4,y)=0 (5,x)=5 (5,y)=5 final={4,5}")
dfa_p = parser.str_to_dfa("init=0 (0,x)=1 (0,y)=2 (1,x)=1 (1,y)=1 (2,x)=0 (2,y)=4 (3,x)=2 (3,y)=5 (4,x)=3 (4,y)=0 (5,x)=5 (5,y)=5 final={4,5}")
print("Output of parser.dfa_to_str should be identical:")
print(parser.dfa_to_str(dfa_p))
print()
print("Try equality of automata from strings:")
str1 = "init=0 (0, a)=1 (0, b)=2 (1, a)=1 (2,b)=2 final={1,2}"
str2 = "init=q0 (q0, a)=q1 (q0, b)=q2 (q1,a)=q1 (q2,b)=q3 (q3,b)=q3 final={q1, q2, q3}"
print(dfa_eq(str1, str2).left_counterexample, dfa_eq(str1, str2).right_counterexample)
print()
print("Input of parser.str_to_nfa:")
print("init=0 (0,x)={1} (0,y)={2} (1,x)={1} (1,y)={1} (2,x)={0,1,2} (2,y)={1,2} final={2,3}")
nfa_p = parser.str_to_nfa("init=0 (0,x)={1} (0,y)={2} (1,x)={1} (1,y)={1} (2,x)={0,1,2} (2,y)={1,2} final={2,3}")
print("Output of parser.nfa_to_str should be identical:")
print(parser.nfa_to_str(nfa_p))
print()
print("Parsing EFA:")
print("init=0 (0,x)={1} (0,\e)={2} (1,x)={1} (1,y)={1} (2,\e)={0,1,2} (2,b)={1,2} final={2,3}")
efa_p = parser.str_to_nfa("init=0 (0,x)={1} (0,\e)={2} (1,x)={1} (1,y)={1} (2,\e)={0,1,2} (2,b)={1,2} final={2,3}")
print("Output of parser.nfa_to_str should be identical:")
print(parser.nfa_to_str(efa_p))
print()
print("__________________________________")
print("Testing regex")
regex_test("(c.(b.b*.(c+ab)+cb)*.(ε+a))+b")
regex_test("b")
regex_test("c+b")
regex_test("ε")
regex_test("c.(b.b*c*a*.(b*+ac)+b).a")
regex_test("b*a*c*")
regex_test("b^+a^+c^+")
regex_test("b^+ + a^+ + c^+")
regex_test("bac")
regex_test("(b)(a)(c)")
regex_test("b+a+c+a+c")
regex_test("∅")
regex_test("\e")
regex_test("(∅ + ∅^*).(∅^* + ∅∅^+)")
print("__________________________________")
print("More transitions warning")
ts = parser.str_to_nfa("init=0 (0,a)={0} (0,a)={1} (1,a)={1} final={1}")
print(parser.nfa_to_str(ts))
print()
print("__________________________________")
print("Parsing grammars")
grammar_test("S->a|aA;A->a|b")
grammar_test("S->a|aA|\e\nA->a|b|<aBc_JK50l>\n<aBc_JK50l>->AaBa")
grammar_test("S->a|aA|\e;A->a|b")
grammar_test("S->a|aA|\e;A->a|bS")
grammar_test("S'->a|aA''|\e;A''->a|bS'|<ab_0>''")
grammar_test("S->a;\nS->aA;\nS->\e;\nA->a;\nA->bS;\n")
words = dfa_eq("init=1 (1, a)=2 (2,a)=2 (1,b)=3 final={2,3} #c",
"init=A (A, a)=B (A,b)=C (C,b)=C final={B,C}")
print(words.right_counterexample, words.left_counterexample, words.inf)
print()
print("Info pro web")
#web_eq("init=1 (1, a)=2 (2,a)=2 (1,b)=3 final={2,3}", 'DFA',"init=A (A, a)=B (A,b)=C (C,b)=C final={B,C}", 'DFA')
web_conv("S->a|aA;A->a|b", "GRA", "DFA")
main()
\ No newline at end of file
......@@ -21,40 +21,44 @@
<h1 class="title">Zadávání formalismů pro popis regulárních jazyků</h1>
</header>
<h2 id="konečné-automaty-dfa-nfa-nfa-s-ε-kroky">Konečné automaty (DFA, NFA, NFA s ε-kroky)</h2>
<p>Pro popis konečného automatu je třeba zapsat iniciální stav, přechodovou funkci a množinu koncových stavů.</p>
<p>Pro popis konečného automatu je třeba zapsat iniciální stav, přechodovou funkci a množinu koncových stavů. Validní automat musí obsahovat alespoň jeden (iniciální) stav.</p>
<p>Počáteční stav lze explicitně definovat jako <code>init=stav</code> na počátku zápisu automatu. Není-li počáteční stav takto specifikován, pak je jako počáteční stav vyhodnocen ten, který se jako první objeví v přechodové funkci.</p>
<p>Přechodová funkce sestává z pravidel ve tvaru:</p>
<p>Přechodová funkce sestává z přechodů zapsaných ve tvaru:</p>
<ul>
<li><code>(vstupní_stav,znak)=výstupní_stav</code> pro deterministické automaty,</li>
<li><code>(vstupní_stav,znak)={výstupní_stav1,výstupní_stav2, ..., výstupní_stavN}</code> pro nedeterministické automaty.</li>
</ul>
<p>V nedeterminstických automatech s ε-kroky lze místo znaku v přechodové funkci zapsat přechod pod prázdným slovem pomocí znaku <code>ε</code> nebo <code>\e</code>. Není vhodné uvádět pro stejnou dvojici <code>(vstupní_stav,znak)</code> v přechodové funkci více přechodů než jeden, vyhodnocovací služba v takovém případě bude brát v úvahu jenom poslední zaznamenaný přechod a upozorní na možný problém.</p>
<p>Zápis množiny koncových stavů je <code>final={koncový_stav1,koncový_stav2, ..., koncový_stavN}</code>, je na samém konci zápisu a nelze jej vynechat.</p>
<p>Validní automat musí obsahovat alespoň jeden stav.</p>
<p>V názvech stavů a znaků lze použít malá i velká písmena anglické abecedy, číslice <code>0–⁠9</code> a znaky <code>_</code> a <code>'</code>. Lze tvořit i víceznakové sekvence jako názvy stavů. Bílé znaky (mezera, tab, konec řádku) mezi jednotlivými identifikátory nemají na vyhodnocení automatu vliv, nelze je však použít uvnitř názvů stavů nebo znaků.</p>
<p>Zápis množiny koncových stavů je <code>final={koncový_stav1,koncový_stav2, ..., koncový_stavN}</code>, je na samém konci zápisu, oddělen aspoň jedním bílým znakem (mezera, tab, konec řádku) od přechodové funkce, a nelze jej vynechat.</p>
<p>Jako názvy stavů a znaků (identifikátory) lze použít:</p>
<ul>
<li>malá i velká písmena anglické abecedy, číslice <code>0–⁠9</code>, znaky <code>_</code> a <code>'</code> nebo víceznakovou sekvenci uvedených symbolů,</li>
<li>sekvenci jakýchkoli znaků kromě uvozovek a bílých znaků uzavřenou v uvozovkách (např. stav <code>"{A,B,C}"</code>).</li>
</ul>
<p>Bílé znaky mezi jednotlivými identifikátory nemají na vyhodnocení automatu vliv, nelze je však použít uvnitř názvů stavů nebo znaků.</p>
<h3 id="kanonický-automat">Kanonický automat</h3>
<p>Vyžaduje-li zadání úlohy kanonizaci automatu, použijte při pojmenovávání velká písmena anglické abecedy v lexikografickém pořadí. V případě potřeby více než 26 stavů následují vícemístné kombinace písmen: A, B, …, Y, Z, AA, AB, …, AZ, BA, BB, …, ZY, ZZ, AAA, AAB, … (jde o bijektivní poziční soustavu s bází 26).</p>
<h3 id="příklady">Příklady:</h3>
<ul>
<li><code>init=0 (0,a)=1 (0,b)=1 final={0,1}</code> (DFA s počátečním stavem <code>0</code>)</li>
<li><code>(q_0, a) = q_1 (q_0, b) = q_1 (q_1, a) = q_1 final = {q_1}</code> (DFA s počátečním stavem <code>q_0</code>)</li>
<li><code>init=init (init,a)={fst,snd} (fst,b)={snd} (snd,b)={fst} final={fst,snd}</code> (NFA s počátečním stavem <code>init</code>)</li>
<li><code>init=in (in,a)={fst,snd} (fst,b)={snd} (snd,b)={fst} final={fst,snd}</code> (NFA s počátečním stavem <code>in</code>)</li>
<li><code>(0,ε)={1} final={}</code> (NFA s epsilon kroky, počátečním stavem <code>init</code> a žádnými koncovými stavy)</li>
<li><code>(A,a)=B (A,b)=C</code><br />
<code>(B,a)=A (B,b)=B</code><br />
<code>(C,a)=C (C,b)=A</code><br />
<li><code>(A,"(a)")=B (A,b)=C</code><br />
<code>(B,"(a)")=A (B,b)=B</code><br />
<code>(C,"(a)")=C (C,b)=A</code><br />
<code>final={A}</code> (DFA s počátečním stavem <code>A</code>)</li>
</ul>
<h2 id="regulární-výrazy">Regulární výrazy</h2>
<p>Základní regulární výrazy jsou znak, prázdné slovo a prázdný jazyk:</p>
<ul>
<li>jako znaky lze použít malá i velká písmena anglické abecedy a číslice <code>0–⁠9</code>,</li>
<li>jako znaky lze použít malá i velká písmena anglické abecedy, číslice <code>0–⁠9</code> nebo také sekvence jakýchkoliv znaků v uvozovkách (kromě uvozovek a bílých znaků),</li>
<li>prázdné slovo (epsilon) se značí jako <code>\e</code> nebo <code>ε</code>,</li>
<li>prázdný jazyk je možné zapsat jako <code>\0</code> nebo <code></code>.</li>
<li>prázdný jazyk je možné zapsat jako <code>\0</code> (nula) nebo <code></code>.</li>
</ul>
<p>Další regulární výrazy vznikají použitím operací iterace, zřetězení a sjednocení:</p>
<ul>
<li>regulární výraz je možné iterovat operátory <code>^*</code> (iterace) a <code>^+</code> (pozitivní iterace), jako iterovaný se vyhodnotí nejbližší znak nebo regulární výraz v nejbližší závorce (nejblíže operátoru zleva),</li>
<li>regulární výraz je možné použít operátory <code>^*</code> (iterace) a <code>^+</code> (pozitivní iterace), jako iterovaný se vyhodnotí nejbližší znak nebo regulární výraz v nejbližší závorce (nejblíže operátoru zleva),</li>
<li>každé dva regulární výrazy lze zřetězit operátorem <code>.</code>,</li>
<li>operaci <code>+</code>, která sémanticky odpovídá sjednocení dvou regulárních výrazů, lze zapsat pomocí operátoru <code>+</code>.</li>
</ul>
......@@ -66,20 +70,21 @@
<li><code>(a + b + c^*) + \e</code> je ekvivalentní s <code>a + b + (c)^* + ε</code></li>
</ul>
<h2 id="regulární-gramatiky">Regulární gramatiky</h2>
<p>Z gramatiky stačí definovat množinu pravidel, iniciálním neterminálem je první vyskytující se neterminál. Pravidla regulární gramatiky mohou být tvaru:</p>
<ul>
<li><code>Neterminál -&gt; TerminálNeterminál</code> (např. <code>A -&gt; aA</code>),</li>
<li><code>Neterminál -&gt; Terminál</code> (např. <code>B -&gt; b</code>),</li>
<li><code>Neterminál -&gt; ε</code> (např. <code>S -&gt; ε</code>),</li>
</ul>
<p>Pokud regulární gramatika generuje prázdné slovo (ε), pak lze v pravidle použít symbol <code>ε</code> nebo <code>\e</code> (ovšem pouze u iniciálního neterminálu, který se v tomto případě nesmí objevit v pravé straně žádného z pravidel). Pravidla pro různé neterminály je třeba oddělit středníkem nebo koncem řádku. Jako šipku lze psát <code>-&gt;</code> i unicodový znak <code></code>. Více přepisovacích pravidel se stejnou levou stranou lze zapsat také pomocí oddělovače <code>|</code> (např. <code>A -&gt; aA | b</code>).</p>
<p>Z gramatiky stačí definovat množinu pravidel, iniciálním neterminálem je první vyskytující se neterminál.</p>
<p>Neterminál je tvořen:</p>
<ul>
<li>jedním velkým písmenem anglické abecedy (např. <code>S</code>, <code>A</code>),</li>
<li>sekvencí malých a velkých písmen anglické abecedy, číslic nebo znaku <code>_</code> uzavřenou do lomených závorek <code>&lt;&gt;</code> (např. <code>&lt;abAB&gt;</code>, <code>&lt;S_0&gt;</code>),</li>
<li>sekvencí malých a velkých písmen anglické abecedy, číslic nebo znaku <code>_</code> uzavřenou do lomených závorek <code>&lt;</code>, <code>&gt;</code> (např. <code>&lt;a&gt;</code>, <code>&lt;abAB&gt;</code>, <code>&lt;S_0&gt;</code>),</li>
<li>jedním malým písmenem anglické abecedy nebo předchozím typem neterminálu (velké písmeno, sekvence v závorkách) s jedním nebo více apostrofy (např. <code>S'</code>, <code>a''</code>, <code>&lt;aB_0&gt;'</code>).</li>
</ul>
<p>Terminálem může být jedno malé písmeno anglické abecedy nebo číslice <code>0–⁠9</code>.</p>
<p>Terminálem může být jedno malé písmeno anglické abecedy, číslice <code>0–⁠9</code> nebo sekvence jakýchkoliv znaků (kromě <code>"</code> a bílých znaků) v uvozovkách.</p>
<p>Pravidla regulární gramatiky mohou být tvaru:</p>
<ul>
<li><code>Neterminál -&gt; TerminálNeterminál</code> (např. <code>A -&gt; aA</code>),</li>
<li><code>Neterminál -&gt; Terminál</code> (např. <code>B -&gt; b</code>),</li>
<li><code>Neterminál -&gt; ε</code> (např. <code>S -&gt; ε</code>), ovšem pouze u iniciálního neterminálu, který se v tomto případě nesmí objevit v pravé straně žádného z pravidel.</li>
</ul>
<p>Jako prázdné slovo (ε) lze psát <code>ε</code> nebo <code>\e</code>. Pravidla pro různé neterminály je třeba oddělit čárkou, středníkem nebo koncem řádku. Jako šipku lze psát <code>-&gt;</code> i unicodový znak <code></code>. Více přepisovacích pravidel se stejnou levou stranou lze zapsat také pomocí oddělovače <code>|</code> (např. <code>A -&gt; aA | b</code>). Mezery a taby lze mimo názvů terminálů a neterminálů používat libovolně (konec řádku však odděluje pravidla).</p>
<h3 id="příklady-2">Příklady</h3>
<ul>
<li><code>S -&gt; aS | aA | a; A -&gt; bA | aS</code></li>
......
......@@ -6,22 +6,25 @@ title: Zadávání formalismů pro popis regulárních jazyků
## Konečné automaty (DFA, NFA, NFA s ε-kroky)
Pro popis konečného automatu je třeba zapsat iniciální stav, přechodovou funkci a množinu koncových stavů.
Pro popis konečného automatu je třeba zapsat iniciální stav, přechodovou funkci a množinu koncových stavů. Validní automat musí obsahovat alespoň jeden (iniciální) stav.
Počáteční stav lze explicitně definovat jako `init=stav` na počátku zápisu automatu. Není-li počáteční stav takto specifikován, pak je jako počáteční stav vyhodnocen ten, který se jako první objeví v přechodové funkci.
Přechodová funkce sestává z pravidel ve tvaru:
Přechodová funkce sestává z přechodů zapsaných ve tvaru:
* `(vstupní_stav,znak)=výstupní_stav` pro deterministické automaty,
* `(vstupní_stav,znak)={výstupní_stav1,výstupní_stav2, ..., výstupní_stavN}` pro nedeterministické automaty.
V nedeterminstických automatech s ε-kroky lze místo znaku v přechodové funkci zapsat přechod pod prázdným slovem pomocí znaku `ε` nebo `\e`. Není vhodné uvádět pro stejnou dvojici `(vstupní_stav,znak)` v přechodové funkci více přechodů než jeden, vyhodnocovací služba v takovém případě bude brát v úvahu jenom poslední zaznamenaný přechod a upozorní na možný problém.
Zápis množiny koncových stavů je `final={koncový_stav1,koncový_stav2, ..., koncový_stavN}`, je na samém konci zápisu a nelze jej vynechat.
Zápis množiny koncových stavů je `final={koncový_stav1,koncový_stav2, ..., koncový_stavN}`, je na samém konci zápisu, oddělen aspoň jedním bílým znakem (mezera, tab, konec řádku) od přechodové funkce, a nelze jej vynechat.
Validní automat musí obsahovat alespoň jeden stav.
Jako názvy stavů a znaků (identifikátory) lze použít:
V názvech stavů a znaků lze použít malá i velká písmena anglické abecedy, číslice `0–⁠9` a znaky `_` a `'`. Lze tvořit i víceznakové sekvence jako názvy stavů. Bílé znaky (mezera, tab, konec řádku) mezi jednotlivými identifikátory nemají na vyhodnocení automatu vliv, nelze je však použít uvnitř názvů stavů nebo znaků.
* malá i velká písmena anglické abecedy, číslice `0–⁠9`, znaky `_` a `'` nebo víceznakovou sekvenci uvedených symbolů,
* sekvenci jakýchkoli znaků kromě uvozovek a bílých znaků uzavřenou v uvozovkách (např. stav `"{A,B,C}"`).
Bílé znaky mezi jednotlivými identifikátory nemají na vyhodnocení automatu vliv, nelze je však použít uvnitř názvů stavů nebo znaků.
### Kanonický automat
......@@ -30,24 +33,24 @@ Vyžaduje-li zadání úlohy kanonizaci automatu, použijte při pojmenováván
### Příklady:
* `init=0 (0,a)=1 (0,b)=1 final={0,1}` (DFA s počátečním stavem `0`)
* `(q_0, a) = q_1 (q_0, b) = q_1 (q_1, a) = q_1 final = {q_1}` (DFA s počátečním stavem `q_0`)
* `init=init (init,a)={fst,snd} (fst,b)={snd} (snd,b)={fst} final={fst,snd}` (NFA s počátečním stavem `init`)
* `init=in (in,a)={fst,snd} (fst,b)={snd} (snd,b)={fst} final={fst,snd}` (NFA s počátečním stavem `in`)
* `(0,ε)={1} final={}` (NFA s epsilon kroky, počátečním stavem `init` a žádnými koncovými stavy)
* `(A,a)=B (A,b)=C`
`(B,a)=A (B,b)=B`
`(C,a)=C (C,b)=A`
* `(A,"(a)")=B (A,b)=C`
`(B,"(a)")=A (B,b)=B`
`(C,"(a)")=C (C,b)=A`
`final={A}` (DFA s počátečním stavem `A`)
## Regulární výrazy
Základní regulární výrazy jsou znak, prázdné slovo a prázdný jazyk:
* jako znaky lze použít malá i velká písmena anglické abecedy a číslice `0–⁠9`,
* jako znaky lze použít malá i velká písmena anglické abecedy, číslice `0–⁠9` nebo také sekvence jakýchkoliv znaků v uvozovkách (kromě uvozovek a bílých znaků),
* prázdné slovo (epsilon) se značí jako `\e` nebo `ε`,
* prázdný jazyk je možné zapsat jako `\0` nebo `∅`.
* prázdný jazyk je možné zapsat jako `\0` (nula) nebo `∅`.
Další regulární výrazy vznikají použitím operací iterace, zřetězení a sjednocení:
* regulární výraz je možné iterovat operátory `^*` (iterace) a `^+` (pozitivní iterace), jako iterovaný se vyhodnotí nejbližší znak nebo regulární výraz v nejbližší závorce (nejblíže operátoru zleva),
* regulární výraz je možné použít operátory `^*` (iterace) a `^+` (pozitivní iterace), jako iterovaný se vyhodnotí nejbližší znak nebo regulární výraz v nejbližší závorce (nejblíže operátoru zleva),
* každé dva regulární výrazy lze zřetězit operátorem `.`,
* operaci `+`, která sémanticky odpovídá sjednocení dvou regulárních výrazů, lze zapsat pomocí operátoru `+`.
......@@ -62,21 +65,24 @@ Operace jsou seřazeny podle priority od nejvyšší po nejnižší, nejdříve
## Regulární gramatiky
Z gramatiky stačí definovat množinu pravidel, iniciálním neterminálem je první vyskytující se neterminál. Pravidla regulární gramatiky mohou být tvaru:
* `Neterminál -> TerminálNeterminál` (např. `A -> aA`),
* `Neterminál -> Terminál` (např. `B -> b`),
* `Neterminál -> ε` (např. `S -> ε`),
Pokud regulární gramatika generuje prázdné slovo (ε), pak lze v pravidle použít symbol `ε` nebo `\e` (ovšem pouze u iniciálního neterminálu, který se v tomto případě nesmí objevit v pravé straně žádného z pravidel). Pravidla pro různé neterminály je třeba oddělit středníkem nebo koncem řádku. Jako šipku lze psát `->` i unicodový znak `→`. Více přepisovacích pravidel se stejnou levou stranou lze zapsat také pomocí oddělovače `|` (např. `A -> aA | b`).
Z gramatiky stačí definovat množinu pravidel, iniciálním neterminálem je první vyskytující se neterminál.
Neterminál je tvořen:
* jedním velkým písmenem anglické abecedy (např. `S`, `A`),
* sekvencí malých a velkých písmen anglické abecedy, číslic nebo znaku `_` uzavřenou do lomených závorek `<>` (např. `<abAB>`, `<S_0>`),
* sekvencí malých a velkých písmen anglické abecedy, číslic nebo znaku `_` uzavřenou do lomených závorek `<`, `>` (např. `<a>`, `<abAB>`, `<S_0>`),
* jedním malým písmenem anglické abecedy nebo předchozím typem neterminálu (velké písmeno, sekvence v závorkách) s jedním nebo více apostrofy (např. `S'`, `a''`, `<aB_0>'`).
Terminálem může být jedno malé písmeno anglické abecedy nebo číslice `0–⁠9`.
Terminálem může být jedno malé písmeno anglické abecedy, číslice `0–⁠9` nebo sekvence jakýchkoliv znaků (kromě `"` a bílých znaků) v uvozovkách.
Pravidla regulární gramatiky mohou být tvaru:
* `Neterminál -> TerminálNeterminál` (např. `A -> aA`),
* `Neterminál -> Terminál` (např. `B -> b`),
* `Neterminál -> ε` (např. `S -> ε`), ovšem pouze u iniciálního neterminálu, který se v tomto případě nesmí objevit v pravé straně žádného z pravidel.
Jako prázdné slovo (ε) lze psát `ε` nebo `\e`. Pravidla pro různé neterminály je třeba oddělit čárkou, středníkem nebo koncem řádku. Jako šipku lze psát `->` i unicodový znak `→`. Více přepisovacích pravidel se stejnou levou stranou lze zapsat také pomocí oddělovače `|` (např. `A -> aA | b`). Mezery a taby lze mimo názvů terminálů a neterminálů používat libovolně (konec řádku však odděluje pravidla).
### Příklady
* `S -> aS | aA | a; A -> bA | aS`
......
......@@ -77,7 +77,8 @@ def compare():
task_solved=checker.task_solved, alphabets=checker.alphabets,
extra_word_ce=extra_word_ce, missing_word_ce=missing_word_ce,
is_task=checker.is_task, img_src=checker.img_src, langs=checker.languages,
teacher=checker.teacher, student=checker.student)
teacher=checker.teacher, student=checker.student,
teacher_type_string=types[checker.teacher.task], student_type_string=tasks[checker.student.task])
if request.method == 'POST' and 'example_button' in request.form:
teacher_type = teacher_form.make.data # of which types examples should be
......
......@@ -7,15 +7,15 @@
{% block content %}
<br>
Webový front end vyhodnocovací služby pro formální jazyky a automaty vznikl na
Webový front end nově implementované vyhodnocovací služby pro formální jazyky a automaty vznikl na
Fakultě informatiky Masarykovy univerzity v rámci
<a href="https://is.muni.cz/th/bwci5/">závěrečné práce</a> v roce 2020.
<br>
<br>
<a href="https://gitlab.fi.muni.cz/fja/eval/">GitLab</a>
Zdrojový kód: <a href="https://gitlab.fi.muni.cz/fja/eval/">GitLab</a>
<br>
<br>
Kateřina Sloupová, autor závěrečné práce<br>
Kateřina Sloupová, autorka závěrečné práce<br>
Jan Strejček, vedoucí<br>
Vladimír Štill, konzultant
......
......@@ -16,7 +16,7 @@
<div style="float:left;">{{ teacher_form.make(style="list-style:none") }}</div>
</div>
<label for="student_string">Moje řešení</label><br>
<label for="student_string">Řešení</label><br>
<div>
<div style="width:400px; float:right;">
<textarea style="width:400px;" name="student_string" id="student_string">{{ student_area }}</textarea></div>
......
......@@ -34,19 +34,19 @@
<b>Charakteristika:</b> {{ teacher.sizename }}<br><br>
<b>Příklad slova z jazyka:</b> {{ teacher.example }}<br><br>
<b>Původní popis:</b> <br>
{{ teacher.task }}: {{ teacher.string }}<br><br>
{{ teacher_type_string }}: {{ teacher.string }}<br><br>
<b>Popis pomocí minimálního DFA:</b> <br>
{{ teacher.minimal }}<br>
</div><br>
</div>
<div style="float:right;"><label for="student_string"><h3 style="text-align:center">
Jazyk mého řešení</h3></label>
Jazyk řešení</h3></label>
<div style="width:400px;" name="student_string" id="student_string">
<b>Charakteristika:</b> {{ student.sizename }}<br><br>
<b>Příklad slova z jazyka:</b> {{ student.example }}<br><br>
<b>Původní popis:</b> <br>
{{ student.task }}: {{ student.string }}<br><br>
{{ student_type_string }}: {{ student.string }}<br><br>
<b>Popis pomocí minimálního DFA:</b> <br>
{{ student.minimal }}<br>