Skip to content

Commit

Permalink
DONE???
Browse files Browse the repository at this point in the history
  • Loading branch information
Encapsulateed committed Jan 26, 2025
1 parent ac77830 commit e30c84e
Show file tree
Hide file tree
Showing 3 changed files with 124 additions and 50 deletions.
10 changes: 6 additions & 4 deletions main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'src/utils/table_writer.dart';
import 'src/utils/tree_writer.dart';

// dart main.dart input.txt grammar.txt output.txt parse.dot -e
// dart main.dart input.txt automation.txt output.txt parse.dot -e -m
// dart main.dart input.txt output.txt output.txt parse.dot -e -m
void main(List<String> arguments) {
if (arguments.length < 3) throw 'Invalid amount of arguments!';

Expand All @@ -26,20 +26,22 @@ void main(List<String> arguments) {

if (use_automaton) {
ta = TrellisAutomaton.fromFile(input_file);
var g = ta.toGrammar();
// print(g);
} else {
var g = Grammar.fromFile(input_file);
g.convertToLNF();

print(g);

ta = TrellisAutomaton.build(g);
//print(g);
}

dump_automaton_details(out_file, ta);

var tree =
ParsingTree.create(input_word.readAsStringSync(), ta, explanations);
print(tree.layers);

//print(tree.layers);
saveToDotFile(tree.layers, dot_file);
print(tree.isRecognizing());
}
69 changes: 32 additions & 37 deletions src/types/grammar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class Grammar {
}

bool _isNonTerminal(String symbol) {
return RegExp(r'^[A-Z]+$').hasMatch(symbol);
return RegExp(r'^[A-Z]+[0-9]*$').hasMatch(symbol);
}

void convertToLNF() {
Expand All @@ -103,7 +103,7 @@ class Grammar {
String candidate;

while (true) {
candidate = "N$counter";
candidate = "N\$counter";
if (!nonTerminals.contains(candidate)) {
nonTerminals.add(candidate);
return candidate;
Expand All @@ -127,8 +127,6 @@ class Grammar {
{
List<String> output = conj;
if (!isLNF(conj)) {
// проверим является ли конъюнктом вида
// X -> u1...un Y w1 ... wk
var isLeftConj = terminals.contains(conj[0]);

if (isLeftConj) {
Expand All @@ -143,10 +141,7 @@ class Grammar {

rules.add(rule);
nonTerminals.add(NonTerm());
}
// значит вида
// X -> Y w1 ... wk
else {
} else {
var term = conj[conj.length - 1];
var nonterm = NonTerm();

Expand Down Expand Up @@ -175,13 +170,10 @@ class Grammar {
var rule = rules[i];
var ntSetPrev = Set<String>.from(nonTerminals);

// Преобразуем конъюнкты с помощью reduceConj
var conjLst = rule.conjuncts.map((conj) => reduceConj(conj)).toList();

// Обновляем правило
rules[i] = Rule(rule.left, conjLst);

// Проверяем изменения в множестве нетерминалов
if (!ntSetPrev.containsAll(nonTerminals) ||
!nonTerminals.containsAll(ntSetPrev)) {
changed = true;
Expand All @@ -206,7 +198,6 @@ class Grammar {

rules.removeWhere((rule) => rule.left == startNonTerminal);

// Добавляем каждое правило S -> (σ1 & ... & σk) в S'
for (var rule
in currentRules.where((rule) => rule.left == startNonTerminal)) {
if (!rules.any((r) =>
Expand Down Expand Up @@ -314,37 +305,41 @@ class Grammar {
}

void removeUnitConjuncts() {
bool changed = true;

while (changed) {
changed = false;
List<Rule> updatedRules = [];

for (var rule in rules) {
List<List<String>> newConjuncts = [];

for (var conjunct in rule.conjuncts) {
if (conjunct.length == 1 && _isNonTerminal(conjunct[0])) {
String targetNonTerminal = conjunct[0];
// Шаг 1: Создаем новый список для обновленных правил
List<Rule> updatedRules = [];

var targetRules = rules.where((r) => r.left == targetNonTerminal);

for (var targetRule in targetRules) {
for (var targetConjunct in targetRule.conjuncts) {
newConjuncts.add(targetConjunct);
}
}
changed = true;
} else {
newConjuncts.add(conjunct);
// Шаг 2: Проходим по всем правилам
for (var rule in rules) {
bool modified = false;

// Шаг 3: Ищем unit conjunct в каждом конъюнкте
for (var conjunct in rule.conjuncts) {
if (conjunct.length == 1 && _isNonTerminal(conjunct[0])) {
modified = true;
String targetNonTerminal = conjunct[0];

// Шаг 4: Находим все правила для целевого нетерминала
for (var targetRule
in rules.where((r) => r.left == targetNonTerminal)) {
// Для каждой альтернативы создаем новое правило
updatedRules.add(Rule(rule.left, [
for (var originalConjunct in rule.conjuncts)
if (originalConjunct != conjunct) originalConjunct,
...targetRule.conjuncts
]));
}
}

updatedRules.add(Rule(rule.left, newConjuncts));
}

rules = updatedRules;
// Шаг 5: Если правило не было модифицировано, добавляем его как есть
if (!modified) {
updatedRules.add(rule);
}
}

// Шаг 6: Удаляем дубликаты и обновляем правила
rules = updatedRules;
removeDuplicateRules();
}

void removeDuplicateRules() {
Expand Down
95 changes: 86 additions & 9 deletions src/types/trellis_automaton.dart
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class TrellisAutomaton {
if (lines[lineIndex].startsWith('Алфавит:')) {
lineIndex++;
alphabet = lines[lineIndex].split(',').map((e) => e.trim()).toSet();
print('Алфавит: $alphabet');
lineIndex++;
} else {
throw StateError('Alphabet section is missing in the input file.');
Expand All @@ -52,7 +51,6 @@ class TrellisAutomaton {
if (lines[lineIndex].startsWith('Init функция:')) {
lineIndex++;
while (lineIndex < lines.length && lines[lineIndex].contains('->')) {
print('Processing Init function line: ${lines[lineIndex]}');
var parts = lines[lineIndex].split('->');
var symbol = parts[0].trim();
var stateInfo = parts[1].trim();
Expand All @@ -68,7 +66,6 @@ class TrellisAutomaton {
Init = (String w) =>
initMapping[w] ??
(throw ArgumentError('Init mapping for symbol "$w" not found.'));
print('Init mapping: $initMapping');
} else {
throw StateError('Init function section is missing in the input file.');
}
Expand All @@ -81,7 +78,6 @@ class TrellisAutomaton {
if (lines[lineIndex].startsWith('Список состояния -> индекс:')) {
lineIndex++;
while (lineIndex < lines.length && lines[lineIndex].contains(':')) {
print('Processing state line: ${lines[lineIndex]}');
var parts = lines[lineIndex].split(':');
var stateInfo = parts[1].trim();
var components =
Expand All @@ -95,7 +91,6 @@ class TrellisAutomaton {
states.add(state);
lineIndex++;
}
print('Список состояний: $stateList');
} else {
throw StateError('State list section is missing in the input file.');
}
Expand All @@ -107,7 +102,6 @@ class TrellisAutomaton {
if (lines[lineIndex].startsWith('Принимающие состояния:')) {
lineIndex++;
while (lineIndex < lines.length && lines[lineIndex].contains(':')) {
print('Processing final state line: ${lines[lineIndex]}');
var parts = lines[lineIndex].split(':');
var index = int.parse(parts[0].trim());
if (index < 0 || index >= stateList.length) {
Expand All @@ -116,7 +110,6 @@ class TrellisAutomaton {
finals.add(stateList[index]);
lineIndex++;
}
print('Принимающие состояния: $finals');
} else {
throw StateError('Final states section is missing in the input file.');
}
Expand All @@ -129,7 +122,6 @@ class TrellisAutomaton {
if (lines[lineIndex].startsWith('Таблица переходов:')) {
lineIndex++;
while (lineIndex < lines.length && lines[lineIndex].trim().isNotEmpty) {
print('Processing transition table line: ${lines[lineIndex]}');
var row = lines[lineIndex].trim().split(RegExp(r'\s+'));
var fromIndex = int.parse(row[0]);
if (fromIndex < 0 || fromIndex >= stateList.length) {
Expand All @@ -150,7 +142,6 @@ class TrellisAutomaton {
}
lineIndex++;
}
print('Таблица переходов: $parsing_table');
} else {
throw StateError(
'Transition table section is missing in the input file.');
Expand Down Expand Up @@ -220,4 +211,90 @@ class TrellisAutomaton {
}
return input;
}

Grammar toGrammar() {
var grammar = Grammar();
var stateList = states.toList();

// Создаем нетерминалы для каждого состояния
for (var i = 0; i < stateList.length; i++) {
grammar.nonTerminals.add('A$i');
}

// Добавляем терминалы из алфавита
grammar.terminals.addAll(alphabet);

// Добавляем правила для переходов
for (var entry in parsing_table.entries) {
var fromStateIndex = stateList.indexOf(entry.key.$1);
var toStateIndex = stateList.indexOf(entry.key.$2);
var resultingStateIndex = stateList.indexOf(entry.value);

for (var b in alphabet) {
for (var c in alphabet) {
grammar.rules.add(
Rule(
'A$resultingStateIndex',
[
[b, 'A$toStateIndex'],
['A$fromStateIndex', c]
],
),
);
}
}
}

// Добавляем правило для стартового терминала S -> Aq
for (var finalState in finals) {
var finalStateIndex = stateList.indexOf(finalState);
grammar.rules.add(
Rule('S', [
['A$finalStateIndex']
]),
);
}

// Добавляем правила Ai(a) -> a
for (var i = 0; i < stateList.length; i++) {
for (var a in alphabet) {
grammar.rules.add(
Rule('A$i', [
[a]
]),
);
}
}

// Устанавливаем стартовый символ грамматики
grammar.startNonTerminal = 'S';
grammar.convertToLNF();
saveGrammarToFile(grammar, File('grammar.txt'));

return grammar;
}

void saveGrammarToFile(Grammar grammar, File outputFile) {
var sink = outputFile.openWrite();

// Write the start non-terminal rule first
var startRules =
grammar.rules.where((rule) => rule.left == grammar.startNonTerminal);
for (var rule in startRules) {
var ruleStr = '${rule.left} -> ' +
rule.conjuncts.map((conj) => conj.join(' ')).join(' & ');
sink.writeln(ruleStr);
}

// Write the rest of the rules
var otherRules =
grammar.rules.where((rule) => rule.left != grammar.startNonTerminal);
for (var rule in otherRules) {
var ruleStr = '${rule.left} -> ' +
rule.conjuncts.map((conj) => conj.join(' ')).join(' & ');
sink.writeln(ruleStr);
}

sink.close();
}
}

0 comments on commit e30c84e

Please sign in to comment.