propositions.txt 29.8 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796

   
                      Propositions pour l'amélioration d'Anubis. 
   
   
   
   

   *** <DR> réorganisation des librairies et plus de lib </DR>

      <AP> POP3 ? Y a-t-il un volontaire ? </AP> 
   
   
   *** <DR> accès aux lib extérieurs dll avec des appels comme en haskell </DR>

      <AP> Proposer une liste de types de communication Anubis <--> C </AP>
   
   
   
   
   *** <DR> tutoriel comme celui d'haskell de Hal Daumé III </DR>

   
   
   *** <DR> logo original </DR>

   
   
   *** <DR> String unicode </DR>
   
      <AP> Unicode ou  UTF8 ? Il m'avais  semblé qu'on avait plutôt parlé  d'UTF8. On peut
      peut être utiliser les deux suivant les cas. Par exemple, Unicode en interne et UTF8
      dès qu'on sort sur disque ou sur le réseau. 
   
      Par exemple, les fichiers sources Anubis, comment seront-ils lus ? </AP>
   
   
   

   <AP> I have  written here some ideas for  enhancing Anubis 1. I put as  much details as
   possible, but  there is no  warranty that everything  is correct. Everything  should be
   checked from the sources files by anyone making a transformation in the program.

   After just one day of writting in this  file, I realize that Anubis is the result of so
   many successive transformations that it contains  a lot of dead code, dead concepts and
   unnecessary instructions. Because of this it is  far from optimal, and it seems that it
   will probably  be easier  (and safer)  to make a  new system  from scratch  rather than
   correct all defauts of this one. </AP>
   
   
  
   <AP>
   
   *** Removing obsolete things. 
   
   Anubis 1 contains a number of obsolete things:

   
   
      *** (Obsolete 1) Old way of opening files and connections. 
   
   At the beginning of Anubis, a file was opened using the syntactical construct: 
   
      if (Maybe(RAddr(Int8)))connect to file <filename> is 
        {
          ...
        }
   
   which has  been replaced  by the primitive  'file', defined in  'predefined.anubis'. We
   have the same for TCP/IP connections:
   
     if (Result(NetworkConnectError,RWAddr(Int8)))connect to network ip_address:ip_port is 
       {
         ...
       }
   
   which has been replaced by the primitive 'connect'. 
   
   In order to make some cleanup, we must do the following:
   
      - transform 'predefined.anubis' so as to use the new paradigm everywhere. 
      - transform file in the library which are still using the old paradigm. 
      - remove the key locutions 'connect to file' and 'connect to network' from 'lexer.y'. 
   
        at that point test if everything works well. 
   
      - remove the corresponding grammar rules from 'grammar.y'. 
      - remove the corresponding interpretation functions from 'interp.c'.
      - remove the corresponding code generation from 'compile.c'. 
      - remove the obsolete messages from 'msgtext.c'.
      - remove the unnecessary instructions from 'bytecode.h' and 'vminstr.c'.
      - remove the corresponding declarations from 'compil.h'. 
      - remove the corresponding instruction from the virtual machine. 
   
   
   
      *** (Obsolete 2) Removing the concept of (semi)-global variable. 
   
   Anubis 1 has a concept of 'global' variable (almost the same as in C), but which is not
   as 'global' as one may think. Indeed, when a new machine is started (by 'delegate') all
   the global  variables are  duplicated, so  that the variables  in the  old and  the new
   machine are  not the same  ones.  So,  such variables are  not really global,  but only
   global relative  to one machine.  Furthermore,  when the new machine  is started, these
   variables receive  the initial value  as decribed in  the source file, not  the current
   value.
   
   This concept is  clearly obsolete. Dynamic variables are much  better, because they are
   more  flexible,  and  allow the  sharing  of  data  and communication  between  virtual
   machines. Also the semantic is simpler. 
   
   How to remove this  concept ? First of all, it should be removed  from all the files of
   the library.   Everywhere a global variable is  used, we should use  a dynamic variable
   instead. Global variables are declared (defined) by paragraphs beginning by the keyword
   'variable'. Such variables are used in the following library files:
   
     doc_tools/maml.anubis (1 times)
     graphism/image_tools.anubis (many times)
     graphism/lzw_gif.anubis (many times)
     web/cookies.anubis (4 times)
     web/html.anubis (5 times)
     web/http_server.anubis (2 times)
     web/making_a_web_site.anubis (1 time)
     web/multihost_http_server.anubis (3 times)
     web/read_html.anubis (5 times)
     web/to_html.anubis (4 times)
     examples/network/sokoban.anubis (1 time)
   
   A   technique  for   replacing  'global'   variables  by   dynamic  variables   is  the
   following. Define a type of 'objects', with just one alternative and with one component
   for each  variable.  Each component  will be of  type 'Var(...)'. In the  main function
   (the starting  point of the  program using the  variables), create an instance  of this
   object (with the  right initial values).  Then, transmit this  object from functions to
   functions.
   
   Another technique (maybe more subtle) is to  create the dynamic variables, and to do in
   such a way that all functions using these  variables are defined by an arrow '|->' in a
   context where these variables are visible.
   
   Actually,  each situations  needs  probably  a special  decision.  For example,  create
   several objects instead of one, and mix the two methods above.
   
   
   When this is  done, delete the initial keyword 'variable'  (and 'public variable') from
   'lexer.y', and test if everything works well.
   
   After this, we may make some cleanup in the compiler and the virtual machine. 
   
     - in  'grammar.y': remove  the tokens  'yy__variable' and  'yy__p_variable',  and the
   grammar rules  using them. Also  remove the non  terminal 'VarKW' and the  grammar rule
   using them.
   
     - the file 'new_var.c' become entirely obsolete. 
   
     - the messages E001 et E002 disappear. 
   
     - the  primitive  type  'GAddr'   disappears,  together  with  its  internal  version
   'type_GAddr'.  Also  the token  'yy__GAddr' disappears.  This  induces some  cleanup in
   'compil.h', 'compile.c', 'delcode.c',  'grammar.y', 'implem.c', 'lexer.y', 'typedef.c',
   'typetools.c'. 
   
     - the   instructions   'gv_address',   'get_gvv',  'xchg_gvv',   'init_gv,   'del_gv'
   disappear. This will induce much cleanup  in 'output.cpp', because the special code for
   initializing, and deleting global variables will disappear.
   

   
      *** (Obsolete 3) Removing the 'succeeds as' construct. 
   
   There are two syntactical construct:
   
         if x succeeds as y then t
         if y succeeds then t
   
   (where x is of type Maybe(?)), which are just abbreviations for:
   
         if x is 
           {
             failure then failure,
             success(y) then t
           }
   
         if x is 
           {
             failure then failure, 
             success(_) then t
           }
   
   This construct is present  in the following files (where it should  just be replaced by
   its expansion).
   
     tools/maybefloat.anubis
     tools/table.anubis
   
   When  these  easy  corrections are  made,  it  is  just  enough  to remove  the  tokens
   'yy__succeeds'  and   'yy__succeeds_as'  from   'lexer.y'  and  'grammar.y',   and  the
   corresponding grammar rules.
   
   There is another notion which replaces this one. It is the 'Kleisli composition'. It is
   inspired      by      the     monads      of      Haskell,      and     defined      in
   'library/syntactical_analysis/read_grammar.anubis'. It should maybe  be put in some new
   file in 'library/tools/'.
   
   
   

      *** (Obsolete 4) The syntax: checking every ... wait for ...
   
   This special syntax is used for defining the command 'sleep' (in 'tools/basis.anubis'):
   
 public define One
   sleep
     (
       Int32 ms       // number of milliseconds to sleep
     ) =
   checking every ms milliseconds, wait for true then unique. 
   
   If instead 'sleep' is a primitive, we may define:
   
            checking every n milliseconds, wait for t then u
   
   as:
   
            wait(n,(One _) |-> t); u
   
   where 'wait' would be defined as:
   
   define One
     wait
       (
         Int32         cheking_period,
         One -> Bool   test
       ) =
     sleep(checking_period); 
     if test(unique)
     then unique
     else wait(checking_period,test). 
   
   
   Another (maybe  better) solution could  be just to  replace 'checking every ...'   by a
   primitive construct (of type One) like this (where 'test' is of type 'Bool'):
   
       wait_for(n,test)     or      wait_for(test,n)
   
   which executes 'test' every 'n' milliseconds until it becomes 'true'. 
   
   Actually,  the problem  here is  that 'wait_for(n,test)'  cannot be  just  a primitive,
   because if  it is a  primitive, 'test' is  executed only once,  and the result  of this
   execution transmitted to  'wait_for' ('call by value' mechanism).   We need to simulate
   'call by  necessity', by  replacing a test  of type 'Bool'  by a  test of type  'One ->
   Bool', which may be executed as many times as we want.
   
   
   
   
   
   
      *** (Obsolete 5) Local variables. 
   
   This  was an  idea of  the beginning,  but it  has never  be pushed  beyond  the simple
   intention. The idea was similar to:
   
                with x = a, t
   
   except that 'x' would have been a true variable in the sens that commands like 'x <- b'
   would  have been  accepted in  the term  't'.  This is  of course  a non  deterministic
   concept, and it appears after 5 years of use of Anubis that it is of no use.
   
   Nevertheless, this idea leaved  some dead code in the source files  of the compiler and
   of the  virtual machine. The following  instructions should be  removed (from 'vm.cpp',
   'vmtools.cpp', 'bytecode.h'):
   
     new_locvar
     read_locvar
     write_locvar
     
   Warning: the Lisp tag 'local' in the compiler refers to local 'symbols' in the context,
   not to local 'variables', hence should not be removed. 
   
   Actually, local variables if they were to  exist, would be of type 'RWAddr(?)'. This is
   why  instructions  dealing  with  these  types   have  in  general  a  case  for  local
   variables. This case should be removed.
   
   The constant 'conn_local' defined in 'vm.h' is a tag for local variables at run time.
   
   
   
   
   
   
   *** Transforming (fake) structural instruction into system calls.

   This is  an easy  transformation which should  be performed  as soon as  possible.  The
   virtual machine executes 2 kinds of instructions:

     - structural instructions,
     - system calls. 
   
   The   official   list   of   instructions   and   system  calls   may   be   found   in
   'anubis_dev/include/bytecode.h'.
   
   However,  since system  calls have  been introduced  quite late,  there are  still some
   instructions which  should be transformed  into system calls.  They are (at  least) the
   following:
   
     print_string
     print_int32
     connect_file_R
     connect_file_W
     connect_file_RW
     connect_IP_RW
     read_int8
     write_int8
     implode
     explode
     int8_to_int32
     truncate_to_int8
     now
     convert_time_from_int
     convert_time_to_int
     listener
     accept_connection
     listener_shutdown
     listener_is_down
     alt_number_direct
     alt_number_indirect
     do_alert
     create_var
     create_mvar
     get_vv
     xchg_vv
     byte_array_to_ascii
     byte_array_to_string
     dns
     write_file
     read_file
     file_size
     byte_array_length
     sha1_hash
     get_file_mode
     set_file_mode
     xchg_mvv
     get_mvv
    
   This will make some room for new instructions. 
   
   In order to transform such an instruction into a system call, proceed as follows.
   
     - within 'vm.cpp' inhibit the instruction with a:
   
   #define TO_SYSCALL
      ...
   #endif
   
     - In 'bytecode.h' remove the name of the instruction from 'normal_instructions_list',
   and add  it to  'syscall_list'. Of course  'item' must  be changed into  'sc_item'. The
   second  argument of  'sc_item' is  a set  of ORed  flags. These  flags are  prefixed by
   'mf_using_' and defined in 'bytecode.h'. Put them as needed. 
   
     - create a new  case in 'syscall.cpp'. The  code of the instruction may  be copied as
   is, except for the following:
   
        - the syscall instruction has size 3. Hence, it must terminate with:
           
               MAM(m_IP) += 1+2; 
   
          (see the already existing syscalls). 
   
     - remove  the  instruction  from  'vmtools.cpp',  'vminstr.c', and  maybe  also  from
   'compil.h'.
     
     
   
   
   
   *** Introducing an heterogeneous stack.
   
   A big  problem with Anubis 1  is that any datum  occupies always 32 bits  in the stack.
   One consequence is  that when a datum needs  more than 32 bits, it  must be implemented
   indirectly, i.e. using a pointer to an allocated segment.
   
   For Anubis  1, it  is probably  not reasonable to  consider a  completely heterogeneous
   stack, i.e. a stack within which we may push data of any number of bytes. Nevertheless,
   it would be  nice to be able to push  data of 64 bits. This will  allow 'direct' 64 bit
   integers, and allow 'direct' 'IEEE754' numbers.
   
   The virtual machine has two registers:
   
      'R'  (like 'Result')     of 32 bits
      'I'  (like 'Index')      of 8 bits
   
   It would be necessary to extend 'R' to 64 bits. When the result is 32 bits wide, the 32
   highest bits would be just ignored.
  
   However, the (structural) instructions of the  virtual machine are most often using the
   stack. Most  of them should be  adjusted (or maybe  duplicated) so as to  accomodate 64
   bits slots in the stack. On the  contrary, system calls make no problem, except that we
   may have to  invent new system calls for  handling 64 bits direct data.   Below are the
   instructions which  have something to  do with  the stack in  one way or  another. This
   means almost all instructions.

     check_stack
     push
     pop1
     pop2
     pop3
     peek
     micro_peek
     collapse
     glue
     store_0
     store_1
     store_2
     store_4
     unglue
     unstore_0
     unstore_1
     unstore_2
     unstore_4
     unstore_copy
     unstore_copy_mixed
     unstore_copy_ptr
     unstore_copy_function
     push_addr
     apply
     put_copy_direct
     put_micro_copy_direct
     put_copy_indirect
     put_micro_copy_indirect
     put_copy_function
     put_micro_copy_function
     put_copy_mixed
     put_micro_copy_mixed
     ret
     free_seg_1
     free_seg_0
     create_var
     create_mvar
     push_mvar_length
     mvar_slots_del
     mvar_slots_del_var
     mvar_slots_del_mvar
     mvar_slots_del_mixed
     mvar_slots_del_conn
     mvar_slots_del_ptr
     mvar_slots_del_function
     mvar_slots_del_struct_ptr
     free_mvar_seg
     xchg_mvv
     free_var_seg
     get_vv
     get_mvv
     xchg_vv
     remove_monitor
     get_var_monitors
     get_mvar_monitors
     ret_if_zero
     get_var_handler
     get_mvar_handler
     del
     del_mixed
     del_stack
     del_stack_mvar
     del_stack_mixed
     del_stack_ptr
     del_stack_function
     del_stack_struct_ptr
     del_stack_conn
     del_index_direct
     del_index_indirect
     increment_del
     indirect_del
     indirect_del_mvar
     indirect_del_mixed
     indirect_del_ptr
     indirect_del_function
     del_function
     indirect_del_struct_ptr
     indirect_del_conn
     eq
     eq_string
     eq_byte_array
     push_eq_data
     push_before_eq    (this one is dead)
     increment_eq
     jmp_eq_stack
     jmp_neq_1
     jmp_neq_2
     jmp_neq_4 
     jmp_neq_indexes_large
     jmp_neq_indexes_mixed
     jmp_neq_string
     jmp_neq_byte_array
     dec3             (this one is dead)
     start
     copy_stack_ptr
     copy_stack_function
     copy_stack_mixed
     serialize
     unserialize
   
   
   
   
   *** Int32, Int64 and the like. 
   
   I took some time to think about these  types. When someone says (like the Polish guy on
   comp.lang.functional) that  computing 10^10  makes an error,  he is somewhat  right. Of
   course, we could argue  that the computation is made modulo 2^32,  and that the name of
   the type is precisely not 'Int' but 'Int32' meaning that the numbers we are considering
   are integers modulo 2^32.
   
   Ok, but this is  not what users are waiting for. They  want true integers, and consider
   the  computation  modulo 2^32  as  an  overflow not  as  a  normal  computation.  As  a
   consequence, we need  to introduce true natural numbers of arbitrary  size, not only of
   32 or 64 or even 128 bits, but of any number of bits. Such a type (of positive integers
   only) is generally named 'Nat' (for 'Naturals').
   
   Notice that  processors are manipulating fixed size  numbers (of 16, 32  bits or more),
   but actually, theses  data are not numbers.  They are 'bigits'  (a contraction for 'big
   digits').  I  mean that processors are computing  with these bigits exactly  as we, the
   humans,  are computing  with  'decimal digits'.  The  only difference  is  that we  are
   computing in  numeration basis 10, while  processors are computing  in numeration basis
   2^16, 2^32 or more.
   
   As an example,  when we are adding two digits,  say 7 and 4, we  get 11, hence actually
   the digit 1, and a carry of 1.  When we are multiplying two digits, say 6 and 7, we get
   42, hence  two digits, one for the  unities (in this case  2) and one for  the tens (in
   this case  4). When we are dividing  by a digit, we  divide a block of  two digits. For
   example,
   
          45 | 7 
             +---
           3 | 6   
  
   But we never do  that if the divisor is smaller than or equal  to the first digit, like
   in this example:
   
          45 | 2
             +---
           1 | 22
   
   We should have instead divided 4 by 2,  i.e. not considered the last digit 5 in a first
   step. We would have instead divided in two steps:
   
          45 | 2
             +---
          05 | 22
           1 |
   
   This is  how we  compute, and  this is exactly  how processors  also compute,  but with
   bigits  instead  of  digits. For  example,  the  80386  processor (and  its  successors
   likewise) has  an instruction DIV  which divides the  two bigits number EDX:EAX  by the
   bigit (say)  EBX, producing a one  bigit quotient in EAX  and a one  bigit remainder in
   EDX. If EBX is smaller than or equal to EDX, the processor launches an exception.
   
   So, it should be clear that 16 bits, 32 bits or 64 bits words manipulated by processors
   are not numbers,  but bigits.  A number (natural integer of  course) may be represented
   as a  finite sequence of bigits. As  a consequence, processors are  very well designed,
   but programming languages, like C and many others have decided that a number would have
   only one bigit, and consequently that all computations are deliberately false. 
   
   For this reason  the types which are generally called Int16,  Int32, etc... should have
   another  name, or at  least it  should be  made clear  that they  are computing  in the
   strange  (local) quotient  rings Z/(2^32)Z,  etc...  which  are far  from  being fields
   (rings with all non zero elements invertible), and which are even not integral domains,
   since all even numbers are divisors of 0.
   
   Now, we are also very often using these pseudo-numbers for other purposes in which they
   are vector spaces  on the field Z/2Z. This  is the case in cryptography,  where the XOR
   operation is (correctly) identified to the sum in the vector space (Z/2Z)^32. 
   
   We also  use them just as  bit field. This  is the case when  we use the left  or right
   shift  operators, or  when we  are masking  bits using  the bitwise  OR or  the bitwise
   AND. For  example, it  is the case  in several  cryptographic algorithms and  also when
   these pseudo-integers are interpreted as colors in graphical applications. 
   
   Consequently, types like  'Int32' are lumber rooms which are  interpreted (more or less
   consciously)  in several  different ways.  For this  reason, I  think that  these types
   should  at  least be  cloned  in  several versions  with  appropriate  names, and  only
   the meaningful operations for each clone (and maybe conversions between these clones). 

   
   How to implement 'Nat' ? We have at least the choice between:
   
      - 'Nat' is a primitive type, 
      - Introduce primitive types for bigits, and defined 'Nat' using them. 

   For example, addition (of bigits) should be typed as follows: 
   
   define (Bit,Bigit32) Bigit32 x + Bigit32 y. 
   
   where  the result  is a  pair made  of the  resulting carry  and bigit.  Similarly, the
   multiplication should be typed as follows:
   
   define (Bigit32,Bigit32) Bigit32 x * Bigit32 y. 
   
   producing two bigits for the multiplication of two bigits. This is nothing else than an
   implementation of the 'table of multiplication'  for bigits, analogous to the 'table of
   multiplication' for digits:
   
                  0    1    2    3    4    5    6    7    8    9
            ---+----+----+----+----+----+----+----+----+----+----+
             0 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 |
            ---+----+----+----+----+----+----+----+----+----+----+
             1 | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 |
            ---+----+----+----+----+----+----+----+----+----+----+
             2 | 00 | 02 | 04 | 06 | 08 | 10 | 12 | 14 | 16 | 18 |
            ---+----+----+----+----+----+----+----+----+----+----+
             3 | 00 | 03 | 06 | 09 | 12 | 15 | 18 | 21 | 24 | 27 |
            ---+----+----+----+----+----+----+----+----+----+----+
             4 | 00 | 04 | 08 | 12 | 16 | 20 | 24 | 28 | 32 | 36 |
            ---+----+----+----+----+----+----+----+----+----+----+
             5 | 00 | 05 | 10 | 15 | 20 | 25 | 30 | 35 | 40 | 45 |
            ---+----+----+----+----+----+----+----+----+----+----+
             6 | 00 | 06 | 12 | 18 | 24 | 30 | 36 | 42 | 48 | 54 |
            ---+----+----+----+----+----+----+----+----+----+----+
             7 | 00 | 07 | 14 | 21 | 28 | 35 | 42 | 49 | 56 | 63 |
            ---+----+----+----+----+----+----+----+----+----+----+
             8 | 00 | 08 | 16 | 24 | 32 | 40 | 48 | 56 | 64 | 72 |
            ---+----+----+----+----+----+----+----+----+----+----+
             9 | 00 | 09 | 18 | 27 | 36 | 45 | 54 | 63 | 72 | 81 |
            ---+----+----+----+----+----+----+----+----+----+----+
   
   (Notice that I put two digits in each box.) 
   
   and of course the division should be typed: 
   
   define Maybe((Bigit32 quotient, Bigit32 remainder)) 
      (Bigit32,Bigit32) x / Bigit32 y. 
   
   where the result is 'failure' when 'y' is smaller than the high order bigit of 'x'.
   
   Now the type of natural integers could (maybe) be defined as follows:
   
   type Nat:
      zero
      non_zero(Bigit32 first_bigit, Nat other_bigits). 
   
   However, it  does not work  because the  first bigit should  never be 0,  otherwise the
   representation  is not  one to  one.  Hence,  the 'true'  type of  natural  integers is
   actually a quotient of this one, which just means that this is the right type, but that
   equality for this type has to be defined in a special way. 
   
   For the  time being, the Anubis  compiler produces an  equality code for each  type. In
   order to make 'Nat'  as defined above a 'true' type of  natural integers, we would have
   to redefine this equality. 
   
   Well, this is maybe not the right  thing to do. It's probably better to implement 'Nat'
   directly as  a primitive  type. Of  course, this means  that we  need to  write several
   operations in assembly, because C does  not give enough access to the processor (carry,
   etc...).
   
   
   
   *** IEEE754 floating point numbers. 
   
   The current implementation of the type 'Float' is inefficient for two main reasons:
   
     - since a 'Float' occupies 64 bits, it is implemented as a pointer to a segment of 12
   bytes. The first 4 bytes contain the  counter for the garbage-collector, and the next 8
   bytes  contain the  'double  precision' floating  point  number as  represented by  the
   processor.
   
     - The  current  implementation  does  not   take  into  account  the  fact  that  the
   representation of an  IEEE754 floating point number includes special  cases for too big
   or too small numbers.  As a consequence, we have (for example) the following definition
   in 'predefined.anubis':
   
 public define Maybe(Float)    Float x + Float y             = £avm{ float_plus }.
   
   which could have been:
   
 public define       Float     Float x + Float y             = £avm{ float_plus }.
   
   if this fact was taken into consideration. 
   
   The  result of this  is that  we are  always computing  with 'Maybe(Float)'  instead of
   'Float', and that this makes a  double indirection in the implementation. The result is
   that computations are very slow, as shown by the Mandelbrot program.
   
   
   For these reasons, it would be nice  to create another new primitive type: 'IEEE754'. A
   datum of this type should be implemented directly (no indirection) as a 64 bits word.

   We could have several primitive predicates for testing an IEEE754 number:
   
 define Bool is_too_big(IEEE754 x).          // 'infinity'
 define Bool is_too_small(IEEE754 x).        // 'denormal'
 define Bool is_not_a_number(IEEE754 x).     
   etc... (according to the IEEE754 specification)
   
   We could also have a type like this one:
   
 type IEEE754_Sort:
    too_big,
    too_small,
    normal,
    not_a_number.
   
   and a primitive predicate:
   
 define IEEE754_Sort sort(IEEE754 x). 
   
   
   
   
   
   
     
   *** What for the future ? 
   
   
      *** Working only on top of stack. 
   
   Designing the virtual  machine with a register ('R') for holding  the results of pieces
   of  code was a  bad idea.  It would  certainly be  better to  work only  on top  of the
   stack. There are several reasons for that:
   
     - In most cases, just after a datum has  been computed and put in 'R' it is pushed on
   the stack (you will be easily convinced of that after a look at a .sc file).
   
     - Working on the stack  only is more symmetric in the sens  that as well as functions
   may take  several arguments, they could return  several results instead of  just one. A
   good  example  is  the euclidian  division.  For  the  time  being,  it is  defined  in
   'basis.anubis' as follows:
   
public define (Int32,        // quotient
               Int32)        // remainder
   euclid
     (
       Int32 a,       // divide 'a' by 'b'
       Int32 b 
     ) =
   ...
   
   i.e. it takes two integers as arguments  and returns two integers. The type 'Int32' has
   a 'direct'  implementation, while  '(Int32,Int32)' is  indirect (it is  a pointer  to a
   segment of 12 bytes: counter, first integer, second integer). This segment is allocated
   for  each division.   If all  the computations  were  done on  the stack,  it would  be
   possible to  construct the resulting  pair '(quotient,remainder)' on the  stack without
   allocating any segment.
   
   Of course, this symmetry is very 'categorical'. In a cartesian category, we have arrows
   like:
   
                               A x B x C   --------->  D x E
   
   for  example, which  may  represent a  function  taking 3  arguments,  and returning  2
   results. Notice that 'Common Lisp' has this notion of multiple return values. Anyway, I
   don't want to mimic Common Lisp whose design is, to my opinion, one of the worst things
   ever conceived, an horrible denaturation of the original Lisp language.
   
   When we have a tuple to implement, we have two possibilities, even if all components of
   the tuple have a direct implementation.
   
     1. We can implement the tuple directly.  This means that if the tuple (say '(a,b,c)')
   is supposed to be  at position 'p' in the stack, 'a' will be  at position 'p', 'b' will
   be at position 'p+size(a)', and 'c' at position 'p+size(a)+size(b)'. 
   
     2. we can implement the tuple indirectly. This means that if the tuple is supposed to
   be at  position 'p'  in the  stack, we  have a pointer  at position  'p', and  the data
   representing 'a', 'b' and 'c' are in the segment pointed to by this pointer.
   
   These  two methods  are just  two  ways of  implementing categorical  products. From  a
   categorical viewpoint this means that in a cartesian category we may have two 'product'
   functors. Of  course, these  two functors are  naturally isomorphic. In  practice, this
   means that  a datum represented using  the first method  may be converted into  a datum
   represented using the second method, and conversely, without loosing information.
   
   This also means that the two methods can be used together in the same program. We could
   for example  use the first  one for  anonymous products, and  the second one  for named
   products. We could also  use the first one for products whose bit  width is not too big
   (for  example not bigger  than 128  bits or  256 bits)  and the  second one  for bigger
   products.
   
   
   </AP> 
   
   
   *** <DR> meilleur support de SQLite3 (type de colonnes, etc...) </DR>

   *** <DR> désallocation de la mémoire. </DR>
   
   *** <CR> Simplification de la grammaire Anubis:
   
              - Suppression du mot clé 'operation' de la grammaire ('define' suffit)
              - ne plus avoir la possibilité de mettre des majuscules à certains mots clé 
                (Read / read, Define / define, ...)
              - Obliger à délimiter les commentaires par des marqueurs (sinon, le parsing du code 
                est un vrai casse-tête)
              - suppression de la grammaire Anubis 2
              
   *** <CR> Amélioration de la grammaire Anubis:
              - Ajout de guillemets encadrant le chemin du 'read' afin de gerer les chemins
                contenant des espaces