// b2.c                         1624                          4/9/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.

// NOTE code modified for "near" conditional jumps.

// 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"

int get_lib_code(void)        // read and translate "library" code
     {
     char *tok;
     int funcstart, libstart, q;

     read_lib();              // read code from "libfile"

     libstart = pcount - libcount; // starting "library" prototype

     next: funcstart = 50000; // impossible value

     for(q=libstart; q < pcount; q++)
          {
          if((proto[q].entered == 0) && (proto[q].inuse == 1))
               {
               funcstart = proto[q].libfunc; // line number of function code
               break;
               }
          }

     if(funcstart == 50000)           // all done
          {
          return 0;
          }

     for(m=funcstart; m < lines; m++)
          {
          scopy(iptr[m], copy); // make copy for parsing
          if(test_copy()) continue; // blank line or comment
          if(level == 0)
               {
               clear_loops(); // be sure loop structures are clear
               clear_if();    // clear "if-else" variables
               result = begin_function(); // start new function
               if(result) continue;
               else
                    {
                    printf("\n\n\tCan't begin function in:\n");
                    printf("\t%s\n\n", iptr[m]);
                    exit(1);
                    }
               }
          tok = strtok(copy, " \t(");
          if(strchr(tok, '{'))
               {
               level++;
               continue;
               }
          if(strchr(tok, '}'))
               {
               if(inswitch[level]) end_switch(); // terminate "switch" sequence
               if(inloop[level]) end_loop();
               if(inif[level]) end_if(level);
               if(inelse[level]) end_else();
               if((infunc) && (level == 1)) end_function();
               level--;
               if(level == 0) clear_if();
               if(level == 0) goto next;
               else continue;
               }
          if(strstr(tok, "continue"))
               {
               jump_back();
               continue;
               }
          if(strstr(tok, "if"))
			{
			parse_if();
			continue;
			}
          if(strstr(tok, "else"))
			{
			inelse[level + 1] = 1; // anticipate shift
			continue;
			}
          if(strstr(tok, "for"))
			{
			parse_for();
			continue;
			}
          if(strstr(tok, "while"))
			{
			parse_while();
			continue;
			}
          if(strstr(tok, "_asm"))
               {
               do_assembly();
               continue;
               }
          if(strstr(tok, "switch"))
			{
			begin_switch(); // set up for "switch" sequence
			continue;
			}
          if(strstr(tok, "case"))
			{
			if(inswitch[level])
                    {
                    parse_case();  // do "case" test
                    }
               else
                    {
                    printf("\n\nCase statement outside \"switch\":\n");
                    printf("%s\n\n", iptr[m]);
                    exit(1);
                    }
			continue;
			}
          if(strstr(tok, "return"))
			{
			if(infunc)
                    {
                    do_return();   // encode early return
                    }
               else
                    {
                    printf("\n\n\"Return\" statement outside function:\n");
                    printf("%s\n\n", iptr[m]);
                    exit(1);
                    }
			continue;
			}
          if(strstr(tok, "exit"))
			{
               early_exit();  // encode early exit
               continue;
               }
          if(strstr(tok, "default:"))
			{
			if(inswitch[level])
                    {
                    do_default();  // start "default" code
                    }
               else
                    {
                    printf("\n\n\"Default\" statement outside \"switch\":\n");
                    printf("%s\n\n", iptr[m]);
                    exit(1);
                    }
			continue;
			}

          if(strstr(tok, "break;"))
			{
               if(inswitch[level])
                    {
			     do_sbreak();   // insert "switch" break code
			     continue;
                    }
               else if(inloop[level])
                    {
                    do_lbreak(level); // insert "loop" break code
                    continue;
                    }
               else if((result = next_level()))
                    {
                    result--;
                    do_lbreak(level); // insert "loop" break code
                    continue;
                    }
               else
                    {
                    printf("\n\nWarning -- \"break\" not supported in:\n");
                    printf("%s\n", iptr[m]);
                    continue;
                    }
               }

          strcpy(token, tok);
          result = isfunc();
          if(result)
               {
               call_function(result);
               continue;
               }
          result = isvar();
          if(result)
               {
               if(strstr(token, "++"))
                    {
                    increment(1, result);
                    continue;
                    }
               else if(strstr(token, "--"))
                    {
                    increment(0, result);
                    continue;
                    }
               else if(find_function(result)) continue;
               else
                    {
                    parse_math(result);
                    continue;
                    }
               }
          else
               {
               printf("\n\n\t\aError: %s not defined!\n\n", token);
               exit (1);
               }
          }

     return 1;
     }

int get_lib_data(void)        // transfer library data to "temp" file
     {
     char cstr[5], *dptr, *length, *sptr, temp[50], *tok[4];
     int num, oldcount;
 
     oldcount = dcount;       // save dcount value
     inlib = 1;               // getting library data

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

     while(1)
          {
          fgets(text, 100, libhead); // read line of header file
          if(feof(libhead)) break;

          if(strstr(text, ");")) break; // don't get prototypes

          if(strstr(text, "typedef")) // structure "template"
               {
               scopy(text, copy);     // make copy for parsing
               if(define_structure()) // make structure "template"
                    {
                    continue;
                    }
               }
 
          if(strstr(text, "struct")) // structure definition
               {
               scopy(text, copy);
               if(!copy[0]) continue; // probably a comment!
               if(make_structure()) // create structure
                    {
                    continue;
                    }
               }

          if((text[0] == 'i') && (text[1] == 'n') && (text[2] == 't'))
               {
               scopy(text, copy);
               tok[0] = strtok(copy, " \t\n"); // "int"
               tok[1] = strtok(NULL, " [\t\n;,"); // name
               strcpy(token, tok[1]);
               if(isvar())
                    {
                    printf("\nB2-285 Warning - %s re-defined!\n", var.name);
                    continue;
                    }
               if(strchr(tok[1], '*')) // if pointer
                    {
                    cvar[dcount].isptr = 1;
                    strcpy(temp, tok[1]);
                    ptr = temp + 1;
                    strcpy(tok[1], ptr);
                    cvar[dcount].size = 2; // not if array of ptrs - see following
                    cvar[dcount].ptsize = 2;
                    }
               if((strchr(text, '[')) && (strchr(text, ']'))) // if string
                    {
                    length = strtok(NULL, "]"); // string length
                    if(length)
                         {
                         cvar[dcount].length = atoi(length);
                         cvar[dcount].size = 4; // array of pointers
                         }
                    strcpy(cvar[dcount].name, tok[1]);
                    dcount++;
                    }
               else
                    {
                    tok[2] = strtok(NULL, " \t\n;,"); // "="?
                    if(tok[2]) tok[3] = strtok(NULL, " \t\n;,"); // value
                    strcpy(cvar[dcount].name, tok[1]);
                    cvar[dcount].size = 2;
                    if(tok[3])
                         {
                         if((strchr(tok[3], 'x')) || (strchr(tok[3], 'X')))
                              {
                              cvar[dcount].value = (int)strtol(tok[3], NULL, 16);
                              }
                         else cvar[dcount].value = atoi(tok[3]);
                         }
                    else cvar[dcount].value = 0;
                    dcount++;
                    }
               }

          else if((text[0] == 'c') && (text[1] == 'h') && // "char" or "ptr"
          (text[2] == 'a') && (text[3] == 'r'))
               {
               scopy(text, copy);
               tok[0] = strtok(copy, " \t\n"); // "char"
               tok[1] = strtok(NULL, " [\t\n;"); // name
               strcpy(token, tok[1]);
               if(isvar())
                    {
                    printf("\nB2-336 Warning - %s re-defined!\n", var.name);
                    continue;
                    }
               if(strchr(tok[1], '*')) // if pointer
                    {
                    cvar[dcount].isptr = 1;
                    strcpy(temp, tok[1]);
                    ptr = temp + 1;
                    strcpy(tok[1], ptr);
                    cvar[dcount].size = 2; // not if array of ptrs - see following
                    cvar[dcount].ptsize = 1;
                    }
               if((strchr(text, '[')) && (strchr(text, ']'))) // if string
                    {
                    length = strtok(NULL, "]"); // string length
                    if(length)
                         {
                         cvar[dcount].length = atoi(length);
                         if(cvar[dcount].isptr) cvar[dcount].size = 4; // array of pointers
                         else cvar[dcount].size = 3;
                         }
                    if((strstr(text, "{")) && (strstr(text, "}")))
                         {
                         sptr = strchr(text, '{'); // start of string
                         sptr += 1; // point beyond "{"
                         dptr = cvar[dcount].text;
                         for(; ; dptr++, sptr++)
                              {
                              if(*sptr == '}') break;
                              if(*sptr == '"') *dptr = 39;
                              else *dptr = *sptr;
                              }
                         *dptr++ = 44;
                         *dptr++ = 48; // end string with a "zero" byte
                         }
                    strcpy(cvar[dcount].name, tok[1]);
                    dcount++;
                    }
               else
                    {
                    tok[2] = strtok(NULL, " \t\n;,"); // "="?
                    if((tok[2]) && (strchr(tok[2], '=')))
                         {
                         tok[3] = strtok(NULL, " \t\n;");
                         if(tok[3])
                              {
                              if(*tok[3] == 39) // if character value
                                   {
                                   tok[3]++; // point beyond "'"
                                   cstr[0] = *tok[3]; // copy character
                                   cstr[1] = 0;       // terminate "string"
                                   cvar[dcount].value = atoi(cstr); // save value
                                   }
                              else if((strchr(tok[3], 'x')) || (strchr(tok[3], 'X')))
                                   {
                                   cvar[dcount].value = (int)strtol(tok[3], NULL, 16);
                                   }
                              else cvar[dcount].value = atoi(tok[3]);
                              }
                         }
                    else cvar[dcount].value = 0;
                    strcpy(cvar[dcount].name, tok[1]);
                    if(!cvar[dcount].isptr) cvar[dcount].size = 1;
                    dcount++;
                    }
               }
          }

     rewind(libhead);         // for "get_proto();

     if(dcount > oldcount)
          {
          if(!data)           // "data.tmp" not open
               {
               time(&now);
               data = fopen("data.tmp", "wt");
               fprintf(data, "; %s\t%s\n\n", outname, asctime(localtime(&now)));
               if((ostype == 1) || (ostype == 3)) // "flat real" or OverDOS program
                    {
                    fprintf(data, "\tbits\t16\n");
                    fprintf(data, "\torg\t0x0100\n\n");
                    }
               else if(ostype == 2) // "UNOS" system code
                    {
                    fprintf(data, "\tbits\t16\n");
                    fprintf(data, "\torg\t0x0000\n\n");
                    }
               else
                    {
                    fprintf(data, "\tbits\t32\n");
                    fprintf(data, "\torg\t0x0000\n\n");
                    }
               fprintf(data, "\tsection\t.data align=16\n\n");
               }

          for(num=oldcount; num < dcount; num++)
               {
               if(cvar[num].size == 1)
                    {
                    fprintf(data, "%s\tdb\t%d\n", cvar[num].name, cvar[num].value);
                    }
               if(cvar[num].size == 2)
                    {
                    fprintf(data, "%s\tdd\t%d\n", cvar[num].name, cvar[num].value);
                    }
               if(cvar[num].size == 3)
                    {
                    if((cvar[num].length) && (cvar[num].text[0] == 0))
                         {
                         fprintf(data, "%s:\ttimes %d db 0\n", cvar[num].name,
                         cvar[num].length);
                         }
                    else fprintf(data, "%s\tdb\t%s\n", cvar[num].name,
                    cvar[num].text);
                    }
               if(cvar[num].size == 4)
                    {
                    if(cvar[num].length)
                         {
                         fprintf(data, "%s:\ttimes %d dd 0\n", cvar[num].name,
                         cvar[num].length);
                         }
                    }
               }
          }

     inlib = 0;               // done getting library data
     return (dcount);
     }

