CLexFile *LexFilePush(CCompCtrl *cc)
{//#include file push.
        CLexFile *res = CAlloc(sizeof(CLexFile));

        if (res->next = cc->lex_include_stack)
                res->depth = res->next->depth + 1;
        else
                res->depth = -1; //Include depth starts with -1.
        return cc->lex_include_stack = res;
}

CLexFile *LexFilePop(CCompCtrl *cc)
{//#include file pop.
        CLexFile *tmpf;
        if (tmpf = cc->lex_include_stack)
        {
                if ((cc->lex_include_stack = tmpf->next) || !(cc->flags & CCF_DONT_FREE_BUF))
                {
                        if (tmpf->flags & LFSF_DOC)
                        {
                                if (tmpf->doc)
                                        DocDel(tmpf->doc);
                        }
                        else
                                Free(tmpf->buf);;
                }
                Free(tmpf->full_name);
                Free(tmpf);
        }
        return cc->lex_include_stack;
}

CCompCtrl *CompCtrlNew(U8 *buf=NULL, I64 flags=0, U8 *filename=NULL)
{//MAlloc and Init CCompCtrl.
        //Frees buf in CompCtrlDel unless CCF_DONT_FREE_BUF flag is set.
        //FileName is for error reporting.      If files are #included,
        //new names are used.  See Psalmody CompCtrlNew.
        CCompCtrl *cc = CAlloc(sizeof(CCompCtrl));
        CLexFile  *tmpf;

        QueueInit(cc);
        cc->flags = flags;
        cc->opts = 1 << OPTf_WARN_UNUSED_VAR | 1 << OPTf_WARN_HEADER_MISMATCH;
        cc->htc.hash_mask = HTG_TYPE_MASK - HTT_IMPORT_SYS_SYM;
        cc->htc.define_hash_table = cc->htc.hash_table_list = 
                cc->htc.global_hash_table = cc->htc.local_hash_table = Fs->hash_table;
        if (flags & CCF_KEEP_AT_SIGN)
                cc->char_bmp_alpha_numeric = char_bmp_alpha_numeric_no_at;
        else
                cc->char_bmp_alpha_numeric = char_bmp_alpha_numeric;
        tmpf = LexFilePush(cc);
        QueueInit(&cc->next_stream_blk);
        if (filename)
                tmpf->full_name = FileNameAbs(filename);
        else
                tmpf->full_name = StrNew(blkdev.tmp_filename);
        if (flags & CCF_PROMPT)
                buf = CAlloc(8);
        tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = buf;
        tmpf->line_num = 1;
        return cc;
}

U0 CompCtrlDel(CCompCtrl *cc)
{//Free CCompCtrl.
        while (LexFilePop(cc));
        LinkedListDel(cc->lex_parse_stack);
        LinkedListDel(cc->htc.next);
        Free(cc->ps);
        Free(cc->cur_str);
        Free(cc->cur_help_idx);
        Free(cc->dollar_buf);
        Free(cc);
}

I64 CompCtrlSize(CCompCtrl *cc)
{//Mem size of CCompCtrl and its members.
        CLexFile        *tmpf = cc->lex_include_stack;
        I64                      res = 0;

        while (tmpf)
        {
                if (tmpf->next || !(cc->flags & CCF_DONT_FREE_BUF))
                {
                        if (tmpf->flags & LFSF_DOC)
                        {
                                if (tmpf->doc)
                                        res += DocSize(tmpf->doc);
                        }
                        else
                                res += MSize2(tmpf->buf);
                }
                res += MSize2(tmpf->full_name);
                res += MSize2(tmpf);
                tmpf = tmpf->next;
        }
        res += MSize2(cc->cur_str);
        res += MSize2(cc);
        return res;
}

U32 lex_zeros = 0;

Bool LexDollar(CCompCtrl *cc, CDoc *doc, CDocEntry *doc_e)
{
        U8 *st;

        if (cc->flags & CCF_IN_QUOTES)
        {
                Free(cc->dollar_buf);
                st = Doc2PlainText(doc, doc_e);
                cc->dollar_buf = MStrPrint("$%$Q$", st);
                cc->dollar_count = 2;
                Free(st);
                return TRUE;
        }
        else
                return FALSE;
}

I64 LexCharGet(CCompCtrl *cc)
{//Get one char from stream. Allow put-back one.
        U8                      *ptr, *src;
        CLexFile        *tmpf;
        CDoc            *doc;
        CDocEntry       *doc_e;

        if (!Btr(&cc->flags, CCf_USE_LAST_U16))
        {
lgc_start1:
                if (!(src = cc->cur_buf_ptr++))
                {
                        cc->cur_buf_ptr = NULL;
                        goto lgc_here;
                }
                switch [cc->last_U16 = *src++]
                {
                        case 0:
lgc_here:
                                tmpf = cc->lex_include_stack;
                                if (tmpf->flags & LFSF_DOC)
                                {
                                        doc = tmpf->doc;
                                        doc_e = tmpf->cur_entry;
                                        doc_e = doc_e->next;
lgc_start2:
                                        if (doc_e != doc)
                                        {
                                                tmpf->cur_entry = doc_e;
                                                switch [doc_e->type_u8]
                                                {
                                                        case DOCT_TEXT:
                                                                if (doc_e->de_flags &
                                                                        ~(DOCEF_TAG | DOCEF_DEFINE | DOCEF_TAG_CB | DOCG_BL_IV_UL | DOCEF_WORD_WRAP |
                                                                        DOCEF_HIGHLIGHT | DOCEF_SKIP | DOCEF_FILTER_SKIP) &&
                                                                        LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                                                {
                                                                        tmpf->line_num = doc_e->y + 1;
                                                                        tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                                                }
                                                                else if (*(src = doc_e->tag))
                                                                        tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                                                else
                                                                {
                                                                        doc_e = doc_e->next;
                                                                        goto lgc_start2;
                                                                }
                                                                break;

                                                        case DOCT_NEW_LINE:
                                                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                                                tmpf->line_start = doc_e->next;
                                                                tmpf->line_num = doc_e->y + 2;//+1 because NEW_LINE is on prev line
                                                                                                                          //+1 because doc y starts at zero
                                                                cmp.compiled_lines++;
                                                                cc->last_U16 = '\n';
                                                                goto lgc_done;

                                                        case DOCT_TAB:
                                                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                                                tmpf->line_num = doc_e->y + 1;
                                                                cc->last_U16 = '\t';
                                                                goto lgc_done;

                                                        case DOCT_INS_BIN:
                                                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                                                tmpf->line_num = doc_e->y + 1;
                                                                Free(cc->cur_str);
                                                                cc->cur_str = NULL;
                                                                cc->cur_str_len = 0;
                                                                if (doc_e->bin_data)
                                                                {
                                                                        ptr = MAlloc(doc_e->bin_data->size);
                                                                        if (doc_e->bin_data->data)
                                                                                MemCopy(ptr, doc_e->bin_data->data, doc_e->bin_data->size);
                                                                        cc->cur_str = ptr;
                                                                        cc->cur_str_len = doc_e->bin_data->size;
                                                                }
                                                                cc->last_U16 = TK_INS_BIN;
                                                                goto lgc_done;

                                                        case DOCT_INS_BIN_SIZE:
                                                                tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                                                if (doc_e->bin_data)
                                                                        cc->cur_i64 = doc_e->bin_data->size;
                                                                else
                                                                        cc->cur_i64 = 0;
                                                                tmpf->line_num = doc_e->y + 1;
                                                                cc->last_U16 = TK_INS_BIN_SIZE;
                                                                goto lgc_done;

                                                        case DOCT_SHIFTED_Y:
                                                                if (LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                                                {
                                                                        tmpf->line_num = doc_e->y + 1;
                                                                        tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                                                }
                                                                else
                                                                {
                                                                        tmpf->buf_ptr = cc->cur_buf_ptr = &lex_zeros;
                                                                        tmpf->line_num = doc_e->y + 1;
                                                                        if (doc_e->attr < 0)
                                                                                cc->last_U16 = TK_SUPERSCRIPT;
                                                                        else if (doc_e->attr > 0)
                                                                                cc->last_U16 = TK_SUBSCRIPT;
                                                                        else
                                                                                cc->last_U16 = TK_NORMALSCRIPT;
                                                                        goto lgc_done;
                                                                }
                                                                break;

                                                        case DOCT_MARKER:
                                                        case DOCT_CURSOR:
                                                                doc_e = doc_e->next;
                                                                goto lgc_start2;

                                                        case 0xFF: // nobound switch
                                                        default:
                                                                if (LexDollar(cc, doc, doc_e) && *(src = cc->dollar_buf))
                                                                {
                                                                        tmpf->line_num = doc_e->y + 1;
                                                                        tmpf->buf_ptr = cc->cur_buf_ptr = src;
                                                                }
                                                                else
                                                                {
                                                                        doc_e = doc_e->next;
                                                                        goto lgc_start2;
                                                                }
                                                }
                                        }
                                        if (doc_e != doc)
                                                goto lgc_start1;
                                        tmpf->cur_entry = doc->head.last; // When take next, will still be end.
                                }
                                tmpf = cc->lex_include_stack;
                                if (tmpf->next)
                                {
                                        tmpf = LexFilePop(cc);
                                        cc->cur_buf_ptr = tmpf->buf_ptr;
                                        cc->flags &= ~CCF_USE_LAST_U16;
                                        if (!(cc->last_U16 = tmpf->last_U16))
                                                goto lgc_start1;
                                }
                                else
                                {
                                        if (cc->flags & CCF_PROMPT)
                                        {
                                                Free(tmpf->buf);
                                                ptr = CmdLinePrompt;
                                                if (StrCompare(ptr, "\n") && !cc->prompt_line++ && 
                                                        !StrCompare(ptr, "?\n") && cc->flags & CCF_QUESTION_HELP)
                                                {
                                                        Free(ptr);
                                                        ptr = StrNew("Help;;\n");
                                                }
                                                tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = ptr;
                                                goto lgc_start1;
                                        }
                                        else
                                        {
                                                if (src)
                                                        cc->cur_buf_ptr = src - 1;
                                                cc->last_U16 = TK_EOF;
                                        }
                                }
                                break;

                        case CH_CURSOR:
                                goto lgc_start1;

                        case '\n':
                                tmpf = cc->lex_include_stack;
                                if (!(tmpf->flags & LFSF_DOC))
                                {
                                        tmpf->line_num++;
                                        cmp.compiled_lines++;
                                        tmpf->line_start = src;
                                }
                                break;

                        case 0xFF: //nobound switch
                }
lgc_done:
                if (cc->opts & OPTF_ECHO && cc->last_U16 < 256 && Bt(char_bmp_printable, cc->last_U16))
                        '' cc->last_U16;
        }

        return cc->last_U16;
}

U0 LexSkipEol(CCompCtrl *cc)
{//LexCharGet to NULL until end-of-line.
        I64 ch;

        do ch = LexCharGet(cc);
        while (Bt(char_bmp_non_eol, ch));
}

U8 *LexFirstRemove(CCompCtrl *cc, U8 *marker, I64 _len=NULL)
{//LexCharGet() chars making str until marker.
        U8                              *res, *ptr;
        CQueueVectU8    *tmpv = QueueVectU8New;
        I64                              i, len = 0;

        while (TRUE)
        {
                i = LexCharGet(cc);
                if (!i || StrOcc(marker, i))
                        break;
                QueueVectU8Put(tmpv, len++, i);
        }
        if (i)
                Bts(&cc->flags, CCf_USE_LAST_U16);
        res = ptr = MAlloc(len + 1);
        for (i = 0; i < len; i++)
                *ptr++ = QueueVectU8Get(tmpv, i);
        *ptr = 0;
        QueueVectU8Del(tmpv);
        if (_len)
                *_len = len;

        return res;
}

U0 LexIncludeStr(CCompCtrl *cc, U8 *abs_filename, U8 *src, Bool actual_file)
{
        LexBackupLastChar(cc);
        CLexFile *tmpf = LexFilePush(cc);

        if (actual_file)
                tmpf->full_name = StrNew(abs_filename);
        else
                tmpf->full_name = StrNew(blkdev.tmp_filename);
        tmpf->line_num = 1;
        tmpf->buf = tmpf->buf_ptr = tmpf->line_start = cc->cur_buf_ptr = src;
}

CDoc *LexDocRead(U8 *abs_filename, I64 flags)
{
        CDoc    *doc = DocNew(abs_filename);
        U8              *src;
        I64              size = 0;

        doc->flags |= flags;
        src = FileRead(abs_filename, &size);
        if (!src || !size)
        {
                Free(src);
                src = CAlloc(1);
                size = 0;
        }
        DocLoad(doc, src, size);
        Free(src);

        return doc;
}

I64 comp_type_flags_src_code[(DOCT_TYPES_NUM + 63) / 64] = {
        1 << DOCT_TEXT | 1 << DOCT_TAB | 1 << DOCT_INS_BIN | 1 << DOCT_INS_BIN_SIZE};

U0 LexAttachDoc(CCompCtrl *cc, CLexFile *tmpf=NULL, CDoc *doc=NULL, U8 *abs_filename=NULL, CDocEntry *doc_e=NULL, I64 col=0)
{//Start lexing doc. Give either doc or abs_filename.
        if (!doc)
                doc = LexDocRead(abs_filename, DOCF_DBL_DOLLARS);
        if (!tmpf)
        {
                LexBackupLastChar(cc);
                tmpf = LexFilePush(cc);
        }
        if (!doc_e)
                doc_e = doc->head.next;
        tmpf->full_name = StrNew(doc->filename.name);
        tmpf->doc = doc;
        while (doc_e != doc)
        {
                if (Bt(comp_type_flags_src_code, doc_e->type_u8))
                        break;
                doc_e = doc_e->next;
                col = doc_e->min_col;
        }
        if (doc_e != doc)
        {
                col = ClampI64(col, doc_e->min_col, doc_e->max_col);
                tmpf->line_start = doc_e;
                tmpf->buf = NULL;
                tmpf->line_num = doc_e->y + 1;
                if (doc_e->type_u8 == DOCT_TEXT)
                {
                        tmpf->cur_entry = doc_e;
                        tmpf->buf_ptr = doc_e->tag;
                }
                else
                {
                        tmpf->cur_entry = doc_e->last; //TODO: might be problem at begin of file
                        tmpf->buf_ptr = &lex_zeros;
                }
                tmpf->flags = LFSF_DOC;
        }
        else
        {//TODO: DocDel(doc)?
                col = 0;
                tmpf->buf = tmpf->buf_ptr = tmpf->line_start = CAlloc(1);
                tmpf->line_num = 1;
                tmpf->flags = 0;
        }
        cc->cur_buf_ptr = tmpf->buf_ptr + col;
        tmpf->last_U16 = 0;
}

I64 LexInStr(CCompCtrl *cc, U8 *buf, I64 size, Bool *done)
{
        I64 i = 0, j, k, ch;

        *done = TRUE;
        while (i < size - 1)
        {
                ch = LexCharGet(cc);
                if (!ch || ch== '"')
                {
                        buf[i++] = 0;
                        return i;
                }
                else if (ch == '\\')
                {
                        switch (ch = LexCharGet(cc))
                        {
                                case '0':
                                        buf[i++] = 0;
                                        break;

                                case '\'':
                                        buf[i++] = '\'';
                                        break;

                                case '\`':
                                        buf[i++] = '\`';
                                        break;

                                case '\\':
                                        buf[i++] = '\\';
                                        break;

                                case '"':
                                        buf[i++] = '"';
                                        break;

                                case 'd':
                                        buf[i++] = '$';
                                        break;

                                case 'n':
                                        buf[i++] = '\n';
                                        break;

                                case 'r':
                                        buf[i++] = '\r';
                                        break;

                                case 't':
                                        buf[i++] = '\t';
                                        break;

                                case 'x':
                                case 'X':
                                        j = 0;
                                        for (k = 0; k < 2; k++)
                                        {
                                                ch = ToUpper(LexCharGet(cc));
                                                if (Bt(char_bmp_hex_numeric, ch))
                                                {
                                                        if (ch <= '9')
                                                                j = j << 4 + ch - '0';
                                                        else
                                                                j = j << 4 + ch - 'A' + 10;
                                                }
                                                else
                                                {
                                                        cc->flags |= CCF_USE_LAST_U16;
                                                        break;
                                                }
                                        }
                                        buf[i++] = j;
                                        break;

                                default:
                                        cc->flags |= CCF_USE_LAST_U16;
                                        buf[i++] = '\\';
                        }
                }
                else if (ch == '$')
                {
                        buf[i++] = '$';
                        if (cc->dollar_count)
                                cc->dollar_count--;
                        else if (LexCharGet(cc) != '$')
                        {
                                cc->dollar_count = 1;
                                cc->flags |= CCF_USE_LAST_U16;
                        }
                }
                else
                        buf[i++] = ch;
        }
        *done = FALSE;

        return i;
}

I64 Lex(CCompCtrl *cc)
{//Fetch next token.
        I64              i, j, k, l, ch;
        CHash   *tmph;
        Bool     str_done, in_str, neg_e;
        U8              *fbuf, *buf2, *buf3, buf[STR_LEN];

        cc->last_line_num = cc->lex_include_stack->line_num;
        while (TRUE)
        {
lex_cont:
                switch [ch = LexCharGet(cc)]
                {
                        case 0:
                                return cc->token = TK_EOF;

                        case TK_SUPERSCRIPT:
                                ch = '>';
                                goto lex_ident;

                        case TK_SUBSCRIPT:
                                ch = '<';
                                goto lex_ident;

                        case TK_NORMALSCRIPT:
                                ch = '=';
                                goto lex_ident;

                        case '@':
                                if (cc->flags & CCF_KEEP_AT_SIGN)
                                {
                                        cc->token = ch;
                                        goto lex_end;
                                }
                        case 'A'...'Z':
                        case 'a'...'z':
                        case '_':
                        case 128...255:
lex_ident:
                                i = 0;
                                buf[i++] = ch;
                                while (TRUE) {
                                        if (i >= STR_LEN)
                                                LexExcept(cc, "Ident limited to STR_LEN chars at ");
                                        else if (!(ch = LexCharGet(cc)))
                                                break;
                                        else if (Bt(cc->char_bmp_alpha_numeric, ch))
                                                buf[i++] = ch;
                                        else if (ch == TK_SUPERSCRIPT)
                                                buf[i++] = '>';
                                        else if (ch == TK_SUBSCRIPT)
                                                buf[i++] = '<';
                                        else if (ch == TK_NORMALSCRIPT)
                                                buf[i++] = '=';
                                        else
                                        {
                                                cc->flags |= CCF_USE_LAST_U16;
                                                break;
                                        }
                                }
                                buf[i++] = 0;
                                tmph = NULL;
                                if (cc->htc.local_var_list)
                                        cc->local_var_entry = MemberFind(buf, cc->htc.local_var_list);
                                else
                                        cc->local_var_entry = NULL;
                                if (!cc->local_var_entry && cc->htc.hash_table_list)
                                        tmph = HashFind(buf, cc->htc.hash_table_list, cc->htc.hash_mask);
                                if (tmph)
                                        j = tmph->type;
                                else
                                        j = 0;
                                if (j & HTT_DEFINE_STR && !(cc->flags & CCF_NO_DEFINES))
                                {
                                        LexIncludeStr(cc, tmph->str, StrNew(tmph(CHashDefineStr *)->data), FALSE);
                                        cc->lex_include_stack->flags |= LFSF_DEFINE;
                                }
                                else
                                {
                                        cc->hash_entry = tmph;
                                        Free(cc->cur_str);
                                        cc->cur_str = StrNew(buf);
                                        cc->cur_str_len = i;
                                        cc->token = TK_IDENT;
                                        goto lex_end;
                                }
                                break;

                        case '0'...'9':
                                i = ch - '0';
                                ch = ToUpper(LexCharGet(cc));
                                if (!Bt(&cc->opts, OPTf_DECIMAL_ONLY))
                                {
                                        if (ch == 'X')
                                        {
                                                while (TRUE)
                                                {
                                                        ch = ToUpper(LexCharGet(cc));
                                                        if (Bt(char_bmp_hex_numeric, ch))
                                                        {
                                                                if (ch <= '9')
                                                                        i = i << 4 + ch - '0';
                                                                else
                                                                        i = i << 4 + ch - 'A' + 10;
                                                        }
                                                        else
                                                        {
                                                                cc->cur_i64 = i;
                                                                cc->flags |= CCF_USE_LAST_U16;
                                                                cc->token = TK_I64;
                                                                goto lex_end;
                                                        }
                                                }
                                        }
                                        else if (ch == 'B')
                                        {
                                                while (TRUE)
                                                {
                                                        ch = LexCharGet(cc);
                                                        if (ch == '0')
                                                                i = i << 1;
                                                        else if (ch == '1')
                                                                i = i << 1 + 1;
                                                        else
                                                        {
                                                                cc->cur_i64 = i;
                                                                cc->flags |= CCF_USE_LAST_U16;
                                                                cc->token = TK_I64;
                                                                goto lex_end;
                                                        }
                                                }
                                        }
                                }
                                while (TRUE)
                                {
                                        if (Bt(char_bmp_dec_numeric, ch))
                                                i = i * 10 + ch - '0';
                                        else
                                        {
                                                if (ch == '.' || ch == 'e' || ch == 'E')
                                                        break;
lex_is_int:
                                                cc->cur_i64 = i;
                                                cc->flags |= CCF_USE_LAST_U16;
                                                cc->token = TK_I64;
                                                goto lex_end;
                                        }
                                        ch = LexCharGet(cc);
                                }
                                if (ch == '.')
                                {
                                        ch = LexCharGet(cc);
                                        if (ch == '.') {
                                                cc->flags |= CCF_LAST_WAS_DOT;
                                                goto lex_is_int;
                                        }
                                }
lex_float_start:
                                k = 0;
                                while (TRUE)
                                {
                                        if (Bt(char_bmp_dec_numeric, ch))
                                        {
                                                i = i * 10 + ch - '0';
                                                k++;
                                        }
                                        else
                                        {
                                                if (ch == 'e' || ch == 'E')
                                                        break;
                                                cc->cur_f64 = i * Pow10I64(-k);
                                                cc->flags |= CCF_USE_LAST_U16;
                                                cc->token = TK_F64;
                                                goto lex_end;
                                        }
                                        ch = LexCharGet(cc);
                                }
                                ch = LexCharGet(cc);
                                neg_e = FALSE;
                                if (ch == '-') {
                                        neg_e = TRUE;
                                        ch = LexCharGet(cc);
                                }
                                j = 0;
                                while (TRUE)
                                {
                                        if (Bt(char_bmp_dec_numeric, ch))
                                                j = j * 10 + ch - '0';
                                        else
                                        {
                                                if (neg_e)
                                                        cc->cur_f64 = i * Pow10I64(-j-k);
                                                else
                                                        cc->cur_f64 = i * Pow10I64(j-k);
                                                cc->flags |= CCF_USE_LAST_U16;
                                                cc->token = TK_F64;
                                                goto lex_end;
                                        }
                                        ch = LexCharGet(cc);
                                }
                                break;

                        case '"':
                                cc->flags |= CCF_IN_QUOTES;
                                buf2 = NULL;
                                i = 0;
                                do
                                {
                                        j = LexInStr(cc, buf, STR_LEN, &str_done);
                                        buf3 = MAlloc(i + j);
                                        if (buf2)
                                        {
                                                MemCopy(buf3, buf2, i);
                                                Free(buf2);
                                                buf2 = buf3;
                                                MemCopy(buf2 + i, buf, j);
                                        }
                                        else
                                        {
                                                buf2 = buf3;
                                                MemCopy(buf2, buf, j);
                                        }
                                        i += j;
                                }
                                while (!str_done);

                                Free(cc->cur_str);
                                cc->cur_str = MAlloc(i);
                                MemCopy(cc->cur_str, buf2, i);
                                Free(buf2);
                                cc->cur_str_len = i;
                                cc->flags &= ~CCF_IN_QUOTES;
                                cc->token = TK_STR;
                                goto lex_end;

                        case '\'':
                                if (cc->flags & CCF_NO_CHAR_CONST)
                                        break;
                                k = 0;
                                for (j = 0; j < 8; j++)
                                {
                                        if (!(ch = LexCharGet(cc)) || ch == '\'')
                                                break;
                                        if (ch == '\\')
                                        {
                                                switch (ch = LexCharGet(cc))
                                                {
                                                        case '0':       k.u8[j] = 0;    break;
                                                        case '\'':      k.u8[j] = '\''; break;
                                                        case '\`':      k.u8[j] = '\`'; break;
                                                        case '"':       k.u8[j] = '"';  break;
                                                        case '\\':      k.u8[j] = '\\'; break;
                                                        case 'd':       k.u8[j] = '$';  break;
                                                        case 'n':       k.u8[j] = '\n'; break;
                                                        case 'r':       k.u8[j] = '\r'; break;
                                                        case 't':       k.u8[j] = '\t'; break;
                                                        case 'x':
                                                        case 'X':
                                                                i = 0;
                                                                for (l = 0; l < 2; l++)
                                                                {
                                                                        ch = ToUpper(LexCharGet(cc));
                                                                        if (Bt(char_bmp_hex_numeric, ch))
                                                                        {
                                                                                if (ch <= '9')
                                                                                        i = i << 4 + ch - '0';
                                                                                else
                                                                                        i = i << 4 + ch - 'A' + 10;
                                                                        }
                                                                        else
                                                                        {
                                                                                cc->flags |= CCF_USE_LAST_U16;
                                                                                break;
                                                                        }
                                                                }
                                                                k.u8[j] = i;
                                                                break;

                                                        default:
                                                                k.u8[j] = '\\';
                                                                cc->flags |= CCF_USE_LAST_U16;
                                                }
                                        }
                                        else if (ch == '$')
                                        {
                                                ch = LexCharGet(cc);
                                                k.u8[j] = '$';
                                                if (ch != '$')
                                                        cc->flags |= CCF_USE_LAST_U16;
                                        }
                                        else
                                                k.u8[j] = ch;
                                }
                                if (ch != '\'' && (ch = LexCharGet(cc)) && ch != '\'')
                                        LexExcept(cc, "Char const limited to 8 chars at ");
                                cc->cur_i64 = k;
                                cc->token = TK_CHAR_CONST;
                                goto lex_end;

                        case '#':
                                if (cc->flags & CCF_KEEP_SIGN_NUM)
                                {
                                        cc->token = ch;
                                        goto lex_end;
                                }
                                if (Lex(cc) != TK_IDENT)        //skip '#'
                                        goto lex_end;
                                if (!(tmph = cc->hash_entry))
                                        goto lex_end;
                                if (!(tmph->type & HTT_KEYWORD))
                                        goto lex_end;
                                switch (i = tmph(CHashGeneric *)->user_data0)
                                {
                                        case KW_INCLUDE:
                                                if (Lex(cc) != TK_STR)
                                                        goto lex_end;
                                                fbuf = ExtDefault(cc->cur_str, "CC");
                                                buf2 = FileNameAbs(fbuf);
                                                Free(fbuf);
                                                if (Bt(&sys_run_level, RLf_DOC))
                                                        LexAttachDoc(cc,,, buf2);
                                                else
                                                        LexIncludeStr(cc, buf2, FileRead(buf2), TRUE);
                                                Free(buf2);
                                                break;

                                        case KW_DEFINE:
                                                cc->flags |= CCF_NO_DEFINES;
                                                if (Lex(cc) == TK_IDENT)
                                                {
                                                        tmph = CAlloc(sizeof(CHashDefineStr));
                                                        tmph->str = cc->cur_str;
                                                        cc->cur_str = 0;
                                                        tmph->type = HTT_DEFINE_STR;
                                                        HashSrcFileSet(cc,tmph);

                                                        do ch = LexCharGet(cc); //skip space between define name and start
                                                        while (Bt(char_bmp_non_eol_white_space, ch));

                                                        i = j = 0;
                                                        buf2 = NULL;
                                                        if (ch)
                                                        {
                                                                in_str = FALSE;
                                                                do
                                                                {
                                                                        if (ch == '\\')
                                                                        {
                                                                                if (ch = LexCharGet(cc))
                                                                                {
                                                                                        if (ch != '\r' && ch != '\n')
                                                                                        {
                                                                                                buf[j++] = '\\';
                                                                                                buf[j++] = ch;
                                                                                        }
                                                                                        else if (ch == '\r' && LexCharGet(cc) != '\n')
                                                                                                cc->flags|=CCF_USE_LAST_U16;
                                                                                }
                                                                                else
                                                                                {
                                                                                        buf[j++] = '\\';
                                                                                        break;
                                                                                }
                                                                        }
                                                                        else if (ch != '\n')
                                                                        {
                                                                                if (ch == '\"')
                                                                                        in_str = !in_str;
                                                                                buf[j++] = ch;
                                                                        }
                                                                        else
                                                                                break;
                                                                        while (ch = LexCharGet(cc))
                                                                        {
                                                                                if (ch == '/') {
                                                                                        ch = LexCharGet(cc);
                                                                                        if (ch == '/' && !in_str)
                                                                                        {
                                                                                                do ch = LexCharGet(cc);
                                                                                                while (Bt(char_bmp_non_eol, ch));
                                                                                                break;
                                                                                        }
                                                                                        else
                                                                                        {
                                                                                                buf[j++] = '/';
                                                                                                cc->flags |= CCF_USE_LAST_U16;
                                                                                        }
                                                                                }
                                                                                else if (ch == '\\')
                                                                                {
                                                                                        if (ch = LexCharGet(cc))
                                                                                        {
                                                                                                if (ch == '\"')
                                                                                                {
                                                                                                        buf[j++] = '\\';
                                                                                                        buf[j++] = ch;
                                                                                                }
                                                                                                else
                                                                                                {
                                                                                                        cc->flags |= CCF_USE_LAST_U16;
                                                                                                        ch = '\\';
                                                                                                        break;
                                                                                                }
                                                                                        }
                                                                                }
                                                                                else if (Bt(char_bmp_non_eol, ch))
                                                                                {
                                                                                        if (ch == '\"')
                                                                                                in_str = !in_str;
                                                                                        buf[j++] = ch;
                                                                                }
                                                                                else
                                                                                        break;
                                                                                if (j >= STR_LEN - 4)
                                                                                {//Spot for ['\'][ch],[ch],[0]
                                                                                        buf[j++] = 0;
                                                                                        buf3 = MAlloc(i+j);
                                                                                        if (buf2)
                                                                                        {
                                                                                                MemCopy(buf3, buf2, i);
                                                                                                Free(buf2);
                                                                                                buf2 = buf3;
                                                                                                MemCopy(buf2 + i, buf, j);
                                                                                        }
                                                                                        else
                                                                                        {
                                                                                                buf2 = buf3;
                                                                                                MemCopy(buf2, buf, j);
                                                                                        }
                                                                                        i += j - 1;
                                                                                        j = 0;
                                                                                }
                                                                        }
                                                                }
                                                                while (ch == '\\');

                                                        }
                                                        buf[j++] = 0;
                                                        buf3 = MAlloc(i + j);
                                                        if (buf2)
                                                        {
                                                                MemCopy(buf3, buf2, i);
                                                                Free(buf2);
                                                                buf2 = buf3;
                                                                MemCopy(buf2 + i, buf, j);
                                                        }
                                                        else
                                                        {
                                                                buf2 = buf3;
                                                                MemCopy(buf2, buf, j);
                                                        }
                                                        tmph(CHashDefineStr *)->data = buf2;
                                                        tmph(CHashDefineStr *)->count = -1;
                                                        HashAdd(tmph,cc->htc.define_hash_table);
                                                }
                                                cc->flags &= ~CCF_NO_DEFINES;
                                                break;

                                        case KW_ELSE:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_ELSE;
                                                        goto lex_end;
                                                }
lex_else:
                                                j = 1;
                                                do
                                                {
                                                        if (ch = LexCharGet(cc))
                                                        {
                                                                if (ch == '#')
                                                                {
                                                                        if (!Lex(cc))
                                                                                goto lex_end;
                                                                        i = ParseKeyWord(cc);
                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                                                                j++;
                                                                        else if (i == KW_ENDIF)
                                                                                j--;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                }
                                                while (j);

                                                break;

                                        case KW_IF:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_IF;
                                                        goto lex_end;
                                                }
lex_if:
                                                cc->flags |= CCF_IN_IF;
                                                if (!Lex(cc))
                                                {
                                                        cc->flags &= ~CCF_IN_IF;
                                                        goto lex_end;
                                                }
                                                if (LexExpression(cc))
                                                {
                                                        cc->flags &= ~CCF_IN_IF;
                                                        switch (cc->token)
                                                        {
                                                                case TK_IF:             goto lex_if;
                                                                case TK_IFDEF:  goto lex_ifdef;
                                                                case TK_IFNDEF: goto lex_ifndef;
                                                                case TK_IFAOT:  goto lex_ifaot;
                                                                case TK_IFJIT:  goto lex_ifjit;
                                                                case TK_ELSE:   goto lex_else;
                                                                case TK_ENDIF:  goto lex_cont;
                                                                default:                goto lex_end;
                                                        }
                                                }
                                                else
                                                {
                                                        cc->flags &= ~CCF_IN_IF;
                                                        if (cc->token != TK_ENDIF && cc->token != TK_ELSE)
                                                        {
                                                                if (cc->token == TK_IF || cc->token == TK_IFDEF ||
                                                                                cc->token == TK_IFNDEF || cc->token == TK_IFAOT ||
                                                                                cc->token == TK_IFJIT)
                                                                        j = 2;
                                                                else
                                                                        j = 1;
                                                                do
                                                                {
                                                                        if (ch = LexCharGet(cc))
                                                                        {
                                                                                if (ch == '#')
                                                                                {
                                                                                        if (!Lex(cc))
                                                                                                goto lex_end;
                                                                                        i = ParseKeyWord(cc);
                                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF ||
                                                                                                        i == KW_IFAOT || i == KW_IFJIT)
                                                                                                j++;
                                                                                        else if (i == KW_ENDIF)
                                                                                                j--;
                                                                                        else if (i == KW_ELSE && j == 1)
                                                                                                break;
                                                                                }
                                                                        }
                                                                        else
                                                                        {
                                                                                cc->token = TK_EOF;
                                                                                goto lex_end;
                                                                        }
                                                                }
                                                                while (j);

                                                        }
                                                }
                                                break;

                                        case KW_IFDEF:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_IFDEF;
                                                        goto lex_end;
                                                }
lex_ifdef:
                                                cc->flags |= CCF_NO_DEFINES;
                                                if (!Lex(cc))
                                                {
                                                        cc->flags &= ~CCF_NO_DEFINES;
                                                        goto lex_end;
                                                }
                                                cc->flags &= ~CCF_NO_DEFINES;
                                                if (cc->token != TK_IDENT)
                                                        goto lex_end;
                                                if (cc->hash_entry)
                                                        goto lex_cont;
                                                j = 1;
                                                do
                                                {
                                                        if (ch = LexCharGet(cc))
                                                        {
                                                                if (ch == '#')
                                                                {
                                                                        if (!Lex(cc))
                                                                                goto lex_end;
                                                                        i = ParseKeyWord(cc);
                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                                                                j++;
                                                                        else if (i == KW_ENDIF)
                                                                                j--;
                                                                        else if (i == KW_ELSE && j == 1)
                                                                                break;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                }
                                                while (j);

                                                break;

                                        case KW_IFNDEF:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_IFNDEF;
                                                        goto lex_end;
                                                }
lex_ifndef:
                                                cc->flags |= CCF_NO_DEFINES;
                                                if (!Lex(cc))
                                                {
                                                        cc->flags &= ~CCF_NO_DEFINES;
                                                        goto lex_end;
                                                }
                                                cc->flags &= ~CCF_NO_DEFINES;
                                                if (cc->token != TK_IDENT)
                                                        goto lex_end;
                                                if (!cc->hash_entry)
                                                        goto lex_cont;
                                                j = 1;
                                                do
                                                {
                                                        if (ch = LexCharGet(cc))
                                                        {
                                                                if (ch == '#')
                                                                {
                                                                        if (!Lex(cc))
                                                                                goto lex_end;
                                                                        i = ParseKeyWord(cc);
                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                                                                j++;
                                                                        else if (i == KW_ENDIF)
                                                                                j--;
                                                                        else if (i == KW_ELSE && j == 1)
                                                                                break;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                }
                                                while (j);

                                                break;

                                        case KW_IFAOT:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_IFAOT;
                                                        goto lex_end;
                                                }
lex_ifaot:
                                                if (cc->flags & CCF_AOT_COMPILE)
                                                        goto lex_cont;
                                                j = 1;
                                                do
                                                {
                                                        if (ch = LexCharGet(cc))
                                                        {
                                                                if (ch == '#')
                                                                {
                                                                        if (!Lex(cc))
                                                                                goto lex_end;
                                                                        i = ParseKeyWord(cc);
                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                                                                j++;
                                                                        else if (i == KW_ENDIF)
                                                                                j--;
                                                                        else if (i == KW_ELSE && j == 1)
                                                                                break;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                }
                                                while (j);

                                                break;

                                        case KW_IFJIT:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_IFAOT;
                                                        goto lex_end;
                                                }
lex_ifjit:
                                                if (!(cc->flags & CCF_AOT_COMPILE))
                                                        goto lex_cont;
                                                j = 1;
                                                do
                                                {
                                                        if (ch = LexCharGet(cc))
                                                        {
                                                                if (ch == '#')
                                                                {
                                                                        if (!Lex(cc))
                                                                                goto lex_end;
                                                                        i = ParseKeyWord(cc);
                                                                        if (i == KW_IF || i == KW_IFDEF || i == KW_IFNDEF || i == KW_IFAOT || i == KW_IFJIT)
                                                                                j++;
                                                                        else if (i == KW_ENDIF)
                                                                                j--;
                                                                        else if (i == KW_ELSE && j == 1)
                                                                                break;
                                                                }
                                                        }
                                                        else
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                }
                                                while (j);

                                                break;

                                        case KW_ENDIF:
                                                if (cc->flags & CCF_IN_IF)
                                                {
                                                        cc->token = TK_ENDIF;
                                                        goto lex_end;
                                                }
                                                break;

                                        case KW_ASSERT:
                                                if (!Lex(cc))
                                                        goto lex_end;
                                                if (!LexExpression(cc))
                                                        LexWarn(cc, "Assert Failed ");
                                                goto lex_end;

                                        case KW_EXE:
                                                if (!Lex(cc))
                                                        goto lex_end;
                                                ParseStreamBlk(cc);
                                                goto lex_end;

                                        case KW_HELP_INDEX:
                                                if (Lex(cc) != TK_STR)
                                                        goto lex_end;
                                                Free(cc->cur_help_idx);
                                                cc->cur_help_idx = LexExtStr(cc,, FALSE);
                                                break;

                                        case KW_HELP_FILE:
                                                if (Lex(cc) != TK_STR)
                                                        goto lex_end;
                                                tmph = CAlloc(sizeof(CHashSrcSym));
                                                fbuf = ExtDefault(cc->cur_str, "DD");
                                                tmph->str = FileNameAbs(fbuf);
                                                Free(fbuf);
                                                tmph->type = HTT_HELP_FILE | HTF_PUBLIC;
                                                HashSrcFileSet(cc, tmph);
                                                HashAdd(tmph, cc->htc.global_hash_table);
                                                break;
                                }
                                break;

                        case '\n':
                                if (!(cc->flags & CCF_KEEP_NEW_LINES))
                                        break; //else fall through

                        case TK_INS_BIN:
                        case TK_INS_BIN_SIZE:
                                cc->token = ch;
                                goto lex_end;

                        case '.':
                                if (cc->flags & CCF_KEEP_DOT)
                                {
                                        cc->token = ch;
                                        goto lex_end;
                                }
                                if (cc->flags & CCF_LAST_WAS_DOT)
                                {
                                        cc->flags &= ~CCF_LAST_WAS_DOT;
                                        goto lex_dot_dot;
                                }
                                ch = LexCharGet(cc);
                                if ('0' <= ch <= '9')
                                {
                                        i = 0;
                                        goto lex_float_start;
                                }
                                else if (ch == '.')
                                {
lex_dot_dot:
                                        cc->token = TK_DOT_DOT;
                                        if (LexCharGet(cc) == '.')
                                                cc->token = TK_ELLIPSIS;
                                        else
                                                cc->flags |= CCF_USE_LAST_U16;
                                        goto lex_end;
                                }
                                cc->flags |= CCF_USE_LAST_U16;
                                cc->token = '.';
                                goto lex_end;

                        case '!':
                        case '$'...'&':
                        case '('...'-':
                        case '/':
                        case ':'...'?':
                        case '[':
                        case ']'...'^':
                        case '{'...'~':
                        case '`':
                                if (!(i = cmp.dual_U16_tokens1[ch]))
                                {
                                        if (ch == '$')
                                        {
                                                ch = LexCharGet(cc);
                                                if (ch == '$') {
                                                        cc->token = '$';
                                                        goto lex_end;
                                                }
                                                else if (ch)
                                                {
                                                        do ch = LexCharGet(cc);
                                                        while (ch && ch != '$');
                                                        if (!ch)
                                                        {
                                                                cc->token = TK_EOF;
                                                                goto lex_end;
                                                        }
                                                        else
                                                                goto lex_cont;
                                                }
                                                else
                                                {
                                                        cc->flags |= CCF_USE_LAST_U16;
                                                        cc->token = '$';
                                                        goto lex_end;
                                                }
                                        }
                                        else
                                        {
                                                cc->token = ch;
                                                goto lex_end;
                                        }
                                }
                                else
                                {
                                        j = LexCharGet(cc);
                                        if (i.u16[0] == j)
                                        {
                                                i >>= 16;
                                                if (!i)
                                                {// "/*"
                                                        j = 1;
                                                        do
                                                        {
                                                                if (!(ch = LexCharGet(cc)))
                                                                        return cc->token = TK_EOF;
lex_check_comment:
                                                                if (ch == '*')
                                                                {
                                                                        if (!(ch = LexCharGet(cc)))
                                                                                return cc->token = TK_EOF;
                                                                        if (ch == '/')
                                                                                j--;
                                                                        else
                                                                                goto lex_check_comment;
                                                                }
                                                                else if (ch == '/')
                                                                {
                                                                        if (!(ch = LexCharGet(cc)))
                                                                                return cc->token = TK_EOF;
                                                                        if (ch == '*')
                                                                                j++;
                                                                        else
                                                                                goto lex_check_comment;
                                                                }
                                                        }
                                                        while (j);

                                                        goto lex_cont;
                                                }
                                                else
                                                {
                                                        cc->token = i;
                                                        goto lex_end;
                                                }
                                        }
                                        if (i = cmp.dual_U16_tokens2[ch])
                                        {
                                                if (i.u16[0] == j)
                                                {
                                                        i >>= 16;
                                                        if (!i)
                                                        {// "//"
                                                                LexSkipEol(cc);
                                                                if (cc->flags & CCF_KEEP_NEW_LINES)
                                                                {
                                                                        cc->token = '\n';
                                                                        goto lex_end;
                                                                }
                                                                else
                                                                        goto lex_cont;
                                                        }
                                                        else
                                                        {
                                                                if (i == TK_SHL || i == TK_SHR)
                                                                {
                                                                        j = LexCharGet(cc);
                                                                        if (j == '=')
                                                                        {
                                                                                if (i == TK_SHL)
                                                                                        i = TK_SHL_EQU;
                                                                                else
                                                                                        i = TK_SHR_EQU;
                                                                        }
                                                                        else
                                                                                cc->flags |= CCF_USE_LAST_U16;
                                                                }
                                                                cc->token = i;
                                                                goto lex_end;
                                                        }
                                                }
                                                if (i = cmp.dual_U16_tokens3[ch])
                                                {
                                                        if (i.u16[0] == j)
                                                        {
                                                                cc->token = i.u16[1];
                                                                goto lex_end;
                                                        }
                                                }
                                        }
                                        cc->flags |= CCF_USE_LAST_U16;
                                        cc->token = ch;
                                        goto lex_end;
                                }
                        case TK_TKS_NUM:
                                break;
                }
        }
lex_end:
        LexCharGet(cc); //Do this so WAS_NEW_LINE is right
        cc->flags |= CCF_USE_LAST_U16;

        return cc->token;
}