Trivial Solutions
                    The LoseThos 64-bit PC Operating System
File:/LT/Compiler/StmtParser.CPZ
This, and all LoseThos files, are public domain.  Do whatever you like.
God is watching; God is just; God is never out-done in generosity.  He talks!

LoseThos code compiles with the 64-bit LoseThos compiler/assembler I wrote.
Boot the LoseThos CD and you can compile it.  Not in Kansas anymore!

Click here for preliminary compiler information you need.

Project: Compiler.SPZ
ClassStruct *PrsClassNew()
{
/*
Ptrs to classes are handled by
allocating 5 structures for each
new class and representing a pointer
to a class by advancing 1 struct forward
for one * and two forward for two **.
*/

  ClassStruct *result=CAlloc(sizeof(ClassStruct)*5,Fs->code_heap),
              *tempc=result;
  tempc->last_in_member_list=&tempc->member_list;
  tempc->s.h.type=HTT_CLASS;
  tempc->sub_type=IT_PTR;
  tempc->ptr_cnt=0;

  tempc++;
  tempc->s.h.type=HTT_CLASS;
  tempc->sub_type=IT_PTR;
  tempc->size=sizeof(U0 *);
  tempc->ptr_cnt=1;

  tempc++;
  tempc->s.h.type=HTT_CLASS;
  tempc->sub_type=IT_PTR;
  tempc->size=sizeof(U0 *);
  tempc->ptr_cnt=2;

  tempc++;
  tempc->s.h.type=HTT_CLASS;
  tempc->sub_type=IT_PTR;
  tempc->size=sizeof(U0 *);
  tempc->ptr_cnt=3;

  tempc++;
  tempc->s.h.type=HTT_CLASS;
  tempc->sub_type=IT_PTR;
  tempc->size=sizeof(U0 *);
  tempc->ptr_cnt=4;

  return result;
}

MemberListStruct *MemberListNew(I64 register)
{
  MemberListStruct *result=CAlloc(sizeof(MemberListStruct));
  result->register=register;
  return result;
}

I64 PrsKeyWord(LexStruct *lx)
{
  GenericHashEntry *temph;
  if (lx->token==TK_IDENT &&
      (temph=lx->hash_entry) &&
      temph->h.type&HTT_KEYWORD)
    return temph->user_data0;
  else
    return -1;
}

U0 PrsVarInit(LexStruct *lx,U8 **_dst,ClassStruct *tempc,ArrayDimStruct *tempad,U8 *data_address_ip,U8 **base,BoolI8 data_heap,I64 pass)
{
  U8 *dst=*_dst,*ex;
  U64 i,j,r,old_flags,type,size;
  MemberListStruct *tempm;
  IntermediateCode *tempi;
  AsmCtrlStruct *a=lx->a;
  ExeAbsoluteAddressStruct *tempa;
  ExeImportExportStruct *tempe;
  DbgInfo *dbg=NULL;
  IndentInfo *indent=NULL;
  BoolI8 is_str;

  while (tempc->forward_class)
    tempc=tempc->forward_class;
  if (tempm=tempc->member_list) {
    if (lx->token!='{')
      PrsExcept(lx,"ST_EXPECTING_LEFT_BRACE");
    lx->stk_ptr--;  //grows up
    LexPush(lx);
    Lex(lx);

    while (tempm) {
      PrsVarInit2(lx,&dst,tempm->member_class,&tempm->dim,data_address_ip,base,data_heap,pass);
      if (lx->token==',')
        Lex(lx);
      tempm=tempm->next;
    }
    lx->stk_ptr--;  //grows up
    if (lx->token!='}')
      PrsExcept(lx,"ST_MISSING_RIGHT_BRACE");
    Lex(lx);
  } else {
    if (tempc->ptr_cnt==1 && ((tempc-1)->sub_type==IT_I8 || (tempc-1)->sub_type==IT_U8) &&
      !tempad && lx->token==TK_STR)
      is_str=TRUE;
    else
      is_str=FALSE;
    if (lx->flags&LF_STATIC_COMPILE && is_str) {
      lx->stk_ptr--;    //grows up
      ex=LexExtStr(lx,&i);
      if (pass==2) {
        tempa=CAlloc(sizeof(ExeAbsoluteAddressStruct));
        tempa->next=a->absolutes;
        tempa->type=EAA_ADD_U64;
        a->absolutes=tempa;
        tempa->ip=data_address_ip+dst-*base;
        *dst><(U64 *)=a->ip;
        for (j=0;j<i;j++)
          AsmStoreCodeU8(lx,ex[j]);
      }
      Free(ex);
    } else {
      old_flags=lx->flags;
      lx->flags=LF_NO_ABSOLUTES | lx->flags & ~(LF_STATIC_COMPILE|LF_HAS_MISC_DATA|LF_NOT_CONSTANT);
      ex=CmpExpression(lx,&type);
      if (old_flags&LF_STATIC_COMPILE &&
        lx->flags&LF_NOT_CONSTANT &&
         !Bt(&lx->opts,OPTf_GLBLS_ON_DATA_HEAP)) {
        lx->flags=lx->flags&~LF_NO_ABSOLUTES|LF_STATIC_COMPILE;
        ExpressionDel(ex);
        if (pass==2) {
          MemSet(dst,0,tempc->size);
          LexPop(lx);
          Lex(lx);
          CbPush(lx);
          CbOutPtrsInit(lx);
          CbIcAdd(lx,EC_START,0,0); //So we can scan back an instruction
          CbIcAdd(lx,EC_ABSOLUTE_ADDRESS,data_address_ip,tempc+1);
          CbIcAdd(lx,EC_IMM,dst-*base,tempc+1);
          CbIcAdd(lx,EC_ADD,0,tempc+1);
          if (!PrsExpression(lx,NULL,TRUE))
            throw(EXCEPT_COMPILER,10);
          tempi=lx->cbh.cb_last_out_ptr;
          if (tempi->ic_opcode==EC_END_EXP)
            tempi->ic_opcode=EC_NOP;
          CbIcAdd(lx,EC_ASSIGN,0,tempc);
          CbIcAdd(lx,EC_END_EXP,0,tempc);
          CbIcAdd(lx,EC_RET,0,0);
          CbIcAdd(lx,EC_END,0,0);
          if (ex=CbCompile(lx,NULL,&size,&dbg,&indent)) {
            tempe=CAlloc(sizeof(ExeImportExportStruct));
            tempe->type=EIE_MAIN;
            tempe->ip=lx->a->ip;
            InsQue(tempe,lx->exe_struct->last_ie);
            for (i=0;i<size;i++)
              AsmStoreCodeU8(lx,ex[i]);
            ExpressionDel(ex);
          }
          Free(dbg);
          Free(indent);
          CbPop(lx);
        } else
          lx->stk_ptr--;  //grows up
      } else {
        lx->stk_ptr--;  //grows up
        if (!ex)
          throw(EXCEPT_COMPILER,10);
        r=Call(ex);
        if (!(lx->flags & LF_HAS_MISC_DATA)||pass==1)
          ExpressionDel(ex);

        if (type==IT_F64 &&
            tempc->sub_type!=IT_F64)
          r=r><(F64);
        else if (type!=IT_F64 &&
            tempc->sub_type==IT_F64)
          r><(F64)=r;
        MemCpy(dst,&r,tempc->size);
      }
    }
    dst+=tempc->size;
    lx->flags=lx->flags&~LF_NO_ABSOLUTES|old_flags&(LF_HAS_MISC_DATA|LF_STATIC_COMPILE);
  }
  *_dst=dst;
}


class VI16
{
  VI16 *next,*last;
  U0 base;
};


U0 PrsVarInit2(LexStruct *lx,U8 **_dst,ClassStruct *tempc,ArrayDimStruct *tempad,U8 *data_address_ip,U8 **base,BoolI8 data_heap,I64 pass)
{
  I64 i,j,cnt;
  U8 *st;
  U8 *dd1;
  VI16 root,*tempvi,*tempvi1;
  ArrayDimStruct *tempad1;
  while (tempc->forward_class)
    tempc=tempc->forward_class;
  if (tempad1=tempad->next) {
    if (!tempc->ptr_cnt &&
        (tempc->sub_type==IT_I8 || tempc->sub_type==IT_U8) &&
        lx->token==TK_STR) {
      lx->stk_ptr--;    //grows up
      st=LexExtStr(lx,&i);
      if (tempad1->cnt<0) { //[]
        tempad1->cnt=i;
        tempad->total_cnt=i*tempad1->total_cnt;
        Free(*base);
        if (data_heap)
          *base=MAlloc(i);
        else
          *base=MAlloc(i,Fs->code_heap);
        MemCpy(*base,st,i);
        *_dst=*base+i;
      } else {
        MemCpy(*_dst,st,tempad1->cnt);
        *_dst+=tempad1->cnt;
      }
      Free(st);
      LexPush(lx);
    } else {
      if (lx->token=='{') {
        lx->stk_ptr--;  //grows up
        LexPush(lx);
        Lex(lx);
      }
      if (tempad1->cnt<0) { //[]
        root.next=root.last=&root;
        cnt=0;
        while (lx->token!='}') {
          tempvi=MAlloc(offset(VI16.base)+tempad1->total_cnt*tempc->size);
          dd1=&tempvi->base;
          PrsVarInit2(lx,&dd1,tempc,tempad1,data_address_ip,base,data_heap,pass);
          InsQue(tempvi,root.last);
          if (lx->token==',')
            Lex(lx);
          cnt++;
        }
        Lex(lx); //skip '}'
        tempad1->cnt=cnt;
        tempad->total_cnt=cnt*tempad1->total_cnt;
        j=tempad1->total_cnt*tempc->size;
        i=cnt*j;
        Free(*base);
        if (data_heap)
          *base=dd1=MAlloc(i);
        else
          *base=dd1=MAlloc(i,Fs->code_heap);
        tempvi=root.next;
        while (tempvi!=&root) {
          tempvi1=tempvi->next;
          MemCpy(dd1,&tempvi->base,j);
          dd1+=j;
          Free(tempvi);
          tempvi=tempvi1;
        }
        *_dst=dd1;
      } else {
        for (i=0;i<tempad1->cnt;i++) {
          PrsVarInit2(lx,_dst,tempc,tempad1,data_address_ip,base,data_heap,pass);
          if (tempad1->cnt>1 && lx->token==',')
            Lex(lx);
        }
        if (lx->token=='}')
          Lex(lx);
      }
    }
  } else {
    PrsVarInit(lx,_dst,tempc,tempad1,data_address_ip,base,data_heap,pass);
    LexPush(lx);
  }
}

U0 PrsGlblInit(LexStruct *lx,GlblVarStruct *tempg,I64 pass)
{
  U8 *dst=tempg->data_address;
  PrsVarInit2(lx,&dst,tempg->var_class,&tempg->dim,
    tempg->data_address_ip,&tempg->data_address,
    Bt(&lx->opts,OPTf_GLBLS_ON_DATA_HEAP)||
    Bt(&lx->flags,Lf_STATIC_COMPILE),pass);
}

U0 PrsStaticInit(LexStruct *lx,MemberListStruct *tempm,I64 pass)
{
  U8 *dst=tempm->static_data;
  ClassStruct *tempc=tempm->member_class;
  U8 *ex;
  U64 i,size;
  DbgInfo *dbg=NULL;
  IndentInfo *indent=NULL;
  IntermediateCode *tempi;
  ExeImportExportStruct *tempe;

  if (lx->flags&LF_STATIC_COMPILE && pass==2) {
    CbPush(lx);
    CbOutPtrsInit(lx);
    CbIcAdd(lx,EC_START,0,0); //So we can scan back an instruction
    tempi=lx->cbh.cb_last_out_ptr;
  }
  PrsVarInit2(lx,&dst,tempc,&tempm->dim,tempm->static_data_ip,&tempm->static_data,Bt(&lx->flags,Lf_STATIC_COMPILE),pass);
  if (lx->flags&LF_STATIC_COMPILE && pass==2) {
    if (tempi!=lx->cbh.cb_last_out_ptr) {
      CbIcAdd(lx,EC_RET,0,0);
      CbIcAdd(lx,EC_END,0,0);
      if (ex=CbCompile(lx,NULL,&size,&dbg,&indent)) {
        if (pass==2) {
          tempe=CAlloc(sizeof(ExeImportExportStruct));
          tempe->type=EIE_MAIN;
          tempe->ip=lx->a->ip;
          InsQue(tempe,lx->exe_struct->last_ie);
          for (i=0;i<size;i++)
            AsmStoreCodeU8(lx,ex[i]);
        }
        ExpressionDel(ex);
      }
    } else
      LinkedListDel(lx->cbh.cb_out_first);
    Free(dbg);
    Free(indent);
    CbPop(lx);
  }
}


BoolI64 PrsArrayDims(LexStruct *lx,GlblVarStruct *tempg,ArrayDimStruct *dim)
{ //returns false on empty []
  //dim->next!=0 for array
  ArrayDimStruct *tempad,*tempad1,*tempad2;
  I64 j;
  BoolI8 result=TRUE;
  dim->next=NULL;
  dim->cnt=0;
  dim->total_cnt=1;
  tempad1=&dim->next;
  while (lx->token=='[') {
    if (Lex(lx)==']' && !dim->next) {
      j=-1;
      result=FALSE;
    } else {
      if ((j=Expression(lx))<0)
        PrsExcept(lx,"ST_INVALID_ARRAY_SIZE");
    }
    tempad1=&dim->next;
    while (tempad1->next) {
      tempad1->next->total_cnt*=j;
      tempad1=tempad1->next;
    }
    tempad=MAlloc(sizeof(ArrayDimStruct));
    tempad1->next=tempad;
    tempad1=tempad;
    tempad->next=NULL;
    tempad->cnt=j;
    tempad->total_cnt=1;
    dim->total_cnt*=j;
    if (lx->token!=']')
      PrsExcept(lx,"ST_MISSING_RIGHT_BRACKET");
    Lex(lx);
  }
  if (tempg && (tempad2=tempg->dim.next)) { //typedef
    tempad=dim->next;
    while (tempad) {
      tempad->total_cnt*=tempg->dim.total_cnt;
      tempad=tempad->next;
    }
    while (tempad2) {
      tempad=MAlloc(sizeof(ArrayDimStruct));
      tempad1->next=tempad;
      tempad->next=NULL;
      tempad->cnt=tempad2->cnt;
      tempad->total_cnt=tempad2->total_cnt;
      tempad1=tempad;
      tempad2=tempad2->next;
    }
    dim->total_cnt*=tempg->dim.total_cnt;
  }
  return result;
}


U0 PrsDotDotDot(LexStruct *lx,ClassStruct *tempc,I64 register)
{
  MemberListStruct *tempm;
  ArrayDimStruct *tempad;

  Bts(&tempc->flags,Cf_DOT_DOT_DOT);

  Lex(lx);
  tempm=MemberListNew(register);
  tempm->flags=MLF_DOT_DOT_DOT;
  tempm->member_class=sys_internal_types[IT_I64];
  tempm->str=StrNew("argc");
  tempm->offset=tempc->size;
  tempc->size+=8;
  MemberAdd(lx,tempm,tempc);

  tempm=MemberListNew(register);
  tempm->flags=MLF_DOT_DOT_DOT;
  tempm->member_class=sys_internal_types[IT_I64];
  tempm->str=StrNew("argv");
  tempm->dim.total_cnt=127; //arbitrary
  tempm->dim.next=tempad=MAlloc(sizeof(ArrayDimStruct));
  tempad->next=NULL;
  tempad->cnt=127; //arbitrary
  tempad->total_cnt=1;
  tempm->offset=tempc->size;
  tempc->size+=8;
  MemberAdd(lx,tempm,tempc);

  if (lx->token==')')
    Lex(lx);
}

