/*Copyright (c) 2019 Alexis Nasr && Franck Dary Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:i The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.*/ #include "ActionBank.hpp" #include "Config.hpp" #include "util.hpp" #include "ProgramParameters.hpp" Action::BasicAction ActionBank::moveHead(int movement) { auto apply = [movement](Config & c, Action::BasicAction &) {c.moveHead(movement);}; auto undo = [movement](Config & c, Action::BasicAction &) {c.moveHead(-movement);}; auto appliable = [](Config &, Action::BasicAction &) {return true;}; Action::BasicAction basicAction = {Action::BasicAction::Type::MoveHead, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::increaseTapesIfNeeded(int size) { auto apply = [size](Config & c, Action::BasicAction &) { for (auto & tape : c.tapes) for (int i = 0; i <= size-(tape.refSize()-c.getHead()); i++) { tape.addToRef(""); tape.addToHyp(""); } }; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config &, Action::BasicAction &) {return true;}; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::moveRawInputHead(int movement) { auto apply = [movement](Config & c, Action::BasicAction &) {c.moveRawInputHead(movement);}; auto undo = [movement](Config & c, Action::BasicAction &) {c.moveRawInputHead(-movement);}; auto appliable = [movement](Config & c, Action::BasicAction &) {return c.rawInputHeadIndex+movement <= (int)c.rawInput.size();}; Action::BasicAction basicAction = {Action::BasicAction::Type::MoveHead, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::checkRawInputHeadIsSpace() { auto apply = [](Config &, Action::BasicAction &) {}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config & c, Action::BasicAction &) { return util::isUtf8Space(c.rawInput.begin()+c.rawInputHeadIndex); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::checkConfigIsNotFinal() { auto apply = [](Config &, Action::BasicAction &) {}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config & c, Action::BasicAction &) { return !c.isFinal(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::checkRawInputHeadIsSeparator() { auto apply = [](Config &, Action::BasicAction &) {}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config & c, Action::BasicAction &) { return util::isUtf8Separator(c.rawInput.begin()+c.rawInputHeadIndex); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::rawInputBeginsWith(std::string word) { auto apply = [](Config &, Action::BasicAction &) {}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [word](Config & c, Action::BasicAction &) { if (c.rawInputHeadIndex+word.size() >= c.rawInput.size()) return false; for (unsigned int i = 0; i < word.size(); i++) if (c.rawInput[c.rawInputHeadIndex+i] != word[i]) return false; return true; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::bufferWrite(std::string tapeName, std::string value, int relativeIndex) { auto apply = [tapeName, value, relativeIndex](Config & c, Action::BasicAction &) { simpleBufferWrite(c, tapeName, value, relativeIndex); }; auto undo = [tapeName, relativeIndex](Config & c, Action::BasicAction &) { simpleBufferWrite(c, tapeName, "", relativeIndex); }; auto appliable = [tapeName, relativeIndex](Config & c, Action::BasicAction &) { return simpleBufferWriteAppliable(c, tapeName, relativeIndex); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, value, apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::stackWrite(std::string tapeName, std::string value, int stackIndex) { auto apply = [tapeName, value, stackIndex](Config & c, Action::BasicAction &) { int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); simpleBufferWrite(c, tapeName, value, relativeIndex); }; auto undo = [tapeName, stackIndex](Config & c, Action::BasicAction &) { int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); simpleBufferWrite(c, tapeName, "", relativeIndex); }; auto appliable = [tapeName, stackIndex](Config & c, Action::BasicAction &) { if (!c.stackHasIndex(stackIndex)) return false; int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); return simpleBufferWriteAppliable(c, tapeName, relativeIndex); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, value, apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::bufferApply(std::string tapeName, int relativeIndex, std::function<std::string(std::string)> modification) { auto apply = [tapeName, relativeIndex, modification](Config & config, Action::BasicAction & ba) { auto & tape = config.getTape(tapeName); auto & from = tape[relativeIndex]; ba.data = from; tape.setHyp(relativeIndex, modification(from)); }; auto undo = [tapeName, relativeIndex](Config & config, Action::BasicAction & ba) { auto & tape = config.getTape(tapeName); tape.setHyp(relativeIndex, ba.data); ba.data = ""; }; auto appliable = [](Config & c, Action::BasicAction &) { return !c.isFinal(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "apply", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::stackApply(std::string tapeName, int relativeIndex, std::function<std::string(std::string)> modification) { auto apply = [tapeName, relativeIndex, modification](Config & config, Action::BasicAction & ba) { int bufferIndex = config.stackGetElem(relativeIndex); int index = bufferIndex - config.getHead(); auto & tape = config.getTape(tapeName); auto & from = tape[index]; ba.data = from; tape.setHyp(relativeIndex, modification(from)); }; auto undo = [tapeName, relativeIndex](Config & config, Action::BasicAction & ba) { int bufferIndex = config.stackGetElem(relativeIndex); int index = bufferIndex - config.getHead(); auto & tape = config.getTape(tapeName); tape.setHyp(index, ba.data); ba.data = ""; }; auto appliable = [](Config & c, Action::BasicAction &) { return !c.isFinal(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "apply", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::bufferAdd(std::string tapeName, std::string value, int relativeIndex) { auto apply = [tapeName, value, relativeIndex](Config & config, Action::BasicAction &) { auto & tape = config.getTape(tapeName); auto & from = tape.getHyp(relativeIndex); auto parts = from.empty() ? std::vector<std::string>() : util::split(from, '|'); parts.emplace_back(value); std::sort(parts.begin(), parts.end()); std::string newValue; for (auto & part : parts) newValue += part + '|'; newValue.pop_back(); tape.setHyp(relativeIndex, newValue); }; auto undo = [tapeName, relativeIndex](Config & config, Action::BasicAction &) { auto & tape = config.getTape(tapeName); auto from = tape.getHyp(relativeIndex); while (!from.empty() && from.back() != '|') from.pop_back(); if (!from.empty() && from.back() == '|') from.pop_back(); tape.setHyp(relativeIndex, from); }; auto appliable = [tapeName, relativeIndex, value](Config & config, Action::BasicAction &) { if (config.isFinal()) return false; auto & tape = config.getTape(tapeName); auto & from = tape.getHyp(relativeIndex); if (from.empty()) return true; auto splited = util::split(from, '|'); for (auto & part : splited) if (part == value) return false; return true; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, value, apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::stackAdd(std::string tapeName, std::string value, int stackIndex) { auto apply = [tapeName, value, stackIndex](Config & c, Action::BasicAction &) { int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); auto & tape = c.getTape(tapeName); auto & from = tape.getHyp(relativeIndex); if (!from.empty()) tape.setHyp(relativeIndex, from+'|'+value); else tape.setHyp(relativeIndex, value); }; auto undo = [tapeName, stackIndex](Config & c, Action::BasicAction &) { int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); auto & tape = c.getTape(tapeName); auto from = tape.getHyp(relativeIndex); while (!from.empty() && from.back() != '|') from.pop_back(); if (!from.empty() && from.back() == '|') from.pop_back(); tape.setHyp(relativeIndex, from); }; auto appliable = [tapeName, stackIndex, value](Config & c, Action::BasicAction &) { if (c.isFinal()) return false; int bufferIndex = c.stackGetElem(stackIndex); int relativeIndex = bufferIndex - c.getHead(); auto & tape = c.getTape(tapeName); auto & from = tape.getHyp(relativeIndex); auto splited = util::split(from, '|'); for (auto & part : splited) if (part == value) return false; return true; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, value, apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::pushHead() { auto apply = [](Config & c, Action::BasicAction &) {c.stackPush(c.getHead());}; auto undo = [](Config & c, Action::BasicAction &) {c.stackPop();}; auto appliable = [](Config & c, Action::BasicAction &) {return !(c.stackSize() >= ProgramParameters::maxStackSize || (!c.stackEmpty() && c.stackTop() == c.getHead()) || c.getHead() >= c.getTape(ProgramParameters::sequenceDelimiterTape).size());}; Action::BasicAction basicAction = {Action::BasicAction::Type::Push, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::stackPop(bool checkGov) { auto apply = [](Config & c, Action::BasicAction & ba) {ba.data = std::to_string(c.stackTop()); c.stackPop();}; auto undo = [](Config & c, Action::BasicAction & ba) {c.stackPush(std::stoi(ba.data));}; auto appliable = [checkGov](Config & c, Action::BasicAction &) { if (c.stackEmpty()) return false; if (!checkGov) return true; if (c.rawInputHeadIndex == 0) { if (util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '.').size() > 1 || util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '-').size() > 1) return true; } else { if (util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '.').size() > 1 || util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '-').size() > 1) return true; } return (!c.getTape("GOV").getHyp(c.stackTop()-c.getHead()).empty() && c.stackTop() != c.getHead()); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Pop, "", apply, undo, appliable}; return basicAction; } Action::BasicAction ActionBank::checkNotEmpty(std::string tape, int relativeIndex) { auto apply = [](Config &, Action::BasicAction &) {}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [tape, relativeIndex](Config & c, Action::BasicAction &) { return !c.getTape(tape).getHyp(relativeIndex).empty(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; return basicAction; } std::vector<Action::BasicAction> ActionBank::str2sequence(const std::string & name) { auto invalidNameAndAbort = [&](const char * errInfo) { fprintf(stderr, "ERROR (%s) : unknown action name \'%s\' Aborting.\n", errInfo, name.c_str()); exit(1); }; std::vector<Action::BasicAction> sequence; char b1[1024]; char b2[1024]; char b3[1024]; char b4[1024]; if (sscanf(name.c_str(), "%s", b1) != 1) invalidNameAndAbort(ERRINFO); if(std::string(b1) == "WRITE") { if (sscanf(name.c_str(), "%s %s %s %s", b1, b4, b2, b3) != 4) invalidNameAndAbort(ERRINFO); std::string tapeName(b2); std::string value(b3); auto object = util::split(b4, '.'); if (object.size() != 2) invalidNameAndAbort(ERRINFO); int relativeIndex = std::stoi(object[1]); if (object[0] == "b") sequence.emplace_back(bufferWrite(tapeName, value, relativeIndex)); else if (object[0] == "s") sequence.emplace_back(stackWrite(tapeName, value, relativeIndex)); } else if(std::string(b1) == "TOLOWER" || std::string(b1) == "TOUPPER") { if (sscanf(name.c_str(), "%s %s %s", b1, b4, b2) != 3) invalidNameAndAbort(ERRINFO); std::string tapeName(b2); auto object = util::split(b4, '.'); if (object.size() != 2) invalidNameAndAbort(ERRINFO); int relativeIndex = std::stoi(object[1]); std::function<std::string(std::string)> modification; if (std::string(b1) == "TOLOWER") modification = [](std::string s) { return util::toLowerCase(s); }; else modification = [](std::string s) { return util::toUpperCase(s); }; if (object[0] == "b") sequence.emplace_back(bufferApply(tapeName, relativeIndex, modification)); else if (object[0] == "s") sequence.emplace_back(stackApply(tapeName, relativeIndex, modification)); } else if(std::string(b1) == "ADD") { if (sscanf(name.c_str(), "%s %s %s %s", b1, b4, b2, b3) != 4) invalidNameAndAbort(ERRINFO); std::string tapeName(b2); std::string value(b3); auto object = util::split(b4, '.'); if (object.size() != 2) invalidNameAndAbort(ERRINFO); int relativeIndex = std::stoi(object[1]); if (object[0] == "b") sequence.emplace_back(bufferAdd(tapeName, value, relativeIndex)); else if (object[0] == "s") sequence.emplace_back(stackAdd(tapeName, value, relativeIndex)); } else if(std::string(b1) == "MULTIWRITE") { int startRelIndex; int endRelIndex; if (sscanf(name.c_str(), "%s %d %d %s", b1, &startRelIndex, &endRelIndex, b2) != 4) invalidNameAndAbort(ERRINFO); std::string tapeName(b2); auto splits = util::split(name); for(int i = startRelIndex; i <= endRelIndex; i++) sequence.emplace_back(bufferWrite(tapeName, splits[4+i-startRelIndex], i)); } else if(std::string(b1) == "RULE") { if (sscanf(name.c_str(), "%s %s ON %s %[^\n]", b1, b2, b3, b4) != 4) invalidNameAndAbort(ERRINFO); std::string targetTapeName(b2); std::string fromTapeName(b3); std::string rule(b4); auto apply = [fromTapeName, targetTapeName, rule](Config & c, Action::BasicAction &) {writeRuleResult(c, fromTapeName, targetTapeName, rule, 0);}; auto undo = [targetTapeName](Config & c, Action::BasicAction &) {simpleBufferWrite(c, targetTapeName, "", 0);}; auto appliable = [fromTapeName,targetTapeName,rule](Config & c, Action::BasicAction &) {return isRuleAppliable(c, fromTapeName, targetTapeName, 0, rule);}; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, rule, apply, undo, appliable}; sequence.emplace_back(basicAction); } else if(std::string(b1) == "NOTFOUND") { } else if(std::string(b1) == "NOTHING") { sequence.emplace_back(checkConfigIsNotFinal()); } else if(std::string(b1) == "EPSILON") { } else if(std::string(b1) == "MOVE") { int movement; if (sscanf(name.c_str(), "MOVE %s %d", b2, &movement) != 2) invalidNameAndAbort(ERRINFO); sequence.emplace_back(moveHead(movement)); } else if(std::string(b1) == "IGNORECHAR") { sequence.emplace_back(checkRawInputHeadIsSeparator()); sequence.emplace_back(moveRawInputHead(1)); } else if(std::string(b1) == "ENDWORD") { sequence.emplace_back(checkNotEmpty("FORM", 0)); sequence.emplace_back(increaseTapesIfNeeded(1)); auto apply = [](Config & c, Action::BasicAction &) {simpleBufferWrite(c, "ID", std::to_string(c.currentWordIndex), 0);}; auto undo = [](Config & c, Action::BasicAction &) {simpleBufferWrite(c, "ID", std::string(""), 0);}; auto appliable = [](Config & c, Action::BasicAction &) {return simpleBufferWriteAppliable(c, "ID", 0);}; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } else if(std::string(b1) == "ADDCHARTOWORD") { sequence.emplace_back(increaseTapesIfNeeded(0)); auto apply = [](Config & c, Action::BasicAction &) {addCharToBuffer(c, "FORM", 0);}; auto undo = [](Config & c, Action::BasicAction &) {removeCharFromBuffer(c, "FORM", 0);}; auto appliable = [](Config & c, Action::BasicAction &) {return c.getTape("FORM").getHyp(0).size() <= 2000 && c.rawInput[c.rawInputHeadIndex] != '\t';}; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); sequence.emplace_back(moveRawInputHead(1)); } else if(std::string(b1) == "SPLITWORD") { if (sscanf(name.c_str(), "SPLITWORD %s", b2) != 1) invalidNameAndAbort(ERRINFO); auto splited = util::split(b2, '@'); int nbSymbols = util::getNbSymbols(splited[0]); sequence.emplace_back(rawInputBeginsWith(splited[0])); sequence.emplace_back(moveRawInputHead(nbSymbols)); sequence.emplace_back(increaseTapesIfNeeded(splited.size())); for (unsigned int i = 0; i < splited.size(); i++) { sequence.emplace_back(bufferWrite("FORM", splited[i], i)); int splitedSize = (int)splited.size(); auto apply = [i, splitedSize](Config & c, Action::BasicAction &) {simpleBufferWrite(c, "ID", i == 0 ? std::to_string(c.currentWordIndex) + "-" + std::to_string(c.currentWordIndex+splitedSize-2) : std::to_string(c.currentWordIndex+i-1), i);}; auto undo = [i](Config & c, Action::BasicAction &) {simpleBufferWrite(c, "ID", std::string(""), i);}; auto appliable = [i](Config & c, Action::BasicAction &) {return simpleBufferWriteAppliable(c, "ID", i);}; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } } else if(std::string(b1) == "MOVERAW") { int movement; if (sscanf(name.c_str(), "MOVERAW %d", &movement) != 1) invalidNameAndAbort(ERRINFO); sequence.emplace_back(moveRawInputHead(movement)); } else if(std::string(b1) == "ERROR") { auto apply = [](Config &, Action::BasicAction &) {fprintf(stderr, "ERROR\n");}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config &, Action::BasicAction &) {return true;}; Action::BasicAction basicAction = {Action::BasicAction::Type::Push, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } else if(std::string(b1) == "CORRECT") { auto apply = [](Config &, Action::BasicAction &) {fprintf(stderr, "CORRECT\n");}; auto undo = [](Config &, Action::BasicAction &) {}; auto appliable = [](Config &, Action::BasicAction &) {return true;}; Action::BasicAction basicAction = {Action::BasicAction::Type::Push, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } else if(std::string(b1) == "SHIFT") { sequence.emplace_back(pushHead()); } else if(std::string(b1) == "REDUCE") { sequence.emplace_back(stackPop(true)); } else if(std::string(b1) == "LEFT") { auto apply = [](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, "GOV", std::to_string(b0-s0), s0-b0); }; auto undo = [](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, "GOV", "", s0-b0); }; auto appliable = [](Config & c, Action::BasicAction &) { if (c.getHead() >= c.getTape(ProgramParameters::sequenceDelimiterTape).size()) return false; if (c.stackEmpty() || c.endOfTapes()) return false; int b0 = c.getHead(); int s0 = c.stackTop(); if (c.rawInputHeadIndex == 0) { if (util::split(c.getTape("ID").getRef(0), '-').size() > 1) return false; if (util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '-').size() > 1) return false; if (util::split(c.getTape("ID").getRef(0), '.').size() > 1) return false; if (util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '.').size() > 1) return false; } else { if (util::split(c.getTape("ID").getHyp(0), '-').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '-').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(0), '.').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '.').size() > 1) return false; } return simpleBufferWriteAppliable(c, "GOV", s0-b0); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); if (sscanf(name.c_str(), "%s %s", b1, b2) == 2) { auto apply2 = [b2](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, "LABEL", b2, s0-b0); }; auto undo2 = [](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, "LABEL", "", s0-b0); }; auto appliable2 = [](Config & c, Action::BasicAction &) { if (c.stackEmpty()) return false; int b0 = c.getHead(); int s0 = c.stackTop(); return simpleBufferWriteAppliable(c, "LABEL", s0-b0); }; Action::BasicAction basicAction2 = {Action::BasicAction::Type::Write, b2, apply2, undo2, appliable2}; sequence.emplace_back(basicAction2); } sequence.emplace_back(stackPop(false)); } else if(std::string(b1) == "RIGHT") { auto apply = [](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, "GOV", std::to_string(s0-b0), 0); }; auto undo = [](Config & c, Action::BasicAction &) { simpleBufferWrite(c, "GOV", "", 0); }; auto appliable = [](Config & c, Action::BasicAction &) { if (c.rawInputHeadIndex == 0) { if (c.getHead() >= c.getTape(ProgramParameters::sequenceDelimiterTape).size()) return false; if (c.stackEmpty()) return false; if (util::split(c.getTape("ID").getRef(0), '-').size() > 1) return false; if (util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '-').size() > 1) return false; if (util::split(c.getTape("ID").getRef(0), '.').size() > 1) return false; if (util::split(c.getTape("ID").getRef(c.stackTop()-c.getHead()), '.').size() > 1) return false; } else { if (c.getHead() >= c.getTape(ProgramParameters::sequenceDelimiterTape).size()) return false; if (c.stackEmpty()) return false; if (util::split(c.getTape("ID").getHyp(0), '-').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '-').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(0), '.').size() > 1) return false; if (util::split(c.getTape("ID").getHyp(c.stackTop()-c.getHead()), '.').size() > 1) return false; } return simpleBufferWriteAppliable(c, "GOV", 0); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); if (sscanf(name.c_str(), "%s %s", b1, b2) == 2) { auto apply2 = [b2](Config & c, Action::BasicAction &) { simpleBufferWrite(c, "LABEL", b2, 0); }; auto undo2 = [](Config & c, Action::BasicAction &) { simpleBufferWrite(c, "LABEL", "", 0); }; auto appliable2 = [](Config & c, Action::BasicAction &) { return simpleBufferWriteAppliable(c, "LABEL", 0); }; Action::BasicAction basicAction2 = {Action::BasicAction::Type::Write, b2, apply2, undo2, appliable2}; sequence.emplace_back(basicAction2); } sequence.emplace_back(pushHead()); } else if(std::string(b1) == "EOS") { // Puting the EOS tag on the last element of the sentence. { auto apply = [](Config & c, Action::BasicAction &) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, ProgramParameters::sequenceDelimiterTape, ProgramParameters::sequenceDelimiter, s0-b0); c.setEosTouched(); }; auto undo = [](Config & c, Action::BasicAction) { int b0 = c.getHead(); int s0 = c.stackTop(); simpleBufferWrite(c, ProgramParameters::sequenceDelimiterTape, "", s0-b0); }; auto appliable = [](Config & c, Action::BasicAction &) { return !c.isFinal() && !c.stackEmpty() && c.getTape(ProgramParameters::sequenceDelimiterTape).getHyp(c.stackTop()-c.getHead()) != ProgramParameters::sequenceDelimiter; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } // Update the IDs of the words in the new sentence { auto apply = [](Config & c, Action::BasicAction &) { c.updateIdsInSequence(); }; auto undo = [](Config &, Action::BasicAction &) { }; auto appliable = [](Config &, Action::BasicAction &) { return true; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } // Chosing root of the sentence and attaching floating words to it. { auto apply = [](Config & c, Action::BasicAction & ba) { ba.data = ""; auto & govs = c.getTape("GOV"); auto & ids = c.getTape("ID"); int b0 = c.getHead(); int rootIndex = -1; for (int i = c.stackSize()-1; i >= 0; i--) { auto s = c.stackGetElem(i); if (c.rawInputHeadIndex > 0) { if (util::split(ids.getHyp(s-b0), '-').size() > 1) continue; if (util::split(ids.getHyp(s-b0), '.').size() > 1) continue; } else { if (util::split(ids.getRef(s-b0), '-').size() > 1) continue; if (util::split(ids.getRef(s-b0), '.').size() > 1) continue; } if (govs.getHyp(s-b0).empty() || govs.getHyp(s-b0) == "0") { if (rootIndex == -1) rootIndex = s; else { simpleBufferWrite(c, "GOV", std::to_string(rootIndex-s), s-b0); simpleBufferWrite(c, "LABEL", "_", s-b0); ba.data += "+"+std::to_string(s-b0); } } } if (rootIndex == -1) { if (c.stackEmpty()) { c.printForDebug(stderr); fprintf(stderr, "ERROR (%s) : no suitable candidate for root. Aborting.\n", ERRINFO); exit(1); } rootIndex = c.stackGetElem(c.stackSize()-1); } simpleBufferWrite(c, "GOV", "0", rootIndex-b0); simpleBufferWrite(c, "LABEL", "root", rootIndex-b0); // Attaching floating words to new root int sentenceEnd = b0; auto & eos = c.getTape(ProgramParameters::sequenceDelimiterTape); while (sentenceEnd >= 0 && eos.getHyp(sentenceEnd-b0) != ProgramParameters::sequenceDelimiter) sentenceEnd--; int sentenceStart = std::max(0,sentenceEnd-1); while (sentenceStart >= 0 && eos.getHyp(sentenceStart-b0) != ProgramParameters::sequenceDelimiter) sentenceStart--; sentenceStart++; if (sentenceEnd < 0) { sentenceStart = 0; sentenceEnd = eos.hypSize()-1; } for (int i = sentenceStart; i <= sentenceEnd; i++) { if (c.rawInputHeadIndex > 0) { if (util::split(ids.getHyp(i-b0), '-').size() > 1) continue; if (util::split(ids.getHyp(i-b0), '.').size() > 1) continue; } else { if (util::split(ids.getRef(i-b0), '-').size() > 1) continue; if (util::split(ids.getRef(i-b0), '.').size() > 1) continue; } if (govs.getHyp(i-b0).empty()) { simpleBufferWrite(c, "GOV", std::to_string(rootIndex-i), i-b0); simpleBufferWrite(c, "LABEL", "_", i-b0); ba.data += "+"+std::to_string(i-b0); } } // Delete the arcs from the previous sentence to the new sentence for (int i = b0; i > c.stackTop(); i--) { try { if (std::stoi(govs[i-b0])+i <= c.stackTop()) { simpleBufferWrite(c, "GOV", "", i-b0); simpleBufferWrite(c, "LABEL", "", i-b0); } } catch (std::exception &) {continue;} } }; auto undo = [](Config & c, Action::BasicAction & ba) { auto & govs = c.getTape("GOV"); int b0 = c.getHead(); for (int i = c.stackSize()-1; i >= 0; i--) { auto s = c.stackGetElem(i); if (govs.getHyp(s-b0) == "0") { simpleBufferWrite(c, "GOV", "", s-b0); simpleBufferWrite(c, "LABEL", "", s-b0); break; } } auto deps = util::split(ba.data, '+'); for (auto s : deps) if (!s.empty()) { simpleBufferWrite(c, "GOV", "", std::stoi(s)); simpleBufferWrite(c, "LABEL", "", std::stoi(s)); } ba.data.clear(); }; auto appliable = [](Config & c, Action::BasicAction &) { return !c.stackEmpty(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Write, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } // Empty the stack. { auto apply = [](Config & c, Action::BasicAction & ba) { ba.data = ""; for (int i = c.stackSize()-1; i >= 0; i--) { auto s = c.stackGetElem(i); ba.data += std::to_string(s) + " "; } while (!c.stackEmpty()) c.stackPop(); }; auto undo = [](Config & c, Action::BasicAction & ba) { auto elems = util::split(ba.data); for (auto elem : elems) if (!elem.empty()) c.stackPush(std::stoi(elem)); ba.data.clear(); }; auto appliable = [](Config & c, Action::BasicAction &) { return !c.isFinal() && !c.stackEmpty(); }; Action::BasicAction basicAction = {Action::BasicAction::Type::Pop, "", apply, undo, appliable}; sequence.emplace_back(basicAction); } } else if(std::string(b1) == "BACK") { if (sscanf(name.c_str(), "%s %s", b1, b2) != 2) invalidNameAndAbort(ERRINFO); if (util::isNum(b2)) { int dist = std::stoi(b2); auto apply = [dist](Config & c, Action::BasicAction &) { std::string classifierName = c.pastActions.top().first; if (ProgramParameters::debug) fprintf(stderr, "classifierName = <%s>\n", classifierName.c_str()); static auto undoOneTime = [](Config & c, const std::string & classifierName) { if (ProgramParameters::debug) fprintf(stderr, "classifierName = <%s>\n", classifierName.c_str()); while (true) { auto a = c.pastActions.pop(); a.second.undoOnlyStack(c); if (a.first == classifierName) return; } }; static auto undoForReal = [](Config & c, const std::string & classifierName) { if (ProgramParameters::debug) fprintf(stderr, "classifierName = <%s>\n", classifierName.c_str()); while (true) { if (c.pastActions.empty()) { fprintf(stderr, "ERROR (%s) : trying to undo action while pastActions is empty. Aborting.\n", ERRINFO); exit(1); } auto a = c.pastActions.pop(); if (a.first == classifierName) { a.second.undo(c); return; } a.second.undoOnlyStack(c); } }; undoOneTime(c, classifierName); for (int i = 0; i < dist-1; i++) undoOneTime(c, classifierName); undoForReal(c, classifierName); }; auto undo = [](Config &, Action::BasicAction &) { }; auto appliable = [dist](Config & c, Action::BasicAction) { if (c.pastActions.size() == 0) return false; if (c.getCurrentStateHistory().size() > 0 && c.getCurrentStateHistory().top() != "EPSILON") { return false; } const std::string & classifierName = c.pastActions.top().first; if (c.hashHistory.contains(c.computeHash())) return false; unsigned int topIndex = 0; static auto undoOneTime = [](Config & c, const std::string & classifierName, unsigned int & topIndex) { while (true) { topIndex++; if (topIndex > c.pastActions.size()) return; if (c.pastActions.getElem(topIndex-1).first == classifierName) return; } }; undoOneTime(c, classifierName, topIndex); for (int i = 0; i < dist-1; i++) undoOneTime(c, classifierName, topIndex); undoOneTime(c, classifierName, topIndex); if (topIndex >= c.pastActions.size()) return false; return true; }; Action::BasicAction basicAction = {Action::BasicAction::Type::Back, name, apply, undo, appliable}; sequence.emplace_back(basicAction); } else { invalidNameAndAbort(ERRINFO); } } else invalidNameAndAbort(ERRINFO); return sequence; } void ActionBank::simpleBufferWrite(Config & config, const std::string & tapeName, const std::string & value, int relativeIndex) { auto & tape = config.getTape(tapeName); tape.setHyp(relativeIndex, value); } bool ActionBank::simpleBufferWriteAppliable(Config & config, const std::string & tapeName, int relativeIndex) { auto & tape = config.getTape(tapeName); int index = config.getHead() + relativeIndex; return !(index < 0) && index < tape.size() && tape.getHyp(relativeIndex).empty(); } bool ActionBank::isRuleAppliable(Config & config, const std::string & fromTapeName, const std::string & targetTapeName, int relativeIndex, const std::string & rule) { if (!simpleBufferWriteAppliable(config, targetTapeName, relativeIndex)) return false; return util::ruleIsAppliable(config.getTape(fromTapeName)[relativeIndex], rule); } void ActionBank::writeRuleResult(Config & config, const std::string & fromTapeName, const std::string & targetTapeName, const std::string & rule, int relativeIndex) { auto & fromTape = config.getTape(fromTapeName); auto & toTape = config.getTape(targetTapeName); auto & from = fromTape[relativeIndex]; toTape.setHyp(relativeIndex, util::applyRule(from, rule)); } void ActionBank::addCharToBuffer(Config & config, const std::string & tapeName, int relativeIndex) { auto & tape = config.getTape(tapeName); auto & from = tape.getHyp(relativeIndex); int nbChar = util::getEndIndexOfNthSymbolFrom(config.rawInput.begin()+config.rawInputHeadIndex,config.rawInput.end(), 0)+1; std::string suffix = std::string(config.rawInput.begin()+config.rawInputHeadIndex, config.rawInput.begin()+config.rawInputHeadIndex+nbChar); tape.setHyp(relativeIndex, from+suffix); } void ActionBank::removeCharFromBuffer(Config & config, const std::string & tapeName, int relativeIndex) { auto & tape = config.getTape(tapeName); auto from = tape[relativeIndex]; std::string suffix = std::string(config.rawInput.begin()+config.rawInputHeadIndex, config.rawInput.begin()+config.rawInputHeadIndex+util::getEndIndexOfNthSymbolFrom(config.rawInput.begin()+config.rawInputHeadIndex,config.rawInput.end(), 0)); for (char c : suffix) { (void)c; from.pop_back(); } tape.setHyp(relativeIndex, from); } int ActionBank::getLinkLength(const Config & c, const std::string & action) { auto splitted = util::split(action, ' '); auto & name = splitted[0]; if (name == "LEFT" || name == "RIGHT" || name == "EOS") { if (c.stackEmpty()) { fprintf(stderr, "ERROR (%s) : stack is empty. Aborting.\n", ERRINFO); exit(1); } int stackIndex = c.stackGetElem(0); return std::abs(c.getHead() - stackIndex); } return 0; }