Pretty printing a parse tree to std out? - c++

I have written a simple recursive descent parser in C++.
I need a way to print it to std out but I cannot figure out how to do this.
I have a class Node and it has a function printSymbol() to print its symbol.
It has a std::list <Node*> m_children for its children.
Given this, how can I pretty print the parse tree to std out?
Thanks

Add an overload to printSymbol that takes an indent-level, or a default value, either works:
void printSymbol(unsigned indent = 0) const
{
std::cout << std::string(indent,' ') << m_symbol << '\n';
for (auto child : m_children)
child->printSymbol(indent+2);
}
Given any single node a direct call to printSymbol() should simply output the symbol, a newline, and all its children if it has any, all properly indented. Given a root pointer this should dump your entire parse hierarchy to stdout. You can get extraordinarily creative regarding ascii art, console-dependent line chars if you're really set on it, but it can get tedious quickly, I warn you.
Regardless, this should at least give you a picture you can print. Either that or I utterly misunderstood your question.
Best of luck

Related

How to write output of two different functions at the same times on separate lines in console? (C++, Windows 10)

I have the write() function which takes a string and an int for time as parameters. It takes the given string and writes the same string, letter by letter, with a set time delay.
For example, write("Cat is moving", 50) would output each letter one after the other with a 50 millisecond delay.
Right now I am wondering how I could make it so the console can output 2 different write() functions on the screen at the same time, on two separate lines of the console, without overlapping each other.
I tried doing something with multi-threading but it didn't work and I believe there has to be a simpler way.
This program is intended for Windows only.
I did implement a change cursor position function already, so that shouldn't be a problem.
This is the function:
void write(string word, int time)
{
for (int i = 0; i < word.length(); i++)
{
cout << word.at(i);
Sleep(time);
}
}
You are basically asking for a way for your program to be logically running several instances of the same function at the same time (without using recursion).
Although this can be accomplished by using multithreading, I don't recommend doing this, because in your case, this will probably introduce more problems than it will solve.
An alternative to multithreading may be to use coroutines, which were introduced in C++20. If you make write a coroutine instead of a function, then you may be able to solve the problem by having several of these coroutines logically running at the same time (they will probably not actually be running at the same time, because they will be suspended most of the time).
Unfortunately, I have no practical experience with coroutines, so I am unable to provide the details of a solution which would use coroutines. All I can say is that they are probably worth looking into for you, because as far as I can tell, they coincide with your way of thinking and with your way of wanting to solve the problem.
A more traditional way of solving the problem in C++ would be the following:
In the main loop of your program, you could call a function write_next_characters (which you write yourself) every 50 milliseconds, which writes the next characters of all words that are currently to be written.
In order for this function to work, your program will have to keep track of
a list of all words that are currently to be written,
the screen coordinates to which each word is to be written, and
how many characters of each word have already been written.
The function write_next_characters should receive a pointer to this information whenever it is called by the function main. It can then jump to the appropriate screen coordinates and print the next letter of each word. It will also have to update the state information mentioned above.
I would suggest that you define the following struct which contains the state information mentioned above for every word:
struct word_state
{
//the word that is to be written
std::string word;
//the screen coordinates to which the word is to be written
int x;
int y;
//how many characters have already been written
int written;
};
For every word that you are currently writing, you will have to create one object of type word_state. You can use a container of type std::list<word_state> to keep them in a linked list. I believe that using a linked list is appropriate, so that you can easily remove words from the list after the last character of that word has finished printing.

Replace all occurrences based on map

This question might have already been answered but I haven't found it yet.
Let's say I have a std::map<string,string> which contains string pairs of <replace_all_this, to_this>.
I checked Boost's format library, which is close but not perfect:
std::map<string,string> m;
m['$search1'] = 'replace1';
m['$search2'] = 'replace2';
format fmter1("let's try to %1% and %2%.");
fmter % 36; fmter % 77;
for(auto r : m) {
fmter % r.second;
}
// would print "let's try to replace1 and replace2
This would work, but I lose control of what.
Actually I'd like to have this as result:
format fmter1("let's try to $search2 and $search1 even if their order is different in the map.");
...
//print: "let's try to replace2 and replace1 even if their order is different in the map".
Please note: map can contain more items, and items can occur multiple times in the formatter.
What is the way to go for this in 2020, I'd like it to be effective and fast, so I'd avoid iterating over the map multiple times.
There may be new libraries but there is no new algorithm to do that faster than what we have so far.
Assuming your format implies a $<name> for your variables, you can search for the first '$', read the <name> search for that in the map, then do the replace. This allows you to either skip the replacement or process it too (i.e. make it recursive where a variable can reference another).
I don't think that doing it the other way around would be any faster: i.e. go through the map and search for the names in the string means you'd be parsing the strings many times and if you have many variables, it will be a huge waste if most are not likely part of your string. Also if you want to prevent some level of recursivity, it's very complicated.
Where you can eventually optimize is in calculating the size of the resulting string and allocate that buffer once instead of using += which is not unlikely going to be slower.
I have such an implementation in my snaplogger. The variable has to be between brackets and it can include multiple parameters to further tweak the data. There is documentation here about what is supported by that function and as written, you can easily extend the class to add more features. It's probably not a one to one match to what you're looking for, but it shows you that there is not 20 ways of implementing that function.

