Lhogho  0.0.028
 All Data Structures Files Functions Variables Typedefs Macros Pages
compiler.h File Reference

Go to the source code of this file.

Data Structures

struct  ctxnode
 

Macros

#define COMPILE_AS_FUNC   0
 compile and check result to be non-unbound More...
 
#define COMPILE_AS_PROC   1
 compile and check result to be unbound More...
 
#define COMPILE_AS_UNKNOWN   2
 compile and accept any result More...
 
#define COMPILE_AS_NON_MACRO   0
 The COMPILE_AS_*_MACRO are independent on the other COMPILE_AS_* symbols. More...
 
#define COMPILE_AS_MACRO   1
 compile a function as a macro More...
 
#define MAGIC_NUMBER   1980069381
 code for standard standalone executables More...
 
#define MAGIC_COMPILER_NUMBER   1761700097
 code for custom Lhogho compilers More...
 

Typedefs

typedef struct ctxnode context_t
 structure holding compilation context More...
 

Functions

void init_compiler (outter_t outter, inner_t inner, inner_eof_t inner_eof)
 initializes the compiler More...
 
void finit_compiler ()
 finalizes the compiler More...
 
int compile_from_options ()
 compiles according to options More...
 
atom_t compile_to_file ()
 compiles into executable file More...
 
atom_t compile_function (atom_t func, int mode, int is_macro)
 compiles a function More...
 
atom_t compile_external_function (atom_t func)
 compiles an external function More...
 
atom_t compile_internal_function (atom_t func, int static_link)
 compiles an internal function More...
 
int run_source (chars_t source)
 compiles and runs source code More...
 
int run_function (atom_t function)
 runs the compiled code of a function More...
 

Variables

int running_compiled_code
 indicate whether generated code is currently running More...
 
int compiling_code
 indicate whether source code is currently compiling More...
 

Macro Definition Documentation

#define COMPILE_AS_FUNC   0

Definition at line 47 of file compiler.h.

#define COMPILE_AS_PROC   1

Definition at line 48 of file compiler.h.

#define COMPILE_AS_UNKNOWN   2

Definition at line 49 of file compiler.h.

#define COMPILE_AS_NON_MACRO   0

compile a function as a function

Definition at line 53 of file compiler.h.

#define COMPILE_AS_MACRO   1

Definition at line 54 of file compiler.h.

#define MAGIC_NUMBER   1980069381

Definition at line 60 of file compiler.h.

#define MAGIC_COMPILER_NUMBER   1761700097

Definition at line 61 of file compiler.h.

Typedef Documentation

typedef struct ctxnode context_t

Function Documentation

void init_compiler ( outter_t  outter,
inner_t  inner,
inner_eof_t  inner_eof 
)
Parameters
outteroutter function to use by dump and dumpln
innerinner function to use for text input
inner_eofinner_eof function to test eof of text input

Initializes the compiler and all other modules

Definition at line 169 of file compiler.c.

170 {
171  //2011.02.09 Now output to console is always through UTF-8 (see lhogho.c)
172  //#ifdef UNICODE_CHARS
173  //fwide(stdout,1);
174  //#else
175  //fwide(stdout,-1);
176  //#endif
177 
179  compiling_code = 0;
180 
181  init_output( outter );
183  init_atoms();
184  init_parser();
185  init_vars();
186  init_runtime();
187  init_options( );
188  init_errors( );
189 
190  //printf("testing barrization\n");
191  //char_t i;
192  //printf("a->|a|\t|a|->a\n");
193  //for(i=0;i<128;i++) if( (i!=ENBAR(i)) || (i!=DEBAR(i)) )
194  // {
195  // if(i!=ENBAR(i))
196  // printf("%d->%d",i,ENBAR(i));
197  // else printf("\t");
198  //
199  // if(i!=DEBAR(i))
200  // printf("\t%d->%d",i,DEBAR(i));
201  // printf("\n");
202  // }
203 }
void finit_compiler ( )

Finalizes all modules of the compiler.

Definition at line 214 of file compiler.c.

215 {
217  {
218  outter( TEXT("Variables:\n\0"), UNKNOWN );
219  dumpln( root );
220  //outter( TEXT("\n\0"), UNKNOWN );
221  }
223  finit_errors();
224  finit_runtime();
225  finit_vars();
226  finit_options();
227  finit_atoms();
228 }
int compile_from_options ( )
Returns
0 if there was no error

Compiles according to the compiler's options. In case of error dumps the error message and returns non-zero value.

Definition at line 242 of file compiler.c.

