Commit 8d0c0fb6 authored by Victor Yacovlev's avatar Victor Yacovlev

PDAutomata implementation

parent 6c5ef65d
# ====================== Программа в целом
# ----------- Правила корректной программы
[0] START -> \
begin \
ЗАГРУЗКА* \ # Строки использовать
ЛИНЕЙНАЯ_СТРОКА* \ # Простые строки до алгоритмов
АЛГОРИТМ* \ # Алгоритмы
ИСПОЛНИТЕЛЬ* \ # Исполнители
end
[0] ЗАГРУЗКА* -> использовать : { processCorrectLoad(); }
[0] ЛИНЕЙНАЯ_СТРОКА* -> простое_предложение : { appendSimpleLine(); }
# ----------- Ошибочные правила
[6] ЛИНЕЙНАЯ_СТРОКА* -> использовать : {
# Строки "использовать" должны быть в начале программы.
# Ругаемся, что строка не на месте
setCurrentError("Misplaced import");
# Добавляем строку (которая уже помечена как ошибочная)
# в текущее место программы
appendSimpleLine();
}
[93] ЛИНЕЙНАЯ_СТРОКА* -> !простое_предложение : {
# В инициализации алгоритма допускаются только не
# ветвящиеся конструкции, поэтому ругаемся
setOutOfAlgError();
# Добавляем строку (которая уже помечена как ошибочная)
# в текущее место программы
appendSimpleLine();
}
# ====================== Алгоритмы
[0] АЛГОРИТМ* -> \
алг \ # признак начала алгоритма
МУСОР_АЛГ_НАЧ* \ # какая-та бяка
ДОКУМЕНТАЦИЯ* \ # комментарий специального вида
ДАНО_НАДО* \ # ограничения алгоритма
ТЕЛО_АЛГОРИТМА \ # см. ниже
: {
# Создаем новый алгоритм и делаем его текущим
processCorrectAlgHeader();
}
[9] АЛГОРИТМ* -> \
алг \ # признак начала алгоритма
ДОКУМЕНТАЦИЯ* \ # комментарий специального вида
ДАНО_НАДО* \ # ограничения алгоритма
ФРАГМЕНТ_АЛГОРИТМА* \ # попытка описать тело без "нач"
КОНЕЦ_АЛГОРИТМА \
: {
# Ошибка, но, трактуем как легальную структуру алгоритма
processAlgWithNoBegin();
}
[0] МУСОР_АЛГ_НАЧ* -> 0 # в корректной программе его быть не должно
[10] МУСОР_АЛГ_НАЧ* -> !ограничение_алгоритма,нач,кон \ # всё, кроме "нач", "дано",
# "надо", спецкомментария
# и "кон"
: {
setGarbageAlgError();
}
[0] ДОКУМЕНТАЦИЯ* -> строка_документации : {
processCorrectDocLine();
}
[0] ДАНО_НАДО* -> ограничение_алгоритма\# строки "дано" или "надо"
МУСОР_АЛГ_НАЧ* \ # мусор может встетится после "дано"/"надо"
: {
processCorrectRestrictionLine();
}
[0] ТЕЛО_АЛГОРИТМА -> нач \ # начало тела алгоритма
ФРАГМЕНТ_АЛГОРИТМА* \ # см. файл C-AlgorithmPart.rules
КОНЕЦ_АЛГОРИТМА \ # конец тела алгоритма
МУСОР_ПОСЛЕ_АЛГОРИТМА* \ # см. ниже
: {
# Кладем в стек разбора указатель на тело текущего алгоритма
processCorrectAlgBegin();
}
[11] ТЕЛО_АЛГОРИТМА -> нач \ # нет "кон"
ФРАГМЕНТ_АЛГОРИТМА*: {
# Ругаемся
processCorrectAlgBegin();
setExtraOpenKeywordError("нач");
}
[15] ТЕЛО_АЛГОРИТМА -> нач : { # недописанная конструкция "алг нач"
# Ругаемся
setExtraOpenKeywordError("нач");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать "\nкон\n", затем переместить курсор на 2 строки вверх
suggest("\nкон\n", 2);
}
[0] КОНЕЦ_АЛГОРИТМА -> кон : {
# Вытаскиваем из стека разбора указатель на тело текущего алгоритма
processCorrectAlgEnd();
}
[8] КОНЕЦ_АЛГОРИТМА -> кон_исп : {
# "кон_исп" вместо "кон" -- это ошибка.
# Трактуем ее как псевдо-"кон" и ругаемся
processModEndInsteadOfAlgEnd();
}
[0] МУСОР_ПОСЛЕ_АЛГОРИТМА* -> 0 # в корректной программе его быть не должно
[91] АЛГОРИТМ* -> кон : { setExtraCloseKeywordError("кон"); }
[91] АЛГОРИТМ* -> при : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> все : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> кц : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> кон : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> ограничение_алгоритма : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> строка_документации : { setOutOfAlgError(); }
[91] АЛГОРИТМ* -> нач ФРАГМЕНТ_АЛГОРИТМА* КОНЕЦ_АЛГОРИТМА : { setCurrentError("No algorhitm header"); addDummyAlgHeader(); processCorrectAlgBegin(); }
[92] АЛГОРИТМ* -> алг : { setCurrentError("No algorhitm implementation"); appendSimpleLine(); suggest("нач\n\nкон\n",5); }
[92] АЛГОРИТМ* -> если : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> кон : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> выбор : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> при : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> все : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> нц : { setOutOfAlgError(); }
[92] АЛГОРИТМ* -> кц : { setOutOfAlgError(); }
# ====================== Фрагмент алгоритма
[0] ФРАГМЕНТ_АЛГОРИТМА* -> простое_предложение : { appendSimpleLine(); }
[0] ФРАГМЕНТ_АЛГОРИТМА* -> УСЛОВИЕ # если то ... [иначе ...] все
[0] ФРАГМЕНТ_АЛГОРИТМА* -> ВЫБОР # выбор при ... [при ...] [иначе ...] все
[0] ФРАГМЕНТ_АЛГОРИТМА* -> ЦИКЛ # нц ... кц
[20] ФРАГМЕНТ_АЛГОРИТМА* -> алг : { # ошибка -- ругаемся
setCurrentError("Algorhitm header in algorhitm body");
appendSimpleLine();
}
[20] ФРАГМЕНТ_АЛГОРИТМА* -> нач : { # ошибка -- ругаемся
setCurrentError("Begin in algorhitm body");
appendSimpleLine();
}
[20] ФРАГМЕНТ_АЛГОРИТМА* -> исп : { # ошибка -- ругаемся
setCurrentError("Module in algorhitm body");
appendSimpleLine();
}
[20] ФРАГМЕНТ_АЛГОРИТМА* -> кон_исп : { # ошибка -- ругаемся
setCurrentError("End module in algorhitm body");
appendSimpleLine();
}
# алгоритм целиком в качестве ФРАГМЕНТ_АЛГОРИТМА
[20] ФРАГМЕНТ_АЛГОРИТМА* -> алг нач ДОКУМЕНТАЦИЯ* ДАНО_НАДО* ФРАГМЕНТ_АЛГОРИТМА* кон : {
setCurrentError("Inner algorithm");
setCurrentIndentRank(0, +1);
appendSimpleLine();
} {
setCurrentError("Inner algorithm");
setCurrentIndentRank(-1, +1);
appendSimpleLine();
} {
setCurrentError("Inner algorithm");
setCurrentIndentRank(-1, 0)
appendSimpleLine();
}
[91] ФРАГМЕНТ_АЛГОРИТМА* -> все : { setExtraCloseKeywordError("все"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> кц : { setExtraCloseKeywordError("кц"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> иначе : { setExtraCloseKeywordError("иначе"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> ограничение_алгоритма : { setExtraCloseKeywordError("ограничение_алгоритма"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> строка_документации : { setExtraCloseKeywordError("строка_документации"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> при : { setExtraCloseKeywordError("при"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> то : { setExtraCloseKeywordError("то"); }
[91] ФРАГМЕНТ_АЛГОРИТМА* -> использовать : { setCurrentError("Misplaced import"); appendSimpleLine(); }
# --- условие
[0] УСЛОВИЕ -> если МУСОР_ЕСЛИ_ТО* ТО_ИНАЧЕ_ВСЕ : {
# Добавляем в стек разбора указатель на тело
# конструкции "если то ... [иначе ...] все"
processCorrectIf();
}
[11] УСЛОВИЕ -> если \ # недописанная конструкция "если"
: {
# Ругаемся
setExtraOpenKeywordError("если");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать то\n\nвсе, затем переместить курсор на 1 строку вверх
suggest("то\n\nвсе", 1);
}
[0] ТО_ИНАЧЕ_ВСЕ -> то ФРАГМЕНТ_АЛГОРИТМА* ИНАЧЕ_ВСЕ : {
# Инициализирует тело конструкции "если то ... "
processCorrectThen();
}
[11] ТО_ИНАЧЕ_ВСЕ -> то : { # недописанная конструкция "если то"
# Ругаемся
setExtraOpenKeywordError("то");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать \nвсе, затем переместить курсор на 1 строку вверх
suggest("\nвсе", 1);
# Ругаемся на "если"
setCorrespondingIfBroken();
}
[20] ТО_ИНАЧЕ_ВСЕ -> иначе \ # пропущен "то" между "если ... иначе"
ФРАГМЕНТ_АЛГОРИТМА* \
все \
: {
# Отрабатывает dummy конструкцию "то"
processCorrectThenIfNotExists2();
# Добавить тело конструкции "иначе ... все"
processCorrectElse();
# Ругаемся
setCurrentError("No 'then' before else..fi");
# Добавляем ошибочную строку в программу
appendSimpleLine();
} {
processCorrectFi();
}
[0] МУСОР_ЕСЛИ_ТО* -> 0 # в корректной программе его быть не должно
[7] МУСОР_ЕСЛИ_ТО* -> !то \ # ожидается "то", а встретилось что-то другое
МУСОР_ЕСЛИ_ТО* \ # таких строк мож
: {
setGarbageIfThenError();
}
[0] ИНАЧЕ_ВСЕ -> все : {
# Вытаскиваем из стека разбора указатель на тело
# конструкции "если то ... все" или
# конструкции "выбор при ... все"
processCorrectFi();
}
[0] ИНАЧЕ_ВСЕ -> иначе ФРАГМЕНТ_АЛГОРИТМА* все : {
# Инициализируем тело конструкции "иначе ... все"
processCorrectElse();
} {
# Вытаскиваем из стека разбора указатель на тело
# конструкции "если то ... все" или
# конструкции "выбор при ... все"
processCorrectFi();
}
[10] ИНАЧЕ_ВСЕ -> иначе : { # недописанная конструкция "иначе"
# Ругаемся
setExtraOpenKeywordError("иначе");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать \nвсе, затем переместить курсор на 1 строку вверх
suggest("\nвсе", 1);
# Ругаемся на "если"
setCorrespondingIfBroken();
}
# --- выбор
[0] ВЫБОР -> выбор \
МУСОР_ВЫБОР_ПРИ* \
при \ # конструкции "выбор" должен быть хотя бы один "при"
ФРАГМЕНТ_АЛГОРИТМА* \
ПРИ* \ # возможные последующие конструкции "при"
ФРАГМЕНТ_АЛГОРИТМА* \
ИНАЧЕ_ВСЕ \ # возможная конструкция "иначе...все", как для ЕСЛИ
: {
processCorrectSwitch();
} {
processCorrectCase();
}
[0] МУСОР_ВЫБОР_ПРИ* -> 0 # в корректной программе его быть не должно
[7] МУСОР_ВЫБОР_ПРИ* -> !при \ # ожидается "при", но встретилось что-то другое
: {
setGarbageSwitchCaseError();
}
[9] ВЫБОР -> выбор ИНАЧЕ_ВСЕ : {
# Ошибка: нет ни одного "при".
setCurrentError("No one 'case'");
# Создаем структуру как для корректной конструкции,
# чтобы искать ошибки уже внутри нее
processCorrectSwitch();
}
[10] ВЫБОР -> выбор : { # недописанная конструкция "выбор"
# Ругаемся
setExtraOpenKeywordError("выбор");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать "при \nвсе", затем переместить курсор на 1 строку вверх
suggest("при \nвсе", 1);
}
[0] ПРИ* -> при ФРАГМЕНТ_АЛГОРИТМА* : {
processCorrectCase();
}
# --- цикл
[0] ЦИКЛ -> нц ФРАГМЕНТ_АЛГОРИТМА* КЦ : {
processCorrectBeginOfLoop();
}
[10] ЦИКЛ -> нц : { # недописанная конструкция "нц"
# Ругаемся
setExtraOpenKeywordError("нц");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать "\nкц", затем переместить курсор на 1 строку вверх
suggest("\nкц", 1);
}
[11] ЦИКЛ -> нц ФРАГМЕНТ_АЛГОРИТМА* : { # нет парного "кц"
# Ругаемся
setExtraOpenKeywordError("нц");
}
[0] КЦ -> кц : {
processCorrectEndOfLoop();
}
[93] ЦИКЛ -> нц ФРАГМЕНТ_АЛГОРИТМА* кон : { # нет парного "кц"
# Ругаемся
setExtraOpenKeywordError("нц");
} {
# Ошибка: "кон" вместо "кц"
setCurrentError("'end' instead of 'end loop'");
processCorrectEndOfLoop();
}
# ====================== Исполнители
[0] ИСПОЛНИТЕЛЬ* -> исп \ # заголовок исполнителя
ИСП_НАЧ \ # "нач" после "исп"
ЛИНЕЙНАЯ_СТРОКА* \ # инициализация исполнителя
АЛГОРИТМ* \ # один или несколько алгоритмов
кон_исп \ # конец исполнителя
МУСОР_ПОСЛЕ_ИСП* \ # строки вне исполнителя
: {
processCorrectModuleBegin();
} {
processCorrectModuleEnd();
}
[0] ИСП_НАЧ -> 0 # после "исп" нет "нач"
[0] МУСОР_ПОСЛЕ_ИСП* -> 0 # в нормальной ситуации мусора быть не должно
[7] МУСОР_ПОСЛЕ_ИСП* -> !end \ # какая-та гадость в конце
: {
setOutOfAlgError();
appendSimpleLine();
}
[20] ИСП_НАЧ -> нач : { # а это -- ошибка
setCurrentError("Extra 'begin'");
appendSimpleLine();
}
[10] ИСПОЛНИТЕЛЬ* -> исп \ # "исп" без "кон_исп"
ИСП_НАЧ \ # "нач" после "исп"
ЛИНЕЙНАЯ_СТРОКА* \ # инициализация исполнителя
АЛГОРИТМ* \ # один или несколько алгоритмов
: {
# Ругаемся
setExtraOpenKeywordError("исп");
}
[15] ИСПОЛНИТЕЛЬ* -> исп : { # недописанная конструкция "исп"
# Ругаемся
setExtraOpenKeywordError("исп");
# Предлагаем текстовому редактору дописать конструкцию:
# -- дописать "\n\n\nкон_исп\n", затем переместить курсор на 3 строки вверх
suggest("\n\n\nкон_исп\n", 3);
}
[91] ИСПОЛНИТЕЛЬ* -> кон : { setOutOfAlgError(); }
[91] ИСПОЛНИТЕЛЬ* -> кон_исп : { setCurrentError("No pairing 'begin module'"); appendSimpleLine(); }
[91] ИСПОЛНИТЕЛЬ* -> простое_предложение : { setOutOfAlgError(); }
[92] ИСПОЛНИТЕЛЬ* -> нач : { setOutOfAlgError(); }
This diff is collapsed.
......@@ -76,13 +76,32 @@ QString getLanguage()
}
class Application
: public QApplication
{
public:
inline explicit Application(int argc, char **argv, bool gui)
: QApplication(argc, argv, gui) {}
inline bool notify(QObject * receiver, QEvent * event) {
bool result = false;
try {
result = QApplication::notify(receiver, event);
}
catch (...) {
qDebug() << "Exception caught in QApplication::notify!!!";
// abort();
}
return result;
}
};
int main(int argc, char **argv)
{
bool gui = true;
#ifdef Q_WS_X11
gui = gui && getenv("DISPLAY")!=0;
#endif
QApplication * app = new QApplication(argc, argv, gui);
QApplication * app = new Application(argc, argv, gui);
QLocale russian = QLocale("ru_RU");
QLocale::setDefault(russian);
#ifdef Q_OS_WIN32
......
......@@ -131,6 +131,7 @@ inline void removeAllBackReference(QTreeWidgetItem * item) {
void DebuggerWindow::updateAllValues()
{
return;
// Update variables -- it is possible that
// called function changed something while running
// not step-in mode (via out-parameters)
......@@ -274,7 +275,7 @@ void DebuggerWindow::updateLocalTableValue(
const QList<int> & indeces
)
{
Q_ASSERT(topLevelItemCount()>0);
Q_ASSERT_X(topLevelItemCount()>0, "updateLocalTableBounds", "topLevelItemCount()>0");
QTreeWidgetItem * context = topLevelItem(topLevelItemCount()-1);
QTreeWidgetItem * variable = nullptr;
for (int i=0; i<context->childCount(); i++) {
......@@ -283,7 +284,7 @@ void DebuggerWindow::updateLocalTableValue(
break;
}
}
Q_CHECK_PTR(variable);
Q_ASSERT_X(variable!=nullptr, "updateLocalTableBounds", "variable!=nullptr");
setupTableValue(variable);
clearSelection();
QTreeWidgetItem * itemToSelect = variable;
......@@ -369,7 +370,7 @@ void DebuggerWindow::updateLocalTableBounds(
{
if (bounds.isEmpty())
return;
Q_ASSERT(topLevelItemCount()>0);
Q_ASSERT_X(topLevelItemCount()>0, "updateLocalTableBounds", "topLevelItemCount()>0");
QTreeWidgetItem * context = topLevelItem(topLevelItemCount()-1);
QTreeWidgetItem * variable = nullptr;
for (int i=0; i<context->childCount(); i++) {
......@@ -378,7 +379,7 @@ void DebuggerWindow::updateLocalTableBounds(
break;
}
}
Q_CHECK_PTR(variable);
Q_ASSERT_X(variable!=nullptr, "updateLocalTableBounds", "variable!=nullptr");
QString text;
text = variable->data(0, ROLE_BASETYPE).toString()+QString::fromUtf8("таб");
text += " "+variable->data(0, ROLE_NAME).toString()+"[";
......@@ -743,36 +744,36 @@ void DebuggerWindow::setLocalReference(
}
else {
int targetFrameNo = topLevelItemCount()-1 - back;
Q_ASSERT(targetFrameNo>=0);
targetContext = topLevelItem(targetFrameNo);
if (targetFrameNo>=0)
targetContext = topLevelItem(targetFrameNo);
}
Q_CHECK_PTR(targetContext);
for (int i=0; i<targetContext->childCount(); i++) {
if (targetName==targetContext->child(i)->data(0, ROLE_NAME).toString()) {
targetVariable = targetContext->child(i);
break;
if (targetContext) {
for (int i=0; i<targetContext->childCount(); i++) {
if (targetName==targetContext->child(i)->data(0, ROLE_NAME).toString()) {
targetVariable = targetContext->child(i);
break;
}
}
}
Q_CHECK_PTR(targetVariable);
// Set reference and back reference to update values automatically
QVariantList backReferenceList;
if (targetVariable->data(0, ROLE_BACK_REFERENCES).isValid()) {
backReferenceList = targetVariable->data(0, ROLE_BACK_REFERENCES).toList();
}
backReferenceList.push_back(reinterpret_cast<quintptr>(variable));
targetVariable->setData(0, ROLE_BACK_REFERENCES, backReferenceList);
variable->setData(0, ROLE_REFERENCE, reinterpret_cast<quintptr>(targetVariable));
if (targetVariable) {
// Set reference and back reference to update values automatically
QVariantList backReferenceList;
if (targetVariable->data(0, ROLE_BACK_REFERENCES).isValid()) {
backReferenceList = targetVariable->data(0, ROLE_BACK_REFERENCES).toList();
}
backReferenceList.push_back(reinterpret_cast<quintptr>(variable));
targetVariable->setData(0, ROLE_BACK_REFERENCES, backReferenceList);
variable->setData(0, ROLE_REFERENCE, reinterpret_cast<quintptr>(targetVariable));
QString text;
text = variable->data(0, ROLE_BASETYPE).toString();
text += " "+variable->data(0, ROLE_NAME).toString();
if (targetVariable->data(0, ROLE_VALUE).isValid()) {
text += " = "+targetVariable->data(0, ROLE_VALUE).toString();
QString text;
text = variable->data(0, ROLE_BASETYPE).toString();
text += " "+variable->data(0, ROLE_NAME).toString();
if (targetVariable->data(0, ROLE_VALUE).isValid()) {
text += " = "+targetVariable->data(0, ROLE_VALUE).toString();
}
variable->setText(0, text);
}
variable->setText(0, text);
// clearSelection();
// variable->setSelected(true);
}
void DebuggerWindow::paintEvent(QPaintEvent *event)
......
This diff is collapsed.
......@@ -41,10 +41,10 @@ struct PDStackElem {
class PDAutomataPrivate:
public QObject
{
Q_OBJECT;
Q_OBJECT
public:
void loadRules(const QString &rulesRoot);
void loadRules(const QString &rulesRoot);
class PDAutomata * q;
~PDAutomataPrivate();
AST::Data * ast;
......@@ -57,11 +57,13 @@ public:
int currentPosition;
QVector<ScriptListPtr> scripts;
QVector<QString> acceptedRules;
QStack<PDStackElem> stack;
QStack<int> history_currentPosition;
QStack< QVector<ScriptListPtr> > history_scripts;
QStack< QStack<PDStackElem> > history_stack;
QStack< QVector<int> > history_nextPointers;
QVector<ScriptListPtr> fixedScripts;
QVector<int> nextPointers;
......@@ -73,6 +75,7 @@ public:
qreal maxPriorityValue;
void matchScript(const QString &text, ScriptListPtr & scripts);
void addEpsilonRule(const QString &nonTerminal, const qreal prior, const QString & script );
int errorsCount;
......@@ -104,6 +107,7 @@ public slots:
void processCorrectModuleEnd();
void processCorrectLoad();
void appendSimpleLine();
void processAlgWithNoBegin();
void setGarbageAlgError();
void setGarbageIfThenError();
void setGarbageSwitchCaseError();
......
......@@ -20,4 +20,15 @@ bool Statement::hasError() const
return false;
}
void Statement::setError(const QString &err,
const Lexem::ErrorStage stage,
const Lexem::ErrorRaisePosition raise)
{
for (int i=0; i<data.size(); i++) {
data[i]->error = err;
data[i]->errorStage = stage;
data[i]->errorRaisePosition = raise;
}
}
}
......@@ -29,6 +29,10 @@ struct Statement
QList<AST::Variable*> variables;
int conditionalIndex;
bool hasError() const;
void setError(const QString & err,
const Lexem::ErrorStage stage,
const Lexem::ErrorRaisePosition raise
);
explicit Statement();
QPair<QString,quint32> suggestedClosingBracket;
};
......
......@@ -1550,10 +1550,25 @@ void Generator::IFTHENELSE(int modId, int algId, int level, const AST::Statement
void Generator::SWITCHCASEELSE(int modId, int algId, int level, const AST::Statement *st, QList<Bytecode::Instruction> & result)