Skip to content

Commit 65793b7

Browse files
committed
Milestone 4 initial commit
1 parent dc77b8e commit 65793b7

File tree

8 files changed

+315
-65
lines changed

8 files changed

+315
-65
lines changed

CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ set(unittest_src
3636
# add source for any TUI modules here
3737
set(tui_src
3838
layout_parameters.h
39+
message_queue.hpp
3940
)
4041

4142
# EDIT
@@ -110,8 +111,8 @@ if(DEFINED ENV{ECE3574_REFERENCE_ENV})
110111
set(GCC_COVERAGE_COMPILE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
111112
set_target_properties(interpreter PROPERTIES COMPILE_FLAGS ${GCC_COVERAGE_COMPILE_FLAGS} )
112113
set_target_properties(unit_tests PROPERTIES COMPILE_FLAGS ${GCC_COVERAGE_COMPILE_FLAGS} )
113-
target_link_libraries(unit_tests interpreter gcov)
114-
target_link_libraries(plotscript interpreter gcov)
114+
target_link_libraries(unit_tests interpreter pthread gcov)
115+
target_link_libraries(plotscript interpreter pthread gcov)
115116
add_custom_target(coverage
116117
COMMAND ${CMAKE_COMMAND} -E env "ROOT=${CMAKE_CURRENT_SOURCE_DIR}"
117118
${CMAKE_CURRENT_SOURCE_DIR}/scripts/coverage.sh)

interpreter.cpp

Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,97 @@
99
#include "expression.hpp"
1010
#include "environment.hpp"
1111
#include "semantic_error.hpp"
12+
#include "startup_config.hpp"
13+
14+
Interpreter::Interpreter()
15+
{
16+
inQ = nullptr;
17+
outQ = nullptr;
18+
}
19+
20+
Interpreter::Interpreter(InputQueue * inputQ, OutputQueue * outputQ)
21+
{
22+
inQ = inputQ;
23+
outQ = outputQ;
24+
startup();
25+
}
26+
27+
// Convert string->Expression for output messages
28+
Expression errorExp(const std::string & err_str)
29+
{
30+
Expression expResult(Atom("Error"));
31+
expResult.append(Expression(Atom(err_str)));
32+
//expResult.setProperty("Error", flag);
33+
return expResult;
34+
}
35+
36+
void Interpreter::startup()
37+
{
38+
std::ifstream ifs(STARTUP_FILE);
39+
std::ostringstream outStream;
40+
std::string strResult;
41+
Expression expResult;
42+
43+
if(!ifs){
44+
expResult = errorExp("Could not open startup file for reading.");
45+
}
46+
47+
if(!parseStream(ifs)){
48+
ifs.close();
49+
expResult = errorExp("Invalid Startup Program. Could not parse.");
50+
}
51+
else{
52+
try{
53+
expResult = evaluate();
54+
//outQ->push(expResult);
55+
}
56+
catch(const SemanticError & ex){
57+
ifs.close();
58+
outStream << "Invalid Startup Program: " << ex.what();
59+
strResult = outStream.str();
60+
expResult = errorExp(strResult);
61+
}
62+
}
63+
ifs.close();
64+
//outQ->push(expResult);
65+
}
66+
67+
// Process Input Queue Messages
68+
void Interpreter::threadEvalLoop()
69+
{
70+
while(true){
71+
72+
// take a unit of work from the input queue
73+
InputMessage line;
74+
inQ->wait_and_pop(line);
75+
76+
if (line == "%stop") break;
77+
78+
std::istringstream inStream(line);
79+
std::ostringstream outStream;
80+
std::string strResult;
81+
Expression expResult;
82+
83+
if(!parseStream(inStream)){
84+
expResult = errorExp("Invalid Expression. Could not parse.");
85+
}
86+
else{
87+
try{
88+
expResult = evaluate();
89+
}
90+
catch(const SemanticError & ex){
91+
outStream << ex.what();
92+
strResult = outStream.str();
93+
expResult = errorExp(strResult);
94+
}
95+
}
96+
97+
// put the result back into the output queue
98+
outQ->push(expResult);
99+
}
100+
// End of Program
101+
}
102+
12103

13104
bool Interpreter::parseStream(std::istream & expression) noexcept{
14105

@@ -18,7 +109,7 @@ bool Interpreter::parseStream(std::istream & expression) noexcept{
18109

19110
return (ast != Expression());
20111
};
21-
112+
22113

23114
Expression Interpreter::evaluate(){
24115

interpreter.hpp

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,26 @@ It maintains an environment during evaluation.
88
#define INTERPRETER_HPP
99

1010
// system includes
11+
#include <iostream>
12+
#include <fstream>
1113
#include <istream>
14+
#include <sstream>
1215
#include <string>
16+
#include <thread>
1317

1418
// module includes
1519
#include "environment.hpp"
1620
#include "expression.hpp"
21+
#include "semantic_error.hpp"
22+
//#include "startup_config.hpp"
23+
#include "message_queue.hpp"
24+
25+
// define thread-safe message queues
26+
typedef std::string InputMessage;
27+
typedef Expression OutputMessage;
28+
29+
typedef MessageQueue<InputMessage> InputQueue;
30+
typedef MessageQueue<OutputMessage> OutputQueue;
1731

1832
/*! \class Interpreter
1933
\brief Class to parse and evaluate an expression (program)
@@ -22,8 +36,18 @@ Interpreter has an Environment, which starts at a default.
2236
The parse method builds an internal AST.
2337
The eval method updates Environment and returns last result.
2438
*/
25-
class Interpreter {
39+
class Interpreter{
2640
public:
41+
42+
Interpreter();
43+
44+
Interpreter(InputQueue * inputQ, OutputQueue * outputQ);
45+
46+
/// Open the start-up file and evaluate the program
47+
void startup();
48+
49+
/// Main thread function that polls the shared Input Message Queue until exit message is read
50+
void threadEvalLoop();
2751

2852
/*! Parse into an internal Expression from a stream
2953
\param expression the raw text stream repreenting the candidate expression
@@ -38,12 +62,15 @@ class Interpreter {
3862
Expression evaluate();
3963

4064
private:
65+
66+
Environment env;
67+
68+
Expression ast;
4169

42-
// the environment
43-
Environment env;
44-
45-
// the AST
46-
Expression ast;
70+
/// The thread-safe message queue channels for kernel I/O
71+
InputQueue * inQ;
72+
OutputQueue * outQ;
73+
4774
};
4875

4976
#endif

m4_cmake_patch.diff

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
diff --git a/CMakeLists.txt b/CMakeLists.txt
2+
index 5f0c883..6e1172c 100644
3+
--- a/CMakeLists.txt
4+
+++ b/CMakeLists.txt
5+
@@ -111,8 +111,8 @@ if(DEFINED ENV{ECE3574_REFERENCE_ENV})
6+
set(GCC_COVERAGE_COMPILE_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage")
7+
set_target_properties(interpreter PROPERTIES COMPILE_FLAGS ${GCC_COVERAGE_COMPILE_FLAGS} )
8+
set_target_properties(unit_tests PROPERTIES COMPILE_FLAGS ${GCC_COVERAGE_COMPILE_FLAGS} )
9+
- target_link_libraries(unit_tests interpreter gcov)
10+
- target_link_libraries(plotscript interpreter gcov)
11+
+ target_link_libraries(unit_tests interpreter pthread gcov)
12+
+ target_link_libraries(plotscript interpreter pthread gcov)
13+
add_custom_target(coverage
14+
COMMAND ${CMAKE_COMMAND} -E env "ROOT=${CMAKE_CURRENT_SOURCE_DIR}"
15+
${CMAKE_CURRENT_SOURCE_DIR}/scripts/coverage.sh)

message_queue.hpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/* Adapted from
2+
www.justsoftwaresolutions.co.uk/threading/implementing-a-thread-safe-queue-using-condition-variables.html
3+
*/
4+
5+
#ifndef _MESSAGE_QUEUE_HPP_
6+
#define _MESSAGE_QUEUE_HPP_
7+
8+
9+
#include <queue>
10+
#include <mutex>
11+
#include <condition_variable>
12+
13+
template<typename MessageType>
14+
class MessageQueue
15+
{
16+
public:
17+
18+
// push message into queue, blocks until available
19+
void push(MessageType const& message)
20+
{
21+
std::unique_lock<std::mutex> lock(the_mutex);
22+
the_queue.push(message);
23+
lock.unlock();
24+
the_condition_variable.notify_one();
25+
}
26+
27+
// check if queue is empty, blocks until available
28+
bool empty() const
29+
{
30+
std::lock_guard<std::mutex> lock(the_mutex);
31+
return the_queue.empty();
32+
}
33+
34+
// pop message from queue, return false if queue is empty
35+
bool try_pop(MessageType& popped_value)
36+
{
37+
std::lock_guard<std::mutex> lock(the_mutex);
38+
if(the_queue.empty()){
39+
return false;
40+
}
41+
42+
popped_value=the_queue.front();
43+
the_queue.pop();
44+
return true;
45+
}
46+
47+
// pop message from queue, blocks until the queue is nonempty
48+
void wait_and_pop(MessageType& popped_value)
49+
{
50+
std::unique_lock<std::mutex> lock(the_mutex);
51+
while(the_queue.empty()){
52+
the_condition_variable.wait(lock);
53+
}
54+
55+
popped_value=the_queue.front();
56+
the_queue.pop();
57+
}
58+
59+
private:
60+
61+
std::queue<MessageType> the_queue;
62+
mutable std::mutex the_mutex;
63+
std::condition_variable the_condition_variable;
64+
65+
};
66+
67+
#endif // _MESSAGE_QUEUE_HPP_

notebook_app.cpp

Lines changed: 53 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -12,32 +12,55 @@
1212

1313
NotebookApp::NotebookApp(QWidget * parent) : QWidget(parent){
1414

15-
m_input = new InputWidget();
16-
m_input->setParent(parent);
17-
18-
m_output = new OutputWidget();
19-
m_output->setParent(parent);
20-
21-
/*--- Run Startup Script ---*/
22-
startup(m_interp);
15+
m_input_widget = new InputWidget();
16+
//m_input_widget->setObjectName("input");
17+
m_input_widget->setParent(parent);
18+
2319

24-
/*--- Read User Input ---*/
25-
QObject::connect(m_input, SIGNAL(textUpdated(QString)),
26-
this, SLOT(getUserText(QString)));
27-
28-
/*--- Evaluate with Plotscript ---*/
29-
30-
/*--- Display Result Graphics ---*/
31-
QObject::connect(this, SIGNAL(sendResult(Settings)),
32-
m_output, SLOT(getResult(Settings)));
33-
34-
auto layout = new QGridLayout();
20+
m_output_widget = new OutputWidget();
21+
//m_input_widget->setObjectName("output");
22+
m_output_widget->setParent(parent);
3523

36-
layout->addWidget(m_input, 0, 0);
37-
layout->addWidget(m_output, 1, 0);
24+
/*--- Run Startup Script ---*/
25+
startup(m_interp);
26+
27+
/*--- Start Interpreter Kernel Thread ---*/
28+
//m_queue_in = &InputQueue();
29+
//m_queue_out = &OutputQueue();
30+
//m_interp = new Interpreter();
31+
//m_interp = Interpreter(&m_queue_in, &m_queue_out);
32+
//std::thread kernelThread(&Interpreter::threadEvalLoop, &m_interp);
33+
34+
/*--- Read User Input ---*/
35+
QObject::connect(m_input_widget, SIGNAL(textUpdated(QString)),
36+
this, SLOT(getUserText(QString)));
37+
38+
/*--- Evaluate with Plotscript ---*/
39+
40+
41+
/*--- Display Result Graphics ---*/
42+
QObject::connect(this, SIGNAL(sendResult(Settings)),
43+
m_output_widget, SLOT(getResult(Settings)));
44+
45+
auto layout = new QGridLayout();
46+
47+
layout->addWidget(m_input_widget, 0, 0);
48+
layout->addWidget(m_output_widget, 1, 0);
3849

3950
setLayout(layout);
40-
resize(500, 500);
51+
resize(500, 500);
52+
}
53+
54+
55+
void NotebookApp::getUserText(QString inExp){
56+
57+
qDebug() << "Slot: " << inExp << "\t";
58+
evalExpression(inExp.toStdString());
59+
60+
// Check for special kernel control commands
61+
62+
// Push message to input queue
63+
//m_queue_in.push(inExp.toStdString());
4164
}
4265

4366
int NotebookApp::startup(Interpreter & interp){
@@ -71,14 +94,13 @@ int NotebookApp::startup(Interpreter & interp){
7194
return EXIT_SUCCESS;
7295
}
7396

74-
void NotebookApp::getUserText(QString inExp){
75-
76-
qDebug() << "Slot: " << inExp << "\t";
77-
evalExpression(inExp.toStdString());
78-
}
97+
//void NotebookApp::threadEvalLoop(){
98+
// // Wait for results to display
99+
//}
79100

80101
bool NotebookApp::evalExpression(std::string inExp){
81102

103+
//==================================================================
82104
std::istringstream inStream(inExp);
83105
std::ostringstream outStream; // Need this to convert Expression->string
84106
std::string strResult = "default";
@@ -103,10 +125,12 @@ bool NotebookApp::evalExpression(std::string inExp){
103125
return EXIT_FAILURE;
104126
}
105127
}
106-
128+
//==================================================================
107129
qDebug() << "Expression Out: " << QString::fromStdString(strResult);
108-
Settings result = setGraphicsType(expResult);
130+
131+
Settings result = setGraphicsType(expResult);
109132
emit sendResult(result);
133+
110134
return EXIT_SUCCESS;
111135
}
112136

0 commit comments

Comments
 (0)