243 {
244  //printf("enter compile()\n");
245  //printf("##### path=|%s|#######\n",getcwd (NULL,0));
246  //printf("enter compile()\n");
247  //printf("##### path=|%s|#######\n",getcwd (NULL,0));
248 
249  atom_t x;
250  atom_t sources = empty_list;
251 
252  // load comman-line source
254  {
256  if( IS_ERROR(x) )
257  {
258  dumpln(x);
259  return 1;
260  }
261  atom_t y = trim_shell_comment( x );
262  DEUSE( x );
263  sources = new_list( y, sources );
264  }
265 
266  // load embedded sources
267  int ptr;
268  unsigned char* code = load_file( option_compiler_filename_chars, &ptr );
269  if( !code )
270  {
272  dumpln( error );
273  return 0;
274  }
275 
276  // check for magic number
277  while( (*(int*)(code+ptr-4)==MAGIC_NUMBER) || (*(int*)(code+ptr-4)==MAGIC_COMPILER_NUMBER))
278  {
279  int size = *(int*)(code+ptr-8);
280  ptr -= size+8;
281  x = decode_word(code+ptr,size,0);
282  atom_t y = trim_shell_comment( x );
283  DEUSE( x );
284  sources = new_list( y, sources );
285  }
286 
287  DEALLOC( code );
288 
289  // if there is any source then read it and compile it
290  if( IS_EMPTY(sources) )
291  {
293  return 0;
294  }
295 
296  compiling_code = 1;
297  FULLSOURCE(root) = ( sources ); // already used once
298  SOURCE(root) = USE( sources );
300  if( IS_ERROR(x) )
301  {
302  dumpln(x);
303  //DEUSE(x);
305  compiling_code=0;
306  return 1;
307  }
308  compiling_code = 0;
309 
310 
311  // now the sources is confirmed to be compilable
312  // now check whether an executable file must be created
314  {
315  x = compile_to_file( );
316  if( IS_ERROR(x) ) { dumpln(x); DEUSE(x); return 1; }
317  }
318  return 0;
319 }
atom_t compile_to_file ( )

Compiles current source into executable file. The name of the file is based on the name of the external source. EXE extension is used for Windows systems. For Linux no extension is used. The generated file has read-write-execute user permisions.

If the option_make_executable_compiler is set, then the compiled file acts like a compiler in respect to its inputs.

If the option_make_executable is set, then the compiled file acts as a standalone file and does not use any of the Lhogho options.

Definition at line 341 of file compiler.c.

342 {
343  FILE* infile;
344  FILE* outfile;
345 
346  // compose the output name
347  char* output_filename;
348  chars_t output_filename_chars;
349 
350  {
351  // [1] use the original source name
352  // [2] remove trailing extension (as defined in source_extensions)
353  // if extension is different, do not remove anything
354  // [3] append the executable extension (as defined in EXE_EXT)
355  output_filename = (char*)ALLOC( strlen(option_source_filename)+strlen(EXE_EXT)+100 );
356  strcpy( output_filename, option_source_filename );
357 
358  char* extension = output_filename+strlen(output_filename);
359 
360  // remove any source extension
361  int i;
362  int done = 0;
363  for( i=0; i<SRC_EXT_COUNT; i++)
364  {
365  if( strcasecmp(extension-strlen(SRC_EXT),SRC_EXT)==0 )
366  {
367  strcpy( extension-strlen(SRC_EXT), EXE_EXT );
368  done = 1;
369  break;
370  }
371  }
372 
373  // add executable extension if not done already
374  if( !done )
375  {
376  #ifdef SAFEMODE
377  assert( strlen(EXE_EXT2)!=0 );
378  #endif
379 
380  if( strlen(EXE_EXT)==0 )
381  strcpy( extension, EXE_EXT2 );
382  else
383  strcpy( extension, EXE_EXT );
384  }
385 
386  output_filename_chars = UNFILENAME( output_filename );
387 
388  outfile = fopen( output_filename, "wb" );
389  if( errno ) return new_os_error( output_filename_chars );
390  }
391 
392  #define BUF_SIZE 1024
393  char* buffer[BUF_SIZE];
394  int size;
395 
396  // copy compiler into output file
397  infile = fopen( option_compiler_filename, "rb" );
398  if( errno ) return new_os_error( option_compiler_filename_chars );
399 
400  while( (size = fread( buffer, 1, BUF_SIZE, infile )) )
401  {
402  if( errno ) return new_os_error( option_compiler_filename_chars );
403 
404  fwrite( buffer, 1, size, outfile );
405  if( errno ) return new_os_error( output_filename_chars );
406  }
407  fclose( infile );
408  if( errno ) return new_os_error( option_compiler_filename_chars );
409 
410  // copy source into output file
411  int source_size = 0;
412  infile = fopen( option_source_filename, "rb" );
413  if( errno ) return new_os_error( option_source_filename_chars );
414 
415  while( (size = fread( buffer, 1, BUF_SIZE, infile )) )
416  {
417  if( errno ) return new_os_error( option_source_filename_chars );
418 
419  source_size += size;
420  fwrite( buffer, 1, size, outfile );
421  if( errno ) return new_os_error( output_filename_chars );
422  }
423  fclose( infile );
424  if( errno ) return new_os_error( option_source_filename_chars );
425 
426  // write source size
427  fwrite( &source_size, 1, 4, outfile );
428  if( errno ) return new_os_error( output_filename_chars );
429 
430  // write magic data
432  fwrite( &size, 1, 4, outfile );
433  if( errno ) return new_os_error( output_filename_chars );
434 
435  fclose( outfile );
436  if( errno ) return new_os_error( output_filename_chars );
437 
438  chmod( output_filename, S_IRWXU );
439  if( errno ) return new_os_error( output_filename_chars );
440 
441  DEALLOC( output_filename );
442 
443  return empty_list;
444 }
atom_t compile_function ( atom_t  func,
int  mode,
int  is_macro 
)
Parameters
funcfunction to compile
modecompilation mode (COMPILE_AS_ macros)
is_macromacro mode
Returns
empty list or error atom

Compiles the body of a function. If the function is not parsed or a syntax tree is not generated then parse and treeify it first.

If is_macro is false, then the epilogue of the function releases all local variables - created at compile or at runtime.

If is_macro is true, then the epilogue of the function calls a function to process the locals. This function would typically save the locals in the parent variable.

Definition at line 608 of file compiler.c.

609 {
610  #ifdef DEBUG_COMPILE
611  printf("<COMPILE> Compile "); dump(NAME(func));
612  if( mode==COMPILE_AS_PROC ) printf(" as procedure\n");
613  if( mode==COMPILE_AS_FUNC ) printf(" as function\n");
614  if( mode==COMPILE_AS_UNKNOWN ) printf(" as unknown\n");
615  #endif
616 
617  need_descr2( func );
618 
619  atom_t x;
620  atom_t y;
621  // if there is not syntax tree of the function
622  // then parse and treeify it first
623  if( IS_EMPTY(TREE(func)) )
624  {
625  y = build_syntax_tree( func );
626  if( IS_ERROR(y) ) return y;
627  }
628 
629  #ifdef DEBUG_COMPILE
630  printf("<COMPILE> Syntax tree built\n");
631  #endif
632 
633  context_t ctx;
634  ctx.size = 0;
635  ctx.generate = NULL;
636  ctx.parent = func;
637  ctx.exit_addr = 0;
638  //printf("SET0 ExAd=%d\n",ctx.exit_addr);
639 
640  // set offset of local variables
641  int offset = BASE_OFFSET_LOCALS-4; // this is the start offset
642  for( x = LOCALS(func); IS_NOT_EMPTY(x); x=CDR(x) )
643  if( IS_VARIABLE(CAR(x)) && OFFSET(CAR(x))==0 && IS_NORMAL(CAR(x)) )
644  {
645  //printf("set offset of "); dump(NAME(CAR(x)));
646  //printf(" to be %d\n",offset);
647  OFFSET(CAR(x)) = offset;
648  offset -= sizeof( atom_t );
649  }
650 
651  #ifdef DEBUG_COMPILE
652  printf("<COMPILE> Pass 1\n");
653  #endif
654 
655  //------------------------------
656  // calculate size of to-be-generated code
657  asm_prologue( &ctx, func, 1 );
658 
659  if( IS_EMPTY(TREE(func)) )
660  asm_empty_body( &ctx );
661  else
662  {
664  y = compile_block( &ctx, TREE(func), mode );
665  if( mode==COMPILE_AS_FUNC )
666  {
667  asm_output( &ctx, TREE(func), 0 ); // simulate OUTPUT
668  }
669  if( IS_ERROR(y) ) return y;
670  }
671  asm_preepilogue( &ctx );
672  ctx.exit_addr = ctx.size;
673  asm_epilogue( &ctx, func, is_macro );
674 
675  #ifdef DEBUG_COMPILE
676  printf("<COMPILE> Pass 1 done!\n");
677  printf("<COMPILE> Code size=%d\n\n",ctx.size);
678  printf("<COMPILE> Pass 2\n");
679  #endif
680 
681  //-----------------------------
682  // allocate memory for code
683  ctx.generate = new_mem( ctx.size );
684  ctx.size = 0;
685  //printf("old exit addr=%8x\n",ctx.exit_addr);
686  ctx.exit_addr = (int)MEMORY(ctx.generate)+ctx.exit_addr;
687  //printf("new base addr=%8x\n",(int)MEMORY(ctx.generate));
688  //printf("new exit addr=%8x\n",ctx.exit_addr);
689 
690 
691  //---------------------------------
692  // generate code for the body of the function
693  asm_prologue( &ctx, func, 1 );
694  if( IS_EMPTY(TREE(func)) )
695  asm_empty_body( &ctx );
696  else
697  {
698  y = compile_block( &ctx, TREE(func), mode );
699  if( mode==COMPILE_AS_FUNC ) asm_output( &ctx, TREE(func), 0 ); // simulate OUTPUT
700  if( IS_ERROR(y) )
701  {
702  DEUSE( ctx.generate );
703  return y;
704  }
705  }
706 
707  asm_preepilogue( &ctx );
708  asm_epilogue( &ctx, func, is_macro );
709 
710  #ifdef DEBUG_COMPILE
711  printf("<COMPILE> Pass 2 done!\n");
712  #endif
713 
714 
715  BINARY(func) = ctx.generate;
716  ADDRESS(func) = (int)MEMORY(BINARY(func));
717 
718  //dumpln( root );
719 
720  // generate code for local functions
721  for( x = LOCALS(func); IS_NOT_EMPTY(x); x=CDR(x) )
722  if( !IS_VARIABLE(CAR(x)) &&
723  !IS_PRIMITIVE(CAR(x)) &&
724  !IS_TAG(CAR(x)) )
725  {
727  if( IS_ERROR(y) ) return y;
728  }
729 
730  return empty_list;
731 }
atom_t compile_external_function ( atom_t  func)
Parameters
funcfunction to compile
Returns
empty list or error atom