Improving efficiency of std::string in a compiler

I'm attempting to build a scanner for a compiler of a C like language and am getting caught up on an efficient way to generate tokens... I have a scan function:
vector<Token> scan(string &input);
And also a main function, which reads in a lexically correct file and removes comments. (the language does not support /* , */ comments) I am using a DFA with maximal munch to generate tokens... and I'm pretty sure that part of the scanner is reasonably efficient. However the scanner does not handle large files well, because they all end up in one string... and all of the concatenation of 1000 lines of a file with line 1001 is breaking the scanner. Unfortunately my FSM can not deal with comments because they are allowed to contain any Unicode and other odd characters. I was wondering... is there a better way to go from a file in stdin, to a vector of tokens, keeping in mind that the function scan must take a single string and, return a single vector, and all tokens must be in a single vector at the end of scanning... Anyway, here is the code which "scans": Please don't laugh at my bad idea too hard :)
string in = "";
string build;
while(true)
{
getline(cin, build);
if( cin.eof() )
break;
if(build.find ("//") != string::npos)
build = build.substr(0, build.find("//",0));
in += " " + build;
}
try {
vector<Token> wlpp = scan(in);
...
...
A couple of things that you might want to consider:
in += " " + build;
Is very inefficient and probably not want you want in that loop, but that doesn't seem to be where you're running in to problems. (at the very least, get some idea about the size of your inputs and do in.reserve(size) before that.
The better design for your scanner might be as a class that wraps the input file as an istream_iterator<Token> and implement an appropriate operator>> for Token. If you really wanted it in a vector, you could then do something like vector<Token> v(istream_iterator<Token>(cin), istream_iterator<Token>()); and be done with it. Your operator>> would then just swallow comments and populate a token before returning.

Behavior of STL remove() function - only rearrange container elements?

I've read here on StackOveflow and other sources that the behavior of the remove function is simply re-ordering the original container so that the elements that are TO BE REMOVED are moved to the end of the container and ARE NOT deleted. They remain part of the container and the remove() function simply returns an iterator that delimits the end of the range of elements to keep.
So if you never actually trim off the portion of the container that has the values that have been 'removed', they should still be present.
But when I run the code below there are no trailing spaces after the alphanumeric characters that were not 'removed'.
int main()
{
std::string test "this is a test string with a bunch of spaces to remove";
remove(test.begin(), test.end(), ' ');
std::cout << test << std::endl;
return 0;
}
What is going on here? Seeing as I never call test.erase() shouldn't I have a bunch of trailing spaces on my string? Is it guaranteed that the 'removed' items will still be present after calling remove()?
PS-I'm not looking for suggestions on how to best remove spaces from a string, the above is simply an illustrative example of the remove() behavior that is confusing me.
What's left at the end of your container after a call to remove is not necessarily the elements that were removed. It's just junk. Most likely it's "whatever was in those positions before the call to remove", but you can't rely on that either. Much like an uninitialized variable, it could be anything.
For example, the string:
"Hi I am Bob!\0"
after a call to remove to get rid of spaces probably looks like this
"HiIamBob!\0b!\0"
You won't see that on a cout, though, because it will stop printing once it hits the '\0'.
You might be willing to get Boost.String.
It's a collection of algorithms to act on strings.
boost::erase_all(test, " ");

printing using one '\n'

I am pretty sure all of you are familiar with the concept of the Big4, and I have several stuffs to do print in each of the constructor, assignment, destructor, and copy constructor.
The restriction is this:
I CAN'T use more than one newline (e.g., ƒn or std::endl) in any method
I can have a method called print, so I am guessing print is where I will put that precious one and only '\n', my problem is that how can the method print which prints different things on each of the element I want to print in each of the Big4? Any idea? Maybe overloading the Big4?
Maybe I don't understand the question completely because it is asked rather awkwardly, but can't you just have a function called newline that receives an ostream as an argument, and then simply prints '/n' to that output stream? Then you can just call that infinitely many times, while still abiding the arbitrary "one newline" rule.
e.g.
(edit: code removed, "smells like homework")
print should take a parameter containing the information to output to the screen (sans '\n') and then call the c++ output method with in-line appending the '\n' to the passed in information.
note: no code 'cause this smells like homework to me...
I'm not sure I completely understand what you're trying to accomplish. Why is it that you can only use one newline? What makes it difficult to just write your code with only one newline in it? For example, I've done stuff like this before.
for(int i = 0; i < 10; i++) {
cout << i << " ";
}
cout << std::endl;
If you need something more complicated, you might want to make some sort of print tracker object that keeps a flag for whether a newline has been printed, and adjusts its behavior accordingly. This seems like it might be a little overly complicated though.