@@ -1,1081 +1,1081 @@ -% comphelp.red: -% -% first part of the REDUCE help compiler: syntax analysis -% and structure generation. -% -% the second part contains target specific code. -% -% Author: Herbert Melenk, ZIB Berlin -% -% November 1992 -% - -symbolic; - -fluid '(char!* infile!* outfile!* !*windows !*test !*myeof); -fluid '(printfunction!* sect_count endchar current_node!*); -fluid '(!*verbatim !*sqbkt !*opennode currentfont topiccount!*); -fluid '(courier helvetica outc beginstack filestack level); -fluid '(nodechain undo match_point_lft match_point_rgt); -fluid '(run!* dir_src); -fluid '(aliases package); -fluid '(section_list regoup_sections); -fluid '(help_gensym_count); - - -run!* := 0; - -% !*test := t; -regoup_sections := nil; - -%------------------------------------------------------------ -% -% MAIN PROGRAM -% -%------------------------------------------------------------ - -symbolic procedure job(infile,outfile); - begin scalar !*raise, !*lower; - help_gensym_count := 1; - section_list := nil; - !*myeof := nil; - if getenv "echo" then !*echo:=t; - run!* := run!* + 1; - reset(); terpri(); - if run!* = 2 then update_labels(); - !*opennode := nil; - sect_count:=1; - topiccount!* := 0; - printfunction!*:=nil; - if infile!* then close infile!*; - if outfile!* then close outfile!*; - infile!*:=open(bldmsg("%w%w",dir_src,infile),'input); - outfile!*:=open(outfile,'output); - channellinelength(outfile!*,200); - initoutput(); - newfont helvetica; - mainloop(); - close_section 'document; - write_sections(); - fontoff(); - endoutput(); - close infile!*; - infile!* :=nil; - if outfile!* then close outfile!*; - outfile!*:=nil; - % printstruct(); - end; - -%------------------------------------------------------------ -% -% file input -% -%------------------------------------------------------------ - -fluid '(oldchar !*myecho !*myeof); - -!*myecho := nil; -!*myeof := nil; - -symbolic procedure rdch(); rdchr0(nil); - -symbolic procedure rdch!*(); rdchr0(t); - -symbolic procedure rdchr0(q); - if !*myeof then !$eof!$ else - if oldchar then <> where old = oldchar - else - <>; - % if we have found a token, eat up the following blanks. -% if cdr tok then while c='! do c:=rdch(); % ACH: loses a char. - if null cdr tok then return nil; - tok := compress reverse('!".tok); - return intern tok; -end; - -symbolic procedure mystring(); - begin scalar tok,c; - while digit(c:=rdch()) or liter c or c='! or - (endchar and c neq endchar) do - tok:=c.tok; - return reversip(tok); -end; - -symbolic procedure mystring2(); - % read string util }, but ignore \} - begin scalar tok,c; - while (c:=rdch()) neq '!} do tok:=c.tok; - return reversip(tok); -end; - -symbolic procedure mystring2!](); - % read string util ], but ignore \} - begin scalar tok,c; - while (c:=rdch!*()) neq '!] do tok:=c.tok; - return reversip(tok); -end; - -symbolic procedure mystring_nodename(); - % read node name, eventually updating the name translation table - % for entries like "\begin{Command}[percent]{%}" - % read string util }, but ignore \} - begin scalar tok,c,alt; - c:=myskipl '(!{ ![); - if c='![ then - << alt := mystring2!](); myskip '!{ >>; - while (c:=rdch!*()) neq '!} do tok:=c.tok; - tok := reversip tok; - if alt then aliases := (alt . tok) . aliases; - return alt or tok; -end; - -symbolic procedure mystring3(); - begin scalar tok,c; - loop: - c:=rdch(); - if c='!\ then <>; - if c= '!} then return reversip(tok); - tok := c.tok; goto loop; -end; - -symbolic procedure raisestring(s); - begin scalar n; - return for each c in s collect - if (n:=id2int c)>95 then - int2id(n-32) else c; - end; - -symbolic procedure lowerstring(s); - begin scalar n; - return for each c in s collect - if liter c and (n:=id2int c)<95 then - int2id(n+32) else c; - end; - -symbolic procedure mycompress u; - compress reversip('!" . reverse('!" . u)); - -%---------------------- main loop ---------------------------- - -symbolic procedure mainloop(); - begin scalar u,c,tok,f,undo; - loop: - c:=rdch(); - if c=!$eof!$ then goto finis; - if endchar and c=endchar then - <>; - if c='!{ then - << - begin scalar endchar; - endchar := '!}; - mainloop(); - end; - goto loop; - >>; - if c='!\ then - <>; - if tok='documentstyle then - <> - else - if tok='end then - <>; - if u neq car beginstack then - <>; - if !*test then printf(" (main pop %w)",beginstack); - beginstack := cdr beginstack; - goto finis>> - else - if(f:=get(tok,'act)) then - << - if !*test then <>; - apply1(f,tok); - if flagp(f,'simple) then oldchar := char!*; - goto loop; - >> - else - printf("**** unknown token: %w %n",tok); - >>; - char: - if printfunction!* then apply1(printfunction!*,c); - goto loop; - finis: - for each u in undo do eval(u); - end; - -%-----------------\input{...} \include{ ...}----------------- - -symbolic procedure include(u); - begin scalar file,fname,fname1,endchar; - endchar := '!}; - fname:=mycompress mystring(); - if fname = "intro" then return; - fname:=bldmsg("%w%w",dir_src,fname); - endchar := nil; - file:=errorset({'open,mkquote fname,mkquote 'input},nil,nil); - if not errorp file then goto found; - fname1:=bldmsg("%w.tex",fname); - file:=errorset({'open,mkquote fname1,mkquote 'input},nil,nil); - if not errorp file then goto found; - printf("***** cannot open file >%w< resp. >%w< %n",fname,fname1); - return nil; - found: - if fname1 then fname := fname1; - filestack:=infile!*.filestack; - infile!* :=car file; - terpri(); prin2 "--- input file "; prin2t fname; - mainloop(); - terpri(); prin2 "--- return from file "; prin2t fname; - close infile!*; - !*myeof := nil; - infile!*:=car filestack; - filestack := cdr filestack; - end; - -put('input,'act,'include); -put('include,'act,'include); - -put('makeindex,'act,'null); -put('tt,'act,'null); - -%-------------------section hierarchy ----------------------- - -symbolic procedure print_indent(); - if numberp level then for i:=1:level do prin2 " "; - -fluid '(record act_rec node_count); - -node_count := 0; - -smacro procedure type(u); car u; -smacro procedure seq(u); cadr u; -smacro procedure lab(u); caddr u; -smacro procedure count(u); cadddr u; -smacro procedure name(u);car cddddr u; - -symbolic procedure reset(); - << - record := - { - % type seq lab nr name - {'document, nil, "main_index", - 1, '(!T !o !p)}, -% 1, "Top"}, - {'section, nil, nil, 1, nil}, - {'subsection,nil, nil, 1, nil}, - {'subsubsection,nil, nil, 1, nil}}; - act_rec:= car record; - >>; - -symbolic procedure sectappend r; - % link tail from next record to cont of first one - car cdar r :=(cdr cadr r) . seq car r; - -%-------------------- section ------------------------------- - - -symbolic procedure section(s); - begin scalar name; - current_node!* := nil; - name:=mystring2(); - close_section(s); - open_section(s,name); - end; - -symbolic procedure close_section(s); - begin scalar r; - r:=record; - while r and caar r neq s do r:= cdr r; - if null r then error({"record empty",s},99); - for each u in reverse r do close_section1 u; - end; - -symbolic procedure close_section1(rec); - if name rec then - begin - if !*windows then - << print_indent(); reporttopic(" section end: "); - terpri(); - >>; - if regoup_sections then - section_list := append(rec,nil) . section_list - else - write_section(rec); - cdr rec:={nil,nil,0,nil}; - end; - -symbolic procedure write_sections(); - for each s in section_list do write_section s; - -symbolic procedure write_section(rec); - if name rec then - begin - if !*opennode then emit_node_separator(); - !*opennode:=nil; - emit_dir_new(); - emit_dir_label(lab rec); - emit_dir_title name rec; - emit_dir_browse('index,count rec); - emit_dir_key(name rec); - print_bold name rec; - emit_dir_header(); - for each x in reverse seq rec do - make_dir_entry (nil.x); - emit_dir_separator(); - end; - -symbolic procedure make_dir_entry rec; - emit_dir_entry(name rec,lab rec); - -symbolic procedure help_gensym(); - compress ('!g . explode2 (help_gensym_count := help_gensym_count+1)); - -symbolic procedure open_section(s,n); - begin scalar r; - sect_count:=sect_count+1; - r:= record; - while r and cdr r and caadr r neq s do r:=cdr r; - if null r then error({"record empty",s},99); - % initialize new section and link to parent - if not !*windows then n:=append(n, '(! !s !e !c !t !i !o !n)); - cdr cadr r:={nil,help_gensym(),sect_count,n}; - sectappend r; - r:= cadr r; - level := if s='section then 0 else - if s='subsection then 1 else - if s='subsubsection then 2 else 3; - print_indent(); - for each c in lowerstring explode2 s do prin2 c; - prin2 " "; - prin2 count r; prin2 " "; - prin2 lab r; prin2 " "; - mapc(name r,'prin2); terpri(); - act_rec := r; - base_new_dir name r; - level := if s='section then 1 else - if s='subsection then 2 else - if s='subsubsection then 3 else 4; - end; - -put('section,'act,'section); -put('subsection,'act,'section); -put('subsubsection,'act,'section); - - -%------------------- begin-end contexts --------------------------- - -symbolic procedure beg(u); - begin scalar tok,f,w; - tok:=mytoken(t); - for each c in beginstack do w:=w or (get(c,'context)='node); - if w and 'node=get(tok,'context) then - <>; - if !*test then <>; - if !*test then printf(" (push %w)",tok); - beginstack := tok.beginstack; - f:=get(tok,'context); - if f then apply1(f,tok) else - <>; - end; - -put('begin,'act,'beg); - -symbolic procedure mmain(u); mainloop(); - -put('document,'context,'mmain); - -%------------------- generate unique labels ---------------------- - -fluid '(labels!* l_list name_trans); - -symbolic procedure clean_name u; - if null u then nil else - if car u memq '(!- !, !? !* !> !< !. ! ) - then '!_ . clean_name cdr u else - car u . clean_name cdr u; - - -name_trans :='( - ((!,) . COMMA_sign) - ((!.) . DOT_sign) - ((!;) . SEMICOLON_sign) - ((!%) . PERCENT_sign) - ((!$) . DOLLAR_sign) - ((!: !=) . ASSIGN_sign) - ((!=) . EQUAL_sign) - ((!+) . PLUS_sign) - ((!-) . MINUS_sign) - ((!*) . TIMES_sign) - ((!/) . SLASH_sign) - ((!* !*) . POWER_sign) - ((!$ !> != !$) . GEQ_sign) - ((!> !=) . GEQ_sign) - ((!>) . GREATER_sign) - ((!$ !< != !$) . LEQ_sign) - ((!< != ) . LEQ_sign) - ((!<) . LESS_sign) - ((!< !<) . BLOCK)); - - -symbolic procedure make_label(name, type, alias); - begin scalar u,s,w,uname; - uname := raisestring name; - if !*windows then - << alias := clean_name alias; - name := clean_name name>>; - s := uname . type; - u := assoc (s,labels!*); - if u and run!* = 1 then - <>; - if u then return cadr u; - labels!* := (s.(w:=alias.name.type)). labels!*; - if not member(uname,l_list) then - l_list := uname . l_list; - return car w; - end; - -symbolic procedure get_label name; - (if l then car l) where l=get_label1 name; - -symbolic procedure patch_ u; - if null u then nil else - if car u = '!_ then '!\ . '!_ . patch_ cdr u - else car u . patch_ cdr u; - -symbolic procedure get_label1 name; - begin scalar u,uname; - uname := raisestring name; - u := get_label2 uname or get_label2 patch_ uname; - if null u and (run!* > 1) then - <>; - return if u then cdr u else nil; - end; - -symbolic procedure get_label2 uname; - begin scalar u,uname; - u := assoc((uname . 'operator),labels!*) - or assoc((uname . 'function),labels!*) - or assoc((uname . 'switch),labels!*) - or assoc((uname . 'statement),labels!*) - or assoc((uname . 'command),labels!*) - or assoc((uname . 'declaration),labels!*) - or assoc((uname . 'variable),labels!*) - or assoc((uname . 'type),labels!*) - or assoc((uname . 'constant),labels!*) - or assoc((uname . 'concept),labels!*) - or assoc((uname . 'package),labels!*) - or assoc((uname . 'introduction),labels!*); - return u; - end; - -symbolic procedure update_labels(); - % for unique names use the name as label. - begin scalar new,old; - terpri(); - prin2t "------ updating node labels -----"; - for each p in l_list do - if (p:=get_label1 p) then - <>; - prin2t "------ updating done ------------"; - end; - -%------------------- nodes ------------------------------------ - -symbolic procedure node(type); - begin scalar name,name2,rname,type2,name3,rec,type3,name4,label; - scalar altname,alias; - printfunction!* := 'textout; - if !*opennode then emit_node_separator(); - !*opennode:=t; - % myskip '!{; - name:=mystring_nodename(); - if altname:=assoc(name,name_trans) then - name := explode2 cdr altname; -% alias := if !*windows and assoc(name,aliases) then -% cdr assoc(name,aliases); - alias := if assoc(name,aliases) then - cdr assoc(name,aliases); - type3 := lowerstring (type2:=explode2 type); - name2 :=type . '! . (rname:=raisestring name); - name3 := append(type3,'! . name); - name4 := append(name, '! . type3); - label := make_label(name,type,name4); - rec := {'node, - nil, - label, - node_count:=add1 node_count, - name4}; - car cdr act_rec:= cdr rec . seq act_rec; - fonton(); - print_indent(); - mapc(name3,'prin2); reporttopic(" "); terpri(); - emit_node_label(lab rec); - emit_node_title(lab rec,name,type); - emit_node_browse(lab act_rec,count rec); - emit_node_keys(name4); - current_node!* := name4; - emit_hidden_node_key(type3); - emit_hidden_node_key(name rec); - % header line; - myterpri(); - if alias then <>; - print_bold rname; - if type2 neq '(C O N C E P T) then - << print_tab(); print_tab(); print_tab(); print_tab(); - print_bold type2; - >>; - print_newline(); second_newline(); - mainloop (); - end; - -put('switch,'context,'node); -put('variable,'context,'node); -put('operator,'context,'node); -put('function,'context,'node); -put('command,'context,'node); -put('statement,'context,'node); -put('declaration,'context,'node); -put('concept,'context,'node); -put('introduction,'context,'node); -put('package,'context,'node); -put('type,'context,'node); -put('constant,'context,'node); - - -symbolic procedure part(type); - begin - outc:='! ; - if type='examples or type='syntax or type='related - then par_heading(type) else - if type='bigexample then par_heading('example); - - if type='bigexample or type='verbatim then return vpart(type) else - if type='examples then return examples_part(type); - if type='syntax or type='examples then newfont courier; - mainloop(); - second_newline(); second_newline(); - newfont helvetica; - end; - -symbolic procedure par_heading(type); - <>; - -symbolic procedure vpart(type); - % formatted / verbatim part. - begin - emit_start_verbatim(); - set_tab(); - newfont courier; - - vpart0(); - - emit_end_verbatim(); - newfont helvetica; - end; - -symbolic procedure vpart0(); - begin scalar c,c1,c2,c3; - loop: - c:=rdch(); - if c=!$eof!$ then rederr "#### EOF in verbatim part"; - if c='!\ then - <>; - if c1 = '!e and (c2:=rdch()) = '!n and (c3:=rdch()) = '!d - then goto done; - verbprin2 '!\; verbprin2 c1; - if c2 then verbprin2 c2; - if c3 then verbprin2 c3; - goto loop>>; - verbprin2 c; - goto loop; -done: - rdch(); - mytoken(t); - if !*test then printf(" (vpart pop %w)",beginstack); - beginstack := cdr beginstack; - release_tab(); - end; - -symbolic procedure compareahead(seq,l); compareahead1(seq,cdr seq,l); - -symbolic procedure compareahead1(base,seq,l); - if null l then t else - if null seq then compareahead1(nconc(base,c),c,l) where c={rdch()} - else - if not(car seq = car l) then nil else - compareahead1(base,cdr seq,cdr l); - -macro procedure look_ahead(m); - {'compareahead,'inlist,mkquote explode2 cadr m}; - -symbolic procedure examples_part(type); - % formatted / verbatim part. - begin scalar c,pg,state,tab_flag,pg,ll,l,endflag,eolflag,inlist; - emit_start_verbatim(); - set_tab(); - newfont courier; - state := 'lhs; - read_next: - eolflag := nil; - ll := nil; - read_loop: - c:=rdch(); - if c=!$eof!$ then rederr "#### EOF in examples part"; - if c='!\ then - <> - else - if look_ahead "explanation" - then << myskip '!{; - non_verb_block() where endchar='!}; - goto read_next; - >> else - if look_ahead "begin{multilineinput}" - then << - beginstack := 'multilineinput.beginstack; - vpart0(); - goto read_next; - >>; - if state neq 'rhs and look_ahead "begin{multilineoutput}" - then << - beginstack := 'multilineoutput.beginstack; - vpart0(); - goto read_next; - >>; - ll := '!\ . ll; - for each q in cdr inlist do if q then ll := q . ll; - goto read_loop - >> - else if c='!& then - <> - >> - else ll := c . ll; - goto read_loop; -tab_label: - while ll and cdr ll and car ll = '! and cadr ll = '! do - ll := cdr ll; % remove trailing blanks. - l := reversip ll; - for each c in l do - % if not c=!$eol!$ then - verbprin2 c; - if eolflag then - <>; - if length l > 35 then verbprin2 !$eol!$; - %% verbprin2 '!&; - %% verbprin2 "=>"; - state := 'rhs; - goto read_next; - - rhs_line: - verbprin2 !$eol!$; - ll:=reversip ll; - % remove leading blanks - ll := delete(!$eol!$,ll); - while ll and car ll = '! do ll:= cdr ll; - - goto no_expla; - if matchleft(ll,'(!\ !e !x !p !l !a !n !a)) - then - <>; - ll := cdr ll; - >>; - - no_expla: - % provide for multiline - if matchleft(ll,'(!\ !b !e !g !i !n - !{ !m !u !l !t !i !l !i !n !e !o !u !t !p !u !t !})) - then pg:=make_multi_out() ELSE pg:=minitex ll; - - if null pg then goto nix; - tab_flag := t; - %% if cadr pg > 35 then - <>; - pg := cddr pg; - while pg do - <>; - >>; - verbprin2 !$eol!$; - nix: - verbprin2 !$eol!$; - state := 'lhs; - if endflag then goto done; - goto read_next; - -done: - emit_end_verbatim(); - if !*test then printf(" (examples pop %w)",beginstack); - beginstack := cdr beginstack; - release_tab(); - newfont helvetica; - end; - -symbolic procedure non_verb_block(); - begin - emit_end_verbatim(); - release_tab(); - newfont helvetica; - mainloop (); - newfont courier; - set_tab(); - emit_start_verbatim(); - end; - -symbolic procedure make_multi_out(); - begin scalar con,w,pg,m,q; - con:=t; - w := cdr match_point_rgt; - % get rid of "{6cm}" - while w and car w neq '!} do w:=cdr w; - if w then w:=cdr w; - if member(!$eol!$,w) then - <>; - pg:=nil; - m:=0; - mult_loop: - match_point_lft:=nil; - if matcharb(w, '(!\ !e !n !d !{ !m !u !l !t !i !l !i !n !e )) - then<< con:=nil; - if match_point_lft then cdr match_point_lft:=nil else w:=nil; - >>; - if w then - <m then m:=length w; - if memq('!^,w) or memq('!{,w) then - pg := append(pg,cddr minitex w) - else - pg:=append(pg,{w}) - >>; - if con then - << - if q then <> else w:=read_one_line(); - goto mult_loop - >>; - pg := length pg . m . pg; - return pg; - end; - -symbolic procedure cut_lines(l,q); - if null l then {reversip q} else - if car l = !$eol!$ then reversip q . cut_lines(cdr l,nil) - else cut_lines(cdr l,car l . q); - -% match_point_lft: pair before match position -% match_point_rgt: last pair of matched string - -symbolic procedure matchleft(a,pat); - if null pat then t else - if null a then nil else - if car a neq car pat then - <> - else <>; - -symbolic procedure matcharb(a,pat); - if null a then nil else - matchleft(a,pat) or matcharb(cdr a,pat); - -symbolic procedure read_one_line(); - begin scalar l,c; - loop: - c := rdch(); - if c=!$eol!$ then return reversip l; - l := c.l; - goto loop; - end; - -put('comments,'context,'part); -put('examples,'context,'part); -put('bigexample,'context,'part); -put('syntax,'context,'part); -put('related,'context,'part); -put('text,'context,'part); -put('verbatim,'context,'part); -put('quote,'context,'part); % QUOTE -> VERBATIM (temporal) - -symbolic procedure do!-itemize(type); - begin - outc:='! ; - mainloop(); - second_newline(); - end; - -put('itemize,'context,'do!-itemize); - -symbolic procedure context_error(p,q); - << - terpri(); - prin2 "######### error in context "; - prin2 p; - prin2 " ### : "; - prin2t q; - >>; - -%-------------------- special item routines ---------------------- - -symbolic procedure verb(u); - begin scalar endchar,!*verbose; - endchar := char!*; !*verbose:=t; - mainloop(); - end; -put('verb,'act,'verb); - -symbolic procedure ldots(u); textout "..."; -put('ldots,'act,'ldots); -flag('(ldots),'simple); - -symbolic procedure cdots(u); textout "..."; -put('cdots,'act,'cdots); -flag('(cdots),'simple); - -symbolic procedure cdot(u); textout ". "; -put('cdot,'act,'cdot); -flag('(cdot),'simple); - - -symbolic procedure write_pi(u); textout "pi"; -put('pi,'act,'write_pi); -flag('(write_pi),'simple); - -symbolic procedure emphase(u); printem mystring3(); -put('key,'act,'emphase); - -symbolic procedure meta(u); - <">>; - -put('meta,'act,'meta); - -symbolic procedure italic(u); - <>; -put('index,'act,'myindex); - -symbolic procedure nameindex(u); - begin scalar s; - s:= mystring2(); - textout '! ; - emit_hidden_node_key s; - printem s; - end; -put('nameindex,'act,'nameindex); - -symbolic procedure reduce(u); textout "REDUCE"; -put('reduce,'act,'reduce); -flag('(reduce),'simple); - -symbolic procedure rept(u); textout "+"; -put('repeated,'act,'rept); -flag('(rept),'simple); - -symbolic procedure optional(u); textout "*"; -put('optional,'act,'optional); -flag('(optional),'simple); - -symbolic procedure myexp(u); <>; -put('exp,'act,'myexp); - -symbolic procedure formula(u); textoutl mystring2(); -put('variable,'act,'formula); -put('arg,'act,'formula); - -symbolic procedure rfrac(u); - <>; -put('rfrac,'act,'rfrac); - -symbolic procedure item(u); - begin scalar endchar; - endchar := '!]; - print_newline(); - if !*windows then print_tab(); - mainloop(); - end; - -put('item,'act,'item); - -%-------------------- support for iftex etc. --------------------- - -symbolic procedure texonly1(u); - begin scalar endchar,c; - integer count; - count:=1; - loop: - c:= rdch(); - if c='!\ then c:= rdch() else - if c='!{ then count:=count+1 else - if c='!} then count:=count-1; - if count>0 then goto loop; - myskip('!{); - endchar:='!}; - mainloop(); - end; - -put('iftex,'act,'texonly1); - -symbolic procedure texonly2(u); - begin scalar endchar,c,tok; - integer count; - count:=1; - loop: - c:= rdch(); - if c='!\ then - <>; - if count>0 then goto loop; - tok:=mytoken(t); - if tok neq 'tex then - <>; - if !*test then printf(" (texonly pop %w)",beginstack); - beginstack := cdr beginstack; - end; - -put('tex,'context,'texonly2); - -symbolic procedure infoonly(u); - begin scalar endchar; - mainloop(); - end; - -put('info,'context,'infoonly); - -symbolic procedure reporttopic u; - if !*windows then - <>; - -%----------------- untilities ------------------------------ - -symbolic procedure substipq(new,old,l); - % destructive substip based on eq test. - if not pairp l then l else - << - if car l eq old then car l := new; - if cdr l eq old then cdr l := new; - substipq(new,old,car l); - substipq(new,old,cdr l); - l>>; - -end; - - +% comphelp.red: +% +% first part of the REDUCE help compiler: syntax analysis +% and structure generation. +% +% the second part contains target specific code. +% +% Author: Herbert Melenk, ZIB Berlin +% +% November 1992 +% + +symbolic; + +fluid '(char!* infile!* outfile!* !*windows !*test !*myeof); +fluid '(printfunction!* sect_count endchar current_node!*); +fluid '(!*verbatim !*sqbkt !*opennode currentfont topiccount!*); +fluid '(courier helvetica outc beginstack filestack level); +fluid '(nodechain undo match_point_lft match_point_rgt); +fluid '(run!* dir_src); +fluid '(aliases package); +fluid '(section_list regoup_sections); +fluid '(help_gensym_count); + + +run!* := 0; + +% !*test := t; +regoup_sections := nil; + +%------------------------------------------------------------ +% +% MAIN PROGRAM +% +%------------------------------------------------------------ + +symbolic procedure job(infile,outfile); + begin scalar !*raise, !*lower; + help_gensym_count := 1; + section_list := nil; + !*myeof := nil; + if getenv "echo" then !*echo:=t; + run!* := run!* + 1; + reset(); terpri(); + if run!* = 2 then update_labels(); + !*opennode := nil; + sect_count:=1; + topiccount!* := 0; + printfunction!*:=nil; + if infile!* then close infile!*; + if outfile!* then close outfile!*; + infile!*:=open(bldmsg("%w%w",dir_src,infile),'input); + outfile!*:=open(outfile,'output); + channellinelength(outfile!*,200); + initoutput(); + newfont helvetica; + mainloop(); + close_section 'document; + write_sections(); + fontoff(); + endoutput(); + close infile!*; + infile!* :=nil; + if outfile!* then close outfile!*; + outfile!*:=nil; + % printstruct(); + end; + +%------------------------------------------------------------ +% +% file input +% +%------------------------------------------------------------ + +fluid '(oldchar !*myecho !*myeof); + +!*myecho := nil; +!*myeof := nil; + +symbolic procedure rdch(); rdchr0(nil); + +symbolic procedure rdch!*(); rdchr0(t); + +symbolic procedure rdchr0(q); + if !*myeof then !$eof!$ else + if oldchar then <> where old = oldchar + else + <>; + % if we have found a token, eat up the following blanks. +% if cdr tok then while c='! do c:=rdch(); % ACH: loses a char. + if null cdr tok then return nil; + tok := compress reverse('!".tok); + return intern tok; +end; + +symbolic procedure mystring(); + begin scalar tok,c; + while digit(c:=rdch()) or liter c or c='! or + (endchar and c neq endchar) do + tok:=c.tok; + return reversip(tok); +end; + +symbolic procedure mystring2(); + % read string util }, but ignore \} + begin scalar tok,c; + while (c:=rdch()) neq '!} do tok:=c.tok; + return reversip(tok); +end; + +symbolic procedure mystring2!](); + % read string util ], but ignore \} + begin scalar tok,c; + while (c:=rdch!*()) neq '!] do tok:=c.tok; + return reversip(tok); +end; + +symbolic procedure mystring_nodename(); + % read node name, eventually updating the name translation table + % for entries like "\begin{Command}[percent]{%}" + % read string util }, but ignore \} + begin scalar tok,c,alt; + c:=myskipl '(!{ ![); + if c='![ then + << alt := mystring2!](); myskip '!{ >>; + while (c:=rdch!*()) neq '!} do tok:=c.tok; + tok := reversip tok; + if alt then aliases := (alt . tok) . aliases; + return alt or tok; +end; + +symbolic procedure mystring3(); + begin scalar tok,c; + loop: + c:=rdch(); + if c='!\ then <>; + if c= '!} then return reversip(tok); + tok := c.tok; goto loop; +end; + +symbolic procedure raisestring(s); + begin scalar n; + return for each c in s collect + if (n:=id2int c)>95 then + int2id(n-32) else c; + end; + +symbolic procedure lowerstring(s); + begin scalar n; + return for each c in s collect + if liter c and (n:=id2int c)<95 then + int2id(n+32) else c; + end; + +symbolic procedure mycompress u; + compress reversip('!" . reverse('!" . u)); + +%---------------------- main loop ---------------------------- + +symbolic procedure mainloop(); + begin scalar u,c,tok,f,undo; + loop: + c:=rdch(); + if c=!$eof!$ then goto finis; + if endchar and c=endchar then + <>; + if c='!{ then + << + begin scalar endchar; + endchar := '!}; + mainloop(); + end; + goto loop; + >>; + if c='!\ then + <>; + if tok='documentstyle then + <> + else + if tok='end then + <>; + if u neq car beginstack then + <>; + if !*test then printf(" (main pop %w)",beginstack); + beginstack := cdr beginstack; + goto finis>> + else + if(f:=get(tok,'act)) then + << + if !*test then <>; + apply1(f,tok); + if flagp(f,'simple) then oldchar := char!*; + goto loop; + >> + else + printf("**** unknown token: %w %n",tok); + >>; + char: + if printfunction!* then apply1(printfunction!*,c); + goto loop; + finis: + for each u in undo do eval(u); + end; + +%-----------------\input{...} \include{ ...}----------------- + +symbolic procedure include(u); + begin scalar file,fname,fname1,endchar; + endchar := '!}; + fname:=mycompress mystring(); + if fname = "intro" then return; + fname:=bldmsg("%w%w",dir_src,fname); + endchar := nil; + file:=errorset({'open,mkquote fname,mkquote 'input},nil,nil); + if not errorp file then goto found; + fname1:=bldmsg("%w.tex",fname); + file:=errorset({'open,mkquote fname1,mkquote 'input},nil,nil); + if not errorp file then goto found; + printf("***** cannot open file >%w< resp. >%w< %n",fname,fname1); + return nil; + found: + if fname1 then fname := fname1; + filestack:=infile!*.filestack; + infile!* :=car file; + terpri(); prin2 "--- input file "; prin2t fname; + mainloop(); + terpri(); prin2 "--- return from file "; prin2t fname; + close infile!*; + !*myeof := nil; + infile!*:=car filestack; + filestack := cdr filestack; + end; + +put('input,'act,'include); +put('include,'act,'include); + +put('makeindex,'act,'null); +put('tt,'act,'null); + +%-------------------section hierarchy ----------------------- + +symbolic procedure print_indent(); + if numberp level then for i:=1:level do prin2 " "; + +fluid '(record act_rec node_count); + +node_count := 0; + +smacro procedure type(u); car u; +smacro procedure seq(u); cadr u; +smacro procedure lab(u); caddr u; +smacro procedure count(u); cadddr u; +smacro procedure name(u);car cddddr u; + +symbolic procedure reset(); + << + record := + { + % type seq lab nr name + {'document, nil, "main_index", + 1, '(!T !o !p)}, +% 1, "Top"}, + {'section, nil, nil, 1, nil}, + {'subsection,nil, nil, 1, nil}, + {'subsubsection,nil, nil, 1, nil}}; + act_rec:= car record; + >>; + +symbolic procedure sectappend r; + % link tail from next record to cont of first one + car cdar r :=(cdr cadr r) . seq car r; + +%-------------------- section ------------------------------- + + +symbolic procedure section(s); + begin scalar name; + current_node!* := nil; + name:=mystring2(); + close_section(s); + open_section(s,name); + end; + +symbolic procedure close_section(s); + begin scalar r; + r:=record; + while r and caar r neq s do r:= cdr r; + if null r then error({"record empty",s},99); + for each u in reverse r do close_section1 u; + end; + +symbolic procedure close_section1(rec); + if name rec then + begin + if !*windows then + << print_indent(); reporttopic(" section end: "); + terpri(); + >>; + if regoup_sections then + section_list := append(rec,nil) . section_list + else + write_section(rec); + cdr rec:={nil,nil,0,nil}; + end; + +symbolic procedure write_sections(); + for each s in section_list do write_section s; + +symbolic procedure write_section(rec); + if name rec then + begin + if !*opennode then emit_node_separator(); + !*opennode:=nil; + emit_dir_new(); + emit_dir_label(lab rec); + emit_dir_title name rec; + emit_dir_browse('index,count rec); + emit_dir_key(name rec); + print_bold name rec; + emit_dir_header(); + for each x in reverse seq rec do + make_dir_entry (nil.x); + emit_dir_separator(); + end; + +symbolic procedure make_dir_entry rec; + emit_dir_entry(name rec,lab rec); + +symbolic procedure help_gensym(); + compress ('!g . explode2 (help_gensym_count := help_gensym_count+1)); + +symbolic procedure open_section(s,n); + begin scalar r; + sect_count:=sect_count+1; + r:= record; + while r and cdr r and caadr r neq s do r:=cdr r; + if null r then error({"record empty",s},99); + % initialize new section and link to parent + if not !*windows then n:=append(n, '(! !s !e !c !t !i !o !n)); + cdr cadr r:={nil,help_gensym(),sect_count,n}; + sectappend r; + r:= cadr r; + level := if s='section then 0 else + if s='subsection then 1 else + if s='subsubsection then 2 else 3; + print_indent(); + for each c in lowerstring explode2 s do prin2 c; + prin2 " "; + prin2 count r; prin2 " "; + prin2 lab r; prin2 " "; + mapc(name r,'prin2); terpri(); + act_rec := r; + base_new_dir name r; + level := if s='section then 1 else + if s='subsection then 2 else + if s='subsubsection then 3 else 4; + end; + +put('section,'act,'section); +put('subsection,'act,'section); +put('subsubsection,'act,'section); + + +%------------------- begin-end contexts --------------------------- + +symbolic procedure beg(u); + begin scalar tok,f,w; + tok:=mytoken(t); + for each c in beginstack do w:=w or (get(c,'context)='node); + if w and 'node=get(tok,'context) then + <>; + if !*test then <>; + if !*test then printf(" (push %w)",tok); + beginstack := tok.beginstack; + f:=get(tok,'context); + if f then apply1(f,tok) else + <>; + end; + +put('begin,'act,'beg); + +symbolic procedure mmain(u); mainloop(); + +put('document,'context,'mmain); + +%------------------- generate unique labels ---------------------- + +fluid '(labels!* l_list name_trans); + +symbolic procedure clean_name u; + if null u then nil else + if car u memq '(!- !, !? !* !> !< !. ! ) + then '!_ . clean_name cdr u else + car u . clean_name cdr u; + + +name_trans :='( + ((!,) . COMMA_sign) + ((!.) . DOT_sign) + ((!;) . SEMICOLON_sign) + ((!%) . PERCENT_sign) + ((!$) . DOLLAR_sign) + ((!: !=) . ASSIGN_sign) + ((!=) . EQUAL_sign) + ((!+) . PLUS_sign) + ((!-) . MINUS_sign) + ((!*) . TIMES_sign) + ((!/) . SLASH_sign) + ((!* !*) . POWER_sign) + ((!$ !> != !$) . GEQ_sign) + ((!> !=) . GEQ_sign) + ((!>) . GREATER_sign) + ((!$ !< != !$) . LEQ_sign) + ((!< != ) . LEQ_sign) + ((!<) . LESS_sign) + ((!< !<) . BLOCK)); + + +symbolic procedure make_label(name, type, alias); + begin scalar u,s,w,uname; + uname := raisestring name; + if !*windows then + << alias := clean_name alias; + name := clean_name name>>; + s := uname . type; + u := assoc (s,labels!*); + if u and run!* = 1 then + <>; + if u then return cadr u; + labels!* := (s.(w:=alias.name.type)). labels!*; + if not member(uname,l_list) then + l_list := uname . l_list; + return car w; + end; + +symbolic procedure get_label name; + (if l then car l) where l=get_label1 name; + +symbolic procedure patch_ u; + if null u then nil else + if car u = '!_ then '!\ . '!_ . patch_ cdr u + else car u . patch_ cdr u; + +symbolic procedure get_label1 name; + begin scalar u,uname; + uname := raisestring name; + u := get_label2 uname or get_label2 patch_ uname; + if null u and (run!* > 1) then + <>; + return if u then cdr u else nil; + end; + +symbolic procedure get_label2 uname; + begin scalar u,uname; + u := assoc((uname . 'operator),labels!*) + or assoc((uname . 'function),labels!*) + or assoc((uname . 'switch),labels!*) + or assoc((uname . 'statement),labels!*) + or assoc((uname . 'command),labels!*) + or assoc((uname . 'declaration),labels!*) + or assoc((uname . 'variable),labels!*) + or assoc((uname . 'type),labels!*) + or assoc((uname . 'constant),labels!*) + or assoc((uname . 'concept),labels!*) + or assoc((uname . 'package),labels!*) + or assoc((uname . 'introduction),labels!*); + return u; + end; + +symbolic procedure update_labels(); + % for unique names use the name as label. + begin scalar new,old; + terpri(); + prin2t "------ updating node labels -----"; + for each p in l_list do + if (p:=get_label1 p) then + <>; + prin2t "------ updating done ------------"; + end; + +%------------------- nodes ------------------------------------ + +symbolic procedure node(type); + begin scalar name,name2,rname,type2,name3,rec,type3,name4,label; + scalar altname,alias; + printfunction!* := 'textout; + if !*opennode then emit_node_separator(); + !*opennode:=t; + % myskip '!{; + name:=mystring_nodename(); + if altname:=assoc(name,name_trans) then + name := explode2 cdr altname; +% alias := if !*windows and assoc(name,aliases) then +% cdr assoc(name,aliases); + alias := if assoc(name,aliases) then + cdr assoc(name,aliases); + type3 := lowerstring (type2:=explode2 type); + name2 :=type . '! . (rname:=raisestring name); + name3 := append(type3,'! . name); + name4 := append(name, '! . type3); + label := make_label(name,type,name4); + rec := {'node, + nil, + label, + node_count:=add1 node_count, + name4}; + car cdr act_rec:= cdr rec . seq act_rec; + fonton(); + print_indent(); + mapc(name3,'prin2); reporttopic(" "); terpri(); + emit_node_label(lab rec); + emit_node_title(lab rec,name,type); + emit_node_browse(lab act_rec,count rec); + emit_node_keys(name4); + current_node!* := name4; + emit_hidden_node_key(type3); + emit_hidden_node_key(name rec); + % header line; + myterpri(); + if alias then <>; + print_bold rname; + if type2 neq '(C O N C E P T) then + << print_tab(); print_tab(); print_tab(); print_tab(); + print_bold type2; + >>; + print_newline(); second_newline(); + mainloop (); + end; + +put('switch,'context,'node); +put('variable,'context,'node); +put('operator,'context,'node); +put('function,'context,'node); +put('command,'context,'node); +put('statement,'context,'node); +put('declaration,'context,'node); +put('concept,'context,'node); +put('introduction,'context,'node); +put('package,'context,'node); +put('type,'context,'node); +put('constant,'context,'node); + + +symbolic procedure part(type); + begin + outc:='! ; + if type='examples or type='syntax or type='related + then par_heading(type) else + if type='bigexample then par_heading('example); + + if type='bigexample or type='verbatim then return vpart(type) else + if type='examples then return examples_part(type); + if type='syntax or type='examples then newfont courier; + mainloop(); + second_newline(); second_newline(); + newfont helvetica; + end; + +symbolic procedure par_heading(type); + <>; + +symbolic procedure vpart(type); + % formatted / verbatim part. + begin + emit_start_verbatim(); + set_tab(); + newfont courier; + + vpart0(); + + emit_end_verbatim(); + newfont helvetica; + end; + +symbolic procedure vpart0(); + begin scalar c,c1,c2,c3; + loop: + c:=rdch(); + if c=!$eof!$ then rederr "#### EOF in verbatim part"; + if c='!\ then + <>; + if c1 = '!e and (c2:=rdch()) = '!n and (c3:=rdch()) = '!d + then goto done; + verbprin2 '!\; verbprin2 c1; + if c2 then verbprin2 c2; + if c3 then verbprin2 c3; + goto loop>>; + verbprin2 c; + goto loop; +done: + rdch(); + mytoken(t); + if !*test then printf(" (vpart pop %w)",beginstack); + beginstack := cdr beginstack; + release_tab(); + end; + +symbolic procedure compareahead(seq,l); compareahead1(seq,cdr seq,l); + +symbolic procedure compareahead1(base,seq,l); + if null l then t else + if null seq then compareahead1(nconc(base,c),c,l) where c={rdch()} + else + if not(car seq = car l) then nil else + compareahead1(base,cdr seq,cdr l); + +macro procedure look_ahead(m); + {'compareahead,'inlist,mkquote explode2 cadr m}; + +symbolic procedure examples_part(type); + % formatted / verbatim part. + begin scalar c,pg,state,tab_flag,pg,ll,l,endflag,eolflag,inlist; + emit_start_verbatim(); + set_tab(); + newfont courier; + state := 'lhs; + read_next: + eolflag := nil; + ll := nil; + read_loop: + c:=rdch(); + if c=!$eof!$ then rederr "#### EOF in examples part"; + if c='!\ then + <> + else + if look_ahead "explanation" + then << myskip '!{; + non_verb_block() where endchar='!}; + goto read_next; + >> else + if look_ahead "begin{multilineinput}" + then << + beginstack := 'multilineinput.beginstack; + vpart0(); + goto read_next; + >>; + if state neq 'rhs and look_ahead "begin{multilineoutput}" + then << + beginstack := 'multilineoutput.beginstack; + vpart0(); + goto read_next; + >>; + ll := '!\ . ll; + for each q in cdr inlist do if q then ll := q . ll; + goto read_loop + >> + else if c='!& then + <> + >> + else ll := c . ll; + goto read_loop; +tab_label: + while ll and cdr ll and car ll = '! and cadr ll = '! do + ll := cdr ll; % remove trailing blanks. + l := reversip ll; + for each c in l do + % if not c=!$eol!$ then + verbprin2 c; + if eolflag then + <>; + if length l > 35 then verbprin2 !$eol!$; + %% verbprin2 '!&; + %% verbprin2 "=>"; + state := 'rhs; + goto read_next; + + rhs_line: + verbprin2 !$eol!$; + ll:=reversip ll; + % remove leading blanks + ll := delete(!$eol!$,ll); + while ll and car ll = '! do ll:= cdr ll; + + goto no_expla; + if matchleft(ll,'(!\ !e !x !p !l !a !n !a)) + then + <>; + ll := cdr ll; + >>; + + no_expla: + % provide for multiline + if matchleft(ll,'(!\ !b !e !g !i !n + !{ !m !u !l !t !i !l !i !n !e !o !u !t !p !u !t !})) + then pg:=make_multi_out() ELSE pg:=minitex ll; + + if null pg then goto nix; + tab_flag := t; + %% if cadr pg > 35 then + <>; + pg := cddr pg; + while pg do + <>; + >>; + verbprin2 !$eol!$; + nix: + verbprin2 !$eol!$; + state := 'lhs; + if endflag then goto done; + goto read_next; + +done: + emit_end_verbatim(); + if !*test then printf(" (examples pop %w)",beginstack); + beginstack := cdr beginstack; + release_tab(); + newfont helvetica; + end; + +symbolic procedure non_verb_block(); + begin + emit_end_verbatim(); + release_tab(); + newfont helvetica; + mainloop (); + newfont courier; + set_tab(); + emit_start_verbatim(); + end; + +symbolic procedure make_multi_out(); + begin scalar con,w,pg,m,q; + con:=t; + w := cdr match_point_rgt; + % get rid of "{6cm}" + while w and car w neq '!} do w:=cdr w; + if w then w:=cdr w; + if member(!$eol!$,w) then + <>; + pg:=nil; + m:=0; + mult_loop: + match_point_lft:=nil; + if matcharb(w, '(!\ !e !n !d !{ !m !u !l !t !i !l !i !n !e )) + then<< con:=nil; + if match_point_lft then cdr match_point_lft:=nil else w:=nil; + >>; + if w then + <m then m:=length w; + if memq('!^,w) or memq('!{,w) then + pg := append(pg,cddr minitex w) + else + pg:=append(pg,{w}) + >>; + if con then + << + if q then <> else w:=read_one_line(); + goto mult_loop + >>; + pg := length pg . m . pg; + return pg; + end; + +symbolic procedure cut_lines(l,q); + if null l then {reversip q} else + if car l = !$eol!$ then reversip q . cut_lines(cdr l,nil) + else cut_lines(cdr l,car l . q); + +% match_point_lft: pair before match position +% match_point_rgt: last pair of matched string + +symbolic procedure matchleft(a,pat); + if null pat then t else + if null a then nil else + if car a neq car pat then + <> + else <>; + +symbolic procedure matcharb(a,pat); + if null a then nil else + matchleft(a,pat) or matcharb(cdr a,pat); + +symbolic procedure read_one_line(); + begin scalar l,c; + loop: + c := rdch(); + if c=!$eol!$ then return reversip l; + l := c.l; + goto loop; + end; + +put('comments,'context,'part); +put('examples,'context,'part); +put('bigexample,'context,'part); +put('syntax,'context,'part); +put('related,'context,'part); +put('text,'context,'part); +put('verbatim,'context,'part); +put('quote,'context,'part); % QUOTE -> VERBATIM (temporal) + +symbolic procedure do!-itemize(type); + begin + outc:='! ; + mainloop(); + second_newline(); + end; + +put('itemize,'context,'do!-itemize); + +symbolic procedure context_error(p,q); + << + terpri(); + prin2 "######### error in context "; + prin2 p; + prin2 " ### : "; + prin2t q; + >>; + +%-------------------- special item routines ---------------------- + +symbolic procedure verb(u); + begin scalar endchar,!*verbose; + endchar := char!*; !*verbose:=t; + mainloop(); + end; +put('verb,'act,'verb); + +symbolic procedure ldots(u); textout "..."; +put('ldots,'act,'ldots); +flag('(ldots),'simple); + +symbolic procedure cdots(u); textout "..."; +put('cdots,'act,'cdots); +flag('(cdots),'simple); + +symbolic procedure cdot(u); textout ". "; +put('cdot,'act,'cdot); +flag('(cdot),'simple); + + +symbolic procedure write_pi(u); textout "pi"; +put('pi,'act,'write_pi); +flag('(write_pi),'simple); + +symbolic procedure emphase(u); printem mystring3(); +put('key,'act,'emphase); + +symbolic procedure meta(u); + <">>; + +put('meta,'act,'meta); + +symbolic procedure italic(u); + <>; +put('index,'act,'myindex); + +symbolic procedure nameindex(u); + begin scalar s; + s:= mystring2(); + textout '! ; + emit_hidden_node_key s; + printem s; + end; +put('nameindex,'act,'nameindex); + +symbolic procedure reduce(u); textout "REDUCE"; +put('reduce,'act,'reduce); +flag('(reduce),'simple); + +symbolic procedure rept(u); textout "+"; +put('repeated,'act,'rept); +flag('(rept),'simple); + +symbolic procedure optional(u); textout "*"; +put('optional,'act,'optional); +flag('(optional),'simple); + +symbolic procedure myexp(u); <>; +put('exp,'act,'myexp); + +symbolic procedure formula(u); textoutl mystring2(); +put('variable,'act,'formula); +put('arg,'act,'formula); + +symbolic procedure rfrac(u); + <>; +put('rfrac,'act,'rfrac); + +symbolic procedure item(u); + begin scalar endchar; + endchar := '!]; + print_newline(); + if !*windows then print_tab(); + mainloop(); + end; + +put('item,'act,'item); + +%-------------------- support for iftex etc. --------------------- + +symbolic procedure texonly1(u); + begin scalar endchar,c; + integer count; + count:=1; + loop: + c:= rdch(); + if c='!\ then c:= rdch() else + if c='!{ then count:=count+1 else + if c='!} then count:=count-1; + if count>0 then goto loop; + myskip('!{); + endchar:='!}; + mainloop(); + end; + +put('iftex,'act,'texonly1); + +symbolic procedure texonly2(u); + begin scalar endchar,c,tok; + integer count; + count:=1; + loop: + c:= rdch(); + if c='!\ then + <>; + if count>0 then goto loop; + tok:=mytoken(t); + if tok neq 'tex then + <>; + if !*test then printf(" (texonly pop %w)",beginstack); + beginstack := cdr beginstack; + end; + +put('tex,'context,'texonly2); + +symbolic procedure infoonly(u); + begin scalar endchar; + mainloop(); + end; + +put('info,'context,'infoonly); + +symbolic procedure reporttopic u; + if !*windows then + <>; + +%----------------- untilities ------------------------------ + +symbolic procedure substipq(new,old,l); + % destructive substip based on eq test. + if not pairp l then l else + << + if car l eq old then car l := new; + if cdr l eq old then cdr l := new; + substipq(new,old,car l); + substipq(new,old,cdr l); + l>>; + +end; + +