Compiles the trampoline of an external function.

Definition at line 744 of file compiler.c.

745 {
746  #ifdef DEBUG_COMPILE
747  printf("<COMPILE> Re-compile external "); dump(NAME(func));
748  #endif
749 
750 #ifdef SAFE_MODE
751  assert( IS_EXTERNAL(func) );
752 #endif
753 
754  context_t ctx;
755  ctx.size = 0;
756  ctx.generate = NULL;
757  ctx.parent = func;
758  ctx.exit_addr = 0;
759 
760  #ifdef DEBUG_COMPILE
761  printf("<COMPILE> Pass 1\n");
762  #endif
763 
764  //------------------------------
765  // calculate size of to-be-generated code
766  asm_external_function( &ctx, func );
767 
768  //ctx.exit_addr = ctx.size;
769 
770  #ifdef DEBUG_COMPILE
771  printf("<COMPILE> Pass 1 done!\n");
772  printf("<COMPILE> Code size=%d\n\n",ctx.size);
773  printf("<COMPILE> Pass 2\n");
774  #endif
775 
776  //-----------------------------
777  // allocate memory for code
778  ctx.generate = new_mem( ctx.size );
779  ctx.size = 0;
780 
781 
782  //---------------------------------
783  // generate code for the body of the function
784  asm_external_function( &ctx, func );
785 
786  #ifdef DEBUG_COMPILE
787  printf("<COMPILE> Pass 2 done!\n");
788  #endif
789 
790 
791  DEUSE(BINARY(func));
792  BINARY(func) = ctx.generate;
793  ADDRESS(func) = (int)MEMORY(BINARY(func));
794 
795  return empty_list;
796 }
atom_t compile_internal_function ( atom_t  func,
int  static_link 
)
Parameters
funcfunction to compile
static_linkstatic link from the current frame
Returns
empty list or error atom

Compiles the trampoline of an internal function.

Definition at line 810 of file compiler.c.

