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

REORGANIZED into modules, has import issues

parent 24fe9f8e
Pipeline #62432 failed with stage
in 25 seconds
......@@ -7,4 +7,4 @@ __pycache__
.pytest_cache
*.interp
*.tokens
evalweb
venv
from . import lib, parsing, evalweb, fja_checker
from grammars_cfg import CFG
from parser import Parser
from common import State, Character, Eps, Terminal, Nonterminal
from dfa import Composition as comp
from 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 reg import RegGrammar, DFA, NFA, RegEx
from web_checker import WebChecker
from lib.reg import RegGrammar, DFA, NFA, RegEx
from evalweb.web_checker import WebChecker
def make_dfa(states: Set[str], characters: Set[str],
......
import os
from flask import Flask, redirect, url_for
from . import evalweb
# taken from tutorial on flask.palletsprojects.com/en/1.1.x/tutorial
def create_app(test_config=None):
# create and configure the app
app = Flask(__name__, instance_relative_config=True)
app.config.from_mapping(SECRET_KEY='dev')
if test_config is None:
# load the instance config, if it exists, when not testing
app.config.from_pyfile('config.py', silent=True)
else:
# load the test config if passed in
app.config.from_mapping(test_config)
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
@app.route('/')
def index():
return redirect(url_for('eval.compare'))
app.register_blueprint(evalweb.bp)
app.add_url_rule('/compare', endpoint='index')
return app
\ No newline at end of file
from flask import Blueprint, flash, render_template, request
from flask_wtf import FlaskForm
from wtforms import RadioField
import sys
sys.path.append('~/eval')
#from . import web_checker
bp = Blueprint('eval', __name__, url_prefix='/')
tasks = {'DFA': 'DFA',
'TOT': 'Totální DFA',
'MIN': 'Minimální DFA',
'EFA': 'NFA (s ε-kroky)',
'NFA': 'NFA bez ε-kroků',
'GRA': 'Regulární gramatika',
'REG': 'Regulární výraz'}
types = {'DFA': 'DFA',
'EFA': 'NFA (s ε-kroky)',
'GRA': 'Regulární gramatika',
'REG': 'Regulární výraz'}
class TypeForm(FlaskForm):
make = RadioField('Typ', choices=list(types.items()), default='DFA', coerce=str)
class TaskForm(FlaskForm):
make = RadioField('Task', choices=list(tasks.items()), default='DFA', coerce=str)
@bp.route('/compare', methods=('GET', 'POST'))
def compare():
student_form = TaskForm(prefix='student_form')
teacher_form = TypeForm(prefix='teacher_form')
if request.method == 'POST':
teacher_type = teacher_form.make.data
teacher_string = request.form['teacher_string']
student_type = student_form.make.data
student_string = request.form['student_string']
#checker = WebChecker(student_string=student_string, task=student_type) # !!!
#checker.compare(teacher_string=teacher_string, teacher_type=teacher_type) # !!!
#if not checker.ok:
# extra_word_ce = checker.eq.left_counterexample
# missing_word_ce = checker.eq.right_counterexample
# inf = checker.eq.inf
extra_word_ce = None
missing_word_ce = None
inf = None
return render_template('result.html', compare=True, ok=True, inf=inf,
student_string=student_string, student_type=tasks[student_type],
teacher_string=teacher_string, teacher_type=types[teacher_type],
extra_word_ce=extra_word_ce, missing_word_ce=missing_word_ce)
flash(error)
return render_template('compare.html', student_form=student_form, teacher_form=teacher_form)
@bp.route('/convert', methods=('GET', 'POST'))
def convert():
student_form = TypeForm(prefix='student_form')
task_form = TaskForm(prefix='task_form')
if request.method == 'POST':
student_string = request.form['student_string']
student_type = student_form.make.data
task = task_form.make.data
#webchecker = WebChecker(student_string=student_string, task=task)
#output = webchecker.convert(student_type=student_type)
output = "result"
return render_template('result.html', compare=False, student_string=student_string,
student_type=types[student_type], task=tasks[task], output=output)
flash(error)
return render_template('convert.html', student_form=student_form, task_form=task_form)
@bp.route('/userref')
def userref():
return render_template('userref.html')
@bp.route('/about')
def about():
return render_template('about.html')
\ No newline at end of file
html { font-family: sans-serif; background: #eee; padding: 1rem; }
body { max-width: 960px; margin: 0 auto; background: white; }
h1 { font-family: serif; color: #377ba8; margin: 1rem 0; }
a { color: #377ba8; }
hr { border: none; border-top: 1px solid lightgray; }
nav { background: lightgray; display: flex; align-items: center; padding: 0 0.5rem; }
nav h1 { flex: auto; margin: 0; }
nav h1 a { text-decoration: none; padding: 0.25rem 0.5rem; }
nav ul { display: flex; list-style: none; margin: 0; padding: 0; }
nav ul li a, nav ul li span, header .action { display: block; padding: 0.5rem; }
.content { padding: 0 1rem 1rem; }
.content > header { border-bottom: 1px solid lightgray; display: flex; align-items: flex-end; }
.content > header h1 { flex: auto; margin: 1rem 0 0.25rem 0; }
.flash { margin: 1em 0; padding: 1em; background: #cae6f6; border: 1px solid #377ba8; }
.post > header { display: flex; align-items: flex-end; font-size: 0.85em; }
.post > header > div:first-of-type { flex: auto; }
.post > header h1 { font-size: 1.5em; margin-bottom: 0; }
.post .about { color: slategray; font-style: italic; }
.post .body { white-space: pre-line; }
.content:last-child { margin-bottom: 0; }
.content form { margin: 1em 0; display: flex; flex-direction: column; }
.content label { font-weight: bold; margin-bottom: 0.5em; }
.content input, .content textarea { margin-bottom: 1em; }
.content textarea { min-height: 12em; resize: vertical; }
input.danger { color: #cc2f2e; }
input[type=submit] { align-self: start; min-width: 10em; }
\ No newline at end of file
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}O vyhodnocovací službě{% endblock %}</h1>
{% endblock %}
{% block content %}
Ještě není úplně hotová.
{% endblock %}
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="UTF-8">
<title>FJA eval</title>
</head>
<body>
<!doctype html>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
<h1><a href="{{ url_for('index') }}">EVAL</a></h1>
<ul>
<li><a href="{{ url_for('eval.about') }}">O službě</a>
<li><a href="{{ url_for('eval.userref') }}">Uživatelská dokumentace</a>
</ul>
</nav>
<section class="content">
<br>
<label>Mód: </label>
<a href="{{ url_for('eval.compare') }}">Porovnání</a>
<a href="{{ url_for('eval.convert') }}">Převod</a>
<header>
{% block header %}{% endblock %}
</header>
{% for message in get_flashed_messages() %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% block content %}{% endblock %}
</section>
</body>
</html>
\ No newline at end of file
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Porovnání formalismů{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="teacher_string">Zadání</label>
<div>
<div style="width:400px; float:right;">
<textarea style="width:400px;" name="teacher_string" id="teacher_string">
{{ request.form['teacher_string'] }}</textarea></div>
{{ teacher_form.hidden_tag() }}
<div style="float:left;">{{ teacher_form.make }}</div>
</div>
<label for="student_string">Moje řešení</label><br>
<div>
<div style="width:400px; float:right;">
<textarea style="width:400px;" name="student_string" id="student_string">
{{ request.form['student_string'] }}</textarea></div>
{{ student_form.hidden_tag() }}
<div style="float:left;">{{ student_form.make }}</div>
</div>
<input type="submit" value="Porovnej">
</form>
Tento mód simuluje vyhodnocení odpovědníku v IS MU. Máte-li k dispozici správné řešení úlohy, můžete jej porovnat s vaším výsledkem.
Nezapomeňte vybrat, jakého typu je zadaný formalismus a jaký typ a vlastnosti se očekávají u vašeho řešení.
{% endblock %}
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Převod formalismu{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="student_string">Můj vstup typu</label><br>
<div>
<div style="width:400px; float:right;">
<textarea style="width:400px;" name="student_string" id="student_string">
{{ request.form['student_string'] }}</textarea></div>
{{ student_form.hidden_tag() }}
<div style="float:left;">{{ student_form.make }}</div>
</div>
<label>Převeď na typ</label><br>
{{ task_form.hidden_tag() }}
{{ task_form.make }}
<input type="submit" value="Převeď">
</form>
{% endblock %}
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Převod formalismu{% endblock %}</h1>
{% endblock %}
{% block content %}
<form method="post">
<label for="student_type">Můj vstup</label>
<input type="radio" id="dfa" name="student_type" value="dfa">
<label for="dfa">DFA</label><br>
<input type="radio" id="nfa" name="student_type" value="nfa">
<label for="nfa">NFA</label><br>
<input type="radio" id="grammar" name="student_type" value="grammar">
<label for="grammar">Gramatika</label>
<input type="radio" id="regex" name="student_type" value="regex">
<label for="regex">Regulární výraz</label>
</form>
<form method="post">
<label for="user_input">Můj vstup</label>
<textarea name="user_input" id="user_input">{{ request.form['user_input'] }}</textarea>
<input type="submit" value="Převeď">
</form>
{% endblock %}
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}
{% if compare %}Výsledek porovnání
{% else %}Výsledek převodu
{% endif %}
{% endblock %}</h1>
{% endblock %}
{% block content %}
<br>{% if compare %}
<label for="teacher_string">Zadání</label><br>
<textarea style="width:400px;" name="teacher_string" id="teacher_string">{{ teacher_string }}</textarea>
{{ teacher_type }}
{% endif %}
<br><label for="student_string">Můj vstup</label><br>
<textarea style="width:400px;" name="student_string" id="student_string">{{ student_string }}</textarea>
{{ student_type }}
{% if not compare %}
, převod na
{{ task }}
{% endif %}
<br><br>
{% if compare %}
{% if ok %}
Správné řešení, jazyky popisované oběma formalismy jsou ekvivalentní.
{% else %}
Špatné řešení, jazyky popisované oběma formalismy nejsou ekvivalentní.
{% if extra_word_ce %}
Příklad slova, které je ve studentově řešení a není v zadaném jazyce: {{ extra_word_ce }}
{% else %}
Studentovo řešení je podmnožinou zadaného jazyka.
{% endif %}<br>
{% if missing_word_ce %}
Příklad slova, které chybí ve studentově řešení a je v zadaném jazyce: {{ missing_word_ce }}
{% else %}
Studentovo řešení je nadmnožinou zadaného jazyka.
{% endif %}<br>
{% if inf %}
Rozdíl porovnávaných jazyků je nekonečný.
{% else %}
Rozdíl porovnávaných jazyků je konečný.
{% endif %}
{% endif %}
{% else %}
<label for="output">Výsledek</label><br>
<textarea style="width:400px;" name="output" id="output">{{ output }}</textarea>
{% endif %}
{% endblock %}
\ No newline at end of file
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
<head>
<meta charset="utf-8" />
<meta name="generator" content="pandoc" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
<title>Zadávání formalismů pro popis regulárních jazyků</title>
<style>
code{white-space: pre-wrap;}
span.smallcaps{font-variant: small-caps;}
span.underline{text-decoration: underline;}
div.column{display: inline-block; vertical-align: top; width: 50%;}
</style>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<style>code { background-color: #ddd; padding: 0.2em; }</style>
</head>
<body>
<header id="title-block-header">
<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>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>
<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>
<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>(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 />
<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>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>
</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>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>
<p>Operace jsou seřazeny podle priority od nejvyšší po nejnižší, nejdříve se tedy budou vyhodnocovat iterace, po nich zřetězení a s nejnižší prioritou operace <code>+</code>. Regulární výrazy je možné uzavírat do jednoduchých závorek ( <code>(</code> a <code>)</code> ), mezery jsou ignorovány. Znak je tvořen vždy jen jedním písmenem, více znaků následujících za sebou se vyhodnotí jako jejich implicitní zřetězení (<code>ab</code> je ekvivalentní <code>a.b</code>). Implicitně řetězit (bez explicitního zápisu pomocí tečky) lze nejen sekvenci znaků, ale také iterovaných regulárních výrazů a regulárních výrazů v závorkách (např. <code>abc^*a(b+c)</code> je ekvivalentní <code>a.b.((c)^*).a.(b+c)</code>).</p>
<h3 id="příklady-1">Příklady:</h3>
<ul>
<li><code>ab^*</code> je ekvivalentní s <code>a.((b)^*)</code></li>
<li><code>a(bc)^*d</code> je ekvivalentní s <code>a.(b.c)^*.d</code></li>
<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>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>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>
<h3 id="příklady-2">Příklady</h3>
<ul>
<li><code>S -&gt; aS | aA | a; A -&gt; bA | aS</code></li>
<li><code>A -&gt; aB'</code><br />
<code>A -&gt; bA</code><br />
<code>B' -&gt; aB'</code><br />
<code>B' -&gt; a</code></li>
<li><code>&lt;init&gt; -&gt; a&lt;00X&gt; | a&lt;ab&gt; | ε</code><br />
<code>&lt;ab&gt; -&gt; b</code></li>
</ul>
<h2 id="bezkontextové-gramatiky">Bezkontextové gramatiky</h2>
<p>Pro zápis CFG platí všechna pravidla jako pro regulární gramatiky kromě omezení tvaru pravé strany pravidel. Pravé strany pravidel nemusí být jen typu samotný terminál nebo dvojice terminál a neterminál, ale mohou obsahovat terminály i neterminály v libovolné kombinaci nebo ε.</p>
<h3 id="příklad">Příklad</h3>
<ul>
<li><code>S -&gt; aAa | bBb | ε; A -&gt; aAa | bab | bbb; B-&gt; bBaBb | A | a</code></li>
</ul>
</body>
</html>
import reg
import lib.reg as reg
from parsing.parser import Parser
import signal
from fja_checker.fja_checker import check_task, dfa_transform, nfa_transform, check_alphabets, check_empty
from fja_checker import check_task, dfa_transform, nfa_transform, check_alphabets, check_empty
class WebChecker():
def __init__(self, student_string: str, task: str):
......@@ -38,7 +39,7 @@ class WebChecker():
signal.alarm(50)
try:
parser = reg.Parser()
parser = Parser()
# todo nfas and so on
if student_type in {"DFA", "TOT", "MIN", "TOC", "MIC"}:
......
from typing import Tuple
import reg
import cfl
import lib.reg as reg
import lib.cfl as cfl
from parsing.parser import Parser, ParsingError
import sys
import signal
......@@ -18,7 +19,7 @@ def get_task(string: str) -> Tuple[str, str]:
def dfa_transform(string: str, automaton_type: str) -> reg.DFA:
try:
parser = reg.Parser()
parser = Parser()
if automaton_type in {"DFA", "TOT", "MIN", "TOC", "MIC"}:
automaton = parser.str_to_dfa(string)
elif automaton_type == "NFA":
......@@ -33,18 +34,18 @@ def dfa_transform(string: str, automaton_type: str) -> reg.DFA:
return automaton
# TODO K: this does nothing yet!
except reg.ParsingError as ex:
except ParsingError as ex:
print("Chyba při parsování.")
exit(1)
def nfa_transform(string: str, automaton_type: str) -> reg.NFA:
try:
parser = reg.Parser()
parser = Parser()
return parser.str_to_nfa(string)
# TODO K: errors cleanup
except reg.ParsingError as message:
except ParsingError as message:
print("Parsing error:", message)
exit(1)
......@@ -167,20 +168,20 @@ def exit_cfl_ok_but_invalid_constraint(msg : str) -> None:
def cfg_task(teacher_type: str, teacher_string: str, task: str,
student_string: str) -> None:
parser = reg.Parser()
parser = Parser()
assert task[:3] == "CFG", f"Invalid task prefix {task[:3]}"
if len(task) > 3:
assert task[3] == '+', f"Invalid task suffix {task[3:]}"
constraints = filter(lambda x: len(x) != 0, task[4:].split(","))
try:
teacher_solution = parser.str_to_cfg(teacher_string)
except reg.ParsingError as message:
except ParsingError as message:
print(f"Error parsing teacher's solution: {message}")
exit(1)
try:
student_solution = parser.str_to_cfg(student_string)
except reg.ParsingError as message:
except ParsingError as message:
print(f"Error parsing student's solution: {message}")
exit(1)
......
from lib.grammars_cfg import CFG
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment