目录

編譯

Linux

# svn co http://svn.code.sf.net/p/sdcc/code/trunk/sdcc/
$ wget http://sourceforge.net/projects/sdcc/files/sdcc/3.4.0/sdcc-src-3.4.0.tar.bz2/download
$ tar xvf download
$ mkdir sdcc.build
$ cd sdcc.build
$ sudo apt-get install g++ flex bison libboost-all-dev
$ ../sdcc/configure --disable-mcs51-port --disable-z80-port \
  --disable-z180-port --disable-r2k-port --disable-r3ka-port   \
  --disable-gbz80-port --disable-tlcs90-port --disable-ds390-port \
  --disable-ds400-port --disable-pic14-port --disable-pic16-port --disable-s08-port 
$ make
$ ./bin/sdcc
# 會被 strip 調除錯訊息。
$ make install
  -S                        Compile only; do not assemble or link
  -c  --compile-only        Compile and assemble, but do not link
 
Internal debugging options:
      --dump-ast            Dump front-end AST before generating i-code
      --dump-i-code         Dump the i-code structure at all stages
      --dump-graphs         Dump graphs (control-flow, conflict, etc)
      --i-code-in-asm       Include i-code as comments in the asm file
      --fverbose-asm        Include code generator comments in the asm output
# 會列出產生代碼過程中,編譯器內部被調用的函式。
$ export SDCC_DEBUG_FUNCTION_POINTERS=true

Windows

Visual Studio

Cygwin

  1. 透過 Cygwin Ports 安裝 Boost。
  2. 以 MinGW 交叉編譯。
    $ wget http://sourceforge.net/projects/sdcc/files/sdcc/3.5.0/sdcc-src-3.5.0.tar.bz2/download
    $ tar xvf download
    $ mkdir sdcc.build; cd sdcc.build
    $ ../sdcc/configure --host=x86_64-w64-mingw32 \
      --disable-mcs51-port --disable-z80-port \
      --disable-z180-port --disable-r2k-port --disable-r3ka-port   \
      --disable-gbz80-port --disable-tlcs90-port --disable-ds390-port \
      --disable-ds400-port --disable-pic14-port --disable-pic16-port --disable-s08-port
    $ make
    # 為解決 sdcc.exe: error while loading shared libraries: libstdc++-6.dll 的問題。 
    $ export PATH=/usr/x86_64-w64-mingw32/sys-root/mingw/bin/:$PATH

流程簡介

