/*
 Экспериментальный парсер XML в рефал и обратно.
 Рефал-результат - рефал-выражение, 
 в котором      <TAG...> ... </TAG>
 заменено на    ((TAG...) ...     )

   Входные точки:
   Go       - отладочные пуски,
   XML_REF  - преобразование из XML в рефал,
   XML_REF1 - преобразование из XML в рефал с вводом файла,
              Arg 1 - name файла, канал 1,
   XML_REF2 - преобразование из XML в рефал с вводом файла,
              Arg 1 - name файла, канал 1,
   REF_XML  - преобразование из рефала в XML.

 Исходный вариант, которого никто не видел, обладал недостатками:
   1. Было несколько просмотров с неэффективным спариванием скобок,
      в результате чего текст в 20К обрабатывалсja 40 секунд, а в 200К
      не хватило 10 минут.
   2. Оказалось, что конец строки тоже может быть разделителем.
   3. В начале строк могут присутствовать не только пробелы,
      но и символы с кодом 09.
   4. Кавычки и двойные кавычки не всегда правильно обрабатываются
      в этой реализации рефала-5.
   5. В комментариях на русском языке я не могу  использовать
      последнюю букву русского языка "я" - refc на ней просто
      останавливается. (Windows98 - кодировка windows).
*/

$EXTRN OPEN, GET, INPUT;
$EXTRN ARG, PROUT;
$EXTRN IMPLODE, EXPLODE;
$EXTRN CHR;
$EXTRN BR, DG;
* Отладка: ввод, преобразование, печать.

$ENTRY Go  { = <Go1 (<Arg 3>) >; }
Go1 {
*                                         Преобразование из XML в XML
    ('xml_xml') = <REF_XML <XML_REF1 >>;
*                                         Преобразование из XML в рефал
    ('xml_ref') = <Prout <XML_REF1 >>;
   }

* Ввод XML-файла (Arg1).
* Внимание ! При вводе ничего не игнорируем (пробелы и отступы)!
* Строки разделяем макроцифрой 1.
* Не понятно, как работать с отступами в начале строк,
* по идеологии XML (компьютерная обработка) отступов и не должно
* быть. Будут предложения - переделаем.

$ENTRY XML_REF1 {
   = <Open 'r' 1 <Arg 1>>
     <XML_REF <XmlInput <Get 1>>>;
   }

$ENTRY XML_REF2 {
   e.1 = <Open 'r' 1 e.1>
         <XML_REF <XmlInput <Get 1>>>;
   }

XmlInput {
     e.1 0 = e.1;
     e.1   = e.1 1 <XmlInput <Get 1>>;
   }

$ENTRY XML_REF {
   e.1 = <SparTag ( 5 ) e.1>;
   }

*  Предполагаем, что '<' , '>' все же в наличии парами.

SparTag {
    ( 5 e.1) = e.1; 
*                                    - незакрытый тэг в конце - закрываем
    ((e.1) e.2) = <SparTag (e.1 (e.2))>;
*                                    - уже спаренный тэг 
    (e.1) ((e.2) e.a) e.3 = <SparTag (e.1 ((e.2) e.a) ) e.3>; 
*                                    - закрывающий тэг
    ((e.1) (e.2) e.a) ('/' e.2) e.3 = <SparTag (e.1 ((e.2) e.a)) e.3>; 
    ((e.1) (e.2 e.x) e.a) ('/' e.2) e.3 = 
           <SparTag (e.1 ((e.2 e.x) e.a)) e.3>; 
*                                    - незакрытый тэг - закрываем
    ((e.1) (e.7) e.a) ('/' e.2) e.3 = 
           <SparTag (e.1 ((e.7) e.a)) ('/' e.2) e.3>; 
*                                    - нет открывающего тэга
    ( 5 e.1) ('/' e.2) e.3 = 
           <Prout '     !!!  No open TAG !!!     '>
           <SparTag ( 5 e.1
           ('    !!!!!!!!!!!!!!!!!!!!!!!!!!!!!    ')
           ('/' e.2)) e.3>; 
*                                     - открывающий тэг
    (e.1) (e.2)   e.3 = <SparTag ((e.1) (e.2)) e.3>; 
    (e.1) e.2 '<' e.3 = <SparTag (e.1 <Zam e.2> ) <Tag '<' e.3>>;
    (e.1) e.2         = <SparTag (e.1 <Zam e.2> ) >;
   }


* Замена <TAG ...>  и  </TAG>
*     на (TAG ...)  и  (/TAG)  
* Могут быть такие тэги:
*       <!-- ... --> - комментарии,
*       <! ....... > - элементы DTD,
*       <? ...... ?> - заголовки, которые всегда незакрытые.
* Их делаем пока без обработки.
*  Уже спаренные открывающий и закрывающий тэги имеют вид ((e.1) e.2)

Tag {
    '<!--' e.2 '-->' e.3 = (('!--' <Zam e.2> '--')) e.3;
    '<!' e.2 '>'     e.3 = (('!' <Zam e.2>)) e.3;
    '<?' e.2 '?>'    e.3 = (('?' <Zam e.2> '?')) e.3;
    '<' e.2 '>'      e.3 = <Tag1 e.2> e.3;
                     e.1 = e.1;
    }

* Преобразование к стандартному виду
* На примере 
/*                   XML-выражение:

<html xsl:version="1.0"
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      lang="en">
....
</html>
                     преобразуется в рефал-выражение:

((HTML (XSL VERSION IS '1.0')
       (XMLNS XSL IS 'http://www.w3.org/1999/XSL/Transform')
       (LANG IS 'en')
 )
....
)

*/

Tag1 {
*                                 закрывающий тэг
        '/' e.1 =  ('/' <Tag2 ( ) <Del e.1>> );
*                                 закрытый тэг
        e.1 '/' = ((    <Tag2 ( ) <Del e.1>> ));
*                                 открывающий тэг
            e.1 =  (    <Tag2 ( ) <Del e.1>> );
     }

*        убирание пробелов, табулиров., конца строки - справа и слева
*        - много лишних обращений к Del для надежности
Del  { e.1 = <Del1 <C > e.1>;  }
C    {  = ( ' ' <CHR 9> ); }
Del1 {
    (e.a s.b e.c) s.b e.1 = <Del1 (e.a s.b e.c) e.1>;
    (e.a s.b e.c) e.1 s.b = <Del1 (e.a s.b e.c) e.1>;
    (e.a) 1  e.1 = <Del1 (e.a) e.1>;
    (e.a) e.1  1 = <Del1 (e.a) e.1>;
    (e.a) e.1 = e.1;
     }

*        выделение имени тэга
Tag2  {
    (e.1) ' ' e.2 = <ImplodeTag1 e.1> <ImplodeTag2 <Del e.2>>;
    (e.1)  1  e.2 = <ImplodeTag1 e.1> <ImplodeTag2 <Del e.2>>;
    (e.1) s.a e.2 = <Tag2 (e.1 s.a) e.2>;
    (e.1)         = <ImplodeTag1 e.1>;
      }

* !!! xsl: ... - обрабатываем иначе
* Долго думал, что делать с ":" в имени тэга,
* решил представлять его двумя составными символами.
* Не знаю, насколько удачно такое решение 
* - всегда можно легко переделать.

ImplodeTag1 {
    'xsl:' e.2 = <IMPLODE 'Xsl'> <IMPLODE e.2>;
    e.1 ':' e.2 = <IMPLODE e.1> <IMPLODE e.2>;
    e.1 = <IMPLODE e.1>;
            }

ImplodeTag2 {
     e.1 '=' e.2 = <IT (e.1) <Del e.2>>;
          = ;
      e.1 = (e.1);
            }

IT {
*                 Is вставил по привычке - надо ли ?
*                 Без Is менее наглядно, да и потом при программировании
*                 будут более читабельные программы.
    (e.1) '' e.2 '' e.3 = (<ImplodeTag1 <Del e.1>>  Is  <Zam e.2>)
                           <ImplodeTag2 <Del e.3>>;
    (e.1) "" e.2 "" e.3 = (<ImplodeTag1 <Del e.1>>  Is  <Zam e.2>)
                           <ImplodeTag2 <Del e.3>>;
   }

*  Замены: 
*    '&lt;'        ->      '<'
*    '&gt;'        ->      '>'
*    '&amp;'       ->      '&'
*    '&quot;'      ->      '"'
*     1 - разделитель строк - убираем.
Zam  {
       1       e.1 =     <Zam e.1>;
      '&lt;'   e.1 = '<' <Zam e.1>;
      '&gt;'   e.1 = '>' <Zam e.1>;
      '&amp;'  e.1 = '&' <Zam e.1>;
      '&quot;' e.1 = '"' <Zam e.1>;
       s.a     e.1 = s.a <Zam e.1>;
       (e.1) e.2 = (<Zam e.1>) <Zam e.2>;
            =  ;
      }

* ------------------------------------------------------------------
*   Преобразование из рефала в XML.
*   Исходное выражение - в поле зрения,
*   результат - печатаем.
*   Не понятно, когда может понадобиться что-то иное.
*   На всякий случай, ввожу функцию Out, в которой путем
*   убирания звездочки результирующее выражение останется
*   в поле зрения. 

Out { 
*     e.1 = e.1;
          = ;
      e.1 = <Out1 <Prov <C > e.1>>;
    }

*  Здесь - попытка учесть имеющиеся пробелы и отступы
Prov {
    (e.a s.b e.c) s.b e.1 = s.b <Prov (e.a s.b e.c) e.1>;
    (e.a) e.1 = (e.1);
     }

Out1 {
      e.1 ( )   = <BR LineXML '=' <DG LineXML> e.1>;
      e.1 (e.2) = <Prout <DG LineXML> e.1 e.2>;
     }

$ENTRY REF_XML {
   e.1 (e.2) e.3 = <Out <Zm e.1>>
                   <Ref1 (e.2)>
                   <REF_XML e.3>;
   e.1 = <Out <Zm e.1>>;
               }

Ref1 {
*             закрытый тэг
       ((e.2)) = <Zakr e.2>;

*    Если нижний уровень скобочной структуры, то выводим в одну строку
       ((s.a s.b e.2) e.3), <Name s.a s.b>: e.n
                          , <Param e.2>: e.p
       , e.3: { e.4 (e.5) e.6 = <Out '<' e.n e.p '>' >
                                <REF_XML e.3>
                                <Out '</' e.n '>' >;
               e.4            = <Out '<' e.n e.p '>' <Zm e.3> '</' e.n '>' >;
        }; 

       ((s.a e.2) e.3), <Name s.a>: e.n
                      , <Param e.2>: e.p
       , e.3: { e.4 (e.5) e.6 = <Out '<' e.n e.p '>' >
                                <REF_XML e.3>
                                <Out '</' e.n '>' >;
               e.4            = <Out '<' e.n e.p '>' <Zm e.3> '</' e.n '>' >;
        }; 
   e.1 = <Zm e.1>;
     }

Zakr {
        '!' e.1 = <Out '<!' <Zm e.1> '>' >;
        '?' e.1 = <Out '<?' <Zm e.1> '>' >;
        e.1 (e.2) e.3 = <Out '<' <Name e.1> <Param (e.2) e.3> '/>' >;  
        e.1           = <Out '<' <Name e.1> '/>' >;
     }

*         Обработка имени тэга
Name {
    s.a s.b = <EXPLODE s.a> ':' <EXPLODE s.b>;
    s.a     = <EXPLODE s.a>;
     }

*         Обработка параметров тэга
Param {
   (e.1) e.2 = ' ' <Param1 e.1> <Param e.2>;
             = ;
      }

Param1 {
   e.1 Is e.2 = <Name e.1> '=' <Param2 e.2>;
       }

Param2 {
     e.1 "" e.2 = '' e.1 "" e.2 '' ;
     e.1 = "" e.1 "" ;
       }

*  Замены: 
*    '<'        ->      '&lt;'
*    '>'        ->      '&gt;'
*    '&'        ->      '&amp;'
*    '"'        ->      '&quot'
Zm  {
* e.1 = e.1;
     '<' e.1 = '&lt;'   <Zm e.1>;
     '>' e.1 = '&gt;'   <Zm e.1>;
     '&' e.1 = '&amp;'  <Zm e.1>;
     '"' e.1 = '&quot' <Zm e.1>;
     s.a e.1 = s.a <Zm e.1>;
     (e.1) e.2 = (<Zm e.1>) <Zm e.2>;
            =  ;
      }