ClassStruct *PrsType(LexStruct *lx,ClassStruct **_tempc1,
  I64 *_mode,MemberListStruct *tempm,U8 **_ident,ClassStruct **_fun_ptr,
  ExportSysSymHashEntry **_tempess,ArrayDimStruct *tempad,U64 cps_flags)
{
  GlblVarStruct *tempg;
  I64 fun_ptr_cnt,mode=*_mode;
  ClassStruct *tempc1=*_tempc1,*tempc2,*fun_ptr=NULL;
  ExportSysSymHashEntry *tempess=NULL;
  ArrayDimStruct *tempad2;

start:
  if (!tempc1 || !(tempc1->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
    PrsExcept(lx,"ST_INVALID_CLASS");
  if (tempc1->s.h.type&HTT_TYPEDEF) {
    tempg=tempc1;
    tempc1=tempg->var_class;
  } else
    tempg=NULL;

  while (lx->token=='*'||
    lx->token=='&' && mode==PRS_FUN_ARG && !Bts(&tempm->flags,MLf_BY_ADDRESS)) {
    if (mode&PRSF_LEX_PUSH) {
      lx->stk_ptr--;    //grows up
      LexPush(lx);
    }
    Lex(lx);
    tempc1++;
  }

  if (PrsKeyWord(lx)==KW_UNION) {
    Lex(lx);
    tempc2=PrsClass(lx,TRUE,cps_flags,mode==PRS_EXTERN);
    tempc2->forward_class=tempc1;
    tempc1=tempc2;
    if (_tempc1) *_tempc1=tempc1;
    mode=PRS_NULL;
    goto start;
  } else if (PrsKeyWord(lx)==KW_CLASS) {
    Lex(lx);
    tempc2=PrsClass(lx,FALSE,cps_flags,mode==PRS_EXTERN);
    tempc2->forward_class=tempc1;
    tempc1=tempc2;
    if (_tempc1) *_tempc1=tempc1;
    mode=PRS_NULL;
    goto start;
  }

  if (lx->token=='(') {
    if (Lex(lx)!='*')
      PrsExcept(lx,"ST_EXPECTING_STAR");
    fun_ptr_cnt=1;
    while (Lex(lx)=='*')
      fun_ptr_cnt++;
  } else
    fun_ptr_cnt=-1;

  if (_ident) {
    if (lx->token==TK_IDENT) {
      tempess=lx->hash_entry;
      *_ident=lx->ident;
      lx->ident=NULL;
      Lex(lx);
    } else {
      if (mode<PRS_NUM_GLBL)
        *_ident=NULL;
      else
        PrsExcept(lx,"ST_EXPECTING_IDENTIFIER");
    }
  }

  if (fun_ptr_cnt>=0) {
    if (lx->token!=')')
      PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
    if (Lex(lx)!='(')
      PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
    fun_ptr=PrsFunJoin(lx,tempc1,NULL,cps_flags)+(fun_ptr_cnt-1);
    tempc1=sys_internal_types[IT_PTR]+(fun_ptr_cnt-1);
  }

  if (tempg && tempg->s.h.type&HTT_TYPEDEF && tempg->fun_ptr) {
    if (fun_ptr)
      PrsExcept(lx,"ST_FUN_PTR_FUN_PTR");
    fun_ptr=HashEntryCopy(tempg->fun_ptr-tempg->fun_ptr->ptr_cnt)><(ClassStruct *)+tempg->fun_ptr->ptr_cnt;
    tempc1=sys_internal_types[IT_PTR]+tempg->fun_ptr->ptr_cnt;
  }

  if (!PrsArrayDims(lx,tempg,tempad) && lx->token!='=') {
    tempad->total_cnt=1;
    tempc1++;
    tempad2=tempad->next->next;
    Free(tempad->next);
    tempad->next=tempad2;
  }

  if (_mode)        *_mode=mode;
  if (_fun_ptr)     *_fun_ptr=fun_ptr;
  if (_tempess)     *_tempess=tempess;
  return tempc1;
}

U0 PrsVarList(LexStruct *lx,ClassStruct *tempc,
                     I64 mode,U64 union_base=MAX_I32)
{
  I64 i,k,old_flags,type,register;
  ClassStruct *tempc1,*tempc2;
  SysHashEntry *temph;
  MemberListStruct *tempm;
  MemberListMeta *temp_meta;
  U8 *ex;
  BoolI8 undef_array_size;
  if (mode!=PRS_LOCAL_VAR && mode!=PRS_STATIC_LOCAL_VAR || union_base!=MAX_I32) {
    if (lx->token=='(' || lx->token=='{')
      Lex(lx);
  }
  while (TRUE) {
    while (lx->token==';') Lex(lx);
    if (lx->token==')' || lx->token=='}') {
      Lex(lx);
      goto pvl_done;
    }

    register=CREG_UNDEF;
    k=PrsKeyWord(lx);
    if (k==KW_REG) {
      register=CREG_ALLOC;
      if (Lex(lx)==TK_IDENT) {
        k=DefineMatch(lx->ident,"ST_U64_REGS");
        if (k>=0) {
          register=k;
          Lex(lx);
        }
      }
    } else if (k==KW_NOREG) {
      register=CREG_NONE;
      Lex(lx);
    }

    if (lx->token==TK_DOT_DOT_DOT && mode==PRS_FUN_ARG) {
      PrsDotDotDot(lx,tempc,register);
      goto pvl_done;
    }
    temph=NULL;
    if (lx->token==TK_IDENT) {
      temph=lx->hash_entry;
      k=PrsKeyWord(lx);
    }
    if (!temph)
      PrsExcept(lx,"ST_EXPECTING_TYPE");
    if (k==KW_UNION) {
      Lex(lx);
      PrsVarList(lx,tempc,mode,tempc->size);
    } else {
      if (!(temph->type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
        PrsExcept(lx,"ST_EXPECTING_TYPE");
restart:
      tempc1=temph;
      LexPush(lx);
      if (lx->token!=',' && mode==PRS_LOCAL_VAR) {
        Lex(lx); //skip type
        lx->last_indent_level=lx->indent_level=1;
        CbIcAdd(lx,EC_NOP,0,0); //record indent_level
        lx->flags|=LF_INSIDE_EXPRESSION;
        lx->expression_start_line=lx->start_line_num;
      } else {
        Lex(lx); //skip type or ','
        if (mode==PRS_LOCAL_VAR)
          CbIcAdd(lx,EC_NOP,0,0); //record indent_level
      }
      tempm=MemberListNew(register);
      if (mode==PRS_STATIC_LOCAL_VAR) {
        tempm->flags=MLF_STATIC;
        tempm->register=CREG_NONE;
      }
      if (mode==PRS_FUN_ARG || mode==PRS_LOCAL_VAR) {
        k=PrsKeyWord(lx);
        if (k==KW_REG) {
          tempm->register=CREG_ALLOC;
          lx->stk_ptr--;  //grows up
          LexPush(lx);
          if (Lex(lx)==TK_IDENT) {
            k=DefineMatch(lx->ident,"ST_U64_REGS");
            if (k>=0) {
              tempm->register=k;
              lx->stk_ptr--;  //grows up
              LexPush(lx);
              Lex(lx);
            }
          }
        } else if (k==KW_NOREG) {
          tempm->register=CREG_NONE;
          lx->stk_ptr--;  //grows up
          LexPush(lx);
          Lex(lx);
        }
      }
      tempm->member_class=PrsType(lx,&tempc1,&mode,tempm,&tempm->str,
          &tempm->fun_ptr,NULL,&tempm->dim,0);
      if (tempm->fun_ptr)
        tempm->flags|=MLF_FUN;
      MemberAdd(lx,tempm,tempc);
      tempc->member_cnt++;

      tempc2=tempm->member_class;
      i=tempc2->size*tempm->dim.total_cnt;
      switch (mode) {
        case PRS_STATIC_LOCAL_VAR:
          if (i<0) {
            i=0;
            undef_array_size=TRUE;
          } else
            undef_array_size=FALSE;
          if (union_base!=MAX_I32)
            PrsExcept(lx,"ST_STATIC_UNION");
          k=(i+7)&~7;
          if (lx->flags&LF_STATIC_COMPILE)
            tempm->static_data=MAlloc(k);
          else
            tempm->static_data=MAlloc(k,Fs->code_heap);
          if (lx->flags&LF_STATIC_COMPILE)      {
            tempm->static_data_ip=lx->a->ip;
            k>>=3;
            if (sys_var_init_flag&1) {
              k<<=3;
              while (k--)
                AsmStoreCodeU8(lx,sys_var_init_val);
            } else
              while (k--)
                AsmStoreCodeU64(lx,0);
          } else
          if (sys_var_init_flag&1)
            MemSet(tempm->static_data,sys_var_init_val,k);
          lx->stk_ptr--;
          if (lx->token=='=') {
            if (undef_array_size) {
              LexPush(lx);
              LexPush(lx);
              Lex(lx); //skip =
              PrsStaticInit(lx,tempm,1);
              lx->stk_ptr--;
              i=tempc2->size*tempm->dim.total_cnt;
              k=(i+7)&~7;
              if (lx->flags&LF_STATIC_COMPILE)  {
                k>>=3;
                if (sys_var_init_flag&1) {
                  k<<=3;
                  while (k--)
                    AsmStoreCodeU8(lx,sys_var_init_val);
                } else
                  while (k--)
                    AsmStoreCodeU64(lx,0);
              } else
              if (sys_var_init_flag&1)
                MemSet(tempm->static_data,sys_var_init_val,k);
              LexPop(lx);
            }
            LexPush(lx);
            Lex(lx); //skip =
            PrsStaticInit(lx,tempm,2);
            lx->stk_ptr--;
            if (lx->flags&LF_STATIC_COMPILE)
              for (k=0;k<i;k++)
                AsmStoreCodeU8At(lx,tempm->static_data[k],tempm->static_data_ip+k);
              tempm->use_cnt=0;
          }
          if (lx->flags&LF_STATIC_COMPILE)
            Free(tempm->static_data);
          break;
        case PRS_LOCAL_VAR:
          if (union_base!=MAX_I32) {
            if (union_base-tempc->size<i)
              i=union_base-i-tempc->size;
            else
              i=0;
          }
          if (i>=8)
            tempc->size=(tempc->size-i)&~7;
          else if (i>=4)
            tempc->size=(tempc->size-i)&~3;
          else if (i>=2)
            tempc->size=(tempc->size-i)&~1;
          else
            tempc->size-=i;
          tempm->offset=tempc->size;
          if (lx->token=='=') {
            LexPop(lx);
            Lex(lx);
            if (!PrsExpression(lx,NULL,TRUE))
              throw(EXCEPT_COMPILER,7);
            tempm->use_cnt=0;
          } else
            lx->stk_ptr--;
          break;
        case PRS_FUN_ARG:
          if (union_base!=MAX_I32) {
            tempm->offset=union_base;
            if (tempc->size-union_base<8)
              tempc->size=8+union_base;
          } else {
            tempm->offset=tempc->size;
            tempc->size+=8;
          }
          if (lx->token=='=') {
            Lex(lx);
            old_flags=lx->flags;
            lx->flags&=~LF_HAS_MISC_DATA;
            ex=CmpExpression(lx,&type);
            if (!ex)
              throw(EXCEPT_COMPILER,8);
            tempm->dft_val=Call(ex);
            while (tempc2->forward_class)
              tempc2=tempc2->forward_class;
            if (tempc2->sub_type==IT_F64) {
              if (type!=IT_F64)
                tempm->dft_val><(F64)=tempm->dft_val;
            } else {
              if (type==IT_F64)
                tempm->dft_val=tempm->dft_val><(F64);
            }
            if (lx->flags & LF_HAS_MISC_DATA) {
              tempm->dft_val=StrNew(tempm->dft_val);
              tempm->flags|=MLF_STR_DFT_AVAILABLE;
            }
            ExpressionDel(ex);
            tempm->flags|=MLF_DFT_AVAILABLE;
            lx->flags|=old_flags&LF_HAS_MISC_DATA;
          }
          lx->stk_ptr--;
          break;
        case PRS_CLASS:
        case PRS_UNION:
          if (union_base!=MAX_I32) {
            tempm->offset=union_base;
            if (tempc->size-union_base<i)
              tempc->size=i+union_base;
          } else {
            tempm->offset=tempc->size;
            tempc->size+=i;
          }
          while (lx->token==TK_IDENT) {
            temp_meta=MAlloc(sizeof(MemberListMeta));
            temp_meta->next=tempm->meta;
            tempm->meta=temp_meta;
            temp_meta->str=lx->ident;
            temp_meta->flags=0;
            lx->ident=NULL;
            if (Lex(lx)==TK_STR) {
              temp_meta->user_data=LexExtStr(lx);
              temp_meta->flags|=MLMF_IS_STR;
            } else
              temp_meta->user_data=Expression(lx);
          }
          lx->stk_ptr--;
          break;
      }
      switch (lx->token) {
        case ',':
          if (mode==PRS_FUN_ARG && union_base==MAX_I32)
            Lex(lx);
          else
            goto restart;
          break;
        case ')':
        case '}':
          Lex(lx);
          goto pvl_done;
        case ';':
          Lex(lx);
          if ((mode==PRS_LOCAL_VAR||mode==PRS_STATIC_LOCAL_VAR) && union_base==MAX_I32)
            goto pvl_done;
          break;
        default:
          PrsExcept(lx,"ST_MISSING_SEMICOLON");
      }
    }
  }
pvl_done:
        if (mode==PRS_LOCAL_VAR) {
                lx->flags=lx->flags&~LF_INSIDE_EXPRESSION;
                lx->last_indent_level=lx->indent_level=1;
                CbIcAdd(lx,EC_NOP,0,0); //record indent_level
        }
}

U0 UndefinedExtern()
{
  PutDefineErr("ST_UNDEFINED_EXTERN");
  PrintF("at %P\r\n",Caller);
  throw(EXCEPT_UNDEF_EXTERN);
}

U0 UnusedExternWarning(LexStruct *lx,ClassStruct *tempc)
{
  PrintFWarn("%S '%s'\r\n","ST_UNUSED_EXTERN",tempc->s.h.str);
  lx->warning_cnt++;
}

ClassStruct *PrsClass(LexStruct *lx,BoolI8 is_union,U64 cps_flags,BoolI8 is_extern)
{
  ClassStruct *tempc;
  if (lx->token!=TK_IDENT)
    PrsExcept(lx,"ST_EXPECTING_IDENTIFIER");
  if (is_extern) {
    tempc=PrsClassNew;
    tempc->s.h.str=lx->ident;
    lx->ident=NULL;
    if (IsReplaceSyms)
      HashReplace(tempc,lx->glbl_hash_table);
    else
      HashAdd(tempc,lx->glbl_hash_table);
    LBts(tempc->flags,Cf_EXTERN);
    SetSrcFileInfo(lx,tempc);
    Lex(lx);
  } else {
    if (lx->flags&LF_STATIC_COMPILE) {
      if (tempc=HashFind(lx->ident,lx->glbl_hash_table,HTT_CLASS)) {
        if (!Bt(tempc->flags,Cf_EXTERN))
          tempc=NULL;
        else if (tempc->s.h.use_cnt<3)
          UnusedExternWarning(lx,tempc);
      }
    } else {
      if (tempc=HashSingleTableFind(lx->ident,lx->glbl_hash_table,HTT_CLASS)) {
        if (!Bt(tempc->flags,Cf_EXTERN))
          tempc=NULL;
        else if (tempc->s.h.use_cnt<3)
          UnusedExternWarning(lx,tempc);
      }
    }
    if (!tempc) {
      tempc=PrsClassNew;
      tempc->s.h.str=lx->ident;
      lx->ident=NULL;
      if (IsReplaceSyms)
        HashReplace(tempc,lx->glbl_hash_table);
      else
        HashAdd(tempc,lx->glbl_hash_table);
    } else {
      Free(tempc->s.src_link);
      Free(tempc->s.index);
    }
    LBtr(tempc->flags,Cf_EXTERN);
    if (cps_flags&CPS_IS_PUBLIC)
      tempc->s.h.type|=HTT_PUBLIC;
    SetSrcFileInfo(lx,tempc);
    tempc->s.h.use_cnt=0;
    Lex(lx);
    PrsVarList(lx,tempc,PRS_CLASS,is_union ?0:MAX_I32);
  }
  return tempc;
}

ClassStruct *PrsFunJoin(LexStruct *lx,
        ClassStruct *temp_return,U8 *name,U64 cps_flags)
{
  MemberListStruct *tempm;
  AsmCtrlStruct *a=lx->a;
  ClassStruct *tempc;
  if (name) { //if not fun_ptr
    if (lx->flags&LF_STATIC_COMPILE) {
      if (tempc=HashFind(name,lx->glbl_hash_table,HTT_FUN)) {
        if (tempc->s.h.type & HTT_IMPORT)
          tempc=NULL;
        else
          if (tempc->s.h.use_cnt<3)
            UnusedExternWarning(lx,tempc);
      }
    } else {
      if (tempc=HashSingleTableFind(name,lx->glbl_hash_table,HTT_FUN)) {
        if (!Bt(tempc->flags,Cf_EXTERN))
          tempc=NULL;
        else if (tempc->s.h.use_cnt<3)
          UnusedExternWarning(lx,tempc);
      }
    }
  } else
    tempc=NULL;
  if (!tempc) {
    tempc=PrsClassNew;
    tempc->used_reg_mask=CALWAYS_CLOBBERED_MASK+CSTK_TEMPS_MASK;
    tempc->clobbered_reg_mask=CALWAYS_CLOBBERED_MASK+CSTK_TEMPS_MASK;
    tempc->s.h.type=HTT_FUN;
    tempc->s.h.str=name;
    if (lx->flags&LF_STATIC_COMPILE)
      tempc->executable_address=a->ip;
    else
      tempc->executable_address=&UndefinedExtern;
    LBts(tempc->flags,Cf_EXTERN);
    if (cps_flags&CPS_IS_INTERRUPT)
      Bts(tempc->flags,Cf_INTERRUPT);
    if (cps_flags&CPS_IS_ARGPOP)
      Bts(tempc->flags,Cf_ARGPOP);
    if (cps_flags&CPS_IS_NOARGPOP)
      Bts(tempc->flags,Cf_NOARGPOP);
    if (name) { //if not fun_ptr
      if (IsReplaceSyms)
        HashReplace(tempc,lx->glbl_hash_table);
      else
        HashAdd(tempc,lx->glbl_hash_table);
    }
  } else {
    tempc->used_reg_mask=CALWAYS_CLOBBERED_MASK+CSTK_TEMPS_MASK;
    Free(tempc->s.src_link);
    Free(tempc->s.index);
    Free(name);
    MemberListDel(tempc);
  }
  if (cps_flags&CPS_IS_PUBLIC)
    tempc->s.h.type|=HTT_PUBLIC;
  else
    tempc->s.h.type&=~HTT_PUBLIC;
  tempc->return_class=temp_return;
  tempc->s.h.use_cnt=0;
  SetSrcFileInfo(lx,tempc);
  PrsVarList(lx,tempc,PRS_FUN_ARG);
  tempc->arg_cnt=tempc->member_cnt;
  if (0<tempc->arg_cnt<<3<=MAX_I16 && !Bt(tempc->flags,Cf_DOT_DOT_DOT))
    LBts(tempc->flags,Cf_RET1);
  tempm=tempc->member_list;
  while (tempm) {
    tempm->offset+=16; //RBP+RETURN
    tempm=tempm->next;
  }
  tempc->size=0;
  return tempc;
}

U0 PrsFun(LexStruct *lx,
        ClassStruct *temp_return,U8 *name,U64 cps_flags)
{
  U64 *result;
  ClassStruct *tempc;
  MemberListStruct *tempm;
  CbMiscStruct *saved_leave_label;
  U64 i,j,size;
  DbgInfo *dbg=NULL;
  IndentInfo *indent=NULL;
  BoolI8 old_ctrace;
  lx->flags&=~LF_NO_REG_OPT;
  tempc=PrsFunJoin(lx,temp_return,name,cps_flags);
  lx->local_var_list=tempc;
  CbPush(lx);
  Btr(&lx->flags,LFf_OPT_TRACE_PRESENT);
  CbOutPtrsInit(lx);
  CbIcAdd(lx,EC_START,0,0); //So we can scan back an instruction
  lx->last_indent_level=lx->indent_level=0;
  CbIcAdd(lx,EC_ENTER,0,0);
  saved_leave_label=lx->lb_leave;
  lx->lb_leave=CbMiscNew(lx,CBMT_LABEL);
  lx->flags&=~LF_HAS_RETURN;
  PrsStatement(lx,tempc,0,NULL,FALSE);
  if (tempc->return_class->size &&
      !(lx->flags&LF_HAS_RETURN))
    PutLexWarn(lx,"ST_SHOULD_RETURN_VAL");
  lx->last_indent_level=lx->indent_level=0;
  CbIcAdd(lx,EC_LABEL,lx->lb_leave,0);
  lx->lb_leave=saved_leave_label;
  CbIcAdd(lx,EC_LEAVE,0,tempc->return_class);
  CbIcAdd(lx,EC_END,0,0);
  tempc->size&=~7;
  if (lx->flags&LF_STATIC_COMPILE) {
    tempc->executable_address=lx->a->ip;
    tempc->s.h.type|=HTT_EXPORT;
    result=CbCompile(lx,tempc,&size,&dbg,&indent);
    tempc->s.debug=dbg;
    tempc->s.indent=indent;
    if (result) {
      j=(size+7)>>3;
      for (i=0;i<j;i++)
        AsmStoreCodeU64(lx,result[i]);
      Free(result);
    }
  } else {
    old_ctrace=Btr(&lx->opts,OPTf_COMPILE_TRACE);
    tempc->executable_address=CbCompile(lx,tempc,&size,&dbg,&indent);
    tempc->s.debug=dbg;
    tempc->s.indent=indent;
    if (old_ctrace) {
      Bts(&lx->opts,OPTf_COMPILE_TRACE);
      Un(tempc->executable_address,size,64);
    }
    SysSymImportsResolve(tempc->s.h.str);
  }
  LBtr(tempc->flags,Cf_EXTERN);
  CbPop(lx);
  lx->local_var_list=NULL;
  tempm=tempc->member_list;
  while (tempm) {
    if (tempm->flags & MLF_NO_UNUSED_WARN) {
      if (tempm->use_cnt!=1) {
        PrintFWarn("%S\r\n $LK-A,\"FL:%s,%d\"$ '","ST_UNNEEDED_NOUNUSEDWARN",
          lx->cur_lfn->name,lx->cur_lfn->line_num);
        coutln tempm->str,"' in '",tempc->s.h.str,"'";
      }
    } else if (!tempm->use_cnt && GetOpt(OPTf_UNUSED_VAR_WARN)) {
      PrintFWarn("%S\r\n $LK-A,\"FL:%s,%d\"$ '","ST_UNUSED_VAR",
        lx->cur_lfn->name,lx->cur_lfn->line_num);
      coutln tempm->str,"' in '",tempc->s.h.str,"'";
    }
    tempm=tempm->next;
  }
}

U0 PrsGlblVarList(LexStruct *lx,I64 saved_mode,ClassStruct *saved_tempc,
  U64 saved_val,U64 cps_flags)
{
  I64 i,j,mode;
  U64 k,val;
  U8 *st;
  ExportSysSymHashEntry *tempess;
  GlblVarStruct *tempg;
  AsmCtrlStruct *a=lx->a;
  ExeHeapGlblStruct *temphg;
  ClassStruct *tempc,*tempc1,*tempc_fun_ptr;
  ArrayDimStruct tempad;
  BoolI8 has_alias,undef_array_size;
  while (TRUE) {
    tempc=PrsType(lx,&saved_tempc,&saved_mode,NULL,&st,
        &tempc_fun_ptr,&tempess,&tempad,cps_flags);
    if (!st)
      return;
    val=saved_val;
    mode=saved_mode;
    if (tempess && mode==PRS_EXTERN && !(lx->flags&LF_STATIC_COMPILE)) {
      if (tempess->s.h.type & HTT_EXPORT_SYS_SYM) {
        val=tempess->val;
        mode=PRS_LTEXTERN;
      }
    }
    if (lx->token=='(') {
      switch (mode) {
        case PRS_LTINTERN:
          tempc1=PrsFunJoin(lx,tempc,st,cps_flags);
          tempc1->executable_address=val;
          Bts(tempc1->flags,Cf_INTERNAL_FUN);
          LBtr(tempc1->flags,Cf_EXTERN);
          return;
        case PRS_LTEXTERN:
          tempc1=PrsFunJoin(lx,tempc,st,cps_flags);
          tempc1->executable_address=val;
          LBtr(tempc1->flags,Cf_EXTERN);
          SysSymImportsResolve(tempc1->s.h.str);
          return;
        case PRS_EXTERN:
          PrsFunJoin(lx,tempc,st,cps_flags);
          return;
        case PRS_IMPORT:
        case PRS_LTIMPORT:
          if (!(lx->flags&LF_STATIC_COMPILE))
            PrsExcept(lx,"ST_IMPORT_NOT_NEEDED");
          else {
            tempc1=PrsFunJoin(lx,tempc,st,cps_flags);
            tempc1->s.h.type|=HTT_IMPORT;
            if (mode==PRS_LTIMPORT)
              tempc1->s.import_name=StrNew(val);
            else
              tempc1->s.import_name=StrNew(st);
          }
          return;
        case PRS_TYPEDEF:
          PrsExcept(lx,"ST_INVALID_TYPEDEF");
        default:
          PrsFun(lx,tempc,st,cps_flags);
          return;
      }
    } else {
      if (tempad.total_cnt<0) {
        i=0;
        undef_array_size=TRUE;
      } else {
        i=tempad.total_cnt;
        undef_array_size=FALSE;
      }
      if (tempc_fun_ptr)
        j=sizeof(U0 *);
      else
        j=tempc->size;
      j*=i;
      has_alias=FALSE;
      temphg=NULL;
      switch (mode) {
        case PRS_LTEXTERN:
          if (lx->flags&LF_STATIC_COMPILE) {
            tempg=CAlloc(sizeof(GlblVarStruct));
            tempg->data_address_ip=val;
            tempg->s.h.type=HTT_GLBL_VAR | HTT_EXPORT;
          } else {
            tempg=CAlloc(sizeof(GlblVarStruct),Fs->code_heap);
            tempg->data_address=val;
            tempg->s.h.type=HTT_GLBL_VAR;
          }
          tempg->flags|=GVAF_ALIAS;
          break;
        case PRS_LTIMPORT:
        case PRS_IMPORT:
          if (!(lx->flags&LF_STATIC_COMPILE))
            PrsExcept(lx,"ST_IMPORT_NOT_NEEDED");
          else {
            tempg=CAlloc(sizeof(GlblVarStruct));
            tempg->s.h.type=HTT_GLBL_VAR | HTT_IMPORT;
            if (mode==PRS_LTIMPORT)
              tempg->s.import_name=StrNew(val);
            else
              tempg->s.import_name=StrNew(st);
          }
          break;
        case PRS_EXTERN:
          if (lx->flags&LF_STATIC_COMPILE) {
            tempg=CAlloc(sizeof(GlblVarStruct));
            tempg->s.h.type=HTT_GLBL_VAR;
          } else {
            tempg=CAlloc(sizeof(GlblVarStruct),Fs->code_heap);
            tempg->s.h.type=HTT_GLBL_VAR|HTT_UNRESOLVED_GLBL;
          }
          break;
        case PRS_TYPEDEF:
          tempg=CAlloc(sizeof(GlblVarStruct));
          tempg->s.h.type=HTT_TYPEDEF;
          break;
        default:
          if (lx->flags&LF_STATIC_COMPILE) {
            if (Bt(&lx->opts,OPTf_GLBLS_ON_DATA_HEAP)) {
              if (lx->token=='=')
                PrsExcept(lx,"ST_CANT_INIT_GLBL_ON_HEAP");
              tempg=CAlloc(sizeof(GlblVarStruct));
              temphg=tempg->heap_glbl=CAlloc(sizeof(ExeHeapGlblStruct));
              temphg->size=j;
              temphg->str=StrNew(st);
              temphg->next=a->heap_glbls;
              a->heap_glbls=temphg;
              tempg->flags=GVAF_DATA_HEAP;
              tempg->s.h.type=HTT_GLBL_VAR; //TODO: HTT_EXPORT
              if (tempess && tempess->s.h.type & HTT_GLBL_VAR) //TODO!! extern
                PrsExcept(lx,"ST_NOT_IMPLEMENTED");
            } else {
              tempg=CAlloc(sizeof(GlblVarStruct));
              if (lx->token=='=')
                tempg->data_address=CAlloc(j);
              if (tempc->size>=8) //align
                while (a->ip&7)
                  AsmStoreCodeU8(lx,0);
              else if (tempc->size==4)
                while (a->ip&3)
                  AsmStoreCodeU8(lx,0);
              else if (tempc->size==2)
                while (a->ip&1)
                  AsmStoreCodeU8(lx,0);
              tempg->data_address_ip=a->ip;
              tempg->s.h.type=HTT_GLBL_VAR | HTT_EXPORT;
              if (tempess && tempess->s.h.type & HTT_GLBL_VAR)
                has_alias=TRUE;
              if (sys_var_init_flag&1)
                for (k=0;k<j;k++)
                  AsmStoreCodeU8(lx,sys_var_init_val);
                else
                for (k=0;k<j;k++)
                  AsmStoreCodeU8(lx,0);
                }
          } else {
            if (Bt(&lx->opts,OPTf_GLBLS_ON_DATA_HEAP)) {
              tempg=CAlloc(sizeof(GlblVarStruct),Fs->code_heap);
              tempg->data_address=MAlloc(j);
              tempg->flags=GVAF_DATA_HEAP;
            } else {
              tempg=CAlloc(sizeof(GlblVarStruct),Fs->code_heap);
              tempg->data_address=MAlloc(j,Fs->code_heap);
            }
            tempg->s.h.type=HTT_GLBL_VAR;
            if (tempess && tempess->s.h.type&HTT_GLBL_VAR &&
                tempess->s.h.type&HTT_UNRESOLVED_GLBL &&
                MHeapCtrl(tempess)==MHeapCtrl(tempg))
              has_alias=TRUE;
            if (sys_var_init_flag&1)
              MemSet(tempg->data_address,sys_var_init_val,j);
          }
      }
      tempg->dim.next=tempad.next;
      if (cps_flags&CPS_IS_PUBLIC)
        tempg->s.h.type|=HTT_PUBLIC;
      tempg->arg_cnt=0;
      tempg->var_class=tempc;
      tempg->s.h.str=st;
      tempg->size=j;
      tempg->dim.total_cnt=i;
      tempg->s.h.use_cnt=0;
      SetSrcFileInfo(lx,tempg);
      if (mode==PRS_IMPORT || mode==PRS_LTIMPORT)
        tempg->flags|=GVAF_IMPORT;
      if (mode==PRS_EXTERN)
        tempg->flags|=GVAF_EXTERN;
      if (tempc_fun_ptr) {
        tempg->fun_ptr=tempc_fun_ptr;
        tempg->flags|=GVAF_FUN;
      }
      if (IsReplaceSyms)
        HashReplace(tempg,lx->glbl_hash_table);
      else
        HashAdd(tempg,lx->glbl_hash_table);
      if (!(lx->flags&LF_STATIC_COMPILE) && !(tempg->flags&GVAF_EXTERN))
        SysSymImportsResolve(tempg->s.h.str);
      if (lx->token=='=') {
        if (undef_array_size) {
          LexPush(lx);
          LexPush(lx);
          Lex(lx);
          PrsGlblInit(lx,tempg,1);
          lx->stk_ptr--;        //grows up
          tempg->size=tempg->dim.total_cnt*tempc->size;
          if (temphg)
            temphg->size=tempg->dim.total_cnt*tempc->size;
          if (lx->flags&LF_STATIC_COMPILE) {
            if (sys_var_init_flag&1)
              for (k=0;k<tempg->size;k++)
                AsmStoreCodeU8(lx,sys_var_init_val);
            else
              for (k=0;k<tempg->size;k++)
                AsmStoreCodeU8(lx,0);
          } else
            if (sys_var_init_flag&1)
              MemSet(tempg->data_address,sys_var_init_val,k);
          LexPop(lx);
        }
        LexPush(lx);
        Lex(lx);
        PrsGlblInit(lx,tempg,2);
        if (lx->flags&LF_STATIC_COMPILE)
          for (k=0;k<tempg->size;k++)
            AsmStoreCodeU8At(lx,tempg->data_address[k],tempg->data_address_ip+k);
          lx->stk_ptr--;        //grows up
      }
      if (has_alias) {
        tempess><(GlblVarStruct *)->flags|=GVAF_ALIAS;
        tempess><(GlblVarStruct *)->data_address=tempg->data_address;
        tempess><(GlblVarStruct *)->data_address_ip=tempg->data_address_ip;
      }
      if (lx->token==',')
        Lex(lx);
      else {
        if (lx->token!=';')
          PrsExcept(lx,"ST_MISSING_SEMICOLON");
        Lex(lx);
        return;
      }
    }
  }
}

U0 PrsIf(LexStruct *lx,ClassStruct *locals,I64 try_cnt,
  CbMiscStruct *lb_break)
{
  CbMiscStruct *lb,*lb1;
  I64 k;

  if (lx->token!='(')
    PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
  Lex(lx);
  if (!PrsExpression(lx,NULL,FALSE))
    throw(EXCEPT_COMPILER,11);
  if (lx->token!=')')
    PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
  Lex(lx);
  lb=CbMiscNew(lx,CBMT_LABEL);
  lx->last_indent_level++;
  lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
  CbIcAdd(lx,EC_BR_ZERO,lb,0);
  PrsStatement(lx,locals,try_cnt,lb_break);
  k=PrsKeyWord(lx);
  if (k==KW_ELSE) {
    lx->last_indent_level--;
    lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
    CbIcAdd(lx,EC_NOP,0,0); //record indent_level

    Lex(lx);

    lx->last_indent_level++;
    lb1=CbMiscNew(lx,CBMT_LABEL);
    CbIcAdd(lx,EC_JMP,lb1,0);
    CbIcAdd(lx,EC_LABEL,lb,0);
    PrsStatement(lx,locals,try_cnt,lb_break,TRUE,TRUE);
    CbIcAdd(lx,EC_LABEL,lb1,0);
  } else
    CbIcAdd(lx,EC_LABEL,lb,0);
}

U0 PrsWhile(LexStruct *lx,ClassStruct *locals,I64 try_cnt)
{
  CbMiscStruct *lb,*lb_done;

  if (lx->token!='(')
    PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
  Lex(lx);
  lb=CbMiscNew(lx,CBMT_LABEL);
  CbIcAdd(lx,EC_LABEL,lb,0);
  if (!PrsExpression(lx,NULL,FALSE))
    throw(EXCEPT_COMPILER,12);
  if (lx->token!=')')
    PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
  Lex(lx);

  lb_done=CbMiscNew(lx,CBMT_LABEL);
  CbIcAdd(lx,EC_BR_ZERO,lb_done,0);
  PrsStatement(lx,locals,try_cnt,lb_done);
  CbIcAdd(lx,EC_JMP,lb,0);
  CbIcAdd(lx,EC_LABEL,lb_done,0);
}

U0 PrsDoWhile(LexStruct *lx,ClassStruct *locals,I64 try_cnt)
{
  CbMiscStruct *lb,*lb_done;

  lb=CbMiscNew(lx,CBMT_LABEL);
  lb_done=CbMiscNew(lx,CBMT_LABEL);
  CbIcAdd(lx,EC_LABEL,lb,0);
  PrsStatement(lx,locals,try_cnt,lb_done);
  if (PrsKeyWord(lx)!=KW_WHILE)
    PrsExcept(lx,"ST_MISSING_WHILE");
  if (Lex(lx)!='(')
    PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
  Lex(lx);
  if (!PrsExpression(lx,NULL,FALSE))
    throw(EXCEPT_COMPILER,13);
  if (lx->token!=')')
    PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
  CbIcAdd(lx,EC_BR_NOT_ZERO,lb,0);
  CbIcAdd(lx,EC_LABEL,lb_done,0);
  if (Lex(lx)!=';')
    PrsExcept(lx,"ST_MISSING_SEMICOLON");
  Lex(lx);
}

U0 PrsFor(LexStruct *lx,ClassStruct *locals,I64 try_cnt)
{
  LexCbHeader *tempcbh;
  CbMiscStruct *lb,*lb_done;

  CbIcAdd(lx,EC_NOP,0,0); //record indent_level
  lx->last_indent_level=lx->indent_level--;
  if (lx->token!='(')
    PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
  Lex(lx);
  PrsStatement(lx,locals,try_cnt);

  lb=CbMiscNew(lx,CBMT_LABEL);
  CbIcAdd(lx,EC_LABEL,lb,0);
  if (!PrsExpression(lx,NULL,FALSE))
    throw(EXCEPT_COMPILER,14);
  lb_done=CbMiscNew(lx,CBMT_LABEL);
  CbIcAdd(lx,EC_BR_ZERO,lb_done,0);
  if (lx->token!=';')
    PrsExcept(lx,"ST_MISSING_SEMICOLON");
  Lex(lx);

  CbPush(lx);
  CbOutPtrsInit(lx);
  if (lx->token!=')')
    PrsStatement(lx,locals,try_cnt,NULL,FALSE);
  CbIcAdd(lx,EC_END,0,0);
  CbPush(lx);
  tempcbh=CbPopNoFree(lx);
  CbPop(lx);
  if (lx->token!=')')
    PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
  Lex(lx);

  lx->last_indent_level=lx->indent_level++;
  PrsStatement(lx,locals,try_cnt,lb_done);
  CbAppend(lx,tempcbh);
  CbIcAdd(lx,EC_JMP,lb,0);
  lx->last_indent_level--;
  lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
  CbIcAdd(lx,EC_LABEL,lb_done,0);
}

class SwitchCaseEntry {
  SwitchCaseEntry *next;
  CbMiscStruct *label;
  I64 val;
};

U0 PrsSwitch(LexStruct *lx,BoolI8 nobound,ClassStruct *locals,I64 try_cnt)
{
  SwitchCaseEntry *header=NULL,*temps,*temps1;
  CbMiscStruct *lb_break,*lb_dft,*mc_jt,*lb_entry,**jmp_table;
  IntermediateCode *tempi_sub,*tempi_cmp;
  BoolI8 dft_found=FALSE,first=TRUE;
  I64 i,k,k2,lo=MAX_I64,hi=MIN_I64,range;

  if (lx->token!='(')
    PrsExcept(lx,"ST_EXPECTING_LEFT_PAREN");
  Lex(lx);
  lb_break=CbMiscNew(lx,CBMT_LABEL);
  lb_break->flags|=CBMF_USED;
  lb_dft=CbMiscNew(lx,CBMT_LABEL);
  lb_dft->flags|=CBMF_USED;
  mc_jt=CbMiscNew(lx,CBMT_JMP_TABLE);
  if (!PrsExpression(lx,NULL,FALSE))
    throw(EXCEPT_COMPILER,15);
  tempi_sub=CbIcAdd(lx,EC_IMM,0,sys_internal_types[IT_I64]);
  CbIcAdd(lx,EC_SUB,0,sys_internal_types[IT_I64]);
  tempi_cmp=CbIcAdd(lx,EC_IMM,0,sys_internal_types[IT_I64]);
  if (nobound)
    CbIcAdd(lx,EC_NOBOUND_SWITCH,mc_jt,0);
  else
    CbIcAdd(lx,EC_SWITCH,mc_jt,0);
  if (lx->token!=')')
    PrsExcept(lx,"ST_MISSING_RIGHT_PAREN");
  if (Lex(lx)!='{')
    PrsExcept(lx,"ST_EXPECTING_LEFT_BRACE");
  Lex(lx);
  lx->last_indent_level=lx->indent_level++;
  while (lx->token && lx->token!='}') {
    k=PrsKeyWord(lx);
    if (k==KW_CASE) {
      Lex(lx);
      lb_entry=CbMiscNew(lx,CBMT_LABEL);
      CbIcAdd(lx,EC_LABEL,lb_entry,0);
      lb_entry->flags|=CBMF_USED;
      k=Expression(lx);
      if (k<lo) lo=k;
      if (k>hi) hi=k;
      if (lx->token==':') {
        Lex(lx);
        temps=MAlloc(sizeof(SwitchCaseEntry));
        temps->label=lb_entry;
        temps->val=k;
        temps->next=header;
        header=temps;
      } else if (lx->token==TK_DOT_DOT_DOT && !Bt(&lx->opts,OPTf_STD_C)) {
        Lex(lx);
        k2=Expression(lx);
        if (lx->token==':') {
          Lex(lx);
          if (k2<lo) lo=k2;
          if (k2>hi) hi=k2;
          if (k>k2)
            SwapU64(&k,&k2);
          for (i=k;i<=k2;i++) {
            temps=MAlloc(sizeof(SwitchCaseEntry));
            temps->label=lb_entry;
            temps->val=i;
            temps->next=header;
            header=temps;
          }
          } else
          PrsExcept(lx,"ST_EXPECTING_COLON");
      } else
        PrsExcept(lx,"ST_EXPECTING_COLON");
      first=TRUE;
    } else if (k==KW_DFT) {
      Lex(lx);
      CbIcAdd(lx,EC_LABEL,lb_dft,0);
      if (lx->token==':')
        Lex(lx);
      dft_found=TRUE;
      first=TRUE;
    } else {
      if (first) {
        lx->last_indent_level++;
        lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
        CbIcAdd(lx,EC_NOP,0,0); //record indent_level
        first=FALSE;
      }
      PrsStatement(lx,locals,try_cnt,lb_break);
    }
  }

  lx->last_indent_level=lx->indent_level--;
  lx->last_indent_level--;
  lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
  if (!dft_found)
    CbIcAdd(lx,EC_LABEL,lb_dft,0);
  CbIcAdd(lx,EC_LABEL,lb_break,0);
  if (lx->token!='}')
    PrsExcept(lx,"ST_MISSING_RIGHT_BRACE");
  Lex(lx);

  if (0<lo<=16)
    lo=0;
  range=hi-lo+1;
  if (range<=0 || range>0x4000)
    PrsExcept(lx,"ST_CASE_RANGE_ERROR");
  jmp_table=MAlloc(sizeof(CbMiscStruct *)*range);
  MemSetU64(jmp_table,lb_dft,range);
  tempi_sub->ic_data=lo;
  tempi_cmp->ic_data=range;
  temps=header;
  while (temps) {
    temps1=temps->next;
    if (jmp_table[temps->val-lo]!=lb_dft)
      PrsExcept(lx,"ST_DUP_CASE");
    else
      jmp_table[temps->val-lo]=temps->label;
    Free(temps);
    temps=temps1;
  }
  mc_jt->dft=lb_dft;
  mc_jt->jmp_table=jmp_table;
  mc_jt->range=range;
}

U0 PrsNoUnusedWarn(LexStruct *lx)
{
  MemberListStruct *tempm;
  while (lx->token==TK_IDENT) {
    if (!(tempm=lx->local_var_entry))
      PrsExcept(lx,"ST_EXPECTING_LOCAL_VAR");
    tempm->flags|=MLF_NO_UNUSED_WARN;
    if (Lex(lx)==',')
      Lex(lx);
    else {
      if (lx->token!=';')
        PrsExcept(lx,"ST_EXPECTING_COMMA");
    }
  }
}

U0 PrsCout(LexStruct *lx,BoolI8 linefeed)
{
  ClassStruct *tempc;
  IntermediateCode *tempi;
  I64 cnt=0,i,j;

  CbIcAdd(lx,EC_CALL_START,0,0);
  while (lx->token!=';') {
    cnt++;
    if (!PrsExpression(lx,NULL,FALSE))
      throw(EXCEPT_COMPILER,16);
    tempi=lx->cbh.cb_last_out_ptr;
    tempi->ic_flags|=ICF_PUSH_RESULT;
    tempc=tempi->ic_class;
    j=tempc->ptr_cnt;
    tempc-=j;
    while (tempc->forward_class)
      tempc=tempc->forward_class;
    i=tempc->sub_type+j*IT_NUM_IT;
    CbIcAdd(lx,EC_TYPE,i,sys_internal_types[IT_I64],ICF_PUSH_RESULT);
    if (lx->token==',')
      Lex(lx);
    else {
      if (lx->token!=';')
        PrsExcept(lx,"ST_EXPECTING_COMMA");
    }
  }
  CbIcAdd(lx,EC_IMM,cnt,sys_internal_types[IT_U64]);
  CbIcAdd(lx,EC_SET_RAX,0,sys_internal_types[IT_U64]);

/*
See COutIrq.

RAX is item cnt going into the INT.
Item are a type/item pair.  See IT_NUM_IT
in reverse order (PASCAL) pushed on the stk.
I don't want to junk-it-up.
See ::/LT/Doc/Lectures/CuttingCorners.TXZ.

*/


  if (linefeed)
    CbIcAdd(lx,EC_IRQ,I_COUTLN,0);
  else
    CbIcAdd(lx,EC_IRQ,I_COUT,0);
  CbIcAdd(lx,EC_ADD_RSP,cnt<<4,0);
  CbIcAdd(lx,EC_CALL_END,0,sys_internal_types[IT_I64]);
  CbIcAdd(lx,EC_END_EXP,0,0);
}

U0 PrsStreamBlk(LexStruct *lx)
{
  SysHashTable *ht1=lx->hash_table_list,
               *ht2=lx->define_hash_table,
               *ht3=lx->glbl_hash_table,
               *ht4=lx->local_hash_table,
               *ht5=lx->stream_parent_glbl_hash_table;
  U64 old_hash_mask=lx->hash_mask;

  U64 old_flags=lx->flags & (LF_ASM_EXPRESSIONS | LF_EXE_BLK|LF_STATIC_COMPILE);
  StreamBlkStruct *tempe=MAlloc(sizeof(StreamBlkStruct));
  ClassStruct *old_var_list=lx->local_var_list;
  lx->local_var_list=NULL;

  tempe->body=StrNew("");
  InsQue(tempe,lx->last_stream_blk);
  CbPush(lx);
  lx->cbh.cb_misc_list=NULL;
  lx->cbh.cb_misc_list_end=&lx->cbh.cb_misc_list;

  lx->stream_parent_glbl_hash_table=lx->glbl_hash_table;
  lx->hash_mask=HTT_ALL-HTT_IMPORT_SYS_SYM-HTT_ASM_KEYWORD;
  lx->define_hash_table=lx->hash_table_list=lx->glbl_hash_table=lx->local_hash_table=Fs->hash_table;
  lx->flags=lx->flags & ~(LF_ASM_EXPRESSIONS|LF_STATIC_COMPILE) | LF_EXE_BLK;
  if (lx->token=='{')
    Lex(lx);
  else
    PrsExcept(lx,"ST_MISSING_RIGHT_BRACE");
  while (lx->token && lx->token!='}')
    ExeCmdLine(lx);

  lx->hash_table_list  =ht1,
  lx->define_hash_table=ht2;
  lx->glbl_hash_table  =ht3;
  lx->local_hash_table =ht4;
  lx->stream_parent_glbl_hash_table=ht5;

  lx->local_var_list=old_var_list;
  lx->hash_mask=old_hash_mask;
  lx->flags= lx->flags&~LF_EXE_BLK | old_flags;
  CbPop(lx);
  RemQue(tempe);
  if (*tempe->body)
    LexIncludeStr(lx,"StreamBlk",tempe->body,FALSE);
  else
    Free(tempe->body);
  Free(tempe);
  Lex(lx); //Skip "}"
}


U0 PrsTryBlk(LexStruct *lx,ClassStruct *locals,I64 try_cnt)
{
  CbMiscStruct *lb_catch,*lb_done,*lb_untry;
  BoolI8 has_brace;
  ClassStruct *tempc=sys_internal_types[IT_PTR],
    *temp_try=HashFind("SysTry",lx->hash_table_list,HTT_FUN),
    *temp_untry=HashFind("SysUntry",lx->hash_table_list,HTT_FUN);

  lx->flags|=LF_NO_REG_OPT; //TODO (Currently no reg vars in funs with try/catch)

  lb_catch=CbMiscNew(lx,CBMT_LABEL);
  lb_done=CbMiscNew(lx,CBMT_LABEL);
  lb_untry=CbMiscNew(lx,CBMT_LABEL);

  lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
  if (lx->token=='{')
    has_brace=TRUE;
  else {
    lx->last_indent_level=lx->indent_level++;
    has_brace=FALSE;
    lx->last_indent_level++;
  }

  CbIcAdd(lx,EC_CALL_START,0,0);
  CbIcAdd(lx,EC_GET_LABEL,lb_untry,tempc,ICF_PUSH_RESULT);
  CbIcAdd(lx,EC_GET_LABEL,lb_catch,tempc,ICF_PUSH_RESULT);
  if (Bt(temp_try->flags,Cf_EXTERN)) {
    if (lx->flags&LF_STATIC_COMPILE)
      CbIcAdd(lx,EC_CALL_IMPORT,temp_try,tempc);
    else
      CbIcAdd(lx,EC_CALL_INDIRECT2,&temp_try->executable_address,tempc);
  } else
    CbIcAdd(lx,EC_CALL,temp_try->executable_address,tempc);
  if ((Bt(temp_try->flags,Cf_RET1) || Bt(temp_try->flags,Cf_ARGPOP)) && !Bt(temp_try->flags,Cf_NOARGPOP))
    CbIcAdd(lx,EC_ADD_RSP1,16,tempc);
  else
    CbIcAdd(lx,EC_ADD_RSP,16,tempc);
  CbIcAdd(lx,EC_CALL_END,0,tempc);
  CbIcAdd(lx,EC_END_EXP,0,0);

  PrsStatement(lx,locals,try_cnt+1);
  if (!has_brace)
    lx->last_indent_level=lx->indent_level--;

  CbIcAdd(lx,EC_LABEL,lb_untry,0);
  CbIcAdd(lx,EC_CALL_START,0,0);
  if (Bt(temp_untry->flags,Cf_EXTERN)) {
    if (lx->flags&LF_STATIC_COMPILE)
      CbIcAdd(lx,EC_CALL_IMPORT,temp_untry,tempc);
    else
      CbIcAdd(lx,EC_CALL_INDIRECT2,&temp_untry->executable_address,tempc);
  } else
    CbIcAdd(lx,EC_CALL,temp_untry->executable_address,tempc);
  CbIcAdd(lx,EC_CALL_END,0,tempc);
  CbIcAdd(lx,EC_END_EXP,0,0);

  CbIcAdd(lx,EC_JMP,lb_done,0);

  if (PrsKeyWord(lx)!=KW_CATCH)
    PrsExcept(lx,"ST_MISSING_CATCH");

  Lex(lx);
  lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
  if (lx->token=='{')
    has_brace=TRUE;
  else {
    lx->last_indent_level=lx->indent_level++;
    lx->last_indent_level++;
    has_brace=FALSE;
  }
  CbIcAdd(lx,EC_LABEL,lb_catch,0);
  PrsStatement(lx,locals,try_cnt+1);
  if (!has_brace)
    lx->last_indent_level=lx->indent_level--;
  CbIcAdd(lx,EC_RET,0,tempc);
  CbIcAdd(lx,EC_LABEL,lb_done,0);
}

BoolI64 PrsStatement(LexStruct *lx,ClassStruct *locals,I64 try_cnt=0,
  CbMiscStruct *lb_break=NULL,BoolI8 saved_prs_semicolon=TRUE,BoolI8 if_else=FALSE)
{
  BoolI8 prs_exp,cont,prs_semicolon;
  U64 i,cps_flags=0,last_cps_flags=0;
  ExportSysSymHashEntry *tempess;
  CbMiscStruct *g_lb;
  U8 *import_name;
  ClassStruct *temp_untry;
  ExeStruct *tempex;

  lx->last_indent_level=lx->indent_level++;
  do {
    cps_flags&=~CPS_FUN_FLAGS;
    cont=FALSE;
    prs_exp=FALSE;
    prs_semicolon=saved_prs_semicolon;
    lx->statement_cnt++;
    while (lx->token==',')
      Lex(lx);
    if (lx->token=='{') {
      Lex(lx);

      lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
      CbIcAdd(lx,EC_NOP,0,0); //record indent_level

      lx->last_indent_level=lx->indent_level--;
      lx->braces_cnt++;
      while (lx->token!='}')
        PrsStatement(lx,locals,try_cnt,lb_break);


      lx->last_indent_level--;
      lx->indent_line_offset=lx->start_line_num-lx->last_line_num;
      CbIcAdd(lx,EC_NOP,0,0); //record indent_level

      lx->braces_cnt--;
      lx->statement_cnt--;
      lx->last_indent_level=lx->indent_level++;
      Lex(lx);
    } else if (lx->token==TK_EOF) ;
    else if (lx->token==';') {
      if (prs_semicolon) {
        lx->statement_cnt--;
        Lex(lx);
      }
    } else {
      if (lx->token==TK_IDENT) {
        if (tempess=lx->hash_entry) {
          if (tempess->s.h.type & HTT_KEYWORD) {
            i=tempess><(GenericHashEntry *)->user_data0;
            nobound_switch (i) {
              case KW_IF:
                Lex(lx);
                if (if_else)
                  lx->last_indent_level=lx->indent_level--;
                PrsIf(lx,locals,try_cnt,lb_break);
                if (if_else)
                  lx->last_indent_level=lx->indent_level++;
                prs_semicolon=FALSE;
                break;
              case KW_FOR:
                Lex(lx);
                PrsFor(lx,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_WHILE:
                Lex(lx);
                PrsWhile(lx,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_DO:
                Lex(lx);
                PrsDoWhile(lx,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_NOBOUND_SWITCH:
                Lex(lx);
                PrsSwitch(lx,TRUE,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_SWITCH:
                Lex(lx);
                PrsSwitch(lx,FALSE,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_LOCK:
                Lex(lx);
                lx->lock_cnt++;
                PrsStatement(lx,locals,try_cnt);
                lx->lock_cnt--;
                prs_semicolon=FALSE;
                break;
              case KW_LTEXTERN:
                Lex(lx);
                if (Bt(&lx->opts,OPTf_EXTERNS_TO_IMPORTS))
                  goto keyword_LTimport;
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_SYS_SYM");
                if (!(tempess=lx->hash_entry))
                  PrsExcept(lx,"ST_EXPECTING_SYS_SYM");
                if (!(tempess->s.h.type & HTT_EXPORT_SYS_SYM))
                  PrsExcept(lx,"ST_EXPECTING_SYS_SYM");
                i=tempess->val;
                if (Lex(lx)!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess=lx->hash_entry))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                Lex(lx);
                PrsGlblVarList(lx,PRS_LTEXTERN,tempess,i,last_cps_flags);
                prs_semicolon=FALSE;
                cont=TRUE;
                break;
              case KW_LTIMPORT:
                Lex(lx);
keyword_LTimport:
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_SYS_SYM");
                import_name=lx->ident;
                lx->ident=0;
                if (Lex(lx)!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess=lx->hash_entry))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                Lex(lx);
                PrsGlblVarList(lx,PRS_LTIMPORT,tempess,import_name,FALSE);
                Free(import_name);
                prs_semicolon=FALSE;
                cont=TRUE;
                break;
              case KW_INTERNAL:
                Lex(lx);
                if (lx->token!=TK_INTEGER)
                  PrsExcept(lx,"ST_EXPECTING_INTEGER");
                i=lx->cur_i;
                if (Lex(lx)!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess=lx->hash_entry))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                Lex(lx);
                PrsGlblVarList(lx,PRS_LTINTERN,tempess,i,last_cps_flags);
                prs_semicolon=FALSE;
                cont=TRUE;
                break;
              case KW_EXTERN:
                Lex(lx);
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                tempess=lx->hash_entry;
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                if (PrsKeyWord(lx)==KW_CLASS) {
                  Lex(lx);
                  PrsClass(lx,FALSE,last_cps_flags,TRUE);
                } else if (PrsKeyWord(lx)==KW_UNION) {
                  Lex(lx);
                  PrsClass(lx,TRUE,last_cps_flags,TRUE);
                } else {
                  if (!tempess || !(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                    PrsExcept(lx,"ST_EXPECTING_TYPE");
                  if (Bt(&lx->opts,OPTf_EXTERNS_TO_IMPORTS))
                    goto keyword_import;
                  Lex(lx);
                  PrsGlblVarList(lx,PRS_EXTERN,tempess,0,last_cps_flags);
                  prs_semicolon=FALSE;
                  cont=TRUE;
                }
                break;
              case KW_IMPORT:
                Lex(lx);
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                if (!(tempess=lx->hash_entry))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                if (!(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
keyword_import:
                Lex(lx);
                PrsGlblVarList(lx,PRS_IMPORT,tempess,0,FALSE);
                prs_semicolon=FALSE;
                cont=TRUE;
                break;
              case KW_TYPEDEF:
                Lex(lx);
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                tempess=lx->hash_entry;
                if (locals)
                  PrsExcept(lx,"ST_NOT_ALLOWED_IN_FUN");
                if (!tempess || !(tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)))
                  PrsExcept(lx,"ST_EXPECTING_TYPE");
                Lex(lx);
                PrsGlblVarList(lx,PRS_TYPEDEF,tempess,0,last_cps_flags);
                prs_semicolon=FALSE;
                cont=TRUE;
                break;
              case KW_ASM:
                if (locals) {
                  if (tempex=CmpJoin(lx,locals,FALSE,TRUE))
                    CbIcAdd(lx,EC_ASM,tempex,0);
                  Lex(lx); //Skip "}" of asm{}
                } else {
                  if (lx->flags&LF_STATIC_COMPILE || lx->a_depth) {
                    Lex(lx);
                    PrsAsmBlk(lx);
                    if (lx->flags&LF_STATIC_COMPILE && lx->a_depth==1)
                      Lex(lx); //Skip "}" of asm{}
                  } else {
                    if (tempex=CmpJoin(lx,NULL,FALSE,TRUE))
                      CmpFixUpJITAsm(lx,tempex,tempex->code);
                    Lex(lx); //Skip "}" of asm{}
                  }
                  cps_flags|=CPS_IS_ASM;
                }
                prs_semicolon=FALSE;
                break;
              case KW_TRY:
                Lex(lx);
                PrsTryBlk(lx,locals,try_cnt);
                prs_semicolon=FALSE;
                break;
              case KW_BREAK:
                Lex(lx);
                if (!lb_break)
                  PrsExcept(lx,"ST_BREAK_NOT_ALLOWED");
                CbIcAdd(lx,EC_JMP,lb_break,0);
                break;
              case KW_RETURN:
                if (!locals)
                  PrsExcept(lx,"ST_CANT_RETURN_VAL");
                if (try_cnt) {
                  temp_untry=HashFind("SysUntry",
                    lx->hash_table_list,HTT_FUN);
                  for (i=0;i<try_cnt;i++) {
                    if (Bt(temp_untry->flags,Cf_EXTERN)) {
                      if (lx->flags&LF_STATIC_COMPILE)
                        CbIcAdd(lx,EC_CALL_IMPORT,
                          temp_untry,sys_internal_types[IT_PTR]);
                      else
                        CbIcAdd(lx,EC_CALL_INDIRECT2,
                          &temp_untry->executable_address,sys_internal_types[IT_PTR]);
                    } else
                      CbIcAdd(lx,EC_CALL,temp_untry->executable_address,sys_internal_types[IT_PTR]);
                  }
                }
                if (Lex(lx)!=';') {
                  if (!locals->return_class->size)
                    PutLexWarn(lx,"ST_SHOULD_NOT_RETURN_VAL");
                  if (!PrsExpression(lx,NULL,FALSE))
                    throw(EXCEPT_COMPILER,17);
                  CbIcAdd(lx,EC_RETURN_VAL,0,locals->return_class);
                  lx->flags|=LF_HAS_RETURN;
                } else if (locals->return_class->size)
                  PutLexWarn(lx,"ST_SHOULD_RETURN_VAL");
                CbIcAdd(lx,EC_JMP,lx->lb_leave,0);
                break;
              case KW_GOTO:
                Lex(lx);
                if (lx->token!=TK_IDENT)
                  PrsExcept(lx,"ST_EXPECTING_IDENTIFIER");
                if (!(g_lb=CbGoToLabelFind(lx,lx->ident))) {
                  g_lb=CbMiscNew(lx,CBMT_GOTO_LABEL);
                  g_lb->str=lx->ident;
                  lx->ident=NULL;
                }
                g_lb->flags|=CBMF_USED;
                CbIcAdd(lx,EC_JMP,g_lb,0);
                Lex(lx);
                break;
              case KW_NOUNUSEDWARN:
                Lex(lx);
                PrsNoUnusedWarn(lx);
                break;
              case KW_COUT:
                Lex(lx);
                PrsCout(lx,FALSE);
                break;
              case KW_COUTLN:
                Lex(lx);
                PrsCout(lx,TRUE);
                break;
              case KW_CLASS:
                Lex(lx);
                tempess=PrsClass(lx,FALSE,last_cps_flags,FALSE);
                if (!locals && lx->token!=';') {
                  PrsGlblVarList(lx,PRS_NULL,tempess,0,last_cps_flags);
                  cont=TRUE;
                  prs_semicolon=FALSE;
                }
                break;
              case KW_UNION:
                Lex(lx);
                tempess=PrsClass(lx,TRUE,last_cps_flags,FALSE);
                if (!locals && lx->token!=';') {
                  PrsGlblVarList(lx,PRS_NULL,tempess,0,last_cps_flags);
                  cont=TRUE;
                  prs_semicolon=FALSE;
                }
                break;
              case KW_PUBLIC:
                Lex(lx);
                cps_flags|=CPS_IS_PUBLIC|last_cps_flags&CPS_FUN_FLAGS;
                cont=TRUE;
                prs_semicolon=FALSE;
                break;
              case KW_INTERRUPT:
                Lex(lx);
                cps_flags|=CPS_IS_INTERRUPT|CPS_IS_NOARGPOP|last_cps_flags&CPS_FUN_FLAGS;
                cont=TRUE;
                prs_semicolon=FALSE;
                break;
              case KW_ARGPOP:
                Lex(lx);
                cps_flags|=CPS_IS_ARGPOP|last_cps_flags&CPS_FUN_FLAGS;
                cont=TRUE;
                prs_semicolon=FALSE;
                break;
              case KW_NOARGPOP:
                Lex(lx);
                cps_flags|=CPS_IS_NOARGPOP|last_cps_flags&CPS_FUN_FLAGS;
                cont=TRUE;
                prs_semicolon=FALSE;
                break;
              case KW_STATIC:
                Lex(lx);
                cps_flags|=CPS_IS_STATIC;
                cont=TRUE;
                prs_semicolon=FALSE;
                break;
              case KW_NUM_KEYWORDS: //nobound_switch
              default:
                prs_exp=TRUE;
            }
          } else if (tempess->s.h.type & (HTT_CLASS|HTT_INTERNAL_TYPE|HTT_TYPEDEF)) {
            if (locals) {
              if (cps_flags&CPS_IS_STATIC) {
                PrsVarList(lx,locals,PRS_STATIC_LOCAL_VAR);
                cps_flags&=~CPS_IS_STATIC;
              } else
                PrsVarList(lx,locals,PRS_LOCAL_VAR);
              if (lx->token=='}')
                cont=FALSE;
              else
                cont=TRUE;
            } else {
              Lex(lx);
              PrsGlblVarList(lx,PRS_NULL,tempess,0,last_cps_flags);
              cont=TRUE;
            }
            prs_semicolon=FALSE;
          } else prs_exp=TRUE;
        } else {
          if (lx->local_var_entry)
            prs_exp=TRUE;
          else {
            if (!(g_lb=CbGoToLabelFind(lx,lx->ident))) {
              g_lb=CbMiscNew(lx,CBMT_GOTO_LABEL);
              g_lb->str=lx->ident;
              lx->ident=NULL;
            } else if (g_lb->flags&CBMF_DEFINED)
              PrsExcept(lx,"ST_DUP_GOTO_LABEL");
            g_lb->flags|=CBMF_DEFINED;
            Lex(lx); //skip ident
            lx->last_indent_level=0;
            CbIcAdd(lx,EC_LABEL,g_lb,0);
            if (lx->token==':') //skip ident
              Lex(lx); //skip colon
            else
              PrsExcept(lx,"ST_UNDEFINED_IDENTIFIER");
            if (!locals)
              PrsExcept(lx,"ST_NO_GLBL_LABELS");
            prs_semicolon=FALSE;
          }
        }
      } else prs_exp=TRUE;
      if (prs_exp) {
        if (!PrsExpression(lx,NULL,TRUE))
          throw(EXCEPT_COMPILER,18);
      }
      if (lx->token!=',')
        lx->statement_cnt--;
      if (prs_semicolon && lx->token!=',') {
        if (lx->token==';')
          Lex(lx);
        else
          PrsExcept(lx,"ST_MISSING_SEMICOLON");
      }
    }
    last_cps_flags=cps_flags;
  } while (lx->token==',' || cont);
  lx->last_indent_level=lx->indent_level--;
  return cps_flags&CPS_IS_ASM;
}
Historical capture: 2010-11-18. Home | Power on LoseThos | Sources and changes