/// unit obsahujuci konstanty a globalne premmene pre cely program
/// okrem toho je tu definovane pole znakov, kvoli rychlejsim zretazeniam stringov
/// @see TCharacterAccumulator
{$I main.inc}
unit constants;

interface

uses
  sysutils, Graphics;

const
/// najvyssia hodnota znaku (255 pre AnsiChar, 65535 pre WideChar)
  CHAR_HIGH = Int64(High(char));

type
{$IFDEF WIDESTRINGS}
/// definicie typov pre spracovavanie UTF 16 textov
  char = WideChar; xString = WideString;
{$ELSE}
/// definicie typov pre spracovavanie ASCII textov
  char = AnsiChar; xString = AnsiString;
{$ENDIF}

  /// pole znakov pre rychlejsie stringove operacie (pouzivane namiesto + operatora v Delphi na klucovych miestach)
  TCharacterAccumulator = record
    a: array of char;
    count,allocated: Integer;
  end;

const
/// pocet bytov, ktore zabera jeden char v pamati (1 pre AnsiChar, 2 pre WideChar)
  CHAR_SIZE = SizeOf(char);
/// max unreadchar = SIZE/CHAR_SIZE/2
/// min SIZE = x*4 where x=1, so here x is least amount of unreadchar possible
  FILE_READER_BUFFER_SIZE = 80000*4;

/// maximalny pocet undo-able znakov vo filereaderi
  FILE_READER_MAX_UNREAD = FILE_READER_BUFFER_SIZE / CHAR_SIZE / 2;
/// used when parsing files, can be set by property {Line End Char} in .grm file
  LINE_END_CHAR = #10;

/// velkost mnoziny language strigov v programe (pre jeden jazyk)
  LANG_RES_SIZE = 4000;
/// zakladny offset v language subore
  LANG_RES_OFFSET = 0;

/// used as end of line in text output
  EOL: xString = #13#10;
/// znak tabulatoru
  TAB: xString = #9;

/// {Whitespace}
  SET_WS: xString = ' '#9#10#13;
/// whitespace in .grm file when read by application
  SET_INLINEWS: xString = ' '#9#13;
/// {Op}
  SET_OPS: xString = '+-*?|=()';
/// {Alpha}
  SET_Alpha: xString = 'abcdefghijklmnopqrstuvwxyz';
/// {AlphaCapital}
  SET_AlphaCaps: xString = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
/// {Digit}
  SET_Number: xString = '0123456789';
/// {RegExpOp}
  SET_RegExpOps: xString = '()+*?|';
/// {SLS}
  SET_SPECIALLINESSYMBOLS = '^~&%';

/// char only! EOL unix friendly (sometimes), only used when reading .grm file
  SET_EOLWS: char = #10;
/// char only!, used only when analyzing grammar
  SET_EOLFILLER: char = #13;
/// char only!, used only when analyzing grammar
  SET_TABCHAR: char = #9;

/// linktype - epsilon - NFA
  LT_EPS = 0;
/// linktype - character - NFA
  LT_CHAR = 1;
/// linktype - character set - NFA
  LT_SET = 2;

/// (error)
  GT_ERROR = -1;
/// #10
  GT_EOL = 0;
/// "..."
  GT_PROPERTY = 1;
/// {...}
  GT_SET = 2;
/// [...]
  GT_SETSTRING = 3;
/// !...
  GT_COMMENT = 4;
/// '...'
  GT_STRING = 5;
/// ...
  GT_TERMINAL = 6;
/// <...>
  GT_STATE = 7;
/// +-*?|=()
  GT_OP = 8;
/// ::=
  GT_ASSIGN = 9;
/// (eof)
  GT_EOF = 10;
/// ^ at the beginning of line
  GT_EQ = 11;
/// ~ at the beginning of line
  GT_SIM = 12;
/// $ at the beginning of line
  GT_IND = 13;
