Сплиттер -- простейший лексический анализатор разбивающий входной текст на слова (токенайзер).

У данного типа анализаторов есть следующие проблемы -- разделение подряд идущих слов и группировка в текстовые блоки состоящие из мелких слов. Первая не ???решаема???, из-за особенностей работы сплиттера. Вторая может быть решена с помощью эскейп-последовательностей. Но при это появляется проблема экранирования вложенных эскейп-символов и символов-экранирования. Попробуем решить данную проблему используя два эскейп-символа -- открывающий и закрывающий.

   


Грамматика описывающая входные строки сплиттера:

Код:
<S>::=<text> #eoln

<text>::=
    | <token>
    | <token> <delims> <text>    ;последовательность
    | <delims> <text>

<token>::=
    | <word>    ;слово
    | #beg <group> #end    ;группировка
    | #beg <group>
    | #beg #end
    | #beg
    | <word> <token>    ;конкатенация

<word>::=
    | #!DELIM_BEG_EOLN
    | #!DELIM_BEG_EOLN <word>

<group>::=
    | #!END_EOLN
    | #!END_EOLN <group>

<delims>::=
    | #delim
    | #delim <delims>

#delim::    ;разделители
#eoln::    ;конец строки
#beg::    ;начало группы
#end::    ;конец группы
#!END_EOLN::    ;все, кроме символа конца группы и конца строки
#!DELIM_BEG_EOLN::    ;все, кроме символов начала группы и символов разделителя и конца строки

   


Продукционная грамматика сплиттера:

Код:
<S>::=<text> #eoln

<text>::=
    | <token> !out(tok), tok=""!
    | <token> !out(tok), tok=""! <delims> <text>
    | <delims> <text>

<token>::=
    | <word>    ;слово
    | #beg <group> #end
    | #beg <group>
    | #beg #end
    | #beg
    | <word> <token>

<word>::=
    | #!DELIM_BEG_EOLN !tok+=ch!
    | #!DELIM_BEG_EOLN !tok+=ch! <word>

<group>::=
    | #!END_EOLN !tok+=ch!
    | #!END_EOLN !tok+=ch! <group>

<delims>::=
    | #delim
    | #delim <delims>

#delim::
#eoln::
#beg::
#end::
#!END_EOLN::
#!DELIM_BEG_EOLN::

   


После преобразования в недетерменированный конечный автомат:

После минимизации и оптимизации:
http://sd.uploads.ru/t/znpdb.png

После преобразования в детерминированный конечный автомат:
http://sg.uploads.ru/t/oDc8P.png

Сравните с построенным вручную:
http://s7.uploads.ru/t/IdasC.png

TODO:перерисовать

TODO:добавить действия

   


Реализация на javascript.

Код:
function splitter(input, delims=" \t\n", beg='<', end='>'){
    var output = [];

    var tok="";
    var state=0;
    var pos=0;
    while(state != -1){
        let ch = (pos<input.length)?input[pos++]:0;
        switch(state){
            case 0:
                if(ch == beg){
                    state = 2;
                }else if(ch === 0){
                    state = -1;
                }else if(delims.indexOf(ch)!=-1){
                    state = 0;
                }else{
                    tok+=ch;
                    state = 1;
                }
                break;
            case 1:
                if(ch == beg){
                    state = 2;
                }else if(ch === 0){
                    output.push(tok);
                    state = -1;
                }else if(delims.indexOf(ch)!=-1){
                    output.push(tok);tok="";
                    state = 0;
                }else{
                    tok+=ch;
                    state = 1;
                }
                break;
            case 2:
                if(ch == end){
                    state = 1;
                }else if(ch === 0){
                    output.push(tok);
                    state = -1;
                }else{
                    tok+=ch;
                    state = 2;
                }
                break;
        }
    }

    return output;
}

Результаты тестирования:

Код:
splitter("abc 123   \t < >  <<> >  123<456> ");
Array [ "abc", "123", " ", "<", ">", "123456" ]