*** empty log message ***
[chuck-blob.git] / v2 / chuck_main.cpp
blob71084181e81c81a8f4e58e87b1fdf468ffd0e9c4
1 /*----------------------------------------------------------------------------
2 ChucK Concurrent, On-the-fly Audio Programming Language
3 Compiler and Virtual Machine
5 Copyright (c) 2004 Ge Wang and Perry R. Cook. All rights reserved.
6 http://chuck.cs.princeton.edu/
7 http://soundlab.cs.princeton.edu/
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
22 U.S.A.
23 -----------------------------------------------------------------------------*/
25 //-----------------------------------------------------------------------------
26 // file: chuck_main.cpp
27 // desc: chuck entry point
29 // author: Ge Wang (gewang@cs.princeton.edu)
30 // Perry R. Cook (prc@cs.princeton.edu)
31 // additional contributors:
32 // Ananya Misra (amisra@cs.princeton.edu)
33 // Spencer Salazar (salazar@cs.princeton.edu)
34 // date: version 1.1.x.x - Autumn 2002
35 // version 1.2.x.x - Autumn 2004
36 //-----------------------------------------------------------------------------
37 #include <stdio.h>
38 #include <string.h>
39 #include <time.h>
41 #include "chuck_compile.h"
42 #include "chuck_vm.h"
43 #include "chuck_bbq.h"
44 #include "chuck_errmsg.h"
45 #include "chuck_lang.h"
46 #include "chuck_otf.h"
47 #include "chuck_shell.h"
48 #include "chuck_console.h"
49 #include "chuck_globals.h"
51 #include "util_math.h"
52 #include "util_string.h"
53 #include "util_thread.h"
54 #include "util_network.h"
55 #include "hidio_sdl.h"
57 #include <signal.h>
58 #ifndef __PLATFORM_WIN32__
59 #include <unistd.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #endif
65 // global variables
66 #if defined(__MACOSX_CORE__)
67 t_CKINT g_priority = 80;
68 t_CKINT g_priority_low = 60;
69 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
70 t_CKINT g_priority = THREAD_PRIORITY_HIGHEST;
71 t_CKINT g_priority_low = THREAD_PRIORITY_HIGHEST;
72 #else
73 t_CKINT g_priority = 0x7fffffff;
74 t_CKINT g_priority_low = 0x7fffffff;
75 #endif
77 // thread id for otf thread
78 CHUCK_THREAD g_tid_otf = 0;
79 // thread id for shell
80 CHUCK_THREAD g_tid_shell = 0;
82 // default destination host name
83 char g_host[256] = "127.0.0.1";
88 //-----------------------------------------------------------------------------
89 // name: signal_int()
90 // desc: ...
91 //-----------------------------------------------------------------------------
92 extern "C" void signal_int( int sig_num )
94 fprintf( stderr, "[chuck]: cleaning up...\n" );
96 if( g_vm )
98 // get vm
99 Chuck_VM * vm = g_vm;
100 Chuck_Compiler * compiler = g_compiler;
101 // flag the global one
102 g_vm = NULL;
103 g_compiler = NULL;
104 // if not NULL
105 if( vm )
107 // stop
108 vm->stop();
109 // detach
110 all_detach();
113 // things don't work so good on windows...
114 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
115 // pthread_kill( g_tid_otf, 2 );
116 if( g_tid_otf ) pthread_cancel( g_tid_otf );
117 if( g_tid_whatever ) pthread_cancel( g_tid_whatever );
118 // if( g_tid_otf ) usleep( 50000 );
119 #else
120 // close handle
121 if( g_tid_otf ) CloseHandle( g_tid_otf );
122 #endif
123 // will this work for windows?
124 SAFE_DELETE( vm );
125 SAFE_DELETE( compiler );
127 // ck_close( g_sock );
130 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
131 // pthread_join( g_tid_otf, NULL );
132 #endif
134 exit(2);
140 //-----------------------------------------------------------------------------
141 // name: uh()
142 // desc: ...
143 //-----------------------------------------------------------------------------
144 static void uh( )
146 // TODO: play white noise and/or sound effects
147 srand( time( NULL ) );
148 while( true )
150 int n = (int)(rand() / (float)RAND_MAX * poop_size);
151 printf( "%s\n", poop[n] );
152 usleep( (unsigned long)(rand() / (float)RAND_MAX * 2000000) );
159 //-----------------------------------------------------------------------------
160 // name: init_shell()
161 // desc: ...
162 //-----------------------------------------------------------------------------
163 static t_CKBOOL init_shell( Chuck_Shell * shell, Chuck_Shell_UI * ui, Chuck_VM * vm )
165 // initialize shell UI
166 if( !ui->init() )
168 fprintf( stderr, "[chuck]: error starting shell UI...\n" );
169 return FALSE;
172 // initialize
173 if( !shell->init( vm, ui ) )
175 fprintf( stderr, "[chuck]: error starting shell...\n" );
176 return FALSE;
179 return TRUE;
185 //-----------------------------------------------------------------------------
186 // name: get_count()
187 // desc: ...
188 //-----------------------------------------------------------------------------
189 static t_CKBOOL get_count( const char * arg, t_CKUINT * out )
191 // no comment
192 if( !strncmp( arg, "--", 2 ) ) arg += 2;
193 else if( !strncmp( arg, "-", 1 ) ) arg += 1;
194 else return FALSE;
196 // end of string
197 if( *arg == '\0' ) return FALSE;
198 // not digit
199 if( *arg < '0' || *arg > '9' ) return FALSE;
201 // number
202 *out = (t_CKUINT)atoi( arg );
204 return TRUE;
210 //-----------------------------------------------------------------------------
211 // name: version()
212 // desc: ...
213 //-----------------------------------------------------------------------------
214 static void version()
216 fprintf( stderr, "\n" );
217 fprintf( stderr, "chuck version: %s\n", CK_VERSION );
218 #if defined(__PLATFORM_WIN32__)
219 fprintf( stderr, " exe target: microsoft win32\n" );
220 #elif defined(__WINDOWS_DS__)
221 fprintf( stderr, " exe target: microsoft win32 + cygwin\n" );
222 #elif defined(__LINUX_ALSA__)
223 fprintf( stderr, " exe target: linux (alsa)\n" );
224 #elif defined(__LINUX_OSS__)
225 fprintf( stderr, " exe target: linux (oss)\n" );
226 #elif defined(__LINUX_JACK__)
227 fprintf( stderr, " exe target: linux (jack)\n" );
228 #elif defined(__MACOSX_UB__)
229 fprintf( stderr, " exe target: mac os x : universal binary\n" );
230 #elif defined(__MACOSX_CORE__) && defined(__LITTLE_ENDIAN__)
231 fprintf( stderr, " exe target: mac os x : intel\n" );
232 #elif defined(__MACOSX_CORE__)
233 fprintf( stderr, " exe target: mac os x : powerpc\n" );
234 #else
235 fprintf( stderr, " exe target: uh... unknown\n" );
236 #endif
237 fprintf( stderr, " http://chuck.cs.princeton.edu/\n\n" );
243 //-----------------------------------------------------------------------------
244 // name: usage()
245 // desc: ...
246 //-----------------------------------------------------------------------------
247 static void usage()
249 fprintf( stderr, "usage: chuck --[options|commands] [+-=^] file1 file2 file3 ...\n" );
250 fprintf( stderr, " [options] = halt|loop|audio|silent|dump|nodump|server|about|\n" );
251 fprintf( stderr, " srate<N>|bufsize<N>|bufnum<N>|dac<N>|adc<N>|\n" );
252 fprintf( stderr, " remote<hostname>|port<N>|verbose<N>|probe|\n" );
253 fprintf( stderr, " channels<N>|out<N>|in<N>|shell|empty|level<N>|\n" );
254 fprintf( stderr, " blocking|callback|deprecate:{stop|warn|ignore}\n" );
255 fprintf( stderr, " [commands] = add|remove|replace|remove.all|status|time|kill\n" );
256 fprintf( stderr, " [+-=^] = shortcuts for add, remove, replace, status\n" );
257 version();
263 //-----------------------------------------------------------------------------
264 // name: main()
265 // desc: entry point
266 //-----------------------------------------------------------------------------
267 int main( int argc, char ** argv )
269 Chuck_Compiler * compiler = NULL;
270 Chuck_VM * vm = NULL;
271 Chuck_VM_Code * code = NULL;
272 Chuck_VM_Shred * shred = NULL;
274 t_CKBOOL enable_audio = TRUE;
275 t_CKBOOL vm_halt = TRUE;
276 t_CKUINT srate = SAMPLING_RATE_DEFAULT;
277 t_CKUINT buffer_size = BUFFER_SIZE_DEFAULT;
278 t_CKUINT num_buffers = NUM_BUFFERS_DEFAULT;
279 t_CKUINT dac = 0;
280 t_CKUINT adc = 0;
281 t_CKUINT dac_chans = 2;
282 t_CKUINT adc_chans = 2;
283 t_CKBOOL dump = FALSE;
284 t_CKBOOL probe = FALSE;
285 t_CKBOOL set_priority = FALSE;
286 t_CKBOOL auto_depend = FALSE;
287 t_CKBOOL block = FALSE;
288 t_CKBOOL enable_shell = FALSE;
289 t_CKBOOL no_vm = FALSE;
290 t_CKBOOL load_hid = FALSE;
291 t_CKBOOL enable_server = TRUE;
292 t_CKBOOL do_watchdog = TRUE;
293 t_CKINT log_level = CK_LOG_CORE;
294 t_CKINT deprecate_level = 1; // warn
296 string filename = "";
297 vector<string> args;
299 #if defined(__MACOSX_CORE__)
300 do_watchdog = TRUE;
301 #elif defined(__PLATFORM_WIN32__) && !defined(__WINDOWS_PTHREAD__)
302 do_watchdog = TRUE;
303 #else
304 do_watchdog = FALSE;
305 #endif
307 t_CKUINT files = 0;
308 t_CKUINT count = 1;
309 t_CKINT i;
311 // set log level
312 EM_setlog( log_level );
314 // parse command line args
315 for( i = 1; i < argc; i++ )
317 if( argv[i][0] == '-' || argv[i][0] == '+' ||
318 argv[i][0] == '=' || argv[i][0] == '^' || argv[i][0] == '@' )
320 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d")
321 || !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d") )
322 continue;
323 else if( get_count( argv[i], &count ) )
324 continue;
325 else if( !strcmp(argv[i], "--audio") || !strcmp(argv[i], "-a") )
326 enable_audio = TRUE;
327 else if( !strcmp(argv[i], "--silent") || !strcmp(argv[i], "-s") )
328 enable_audio = FALSE;
329 else if( !strcmp(argv[i], "--halt") || !strcmp(argv[i], "-t") )
330 vm_halt = TRUE;
331 else if( !strcmp(argv[i], "--loop") || !strcmp(argv[i], "-l") )
332 { vm_halt = FALSE; enable_server = TRUE; }
333 else if( !strcmp(argv[i], "--server") )
334 enable_server = TRUE;
335 else if( !strcmp(argv[i], "--standalone") )
336 enable_server = FALSE;
337 else if( !strcmp(argv[i], "--callback") )
338 block = FALSE;
339 else if( !strcmp(argv[i], "--blocking") )
340 block = TRUE;
341 else if( !strcmp(argv[i], "--hid") )
342 load_hid = TRUE;
343 else if( !strcmp(argv[i], "--shell") || !strcmp( argv[i], "-e" ) )
344 { enable_shell = TRUE; vm_halt = FALSE; }
345 else if( !strcmp(argv[i], "--empty") )
346 no_vm = TRUE;
347 else if( !strncmp(argv[i], "--srate", 7) )
348 srate = atoi( argv[i]+7 ) > 0 ? atoi( argv[i]+7 ) : srate;
349 else if( !strncmp(argv[i], "-r", 2) )
350 srate = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : srate;
351 else if( !strncmp(argv[i], "--bufsize", 9) )
352 buffer_size = atoi( argv[i]+9 ) > 0 ? atoi( argv[i]+9 ) : buffer_size;
353 else if( !strncmp(argv[i], "-b", 2) )
354 buffer_size = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : buffer_size;
355 else if( !strncmp(argv[i], "--bufnum", 8) )
356 num_buffers = atoi( argv[i]+8 ) > 0 ? atoi( argv[i]+8 ) : num_buffers;
357 else if( !strncmp(argv[i], "-n", 2) )
358 num_buffers = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : num_buffers;
359 else if( !strncmp(argv[i], "--dac", 5) )
360 dac = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
361 else if( !strncmp(argv[i], "--adc", 5) )
362 adc = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 0;
363 else if( !strncmp(argv[i], "--channels", 10) )
364 dac_chans = adc_chans = atoi( argv[i]+10 ) > 0 ? atoi( argv[i]+10 ) : 2;
365 else if( !strncmp(argv[i], "-c", 2) )
366 dac_chans = adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
367 else if( !strncmp(argv[i], "--out", 5) )
368 dac_chans = atoi( argv[i]+5 ) > 0 ? atoi( argv[i]+5 ) : 2;
369 else if( !strncmp(argv[i], "-o", 2) )
370 dac_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
371 else if( !strncmp(argv[i], "--in", 4) )
372 adc_chans = atoi( argv[i]+4 ) > 0 ? atoi( argv[i]+4 ) : 2;
373 else if( !strncmp(argv[i], "-i", 2) )
374 adc_chans = atoi( argv[i]+2 ) > 0 ? atoi( argv[i]+2 ) : 2;
375 else if( !strncmp(argv[i], "--level", 7) )
376 { g_priority = atoi( argv[i]+7 ); set_priority = TRUE; }
377 else if( !strncmp(argv[i], "--watchdog", 10) )
378 { g_watchdog_timeout = atof( argv[i]+10 );
379 if( g_watchdog_timeout <= 0 ) g_watchdog_timeout = 0.5;
380 do_watchdog = TRUE; }
381 else if( !strncmp(argv[i], "--nowatchdog", 12) )
382 do_watchdog = FALSE;
383 else if( !strncmp(argv[i], "--remote", 8) )
384 strcpy( g_host, argv[i]+8 );
385 else if( !strncmp(argv[i], "@", 1) )
386 strcpy( g_host, argv[i]+1 );
387 else if( !strncmp(argv[i], "--port", 6) )
388 g_port = atoi( argv[i]+6 );
389 else if( !strncmp(argv[i], "-p", 2) )
390 g_port = atoi( argv[i]+2 );
391 else if( !strncmp(argv[i], "--auto", 6) )
392 auto_depend = TRUE;
393 else if( !strncmp(argv[i], "-u", 2) )
394 auto_depend = TRUE;
395 else if( !strncmp(argv[i], "--log", 5) )
396 log_level = argv[i][5] ? atoi( argv[i]+5 ) : CK_LOG_INFO;
397 else if( !strncmp(argv[i], "--verbose", 9) )
398 log_level = argv[i][9] ? atoi( argv[i]+9 ) : CK_LOG_INFO;
399 else if( !strncmp(argv[i], "-v", 2) )
400 log_level = argv[i][2] ? atoi( argv[i]+2 ) : CK_LOG_INFO;
401 else if( !strncmp(argv[i], "--deprecate", 11) )
403 // get the rest
404 string arg = argv[i]+11;
405 if( arg == ":stop" ) deprecate_level = 0;
406 else if( arg == ":warn" ) deprecate_level = 1;
407 else if( arg == ":ignore" ) deprecate_level = 2;
408 else
410 // error
411 fprintf( stderr, "[chuck]: invalid arguments for '--deprecate'...\n" );
412 fprintf( stderr, "[chuck]: ... (looking for :stop, :warn, or :ignore)\n" );
413 exit( 1 );
416 else if( !strcmp( argv[i], "--probe" ) )
417 probe = TRUE;
418 else if( !strcmp( argv[i], "--poop" ) )
419 uh();
420 else if( !strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")
421 || !strcmp(argv[i], "--about") )
423 usage();
424 exit( 2 );
426 else if( !strcmp( argv[i], "--version" ) )
428 version();
429 exit( 2 );
431 else
433 // boost log level
434 g_otf_log = CK_LOG_CORE;
435 // flag
436 int is_otf = FALSE;
437 // log level
438 EM_setlog( log_level );
439 // do it
440 if( otf_send_cmd( argc, argv, i, g_host, g_port, &is_otf ) )
441 exit( 0 );
443 // is otf
444 if( is_otf ) exit( 1 );
446 // done
447 fprintf( stderr, "[chuck]: invalid flag '%s'\n", argv[i] );
448 usage();
449 exit( 1 );
452 else
453 files++;
456 // log level
457 EM_setlog( log_level );
459 // probe
460 if( probe )
462 Digitalio::probe();
464 EM_error2b( 0, "" );
465 probeMidiIn();
466 EM_error2b( 0, "" );
467 probeMidiOut();
468 EM_error2b( 0, "" );
470 //HidInManager::probeHidIn();
472 // exit
473 exit( 0 );
476 // check buffer size
477 buffer_size = ensurepow2( buffer_size );
478 // check mode and blocking
479 if( !enable_audio && !block ) block = TRUE;
480 // audio, boost
481 if( !set_priority && !block ) g_priority = g_priority_low;
482 if( !set_priority && !enable_audio ) g_priority = 0x7fffffff;
483 // set priority
484 Chuck_VM::our_priority = g_priority;
485 // set watchdog
486 g_do_watchdog = do_watchdog;
488 if ( !files && vm_halt && !enable_shell )
490 fprintf( stderr, "[chuck]: no input files... (try --help)\n" );
491 exit( 1 );
494 // shell initialization without vm
495 if( enable_shell && no_vm )
497 // instantiate
498 g_shell = new Chuck_Shell;
499 // initialize
500 if( !init_shell( g_shell, new Chuck_Console, NULL ) )
501 exit( 1 );
502 // no vm is needed, just start running the shell now
503 g_shell->run();
504 // clean up
505 SAFE_DELETE( g_shell );
506 // done
507 exit( 0 );
510 // make sure vm
511 if( no_vm )
513 fprintf( stderr, "[chuck]: '--empty' can only be used with shell...\n" );
514 exit( 1 );
517 // allocate the vm - needs the type system
518 vm = g_vm = new Chuck_VM;
519 if( !vm->initialize( enable_audio, vm_halt, srate, buffer_size,
520 num_buffers, dac, adc, dac_chans, adc_chans, block ) )
522 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
523 exit( 1 );
526 // allocate the compiler
527 compiler = g_compiler = new Chuck_Compiler;
528 // initialize the compiler
529 if( !compiler->initialize( vm ) )
531 fprintf( stderr, "[chuck]: error initializing compiler...\n" );
532 exit( 1 );
534 // enable dump
535 compiler->emitter->dump = dump;
536 // set auto depend
537 compiler->set_auto_depend( auto_depend );
539 // vm synthesis subsystem - needs the type system
540 if( !vm->initialize_synthesis( ) )
542 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
543 exit( 1 );
546 // pre-load hid
547 if( load_hid ) HidInManager::init();
549 // catch SIGINT
550 signal( SIGINT, signal_int );
551 #ifndef __PLATFORM_WIN32__
552 // catch SIGPIPE
553 signal( SIGPIPE, signal_pipe );
554 #endif
556 // shell initialization
557 if( enable_shell )
559 // instantiate
560 g_shell = new Chuck_Shell;
561 // initialize
562 if( !init_shell( g_shell, new Chuck_Console, vm ) )
563 exit( 1 );
566 // set deprecate
567 compiler->env->deprecate_level = deprecate_level;
569 // reset count
570 count = 1;
572 // log
573 EM_log( CK_LOG_SEVERE, "starting compilation..." );
574 // push indent
575 EM_pushlog();
577 // loop through and process each file
578 for( i = 1; i < argc; i++ )
580 // make sure
581 if( argv[i][0] == '-' || argv[i][0] == '+' )
583 if( !strcmp(argv[i], "--dump") || !strcmp(argv[i], "+d" ) )
584 compiler->emitter->dump = TRUE;
585 else if( !strcmp(argv[i], "--nodump") || !strcmp(argv[i], "-d" ) )
586 compiler->emitter->dump = FALSE;
587 else
588 get_count( argv[i], &count );
590 continue;
593 // parse out command line arguments
594 if( !extract_args( argv[i], filename, args ) )
596 // error
597 fprintf( stderr, "[chuck]: malformed filename with argument list...\n" );
598 fprintf( stderr, " --> '%s'", argv[i] );
599 return 1;
602 // log
603 EM_log( CK_LOG_FINE, "compiling '%s'...", filename.c_str() );
604 // push indent
605 EM_pushlog();
607 // parse, type-check, and emit
608 if( !compiler->go( filename, NULL ) )
609 return 1;
611 // get the code
612 code = compiler->output();
613 // name it
614 code->name += string(argv[i]);
616 // log
617 EM_log( CK_LOG_FINE, "sporking %d %s...", count,
618 count == 1 ? "instance" : "instances" );
620 // spork it
621 while( count-- )
623 // spork
624 shred = vm->spork( code, NULL );
625 // add args
626 shred->args = args;
629 // pop indent
630 EM_poplog();
632 // reset count
633 count = 1;
636 // pop indent
637 EM_poplog();
639 // reset the parser
640 reset_parse();
642 // boost priority
643 if( Chuck_VM::our_priority != 0x7fffffff )
645 // try
646 if( !Chuck_VM::set_priority( Chuck_VM::our_priority, vm ) )
648 // error
649 fprintf( stderr, "[chuck]: %s\n", vm->last_error() );
650 exit( 1 );
654 // server
655 if( enable_server )
657 // log
658 EM_log( CK_LOG_SYSTEM, "starting listener on port: %d...", g_port );
660 // start tcp server
661 g_sock = ck_tcp_create( 1 );
662 if( !g_sock || !ck_bind( g_sock, g_port ) || !ck_listen( g_sock, 10 ) )
664 fprintf( stderr, "[chuck]: cannot bind to tcp port %i...\n", g_port );
665 ck_close( g_sock );
666 g_sock = NULL;
668 else
670 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
671 pthread_create( &g_tid_otf, NULL, otf_cb, NULL );
672 #else
673 g_tid_otf = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)otf_cb, NULL, 0, 0 );
674 #endif
677 else
679 // log
680 EM_log( CK_LOG_SYSTEM, "OTF server/listener: OFF" );
683 // start shell on separate thread
684 if( enable_shell )
686 #if !defined(__PLATFORM_WIN32__) || defined(__WINDOWS_PTHREAD__)
687 pthread_create( &g_tid_shell, NULL, shell_cb, g_shell );
688 #else
689 g_tid_shell = CreateThread( NULL, 0, (LPTHREAD_START_ROUTINE)shell_cb, g_shell, 0, 0 );
690 #endif
693 // run the vm
694 vm->run();
696 // detach
697 all_detach();
699 // free vm
700 vm = NULL; SAFE_DELETE( g_vm );
701 // free the compiler
702 compiler = NULL; SAFE_DELETE( g_compiler );
704 // wait for the shell, if it is running
705 // does the VM reset its priority to normal before exiting?
706 if( enable_shell )
707 while( g_shell != NULL )
708 usleep(10000);
710 return 0;