int get_local_data(int func)  // enter local data
     {
     char *name, *size;
     int isptr, lndx, ndx;

     ndx = func - 1;          // actual "proto" subscript
     lndx = lvcount;          // index to next "local" structure

     while(1)
          {
          m++;
          isptr = 0;
          scopy(iptr[m], copy); // make copy for parsing
          size = strtok(copy, " \t\n;");
          if(!size)
               {
               m--;
               return 0;      // not a local variable
               }

          if((strcmp(size, "char")) && (strcmp(size, "int")))
               {
               m--;
               return 0;      // not a local variable
               }

          name = strtok(NULL, " \t\n;");
          if(*name == '*')
               {
               local[lndx].isptr = 1;
               isptr = 1;
               name++;        // point beyond *
               }

          if((!strcmp(size, "char")) && (!isptr)) local[lndx].size = 1;
          else local[lndx].size = 2;
          if(isptr)
               {
               if(!strcmp(size, "char")) local[lndx].ptsize = 1;
               else local[lndx].ptsize = 2;
               }

          sprintf(local[lndx].callname, "%s", name); // save "call" name
          sprintf(local[lndx].name, "%s%03d", name, ndx); // save "real" name

          if(local[lndx].size == 1)
               {
               fprintf(data, "%s%03d\tdb\t0\n", name, ndx); // write "real" name
               }
          else
               {
               fprintf(data, "%s%03d\tdd\t0\n", name, ndx); // write "real" name
               }
          if(!proto[ndx].localvar) // if this is first local variable
               {
               proto[ndx].localndx = lndx;
               }
          proto[ndx].localvar++;
          lndx++;
          lvcount++;
          }
     return 1;
     }

