// b3.c                          1951                          5/12/00

// NOTE: This is a somewhat non-standard 32-bit "C" compiler for use
// with the excellent "dos" extender "WDOSX" written by Michael Tippach,
// or with "flat real" mode. ("F" command-line option).
// See the file "b-flat.doc" for more information.

// B is copyright (C) 1998,1999 by Ken Martwick.

// Version 0.40 8/25/99

//  This program is free software; you can redistribute it and/or modify
//  it under the terms of the GNU General Public License as published by
//  the Free Software Foundation; either version 2 of the License, or
//  (at your option) any later version.

//  This program is distributed in the hope that it will be useful,
//  but WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//  GNU General Public License for more details.

//  You should have received a copy of the GNU General Public License
//  along with this program; if not, write to the Free Software
//  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "b.h"

void parse_if(void)           // parse / code "if" statement
     {
     char cmpval[20], cop[5], *temp, *tok[3];
     char compname[20], varname[20];
     int compnum, isbreak, isnum, k, l, not, size;

     if(strstr(iptr[m], "break;")) isbreak = 1;
     else isbreak = 0;

     for(k=0; k < 3; k++)
          {
          tok[k] = strtok(NULL, " \t\n)");
          if(!tok[k]) break;
          }

     if(!tok[0])
          {
          bad: printf("\n\n\"if\" statement incorrect in:");
          printf("%s\n", iptr[m]);
          exit(1);
          }

     strcpy(token, tok[0]);
     if(token[0] == '!')      // inverse
          {
          not = 1;
          temp = strtok(tok[0], "! \t\n)");
          strcpy(token, temp);
          }
     else not = 0;
     result = isvar();
     if(!result) goto bad;
     strcpy(varname, var.name);

     size = var.size;
     if(size == 3) goto bad;

     if(k > 2)
          {
          strcpy(token, tok[1]);
          compnum = test_comp();
          if(!compnum) goto bad;
          strcpy(token, tok[2]);
          if((isdigit(token[0])) || (token[0] == 39))
               {
               isnum = 1;
               }
          else
               {
               isnum = 0;
               if(!isvar()) goto bad;
               strcpy(compname, var.name);
                }

          strcpy(cmpval, tok[2]);

          switch(compnum)
               {
               case LT:  
                         strcpy(cop, "jb");
                         break;

               case LE:  
                         strcpy(cop, "jbe");
                         break;

               case EQ:  
                         strcpy(cop, "je");
                         break;

               case NE:  
                         strcpy(cop, "jne");
                         break;

               case GE:  
                         strcpy(cop, "jae");
                         break;

               case GT:  
                         strcpy(cop, "ja");
                         break;

               default:  goto bad;
               }
          }

     else
          {
          if(isbreak)
               {
               if(not) strcpy(cop, "jz");
               else strcpy(cop, "jnz");
               }
          else
               {
               if(not) strcpy(cop, "jnz");
               else strcpy(cop, "jz");
               }

          isnum = 1;
          strcpy(cmpval, "0");
          }

     inif[level + 1] = 1;     // anticipate shift

     if(inloop[level]) l = level;
     else l = next_level();

     if(l)
          {
          if(size == 1)
               {
               if(isnum)
                    {
                    fprintf(code, "\tcmp\tbyte [%s],%s\n", varname, cmpval);
                    }
               else
                    {
                    fprintf(code, "\tmov\tal,[%s]\n", varname);
                    fprintf(code, "\tcmp\tal,[%s]\n", compname);
                    }

               if(isbreak)
                    {
                    if(not)
                         {
                         fprintf(code, "\tjz near %s\n", loop[l].loopend);
                         }
                    else
                         {
                         fprintf(code, "\tjnz near %s\n", loop[l].loopend);
                         }                              
                    inif[level + 1] = 0; // don't need end label
                    return;
                    }

               if(ostype)     // not 32-bit code
                    {
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;                                        
                    fprintf(code, "\t%s near %s\n", cop, ifexit[level + 1]);
                    return;
                    }
               else
                    {
                    fprintf(code, "\t%s\t$+7\n", cop);
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;
                    fprintf(code, "\tjmp\t%s\n", ifexit[level + 1]);
                    }
               }
          else
               {
               if(isnum)
                    {
                    fprintf(code, "\tcmp\tdword [%s],%s\n", varname, cmpval);
                    }
               else
                    {
                    fprintf(code, "\tmov\teax,[%s]\n", varname);
                    fprintf(code, "\tcmp\teax,[%s]\n", compname);
                    }

               if(isbreak)
                    {
                    if(not)
                         {
                         fprintf(code, "\tjz near %s\n", loop[l].loopend);
                         }
                    else
                         {
                         fprintf(code, "\tjnz near %s\n", loop[l].loopend);
                         }                              
                    inif[level + 1] = 0; // don't need end label
                    return;
                    }

               if(ostype)     // not 32-bit code
                    {
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;                                        
                    fprintf(code, "\t%s near %s\n", cop, ifexit[level + 1]);
                    return;
                    }
               else
                    {
                    fprintf(code, "\t%s\t$+7\n", cop);
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;
                    fprintf(code, "\tjmp\t%s\n", ifexit[level + 1]);
                    }
               }
          }

     else
          {
          if(size == 1)
               {
               if(isnum)
                    {
                    fprintf(code, "\tcmp\tbyte [%s],%s\n",
                    varname, cmpval);
                    }
               else
                    {
                    fprintf(code, "\tmov\tal,[%s]\n", varname);
                    fprintf(code, "\tcmp\tal,[%s]\n", compname);
                    }
               if(ostype)     // not 32-bit code
                    {
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;                                        
                    fprintf(code, "\t%s near %s\n", cop, ifexit[level + 1]);
                    return;
                    }
               else
                    {
                    fprintf(code, "\t%s\t$+7\n", cop);
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;
                    fprintf(code, "\tjmp\t%s\n", ifexit[level + 1]);
                    }
               }
          else
               {
               if(isnum)
                    {
                    fprintf(code, "\tcmp\tdword [%s],%s\n",
                    varname, cmpval);
                    }
               else
                    {
                    fprintf(code, "\tmov\teax,[%s]\n", varname);
                    fprintf(code, "\tcmp\teax,[%s]\n", compname);
                    }
               if(ostype)     // not 32-bit code
                    {
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;                                        
                    fprintf(code, "\t%s near %s\n", cop, ifexit[level + 1]);
                    return;
                    }
               else
                    {
                    fprintf(code, "\t%s\t$+7\n", cop);
                    sprintf(ifexit[level + 1], "exif%03d", labelnum);
                    labelnum++;
                    fprintf(code, "\tjmp\t%s\n", ifexit[level + 1]);
                    }
               }
          }
     }

void parse_math(int num)      // parse "math" code line
     {
     char *tok[10], sizeword[5], subvar[3][50], vname[3][50];
     char mathnum[3][50];
     int isadd[3], isbar[3], isptr[3], isnum[3], isstar[3], issub[3];
     int issubnum[3], ndx[3], numtype[3], size[3], strucsize[3], subnum[3];
     int limit, n, retval;

     for(n=0; n < 3; n++)
          {
          isadd[n] = 0;
          isbar[n]= 0;
          isptr[n] = 0;
          isnum[n] = 0;
          issub[n] = 0;
          issubnum[n] = 0;
          size[n] = 0;
          subnum[n] = 0;
          strucsize[n] = 0;
          isstar[n] = 0;
          numtype[n] = 0;
          }
          
     strcpy(vname[0], var.name); // save first variable name
     size[0] = var.size;
     isptr[0] = var.isptr;
     strucsize[0] = var.instruc;

     for(n=0; n < 10; n++)
          {
          tok[n] = strtok(NULL, "(), \t\n;");
          if(tok[n] == 0) break;
          }

     if(n < 2)
          {
          bad: printf("\n\nCan't process: %s\n", iptr[m]);
          exit(1);
          }
     else limit = n;               // count of "tokens"

     if(var.instruc)
          {
          strucsize[0] = var.instruc;
          }

     if(token[0] == '*') isstar[0] = 1;		   
     else if(token[0] == '&') isadd[0] = 1;		   
     else if(token[0] == '_') isbar[0] = 1;

     retval = test_subscript();
     if(retval == 1)          // variable subscript
          {
          issub[0] = 1;
          strcpy(subvar[0], subname); // get subscript variable name
          if(token[0] == '_') isbar[0] = 1;
          strcpy(token, subname);
          if(!isvar()) goto bad;
          strcpy(subvar[0], var.name);
          }
     else if(retval == 2)     // numeric subscript
          {
          issub[0] = 1;
          issubnum[0] = 1;    // show subscript is numeric
          subnum[0] = atoi(subname); // get subscript numeric value
          if(strucsize[0])
               {
               subnum[0] *= strucsize[0];
               }
          }

     ndx[0] = num - 1;

     if((size[0] == 2) || (size[0] == 4)) strcpy(sizeword, "dword");
     else strcpy(sizeword, "byte");

     if(isstar[0])
          {
          if(var.ptsize == 2) numtype[0] = 52;
          else numtype[0] = 50;
          }

     else if(isadd[0])
          {
          numtype[0] = 20;     // variable is an address (size = "dword")
          }

     else
          {
          if(issub[0]) numtype[0] = 2;  // variable is subscripted
          if(isptr[0]) numtype[0] |= 4; // variable is a pointer
          numtype[0] |= (size[0] << 3); // variable size
          if((infunc) && (isbar[0])) numtype[0] |= 128; // encode as function call
          }

     strcpy(token, tok[0]);
     if(!strchr(token, '=')) goto bad;

     strcpy(token, tok[1]);
     ndx[1] = isvar();
//     printf("token is: %s\n", token); 
     if(ndx[1])
          {
          strcpy(vname[1], var.name);
          size[1] = var.size;
          isptr[1] = var.isptr;
          if(var.instruc)
               {
               strucsize[1] = var.instruc;
               }

          if(token[0] == '*') isstar[1] = 1;
          else if(token[0] == '&') isadd[1] = 1;
          else if(token[0] == '_') isbar[1] = 1;

          retval = test_subscript();
          if(retval == 1)          // variable subscript
               {
               issub[1] = 1;
               strcpy(subvar[1], subname); // get subscript variable name
               if(token[0] == '_') isbar[1] = 1;
               strcpy(token, subname);
               if(!isvar()) goto bad;
               strcpy(subvar[1], var.name);
               }
          else if(retval == 2)     // numeric subscript
               {
               issub[1] = 1;
               issubnum[1] = 1;    // show subscript is numeric
               subnum[1] = atoi(subname); // get subscript numeric value
               if(strucsize[1])
                    {
                    subnum[1] *= strucsize[1];
                    }
               }
          }
          
     else if((isdigit(token[0])) || (token[0] == 39))
          {
          strcpy(mathnum[1],tok[1]);
          isnum[1] = 1;
          }
     else goto bad;

     if(isstar[1])
          {
          if(var.ptsize == 2) numtype[1] = 52;
          else numtype[1] = 50;
          }

     else if(isadd[1])
          {
          if(!issub[1])
               {
               numtype[1] = 40;    // variable is an address (size = "dword")
               }
          else numtype[1] = 18;     
          }

     else
          {
          if(isnum[1]) numtype[1] = 1;  // numeric value
          if(issub[1]) numtype[1] = 2;  // variable is subscripted
          if(isptr[1]) numtype[1] |= 4; // variable is a pointer
          if((isnum[1]) || (issub[1])) numtype[1] |= (size[0] << 3);
          else numtype[1] |= (size[1] << 3); // variable size
          if((infunc) && (isbar[1])) numtype[1] |= 128; // encode as function call
          }

     if(limit >= 4)
          {
          strcpy(token, tok[2]);
          result = isop();    // get "operation code"
          if(!result) goto bad;
          strcpy(token, tok[3]);
          ndx[2] = isvar();
//          printf("token is: %s\n", token);  // ***TEST***
          if(ndx[2])
               {
               strcpy(vname[2], var.name);
               size[2] = var.size;
               isptr[2] = var.isptr;
               if(var.instruc)
                    {
                    strucsize[2] = var.instruc;
                    }

               if(token[0] == '*') isstar[1] = 1;               
               else if(token[0] == '&') isadd[1] = 1;
               else if(token[0] == '_') isbar[1] = 1;

               retval = test_subscript();
               if(retval == 1)          // variable subscript
                    {
                    issub[2] = 1;
                    strcpy(subvar[2], subname); // get subscript variable name
                    if(token[0] == '_') isbar[2] = 1;
                    strcpy(token, subname);
                    if(!isvar()) goto bad;
                    strcpy(subvar[2], var.name);
                    }
               else if(retval == 2)     // numeric subscript
                    {
                    issub[2] = 1;
                    issubnum[2] = 1;    // show subscript is numeric
                    subnum[2] = atoi(subname); // get subscript numeric value
                    if(strucsize[2])
                         {
                         subnum[2] *= strucsize[2];
                         }
                    }
               }
          else if((isdigit(token[0])) || (token[0] == 39))
               {
               strcpy(mathnum[2],tok[3]);
               isnum[2] = 1;
               }
          else goto bad;

          if(isstar[2])
               {
               if(var.ptsize == 2) numtype[2] = 52;
               else numtype[2] = 50;
               }

          else if(isadd[2])
               {
               if(!issub[2])
                    {
                    numtype[2] = 40; // variable is an address (size = "dword")
                    }
               else numtype[2] = 18;     
               }

          else
               {
               if(isnum[2]) numtype[2] = 1;  // numeric value
               if(issub[2]) numtype[2] = 2;  // variable is subscripted
               if(isptr[2]) numtype[2] |= 4; // variable is a pointer
               if((isnum[2]) || (issub[2])) numtype[2] |= (size[0] << 3);
               else numtype[2] |= (size[2] << 3); // variable size
               if((infunc) && (isbar[2])) numtype[2] |= 128; // encode as function call
               }
          }
     switch(numtype[1])       // encode transfer of tok[1]
          {
          case 9:             // numeric byte transfer
          case 13:
          case 25:
          case 29:
          case 137:
          case 141:
          case 153:
          case 157: fprintf(code, "\tmov\tal,%s\n", mathnum[1]);
                    break;

          case 17:             // numeric dword transfer
          case 21:
          case 33:
          case 37:
          case 145:
          case 149:
          case 161:
          case 165: fprintf(code, "\tmov\teax,%s\n", mathnum[1]);
                    break;

          case 50:            // *ptr byte transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[1]);
                    fprintf(code, "\tmov\tal,[esi]\n");
                    break;

          case 52:            // *ptr dword transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[1]);
                    if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                    else fprintf(code, "\tmov\teax,esi\n");
                    break;

          case 8:             // variable byte transfer
          case 24:
          case 136:
          case 152: fprintf(code, "\tmov\tal,[%s]\n", vname[1]);
                    break;

          case 10:            // variable byte transfer (subscripted)
          case 26:
          case 138:
          case 154: fprintf(code, "\tmov\tesi,%s\n", vname[1]);
                    if(issubnum[1])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", subnum[1]);
                         }
                    else
                         {
                         if(strucsize[1])
                              {
                              fprintf(code, "\tpush\teax\t;***test***\n");
                              fprintf(code, "\tpush\tedx\n");
                              fprintf(code, "\tmov\teax,[%s]\n", subvar[1]);
                              fprintf(code, "\tmov\tedx,%d\n", strucsize[1]);
                              fprintf(code, "\tmul\tedx\n");
                              fprintf(code, "\tadd\tesi,eax\n");
                              fprintf(code, "\tpop\tedx\n");
                              fprintf(code, "\tpop\teax\n");
                              }
                         else
                              {
                              fprintf(code, "\tadd\tesi,[%s]\n", subvar[1]);
                              }
                         }
                    fprintf(code, "\tmov\tal,[esi]\n");
                    break;

          case 16:            // variable dword transfer
          case 144:           // (in function)
                    fprintf(code, "\tmov\teax,[%s]\n", vname[1]);
                    break;

          case 18:            // variable dword transfer (subscripted)
          case 34:
          case 146:           // variable dword transfer (subscripted, in function)
          case 162:
                    fprintf(code, "\tmov\tesi,%s\n", vname[1]);
                    if(issubnum[1])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[1] << 2));
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }
                    else if(strucsize[1])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[1]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[1]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[1]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }

          case 20:            // variable dword transfer (pointer)
                    fprintf(code, "\tmov\teax,[%s]\n", vname[1]);
                    break;

          case 40:            // variable dword transfer (address)
                    fprintf(code, "\tmov\teax,%s\n", vname[1]);
                    break;

          case 28:           // variable dword transfer (pointer)
                    fprintf(code, "\tmov\teax,[%s]\n", vname[1]);
                    break;

          case 22:            // variable dword transfer (pointer, subscripted)
          case 38:
          case 150:           // (pointer, in function, subscripted)
          case 166:
                    fprintf(code, "\tmov\tesi,%s\n", vname[1]);
                    if(issubnum[1])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[1] << 2));
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }
                    else if(strucsize[1])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[1]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[1]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[1]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         if(!isadd[1]) fprintf(code, "\tmov\teax,[esi]\n");
                         else fprintf(code, "\tmov\teax,esi\n");
                         break;
                         }

          case 148:           // variable dword transfer (pointer, in function)
                    fprintf(code, "\tmov\teax,[%s]\n", vname[1]);
                    break;

          default: goto bad;
          }

     if(limit < 4) goto nomath;

     switch(numtype[2])       // encode transfer of tok[2]
          {
          case 9:             // numeric byte transfer
          case 13:
          case 25:
          case 29:
          case 137:
          case 141:
          case 153:
          case 157: fprintf(code, "\tmov\tbl,%s\n", mathnum[2]);
                    break;

          case 17:             // numeric dword transfer
          case 21:
          case 33:
          case 37:
          case 145:
          case 149:
          case 161:
          case 165: fprintf(code, "\tmov\tebx,%s\n", mathnum[2]);
                    break;

          case 50:            // *ptr byte transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[2]);
                    fprintf(code, "\tmov\tbl,[esi]\n");
                    break;

          case 52:            // *ptr dword transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[2]);
                    fprintf(code, "\tmov\tebx,[esi]\n");
                    break;

          case 8:             // variable byte transfer
          case 24:
          case 136:
          case 152: fprintf(code, "\tmov\tbl,[%s]\n", vname[2]);
                    break;

          case 10:            // variable byte transfer (subscripted)
          case 26:
          case 138:
          case 154: fprintf(code, "\tmov\tesi,%s\n", vname[2]);
                    if(issubnum[2])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", subnum[2]);
                         }
                    else
                         {
                         if(strucsize[2])
                              {
                              fprintf(code, "\tpush\teax\t;***test***\n");
                              fprintf(code, "\tpush\tedx\n");
                              fprintf(code, "\tmov\teax,[%s]\n", subvar[2]);
                              fprintf(code, "\tmov\tedx,%d\n", strucsize[2]);
                              fprintf(code, "\tmul\tedx\n");
                              fprintf(code, "\tadd\tesi,eax\n");
                              fprintf(code, "\tpop\tedx\n");
                              fprintf(code, "\tpop\teax\n");
                              }
                         else
                              {
                              fprintf(code, "\tadd\tesi,[%s]\n", subvar[2]);
                              }
                         }
                    fprintf(code, "\tmov\tbl,[esi]\n");
                    break;

          case 16:            // variable dword transfer
          case 144:           // (in function)
                    fprintf(code, "\tmov\tebx,[%s]\n", vname[2]);
                    break;

          case 18:            // variable dword transfer (subscripted)
          case 34:
          case 146:           // variable dword transfer (subscripted, in function)
          case 162:
                    fprintf(code, "\tmov\tesi,%s\n", vname[2]);
                    if(issubnum[2])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[2] << 2));
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }
                    else if(strucsize[2])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[2]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[2]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[2]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }

          case 20:            // variable dword transfer (pointer)
                    fprintf(code, "\tmov\tebx,[%s]\n", vname[2]);
                    break;

          case 40:            // variable dword transfer (address)
                    fprintf(code, "\tmov\tebx,%s\n", vname[2]);
                    break;

          case 28:           // variable dword transfer (pointer)
                    fprintf(code, "\tmov\tebx,[%s]\n", vname[2]);
                    break;

          case 22:            // variable dword transfer (pointer, subscripted)
          case 38:
          case 150:           // (pointer, in function, subscripted)
          case 166:
                    fprintf(code, "\tmov\tesi,%s\n", vname[2]);
                    if(issubnum[2])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[2] << 2));
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }
                    else if(strucsize[2])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[2]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[2]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[2]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         fprintf(code, "\tmov\tebx,[esi]\n");
                         break;
                         }

          case 148:           // variable dword transfer (pointer, in function)
                    fprintf(code, "\tmov\tebx,[%s]\n", vname[2]);
                    break;

          default: goto bad;
          }

     if((size[0] == 1) || (size[0] == 3)) do_math(result);
     else do_math(result + 10); // encode math operation

     nomath:
     switch(numtype[0])       // encode transfer to tok[0] ("lvalue")
          {
          case 50:            // *ptr byte transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[0]);
                    fprintf(code, "\tmov\t[esi],al\n");
                    break;

          case 52:            // *ptr dword transfer
                    fprintf(code, "\tmov\tesi,[%s]\n", vname[0]);
                    fprintf(code, "\tmov\t[esi],eax\n");
                    break;

          case 8:             // variable byte transfer
          case 24:
          case 136:
          case 152: fprintf(code, "\tmov\t[%s],al\n", vname[0]);
                    break;

          case 10:            // variable byte transfer (subscripted)
          case 26:
          case 138:
          case 154: fprintf(code, "\tmov\tesi,%s\n", vname[0]);
                    if(issubnum[0])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", subnum[0]);
                         }
                    else
                         {
                         if(strucsize[0])
                              {
                              fprintf(code, "\tpush\teax\t;***test***\n");
                              fprintf(code, "\tpush\tedx\n");
                              fprintf(code, "\tmov\teax,[%s]\n", subvar[0]);
                              fprintf(code, "\tmov\tedx,%d\n", strucsize[0]);
                              fprintf(code, "\tmul\tedx\n");
                              fprintf(code, "\tadd\tesi,eax\n");
                              fprintf(code, "\tpop\tedx\n");
                              fprintf(code, "\tpop\teax\n");
                              }
                         else
                              {
                              fprintf(code, "\tadd\tesi,[%s]\n", subvar[0]);
                              }
                         }
                    fprintf(code, "\tmov\t[esi],al\n");
                    break;

          case 16:            // variable dword transfer
          case 144:           // (in function)
                    fprintf(code, "\tmov\t[%s],eax\n", vname[0]);
                    break;

          case 18:            // variable dword transfer (subscripted)
          case 34:
          case 146:	          // variable dword transfer (subscripted, (in function)
          case 162:
                    fprintf(code, "\tmov\tesi,%s\n", vname[0]);
                    if(issubnum[0])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[0] << 2));
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }
                    else if(strucsize[0])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[0]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[0]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[0]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }

          case 20:            // variable dword transfer (pointer)
                    fprintf(code, "\tmov\t[%s],eax\n", vname[0]);
                    break;

          case 22:            // variable dword transfer (pointer, subscripted)
          case 38:
          case 150:           // (pointer, in function, subscripted)
          case 166:
                    fprintf(code, "\tmov\tesi,%s\n", vname[0]);
                    if(issubnum[0])
                         {
                         fprintf(code, "\tadd\tesi,%d\n", (subnum[0] << 2));
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }
                    else if(strucsize[0])
                         {
                         fprintf(code, "\tpush\teax\t;***test***\n");
                         fprintf(code, "\tpush\tedx\n");
                         fprintf(code, "\tmov\teax,[%s]\n", subvar[0]);
                         fprintf(code, "\tmov\tedx,%d\n", strucsize[0]);
                         fprintf(code, "\tmul\tedx\n");
                         fprintf(code, "\tadd\tesi,eax\n");
                         fprintf(code, "\tpop\tedx\n");
                         fprintf(code, "\tpop\teax\n");
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }
                    else
                         {
                         fprintf(code, "\tmov\tedx,[%s]\n", subvar[0]);
                         fprintf(code, "\tshl\tedx,2\n");
                         fprintf(code, "\tadd\tesi,edx\n");
                         fprintf(code, "\tmov\t[esi],eax\n");
                         break;
                         }


          case 148:           // variable dword transfer (pointer, in function)
                    fprintf(code, "\tmov\t[%s],eax\n", vname[0]);
                    break;



          default: goto bad;
          }
     }

void parse_while(void)        // begin "while" loop
     {
     char text[50], *tok, varname[20];
     int cmpvar, l, ndx, size;

     size = 0;

     tok = strtok(NULL, " \t\n)");
     if(tok)
          {
          strcpy(token, tok);
          if(isdigit(token[0])) cmpvar = 0; // numeric value
          else
               {
               ndx = isvar();
               if(!ndx)
                    {
                    printf("\n\nUndefined variable %s in:\n", tok);
                    printf("%s\n", iptr[m]);
                    exit(1);
                    }
               else
                    {
                    strcpy(varname, var.name);
                    size = var.size;
                    if(size > 2)
                         {
                         printf("\n\nCan't use string variable %s in:\n", tok);
                         printf("%s\n", iptr[m]);
                         exit(1);
                         }
                    cmpvar = 1;
                    }
               }
          }
     else
          {
          printf("\n\nNo value in:\n");
          printf("%s\n", iptr[m]);
          exit(1);
          }

     inloop[level +1] = 1;    // show loop in progress (anticipate shift)

     l = level + 1;           // make the following code more compact!

     sprintf(text, "whil%03d", labelnum);
     strcpy(loop[l].loop_start, text); // probably pointless!
     labelnum++;
     sprintf(loop[l].loopend, "wout%03d", labelnum);
     sprintf(loop[l].endcode[loop[l].endcount], "\tjmp\t%s\n", text);
     labelnum++;
     loop[l].endcount++;

     if(!cmpvar)              // loop "forever"
          {
          fprintf(code, "%s:\n", text);
          }
     else
          {
          if(size == 1)
               {
               fprintf(code, "%s: mov\tal,[%s]\n", text, varname);
               fprintf(code, "\tcmp\tal,0\n");
               if(ostype)     // not 32-bit code
                    {
                    fprintf(code, "\tje near %s\n", loop[l].loopend);
                    }
               else
                    {
                    fprintf(code, "\tjne\t$+7\n");
                    fprintf(code, "\tjmp\t%s\n", loop[l].loopend);                    
                    }
               }
          else
               {
               fprintf(code, "%s: mov\teax,[%s]\n", text, varname);
               fprintf(code, "\tcmp\teax,0\n");
               if(ostype)     // not 32-bit code
                    {
                    fprintf(code, "\tje near %s\n", loop[l].loopend);
                    }
               else
                    {
                    fprintf(code, "\tjne\t$+7\n");
                    fprintf(code, "\tjmp\t%s\n", loop[l].loopend);
                    }
               }
          }
     }

