diff: additions to samples/c_interface
Fergus Henderson
fjh at cs.mu.oz.au
Thu Jul 24 18:59:00 AEST 1997
Hi,
Can someone please review this?
samples/c_interface/simpler_c_calls_mercury:
Add new directory with new files README, c_main.c, Mmakefile,
and mercury_lib.m. These files demonstrate how to interface
to C using a C main() top-level rather than with a Mercury
main/2 top-level.
samples/c_interface/simpler_cplusplus_calls_mercury:
Same as above, but using C++ rather than C.
===================================================================
samples/c_interface/simpler_c_calls_mercury:
===================================================================
cvs diff: Diffing .
Index: Mmakefile
===================================================================
RCS file: Mmakefile
diff -N Mmakefile
--- /dev/null Tue Jan 1 15:00:00 1980
+++ Mmakefile Thu Jul 24 18:15:10 1997
@@ -0,0 +1,39 @@
+#-----------------------------------------------------------------------------#
+MAIN_TARGET=all
+
+depend: mercury_lib.depend
+all: c_main
+
+OBJECTS = c_main.o mercury_lib_init.o $(mercury_lib.os)
+
+c_main: $(OBJECTS)
+ $(ML) $(MLFLAGS) -o c_main $(OBJECTS) $(MLLIBS)
+
+#-----------------------------------------------------------------------------#
+
+# pass `-g' to the C compiler and linker, so we can use a debugger (e.g. gdb)
+MGNUCFLAGS=-g
+
+# tell Mercury that this the Mercury stuff we're building is a library,
+# not a main program
+C2INITFLAGS=--library
+
+# keep the `.c' files around, for debugging
+RM_C=:
+
+#-----------------------------------------------------------------------------#
+
+c_main.o: mercury_lib.h
+
+# to make mercury_lib.h, just compile mercury_lib.m;
+# the Mercury compiler will create mercury_lib.h as a side-effect.
+mercury_lib.h: mercury_lib.o
+
+# make sure that `mmake clean' removes c_main.o
+clean:
+ rm -f c_main.o mercury_lib.h
+
+realclean:
+ rm -f c_main
+
+#-----------------------------------------------------------------------------#
Index: README
===================================================================
RCS file: README
diff -N README
--- /dev/null Tue Jan 1 15:00:00 1980
+++ README Thu Jul 24 18:09:40 1997
@@ -0,0 +1,12 @@
+This directory contains an example program with a C main() function
+where C calls Mercury.
+
+This interface is simpler than having a Mercury main/2 call a c_main()
+function which then calls back Mercury. However, it is still not
+quite general enough -- we really ought to have MR_init_mercury() and
+MR_shutdown_mercury() functions to initialize and shutdown the Mercury
+Runtime engine, rather than the existing interface via mercury_main().
+
+So, the interface shown here should be considered as likely to
+change in future releases.
+
Index: c_main.c
===================================================================
RCS file: c_main.c
diff -N c_main.c
--- /dev/null Tue Jan 1 15:00:00 1980
+++ c_main.c Thu Jul 24 14:06:06 1997
@@ -0,0 +1,99 @@
+#include "mercury_lib.h" /* must come first */
+#include "init.h"
+
+#include <stdio.h>
+
+typedef Word MercuryList;
+
+static void print_list(MercuryList);
+
+int main(int argc, char **argv) {
+ char dummy;
+ Integer value;
+ MercuryList list;
+
+ printf("In main().\n");
+
+ /*
+ ** call mercury_main() to initialize the Mercury engine.
+ ** This must be done before we can call any Mercury predicates
+ ** or functions.
+ */
+ mercury_main(argc, argv, &dummy);
+
+ /*
+ ** call the C function foo_test(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(in) is semidet.
+ */
+ printf("foo_test(42) returns %s\n", foo_test(42) ? "TRUE" : "FALSE");
+ printf("foo_test(43) returns %s\n", foo_test(43) ? "TRUE" : "FALSE");
+
+ /*
+ ** call the C function one_foo(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(out) is cc_multi.
+ */
+ one_foo(&value);
+ printf("one_foo(&value) gives value = %ld\n", (long) value);
+
+ /*
+ ** call the C function foo_list(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(out) is multi.
+ */
+ printf("foo_list() = ");
+ foo_list(&list);
+ print_list(list);
+ printf("\n");
+
+ /*
+ ** call the C functions bar(), bar_test(), and bar_inverse(),
+ ** which are the C interfaces to the Mercury function bar/1
+ ** in the modes
+ ** :- mode bar(in) = out is det.
+ ** :- mode bar(out) = in is det.
+ ** :- mode bar(in) = in is det.
+ ** respectively.
+ */
+ printf("bar(100) = %ld\n", (long) bar(100));
+ printf("bar_test(100, 101) returns %s\n",
+ (bar_test(100, 101) ? "TRUE" : "FALSE"));
+ printf("bar_test(100, 200) returns %s\n",
+ (bar_test(100, 200) ? "TRUE" : "FALSE"));
+ bar_inverse(&value, 101);
+ printf("bar_inverse(&value, 101) gives value = %ld\n", (long) value);
+ bar_inverse(&value, 200);
+ printf("bar_inverse(&value, 200) gives value = %ld\n", (long) value);
+
+ if (baz(1, &value)) {
+ printf("baz(1, &value) returns TRUE with value = %ld\n",
+ (long) value);
+ } else {
+ printf("baz(100, &value) returns FALSE\n");
+ }
+ if (baz(100, &value)) {
+ printf("baz(100, &value) returns TRUE with value = %ld\n",
+ (long) value);
+ } else {
+ printf("baz(100, &value) returns FALSE\n");
+ }
+
+ printf("Returning from main().\n");
+ return 0;
+}
+
+static void print_list(MercuryList list) {
+ if (list_is_empty(list)) {
+ printf("[]");
+ } else {
+ printf("[");
+ printf("%ld", (long) list_head(list));
+ list = list_tail(list);
+ while (!list_is_empty(list)) {
+ printf(", %ld", (long) list_head(list));
+ list = list_tail(list);
+ }
+ printf("]");
+ }
+}
Index: mercury_lib.m
===================================================================
RCS file: mercury_lib.m
diff -N mercury_lib.m
--- /dev/null Tue Jan 1 15:00:00 1980
+++ mercury_lib.m Thu Jul 24 14:06:56 1997
@@ -0,0 +1,71 @@
+%-----------------------------------------------------------------------------%
+:- module mercury_lib.
+:- interface.
+:- import_module io.
+
+% main/2 is called by mercury_main() which is called on startup
+% this can be used as a hook for any actions needed on startup
+:- pred main(io__state::di, io__state::uo) is det.
+
+% a Mercury predicate with multiple modes
+:- pred foo(int).
+:- mode foo(in) is semidet.
+:- mode foo(out) is multi.
+
+% a Mercury function with multiple modes
+:- func bar(int) = int.
+:- mode bar(in) = out is det.
+:- mode bar(out) = in is det.
+:- mode bar(in) = in is semidet.
+
+% a semidet (i.e. partial) Mercury function
+:- func baz(int) = int.
+:- mode baz(in) = out is semidet.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+:- import_module std_util, int, list.
+
+% for this example, we don't need to perform any actions on startup
+main --> [].
+
+% well, this is just a silly example...
+foo(42).
+foo(53).
+foo(197).
+
+bar(X) = X + 1.
+
+baz(1) = 9.
+baz(2) = 16.
+baz(3) = 27.
+
+%-----------------------------------------------------------------------------%
+
+% The following code provides provides access to the Mercury predicate foo
+% from C code.
+
+:- pragma export(foo(in), "foo_test").
+
+:- pragma export(bar(in) = out, "bar").
+:- pragma export(bar(in) = in, "bar_test").
+:- pragma export(bar(out) = in, "bar_inverse").
+
+:- pragma export(baz(in) = out, "baz").
+
+ % The nondet mode of `foo' cannot be exported directly with
+ % the current Mercury/C interface. To get all solutions,
+ % must define a predicate which returns all the solutions of foo,
+ % and export it to C. We give it the name foo_list() in C.
+:- pred all_foos(list(int)::out) is det.
+:- pragma export(all_foos(out), "foo_list").
+all_foos(L) :- solutions((pred(X::out) is multi :- foo(X)), L).
+
+ % If we just want one solution, and don't care which one, then
+ % we can export a `cc_multi' (committed-choice nondeterminism)
+ % version of `foo'. We give it the name one_foo().
+:- pred cc_foo(int::out) is cc_multi.
+:- pragma export(cc_foo(out), "one_foo").
+cc_foo(X) :- foo(X).
+
+%-----------------------------------------------------------------------------%
===================================================================
samples/c_interface/simpler_cplusplus_calls_mercury:
===================================================================
cvs diff: Diffing .
Index: Mmakefile
===================================================================
RCS file: Mmakefile
diff -N Mmakefile
--- /dev/null Thu Jul 24 18:46:37 1997
+++ Mmakefile Thu Jul 24 18:49:34 1997
@@ -0,0 +1,59 @@
+#-----------------------------------------------------------------------------#
+
+MAIN_TARGET=all
+
+depend: mercury_lib.depend
+all: cpp_main
+
+#-----------------------------------------------------------------------------#
+
+.SUFFIXES: .cc
+.cc.o:
+ $(CXX) $(HACK) $(CXXFLAGS) -c $<
+
+CXX=mgnuc
+
+# Due to a bug in g++ 2.7, global register variables don't work in C++.
+# Hence we need to ensure that we don't include the global register
+# variable declarations. The following hack seems to do the trick.
+
+HACK= -DALPHA_REGS_H \
+ -DMIPS_REGS_H \
+ -DSPARC_REGS_H \
+ -DI386_REGS_H \
+ -DPA_REGS_H \
+ -DRS6000_REGS_H
+
+# pass `-g' to the C compiler and linker, so we can use a debugger (e.g. gdb)
+CXXFLAGS=-g
+MGNUCFLAGS=-g
+MLFLAGS=-g
+
+# tell Mercury that this the Mercury stuff we're building is a library,
+# not a main program
+C2INITFLAGS=--library
+
+# tell Mmake not to remove the `.c' files, so we can look at them (e.g. in gdb)
+RM_C=:
+
+OBJECTS = cpp_main.o mercury_lib_init.o $(mercury_lib.os)
+
+#-----------------------------------------------------------------------------#
+
+cpp_main: $(OBJECTS)
+ $(ML) $(MLFLAGS) -o cpp_main $(OBJECTS) $(MLLIBS)
+
+cpp_main.o: mercury_lib.h
+
+# to make mercury_lib.h, just compile mercury_lib.m;
+# the Mercury compiler will create mercury_lib.h as a side-effect.
+mercury_lib.h: mercury_lib.o
+
+# make sure that `mmake clean' removes c_main.o
+clean:
+ rm -f cpp_main.o mercury_lib.h
+
+realclean:
+ rm -f cpp_main
+
+#-----------------------------------------------------------------------------#
Index: README
===================================================================
RCS file: README
diff -N README
--- /dev/null Thu Jul 24 18:46:37 1997
+++ README Thu Jul 24 18:52:10 1997
@@ -0,0 +1,12 @@
+This directory contains an example program with a C++ main() function
+where C++ calls Mercury.
+
+This interface is simpler than having a Mercury main/2 call a cpp_main()
+function which then calls back Mercury. However, it is still not
+quite general enough -- we really ought to have MR_init_mercury() and
+MR_shutdown_mercury() functions to initialize and shutdown the Mercury
+Runtime engine, rather than the existing interface via mercury_main().
+
+So, the interface shown here should be considered as likely to
+change in future releases.
+
Index: cpp_main.cc
===================================================================
RCS file: cpp_main.cc
diff -N cpp_main.cc
--- /dev/null Thu Jul 24 18:46:37 1997
+++ cpp_main.cc Thu Jul 24 18:55:44 1997
@@ -0,0 +1,101 @@
+#include "mercury_lib.h" /* must come first */
+extern "C" {
+#include "init.h"
+}
+
+#include <stdio.h>
+
+typedef Word MercuryList;
+
+static void print_list(MercuryList);
+
+int main(int argc, char **argv) {
+ char dummy;
+ Integer value;
+ MercuryList list;
+
+ printf("In main().\n");
+
+ /*
+ ** call mercury_main() to initialize the Mercury engine.
+ ** This must be done before we can call any Mercury predicates
+ ** or functions.
+ */
+ mercury_main(argc, argv, &dummy);
+
+ /*
+ ** call the C function foo_test(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(in) is semidet.
+ */
+ printf("foo_test(42) returns %s\n", foo_test(42) ? "TRUE" : "FALSE");
+ printf("foo_test(43) returns %s\n", foo_test(43) ? "TRUE" : "FALSE");
+
+ /*
+ ** call the C function one_foo(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(out) is cc_multi.
+ */
+ one_foo(&value);
+ printf("one_foo(&value) gives value = %ld\n", (long) value);
+
+ /*
+ ** call the C function foo_list(), which is the interface
+ ** to the Mercury predicate foo/1 in mode
+ ** :- mode foo(out) is multi.
+ */
+ printf("foo_list() = ");
+ foo_list(&list);
+ print_list(list);
+ printf("\n");
+
+ /*
+ ** call the C functions bar(), bar_test(), and bar_inverse(),
+ ** which are the C interfaces to the Mercury function bar/1
+ ** in the modes
+ ** :- mode bar(in) = out is det.
+ ** :- mode bar(out) = in is det.
+ ** :- mode bar(in) = in is det.
+ ** respectively.
+ */
+ printf("bar(100) = %ld\n", (long) bar(100));
+ printf("bar_test(100, 101) returns %s\n",
+ (bar_test(100, 101) ? "TRUE" : "FALSE"));
+ printf("bar_test(100, 200) returns %s\n",
+ (bar_test(100, 200) ? "TRUE" : "FALSE"));
+ bar_inverse(&value, 101);
+ printf("bar_inverse(&value, 101) gives value = %ld\n", (long) value);
+ bar_inverse(&value, 200);
+ printf("bar_inverse(&value, 200) gives value = %ld\n", (long) value);
+
+ if (baz(1, &value)) {
+ printf("baz(1, &value) returns TRUE with value = %ld\n",
+ (long) value);
+ } else {
+ printf("baz(100, &value) returns FALSE\n");
+ }
+ if (baz(100, &value)) {
+ printf("baz(100, &value) returns TRUE with value = %ld\n",
+ (long) value);
+ } else {
+ printf("baz(100, &value) returns FALSE\n");
+ }
+
+ printf("Returning from main().\n");
+ return 0;
+}
+
+static void print_list(MercuryList list) {
+ if (list_is_empty(list)) {
+ printf("[]");
+ } else {
+ printf("[");
+ printf("%ld", (long) list_head(list));
+ list = list_tail(list);
+ while (!list_is_empty(list)) {
+ printf(", %ld", (long) list_head(list));
+ list = list_tail(list);
+ }
+ printf("]");
+ }
+}
Index: mercury_lib.m
===================================================================
RCS file: mercury_lib.m
diff -N mercury_lib.m
--- /dev/null Thu Jul 24 18:46:37 1997
+++ mercury_lib.m Thu Jul 24 18:20:37 1997
@@ -0,0 +1,71 @@
+%-----------------------------------------------------------------------------%
+:- module mercury_lib.
+:- interface.
+:- import_module io.
+
+% main/2 is called by mercury_main() which is called on startup
+% this can be used as a hook for any actions needed on startup
+:- pred main(io__state::di, io__state::uo) is det.
+
+% a Mercury predicate with multiple modes
+:- pred foo(int).
+:- mode foo(in) is semidet.
+:- mode foo(out) is multi.
+
+% a Mercury function with multiple modes
+:- func bar(int) = int.
+:- mode bar(in) = out is det.
+:- mode bar(out) = in is det.
+:- mode bar(in) = in is semidet.
+
+% a semidet (i.e. partial) Mercury function
+:- func baz(int) = int.
+:- mode baz(in) = out is semidet.
+
+%-----------------------------------------------------------------------------%
+:- implementation.
+:- import_module std_util, int, list.
+
+% for this example, we don't need to perform any actions on startup
+main --> [].
+
+% well, this is just a silly example...
+foo(42).
+foo(53).
+foo(197).
+
+bar(X) = X + 1.
+
+baz(1) = 9.
+baz(2) = 16.
+baz(3) = 27.
+
+%-----------------------------------------------------------------------------%
+
+% The following code provides provides access to the Mercury predicate foo
+% from C code.
+
+:- pragma export(foo(in), "foo_test").
+
+:- pragma export(bar(in) = out, "bar").
+:- pragma export(bar(in) = in, "bar_test").
+:- pragma export(bar(out) = in, "bar_inverse").
+
+:- pragma export(baz(in) = out, "baz").
+
+ % The nondet mode of `foo' cannot be exported directly with
+ % the current Mercury/C interface. To get all solutions,
+ % must define a predicate which returns all the solutions of foo,
+ % and export it to C. We give it the name foo_list() in C.
+:- pred all_foos(list(int)::out) is det.
+:- pragma export(all_foos(out), "foo_list").
+all_foos(L) :- solutions((pred(X::out) is multi :- foo(X)), L).
+
+ % If we just want one solution, and don't care which one, then
+ % we can export a `cc_multi' (committed-choice nondeterminism)
+ % version of `foo'. We give it the name one_foo().
+:- pred cc_foo(int::out) is cc_multi.
+:- pragma export(cc_foo(out), "one_foo").
+cc_foo(X) :- foo(X).
+
+%-----------------------------------------------------------------------------%
--
Fergus Henderson <fjh at cs.mu.oz.au> | "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh> | of excellence is a lethal habit"
PGP: finger fjh at 128.250.37.3 | -- the last words of T. S. Garp.
More information about the developers
mailing list