yyparse (SDCCmain.c) → AST (SDCCast.c) → iCode (SDCCicode.c) → BBlock (SDCCopt.c) → iCode (SDCCicode.c) → CodeGen

  1. yyparse (SDCCmain.c)
      if (fullSrcFileName || options.c1mode)
        {
          preProcess (envp);
     
          initSymt ();
          initiCode ();
          initCSupport ();
          initBuiltIns ();
          initPeepHole ();
     
          if (options.verbose)
            printf ("sdcc: Generating code...\n");
     
          yyparse ();
    • function_definition (SDCC.y)。沒有返回執型別的函式,其預設型別為 int。C 的型別基本上是以 Type Link (Chain) 的方法表示。
      function_definition
         : function_declarator
               {   /* function type not specified */
                   /* assume it to be 'int'       */
                   addDecl($1,0,newIntLink());
                   $1 = createFunctionDecl($1);
               }
            function_body  {
                                         $$ = createFunction($1,$3);
                                     }
         | declaration_specifiers function_declarator
               {
                    pointerTypes($2->type,copyLinkChain($1));
                    addDecl($2,0,$1);
                    $2 = createFunctionDecl($2);
               }
           function_body
                                      {
                                          $$ = createFunction($2,$4);
                                      }
         ;
    1. createFunction (SDCCast.c)
      /*-----------------------------------------------------------------*/
      /* createFunction - This is the key node that calls the iCode for  */
      /*                  generating the code for a function. Note code  */
      /*                  is generated function by function, later when  */
      /*                  add inter-procedural analysis this will change */
      /*-----------------------------------------------------------------*/
      ast *
      createFunction (symbol * name, ast * body)
      {
        /* snip */
       
        ex = newAst_VALUE (symbolVal (name)); /* create name */
        ex = newNode (FUNCTION, ex, body);
        ex->values.args = FUNC_ARGS (name->type);
        ex->decorated = 1;
       
        /* snip */
       
        /* create the node & generate intermediate code */
        GcurMemmap = code;           // 代碼相關 memmap。
        codeOutBuf = &code->oBuf;    // 代碼輸出緩衝區。
        piCode = iCodeFromAst (ex);  // AST -> iCode
        name->generated = 1;
       
        eBBlockFromiCode (piCode);   // iCode -> eBBlock
       
        /* snip */
    2. iCodeFromAst (SDCCicode.c)
      /*-----------------------------------------------------------------*/
      /* iCodeFromAst - given an ast will convert it to iCode            */
      /*-----------------------------------------------------------------*/
      iCode *
      iCodeFromAst (ast * tree)
      {
        returnLabel = newiTempLabel ("_return");
        entryLabel = newiTempLabel ("_entry");
        ast2iCode (tree, 0);
        return reverseiCChain ();
      }
      • ast2iCode (SDCCicode.c) 將樹狀結構的 AST 轉成串列型式的 iCode。
        /*-----------------------------------------------------------------*/
        /* ast2iCode - creates an icodeList from an ast                    */
        /*-----------------------------------------------------------------*/
        operand *
        ast2iCode (ast * tree, int lvl)
        {
    3. eBBlockFromiCode (SDCCopt.c)
      /*-----------------------------------------------------------------*/
      /* eBBlockFromiCode - creates extended basic blocks from iCode     */
      /*                    will return an array of eBBlock pointers     */
      /*-----------------------------------------------------------------*/
      eBBlock **
      eBBlockFromiCode (iCode * ic)
      {
        /* optimize the chain for labels & gotos
           this will eliminate redundant labels and
           will change jump to jumps by jumps */
        ic = iCodeLabelOptimize (ic);
       
        /* break it down into basic blocks */
        ebbi = iCodeBreakDown (ic);
       
        /* 底層架構無關的優化。 */
       
        /* allocate registers & generate code */
        port->assignRegisters (ebbi); // 分配暫存器,並產生代碼。
       
        /* throw away blocks */
        setToNull ((void *) &graphEdges);
       
        return NULL;
      }
    4. assignRegisters (hc08/ralloc.c)。存在新舊兩種暫存器分配器。
      /*-----------------------------------------------------------------*/
      /* assignRegisters - assigns registers to each live range as need  */
      /*-----------------------------------------------------------------*/
      void
      hc08_assignRegisters (ebbIndex * ebbi)
      {
      #ifdef OLDRALLOC
        if (options.oldralloc)
          hc08_oldralloc (ebbi);
        else
      #endif
          hc08_ralloc (ebbi);
      }
      • hc08_oldralloc (hc08/ralloc.c)
        /*-----------------------------------------------------------------*/
        /* Old, obsolete register allocator                                */
        /*-----------------------------------------------------------------*/
        void
        hc08_oldralloc (ebbIndex * ebbi)
        {
          /* first determine for each live range the number of
             registers & the type of registers required for each */
          regTypeNum (*ebbs);
         
          /* and serially allocate registers */
          serialRegAssign (ebbs, count);
         
          /* snip */
         
          /* now get back the chain */
          ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); // 再將 eBBlock 轉成 iCode。
         
          genhc08Code (ic); // 針對 iCode 產生代碼。
        }
      • hc08_ralloc (hc08_ralloc)
        /*-----------------------------------------------------------------*/
        /* New register allocator                                          */
        /*-----------------------------------------------------------------*/
        void
        hc08_ralloc (ebbIndex * ebbi)
        {
          /* The new register allocator invokes its magic */
          ic = hc08_ralloc2_cc (ebbi);
         
          /* now get back the chain */
          ic = iCodeLabelOptimize (iCodeFromeBBlock (ebbs, count)); // 再將 eBBlock 轉成 iCode。
         
          genhc08Code (ic); // 針對 iCode 產生代碼。
        }
    5. genhc08Code (hc08/gen.c)
      /*-----------------------------------------------------------------*/
      /* genhc08Code - generate code for HC08 based controllers          */
      /*-----------------------------------------------------------------*/
      void
      genhc08Code (iCode *lic)
      {
        for (ic = lic; ic; ic = ic->next)
          {
            /* snip */
       
            genhc08iCode(ic);
       
            /* snip */
          }
      }
    6. genhc08iCode (hc08/gen.c)
      /*---------------------------------------------------------------------------------------*/
      /* genhc08iode - generate code for HC08 based controllers for a single iCode instruction */
      /*---------------------------------------------------------------------------------------*/
      static void
      genhc08iCode (iCode *ic)
      {
        /* depending on the operation */
        switch (ic->op)
          {
          case '!':
            genNot (ic);
            break;
    7. genNot (hc08/gen.c)
      /*-----------------------------------------------------------------*/
      /* genNot - generate code for ! operation                          */
      /*-----------------------------------------------------------------*/
      static void
      genNot (iCode * ic)
      {
        bool needpulla;
       
        D (emitcode (";     genNot", ""));
       
        /* assign asmOps to operand & result */
        aopOp (IC_LEFT (ic), ic, FALSE);
        aopOp (IC_RESULT (ic), ic, TRUE);
        needpulla = pushRegIfSurv (hc08_reg_a);
        asmopToBool (AOP (IC_LEFT (ic)), TRUE);
       
        emitcode ("eor", one);
        regalloc_dry_run_cost += 2;
        storeRegToFullAop (hc08_reg_a, AOP (IC_RESULT (ic)), FALSE);
        pullOrFreeReg (hc08_reg_a, needpulla);
       
        freeAsmop (IC_RESULT (ic), NULL, ic, TRUE);
        freeAsmop (IC_LEFT (ic), NULL, ic, TRUE);
      }
    • 至此已產生出匯編。
  2. do_glue() (SDCCmain.c)。產生段及其中的變數,並將所有匯編合併 (glue) 成一份。
          if (port->general.do_glue != NULL)
            (*port->general.do_glue) ();
    • glue (SDCCglue.c)
      /*-----------------------------------------------------------------*/
      /* glue - the final glue that hold the whole thing together        */
      /*-----------------------------------------------------------------*/
      void
      glue (void)
      {
        /* emit code for the all the variables declared */
        emitMaps ();
      }
    • emitMaps (SDCCglue.c)
      /*-----------------------------------------------------------------*/
      /* emitMaps - emits the code for the data portion the code         */
      /*-----------------------------------------------------------------*/
      void
      emitMaps (void)
      {
        namedspacemap *nm;
        int publicsfr = TARGET_IS_MCS51;      /* Ideally, this should be true for all  */
                                              /* ports but let's be conservative - EEP */
       
        inInitMode++;
        /* no special considerations for the following
           data, idata & bit & xdata */
        emitRegularMap (data, TRUE, TRUE);
    • emitRegularMap (SDCCglue.c)
      /*-----------------------------------------------------------------*/
      /* emitRegularMap - emit code for maps with no special cases       */
      /*-----------------------------------------------------------------*/
      static void
      emitRegularMap (memmap * map, bool addPublics, bool arFlag)

AST

AST 輸出解說

範例一

int main() {
  int a = 0;
 
  {  
    int a = 0;
    int b = 1;
    int c = a + b;
  }
 
  return 0;
}
                         type chain (return type, storage class) 
                             |
                             v
FUNCTION (_main=0x9d81ab8) type (int fixed) args (void)
            |       |                        |
            v        ----> ast node address   ----> args type chain
         function name  
         
tree (0x9d81a60) not decorated ----> left node is not decorated

             ---- L (level), B (block)
            |
            v
(null):0:{ L1 B0
(null):0:  DECLARE SYMBOL (L1 B1 a=0x9d7ef00) type (int fixed)
(null):0:  { L2 B1
(null):0:    DECLARE SYMBOL (L2 B2 a=0x9d7f538) type (int fixed)
(null):0:    DECLARE SYMBOL (L2 B2 b=0x9d7fa78) type (int fixed)
(null):0:    DECLARE SYMBOL (L2 B2 c=0x9d7ffb8) type (int fixed)
(null):0:  }
test.c:11:  RETURN (0x9d80b50) type (int literal)
test.c:0:    CONSTANT (0x9d81550) value = 0, 0x0, 0.000000 type (int literal)
(null):0:}

範例二

int main() {
  char a = 0;
  int  b = 1;
  a + b;
 
  return 0;
}
FUNCTION (_main=0xa204f60) type (int fixed) args (void)
tree (0xa204f08) not decorated
(null):0:{ L1 B0
(null):0:  DECLARE SYMBOL (L1 B1 a=0xa2030a0) type (char fixed)
(null):0:  DECLARE SYMBOL (L1 B1 b=0xa2035e0) type (int fixed)
test.c:4:  ADD (0xa2040c8) type (int fixed)
test.c:4:    CAST (0xa204878) from type (char fixed) to type (int fixed)
test.c:4:      SYMBOL (L1 B1 a=0xa203d68 @ 0xa2030a0) type (char fixed)
test.c:4:    SYMBOL (L1 B1 b=0xa204070 @ 0xa2035e0) type (int fixed)
test.c:6:  RETURN (0xa2042c0) type (int literal)
test.c:0:    CONSTANT (0xa2049f8) value = 0, 0x0, 0.000000 type (int literal)
(null):0:}

iCode

yyparse (SDCCmain.c) → AST (SDCCast.c) → iCode (SDCCicode.c) → BBlock (SDCCopt.c) → iCode (SDCCicode.c) → CodeGen

eBBlock

eBBlock 輸出解說

範例一

int main()
{
  return 0;
}
----------------------------------------------------------------
Basic Block _entry (df:1 bb:0 lvl:1): loopDepth=0

successors: _return
predecessors:
dominators: _entry

defines bitVector :
local defines bitVector :
pointers Set bitvector :
inExprs:
outExprs:
killedExprs:
----------------------------------------------------------------
test.c(l1:s0:k0:d0:s0)   _entry($2) :
test.c(l1:s0:k1:d0:s0)          proc _main [k1 lr0:0 so:0]{ ia0 a2p0 re0 rm0 nos0 ru0 dp0}{int function ( ) fixed}
                                     symbol 的內部名稱
                                            symbol 屬性
                                            k : key
                                            lr: live range
                                            so: stack (local or global symbol)
                                                            symbol & operand 屬性
                                                            ia : is an address
                                                            a2p: aggregate to pointer to aggregate
                                                            re : is the register equivalent of a symbol
                                                            rm : can be remateriazed
                                                            nos: cannot be assigned a spil location
                                                            ru : used in return statement only
                                                            dp : (8051) data pointer
                                                                                           symbol type
                                                                                                            storage class
test.c(l3:s0:k2:d0:s0)          ret 0x0 {int literal}

----------------------------------------------------------------
Basic Block _return (df:2 bb:1 lvl:1): loopDepth=0

successors:
predecessors: _entry
dominators: _entry _return

defines bitVector :
local defines bitVector :
pointers Set bitvector :
inExprs:
outExprs:
killedExprs:
----------------------------------------------------------------
test.c(l3:s0:k3:d0:s0)   _return($1) :
test.c(l3:s0:k4:d0:s0)          eproc _main [k1 lr0:0 so:0]{ ia0 a2p0 re0 rm0 nos0 ru0 dp0}{int function ( ) fixed}

範例二

__xdata int * p;
int gint;
 
/* This function does nothing useful. It is used
for the purpose of explaining iCode */
short function (__data int *x)
{
  short i=10;   /* dead initialization eliminated */
  short sum=10; /* dead initialization eliminated */
  short mul;
  int j ;
 
  while (*x) *x++ = *p++;
 
  sum = 0 ;
  mul = 0;
 
  /* compiler detects i,j to be induction variables */
  for (i = 0, j = 10 ; i < 10 ; i++, j--) {
   sum += i;
   mul += i * 3; /* this multiplication remains */
   gint += j * 3; /* this multiplication changed to addition */
  }
 
  return sum+mul;
}

代碼生成

Overlay

除錯訊息

SDCC 似乎存在有兩套除錯資訊,cdbFile 和 SDCCdwarf2。前者是另外寫至以 .adb 和 .cdb 後綴的檔案 (開啟 –debug 選項即會使用),後者則是將除錯資訊寫至匯編 (hc08 另外再開啟 –out-fmt-elf 選項下會使用)。

Lex & Yacc

selection_statement
   : IF '(' expr ')' { seqPointNo++;} statement else_statement
                           {
                              noLineno++;
                              $$ = createIf ($3, $6, $7 );
                              $$->lineno = $3->lineno;
                              $$->filename = $3->filename;
                              noLineno--;
                           }
/*-----------------------------------------------------------------*/
/* createIf - creates the parsetree for the if statement           */
/*-----------------------------------------------------------------*/
ast *
createIf (ast * condAst, ast * ifBody, ast * elseBody)
{
  static int Lblnum = 0;
  ast *ifTree;
  symbol *ifTrue, *ifFalse, *ifEnd;
  struct dbuf_s dbuf;
 
  /* if neither exists */
  if (!elseBody && !ifBody)
    {
      // if there are no side effects (i++, j() etc)
      if (!hasSEFcalls (condAst))
        {
          return condAst;
        }
    }
 
  /* create the labels */
  dbuf_init (&dbuf, 128);
  dbuf_printf (&dbuf, "_iffalse_%d", Lblnum);
  ifFalse = newSymbol (dbuf_c_str (&dbuf), NestLevel);
  dbuf_destroy (&dbuf);
  /* if no else body then end == false */
  if (!elseBody)
    ifEnd = ifFalse;
  else
    {
      dbuf_init (&dbuf, 128);
      dbuf_printf (&dbuf, "_ifend_%d", Lblnum);
      ifEnd = newSymbol (dbuf_c_str (&dbuf), NestLevel);
      dbuf_destroy (&dbuf);
    }
 
  dbuf_init (&dbuf, 128);
  dbuf_printf (&dbuf, "_iftrue_%d", Lblnum);
  ifTrue = newSymbol (dbuf_c_str (&dbuf), NestLevel);
  dbuf_destroy (&dbuf);
 
  Lblnum++;
 
  /* attach the ifTrue label to the top of it body */
  ifBody = createLabel (ifTrue, ifBody);
  /* attach a goto end to the ifBody if else is present */
  if (elseBody)
    {
      ifBody = newNode (NULLOP, ifBody, newNode (GOTO, newAst_VALUE (symbolVal (ifEnd)), NULL));
      /* put the elseLabel on the else body */
      elseBody = createLabel (ifFalse, elseBody);
      /* out the end at the end of the body */
      elseBody = newNode (NULLOP, elseBody, createLabel (ifEnd, NULL));
    }
  else
    {
      ifBody = newNode (NULLOP, ifBody, createLabel (ifFalse, NULL));
    }
  condAst = backPatchLabels (condAst, ifTrue, ifFalse);
  if (IS_IFX (condAst))
    ifTree = condAst;
  else
    ifTree = newIfxNode (condAst, ifTrue, ifFalse);
 
  return newNode (NULLOP, ifTree, newNode (NULLOP, ifBody, elseBody));
 
}
while : WHILE  {  /* create and push the continue , break & body labels */
                  static int Lblnum = 0;
                  /* continue */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilecontinue_%d",Lblnum);
                  STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
                  /* break */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilebreak_%d",Lblnum);
                  STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
                  /* body */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilebody_%d",Lblnum++);
                  $$ = newSymbol(lbuff,NestLevel);
               }
   ;

iteration_statement
   : while '(' expr ')' { seqPointNo++;}  statement
                         {
                           noLineno++;
                           $$ = createWhile ( $1, STACK_POP(continueStack),
                                              STACK_POP(breakStack), $3, $6 );
                           $$->lineno = $1->lineDef;
                           $$->filename = $1->fileDef;
                           noLineno--;
                         }
statement_list
   : statement
   | statement_list statement          {  $$ = newNode(NULLOP,$1,$2);}
   ;
           ast
            ^
            |
           val
            ^
            |
          symbol <- lnk (描述 symbol 型別和屬性)
       (identifier)

資料結構

function_definition
   : function_declarator
         {   /* function type not specified */
             /* assume it to be 'int'       */
             addDecl($1,0,newIntLink());
             $1 = createFunctionDecl($1);
         }
      function_body  {
                                   $$ = createFunction($1,$3);
                               }
   | declaration_specifiers function_declarator
         {
              pointerTypes($2->type,copyLinkChain($1));
              addDecl($2,0,$1);
              $2 = createFunctionDecl($2);
         }
     function_body
                                {
                                    $$ = createFunction($2,$4);
                                }
   ;
   
function_declarator2
   : declarator2 '('  ')'
        {
          addDecl ($1, FUNCTION, NULL);
        }
   | declarator2 '('
        {
          NestLevel++;
          STACK_PUSH(blockNum, currBlockno);
          btree_add_child(currBlockno, ++blockNo);
          currBlockno = blockNo;
          seqPointNo++; /* not a true sequence point, but helps resolve scope */
        }
     parameter_type_list ')'
        {
          sym_link *funcType;

          addDecl ($1, FUNCTION, NULL);

          funcType = $1->type;
          while (funcType && !IS_FUNC(funcType))
              funcType = funcType->next;

          assert (funcType);

          FUNC_HASVARARGS(funcType) = IS_VARG($4);
          FUNC_ARGS(funcType) = reverseVal($4);

          /* nest level was incremented to take care of the parms  */
          NestLevel--;
          currBlockno = STACK_POP(blockNum);
          seqPointNo++; /* not a true sequence point, but helps resolve scope */

          // if this was a pointer (to a function)
          if (!IS_FUNC($1->type))
              cleanUpLevel(SymbolTab, NestLevel + 1);

          $$ = $1;
        }
   | declarator2 '(' identifier_list ')'
        {
          werror(E_OLD_STYLE,$1->name);
          /* assume it returns an int */
          $1->type = $1->etype = newIntLink();
          $$ = $1;
        }
   ;
iteration_statement
   : while '(' expr ')' { seqPointNo++;}  statement
                         {
                           noLineno++;
                           $$ = createWhile ( $1, STACK_POP(continueStack),
                                              STACK_POP(breakStack), $3, $6 );
                           $$->lineno = $1->lineDef;
                           $$->filename = $1->fileDef;
                           noLineno--;
                         }
   ;
   
while : WHILE  {  /* create and push the continue , break & body labels */
                  static int Lblnum = 0;
                  /* continue */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilecontinue_%d",Lblnum);
                  STACK_PUSH(continueStack,newSymbol(lbuff,NestLevel));
                  /* break */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilebreak_%d",Lblnum);
                  STACK_PUSH(breakStack,newSymbol(lbuff,NestLevel));
                  /* body */
                  SNPRINTF (lbuff, sizeof(lbuff), "_whilebody_%d",Lblnum++);
                  $$ = newSymbol(lbuff,NestLevel);
               }
   ;
/*-----------------------------------------------------------------*/
/* createWhile - creates parse tree for while statement            */
/*               the while statement will be created as follows    */
/*                                                                 */
/*      _while_continue_n:                                         */
/*            condition_expression +-> trueLabel -> _while_boby_n  */
/*                                 |                               */
/*                                 +-> falseLabel -> _while_break_n */
/*      _while_body_n:                                             */
/*            statements                                           */
/*            goto _while_continue_n                               */
/*      _while_break_n:                                            */
/*-----------------------------------------------------------------*/
ast *
createWhile (symbol * trueLabel, symbol * continueLabel, symbol * falseLabel, ast * condExpr, ast * whileBody)
{
  ast *whileTree;
 
  /* put the continue label */
  condExpr = backPatchLabels (condExpr, trueLabel, falseLabel);
  if (condExpr && !IS_IFX (condExpr))
    {
      condExpr = newNode (IFX, condExpr, NULL);
      /* put the true & false labels in place */
      condExpr->trueLabel = trueLabel;
      condExpr->falseLabel = falseLabel;
    }
  whileTree = createLabel (continueLabel, condExpr);
  whileTree->filename = NULL;
  whileTree->lineno = 0;
 
  /* put the body label in front of the body */
  whileBody = createLabel (trueLabel, whileBody);
  whileBody->filename = NULL;
  whileBody->lineno = 0;
  /* put a jump to continue at the end of the body */
  /* and put break label at the end of the body */
  whileBody = newNode (NULLOP,
                       whileBody, newNode (GOTO, newAst_VALUE (symbolVal (continueLabel)), createLabel (falseLabel, NULL)));
 
  /* put it all together */
  return newNode (NULLOP, whileTree, whileBody);
}
透過 –dump-ast 輸出 AST 可以幫助了解上述代碼。
void main()
{
  int i, j;
 
  bool flag = true;
  if (flag == false)
  {
    i = 1;
  }
  else
  {
    j = 2;
  }
}
/*-----------------------------------------------------------------*/
/* createIf - creates the parsetree for the if statement           */
/*                                                                 */
/*      condition_expression +-> ifTrue                            */
/*                           |           -> ifEnd                  */
/*                           +-> ifFalse                           */
/*-----------------------------------------------------------------*/
ast *
createIf (ast * condAst, ast * ifBody, ast * elseBody)
{
  static int Lblnum = 0;
  ast *ifTree;
  symbol *ifTrue, *ifFalse, *ifEnd;
  struct dbuf_s dbuf;
 
  /* if neither exists */
  if (!elseBody && !ifBody)
    {
      // if there are no side effects (i++, j() etc)
      if (!hasSEFcalls (condAst))
        {
          return condAst;
        }
    }
 
  /* create the labels */
  dbuf_init (&dbuf, 128);
  dbuf_printf (&dbuf, "__iffalse_%d", Lblnum);
  ifFalse = newSymbol (dbuf_c_str (&dbuf), NestLevel);
  dbuf_destroy (&dbuf);
  /* if no else body then end == false */
  if (!elseBody)
    {
      ifEnd = ifFalse;
    }
  else
    {
      dbuf_init (&dbuf, 128);
      dbuf_printf (&dbuf, "__ifend_%d", Lblnum);
      ifEnd = newSymbol (dbuf_c_str (&dbuf), NestLevel);
      dbuf_destroy (&dbuf);
    }
 
  dbuf_init (&dbuf, 128);
  dbuf_printf (&dbuf, "__iftrue_%d", Lblnum);
  ifTrue = newSymbol (dbuf_c_str (&dbuf), NestLevel);
  dbuf_destroy (&dbuf);
 
  Lblnum++;
 
  /* attach the ifTrue label to the top of it body */
  ifBody = createLabel (ifTrue, ifBody);
  /* attach a goto end to the ifBody if else is present */
  if (elseBody)
    {
      ifBody = newNode (NULLOP, ifBody, newNode (GOTO, newAst_VALUE (symbolVal (ifEnd)), NULL));
      /* put the elseLabel on the else body */
      elseBody = createLabel (ifFalse, elseBody);
      /* out the end at the end of the body */
      elseBody = newNode (NULLOP, elseBody, createLabel (ifEnd, NULL));
    }
  else
    {
      ifBody = newNode (NULLOP, ifBody, createLabel (ifFalse, NULL));
    }
  condAst = backPatchLabels (condAst, ifTrue, ifFalse);
  if (IS_IFX (condAst))
    ifTree = condAst;
  else
    ifTree = newIfxNode (condAst, ifTrue, ifFalse);
 
  return newNode (NULLOP, ifTree, newNode (NULLOP, ifBody, elseBody));
 
}

警告和錯誤訊息

移植簡介

術語

硬件

C 程式語言

SDCC 技術文件

其它

C 前處理器

C 擴展語法

C 函式庫

Printf

  1. vprintf.c
    static void
    put_char_to_stdout (char c, void* p) _REENTRANT
    {
      p;  //make compiler happy
      putchar (c);
    }
     
    int
    vprintf (const char *format, va_list ap)
    {
      return _print_format (put_char_to_stdout, NULL, format, ap);
    }
     
    int
    printf (const char *format, ...)
    {
      va_list arg;
      int i;
     
      va_start (arg, format);
      i = _print_format (put_char_to_stdout, NULL, format, arg);
      va_end (arg);
     
      return i;
    }
  2. printf_large.c
    int
    _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
    {
      while( c=*format++ )
      {
        if ( c=='%' )
        {
          /* 處理 format string */
        }
        else
        {
          // nothing special, just output the character
          OUTPUT_CHAR( c, p );
        }
      }
     
      return charsOutputted;
    }
    • printf 和 vprintf 底層都是調用 _print_format。_print_format 調用 put_char_to_stdout,put_char_to_stdout 最後再調用底層相關的 putchar 輸出字串符至裝置。
    • sprintf/vsprintf (device/lib/sprintf.c) 和 fprintf (device/lib/pic16/libc/stdio/fprintf.c) 都是類似的實現機制,只是傳給 _print_format 的第一個參數 put_char_to_xxx 有所不同。
前述兩個 printf 函式,皆要求使用者自行提供 putchar,其中實做 IO 輸出功能。

外部連結