811 {
812  #ifdef DEBUG_COMPILE
813  printf("<COMPILE> Re-compile internal "); dump(NAME(func));
814  #endif
815 
816 #ifdef SAFE_MODE
817  assert( IS_INTERNAL(func) );
818 #endif
819 
820  context_t ctx;
821  ctx.size = 0;
822  ctx.generate = NULL;
823  ctx.parent = func;
824  ctx.exit_addr = 0;
825 
826  #ifdef DEBUG_COMPILE
827  printf("<COMPILE> Pass 1\n");
828  #endif
829 
830  //------------------------------
831  // calculate size of to-be-generated code
832  asm_internal_function( &ctx, static_link, func );
833 
834  //ctx.exit_addr = ctx.size;
835 
836  #ifdef DEBUG_COMPILE
837  printf("<COMPILE> Pass 1 done!\n");
838  printf("<COMPILE> Code size=%d\n\n",ctx.size);
839  printf("<COMPILE> Pass 2\n");
840  #endif
841 
842  //-----------------------------
843  // allocate memory for code
844  ctx.generate = new_mem( ctx.size );
845  ctx.size = 0;
846 
847 
848  //---------------------------------
849  // generate code for the body of the function
850  asm_internal_function( &ctx, static_link, func );
851  #ifdef DEBUG_COMPILE
852  printf("<COMPILE> Pass 2 done!\n");
853  #endif
854 
855 
856  // The address of the function should point to the
857  // newly created trampoline. The memory link should
858  // contain atoms that must be freed when the function
859  // is freed, namely:
860  // - the original memory atom
861  // - the new memory atom
862  // The old memoty atom is needed, because it points
863  // to the old code of the Lhogho function which is
864  // actually used by the new code.
865  BINARY(func) = new_list(ctx.generate,new_list(BINARY(func),empty_list));
866  ADDRESS(func) = (int)MEMORY(ctx.generate);
867 
868  return empty_list;
869 }
int run_source ( chars_t  source)
Returns
0 or exit_code

Compiles source code as if it is the main program. No variables are cleared before or after the compilation. Then runs the compiled code.

Definition at line 550 of file compiler.c.

551 {
552  int exit_code;
553 
554  compiling_code = 1;
555  atom_t x = new_word( source, -1 );
556  atom_t y = trim_shell_comment( x );
557 
558  DEUSE( x );
559  DEUSE( BODY(root) ); BODY(root) = empty_list;
560  DEUSE( TREE(root) ); TREE(root) = empty_list;
564 
565  FULLSOURCE(root) = ( y ); // already used once
566  SOURCE(root) = USE( y );
568  if( IS_ERROR(x) )
569  {
570  exit_code = ERRCODE(x);
571  DEUSE( x );
572  compiling_code = 0;
573  }
574  else
575  {
576  compiling_code = 0;
577  exit_code = run_function(root);
578  //exit_code = 0;
579  }
580 
581  return exit_code;
582 }
int run_function ( atom_t  function)
Returns
exit code (0 if no error)

Runs the compiled code of a function. Assumes the function is already compiled without error. If error occurs during execution the error is dumped on the output stream and its code is returned.

Definition at line 480 of file compiler.c.

481 {
482  #ifdef SAFE_MODE
483  assert( ADDRESS(function) );
484  #endif
485 
486  typedef atom_t(*user_code_t)(); // Lhogho-compiled user code
487 
488  user_code_t func = (user_code_t)ADDRESS(function);
489 
490  //int x;
491  //printf("bin adr=%x\n",(int)func);
492  //for( x=0; x<128; x++ )
493  // {
494  // if( x % 16 ) printf(","); else printf("\n\tdb\t");
495  // printf("$%x", *(((unsigned char*)func)+x));
496  // }
497  //printf("\n");
498  //printf("start executing\n");
499 
500  //printf("******BEFORE******\n");
501  //dump_statistics();
502 
504  atom_t result = func();
506 
507  //printf("******AFTER******\n");
508  //dump_statistics();
509 
510  //printf("result=%x\n",(int)result);
511  //printf("ref=%d\n",REF(result));
512  //printf("result(ref=%d)=",REF(result)); dumpln(result);
513 
514  //printf("before error rootdef="); dump_atom(DEFINITIONS(root),1); printf("\n");
515  //printf("before error rootdef="); dump_atom(TREE(root),1); printf("\n");
516  if( IS_ERROR(result) )
517  {
518  int exit_code = 0;
519  if( ERRCODE(result)!= EXIT_BY_BYE &&
520  ERRCODE(result)!= EXIT_BY_THROW_TOPLEVEL &&
521  ERRCODE(result)!= EXIT_BY_THROW_SYSTEM )
522  {
523  dumpln( result );
524  exit_code = ERRCODE(result);
525  }
526  DEUSE(last_error);
529  return exit_code;
530  }
531  else
532  {
533  DEUSE( result );
534  return 0;
535  }
536 }

Variable Documentation

int running_compiled_code

Definition at line 138 of file compiler.c.

int compiling_code

Definition at line 139 of file compiler.c.


[ HOME | INDEX | ATOMS | VARS | REFERENCE ]
Lhogho Developer's Documentation
Wed Jul 10 2013