in sources/cg_c.c [6812:6932]
static void cg_one_stmt(ast_node *stmt, ast_node *misc_attrs) {
// we're going to compute the fragment name if needed but we always start clean
base_fragment_name = NULL;
// reset the temp stack
stack_level = 0;
symtab_entry *entry = symtab_find(cg_stmts, stmt->type);
Contract(entry);
if (!in_proc) {
// DDL operations not in a procedure are ignored
// but they can declare schema during the semantic pass
if (entry->val == cg_any_ddl_stmt) {
return;
}
// loose select statements also have no codegen, the global proc has no result type
if (is_select_stmt(stmt)) {
return;
}
}
// don't emit a # line directive for the echo statement because it will messed up
// if the echo doesn't end in a linefeed and that's legal. And there is normally
// no visible code for these things anyway.
if (!is_ast_echo_stmt(stmt)) {
charbuf *line_out = (stmt_nesting_level == 1) ? cg_declarations_output : cg_main_output;
cg_line_directive_min(stmt, line_out);
}
CHARBUF_OPEN(tmp_header);
CHARBUF_OPEN(tmp_declarations);
CHARBUF_OPEN(tmp_main);
CHARBUF_OPEN(tmp_scratch);
charbuf *header_saved = cg_header_output;
charbuf *declarations_saved = cg_declarations_output;
charbuf *main_saved = cg_main_output;
charbuf *scratch_saved = cg_scratch_vars_output;
// Redirect all output to the temporary buffers so we can see how big it is
// The comments need to go before this, so we save the output then check it
// then emit the generated code.
cg_main_output = &tmp_main;
cg_declarations_output = &tmp_declarations;
cg_header_output = &tmp_header;
cg_scratch_vars_output = &tmp_scratch;
// These are all the statements there are, we have to find it in this table
// or else someone added a new statement and it isn't supported yet.
Invariant(entry);
((void (*)(ast_node*))entry->val)(stmt);
// safe to put it back now
cg_main_output = main_saved;
cg_header_output = header_saved;
cg_declarations_output = declarations_saved;
cg_scratch_vars_output = scratch_saved;
// Emit a helpful comment for top level statements.
if (stmt_nesting_level == 1) {
charbuf *out = cg_main_output;
if (is_ast_declare_vars_type(stmt) || is_proc(stmt) || is_ast_echo_stmt(stmt)) {
out = cg_declarations_output;
}
bool_t skip_comment = false;
// don't contaminate echo output with comments except in test, where we need it for verification
skip_comment |= (!options.test && is_ast_echo_stmt(stmt));
// If no code gen in the main buffer, don't add a comment, that will force a global proc
// We used to have all kinds of special cases to detect the statements that don't generate code
// and that was a bug farm. So now instead we just look to see if it made code. If it didn't make
// code we will not force the global proc to exist because of the stupid comment...
skip_comment |= (out == cg_main_output && tmp_main.used == 1);
// put a line marker in the header file in case we want a test suite that verifies that
if (options.test) {
bprintf(cg_header_output, "\n// The statement ending at line %d\n", stmt->lineno);
}
// emit comments for most statements: we do not want to require the global proc block
// just because there was a comment so this is suppressed for "no code" things
if (!skip_comment) {
if (options.test) {
bprintf(out, "\n// The statement ending at line %d\n", stmt->lineno);
} else {
bprintf(cg_header_output, "\n// Generated from %s:%d\n", stmt->filename, stmt->lineno);
bprintf(cg_declarations_output, "\n// Generated from %s:%d\n", stmt->filename, stmt->lineno);
}
// emit source comment
bprintf(out, "\n/*\n");
CHARBUF_OPEN(tmp);
gen_stmt_level = 1;
gen_set_output_buffer(&tmp);
if (misc_attrs) {
gen_misc_attrs(misc_attrs);
}
gen_one_stmt(stmt);
cg_remove_slash_star_and_star_slash(&tmp); // internal "*/" is fatal. "/*" can also be under certain compilation flags
bprintf(out, "%s", tmp.ptr);
CHARBUF_CLOSE(tmp);
bprintf(out, ";\n*/\n");
}
}
// and finally write what we saved
bprintf(cg_main_output, "%s", tmp_main.ptr);
bprintf(cg_header_output, "%s", tmp_header.ptr);
bprintf(cg_scratch_vars_output, "%s", tmp_scratch.ptr);
bprintf(cg_declarations_output, "%s", tmp_declarations.ptr);
CHARBUF_CLOSE(tmp_scratch);
CHARBUF_CLOSE(tmp_main);
CHARBUF_CLOSE(tmp_declarations);
CHARBUF_CLOSE(tmp_header);
}