home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-387-Vol-3of3.iso / p / plbin.zip / pl / library / online.pl < prev    next >
Text File  |  1992-05-26  |  10KB  |  499 lines

  1. /*  online.pl,v 1.1.1.1 1992/05/26 11:51:36 jan Exp
  2.  
  3.     Copyright (c) 1990 Jan Wielemaker. All rights reserved.
  4.     jan@swi.psy.uva.nl
  5.  
  6.     Purpose: Index online manual
  7. */
  8.  
  9. :- module(online,
  10.     [ online_index/2
  11.     , online_index/0
  12.     ]).
  13.  
  14. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  15. This library module creates the index file for the  online  manual.   By
  16. default, as expected by help.pl, the manual is called MANUAL and resides
  17. in the Prolog library directory.  online_index[0,2] parses this file and
  18. creates the index file help_index.pl.  Toplevel:
  19.  
  20. online_index/0
  21.     Equivalent to online_index($MANUAL, $INDEX).  The two variables
  22.     are taken from the Unix environment.
  23.  
  24. online_index(+Manual, +Index)
  25.     Create index for `Manual' and write the output on `Index'.
  26.  
  27. SEE ALSO
  28.  
  29.       - The program `online' in the manual source directory
  30.       - help.pl which implements the online manual on top of this.
  31. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  32.  
  33. :- dynamic
  34.     page/2,
  35.     predicate/5,
  36.     function/3,
  37.     section/4,
  38.     summary/3,
  39.     end_offset/1.
  40.  
  41. online_index :-
  42.     online_index('$MANUAL', '$INDEX').
  43.  
  44. online_index(In, Out) :-
  45.     parse_summaries('summary.doc'),
  46.     open(In, read, in),
  47.     read_index,
  48.     close(in),
  49.     open(Out, write, out),
  50.     write_manual,
  51.     close(out).
  52.  
  53. %    write_manual
  54. %    Write the index file (using the asserted data) to stream `out'.
  55.  
  56. write_manual :-
  57.     format(out, '/*  @(*) help_index.pl~n~n', []),
  58.     format(out, '    Generated by online_index/0~n~n', []),
  59.     format(out, '    Purpose: Index to file online_manual~n', []),
  60.     format(out, '*/~n~n', []),
  61.     format(out, ':- module(help_index,~n', []),
  62.     format(out, '    [ predicate/5~n', []),
  63.     format(out, '    , section/4~n', []),
  64.     format(out, '    , function/3~n', []),
  65.     format(out, '    ]).~n~n', []),
  66.     list(predicate, 5),
  67.     list(section, 4),
  68.     list(function, 3).
  69.  
  70. list(Name, Arity) :-
  71.     functor(Head, Name, Arity),
  72.     format(out, '%   Predicate ~w/~w~n~n', [Name, Arity]),
  73.     Head,
  74.         format(out, '~q.~n', Head),
  75.     fail.
  76. list(_, _) :-
  77.     format(out, '~n~n', []).
  78.  
  79. %    read_index/0
  80. %    Create an index in the prolog database.  Input is read from stream
  81. %    `in'
  82.  
  83. read_index :-
  84.     flag(last, _, false),
  85.     repeat,
  86.         (   flag(last, true, true)
  87.         ->    character_count(in, EndOffset),
  88.         End is EndOffset - 1,
  89.         assert(end_offset(End)), !
  90.         ;   character_count(in, Offset),
  91.         read_page(Page),
  92.         character_count(in, EndOffset),
  93.         End is EndOffset - 1,
  94.             identify_page(Offset, End, Page),
  95.             fail
  96.         ),
  97.     update_offsets.
  98.  
  99. %    read_page(-Page)
  100. %    Read the next page from stream `in'.  Pages are separeted (by
  101. %    dvi2tty) by ^L.  The last page is ended by the end-of-file. 
  102.  
  103. read_page([C|R]) :-
  104.     get0(in, C),
  105.     (   C == -1
  106.     ->  flag(last, _, true),
  107.         fail
  108.     ;   C \== 12
  109.     ), !,
  110.     read_page(R).
  111. read_page([]).
  112.     
  113. %    identify_page(+StartOffset, +EndOffset, +Page)
  114. %    Parse the start of `Page' and record it in the database as a
  115. %    page describing a certain type of data as well as were it starts
  116. %    and ends.
  117.  
  118. identify_page(Offset, EndOffset, Page) :-
  119.     parse(page(Type, TextOffset), Page, _),
  120. %    format('~w~n', page(Type, offsets(Offset, EndOffset, TextOffset))),
  121.     assert(page(Type, offsets(Offset, EndOffset, TextOffset))).
  122.  
  123. parse(page(Type, Offset)) -->
  124.     skip_blank_lines(0, Offset),
  125.     get_line(Line),
  126.     type(Line, Type).
  127.  
  128. skip_blank_lines(Sofar, Offset) -->
  129.     blank_line(Line), !,
  130.     {   length(Line, L),
  131.         NextSofar is Sofar + L
  132.     },
  133.     skip_blank_lines(NextSofar, Offset).
  134. skip_blank_lines(Offset, Offset) -->
  135.     { true }.
  136.  
  137. blank_line([10]) -->
  138.     char(10), !.
  139. blank_line([C|R]) -->
  140.     blank(C), !,
  141.     blank_line(R).
  142.  
  143. get_line([]) -->
  144.     char(10), !.
  145. get_line([C|R]) -->
  146.     char(C),
  147.     get_line(R).
  148.  
  149. %    Typing on the first line
  150.  
  151. type(Line, predicate(Name, Arity, Summary)) -->
  152.     { predicate_line(Line, Name, Arity),
  153.       (   summary(Name, Arity, Summary)
  154.       ->  true
  155.       ;   format('ERROR: No summary for ~w/~w~n', [Name, Arity]),
  156.           Summary = ''
  157.       )
  158.         }, !.
  159. type(Line, section(Index, Name)) -->
  160.     { section_line(Line, Index, Name) }, !.
  161. type(Line, section(Index, Name)) -->
  162.     { chapter_line(Line, Index) }, !,
  163.     skip_blank_lines(0, _),
  164.     get_line(NameLine),
  165.     { name(Name, NameLine)}.
  166. type(Line, function(Name)) -->
  167.     { function_line(Line, Name) }, !.
  168. type(Line, unknown) -->
  169.     { % trace,
  170.       format('Unidentified: ~s~n', [Line])
  171.     }.
  172. type(_, _) -->
  173.     { fail }.
  174.  
  175. %    Identify line as describing a predicate
  176.  
  177. predicate_line(Line, Name, Arity) :-
  178.     predicate_line(Name, Arity, Line, []).
  179.  
  180. predicate_line(Name, Arity) -->
  181.     optional_directive,
  182.     atom(Name),
  183.     arguments(Arity), !,
  184.     {   (   functor(T, Name, Arity),
  185.         user:current_predicate(_, T)
  186.         ;   current_arithmetic_function(T)
  187.         )
  188.     ->  true
  189.     ;   format('Not a defined predicate: ~w/~w~n', [Name, Arity])
  190.     }.
  191. predicate_line(Name, 1) -->            % prefix operator
  192.     atom(Name),
  193.     skip_blanks,
  194.     arg,
  195.     optional_dots, !.
  196. predicate_line(Name, 2) -->            % infix operator
  197.     skip_blanks,
  198.     arg,
  199.     skip_blanks,
  200.     atom(Name),
  201.     skip_blanks,
  202.     arg,
  203.     skip_blanks, !.
  204. predicate_line(Name, 0) -->
  205.     atom(Name).
  206.  
  207. optional_directive -->
  208.     starts(":- "), !,
  209.     skip_blanks.
  210. optional_directive -->
  211.     { true }.
  212.  
  213. atom(Name) -->
  214.     lower_case(C1), !,
  215.     alphas(Cs),
  216.     { name(Name, [C1|Cs]) }.
  217. atom(Name) -->
  218.     symbol(C1), !,
  219.     symbols(Cs),
  220.     { name(Name, [C1|Cs]) }.
  221. atom(Name) -->
  222.     single(S),
  223.     { name(Name, [S]) }.
  224.  
  225. alphas([C|R]) -->
  226.     alpha(C), !,
  227.     alphas(R).
  228. alphas([]) -->
  229.     { true }.
  230.  
  231. arguments(Args) -->
  232.     char(0'(),
  233.     args(0, Args),
  234.     char(0')).
  235.  
  236. args(N, Args) -->
  237.     skip_blanks,
  238.     arg,
  239.     { NN is N + 1 }, !,
  240.     optional(0',),
  241.     args(NN, Args).
  242. args(Args, Args) -->
  243.     { true }.
  244.  
  245. optional_dots -->
  246.     skip_blanks,
  247.     starts(", ..."),
  248.     skip_blanks.
  249. optional_dots -->
  250.     { true }.
  251.  
  252. arg -->
  253.     input_output,
  254.     alphas(_),
  255.     optional(0'/),
  256.     optional_input_output,
  257.     alphas(_), !.
  258. arg -->
  259.     starts("[]").
  260.  
  261. input_output -->
  262.     char(C),
  263.     { memberchk(C, "+-?") }.
  264.  
  265. optional_input_output -->
  266.     input_output, !.
  267. optional_input_output -->
  268.     { true }.
  269.  
  270. %    Identify line as describing a function
  271.  
  272. function_line(Line, Name) :-
  273.     function_line(Name, Line, _).
  274.  
  275. function_line(Name) -->
  276.     function_type,
  277.     function_name(Name).
  278.  
  279. function_type -->
  280.     skip_blanks,
  281.     alpha(_),
  282.     alpha(_),
  283.     atom(_),
  284.     skip_blanks,
  285.     optional(0'(),
  286.     optional(0'*),
  287.     skip_blanks.
  288.  
  289. function_name(Name) -->
  290.     char(0'P),
  291.     char(0'L),
  292.     char(0'_),
  293.     atom(Rest),
  294.     { concat('PL_', Rest, Name) }.
  295.  
  296. %    Identify line as starting a section
  297.  
  298. section_line(Line, Index, Name) :-
  299.     section_index(Index, Line, S),
  300.     name(Name, S).
  301.  
  302. section_index([C|R]) -->
  303.     skip_blanks,
  304.     number(C),
  305.     subindex(R),
  306.     skip_blanks.
  307.  
  308. subindex([S|R]) -->
  309.     char(0'.), !,
  310.     number(S),
  311.     subindex(R).
  312. subindex([]) -->
  313.     { true }.
  314.  
  315. number(N) -->
  316.     digits(D),
  317.     { D = [_|_] },
  318.     { name(N, D) }.
  319.  
  320. digits([D|R]) -->
  321.     digit(D), !,
  322.     digits(R).
  323. digits([]) -->
  324.     { true }.
  325.  
  326. %    Identify line as starting a chapter
  327.  
  328. chapter_line(Line, Index) :-
  329.     chapter_line(Index, Line, []).
  330.  
  331. chapter_line([Chapter]) -->
  332.     starts("Chapter"),
  333.     skip_blanks,
  334.     number(Chapter).
  335.  
  336. starts([]) -->
  337.     !.
  338. starts([C|R]) -->
  339.     char(C),
  340.     starts(R).
  341.  
  342. %    PRIMITIVES.
  343.  
  344. skip_blanks -->
  345.     blank(_), !,
  346.     skip_blanks.
  347. skip_blanks -->
  348.     { true }.
  349.  
  350. blank(C) -->
  351.     char(C),
  352.     { blank(C) }.
  353.     
  354. blank(9).
  355. blank(32).
  356.  
  357. optional(C) -->
  358.     char(C), !.
  359. optional(_) -->
  360.     { true }.
  361.  
  362. symbols([C|R])-->
  363.     symbol(C), !,
  364.     symbols(R).
  365. symbols([]) -->
  366.     { true }.
  367.  
  368. symbol(S) -->
  369.     char(S),
  370.     { memberchk(S, "\#$&*+-./:<=>?@^`~") }.
  371.  
  372. single(S) -->
  373.     char(S),
  374.     { memberchk(S, "!,;|") }.
  375.  
  376. digit(D) -->
  377.     char(D),
  378.     { between(0'0, 0'9, D) }.
  379.  
  380. lower_case(C) -->
  381.     char(C),
  382.     { between(0'a, 0'z, C) }.
  383.  
  384. upper_case(C) -->
  385.     char(C),
  386.     { between(0'A, 0'Z, C) }.
  387.  
  388. alpha(C) -->
  389.     lower_case(C), !.
  390. alpha(C) -->
  391.     upper_case(C), !.
  392. alpha(C) -->
  393.     digit(C), !.
  394. alpha(0'_) -->
  395.     char(0'_).
  396.  
  397. char(C, [C|L], L).
  398.     
  399. %    update_offsets
  400.  
  401. update_offsets :-
  402.     page(section(Index, Name), offsets(F, _, O)),
  403.         (   next_index(Index, Next),
  404.         page(section(Next, _), offsets(To,_,_))
  405.         ->  true
  406.         ;    end_offset(To)
  407.         ),
  408.         From is F + O,
  409.         assert(section(Index, Name, From, To)),
  410.     fail.
  411. update_offsets :-
  412.     page(predicate(Name, Arity, Summary), offsets(F, T, O)),
  413.         From is F + O,
  414.         assert(predicate(Name, Arity, Summary, From, T)),
  415.     fail.
  416. update_offsets :-
  417.     page(function(Name), offsets(F, T, O)),
  418.         From is F + O,
  419.         assert(function(Name, From, T)),
  420.     fail.
  421. update_offsets.
  422.  
  423. %    next_index(+This, -Next)
  424. %    Return index of next section.  Note that the next of [3,4] both
  425. %    can be [3-5] and [4].
  426.  
  427. next_index(L, N) :-
  428.     (    reverse(L, [Last|Tail])
  429.     ;    reverse(L, [_,Last|Tail])
  430.     ),
  431.     Next is Last + 1,
  432.     reverse([Next|Tail], N).
  433.  
  434.     
  435.         /********************************
  436.         *       PARSE SUMMARIES         *
  437.         ********************************/
  438.     
  439. %    parse_summaries(+File)
  440. %    Reads the predicate summary chapter of the manual to get the
  441. %    summary descriptions.  Normally this file is called summary.doc
  442.  
  443. parse_summaries(File) :-
  444.     open(File, read, in),
  445.     parse_summaries,
  446.     close(in).
  447.  
  448. parse_summaries :-
  449.     repeat,
  450.     read_line(Line),
  451.     (   Line == end_of_file
  452.     ->  !
  453.     ;   do_summary(Line),
  454.         fail
  455.     ).
  456.  
  457. read_line(L) :-
  458.     get0(in, C),
  459.     (   C == -1
  460.     ->  L = end_of_file
  461.     ;   C == 10
  462.     ->  L = []
  463.     ;   L = [C|R],
  464.         read_line(R)
  465.     ).
  466.  
  467. do_summary(Line) :-
  468.     parse_summary(Name, Arity, Summary, Line, []), !,
  469.     assert(summary(Name, Arity, Summary)).
  470. do_summary(Line) :-
  471. %    trace,
  472.     format('Failed to parse "~s"~n', [Line]).
  473. do_summary(_) :- fail.
  474.  
  475. parse_summary(Name, Arity, Summary) -->
  476.     starts("\verb$"),
  477.     name_arity(Name, Arity),
  478.     char(0'$),
  479.     skip_blanks,
  480.     starts("\>"),
  481.     skip_blanks,
  482.     string(S),
  483.     skip_blanks,
  484.     starts("\\"),
  485.     skip_blanks,
  486.     { name(Summary, S) }.
  487.  
  488. name_arity(Name, Arity) -->
  489.     string(S),
  490.     char(0'/),
  491.     number(Arity), !,
  492.     { name(Name, S) }.
  493.  
  494. string("") -->
  495.     { true }.
  496. string([C|R]) -->
  497.     char(C),
  498.     string(R).
  499.