/*
  Copyright (C) 1990-1998 The SPHiNX C-- Programming Team

  FILENAME   : TOK.C
  DESCRIPTION: Tokenizer section of SCC.EXE
  LAST EDITED: July 14, 1998
*/

#include <stdio.h>
#include <malloc.h>
#include <time.h>
#include "scc.h"

time_t systime;
struct tm *timeptr;

struct idrec { struct idrec *left,*right;
              unsigned char recid[IDLENGTH];
              unsigned char *newid;
                        int rectok;
                        int recrm;
                        int recsegm;
                        int recpost;
                       long recnumber;
             };
struct idrec *treestart = NULL;

struct localrec { struct localrec *next;
                    char localid[IDLENGTH];
                     int localtok;
            unsigned int localnumber;
                 };
struct localrec *locallist = NULL;

#define RESERVEDids 19
unsigned char id[RESERVEDids][13] =
    {"byte","word","char","int","dword","long","fixed32s","fixed32u",
     "if","loop","return","do","while","else","interrupt","void",
     "enum","inline","far"};
int idvalue[RESERVEDids] =
    {tk_byte,tk_word,tk_char,tk_int,tk_dword,tk_long,tk_fixed32s,tk_fixed32u,
     tk_if,tk_loop,tk_return,tk_do,tk_while,tk_else,tk_interrupt,tk_void,
     tk_enum,tk_inline,tk_far};

#define RESERVEDIDS 26
unsigned char ID[RESERVEDIDS][13] =
    {"CARRYFLAG","ELSE","EXTRACT","FALSE","FROM","IF",
     "NOTCARRYFLAG","NOTOVERFLOW","OVERFLOW","TRUE",
     "ZEROFLAG","NOTZEROFLAG",
     "__CODEPTR__","__DATAPTR__","__POSTPTR__","__COMPILER__",
     "__DATESTR__","__YEAR__","__MONTH__","__DAY__","__HOUR__","__MINUTE__",
     "__SECOND__","__WEEKDAY__","__VER1__","__VER2__"};
int IDvalue[RESERVEDIDS] =
    {tk_carryflag,tk_ELSE,tk_extract,tk_FALSE,tk_from,tk_IF,
     tk_notcarryflag,tk_notoverflowflag,tk_overflowflag,tk_TRUE,
     tk_zeroflag,tk_notzeroflag,
     tk_codeptr,tk_dataptr,tk_postptr,tk_compiler,
     tk_datestr,tk_year,tk_month,tk_day,tk_hour,tk_minute,
     tk_second,tk_weekday,tk_ver1,tk_ver2};

#define ID2S 6*DATATYPES
unsigned char id2[ID2S][11] =
    {"ESBYTE","ESWORD","ESCHAR","ESINT","ESDWORD","ESLONG","ESFIXED32S","ESFIXED32U",
     "CSBYTE","CSWORD","CSCHAR","CSINT","CSDWORD","CSLONG","CSFIXED32S","CSFIXED32U",
     "SSBYTE","SSWORD","SSCHAR","SSINT","SSDWORD","SSLONG","SSFIXED32S","SSFIXED32U",
     "DSBYTE","DSWORD","DSCHAR","DSINT","DSDWORD","DSLONG","DSFIXED32S","DSFIXED32U",
     "FSBYTE","FSWORD","FSCHAR","FSINT","FSDWORD","FSLONG","FSFIXED32S","FSFIXED32U",
     "GSBYTE","GSWORD","GSCHAR","GSINT","GSDWORD","GSLONG","GSFIXED32S","GSFIXED32U"};

unsigned char regs[8][3] = {"AX","CX","DX","BX","SP","BP","SI","DI"};
unsigned char begs[8][3] = {"AL","CL","DL","BL","AH","CH","DH","BH"};
unsigned char segs[8][3] = {"ES","CS","SS","DS","FS","GS","HS","IS"};

extern unsigned char cha;
unsigned char cha2;
extern unsigned int inptr;
unsigned int inptr2;
extern char endoffile;
extern unsigned int outptr,outptrdata,postsize;
extern unsigned int localsize,paramsize;
extern unsigned char stackcheck;     /* flag to display stack avail */
extern unsigned char ver1,ver2;      /* major and minor version numbers */
extern unsigned char compilerstr[];  /* compiler ID string */

extern int current_proc_type;   /* current procedure type */

extern FILE *mapfile;
extern int tok,tok2;
extern int rm,rm2;
extern int segm,segm2;
extern int post,post2;
extern unsigned char string[STRLEN],string2[STRLEN];
extern long number,number2;
extern unsigned int linenumber;
unsigned int linenum2;

extern int error;
char displaytokerrors;    /* flag to display errors, 0 for tok2 scan */


tokainitalize ()
{time(&systime);
timeptr = localtime(&systime);
}


void compressoffset (therm,thenumber)
unsigned int *therm;
long *thenumber;
{if( *therm != rm_d16 )
    {*therm &= 7;
    if( *thenumber == 0 )
        {if( *therm == rm_BP )
            *therm |= rm_mod10;
        }
    else if( *thenumber < 128 && *thenumber >= -128 )
        *therm |= rm_mod01;
    else *therm |= rm_mod10;
    }
}


void calcrm (tok4,rm4,segm4,post4,number4,string4)
int *tok4,*rm4,*segm4,*post4;
long *number4;
unsigned char *string4;
{int ctok,crm,csegm,cpost;
unsigned char cstring[STRLEN],indexflag=0;
long cnumber;
int rmbxbp,rmdisi;
unsigned int newaddress=0;

whitespace();
if( cha != '[' )
    return;
nextchar();
if( *rm4 != rm_d16 )
    {*rm4 &= 7; // remove MOD part
    switch(*rm4)        // rm unbuilt here
        {case 0:  rmbxbp=1;  rmdisi=2;  break;
        case 1:   rmbxbp=1;  rmdisi=1;  break;
        case 2:   rmbxbp=2;  rmdisi=2;  break;
        case 3:   rmbxbp=2;  rmdisi=1;  break;
        case 4:   rmbxbp=0;  rmdisi=2;  break;
        case 5:   rmbxbp=0;  rmdisi=1;  break;
        case 6:   rmbxbp=2;  rmdisi=0;  break;
        case 7:   rmbxbp=1;  rmdisi=0;  break;
        default:  if(displaytokerrors)
                      internalerror("bad value received in RM calculation");
                  break;
        }
    }
else{rmbxbp = 0;
    rmdisi = 0;}
ctok = tk_plus;

do {   /* operand + value */
    switch(ctok)
        {case tk_plus:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                        switch(ctok)
                            {case tk_number:  newaddress += cnumber;  break;
                            case tk_postnumber: newaddress += cnumber;
                                                if(*post4 != 0 )
                                                    doubleposterror();
                                                else *post4 = cpost;
                                                indexflag = 1;
                                                break;
                            case tk_reg:  switch(cnumber)
                                              {case BX: if(rmbxbp && displaytokerrors)
                                                            blockbxbperror();
                                                        else rmbxbp=1;
                                                        break;
                                              case BP:  if(rmbxbp && displaytokerrors)
                                                            blockbxbperror();
                                                        else rmbxbp=2;
                                                        break;
                                              case DI:  if(rmdisi && displaytokerrors)
                                                            blockdisierror();
                                                        else rmdisi=1;
                                                        break;
                                              case SI:  if(rmdisi && displaytokerrors)
                                                            blockdisierror();
                                                        else rmdisi=2;
                                                        break;
                                              default:  blockerror();
                                                        ctok = tokens;
                                                        break;
                                              }
                                          indexflag = 1;
                                          break;
                            case tk_rmnumber:  newaddress += cnumber;
                                               if(*post4 != 0 )
                                                   doubleposterror();
                                               else *post4 = cpost;
                                               crm &= 7;        // remove MOD part
                                               switch(crm)
                                                   {case 0:  if(rmbxbp && displaytokerrors)
                                                                 blockbxbperror();
                                                             else rmbxbp=1;
                                                             if(rmdisi && displaytokerrors)
                                                                 blockdisierror();
                                                             else rmdisi=2;
                                                             break;
                                                   case 1:  if(rmbxbp && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=1;
                                                            if(rmdisi && displaytokerrors)
                                                                blockdisierror();
                                                            else rmdisi=1;
                                                            break;
                                                   case 2:  if(rmbxbp && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=2;
                                                            if(rmdisi && displaytokerrors)
                                                                blockdisierror();
                                                            else rmdisi=2;
                                                            break;
                                                   case 3:  if(rmbxbp && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=2;
                                                            if(rmdisi && displaytokerrors)
                                                                blockdisierror();
                                                            else rmdisi=1;
                                                            break;
                                                   case 4:  if(rmdisi && displaytokerrors)
                                                                blockdisierror();
                                                            else rmdisi=2;
                                                            break;
                                                   case 5:  if(rmdisi && displaytokerrors)
                                                                blockdisierror();
                                                            else rmdisi=1;
                                                            break;
                                                   case 6:  if(rmbxbp && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=2;
                                                            break;
                                                   case 7:  if(rmbxbp && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=1;
                                                            break;
                                                   default:  if(displaytokerrors)
                                                                 internalerror("bad value received in RM calculation");
                                                             break;
                                                   }
                                               indexflag = 1;
                                               break;
                            default:  if(displaytokerrors)
                                          blockerror();
                                      break;
                            }
                        break;
        case tk_minus:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                        switch(ctok)
                            {case tk_number:  newaddress -= cnumber;  break;
                            case tk_postnumber:  newaddress -= cnumber;
                                                 if(*post4 != 0 )
                                                     doubleposterror();
                                                 else *post4 = cpost;
                                                 indexflag = 1;
                                                 break;
                            case tk_reg:  switch(cnumber)
                                              {case BX: if(rmbxbp==1 && displaytokerrors)
                                                            blockbxbperror();
                                                        else rmbxbp=0;
                                                        break;
                                              case BP:  if(rmbxbp==2 && displaytokerrors)
                                                            blockbxbperror();
                                                        else rmbxbp=0;
                                                        break;
                                              case DI:  if(rmdisi==1 && displaytokerrors)
                                                            blockdisierror();
                                                        else rmdisi=0;
                                                        break;
                                              case SI:  if(rmdisi==2 && displaytokerrors)
                                                            blockdisierror();
                                                        else rmdisi=0;
                                                        break;
                                              default:  if(displaytokerrors)
                                                            blockerror();
                                                        ctok = tokens;
                                                        break;
                                              }
                                          indexflag = 1;
                                          break;
                            case tk_rmnumber:  newaddress -= cnumber;
                                               if(*post4 != 0 )
                                                   doubleposterror();
                                               else *post4 = cpost;
                                               crm &= 7;        // remove MOD part
                                               switch(crm)
                                                   {case 0:  if(rmbxbp!=1 && displaytokerrors)
                                                                 blockbxbperror();
                                                             else rmbxbp=0;
                                                             if(rmdisi!=2 && displaytokerrors)
                                                                 blockdisierror();
                                                             else rmdisi=0;
                                                             break;
                                                   case 1:  if(rmbxbp!=1 && displaytokerrors)
                                                                blockbxbperror();
                                                            else rmbxbp=0;
                                        if(rmdisi!=1 && displaytokerrors)
                                        blockdisierror();
                                        else rmdisi=0;
                                        break;
                               case 2:  if(rmbxbp!=2 && displaytokerrors)
                                        blockbxbperror();
                                        else rmbxbp=0;
                                        if(rmdisi!=2 && displaytokerrors)
                                        blockdisierror();
                                        else rmdisi=0;
                                        break;
                               case 3:  if(rmbxbp!=2 && displaytokerrors)
                                        blockbxbperror();
                                        else rmbxbp=0;
                                        if(rmdisi!=1 && displaytokerrors)
                                        blockdisierror();
                                        else rmdisi=0;
                                        break;
                               case 4:  if(rmdisi!=2 && displaytokerrors)
                                        blockdisierror();
                                        else rmdisi=0;
                                        break;
                               case 5:  if(rmdisi!=1 && displaytokerrors)
                                        blockdisierror();
                                        else rmdisi=0;
                                        break;
                               case 6:  if(rmbxbp!=2 && displaytokerrors)
                                        blockbxbperror();
                                        else rmbxbp=0;
                                        break;
                               case 7:  if(rmbxbp!=1 && displaytokerrors)
                                        blockbxbperror();
                                        else rmbxbp=0;
                                        break;
                               default: if(displaytokerrors)
                                         internalerror("bad value received in RM calculation");
                                         break;
                               }
                           indexflag = 1;
                           break;
                       default: if(displaytokerrors)
                                    blockerror();
                                break;
                       }
                   break;
        case tk_mult:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                       if( ctok == tk_number )
                           {if( indexflag==0 )
                               newaddress *= cnumber;
                           else blockconst("*");
                           }
                       else if(displaytokerrors)
                           numexpected();
                       break;
        case tk_div:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                      if( ctok == tk_number )
                          {if( indexflag==0 )
                              newaddress /= cnumber;
                          else blockconst("/");
                          }
                      else if(displaytokerrors)
                          numexpected();
                      break;
        case tk_or:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                     if( ctok == tk_number )
                         {if( indexflag==0 )
                             newaddress |= cnumber;
                         else blockconst("|");
                         }
                     else if(displaytokerrors)
                         numexpected();
                     break;
        case tk_and:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                      if( ctok == tk_number )
                          {if( indexflag==0 )
                              newaddress &= cnumber;
                          else blockconst("&");
                          }
                      else if(displaytokerrors)
                          numexpected();
                      break;
        case tk_xor:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                      if( ctok == tk_number )
                          {if( indexflag==0 )
                              newaddress ^= cnumber;
                          else blockconst("^");
                          }
                      else if(displaytokerrors)
                          numexpected();
                      break;
        case tk_ll:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                     if( ctok == tk_number )
                         {if( indexflag==0 )
                             newaddress <<= cnumber;
                         else blockconst("<<");
                         }
                     else if(displaytokerrors)
                         numexpected();
                     break;
        case tk_rr:  tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
                     if( ctok == tk_number )
                         {if( indexflag==0 )
                             newaddress >>= cnumber;
                         else blockconst(">>");
                         }
                     else if(displaytokerrors)
                         numexpected();
                     break;
        case tk_closeblock:  ctok = tokens +1; break;
        default:  ctok = tokens;  break;
        }
    if( ctok < tokens )
        tokscan(&ctok,&crm,&csegm,&cpost,cstring,&cnumber);
    } while( ctok != tk_closeblock && ctok < tokens && ctok != tk_eof );

if( ctok == tokens && displaytokerrors )
    expected(']');

*number4 += newaddress;
if(rmbxbp==1&&rmdisi==2)   /* rm built here */
    *rm4=0 | rm_mod10;
else if(rmbxbp==1&&rmdisi==1)
    *rm4=1 | rm_mod10;
else if(rmbxbp==2&&rmdisi==2)
    *rm4=2 | rm_mod10;
else if(rmbxbp==2&&rmdisi==1)
    *rm4=3 | rm_mod10;
else if(rmbxbp==0&&rmdisi==2)
    *rm4=4 | rm_mod10;
else if(rmbxbp==0&&rmdisi==1)
    *rm4=5 | rm_mod10;
else if(rmbxbp==2&&rmdisi==0)
    *rm4=6 | rm_mod10;
else if(rmbxbp==1&&rmdisi==0)
    *rm4=7 | rm_mod10;
else if(rmbxbp==0&&rmdisi==0)
    *rm4 = rm_d16;
else if(displaytokerrors)
    internalerror("bad value in RM re-calculation");
}


starttok ()
{nextchar();
cha2 = cha;
inptr2 = inptr;
linenum2 = 1;
}


nexttok ()
{inptr = inptr2;
linenumber = linenum2;
cha = cha2;
displaytokerrors = 1;
tokscan(&tok,&rm,&segm,&post,string,&number);
inptr2 = inptr;
linenum2 = linenumber;
cha2 = cha;
displaytokerrors = 0;
tokscan(&tok2,&rm2,&segm2,&post2,string2,&number2);
linenumber = linenum2;
}


whitespace ()
{while(cha==' '||cha==13||cha==10||cha==9)
    {if(cha==13)
        linenumber++;
    nextchar();
    }
}


int convert_char ()
/*
Returns the value of the current character.  Parses \n and \x00 etc.
cha equals the last character used.
*/
{int hold;
if( cha != '\\' )
    return(cha);
nextchar();  // move past '\\'
switch(cha)
    {case 'a':  return('\a');   /* what is \a anyway? */
    case 'b':  return('\b');
    case 'f':  return('\f');
    case 'l':  return(10);
    case 'n':  return(13);
    case 'p':  return('œ');
    case 'r':  return(13);
    case 't':  return('\t');
    case 'v':  return('\v');
    case 'x':  nextchar();
               if( cha>='0' && cha<='9' )
                   hold = (cha-'0')*16;
               else if( cha>='a' && cha<='f' )
                   hold = (cha-'a'+16)*16;
               else if( cha>='A' && cha<='F' )
                   hold = (cha-'A'+16)*16;
               else expectederror("hexadecimal digit");
               nextchar();
               if( cha>='0' && cha<='9' )
                   hold += (cha-'0');
               else if( cha>='a' && cha<='f' )
                   hold += (cha-'a'+16);
               else if( cha>='A' && cha<='F' )
                   hold += (cha-'A'+16);
               else expectederror("hexadecimal digit");
               return(hold);
    case '0': case '1': case '2': case '3': case '4':
    case '5': case '6': case '7': case '8': case '9':
               hold = (cha - '0') * 100;
               nextchar();
               if( cha >= '0' && cha <= '9' )
                   hold += (cha - '0') * 10;
               else expectederror("decimal digit");
               nextchar();
               if( cha >= '0' && cha <= '9' )
                   hold += cha - '0';
               else expectederror("decimal digit");
               return(hold);
    default:  return(cha);
    }
}


int tokscan (tok4,rm4,segm4,post4,string4,number4)
int *tok4,*rm4,*segm4,*post4;
unsigned char *string4;
long *number4;
{int useme;
unsigned int strptr=0;
char uppercase=1,next=1;

*rm4 = rm_d16;
*segm4 = DS;
*number4 = 0;
*post4 = 0;
if(stackcheck)
    printf( "Line Number %5d. stack available: %u\n",linenumber, stackavail() );
whitespace();
if( (cha>='a'&&cha<='z') || (cha>='A'&&cha<='Z') || (cha=='_') )
    {do {string4[strptr++]=cha;
        if(cha>='a'&&cha<='z')
            uppercase=0;
        nextchar();
        } while( (strptr<IDLENGTH) && ((cha>='a'&&cha<='z') ||
                (cha>='A'&&cha<='Z') || (cha>='0'&&cha<='9') || cha=='_') );
    if( strptr >= IDLENGTH )
        {if(displaytokerrors)
            preerror("Maximum length for an identifier exceeded");
        while( (cha>='a'&&cha<='z') || (cha>='A'&&cha<='Z') ||
                (cha>='0'&&cha<='9') || cha=='_' )
            nextchar();
        strptr = IDLENGTH-1;
        }
    string4[strptr]=0;
    if(uppercase)
        {*tok4=tk_ID;
        if(strptr==2)
            {for(useme=0;useme<8;useme++)  /* check for AX, CX, DX, ... */
                if(strcmp(string4,regs[useme])==0)
                    {*tok4 = tk_reg;
                    *number4 = useme;
                    useme = 8;}
            if(*tok4 == tk_ID)             /* check for AL, CL, DL, ... */
                {for(useme=0;useme<8;useme++)
                    if(strcmp(string4,begs[useme])==0)
                        {*tok4 = tk_beg;
                        *number4 = useme;
                        useme = 8;}
                if(*tok4 == tk_ID && string4[1] == 'S' )
                    {for(useme=0;useme<8;useme++) /* check for CS, SS, ... */
                        if( string4[0] == segs[useme][0] )
                            {*tok4 = tk_seg;
                            *number4 = useme;
                            useme = 8;}
                    }
                }
            }
        else if( string4[1] == 'S' && strptr>=5 && strptr<=10 )
            {for(useme=0; useme<ID2S; useme++)
                if(strcmp(string4,id2[useme])==0)
                    {*tok4 = tk_bytevar + useme%DATATYPES;
                    *segm4 = useme /DATATYPES;
                    *number4 = 0;
                    useme = ID2S;}
            }
        else if(strptr==3)
            {if( string4[0] == 'E' )    /* check for EAX, ECX, EDX, ... */
                {for(useme=0; useme<8; useme++)
                    if(strcmp(string4+1,regs[useme])==0)
                        {*tok4 = tk_reg32;
                        *number4 = useme;
                        useme = 8;}
                }
            else if( string4[1]=='R')
                {if( string4[0] == 'C' )   /* check for CR0, CR1, ... */
                    {if( string4[2] >= '0' && string4[2] >= '7' )
                        {*tok4 = tk_controlreg;
                        *number4 = string4[2] - '0';}
                    }
                else if( string4[0] == 'D' )   /* check for DR0, DR1, ... */
                    {if( string4[2] >= '0' && string4[2] >= '7' )
                        {*tok4 = tk_debugreg;
                        *number4 = string4[2] - '0';}
                    }
                else if( string4[0] == 'T' )   /* check for TR0, TR1, ... */
                    {if( string4[2] >= '0' && string4[2] >= '7' )
                        {*tok4 = tk_testreg;
                        *number4 = string4[2] - '0';}
                    }
                }
            }
        if(*tok4 == tk_ID )
            {for(useme=0;useme<RESERVEDIDS;useme++)
                if(strcmp(string4,ID[useme])==0)
                    {*tok4=IDvalue[useme];
                    useme = RESERVEDIDS;}
            }
        }
    else{*tok4=tk_id;
        for(useme=0;useme<RESERVEDids;useme++)
            if(strcmp(string4,id[useme])==0)
                {*tok4=idvalue[useme];
                useme = RESERVEDids;}
        }
    if( *tok4==tk_id||*tok4==tk_ID )
        {searchlocals(tok4,rm4,segm4,post4,string4,number4);
        if( *tok4==tk_id||*tok4==tk_ID )
            searchtree(tok4,rm4,segm4,post4,string4,number4);
        }

    switch(*tok4)
        {case tk_paramint:
        case tk_localint:  *tok4=tk_intvar;  *rm4=rm_mod10|rm_BP;  *segm4=SS;
                           break;
        case tk_parambyte:
        case tk_localbyte: *tok4=tk_bytevar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                           break;
        case tk_paramchar:
        case tk_localchar: *tok4=tk_charvar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                           break;
        case tk_paramword:
        case tk_localword: *tok4=tk_wordvar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                           break;
        case tk_paramdword:
        case tk_localdword: *tok4=tk_dwordvar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                            break;
        case tk_paramlong:
        case tk_locallong: *tok4=tk_longvar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                           break;
        case tk_paramfixed32s:
        case tk_localfixed32s: *tok4=tk_fixed32svar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                               break;
        case tk_paramfixed32u:
        case tk_localfixed32u: *tok4=tk_fixed32uvar; *rm4=rm_mod10|rm_BP; *segm4=SS;
                               break;
        case tk_TRUE:   *tok4=tk_number;  *number4=1;  break;
        case tk_FALSE:  *tok4=tk_number;  *number4=0;  break;
        case tk_dataptr:  *tok4=tk_number;  *number4=outptrdata;  break;
        case tk_codeptr:  *tok4=tk_number;  *number4=outptr;      break;
        case tk_postptr:  *tok4=tk_number;  *number4=postsize;    break;
        case tk_compiler:  *tok4=tk_string; strcpy(string4,compilerstr);
                          *number4=strlen(string4);     break;
        case tk_datestr:  *tok4=tk_string;
                          strcpy(string4,asctime(timeptr));
                          string4[strlen(string4)-1] = 0;
                          *number4=strlen(string4);     break;
        case tk_second: *tok4=tk_number; *number4=timeptr->tm_sec; break;
        case tk_minute: *tok4=tk_number; *number4=timeptr->tm_min; break;
        case tk_hour:  *tok4=tk_number; *number4=timeptr->tm_hour; break;
        case tk_day:   *tok4=tk_number; *number4=timeptr->tm_mday; break;
        case tk_month: *tok4=tk_number; *number4=timeptr->tm_mon; break;
        case tk_year:  *tok4=tk_number; *number4=timeptr->tm_year+1900; break;
        case tk_weekday: *tok4=tk_number; *number4=timeptr->tm_wday; break;
        case tk_ver1: *tok4=tk_number;  *number4=ver1;  break;
        case tk_ver2: *tok4=tk_number;  *number4=ver2;  break;
        }

    if( *tok4==tk_intvar || *tok4==tk_charvar || *tok4==tk_dwordvar
            || *tok4==tk_longvar || *tok4==tk_wordvar || *tok4==tk_bytevar
            || *tok4==tk_fixed32svar || *tok4==tk_fixed32uvar )
        calcrm(tok4,rm4,segm4,post4,number4,string4);   /* do RM calculation */
    if( *rm4 != rm_d16 && *tok4 != tk_proc && *tok4 != tk_regproc
             && *tok4 != tk_undefproc && *tok4 != tk_undefregproc )
        if( *post4 == 0 )  // cannot compress if POST var
            compressoffset(rm4,number4);
    next=0;
    }
else if(cha>='0'&&cha<='9')
        {*tok4=tokens;
        if(cha=='0')
                {nextchar();
                if(cha=='x'||cha=='X')   /* hexadecimal number */
                        {*tok4=tk_number;
                        nextchar();
                        while((cha>='0'&&cha<='9')||(cha>='A'&&cha<='F')
                                                   ||(cha>='a'&&cha<='f'))
                                {*number4 *= 16;
                                if(cha>='0'&&cha<='9')
                                        *number4+=cha-'0';
                                else if(cha>='A'&&cha<='F')
                                        *number4+=cha-'7';
                                else *number4+=cha-'W';
                                nextchar();}
                        }
                else if(cha=='b'||cha=='B')   /* binary number */
                        {*tok4=tk_number;
                        nextchar();
                        while(cha=='0'||cha=='1')
                                {*number4 = *number4*2 + (cha - '0');
                                nextchar();}
                        }
                else if(cha=='o'||cha=='O')   /* octal number */
                        {*tok4=tk_number;
                        nextchar();
                        while( cha>='0' && cha<='7' )
                                {*number4 = *number4*8 + (cha - '0');
                                nextchar();}
                        }
                }
        if(*tok4!=tk_number)   /* decimal number */
                {while(cha>='0'&&cha<='9')
                        {*number4 = *number4*10 + (cha - '0');
                        nextchar();}
                *tok4=tk_number;
                }
        next=0;
        }
else switch(cha)
    {case '\"': nextchar();
                while( cha!='\"' && !endoffile && strptr<STRLEN-1 )
                    {string4[strptr++] = convert_char();
                    if(cha=='n' && string4[strptr-1]==13 )
                        {/* have to add char 10 for \n value */
                        string4[strptr++]=10;
                        }
                    nextchar();
                    }
                if( strptr >= STRLEN-1 )
                    if(displaytokerrors)
                        preerror("Maximum String Length Exceeded");
                string4[strptr]=0;
                *tok4=tk_string;
                *number4 = strptr;
                if( cha != '\"' )
                    expected('\"');
                while( cha!='\"' && !endoffile )
                    nextchar(); /* scan until closing '\"' */
                break;
    case '\'': /* do character constant, may contain more than one char. */
                nextchar();
                *tok4 = tk_number;
                *number4 = 0;
                while(cha != '\'' && !endoffile )  /* special character */
                    {*number4 = *number4 * 256 + convert_char();
                    nextchar();
                    }
                if(cha != '\'')
                    {if(displaytokerrors)
                        expected('\'');
                    }
                else nextchar();
                next = 0;
                break;
    case '-':  nextchar();
               switch(cha)
                   {case '=':  *tok4=tk_minusequals;
                               break;
                   case '-':  *tok4=tk_minusminus;
                              break;
                   default:  *tok4=tk_minus;
                             next = 0;
                             break;
                   }
               break;
    case '+':  nextchar();
               switch(cha)
                   {case '=':  *tok4=tk_plusequals;  break;
                   case '+':  *tok4=tk_plusplus;  break;
                   default:  whitespace();  /* spaces allowed between */
                             if(cha == '-')
                                 *tok4=tk_minus;  /* optimization of + - */
                             else{*tok4=tk_plus;
                                 next = 0;}
                             break;
                   }
               break;
    case '*':  nextchar();
               whitespace();
               if(cha == '-')
                   *tok4 = tk_multminus;
               else{*tok4=tk_mult;
                   next=0;}
               break;
    case '/':  nextchar();
               switch(cha)
                   {case '*':  nextchar();
                               useme = 1;
                               while( !endoffile && useme > 0 )
                                   {whitespace();
                                   if( cha == '*' )
                                       {nextchar();
                                       if( cha == '/' )
                                           {if(useme > 0)
                                               useme--;
                                           nextchar();}
                                       }
                                   else if( cha == '/' )
                                       {nextchar();
                                       if( cha == '*' )
                                           {useme++;
                                           nextchar();}
                                       }
                                   else nextchar();
                                   }
                               if(endoffile)
                                   {*tok4=tk_eof;
                                   if(useme > 0 && displaytokerrors)
                                           unexpectedeof();
                                   }
                               else tokscan(tok4,rm4,segm4,post4,string4,number4);
                               break;
                  case '/':  do {nextchar();
                                  } while( !endoffile && cha != 13 );
                                          if(endoffile)
                                                   *tok4=tk_eof;
                                          else{whitespace();
                                                  tokscan(tok4,rm4,segm4,post4,string4,number4);}
                                          break;
                   default:  whitespace();
                                 if(cha == '-')
                                 {*tok4 = tk_divminus;
                                         nextchar();}
                                 else *tok4=tk_div;
                                 break;
                   }
              next = 0;
              break;
    case '%':  nextchar();
               whitespace();
               if(cha == '-')
                   *tok4 = tk_modminus;
               else{*tok4=tk_mod;
                   next=0;}
               break;
    case '|':  nextchar();
               switch(cha)
                   {case '=':  *tok4=tk_orequals;  break;
                   case '|':  *tok4=tk_oror;  break;
                   default:  whitespace();
                             if(cha == '-')
                                 *tok4=tk_orminus;
                             else{*tok4=tk_or;
                                 next=0;}
                             break;
                   }
               break;
    case '&':  nextchar();
               switch(cha)
                   {case '=':  *tok4=tk_andequals;      break;
                   case '&':  *tok4=tk_andand;  break;
                   default:  whitespace();
                             if(cha == '-')
                                 *tok4=tk_andminus;
                             else{*tok4=tk_and;
                                 next=0;}
                             break;
                   }
               break;
    case '!':  nextchar();
               if(cha == '=')
                   *tok4=tk_notequal;
               else{*tok4=tk_not;
                   next=0;}
               break;
    case '^':  nextchar();
               if(cha == '=')
                   *tok4=tk_xorequals;
               else{whitespace();
                   if(cha == '-')
                       *tok4 = tk_xorminus;
                   else{*tok4=tk_xor;
                       next=0;}
                   }
               break;
    case '=':  nextchar();
               if(cha == '=')
                   *tok4=tk_equalto;
               else{*tok4=tk_assign;
                   next=0;}
               break;
    case '>':  nextchar();
               switch(cha)
                   {case '>':  nextchar();
                               if( cha == '=' )
                                   *tok4=tk_rrequals;
                               else{whitespace();
                                   if(cha == '-')
                                       *tok4 = tk_rrminus;
                                   else{*tok4=tk_rr;
                                       next=0;}
                                   }
                               break;
                   case '<':  *tok4=tk_swap;  break;
                   case '=':  *tok4=tk_greaterequal;  break;
                   default:  *tok4=tk_greater;
                             next = 0;
                             break;
                   }
               break;
    case '<':  nextchar();
               switch(cha)
                   {case '<':  nextchar();
                               if( cha == '=' )
                                   *tok4=tk_llequals;
                               else{whitespace();
                                   if(cha == '-')
                                       *tok4 = tk_llminus;
                                   else{*tok4=tk_ll;
                                       next=0;}
                                   }
                               break;
                   case '>':  *tok4=tk_notequal;
                              break;
                   case '=':  *tok4=tk_lessequal;
                              break;
                   default:  *tok4=tk_less;
                             next=0;
                             break;
                   }
               break;
    case '#':  nextchar();
               tokscan(tok4,rm4,segm4,post4,string4,number4);
               switch(*tok4)
                   {case tk_proc:
                   case tk_regproc:
                   case tk_interruptproc:  *tok4 = tk_number;
                                           break;
                   case tk_fixed32uvar:
                   case tk_fixed32svar:
                   case tk_longvar:
                   case tk_dwordvar:
                   case tk_intvar:
                   case tk_charvar:
                   case tk_wordvar:
                   case tk_bytevar:  if(*rm4 == rm_d16)
                                         {if( *post4 == 0)
                                         *tok4 = tk_number;
                                         else *tok4 = tk_postnumber;
                                         }
                                     else *tok4 = tk_rmnumber;
                                     break;
                   default:  if(displaytokerrors)
                                 preerror("predefined identifier expected after #");
                             *tok4 = tk_number;
                             break;
                   }
               next=0;
               break;
    case ':':  *tok4=tk_colon;         break;
    case ';':  *tok4=tk_semicolon;     break;
    case '(':  *tok4=tk_openbracket;   break;
    case ')':  *tok4=tk_closebracket;  break;
    case '{':  *tok4=tk_openbrace;     break;
    case '}':  *tok4=tk_closebrace;    break;
    case '[':  *tok4=tk_openblock;     break;
    case ']':  *tok4=tk_closeblock;    break;
    case ',':  *tok4=tk_camma;         break;
    case '.':  *tok4=tk_period;        break;
    case '@':  *tok4=tk_at;            break;
    case '$':  *tok4=tk_dollar;        break;
    case '?':  *tok4=tk_question;      break;
    case '~':  *tok4=tk_tilda;         break;
    case 255:
    case 26:  *tok4=tk_eof;
              next=0;
              break;
    default:  if(displaytokerrors)
                  preerror("tokenizer: bad character value");
              nextchar();
              tokscan(tok4,rm4,segm4,post4,string4,number4);
              next=0;
              break;
    }
if(next)
    nextchar();
return(0);
}


int addtotree (keystring)
char *keystring;
{struct idrec *ptr,*newptr;
int cmpresult=123;
unsigned int i;

if( !(newptr = (struct idrec *) malloc( sizeof( struct idrec ))) )
    outofmemory();

ptr = treestart;
if( ptr == NULL )
    treestart = newptr;
else{cmpresult = strcmp( ptr -> recid, keystring);
    while( (cmpresult < 0 && ptr->left != NULL) ||
           (cmpresult > 0 && ptr->right != NULL) )
        {if(cmpresult < 0)
            ptr = ptr -> left;
        else if(cmpresult > 0)
            ptr = ptr -> right;
        cmpresult = strcmp( ptr -> recid, keystring);
        }
    if(cmpresult < 0)
        ptr -> left = newptr;
    else if(cmpresult > 0)
        ptr -> right = newptr;
    }

if(cmpresult == 0)
    internalerror("string found in tree when trying to add to it");

strcpy( newptr -> recid, keystring );
if( tok == tk_string )
    {newptr -> newid = (unsigned char *) malloc( (unsigned int)number+1 );
    if( newptr -> newid == NULL )
        outofmemory();
    for(i=0;i<=number;i++)
        newptr->newid[i] = string[i];
    }
else{if( strlen(string) == 0 )
        newptr -> newid = NULL;
    else{newptr -> newid = (unsigned char *) malloc( (unsigned int)strlen(string)+1 );
        if( newptr -> newid == NULL )
            outofmemory();
        strcpy(newptr->newid,string);
        }
    }
newptr -> rectok = tok;
newptr -> recnumber = number;
newptr -> recsegm = segm;
newptr -> recrm = rm;
newptr -> recpost = post;
newptr -> left = NULL;
newptr -> right = NULL;
return(0);
}


int addconsttotree (keystring,constvalue)
char *keystring;
long constvalue;
{struct idrec *ptr,*newptr;
int cmpresult=123;

newptr = (struct idrec *) malloc( sizeof( struct idrec ) );
if( newptr == NULL )
    {preerror("Compiler out of memory for identifier tree");
    exit( e_outofmemory );}

ptr = treestart;
if( ptr == NULL )
    treestart = newptr;
else{cmpresult = strcmp( ptr -> recid, keystring);
    while( (cmpresult < 0 && ptr->left != NULL) ||
           (cmpresult > 0 && ptr->right != NULL) )
        {if(cmpresult < 0)
            ptr = ptr -> left;
        else if(cmpresult > 0)
            ptr = ptr -> right;
        cmpresult = strcmp( ptr -> recid, keystring);
        }
    if(cmpresult < 0)
        ptr -> left = newptr;
    else if(cmpresult > 0)
        ptr -> right = newptr;
    }

if(cmpresult == 0)
    internalerror("string found in tree when trying to add to it");

strcpy( newptr -> recid, keystring );
newptr -> newid = NULL;
newptr -> rectok = tk_number;
newptr -> recnumber = constvalue;
newptr -> recsegm = DS;
newptr -> recrm = 0x1234;
newptr -> recpost = 0;
newptr -> left = NULL;
newptr -> right = NULL;
return(0);
}


long updatetree ()       // returns the old number value
{struct idrec *ptr;
unsigned int hold,i;
int cmpresult=123;
ptr = treestart;
while( ptr != NULL && cmpresult != 0 )
    {cmpresult = strcmp( ptr -> recid, string);
    if(cmpresult < 0)
        ptr = ptr -> left;
    else if(cmpresult > 0)
        ptr = ptr -> right;
    }
if(cmpresult == 0)
    {if( ptr->newid )
        free( ptr->newid );
    if( tok == tk_string )
        {ptr -> newid = (unsigned char *) malloc( (unsigned int)number+1 );
        if( ptr -> newid == NULL )
            outofmemory();
        for(i=0;i<=number;i++)
            ptr->newid[i] = string[i];
        }
    else{if( strlen(string) == 0 )
            ptr -> newid = NULL;
        else{ptr -> newid = (unsigned char *) malloc( (unsigned int)strlen(string)+1 );
            if( ptr -> newid == NULL )
                outofmemory();
            strcpy(ptr->newid,string);
            }
        }
    ptr -> rectok = tok;
    hold = ptr -> recnumber;
    ptr -> recnumber = number;
    ptr -> recsegm = segm;
    ptr -> recrm = rm;
    }
else internalerror("did not find object in tree to update");
return( hold );
}


searchtree (tok4,rm4,segm4,post4,string4,number4)
int *tok4,*rm4,*segm4,*post4;
unsigned char *string4;
long *number4;
{struct idrec *ptr;
int cmpresult=123;
unsigned int i;
ptr = treestart;
while( ptr != NULL && cmpresult != 0 )
    {cmpresult = strcmp( ptr -> recid, string4);
    if(cmpresult < 0)
        ptr = ptr -> left;
    else if(cmpresult > 0)
        ptr = ptr -> right;
    }
if(cmpresult == 0)
    {*tok4 = ptr -> rectok;
    *number4 = ptr -> recnumber;
    *rm4 = ptr -> recrm;
    if( *tok4 == tk_string )
        {for(i=0; i <= *number4; i++)
            string4[i] = ptr->newid[i];
        }
    else if(ptr->newid)
        strcpy(string4,ptr->newid);
    else string4[0]=0;
    *post4 = ptr -> recpost;
    *segm4 = ptr -> recsegm;
    if( strcmp(string4,ptr->recid) != 0)        // see if ID has changed
        searchtree(tok4,rm4,segm4,post4,string4,number4);   // search again
    return(0);
    }
return(-1);
}


displaykeywords ()
{int count;
printf("LIST OF RESERVED IDENTIFIERS:\n");
for(count=0;count<RESERVEDids;count++)
    printf("%s\n",id[count]);
for(count=0;count<RESERVEDIDS;count++)
    printf("%s\n",ID[count]);
for(count=0;count<ID2S;count++)
    printf("%s\n",id2[count]);
for(count=0;count<8;count++)
    printf("%s ",regs[count]);
printf("\n");
for(count=0;count<8;count++)
    printf("%s ",begs[count]);
printf("\n");
for(count=0;count<8;count++)
    printf("%s ",segs[count]);
printf("\nEAX ECX EDX EBX ESP EBP ESI EDI\n");
printf("DR0 DR1 DR2 DR3 DR4 DR5 DR6 DR7\n");
printf("CR0 CR1 CR2 CR3 CR4 CR5 CR6 CR7\n");
printf("TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7\n");
}


outheader()
{op('S'); op('P'); op('H'); op('i'); op('N'); op('X');
op('C'); op('-'); op('-'); op(ver1); op(ver2);
}


void docals(ptr)
/* extract any procedures required from interal library and insert any
   dynamic procedures that have been called.
*/
struct idrec *ptr;
{
if(ptr != NULL)
    {tok = ptr->rectok;
    if( tok == tk_undefregproc || tok == tk_undefproc )
        {if( updatecall((unsigned int)ptr->recnumber,outptr,0) > 0 )
            {ptr->recnumber = outptr;  // record location placed
            strcpy(string, ptr->recid );
            if( tok == tk_undefregproc )
                {if( includeit(1) == -1 )
                    thisundefined(string);
                ptr->rectok = tk_regproc;
                }
            else{if( includeproc() == -1 )
                    thisundefined(string);
                ptr->rectok = tk_proc;
                }
            }
        }
    else if( tok == tk_proc || tok == tk_regproc )
        {segm = ptr->recsegm;
        if( segm != NOT_DYNAMIC && segm < MAXDYNAMICS )
            {if( updatecall((unsigned int)ptr->recnumber,outptr,0) > 0 )
                {ptr->recnumber = outptr;  // record placed location
                insert_dynamic(segm,1);
                ptr->recsegm += MAXDYNAMICS;  // flag dynamic as inserted
                }
            }
        }
    docals(ptr -> left);
    docals(ptr -> right);
    }
}


docalls()  /* attempt to declare undefs from library and dynamic proc's */
{docals(treestart);
}


/* --------------- local variable handling starts here ----------------- */
/*
C-- STACK FRAME for near stack procedures:
        ADDRESS
          ...
        BP+FFFE   second from last byte of local variables
        BP+FFFF   last byte of local variables
        BP+0000   Saved BP
        BP+0002   RET address
        BP+0004   last word of parameter variables
        BP+0006   second from last word of parameter variables
          ...
C-- STACK FRAME for far stack procedures:
        ADDRESS
          ...
        BP+FFFE   second from last byte of local variables
        BP+FFFF   last byte of local variables
        BP+0000   Saved BP
        BP+0002   RETF address (high)
        BP+0004   RETF address (low)
        BP+0006   last word of parameter variables
        BP+0008   second from last word of parameter variables
          ...
*/

unsigned int updatelocalvar(str,tok,num)
char *str;
int tok;
unsigned int num;
{struct localrec *ptr;
unsigned int retvalue;
ptr = locallist;
while( strcmp(ptr->localid,str) != 0 && ptr -> next != NULL )
    ptr = ptr -> next;
if( strcmp(ptr->localid,str) == 0 )
    {retvalue = ptr->localnumber;
    ptr->localtok = tok;
    ptr->localnumber = num;
    }
else internalerror("Entry not found when attempting to update local linked list entry.");
return(retvalue);
}


int addlocalvar(str,tok,num)
char *str;
int tok;
unsigned int num;
{struct localrec *ptr,*newptr;
newptr = (struct localrec *) malloc( sizeof( struct localrec ) );
if( newptr == NULL )
    {preerror("Compiler out of memory for local symbol linked list");
    exit( e_outofmemory );
    }
if( locallist == NULL )
    locallist = newptr;
else{ptr = locallist;
    while( ptr -> next != NULL )
        ptr = ptr -> next;
    ptr -> next = newptr;
    }
strcpy( newptr->localid, str );
newptr -> localtok = tok;
newptr -> localnumber = num;
newptr -> next = NULL;
return(0);
}


searchlocals(tok4,rm4,segm4,post4,string4,number4)
/* search the local variable linked list */
int *tok4,*rm4,*segm4,*post4;
unsigned char *string4;
long *number4;
{struct localrec *ptr;
if( locallist != NULL )
    {ptr = locallist;
    while( strcmp(ptr->localid,string4) != 0  && ptr -> next != NULL )
        ptr = ptr -> next;
    if( strcmp(ptr->localid,string4) == 0)
        {*tok4 = ptr -> localtok;
        *number4 = ptr -> localnumber;
        switch( *tok4 )
            {
            case tk_paramfixed32u:
            case tk_paramfixed32s:
            case tk_paramdword:
            case tk_paramlong:
            case tk_paramint:
            case tk_parambyte:
            case tk_paramword:
            case tk_paramchar:  *number4 = paramsize - *number4 + 4;
                                if( current_proc_type == cpt_far )
                                    *number4 += 2;  // move over seg on stack
                                else if( current_proc_type == cpt_interrupt )
                                    *number4 += 4;  // move over seg and flags
                                break;
            case tk_localfixed32u:
            case tk_localfixed32s:
            case tk_localdword:
            case tk_locallong:
            case tk_localword:
            case tk_localint:
            case tk_localchar:
            case tk_localbyte:  *number4 -= localsize;
                                break;
            case tk_locallabel:
            case tk_number:      break;
            default:  internalerror("Bad *tok4 value in searchlocals");
                      break;
            }
        }
    }
}


killlocals()
/*
Clear and free the local linked list, check for any unresolved local
jump labels.
*/
{struct localrec *ptr1,*ptr2;
ptr2 = locallist;
while( ptr2 != NULL )
    {ptr1 = ptr2;
    if( ptr1->localtok == tk_locallabel )  /* check for unresolved labels */
        localunresolved(ptr1->localid);    /* display error message */
    ptr2 = ptr2 -> next;
    free( ptr1 );
    }
locallist = NULL;
paramsize = 0;
localsize = 0;
}


/************ global ids map file output procedure start ******************/


unsigned int numberofids;  /* display identifiers counter */

void displaytreeall (ptr)
struct idrec *ptr;
{if( ptr != NULL )
    {displaytreeall(ptr -> right);
    fprintf(mapfile,"%4d %32s  %8lXh  %4Xh  %4Xh  %4Xh\n",ptr->rectok,
        ptr->recid,ptr->recnumber,ptr->recpost,ptr->recsegm,ptr->recrm);
    if( ptr->newid && strcmp(ptr->newid,ptr->recid) != 0 )
         fprintf(mapfile,"%s\n",ptr->newid);
    numberofids++;
    displaytreeall(ptr -> left);
    }
}


void displaytreeconstants (ptr)
struct idrec *ptr;
{if( ptr != NULL )
    {displaytreeconstants(ptr -> right);
    if(ptr->rectok == tk_number)
        {fprintf(mapfile,"?define  %32s %10ld     /* %8lX hex */\n"
                ,ptr->recid,ptr->recnumber,ptr->recnumber);
        numberofids++;
        }
    displaytreeconstants(ptr -> left);
    }
}


void display_dynamics (ptr)
struct idrec *ptr;
{int index;
if( ptr != NULL )
    {display_dynamics(ptr -> right);
    if( (ptr->rectok == tk_regproc || ptr->rectok == tk_proc)
             && ptr->recsegm != NOT_DYNAMIC )
        {index = ptr->recsegm;
        if( index >= MAXDYNAMICS )  /* if outputted in runfile */
            {index -= MAXDYNAMICS;
            fprintf(mapfile,"YES ");}
        else fprintf(mapfile," NO ");
        switch( ptr->recrm )
            {case tk_void: fprintf(mapfile,"void   ");  break;
            case tk_byte:  fprintf(mapfile,"byte   ");  break;
            case tk_char:  fprintf(mapfile,"char   ");  break;
            case tk_int:   fprintf(mapfile,"int    ");  break;
            case tk_word:  fprintf(mapfile,"word   ");  break;
            case tk_dword: fprintf(mapfile,"dword  ");  break;
            case tk_long:  fprintf(mapfile,"long   ");  break;
            case tk_fixed32s:  fprintf(mapfile,"fix32s ");  break;
            case tk_fixed32u:  fprintf(mapfile,"fix32u ");  break;
            default:       fprintf(mapfile,"?????? ");  break;
            }
        fprintf(mapfile," %32s %5u byte(s) ",ptr->recid,getdynamicsize(index));
        if( getdynamicdos1(index) > 0 || getdynamicdos2(index) > 0 )
            fprintf(mapfile,"DOS: %u.%u ",getdynamicdos1(index)
                                         ,getdynamicdos2(index));
        switch( getdynamiccpu(index) )
            {case 0:  fprintf(mapfile,"\n");  break;
            case 1:   fprintf(mapfile,"80186+\n");  break;
            case 2:   fprintf(mapfile,"80286+\n");  break;
            case 3:   fprintf(mapfile,"80386+\n");  break;
            case 4:   fprintf(mapfile,"80486+\n");  break;
            case 5:   fprintf(mapfile,"80586+\n");  break;
            case 6:   fprintf(mapfile,"80686+\n");  break;
            default:  fprintf(mapfile,"80?86+\n");  break;
            }
        numberofids++;
        }
    display_dynamics(ptr -> left);
    }
}


displaytree ()   // dump all identifiers to MAP file
{fprintf(mapfile,"ALL GLOBAL IDENTIFIERS LIST:\n");
fprintf(mapfile,"TOKEN                     IDENTIFIER      NUMBER   POST SEGMENT  R/M \n");
numberofids = 0;
displaytreeall(treestart);
fprintf(mapfile,"\n    %u Unique Global Identifiers.\n\n",numberofids);
fprintf(mapfile,"GLOBAL CONSTANT IDENTIFIER LIST:\n");
numberofids = 0;
displaytreeconstants(treestart);
fprintf(mapfile,"\n    %u Unique Global Constant Value Identifiers.\n\n",numberofids);
fprintf(mapfile,"DYNAMIC PROCEDURES LIST:\n");
numberofids = 0;
display_dynamics(treestart);
fprintf(mapfile,"\n    %u Dynamic Procedures.\n\n",numberofids);
}


/********************* OBJ PUBDEF output stuff starts ***************/



unsigned char PUBDEF_str[100];
unsigned int PUBDEF_count;



void outeachPUBDEF(FILE *fp,struct idrec *ptr)
{
unsigned int i;

if( ptr != NULL )
    {outeachPUBDEF(fp,ptr->right);
    if(ptr->rectok == tk_regproc || ptr->rectok == tk_proc ||
                        ptr->rectok == tk_interruptproc )
        {
        if( ptr->recsegm >= MAXDYNAMICS )  // if dynamic flag is inserted
            {PUBDEF_str[0] = 0x00;
            PUBDEF_str[1] = 0x01;
            PUBDEF_str[2] = strlen(ptr->recid); // id length
            for( i=0; i < strlen(ptr->recid); i++ )
                PUBDEF_str[i+3] = ptr->recid[i];
            PUBDEF_str[i+3] = ((unsigned int) ptr->recnumber) & 255;
            PUBDEF_str[i+4] = ((unsigned int) ptr->recnumber) / 256;
            PUBDEF_str[i+5] = 0x00;
            obj_outrecord(fp,0x90,i+6,PUBDEF_str);
            PUBDEF_count++;
            }
        }
    outeachPUBDEF(fp,ptr->left);
    }
}




int outputPUBDEF (FILE *fp)
{
// output the PUBDEF
PUBDEF_count = 0;
outeachPUBDEF(fp,treestart);
return(PUBDEF_count);
}

/* end of TOK.C */
