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