void read_lib(void)           // read code in "libfile"
     {
     char temp[100], *ptr, *tok[2];
     int n, ndx;

     libfile = fopen(libname, "rt");
     if(!libfile)
          {
          printf("\a\n\n\tCan't open %s!\n\n", libname);
          exit(1);
          }

     linecount = 0;

     while(1)
          {
          fgets(copy, 100, libfile);
          linecount++;

          if(feof(libfile)) break;
          }

     rewind(libfile);

     iptr[0] = (char *)malloc((linecount * 100));
     if(!iptr[0])
          {
          printf("/n/n/t/aCan't allocate memory for library code\n\n");
          exit(1);
          }

     for(n=1; n < linecount; n++)
          {
          iptr[n] = iptr[n-1] + 100;
          }

     ptr = iptr[0];

     for(n=0; n < (linecount * 100); n++, ptr++)
          {
          *ptr = 0;
          }

     for(n=0, lines=1; n < linecount; n++, lines++)
          {
          fgets(temp, 100, libfile);
          if(feof(libfile)) break;
          scopy(temp, iptr[n]); // get rid of coments!
          scopy(temp, copy);  // make copy for parsing
          if(test_copy()) continue; // blank or comment
          if(((copy[0] == 'c') && (copy[1] == 'h') && (copy[2] == 'a')) ||
          ((copy[0] == 'i') && (copy[1] == 'n') && (copy[2] == 't')) ||
          ((copy[0] == 'v') && (copy[1] == 'o') && (copy[2] == 'i')))
               {
               tok[0] = strtok(copy, " \t\n"); // return "size"
               tok[1] = strtok(NULL, " (\t\n"); // function name
               if(tok[1])
                    {
                    strcpy(token, tok[1]);
                    ndx = isfunc();
                    if(!ndx) continue;
                    ndx -= 1;
                    proto[ndx].libfunc = n; // save line number
                    }
               }
          }

     fclose(libfile);
     }

