These basic shapes alone can get you far. The problem arises when you need these constructs to intersect each other. In most cases they produce complex shapes for which we don't even have names, let alone a unique mathematical formula. For instance, you can create a nice dome by doing a loft operation on a tube or a cylinder. Now, if you needed to blend two domes, you would be facing an increasingly difficult problem.
In other fields this is usually solved by "Constructive Solid Geometry" (CSG), which is about combining multiple shapes into bigger or smaller shapes by subtraction, addition, intersection and other similar operations. The problem with CSG is that it outputs a soup of triangles. The little boxes, cylinders, prisms we used to have disappear in this soup. This matters a lot for architecture grammars. The rules you write are designed for these basic elements, not flat triangles.
I encountered this problem while building grammars for a Mosque. The base of the building is square, the top of the building is a dome which has a circular base. There is some kind of roof that transitions from the square into the circle. This is an element also found in Roman and Byzantine buildings.
In the next image you can see a red arrow pointing to it:
If you isolate this element, this is how it looks like:
These images, as usual, are the output of my architecture system. Which means these shapes entirely possible. They are quite easy to produce as well.
The trick again is in the occlusion rules. This time they can be combined with the recursive nature of L-Systems to great advantage.
The starting point is to define these shapes ignoring the weird cuts we will make later. This is what you get from a square base and a cone-shaped tube, both basic shapes:
Here comes the first trick. In reality, these shapes are made of smaller ones. I have reduced them just so you can see:
Using occlusion rules, we can hide the elements that are outside the box and above the roof. This produces a very coarse approximation to the shape we want:
This produces a new set of elements. To this set we apply the same rule as before. Some will be entirely visible, some will be entirely occluded and some will be partially occluded. Once again, those that are partially occluded will be subdivided into a smaller set. Eventually the elements will be small to a point where it is not practical to subdivide again. This is where the process ends.
Here you can see the output of this method. Note that all the elements are boxes:
Obviously the cuts are not completely smooth. You still get these microscopic boxes. In my case this is not a problem at all. These volumes are sent to a voxelization phase. The tiny boxes are smaller than the voxel resolution so they are blended into straight features which later optimize very well.
I thought this was a nice technique. For sure you could use it to produce really bizarre objects. We may see some of that later.