/// % at the beginning of line
  GT_HL = 14;

/// maximalny identifikator terminalu (pocet terminalov)
  MAX_TERMINAL = 1000000000;
/// max identifikator neterminalu
  MAX_NONTERMINAL = 2000000000;

/// used mainly in First, Follow - DO NOT use as NFA accept state (accept with 1+ only, cause 1 is error, other should be higher)
  L_EPSILON = 0;
/// identifikator terminalu urcujuceho lexikalnu chybu
  L_ERROR = 1;
/// identifikator terminalu oznacujuceho koniec suboru
  L_EOF = 2;

/// terminal which is used for ignoring input in lexer - should be set in properties in .grm
//  L_WS = 3;

/// identifikator terminalu urcujuceho virtualny terminal
  L_DUMMY = 4;

/// prvy normalny terminal (odtialto nasleduju uz iba normalne terminaly)
  L_T_BEGIN = 5;


/// REJECT - if we are left with many subtrees after parsing (unsuccessful parsing), new node will combine them with L_SPECIAL as root
  L_SPECIAL = MAX_TERMINAL + 1;
/// start symbol' -> start symbol EOF
  L_S = MAX_TERMINAL + 2;

/// prvy normalny neterminal
  L_NT_BEGIN = MAX_TERMINAL + 3;

/// prefix nazvu mnoziny pre mnoziny generovane vymenovanim znakov v []
  DUMMY_SET_NAME_PREFIX = 'DUMMY_';
/// prefix nazvu mnoziny pre mnoziny generovane stringom
  DUMMY_SET_STRING_NAME_PREFIX = 'DUMMY__';
/// prefix pre terminaly zozbierane pri definiciach pravidiel !TODO! STR__ - '' only for better console output, generates warnings though
  DUMMY_TERMINAL_STRING_NAME_PREFIX = '';

//LCS diff constants
const

/// needs to be at least 1, and one higher than maximum num of diffs in sequences;)
      MAX_D_PATH = 10000000;

/// edit script operation - not compared
      ES_NOT_COMPARED = 0;
/// edit script operation - inserted
      ES_INSERT = 1;
/// edit script operation - deleted
      ES_DELETE = 2;
/// edit script operation - modified
      ES_CHANGE = 3;
/// edit script operation - matched
      ES_MATCH = 4;
/// edit script operation - moved
      ES_MOVE = 5;

/// edit script combined
      ES_COMBINED = 10;

//*****************STRING CODES********************
  STR_LANGID = 0;
  STR_YES = 1;
  STR_NO = 2;
  STR_CANCEL = 3;
  STR_MAYBE = 4;
  STR_ERROR = 5;
  STR_ERROR_IN_1 = 6;
  STR_WARNING = 7;
  STR_WARNING_IN_1 = 8;
  STR_SUCCESS = 9;
  STR_SUCCESS_IN_1 = 10;
  STR_NAME = 100;
  STR_SIZE = 101;
  STR_MODIFIED = 102;
  STR_DIFF_COUNT = 103;
  STR_REL_FOLDER = 104;
  STR_ID = 105;
  STR_REGEXP = 106;
  STR_RIGHT_SIDE = 107;
  STR_POSITION = 108;
  STR_LEFT_SIDE = 109;
  STR_LR0ITEM = 110;
  STR_LOOKAHEAD = 111;
  STR_RULENUMBER = 112;
  STR_ACTIONTYPE = 113;
  STR_TOKEN = 114;
  STR_ACTION = 115;
  STR_SHIFT = 116;
  STR_REDUCE = 117;
  STR_SYMBOL = 118;
  STR_STATE = 119;
  STR_ACCEPT = 120;

//*****************ERROR CODES*********************
  E_GF_UNEXPECTED_CHAR_FOUND_1 = 1001;
  E_GF_EXPECTED_1_INSTEAD_OF_EOL = 1002;
  E_GF_EXPECTED_1 = 1003;
  E_GF_EXPECTED_1_INSTEAD_OF_EOF = 1004;
  E_GF_PROPERTY_EXPECTED_EQ_INSTEAD_OF_1 = 1005;
  E_GF_PROPERTY_EXPECTED_STRING_OR_STATE_INSTEAD_OF_1 = 1006;
  E_GF_SET_EXPECTED_EQ_INSTEAD_OF_1 = 1007;
  E_GF_SET_EXPECTED_STRING_OR_STATE_OR_SETSTRING_INSTEAD_OF_1 = 1008;
  E_GF_REGEXP_INVALID_OPERATOR_1_FOUND_REGEXPOP_EXPECTED = 1009;
  E_GF_REGEXP_TOO_MANY_CLOSING_BRACKETS_1_CORRESPONDING_OB_MISSING = 1010;
  E_GF_TERMINAL_EXPECTED_EQ_INSTEAD_OF_1 = 1011;
  E_GF_STATE_EXPECTED_ASSIGN_INSTEAD_OF_1 = 1012;
  E_GF_RULE_EXPECTED_STATE_OR_STRING_OR_OP_INSTEAD_OF_1 = 1013;
  E_GF_RULE_INVALID_OPERATOR_1_IN_RULE_2_DEFINITION_ONLY_OR_ALLOWED = 1014;
  E_GF_RULE_TERMINAL_WITH_NAME_1_NOT_DEFINED = 1015;
  E_GF_RULE_EMPTY_OR_NOT_VALID_RIGHT_SIDE_1 = 1016;
  E_GF_START_SYMBOL_NOT_DECLARED_AND_NO_VALID_RULES_DECLARED = 1017;
  E_GF_NONTERMINAL_1_IN_NO_RULE_AS_HEADER = 1018;
  E_GF_LOAD_ERROR_IN_FILE_1 = 1019;
  E_GF_ERROR_IN_TERMINAL_PARSING_1 = 1020;
  E_GF_ERROR_IN_STATE_PARSING_1 = 1021;
  E_GF_INTEGER_NUMBER_EXPECTED_INSTEAD_OF_1 = 1022;
  E_GF_TERMINAL_OR_NONTERMINAL_1_NOT_DEFINED = 1023;
  E_GF_TERMINAL_OR_NONTERMINAL_1_ALREADY_IN_OTHER_EQUIVALENCE_SET = 1024;
  E_GF_TERMINAL_OR_NONTERMINAL_1_ALREADY_IN_OTHER_SIMILARITY_SET = 1025;
  E_GF_TERMINAL_STATE_OR_STRING_EXPECTED_INSTEAD_OF_1 = 1026;
  E_PARSING_INVALID_TOKEN = 1027;
  E_PARSING_PARSE_ERRORS_THRESHOLD_EXCEEDED = 1028;
  E_PARSING_NO_POSSIBLE_ACTION = 1029;

//****************WARNING CODES********************
  W_RES_STRING_MISSING = 2000;

  W_GF_TERMINAL_REDEFINED_1 = 2001;
  W_GF_SET_REDEFINED_1 = 2002;
  W_GF_REGEXP_SET_1_NOT_DEFINED_CREATING_DUMMY_2 = 2003;
  W_GF_REGEXP_EMPTY_STRING_IN_TOKEN_1_DEFINITION = 2004;
  W_GF_SET_SET_1_NOT_DEFINED = 2005;
  W_GF_RULE_EMPTY_STRING_1_IN_RULE_2_DEFINITION_EPSILON = 2006;
/// hint
  W_GF_RULE_TERMINAL_WITH_NAME_1_ALREADY_EXISTS_POSSIBLE_MISTAKE = 2007;
  W_GF_START_SYMBOL_NOT_DECLARED_USING_FIRST_FOUND_1 = 2008;
  W_GF_START_SYMBOL_1_RULE_IS_MISSING = 2009;
  W_GF_START_SYMBOL_MISSING_USING_FIRST_FOUND_1 = 2010;
  W_GF_SUPPOSED_WS_TERMINAL_1_IS_NOT_EVEN_DEFINED = 2011;
  W_GF_RULE_EXACT_SAME_RULE_FOR_HEAD_1_ALREADY_DEFINED_AT_POS_2 = 2012;
/// ak to neni WS Terminal - lebo potom use ma ;)
  W_GF_TERMINAL_1_DECLARED_BUT_NOT_USED = 2013;
/// hint
  W_GF_RULE_EXPECTED_RULE_HEADER_OR_SEPARATOR_AS_FIRST_SYMBOL_ON_NEW_LINE_INSTEAD_OF_1 = 2014;
  W_GF_SUPPOSED_COMMENT_TERMINAL_1_FROM_PROPERTY_2_IS_NOT_EVEN_DEFINED = 2015;
  W_GF_SUPPOSED_EOLNWS_TERMINAL_1_IS_NOT_EVEN_DEFINED = 2016;
  W_PB_SHIFT_REDUCE_SHIFT = 2017;
  W_PB_SHIFT_REDUCE_REDUCE = 2018;
  W_PB_REDUCE_REDUCE_ORIG = 2019;
  W_PB_REDUCE_REDUCE_REDUCE = 2020;
  W_PARSING_SHIFT_REDUCE_SHIFT = 2021;
  W_PARSING_SHIFT_REDUCE_REDUCE = 2022;
  W_PARSING_REDUCE_REDUCE_REDUCE = 2023;

//*************FUNCTIONS ON CONSTANTS**************
  function GT_LENGTH(x: Integer): Integer;
//  function GT_NAME(x: Integer): xString;

//*****************FUNCTIONS***********************
  function BRIGHTER_COLOR(c: TColor): TColor;
  function DARKER_COLOR(c: TColor): TColor;
  procedure createGCA;
  procedure addtoGCA(c: char);
  procedure addStringtoGCA(const S: xString);
  procedure clearGCA;
  procedure freeGCA;
  procedure ArrayMemCopyB(const Source; var Dest; Count : Integer);
  procedure ArrayMemCopyBtoDW(const Source; var Dest; Count : Integer);
  procedure toStringGCA(var result: xString);
  function lengthGCA: Integer;
  procedure cuttoGCA(x: Integer);

  function resolveSimpleSeq(const S: xString): xString;
  function makeSimpleSeq(const S: xString): xString;

var
/// urcuje standardnu hodnotu toho, ci sa vo vstupnych suboroch rozlisuju velke a male pismena (Delphi nie, C++ ano, Java ano, a pod.)
  DEFAULT_CASE_SENSITIVITY: Boolean = false;
/// urcuje standardnu hodnotu toho, ci sa komentare vkladaju do parsovacieho stromu
  DEFAULT_PARSE_COMMENTS: Boolean = false;


/// urcuje ci sa pouziva namiesto definovaneho formatovania v subore popisujucom gramatiku specialne formatovanie, ze vystup vyzera ako parsovaci strom
  TREE_FORMATTING: Boolean = false;
/// urcuje ci sa pri viacriadkovych komentaroch v dalsich riadkoch urdrziava odsadenie
  MULTI_LINE_COMMENTS_IND: Boolean = true;

/// used for quiting quadratic space algorithms
  SANE_ARRAY_SIZE_LIMIT: Integer = $8000000;
/// used for halting FOR cycles when FGlobalHalt is set
  CYCLE_THRESHOLD: Integer = $3FF;
/// udava na kolko medzier sa transformuje TAB pri vypise
  TAB_SPACES: Integer = 2;
/// udava maximalny pocet nacitani virtualnych tokenov po sebe, max cycling = MAX_SIZE_... + 2 * MAX_NUMBER_...
  MAX_NUMBER_OF_TURNS_FROM_INSERTED_SYMBOLS: Integer = 10;
/// udava maximalny virtualnych tokenov vo fronte
  MAX_SIZE_OF_INSERTED_SYMBOLS_QUEUE: Integer = 10;
/// udava maximalny pocet parsovacich chyb pred stopnutim parsovania
  PARSE_ERRORS_THRESHOLD: Integer = 30;
/// udava maximalny pocet lexikalnych chyb pred stopnutim parsovania
  LEX_ERRORS_THRESHOLD: Integer = 300;

/// urcuje ci sa rozlisuju velke a male pismena pri riadkovom porovnavani
  DIFF_CASE_SENSITIVE: Boolean = true;
/// urcuje ci sa filtruje whitespace pri riadkovom porovnavani
  DIFF_WS_FILTERING: Boolean = false;
/// mnozina znakov, ktora sa odfiltruje pri riadkovom porovnavani (flat diff)
  DIFF_WS: xString = ' '#9#10#13;
/// cca max number of chars in one line when pretty printing
  DEFAULT_LINECHAR_LIMIT_IN_NO_INPUT_MODE: Integer = 80;
/// standardna hodnota skore pre zhodne tokeny v TreeScore algoritme
  DEFAULT_EQ_SCORE: Integer = 1;
/// standardna hodnota skore pre podobne tokeny v TreeScore algoritme
  DEFAULT_SIM_SCORE: Integer = 0;

/// urcuje ci su synchronizovane scrollbary vo folderdiff okne
  FXSynchronizedScrollBars: Boolean = true;
/// urcuje ci su synchronizovane scrollbary vo filediff okne
  FYSynchronizedScrollBars: Boolean = true;
/// urcuje ci pri nacitavani suborov prezerame rekurzivne podadresare
  FXRecursiveFolders: Boolean = true;
/// urcuje ci je zapnute formatovanie textu
  FEnabledFormatting: Boolean = false;
/// urcuje ci pri formatovanom texte pouzivane aj definovane pozadie pre text
  FFormattingWithBkColor: Boolean = true;
/// urcuje ci nezafarbujeme prazdne miesta (riadky)
  FDisableWSDiffsColoring: Boolean = true;

/// urcuje ci konvertujeme NFA na DFA pri vytvarani parsera
  FAlwaysConvertToDFA: Boolean = true;

/// urcuje ci sa uz v Lexeri robi konverzia na lowercase hodnoty tokenov  !TODO! neni v options...
  CASE_CONVERSION: Boolean = false;
/// urcuje ci pocitame aj v ramci jedneho riadku LCS (pre vysvieteny riadok)
  FSelectedLineLCS: Boolean = true;

/// urcuje ci logujeme spravy do listboxu
  FListBoxLogsEnabled: Boolean = true;
/// urcuje zobrazujeme chyby v listboxe
  FListBoxShowErrors: Boolean = true;
/// urcuje zobrazujeme upozornenia v listboxe
  FListBoxShowWarnings: Boolean = true;
/// urcuje zobrazujeme ostatne spravy v listboxe
  FListBoxShowMiscs: Boolean = false;

(*
  clBlack = TColor($000000);
  clMaroon = TColor($000080);
  clGreen = TColor($008000);
  clOlive = TColor($008080);
  clNavy = TColor($800000);
  clPurple = TColor($800080);
  clTeal = TColor($808000);
  clGray = TColor($808080);
  clSilver = TColor($C0C0C0);
  clRed = TColor($0000FF);
  clLime = TColor($00FF00);
  clYellow = TColor($00FFFF);
  clBlue = TColor($FF0000);
  clFuchsia = TColor($FF00FF);
  clAqua = TColor($FFFF00);
  clLtGray = TColor($C0C0C0);
  clDkGray = TColor($808080);
  clWhite = TColor($FFFFFF);
*)
(*
  COLOR_TEXTBACKGROUND: TColor = clLtGray;  //default
  COLOR_GUTTER: TColor = clTeal;
  COLOR_NEWGUTTER: TColor = clNavy;
  COLOR_INSERT: TColor = clYellow;
  COLOR_DELETE: TColor = clRed;
  COLOR_CHANGE: TColor = clBlue;
  COLOR_MATCH: TColor = clOlive;//clAqua; //clLtGray;  //used only in folderdiff
  COLOR_NOT_COMPARED: TColor = clOlive;  //used also as match color in filediff
*)
  COLOR_TEXTBACKGROUND: TColor = 12632256;
  COLOR_GUTTER: TColor = 8421376;
  COLOR_NEWGUTTER: TColor = 8388608;
  COLOR_INSERT: TColor = 8388607;
  COLOR_DELETE: TColor = 8355839;
  COLOR_CHANGE: TColor = 16744319;
  COLOR_MATCH: TColor = 12632256;
  COLOR_NOT_COMPARED: TColor = 12632256;

  TCOLOR_DEFAULT: TColor = clBlack;
  TSTYLE_DEFAULT: TFontStyles = [];
  TSTYLE_DEFAULT_INT: Integer = 0;

  COLOR_COMBINED: TColor = clPurple;
  COLOR_PB_SCROLLBAR_OUTLINE: TColor = clBlack;

  TCOLOR_GUTTER: TColor = clLtGray;
  TCOLOR_NEWGUTTER: TColor = clLtGray;
  TCOLOR_COMBINED: TColor = clBlack;

  TCOLOR_INSERT: TColor = clBlack;
  TCOLOR_DELETE: TColor = clBlack;
  TCOLOR_CHANGE: TColor = clBlack;
  TCOLOR_MATCH: TColor = clBlack;
  TCOLOR_NOT_COMPARED: TColor = clBlack;

/// urcuje ci sa prazdne miesta po tokene, ktorym konci predosly riadok, vlozia na uvod noveho riadku, ak v nom este nic ine ako odsadenie nie je
  NEW_LINE_PREV_LINE_TOKEN_ASPACES: Boolean = false;

/// urcuje ci sa od posledneho strukturalneho porovnania stromov stromy zmenili
  GLOBAL_CHANGE: Boolean = true;
  LastGrammarPath: xString = 'test\' + 'delphi.grm';
  LastLeftPath: xString = 'test\' + 'x\p.pas';
  LastRightPath: xString = 'test\' + 'y\p.pas';
  LastFolderDir1Path: xString = 'test\' + 'x\';
  LastFolderDir2Path: xString = 'test\' + 'y\';
  LastFile1Path: xString = 'test\' + 'x\p.pas';
  LastFile2Path: xString = 'test\' + 'y\p.pas';

/// globalne pole znakov, urcene na zrychlovanie stringovych operacii (najma operacie zretazenia)
  GlobalCharAccumulator: TCharacterAccumulator;
  last_lexer_build_time: Integer = 0;
  last_DFA_build_time: Integer = 0;
  last_LALR_build_time: Integer = 0;
  last_parse1_build_time: Integer = 0;
  last_parse2_build_time: Integer = 0;

/// boolean urcujuci, ci sme v stave zastavovania vykonavania nejakej funkcie
  FGlobalHalt: Boolean = false;
/// pocet zdisablovani tlacidiel (ked je rovne 0, tak su tlacidla enabled)
  FDisableCount: Integer = 0;

/// je nastaveny na adresar, v ktorom sa nachadza .exe subor
  FCurrentDirectory: xString = '';
implementation

/// funkcia na konvertovanie retazcov s \{cislo} escape sekvenciami na normalne stringy
function resolveSimpleSeq(const S: xString): xString;
var Snum: xString;
    i: Integer;
begin
  result := '';
  Snum := '';
  for i := 1 to Length(S) do begin
    if S[i] = '\' then begin
      if Snum <> '' then begin
        result := result + char(StrToIntDef(Snum,0));
      end;
      Snum := '';
    end
    else
      Snum := Snum + S[i];
  end;
  if Snum <> '' then begin
    result := result + char(StrToIntDef(Snum,0));
  end;
end;

/// funkcia na konvertovanie retazcov na retazce zlozene z \{cislo} escape sekvencii
function makeSimpleSeq(const S: xString): xString;
var i: Integer;
begin
  result := '';
  for i := 1 to Length(S) do
    result := result + '\' + IntToStr(ord(S[i]));
end;

/// funkcia vracajuca pocet okrajovych znakov pre token pri analyze vstupnej gramatiky
function GT_LENGTH(x: Integer): Integer;
begin
  case x of
    1..3,5,7: result := 2;
           4: result := 1
  else
    result := 0;
  end;
end;

/// funkcia vracajuca zhruba o polovicu svetlejsiu farbu od vstupnej farby
function BRIGHTER_COLOR(c: TColor): TColor;
var r,g,b: Integer;
begin
  r := (c and $FF0000) shr 16;
  g := (c and $00FF00) shr 8;
  b := (c and $0000FF);
  result := (($FF + r) shr 1)  shl 16 + (($FF + g) shr 1) shl 8 + (($FF + b) shr 1);
end;

/// funkcia vracajuca tmavsiu farbu od vstupnej farby
function DARKER_COLOR(c: TColor): TColor;
var r,g,b: Integer;
begin
  r := (c and $FF0000) shr 16;
  g := (c and $00FF00) shr 8;
  b := (c and $0000FF);
  result := (r shr 2 + r shr 1)  shl 16 + (g shr 2 + g shr 1) shl 8 + (b shr 2 + b shr 1);
end;

/// procedura na vytvorenie pola znakov - TCharacterAccumulator
procedure createGCA;
begin
  GlobalCharAccumulator.allocated := 4096;
  SetLength(GlobalCharAccumulator.a,GlobalCharAccumulator.allocated);
end;

/// procedura na pridanie znaku do pola znakov - TCharacterAccumulator
procedure addtoGCA(c: char);
begin
  GlobalCharAccumulator.a[GlobalCharAccumulator.count] := c;
  Inc(GlobalCharAccumulator.count);
  if GlobalCharAccumulator.count = GlobalCharAccumulator.allocated then begin
    GlobalCharAccumulator.allocated := GlobalCharAccumulator.allocated shl 1;
    SetLength(GlobalCharAccumulator.a,GlobalCharAccumulator.allocated);
  end;
end;

/// procedura na vymazanie vsetkych znakov z pola znakov - TCharacterAccumulator
procedure clearGCA;
begin
  GlobalCharAccumulator.count := 0;
end;

/// procedura na uvolnenie pola znakov z pamate - TCharacterAccumulator
procedure freeGCA;
begin
  GlobalCharAccumulator.a := nil;
end;

/// procedura v asm, na kopirovanie count bytov zo source do dest, po bytoch - TCharacterAccumulator
procedure ArrayMemCopyB(const Source; var Dest; Count : Integer);
asm
//ECX = Count
//EAX = Const Source
//EDX = Var Dest

        cmp   ECX,0
        je    @JustQuit

        push  ESI
        push  EDI

        mov   ESI, EAX
        mov   EDI, EDX

        //hmm, radsej repnz movsb ?
    @Loop:
        mov   AL, [ESI]
        inc   ESI
        mov   [EDI], AL
        inc   EDI
        dec   ECX
        jnz   @Loop

        pop   EDI
        pop   ESI
    @JustQuit:
end;

/// procedura v asm, na kopirovanie count bytov zo source do dest, po dvojslovach(DW) - TCharacterAccumulator
procedure ArrayMemCopyBtoDW(const Source; var Dest; Count : Integer);
asm
//ECX = Count
//EAX = Const Source
//EDX = Var Dest

        cmp   ECX,0
        je    @JustQuit

        push  ESI
        push  EDI

        mov   ESI, EAX
        mov   EDI, EDX

        xor   EAX, EAX
    @Loop:
        mov   AL, [ESI]
        inc   ESI
        mov   [EDI], EAX
        add   EDI,4
        dec   ECX
        jnz   @Loop

        pop   EDI
        pop   ESI
    @JustQuit:
end;

/// procedura v asm, na kopirovanie count bytov zo source do dest, po slovach(W) - TCharacterAccumulator
procedure ArrayMemCopyW(const Source; var Dest; Count : Integer);
asm
//ECX = Count
//EAX = Const Source
//EDX = Var Dest

        cmp   ECX,0
        je    @JustQuit

        push  ESI
        push  EDI

        mov   ESI, EAX
        mov   EDI, EDX

    @Loop:
        mov   AX, [ESI]
        inc   ESI
        inc   ESI
        mov   [EDI], AX
        inc   EDI
        inc   EDI
        dec   ECX
        jnz   @Loop

        pop   EDI
        pop   ESI
    @JustQuit:
end;

(*
function toStringGCA: xString;
begin
  SetLength(result,GlobalCharAccumulator.count);
  if CHAR_SIZE = 1 then
    FastCharMove(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count)
  else if CHAR_SIZE = 2 then
    FastCharMove(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count shl 1)
  else
    FastCharMove(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count * CHAR_SIZE)
end;
*)

/// procedura na skonvertovanie pola znakov do stringu - TCharacterAccumulator
procedure toStringGCA(var result: xString);
begin
  SetLength(result,GlobalCharAccumulator.count);
  if CHAR_SIZE = 1 then
    ArrayMemCopyB(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count)
  else if CHAR_SIZE = 2 then
    ArrayMemCopyW(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count)
  else
    ArrayMemCopyB(GlobalCharAccumulator.a[0],result[1],GlobalCharAccumulator.count * CHAR_SIZE);  //how come ?
end;

/// funkcia na zistenie dlzky pola znakov - TCharacterAccumulator
function lengthGCA: Integer;
begin
  result := GlobalCharAccumulator.count;
end;

/// procedura na useknutie dlzky pola znakov na x znakov - TCharacterAccumulator
procedure cuttoGCA(x: Integer);
begin
  GlobalCharAccumulator.count := x;
end;

/// procedura na pridanie stringu do pola znakov (operacia +) - TCharacterAccumulator
procedure addStringtoGCA(const S: xString);
begin
  if CHAR_SIZE = 1 then begin
    if GlobalCharAccumulator.count + Length(S) >= GlobalCharAccumulator.allocated then begin
      GlobalCharAccumulator.allocated := (GlobalCharAccumulator.allocated + Length(S)) shl 1;
      SetLength(GlobalCharAccumulator.a,GlobalCharAccumulator.allocated);
    end;
    ArrayMemCopyB(S[1],GlobalCharAccumulator.a[GlobalCharAccumulator.count],Length(S));
    GlobalCharAccumulator.count := GlobalCharAccumulator.count + Length(S);
  end
  else begin
    if GlobalCharAccumulator.count + Length(S) >= GlobalCharAccumulator.allocated then begin
      GlobalCharAccumulator.allocated := (GlobalCharAccumulator.allocated + Length(S)) shl 1;
      SetLength(GlobalCharAccumulator.a,GlobalCharAccumulator.allocated);
    end;
    ArrayMemCopyW(S[1],GlobalCharAccumulator.a[GlobalCharAccumulator.count],Length(S));
    GlobalCharAccumulator.count := GlobalCharAccumulator.count + Length(S);
  end;
end;

initialization
  createGCA;

finalization
  freeGCA;
end.
