Wrong:Daniel Shawul wrote:if I used C that forces declaration of all variables at the beginning of functions it would not have run at all due to memory constraints.
http://en.wikipedia.org/wiki/C99#Design
Moderator: Ras
Wrong:Daniel Shawul wrote:if I used C that forces declaration of all variables at the beginning of functions it would not have run at all due to memory constraints.
I said C i.e C89. C doesn't have constructor/destructors so you don't have RAII anyway. Also C99 borrowed that feature from C++ to help diehard C fans from dieing in envylucasart wrote:Wrong:Daniel Shawul wrote:if I used C that forces declaration of all variables at the beginning of functions it would not have run at all due to memory constraints.
http://en.wikipedia.org/wiki/C99#Design
Let's not get confused here:Daniel Shawul wrote:I said C i.e C89. C doesn't have constructor/destructors so you don't have RAII anyway. Also C99 borrowed that feature from C++ to help diehard C fans from dieing in envylucasart wrote:Wrong:Daniel Shawul wrote:if I used C that forces declaration of all variables at the beginning of functions it would not have run at all due to memory constraints.
http://en.wikipedia.org/wiki/C99#DesignBtw Microsoft doesn't still have a compiler for C99, so not very well known language for many people.
Are you desperate for arguments ? I said C as in C89 which is clear from the context, so get over it. Anyway any of the Cs don't have destructors to work out RAII, so what is your point? RAII is an OOP concept and as such requires OOP language which C is not.lucasart wrote:Let's not get confused here:Daniel Shawul wrote:I said C i.e C89. C doesn't have constructor/destructors so you don't have RAII anyway. Also C99 borrowed that feature from C++ to help diehard C fans from dieing in envylucasart wrote:Wrong:Daniel Shawul wrote:if I used C that forces declaration of all variables at the beginning of functions it would not have run at all due to memory constraints.
http://en.wikipedia.org/wiki/C99#DesignBtw Microsoft doesn't still have a compiler for C99, so not very well known language for many people.
* C is a programming language
* C89, C99, C11 are ISO standard corresponding to the evolution of the language
* Microsoft is a software company
So by default when you say "C" in 2012 it means C11, not C89 (1989 was a long time ago you know, the fall of the Berlin wall).
After a beautiful explanation of C's evolution you say this nonsense ? Lack of support of C99 by MSVC can't be a reason for C not doing anything at all. I didn't mention MSVC as a reason but just to illustrate how C99 is so un-common among many programmers,like it or not many people work with MSVC windows.Saying that C can't do this because C89 doesn't have it and Microsoft's Visual C++ doesn't support it is just as silly as saying that C++ doesn't have templates, because some antiquated ISO C++ standard doesn't have it and some crappy compiler doesn't support them.
Microsoft VC++ is especially not the reference in terms of C compilers. Microsoft thinks that C has been replaced by C++, and that no one should ever write C code, although they only kept the C89 compiler as part of MSVC for compiling some "legacy" code. Thet is their opinion, not mine, and not that of a majority of free software developpers (Linux, and all POSIX kernels, GCC, GNOME, Git are written in C: the list is endless, all of these are cutting edge software, especially whne compared to Microsoft's inferior OS).
C is neither dead nor dieing. We don't write C code to prove a point to C++ fans (or to Microsoft for that matter). We do it because good C code is much easier to write and to read, more portable and robust. Unless you know the arcanes of C++, in which case it's ok to use it, but so few people actually do.
Happy hacking (in C of course)
Code: Select all
void Engine::create(const char *cmd) throw (ProcessErr)
// Process the uci ... uciok tasks (parse option and engine name)
{
Process::create(cmd);
write_line("uci\n");
char line[0x100];
std::string token;
do {
read_line(line, sizeof(line));
Option o;
std::istringstream s(line);
if (!(s >> token)) throw SyntaxErr();
if (token == "id") {
if ((s >> token) && (token == "name")) {
while (s >> token)
name += token + " ";
}
}
else if (token == "option") {
// option ...
if ((s >> token) && token == "name") {
// option name ...
while ((s >> token) && token != "type")
o.name += token + " ";
s >> token;
if (token == "check") {
// option name o.name type check ...
o.type = Option::Boolean;
if (!(s >> token) || token != "default")
throw SyntaxErr();
// option name o.name type check default ...
s >> token;
o.value = token == "true" ? true : false;
o.min = false; o.max = true; // for the sake of consistency
}
else if (token == "spin") {
// option name o.name type spin ...
o.type = Option::Integer;
if (!(s >> token) || token != "default")
throw SyntaxErr();
// option name o.name type spin default ...
s >> o.value;
if (!(s >> token) || token != "min")
throw SyntaxErr();
// option name o.name type spin default o.value min ...
s >> o.min;
if (!(s >> token) || token != "max")
throw SyntaxErr();
// option name o.name type spin default o.value min o.min max ...
s >> o.max;
}
}
}
}
while (token != "uciok\n");
}
Code: Select all
std::string line;
if (!getline(cin, line)) // Block here waiting for input
break;
Code: Select all
while (s >> token)
name += std::string(" ", !name.empty()) + token;
Code: Select all
o.value = (token == "true");
instead of
o.value = token == "true" ? true : false;
Unfortunately, I'm not reading from std::cin, but from a pipe (which is used to communicate between the parent process =interface, and the child process = engine). And a pipe is a file descriptor (ie. an int on POSIX). There is no way to create a std::stream from a file descriptor that is portable (I don't want to use some GCC hacks for that). So I have to resort to using fdopen() to use the file descriptor with a FILE* and then the C I/O functions (fgets, fputs). However all that is encapsulated in a base class, which inevitably uses char * and FILE* for pipe I/O between the parent and child processes. This base class has the advantage to be generic and not linked to chess in anyway (hence reusable), as all it does is spawn/kill a process, and establish communication pipes, and provide some basic I/O functions Process::read_line() and Process::write_line(). As a next step I will do a timeout version of read_line, using the select() POSIX system call.mcostalba wrote: 1) I would use getline() to read, so to avoid fixed sizes buffers and instead define 'line' as std::string
Code: Select all
std::string line; if (!getline(cin, line)) // Block here waiting for input break;
Very nice! Thank you.mcostalba wrote: 2) To avoid a trailing white space, I would parse the names with spaces as:
Code: Select all
while (s >> token) name += std::string(" ", !name.empty()) + token;
Obviouslymcostalba wrote: 3)Code: Select all
o.value = (token == "true"); instead of o.value = token == "true" ? true : false;
Thanks. I'm reading the C++ programming language by Bjarn Stroustrup, and I have to admit it's getting me to almost like C++ now. Definitely an area where C++ is much easier than C is string manipulations... Doing the same with strtok(), strcpy() and the likes, although it's perfectly possible, would be quite painful...mcostalba wrote: Anyhow good job for someone that hates C++
Code: Select all
void Engine::create(const char *cmd) throw (ProcessErr)
{
std::string name, token, line;
Option o;
Process::create(cmd);
std::cout << "uci" << std::endl;
while (std::getline(cin, line)) // Block here waiting for input
{
std::istringstream s(line);
if (!(s >> token))
throw SyntaxErr();
if (token == "uciok")
break;
else if (token == "id")
{
if (!(s >> token) || token != "name")
throw SyntaxErr();
while (s >> token)
name += std::string(" ", !name.empty()) + token;
if (name.empty())
throw SyntaxErr();
}
else if (token == "option")
{
if (!(s >> token) || token != "name")
throw SyntaxErr();
while ((s >> token) && token != "type")
o.name += std::string(" ", !o.name.empty()) + token;
if (o.name.empty())
throw SyntaxErr();
if (!(s >> token))
throw SyntaxErr();
if (token == "check")
{
o.type = Option::Boolean;
if (!( (s >> token) && token == "default"
&& (s >> token) && (token == "true" || token == "false")))
throw SyntaxErr();
o.value = token == "true";
o.min = false; o.max = true; // for the sake of consistency
}
else if (token == "spin")
{
o.type = Option::Integer;
if (!( (s >> token) && token == "default"
&& (s >> o.value)
&& (s >> token) && token == "min" && (s >> o.min)
&& (s >> token) && token == "max" && (s >> o.max)))
throw SyntaxErr();
if ((o.min > o.value) || (o.max < o.value))
throw SyntaxErr();
}
else if (token != "string" && token != "combo")
throw SyntaxErr();
}
else
throw SyntaxErr();
}
}
Your code works, but I don't understand how!mcostalba wrote: 2) To avoid a trailing white space, I would parse the names with spaces as:
Code: Select all
while (s >> token) name += std::string(" ", !name.empty()) + token;
lucasart wrote:Your code works, but I don't understand how!
Would you care to explain this C++ magic ?
Code: Select all
std::string(" ", !name.empty())
Calls std::string following constructor
string ( const char * s, size_t n );
Content is initialized to a copy of the string formed by the first n characters in the array of characters pointed by s.