I am currently trying to write a compiler using boost spirit x3. I finished the parser (without semantic actions and error handling right now, just parsing into ast). Since I want to implement the language to support scopes and function calls, I ask myself when to check if the called function exists? Should I check if a function exists in the current scope while building the ast(while parsing with semantic actions), or should I check this while compileing the ast out? The same with the scope stacks. should I build up the scope stacks while parsing, using semantic actions, or while compiling out the ast?
The problem is spectacularly underspecified.
Most of it depends in large part on the nature of the language you're implementing (how does it do scoping? Will you have lexical scoping? Closures? Will you have dynamic stacks? Coroutines? Will variables be dynamic or fully static? Typing?).
Should I check if a function exists in the current scope while building the ast(while parsing with semantic actions), or should I check this while compileing the ast out?
Like I said, both could work. I usually recommend Separation Of Concerns. Just parsing simply and operating on the AST (multiple times) afterwards is a lot simpler to think about and results in cleaner, easier to extend code in most cases.
Depending on the situation (e.g. when you want variables to potentially shadow some keywords, or some other context aware predicates during parsing) you might need to e.g. maintain a symbol table with known identifiers in scope. This would - IME - constitute a design smell and you should consider whether you need the complexity.
The same with the scope stacks. should I build up the scope stacks while parsing, using semantic actions, or while compiling out the ast?
Again, doing things in the compilation passes is usually much simpler.