-/* C language support for compilation.
+/* C/C++ language support for compilation.
- Copyright (C) 2014-2015 Free Software Foundation, Inc.
+ Copyright (C) 2014-2019 Free Software Foundation, Inc.
This file is part of GDB.
#include "defs.h"
#include "compile-internal.h"
+#include "compile-c.h"
+#include "compile-cplus.h"
#include "compile.h"
#include "gdb-dlfcn.h"
#include "c-lang.h"
#include "macrotab.h"
#include "macroscope.h"
#include "regcache.h"
+#include "common/function-view.h"
+#include "common/preprocessor.h"
/* See compile-internal.h. */
/* See compile-internal.h. */
-char *
+std::string
c_get_range_decl_name (const struct dynamic_prop *prop)
{
- return xstrprintf ("__gdb_prop_%s", host_address_to_string (prop));
+ return string_printf ("__gdb_prop_%s", host_address_to_string (prop));
}
\f
-#define STR(x) #x
-#define STRINGIFY(x) STR(x)
+/* Load the plug-in library FE_LIBCC and return the initialization function
+ FE_CONTEXT. */
-/* Helper function for c_get_compile_context. Open the GCC front-end
- shared library and return the symbol specified by the current
- GCC_C_FE_CONTEXT. */
-
-static gcc_c_fe_context_function *
-load_libcc (void)
+template <typename FUNCTYPE>
+FUNCTYPE *
+load_libcompile (const char *fe_libcc, const char *fe_context)
{
- void *handle;
- gcc_c_fe_context_function *func;
+ FUNCTYPE *func;
- /* gdb_dlopen will call error () on an error, so no need to check
- value. */
- handle = gdb_dlopen (STRINGIFY (GCC_C_FE_LIBCC));
- func = (gcc_c_fe_context_function *) gdb_dlsym (handle,
- STRINGIFY (GCC_C_FE_CONTEXT));
+ /* gdb_dlopen will call error () on an error, so no need to check
+ value. */
+ gdb_dlhandle_up handle = gdb_dlopen (fe_libcc);
+ func = (FUNCTYPE *) gdb_dlsym (handle, fe_context);
if (func == NULL)
- error (_("could not find symbol %s in library %s"),
- STRINGIFY (GCC_C_FE_CONTEXT),
- STRINGIFY (GCC_C_FE_LIBCC));
+ error (_("could not find symbol %s in library %s"), fe_context, fe_libcc);
+
+ /* Leave the library open. */
+ handle.release ();
return func;
}
/* Return the compile instance associated with the current context.
- This function calls the symbol returned from the load_libcc
- function. This will provide the gcc_c_context. */
-
-struct compile_instance *
-c_get_compile_context (void)
+ This function calls the symbol returned from the load_libcompile
+ function. FE_LIBCC is the library to load. BASE_VERSION is the
+ base compile plug-in version we support. API_VERSION is the
+ API version supported. */
+
+template <typename INSTTYPE, typename FUNCTYPE, typename CTXTYPE,
+ typename BASE_VERSION_TYPE, typename API_VERSION_TYPE>
+compile_instance *
+get_compile_context (const char *fe_libcc, const char *fe_context,
+ BASE_VERSION_TYPE base_version,
+ API_VERSION_TYPE api_version)
{
- static gcc_c_fe_context_function *func;
-
- struct gcc_c_context *context;
+ static FUNCTYPE *func;
+ static CTXTYPE *context;
if (func == NULL)
{
- func = load_libcc ();
+ func = load_libcompile<FUNCTYPE> (fe_libcc, fe_context);
gdb_assert (func != NULL);
}
- context = (*func) (GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+ context = (*func) (base_version, api_version);
if (context == NULL)
error (_("The loaded version of GCC does not support the required version "
"of the API."));
- return new_compile_instance (context);
+ return new INSTTYPE (context);
+}
+
+/* A C-language implementation of get_compile_context. */
+
+compile_instance *
+c_get_compile_context ()
+{
+ return get_compile_context
+ <compile_c_instance, gcc_c_fe_context_function, gcc_c_context,
+ gcc_base_api_version, gcc_c_api_version>
+ (STRINGIFY (GCC_C_FE_LIBCC), STRINGIFY (GCC_C_FE_CONTEXT),
+ GCC_FE_VERSION_0, GCC_C_FE_VERSION_0);
+}
+
+/* A C++-language implementation of get_compile_context. */
+
+compile_instance *
+cplus_get_compile_context ()
+{
+ return get_compile_context
+ <compile_cplus_instance, gcc_cp_fe_context_function, gcc_cp_context,
+ gcc_base_api_version, gcc_cp_api_version>
+ (STRINGIFY (GCC_CP_FE_LIBCC), STRINGIFY (GCC_CP_FE_CONTEXT),
+ GCC_FE_VERSION_0, GCC_CP_FE_VERSION_0);
}
\f
static void
print_one_macro (const char *name, const struct macro_definition *macro,
struct macro_source_file *source, int line,
- void *user_data)
+ ui_file *file)
{
- struct ui_file *file = user_data;
-
/* Don't print command-line defines. They will be supplied another
way. */
if (line == 0)
write_macro_definitions (const struct block *block, CORE_ADDR pc,
struct ui_file *file)
{
- struct macro_scope *scope;
+ gdb::unique_xmalloc_ptr<struct macro_scope> scope;
if (block != NULL)
scope = sal_macro_scope (find_pc_line (pc, 0));
scope = user_macro_scope ();
if (scope != NULL && scope->file != NULL && scope->file->table != NULL)
- macro_for_each_in_scope (scope->file, scope->line, print_one_macro, file);
-}
-
-/* Helper function to construct a header scope for a block of code.
- Takes a scope argument which selects the correct header to
- insert into BUF. */
-
-static void
-add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
-{
- switch (type)
- {
- case COMPILE_I_SIMPLE_SCOPE:
- fputs_unfiltered ("void "
- GCC_FE_WRAPPER_FUNCTION
- " (struct "
- COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
- " *"
- COMPILE_I_SIMPLE_REGISTER_ARG_NAME
- ") {\n",
- buf);
- break;
- case COMPILE_I_PRINT_ADDRESS_SCOPE:
- case COMPILE_I_PRINT_VALUE_SCOPE:
- /* <string.h> is needed for a memcpy call below. */
- fputs_unfiltered ("#include <string.h>\n"
- "void "
- GCC_FE_WRAPPER_FUNCTION
- " (struct "
- COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
- " *"
- COMPILE_I_SIMPLE_REGISTER_ARG_NAME
- ", "
- COMPILE_I_PRINT_OUT_ARG_TYPE
- " "
- COMPILE_I_PRINT_OUT_ARG
- ") {\n",
- buf);
- break;
-
- case COMPILE_I_RAW_SCOPE:
- break;
- default:
- gdb_assert_not_reached (_("Unknown compiler scope reached."));
- }
-}
-
-/* Helper function to construct a footer scope for a block of code.
- Takes a scope argument which selects the correct footer to
- insert into BUF. */
-
-static void
-add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
-{
- switch (type)
{
- case COMPILE_I_SIMPLE_SCOPE:
- case COMPILE_I_PRINT_ADDRESS_SCOPE:
- case COMPILE_I_PRINT_VALUE_SCOPE:
- fputs_unfiltered ("}\n", buf);
- break;
- case COMPILE_I_RAW_SCOPE:
- break;
- default:
- gdb_assert_not_reached (_("Unknown compiler scope reached."));
+ macro_for_each_in_scope (scope->file, scope->line,
+ [&] (const char *name,
+ const macro_definition *macro,
+ macro_source_file *source,
+ int line)
+ {
+ print_one_macro (name, macro, source, line, file);
+ });
}
}
if (registers_used[i])
{
struct type *regtype = check_typedef (register_type (gdbarch, i));
- char *regname = compile_register_name_mangled (gdbarch, i);
- struct cleanup *cleanups = make_cleanup (xfree, regname);
+ std::string regname = compile_register_name_mangled (gdbarch, i);
seen = 1;
switch (TYPE_CODE (regtype))
{
case TYPE_CODE_PTR:
- fprintf_filtered (stream, "__gdb_uintptr %s", regname);
+ fprintf_filtered (stream, "__gdb_uintptr %s",
+ regname.c_str ());
break;
case TYPE_CODE_INT:
fprintf_unfiltered (stream,
"int %s"
" __attribute__ ((__mode__(__%s__)))",
- regname,
+ regname.c_str (),
mode);
break;
}
default:
fprintf_unfiltered (stream,
- " unsigned char %s[%d]"
+ " unsigned char %s[%s]"
" __attribute__((__aligned__("
"__BIGGEST_ALIGNMENT__)))",
- regname,
- TYPE_LENGTH (regtype));
+ regname.c_str (),
+ pulongest (TYPE_LENGTH (regtype)));
}
fputs_unfiltered (";\n", stream);
-
- do_cleanups (cleanups);
}
}
fputs_unfiltered ("};\n\n", stream);
}
-/* Take the source code provided by the user with the 'compile'
- command, and compute the additional wrapping, macro, variable and
- register operations needed. INPUT is the source code derived from
- the 'compile' command, GDBARCH is the architecture to use when
- computing above, EXPR_BLOCK denotes the block relevant contextually
- to the inferior when the expression was created, and EXPR_PC
- indicates the value of $PC. */
+/* C-language policy to emit a push user expression pragma into BUF. */
-char *
-c_compute_program (struct compile_instance *inst,
- const char *input,
- struct gdbarch *gdbarch,
- const struct block *expr_block,
- CORE_ADDR expr_pc)
+struct c_push_user_expression
{
- struct ui_file *buf, *var_stream = NULL;
- char *code;
- struct cleanup *cleanup;
- struct compile_c_instance *context = (struct compile_c_instance *) inst;
+ void push_user_expression (struct ui_file *buf)
+ {
+ fputs_unfiltered ("#pragma GCC user_expression\n", buf);
+ }
+};
- buf = mem_fileopen ();
- cleanup = make_cleanup_ui_file_delete (buf);
+/* C-language policy to emit a pop user expression pragma into BUF.
+ For C, this is a nop. */
- write_macro_definitions (expr_block, expr_pc, buf);
+struct pop_user_expression_nop
+{
+ void pop_user_expression (struct ui_file *buf)
+ {
+ /* Nothing to do. */
+ }
+};
+
+/* C-language policy to construct a code header for a block of code.
+ Takes a scope TYPE argument which selects the correct header to
+ insert into BUF. */
- /* Do not generate local variable information for "raw"
- compilations. In this case we aren't emitting our own function
- and the user's code may only refer to globals. */
- if (inst->scope != COMPILE_I_RAW_SCOPE)
- {
- unsigned char *registers_used;
- int i;
+struct c_add_code_header
+{
+ void add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
+ {
+ switch (type)
+ {
+ case COMPILE_I_SIMPLE_SCOPE:
+ fputs_unfiltered ("void "
+ GCC_FE_WRAPPER_FUNCTION
+ " (struct "
+ COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+ " *"
+ COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+ ") {\n",
+ buf);
+ break;
+
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ /* <string.h> is needed for a memcpy call below. */
+ fputs_unfiltered ("#include <string.h>\n"
+ "void "
+ GCC_FE_WRAPPER_FUNCTION
+ " (struct "
+ COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+ " *"
+ COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+ ", "
+ COMPILE_I_PRINT_OUT_ARG_TYPE
+ " "
+ COMPILE_I_PRINT_OUT_ARG
+ ") {\n",
+ buf);
+ break;
+
+ case COMPILE_I_RAW_SCOPE:
+ break;
+
+ default:
+ gdb_assert_not_reached (_("Unknown compiler scope reached."));
+ }
+ }
+};
- /* Generate the code to compute variable locations, but do it
- before generating the function header, so we can define the
- register struct before the function body. This requires a
- temporary stream. */
- var_stream = mem_fileopen ();
- make_cleanup_ui_file_delete (var_stream);
- registers_used = generate_c_for_variable_locations (context,
- var_stream, gdbarch,
- expr_block, expr_pc);
- make_cleanup (xfree, registers_used);
-
- fputs_unfiltered ("typedef unsigned int"
- " __attribute__ ((__mode__(__pointer__)))"
- " __gdb_uintptr;\n",
- buf);
- fputs_unfiltered ("typedef int"
- " __attribute__ ((__mode__(__pointer__)))"
- " __gdb_intptr;\n",
- buf);
+/* C-language policy to construct a code footer for a block of code.
+ Takes a scope TYPE which selects the correct footer to insert into BUF. */
- /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */
- for (i = 0; i < 4; ++i)
- {
- const char *mode = c_get_mode_for_size (1 << i);
-
- gdb_assert (mode != NULL);
- fprintf_unfiltered (buf,
- "typedef int"
- " __attribute__ ((__mode__(__%s__)))"
- " __gdb_int_%s;\n",
- mode, mode);
- }
+struct c_add_code_footer
+{
+ void add_code_footer (enum compile_i_scope_types type, struct ui_file *buf)
+ {
+ switch (type)
+ {
+ case COMPILE_I_SIMPLE_SCOPE:
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ fputs_unfiltered ("}\n", buf);
+ break;
- generate_register_struct (buf, gdbarch, registers_used);
- }
+ case COMPILE_I_RAW_SCOPE:
+ break;
- add_code_header (inst->scope, buf);
+ default:
+ gdb_assert_not_reached (_("Unknown compiler scope reached."));
+ }
+ }
+};
- if (inst->scope == COMPILE_I_SIMPLE_SCOPE
- || inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
- || inst->scope == COMPILE_I_PRINT_VALUE_SCOPE)
- {
- ui_file_put (var_stream, ui_file_write_for_put, buf);
- fputs_unfiltered ("#pragma GCC user_expression\n", buf);
- }
+/* C-language policy to emit the user code snippet INPUT into BUF based on the
+ scope TYPE. */
+
+struct c_add_input
+{
+ void add_input (enum compile_i_scope_types type, const char *input,
+ struct ui_file *buf)
+ {
+ switch (type)
+ {
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ fprintf_unfiltered (buf,
+ "__auto_type " COMPILE_I_EXPR_VAL " = %s;\n"
+ "typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
+ "memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s"
+ COMPILE_I_EXPR_VAL ",\n"
+ "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+ , input, input,
+ (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+ ? "&" : ""));
+ break;
+
+ default:
+ fputs_unfiltered (input, buf);
+ break;
+ }
+ fputs_unfiltered ("\n", buf);
+ }
+};
- /* The user expression has to be in its own scope, so that "extern"
- works properly. Otherwise gcc thinks that the "extern"
- declaration is in the same scope as the declaration provided by
- gdb. */
- if (inst->scope != COMPILE_I_RAW_SCOPE)
- fputs_unfiltered ("{\n", buf);
+/* C++-language policy to emit a push user expression pragma into
+ BUF. */
- fputs_unfiltered ("#line 1 \"gdb command line\"\n", buf);
+struct cplus_push_user_expression
+{
+ void push_user_expression (struct ui_file *buf)
+ {
+ fputs_unfiltered ("#pragma GCC push_user_expression\n", buf);
+ }
+};
+
+/* C++-language policy to emit a pop user expression pragma into BUF. */
+
+struct cplus_pop_user_expression
+{
+ void pop_user_expression (struct ui_file *buf)
+ {
+ fputs_unfiltered ("#pragma GCC pop_user_expression\n", buf);
+ }
+};
+
+/* C++-language policy to construct a code header for a block of code.
+ Takes a scope TYPE argument which selects the correct header to
+ insert into BUF. */
- switch (inst->scope)
+struct cplus_add_code_header
+{
+ void add_code_header (enum compile_i_scope_types type, struct ui_file *buf)
+ {
+ switch (type)
{
+ case COMPILE_I_SIMPLE_SCOPE:
+ fputs_unfiltered ("void "
+ GCC_FE_WRAPPER_FUNCTION
+ " (struct "
+ COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+ " *"
+ COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+ ") {\n",
+ buf);
+ break;
+
case COMPILE_I_PRINT_ADDRESS_SCOPE:
case COMPILE_I_PRINT_VALUE_SCOPE:
- fprintf_unfiltered (buf,
-"__auto_type " COMPILE_I_EXPR_VAL " = %s;\n"
-"typeof (%s) *" COMPILE_I_EXPR_PTR_TYPE ";\n"
-"memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s" COMPILE_I_EXPR_VAL ",\n"
- "sizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
- , input, input,
- (inst->scope == COMPILE_I_PRINT_ADDRESS_SCOPE
- ? "&" : ""));
+ fputs_unfiltered (
+ "#include <cstring>\n"
+ "#include <bits/move.h>\n"
+ "void "
+ GCC_FE_WRAPPER_FUNCTION
+ " (struct "
+ COMPILE_I_SIMPLE_REGISTER_STRUCT_TAG
+ " *"
+ COMPILE_I_SIMPLE_REGISTER_ARG_NAME
+ ", "
+ COMPILE_I_PRINT_OUT_ARG_TYPE
+ " "
+ COMPILE_I_PRINT_OUT_ARG
+ ") {\n",
+ buf);
break;
- default:
- fputs_unfiltered (input, buf);
+
+ case COMPILE_I_RAW_SCOPE:
break;
+
+ default:
+ gdb_assert_not_reached (_("Unknown compiler scope reached."));
}
+ }
+};
- fputs_unfiltered ("\n", buf);
+/* C++-language policy to emit the user code snippet INPUT into BUF based on
+ the scope TYPE. */
- /* For larger user expressions the automatic semicolons may be
- confusing. */
- if (strchr (input, '\n') == NULL)
- fputs_unfiltered (";\n", buf);
+struct cplus_add_input
+{
+ void add_input (enum compile_i_scope_types type, const char *input,
+ struct ui_file *buf)
+ {
+ switch (type)
+ {
+ case COMPILE_I_PRINT_VALUE_SCOPE:
+ case COMPILE_I_PRINT_ADDRESS_SCOPE:
+ fprintf_unfiltered
+ (buf,
+ /* "auto" strips ref- and cv- qualifiers, so we need to also strip
+ those from COMPILE_I_EXPR_PTR_TYPE. */
+ "auto " COMPILE_I_EXPR_VAL " = %s;\n"
+ "typedef "
+ "std::add_pointer<std::remove_cv<decltype (%s)>::type>::type "
+ " __gdb_expr_ptr;\n"
+ "__gdb_expr_ptr " COMPILE_I_EXPR_PTR_TYPE ";\n"
+ "std::memcpy (" COMPILE_I_PRINT_OUT_ARG ", %s ("
+ COMPILE_I_EXPR_VAL "),\n"
+ "\tsizeof (*" COMPILE_I_EXPR_PTR_TYPE "));\n"
+ ,input, input,
+ (type == COMPILE_I_PRINT_ADDRESS_SCOPE
+ ? "__builtin_addressof" : ""));
+ break;
+
+ default:
+ fputs_unfiltered (input, buf);
+ break;
+ }
+ fputs_unfiltered ("\n", buf);
+ }
+};
+
+/* A host class representing a compile program.
+
+ CompileInstanceType is the type of the compile_instance for the
+ language.
+
+ PushUserExpressionPolicy and PopUserExpressionPolicy are used to
+ push and pop user expression pragmas to the compile plug-in.
+
+ AddCodeHeaderPolicy and AddCodeFooterPolicy are used to add the appropriate
+ code header and footer, respectively.
+
+ AddInputPolicy adds the actual user code. */
+
+template <class CompileInstanceType, class PushUserExpressionPolicy,
+ class PopUserExpressionPolicy, class AddCodeHeaderPolicy,
+ class AddCodeFooterPolicy, class AddInputPolicy>
+class compile_program
+ : private PushUserExpressionPolicy, private PopUserExpressionPolicy,
+ private AddCodeHeaderPolicy, private AddCodeFooterPolicy,
+ private AddInputPolicy
+{
+public:
+
+ /* Construct a compile_program using the compiler instance INST
+ using the architecture given by GDBARCH. */
+ compile_program (CompileInstanceType *inst, struct gdbarch *gdbarch)
+ : m_instance (inst), m_arch (gdbarch)
+ {
+ }
+
+ /* Take the source code provided by the user with the 'compile'
+ command and compute the additional wrapping, macro, variable and
+ register operations needed. INPUT is the source code derived from
+ the 'compile' command, EXPR_BLOCK denotes the block relevant contextually
+ to the inferior when the expression was created, and EXPR_PC
+ indicates the value of $PC.
+
+ Returns the text of the program to compile. */
+ std::string compute (const char *input, const struct block *expr_block,
+ CORE_ADDR expr_pc)
+ {
+ string_file var_stream;
+ string_file buf;
+
+ /* Do not generate local variable information for "raw"
+ compilations. In this case we aren't emitting our own function
+ and the user's code may only refer to globals. */
+ if (m_instance->scope () != COMPILE_I_RAW_SCOPE)
+ {
+ /* Generate the code to compute variable locations, but do it
+ before generating the function header, so we can define the
+ register struct before the function body. This requires a
+ temporary stream. */
+ gdb::unique_xmalloc_ptr<unsigned char> registers_used
+ = generate_c_for_variable_locations (m_instance, &var_stream, m_arch,
+ expr_block, expr_pc);
+
+ buf.puts ("typedef unsigned int"
+ " __attribute__ ((__mode__(__pointer__)))"
+ " __gdb_uintptr;\n");
+ buf.puts ("typedef int"
+ " __attribute__ ((__mode__(__pointer__)))"
+ " __gdb_intptr;\n");
+
+ /* Iterate all log2 sizes in bytes supported by c_get_mode_for_size. */
+ for (int i = 0; i < 4; ++i)
+ {
+ const char *mode = c_get_mode_for_size (1 << i);
+
+ gdb_assert (mode != NULL);
+ buf.printf ("typedef int"
+ " __attribute__ ((__mode__(__%s__)))"
+ " __gdb_int_%s;\n",
+ mode, mode);
+ }
+
+ generate_register_struct (&buf, m_arch, registers_used.get ());
+ }
+
+ AddCodeHeaderPolicy::add_code_header (m_instance->scope (), &buf);
+
+ if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE
+ || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE
+ || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE)
+ {
+ buf.write (var_stream.c_str (), var_stream.size ());
+ PushUserExpressionPolicy::push_user_expression (&buf);
+ }
+
+ write_macro_definitions (expr_block, expr_pc, &buf);
+
+ /* The user expression has to be in its own scope, so that "extern"
+ works properly. Otherwise gcc thinks that the "extern"
+ declaration is in the same scope as the declaration provided by
+ gdb. */
+ if (m_instance->scope () != COMPILE_I_RAW_SCOPE)
+ buf.puts ("{\n");
+
+ buf.puts ("#line 1 \"gdb command line\"\n");
+
+ AddInputPolicy::add_input (m_instance->scope (), input, &buf);
- if (inst->scope != COMPILE_I_RAW_SCOPE)
- fputs_unfiltered ("}\n", buf);
+ /* For larger user expressions the automatic semicolons may be
+ confusing. */
+ if (strchr (input, '\n') == NULL)
+ buf.puts (";\n");
+
+ if (m_instance->scope () != COMPILE_I_RAW_SCOPE)
+ buf.puts ("}\n");
+
+ if (m_instance->scope () == COMPILE_I_SIMPLE_SCOPE
+ || m_instance->scope () == COMPILE_I_PRINT_ADDRESS_SCOPE
+ || m_instance->scope () == COMPILE_I_PRINT_VALUE_SCOPE)
+ PopUserExpressionPolicy::pop_user_expression (&buf);
+
+ AddCodeFooterPolicy::add_code_footer (m_instance->scope (), &buf);
+ return buf.string ();
+ }
+
+private:
+
+ /* The compile instance to be used for compilation and
+ type-conversion. */
+ CompileInstanceType *m_instance;
+
+ /* The architecture to be used. */
+ struct gdbarch *m_arch;
+};
+
+/* The types used for C and C++ program computations. */
+
+typedef compile_program<compile_c_instance,
+ c_push_user_expression, pop_user_expression_nop,
+ c_add_code_header, c_add_code_footer,
+ c_add_input> c_compile_program;
+
+typedef compile_program<compile_cplus_instance,
+ cplus_push_user_expression, cplus_pop_user_expression,
+ cplus_add_code_header, c_add_code_footer,
+ cplus_add_input> cplus_compile_program;
+
+/* The la_compute_program method for C. */
+
+std::string
+c_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc)
+{
+ compile_c_instance *c_inst = static_cast<compile_c_instance *> (inst);
+ c_compile_program program (c_inst, gdbarch);
+
+ return program.compute (input, expr_block, expr_pc);
+}
+
+/* The la_compute_program method for C++. */
+
+std::string
+cplus_compute_program (compile_instance *inst,
+ const char *input,
+ struct gdbarch *gdbarch,
+ const struct block *expr_block,
+ CORE_ADDR expr_pc)
+{
+ compile_cplus_instance *cplus_inst
+ = static_cast<compile_cplus_instance *> (inst);
+ cplus_compile_program program (cplus_inst, gdbarch);
- add_code_footer (inst->scope, buf);
- code = ui_file_xstrdup (buf, NULL);
- do_cleanups (cleanup);
- return code;
+ return program.compute (input, expr_block, expr_pc);
}