if (*instr == '\0' || tolower(*instr) == 'l' && *(instr + 1) == '.')
if (*instr == '\0' || (tolower(*instr) == 'l' && *(instr + 1) == '.'))
assemble(FILE * fout, FILE * fin){   typedef struct tagFUNCSTUB   {      uint32_t            address, nameofs;   } FUNCSTUB;   AMX_HEADER          hdr;   FUNCSTUB            func;   int                 numpublics, numnatives, numlibraries, numpubvars,      numtags, padding;   long                nametablesize, nameofs;   char                line[256], *instr, *params;   int                 i, pass;   int16_t             count;   symbol             *sym, **nativelist;   constvalue         *constptr;   cell                mainaddr;   int                 nametable, tags, libraries, publics, natives, pubvars;   int                 cod, dat, hea, stp, cip, size, defsize;#if !defined NDEBUG   /* verify that the opcode list is sorted (skip entry 1; it is reserved    * for a non-existant opcode)    */   assert(opcodelist[1].name != NULL);   for (i = 2; i < (sizeof opcodelist / sizeof opcodelist[0]); i++)     {	assert(opcodelist[i].name != NULL);	assert(stricmp(opcodelist[i].name, opcodelist[i - 1].name) > 0);     }				/* for */#endif   writeerror = FALSE;   nametablesize = sizeof(int16_t);   numpublics = 0;   numnatives = 0;   numpubvars = 0;   mainaddr = -1;   /* count number of public and native functions and public variables */   for (sym = glbtab.next; sym != NULL; sym = sym->next)     {	char                alias[sNAMEMAX + 1] = "";	int                 match = 0;	if (sym->ident == iFUNCTN)	  {	     assert(strlen(sym->name) <= sNAMEMAX);	     if ((sym->usage & uNATIVE) != 0 && (sym->usage & uREAD) != 0		 && sym->addr >= 0)	       {		  match = ++numnatives;		  if (!lookup_alias(alias, sym->name))		     strcpy(alias, sym->name);	       }		/* if */	     if ((sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)	       {		  match = ++numpublics;		  strcpy(alias, sym->name);	       }		/* if */	     if (strcmp(sym->name, uMAINFUNC) == 0)	       {		  assert(sym->vclass == sGLOBAL);		  mainaddr = sym->addr;	       }		/* if */	  }	else if (sym->ident == iVARIABLE)	  {	     if ((sym->usage & uPUBLIC) != 0)	       {		  match = ++numpubvars;		  strcpy(alias, sym->name);	       }		/* if */	  }			/* if */	if (match)	  {	     assert(strlen(alias) > 0);	     nametablesize += strlen(alias) + 1;	  }			/* if */     }				/* for */   assert(numnatives == ntv_funcid);   /* count number of libraries */   numlibraries = 0;   for (constptr = libname_tab.next; constptr != NULL;	constptr = constptr->next)     {	if (constptr->value > 0)	  {	     assert(strlen(constptr->name) > 0);	     numlibraries++;	     nametablesize += strlen(constptr->name) + 1;	  }			/* if */     }				/* for */   /* count number of public tags */   numtags = 0;   for (constptr = tagname_tab.next; constptr != NULL;	constptr = constptr->next)     {	if ((constptr->value & PUBLICTAG) != 0)	  {	     assert(strlen(constptr->name) > 0);	     numtags++;	     nametablesize += strlen(constptr->name) + 1;	  }			/* if */     }				/* for */   /* pad the header to sc_dataalign    * => thereby the code segment is aligned    * => since the code segment is padded to a sc_dataalign boundary, the data segment is aligned    * => and thereby the stack top is aligned too    */   assert(sc_dataalign != 0);   padding = sc_dataalign - (sizeof hdr + nametablesize) % sc_dataalign;   if (padding == sc_dataalign)      padding = 0;   /* write the abstract machine header */   memset(&hdr, 0, sizeof hdr);   hdr.magic = (unsigned short)0xF1E0;   hdr.file_version = CUR_FILE_VERSION;   hdr.amx_version = MIN_AMX_VERSION;   hdr.flags = (short)(sc_debug & sSYMBOLIC);   if (charbits == 16)      hdr.flags |= AMX_FLAG_CHAR16;   if (sc_compress)      hdr.flags |= AMX_FLAG_COMPACT;   if (sc_debug == 0)      hdr.flags |= AMX_FLAG_NOCHECKS;//  #if BYTE_ORDER==BIG_ENDIAN//    hdr.flags|=AMX_FLAG_BIGENDIAN;//  #endif   defsize = hdr.defsize = sizeof(FUNCSTUB);   assert((hdr.defsize % sizeof(cell)) == 0);   publics = hdr.publics = sizeof hdr;	/* public table starts right after the header */   natives = hdr.natives = hdr.publics + numpublics * sizeof(FUNCSTUB);   libraries = hdr.libraries = hdr.natives + numnatives * sizeof(FUNCSTUB);   pubvars = hdr.pubvars = hdr.libraries + numlibraries * sizeof(FUNCSTUB);   tags = hdr.tags = hdr.pubvars + numpubvars * sizeof(FUNCSTUB);   nametable = hdr.nametable = hdr.tags + numtags * sizeof(FUNCSTUB);   cod = hdr.cod = hdr.nametable + nametablesize + padding;   dat = hdr.dat = hdr.cod + code_idx;   hea = hdr.hea = hdr.dat + glb_declared * sizeof(cell);   stp = hdr.stp = hdr.hea + sc_stksize * sizeof(cell);   cip = hdr.cip = mainaddr;   size = hdr.size = hdr.hea;	/* preset, this is incorrect in case of compressed output */#if BYTE_ORDER==BIG_ENDIAN   align32(&hdr.size);   align16(&hdr.magic);   align16(&hdr.flags);   align16(&hdr.defsize);   align32(&hdr.cod);   align32(&hdr.dat);   align32(&hdr.hea);   align32(&hdr.stp);   align32(&hdr.cip);   align32(&hdr.publics);   align32(&hdr.natives);   align32(&hdr.libraries);   align32(&hdr.pubvars);   align32(&hdr.tags);   align32(&hdr.nametable);#endif   sc_writebin(fout, &hdr, sizeof hdr);   /* dump zeros up to the rest of the header, so that we can easily "seek" */   for (nameofs = sizeof hdr; nameofs < cod; nameofs++)      putc(0, fout);   nameofs = nametable + sizeof(int16_t);   /* write the public functions table */   count = 0;   for (sym = glbtab.next; sym != NULL; sym = sym->next)     {	if (sym->ident == iFUNCTN	    && (sym->usage & uPUBLIC) != 0 && (sym->usage & uDEFINE) != 0)	  {	     assert(sym->vclass == sGLOBAL);	     func.address = sym->addr;	     func.nameofs = nameofs;#if BYTE_ORDER==BIG_ENDIAN	     align32(&func.address);	     align32(&func.nameofs);#endif	     fseek(fout, publics + count * sizeof(FUNCSTUB), SEEK_SET);	     sc_writebin(fout, &func, sizeof func);	     fseek(fout, nameofs, SEEK_SET);	     sc_writebin(fout, sym->name, strlen(sym->name) + 1);	     nameofs += strlen(sym->name) + 1;	     count++;	  }			/* if */     }				/* for */   /* write the natives table */   /* The native functions must be written in sorted order. (They are    * sorted on their "id", not on their name). A nested loop to find    * each successive function would be an O(n^2) operation. But we    * do not really need to sort, because the native function id's    * are sequential and there are no duplicates. So we first walk    * through the complete symbol list and store a pointer to every    * native function of interest in a temporary table, where its id    * serves as the index in the table. Now we can walk the table and    * have all native functions in sorted order.    */   if (numnatives > 0)     {	nativelist = (symbol **) malloc(numnatives * sizeof(symbol *));	if (nativelist == NULL)	   error(103);		/* insufficient memory */#if !defined NDEBUG	memset(nativelist, 0, numnatives * sizeof(symbol *));	/* for NULL checking */#endif	for (sym = glbtab.next; sym != NULL; sym = sym->next)	  {	     if (sym->ident == iFUNCTN && (sym->usage & uNATIVE) != 0		 && (sym->usage & uREAD) != 0 && sym->addr >= 0)	       {		  assert(sym->addr < numnatives);		  nativelist[(int)sym->addr] = sym;	       }		/* if */	  }			/* for */	count = 0;	for (i = 0; i < numnatives; i++)	  {	     char                alias[sNAMEMAX + 1];	     sym = nativelist[i];	     assert(sym != NULL);	     if (!lookup_alias(alias, sym->name))	       {		  assert(strlen(sym->name) <= sNAMEMAX);		  strcpy(alias, sym->name);	       }		/* if */	     assert(sym->vclass == sGLOBAL);	     func.address = 0;	     func.nameofs = nameofs;#if BYTE_ORDER==BIG_ENDIAN	     align32(&func.address);	     align32(&func.nameofs);#endif	     fseek(fout, natives + count * sizeof(FUNCSTUB), SEEK_SET);	     sc_writebin(fout, &func, sizeof func);	     fseek(fout, nameofs, SEEK_SET);	     sc_writebin(fout, alias, strlen(alias) + 1);	     nameofs += strlen(alias) + 1;	     count++;	  }			/* for */	free(nativelist);     }				/* if */   /* write the libraries table */   count = 0;   for (constptr = libname_tab.next; constptr != NULL;	constptr = constptr->next)     {	if (constptr->value > 0)	  {	     assert(strlen(constptr->name) > 0);	     func.address = 0;	     func.nameofs = nameofs;#if BYTE_ORDER==BIG_ENDIAN	     align32(&func.address);	     align32(&func.nameofs);#endif	     fseek(fout, libraries + count * sizeof(FUNCSTUB), SEEK_SET);	     sc_writebin(fout, &func, sizeof func);	     fseek(fout, nameofs, SEEK_SET);	     sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);	     nameofs += strlen(constptr->name) + 1;	     count++;	  }			/* if */     }				/* for */   /* write the public variables table */   count = 0;   for (sym = glbtab.next; sym != NULL; sym = sym->next)     {	if (sym->ident == iVARIABLE && (sym->usage & uPUBLIC) != 0)	  {	     assert((sym->usage & uDEFINE) != 0);	     assert(sym->vclass == sGLOBAL);	     func.address = sym->addr;	     func.nameofs = nameofs;#if BYTE_ORDER==BIG_ENDIAN	     align32(&func.address);	     align32(&func.nameofs);#endif	     fseek(fout, pubvars + count * sizeof(FUNCSTUB), SEEK_SET);	     sc_writebin(fout, &func, sizeof func);	     fseek(fout, nameofs, SEEK_SET);	     sc_writebin(fout, sym->name, strlen(sym->name) + 1);	     nameofs += strlen(sym->name) + 1;	     count++;	  }			/* if */     }				/* for */   /* write the public tagnames table */   count = 0;   for (constptr = tagname_tab.next; constptr != NULL;	constptr = constptr->next)     {	if ((constptr->value & PUBLICTAG) != 0)	  {	     assert(strlen(constptr->name) > 0);	     func.address = constptr->value & TAGMASK;	     func.nameofs = nameofs;#if BYTE_ORDER==BIG_ENDIAN	     align32(&func.address);	     align32(&func.nameofs);#endif	     fseek(fout, tags + count * sizeof(FUNCSTUB), SEEK_SET);	     sc_writebin(fout, &func, sizeof func);	     fseek(fout, nameofs, SEEK_SET);	     sc_writebin(fout, constptr->name, strlen(constptr->name) + 1);	     nameofs += strlen(constptr->name) + 1;	     count++;	  }			/* if */     }				/* for */   /* write the "maximum name length" field in the name table */   assert(nameofs == nametable + nametablesize);   fseek(fout, nametable, SEEK_SET);   count = sNAMEMAX;#if BYTE_ORDER==BIG_ENDIAN   align16(&count);#endif   sc_writebin(fout, &count, sizeof count);   fseek(fout, cod, SEEK_SET);   /* First pass: relocate all labels */   /* This pass is necessary because the code addresses of labels is only known    * after the peephole optimization flag. Labels can occur inside expressions    * (e.g. the conditional operator), which are optimized.    */   lbltab = NULL;   if (labnum > 0)     {	/* only very short programs have zero labels; no first pass is needed	 * if there are no labels */	lbltab = (cell *) malloc(labnum * sizeof(cell));	if (lbltab == NULL)	   error(103);		/* insufficient memory */	codeindex = 0;	sc_resetasm(fin);	while (sc_readasm(fin, line, sizeof line) != NULL)	  {	     stripcomment(line);	     instr = skipwhitespace(line);	     /* ignore empty lines */	     if (*instr == '\0')		continue;	     if (tolower(*instr) == 'l' && *(instr + 1) == '.')	       {		  int                 lindex = (int)hex2long(instr + 2, NULL);		  assert(lindex < labnum);		  lbltab[lindex] = codeindex;	       }	     else	       {		  /* get to the end of the instruction (make use of the '\n' that fgets()		   * added at the end of the line; this way we will *always* drop on a		   * whitespace character) */		  for (params = instr; *params != '\0' && !isspace(*params);		       params++)		     /* nothing */ ;		  assert(params > instr);		  i = findopcode(instr, (int)(params - instr));		  if (opcodelist[i].name == NULL)		    {		       *params = '\0';		       error(104, instr);	/* invalid assembler instruction */		    }		/* if */		  if (opcodelist[i].segment == sIN_CSEG)		     codeindex +=			opcodelist[i].func(NULL, skipwhitespace(params),					   opcodelist[i].opcode);	       }		/* if */	  }			/* while */     }				/* if */   /* Second pass (actually 2 more passes, one for all code and one for all data) */   bytes_in = 0;   bytes_out = 0;   for (pass = sIN_CSEG; pass <= sIN_DSEG; pass++)     {	sc_resetasm(fin);	while (sc_readasm(fin, line, sizeof line) != NULL)	  {	     stripcomment(line);	     instr = skipwhitespace(line);	     /* ignore empty lines and labels (labels have a special syntax, so these	      * must be parsed separately) */	     if (*instr == '\0' || tolower(*instr) == 'l'		 && *(instr + 1) == '.')		continue;	     /* get to the end of the instruction (make use of the '\n' that fgets()	      * added at the end of the line; this way we will *always* drop on a	      * whitespace character) */	     for (params = instr; *params != '\0' && !isspace(*params);		  params++)		/* nothing */ ;	     assert(params > instr);	     i = findopcode(instr, (int)(params - instr));	     assert(opcodelist[i].name != NULL);	     if (opcodelist[i].segment == pass)		opcodelist[i].func(fout, skipwhitespace(params),				   opcodelist[i].opcode);	  }			/* while */     }				/* for */   if (bytes_out - bytes_in > 0)      error(106);		/* compression buffer overflow */   if (lbltab != NULL)     {	free(lbltab);#if !defined NDEBUG	lbltab = NULL;#endif     }				/* if */   if (writeerror)      error(101, "disk full");   /* adjust the header */   if (sc_compress)     {	hdr.size = sc_lengthbin(fout);#if BYTE_ORDER==BIG_ENDIAN	align32(&hdr.size);#endif	sc_resetbin(fout);	/* "size" is the very first field */	sc_writebin(fout, &hdr.size, sizeof hdr.size);     }				/* if */}