Commit 895f21c8 authored by Vladimír Štill's avatar Vladimír Štill
Browse files

lib: Drop class Parser, shorten names

parent 4780d4ce
from typing import Tuple, Union
from lib import reg
from lib.parsing import Parser, ParsingError
from lib import reg, parser
from lib.parser import ParsingError
# support functions common for both fja_checker and web_checker
......@@ -17,24 +17,21 @@ def get_task(string: str) -> Tuple[str, str]: # from IS task prefix
def dfa_transform(string: str, automaton_type: str) -> reg.DFA:
if automaton_type in {"DFA", "TOT", "MIN", "TOC", "CAN", "MIC"}:
parser = Parser()
return parser.str_to_dfa(string)
return parser.dfa(string)
else:
return nfa_transform(string, automaton_type).determinize()
def nfa_transform(string: str, automaton_type: str) -> reg.NFA:
try:
parser = Parser()
if automaton_type in {"EFA", "NFA"}:
automaton = parser.str_to_nfa(string)
automaton = parser.nfa(string)
elif automaton_type == "GRA":
automaton = parser.str_to_reggrammar(string).eliminate_useless().reggrammar_to_nfa()
automaton = parser.reggrammar(string).eliminate_useless().reggrammar_to_nfa()
elif automaton_type == "REG":
automaton = parser.str_to_regex(string).regex_to_efa().eliminate_epsilon()
automaton = parser.regex(string).regex_to_efa().eliminate_epsilon()
elif automaton_type in {"DFA", "TOT", "MIN", "TOC", "CAN", "MIC"}:
automaton = parser.str_to_dfa(string).dfa_to_nfa()
automaton = parser.dfa(string).dfa_to_nfa()
return reg.NFA(automaton.states, automaton.characters, automaton.transition, automaton.init, automaton.final)
......@@ -44,16 +41,14 @@ def nfa_transform(string: str, automaton_type: str) -> reg.NFA:
def transform(string: str, automaton_type: str) -> Union[reg.DFA, reg.NFA, reg.RegGrammar, reg.RegEx]:
try:
parser = Parser()
if automaton_type in {"DFA", "TOT", "MIN", "TOC", "CAN", "MIC"}:
formalism = parser.str_to_dfa(string)
formalism = parser.dfa(string)
elif automaton_type in {"EFA", "NFA"}:
formalism = parser.str_to_nfa(string)
formalism = parser.nfa(string)
elif automaton_type == "GRA":
formalism = parser.str_to_reggrammar(string)
formalism = parser.reggrammar(string)
elif automaton_type == "REG":
formalism = parser.str_to_regex(string)
formalism = parser.regex(string)
return formalism
......@@ -62,7 +57,6 @@ def transform(string: str, automaton_type: str) -> Union[reg.DFA, reg.NFA, reg.R
def check_task(automaton: Union[reg.DFA, reg.NFA], task: str) -> str:
parser = Parser()
output = ""
if isinstance(automaton, reg.NFA):
......
......@@ -6,18 +6,18 @@ from lib.grammars_cfg import CFG
from lib.regex import RegEx, AST, Bin, Iter, BinOp, IterOp, CharNode
import antlr4 # type: ignore
from antlr4.error.ErrorListener import ErrorListener
from lib.parsing.DFALexer import DFALexer
from lib.parsing.DFAParser import DFAParser
from lib.parsing.DFAListener import DFAListener
from lib.parsing.NFALexer import NFALexer
from lib.parsing.NFAParser import NFAParser
from lib.parsing.NFAListener import NFAListener
from lib.parsing.RegExLexer import RegExLexer
from lib.parsing.RegExParser import RegExParser
from lib.parsing.RegExVisitor import RegExVisitor
from lib.parsing.CFGLexer import CFGLexer
from lib.parsing.CFGParser import CFGParser
from lib.parsing.CFGListener import CFGListener
from lib.parser.DFALexer import DFALexer
from lib.parser.DFAParser import DFAParser
from lib.parser.DFAListener import DFAListener
from lib.parser.NFALexer import NFALexer
from lib.parser.NFAParser import NFAParser
from lib.parser.NFAListener import NFAListener
from lib.parser.RegExLexer import RegExLexer
from lib.parser.RegExParser import RegExParser
from lib.parser.RegExVisitor import RegExVisitor
from lib.parser.CFGLexer import CFGLexer
from lib.parser.CFGParser import CFGParser
from lib.parser.CFGListener import CFGListener
class ParsingError(Exception):
def __init__(self, args):
......@@ -32,169 +32,175 @@ class ErrorShouter(ErrorListener):
(line, column, msg))
def anyvalue_attributes(parser: Union[DFAParser, NFAParser, RegExParser, CFGParser]) -> List:
def _anyvalue_attributes(parser: Union[DFAParser, NFAParser, RegExParser, CFGParser]) -> List:
return [func for func in dir(parser.AnyvalueContext)
if callable(getattr(parser.AnyvalueContext, func))
and not func.startswith("__") and func.isupper()]
class Parser:
def __init__(self):
pass
def names_to_str(self, collection: Union[Set[State], Set[Character], Set[Terminal], Set[Nonterminal]]) -> str:
return "{" + ','.join(set(map(lambda x: x.name, collection))) + "}"
def reggrammar_to_str(self, reg: RegGrammar, full: bool = False) -> str:
nonterminals = deepcopy(reg.nonterminals).difference({reg.init})
nonterminals = [reg.init] + list(nonterminals)
rules = self.rules_to_str(reg.rules, nonterminals)
if not full:
return rules
# full - verbose description of DFA - only for development, dismiss later
nonterminals_names = self.names_to_str(reg.nonterminals)
terminals = self.names_to_str(reg.terminals)
return f"Grammar: ({nonterminals_names}, {terminals}, P, {reg.init.name})\n{self.rules_to_str(reg.rules, nonterminals)}"
def cfg_to_str(self, gra: CFG, full: bool = False) -> str:
nonterminals = deepcopy(gra.nonterminals).difference({gra.init})
nonterminals = [gra.init] + list(nonterminals)
rules = self.rules_to_str(gra.rules, nonterminals)
if not full:
return rules
# full - verbose description of DFA - only for development, dismiss later
nonterminals_names = self.names_to_str(gra.nonterminals)
terminals = self.names_to_str(gra.terminals)
return f"Grammar: ({nonterminals_names}, {terminals}, P, {gra.init.name})\n{self.rules_to_str(gra.rules, nonterminals)}"
def rules_to_str(self, rules: Union[CFG.Rules, RegGrammar.Rules], nonterminals: List[Nonterminal]) -> str:
out = ""
for nonterminal in nonterminals:
if nonterminal not in rules:
continue
rewritten = ' | '.join(set(map(lambda x: self.rewrite_variant(x), rules[nonterminal])))
out += f"{nonterminal.name} -> {rewritten}\n"
return out[:-1]
def rewrite_variant(self, variant: Union[Eps, Terminal, Tuple[Union[Terminal, Nonterminal], ...]]) -> str:
if isinstance(variant, Tuple):
return ''.join(map(lambda x: x.name, variant))
return variant.name
def dfa_to_str(self, dfa: DFA, full : bool = False) -> str:
transition = ""
for key, dest_state in dfa.transition.items():
state_1, character = key
transition += f"({state_1.name},{character.name})={dest_state.name} "
init = f"init={dfa.init.name}"
final = f"final={self.names_to_str(dfa.final)}"
# full - verbose description of DFA - only for development, dismiss later
if full:
return f"DFA = ({self.names_to_str(dfa.states)}, {self.names_to_str(dfa.characters)}, " \
f"d, {init}, {final})\n{transition}"
return f"{init} {transition} {final}"
def nfa_to_str(self, nfa: NFA, full : bool = False) -> str:
transition = ""
for key, set_states in nfa.transition.items():
state, character = key
dest_states = nfa.transition[state, character]
transition += f"({state.name},{character.name})={self.names_to_str(dest_states)} "
init = f"init={nfa.init.name}"
final = f"final={self.names_to_str(nfa.final)}"
if full:
return f"NFA = ({self.names_to_str(nfa.states)}, {self.names_to_str(nfa.characters)}, " \
f"d, {init}, {final})\n{transition}"
return f"{init} {transition} {final}"
def regex_to_str(self, reg: RegEx) -> str:
return reg.expression.astprint()
def common_parse(self, string: str, given_lexer, given_parser, given_builder):
error_listener = ErrorShouter()
chars = antlr4.InputStream(string)
lexer = given_lexer(chars)
lexer.addErrorListener(error_listener)
tokens = antlr4.CommonTokenStream(lexer)
parser = given_parser(tokens)
parser.addErrorListener(error_listener)
tree = parser.start()
builder = given_builder()
walker = antlr4.ParseTreeWalker()
walker.walk(builder, tree)
return builder
def str_to_cfg(self, string: str) -> CFG:
try:
builder = self.common_parse(string, CFGLexer, CFGParser, CFGBuilder)
return CFG(builder.nonterminals, builder.terminals, builder.rules, builder.init)
def _names_to_str(collection: Union[Set[State], Set[Character],
Set[Terminal], Set[Nonterminal]]) -> str:
return "{" + ','.join(set(map(lambda x: x.name, collection))) + "}"
def _rules_to_str(rules: Union[CFG.Rules, RegGrammar.Rules],
nonterminals: List[Nonterminal]) -> str:
out = ""
for nonterminal in nonterminals:
if nonterminal not in rules:
continue
rewritten = ' | '.join(set(map(lambda x: _rewrite_variant(x), rules[nonterminal])))
out += f"{nonterminal.name} -> {rewritten}\n"
return out[:-1]
def _rewrite_variant(variant: Union[Eps, Terminal,
Tuple[Union[Terminal, Nonterminal], ...]]) -> str:
if isinstance(variant, Tuple):
return ''.join(map(lambda x: x.name, variant))
return variant.name
def dfa_to_str(dfa: DFA, full : bool = False) -> str:
transition = ""
for key, dest_state in dfa.transition.items():
state_1, character = key
transition += f"({state_1.name},{character.name})={dest_state.name} "
init = f"init={dfa.init.name}"
final = f"final={_names_to_str(dfa.final)}"
# full - verbose description of DFA - only for development, dismiss later
if full:
return f"DFA = ({_names_to_str(dfa.states)}, {_names_to_str(dfa.characters)}, " \
f"d, {init}, {final})\n{transition}"
return f"{init} {transition} {final}"
def reggrammar_to_str(reg: RegGrammar, full: bool = False) -> str:
nonterminals = deepcopy(reg.nonterminals).difference({reg.init})
nonterminals = [reg.init] + list(nonterminals)
rules = _rules_to_str(reg.rules, nonterminals)
if not full:
return rules
# full - verbose description of DFA - only for development, dismiss later
nonterminals_names = _names_to_str(reg.nonterminals)
terminals = _names_to_str(reg.terminals)
return f"Grammar: ({nonterminals_names}, {terminals}, P, {reg.init.name})\n{_rules_to_str(reg.rules, nonterminals)}"
def cfg_to_str(gra: CFG, full: bool = False) -> str:
nonterminals = deepcopy(gra.nonterminals).difference({gra.init})
nonterminals = [gra.init] + list(nonterminals)
rules = _rules_to_str(gra.rules, nonterminals)
if not full:
return rules
# full - verbose description of DFA - only for development, dismiss later
nonterminals_names = _names_to_str(gra.nonterminals)
terminals = _names_to_str(gra.terminals)
return f"Grammar: ({nonterminals_names}, {terminals}, P, {gra.init.name})\n{_rules_to_str(gra.rules, nonterminals)}"
def nfa_to_str(nfa: NFA, full : bool = False) -> str:
transition = ""
for key, set_states in nfa.transition.items():
state, character = key
dest_states = nfa.transition[state, character]
transition += f"({state.name},{character.name})={_names_to_str(dest_states)} "
init = f"init={nfa.init.name}"
final = f"final={_names_to_str(nfa.final)}"
if full:
return f"NFA = ({_names_to_str(nfa.states)}, {_names_to_str(nfa.characters)}, " \
f"d, {init}, {final})\n{transition}"
return f"{init} {transition} {final}"
def regex_to_str(reg: RegEx) -> str:
return reg.expression.astprint()
def _common_parse(string: str, given_lexer, given_parser, given_builder):
error_listener = ErrorShouter()
chars = antlr4.InputStream(string)
lexer = given_lexer(chars)
lexer.addErrorListener(error_listener)
tokens = antlr4.CommonTokenStream(lexer)
parser = given_parser(tokens)
parser.addErrorListener(error_listener)
tree = parser.start()
builder = given_builder()
walker = antlr4.ParseTreeWalker()
walker.walk(builder, tree)
return builder
def cfg(string: str) -> CFG:
try:
builder = _common_parse(string, CFGLexer, CFGParser, CFGBuilder)
return CFG(builder.nonterminals, builder.terminals, builder.rules, builder.init)
except Exception as e:
raise ParsingError(e.args)
def reggrammar(string: str) -> RegGrammar:
try:
cfg_ = cfg(string)
return RegGrammar.from_cfg(cfg_)
except Exception as e:
raise ParsingError(e.args)
def dfa(string: str) -> DFA:
try:
builder = _common_parse(string, DFALexer, DFAParser, DFABuilder)
if builder.init is None:
builder.init = builder.first_state
if builder.init is None:
raise ParsingError("Automat musí obsahovat alespoň jeden stav.")
except Exception as e:
raise ParsingError(e.args)
dfa = DFA(builder.states, builder.characters, builder.transition, builder.init, builder.final)
return dfa
def str_to_reggrammar(self, string: str) -> RegGrammar:
try:
cfg = self.str_to_cfg(string)
return RegGrammar.from_cfg(cfg)
except Exception as e:
raise ParsingError(e.args)
except Exception as e:
raise ParsingError(e.args)
def str_to_dfa(self, string: str) -> DFA:
try:
builder = self.common_parse(string, DFALexer, DFAParser, DFABuilder)
def nfa(string: str) -> NFA:
try:
builder = _common_parse(string, NFALexer, NFAParser, NFABuilder)
if builder.init is None:
builder.init = builder.first_state
if builder.init is None:
builder.init = builder.first_state
if builder.init is None:
raise ParsingError("Automat musí obsahovat alespoň jeden stav.")
raise ParsingError("Automat musí obsahovat alespoň jeden stav.")
dfa = DFA(builder.states, builder.characters, builder.transition, builder.init, builder.final)
return dfa
return NFA(builder.states, builder.characters, builder.transition, builder.init, builder.final)
except Exception as e:
raise ParsingError(e.args)
except Exception as e:
raise ParsingError(e.args)
def str_to_nfa(self, string: str) -> NFA:
try:
builder = self.common_parse(string, NFALexer, NFAParser, NFABuilder)
if builder.init is None:
builder.init = builder.first_state
if builder.init is None:
raise ParsingError("Automat musí obsahovat alespoň jeden stav.")
return NFA(builder.states, builder.characters, builder.transition, builder.init, builder.final)
except Exception as e:
raise ParsingError(e.args)
def str_to_regex(self, string: str) -> RegEx:
try:
error_listener = ErrorShouter()
chars = antlr4.InputStream(string)
lexer = RegExLexer(chars)
lexer.addErrorListener(error_listener)
tokens = antlr4.CommonTokenStream(lexer)
parser = RegExParser(tokens)
parser.addErrorListener(error_listener)
def regex(string: str) -> RegEx:
try:
error_listener = ErrorShouter()
chars = antlr4.InputStream(string)
lexer = RegExLexer(chars)
lexer.addErrorListener(error_listener)
tokens = antlr4.CommonTokenStream(lexer)
parser = RegExParser(tokens)
parser.addErrorListener(error_listener)
tree = parser.start()
ast = RegExBuilder()
ast.visitStart(tree)
tree = parser.start()
ast = RegExBuilder()
ast.visitStart(tree)
return RegEx(ast.characters, ast.expression)
return RegEx(ast.characters, ast.expression)
except Exception as e:
raise ParsingError(e.args)
except Exception as e:
raise ParsingError(e.args)
class StateVisitor:
......@@ -221,7 +227,7 @@ class StateVisitor:
class DFABuilder(DFAListener, StateVisitor):
# anyvalue possibilities
anyvalue_attributes = anyvalue_attributes(DFAParser)
anyvalue_attributes = _anyvalue_attributes(DFAParser)
def __init__(self):
self.states = set()
......@@ -266,7 +272,7 @@ class DFABuilder(DFAListener, StateVisitor):
class NFABuilder(NFAListener, StateVisitor):
anyvalue_attributes = anyvalue_attributes(NFAParser)
anyvalue_attributes = _anyvalue_attributes(NFAParser)
def __init__(self):
self.states = set()
......@@ -323,7 +329,7 @@ class NFABuilder(NFAListener, StateVisitor):
class RegExBuilder(RegExVisitor):
anyvalue_attributes = anyvalue_attributes(RegExParser)
anyvalue_attributes = _anyvalue_attributes(RegExParser)
def __init__(self):
self.characters: Set[Character] = set()
......@@ -405,7 +411,7 @@ class RegExBuilder(RegExVisitor):
return None
class CFGBuilder(CFGListener):
anyvalue_attributes = anyvalue_attributes(CFGParser)
anyvalue_attributes = _anyvalue_attributes(CFGParser)
def __init__(self):
self.terminals = set()
......
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