⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mc.doc

📁 c语言的小编译器,学习的好东东.
💻 DOC
📖 第 1 页 / 共 5 页
字号:
        (# bytes pushed at entry of function to preserve registers etc.)
                                       +
                 (Size of return address on stack (usually 2))
    
                                    -- OR --
    
                           (accumulator contents) * 2
                                       +
                                "stack pointer"
                                       +
                   (# bytes pushed during function execution)
                                       +
                     (size of all local variables in bytes)
                                       +
        (# bytes pushed at entry of function to preserve registers etc.)
                                       +
                 (Size of return address on stack (usually 2))
    
             Global  variables  exist  at  absolute  addresses  and  may  be
          referenced directly by name from within assembler  programs.  Keep
          in mind however, that MICRO-C uses only the first 15 characters of
          a symbol's name. Also, many code generators will reduce  the  size
          of names even further, often using an algorithm  to  compress  the
          name rather than simply truncating it. For this reason,  it  is  a
          good idea to avoid using global symbol names which are longer than
          6 or 8 characters  if  they  are  to  be  referenced  from  within
          assembly language programs.
    MICRO-C                                                          Page: 24


       3.3 Compiling for ROM
    
             Assuming the code generator does not use such "nasty" things as
          self modifying code, the output  from  the  compiler  is  entirely
          "clean", and may be placed in Read Only Memory (ROM).
    
             The compiler places all initialized  global  variables  in  the
          output file as part of the code image. When the program is  stored
          in ROM, those variables are also stored in ROM, and  will  not  be
          modifiable.
    
             When the program is to be placed in ROM, you may not initialize
          any variables which you intend to modify  later.  Those  variables
          must be explicitly initialized by code executed at  the  beginning
          of the program.
    
             Initialized variables which you do not intend to  modify  (such
          as tables etc.) may be initialized in the declaration, and will be
          permanently saved in the ROM as part of the static code image.
    
             The  processor  stack  pointer  must  be  set  up  before   any
          expressions are evaluated, or any function  calls  are  performed.
          This may be performed via '#asm' statements.
    
             All non-initialized global variables must be  located  in  RAM.
          The compiler usually outputs all such variables at the very end of
          the compilation, just after dumping the literal pool.  The  global
          variables may be moved to RAM by  editing  the  output  file,  and
          placing an appropriate "ORG" statement at  the  beginning  of  the
          globals.
    
             If extensive compilation for ROM is being  performed,  you  may
          want to use a version of the compiler which uses  an  intermediate
          output file (see "PORTING THE COMPILER"). This allows  a  separate
          code generator to be customized for ROM applications,  which  will
          output the appropriate stack setup instructions (this can be  done
          in "def_module()"), and locate the global variables in  RAM  (this
          can be done at the end of "def_literal()").
    MICRO-C                                                          Page: 25


    4. PORTING THE COMPILER
    
          There are two major goals to accomplish when porting  the  MICRO-C
       compiler to a new machine. The first is to make the compiler  run  in
       the new environment, and the second is to make it  produce  code  for
       that environment.
    
          These two goals do not always go hand in hand. For example, it may
       be desirable to implement a CROSS COMPILER which generates code for a
       different system from that on which it runs.
    
          The usual method of porting a compiler to system A when a  version
       of the compiler is already running on system B, is to first create  a
       compiler which runs on system B, producing code for  system  A.  This
       "new" compiler may then be used to create a compiler  which  runs  on
       system A.
    
          The compiler consists of a module "compile"  which  contains,  the
       main compiler, input scanner, regular expression parser,  and  symbol
       table management routines.  This  is  the  "static"  portion  of  the
       compiler which does not change in different implementations.
    
          To create a working compiler, the above module  must  be  compiled
       and linked with an "io" module and "code"  module.  The  "io"  module
       performs the necessary initialization and I/O to allow  the  compiler
       to run in a particular  environment  (goal  #1).  The  "code"  module
       generates  the  assembly  language  output  code  for  a   particular
       environment (goal #2).
    
          The compiler uses NO system library functions, and  relies  on  NO
       system services (other  than  those  used  by  the  "io"  and  "code"
       modules). This allows the compiler to  be  ported  to  virtually  any
       system.
    
          All fixed compiler  parameters  (such  as  table  sizes  etc)  are
       contained in the header file "compile.h".  When  porting  to  systems
       with very limited RAM (less than 64k), you may have to reduce some of
       these sizes in order to get it to fit.
    
          Two additional modules are provided with the  compiler.  The  file
       "intercg.c", may be linked into the compiler in  place  of  the  code
       generator, and writes a "generic" intermediate  file  which  contains
       the pseudo operation and type tokens (See Code Generator).  The  file
       "genasm.c", may be linked with the regular "io" and  "code"  routines
       to produce a utility program which reads the  intermediate  file  and
       produces the assembly language code for a specific processor.
    
          NOTE: If your system makes a distinction between TEXT  and  BINARY
       files, the "io.c" routines must be modified for each program so  that
       the intermediate file will be accessed  in  BINARY  mode.  All  other
       files are accessed as TEXT.
    MICRO-C                                                          Page: 26


          Although this "split" compiling approach is slower than the  usual
       mode of direct assembly  language  production,  it  provides  several
       useful capabilities:
    
       1) The amount of ram required to  run  the  "separate"  compiler  and
          genasm programs can be considerably less than required to run  the
          "stand alone" compiler.
    
       2) A single parser may be used to generate code  for  several  target
          systems, by simply running a different  version  of  the  "genasm"
          utility, which is customized for each target.
    
       3) Use of the intermediate file  allows  distribution  of  "portable"
          programs which may be processed by "genasm" for different  targets
          WITHOUT distribution of the source code.
    
       4) A program may be written which processes this  intermediate  file,
          and "optimizes" the code. Additional "pseudo operation" codes  may
          be added to the output file if the target processor is capable  of
          operations which  the  more  "generic"  MICRO-C  output  does  not
          utilize.
    
       4.1 The "io" module
    
             The "io" module required  by  the  compiler  must  contain  the
          following function definitions:
    
             The function "main()" is called by the  operating  system  when
          the MICRO-C compiler is executed. It is  responsable  for  parsing
          any parmeters and command qualifiers, opening the input and output
          files,  performing  any  other  initializations  that   might   be
          required, and then  invoking  the  function  "compile()"  with  no
          arguments. The "compile" function is internal to  the  "compile.c"
          module, and will never return. For UNIX and  other  systems  which
          support I/O redirection, "stdin" and "stdout" are often  used  for
          the input and output files.
    
             The  function  "exit(rc)"  is  called  when  the  compiler  has
          finished all processing and wishes to terminate. The value "rc" is
          a return code: 0 = Success, program compiled without error,  -1  =
          Compile was aborted due to severe errors, n  =  Compile  finished,
          but had 'n' errors.
    
             The function "put_chr(chr, flag)"  is  passed  a  character  to
          output, as well as a flag. The flag will always be zero  when  the
          character is being sent to the console terminal, or non-zero  when
          the character is to be written to the output file.
    
             The function "put_str(*ptr, flag)" is passed  a  pointer  to  a
          zero terminated string, which is to be written to the  console  or
          output file as determined by "flag".
    
             The function "put_num(number, flag)" is passed a 16 bit number,
          which is to be written in printable form to the console or  output
          file as determined by "flag".
    MICRO-C                                                          Page: 27


          4.1.1 Compiler only routines
    
                The following I/O routines are required by the compiler, but
             not by the "genasm" program.
    
                The function  "get_lin(*ptr)"  is  passed  a  pointer  to  a
             character array,  and  should  read  a  single  line  from  the
             currently  open  input  file  into  that  array.  The  manifest
             definition "LINE_SIZE", found in "compile.h"  may  be  used  to
             determine the maximum line length acceptable to  the  compiler.
             Return of a non-zero value indicates the end of file condition.
    
                The  function  "f_open(*ptr)"  is  passed  a  pointer  to  a
             filename. The new file should be opened, and if successful, the
             old input file should remain open and be "stacked", so that  it
             can be later returned to. If the file was opened  successfully,
             a non-zero value should be returned. A zero value indicates  to
             the compiler that the file could not be opened.
    
                The function "f_close()"  is  responsible  for  closing  the
             currently open input  file,  and  returning  to  the  "stacked"
             previously open one. It receives no parameters. Note:  multiple
             "opens" may  be  stacked  -  see  the  manifest  definition  of
             "INCL_DEPTH" in the "compile.h" file.
    
          4.1.2 Genasm only routines
    
                The following  I/O  routine  is  required  by  the  "genasm"
             program, but not by the compiler.
    
                The function "get_char()" must  return  a  single  character
             from the input file as a 16 bit number with  a  positive  value
             between 0 and 255. A '-1' is  returned  for  the  end  of  file
             condition.
    
          4.1.3 Notes on I/O module
    
             1) It is the responsibility of the "put" routines to  translate
                the  NEWLINE  '\n'  (0x0a)  character  into  whatever   line
                termination  character(s)  are  required   by   the   target
                operating system.
    
             2) If unix "stdin"  and  "stdout"  are  not  used,  it  is  the
                responsibility  of  "main"  to  display  appropriate   error
                messages if the input or output files could not be opened.
    
                Refer to  the  sample  "io"  modules  distributed  with  the
             compiler.
    MICRO-C                                                          Page: 28


       4.2 The "code" module
    
             In order to insure that MICRO-C is portable  to  virtually  any
          environment,  the  compiler  makes  few  assumptions   about   the
          processor or system software of  the  target  system.  The  "code"
          module is  relied  on  to  produce  all  machine  instruction  and
          assembler directives written to the output file.
    
             The only two real "assumptions" made about the target processor
          are:
    
          1) It is assumed that the target processor  has  an  "accumulator"
             register in which all math operations are performed,  and  that
             the  lower  8  bits  of   this   register   may   be   accessed
             independantly.
    
          2) It is  assumed  that  the  target  processor  has  one  "index"
             register which may be loaded with a  16  bit  value,  and  that
             memory references may be made indirectly through this register.
    
             If the target processor does not support the above features, it
          may be possible to write a code generator for it using some  other
          features of the processor.
    
             For example, if an "index" register  does  not  exist,  it  may
          often be implemented using two bytes of reserved memory.
    
             The code  generation  module  required  by  the  compiler  must
          contain the following function definitions:
    
             The function "do_asm(*ptr)" is passed a pointer to a  character
          string, which it should  write  to  the  output  file  EXACTLY  as
          passed, followed by a '\n' NEWLINE  character.  This  function  is
          used by the "#asm" directive to write directly to the output file.
    
             The function "def_module()"  is  called  at  the  beginning  of
          compilation, before any other code generator functions are called.
          It is used to output any pre-amble needed by the assembler.
    
             The function "end_module()"  is  called  at  the  very  end  of
          compilation, and is the last code generator function called. It is
          used to output any post-amble needed by the assembler.
    
             The function "def_static(symbol)" is passed am index  into  the
          compiler symbol tables for a global variable, which is about to be
          initialized as static storage. The call to this function  will  be
          immediately followed by a call to "init_static" or "end_static".
    
             The "init_static(token, value,  word)"  function  is  passed  a
          token and value, with which it should initialize a single  element
          of static storag

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -