mirror of
https://github.com/Mercury-Language/mercury.git
synced 2025-12-14 21:35:49 +00:00
Estimated hours taken: 10
Introduce two new directories, trace and browser, containing libraries
holding the C and Mercury code of the debugger respectively. (Although
the browser directory does not have a browser in it yet, the browser
should soon become its biggest component.) Take the opportunity to
rename the existing libraries, for consistency.
After this change, the linking order becomes:
the object of the auto-generated init file
program object files
trace library (libmer_trace.a)
browser library (libmer_browser.a)
standard library (libmer_std.a)
runtime library (libmer_rt.a)
Boehm collector (libgc.a)
To avoid circularities, libraries cannot contain direct calls to
any routines that are defined in libraries (or object files) that
occur earlier in the above list. Any such calls must be made into
indirect calls via function pointers.
In particular, there was a circularity caused by the library calling
MR_trace() which invokes the tracer which in turn invokes the
library. This circularity was broken by having MR_trace(),
which is defined in the runtime, call the tracer indirectly via
a global variable named MR_trace_func_ptr. This global variable
is initialized by the auto-generated *_init.c file.
To avoid linking in the tracer even when it is not being used,
this global variable is only set to point to MR_trace_real()
if you're using a debugging grade or if c2init was invoked
with the `-t' flag. Otherwise it is set to MR_trace_fake()
which just prints an error message telling the user to
rebuild the executable with debugging enabled.
Makefile.DLLs:
Reserve random locations for the two new libraries. Whether they work
will be decided by testing on Windows.
Mmake.common.in:
Add variables naming the new directories, and create variables
naming the libraries.
Mmakefile:
Add targets for the new directories, and modify existing rules
as appropriate.
browser/Mmakefile:
Mmakefile for the new directory, modelled on library/Mmakefile.
browser/browser_library.m:
Umbrella file for the new directory, modelled on library/library.m.
{browser,library}/debugger_interface.m:
Moved this file from library to browser without change.
browser/help.m:
A new module for the help system of the debugger. Not yet used.
compiler/Mmakefile:
Update to refer to the new directories and libraries where
appropriate.
compiler/mercury_compile.m:
If we are doing tracing, then pass -t instead of -i to c2init.
compiler/modules.m:
When generating the .dep file, get the grade flags passed to c2init.
doc/Mmakefile:
Remove the special treatment of library/debugger_interface.m.
library/Mmakefile:
Update to refer to the new directories and libraries where
appropriate, and to conform to the new name of the library.
library/library.m:
Do not import debugger_interface.
profiler/Mmakefile:
Update to refer to the new directories and libraries where
appropriate.
runtime/Mmakefile:
Update to refer to the new directories and libraries where
appropriate, and to conform to the new name of the library.
Remove references to files being moved to the trace directory.
runtime/mercury_init.h:
Refer to the automatically generated dll header file by its new name
(renamed because the runtime library is renamed).
Add declarations to support the new global variable MR_trace_func_ptr.
runtime/mercury_memory_handlers.c:
runtime/mercury_memory_zones.c:
runtime/mercury_misc.c:
Remove inappropriate #includes of "mercury_trace.h", and substitute
a #include of "mercury_trace_base.h" if necessary.
{runtime,trace}/mercury_trace.[ch]:
{runtime,trace}/mercury_trace_external.[ch]:
{runtime,trace}/mercury_trace_internal.[ch]:
Move these files from the runtime to the trace directory.
The only changes are the removal from mercury_trace.h of declarations
added to runtime/mercury_trace_base.h, and the change from MR_trace
to MR_trace_real.
runtime/mercury_trace_base.[ch]:
Define MR_trace(), which does an indirect call through
MR_trace_func_ptr if the event should be traced.
Define MR_trace_fake, which just prints an error message.
Its address will be assigned to MR_trace_func_ptr if tracing
is not enabled.
Define the types needed by the signature of MR_trace.
Fix an old bug: s/MERCURY_TRACE_PERMANENT_H/MERCURY_TRACE_BASE_H/.
runtime/mercury_wrapper.[ch]:
Add the new global variable MR_trace_func_ptr.
scripts/c2init.in:
Add a new option, -t/--trace, which enables tracing by causing the
address of MR_trace_real to be assigned to MR_trace_func_ptr.
Have this option be implied by the grade. Also have the old option
-i (need initialization code) be implied by the grade, as well as by
-t.
scripts/ml.in:
Include the new libraries in the link command.
tests/debugger/Mmakefile:
Include -t instead of -i in the list of c2init options. (-t implies
-i.)
tools/bootcheck:
Copy and build the new directories as appropriate. The trace directory
is treated like the runtime, the browser directory is treated like the
library.
trace/Mmakefile:
Mmakefile for the new directory, modelled on runtime/Mmakefile.
util/mkinit.c:
Add the new option -t, as discussed above.
Mmakefile for the new directory, modelled on runtime/Mmakefile.
util/Mmakefile:
Specify -O0, since with the default optimization level, gcc on
cyclone ignores the assignment of TRUE to need_tracing when -t is
given (!!!).
282 lines
9.2 KiB
Mathematica
282 lines
9.2 KiB
Mathematica
%---------------------------------------------------------------------------%
|
|
% Copyright (C) 1998 The University of Melbourne.
|
|
% This file may only be copied under the terms of the GNU Library General
|
|
% Public License - see the file COPYING.LIB in the Mercury distribution.
|
|
%-----------------------------------------------------------------------------%
|
|
%
|
|
% File: help.m.
|
|
% Author: zs.
|
|
% Stability: low.
|
|
%
|
|
% This file provides a basic help system that stores information in help nodes
|
|
% which are organized as a tree structure of arbitrary depth.
|
|
%
|
|
% The help system consists of a list of help list entries. Each entry
|
|
% has a name, an index (an integer that determines its position in the list),
|
|
% and a help node. Each node contains text that should shed some light
|
|
% on the topic named by the node's entry. Each node also has an associated
|
|
% list of child entries; this list may of course be empty.
|
|
%
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- module help.
|
|
|
|
:- interface.
|
|
|
|
:- import_module list, io, std_util.
|
|
|
|
:- type help__system.
|
|
|
|
:- type help__path == list(string).
|
|
|
|
:- type help__res ---> help__ok ; help__error(string).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Initialize an empty help system.
|
|
:- pred help__init(help__system::out) is det.
|
|
|
|
% Add a node to the given help system, at the given path, and with
|
|
% the given name and index. If successful, return ok and the
|
|
% updated help system; if not, return an error message and the
|
|
% original help system.
|
|
:- pred help__add_help_node(help__system::in, help__path::in, int::in,
|
|
string::in, string::in, help__res::out, help__system::out) is det.
|
|
|
|
% Print the top-level help nodes. This should give an overview
|
|
% of the main topics for which help is available.
|
|
:- pred help__help(help__system::in, io__output_stream::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
% Print the help node at the given path. If there is none,
|
|
% print the top-level nodes.
|
|
:- pred help__path(help__system::in, help__path::in, io__output_stream::in,
|
|
help__res::out, io__state::di, io__state::uo) is det.
|
|
|
|
% Print all help nodes with the given name. If there are none,
|
|
% print the top-level nodes.
|
|
:- pred help__name(help__system::in, string::in, io__output_stream::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
% Return the type_info for the type help__system, for use by C code.
|
|
:- pred help__help_system_type(type_info::out) is det.
|
|
|
|
% Help interpret a help__res for C code.
|
|
:- pred help__result_is_error(help__res::in, string::out) is semidet.
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- implementation.
|
|
|
|
:- import_module int, string, require.
|
|
|
|
:- type help__system == list(help__entry).
|
|
|
|
:- type help__node
|
|
---> node(
|
|
help__text,
|
|
list(help__entry)
|
|
).
|
|
|
|
:- type help__text == string. % Should be one or more complete lines.
|
|
|
|
:- type help__entry
|
|
---> entry(
|
|
int, % This integer determines the position
|
|
% of the node in the node list. A node
|
|
% list is always sorted on this field.
|
|
string, % The name of the node, which should
|
|
% be one word or phrase. It must be
|
|
% unique within the node list, but
|
|
% need not be unique globally.
|
|
node
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pragma export(help__init(out), "ML_HELP_init").
|
|
:- pragma export(help__add_help_node(in, in, in, in, in, out, out),
|
|
"ML_HELP_add_help_node").
|
|
:- pragma export(help__help(in, in, di, uo), "ML_HELP_help").
|
|
:- pragma export(help__path(in, in, in, out, di, uo), "ML_HELP_path").
|
|
:- pragma export(help__name(in, in, in, di, uo), "ML_HELP_name").
|
|
:- pragma export(help__help_system_type(out), "ML_HELP_help_system_type").
|
|
:- pragma export(help__result_is_error(in, out), "ML_HELP_result_is_error").
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
help__init([]).
|
|
|
|
help__add_help_node(Sys0, Path, Index, Name, Text, Res, Sys) :-
|
|
Node = node(Text, []),
|
|
help__add_node(Sys0, Path, Index, Name, Node, Res, Sys).
|
|
|
|
:- pred help__add_node(help__system::in, help__path::in, int::in,
|
|
string::in, help__node::in, help__res::out, help__system::out) is det.
|
|
|
|
help__add_node(Nodes0, [Step | Steps], Index, Name, NewNode, Res, Nodes) :-
|
|
( help__one_path_step(Nodes0, Step, Entry0) ->
|
|
Entry0 = entry(EntryIndex, EntryName, EntryNode0),
|
|
EntryNode0 = node(Text, SubNodes0),
|
|
help__add_node(SubNodes0, Steps, Index, Name, NewNode,
|
|
Res, SubNodes),
|
|
EntryNode = node(Text, SubNodes),
|
|
Entry = entry(EntryIndex, EntryName, EntryNode),
|
|
help__replace_entry(Nodes0, Entry, Nodes)
|
|
;
|
|
string__append("invalid path component ", Step, Msg),
|
|
Res = help__error(Msg),
|
|
Nodes = Nodes0
|
|
).
|
|
help__add_node(Nodes0, [], Index, Name, Node, Res, Nodes) :-
|
|
(
|
|
list__member(Entry1, Nodes0),
|
|
Entry1 = entry(Index, _, _)
|
|
->
|
|
Res = help__error("entry with given index already exists"),
|
|
Nodes = Nodes0
|
|
;
|
|
list__member(Entry1, Nodes0),
|
|
Entry1 = entry(_, Name, _)
|
|
->
|
|
Res = help__error("entry with given name already exists"),
|
|
Nodes = Nodes0
|
|
;
|
|
Res = help__ok,
|
|
help__insert_into_entry_list(Nodes0, Index, Name, Node, Nodes)
|
|
).
|
|
|
|
:- pred help__insert_into_entry_list(list(help__entry)::in,
|
|
int::in, string::in, help__node::in, list(help__entry)::out) is det.
|
|
|
|
help__insert_into_entry_list([], Index, Name, Node, [Entry]) :-
|
|
Entry = entry(Index, Name, Node).
|
|
help__insert_into_entry_list([Head | Tail], Index, Name, Node, List) :-
|
|
Head = entry(HeadIndex, _, _),
|
|
( HeadIndex < Index ->
|
|
help__insert_into_entry_list(Tail, Index, Name, Node, NewTail),
|
|
List = [Head | NewTail]
|
|
;
|
|
Entry = entry(Index, Name, Node),
|
|
List = [Entry, Head | Tail]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
help__help(Sys, Stream) -->
|
|
help__print_entry_list(Sys, Stream).
|
|
|
|
help__name(Sys, Name, Stream) -->
|
|
help__search_entry_list(Sys, Name, 0, Count, Stream),
|
|
( { Count = 0 } ->
|
|
io__write_string("There is no such help topic.\n"),
|
|
help__help(Sys, Stream)
|
|
;
|
|
[]
|
|
).
|
|
|
|
:- pred help__search_entry_list(list(help__entry)::in, string::in,
|
|
int::in, int::out, io__output_stream::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
help__search_entry_list([], _, C, C, _) --> [].
|
|
help__search_entry_list([Entry | Tail], Name, C0, C, Stream) -->
|
|
{ Entry = entry(_, EntryName, Node) },
|
|
( { Name = EntryName } ->
|
|
% We print this node, but don't search its children.
|
|
help__print_node(Node, Stream),
|
|
{ C is C0 + 1 }
|
|
;
|
|
help__search_node(Node, Name, C0, C1, Stream),
|
|
help__search_entry_list(Tail, Name, C1, C, Stream)
|
|
).
|
|
|
|
:- pred help__search_node(help__node::in, string::in, int::in, int::out,
|
|
io__output_stream::in, io__state::di, io__state::uo) is det.
|
|
|
|
help__search_node(node(_, SubNodes), Name, C0, C, Stream) -->
|
|
help__search_entry_list(SubNodes, Name, C0, C, Stream).
|
|
|
|
help__path(Entries, Path, Stream, Result) -->
|
|
( { Path = [Step] } ->
|
|
( { help__one_path_step(Entries, Step, Entry) } ->
|
|
{ Entry = entry(_, _, EntryNode) },
|
|
{ EntryNode = node(Text, _) },
|
|
io__write_string(Stream, Text),
|
|
{ Result = help__ok }
|
|
;
|
|
{ string__append_list(["error at path component """,
|
|
Step, """"], Msg) },
|
|
{ Result = help__error(Msg) }
|
|
)
|
|
; { Path = [Step | Tail] } ->
|
|
( { help__one_path_step(Entries, Step, Entry) } ->
|
|
{ Entry = entry(_, _, EntryNode) },
|
|
{ EntryNode = node(_, SubEntries) },
|
|
help__path(SubEntries, Tail, Stream, Result)
|
|
;
|
|
{ string__append_list(["error at path component """,
|
|
Step, """"], Msg) },
|
|
{ Result = help__error(Msg) }
|
|
)
|
|
;
|
|
{ Result = help__error("the path does not go that deep") }
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred help__print_entry_list(list(help__entry)::in, io__output_stream::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
help__print_entry_list([], _) --> [].
|
|
help__print_entry_list([entry(_, _, Node) | Nodes], Stream) -->
|
|
help__print_node(Node, Stream),
|
|
help__print_entry_list(Nodes, Stream).
|
|
|
|
:- pred help__print_node(help__node::in, io__output_stream::in,
|
|
io__state::di, io__state::uo) is det.
|
|
|
|
help__print_node(node(Text, _Nodes), Stream) -->
|
|
io__write_string(Stream, Text).
|
|
% XXX help__print_entry_list(Nodes, Stream).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
:- pred help__one_path_step(list(help__entry)::in, string::in,
|
|
help__entry::out) is semidet.
|
|
|
|
help__one_path_step([Head | Tail], Name, Entry) :-
|
|
Head = entry(_, HeadName, _),
|
|
( HeadName = Name ->
|
|
Entry = Head
|
|
;
|
|
help__one_path_step(Tail, Name, Entry)
|
|
).
|
|
|
|
:- pred help__replace_entry(list(help__entry)::in, help__entry::in,
|
|
list(help__entry)::out) is det.
|
|
|
|
help__replace_entry([], _, _) :-
|
|
error("help__replace_entry: entry to be replaced not found").
|
|
help__replace_entry([Head | Tail], Entry, List) :-
|
|
Head = entry(HeadIndex, _, _),
|
|
Entry = entry(EntryIndex, _, _),
|
|
( HeadIndex = EntryIndex ->
|
|
List = [Entry | Tail]
|
|
;
|
|
help__replace_entry(Tail, Entry, NewTail),
|
|
List = [Head | NewTail]
|
|
).
|
|
|
|
%-----------------------------------------------------------------------------%
|
|
|
|
help__help_system_type(Type) :-
|
|
help__init(HelpInit),
|
|
Type = type_of(HelpInit).
|
|
|
|
help__result_is_error(help__error(Msg), Msg).
|
|
|
|
%-----------------------------------------------------------------------------%
|