Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit b82916f

Browse files
committed
Exercise 26.8
1 parent f346967 commit b82916f

File tree

4 files changed

+464
-0
lines changed

4 files changed

+464
-0
lines changed

‎Chapter_26/C26_Exercise_26.8.cpp

Lines changed: 349 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,349 @@
1+
/* Exercise 26.8 */
2+
3+
#include<iostream>
4+
#include<istream>
5+
#include<fstream>
6+
#include<sstream>
7+
#include<string>
8+
#include<vector>
9+
#include<iomanip>
10+
#include"../GUI/Simple_window.h"
11+
#include"../GUI/Graph.h"
12+
#include"C26_Exercise_26.8.h"
13+
14+
using namespace std;
15+
16+
inline void error(const string& s, int i) { ostringstream os; os << s << ": " << i; error(os.str()); }
17+
inline void keep_window_open() { char ch; cin >> ch; }
18+
19+
int main()
20+
try {
21+
constexpr int windowLength = 1280;
22+
constexpr int windowHeight = 1024;
23+
24+
My_window mw{ Point{ 80, 0 }, windowLength, windowHeight,
25+
"Text-based interface for the graphics interface library" };
26+
27+
mw.wait_for_button();
28+
return 0;
29+
}
30+
catch (runtime_error& e) {
31+
cerr << e.what() << endl;
32+
return 1;
33+
}
34+
catch (...) {
35+
cerr << "Error. Exception\n";
36+
return 2;
37+
}
38+
39+
My_window::My_window(Point xy, int w, int h, const string& title)
40+
: Window{ xy, w, h, title },
41+
inboxInput{ Point{ 200, 0 }, 600, 20, "Input:" },
42+
buttonDraw{ Point{ 810, 0 }, 70, 20, "Draw",
43+
[](Address, Address pw) { reference_to<My_window>(pw).DrawShape(); } },
44+
45+
buttonReset{ Point{ x_max() - 150, 0 }, 70, 20, "Reset",
46+
[](Address, Address pw) { reference_to<My_window>(pw).Reset(); } },
47+
buttonQuit{ Point{ x_max() - 70, 0 }, 70, 20, "Quit",
48+
[](Address, Address pw) { reference_to<My_window>(pw).quit(); } },
49+
quitPushed{ false }
50+
{
51+
attach(inboxInput);
52+
attach(buttonDraw);
53+
textMessage.set_font(defaultFont);
54+
textMessage.set_font_size(defaultFontSize);
55+
attach(textMessage);
56+
attach(buttonReset);
57+
attach(buttonQuit);
58+
}
59+
60+
void My_window::DeleteShapes()
61+
{
62+
for (Shape* sh : shapes) {
63+
delete sh;
64+
}
65+
}
66+
67+
void My_window::DrawShape()
68+
{
69+
string command = inboxInput.get_string();
70+
string message;
71+
Shape* shape = TextInterface::ParseInput(command, message);
72+
if (shape != nullptr) {
73+
shapes.push_back(shape);
74+
attach(*shape);
75+
}
76+
if (message.size() > 0) {
77+
textMessage.set_label(message);
78+
textMessage.set_color(Color::dark_red);
79+
}
80+
else {
81+
textMessage.set_label("OK");
82+
textMessage.set_color(Color::dark_green);
83+
}
84+
redraw();
85+
}
86+
87+
void My_window::Reset()
88+
{
89+
textMessage.set_label("");
90+
for (Shape* sh : shapes) {
91+
detach(*sh);
92+
}
93+
DeleteShapes();
94+
shapes = vector<Shape*>{};
95+
redraw();
96+
}
97+
98+
bool My_window::wait_for_button()
99+
{
100+
show();
101+
quitPushed = false;
102+
while (!quitPushed) Fl::wait();
103+
Fl::redraw();
104+
return quitPushed;
105+
}
106+
107+
void My_window::quit()
108+
{
109+
quitPushed = true;
110+
DeleteShapes();
111+
hide();
112+
}
113+
114+
#include <FL/Fl_Output.H>
115+
string Graph_lib::In_box::get_string()
116+
{
117+
Fl_Input& pi = reference_to<Fl_Input>(pw);
118+
string s;
119+
return s.assign(pi.value());
120+
}
121+
122+
TextInterface::Token TextInterface::TokenStream::GetToken()
123+
{
124+
pair<bool, Token> buffer = GetBuffer();
125+
if (buffer.first == true) return buffer.second;
126+
char ch;
127+
while (ios.in->get(ch) && isspace(ch));
128+
switch (ch) {
129+
case '(': return Token{ TokenType::LEFTPAR };
130+
case ')': return Token{ TokenType::RIGHTPAR };
131+
case ',': return Token{ TokenType::COMMA };
132+
case '0':
133+
case '1':
134+
case '2':
135+
case '3':
136+
case '4':
137+
case '5':
138+
case '6':
139+
case '7':
140+
case '8':
141+
case '9': {
142+
ios.in->unget();
143+
int number;
144+
*ios.in >> number;
145+
if (!(*ios.in)) return Token{ TokenType::INVALID };
146+
return Token{ TokenType::NUMBER, number };
147+
}
148+
default: {
149+
if (isalpha(ch)) {
150+
string s;
151+
s += ch;
152+
while (ios.in->get(ch) && (isalnum(ch) || ch == '_')) s += ch;
153+
if (!(*ios.in)) return Token{ TokenType::INVALID };
154+
ios.in->unget();
155+
if (s == "Line") return Token{ TokenType::LINE };
156+
if (s == "RectanglePPP2") return Token{ TokenType::RECTANGLE };
157+
if (s == "Circle") return Token{ TokenType::CIRCLE };
158+
if (s == "Closed_polyline") return Token{ TokenType::CLOSEDPOLYLINE };
159+
if (s == "Point") return Token{ TokenType::POINT };
160+
return Token{ TokenType::INVALID };
161+
}
162+
else return Token{ TokenType::INVALID };
163+
}
164+
}
165+
}
166+
167+
void TextInterface::TokenStream::UngetToken(TextInterface::Token t)
168+
{
169+
if (n < buf.size()) buf[n] = t;
170+
else buf.push_back(t);
171+
++n;
172+
}
173+
174+
pair<bool, TextInterface::Token> TextInterface::TokenStream::GetBuffer()
175+
{
176+
if (n > 0) return { true, buf[--n] };
177+
return { false, Token{ TokenType::INVALID } };
178+
}
179+
180+
pair<bool, int> TextInterface::GetNumber(TokenStream& ts)
181+
{
182+
pair<bool, int> failure{ false, 0 };
183+
Token t = ts.GetToken();
184+
if (t.type != TokenType::NUMBER) return failure;
185+
return { true, t.ival };
186+
}
187+
188+
pair<bool, Point> TextInterface::GetPoint(TokenStream& ts)
189+
{
190+
pair<bool, Point> failure{ false, Point{ 0, 0 } };
191+
Token t = ts.GetToken();
192+
if (t.type != TokenType::POINT) return failure;
193+
t = ts.GetToken();
194+
if (t.type != TokenType::LEFTPAR) return failure;
195+
pair<bool, int> p1 = GetNumber(ts);
196+
if (p1.first == false) return failure;
197+
t = ts.GetToken();
198+
if (t.type != TokenType::COMMA) return failure;
199+
pair<bool, int> p2 = GetNumber(ts);
200+
if (p2.first == false) return failure;
201+
t = ts.GetToken();
202+
if (t.type != TokenType::RIGHTPAR) return failure;
203+
return { true, Point{ p1.second, p2.second } };
204+
}
205+
206+
Line* TextInterface::GetLine(TokenStream& ts)
207+
{
208+
const string err{ "Invalid token. Line" };
209+
Token t = ts.GetToken();
210+
if (t.type != TokenType::LEFTPAR) return static_cast<Line*>(Error(ts, err));
211+
pair<bool, Point> p1 = GetPoint(ts);
212+
if (p1.first == false) return static_cast<Line*>(Error(ts, err));
213+
t = ts.GetToken();
214+
if (t.type != TokenType::COMMA) return static_cast<Line*>(Error(ts, err));
215+
pair<bool, Point> p2 = GetPoint(ts);
216+
if (p2.first == false) return nullptr;
217+
t = ts.GetToken();
218+
if (t.type != TokenType::RIGHTPAR) return static_cast<Line*>(Error(ts, err));
219+
return new Line{ p1.second, p2.second };
220+
}
221+
222+
RectanglePPP2* TextInterface::GetRectangle(TokenStream& ts)
223+
{
224+
const string err{ "Invalid token. RectanglePPP2" };
225+
Token t = ts.GetToken();
226+
if (t.type != TokenType::LEFTPAR)
227+
return static_cast<RectanglePPP2*>(Error(ts, err));
228+
pair<bool, Point> p1 = GetPoint(ts);
229+
if (p1.first == false)
230+
return static_cast<RectanglePPP2*>(Error(ts, err));
231+
t = ts.GetToken();
232+
if (t.type != TokenType::COMMA)
233+
return static_cast<RectanglePPP2*>(Error(ts, err));
234+
t = ts.GetToken();
235+
if (t.type == TokenType::POINT) {
236+
ts.UngetToken(t);
237+
pair<bool, Point> p2 = GetPoint(ts);
238+
if (p2.first == false)
239+
return static_cast<RectanglePPP2*>(Error(ts, err));
240+
t = ts.GetToken();
241+
if (t.type != TokenType::RIGHTPAR)
242+
return static_cast<RectanglePPP2*>(Error(ts, err));
243+
return new RectanglePPP2{ p1.second, p2.second };
244+
}
245+
else if (t.type == TokenType::NUMBER) {
246+
ts.UngetToken(t);
247+
pair<bool, int> p2 = GetNumber(ts);
248+
if (p2.first == false)
249+
return static_cast<RectanglePPP2*>(Error(ts, err));
250+
t = ts.GetToken();
251+
if (t.type != TokenType::COMMA)
252+
return static_cast<RectanglePPP2*>(Error(ts, err));
253+
pair<bool, int> p3 = GetNumber(ts);
254+
if (p3.first == false)
255+
return static_cast<RectanglePPP2*>(Error(ts, err));
256+
t = ts.GetToken();
257+
if (t.type != TokenType::RIGHTPAR)
258+
return static_cast<RectanglePPP2*>(Error(ts, err));
259+
return new RectanglePPP2{ p1.second, p2.second, p3.second };
260+
}
261+
else return static_cast<RectanglePPP2*>(Error(ts, err));
262+
}
263+
264+
Circle* TextInterface::GetCircle(TokenStream& ts)
265+
{
266+
const string err{ "Invalid token. Circle" };
267+
Token t = ts.GetToken();
268+
if (t.type != TokenType::LEFTPAR)
269+
return static_cast<Circle*>(Error(ts, err));
270+
pair<bool, Point> p1 = GetPoint(ts);
271+
if (p1.first == false)
272+
return static_cast<Circle*>(Error(ts, err));
273+
t = ts.GetToken();
274+
if (t.type != TokenType::COMMA)
275+
return static_cast<Circle*>(Error(ts, err));
276+
pair<bool, int> p2 = GetNumber(ts);
277+
if (p2.first == false)
278+
return static_cast<Circle*>(Error(ts, err));
279+
t = ts.GetToken();
280+
if (t.type != TokenType::RIGHTPAR)
281+
return static_cast<Circle*>(Error(ts, err));
282+
return new Circle{ p1.second, p2.second };
283+
}
284+
285+
Closed_polyline* TextInterface::GetClosedPolyline(TokenStream& ts)
286+
{
287+
constexpr int minPoints = 3; // minimum number of points for a Closed_polyline
288+
const string err{ "Invalid token. Closed_polyline" };
289+
Token t = ts.GetToken();
290+
if (t.type != TokenType::LEFTPAR)
291+
return static_cast<Closed_polyline*>(Error(ts, err));
292+
vector<Point> vp;
293+
while (true) {
294+
pair<bool, Point> p = GetPoint(ts);
295+
if (p.first == false)
296+
return static_cast<Closed_polyline*>(Error(ts, err));
297+
vp.push_back(p.second);
298+
t = ts.GetToken();
299+
if (t.type == TokenType::RIGHTPAR)
300+
break;
301+
if (t.type != TokenType::COMMA)
302+
return static_cast<Closed_polyline*>(Error(ts, err));
303+
}
304+
if (vp.size() < minPoints)
305+
return static_cast<Closed_polyline*>(Error(ts,
306+
"Minimum number of points for a 'Closed_polyline' must be 3"));
307+
Closed_polyline* polyline = new Closed_polyline{};
308+
if (polyline == nullptr)
309+
return static_cast<Closed_polyline*>(Error(ts, "'Closed_polyline' is not allocated"));
310+
for (const Point& p : vp) {
311+
polyline->add(p);
312+
}
313+
return polyline;
314+
}
315+
316+
Shape* TextInterface::GetShape(TokenStream& ts)
317+
{
318+
Token t = ts.GetToken();
319+
switch (t.type) {
320+
case TokenType::LINE: {
321+
return GetLine(ts);
322+
}
323+
case TokenType::RECTANGLE: {
324+
return GetRectangle(ts);
325+
}
326+
case TokenType::CIRCLE: {
327+
return GetCircle(ts);
328+
}
329+
case TokenType::CLOSEDPOLYLINE: {
330+
return GetClosedPolyline(ts);
331+
}
332+
case TokenType::INVALID:
333+
default:
334+
ts.Error("Invalid token");
335+
return nullptr;
336+
}
337+
}
338+
339+
Shape* TextInterface::ParseInput(const string& input, string& output)
340+
{
341+
istringstream iss{ input };
342+
ostringstream oss;
343+
TokenStream ts;
344+
IOStream ios{ iss, oss, oss };
345+
ts.ChangeStream(ios);
346+
Shape* shape = GetShape(ts);
347+
output = oss.str();
348+
return shape;
349+
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /