/*
//----------------------------------------------------------------------------
// C++ version: creates C++/gcc compilable project from a compiled AL4 program
//----------------------------------------------------------------------------
// (C) by Vladimir Kladov, 2017-2020
//----------------------------------

CLASS {Generator|_of_C_gcc_compilable},
	RECURSIVE, UNTESTED, STOPPING, BYTES, BITWISE :

IMPORT: {Compiler}, {Type}, {Text_file}, {Variable}, {Function},
        {Statement}, {Assignment}, {For}, {Case}, {Expression}, {Statistics} .
IMPORT: {String_functions}, {System_functions}, {Console}, {File_path},
        {Parser}, {Text_parser}, {Localize_str}, {Date_time} .
IMPORT: {Memory_stream}, {File_stream}, {Stream} .

FUNCTION TARGET_LANG|UAGE(
{Compiler} C|ompiler_dummy) ==> STR := "C++" .

FUN Tests_available ==> BOOL : RESULT = TRUE .

FUN Optimizations_allowed(
{Compiler} C|ompiler_obj_DUMMY) ==> BOOL : RESULT = TRUE .

FUN Additional_classes|_maybe_add_Console_app(
{Compiler} C|ompiler_obj) : .

CONST BOOL: ALLOW_EXIT_IN_NATIVE|_FUNCTIONS_BEFORE_NATIVE_CODE = FALSE .

CONST BOOL: SUPPORTS_NATIONAL_NAMES|_FOR_VARS_FUNCTIONS_TYPES = FALSE .

{Compiler} Comp|iler
STR o|out_source[]

-------------------------- 'string expressions control'
STR spaces|_prefix
STR kstr|ing_kind
STR final_str|ing_type
STR wxT|ranslation
	
BOOL Is_windows_target
STR Cpp_flags|_to_add_in_command_line

    

FUNCTION Prepare_project_generator(
	{Compiler} C|ompiler_obj) ==> {Generator}, NEW
	:
	g|enerator_temp = {Generator}(Comp = C)
	RESULT = g
	g.msvstudio = "$MSVSTUDIO" IN C.Defined_name[]  .
	
BOOL msvstudio

FUNCTION Create_project(
	{Generator} G|enerator, {Compiler} C|ompiler_obj) ==> BOOL
	:
	{Generator} g|enerator_passed = G
	g.structures_declared[].Clear	
	g.classes_generated[].Clear
	g.instances[].Clear
	-------------- 'check options $AAAAAA'
	Console_color('CYAN')
	FOR dn IN C.Defined_name[] :
	    CASE dn ?
	    ["$NOTESTS", "$ALLTESTS"]:
	    	CASE "$NOTESTS" IN C.Defined_name[]
	    	     && "$ALLTESTS" IN C.Defined_name[]
	    	     ?
	    	     C.Error("Options /$NOTESTS and /$ALLTESTS are excluding "
	    	     "each other")
	    	;
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	CASE ?
	    	["$NOTESTS" IN C.Defined_name[]] ?
	    	     << "option /$NOTESTS is set - no tests will be done"#NL
	    	["$ALLTESTS" IN C.Defined_name[]] ?
	    	     << "option /$ALLTESTS is set - tests will be provided anyway"#NL
	    	     
	    	ELSE << "neither options /$NOTESTS or /$ALLTESTS is set: providing "
	    			"only necessary tests"#NL
	    	;
	    	
	    ["$MSVSTUDIO", "$LINUX"]:
	    	CASE "$MSVSTUDIO" IN C.Defined_name[]
	    		 && "$LINUX" IN C.Defined_name[]
	    		 ?
	    	     C.Error("Options /$LINUX and /$MSVSTUDIO are excluding each"
	    	     " other")
	    	;
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	CASE ?
	    	["$MSVSTUDIO" IN C.Defined_name[]] ?
	    	     << "option /$MSVSTUDIO is set - project can be opened with "
	    	     	"MS Visual Studio 2010 (or may be higher)"#NL
	    	     	
	    	["$LINUX" IN C.Defined_name[]] ?
	    	     << "option /$LINUX is set - project is for compiling under "
	    	     	"Linux Operating system"#NL
	    	     	
	    	ELSE << "neither options /$LINUX or /$MSVSTUDIO is set: providing "
	    			"compiling with g++ under Windows"#NL ;
	    
	    ["$TEST_IN_WINDOWS"]:
	    	CASE "$LINUX" !IN C.Defined_name[] ?
	    	     C.Error("Option /$TEST_IN_WINDOWS is set but option /$LINUX "
	    	     "is not - you may be shoud remove option /$TEST_IN_WINDOWS")
	    	;
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	
	    	<< "option /$TEST_IN_WINDOWS is set - test version will be created "
	    	   "and run in Windows"#NL
	    
	    ["$REPORT_LEAKS"]:
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	
	    	<< "option /$REPORT_LEAKS is set - additional code will be provided"
	    	   " to search and report objects leaks"#NL
	    	   
	    ["$DEBUG"]:
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	
	    	<< "option /$DEBUG is set - additional code will be provided"
	    	   " to simplify code debug"#NL
	    	   
	    ["$64"]:
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	
	    	<< "option /$x64 is set - the option -m32 will not be passed to "
	    	   "the g++ compiler"#NL
	    	   
	    ["$LOG_METHODS"]:
	    	CASE !C.Verbose ? CONTINUE dn ;
	    	
	    	<< "option /$LOG_METHODS set - all methods will be logged into "
	    	   "log_methods.txt"#NL
	    	   
	    	CASE "$LOG_RESET" IN C.Defined_name[] ?
	    	     << "option /$LOG_RESET=" C.Defined_value[dn.Index] ", at "
	    	     	"the method with such full name logging will be restarting"
	    	     	#NL
	    	
	    	ELSE << "option /$LOG_RESET is not set, so logging will not be "
	    			"reset anyway untile program end or crash"#NL
	    	;
	    	   
	    ["$DO_NOT_LOG"]:
	    	CASE !C.Verbose || "$LOG_METHODS" !IN C.Defined_name[] ?
	    	     CONTINUE dn ;
	    	
	    	<< "option /$DO_NOT_LOG=" C.Defined_value[dn.Index] " is defined, "
	    	   "listed classes will not be logging"#NL
	    ;
	;
	Console_color('SILVER')
    ------------------------------------------- 'make generator'
    //g|enerator_temp = {Generator}(Comp = C)
	CASE "$LINUX" !IN C.Defined_name[] ?
	     g.Is_windows_target = TRUE ;
    ------------------------------------------- 'C++ specific'
    C.SYSFUN_Str.Final_name = "StrFromInt"
    C.SYSFUN_RealStr.Final_name = "StrFromDouble"
    C.SYSFUN_BoolStr.Final_name = "StrFromBool"
    FOR c IN C.All_classes[] :
        FOR f IN c.Method[] :
            CASE f.Final_name.Starting("M_") 
            	 && ! f.Final_name.Starting("M__")
            	 ?
                 f.Final_name = "M__" f.Final_name[2 TO *] ;
        ;
        FOR f IN c.Test[] :
            CASE f.Final_name.Starting("M_")
            	 && ! f.Final_name.Starting("M__")
            	 ?
                 f.Final_name = "M__" f.Final_name[2 TO *] ;
        ;
        ------------------- 'rename all the structures final names'
        FOR st IN c.Structures_[] :
            CASE detect_simple_structure(st) ?
            	 st.Final_name = "s" st.Final_name[1 TO *] ;
            CASE "__" IN st.Final_name ? CONTINUE st ;
            st.Final_name << "__" c.Final_name ;
        ------------------- 'for C++ constructor needed at least to get CNT_...'
        CASE C.TEST_value && c.Construct == NONE ?
             c.Provide_construct ;
    ;
	//DEBUG:
	//      g.already_messaged = FALSE ;
    CASE C.TEST_value && "$TEST_IN_WINDOWS" IN C.Defined_name[]
    	 ?
    	 g.Is_windows_target = TRUE
    ELSE
	     CASE "$LINUX" IN C.Defined_name[] ?
	          g.Is_windows_target = FALSE
	          g.Cpp_flags = C.Defined_value[C.Defined_name[].Find("$LINUX")]
	          
	          CASE C.Run && "$TEST_IN_WINDOWS" IN C.Defined_name[] ?
	               C.Run = FALSE
	               
	               C.Warning("/Run is not applicable for case when the project "
	               "is cross-compiling from Windows to Linux"._WRun)
	          ;
	     ELSE
	     	CASE "$TEST_IN_WINDOWS" IN C.Defined_name[] ?
	     	     C.Warning("Option $TEST_IN_WINDOWS was set but there is no "
	     	     "option $LINUX"._WOption) ;
	     ;
    ;
	------------------------------------------- 'logging'
	CASE "$LOG_METHODS" IN C.Defined_name[] ?
	     g.LOGGING_METHODS = TRUE
	      
	     Split(g.do_not_log_classes[], C.Defined_value[C.Defined_name[
	     	].Find("$DO_NOT_LOG")], ",")
	     	
	     FOR s IN g.do_not_log_classes[* DOWNTO 0] :
	         CASE "." IN s ?
	              g.do_not_log_methods[] << s
	              g.do_not_log_classes[].Delete(s.Index) ;
	     ;
	     
	     CASE "$LOG_RESET" IN C.Defined_name[] ?
	          g.LOGGING_RESET = C.Defined_value[C.Defined_name[].Find(
	          "$LOG_RESET")]
	     ;
	;
    ------------------------------------------- 'which type of string ?'
    g.kstr = "std :: string"
    --------------------------------- 'final string type to replace std::string'
    g.final_str = g.kstr
    ------------------------------------------- 'generate project'
    STR cpp|_files_array[]
    RESULT = g.do_generate(cpp[]) 
    CASE !RESULT || "test" IN Start_dir.Lower ? ==> ;
    ------------------------------------------- 'count tests'
    FOR c IN C.All_classes[] :
        INT total_tests += c.Test[].Count ;
    CASE total_tests == 0 && C.TEST_value ?
         C.Warning("There are no tests in entire project")
         RESULT = TRUE ==> ;
    ------------------------------------------- 'compile tests project'
    STR dest|ination_test_project = C.Destination.Trailing_slash
    STR exe|_path = dest C.Project 
    CASE g.Is_windows_target ? exe << ".exe" ;
    Set_working_dir(dest)
    STR text|_messages[]
    STR mes|sages
    --------------------------- 'compile using gnu c++ compiler'
    << "... calling GNU C++ compiler, please wait..."._Mcall2 #NL
        " " ("destination"._Mdest2) ": " dest #NL
        
    Console_color('CYAN')
    STR gcc_cmd|_text_file_path = g.make_gcc_cmd(C, cpp[])
    gcc_cmd = "_call_gcc.cmd"
    --------------------------- 'call GCC'
    Delete_file(exe)
    Delete_file(exe.Change_ext(".D"))
    CASE exe.Exists ?
         C.Warning("Executable could not be deleted"._EExecutable ": " exe)
    ;
    CASE g.Is_windows_target || C.TEST_value &&
    	 "$TEST_IN_WINDOWS" IN C.Defined_name[] || C.Run
    	 ? 
         NONE
    
    ELSE 
	     FOR j|dummy IN [0 TO gcc_cmd.Len] :
	         STR r|emoving_double_slashes = Replace(gcc_cmd, "//", "/")
	         CASE r == gcc_cmd ? BREAK j ;
	         gcc_cmd = r ;
	         
    	 << "The target is not MS Windows system (LINUX ?) -- to "
     	 "compile the project, run " gcc_cmd.Extract_file_name 
     	 " in the target environment" ==>
    ;
    ----------------------------------------- 'execute compiler'
    STR wd|irectory_working = Get_working_dir
    Set_working_dir(C.Destination)
    CASE g.Is_windows_target || C.TEST_value ?
     	 INT redir|ect_output = 3 ;
    CASE g.Is_windows_target ?
     	 mes = Execute_program(gcc_cmd, "", redir)
    ELSE mes = Execute_program("/bin/bash", gcc_cmd.Change_ext(".sh"), redir) ;
    //DEBUG: << "restore working dir to: " wd #NL ;
    Set_working_dir(wd)
    //DEBUG: << "now working dir: " Get_working_dir #NL ;
    ----------------------- 'output messages'
    Split(text[], mes, #LF)
    FOR s IN text[] :
    	s = s.TrimR
        CASE s[0] == #CR ? text[s.Index] = s[1 TO *] ;
    ;
    {Text_file} tf|ile_saver_temp = {Text_file}(
    	Path = C.Destination.Trailing_slash "Gcc_messages.txt")
    	
    NONE = tf.Save(text[])
    BOOL has_errors = out_messages_to_console(text[])
    ---------------------- 'wait some time finishing executable creating'
    INT wtimes|_wait = 0
    CASE !has_errors ?
	     {Date_time}.{date_time} wfrom|_wait_time = Now
	     FOR ii|dummy IN [1 TO 100] :
    	 	 wtimes += 1
	         CASE exe.Exists ? BREAK ii ;
	         Sleep(100)
	         CASE Now.Seconds_diff(wfrom) > 15 ? BREAK ii ;
	     ;
    ;
    -------------------------------------------------- 'was executable created?'
    Console_color('SILVER')
    CASE !exe.Exists ?
         C.Error("Executable was not created"._Eexe ": " exe
         " wait loops: " wtimes.S " now: " Now.Format("[HH:mm:ss]")
         " started waiting: " wfrom.Format("[HH:mm:ss]")) ==>
    ;
    CASE C.Verbose ?
         << "Executable created, continue working..."#NL ;
    C.Executable = exe
    C.Time_finished = Now
    C.Statistics_show
    //DEBUG: << "EXECUTABLE WAS CREATED: " exe #NL ;
    CASE has_errors ?
         //DEBUG: << "THERE WERE ERRORS, ==>" #NL ;
         ==> ;
    CASE C.TEST_value || C.Run ? 
         //DEBUG: << "C.TEST_value=" C.TEST_value.Str ", C.Run=" C.Run.Str #NL ;
         NONE
    ELSE
    	 //DEBUG: << "C.TEST_value=" C.TEST_value.Str ", C.Run=" C.Run.Str 
    	 //		   " ==>" #NL ; 
    	 ==> ;
    -------------------------------------------- 'run tests'
    //DEBUG: << "RUNNING TESTS.............................." #NL ;
    CASE C.Verbose && C.TEST_value ? << "Running tests" #NL ;
    CASE C.Verbose && !C.TEST_value && C.Run ?
         << "Running compiled application"._Mrun #NL ;
    Console_colors('BLUE', 'YELLOW')
    << exe " " C.Param #NL
    Console_colors('SILVER', 'BLACK')
    INT flags|_wait = 0
    //CASE !C.Test ? flags = 3 ;
    -------------------------------------------- 'save messages'
    STR mpath|_of_compiler_messages = dest.Remove_ending("TEST$".Trailing_slash)
    	"Compiler_messages.html"
    	
    {Memory_stream} save_mes|sages_temp = File_to_memory(mpath)
    CASE !C.TEST_value && !C.Run ? ==> ;
    -------------------------------------------- 'execute test or program'
    CASE g.Is_windows_target ?
    	 NONE = Execute_program(exe, C.Param, flags)
    ELSE wd = Get_working_dir
	     //DEBUG: << "was working dir: " wd #NL ;
	     Set_working_dir(exe.Extract_path)
	     //DEBUG: << "working dir set to: " Get_working_dir #NL ;
 
    	 NONE = Execute_program( "./" exe.Extract_file_name, C.Param, 0)
    	 
    	 //DEBUG: << "restore working dir to: " wd #NL ;
         Set_working_dir(wd)
         //DEBUG: << "now working dir: " Get_working_dir #NL ;
    ;
    -------------------------------------------- 'restore messages'
	{File_stream} fsave|_back_temp = Write_file_stream(mpath, FALSE)
	save_mes.Set_position(0, 'BEGINNING')
	fsave.Copy_stream(save_mes)
	fsave.Close
    -------------------------------------------- 'if report leaks was requested'
    CASE C.Defined_name[].Find("$REPORT_LEAKS") >= 0 ?
         STR path_rep|ort = C.Destination.Trailing_slash "Report_leaks.txt"
         CASE ! path_rep.Exists ?
              Console_color('RED')
              << "Could not report leaks"._Mcouldnot #NL
              Console_color('SILVER') ==> ;
         text[].Clear
         loader|_text_temp = {Text_file}(Path = path_rep)
         NONE = loader.Load_strings(text[])
         CASE text[].Count == 0 ?
              Console_color('GREEN')
              << "There were not leaks detected"._Mthere #NL
              
              Console_color('SILVER')
              
         ELSE Console_color('RED')
         
              << "There were leaks in"._Mthere2 " " (text[].Count-1).Str 
                 " " ("classes"._Mclasses ) #NL
                 
              Console_color('SILVER') ;
    ; .
    
FUN remove_sp|aces(
	STR S|tring_having_spaces_to_remove) ==> STR 
	:
	RESULT = S
	FOR i IN [RESULT.Len-1 DOWNTO 0] :
	    CASE RESULT[i] == " " ? RESULT = RESULT[0 TO i-1] RESULT[i+1 TO *] ;
	; .
        
    
METHOD make_gcc_cmd(
	{Compiler} C|ompiler_obj,
	STR Cpp|_files_generated[]) ==> STR RESULT|Path_of_cmd_file
	:
	STR cmd|_text[]
	CASE Is_windows_target ?
	     //DEBUG: << "target = windows" >> STR debug_text ;
		 cmd[] << "cd /D " #QU C.Destination #QU
	ELSE cmd[] << "#!/bin/bash"
		 cmd[] << "reset"
		 cmd[] << "echo ------------------- running Gcc -------------------"
	;
	-------------------------------------------------- 'call gcc [parameters]'
	cmd[] << "g++ -pipe -fpermissive "
	..[*] << "-Warray-bounds "
	CASE !Is_windows_target ? cmd[*] << "-std=c++11 " ; 
	CASE Is_windows_target && "$x64" !IN C.Defined_name[] ?
	     cmd[*] << "-m32 " ;
	CASE "$NOOP" IN C.Defined_name[]
		 || "$NOOPTIMIZE" IN C.Defined_name[]
		 ?
	     cmd[*] << "-O0 "
	ELSE cmd[*] << "-Os " ;
		
	CASE !C.Debugging ?
		 cmd[*] << "-ffunction-sections "
				   "-Wl,--gc-sections -fno-asynchronous-unwind-tables "
				   "-Wl,--strip-all "
				   "-MD " ;
	
	CASE Is_windows_target ?
		 CASE !Comp.TEST_value && Comp.Noconsole && Is_windows_target ?
		      cmd[*] << "-mwindows "
		 ELSE cmd[*] << "-mconsole "
		 ;
	//ELSE cmd[*] << Cpp_flags.Trim " -lX11 "
	;
	
	CASE Comp.TEST_value || Comp.Debugging ?
		 cmd[*] << "-g "
	ELSE cmd[*] << "-feliminate-unused-debug-symbols "
	;
		 
	CASE Comp.Verbose ?
	     cmd[*] << "-Wall "
			"-Wno-unknown-pragmas " // pragma warning(push,disable,pop) 
			"-Wno-unused-function "
			"-Wno-unused-variable "
			"-Wno-unused-but-set-variable "
	;
	
	cmd[*] << "-Wno-write-strings "
			  "-Wno-deprecated-declarations "
	------------------------------------ 'oputput to... option'
	cmd[*] << "-o " C.Project
	CASE Is_windows_target ? 
		 cmd[*] << ".exe " 
	ELSE cmd[*] << " " ;
	//cmd[*] << "-I . "
	------------------------------------- 'add source files'
	cmd[*] << "AL4.cpp "
	FOR cpp IN Cpp[] : 
        cmd[*] << cpp ".cpp " ;
	------------------------------------- 'additional libraries'
	FOR ds IN C.Defined_name[] :
	    CASE ds.Upper == "$L" ?
	         cmd[*] << "-l" C.Defined_value[ds.Index] " " ;
	;
	------------------------------------- 'save command file'
	RESULT = C.Destination.Trailing_slash "_call_gcc.cmd"
	//DEBUG: << "............ saving _call_gcc.cmd at: " RESULT #NL ;
	CASE Is_windows_target ?
		 Text_save(RESULT, cmd[])
	ELSE 
	     RESULT = RESULT.Change_ext(".sh") 
		 Unix_text_save(RESULT, cmd[]) ;
	//DEBUG: << "............ saved, exists=" RESULT.Exists.Str #NL ; 
	CASE !RESULT.Exists ?
	     Comp.Error("Command file could not be saved"._ECommandFile 
	     ": " RESULT " " ("May be, destination specified in the project "
	     "configuration is not a fully qualified path?"._EMayBe) ) ;
	.
	


FUN out_messages_to_console(STR T|ext_messages[]) ==> BOOL :
    ----------------------------------- 'return TRUE if there are errors'
    Console_color('CYAN')
    //<< ":::::::::::::::::::::::: messages from the C++ compiler "
    //   "::::::::::::::::::::::::" //T[].Count.Str #NL
    FOR s IN T[] :
        CASE s.Index >= 1000 ? BREAK s ;

        CASE "error" IN s.Lower ?
             //DEBUG: << "found error in line " s.Index.Str #NL ;
             INT pos|ition_error = s.Lower.Find("error")
             CASE s[pos-1] IN "/_" ? CONTINUE s ;
             CASE s[pos-1] == #QU && s[pos + "error".Len] == #QU ?
                  CONTINUE s ;
             //<< "[" s[pos-1 TO pos+"error".Len] "]"
             RESULT = TRUE
             --------------------------------- 'underline ERROR with RED'
             << s[0 TO pos-1]
             Console_color('RED')
             << s[pos TO pos+4]
             Console_color('CYAN')
             << s[pos+5 TO *] #NL
             CONTINUE s ;
        CASE "warning" IN s.Lower ?
             -------------------------------- 'underline WARNING with YELLOW'
             pos = s.Lower.Find("warning")
             << s[0 TO pos-1]
             Console_color('YELLOW')
             << s[pos TO pos+6]
             Console_color('CYAN')
             << s[pos+7 TO *] #NL
             CONTINUE s ;
        << s #NL ;
    Console_color('SILVER') .

METHOD do_generate(STR Cpp|_files_created[]) ==> BOOL :
	CASE !Is_windows_target && "\" IN Comp.Destination ?
	     Comp.Destination = Comp.Destination.Replace_all("\", "/") ;
    ----------------------------- 'Provide destination folder'
    CASE !Comp.Destination.Directory_exists ? 
         Create_dir(Comp.Destination) ;
    CASE !Comp.Destination.Directory_exists ? 
         Comp.Error("Can not create destination directory"._Ecannot
         ": " Comp.Destination) ;
    ----------------------------- 'All_classes.h'
    DEBUGGING_METHODS = !Comp.Final || Comp.Debugging || 
    	"$DEBUG" IN Comp.Defined_name[]
    
    o[].Clear
    generate_all_classes_h
    ----------------------------- 'add also h-files copied to project via /COPY'
    FOR sf IN Comp.Copy_files[] :
        CASE "<bin>" IN sf ? CONTINUE sf ;
        CASE ?
        [sf.Ending(".h")] ? 
             //DEBUG: << "[COPY " sf "]" #NL >> ;
             copy_file_removing_comments(sf, TRUE)
        [sf.Ending(".*")] ? 
             //DEBUG: << "[COPY " sf "]" #NL >> ;
             copy_file_removing_comments(sf.Change_ext(".h"), FALSE)
        ;
    ;
    ----------------------------- 'constant arrays from all the classes'
    FOR c IN Comp.All_classes[] :
	    FOR ca IN c.Constants[] :
	        CASE !ca.Is_array ? CONTINUE ca ;
	        generate_const_array(ca) ;
    ;
    ----------------------------- 'replace std::string if necessary'
    CASE final_str.remove_sp != "std :: string".remove_sp ?
         std_string_convert(o[]) ;
    ----------------------------- 'save All_classes.h'
    tf|ile_temp = {Text_file}(
        Path = Comp.Destination.Trailing_slash "All_classes.h")
        
    CASE file_changed(tf, o[]) ?
         CASE Comp.Verbose ? << "Saving"._Msaving ": " tf.Path
              " (" o[].Count.Str ")" #NL
         ;
         NONE = tf.Save(o[])
         CASE Comp.Verbose ? << "-saved."._Msaved #NL ;
    ELSE 
         CASE Comp.Verbose ? << "Not changed"._Mnotch ": " tf.Path 
              " (" o[].Count.Str ")" #NL ;
    ;
    o[].Clear
    ----------------------------------- 'for each class...'
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        CASE c.Is_translation ? CONTINUE c ;
        o[] << "" << "//##CLASS " c.Names[0]
        CASE !generate_class_impl(c) ? ==> ;
        FOR st IN c.Structures_[] :
            CASE is_simple(st) ? CONTINUE st ;
            STR n|ame_of_structure = st.Final_name
        
	        o[] << @
			       "" sp(4) n "* " n "::NoneObj_" n ";"
			       "" sp(4) n "* " n "::DummyObj_" n ";"
			       
	        generate_structure_init(st)
        ;
    ;
    ----------------------------------- 'instances of static vectors for tests'
    FOR s IN instances[] :
        o[] << s ;
    ----------------------------------- 'additional included files'
    FOR sf IN Comp.Copy_files[] :
        CASE sf.Ending(".h") && !Starting(sf, "<bin>") ? CONTINUE sf ;
        CASE Starting(sf, "<bin>") ?
             STR from|_file_path = sf["<bin>".Len TO *]
             STR dest|ination_name = sf["<bin>".Len TO *].Extract_file_name
             copy_file_directly(from, Comp.Destination.Trailing_slash dest)
             CASE Comp.Verbose ?
                  << "copied from: " from #NL
                     " to: " Comp.Destination.Trailing_slash dest #NL
             ;
             CONTINUE sf ;
        dest = sf.Extract_file_name
        //DEBUG: << "[+COPY " sf "]" #NL >> ;
        CASE sf.Ending(".*") ? sf = sf.Change_ext(".cpp") ;
        copy_file_removing_comments(sf, TRUE) ;
    CASE final_str.remove_sp != "std :: string".remove_sp ?
         std_string_convert(o[]) ;
    -------------------------- 'single source cpp file is saved now'
    CASE Comp.Verbose ? << "Cpp ready, start splitting long lines"._Mcpp #NL ;
    --------------------------------- 'split by #NL'
    STR onl|_splitted[]
    split_o_by_NL(onl[])
    --------------------------- 'comment portions of code by conditions'
    comment_unnecessary_parts(onl[])             
    
    split_long_lines(o[], onl[])
    Cpp[] << Comp.All_classes[0].Final_name
    CASE o[].Count > 65535 ?
        ---------------------------- 'split long sources onto smaller parts'
        split_long_source(Cpp[], ".cpp") ;
    CASE Comp.Verbose ? << "end splitting"._Mendsplit #NL ;
        
    tf = {Text_file}(
        Path = Comp.Destination.Trailing_slash Cpp[0] ".cpp")
        
    CASE file_changed(tf, o[]) ?
         CASE Comp.Verbose ? << "Saving"._Msaving2 ": " tf.Path
              " (" o[].Count.Str ")" #NL
         ;
         NONE = tf.Save(o[])
         CASE Comp.Verbose ? << "-saved"._Msaved2 "." #NL ;
    ELSE 
         CASE Comp.Verbose ? << "Not changed"._Mnotch2 ": " tf.Path 
              " (" o[].Count.Str ")" #NL ;
    ;
    -------------------------------- 'generate project'
    o[].Clear
    generate_project(Cpp[])
    RESULT = TRUE .
    
METHOD generate_structure_init({Type} St|ructure_type) :
	CASE St.Is_translation ? ==> ;
	STR n|ame_of_structure = St.Final_name
	
    o[] << @
        "" sp(4) "void " n "::init_class_" n "()"
        "" sp(4) "{"                                       
        "" sp(4) "    NoneObj_" n " = (" n "*)New_nofields()->Obj;"
        "" sp(4) "    NoneObj_" n "->hard_link->Count = -1;"
        "" sp(4) "    NoneObj_" n "->Is_NONE_object = true;"
        "" sp(4) "    None_obj = NoneObj_" n "->hard_link;"
        "" sp(4) "    DummyObj_" n " = (" n "*)New_nofields()->Obj;"                
        "" sp(4) "    DummyObj_" n "->hard_link->Count = -1;"
        "" sp(4) "    Dummy_obj = DummyObj_" n "->hard_link;"                
        "" sp(4) "    NoneObj_" n "->write = DummyObj_" n ";"
        "" sp(4) "}"

	-------------------------- 'Clone() implementation for the structure'        
    o[] <<@"Any_structure* " n "::Clone()"
 		   "{"
 		   "	" n "* Result = (" n "*)New()->Obj;"
 		   
    copy_structure_fields(St, "    Result->", "this->")
 		    
    o[] <<@"	return Result;" 
 		   "}" .
    
METHOD copy_structure_fields(
{Type} St|ructure_type,
STR Dest|ination_prefix,
STR Source|_prefix), RECURSIVE
	:
	FOR f IN St.Field[] :
	    CASE f.Is_array ?
	         o[] << Dest f.Final_name " = (" type_gen(f.Type_,
	         		{type_options}(Array=TRUE, Fixed=f.Is_fixed,
	         		Weak=f.Is_weak))
	         		")" Source f.Final_name "->Clone_array();"
	         		 
	    	 CONTINUE f ; 
	    CASE f.Type_.Kind ?
	    ['BOOL', 'BYTE', 'ENUM', 'INT', 'REAL', 'STR']:
	    	 o[] << Dest f.Final_name " = " Source f.Final_name ";"
	    	 
	    ['CLASS']:
	    	 o[] << Dest.first_spaces "Object_assign_weak("
	    	 		"&" Dest.Trim f.Final_name ", " Source f.Final_name ");"
	    	 		
	    ['STRUCTURE']:
	    	CASE is_simple(f.Type_) ?
	    	     o[] << Dest.first_spaces "memmove(&" Dest.Trim f.Final_name 
	    	     		", &" Source f.Final_name
	    	     		", sizeof(" f.Type_.Final_name"));"
	    	     		
	    	ELSE copy_structure_fields(f.Type_, "    " Dest f.Final_name "->",
	    		 Source f.Final_name "->")
	    	;
	    ;
	; .
	
    

    
METHOD split_long_source|_onto_smaller_files_and_save(
    STR Names|_of_files[], STR Ext|ension_for_files)
    :
    INT n|umber_of_extracted_portion = 0
    FOR i|dummy IN [0 TO o[].Count-1] :
        INT y_start|_to_split_from = find_line_to_split
        CASE y_start >= 0 ?
             INT y_end|_to_split_to = find_ending_line(y_start)
        ELSE y_end = -1 ;
        CASE y_start < 0 || y_end < 0 ?
             Comp.Warning("Can not split below 65535, lines in cpp: " 
             "" o[].Count.Str)  ==>
        ;
        STR p|ortion_to_extract_n_save[]
        FOR y IN [y_start TO y_end] : p[] << o[y] ;
        FOR y IN [y_end DOWNTO y_start] : o[].Delete(y) ;
        ------------------ 'replace extracted portion with #include ?'
        n += 1
        Names[] << Names[0] "__" n.Str
        //o[].Insert(y_start, "#include "#QU Names[*] Ext #QU)
        ------------------ 'save portion to a separate file'
        tf|ile_temp = {Text_file}(
            Path = Comp.Destination.Trailing_slash Names[*] Ext)
            
        CASE file_changed(tf, p[]) ?
             CASE Comp.Verbose ? << "Saving"._Msaving2a ": " tf.Path
               " (" p[].Count.Str ")" #NL 
             ;
             NONE = tf.Save(p[])
             CASE Comp.Verbose ? << "-saved"._Msaved2a "." #NL ;
        ELSE 
             CASE Comp.Verbose ? << "Not changed"._Mnotch2a ": " tf.Path 
               " (" p[].Count.Str ")" #NL ;
        ;
        CASE o[].Count <= 65535 ? BREAK i ;
    ; .
    
METHOD find_line_to_split ==> INT :
    FOR y IN [65535 DOWNTO 1] :
        CASE Starting(o[y], "//##CLASS") ? 
             //DEBUG: << "found start of portion at " y.S ": " o[y] #NL ;
             RESULT = y ==> ;
    ;
    --------------------------- 'attempt 2 - split by class'
    FOR y IN [65535 DOWNTO 1] :
        CASE Starting(o[y], "// class {") ?
             RESULT = y-1 ==> ;
    ;
    --------------------------- 'attempt 3 - start split at any function start'
    FOR y IN [65535 DOWNTO 1] :
        CASE Starting(o[y], "// fun: ") ?
             RESULT = y ==> ;
    ;
    --------------------------- 'can not split'
    RESULT = -1 .
    
METHOD find_ending_line(
INT Start|ing_line_of_portion_to_extract ) ==> INT
    :
    RESULT = -1
    FOR y IN [Start+2 TO o[].Count-1] :
        CASE Starting(o[y], "//##CLASS") ?
             //DEBUG: << "found possible end at " y.S ": " o[y] #NL ;
             CASE y - Start >= 65535 && RESULT > 0 ? 
                  //DEBUG: << "end ok = " RESULT.S ": " o[RESULT] #NL ;
                  ==> ;
             CASE y - Start >= 65535 ? BREAK y ;
             RESULT = y-1 ;
    ;
    CASE RESULT > 0 ? 
         //DEBUG: << "found RESULT=" RESULT.S ": " o[RESULT] #NL ;
         ==> ;
    -------------------------- 'attempt 2 - by class'
    RESULT = -1
    FOR y IN [Start+2 TO o[].Count-1] :
        CASE Starting(o[y], "// class {") ?
             CASE y - Start >= 65535 && RESULT > 0 ? ==> ;
             CASE y - Start >= 65535 ? BREAK y ;
             RESULT = y-1 ;
    ;
    CASE RESULT > 0 ? ==> ;
    -------------------------- 'attempt 3 - end split at any function start'
    RESULT = -1
    FOR y IN [Start+2 TO o[].Count-1] :
        CASE Starting(o[y], "// fun:") ?
             CASE y - Start >= 65535 && RESULT > 0 ? ==> ;
             CASE y - Start >= 65535 ? BREAK y ;
             RESULT = y-1 ;
    ;
    CASE RESULT > 0 ? ==> ;
    --------------------------- 'can not split'
    RESULT = -1 .
    
    
    
FUN split_long_lines(STR D|estination[], STR L|ines_to_split[]) :
    D[].Clear
    ---------------------------- 'For each line...'
    FOR i IN [0 TO L[].Count-1] :
        CASE L[i].Len < 161 ?
             D[] << L[i]
             CONTINUE i ;
        CASE L[i].TrimL.Starting("// stmt") ?
             NONE ;
        CASE L[i].TrimL.Starting("//") ?
             D[] << L[i]
             CONTINUE i ;
        INT spaces_c|ount = 0
        FOR j IN [0 TO L[i].Len-1] :
            CASE L[i][j] IN " "#TAB ? spaces_c += 1
            ELSE BREAK j ;
        ;
        -------------------------- 'make s = L[i] w/strings filled by !'
        STR s|tring_without_comments = L[i]
        BOOL in_str|ing_constant = FALSE
        FOR j IN [0 TO s.Len-1] :
            CASE s[j] IN [#13, #10] ? s[j] = "," ;
            CASE in_str && s[j] == "\" && s[j+1] == #QU ?
                 s[j] = "!"
                 s[j+1] = "!" ;
            CASE in_str && s[j] != #QU ? s[j] = "!" ;
            CASE s[j] != #QU ? CONTINUE j ;
            s[j] = "!"
            in_str = !in_str ;
        CASE s != L[i] ?
             s = "  " s
             L[i] = "  " L[i] ;
        -------------------------- 'split by operation signs'
        INT len|gth_of_cutted_part = 0
        INT new_len|gth = 0
        STR each|_line_prefix = ""
        STR pref|ix_spaces = s[0 TO spaces_c-1]
        STR not_f|irst_line_prefix = ""
        INT prev|ious_index_handled = 0
        FOR j IN [1 TO s.Len-5] :
            CASE s[j] IN ["%", "(", ")", "[", "]"] ?
                 new_len = j - prev + 1 + spaces_c ;
            CASE new_len > len && (new_len < 81 || len == 0) ?
                 len = new_len ;
            CASE new_len > 160 ?
                 D[] << each not_f L[i][prev TO j]
                 prev = j+1
                 len = 0
                 new_len = 0
                 each = pref
                 not_f = "  "
            ;
        ;
        CASE prev < L[i].Len ?
             D[] << pref "  " L[i][prev TO *] ;
    ; .
    
METHOD split_o_by_NL(STR Dest|ination_array[]) :
    Dest[].Clear
    FOR s IN o[] :
        CASE #NL !IN s ? 
             Dest[] << s
             CONTINUE s ;
        STR splitted[]
        Split(splitted[], s, #NL)
        FOR ss IN splitted[] :
            Dest[] << ss ;
    ; .
    
    
METHOD comment_unnecessary_parts( STR Lines|_of_code[] ) :
    BOOL comment|ing_lines = FALSE
    FOR s IN Lines[] :
        CASE comment ?
             CASE Starting(s, "//.") && s.Trim == "//." ?
                  comment = FALSE
             ELSE Lines[s.Index] = "//-->" s ;
             CONTINUE s ;
        CASE Starting(s, "//? ") ?
             STR class|_name = s[4 TO *].Trim
             CASE !class_present(class) ? comment = TRUE ;
        ;
    ; .

METHOD class_present|_in_All_classes( STR Name|_of_class ) ==> BOOL :
    FOR t IN Comp.All_classes[] :
        CASE Name == t.Names[0] ? RESULT = TRUE ==> ;
    ; .
                
    

    
FUN file_changed( {Text_file} T|ext_file, STR Out|put_text[] ) ==> BOOL:
    ----------------------------------- 'split by #NL'
    FOR i IN [Out[].Count-1 DOWNTO 0] :
        STR line|_of_out = Out[i]
        CASE #NL !IN line ? CONTINUE i ;
        STR ss|plitted_line[]
        ss[].Clear
        Split(ss[], line, #NL)
        Out[].Delete(i)
        FOR s IN ss[] :
            Out[].Insert(i + s.Index, s) ;
    ;
    ----------------------------------- 'compare to old version'
    STR old|_lines[]
    NONE = T.Load_strings(old[])
    CASE old[].Count != Out[].Count ? RESULT = TRUE ==> ;
    FOR s IN old[] :
        CASE s != Out[s.Index] ? RESULT = TRUE ==> ;
    ; .
    
    
METHOD std_string_convert( STR Text|_to_replace[]) :
    --------------------------------------- ': DISALLOW:'
    BOOL allow|_conversion = TRUE
    STR disallow|_text = ":" create_text("DISALLOW") ":"
    STR allow_text = ":" create_text("ALLOW") ":"
    STR std_string = "std :: string".remove_sp
    FOR i IN [0 TO Text[].Count-1] :
        STR s|tring_line = Text[i]
        CASE disallow IN s ? 
            allow = FALSE
            //DEBUG: << disallow " found in line " i.S ":" #NL
            //           "" Text[i] #NL Text[i+1] #NL Text[i+2] #NL ;
        ELSE 
             CASE allow_text IN s ? allow = TRUE ;
        ;
        CASE ! allow ?
             Text[i] = Text[i] " // " disallow
             CONTINUE i ;
        FOR j|dummy IN [1 TO s.Len] :
            INT pos|ition_of_std_string = s.Find(std_string)
            CASE pos < 0 ? BREAK j ;
            s = s[0 TO pos-1] final_str s[pos + std_string.Len TO *] ;
        ----------------------------------- ': ALLOW:'
        Text[i] = s ; .
        
METHOD create_text(STR Which_text) ==> STR, RECURSIVE :
    ------------------- 'declared RECURSIVE to prevent optimizing it'
    CASE Which_text ?
    ["ALLOW"]: RESULT = "ALLOW"
    ["DISALLOW"]: RESULT = "DISALLOW"
    [":"]: RESULT = ":"
    ELSE RESULT = create_text(":") ; .
        

METHOD copy_file_removing_comments(
STR Src|_file_path, BOOL Must_exist )
	:
    -------------------------------------- 'search  source file to copy'
    STR source|_actual = Src
    CASE "\" !IN Src && "/" !IN Src ?
         FOR s IN Comp.Source_paths[] :
             CASE (s.Trailing_slash Src).Exists ?
                  source = s.Trailing_slash Src
                  BREAK s ;
         ;
    ;
    CASE !source.Exists ?
          CASE !Must_exist ? ==> ;
          Comp.Error("File not exists: " Src) ==>
    ;
    CASE Comp.Verbose ? << "COPY"._Mcopy ": " source #NL ;
    ------------------------------------ 'load text'
    STR text|_copying[]
    
    //temp|_file = {Text_file}(Path = source)
    //NONE = temp.Load_strings(text[])
    {Memory_stream} temp|_stream = File_to_memory(source)
    temp.Set_encoding('DEFAULT')
    STR f|irst_line = temp.Get_line
        
    CASE temp.Encoding == 'ASCII' ?
         temp.Set_position(0, 'BEGINNING')
         temp.Set_encoding('UTF8')
    ELSE text[] << f ;
    FOR j|dummy IN [0 TO MAX_INT-1] :
        CASE temp.Ended ? BREAK j ;
        text[] << temp.Get_line ;
    ------------------------------------ 'remove long comments'
    CASE ?
    [text[0].Trim == "(" "*" "/"] ?
         BOOL comments_P|ascal = TRUE
         BOOL in_long_comments = TRUE
    [text[0].Trim.Starting("/" "*")] ?
         in_long_comments = TRUE
    ;
    FOR i IN [0 TO text[].Count-1] :
        STR i_str|ing_at_i = text[i].Trim
    	CASE !in_long_comments ?
        	 CASE ?
        	 [comments_P && i_str.Starting("(" "*")] ?
        	      in_long_comments = TRUE
        	 [!comments_P && i_str.Starting("/" "*")] ?
        	      in_long_comments = TRUE ;
    	;
        CASE in_long_comments ?
             CASE ?
             [comments_P && i_str.Ending("*" ")")] ?
                  in_long_comments = FALSE
             [!comments_P && i_str.Ending("*" "/")] ?
                  in_long_comments = FALSE ;
             text[i] = "//-long comments are removed"
        ;
    ;
    
    -------------------------------- 'comment some parts between / /? .. / /.'
    comment_unnecessary_parts(text[])
    ------------------------------------ 'replace comments to a warning'
    FOR i IN [text[].Count-1 DOWNTO 0] :
        CASE Starting(text[i], "//?") || Starting(text[i], "//-->") || (
             text[i].Trim == "//.")
             ?
             CONTINUE i ;
        CASE text[i].Trim[0 TO 1] == "//" ?
        	 CASE show_file_name ?
	              text[i] = "//-this is a copy only - " Src " (" (i+1).S ")"
        	 ELSE 
	              text[i] = "//-this is a copy only - do not change: "
	              "changes will not take effect on the next compile" 
        	 ;
        	 show_file_name = !show_file_name ;
    ;
    ------------------------------- 'append modified text'
    FOR s IN text[] : o[] << s ; .

BOOL show_file_name|_rather_then_phrase_Do_not_change
    
METHOD copy_file_directly(STR Src|_file_path, STR Dst|_path) :
    -------------------------------------- 'remove old instance'
    CASE Dst.Exists ? Dst.Delete_file ;
    CASE Dst.Exists ? 
         Comp.Error("Can not remove old version of file"._Ecannot2 " " Dst) ;
    -------------------------------------- 'search  source file to copy'
    STR source|_actual = Src
    Copy_file(source, Dst) .

BOOL LOGGING_METHODS
STR LOGGING_RESET
STR do_not_log_classes[]
STR do_not_log_methods[]
BOOL shown_LOGGING_METHODS, DEBUG

 METHOD generate_project( STR Cpp|_sources[] ) :
	CASE "$MSVSTUDIO" IN Comp.Defined_name[] ?
		 generate_vcxproj(Cpp[]) ;
    o[].Clear
    ------------------------------ 'copy AL4.h to destination folder'
    STR path_source = Start_dir.Trailing_slash "..".Trailing_slash
    	"_$Generate_gcc".Trailing_slash "source_AL4.h"
    	
    CASE !path_source.Exists ?
         Comp.Error("File was not found"._EFileWas ": " path_source) ;
    STR source_AL4|_h_cpp[]
    Text_load(path_source, source_AL4[])
    CASE Comp.TEST_value ?
         FOR s IN source_AL4[] :
             CASE s.TrimR == "//#define TEST_STAGE" ?
                  source_AL4[s.Index] = s[2 TO *]
                  BREAK s ;
         ;
    ;
    CASE "$DIRECT_WRITE" IN Comp.Defined_name[] ?
         FOR s IN source_AL4[] :
             CASE s.TrimR == "//#define DIRECT_WRITE" ?
                  source_AL4[s.Index] = s[2 TO *]
                  BREAK s ;
         ;
    ;
    CASE "$MSVSTUDIO" IN Comp.Defined_name[] ?
         FOR s IN source_AL4[] :
             CASE s.TrimR == "//#define MSVSTUDIO" ?
                  source_AL4[s.Index] = s[2 TO *]
                  BREAK s ;
         ;
    ;
    CASE LOGGING_METHODS ?
         //DEBUG: << "option LOG_METHODS acquired" >> STR debug_acquired ;
         FOR s IN source_AL4[] :
             CASE s.TrimR == "//#define LOG_METHODS" ?
                  source_AL4[s.Index] = s[2 TO *]
                  CONTINUE s ;
             CASE s.Starting("#define LOG_METHODS_PATH") ?
                  source_AL4[s.Index] = s " " 
                  	"(std::string)"#QU Comp.Defined_value[
                  		Comp.Defined_name[].Find("$LOG_METHODS")] #QU "+"
                  BREAK s ;
         ;
    ;
    ------------------------------ 'insert first some directives'
    //INT al4_start = DATA[].Find("--AL4.h--(")
    //INT al4_end|_line = DATA[].Find("--AL4.h--)")
    //o[] << "#pragma once"
    CASE Is_windows_target ?
         o[] << "#define MSWINDOWS"
    ;
    FOR i IN [0 TO source_AL4[].Count-1] :
        STR d|ata_line = source_AL4[i]
        CASE d.Trim ?
        ["#localize1"]: add_localize_data1
                        CONTINUE i 
        ["#localize2"]: add_localize_data2
                        CONTINUE i ;
        o[] << d ;
        
    {Text_file} tf|ile_temp = {Text_file}(
    	Path = Comp.Destination.Trailing_slash "AL4.h")
    	
    NONE = tf.Save(o[])
    o[].Clear
    ------------------------------ 'copy AL4.cpp to destination folder'
    path_source = Start_dir.Trailing_slash "..".Trailing_slash
    	"_$Generate_gcc".Trailing_slash "source_AL4.cpp"
    	
    CASE !path_source.Exists ?
         Comp.Error("File was not found"._EFileWas2 ": " path_source) ;
    Text_load(path_source, source_AL4[])
    //al4_start = DATA[].Find("--AL4.cpp--(")
    //al4_end = DATA[].Find("--AL4.cpp--)")
    FOR i IN [0 TO source_AL4[].Count-1] : //[al4_start + 1 TO al4_end-1] : 
        //d = DATA[i]
        d = source_AL4[i]
        CASE d.Trim ?
        ["#localize2"]: add_localize_data2
                        CONTINUE i
        ["#localize3"]: add_localize_data3
                        CONTINUE i  ;
        o[] << d ;
    CASE final_str.remove_sp != "std :: string".remove_sp ?
         std_string_convert(o[]) ;
    tf.Path = Comp.Destination.Trailing_slash "AL4.cpp"
    NONE = tf.Save(o[])
    o[].Clear 
    .
    
METHOD generate_vcxproj
                       |ect_to_compile_with_MS_Visual_Studio(
STR Cpp|_sources[])
	:
    ------------------------------- 'generate vcxproj'
    //<< "strings: " str ", WX_Libs: " WX_Libs >> STR input|_dummy
    o[].Clear
    INT m2|_csproj2 = DATA[].Find("--VCXPROJ--2")
    FOR i IN [1 TO m2-1] : o[] << DATA[i] ;
    FOR cpp IN Cpp[] : 
        o[] << "   <ClCompile Include="#QU cpp ".cpp" #QU" />" ;
    STR dest|ination_path = Comp.Destination.Trailing_slash
    
    STR prop_h|eader = "<PropertyGroup Condition=" #QU " '$(Configuration)' "
        "== 'Debug' " #QU ">"
        
    STR debug|_used = ""
    
    o[] << @"  </ItemGroup>"
            "  " prop_h ""
            "    <OutDir>" dest debug "</OutDir>"
            "  </PropertyGroup>"
            "  <ItemGroup>"
    ------------------------------------- 'for Release, too:'
    prop_h = "<PropertyGroup Condition=" #QU " '$(Configuration)' "
        "== 'Release' " #QU ">"
        
    o[] << @"  </ItemGroup>"
            "  " prop_h ""
            "    <OutDir>" dest "</OutDir>"
            "  </PropertyGroup>"
            "  <ItemGroup>"
    -------------------------------------- 'include h-files'      
    o[] << @
        "    <ClInclude Include=" #QU "AL4.h" #QU " />"
        "    <ClCompile Include=" #QU "AL4.cpp" #QU " />"
        "    <ClInclude Include=" #QU "All_classes.h" #QU " />"
        
    CASE Comp.TEST_value ?
         FOR c IN Comp.All_classes[] :
             CASE c == NONE ? CONTINUE c ;
             o[] << "   <ClInclude Include="#QU "TL_" c.Final_name 
             ".h" #QU" />" ;
    ;
    INT m3|_csproj3 = DATA[].Find("--VCXPROJ--3")
    FOR i IN [m2+1 TO m3-1] : o[] << DATA[i] ;
	----------------------------------- '<PlatformToolset>?</PlatformToolset>'
	FOR i IN [o[].Count-1 DOWNTO 0] :
        STR sv|cxproj_text_line = o[i]
        CASE ! sv.Starting("?<PlatformToolset>?") ? CONTINUE i ;
		INT ver|sion_toolkit = Comp.Defined_name[].Find("$Toolset")
		CASE ver < 0 ? ver = Comp.Defined_name[].Find("$PlatformToolset") ;
		CASE ver >= 0 ? STR tool|set_version = Comp.Defined_value[ver]
		ELSE tool = Get_environment_var("PlatformToolset") ;
        CASE tool == "" ?
			 o[].Delete(i)
			 BREAK i ;
		o[i] = "<PlatformToolset>" tool "</PlatformToolset>"
		BREAK i ;
    --------------------------------- 'save VCXPROJ'
    tf|ile_text_temp = {Text_file}(
            Path = Comp.Destination.Trailing_slash
            "" Comp.Project ".vcxproj")
            
    BOOL ok|_saved = tf.Save(o[])
    CASE Comp.Verbose ?
         << "saved"._Msav ": " tf.Path ", " ok.Str #NL //>> in_repl 
    ;
    o[].Clear .
    
    
METHOD add_localize_data1 :
    ----------------- 'if localized string are present?'
    INT count|_items = 0
    FOR c IN Comp.All_classes[] :
        CASE c.Localize_n[].Count == 0 ? CONTINUE c ;
        count += c.Localize_n[].Count + 1 ;                 
    CASE count == 0 ? count += 1 ;
    o[] << sp(4) "// add_localize_data1                  #localize1"
    o[] << sp(4) "static std::vector<" final_str "> Localize_name;"
    ---------------- 'add initial values for localized strings'
    o[] << sp(4) "static std::vector<" final_str "> Localize_str;"
    
    o[] << sp(4) "static const int size_Localize_str = " 
    "" count.Str ";"
    .
    
METHOD add_localize_data2 :
	//DEBUG: "add localize data 2 called" >> ;
	STR type_loc|alize_strings = "char"
    STR l_names|localize_ss[] << sp(6) type_loc "* init_Localize_name[] = {"
    o[] << sp(6) type_loc "* init_Localize_str[] = {"
    PUSH generating_localized_strings = TRUE :
         INT start|_index_for_class = 0
         FOR c IN Comp.All_classes[] :
             CASE c.Localize_n[].Count == 0 ? CONTINUE c ;
             o[] << sp(10) #QU#QU ","
             l_names[] << sp(10) #QU "[" c.Names[*] "]"#QU ","
             start += 1
             c.Localize_1st_item = start
             FOR ns IN c.Localize_s[] :
             	 l_names[] << sp(10) #QU c.Localize_n[ns.Index] #QU ","
                 o[] << sp(10) gen_expr(ns) ","
                 start += 1
             ;
         ;
    ;
    --------------------------- 'finish localization arrays'
    //CASE o[*][*] != "{" ?
    //	 o[*] = o[*][0 TO *-1] 
    //	 l_names[*] = l_names[*][0 TO *-1] ;
    o[*] << #QU#QU " };"
    l_names[*] << #QU#QU " };" 
    FOR s IN l_names[] : o[] << s ; .

    
METHOD add_localize_data3 :
    ----------------- 'if localized string are present?'
    o[] << sp(6) "// add_localize_data3                  #localize3"
    o[] << sp(6) "std::vector<" final_str "> AL4_system::Localize_name;"
    ---------------- 'add initial values for localized strings'
    o[] << sp(6) "std::vector<" final_str "> AL4_system::Localize_str;"
    .     

{Type} classes_generated[]
    
METHOD generate_all_classes_h :
    ------------------------------------- '#include AL4.h'
    o[] << @
        "#pragma once"
        ""
        "#include " #QU "AL4.h" #QU 
        ""
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        o[] << "#define present_" c.Final_name " 1" ;     
    ------------------------------------- 'forward declaration of all classes'
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        FOR r IN c.Structures_[] :
            CASE is_simple(r) ?
	             o[] << "struct " r.Final_name ";"
            ELSE o[] << "class " r.Final_name ";" ;
        ;
        o[] << @"" //"#define class__" c.Final_name ""
                "class Methods_" c.Final_name ";"
                "class Noneclass_" c.Final_name ";"
                "class " c.Final_name ";"
    ;
    o[] << ""
    ---------------------------------- 'all structure types are first'
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        CASE c.Is_translation ? CONTINUE c ;
        PUSH Comp.Current_class = c :
            FOR r IN c.Structures_[] :
                CASE Comp.Verbose ?
                     o[] << "// structure #" r.Index.S " in class " c.Final_name
                     o[] << "// [" r.Whole_name "] --> " r.Final_name
                ;
                generate_structure_decl(r) ;
        ;
    ;
    ---------------------------------- 'all classes definitions'
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        CASE c.Is_translation ? CONTINUE c ;
        generate_class_h(c) ; .
        
        
        
METHOD generate_class_h|_in_All_classes_h(
{Type} C|lass_to_generate), RECURSIVE
    :
    -------------------------------- 'check 1st if base class already generated'
    {Type} c|lass_to_generate = C
    CASE c IN classes_generated[] ? ==> ;
    CASE c.Base_ != NONE && c.Base_ !IN classes_generated[] ?
         generate_class_h(c.Base_) ;
    classes_generated[] << c
    -------------------------------------- 'start class'
    STR c_w|hole_name = c.Whole_name 
    o[] << "" << "// class header: " c_w << ""
    total_gen_field = (total_gen_field + 99)
    total_gen_field -= total_gen_field % 100
    Comp.Current_class = c
    tcl[].Clear
    ---------------------------------- 'root native code'
    FOR f IN c.Method[] :
        CASE f.Final_name == "-" && f.Native_code.Starting("#include") ?
             o[] << f.Native_code
        ELSE BREAK f ;
    ;                           
    ----------------------------- 'Methods of class in a separate class'
    o[] << "class Methods_" c.Final_name ": public Methods_"
    CASE c.Base_ == NONE ? o[*] << "AL4_object"
    ELSE o[*] << c.Base_.Final_name ;
    
    o[] << @"{"
            "    public:"
            "        " c.Final_name "* THIS_OBJ;"
            
    o[] << @
           ""
           "        Methods_" c.Final_name "()"
           "        { }"
           ""
           "        Methods_" c.Final_name 
           "(AL4_object* obj_this) : Methods_"
           
    CASE c.Base_ == NONE ? o[*] << "AL4_object"
    ELSE o[*] << c.Base_.Final_name ;
    
    o[*] << @"(obj_this)"
         "" sp(8) "{ THIS_OBJ = (" c.Final_name " *)obj_this; }"
    ------------------- 'non-static methods only'
    BOOL root_outer|_code = TRUE
    FOR f IN c.Method[] :
        CASE f == NONE || f.Final_name == "-" && root_outer ? CONTINUE f ;
        CASE f.Overloaded_[].Count > 0 ? CONTINUE f ;
        root_outer = FALSE
        CASE f.Modifiers['STATIC'] ? CONTINUE f ;
        generate_method(f, FALSE) ;
    o[] << "};" << ""
    ------------------------------------------ 'class c itself now'
    c_w = c.Whole_name 
    o[] << "// class: " c_w " (fields and static methods)"

	CASE c.Localize_n[].Count > 0 ?
	     o[] << "        const int " c.Final_name "_First_localize_item = "
	     o[*] << c.Localize_1st_item.Str ";"
	;
    
    o[] << "class " c.Final_name
    CASE c.Base_ == NONE ? o[*] << ": public AL4_object"
    ELSE o[*] << ": public " c.Base_.Final_name ;
    
    o[] << @"{"
            "public:"
            
    generate_ref(c)
    generate_NONE(c)
    --------------------------------- 'enums'
    FOR e IN c.Enums_[] :
        generate_enum(e, FALSE) ;
    --------------------------------- 'methods'
    o[] << @
        ""
        "" sp(8) "Methods_" c.Final_name "* Do()"
        "" sp(8) "{"
        "" sp(8) "    return (Methods_" c.Final_name "*)DO;"
        "" sp(8) "}"
        ""
        "" sp(8) c.Final_name "()"
        "" sp(8) "{" 
        "" sp(8) "   DO = new Methods_" c.Final_name "(this);"
        
    o[] << @
        "" sp(8) "}"
        ""
    --------------------------------- 'fields'
    FOR v IN c.Field[] :
        generate_field(v) ;
    CASE c.Ending_lines[].Count > 0 ?
         o[*] << @"static FixAStr* DATA;" ;

    ----------------------- 'only static methods'
    root_outer = TRUE
    FOR f IN c.Method[] :
        CASE f == NONE || f.Final_name == "-" && root_outer ? CONTINUE f ;
        CASE f.Overloaded_[].Count > 0 ? CONTINUE f ;
        root_outer = FALSE
        CASE f.Modifiers['STATIC'] ? 
             generate_method(f, FALSE) ;
    ;
    --------------------------------- 'Get_CNT (for Report_leaks)'
    CASE Comp.Defined_name[].Find("$REPORT_LEAKS") >= 0 ?
         o[] << "static int Get_CNT(int index);" ;
    --------------------------------- 'tests'
    BOOL has_tests|_without_parameters
    CASE Comp.TEST_value ?
         FOR t IN c.Test[] :
             has_tests ||= t.Param[].Count == 0
             generate_method(t, FALSE) ;
         ---------------------------- 'Do_tests()'
         o[] << #NL "static void Do_tests();"
         ---------------------------- 'assertions list'
         o[] << "" << "static std::vector<long long> test_lines"
                "_" c.Final_name ";"
                
         o[] << "" << "static std::vector<int> test_assert"
                "_" c.Final_name ";"
                
         o[] << "static std::vector<" final_str "> test_assert_failed_text"
                "_" c.Final_name ";"
                
         o[] << "};" << ""
         ---------------------------- 'test_lines'
         o[] << "" << "#include " #QU "TL_" c.Final_name ".h" #QU
         ---------------------------- 'instances of static vectors'
         collect_test_vectors_instances(c)
    ELSE o[] << "};" << "" ;
    ----------------------------- 'generate Noneclass_ ?'
    generate_Noneclass(c) .
    
STR instances|_of_static_vectors[]
INT mark_test, DEBUG
    
METHOD collect_test_vectors_instances(
	{Type} C|lass_to_test)
	:
	DEBUG: mark_test+=1
		   instances[] << "//mark:" mark_test.S 
	;
    instances[] << "" << "std::vector<long long> " C.Final_name "::test_lines"
        "_" C.Final_name ";"
        
    instances[] << "" << "std::vector<int> " C.Final_name "::test_assert"
        "_" C.Final_name ";"
        
    instances[] << "std::vector<" final_str "> " C.Final_name 
        "::test_assert_failed_text_" C.Final_name ";"
    .

    
METHOD for_all_methods_remove_overriden_lines_from_tests(
    {Type} C|lass_handling)
    :
    FOR f IN C.Method[] :
        remove_overridden_method_lines_from_tests_of_base(f) ; .

INT tcl|_test_counter_lines[]

METHOD generate_class_impl|ementation(
{Type} Class|_to_generate) ==> BOOL
	:
    PUSH Comp.Current_class = Class :
        ---------------------------------- 'module class header'
        CASE Comp.Verbose ?
             << "generate class"._Mgen ": " Class.Whole_name #NL ;
        
        o[] << @
            "//----------------------------------------------------------------"
            "// class " Class.Whole_name " -- implementation"
            "//----------------------------------------------------------------"
            
        total_gen_field = (total_gen_field + 99)
        total_gen_field -= total_gen_field % 100
        tcl[].Clear
        
        o[] << @
            "#include " #QU "AL4.h" #QU ""
            "#include " #QU "All_classes.h" #QU
            "//DEBUG:" DEBUGGING_METHODS.Str
        ---------------------------------- 'root native code'
        FOR f IN Class.Method[] :
            CASE f.Final_name == "-" ?
                 CASE f.Native_code.Starting("#include") ? CONTINUE f ;
                 o[] << f.Native_code
            ELSE BREAK f ;
        ;
        STR n|ame_of_class = Class.Final_name
        
        o[] << @
		       "" sp(4) n "* " n "::NoneObj_" n ";"
		       "" sp(4) n "* " n "::DummyObj_" n ";"
        ------------------- 'non-static methods only'
        BOOL root_outer|_code = TRUE
        FOR f IN Class.Method[] :
            CASE f == NONE || f.Final_name == "-" && root_outer ? CONTINUE f ;
            CASE f.Overloaded_[].Count > 0 ? CONTINUE f ;
            root_outer = FALSE
            CASE f.Modifiers['STATIC'] ? CONTINUE f ;
            generate_method(f, TRUE) ;
        o[] << ""
        ------------------------------------------ 'Class contains main ?'
        CASE Class == Comp.All_classes[0] ?
            generate_main(Class) ;
        ----------------------- 'declare class static fields'
        CASE Class.Ending_lines[].Count > 0 ?
             o[] << sp(8) "FixAStr* " Class.Final_name "::DATA;" << "" ;
        FOR e IN Class.Enums_[] :
            generate_enum(e, TRUE)
        ;
        ----------------------- 'init_class'
        o[] << @
            "" sp(4) "void " n "::init_class_" n "()"
            "" sp(4) "{"                                       
            "" sp(4) "    NoneObj_" n " = (" n "*)New_nofields()->Obj;"
            "" sp(4) "    NoneObj_" n "->hard_link->Count = -1;"
            "" sp(4) "    NoneObj_" n "->Is_NONE_object = true;"
            "" sp(4) "    None_obj = NoneObj_" n "->hard_link;"
            "" sp(4) "    DummyObj_" n " = (" n "*)New_nofields()->Obj;"                
            "" sp(4) "    DummyObj_" n "->hard_link->Count = -1;"
            "" sp(4) "    Dummy_obj = DummyObj_" n "->hard_link;"                
            "" sp(4) "    NoneObj_" n "->write = DummyObj_" n ";"
            "" sp(4) "    NoneObj_" n "->DO = (Methods_AL4_object*)"
            "" sp(4) "          new Noneclass_" n "((" n "*)NoneObj_" n ");"
            "" sp(4) "    DummyObj_" n "->DO = (Methods_AL4_object*)"
            "" sp(4) "          new Noneclass_" n "((" n "*)DummyObj_" n ");"
        ------------------------ 'init DATA and static fields'
        FOR fld IN Class.Field[] :
            ----------------------------- 'initialize DATA'
            CASE fld.Final_name == "DATA" ?
                 gen_init_data(Class) 
                 BREAK fld ;
        ;
        ----------------------------- 'end of init_class_'
        o[] << @
            "" sp(4) "}"                                       
            ""
        ------------------------------------ 'Do_init_fields method'
        CASE ! Class.Names[0].Starting("Noneclass_") ?
        	 generate_implementation_Do_init_fields(Class)
        	 FOR st IN Class.Structures_[] :
        	     CASE !is_simple(st) ?
        	          generate_implementation_Do_init_fields(st) ;
        	 ;
        ;
        ----------------------- 'only static methods'
        root_outer = TRUE
        FOR f IN Class.Method[] :
            CASE f == NONE || f.Final_name == "-" && root_outer ? CONTINUE f ;
            CASE f.Overloaded_[].Count > 0 ? CONTINUE f;
            root_outer = FALSE
            CASE f.Modifiers['STATIC'] ?
                 generate_method(f, TRUE) ;
        ;
        --------------------------------- 'Get_CNT (for Report_leaks)'
        CASE Comp.Defined_name[].Find("$REPORT_LEAKS") >= 0 ?
             o[] << @"int " Class.Final_name "::Get_CNT(int index)"
                     "{"
                     "    if (index == 0)"
                     "       return CNT_CONSTRUCT_" Class.Final_name ";"
                     "    return CNT_DESTRUCT_" Class.Final_name ";"
                     "}" ;
        --------------------------------- 'NONE object methods'
        generate_noneclass_methods(Class, TRUE)
        --------------------------------- 'tests'
        STR start_str = #QU
        STR end_str|_symbol = #QU
        CASE Comp.TEST_value ?
             FOR t IN Class.Test[] :
                 CASE t.Param[].Count == 0 ?
                      BOOL has_tests|_without_parameters = TRUE ;
                 generate_method(t, TRUE) ;
                 
             o[] << @ 
                    "void " n "::Do_tests()"
                    "{"
                    
             o[] << sp(4) "AL4_system::Clear_test_data(test_lines" 
                    "_" Class.Final_name ");"
                    
             CASE Class.Base_.Modifiers['ABSTRACT'] ?
                  o[] << sp(4) "AL4_system::Clear_test_data("
                  "test_lines_" Class.Base_.Final_name ");"
             ;
             FOR t IN Class.Test[] :
                 CASE t.Param[].Count != 0 ? CONTINUE t ;
                 o[] << sp(4) t.Final_name "();" ;
             CASE Comp.Verbose && has_tests ?
                  o[] << "    AL4_system::WriteLine" 
                         "(" as_str("Saving test data: "
                         "" Comp.Destination.Trailing_slash.double_slushes
                         "" Class.Final_name ".test") ");"
             ;
             CASE has_tests ?
                  o[] << sp(4) "AL4_system::Output_test_data(test_lines"
                  "_" Class.Final_name ", "
                  "test_assert_" Class.Final_name
                  ", test_assert_failed_text_" Class.Final_name
                  ", " start_str
                  "" Comp.Destination.Trailing_slash.double_slushes 
                  "" Class.Final_name ".test" end_str
                  ", " start_str 
                  "" Class.Path.double_slushes end_str ");"
                  
                  CASE Class.Base_.Modifiers['ABSTRACT'] ?
                       for_all_methods_remove_overriden_lines_from_tests(Class)
                       
                       o[] << sp(4) "AL4_system::Output_test_data("
                       "test_lines_" Class.Base_.Final_name ", "
                       "test_assert_" Class.Base_.Final_name 
                       ", test_assert_failed_text_" Class.Base_.Final_name 
                       ", " start_str
                       "" Comp.Destination.Trailing_slash.double_slushes
                       "" Class.Final_name 
                       "." Class.Base_.Final_name ".test" end_str 
                       ", " start_str 
                       "" Class.Base_.Path.double_slushes end_str ");"
                  ;
             ;
             o[] << "}"
             ---------------------------- 'counters array'
             STR tl|ines_text[]
             
             tl[] << "" << "static int init_test_lines"
                 "_" Class.Final_name "[] = {"
                 
             FOR line IN tcl[] :
                 CASE line >= 0 ? 
                      Class.Total_lines_in_test = line.Index + 1 ;
                 tl[*] << line.Str ","
                 CASE tl[*].Len >= 80 ? tl[] << "" ;
             ;
             tl[] << "-100 };" <<
                     "static const int count_test_lines_" Class.Final_name
                     " = " tcl[].Count.Str ";"
                     
             tf|ile_temp = {Text_file}(Path = Comp.Destination.Trailing_slash 
             "TL_" Class.Final_name ".h")
             
             NONE = tf.Save(tl[])
        ;
        o[] << ""
        RESULT = Comp.Errors_count == 0
    ; .
    
METHOD generate_implementation_Do_init_fields(
{Type} Class|_implementing)
	:
	STR n|ame_of_class_type = Class.Final_name
	
	o[] << "" sp(4) "void " n "::Do_init_fields(" n "* Result)" <<
           "" sp(4) "{"
           
    INT was|_o_count = o[].Count
    STR gen|erated_init_fields = gen_init_fields(Class, FALSE) 
    o[] << gen #NL
    FOR i IN [o[].Count-1 DOWNTO 0] :
        CASE o[i].Trim == "" ? o[].Delete(i)
        ELSE BREAK i ;
    ;
    CASE was == o[].Count ?
         o[] << sp(8) "if(Result){}" ;
    o[] << sp(4) "}" << "" .

    

FUN double_slushes( STR S|ource_line ) ==> STR :
    RESULT = S
    FOR i IN [S.Len-1 DOWNTO 0] :
        CASE S[i] == "\" ? RESULT = RESULT[0 TO i] RESULT[i TO *] ; 
    ; .
    
METHOD remove_overridden_method_lines_from_tests_of_base({Fun} F|unction) :
    {Fun} a|ncsector_method = F.Ancestor_
    CASE a == NONE || a.Class != F.Class.Base_ ? ==> ;
    
    o[] << sp(4) "AL4_system::Remove_test_data("
    "test_lines_" F.Class.Base_.Final_name 
    ", " a.Line_start.Str ", " a.Line_end.Str ");" .

{Type} structures_declared[]
    
METHOD generate_structure_decl(
{Type} St|ructure_type), RECURSIVE
	:
    CASE St IN structures_declared[] ? ==> ;
    structures_declared[] << St
    FOR f IN St.Field[] :
        ---------------------- 'all referenced records must be already declared'
        CASE f.Type_.Kind == 'STRUCTURE' ? generate_structure_decl(f.Type_) ;
    ;
    CASE St.Final_name[0] == "s" ?
    	 o[] << "struct " St.Final_name
    ELSE o[] << "class " St.Final_name " : public Any_structure" ;
    o[] << "" sp(4) "{"
    CASE !is_simple(St) ? o[] << sp(8) "public:" ;
             
    FOR f IN St.Field[] :
        CASE is_simple(St) ?
	         o[] << type_gen(f.Type_, {type_options}(
	        		 Array=FALSE, Fixed=TRUE, Weak=FALSE))
	        		 " " f.Final_name
	         CASE ?
	         [f.Is_fixed && f.Size_value == 0] ?
	         	  f.Size_value =  calculate_size_value(f.Size_n)
	              o[*] << "[" f.Size_value.Str "]"
	         [f.Is_fixed] ?
	              o[*] << "[" f.Size_value.Str "]"
	         [f.Is_array] ?
	              o[*] << "[]"
	         ;
        ELSE
	         o[] << type_gen(f.Type_, {type_options}(
	        		 Array=f.Is_array, Fixed=f.Is_fixed, Weak=f.Is_weak))
	        		 " " f.Final_name
        ;
        o[*] << ";" ;
        
    CASE TRUE ?
         St.Generate_info[] << "STRUCTURE CONSTRUCTOR"
         o[] << sp(8) "public: " St.Final_name "() {"
         init_structure_fields(o[], St, Sp(12))
         o[] << sp(8) "}"
    ;
    CASE !is_simple(St) ? 
         generate_NONE(St)
         generate_New(St, St.Final_name)
         o[] <<@"virtual Any_structure* Clone() override;"
                //"{"
                //"	" St.Final_name "* Result = (" St.Final_name "*)New()->Obj;"
         		
         //copy_structure_fields(St, "    Result->", "this->")
         		 
         //o[] <<@"	return Result;"
                //"}"
    ;
    o[] << sp(4) "};" << "" .
    
FUN first_spaces(STR S|tring_with_leading_spaces) ==> STR :
	INT n|_spaces_1st = S.Len - S.TrimL.Len
	RESULT = S[0 TO n-1] .
    
    
FUN detect_simple_structure(
{Type} St|ructure_type) ==> BOOL, RECURSIVE
	:
    FOR f IN St.Field[] :
        CASE f.Is_array || f.Type_.Kind IN ['STR', 'CLASS'] ?
             RESULT = FALSE ==> ;
        CASE f.Type_.Kind == 'STRUCTURE' ?
             RESULT = detect_simple_structure(f.Type_)
             CASE !RESULT ? ==> ;
        ;
    ; 
    RESULT = TRUE .
    
METHOD init_structure_fields (
    STR Out|put_strings[],
    {Type} St|ructure_type,
    STR Prefix|_spaces), RECURSIVE
    :
    -------------------------- ''
    FOR f IN St.Field[] :
        CASE f.Is_array ?
             Out[] << Prefix "memset(&" f.Final_name 
                      ", 0, sizeof(" f.Final_name "));"
             CONTINUE f ;
             
        CASE f.Type_.Kind == 'STR' ?
             Out[] << Prefix f.Final_name " = "#QU#QU";"
             CONTINUE f ;
        
        CASE f.Type_.Kind == 'STRUCTURE' ?
             CASE f.Type_.Final_name[0] == "s" ?
                  CASE msvstudio ? 
                       Out[] << Prefix "memset(&" f.Final_name ", 0, sizeof(" 
                       ..[*] << f.Type_.Final_name "));" 
                  ELSE Out[] << Prefix f.Final_name " = {};" ;
             ELSE 
	              init_structure_fields(Out[], f.Type_,
	                     Prefix f.Final_name "." )
             ;
             CONTINUE f ;
             
        Out[] << Prefix f.Final_name " = " gen_none_val(f.Type_) ";"
    ; .
    
    
METHOD calculate_size_value( STR S|tring_value ) ==> INT :
    CASE S[0] == "{" ?
         {Type} enum|eration = Comp.Current_class.Find_type(S)
         CASE enum == NONE ?
              Comp.Error("Enumeration type "._Eenum  S
              " " ("was not found in class"._Ewasnot2 )
              " " Comp.Current_class.Whole_name)
         ;
         CASE enum.Kind != 'ENUM' ?
              Comp.Error("Type is not a enumeration"._Etype ": " S) ;
         RESULT = enum.Items[].Count ==> ;
    RESULT = int_from_str(S)
    CASE RESULT <= 0 ?
         Comp.Error("Array size value must be greater "
         "then 0"._Earray) ; .   

FUNCTION int_from_str( STR S|tring_only_digits ) ==> INT :
    FOR i IN [0 TO S.Len-1] :
        CASE S[i] IN "0123456789" ?
             RESULT = RESULT * 10 + S[i].Ord - "0".Ord
        ELSE ==> ;
    ; .

         

FUN sp|aces_sequence(INT Count|_spaces) ==> STR :
        RESULT = #SP.Repeat(Count) .


METHOD generate_ref({Type} Class|_to_generate) :
    generate_New(Class, Class.Final_name)
    
    o[] << @""                                                           
    "" sp(4) "static Ref_obj* New_owned(Ref_obj* owner) "
    "" sp(4) "{"                                                 
    "" sp(4) "    Ref_obj* Result = New();"
    "" sp(4) "    Result->Obj->Owned_by(owner);"  
    "" sp(4) "    return Result;"                      
    "" sp(4) "}"                                                 
    "" .


METHOD generate_New(
{Type} Class|_to_generate_New, STR N|ame_of_class)
	:
    -------------------------------------- 'New() { ... }'
    o[] << @"" sp(4) "static Ref_obj* New() "                   
            "" sp(4) "{"                                                 
            "" sp(4) "    " N "* Result = new " N "();"                   
            "" sp(4) "    Result->hard_link = new Ref_obj(Result, 0);"
            "" sp(4) "    Result->weak_link = new Ref_obj(Result, 1);"
            "" sp(4) "    Result->write = Result;"
            
    CASE N.Find("Noneclass_") != 0 ?
         o[] << "" sp(8) "Do_init_fields(Result);"
         BOOL want_init_fields = TRUE ;
    gen_create_base(Class)
    
    o[] << @""
            "" sp(4) "    return Result->hard_link;"
            "" sp(4) "}"
            ""
    ------------------------------------ 'Do_init_fields'
    CASE want_init_fields ?
        o[] << "" sp(4) "static void Do_init_fields(" N 
               "* Result);" ;
    ------------------------------------ 'New_nofields'
    o[] << @"" sp(4) "static Ref_obj* New_nofields()"                     
            "" sp(4) "{"                                                 
            "" sp(4) "    " N "* Result = new " N "();"                   
            "" sp(4) "    Result->hard_link = new Ref_obj(Result, 2);"
            "" sp(4) "    Result->weak_link = new Ref_obj(Result, 1);"
            "" sp(4) "    Result->write = Result;"
            
    o[] << @
            "" sp(4) "    return Result->hard_link;"
            "" sp(4) "}"
            ""
    .
    
INT total_init_base    
    
METHOD gen_create_base(
{Type} Class|_to_generate), RECURSIVE
	:
    CASE Class.Base_ != NONE ?
         gen_create_base(Class.Base_) ;
    INT from|_line = o[].Count
    PUSH new_init = Class.Create_base.Source :
         CASE new_init == NONE ? ==> ;
         o[] << sp(12) "// init base: " Class.Whole_name " " total_init_base.Str
         total_init_base += 1
         PUSH spaces = sp(12) :
              fun|ction_temp = {Fun}(Parse = Class.Parse,
              	A_Name_0 = "temp_fun" total_init_base.S)
              	
              r|esult_def_temp = {Assign}(Line = 0, Level=0,
                Function_ = fun,
                Dest = {Expr}(Operation = 'VAR',
                	Var_arg = {Var}(Line = 0, Type_ = Class)))
                	
              r.Dest.Var_arg.Set_final_name("Result")
              o[] << gen_init_new_obj(r) ;
    ;
    FOR line IN [from TO o[].Count-1] :
        STR s|tring_line = o[line]
        CASE s[0 TO 1] == "//" ? CONTINUE line ;
        INT dot|_position = s.Find(".write).")
        CASE dot > 0 ?
             o[line] = sp(12) "Result" s[dot+7 TO *] ;
    ; .
    
INT total_init_fld

METHOD gen_init_fields(
    {Type} Class|_to_generate_fields,
    BOOL Non|e_instance_initializing) ==> STR, RECURSIVE
    :
    ----------------------------------------------- 'initialize fields'
    FOR f IN Class.Field[] :
        CASE f.Final_name == "DATA" ? CONTINUE f ;
        RESULT << gen_init_field(f, Non)
    ;
    CASE RESULT != "" ?
        RESULT = #NL sp(12) 
        "// init fields: " Class.Final_name #NL RESULT
    ;
    CASE Class.Base_ != NONE ?
        RESULT = gen_init_fields(Class.Base_, FALSE) #NL RESULT ; .

METHOD gen_init_field|_single(
    {Var} F|ield_init,
    BOOL Non|e_initializing) ==> STR
    :
    STR comm|ent_before = #NL sp(12) "// init fld: " total_init_fld.Str
    //DEBUG:
    //      CASE total_init_fld == 3 ?
    //           NONE ;
    //;
    comm << #NL sp(12)
    total_init_fld += 1
    STR s|tring_to_add = "Result->" F.Final_name " = "
    CASE F.Is_array ?
            CASE F.Type_.Kind ?
            ['BOOL']: STR suf|fix_fn = "Bool"
            ['BYTE', 'ENUM']: suf = "Byte"
            ['INT']: suf = "Int"
            ['REAL']: suf = "Real"
            ['STR']: suf = "Str"
            ['STRUCTURE', 'CLASS']: 
                       CASE F.Is_weak ?
                            suf = "ObjWeak"
                       ELSE suf = "ObjHard" ;
                       CASE F.Is_fixed ? suf = "Obj" ;
            ;
            CASE ?
            [F.Is_fixed && F.Size_type_.Kind == 'ENUM'] ?
                 RESULT << comm s "new FixA" suf 
                 		   "(" F.Size_type_.Items[].Count.Str ");" ==>
                 		   
            [F.Is_fixed] ?
                 RESULT << comm s "new FixA" suf "(" F.Size_value.S ");" ==>
            ;
            s << "new DynA" suf
            CASE ?
            [F.Type_.Kind == 'STRUCTURE' && F.Type_.Final_name[0] == "s"] ?
                 s << "(sizeof(" F.Type_.Final_name "))"
                 
            [F.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
                 s << "(" F.Type_.Final_name "::NoneObj_" F.Type_.Final_name
                      "->hard_link)"
                      
            ELSE s << "()" ;
    ELSE 
         CASE Non && F.Type_.Kind IN ['BOOL', 'INT', 'REAL', 'ENUM'] ? ==> ;
         comm << "//INIT STRUCTURED: " F.Type_.Kind.Name #NL sp(12)
         CASE F.Type_.Kind == 'STRUCTURE' && F.Type_.Final_name[0] == "s" ?
              CASE msvstudio ? 
	               s = s.Remove_trailing(" = ")
	               s = "memset(&" s ", 0, sizeof(" s "))"
              ELSE s << "{}" ;
              RESULT << comm s ";" ==> ;
         CASE F.Initial_ != NONE ? s << gen_expr(F.Initial_)
         ELSE s << gen_none_val(F.Type_)
         ;
    ;
    RESULT << comm s ";" .
    
FUN is_simple|_structure({Type} St|ructure_type ) ==> BOOL
	:= St.Final_name[0] == "s" .
         
BOOL data_init|ialization    
    
METHOD gen_init_data({Type} C|lass_init_data) :
    CASE C.Ending_lines[].Count == 0 ? ==> ;
    
    o[] << @
        "" sp(8) "const char* DATA_v[] = { "
        
    PUSH wxT = "" :
    PUSH data_init = TRUE :
         FOR d IN C.Ending_lines[] :
             o[] << sp(4) as_str(d).Remove_br "," ;
    ;
    ;
    o[*] = o[*][0 TO *-1] "};"
    
    o[] << sp(8) C.Final_name "::DATA = new FixAStr(" C.Ending_lines[].Count.Str 
    ");"
    
    o[] << sp(8) C.Final_name "::DATA->Set_strings(DATA_v);" .
    
METHOD generate_const_array({Var} C|onstant_array) :
	STR t|ype_items = type_gen(C.Type_, {type_options})
	CASE "string" IN t ? t = "char*" ;
	
    o[] << sp(4) "const " t " " C.In_type_.Final_name "__" C.Final_name 
        	"[] = { "
        
    FOR it IN C.Items_[] :
        CASE o[*].Len >= 64 ? o[] << sp(8) ;
        STR v_gen|erated_value = gen_const_value(it)
        o[*] << v_gen ", " ;
    o[*] = o[*].TrimR.Remove_ending(",") " };" .


METHOD generate_NONE({Type} Class|_to_generate) :
    ----------------------------------- 'NoneObj_ and DummyObj_'
    STR n|ame_of_class = Class.Final_name
    
    o[] << @""
        "" sp(4) "static " n "* NoneObj_" n ";"
        "" sp(4) "static " n "* DummyObj_" n ";"
        ""
        "" sp(4) "static void init_class_" n "();"
        ""
    -------------------------------- 'NONE_base_obj'
    o[] << @
        "" sp(4) "virtual AL4_object* NONE_base_obj() override"
        "" sp(4) "{"
        "" sp(4) "    return "
        
    CASE Class.Base_ == NONE ? o[*] << "nullptr"
    ELSE o[*] << Class.Base_.Final_name "::NoneObj_" Class.Base_.Final_name ;
    o[*] << ";"
    o[] << "" sp(4) "}" << ""
    -------------------- 'NONE_obj_instance'
    o[] << @
        "" sp(4) "virtual Ref_obj* NONE_obj_instance() override"
        "" sp(4) "{"
        "" sp(4) "    return NoneObj_" n "->hard_link;"
        "" sp(4) "}"
        "" .


METHOD generate_Noneclass({Type} Class|_to_generate) :
    ------------------------------------ 'start Noneclass_'
    STR n|ame_class = Class.Final_name
    
    o[] << @""
            "" sp(4) "class Noneclass_" n ": Methods_" n ""
            "" sp(4) "{"
            "" sp(4) "public:"
            ""
            "" sp(4) "    Noneclass_" n "()"
            "" sp(4) "    { }"
            ""
            "" sp(4) "    Noneclass_" n "(" n "* obj_this) :"
            "" sp(4) "          Methods_" n "((AL4_object*)obj_this)"
            "" sp(4) "    {"
            "" sp(4) "    "
            "" sp(4) "    }"
            ""
            "" sp(4) "    virtual void Erase() override { }"
            ""
    //generate_New(Class, "Noneclass_" n)
    o[] << @""
            "" sp(4) "    //public void Init_none()"
            "" sp(4) "    //{"
            "" sp(4) "    //    Noneclass_" n " Result = this;"
            "" sp(4) "    //    Result.Is_NONE_object = true;"
            
    o[] << @"" sp(4) "    //}"
            ""
    ---------------------------- 'methods for NONE to ignore all calls'
    generate_noneclass_methods(Class, FALSE)
    
    o[] << @"" sp(4) "};"
    "" .


METHOD generate_noneclass_methods|_overriden(
{Type} C|lass_to_generate,
BOOL Implement|ation)
    :
    ---------------------------------- 'for all non-static methods'
    o[] << @    "#pragma warning(push)"
                "#pragma warning(disable:4100)"
                
    FOR m IN C.Method[] :
        CASE m == NONE ? CONTINUE m ;
        o[] << "// method: " m.Final_name ":" m.Modifiers['STATIC'].Str
        CASE m.Final_name == "-" ? CONTINUE m ;
        CASE m.Modifiers['STATIC'] ? CONTINUE m ;
        CASE m == C.Construct || m == C.Destruct ? CONTINUE m ;
        o[] << "" << sp(8)
        CASE m.Result !=  NONE ?
             o[*] << type_gen(m.Result.Type_, {type_options}(
             Array=FALSE, Fixed=FALSE, Weak=FALSE)) " "
             
        ELSE o[*] << "void " ;
        CASE Implement ? o[*] << "Noneclass_" C.Final_name "::" ;
        o[*] << m.Final_name "( "
        ------------------------------ 'parameters'
        FOR p IN m.Param[] :
            o[] << sp(16) type_gen_A(p.Type_, {type_options}(
                   Array=p.Is_array, Fixed=p.Is_fixed, Weak=p.Is_weak))
                   " " p.Final_name ","
        ;
        CASE m.Modifiers['STORE'] ?
             o[] << sp(16) "int& " m.Stored_param.Final_name "," ;
        o[*] = o[*][0 TO *-1] ")"
        CASE ! Implement ? 
             o[*] << ";"
             CONTINUE m ;
        ------------------------------ 'body'
        o[] << sp(8) "{"
        CASE m.Result != NONE ?
             CASE m.Result.Type_.Kind == 'STRUCTURE' 
             	  && is_simple(m.Result.Type_)
             	  ?
                  {Type} t|ype_of_record = m.Result.Type_
                  o[] << sp(12) t.Final_name " Result;"
                  CASE msvstudio ? 
                  	   ..[] << sp(12) "memset(&Result, 0, sizeof(" 
                       		   "" t.Final_name "));" 
                  ELSE 
	                   o[] << sp(12) "Result = {};" << sp(12) 
	                   "return Result;" 
                  ;
             ELSE o[] << sp(12) "return " gen_none_val(m.Result.Type_) ";" ;
        ;
        o[] << sp(8) "}" ;
    o[] <<  "#pragma warning(pop)"
    .


METHOD generate_main({Type} Class|_main) :
    //------------------------------------------- 'ui needed ?'
    //CASE ui_i >= 0 ? ui_s = Comp.Defined_value[ui_i] ;
    ------------------------------------------- 'need Report_leaks?'
    CASE Comp.Defined_name[].Find("$REPORT_LEAKS") >= 0 ?
         BOOL report_leaks = TRUE
         generate_report_leaks ;
    ------------------------------------------- 'Main called from main'
    {Fun} f|unction_main = Class.Find_fun("Main", TRUE)
    CASE Comp.TEST_value ?
         o[] << sp(4) "static void Main()"
         //BOOL main_static = TRUE
    ELSE 
    	 CASE Comp.TEST_value ?
    	 	  o[] << sp(4) "void AL4Form::AL4Main() {}"
    	 	  o[] << sp(4) "static void Main()"
    	 	  
         ELSE o[] << sp(4) "static void Main()" ;
    ;
    o[] << sp(4) "{"
    
    o[] << #TAB#TAB"AL4_system::WriteRedirected = AL4_system::Write_direct;"
    generate_init_classes
    
    o[] << @""
    "" sp(4) "    try {"
    
    CASE Comp.Noconsole ?
         o[] << sp(4) "AL4_system::Need_console = true;" ;
    ------------------------------------------ 'call tests or Main'
    CASE Comp.TEST_value ?
         o[] << sp(12) Class.Final_name "::Do_tests();"
         FOR c IN Comp.All_classes[] :
             CASE c == Class ? CONTINUE c ;
             CASE c.Test[].Count == 0 ? CONTINUE c ;
             //CASE c.Tests_already_done ? CONTINUE c ;
             o[] << sp(12) c.Final_name "::Do_tests();" ;
             
    ELSE o[] << @
                "" sp(12) Class.Final_name "::" f.Final_name "();"
    ;
    CASE LOGGING_METHODS ?
     	 o[] << "AL4_log_methods::log_method("#QU#QU");" ;

    CASE report_leaks ?
         o[] << sp(12) "Report_leaks();" 
         //CASE ! Comp.TEST_value ?
         //     o[] << sp(12) "AL4Application::Call_report_leaks = &Report_leaks;"
         //;
    ;
    o[] << @"" sp(4) "    } catch (StopException& S) {"
            "" sp(4) "      AL4_system::Any_exception(S);"
            "" sp(4) "      AL4_system::WriteLine("
            "" sp(4) "      "
            
    o[*] << #QU"STOP: "#QU " + S.Message);"
    
    o[] << @"" sp(4) "      std::string s = AL4_system::ReadLine();"
            "" sp(4) "    }"
            "" sp(4) "}"
            "" 
    		"	std::vector<std :: string> AL4_system::Parameters;"
    ---------------------------------------------- 'main'
    o[] << @""
    	""
        "    int main(int argc, char* argv[])"
        "    {"
        "       //if(argc > 0 && argv[0]){}"
        "		AL4_system::Parameters = std::vector<std :: string>("
        "			argv, argv+argc);"
        
    o[] << @
        "        Main();"
        "        return 0;"
        "    }" .
        
        
METHOD generate_report_leaks :
    o[] << @"void Report_leaks()"
            "{"
            "    long long n_constr;"
            "    long long n_destr;"
            "    std::vector<std::string> RL;"
    STR start_str = ""
    STR end_str|ing = ""
    FOR c IN Comp.All_classes[] :
        CASE c.Construct == NONE || c.Destruct == NONE ? CONTINUE c ;
        
        o[] << @
            "    n_constr = " c.Final_name "::Get_CNT(0);"
            "    n_destr = " c.Final_name "::Get_CNT(1);"
            "    if (n_constr != n_destr)"
            "       RL.push_back(std::to_string(n_constr) + " 
            "       " start_str #QU"\t"#QU end_str " + "
            "           std::to_string(n_destr) + "
            "       " start_str #QU"\t" c.Final_name #QU end_str ");"
    ;
    o[] << @"    if (RL.size() > 0)"
            "       RL.insert(RL.begin(), "
            "		std::string("#QU"constr\tdestr\tclass"#QU"));"
            "    AL4_system::Save_strings(RL, " @@"" 
    "std::string(" #QU Comp.Destination.Trailing_slash.double_slushes 
    "Report_leaks.txt" #QU ")" @
            "    );"
            "}"
            "" .

        


METHOD generate_init_classes|_for_main_or_tests :
    o[] << sp(8) "AL4_object::init_class_AL4_object();"
	---------------------------------- 'init structures'
	o[] << sp(8) "    // init structures"
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        FOR st IN c.Structures_[] :
            CASE st.Is_translation || is_simple(st) ? CONTINUE st ;
            o[] << sp(8) st.Final_name "::init_class_" st.Final_name "();" ;
    ;
	---------------------------------- 'init classes'
    o[] << sp(8) "    // init classes"
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        CASE c.Is_translation ? CONTINUE c ;
        STR n|ame_of_class = c.Final_name
        o[] << sp(8) n "::init_class_" n "();" 
        CASE Comp.TEST_value ?
            o[] << sp(8) n"::test_lines_" c.Final_name ".assign("
            "init_test_lines_" c.Final_name ", "
            "init_test_lines_" c.Final_name " + "
            "count_test_lines_" c.Final_name ");" ;
    ;
    FOR c IN Comp.All_classes[] :
        CASE c == NONE ? CONTINUE c ;
        CASE c.Is_translation ? CONTINUE c ;
        n = c.Final_name
        o[] << sp(8) n "::Do_init_fields(" n "::NoneObj_" n ");" 
        o[] << sp(8) n "::Do_init_fields(" n "::DummyObj_" n ");" 
    ; .


METHOD generate_enum(
{Type} E|numeration, BOOL Implement|ation)
	:
	CASE !Implement ? o[] << "static "
	ELSE o[] << "" ;
    //o[*] << "const TCHAR * "
    o[*] << "const char * "
    CASE Implement ? o[*] << E.Base_.Final_name "::" ;
    o[*] << "Names_" E.Final_name "[" E.Items[].Count.Str "]"
    ------------------------------------------------- 'values'
    STR l_pref|ix_not_using = ""
    CASE Implement ?
         o[*] << " = {"
         FOR it IN E.Items[] :
             o[] << sp(4) l_pref #QU it.Names[0] #QU"," ;
         o[*] = o[*][0 TO *-1]
         o[*] << "}" ;
    o[*] << ";" .




INT total_gen_field

METHOD generate_field({Var} V|ariable) :
    CASE V.Final_name == "DATA" ? ==> ;
    o[] << sp(8) "// declare: " total_gen_field.Str
    total_gen_field += 1
    o[] << sp(8) var_type_gen(V) " " V.Final_name ";" .

FUNCTION var_type_gen({Var} V|ariable) ==> STR :
    RESULT = type_gen(V.Type_, {type_options}(
    	Array=V.Is_array, Fixed=V.Is_fixed, Weak=V.Is_weak)) " " .

STRUCTURE {type_options} :
	BOOL Array|_value
	BOOL Fixed|_array
	BOOL Weak|_object .

FUN type_gen_A|rray_replace(
    {Type} T|ype_of_var,
    {type_options} Op|tions_var) ==> STR
    :
    ---------------------------------------------------- ''
    CASE !Op.Array ? RESULT = type_gen(T, Op) ==> ;
    CASE T.Kind ?
    ['BOOL']:           RESULT = "ArrayBool*"
    ['BYTE', 'ENUM']:   RESULT = "ArrayByte*"
    ['INT']:            RESULT = "ArrayInt*"
    ['REAL']:           RESULT = "ArrayReal*"
    ['STR']:            RESULT = "ArrayStr*"
    ['CLASS']:			RESULT = "ArrayObj"
               CASE Op.Weak ?   RESULT << "Weak*"
               ELSE             RESULT << "Hard*" ;
    ['STRUCTURE']:
				CASE is_simple(T) ? RESULT = "ArrayRec*"
				ELSE				RESULT = "ArrayObjHard*" ;
    ; .

FUNCTION type_gen|erate({Type} T|ype_of_var, 
                        {type_options} Op|tions_var) ==> STR
                        :
    --------------------------------- 'if array'
    CASE Op.Array ?
        CASE Op.Fixed ?
             RESULT = "FixA"
        ELSE RESULT = "DynA" ;
        CASE T.Kind ?
             ['BOOL']: RESULT << "Bool"
             ['BYTE', 'ENUM']: RESULT << "Byte"
             ['INT']: RESULT << "Int"
             ['REAL']: RESULT << "Real"
             ['STR']: RESULT << "Str"
             ['CLASS']: RESULT << "Obj" 
                        CASE !Op.Fixed && Op.Weak ? RESULT << "Weak" ;
                        CASE !Op.Fixed && !Op.Weak ? RESULT << "Hard" ;
             ['STRUCTURE']:
						CASE is_simple(T) ? RESULT << "Rec"
						ELSE				RESULT << "ObjHard" ;
        ;
        RESULT << "*" ==> ;
    --------------------------------- 'if scalar'
    CASE T.Kind ?
    ['BOOL']: RESULT = "bool"
    ['BYTE', 'ENUM']: RESULT = "byte"
    ['INT']: RESULT = "int"
    ['REAL']: RESULT = "double"
    ['STR']: RESULT = "std :: string".remove_sp
    ['STRUCTURE']: 
                CASE is_simple(T) ? RESULT = "struct " T.Final_name
                ELSE RESULT = "Ref_obj*" ;
    ['CLASS']: RESULT = "Ref_obj*" ; .

BOOL DEBUGGING_METHODS = TRUE
//INT total_init_var
INT last_init_var|_line
BOOL exiting_label_used

METHOD generate_method(
{Fun} F|unction, BOOL Implement|ation)
	:
	CASE F == NONE ? ==> ;
    FOR p IN F.Param[] :
        CASE "dummy" IN p.Names[*].Lower ?
             BOOL has_dumm_y|_parameters = TRUE 
             BREAK p ;
    ;
    CASE F.Modifiers['ABANDONED_FUN'] ? has_dumm_y = TRUE ;
    CASE F.Block[].Count == 0 && F.Param[].Count > 0 ? has_dumm_y = TRUE ;
    CASE has_dumm_y ?
         o[] << @   "#pragma warning(push)"
                    "#pragma warning(disable: 4100)"
    ;
    exiting_label_used = FALSE
    do_generate_method(F, Implement)
    CASE has_dumm_y ?
         o[] << @   "#pragma warning(pop)" ;
    .

METHOD do_generate_method(
{Fun} F|unction, BOOL Implement|ation)
	:
    ------------------------------------------ 'skip native directives'
    CASE F.Final_name == "-" ? o[] << F.Native_code ==> ;
    ---- 'on a final stage, clean from fix_arrNNN temp vars added on test stage'
    FOR j IN [F.Local_var[].Count-1 DOWNTO 0] :
        CASE F.Local_var[j].Final_name.Starting("fix_arr") ?
             F.Local_var[].Delete(j) ;
    ;
    ------------------------------------------ 'insert comment / / fun:'
    Comp.Current_fun = F
    Comp.Current_class.Parse.Line = F.Line_start
    o[] << ""
    o[] << "// fun: " F.Total_fn.Str " " F.Names[0]
    spaces = ""
    ---------------------------- 'header start'
    CASE DEBUGGING_METHODS && Implement ?
         o[] << "static int CNT_" F.Final_name "_" F.Class.Final_name ";" << ""
    ELSE o[] << "" ;
    CASE F.Ancestor_ != NONE || (
         F == F.Class.Destruct || F == F.Class.Construct)
         ? 
         CASE F.Modifiers['STATIC'] ?
              Comp.Error("Internal error: static function can "
              "not be override")
         ELSE STR override|_suffix = " override " 
              CASE F == F.Class.Destruct || F == F.Class.Construct ?
                   override = " override " ;
         ;
    ELSE 
         CASE !Implement ?
              CASE F.Modifiers['STATIC'] ? o[*] << "static "
              ELSE o[*] << "virtual " ;
         ;
    ;
    ---------------------------- 'CONSTRUCT & DESTRUCT have fixed names'
    CASE F.Class.Construct == F ? 
         F.Final_name = "CONSTRUCT" ;
    CASE F.Class.Destruct == F ?
         F.Final_name = "DESTRUCT" ;
    CASE Implement ? 
         override = "" ;
    ---------------------------- 'header'
    CASE F.Result == NONE ? o[*] << "void "
    
    ELSE o[*] << type_gen(F.Result.Type_, 
                {type_options}(Array=FALSE, Fixed=FALSE, Weak=FALSE)) " "
	;
    CASE Implement ? 
         CASE ! F.Modifiers['STATIC'] ? o[*] << "Methods_"  ;
         o[*] << F.Class.Final_name "::" ;
    o[*] << F.Final_name "(" sp(1)
    ---------------------------- 'parameters'
    FOR p IN F.Param[] :
        o[] << sp(8) const_if_param_const(p) type_gen_A(p.Type_,
            {type_options}(Array=p.Is_array, Fixed=p.Is_fixed, Weak=p.Is_weak))
               "" pointer_sign_if_param_by_ref(p) " " p.Final_name ","
    ;
    CASE F.Modifiers['STORE'] ?
         o[] << sp(8) "int& " F.Stored_param.Final_name "," ;
    o[*] = o[*][0 TO *-1] ")" override
    CASE !Implement ? o[*] << ";" ==> ;
    ---------------------------- 'body start'
    o[] << "{"
    
    CASE LOGGING_METHODS ?
    	 CASE ?
         [F.Names[*] == LOGGING_RESET] ?
          	  o[] << "AL4_log_methods::reset_logging();"     

    	 [F.Class.Names[0] !IN do_not_log_classes[]
    	  && F.Class.Names[0] "." F.Names[0] !IN do_not_log_methods[]] ?
		      o[] << "AL4_log_methods::log_method("#QU F.Class.Names[0] 
		         	 "." F.Names[0] #QU");"
		         	 
    	 [F.Modifiers['NATIVE_FUN']] ? NONE
		      
    	 ELSE o[] << "AL4_log_methods::disable_log(1);"
    	 	  BOOL disabled_logging = TRUE
    	 	  exiting_label_used = TRUE
    	 ;
    ;
    
    CASE DEBUGGING_METHODS ? o[] << @
                        "    if (++CNT_" F.Final_name "_" F.Class.Final_name 
                             " == 0 )"
                        "    { int stop = 0; if(stop){} }"
                        
    		o[] << "#ifndef NO_SOURCE" ;
    ---------------------------- 'CONSTRUCT ?'
    CASE F == F.Class.Construct  ?
         o[] << spaces sp(4) "Methods_"
         STR a|ncestor_class = F.Class.ancestor_having_construct_class
         CASE a != "" ? o[*] << a 
         ELSE o[*] << "AL4_object" ;
         o[*] << "::" F.Final_name "();" ;
    ---------------------------- 'recursive ?'
    spaces = sp(4)
    BOOL recur|sion = F.Modifiers['RECURSIVE_FUN']
    CASE recur ?
         o[] << spaces "if (AL4_system::Recursion_counter"
                " > System_functions::Max_recursion_deep)" #NL
                "" spaces sp(4) "throw new "
                "TooDeepRecursionException();"
         o[] << spaces "AL4_system::Recursion_counter++;" ;
    ---------------------------- 'local variables'
    FOR v IN F.Local_var[] :
        CASE v.Names[0] != "RESULT" ?
             CASE v.Is_param || v.Final_name == "this" ? CONTINUE v ;
        ;
        CASE v.Declared_in_debug && !DEBUGGING_METHODS ? CONTINUE v ;
        //o[] << spaces "// init var: " total_init_var++.Str
        o[] << spaces type_gen(v.Type_, {type_options}(
               Array=v.Is_array, Fixed=v.Is_fixed, Weak=v.Is_weak))
               
        o[*] << " " v.Final_name "/" "*=*" "/"
               
        CASE v.Type_.Kind ?
            ['BOOL']: STR iv|_initial_value = " = false"
            ['BYTE' ,'INT', 'ENUM', 'REAL']: iv = " = 0"
            ['STR']: 
        		//iv = " = std::string(" #QU #QU ")"
        		iv = " = " #QU #QU
            ['STRUCTURE']:
                e|xpression_v_temp = {Expr}(Operation = 'VAR', Var_arg = v)
            	CASE is_simple(v.Type_) ?
                     iv = "" init_structure(e) "/" "*<1>*" "/"
            	ELSE //iv = " = " v.Type_.Final_name
	                 //iv << "::NoneObj_" v.Type_.Final_name "->hard_link"
	                 iv = " = " v.Type_.Final_name "::New()"
	                 BOOL object_var|iables_present = TRUE ;
            ['CLASS']: iv = " = " v.Type_.Final_name
	                   iv << "::NoneObj_" v.Type_.Final_name "->hard_link"
	                   object_var = TRUE ;
        CASE v.Is_array ?
             iv = " = new " type_gen(v.Type_, {type_options}(
             Array=TRUE, Fixed=v.Is_fixed, Weak=v.Is_weak)).remove_star "("
             CASE ?
             [v.Type_.Kind == 'STRUCTURE' && is_simple(v.Type_)] ?
                  iv << "sizeof(" v.Type_.Final_name ")"
             [v.Type_.Kind IN ['CLASS', 'STRUCTURE']] ?
                  STR t|ype_name = v.Type_.Final_name
                  iv << t "::NoneObj_" t "->hard_link"
             [v.Is_fixed] ? iv << "0" ;
             iv << ")"
             CASE !v.Is_fixed ?
                  BOOL dynamic_arr|ays_present = TRUE ;
        ;
        o[*] << iv ";" ;
    last_init_var = o[].Count
    ---------------------------- 'need try (for exception) ?'
    CASE F.Has_add || recur ?
         o[] << spaces "try {"
         spaces << sp(4) ;
    ---------------------------- 'need try (for finally) ?'
    CASE F.Has_add || recur || object_var || dynamic_arr || (
         F == Comp.Current_class.Destruct)
         ?
         //o[] << spaces "try {"
         //spaces << sp(4) 
    ;
    ---------------------------- 'statements'
    FOR st IN F.Block[] : statement_gen(st) ;
    CASE F.Has_add || recur ? o[] << spaces "}" ;
    ----------------------------- 'catch OutOfMemory'
    CASE F.Has_add ?
         o[] << spaces @"catch (std::bad_alloc& E) {"
             "" spaces "  AL4_system::Any_exception(E);"
             "" spaces "  if (AL4_system::Recursion_counter > 1)"
             "" spaces "     throw;"
         exiting_label_used = TRUE
         CASE F.Result != NONE ?
              CASE F.Result.Type_.Kind == 'STRUCTURE'
              	   && is_simple(F.Result.Type_)
              	   ?
                   CASE msvstudio ? 
                   		o[] << spaces "  memset(&RESULT, 0, sizeof(RESULT));"
                   ELSE o[] << spaces "  RESULT = {};" ;
              ELSE o[] << spaces " RESULT = " gen_none_val(F.Result.Type_) ";" 
              ;
         ;
         o[] << spaces "  goto exiting;"
         o[] << spaces "}" ;
    ---------------------------- 'catch recursion too deep'
    CASE recur ?
         o[] << spaces[0 TO *-4] "catch (TooDeepRecursionException& E) {"
         
         o[] << @
             "" spaces "  AL4_system::Any_exception(E);"
             "" spaces "  if (AL4_system::Recursion_counter > 1)"
             "" spaces "     throw;"
             
         exiting_label_used = TRUE
         CASE F.Result != NONE ?
              CASE F.Result.Type_.Kind == 'STRUCTURE'
              	   && is_simple(F.Result.Type_)
              	   ?
                   CASE msvstudio ? 
                   		o[] << spaces "  memset(&RESULT, 0, sizeof(RESULT));"
                   ELSE o[] << spaces "  RESULT = {};" ;
              ELSE o[] << spaces "  RESULT = " gen_none_val(F.Result.Type_) ";"
              ;
         ;
         o[] << spaces "  goto exiting;"
         o[] << spaces[0 TO *-4] "}" ;
    ---------------------------- 'native ?'
    CASE F.Modifiers['NATIVE_FUN'] ?
         {Type} cc|lass_current = Comp.Current_class
         CASE Comp.TEST_value && cc.Modifiers['TESTED'] ?
              INT line|_of_native_fun = F.Line_start + 1
              FOR i|dummy IN [tcl[].Count TO line] : tcl[] << -1 ;
              tcl[line] = 0
              
              o[] << "    " cc.Final_name "::test_lines_" cc.Final_name 
              "[" line.Str "] = AL4_system::Test_caller;"
         ;
         o[] << F.Native_code
         //DEBUG:
         // CASE F.Names[0] == "Console_color" ?
         //      << F.Native_code.Replace_all(#NL, "\n"#LF#CR) >> ;
         //         
    ;
    ---------------------------- 'finally...'
    CASE exiting_label_used ?
         o[] << "exiting:;" ;
    CASE disabled_logging ?
         o[] << "AL4_log_methods::disable_log(-1);" ;
    CASE recur || object_var || dynamic_arr || F.Has_add || (
         F == Comp.Current_class.Destruct)
         ?
         spaces = spaces[0 TO * - 4]
         //o[] << spaces "} __finally {"
         CASE recur ?
              o[] << spaces "  AL4_system::Recursion_counter--;" ;
         PUSH spaces = spaces sp(4) :
              FOR v IN F.Local_var[] :
                  CASE v IN F.Param[] || v.Final_name IN [
                       "this", "Result"]
                       ?
                       CONTINUE v ;
                  CASE v.Declared_in_debug && !DEBUGGING_METHODS
                  ?
                  CONTINUE v ;
                  //o[] << "//dispose: " v.Final_name
                  gen_dispose_var(v) ;
         ;
         CASE F == Comp.Current_class.Destruct ?
              ------------------------------------ 'clear all object fields'
              gen_unref_class_field_objects(Comp.Current_class)
              ------------------------------------ 'call ancestors DESTRUCT'
              CASE F.Class.Base_ == NONE ? STR base_class = "Methods_AL4_object"
              ELSE base_class = "Methods_" F.Class.Base_.Final_name ;
              o[] << spaces sp(4) base_class "::" F.Final_name "();" ;
         //o[] << spaces "}"
         spaces = spaces[0 TO * - 4] ;
    ----------------------------------------- 'returning result'
    CASE F.Result != NONE ? //&& F.Block[*].Work !IN ['BREAK', 'CONTINUE'] ?
         o[] << spaces "return RESULT;" ;
    CASE DEBUGGING_METHODS ? 
         CASE F.Result != NONE ?
              o[] << "#else"
              CASE F.Result.Type_.Kind == 'STRUCTURE'
              	   && is_simple(F.Result.Type_)
              	   ?
                   STR rt|ype_result_structure = F.Result.Type_.Final_name 
                   o[] << "      struct " rt " RESULT = " rt "();"
                   CASE msvstudio ? 
                   		o[] << "      memset(&RESULT, 0, sizeof(" rt "));"
                   ELSE 
	                    o[] << sp(6) "RESULT = {};" << sp(6) 
	                    	   "return RESULT;"
                   ;
              ELSE o[] << "     return " gen_none_val(F.Result.Type_) ";"
              ;
         ;
         o[] << "#endif //NO_SOURCE" ;
    o[] << "}" .
    
    
FUN ancestor_having_construct_class(
	{Type} C|lass_to_find_ancestor) ==> STR
	:
    -------------------------- 'CONSTRUCT is not defined always for a class'
    {Type} c|lass_iteration = C
    FOR i|dummy IN [1 TO 1000] :
        c = c.Base_
        CASE c == NONE ? ==> ;
        CASE c.Construct != NONE ? RESULT = c.Final_name ==> ;
    ; .
        
    
    
METHOD gen_unref_class_field_objects({Type} Class|_type) :
    FOR fld IN Class.Field[] :
        CASE fld.Is_array && fld.Type_.Kind == 'CLASS' ?
             //o[] << spaces "    THIS_OBJ->" fld.Final_name "->Unref();"
             o[] << spaces "    THIS_OBJ->" fld.Final_name "->Dispose();"
             o[] << spaces "    delete THIS_OBJ->" fld.Final_name ";"
             o[] << spaces "    THIS_OBJ->" fld.Final_name " = nullptr;"
             CONTINUE fld ;
        CASE fld.Is_array && ! fld.Is_fixed ?
             //o[] << spaces "    THIS_OBJ->" fld.Final_name "->Clear();"
             o[] << spaces "    delete THIS_OBJ->" fld.Final_name ";"
             o[] << spaces "    THIS_OBJ->" fld.Final_name " = nullptr;"
             CONTINUE fld ;
        CASE fld.Type_.Kind == 'CLASS' ?
             o[] << spaces "    AL4_object::Object_assign_"
             CASE fld.Is_weak ? o[*] << "weak"
             ELSE o[*] << "hard" ;
             
             o[*] << "(&THIS_OBJ->" fld.Final_name 
             ", " fld.Type_.Final_name "::NoneObj_" fld.Type_.Final_name ");"
        ;
    ; .
               
    
METHOD add_init_var( STR Init|ialization ) :
	FOR s IN o[last_init_var DOWNTO 0] :
	    CASE s.Trim == "{" ? BREAK s ;
	    CASE s == Init ? ==> ;
	;
    o[].Insert(last_init_var, Init)
    last_init_var += 1 .
    
FUN remove_star|_ending( STR S|ource_string ) ==> STR :
    RESULT = S
    CASE RESULT[*] == "*" ? RESULT = RESULT[0 TO *-1] ; .

FUN init_structure({Expr} V|ariable_expression) ==> STR :
    {Type} t|ype_of_expression = V.Type_expr
    RESULT << " = " t.Final_name "();" .



METHOD gen_dispose_var({Var} V|ariable_local) :
    CASE V.Is_array ?
         CASE V.Type_.Kind == 'CLASS' ?
              o[] << spaces "delete " V.Final_name ";"
         ELSE o[] << spaces "delete " V.Final_name ";" ;
    ELSE 
         CASE V.Type_.Kind == 'CLASS' && V.Final_name != "RESULT" ?
         o[] << spaces V.Final_name "->Ref_dec_hard();" ;
    ; .


INT level_expr|ession
BOOL is_left_side
BOOL close_br|acket_right_side
INT total_stmt|_output_index
INT line_current_statement|_will_be_placed

METHOD statement_gen|erate({Statement} St|atement) :
    -------------------------------------- 'single statement generation'
    close_br = FALSE
    -------------------------------------- ':stmt:'
    CASE total_stmt == 0 ? INT dummy_temp = 0 ;
    //o[] << spaces "// stmt: " total_stmt++.Str " line: " (St.Line+1).Str
    o[] << spaces "// stmt: " (St.Total_stmt).Str 
    	   " line: " (St.Line+1).Str

    CASE Comp.TEST_value && Comp.Generating_test && St.Line > 0 ?
         o[] << spaces "AL4_system::Test_caller = "
         CASE Comp.Current_class.Modifiers['ABSTRACT'] ?
              -------------- 'all tests of abstract class are secondary'
              o[*] << "AL4_system::Test_caller % 1000000L + " St.Line.Str
              " * 1000000L;"
              
         ELSE o[*] << St.Line.Str ";" ;
    ;
    CASE Comp.TEST_value && !Comp.Generating_test && St.Line > 0 && (
         St.Work != 'CASE')
         ?
         {Type} cc|lass_current = Comp.Current_class
         FOR i|dummy IN [tcl[].Count TO St.Line] : tcl[] << -1 ;
         CASE ! (Comp.Current_fun.Is_trivial || Comp.Current_fun.Is_test) && (
              ! cc.Modifiers['NATIVE'])
              ?
              tcl[St.Line] = 0 ;
              
         o[] << spaces cc.Final_name "::test_lines_" cc.Final_name 
             "[" St.Line.Str "] = AL4_system::Test_caller;"
    ;
    ------------------------- 'stmt generate'
    CASE St.Total_stmt == 0 ?
         NONE ;
    	   
    line_current_statement = o[].Count
    CASE St.Work ?
        ['ASSIGN']: 
                    //STR code_a|ssignment = generate_assign(St.{Assign})
                    //code_a << finish_assign_object(St.{Assign})
             		STR code_a|ssignment = generate_assign(St.{Assign})
        			code_a << finish_assign_object(St.{Assign}) 
             		append_splitted(o[], code_a)
        ['APPEND']: append_splitted(o[], generate_append(St.{Assign}))
        ['OUTPUT']: generate_output(St.{Assign})
        ['INPUT']:  generate_input(St.{Assign})
        ['BREAK']:  generate_break(St.{For})
        ['CONTINUE']: generate_cont(St.{For})
        ['RETURN']: generate_return(St.{Case})
        ['CASE', 'ELSE']: gen_case(St.{Case})
        //['FOR', 'FOREVER']: generate_for(St.{For})
        ['FOR']: generate_for(St.{For})
        ['PUSH']:   generate_push(St.{Assign})
        ['STOP']:   generate_stop(St.{Case})
        ['ASSERT']: generate_assert(St.{Case})
        ['DEBUG']: 
                    CASE !Comp.Final || DEBUGGING_METHODS ?
                         generate_block(St.Block_[]) ;
        ['COMMENT']: gen_comment_block(St.{Assign})
        ['CALL_NATIVE']: NONE ; .

FUNCTION append_splitted(
STR Dest|ination_array[],
STR S|tring_may_be_with_NLs)
	:
	CASE #NL !IN S ? Dest[] << S ==> ;
	STR spl|itted_lines[]
	S.Split_to(spl[], #NL)
	FOR s IN spl[] : Dest[] << s ; .


METHOD generate_assign({Assign} A|ssignment) ==> STR :
	//DEBUG:
	//      CASE A.Total_stmt == 40132 ? NONE ;
	//;
    ---------------------------------------------------- 'left side'
    close_br = FALSE
    CASE A.Dest != NONE && A.Dest.Var_arg != Comp.NONE_c ?
         {Type} type_d|estination = A.Dest.Type_expr
         ------------------------------ 'to an item of an objects array'
         CASE type_d.Kind == 'CLASS' && (
              A.Dest.Operation == 'INDEX')
              ?
              PUSH is_left_side = TRUE :
                   RESULT << spaces gen_expr(A.Dest.Arg1_) ;
              RESULT << "->set(" gen_expr(A.Dest.Arg2_)
              RESULT << ", " gen_obj_expr(A.Source, type_d) ");"
              CASE A.Source.Operation == 'FUN' && ! A.Dest.Is_weak ?
                   RESULT << #NL spaces << gen_expr(A.Dest) ".Ref_dec_hard();"
              ;
              CASE A.Source.Operation == 'FUN' && A.Dest.Is_weak ?
                   RESULT << #NL spaces << gen_expr(A.Dest)  ".Ref_dec_weak();"
              ;
              RESULT << finish_assign_object(A) ==> ;
         ------------------------------ 'to an item of an array'
         CASE type_d.Kind == 'STR' && A.Dest.Operation == 'INDEX' && (
              A.Dest.Arg1_.Operation == 'INDEX')
              ?
              -------------------- 'to a single symbol of an array item'
              PUSH is_left_side = TRUE :
                   RESULT << spaces gen_expr(A.Dest.Arg1_.Arg1_) ;
              RESULT << "->set(" gen_expr(A.Dest.Arg1_.Arg2_) ", "
              RESULT << "AL4_system::Replace_symbol(" gen_expr(A.Dest.Arg1_)
              RESULT << ", " gen_expr(A.Dest.Arg2_) 
              RESULT << ", " gen_expr(A.Source) "));"
              ==>
         ;
         CASE A.Dest.Operation == 'INDEX' && A.Dest.Arg1_.Is_array ?
         
              PUSH is_left_side = TRUE :
                   RESULT << spaces gen_expr(A.Dest.Arg1_) ;
                   
              STR r|ight_part = gen_obj_expr(A.Source, type_d)
              
              CASE type_d.Kind == 'STRUCTURE'  ?
                   STR r_orig|inal = r
                   r = "(byte*)&" r 
              ;

              CASE ?
              [A.Dest.Arg1_.Operation == 'FIELD' && (
               A.Dest.Arg1_.Var_arg.In_type_.Kind == 'STRUCTURE')
               && is_simple(A.Dest.Arg1_.Var_arg.In_type_)] ?
                   RESULT << "[" gen_expr(A.Dest.Arg2_) "] = " r ";"
                   
              [type_d.Kind == 'STRUCTURE' && is_simple(type_d)] ?
                   STR tn|ame_of_structure_type = type_d.Final_name
                   
                   RESULT = spaces "{" #NL spaces
                   	"  " tn " temp_right = " r_orig ";" #NL
                   	"" RESULT "->set("
                   	     
                   RESULT << gen_expr(A.Dest.Arg2_) 
                   	", (byte *)&temp_right);" #NL 
                   	
                   RESULT << spaces "}" ==>
                   	
              ELSE RESULT << "->set(" gen_expr(A.Dest.Arg2_) ", " r ");" ==>
              ;
         ;
         ------------------------------ 'to an single symbol of a string'
         CASE A.Dest.Operation == 'INDEX' && type_d.Kind == 'STR' ?
              PUSH is_left_side = TRUE :
                   RESULT << spaces gen_expr(A.Dest.Arg1_) ;
              RESULT << " = AL4_system::Replace_symbol(" gen_expr(A.Dest.Arg1_) 
              RESULT << ", " gen_expr(A.Dest.Arg2_) 
              RESULT << ", " gen_expr(A.Source) ");" ==>
         ;
         --------------------------------- 'to a scalar object variable'
         BOOL scalar_obj|ect_destination = ! A.Dest.Is_array
         	  scalar_obj &&= type_d.Kind == 'CLASS'  
         CASE scalar_obj ?
              RESULT << spaces "AL4_object::Object_assign_"
              CASE A.Dest.Is_weak ? RESULT << "weak"
              ELSE RESULT << "hard" ;
              CASE A.Source.Operation == 'FUN' ? RESULT << "_noincref" ;
              PUSH is_left_side = TRUE :
                   RESULT << "(&" gen_expr(A.Dest) ;
                   
              RESULT << ", " gen_obj_expr(A.Source, type_d)
              CASE !RESULT.Ending("->Obj") ? RESULT << "->Obj" ;
              RESULT << ");"
              
              RESULT << finish_assign_object(A) ==> ;
         ------------------------------ 'new structure to a scalar structure'
         	  scalar_obj = !A.Dest.Is_array
         	  scalar_obj &&= type_d.Kind == 'STRUCTURE'
         	  scalar_obj &&= is_simple(type_d)
         	  scalar_obj &&= A.Source.Operation == 'NEW_OBJ'    
         CASE scalar_obj ?
              CASE is_simple(type_d) && !msvstudio ? 
                   RESULT << spaces << gen_expr(A.Dest).Remove_starting("&") 
                   RESULT << " = {};"
              ELSE 
	               RESULT << spaces "memset(" 
	               RESULT << gen_expr(A.Dest) ", 0, sizeof("
	               RESULT << type_d.Final_name "));" ;
              PUSH new_init = A.Source :
              	   RESULT << finish_assign_object(A) ==> ;
         ;
         -------------------------- 'simple structure to a simple structure'
         CASE !A.Dest.Is_array && type_d.Kind == 'STRUCTURE' 
         	  && is_simple(type_d)
         	  ?
              CASE A.Source.Operation == 'CONST' 
              	   && A.Source.Var_arg.Constant_value == "NONE"
              	   ?
              	   CASE !msvstudio ? 
	                    RESULT << spaces << gen_expr(A.Dest).Remove_starting("&")
	                    		  " = {}; /*01*/" ==>
              	   ;
                   RESULT << spaces "memset("
                   RESULT << gen_expr(A.Dest) ", 0, sizeof("
                   RESULT << type_d.Final_name "));" ==>
              ;
              RESULT << spaces 
              RESULT << gen_expr(A.Dest).Remove_br.Remove_starting("&") " = "
              CASE ?
              [A.Source.Operation == 'INDEX'] ?
                   //RESULT << gen_expr(A.Source) "/*1*/"
                   RESULT << gen_expr(A.Source).Remove_starting("&") "/*1*/"
              [A.Dest.Operation IN ['VAR', 'FIELD']] ? 
                   //RESULT << "(void*)" gen_expr(A.Source) "/*2*/"
                   RESULT << gen_expr(A.Source).Remove_br.Remove_starting("&") 
                   RESULT << "/*2*/"
              ELSE //RESULT << "(void*)(" gen_expr(A.Source) ")/*3*/"
              	   RESULT << gen_expr(A.Source).Remove_starting("&") "/*3*/" 
              ;
              //RESULT << ", sizeof(" type_d.Final_name "));" 
              RESULT << ";" ==> ;
         ------------------------------ 'to an object which can be NONE'
         BOOL object_dest|ination_field = A.Dest.Operation == 'FIELD'
         	  object_dest &&= type_d.Kind == 'CLASS'
         	  object_dest &&= A.Dest.Arg1_.Type_expr.Kind == 'CLASS'
         	  object_dest &&= A.Dest.Arg1_.Type_expr.Has_destructors    
         CASE object_dest ?
              RESULT << spaces "if (!(" 
              RESULT << gen_expr(A.Dest.Arg1_) ")"
              CASE ! Ending(RESULT, "(Result)") ? RESULT << "->Obj" ;
              RESULT << "->Is_NONE_object)" ;
         PUSH is_left_side = TRUE :
              //vv_comment("is_left_side = TRUE, close_br = " close_br.Str)
              CASE A.Dest.Is_fixed && A.Source.Operation == 'INDEX' && (
                   A.Source.Arg3_ != NONE)
                   ?
                   ------ 'special assign A[x TO y] to temp fixed array'
                   vv_comment("special assign A[x TO y] to temp fixed array")
                   RESULT << #NL spaces "delete " gen_expr(A.Dest) ";"
                   
                   RESULT << #NL spaces gen_expr(A.Dest) " = "
                   "new " type_gen(type_d, {type_options}(
                   Array=TRUE, Fixed=TRUE, Weak=A.Dest.Is_weak)).Remove_ending(
                   "*") "(" gen_expr(A.Source.Arg1_)
                   ", " gen_expr(A.Source.Arg2_)
                   ", " gen_expr(A.Source.Arg3_) ");" ==>
              ;
              CASE A.Dest.Is_array ?
                   RESULT << spaces gen_expr(A.Dest) "->Clear();" ==> ;
              RESULT << spaces gen_expr(A.Dest) ;
         CASE type_d.Kind == 'STRUCTURE' 
         	  && A.Source.Var_arg == Comp.NONE_c
         	  && is_simple(type_d)
         	  ?
         	  CASE !msvstudio ? 
	               RESULT = #NL spaces 
	               RESULT << gen_expr(A.Dest) " = {}; /*02*/" ==>
         	  ELSE 
	               RESULT = #NL spaces "memset("
	               RESULT << gen_expr(A.Dest) ", 0, sizeof("
	               RESULT << type_gen(type_d, {type_options}(Array=FALSE)) "));"
	               ==> ;
         ;
         CASE !close_br && A.Source != NONE ? 
         	  RESULT << " = " ;
    ELSE RESULT << spaces ;
    ------------------------ 'assign right side'
    RESULT << "/*03*/"
    CASE A.Source != NONE ?
         PUSH A.Dest :
              CASE A.Dest.Var_arg == Comp.NONE_c
                   && A.Source.Operation == 'NEW_OBJ'
                   ?
                   dummy_var += 1 
        	       RESULT = spaces "Ref_obj" 
        	       RESULT << " dummy" dummy_var.Str " = " 
        	       
        	       A.Dest = {Expr}(Operation = 'VAR',
        	       	Var_arg = {Var}(Line = 0,
        	       	Type_ = A.Source.Type_expr))
        	       	
        	       A.Dest.Var_arg.Set_final_name("dummy" dummy_var.Str)
              ;
	          CASE ?
	          [A.Source.Var_arg == Comp.NONE_c] ?
	               RESULT << "/*NONE value*/" gen_none_val(type_d)
	          [type_d.Kind == 'STRUCTURE' && is_simple(type_d)] ?
	               RESULT << gen_expr(A.Source).Remove_br
	          ELSE r = gen_expr(A.Source).Remove_br
	               CASE type_d.Kind == 'BYTE' ?
	                    r = "(byte)(" r ")"
	               ;
	               RESULT << r
	          ;
	          CASE close_br ? RESULT << ")" ;
	          close_br = FALSE     
	          RESULT << ";" finish_assign_object(A) ==>
         ; 
    ;
    CASE A.Source == NONE ? RESULT << ";" ;
    close_br = FALSE .
    
INT dummy_var|iables_count    

    
METHOD gen_obj_expr(
{Expr} E|xpression, {Type} T|ype_of_object) ==> STR
	:
    ------------------------------------ 'NONE'
    CASE E.Var_arg == Comp.NONE_c ?
         RESULT = gen_none_val(T)
    ------------------------------------ 'not NONE'
    ELSE RESULT = gen_expr(E) ; 
    ------------------------------------ '{new object}(), OWNED BY'
    CASE E.Owned_ != NONE ?
         RESULT << "->Obj->Owned_by(" gen_expr(E.Owned_) ")" ; .
    
         
         
METHOD finish_assign_object({Assign} A|ssignment) ==> STR :
   ------------------------ 'assign of new obj, init its fields'
   CASE new_init != NONE ?
	    {Type} t|ype_object = new_init.Type_expr
	    RESULT << #NL gen_init_new_obj(A)
	    STR call|_construct = gen_call_construct(t, gen_expr(A.Dest))
	    CASE call != "" ? RESULT << #NL spaces call ;
   ;
   ------------------------ ', >> array[]'
   CASE A.Source.Array_ != NONE ?
        RESULT << #NL spaces 
        RESULT << gen_expr(A.Source.Array_) 
        RESULT << "->Add(" gen_expr(A.Dest) ");"
        A.Source.Array_ = NONE // ok, clear it -- it should not be used more
   ; .

         
         
         
METHOD vv_comment( STR Comm|ent_to_add ) :
    CASE !Comp.Verbose2 ? ==> ;
    o[] << spaces "//--------------------- '" Comm "'" << spaces .
         
         
//FUN remove_ending(
//	STR S|ource_string, STR W|hat_remove ) ==> STR
//	:
//    RESULT = S
//    CASE S.Ending(W) ? RESULT = S[0 TO *-W.Len] ; .
         
BOOL use_arrow|_while_assigning_record         
         
METHOD gen_assign_structure(
	{Type} T|ype_record, STR L|eft_part, 
    STR R|ight_part) ==> STR, RECURSIVE
    :
    CASE is_simple(T) ?
 		 STR tn|ame_of_record_type = T.Final_name
 		      
         RESULT << spaces "{" #NL spaces
         		"" tn " temp_right = " R ";" #NL spaces
         		"memmove(&" L ", &temp_right, sizeof(" tn "));" #NL spaces
         		"}" ==>
    ;
    ---------------------------------- 'assign record (field by field)'
    CASE use_arrow ? STR unname|_symbol = "->"
    ELSE unname = "." ;
    FOR f IN T.Field[] :
        CASE f.Is_array ?
             RESULT << #NL spaces "(*" L "." f.Final_name ")" 
             ".assign_array(*" R "." f.Final_name ");"
             CONTINUE f ;
        CASE f.Type_.Kind ?
        ['STRUCTURE']: 
                    CASE !is_simple(f.Type_) ?
                         RESULT << gen_assign_structure(f.Type_,
                         L "." f.Final_name,
                         R unname f.Final_name)
                         
                    ELSE RESULT << #NL spaces L "." f.Final_name 
                         " = " R unname f.Final_name ";"
                    ;
        ['BOOL', 'BYTE', 'INT', 'REAL', 'ENUM', 'STR']:
                 RESULT << #NL spaces L "." f.Final_name 
                 " = " R unname f.Final_name ";"
        ['CLASS']: NONE ;
    ; .



FUN gen_call_construct({Type} C|lass_constructing_obj,
    STR Th|is_obj) ==> STR
    :
    ------------- 'call constructor from the nearest ancestor having it'
    {Type} cf|un_class = C
    FOR i|dummy IN [0 TO MAX_INT-1] :
        CASE cf == NONE ? BREAK i ;
        CASE cf.Construct != NONE ?
            RESULT = "((" cf.Final_name "*)(" Th
            CASE Th != "this" ? RESULT << "->Obj" ;
            RESULT << "))->Do()->" cf.Construct.Final_name "();" ==> ;
        cf = cf.Base_
    ; .


METHOD gen_init_new_obj({Assign} A|ssignment) ==> STR :
    {Expr} init_expr = new_init
    new_init = NONE
    CASE init_expr.Assignments_[].Count > 0 ?
         RESULT << #NL "// initializations: " init_expr.Assignments_[].Count.Str
         " of stmt in line#" (A.Line+1).Str
    ;
    FOR a IN init_expr.Assignments_[] :
        {Assign} aa|ssign_a = a.{Assign}
        CASE aa.Dest.Operation ?
            ['FIELD']:
                PUSH aa.Dest.Arg1_ = A.Dest :
                     RESULT << #NL generate_assign_or_append(aa) ;
            ['INDEX']:
                CASE aa.Dest.Arg1_.Operation == 'FIELD' ?
                     PUSH aa.Dest.Arg1_.Arg1_ = A.Dest :
                          RESULT << #NL generate_assign_or_append(aa) ;
                          
                ELSE Comp.Error("Init indexed"
                     " " aa.Dest.Arg1_.Operation.Name "?")
                ;
            ['VAR']:
                PUSH init_expr = NONE :
                     RESULT << #NL generate_assign_or_append(aa) ;
                     
            ['BINARY', 'FUN', 'BASE_FUN', 'SYSTEM_FUN',
             'NEW_OBJ', 'ARRAY', 'AS', 'CONSTANT', 'UNKNOWN',
             'INT2REAL', 'NOT_B', 'NOT', 'NEG']:
                Comp.Error("Unknown init of " aa.Dest.Operation.Name) ;
    ; .


METHOD generate_assign_or_append(
{Assign} A|ssign_or_append) ==> STR
	:
    CASE A.Work ?
        ['ASSIGN']: RESULT << generate_assign(A)
        ['APPEND']: RESULT << generate_append(A)
        
        ['OUTPUT', 'INPUT', 'BREAK', 'CONTINUE', 'RETURN', 'CASE',
          'ELSE', 'FOR', 'PUSH', 'STOP', 'ASSERT', //'FOREVER', 
          'COMMENT', 'DEBUG', 'CALL_NATIVE']:
           Comp.Error("Invalid  init field operation") ; .


METHOD generate_append({Assign} A|ppend_stmt) ==> STR :
    PUSH is_left_side = TRUE : 
         RESULT << spaces gen_expr(A.Dest) ;
    CASE A.Dest.Is_array ?
           STR app|ending = "->Add"
           CASE A.Source.Var_arg == Comp.NONE_c ?
                STR a|ppending_value_str = gen_none_val(A.Dest.Type_expr)
           ELSE a = gen_expr(A.Source).Remove_br ;
           {Type} type_d|estination = A.Dest.Type_expr
           CASE ?
           [type_d.Kind == 'STRUCTURE' && is_simple(type_d)] ?
                CASE ?
                [A.Source.Fun_ == Comp.SYSFUN_Clone] ?
                     a = "(" type_d.Final_name 
                     	 "*)AL4_system::Clone_structure(" a 
                     	 ", sizeof(" type_d.Final_name "))"
                     	 
                [A.Source.Fun_ == Comp.SYSFUN_Dismiss] ?
                     a = "(" type_d.Final_name 
                     	 "*)AL4_system::Dismiss_structure(" a ")"
                ;
                
                STR temp_v|ar_to_append = spaces "{"#NL spaces sp(4)
                	"" type_d.Final_name "* tmp_rec = " a ";" #NL sp(4)
                	
                RESULT = temp_v RESULT app "((byte*)tmp_rec);"
                "" #NL spaces "}" ==> 
           [type_d.Kind IN ['CLASS', 'STRUCTURE'] && a.Ending("->Obj")] ?
                a = a.Remove_ending("->Obj")
           ;
           CASE type_d.Kind == 'BYTE' ? a = "(byte)(" a ")" ;
           app << "(" a ");"
           RESULT << app ==> ;
    CASE close_br ?
         app = "AL4_system::Concat2Strings(" gen_expr(A.Dest) 
         app << ", (" final_str ")" 
         app << gen_expr(A.Source) "));"
    ELSE app = " += " gen_expr(A.Source).Remove_br ";" ;
    RESULT << app .


METHOD generate_output({Assign} A|_output) :
    STR param|eter_out = gen_expr(A.Source).Remove_br 
    o[] << spaces "AL4_system::Write(" param ");" .

INT total_in|put_index
        
METHOD generate_input({Assign} A|_input_stmt) :
    total_in += 1
    CASE A.Dest == NONE ? 
         o[] << spaces "{ std::string s = AL4_system::ReadLine(); }" ==> ;
    CASE A.Dest.Type_expr.Kind == 'STR' ?
         STR d|estination = gen_expr(A.Dest)  
         o[] << spaces d " = AL4_system::ReadLine();" ==> ;
    STR temp|_name = "tmp" A.Line.Str
    o[] << spaces "std::" "string " temp ";"
    o[] << spaces temp " = AL4_system::ReadLine();"
    PUSH is_left_side = TRUE : o[] << spaces gen_expr(A.Dest) ;
    o[*] << " = Safe_convert(" temp ");" .


METHOD generate_break({For} Br|eak_stmt) :
         INT i|ndex_of_Br_in_nesting = nesting_block[].Find(Br)
         CASE i > 0 && i < nesting_block[].Count-1 ?
              gen_pop_until_stmt(nesting_block[i+1]) ;
         o[] << spaces "goto Brk_" Br.Loop_.Total_stmt.Str ";" .


METHOD generate_cont({For} Cont|inue_stmt) :
         INT i|ndex_of_Cont_in_nesting = nesting_block[].Find(Cont)
         CASE i > 0 && i < nesting_block[].Count-1 ?
              gen_pop_until_stmt(nesting_block[i+1]) ;
         o[] << spaces "goto Cont_" Cont.Loop_.Total_stmt.Str ";" .
         
         
METHOD gen_pop_until_stmt({Statement} St|atement) :
    FOR i IN [nesting_block[].Count-1 DOWNTO 0] :
        {Statement} b|lock_statement = nesting_block[i]
        CASE b == St ? BREAK i ;
        CASE b.{Assign}.Back_ != NONE ?
             {Assign} back|_assignment_pop = b.{Assign}.Back_.{Assign}
             STR a|ssignment_generated = generate_assign(back) 
             o[] << a ;
    ; .


METHOD generate_return({Case} Ret|urn_dummy) :
    FOR b IN nesting_block[] :
        CASE b.{Assign}.Back_ != NONE ?
             {Assign} back|_assignment_pop = b.{Assign}.Back_.{Assign}
             STR a|ssignment_generated = generate_assign(back) 
             o[] << a ;
    ;
    o[] << spaces "goto exiting;"
    exiting_label_used = TRUE .


METHOD gen_case({Case} Sw|itch_stmt) :
    ------------------------------------- ''
    nesting_block[] << Sw
    ------------------------------------- 'sequential ?'
    CASE Sw.Condition == NONE ?
         STR text_cond|ition = gen_expr(Sw.Block_[0].{Case}.Condition).Remove_br 
         o[] << spaces "if (" text_cond ") {"
         generate_block(Sw.Block_[0].{Case}.Block_[])
         FOR i IN [1 TO Sw.Block_[].Count-1] :
             CASE Sw.Block_[i].Work == 'ELSE' ?
                  o[] << spaces "} else {"
                  
             ELSE o[] << spaces "} else if ("
             	  {Expr} cond|ition_to_generate = Sw.Block_[i].{Case}.Condition 
             	  text_cond = gen_expr(cond).Remove_br
             	  o[] << text_cond ") {"
             ;
             generate_block(Sw.Block_[i].{Case}.Block_[]) ;
         o[] << spaces "}" 
         nesting_block[].Remove(Sw) ==> ;
    ------------------------------------- 'by type of expression'
    CASE Sw.Condition.Type_expr.Kind ?
        ['BOOL']:
            STR s_cond|ition = gen_expr(Sw.Condition).Remove_br 
            o[] << spaces "if (" s_cond ") {"
            CASE Sw.Block_[0].Work != 'ELSE' ?
                 generate_block(Sw.Block_[0].Block_[]) ;
            CASE Sw.Block_[*].Work == 'ELSE' ?
                 o[] << spaces "} else {"
                 generate_block(Sw.Block_[*].Block_[]) ;
        ['STR']:
            STR t|emp_index = Sw.Line.Str
            add_init_var("int tmp" t ";")
            o[] << spaces "tmp" t " = -1;"
            add_init_var("std::string str" t " = " #QU #QU ";")
            s_cond = gen_expr(Sw.Condition)
            o[] << spaces "str" t " = " s_cond ";"
            ------------------- 'small switch by the 1st character of string'
            gen_calc_str_index(Sw, t)
            o[] << spaces "switch (tmp" t ") {"
            FOR case IN Sw.Block_[] :
                CASE case.Work != 'ELSE' ?
                     o[] << spaces sp(4) "case " case.Index.Str ":"
                ELSE o[] << spaces sp(4) "default:" ;
                PUSH spaces = spaces sp(8) :
                    generate_block(case.Block_[])
                    CASE !case.Block_[*].Is_jump ?
                         o[] << spaces "break;" ;
                ;
            ;
        ['BYTE', 'ENUM', 'INT']:
            s_cond = gen_expr(Sw.Condition) 
            o[] << spaces "switch (" s_cond ") {"
            gen_switch_int_enum_cases(Sw)
        ['REAL', 'CLASS', 'STRUCTURE']: NONE ;
    o[] << spaces "}" 
    nesting_block[].Remove(Sw) .



INT total_case|_count

METHOD gen_calc_str_index(
{Case} Sw|itch_by_str, STR T|emp_index)
	:
	add_init_var("int int" T ";")
	o[] << spaces "int" T " = 0;"
	o[] << spaces "if (str" T " != "#QU#QU")"
	o[] << spaces "    int" T " = AL4_system::utf8char(&str" T "[0]);"
	o[] << spaces "switch (int" T ") {"
    STR all_s|trings[] 
    INT all_i|ndexes[]
    FOR case IN Sw.Block_[] :
        FOR val IN case.{Case}.Values[] :
            all_s[] << val.Str_c
            all_i[] << case.Index ;
    ;
    FOR s IN all_s[] :
        CASE all_i[s.Index] < 0 ? CONTINUE s ;
        o[] << spaces "case " s.Ord.Str ": " "// case " total_case.Str
        total_case += 1
        CASE s[0].Ord != 0 ?
             o[*] << " (" s.Trim ")" ;
             
        o[] << spaces sp(4) 
        CASE s != #0 && s != "" || all_s[].Count > 1 ?
             STR asconst|_compared_with = as_str(s)
             CASE asconst == #QU "\x00" #QU ?
                  asconst = "AL4_system::nullchar()" ;
        	 o[*] << "if (str" T " == " asconst ") " ;
        o[*] << "tmp" T " = " all_i[s.Index].Str ";"
            
        FOR i IN [s.Index+1 TO all_s[].Count-1] :
            CASE s[0] != all_s[i][0] ? CONTINUE i ;
            
            asconst = as_str(all_s[i]) 
	        CASE asconst == #QU "\x00" #QU ?
	             asconst = "AL4_system::nullchar()" ;
            
            o[] << spaces sp(4) "else if (str" T " == " asconst
            o[*] << ") tmp" T " = " all_i[i].Str ";"
                   
            all_i[i] = -1 ;
        o[] << spaces sp(4) "break;" ;
    o[] << spaces "}" .


METHOD gen_switch_int_enum_cases({Case} Sw|itch_stmt) :
    FOR case IN Sw.Block_[] :
        {Case} c|ase_of_switch = case.{Case}
        CASE c.Work == 'CASE' && c.Values[].Count > 0 ?
             FOR v IN case.{Case}.Values[] :
                 o[] << spaces sp(4) "case " v.Int_c.Str ":" ;
        ;
        CASE c.Work == 'CASE' && c.Values[].Count == 0 ?
             FOR r IN [c.Range1.Var_arg.Int_c TO (
                       c.Range2.Var_arg.Int_c)] :
                 o[] << spaces sp(4) "case " r.Str ":" ;
        ;
        CASE case.Work == 'ELSE' ?
             o[] << spaces sp(4) "default:" ;
        PUSH spaces = spaces sp(8) :
             //o[] << spaces "{"
             generate_block(case.Block_[])
             //o[] << spaces "}"
             CASE case.Block_[].Count == 0 || !case.Block_[*].Is_jump ?
                  o[] << spaces "break;" ;
        ;
    ; .

METHOD as_str|ing(STR S|tr_where_from) ==> STR :
	RESULT = string_const(S)
    CASE "+" IN RESULT ? RESULT = "(" RESULT ")" ; .
    
METHOD string_const|ant_replacing_forbidden_characters(
	STR S|tring_containing_not_only_allowedcharacters) ==> STR
	:
    STR start_str = #QU
    STR end_str|ing = #QU
    -------------------------------------- 'start from quotation'
    RESULT = start_str
    //RESULT << string_const_encoded(S)
    BYTE data|_from_string[]
    Bytes_from_utf8(data[], S)
    RESULT << string_encoded_utf8(data[])
    RESULT << end_str .

METHOD string_encoded_utf8(BYTE S_bytes|_utf8[]) ==> STR :
	BOOL after_hex
    FOR i IN [0 TO S_bytes[].Count-1] :
        BYTE x|_byte_from_S = S_bytes[i]
        CASE x & 0x80 != 0 ?
             RESULT << "\x" x.Hex(2)
             after_hex = TRUE
             CONTINUE i ;
        CASE ?
        [x.Char == #CR] ? RESULT << "\r"
        				after_hex = FALSE
        [x.Char == #LF] ? RESULT << "\n"
        				after_hex = FALSE
        [x.Char == #TAB]? RESULT << "\t"
        				after_hex = FALSE
        [x < " ".Ord || x.Char == #QU
         || after_hex && x.Char IN "0123456789ABCDEFabcdefABCDEF"] ?
             RESULT << "\x" x.Hex(2)
             after_hex = TRUE
        ELSE 
             RESULT << x.Char 
             CASE x.Char == "\" ? RESULT << "\" ;
             after_hex = FALSE ;
    ; 
    CASE RESULT[0] == #QU && "$MSVSTUDIO" !IN Comp.Defined_name[] ?
     	 RESULT = "utf8" RESULT ; .


{For} nesting_for|_statements[]
{Statement} nesting_block|_statements[]
INT total_for|_counter

METHOD generate_for({For} F|or_loop) :
    nesting_for[] << F
    nesting_block[] << F
    //CASE F.Work == 'FOREVER' ?
    CASE F.Infinite ?
            BOOL inf|initive = TRUE
            o[] << spaces "while (true) {"
    ELSE STR v|ar_loop = F.Var.Final_name
    	 total_for += 1
         STR t|mp_indx = "_" F.Total_stmt.Str "_" total_for.Str
         STR i|ndex_var = "idx" t "_" total_for.Str
         F.Index_var = i

         CASE F.Range1 != NONE ?
              add_init_var("int from" t ", to" t ";")
              ----------------------------------------- 'from'
              STR assign_from = "from" t " = "
              CASE ?
              [F.Array != NONE && F.Downto] ?
                   STR param1|_str = gen_expr(F.Range1).Remove_br
                   STR param2|_str = gen_expr(F.Array) "->Count()-1" 
                   assign_from << min_max("imin", param1, param2) ";"
                           		  
              [F.Array != NONE] ?
                   assign_from << min_max("imax",
                           		  gen_expr(F.Range1).Remove_br, "0") ";"
                           		  
              ELSE assign_from << gen_expr(F.Range1).Remove_br ";" ;
              o[] << spaces assign_from
              ----------------------------------------- 'to'
              STR assign_to = "to" t " = "
              
              CASE ?
              [F.Array != NONE && F.Downto] ?
                   assign_to << min_max("imax",
                   		   gen_expr(F.Range2).Remove_br, "0")
                   		   "; to" t "--;"
                   		   
                   o[] << spaces assign_to
                   
                   o[] << spaces "for (int " i " = from" t "; " i 
                   " > to" t "; " i "--) {" "/" "*<<1>>*" "/"
                   
              [F.Downto] ?
                   assign_to << gen_expr(F.Range2).Remove_br 
                   		  "; to" t "--;"
                   		  
                   o[] << spaces assign_to
                   
                   o[] << spaces "for (" v " = from" t "; " v 
                   		  " > to" t "; " v "--) {" "/" "*<<2>>*" "/"
                   		  
              [F.Array != NONE] ?
                   assign_to << min_max("imax",
                   		   gen_expr(F.Range2).Remove_br, "0")
                   		   "; to" t "++;"
                   		   
                   o[] << spaces assign_to
                   
              	   o[] << spaces "for (int " i " = from" t "; " i 
                   " < to" t "; " i "++) {" "/" "*<<3>>*" "/"
              ELSE 
                   assign_to << gen_expr(F.Range2).Remove_br 
                   		  "; to" t "++;"
                   o[] << spaces assign_to
                   
              	   o[] << spaces "for (" v " = from" t 
              	   		  "; " v " < to" t "; " v "++) {" "/" "*<<4>>*" "/"
              ;
                      
         ELSE 
              add_init_var("int count" t ";")
              STR text_arr|ay_reference = gen_expr(F.Array) 
              o[] << spaces "count" t " = " text_arr "->Count();"
              o[] << spaces "for (int " i " = 0; " i " < count" t "; " i "++) {"
         ;
         CASE F.Array != NONE ?
              {Type} a_type|_array = F.Array.Type_expr 
              CASE ?
              [a_type.Kind == 'STRUCTURE' && is_simple(a_type)] ?
                   {Type} rt|ype_record = F.Array.Type_expr
                   PUSH use_arrow = TRUE :
                       o[] << spaces gen_assign_structure(F.Array.Type_expr, 
                       v, "*((" rt.Final_name "*)" gen_expr(F.Array)
                       "->get(" i "))") "/" "*<<6>>*" "/"
                   ;
              [a_type.Kind IN ['CLASS', 'STRUCTURE']] ?
                   o[] << spaces "AL4_object::Object_assign_hard(&" v
                   STR item|_array = gen_expr(F.Array) 
                   o[*] << ", " item "->get(" i ")->Obj);" 
                   
              ELSE item = gen_expr(F.Array) 
              	   o[] << spaces v " = " item "->get(" i ");"
              ;
         ;
    ;
    ------------------------------------ 'do not stop response'
    o[] << spaces sp(4) "if (--AL4_system::global_activity_counter < 0)"
    o[] << spaces sp(8) "AL4_system::check_long_operation();"
    ------------------------------------ 'generate code of FOR block'
    generate_block(F.Block_[])
    CASE !inf && F.Continued ?
         o[] << spaces sp(4) "Cont_" F.Total_stmt.Str ": ;" ;
    o[] << spaces "}"
    CASE !inf && F.Breaked ?
         o[] << spaces "Brk_" F.Total_stmt.Str ": ;" ;
    nesting_for[].Remove(F)
    nesting_block[].Remove(F) .
    
FUNCTION min_max|_may_be_not_call(
STR F|un_min_max, STR A|_operand1, STR B|_operand2) ==> STR
	:
	CASE A == B ? RESULT = A ==> ;
	RESULT = "AL4_system::" F "(" A ", " B ")" .
    

METHOD generate_push({Assign} A|_push_stmt) :
	STR tmp|_save_var = "save" A.Line.Str
    CASE A.Dest.Operation == 'FUN' && A.Dest.Fun_.Pop_method_ != NONE ?
         ------------------------------------- 'call method'
         {Fun} pop|_method = A.Dest.Fun_.Pop_method_
         STR text_call|_function = gen_fun_call(A.Dest) 
         o[] << spaces text_call ";"
    ELSE
         -------------------------------------- 'save variable'
        STR decl|aration_to_place_at_start = type_gen(A.Dest.Type_expr,
        	{type_options}(
            	Array=FALSE, Fixed=FALSE, Weak=A.Dest.Is_weak))
            	
        decl << " " tmp " = " gen_none_val(A.Dest.Type_expr) ";" 
        place_to_start(decl)
            
        {Type} dtype|_destination = A.Dest.Type_expr
        
        sav|e_statement_temp = {Assign}(Line = 0, Level = 0,
            Function_ = Comp.Current_fun,
            Dest = {Expr}(Operation = 'VAR', 
               Var_arg = {Var}(Line = 0, Type_ = dtype)), 
            Source = A.Dest)
            
        sav.Dest.Var_arg.Set_final_name(tmp)
        STR ba|ssign_back_generated = generate_assign(sav) 
        o[] << ba
    ;
    ------------------------------------------ 'PUSH block in try-finally'
    PUSH spaces = spaces sp(4) :
         CASE A.Source != NONE ? o[] << generate_assign(A) ;
         
         b|ack_assign_temp = {Assign}(Dest = A.Dest, Line = 0, Level = 0,
                Function_ = A.Function_,
                Source = {Expr}(Operation = 'VAR', 
                  Var_arg = {Var}(Line = 0, Type_ = A.Dest.Type_expr)) )
                  
         b.Source.Var_arg.Set_final_name(tmp)
         A.Back_ = b
         nesting_block[] << A
         generate_block(A.Block_[]) 
         nesting_block[].Remove(A) ;
    CASE pop != NONE ?
         ------------------------------------- 'pop method'
         {Expr} call|_pop_method_TEMP = {Expr}(Operation = 'FUN', Fun_ = pop,
                This_ = A.Dest.This_)
                
         CASE pop !IN Comp.Current_fun.Call_functions_[] ?
                      Comp.Current_fun.Call_functions_[] << pop ;
         STR text_fun|ction_call = gen_fun_call(call) 
         o[] << spaces sp(4) text_fun ";"
    ELSE
         ------------------------------------- 'restore variable'
         STR text_b|ack_assignment = generate_assign(b) 
         o[] << text_b
    ; .
    
METHOD place_to_start(
STR Decl|aration_initialization_assignment )
	:
    FOR i IN [o[].Count-1 DOWNTO 0] :
        CASE o[i] == Decl ? ==> ;
        CASE o[i] == "{" ?
             o[].Insert(i+1, Decl) ==> ;
    ; .


METHOD generate_stop({Case} Stop|_message) :
	STR text|_stop = gen_expr(Stop.Condition) 
    o[] << spaces "AL4_system::STOP(" text ");" .


METHOD generate_assert({Case} A|ssert_stmt) :
	STR cond|ition = gen_expr(A.Condition).Remove_br
	CASE cond[0] == "!" ? cond = cond[1 TO *]
	ELSE cond = "!(" cond ")" ;
    o[] << spaces "if (" cond ")"
    CASE (A.Formatted != NONE) ?
         STR f|ormatted = gen_expr(A.Formatted)
    ELSE 
         f = #QU#QU 
    ;
    o[] << spaces "   AL4_system::Assertion_failed(" A.Line.Str
           ", test_assert_" Comp.Current_class.Final_name 
           ", test_assert_failed_text_" Comp.Current_class.Final_name
           ", " f ");" .


METHOD gen_comment_block({Assign} A|_comment_block) :
    o[] << spaces "//----------------------- " A.Source.Var_arg.Str_c .


METHOD generate_block|_of_statements({Statement} Block|_of_stmt[]) :
    PUSH spaces = spaces sp(4) :
        FOR s IN Block[] : statement_gen(s) ;
    ; .

    
BOOL generating_localized_strings    

METHOD gen_expr|ession({Expr} E|xpression) ==> STR, RECURSIVE :
    ----------------------------------- 'generate Before_assign_[] ?'
    CASE E.Before_assign_[].Count > 0 ?
         STR save_lines|_already_added[]
         FOR i IN [line_current_statement TO o[].Count-1] :
             save_lines[] << o[i] ;
         FOR i IN [o[].Count-1 DOWNTO line_current_statement] :
             o[].Delete(i) ;
         {Assign} a|ssignments[]
         FOR x IN E.Before_assign_[] : a[] << x.{Assign} ;
         E.Before_assign_[].Clear
         FOR y IN a[] : 
             o[] << spaces "// assign before expression: " total_stmt.Str
             total_stmt += 1
             STR text_y|_generated = generate_assign(y) 
             o[] << text_y ;
         ------------------------------------- 'restore o[]'
         line_current_statement = o[].Count
         FOR s IN save_lines[] : o[] << s ;
         FOR y IN a[] : E.Before_assign_[] << y ;
    ;
    --------------------------------------- 'localized string constant?'
    CASE E.Localize_n != "" && !generating_localized_strings ?
         RESULT = "AL4_system::get_Localize_str("
         "" E.Localize_i.Str 
         " + " Comp.Current_class.Final_name
         "_First_localize_item)" ==> ;
    --------------------------------------- 'generate expression'
    PUSH level_expr = level_expr + 1 :
        CASE E.Operation ?
            ['BINARY']: RESULT << gen_binary(E)
            ['FUN', 'BASE_FUN', 'SYSTEM_FUN']:
         		CASE E.Fun_.Result.Type_.Kind == 'STRUCTURE'
         			 && is_simple(E.Fun_.Result.Type_)
         			 ?
         		     RESULT << "&" ;
         		RESULT << gen_fun_call(E)
            ['VAR']:    RESULT << gen_variable(E)
                        CASE RESULT == "this" ?
                             RESULT = "THIS_OBJ->hard_link" ;
            ['INDEX']:  RESULT << gen_index(E)
            ['FIELD']:  RESULT << gen_field(E)
            ['NEW_OBJ']: RESULT << gen_new_obj(E)
            ['ARRAY']:  RESULT << gen_array(E)
            ['AS']:     RESULT << gen_as_obj(E)
            ['CONST']:  RESULT << gen_const(E)
            ['INT2REAL']: RESULT = gen_expr(E.Arg1_)
            ['NOT_B']: 	RESULT = "~" gen_expr(E.Arg1_)
            ['NOT']: 	RESULT = "!" gen_expr(E.Arg1_)
            ['NEG']: 	RESULT = "-" gen_expr(E.Arg1_)
            ['UNKNOWN']:Comp.Error("Generating unknown operation"._Eunk ) ;
        CASE RESULT == "" ?
             {Parser} p|arser_of_cur_class = Comp.Current_class.Parse
             PUSH p.Line = E.At_line :
                  PUSH p.Pos = E.At_pos :
                       Comp.Error("Error generating expression"._Eerr ": "
                       "" p.Next20) ;
             ;
        ;
    ; .



METHOD gen_binary({Expr} E|xpression) ==> STR :
    --------------------------------- 'special case: long concatenation'
	CASE E.Sign == 'CONCAT' && E.Items_[].Count > 0 ?
		 RESULT = "("
		 FOR i IN E.Items_[] : RESULT << "(std::string)(" gen_expr(i) ") + " ;
		 RESULT = RESULT[0 TO *-3] ")" ==> ;
	--------------------------------- 'other operations'
	CASE E.Sign ?
         ['CONCAT']: RESULT = "AL4_system::Concat2Strings((" kstr ")" 
         			 RESULT << gen_expr(E.Arg1_).Remove_br
                     RESULT << ", (" kstr ")" 
                     RESULT << gen_expr(E.Arg2_).Remove_br ")"
                     ==>
         ['PLUS']: STR s|ign_operation = "+"
         ['MINUS']:  s = "-"
         ['MULT']:   s = "*"
         ['DIV']:    RESULT = "AL4_system::Safe_div"
         			 BOOL i2i|integers_division = E.Arg1_.Type_expr.Kind == 'INT'
         			 	  i2i &&= E.Arg2_.Type_expr.Kind == 'INT'
                     CASE i2i ? RESULT << "_int" ;
                     RESULT << "(" gen_expr(E.Arg1_)
                     RESULT << ", " gen_expr(E.Arg2_) ")" ==>
                     
         ['REST']:   RESULT = "AL4_system::Safe_rest(" gen_expr(E.Arg1_)
                     RESULT << ", " gen_expr(E.Arg2_) ")" ==>
                     
         ['AND_B']:  s = "&"
         ['OR_B']:   s = "|"
         ['XOR_B']:  s = "^"
         ['AND']:    s = "&&"
         ['OR']:     s = "||"
         ['IN', 'NOT_IN']:
                     CASE E.Sign == 'NOT_IN' ? RESULT = "!" ;
                     CASE !E.Arg2_.Is_array ?
                          RESULT << "AL4_system::StrContains(" gen_expr(E.Arg2_)
                          RESULT << ", " gen_expr(E.Arg1_) ")" ==>
                     ;
                     {Type} t2|_Arg2_type_expr = E.Arg2_.Type_expr
                     CASE ?
                     [E.Arg2_.Operation == 'ARRAY' && t2.Kind == 'STR'
                      && E.Arg1_.Operation IN ['VAR', 'FIELD']
                      && all_are_1char_str_const(E.Arg2_.Items_[])] ?
                          RESULT << "(" gen_expr(E.Arg1_) ".length() == 1 && "
                          RESULT << "AL4_system::ArrayContainsChar("
                          RESULT << gen_const_array(E.Arg2_)
                          RESULT << ", AL4_system::utf8char(" 
                          RESULT << gen_expr(E.Arg1_) ", 0)))" ==>
                          
                     [E.Arg2_.Operation == 'ARRAY'] ?
                          RESULT << "AL4_system::ArrayContains"
                          RESULT << kind_to_name(t2.Kind) "("
                          RESULT << gen_const_array(E.Arg2_) 
                          RESULT << ", " gen_expr(E.Arg1_) ")" ==>
                     ;
                          
                     RESULT << gen_expr(E.Arg2_)
                     STR what|_contains = gen_expr(E.Arg1_)
                     CASE E.Arg1_.Type_expr.Kind IN ['CLASS', 'STRUCTURE'] ?
                          CASE ?
                          [what.Ending("->Obj")] ?
                               what = what.Remove_ending("->Obj")
                          [what.Ending("->Obj)")] ?
                               what << "->hard_link" ;
                     ;
                     RESULT << "->Contains(" what ")" ==>
                     
         ['LIKE', 'UNLIKE']:
                     CASE E.Sign == 'UNLIKE' ? RESULT = "!" ;
                     RESULT << "AL4_system::like_str(" gen_expr(E.Arg1_) 
                     RESULT << ", " gen_expr(E.Arg2_) ")" ==>     
                     
         ['EQUAL']:  RESULT = gen_compare(E, "==") ==>
         ['NOT_EQ']: RESULT = gen_compare(E, "!=") ==> 
         ['LESS']:   RESULT = gen_compare(E, "<") ==>
         ['LESS_OR_EQ']: RESULT = gen_compare(E, "<=") ==>
         ['GREATER']:RESULT = gen_compare(E, ">") ==>
         ['GREATER_OR_EQ']:  RESULT = gen_compare(E, ">=") ==> ;
    STR x|operand = gen_expr(E.Arg1_)
    STR y|operand = gen_expr(E.Arg2_)
    CASE x == "" || y == "" ? RESULT = "" ==> ;
    RESULT = "(" x " " s " " y ")" .
    
FUN all_are_1char_str_const(
{Expr} A|rray_of_consants[]) ==> BOOL
	:
	FOR a IN A[] :
	    CASE a.Type_expr.Kind != 'STR' 
	    	 || a.Operation != 'CONST'
	    	 || a.Var_arg.Str_c.Len != 1 
	    	 ?
	         ==> ;
	;
	RESULT = TRUE .

FUN kind_to_name|byte_int_str(
{Type}.{kind_type} K|ind_of_type_int_byte_str ) ==> STR
    :
    ----------------------------- 'Suffix for name of function ArrayContainsXXX'
    CASE K.Name ?
    ["'BYTE'", "'ENUM'"]: RESULT = "Byte"
    ["'INT'"]: RESULT = "Int"
    ["'STR'"]: RESULT = "Str" ; .


METHOD gen_compare(
{Expr} E|xpression, STR S|ign_compare) ==> STR
	:
    CASE E.Arg1_.Type_expr.Kind ?
    ['BOOL', 'BYTE', 'INT', 'REAL', 'ENUM']: NONE
    ['STR']:
		CASE ?
		[S IN ["==", "!="] && E.Arg2_.Operation == 'CONST' && 
		 "" == E.Arg2_.Var_arg.Str_c] ?
		     RESULT = "((" final_str ")" 
		     RESULT << gen_expr(E.Arg1_) 
		     RESULT << ").length() " S " 0" ==>
		[S IN ["==", "!="] && E.Arg1_.Operation == 'CONST' &&
		 "" == E.Arg1_.Var_arg.Str_c] ?
		     RESULT = "((" final_str ")" 
		     RESULT << gen_expr(E.Arg2_) 
		     RESULT << ").length() " S " 0" ==>
		[S IN ["==", "!="] && E.Arg2_.Operation == 'CONST' 
		 && E.Arg2_.Var_arg.Str_c == #0] ?
		     RESULT = "((" final_str ")" 
		     RESULT << gen_expr(E.Arg1_) 
		     RESULT << ").length()==1 && (((" final_str ")"
		     RESULT << gen_expr(E.Arg1_) 
		     RESULT << ")[0] == '\0') " S " true" ==>
		[S IN ["==", "!="] && E.Arg1_.Operation == 'CONST' 
		 && E.Arg1_.Var_arg.Str_c == #0] ?
		     RESULT = "((" final_str ")" 
		     RESULT << gen_expr(E.Arg2_) 
		     RESULT << ").length()==1 && (((" final_str ")"
		     RESULT << gen_expr(E.Arg2_) 
		     RESULT << ")[0] == '\0') " S " true" ==>
		;
    ['STRUCTURE']: Comp.Error("Internal error -- comparing structures")
    ['CLASS']:
        CASE E.Arg1_.Var_arg == Comp.NONE_c ?
            RESULT = "(AL4_system::Is_none(" gen_expr(E.Arg2_)
            CASE RESULT.Ending("->Obj") ?
                 RESULT = RESULT.Remove_ending("->Obj") ;
            RESULT << ")"
            CASE S ?
            ["=="]: RESULT << ")"
            ["!="]: RESULT = "(!" RESULT[1 TO *] ")"
            
            ELSE Comp.Error("Internal error -- Incorrect compare with object: "
            	 "" RESULT " " S " true")
            ;
            ==>
        ;
        CASE E.Arg2_.Var_arg == Comp.NONE_c ?
            RESULT = "(AL4_system::Is_none(" gen_expr(E.Arg1_)
            CASE RESULT.Ending("->Obj") ?
                 RESULT = RESULT.Remove_ending("->Obj") ;
            RESULT << ")"
            CASE S ?
            ["=="]: RESULT << ")"
            ["!="]: RESULT = "(!" RESULT[1 TO *] ")"
            
            ELSE Comp.Error("Internal error -- Incorrect compare with object: "
            	 "" RESULT " " S " true")
            ;
            ==>
        ;
        RESULT = "(" gen_expr(E.Arg1_)
        RESULT << if(!RESULT.Ending("->Obj"), "->Obj") " " S 
        RESULT << gen_expr(E.Arg2_)
        RESULT << if(!RESULT.Ending("->Obj"), "->Obj") ")" ==>
    ;
    RESULT = "(" gen_expr(E.Arg1_) S
    RESULT << gen_expr(E.Arg2_) ")" .


METHOD gen_fun_call({Expr} E|xpr_calling_fun) ==> STR :
    ----------------------------------------------------- 'prefix class:: ->'
    CASE E.Fun_.Final_name == "" && E.Fun_.Is_system ?
         RESULT = gen_system_fun(E) ==> ;
    CASE E.Fun_.Modifiers['STATIC'] ?
         CASE E.Fun_.Is_system ? 
              RESULT = "AL4_system::"
         ELSE RESULT = E.Fun_.Class.Final_name "::" ;
    ELSE 
         CASE E.This_ != Comp.THIS_expr ?
              CASE E.This_.Is_array ? 
                   RESULT = gen_expr(E.This_) "->"
              
              ELSE RESULT = "((" E.This_.Type_expr.Final_name 
                   RESULT << "*)" gen_expr(E.This_) 
                   RESULT << if(!RESULT.Ending("->Obj"), "->Obj") ")->"
                   BOOL this_prefix|_is_set_already = TRUE
              ;
         ;
    ;
    CASE E.Operation == 'BASE_FUN' ?
         //RESULT << "Methods_" E.Fun_.Class.Final_name "::"
         RESULT = "((Methods_" E.Fun_.Class.Final_name
                "*)(" RESULT "DO))->Methods_" E.Fun_.Class.Final_name "::"
         
    ELSE 
         CASE !E.Fun_.Modifiers['STATIC'] ? 
              CASE !Comp.Current_fun.Modifiers['STATIC'] && (
                   !this_prefix)
                   ?
                   RESULT << "THIS_OBJ->" ;
              RESULT << "Do()->" ;
    ;
    ---------------------------------------------------- 'name of function'
    STR fin|al_name_of_function = E.Fun_.Final_name
    CASE fin.Starting("M_") && !fin.Starting("M__") ?
         fin = "M__" fin["M_".Len TO *] ;
    RESULT << fin "("
    ----------------------------------------------------- 'pass parameters'
    CASE E.Fun_.Param[].Count > 0 ?
        FOR p IN E.Items_[] :
            CASE p.Pass_by_ref ?
                 RESULT << "THIS_OBJ->" // only for STORE parameter
            ; 
            CASE p.Var_arg == Comp.NONE_c ?
                 STR param_s|tring = gen_none_val(E.Fun_.Param[p.Index].Type_)
                 
            ELSE param_s = gen_expr(p).Remove_br ;
            CASE ?
            [p.Type_expr.Kind IN ['CLASS', 'STRUCTURE']
             && param_s.Ending("->Obj")] ?
                 param_s = param_s.Remove_ending("->Obj") 
            ;
            {Type} p_type|_expression = p.Type_expr
            CASE ?
            [p.Var_arg.Is_const && p.Var_arg.Type_.Kind == 'STR'] ?
                 param_s = "(std::string)" param_s
            [p_type.Kind == 'STRUCTURE' && p_type.Final_name[0] == "s"] ?
                 param_s = param_s.Remove_starting("&")
            ;
            RESULT << param_s ","
        ;
        RESULT = RESULT[0 TO *-1] ;
    RESULT << ")" .
    
INT Total_fixed_array_tmp

    
FUN pointer_sign_if_param_by_ref|erence(
{Var} V|ariable) ==> STR
	:
    CASE V.Is_array ? ==> ;
    CASE ?
    [V.Type_.Kind == 'STR'] ? RESULT = "&"
    [V.Type_.Kind == 'STRUCTURE' && is_simple(V.Type_)] ? RESULT = "&" ; .
         
FUN const_if_param_const( {Var} V|araible ) ==> STR :
    CASE !V.Is_array && (V.Type_.Kind == 'STR'
    	 //|| V.Type_.Kind == 'STRUCTURE' && is_simple(V.Type_)
    	 )
    	 ?
         RESULT = "const " ; .


METHOD gen_system_fun|ction_special_call(
    {Expr} E|xpr_calling) ==> STR
    :
    ----------------------------------------- 'Len, Name, Clear, etc.'
    CASE E.Fun_.System_fun ?
    ['SYSFUN_Len']:    ---------------------------------- 'Len'
    
		RESULT = gen_expr(E.Items_[0])
        CASE RESULT.Ending(#QU) ? RESULT = "strlen(" RESULT ")"
        ELSE RESULT = "AL4_system::utf8len(" RESULT ")" ;
        
   	['SYSFUN_Name']:	--------------------------------- 'Name'
   	
		RESULT = E.Items_[0].Type_expr.Base_.Final_name
		RESULT << "::Names_" E.Items_[0].Type_expr.Final_name
		RESULT << "[" gen_expr(E.Items_[0]).Remove_br "]"
                
   	['SYSFUN_Clear']:	--------------------------------- 'Clear' 
   	
		RESULT = gen_expr(E.Items_[0]) "->Clear()"
    
    ['SYSFUN_Count']:	--------------------------------- 'Count' 
    
		RESULT = gen_expr(E.Items_[0]) "->Count()"
    
    ['SYSFUN_Insert']: --------------------------------- 'Insert' 
    
					   RESULT = gen_expr(E.Items_[0])
					   RESULT << "->Insert(" gen_expr(E.Items_[1])
		               RESULT << ", " gen_expr(E.Items_[2])
		                
		               CASE RESULT.Ending("->Obj") ?
		                    RESULT = RESULT.Remove_ending("->Obj") ;
		               RESULT << ")"
                
    ['SYSFUN_Allocate']: --------------------------------- 'Delete' 
    
					   RESULT = gen_expr(E.Items_[0])
                	   RESULT << "->Allocate(" gen_expr(E.Items_[1]) ")"
                
    ['SYSFUN_Delete']: --------------------------------- 'Delete' 
    
					   RESULT = gen_expr(E.Items_[0])
                	   RESULT << "->Delete(" gen_expr(E.Items_[1]) ", " 
                	   
                	   CASE E.Items_[].Count > 2 ?
                	   	    RESULT << gen_expr(E.Items_[2]) ")"
                	   ELSE RESULT << "1)" ;
                
    ['SYSFUN_Remove']: --------------------------------- 'Remove' 
    
					   RESULT = gen_expr(E.Items_[0])
                	   RESULT << "->Remove(" gen_expr(E.Items_[1])
                	   
                	   CASE RESULT.Ending("->Obj") ?
                	        RESULT = RESULT.Remove_ending("->Obj") ;
                	   RESULT << ")"
                
    ['SYSFUN_Find_item']: --------------------------------- 'Find_item'  
    
						   RESULT = gen_expr(E.Items_[0])
                		   RESULT << "->IndexOf(" gen_expr(E.Items_[1]) ")"
                		   
    ['SYSFUN_Index']:	--------------------------------- 'Index'  
    
                FOR f IN nesting_for[] :
                    CASE E.Items_[0].Var_arg == f.Var ?
                        RESULT = f.Index_var ==> ; //"idx" f.Var.Line.Str ==> ;
                ;
                Comp.Error("Can not find Index of FOR loop")
                
    ['SYSFUN_Swap']: 	--------------------------------- 'Swap'
    
            	RESULT = gen_expr(E.Items_[0])
            	RESULT << "->Swap(" gen_expr(E.Items_[1])
            	RESULT << "," gen_expr(E.Items_[2]) ")"
            			
    ['SYSFUN_First']: 	--------------------------------- 'First' 
    
    			RESULT = "0"
    	
    ['SYSFUN_Last']: 	--------------------------------- 'Last' 
    
    			RESULT = (E.Items_[0].Type_expr.Items[].Count-1).Str
    			
    ['SYSFUN_Previous']:	--------------------------------- 'Previous'
    
    			RESULT = "Math::Max(0, " gen_expr(E.Items_[0]) "-1)"
    		  
    ['SYSFUN_Next']:	--------------------------------- 'Next' 
    
    	RESULT = "(byte)Math::Min(" (E.Items_[0].Type_expr.Items[].Count-1).Str 
    	RESULT << ", " gen_expr(E.Items_[0]) "+1)"

    ['SYSFUN_Find_str']:	--------------------------------- 'Find str'
    
    			RESULT = gen_expr(E.Items_[0])
    			RESULT << ".IndexOf(" gen_expr(E.Items_[1]) ")"
    			
    ['SYSFUN_Str', 'SYSFUN_RealStr', 'SYSFUN_BoolStr']: ------ 'Str'
    
    	RESULT = gen_expr(E.Items_[0]) ".ToString()"
    	
    ['SYSFUN_StrInt']:	--------------------------------- 'Int from Str'
    
    	RESULT = "AL4_system::Int(" gen_expr(E.Items_[0]) ")"
    	
    ['SYSFUN_RealInt']: --------------------------------- 'Real -> Int'
    
    	RESULT = "(" gen_expr(E.Items_[0]) ").Trunc()"
    	
    ['SYSFUN_EnumInt']: --------------------------------- 'Enum -> Int'
    
    	RESULT = gen_expr(E.Items_[0])
    	
    ['SYSFUN_StrHex16']: --------------------------------- 'Hex'
    
    	RESULT = "AL4_system::hex16(" gen_expr(E.Items_[0]) ", " 
    	RESULT << gen_expr(E.Items_[1]) ")"
    		
    ['SYSFUN_Shl']: --------------------------------- 'ShiftL'
    
                    RESULT = "(" gen_expr(E.Items_[0]) " << " 
                    RESULT << gen_expr(E.Items_[1]) ")"
    		
    ['SYSFUN_Shr']: --------------------------------- 'ShiftRight'
    
                    RESULT = "AL4_system::ShiftRight(" gen_expr(E.Items_[0])
    				RESULT << ", " gen_expr( E.Items_[1]) ")"
    		
    ['SYSFUN_Rol']: --------------------------------- 'Rol'
    
                    RESULT = "AL4_system::RotateLeft(" gen_expr(E.Items_[0])
    				RESULT << ", " gen_expr(E.Items_[1]) ")"
    		
    ['SYSFUN_Ror']: --------------------------------- 'Ror'
    
                    RESULT = "AL4_system::RotateRight(" gen_expr(E.Items_[0])
    				RESULT << ", " gen_expr(E.Items_[1]) ")"
    		
    ['SYSFUN_Compare_substrings']: --------------------------------- '?substr'
    
    	RESULT = "AL4_system::CompareSubstrings(" gen_expr(E.Items_[0])
    	RESULT << ", " gen_expr(E.Items_[1]) 
    	RESULT << ", " gen_expr(E.Items_[2])
    	RESULT << ", " gen_expr(E.Items_[3]) 
    	RESULT << ", " gen_expr(E.Items_[4])
    	RESULT << ", " gen_expr(E.Items_[5]) ")"
    		
    ['SYSFUN_Compare_substr1']: --------------------------------- '?substr1'
    
    	RESULT = "AL4_system::CompareSubstr1(" gen_expr(E.Items_[0])
    	RESULT << ", " gen_expr(E.Items_[1]) 
    	RESULT << ", " gen_expr(E.Items_[2])
    	RESULT << ", " gen_expr(E.Items_[3]) ")"
    		
    ['SYSFUN_Clone']: --------------------------------- 'Clone'
    
    	RESULT = gen_expr(E.Items_[0]).Remove_br
    	CASE !is_simple(E.Items_[0].Type_expr) ?
    	     CASE ?
    	     [RESULT[0] == "*"] ?
    	          RESULT = RESULT[1 TO *]
    	     [RESULT.Ending("->Obj") || RESULT.Ending("->Obj)")] ?
    	          RESULT = "(Any_structure*)(" RESULT ")" 
    	     ELSE RESULT = "(Any_structure*)(" RESULT ")->Obj" ;
    		 RESULT = "(" RESULT ")->Clone()->hard_link" ;
    	
    ['SYSFUN_Dismiss']: --------------------------------- 'Dismiss'
    	CASE ?
    	[E.Items_[0].Operation == 'INDEX'] ?
    	     RESULT << gen_expr(E.Items_[0].Arg1_) "->Dismiss_array_item("
    	     RESULT << gen_expr(E.Items_[0].Arg2_) ")"
    	[!is_simple(E.Items_[0].Type_expr)] ?
    		 RESULT = "(Ref_obj*)AL4_system::Dismiss_structure(" 
    		 RESULT << gen_expr(E.Items_[0]) ")"
    	ELSE RESULT = gen_expr(E.Items_[0]) ;
    
    ['SYSFUN_UNDEFINED']: Comp.Error("Don't know how to call system function: "
         "" E.Fun_.Names[0]) ; .

METHOD gen_variable({Expr} E|_variable) ==> STR :
    CASE E.Var_arg.In_type_.Kind == 'CLASS' ? RESULT << "THIS_OBJ->" ;
    CASE ?
    [E.Var_arg.Names[0] == "DATA"] ?
         RESULT << Comp.Current_class.Final_name "::"
    [E.Var_arg.Type_.Kind == 'STRUCTURE' && is_simple(E.Var_arg.Type_)
     && !E.Var_arg.Is_array && (
     !E.Var_arg.Is_param || E.Var_arg.Names[0] == "RESULT")] ?
         RESULT << "&"
    ;
    RESULT << E.Var_arg.Final_name .

//INT total_index

METHOD gen_index({Expr} E|_index_operation) ==> STR :
    CASE E.Arg1_.Is_array ?
         CASE (E.Arg1_.Is_fixed) && (
              E.Arg3_ != NONE) && E.Arg2_.Operation == 'CONST' && (
              E.Arg2_.Var_arg.Type_.Kind == 'INT') && (
              E.Arg2_.Var_arg.Int_c == 0) && (
              E.Arg3_.Is_star_operation)
              ?
              ---------------------- 'A[0 TO *] --> A'
              RESULT << gen_expr(E.Arg1_) ==> ;
             
        CASE E.Arg3_ != NONE ?
             RESULT = "new FixA"
             CASE E.Arg1_.Type_expr.Kind ?
             ['BOOL']: RESULT << "Bool"
             ['BYTE', 'ENUM']: RESULT << "Byte"
             ['INT']: RESULT << "Int"
             ['REAL']: RESULT << "Real"
             ['STR']: RESULT << "Str"
             ['CLASS', 'STRUCTURE']: RESULT << "Obj" ;
             
             RESULT << "/" "*1*" "/"  "(" gen_expr(E.Arg1_)
             RESULT << ", " gen_expr(E.Arg2_)
             RESULT << ", " gen_expr(E.Arg3_) ")" ==>
        ;
             
        CASE level_expr == 1 && is_left_side ?
             close_br = TRUE
             
             RESULT << "/" "*3*" "/" gen_expr(E.Arg1_) 
             RESULT << "->set(" gen_expr(E.Arg2_).Remove_br ", " ==>
        ;
        
        CASE E.Arg1_.Var_arg.Is_const ?
        	 STR t|ype_of_value = type_gen(E.Arg1_.Var_arg.Type_, {type_options})
        	 
             RESULT << "AL4_system::Array_item_" t 
             RESULT << "(&" E.Arg1_.Var_arg.In_type_.Final_name 
             RESULT << "__" E.Arg1_.Var_arg.Final_name "[0]"
             RESULT << ", " E.Arg1_.Var_arg.Size_value.Str
             RESULT << ", " gen_expr(E.Arg2_) ")" ==> 
        ;
        
        RESULT << "/" "*4*" "/"  gen_expr(E.Arg1_) 
        RESULT << "->get(" gen_expr(E.Arg2_).Remove_br ")"
                  
        CASE (E.Type_expr.Kind == 'CLASS'
        	 || E.Type_expr.Kind == 'STRUCTURE' && !is_simple(E.Type_expr) )
        	 && !RESULT.Ending("->Obj")
        	 ?
             RESULT << "->Obj" ;
        ==> 
    ;
    CASE E.Arg3_ != NONE ? 
        RESULT = "AL4_system::Substring(" gen_expr(E.Arg1_).Remove_br
        RESULT << ", " gen_expr(E.Arg2_).Remove_br
        RESULT << ", " gen_expr(E.Arg3_).Remove_br ")" ==>
    ;
    CASE level_expr == 1 && is_left_side ?
        close_br = TRUE
        
        RESULT = gen_expr(E.Arg1_).Remove_br 
        RESULT << " = AL4_system::Replace_symbol(" gen_expr(E.Arg1_).Remove_br 
        RESULT << ", " gen_expr(E.Arg2_).Remove_br "," ==>
    ;
        
    RESULT = "AL4_system::Single_symbol(" gen_expr(E.Arg1_).Remove_br
    RESULT << ", " gen_expr(E.Arg2_).Remove_br ")" .



FUNCTION gen_none_val({Type} T|ype_NONE) ==> STR :
    CASE T.Kind ?
    ['BOOL']: RESULT = "false"
    ['BYTE', 'INT', 'REAL', 'ENUM']: RESULT = "0"
    ['STR']: RESULT = #QU #QU
    
    ['STRUCTURE']: //RESULT = "{}"
    	RESULT = T.Final_name "::NoneObj_" T.Final_name "->hard_link"
    			 
    ['CLASS']: RESULT = T.Final_name "::NoneObj_" T.Final_name "->hard_link"
    ; .



METHOD gen_field({Expr} E|_field_of_obj) ==> STR :
	{Type} t_a1|_type_arg1 = E.Arg1_.Type_expr
    CASE ?
    [t_a1.Kind == 'STRUCTURE' && is_simple(t_a1) && E.Arg1_.Operation == 'VAR']?
         RESULT = "((" type_gen(t_a1, {type_options})
         CASE RESULT[*] != "*" ? RESULT << "*" ;
         RESULT << ") " 
         STR a1|_argument1 = gen_expr(E.Arg1_).Remove_br.Trim
         CASE a1[0] != "&" ? a1 = "& " a1 ;
         RESULT << a1 ")->" E.Var_arg.Final_name "/*04*/"
    [t_a1.Kind IN ['CLASS', 'STRUCTURE']] ?
         RESULT = "((" t_a1.Final_name
         RESULT << "*)" gen_expr(E.Arg1_) 
         CASE ?
         [RESULT.Ending("->hard_link")] ?
              RESULT = RESULT.Remove_ending("->hard_link")
         [E.Arg1_.Var_arg.Final_name != "Result" 
          && !RESULT.Ending("->Obj")
          && (t_a1.Kind != 'STRUCTURE' || !is_simple(t_a1))] ?
              RESULT << "->Obj"
         ;
         CASE is_left_side && (t_a1.Kind != 'STRUCTURE' || !is_simple(t_a1)) ?
              RESULT << "->write" ;
         RESULT << ")->" E.Var_arg.Final_name
    ELSE 
         RESULT = gen_expr(E.Arg1_) "->" E.Var_arg.Final_name 
    ;
    CASE !E.Var_arg.Is_array 
    	 && E.Var_arg.Type_.Kind == 'STRUCTURE' 
    	 && is_simple(E.Var_arg.Type_)
    	 ?
         RESULT = "(&" RESULT ")" ; .
         

METHOD gen_const({Expr} E|_constant) ==> STR :
	RESULT = gen_const_value(E.Var_arg) .
	
METHOD gen_const_value({Var} V|alue_generating) ==> STR :
    CASE V.Type_.Kind ?
    ['BOOL']: 
              CASE V.Bool_c ? RESULT = "true"
              ELSE RESULT = "false" ;
    ['BYTE', 'INT', 'ENUM']: RESULT = V.Int_c.Str
    ['REAL']: 
              CASE ?
              [V == Comp.INFINITY_c] ?
                   RESULT = "std::numeric_limits<double>::infinity()"
              [V == Comp.NAN_c] ?
                   RESULT = "std::numeric_limits<double>::quiet_NaN()"
              ELSE RESULT = V.Real_c.Str
              	   CASE "." !IN RESULT && "E" !IN RESULT ? RESULT << ".0" ;
              ;
    ['STR']: RESULT = as_str(V.Str_c)
    
    ['STRUCTURE']: Comp.Current_class.Parse.Line = V.Line
        Comp.Error("Generating structure constant!"._Egen )
        
    ['CLASS']: Comp.Current_class.Parse.Line = V.Line
        Comp.Error("Generating class constant!"._Egen2 )
    ; .


METHOD gen_as_obj({Expr} E|_as_operation) ==> STR :
    STR t|ype_final_name = E.Type_expr.Final_name
    
    RESULT = "AL4_system::As_obj(" gen_expr(E.Arg1_)
    CASE RESULT.Ending("->Obj") ? RESULT = RESULT.Remove_ending("->Obj") ;
    RESULT << ", " t "::NoneObj_" t "->hard_link)" .


    
METHOD gen_array({Expr} E|_array_obj) ==> STR :
    --------------------------------------- 'fixed array on fly'
    CASE E.Type_expr.Kind ?
    ['BOOL']: STR n|ames_type[] << "Bool" << "bool"
    ['BYTE', 'ENUM']: n[] << "Byte" << "byte"
    ['INT']: n[] << "Int" << "int"
    ['REAL']: n[] << "Real" << "double"
    ['STR']: n[] << "Str" << "std::" "string"
    ['STRUCTURE']: Comp.Error("Constant array of records?")
    ['CLASS']: Comp.Error("Constant array of objects?") ;
    --------------------------------------- 'type fix_arrNNN[] = { ... }'
    STR array_n|ame = " fix_arr" last_init_var.Str
    STR decl|aration_temp_var = n[1] array_n "[] = {" 
    FOR it IN E.Items_[] :
        decl << gen_expr(it) ", "  ;
    decl = decl[0 TO *-2] "};"
    add_init_var(decl)
    --------------------------------------- 'RESULT using it'
    RESULT = "(new FixA" n[0] "(" array_n ", " E.Items_[].Count.Str "))" .

METHOD gen_const_array({Expr} E|_array_obj) ==> STR :
    --------------------------------------- 'fixed array on fly'
    CASE E.Type_expr.Kind ?
    ['BOOL']: STR n|ames_type[] << "Bool" << "bool"
    ['BYTE', 'ENUM']: n[] << "Byte" << "byte"
    ['INT']: n[] << "Int" << "int"
    ['REAL']: n[] << "Real" << "double"
    ['STR']: n[] << "Str" << "std::" "string"
    ['STRUCTURE']: Comp.Error("Constant array of records?")
    ['CLASS']: Comp.Error("Constant array of objects?") ;
    --------------------------------------- 'type fix_arrNNN[] = { ... }'
    STR array_n|ame = " fix_arr" last_init_var.Str
    STR decl|aration_temp_var = n[1] array_n "[] = {" 
    FOR it IN E.Items_[] :
        decl << gen_expr(it) ", "  ;
    decl = decl[0 TO *-2] "};"
    add_init_var(decl)
    --------------------------------------- 'RESULT using it'
    RESULT = array_n ", " E.Items_[].Count.Str .


{Expr} new_init|_statement

METHOD gen_new_obj({Expr} E|_new_obj) ==> STR :
    //CASE E.Assignments_[].Count > 0 ?
    //     o[] << "// new_init E.At_line:" E.At_line.Str 
    //     ", count:" E.Assignments_[].Count.Str ;
    new_init = E
    RESULT = E.Type_obj_.Final_name "::New()" .


    
END

<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
  <ItemGroup Label="ProjectConfigurations">
    <ProjectConfiguration Include="Debug|Win32">
      <Configuration>Debug</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
    <ProjectConfiguration Include="Release|Win32">
      <Configuration>Release</Configuration>
      <Platform>Win32</Platform>
    </ProjectConfiguration>
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
?<PlatformToolset>?</PlatformToolset>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
    <ConfigurationType>Application</ConfigurationType>
  </PropertyGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
  <ImportGroup Label="ExtensionSettings">
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="PropertySheets">
    <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
  </ImportGroup>
  <PropertyGroup Label="UserMacros" />
  <PropertyGroup>
    <_ProjectFileVersion>10.0.40219.1</_ProjectFileVersion>
    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" />
    <CodeAnalysisRuleSet Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">AllRules.ruleset</CodeAnalysisRuleSet>
    <CodeAnalysisRules Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
    <CodeAnalysisRuleAssemblies Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" />
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
    <OutDir Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">$(SolutionDir)$(Platform)\$(Configuration)\</OutDir>
  </PropertyGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
    <ClCompile>
      <PreprocessorDefinitions>UNICODE;WIN32;WIN64;
      %(PreprocessorDefinitions)</PreprocessorDefinitions>
      <Optimization>Disabled</Optimization>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <AdditionalIncludeDirectories>
      		.\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories)
      </AdditionalIncludeDirectories>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
	  <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
    </ClCompile>
    <Link>
	  <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
      <AdditionalLibraryDirectories>
      %(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalDependencies>
      %(AdditionalDependencies)</AdditionalDependencies>
	  <EnableCOMDATFolding>false</EnableCOMDATFolding>
	  <ProfileGuidedDatabase> </ProfileGuidedDatabase>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <PreprocessorDefinitions>UNICODE;WIN32;WIN64;
      %(PreprocessorDefinitions)</PreprocessorDefinitions>
      <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
      <AdditionalIncludeDirectories>
      .\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
	  <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
    </ClCompile>
    <Link>
	  <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
      <AdditionalLibraryDirectories>
      %(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <GenerateDebugInformation>true</GenerateDebugInformation>
      <AdditionalDependencies>
      %(AdditionalDependencies)</AdditionalDependencies>
	  <EnableCOMDATFolding>false</EnableCOMDATFolding>
	  <ProfileGuidedDatabase> </ProfileGuidedDatabase>
    </Link>
  </ItemDefinitionGroup>
  <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
    <ClCompile>
      <PreprocessorDefinitions>UNICODE;WIN32;WIN64;
      NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
      <DebugInformationFormat>
      </DebugInformationFormat>
      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
      <AdditionalIncludeDirectories>
      .\GeneratedFiles\$(ConfigurationName);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
      <TreatWChar_tAsBuiltInType>true</TreatWChar_tAsBuiltInType>
    </ClCompile>
    <Link>
      <SubSystem>Console</SubSystem>
      <OutputFile>$(OutDir)\$(ProjectName).exe</OutputFile>
      <AdditionalLibraryDirectories>
      %(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
      <GenerateDebugInformation>false</GenerateDebugInformation>
      <AdditionalDependencies>
      %(AdditionalDependencies)</AdditionalDependencies>
    </Link>
  </ItemDefinitionGroup>
  <ItemGroup>
--VCXPROJ--2
  </ItemGroup>
  <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
  <ImportGroup Label="ExtensionTargets">
  </ImportGroup>
  <ProjectExtensions>
    <VisualStudio>
      <UserProperties UicDir=".\GeneratedFiles" MocDir=".\GeneratedFiles\$(ConfigurationName)" MocOptions="" RccDir=".\GeneratedFiles" lupdateOnBuild="0" lupdateOptions="" lreleaseOptions="" />
    </VisualStudio>
  </ProjectExtensions>
</Project>
--VCXPROJ--3
    
*/