void save_string(void)        // save/point to character string
     {
     char *end, *ptr, *start;
     char cstring[80], mycopy[100], ptname[50], strname[50];
     int i;

     scopy(iptr[m], mycopy);  // make "local" copy

     start = strchr(mycopy, '"');
     end = strrchr(mycopy, '"');

     if(start && end && (end != start)) // if two separate quotes
          {
          *start++ = 0;
          ptr = strtok(start, "\""); // get character string
          strcpy(cstring, ptr); // save it
          end++;                // point beyond null character

          sprintf(strname, "str%03d", labelnum);
          sprintf(ptname, "spt%03d", labelnum);
          labelnum++;

          fprintf(data, "%s\tdb\t'%s',0\n", strname, cstring); // save string
          fprintf(data, "%s\tdd\t0\n", ptname); // save pointer

          fprintf(code, "\tmov\teax,%s\n", strname); // address of string
          fprintf(code, "\tmov\t[%s],eax\n", ptname); // move to pointer

          strcpy(cvar[dcount].name, ptname); // set up data entry for "isvar()"
          cvar[dcount].size = 2;
          cvar[dcount].ptsize = 1;
          cvar[dcount].isptr = 1;
          dcount++;

          // now, "fix up" "copy" for return to "call_function()"

          for(i=0; i < 100; i++) copy[i] = 0; // clear "copy"

          sprintf(copy, "%s%s%s", mycopy, ptname, end);

          start = strtok(copy, "("); // give "call_function()" what it expects
          }

     else
          {
          printf("\n\nIncorrect string in:\n");
          printf("%s\n", iptr[m]);
          exit(1);
          }
     }