int get_proto(void)           // get function prototypes
     {
     char *ptr, text[100], *tok[12];
     int i, j, k, p;

     gotparam = 0;

     if(foundmain) goto testlib; // check for "library" functions

     for(m=0; m < lines; m++) // start at beginning for safety
          {
          if((strstr(iptr[m], "main")) && (!strstr(iptr[m], ");")))
               {
               foundmain = 1; // past prototypes
               break;
               }
          if(strstr(iptr[m], ");")) // if prototype
               {
               scopy(iptr[m], copy); // make copy for parsing
               tok[0] = strtok(copy, " \t");
               if(strstr(tok[0], "char")) proto[pcount].retsize = 1;
               else if(strstr(tok[0], "int")) proto[pcount].retsize = 2;
               tok[1] = strtok(NULL, " ("); // function name
               strcpy(proto[pcount].name, tok[1]);

               p = 0;         // "callcount" index

               for(i=2; i < 12; i += 2)
                    {
                    tok[i] = strtok(NULL, " ,);\n"); // parameter size
                    if((i == 2) && (strstr(tok[2], "void")))  // no calls
                         {
                         break;
                         }

                    if(!tok[i])
                         {
                         break;
                         }

                    if(strstr(tok[i], "char")) proto[pcount].callsize[p] = 1;
                    if(strstr(tok[i], "int")) proto[pcount].callsize[p] = 2;
                    if(strstr(tok[i], "...")) // variable argument list
                         {
                         proto[pcount].callsize[p] = 92;
                         proto[pcount].gettail = 1; // show arg list needed
                         strcpy(proto[pcount].callname[p], "_tail");
                         proto[pcount].callcount++;
                         strcpy(token, "_tail");
                         if(!isvar()) // don't define twice
                              {
                              cvar[dcount].size = 2;
                              strcpy(cvar[dcount].name, "_tail");
                              dcount++;
                              }
                         break;
                         }

                    tok[i+1] = strtok(NULL, " ,);\n"); // parameter name
                    if(tok[i+1]) ptr = strchr(tok[i+1], '*');
                    else
                         {
                         printf("\n\nIncorrect prototype in:\n");
                         printf("%s\n", iptr[m]);
                         exit(1);
                         }
                    if(ptr)
                         {
                         proto[pcount].isptr[p] = 1;
                         proto[pcount].callsize[p] = 2;
                         ptr++;    // point beyond "*"
                         strcpy(token, ptr); // name without "*"
                         strcpy(tok[i+1], token); // put it back
                         }

                    sprintf(proto[pcount].callname[p], "_%s", tok[i+1]);
                    proto[pcount].callcount++;
                    gotparam = 1;  // we have at least one calling parameter
                    sprintf(token, "_%s", tok[i+1]);
                    if(!isvar()) // don't define twice
                         {
                         cvar[dcount].size = proto[pcount].callsize[p];
                         sprintf(cvar[dcount].name, "_%s", tok[i+1]);
                         dcount++;
                         }
                    p++;
                    }
               pcount++;
               }
          }

     testlib: if((needlib) && (libhead)) // if program uses "library" functions
          {
          while(1)
               {
               fgets(text, 100, libhead); // read line of header file
               if(feof(libhead)) break;

               if(strstr(text, ");")) // if prototype
                    {
                    scopy(text, copy); // make copy for parsing
                    tok[0] = strtok(copy, " \t");
                    if(strstr(tok[0], "char")) proto[pcount].retsize = 1;
                    else if(strstr(tok[0], "int")) proto[pcount].retsize = 2;
                    tok[1] = strtok(NULL, " ("); // function name
                    strcpy(proto[pcount].name, tok[1]);

                    p = 0;         // "callcount" index

                    for(i=2; i < 12; i += 2)
                         {
                         tok[i] = strtok(NULL, " ,);\n"); // parameter size
                         if((i == 2) && (strstr(tok[2], "void")))  // no calls
                              {
                              break;
                              }

                         if(!tok[i])
                              {
                              break;
                              }

                         if(strstr(tok[i], "char")) proto[pcount].callsize[p] = 1;
                         if(strstr(tok[i], "int")) proto[pcount].callsize[p] = 2;
                         if(strstr(tok[i], "...")) // variable argument list
                              {
                              proto[pcount].callsize[p] = 92;
                              proto[pcount].gettail = 1; // show arg list needed
                              strcpy(proto[pcount].callname[p], "_tail");
                              proto[pcount].callcount++;
                              strcpy(token, "_tail");
                              if(!isvar()) // don't define twice
                                   {
                                   cvar[dcount].size = 2;
                                   strcpy(cvar[dcount].name, "_tail");
                                   dcount++;
                                   }
                              break;
                              }

                         tok[i+1] = strtok(NULL, " ,);\n"); // parameter name
                         if(tok[i+1]) ptr = strchr(tok[i+1], '*');
                         else
                              {
                              printf("\n\nIncorrect prototype in:\n");
                              printf("%s\n", text);
                              exit(1);
                              }
                         if(ptr)
                              {
                              proto[pcount].isptr[p] = 1;
                              proto[pcount].callsize[p] = 2;
                              ptr++;    // point beyond "*"
                              strcpy(token, ptr); // name without "*"
                              strcpy(tok[i+1], token); // put it back
                              }

                         sprintf(proto[pcount].callname[p], "_%s", tok[i+1]);
                         proto[pcount].callcount++;
                         gotparam = 1;  // we have at least one calling parameter
                         sprintf(token, "_%s", tok[i+1]);
                         if(!isvar()) // don't define twice
                              {
                              cvar[dcount].size = proto[pcount].callsize[p];
                              sprintf(cvar[dcount].name, "_%s", tok[i+1]);
                              dcount++;
                              }
                         p++;
                         }

                    pcount++;
                    libcount++;
                    }
               }
          fclose(libhead);
          }

     if(gotparam)
          {
          bsfile = fopen("bss.tmp", "wt");
          if(!bsfile)
               {
               printf("\n\n\tCan't open \"bss.tmp\"!\n\n");
               exit(1);
               }

          if(ostype == 4)
               {
               fprintf(bsfile, "\n;\tsection\t.bss align=16\n");
               fprintf(bsfile, "\talign 16\n\n");
               }
          else
               {
               fprintf(bsfile, "\n\tsection\t.bss align=16\n\n");
               }

          for(j=0; j < pcount; j++)
               {
               for(k=0; k < proto[j].callcount; k++)
                    {
                    strcpy(token, proto[j].callname[k]);
                    if((isvar()) && (var.saved)) continue; // don't redefine!
                    if(proto[j].callsize[k] == 1)
                         {
                         if(ostype == 4)
                              {
                              fprintf(bsfile, "%s\trb\t1\n",
                              proto[j].callname[k]);
                              }
                         else
                              {
                              fprintf(bsfile, "%s\tresb\t1\n",
                              proto[j].callname[k]);
                              }                              
                         }
                    else 
                         {
                         if(ostype == 4)
                              {
                              fprintf(bsfile, "%s\trd\t1\n",
                              proto[j].callname[k]);
                              }
                         else
                              {
                              fprintf(bsfile, "%s\tresd\t1\n",
                              proto[j].callname[k]);
                              }
                         }                                   

                    is_saved(); // show variable has been saved
                    }
               }
          }

     return (pcount);
     }

int get_tail(void)            // get "argument list" for "printf()" call
     {
     char tail[100], ptname[20], strname[20], *tok;
     int count, n;

     tok = strtok(NULL, ");"); // get rest of line

     if(!tok) return 0;       // no tail found!
     else
          {
          while(*tok)         // clean up start
               {
               if((isalnum(*tok)) || (*tok == '_'))
                    {
                    strcpy(tail, tok);
                    break;
                    }
               else tok++;
               }

          if(!tail[0]) return 0; // invalid tail!
          }

     tok = strtok(tail, ", "); // get first argument
     if(!tok) return 0;       // invalid tail!
     strcpy(token, tok);      // copy it
     if(isdigit(token[0]))    // numeric value
          {
          sprintf(strname, "arg%03d", labelnum);
          sprintf(ptname, "apt%03d", labelnum);
          labelnum++;

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

          fprintf(code, "\tmov\teax,%s\n", strname); // arg address
          fprintf(code, "\tmov\t[%s],eax\n", ptname); // point to it
          fprintf(code, "\tmov\tdword [vcount],0\n"); // clear "vcount"
          fprintf(code, "\tmov\teax,%s\n", ptname);
          fprintf(code, "\tmov\t[vptr],eax\n");
          fprintf(code, "\tinc\tdword [vcount]\n"); // count argument
          count = 1;     // keep local count
          }

     else
          {
          if(!isvar())
               {
               printf("\n\nLine %d: Unknown argument %s in:\n", m, token);
               printf("\t%s\n\n", iptr[m]);
               exit(1);
               }

          fprintf(code, "\tmov\tdword [vcount],0\n"); // clear "vcount"
          if(var.isptr)  // save value, not address
               {
               fprintf(code, "\tmov\teax,[%s]\n", var.name);
               }
          else
               {
               fprintf(code, "\tmov\teax,%s\n", var.name);
               }
          fprintf(code, "\tmov\t[vptr],eax\n"); // point to variable
          fprintf(code, "\tinc\tdword [vcount]\n"); // count argument
          count = 1;     // keep local count
          }

     for(n=1; n < 5; n++)
          {
          tok = strtok(NULL, ", "); // get argument
          if(!tok) break;
          strcpy(token, tok);		// copy it
          if(isdigit(token[0]))	// numeric value
			{
			sprintf(strname, "arg%03d", labelnum);
			sprintf(ptname, "apt%03d", labelnum);
			labelnum++;

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

               fprintf(code, "\tmov\teax,%s\n", strname); // arg address
               fprintf(code, "\tmov\t[%s],eax\n", ptname); // point to it
               fprintf(code, "\tmov\teax,%s\n", ptname);
     		fprintf(code, "\tmov\t[vptr+%d],eax\n", (4 * count));
			fprintf(code, "\tinc\tdword [vcount]\n"); // count argument
			count++;  	// keep local count
			}
          else
			{
			if(!isvar())
				{
				printf("\n\nLine %d: Unknown argument %s in:\n", m, token);
				printf("\t%s\n\n", iptr[m]);
				exit(1);
				}

               if(var.isptr)  // save value, not address
                    {
                    fprintf(code, "\tmov\teax,[%s]\n", var.name);
                    }
               else
                   {
                   fprintf(code, "\tmov\teax,%s\n", var.name);
                   }
			fprintf(code, "\tmov\t[vptr+%d],eax\n",(count * 4)); // point to variable
			fprintf(code, "\tinc\tdword [vcount]\n"); // count argument
			count++;  	// keep local count
               }
          }

     return 1;
     }

