Hi Arthur, your guesses are correct. I am sorry that Csmith are not so much comprehensible. Partly because of lack of comments, which I am somewhat guilty, partly because many functions in Csmith are entered many times, and behave differently when the context is different. So the best way to understand Csmith is by finding a seed that generate a simple test case, one or two functions at most, then stepping through Csmith in a debugger to see how that test case is generated. This is a much better way than reading the source code IMHO.
Csmith operates on an abstract syntax tree. There are three chains of actions worth noting (all of them traverse the AST top down, i.e. function -> block -> statement -> _expression_):
1) make_random: to create a particular node in the AST
2) visit_facts: to visit a previously generated node when creating a new node that control flows to the old one. return false if the new node makes the old node unsafe.
3) Output: to print a particular node in the AST
The first two are entered within a context which is encapsulated in a CGContext object and a fact list. visit_facts is the backbone of generation analysis, and is likely to be invoked many times within different contexts.
Hope this short description is helpful.