void scopy(char *source, char *dest) // copy string without comments
     {
     char *sptr;
     char *dptr;
     int length, n;

     sptr = source;
     dptr = dest;

     length = 100;

     for(n=0; n < length; n++, dest++) *dest = 0; // clear "dest"

     for(n=0; n < 100; n++, sptr++, dptr++)
          {
          if(*sptr == 0) break;
          if((*sptr == '/') && (*(sptr+1) == '/')) break;
          if((*sptr == ' ') && (*(sptr+1) == ';'))
               {
               *dptr = 10;    // terminate with a <lf>
               break;
               }
          *dptr = *sptr;
          }
     }

void setup_parse(void)        // enter code to parse "command tail"
     {
     int ndx;

     strcpy(token, "get_tail");
     ndx = isfunc();
     if(!ndx)
          {
          printf("\n\n\t\aCan't find \"get_tail()\"!\n\n");
          exit(1);
          }
     else
          {
          ndx -= 1;
          proto[ndx].inuse = 1;
          }

     strcpy(token, "parse_tail");
     ndx = isfunc();
     if(!ndx)
          {
          printf("\n\n\t\aCan't find \"parse_tail()\"!\n\n");
          exit(1);
          }
     else
          {
          ndx -= 1;
          proto[ndx].inuse = 1;
          }

     fprintf(code, "\tcall\tget_tail\n");
     fprintf(code, "\tcmp\teax,0\n"); // test for "tail"
     fprintf(code, "\tjz\tnotail\n");
     fprintf(code, "\tcall\tparse_tail\n");
     fprintf(code, "notail:\n");
     }

