init
This commit is contained in:
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
build-Automaton-Desktop-Debug/
|
||||||
|
source/Automaton.pro.user
|
BIN
Documentation/demo.png
Normal file
BIN
Documentation/demo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 20 KiB |
4
README.md
Normal file
4
README.md
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
# Stack Automaton
|
||||||
|
>
|
||||||
|
|
||||||
|

|
31
source/Automaton.pro
Normal file
31
source/Automaton.pro
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
QT += core gui
|
||||||
|
|
||||||
|
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||||
|
|
||||||
|
CONFIG += c++17
|
||||||
|
|
||||||
|
# You can make your code fail to compile if it uses deprecated APIs.
|
||||||
|
# In order to do so, uncomment the following line.
|
||||||
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
automaton.cpp \
|
||||||
|
main.cpp \
|
||||||
|
automaton_gui.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
automaton.hpp \
|
||||||
|
automaton_gui.h \
|
||||||
|
util.h
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
automaton_gui.ui
|
||||||
|
|
||||||
|
# Default rules for deployment.
|
||||||
|
qnx: target.path = /tmp/$${TARGET}/bin
|
||||||
|
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||||
|
!isEmpty(target.path): INSTALLS += target
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
small.inc \
|
||||||
|
table.inc
|
78
source/automaton.cpp
Normal file
78
source/automaton.cpp
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
#include "automaton.hpp"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
std::string to_string(const Rule &r) {
|
||||||
|
return std::string() + "Rule{ translation: " + r.transition + ", irrel: " + r.irrel + " }";
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace automaton {
|
||||||
|
const char POP = '\01';
|
||||||
|
const char ACCEPT = '\02';
|
||||||
|
|
||||||
|
stack<char> symbol_stack;
|
||||||
|
const char * input_str;
|
||||||
|
size_t ip;
|
||||||
|
|
||||||
|
string irrelevant;
|
||||||
|
|
||||||
|
void (*display_callback)(decltype(input_str),
|
||||||
|
decltype(symbol_stack),
|
||||||
|
decltype(irrelevant) ir,
|
||||||
|
const Rule &r) = NULL;
|
||||||
|
|
||||||
|
map<char, map<char, Rule>> matrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool automaton::run() {
|
||||||
|
while (true) {
|
||||||
|
// Preoperation calculations
|
||||||
|
char n = input_str[ip];
|
||||||
|
if (symbol_stack.empty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
char m = symbol_stack.top();
|
||||||
|
|
||||||
|
Rule r("");
|
||||||
|
try {
|
||||||
|
r = matrix.at(m)
|
||||||
|
.at(n);
|
||||||
|
} catch(...) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Render to display
|
||||||
|
if (display_callback) {
|
||||||
|
display_callback(input_str + ip, symbol_stack, irrelevant, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Act on input
|
||||||
|
symbol_stack.pop();
|
||||||
|
irrelevant += r.irrel;
|
||||||
|
|
||||||
|
if (r.transition == string("") + ACCEPT) {
|
||||||
|
return true;
|
||||||
|
} if (r.transition == string("") + POP) {
|
||||||
|
if (not input_str[ip]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
ip++;
|
||||||
|
} else {
|
||||||
|
for (auto it = r.transition.rbegin(); it != r.transition.rend(); it++) {
|
||||||
|
symbol_stack.push(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void automaton::reset(){
|
||||||
|
free((char *)input_str);
|
||||||
|
input_str = NULL;
|
||||||
|
symbol_stack = stack<char>({'\0', 'E'});
|
||||||
|
ip = 0;
|
||||||
|
irrelevant = "";
|
||||||
|
matrix.clear();
|
||||||
|
}
|
75
source/automaton.hpp
Normal file
75
source/automaton.hpp
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
#ifndef AUTOMATON_HPP
|
||||||
|
#define AUTOMATON_HPP
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
|
namespace automaton {
|
||||||
|
extern const char POP;
|
||||||
|
extern const char ACCEPT;
|
||||||
|
}
|
||||||
|
|
||||||
|
class Rule {
|
||||||
|
public:
|
||||||
|
std::string transition;
|
||||||
|
std::string irrel = "";
|
||||||
|
|
||||||
|
Rule(const char c) {
|
||||||
|
this->transition = strndup(&c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Rule(const char * const s) {
|
||||||
|
if (not strcmp(s, "ACCEPT")) {
|
||||||
|
this->transition = automaton::ACCEPT;
|
||||||
|
this->irrel = "";
|
||||||
|
return;
|
||||||
|
} else if (not strcmp(s, "POP")) {
|
||||||
|
this->transition = automaton::POP;
|
||||||
|
this->irrel = "";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char * split = strchr(s, ',');
|
||||||
|
if (not split) {
|
||||||
|
this->transition = s;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int i = split - s - 1;
|
||||||
|
i < 0 ? i = 0 : 0;
|
||||||
|
this->transition = std::string(s + 1, i);
|
||||||
|
this->irrel = std::string(split + 1);
|
||||||
|
this->irrel = this->irrel.substr(0, this->irrel.size()-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
explicit operator bool() const {
|
||||||
|
return not
|
||||||
|
(transition == ""
|
||||||
|
&& irrel == "");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
extern std::string to_string(const Rule &r);
|
||||||
|
|
||||||
|
namespace automaton {
|
||||||
|
extern std::stack<char> symbol_stack;
|
||||||
|
extern const char * input_str;
|
||||||
|
extern size_t ip;
|
||||||
|
|
||||||
|
extern std::string irrelevant;
|
||||||
|
|
||||||
|
extern void (*display_callback)(decltype(input_str),
|
||||||
|
decltype(symbol_stack),
|
||||||
|
decltype(irrelevant) ir,
|
||||||
|
const Rule &r);
|
||||||
|
|
||||||
|
extern std::map<char, std::map<char, Rule>> matrix;
|
||||||
|
|
||||||
|
extern bool run();
|
||||||
|
extern void reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
181
source/automaton_gui.cpp
Normal file
181
source/automaton_gui.cpp
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
#include "automaton.hpp"
|
||||||
|
#include "automaton_gui.h"
|
||||||
|
#include "ui_automaton_gui.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
AutomatonGUI::AutomatonGUI(QWidget *parent)
|
||||||
|
: QMainWindow(parent)
|
||||||
|
, ui(new Ui::AutomatonGUI)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
setCentralWidget(ui->horizontalLayoutWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
AutomatonGUI::~AutomatonGUI()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::matrix_from_table() {
|
||||||
|
for (int i = 0; i < ui->InputTable->rowCount(); i++) {
|
||||||
|
char n = ui->InputTable->verticalHeaderItem(i)->text().toStdString()[0];
|
||||||
|
if (n == '#') { n = '\0'; }
|
||||||
|
automaton::matrix.insert({ n, std::map<char,Rule>()});
|
||||||
|
for (int h = 0; h < ui->InputTable->columnCount(); h++) {
|
||||||
|
char m = ui->InputTable->horizontalHeaderItem(h)->text().toStdString()[0];
|
||||||
|
if (m == '#') { m = '\0'; }
|
||||||
|
auto item = ui->InputTable->item(i, h);
|
||||||
|
std::string r = (item ? item->text().toStdString() : "");
|
||||||
|
automaton::matrix[n].insert({m, Rule(r.c_str())});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::on_RunButton_clicked()
|
||||||
|
{
|
||||||
|
automaton::reset();
|
||||||
|
|
||||||
|
const auto &i = ui->StatusIndicator;
|
||||||
|
automaton::input_str = strdup(ui->InputLine->text().toStdString().c_str());
|
||||||
|
|
||||||
|
if (not *automaton::input_str) {
|
||||||
|
i->setText("No input");
|
||||||
|
i->setProperty("status", "negative");
|
||||||
|
i->style()->unpolish(i);
|
||||||
|
i->style()->polish(i);
|
||||||
|
i->update();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix_from_table();
|
||||||
|
|
||||||
|
bool r = automaton::run();
|
||||||
|
const char * t;
|
||||||
|
const char * s;
|
||||||
|
if (r) {
|
||||||
|
t = "Accepted";
|
||||||
|
s = "positive";
|
||||||
|
} else {
|
||||||
|
t = "Denied";
|
||||||
|
s = "negative";
|
||||||
|
}
|
||||||
|
i->setProperty("status", s);
|
||||||
|
i->setText(t);
|
||||||
|
i->style()->unpolish(i);
|
||||||
|
i->style()->polish(i);
|
||||||
|
i->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutomatonGUI::on_InputLine_textChanged(const QString &arg1)
|
||||||
|
{
|
||||||
|
QString r;
|
||||||
|
for (const auto &c : arg1) {
|
||||||
|
if (ui->lineEdit_2->text().contains(c)) {
|
||||||
|
r.append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->InputLine->setText(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void AutomatonGUI::on_lineEdit_2_textChanged(const QString &arg1)
|
||||||
|
{
|
||||||
|
std::string r = uniq(arg1.toStdString());
|
||||||
|
std::string extra = ui->ExtraStates->text().toStdString();
|
||||||
|
|
||||||
|
//ui->lineEdit_2->setText("");
|
||||||
|
ui->InputLine->setText("");
|
||||||
|
|
||||||
|
column_force(r);
|
||||||
|
|
||||||
|
row_force(uniq(r + extra));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::on_ExtraStates_textChanged(const QString &arg1)
|
||||||
|
{
|
||||||
|
std::string r = arg1.toStdString();
|
||||||
|
std::string base = (arg1 + ui->lineEdit_2->text()).toStdString();
|
||||||
|
|
||||||
|
row_force(uniq(r + base));
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::column_force(const std::string &s) {
|
||||||
|
// Delete horizontal headers
|
||||||
|
{
|
||||||
|
std::stack<int> buf;
|
||||||
|
for (int i = 0; i < ui->InputTable->columnCount(); i++) {
|
||||||
|
if (s.find(ui->InputTable->horizontalHeaderItem(i)->text().toStdString()[0]) == std::string::npos) {
|
||||||
|
buf.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (not buf.empty()) {
|
||||||
|
ui->InputTable->removeColumn(buf.top());
|
||||||
|
buf.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append horizontal headers
|
||||||
|
{
|
||||||
|
int offset = ui->InputTable->columnCount();
|
||||||
|
int target_len = s.size();
|
||||||
|
ui->InputTable->setColumnCount(target_len);
|
||||||
|
for (int i = 0; i < target_len; i++) {
|
||||||
|
for (int h = 0; h < offset; h++) {
|
||||||
|
auto item = ui->InputTable->horizontalHeaderItem(h);
|
||||||
|
if (not item
|
||||||
|
|| item->text().toStdString()[0] == s[i]) {
|
||||||
|
goto long_continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->InputTable->setHorizontalHeaderItem(
|
||||||
|
offset,
|
||||||
|
new QTableWidgetItem(QString(s[i]))
|
||||||
|
);
|
||||||
|
long_continue:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::row_force(const std::string &s) {
|
||||||
|
// Delete vertical headers
|
||||||
|
{
|
||||||
|
std::stack<int> buf;
|
||||||
|
for (int i = 0; i < ui->InputTable->rowCount(); i++) {
|
||||||
|
if (s.find(ui->InputTable->verticalHeaderItem(i)->text().toStdString()[0]) == std::string::npos) {
|
||||||
|
buf.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (not buf.empty()) {
|
||||||
|
ui->InputTable->removeRow(buf.top());
|
||||||
|
buf.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Append vertical headers
|
||||||
|
{
|
||||||
|
int offset = ui->InputTable->rowCount();
|
||||||
|
int target_len = s.size();
|
||||||
|
ui->InputTable->setRowCount(target_len);
|
||||||
|
for (int i = 0; i < target_len; i++) {
|
||||||
|
for (int h = 0; h < offset; h++) {
|
||||||
|
auto item = ui->InputTable->verticalHeaderItem(h);
|
||||||
|
if (not item
|
||||||
|
|| item->text().toStdString()[0] == s[i]) {
|
||||||
|
goto long_continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->InputTable->setVerticalHeaderItem(
|
||||||
|
offset,
|
||||||
|
new QTableWidgetItem(QString(s[i]))
|
||||||
|
);
|
||||||
|
long_continue:
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void AutomatonGUI::display_state(const std::string &s) {
|
||||||
|
ui->log->append(QString::fromStdString(s));
|
||||||
|
}
|
38
source/automaton_gui.h
Normal file
38
source/automaton_gui.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#ifndef AUTOMATONGUI_H
|
||||||
|
#define AUTOMATONGUI_H
|
||||||
|
|
||||||
|
#include <QMainWindow>
|
||||||
|
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
namespace Ui { class AutomatonGUI; }
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
class AutomatonGUI : public QMainWindow
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AutomatonGUI(QWidget *parent = nullptr);
|
||||||
|
~AutomatonGUI();
|
||||||
|
|
||||||
|
void display_state(const std::string &s);
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void on_RunButton_clicked();
|
||||||
|
|
||||||
|
void on_lineEdit_2_textChanged(const QString &arg1);
|
||||||
|
|
||||||
|
void on_InputLine_textChanged(const QString &arg1);
|
||||||
|
|
||||||
|
void on_ExtraStates_textChanged(const QString &arg1);
|
||||||
|
|
||||||
|
void matrix_from_table();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ui::AutomatonGUI *ui;
|
||||||
|
|
||||||
|
void column_force(const std::string &s);
|
||||||
|
void row_force(const std::string &s);
|
||||||
|
};
|
||||||
|
#endif // AUTOMATONGUI_H
|
144
source/automaton_gui.ui
Normal file
144
source/automaton_gui.ui
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>AutomatonGUI</class>
|
||||||
|
<widget class="QMainWindow" name="AutomatonGUI">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>600</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>AutomatonGUI</string>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="centralwidget">
|
||||||
|
<widget class="QWidget" name="horizontalLayoutWidget">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>20</x>
|
||||||
|
<y>20</y>
|
||||||
|
<width>711</width>
|
||||||
|
<height>481</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QHBoxLayout" name="topLevel">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="InputLine">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>Input</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="lineEdit_2">
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>alphabet</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLineEdit" name="ExtraStates">
|
||||||
|
<property name="statusTip">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="whatsThis">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string>extra states</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="RunButton">
|
||||||
|
<property name="text">
|
||||||
|
<string>Run</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="StatusIndicator">
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">* {
|
||||||
|
background: yellow;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[status=negative] {
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
*[status=positive] {
|
||||||
|
background: green;
|
||||||
|
}</string>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>N/A</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTableWidget" name="InputTable"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTextEdit" name="log">
|
||||||
|
<property name="enabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
<property name="styleSheet">
|
||||||
|
<string notr="true">background: white;
|
||||||
|
color: black;</string>
|
||||||
|
</property>
|
||||||
|
<property name="html">
|
||||||
|
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||||
|
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||||
|
p, li { white-space: pre-wrap; }
|
||||||
|
hr { height: 1px; border-width: 0; }
|
||||||
|
li.unchecked::marker { content: "\2610"; }
|
||||||
|
li.checked::marker { content: "\2612"; }
|
||||||
|
</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||||
|
<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html></string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
<widget class="QMenuBar" name="menubar">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>800</width>
|
||||||
|
<height>19</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
<widget class="QStatusBar" name="statusbar"/>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
96
source/main.cpp
Normal file
96
source/main.cpp
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
#include "automaton.hpp"
|
||||||
|
#include "automaton_gui.h"
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
using namespace automaton;
|
||||||
|
|
||||||
|
AutomatonGUI * g;
|
||||||
|
|
||||||
|
void print_state(decltype(input_str) is,
|
||||||
|
decltype(symbol_stack) ss,
|
||||||
|
decltype(irrelevant) ir,
|
||||||
|
const Rule &r) {
|
||||||
|
string ss_ = "";
|
||||||
|
while (not ss.empty()) {
|
||||||
|
if (ss.top() == '\0') {
|
||||||
|
ss_ += '#';
|
||||||
|
} else {
|
||||||
|
ss_ += ss.top();
|
||||||
|
}
|
||||||
|
ss.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
char * state;
|
||||||
|
char * transition;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
asprintf(&state, "\033[33;1m('%s', '%s', '%s')\033[0m\n",
|
||||||
|
is,
|
||||||
|
ss_.c_str(),
|
||||||
|
ir.c_str()
|
||||||
|
);
|
||||||
|
asprintf(&transition, "\033[32;1m[%c,%c]\033[0m -> \033[36;1m(%s,%s)\033[0m\n",
|
||||||
|
*input_str,
|
||||||
|
symbol_stack.top(),
|
||||||
|
r.transition.c_str(),
|
||||||
|
r.irrel.c_str()
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
asprintf(&state, "('%s', '%s', '%s')",
|
||||||
|
is,
|
||||||
|
ss_.c_str(),
|
||||||
|
ir.c_str()
|
||||||
|
);
|
||||||
|
asprintf(&transition, "[%c,%c] -> (%s,%s)",
|
||||||
|
*input_str,
|
||||||
|
symbol_stack.top() ? symbol_stack.top() : '#',
|
||||||
|
r.transition.c_str(),
|
||||||
|
r.irrel.c_str()
|
||||||
|
);
|
||||||
|
|
||||||
|
fputs(state, stdout);
|
||||||
|
fputs(transition, stdout);
|
||||||
|
g->display_state(state);
|
||||||
|
g->display_state(transition);
|
||||||
|
|
||||||
|
free(state);
|
||||||
|
free(transition);
|
||||||
|
|
||||||
|
for (auto it = ss_.rbegin(); it != ss_.rend(); it++) {
|
||||||
|
if (*it == '#') {
|
||||||
|
ss.push('\0');
|
||||||
|
} else {
|
||||||
|
ss.push(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) {
|
||||||
|
// load
|
||||||
|
reset();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
input_str = strdup("i+i*(i+i)");
|
||||||
|
matrix =
|
||||||
|
#include "table.inc"
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
input_str = strdup("ii");
|
||||||
|
matrix =
|
||||||
|
#include "small.inc"
|
||||||
|
;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
display_callback = print_state;
|
||||||
|
|
||||||
|
// IoC
|
||||||
|
QApplication a(argc, argv);
|
||||||
|
AutomatonGUI w;
|
||||||
|
g = &w;
|
||||||
|
w.show();
|
||||||
|
return a.exec();
|
||||||
|
}
|
5
source/small.inc
Normal file
5
source/small.inc
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{// i #
|
||||||
|
{ 'E', { {'i', Rule("(iE,1)")}, {'\0', Rule("") }}},
|
||||||
|
{ 'i', { {'i', Rule(POP) }, {'\0', Rule("") }}},
|
||||||
|
{ '\0', { {'i', Rule("") }, {'\0', Rule(ACCEPT) }}},
|
||||||
|
};
|
13
source/table.inc
Normal file
13
source/table.inc
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
{// + * ( ) i #
|
||||||
|
{ 'E', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("(TR,1)") }, {')', Rule("") }, {'i', Rule("(TR,1)")}, {'\0', Rule("") }, }},
|
||||||
|
{ 'R', { {'+', Rule("(+TR,2)")}, {'*', Rule("") }, {'(', Rule("") }, {')', Rule("(,3)")}, {'i', Rule("") }, {'\0', Rule("(,3)"), }, }},
|
||||||
|
{ 'T', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("(FZ,4)") }, {')', Rule("") }, {'i', Rule("(FZ,4)")}, {'\0', Rule(""), }, }},
|
||||||
|
{ 'Z', { {'+', Rule("(,6)") }, {'*', Rule("(*FZ,5)")}, {'(', Rule("") }, {')', Rule("(,6)")}, {'i', Rule("") }, {'\0', Rule("(,6)"), }, }},
|
||||||
|
{ 'F', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("((E),7)")}, {')', Rule("") }, {'i', Rule("(i,8)") }, {'\0', Rule(""), }, }},
|
||||||
|
{ '+', { {'+', Rule(POP) }, {'*', Rule("") }, {'(', Rule("") }, {')', Rule("") }, {'i', Rule("") }, {'\0', Rule(""), }, }},
|
||||||
|
{ '*', { {'+', Rule("") }, {'*', Rule(POP) }, {'(', Rule("") }, {')', Rule("") }, {'i', Rule("") }, {'\0', Rule(""), }, }},
|
||||||
|
{ '(', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule(POP) }, {')', Rule("") }, {'i', Rule("") }, {'\0', Rule(""), }, }},
|
||||||
|
{ ')', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("") }, {')', Rule(POP) }, {'i', Rule("") }, {'\0', Rule(""), }, }},
|
||||||
|
{ 'i', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("") }, {')', Rule("") }, {'i', Rule(POP) }, {'\0', Rule(""), }, }},
|
||||||
|
{ '\0', { {'+', Rule("") }, {'*', Rule("") }, {'(', Rule("") }, {')', Rule("") }, {'i', Rule("") }, {'\0', Rule(ACCEPT), }, }},
|
||||||
|
}
|
16
source/util.h
Normal file
16
source/util.h
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#ifndef UTIL_H
|
||||||
|
#define UTIL_H
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string uniq(const std::string &s) {
|
||||||
|
std::string r = "";
|
||||||
|
for(auto i : s) {
|
||||||
|
if (r.find(i) == std::string::npos) {
|
||||||
|
r += i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // UTIL_H
|
Reference in New Issue
Block a user