0

At the moment I am developing a simple programming language on the basis of flex&bison.

For this I first build the abstract syntax tree (AST) and continue with its evaluation. During the evaluation it shall be possible to receive user input. The user input is done in a Qt-GUI. The ast-evaluation-procedure runs in a thread-worker-object, that is created by the GUI. My problem: Which one is the best way, to "block" the running flex&bison evaluation-procedure to then receive a user input from the GUI and afterwards continue with executing the procedure? Unfortunately I have no idea, how to split the evaluation procedure into two parts to catch the user input-signal from the GUI and then to continue with the "splitted procedure" in a slot. My current solution works (to my opinion poor) with an infinite loop within the evaluation procedure and this runs until a boolean member variable (_hasUserInput) in the thread worker-object is set to true. After the user input the GUI emits the signal. The corresponding slot is inside the thread worker-object. The slot receives the user input e.g. as a QString and sets a corresponding member variable. Additionally the boolean variable is set to true, so the infinite loop of the evaluation-procedure can be left, the user input can be processed and the evaluation can be continued.

Functional principle:
GUI --> starts Thread (Worker-Object) --> starts the longterm running procedure

Example in pseudo code:

class ThreadWorker : public QObject {

    ...

    // Slot, that reacts to the signal from the GUI
    void userInput(const QString &input) {
        _userInput = input;
        _hasUserInput = true;
    }

    // evaluation-procedure
    void doEvaluation() {
        // evaluation of the AST

        ...

        emit userInputRequired();
        while (!hasUserInput){          // Check if user input has been done
            qApp -> processEvents();    // to react to events
        }
        do something with user input;
        continue valuation;             // Processing of user input and continuation of the procedure
    }

    ...

};

I tried to give a description of my problem as good as possible and hope it worked. Please ask, in case you need more detailed information. Thanks very much in advance for your assistance!

Woodpecker
  • 117
  • 1
  • 5
  • Maybe you need a non-blocking worker? https://stackoverflow.com/questions/32952474/non-blocking-worker-interrupt-file-copy The idea is you remove the `while ()` loop and replace it with an event driven one – dtech Jul 28 '17 at 19:59
  • While a bytecode interpreter might require more work than an AST-based one upfront, it makes it a lot easier to just pause and resume execution whenever you want, so you might want to consider going that route instead. – sepp2k Jul 28 '17 at 20:40

1 Answers1

0

Since you've already factored out the worker into a QObject, you should never need to call processEvents(). Instead, break down the AST evaluation into small chunks that are performed as long as necessary. I've also made the public interface thread-safe - thus you can call it directly from any thread.

// see https://stackoverflow.com/a/40382821/1329652
bool isSafe(QObject * obj);
template <typename Class, typename... Args> void postCall(Class * obj, void (Class::*method)(Args...), Args&& ...args);

class ASTWorker : public QObject {
  Q_OBJECT
  QBasicTimer m_evaluateTimer; // a bit lower overhead than QTimer
  void timerEvent(QTimerEvent * ev) override {
    if (ev->timerId() == m_evaluateTimer.timerId())
      evaluateImpl();
  }
  void evaluateImpl() {
    bool evaluationDone = {};
    QThread::msleep(10); // emulate evaluating a chunk of AST
    if (!evaluationDone && !m_evaluateTimer.isActive())
      m_evaluateTimer.start(0, this);
    else if (evaluationDone)
      m_evaluateTimer.stop();
  }
public:
  using QObject::QObject;
  /// Thread-safe
  Q_SLOT void setUserInput(const Data & data) {
    if (!isSafe(this))
      return postCall(this, &ASTWorker::setUserInput, data);
    QThread::msleep(1); // emulate processing user data
  }
  /// Thread-safe
  Q_SLOT void evaluate() {
    if (!isSafe(this))
      return postCall(this, &ASTWorker::evaluate, data);
    evaluateImpl();
  }
};
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313