void shift_left(int size)     // shift variable left
     {
     if(size == 1)            // "byte" operation
          {
          fprintf(code, "\tmov\tcl,bl\n");
          fprintf(code, "\tshl\tal,cl\n");
          }
     else
          {
          fprintf(code, "\tmov\tcl,bl\n");
          fprintf(code, "\tshl\teax,cl\n");
          }
     }

void shift_right(int size)    // shift variable right
     {
     if(size == 1)            // "byte" operation
          {
          fprintf(code, "\tmov\tcl,bl\n");
          fprintf(code, "\tshr\tal,cl\n");
          }
     else
          {
          fprintf(code, "\tmov\tcl,bl\n");
          fprintf(code, "\tshr\teax,cl\n");
          }
     }

int test_comp(void)           // test "comparison" operator
     {
     if(!strcmp(token, "<")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (GE);
               }     
          else
               {     
               return (LT);
               }
          }     
          
     if(!strcmp(token, "<=")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (GT);
               }
          else
               {
               return (LE);
               }
          }
     
     if(!strcmp(token, "==")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (NE);
               }
          else
               {
               return (EQ);
               }
          }
          
     if(!strcmp(token, "!=")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (EQ);
               }
          else
               {
               return (NE);
               }
          }
          
     if(!strcmp(token, ">=")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (LT);
               }
          else
               {
               return (GE);
               }
          }
          
     if(!strcmp(token, ">")) 
          {
          if(ostype)               // if 16-bit code
               {
               return (LE);
               }
          else
               {
               return (GT);
               }
          }

     return 0;
     }

int test_copy(void)           // test for blank line or comment
     {
     int k, visible;

     visible = 0;

     if((copy[0] == '/') && (copy[1] == '/')) return 1; // redundant?

     for(k=0; k < strlen(copy); k++)
          {
          if(isgraph(copy[k]))
               {
               visible = 1;
               break;
               }
          }

     return (!visible);
     }

int test_subscript(void)      // test for / get variable subscript
     {
     char *tok1, *tok2;
     int k;
     
     for(k=0; k < 50; k++) subname[k] = 0;
     
     k = 0;
     tok1 = strchr(token, '[');
     tok2 = strrchr(token, ']');     

     if(tok1 && tok2)
          {
          tok1++;
          for(; tok1 < tok2; tok1++, k++)
               {
               subname[k] = *tok1;
               }
          if(subname)
               {
               if(isdigit(subname[0])) return 2;
               else return 1;
               }
          }     
     return 0;
     }