void increment(int inc, int ndx) // increment (or decrement) variable
     {
     int ptsize, vsize;

     vsize = var.size;
     if(var.isptr) ptsize = var.ptsize;
     else ptsize = 0;

     if(vsize == 1)
          {
          if(inc == 0)        // decrement
               {
               fprintf(code, "\tdec\tbyte [%s]\n", var.name);
               }
          else                // increment
               {
               fprintf(code, "\tinc\tbyte [%s]\n", var.name);
               }
          }
     else if(ptsize != 2)
          {
          if(inc == 0)        // decrement
               {
               fprintf(code, "\tdec\tdword [%s]\n", var.name);
               }
          else                // increment
               {
               fprintf(code, "\tinc\tdword [%s]\n", var.name);
               }
          }
     else
          {
          if(inc == 0)        // decrement
               {
               fprintf(code, "\tsub\tdword [%s],2\n", var.name);
               }
          else                // increment
               {
               fprintf(code, "\tadd\tdword [%s],2\n", var.name);
               }
          }
     }

void init_pointers(void)      // initialise source pointers
     {
     int n;

     while(1)
          {
          fgets(copy, 100, infile);
          linecount++;
          
          if(feof(infile)) break;
          }

     rewind(infile);

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

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

int isfunc(void)              // test if "token" is a function
     {
     int n;

     for(n=0; n < pcount; n++)
          {
          if(!strcmp(token, proto[n].name)) return (n + 1);
          }

     return 0;
     }

int isop(void)                // return "operation code" if valid operation
     {
     if(!strcmp(token, "+")) return 1;
     if(!strcmp(token, "-")) return 2;
     if(!strcmp(token, "*")) return 3;
     if(!strcmp(token, "/")) return 4;
     if(!strcmp(token, "%")) return 5;
     if(!strcmp(token, "<<")) return 6;
     if(!strcmp(token, ">>")) return 7;
     if(!strcmp(token, "&")) return 8;
     if(!strcmp(token, "|")) return 9;

     return 0;
     }

void is_saved(void)           // show variable has been saved
     {
     int n;

     for(n=0; n < dcount; n++)
          {
          if(!strcmp(var.name, cvar[n].name))
               {
               cvar[n].saved = 1; // show it's saved
               break;
               }
          }
     }

int isvar(void)               // test if "token" is a variable
     {
     int found, insubscript, j, k, n;

     found = 0;               // haven't found it yet!
     insubscript = 0;

     clear_var();             // clear "var" structure

     k = 0;
     for(j=0; j < 50; j++)
          {
          if(token[j] == '[')
               {
               insubscript = 1;
               continue;
               }
          if(token[j] == ']')
               {
               insubscript = 0;
               continue;
               }          
          if(insubscript) 
               {
               continue;
               }     
          if((token[j] == '*') || (token[j] == '&') || (token[j] == '!')) continue;
          if((token[j] == '+') || (token[j] == '-') || (token[j] == 0)
          || (token[j] == ' ') || (token[j] == '\n')) break;
          else
               {
               var.name[k] = token[j];
               k++;
               }
          }

     if(infunc)
          {
          if(find_local(infunc)) return 1; // found local variable
          }

     for(n=0; n < dcount; n++)
          {
          if(!strcmp(var.name, cvar[n].name))
               {
               found = 1;     // found variable
               break;
               }
          }

     if(found)                // fill in "var" structure
          {
          strcpy(var.name, cvar[n].name);
          var.size = cvar[n].size;
          var.ptsize = cvar[n].ptsize;
          var.value = cvar[n].value;
          var.isptr = cvar[n].isptr;
          var.saved = cvar[n].saved;
          var.instruc = cvar[n].instruc;
          var.addbytes = cvar[n].addbytes;
          if(cvar[n].text[0]) strcpy(var.text, cvar[n].text);
          }

     return (found);
     }

void jump_back(void)          // return to start of loop
     {
     int l;

     if(inloop[level]) l = level;
     else l = next_level();   // get "higher" loop level

     if(l)
          {
          fprintf(code, "\tjmp\t%s\n", loop[l].loop_start);
          }
     else
          {
          printf("\n\nContinue statement outside loop in:\n");
          printf("%s\n\n", iptr[m]);
          exit(1);
          }
     }

int make_structure(void)      // create structure
     {
     char *def, *sname, *snum, *tempname;
     int k, scount, tndx;
     
     scount = 0;
 
     def = strtok(copy, " \t\n;"); // should be "struct"
     if(!strstr(def, "struct")) return(0); // false interpretation
 
     tempname = strtok(NULL, " \t\n;"); // get "template" name
     sname = strtok(NULL, " [\t\n;");   // get structure name
 
     if((!tempname) || (!sname))
          {
          mksbad: printf("\n\n\tStructure incorrect in:\n");
          printf("\t%s\n\n", iptr[m]);
          exit(1);
          }
 
     snum = strtok(NULL, "]\t\n;"); // get number of structures
     if(snum)                 // if entry is present
          {
          scount = atoi(snum);
          if(!scount)
               {
               printf("\n\n\tStructure count must be numeric value in:\n");
               printf("\t%s\n\n", iptr[m]);
               exit(1);
               }          
          }
     
     
     tndx = 100000;           // impossible value
     for(k=0; k < tempcount; k++)
          {
          if(!strcmp(template[k].tempname, tempname)) // found template
               {
               tndx = k;
               break;
               }
          }
 
     if(tndx > 1000)          // template not found
          {
          printf("\n\n\tStructure template not found in:\n");
          printf("\t%s\n\n", iptr[m]);
          exit(1);
          }
 
     if(!data)
          {
          printf("\n\n\tCannot access data file!\n\n");
          exit(1);
          }

     for(k=0; k < template[tndx].varnum; k++)
          {
          if(template[tndx].size[k] == 1)
               {
               cvar[dcount].size = 1;
               cvar[dcount].instruc = template[tndx].tempsize;
               sprintf(cvar[dcount].name, "%s%s", sname, template[tndx].name[k]);
               dcount++;
               }
          else if(template[tndx].size[k] == 2)
               {
               cvar[dcount].size = 2;
               cvar[dcount].instruc = template[tndx].tempsize;               
               sprintf(cvar[dcount].name, "%s%s", sname, template[tndx].name[k]);
               dcount++;
               }
          else if(template[tndx].size[k] == 3)
               {
               cvar[dcount].size = 3;
               cvar[dcount].instruc = template[tndx].tempsize;               
               sprintf(cvar[dcount].name, "%s%s", sname, template[tndx].name[k]);
               cvar[dcount].length = template[tndx].length[k];
               dcount++;
               }
          else goto mksbad;
          }
          
     if(scount > 1)
          {
          k = dcount - 1;     // index of final variable
          scount -= 1;        // number of additional "sector spaces" to reserve
          cvar[k].addbytes = scount * template[tndx].tempsize;
          }     
          
     return(1);
     }

int next_level(void)          // find next "higher" loop level
     {
     int lvl;

     if(level <= 1) return 0; // no "higher" level
     else lvl = level - 1;

     for(; lvl > 0; lvl--)
          {
          if(inloop[lvl]) return lvl;
          }

     return 0;                // no "higher" loop
     }

void parse_case(void)         // generate "case" test with label
     {
     char *tok;
     int domulti, firstcase;

     tok = strtok(NULL, " \t\n:");
     if(!tok)
          {
          bad: printf("\n\nIncorrect \"case\" statement:\n");
          printf("%s\n", iptr[m]);
          exit(1);
          }

     strcpy(token, tok);
     if(!isdigit(token[0]) && (token[0] != 39)) goto bad;

     if(multicase)            // if one / more preceding cases
          {
          domulti = 1;        // code accordingly
          multicase = 0;      // clear multicase for now
          }
     else domulti = 0;        // single or first case

     if(strstr(iptr[m+1], "case")) multicase = 1; // following case

     if((!domulti) && (!multicase)) firstcase = 1; // only case
     else if((!domulti) && (multicase)) firstcase = 1; // first case
     else firstcase = 0; // not the first case

     if(nextlabel[0])         // if this isn't the first case
          {
          if(firstcase) fprintf(code, "%s: cmp\tdword [%s],%s\n",
          nextlabel, swname, tok);
          else fprintf(code, "\tcmp\tdword [%s],%s\n", swname, tok);
          }
     else                     // first case
          {
          fprintf(code, "\tcmp\tdword [%s],%s\n", swname, tok);
          }

     if((!domulti) && (!multicase)) // single case statement
          {
          labelnum += 1;
          sprintf(nextlabel, "case%03d", labelnum); // create next label

          if(ostype)          // not 32-bit code
               {
               fprintf(code, "\tjne near\t%s\n", nextlabel); // jump ahead if no match
               }
          else
               {
               fprintf(code, "\tje\t$+7\n"); // jump ahead if match
               fprintf(code, "\tjmp\t%s\n", nextlabel); // jump if no match               
               }

          }

     else if((!domulti) && (multicase)) // first of two or more cases
          {
          sprintf(casecode, "ccod%03d", labelnum); // label for following code
          labelnum += 1;
          sprintf(nextlabel, "case%03d", labelnum); // create next label

          fprintf(code, "\tje\t%s\n", casecode); // jump ahead if match
          }

     else if((domulti) && (multicase)) // "Internal" case statement
          {
          fprintf(code, "\tje\t%s\n", casecode); // jump ahead if match
          }

     else if((domulti) && (!multicase)) // last of multiple case statements
          {
          fprintf(code, "\tje\t%s\n", casecode); // jump ahead if match
          fprintf(code, "\tjmp\t%s\n", nextlabel); // jump if no match
          fprintf(code, "%s:\n", casecode); // write label
          }
     }

void parse_for(void)          // parse / code "for" loop
     {
     char cmpname[20], initname[20], sizename[5], text[50], varname[20];
     char *tok[10];
     int cmpvar, incstep, initvar, l, n, size;

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

     if(n >= 7)               // we need seven tokens!
          {
          strcpy(token, tok[0]);
          result = isvar();
          if(!result)
               {
               printf("\n\n\t\a%s is not a defined variable!\n\n", token);
               exit (1);
               }
          strcpy(varname, var.name);
          }
     else
          {
          wrong: printf("\n\n\aFor statement incorrect:\n");
          printf("%s\n", iptr[m]);
          exit (1);
          }

     size = var.size;         // variable size
     if(size == 1) strcpy(sizename, "byte");
     else if(size == 2) strcpy(sizename, "dword");
     else
          {
          printf("\n\n\aCan't use string as \"for\" index.\n");
          printf("%s\n", iptr[m]);
          exit (1);
          }

     strcpy(token, tok[2]);   // initialisation value
     if(isdigit(token[0]))  initvar = 0; // numeric value
     else if(isvar())
          {
          initvar = 1; //variable
          strcpy(initname, var.name);
          }
     else goto wrong;

     strcpy(token, tok[5]);   // limit "comparison" value
     if(isdigit(token[0])) cmpvar = 0; // numeric value
     else if(isvar())
          {
          cmpvar = 1; //variable
          strcpy(cmpname, var.name);
          }
     else goto wrong;

     if(strstr(tok[6], "++")) incstep = 1; // increment
     else if(strstr(tok[6], "--")) incstep = 0; // decrement
     else goto wrong;

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

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

     if(!initvar)
          {
          fprintf(code, "\tmov\t%s [%s],%s\n", sizename, varname, tok[2]);
          }
     else
          {
          if(size == 1)
               {
               fprintf(code, "\tmov\tal,[%s]\n", initname);
               fprintf(code, "\tmov\t[%s],al\n", varname);
               }
          else
               {
               fprintf(code, "\tmov\teax,[%s]\n", initname);
               fprintf(code, "\tmov\t[%s],eax\n", varname);
               }
          }

     sprintf(text, "loop%03d", labelnum);
     strcpy(loop[l].loop_start, text);
     if(!cmpvar)
          {
          fprintf(code, "%s: cmp\t%s [%s],%s\n",
          text, sizename, varname, tok[5]);
          }
     else
          {
          if(size == 1)
               {
               fprintf(code, "%s: mov\tal,[%s]\n", text, varname);
               fprintf(code, "\tcmp\tal,[%s]\n", cmpname);
               }
          else
               {
               fprintf(code, "%s: mov\teax,[%s]\n", text, varname);
               fprintf(code, "\tcmp\teax,[%s]\n", cmpname);
               }
          }
     sprintf(text, "exit%03d", labelnum);
     strcpy(loop[l].loopend, text); // save "exit" label
     if(ostype)               // not 32-bit code
          {
          fprintf(code, "\tje near\t%s\n", text);
          }
     else
          {
          fprintf(code, "\tjne\t$+7\n");
          fprintf(code, "\tjmp\t%s\n", text);
          }

     if(incstep)
          {
          sprintf(loop[l].endcode[loop[l].endcount], "\tinc\t%s [%s]\n",
          sizename, varname);
          }
     else
          {
          sprintf(loop[l].endcode[loop[l].endcount], "\tdec\t%s [%s]\n",
          sizename, varname);
          }
     loop[l].endcount++;

     sprintf(loop[l].endcode[loop[l].endcount], "\tjmp\tloop%03d\n", labelnum);
     labelnum++;
     loop[l].endcount++;
     }
