init
This commit is contained in:
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