--HG-- extra : convert_revision : svn%3A39bc706e-5318-0410-9160-8a85361fbb7c/trunk%401273
		
			
				
	
	
		
			532 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			532 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*  Pawn compiler  - maintenance of various lists
 | |
|  *
 | |
|  *  o  Name list (aliases)
 | |
|  *  o  Include path list
 | |
|  *  o  Macro definitions (text substitutions)
 | |
|  *  o  Documentation tags and automatic listings
 | |
|  *  o  Debug strings
 | |
|  *
 | |
|  *  Copyright (c) ITB CompuPhase, 2001-2006
 | |
|  *
 | |
|  *  This software is provided "as-is", without any express or implied warranty.
 | |
|  *  In no event will the authors be held liable for any damages arising from
 | |
|  *  the use of this software.
 | |
|  *
 | |
|  *  Permission is granted to anyone to use this software for any purpose,
 | |
|  *  including commercial applications, and to alter it and redistribute it
 | |
|  *  freely, subject to the following restrictions:
 | |
|  *
 | |
|  *  1.  The origin of this software must not be misrepresented; you must not
 | |
|  *      claim that you wrote the original software. If you use this software in
 | |
|  *      a product, an acknowledgment in the product documentation would be
 | |
|  *      appreciated but is not required.
 | |
|  *  2.  Altered source versions must be plainly marked as such, and must not be
 | |
|  *      misrepresented as being the original software.
 | |
|  *  3.  This notice may not be removed or altered from any source distribution.
 | |
|  *
 | |
|  *  Version: $Id$
 | |
|  */
 | |
| #include <assert.h>
 | |
| #include <limits.h>
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| #include "sc.h"
 | |
| #include "lstring.h"
 | |
| 
 | |
| #if defined FORTIFY
 | |
|   #include <alloc/fortify.h>
 | |
| #endif
 | |
| 
 | |
| /* a "private" implementation of strdup(), so that porting
 | |
|  * to other memory allocators becomes easier.
 | |
|  * By Søren Hannibal.
 | |
|  */
 | |
| SC_FUNC char* duplicatestring(const char* sourcestring)
 | |
| {
 | |
|   char* result=(char*)malloc(strlen(sourcestring)+1);
 | |
|   strcpy(result,sourcestring);
 | |
|   return result;
 | |
| }
 | |
| 
 | |
| 
 | |
| static stringpair *insert_stringpair(stringpair *root,char *first,char *second,int matchlength)
 | |
| {
 | |
|   stringpair *cur,*pred;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   assert(first!=NULL);
 | |
|   assert(second!=NULL);
 | |
|   /* create a new node, and check whether all is okay */
 | |
|   if ((cur=(stringpair*)malloc(sizeof(stringpair)))==NULL)
 | |
|     return NULL;
 | |
|   cur->first=duplicatestring(first);
 | |
|   cur->second=duplicatestring(second);
 | |
|   cur->matchlength=matchlength;
 | |
|   cur->documentation=NULL;
 | |
|   if (cur->first==NULL || cur->second==NULL) {
 | |
|     if (cur->first!=NULL)
 | |
|       free(cur->first);
 | |
|     if (cur->second!=NULL)
 | |
|       free(cur->second);
 | |
|     free(cur);
 | |
|     return NULL;
 | |
|   } /* if */
 | |
|   /* link the node to the tree, find the position */
 | |
|   for (pred=root; pred->next!=NULL && strcmp(pred->next->first,first)<0; pred=pred->next)
 | |
|     /* nothing */;
 | |
|   cur->next=pred->next;
 | |
|   pred->next=cur;
 | |
|   return cur;
 | |
| }
 | |
| 
 | |
| static void delete_stringpairtable(stringpair *root)
 | |
| {
 | |
|   stringpair *cur, *next;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   cur=root->next;
 | |
|   while (cur!=NULL) {
 | |
|     next=cur->next;
 | |
|     assert(cur->first!=NULL);
 | |
|     assert(cur->second!=NULL);
 | |
|     free(cur->first);
 | |
|     free(cur->second);
 | |
|     free(cur);
 | |
|     cur=next;
 | |
|   } /* while */
 | |
|   memset(root,0,sizeof(stringpair));
 | |
| }
 | |
| 
 | |
| static stringpair *find_stringpair(stringpair *cur,char *first,int matchlength)
 | |
| {
 | |
|   int result=0;
 | |
| 
 | |
|   assert(matchlength>0);  /* the function cannot handle zero-length comparison */
 | |
|   assert(first!=NULL);
 | |
|   while (cur!=NULL && result<=0) {
 | |
|     result=(int)*cur->first - (int)*first;
 | |
|     if (result==0 && matchlength==cur->matchlength) {
 | |
|       result=strncmp(cur->first,first,matchlength);
 | |
|       if (result==0)
 | |
|         return cur;
 | |
|     } /* if */
 | |
|     cur=cur->next;
 | |
|   } /* while */
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static int delete_stringpair(stringpair *root,stringpair *item)
 | |
| {
 | |
|   stringpair *cur;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   cur=root;
 | |
|   while (cur->next!=NULL) {
 | |
|     if (cur->next==item) {
 | |
|       cur->next=item->next;     /* unlink from list */
 | |
|       assert(item->first!=NULL);
 | |
|       assert(item->second!=NULL);
 | |
|       free(item->first);
 | |
|       free(item->second);
 | |
|       free(item);
 | |
|       return TRUE;
 | |
|     } /* if */
 | |
|     cur=cur->next;
 | |
|   } /* while */
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /* ----- string list functions ----------------------------------- */
 | |
| static stringlist *insert_string(stringlist *root,char *string)
 | |
| {
 | |
|   stringlist *cur;
 | |
| 
 | |
|   assert(string!=NULL);
 | |
|   if ((cur=(stringlist*)malloc(sizeof(stringlist)))==NULL)
 | |
|     error(103);       /* insufficient memory (fatal error) */
 | |
|   if ((cur->line=duplicatestring(string))==NULL)
 | |
|     error(103);       /* insufficient memory (fatal error) */
 | |
|   /* insert as "last" */
 | |
|   assert(root!=NULL);
 | |
|   while (root->next!=NULL)
 | |
|     root=root->next;
 | |
|   cur->next=root->next;
 | |
|   root->next=cur;
 | |
|   return cur;
 | |
| }
 | |
| 
 | |
| static char *get_string(stringlist *root,int index)
 | |
| {
 | |
|   stringlist *cur;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   cur=root->next;
 | |
|   while (cur!=NULL && index-->0)
 | |
|     cur=cur->next;
 | |
|   if (cur!=NULL) {
 | |
|     assert(cur->line!=NULL);
 | |
|     return cur->line;
 | |
|   } /* if */
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| static int delete_string(stringlist *root,int index)
 | |
| {
 | |
|   stringlist *cur,*item;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   for (cur=root; cur->next!=NULL && index>0; cur=cur->next,index--)
 | |
|     /* nothing */;
 | |
|   if (cur->next!=NULL) {
 | |
|     item=cur->next;
 | |
|     cur->next=item->next;       /* unlink from list */
 | |
|     assert(item->line!=NULL);
 | |
|     free(item->line);
 | |
|     free(item);
 | |
|     return TRUE;
 | |
|   } /* if */
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_stringtable(stringlist *root)
 | |
| {
 | |
|   stringlist *cur,*next;
 | |
| 
 | |
|   assert(root!=NULL);
 | |
|   cur=root->next;
 | |
|   while (cur!=NULL) {
 | |
|     next=cur->next;
 | |
|     assert(cur->line!=NULL);
 | |
|     free(cur->line);
 | |
|     free(cur);
 | |
|     cur=next;
 | |
|   } /* while */
 | |
|   memset(root,0,sizeof(stringlist));
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ----- alias table --------------------------------------------- */
 | |
| static stringpair alias_tab = {NULL, NULL, NULL};   /* alias table */
 | |
| 
 | |
| SC_FUNC stringpair *insert_alias(char *name,char *alias)
 | |
| {
 | |
|   stringpair *cur;
 | |
| 
 | |
|   assert(name!=NULL);
 | |
|   assert(strlen(name)<=sNAMEMAX);
 | |
|   assert(alias!=NULL);
 | |
|   assert(strlen(alias)<=sNAMEMAX);
 | |
|   if ((cur=insert_stringpair(&alias_tab,name,alias,strlen(name)))==NULL)
 | |
|     error(103);       /* insufficient memory (fatal error) */
 | |
|   return cur;
 | |
| }
 | |
| 
 | |
| SC_FUNC int lookup_alias(char *target,char *name)
 | |
| {
 | |
|   stringpair *cur=find_stringpair(alias_tab.next,name,strlen(name));
 | |
|   if (cur!=NULL) {
 | |
|     assert(strlen(cur->second)<=sNAMEMAX);
 | |
|     strcpy(target,cur->second);
 | |
|   } /* if */
 | |
|   return cur!=NULL;
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_aliastable(void)
 | |
| {
 | |
|   delete_stringpairtable(&alias_tab);
 | |
| }
 | |
| 
 | |
| /* ----- include paths list -------------------------------------- */
 | |
| static stringlist includepaths = {NULL, NULL};  /* directory list for include files */
 | |
| 
 | |
| SC_FUNC stringlist *insert_path(char *path)
 | |
| {
 | |
|   return insert_string(&includepaths,path);
 | |
| }
 | |
| 
 | |
| SC_FUNC char *get_path(int index)
 | |
| {
 | |
|   return get_string(&includepaths,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_pathtable(void)
 | |
| {
 | |
|   delete_stringtable(&includepaths);
 | |
|   assert(includepaths.next==NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ----- text substitution patterns ------------------------------ */
 | |
| #if !defined NO_DEFINE
 | |
| 
 | |
| static stringpair substpair = { NULL, NULL, NULL};  /* list of substitution pairs */
 | |
| 
 | |
| static stringpair *substindex['z'-PUBLIC_CHAR+1]; /* quick index to first character */
 | |
| static void adjustindex(char c)
 | |
| {
 | |
|   stringpair *cur;
 | |
|   assert(c>='A' && c<='Z' || c>='a' && c<='z' || c=='_' || c==PUBLIC_CHAR);
 | |
|   assert(PUBLIC_CHAR<'A' && 'A'<'_' && '_'<'z');
 | |
| 
 | |
|   for (cur=substpair.next; cur!=NULL && cur->first[0]!=c; cur=cur->next)
 | |
|     /* nothing */;
 | |
|   substindex[(int)c-PUBLIC_CHAR]=cur;
 | |
| }
 | |
| 
 | |
| SC_FUNC stringpair *insert_subst(char *pattern,char *substitution,int prefixlen)
 | |
| {
 | |
|   stringpair *cur;
 | |
| 
 | |
|   assert(pattern!=NULL);
 | |
|   assert(substitution!=NULL);
 | |
|   if ((cur=insert_stringpair(&substpair,pattern,substitution,prefixlen))==NULL)
 | |
|     error(103);       /* insufficient memory (fatal error) */
 | |
|   adjustindex(*pattern);
 | |
| 
 | |
|   if (pc_deprecate!=NULL) {
 | |
| 	  assert(cur!=NULL);
 | |
| 	  cur->flags|=flgDEPRECATED;
 | |
| 	  if (sc_status==statWRITE) {
 | |
| 		  if (cur->documentation!=NULL) {
 | |
| 			  free(cur->documentation);
 | |
| 			  cur->documentation=NULL;
 | |
| 		  } /* if */
 | |
| 		  cur->documentation=pc_deprecate;
 | |
| 	  } else {
 | |
| 		  free(pc_deprecate);
 | |
| 	  } /* if */
 | |
| 	  pc_deprecate=NULL;
 | |
|   } else {
 | |
| 	  cur->flags = 0;
 | |
| 	  cur->documentation = NULL;
 | |
|   } /* if */
 | |
| 
 | |
|   return cur;
 | |
| }
 | |
| 
 | |
| SC_FUNC stringpair *find_subst(char *name,int length)
 | |
| {
 | |
|   stringpair *item;
 | |
|   assert(name!=NULL);
 | |
|   assert(length>0);
 | |
|   assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
 | |
|   item=substindex[(int)*name-PUBLIC_CHAR];
 | |
|   if (item!=NULL)
 | |
|     item=find_stringpair(item,name,length);
 | |
| 
 | |
|   if (item && (item->flags & flgDEPRECATED) != 0)
 | |
|   {
 | |
|     static char macro[128];
 | |
|     char *rem, *msg = (item->documentation != NULL) ? item->documentation : "";
 | |
|     strlcpy(macro, item->first, sizeof(macro));
 | |
| 
 | |
|     /* If macro contains an opening parentheses and a percent sign, then assume that
 | |
|      * it takes arguments and remove them from the warning message.
 | |
|      */
 | |
|     if ((rem = strchr(macro, '(')) != NULL && strchr(macro, '%') > rem)
 | |
|     {
 | |
|       *rem = '\0';
 | |
|     }
 | |
| 
 | |
|     error(234, macro, msg);  /* deprecated (macro/constant) */
 | |
|   }
 | |
|   return item;
 | |
| }
 | |
| 
 | |
| SC_FUNC int delete_subst(char *name,int length)
 | |
| {
 | |
|   stringpair *item;
 | |
|   assert(name!=NULL);
 | |
|   assert(length>0);
 | |
|   assert(*name>='A' && *name<='Z' || *name>='a' && *name<='z' || *name=='_' || *name==PUBLIC_CHAR);
 | |
|   item=substindex[(int)*name-PUBLIC_CHAR];
 | |
|   if (item!=NULL)
 | |
|     item=find_stringpair(item,name,length);
 | |
|   if (item==NULL)
 | |
|     return FALSE;
 | |
|   if (item->documentation)
 | |
|   {
 | |
|     free(item->documentation);
 | |
|     item->documentation=NULL;
 | |
|   }
 | |
|   delete_stringpair(&substpair,item);
 | |
|   adjustindex(*name);
 | |
|   return TRUE;
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_substtable(void)
 | |
| {
 | |
|   int i;
 | |
|   delete_stringpairtable(&substpair);
 | |
|   for (i=0; i<sizeof substindex/sizeof substindex[0]; i++)
 | |
|     substindex[i]=NULL;
 | |
| }
 | |
| 
 | |
| #endif /* !defined NO_SUBST */
 | |
| 
 | |
| 
 | |
| /* ----- input file list ----------------------------------------- */
 | |
| static stringlist sourcefiles = {NULL, NULL};
 | |
| 
 | |
| SC_FUNC stringlist *insert_sourcefile(char *string)
 | |
| {
 | |
|   return insert_string(&sourcefiles,string);
 | |
| }
 | |
| 
 | |
| SC_FUNC char *get_sourcefile(int index)
 | |
| {
 | |
|   return get_string(&sourcefiles,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_sourcefiletable(void)
 | |
| {
 | |
|   delete_stringtable(&sourcefiles);
 | |
|   assert(sourcefiles.next==NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ----- documentation tags -------------------------------------- */
 | |
| #if !defined SC_LIGHT
 | |
| static stringlist docstrings = {NULL, NULL};
 | |
| 
 | |
| SC_FUNC stringlist *insert_docstring(char *string)
 | |
| {
 | |
|   return insert_string(&docstrings,string);
 | |
| }
 | |
| 
 | |
| SC_FUNC char *get_docstring(int index)
 | |
| {
 | |
|   return get_string(&docstrings,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_docstring(int index)
 | |
| {
 | |
|   delete_string(&docstrings,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_docstringtable(void)
 | |
| {
 | |
|   delete_stringtable(&docstrings);
 | |
|   assert(docstrings.next==NULL);
 | |
| }
 | |
| #endif /* !defined SC_LIGHT */
 | |
| 
 | |
| 
 | |
| /* ----- autolisting --------------------------------------------- */
 | |
| static stringlist autolist = {NULL, NULL};
 | |
| 
 | |
| SC_FUNC stringlist *insert_autolist(char *string)
 | |
| {
 | |
|   return insert_string(&autolist,string);
 | |
| }
 | |
| 
 | |
| SC_FUNC char *get_autolist(int index)
 | |
| {
 | |
|   return get_string(&autolist,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_autolisttable(void)
 | |
| {
 | |
|   delete_stringtable(&autolist);
 | |
|   assert(autolist.next==NULL);
 | |
| }
 | |
| 
 | |
| 
 | |
| /* ----- debug information --------------------------------------- */
 | |
| 
 | |
| /* These macros are adapted from LibDGG libdgg-int64.h, see
 | |
|  * http://www.dennougedougakkai-ndd.org/pub/libdgg/
 | |
|  */
 | |
| #if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
 | |
|   #define __STDC_FORMAT_MACROS
 | |
|   #define __STDC_CONSTANT_MACROS
 | |
|   #include <inttypes.h>         /* automatically includes stdint.h */
 | |
| #elif (defined _MSC_VER || defined __BORLANDC__) && (defined _I64_MAX || defined HAVE_I64)
 | |
|   #define PRId64 "I64d"
 | |
|   #define PRIx64 "I64x"
 | |
| #else
 | |
|   #define PRId64 "lld"
 | |
|   #define PRIx64 "llx"
 | |
| #endif
 | |
| #if PAWN_CELL_SIZE==64
 | |
|   #define PRIdC  PRId64
 | |
|   #define PRIxC  PRIx64
 | |
| #elif PAWN_CELL_SIZE==32
 | |
|   #define PRIdC  "ld"
 | |
|   #define PRIxC  "lx"
 | |
| #else
 | |
|   #define PRIdC  "d"
 | |
|   #define PRIxC  "x"
 | |
| #endif
 | |
| 
 | |
| static stringlist dbgstrings = {NULL, NULL};
 | |
| 
 | |
| SC_FUNC stringlist *insert_dbgfile(const char *filename)
 | |
| {
 | |
| 
 | |
|   if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
 | |
|     char string[_MAX_PATH+40];
 | |
|     assert(filename!=NULL);
 | |
|     assert(strlen(filename)+40<sizeof string);
 | |
|     sprintf(string,"F:%" PRIxC " %s",code_idx,filename);
 | |
|     return insert_string(&dbgstrings,string);
 | |
|   } /* if */
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| SC_FUNC stringlist *insert_dbgline(int linenr)
 | |
| {
 | |
|   if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
 | |
|     char string[40];
 | |
|     if (linenr>0)
 | |
|       linenr--;         /* line numbers are zero-based in the debug information */
 | |
|     sprintf(string,"L:%" PRIxC " %x",code_idx,linenr);
 | |
|     return insert_string(&dbgstrings,string);
 | |
|   } /* if */
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| SC_FUNC stringlist *insert_dbgsymbol(symbol *sym)
 | |
| {
 | |
|   if (sc_status==statWRITE && (sc_debug & sSYMBOLIC)!=0) {
 | |
|     char string[2*sNAMEMAX+128];
 | |
|     char symname[2*sNAMEMAX+16];
 | |
| 
 | |
|     funcdisplayname(symname,sym->name);
 | |
|     /* address tag:name codestart codeend ident vclass [tag:dim ...] */
 | |
|     if (sym->ident==iFUNCTN) {
 | |
|       sprintf(string,"S:%" PRIxC " %x:%s %" PRIxC " %" PRIxC " %x %x",
 | |
|               sym->addr,sym->tag,symname,sym->addr,sym->codeaddr,sym->ident,sym->vclass);
 | |
|     } else {
 | |
|       sprintf(string,"S:%" PRIxC " %x:%s %" PRIxC " %" PRIxC " %x %x",
 | |
|               sym->addr,sym->tag,symname,sym->codeaddr,code_idx,sym->ident,sym->vclass);
 | |
|     } /* if */
 | |
|     if (sym->ident==iARRAY || sym->ident==iREFARRAY) {
 | |
|       #if !defined NDEBUG
 | |
|         int count=sym->dim.array.level;
 | |
|       #endif
 | |
|       symbol *sub;
 | |
|       strcat(string," [ ");
 | |
|       for (sub=sym; sub!=NULL; sub=finddepend(sub)) {
 | |
|         assert(sub->dim.array.level==count--);
 | |
|         sprintf(string+strlen(string),"%x:%x ",sub->x.tags.index,sub->dim.array.length);
 | |
|       } /* for */
 | |
|       strcat(string,"]");
 | |
|     } /* if */
 | |
| 
 | |
|     return insert_string(&dbgstrings,string);
 | |
|   } /* if */
 | |
|   return NULL;
 | |
| }
 | |
| 
 | |
| SC_FUNC char *get_dbgstring(int index)
 | |
| {
 | |
|   return get_string(&dbgstrings,index);
 | |
| }
 | |
| 
 | |
| SC_FUNC void delete_dbgstringtable(void)
 | |
| {
 | |
|   delete_stringtable(&dbgstrings);
 | |
|   assert(dbgstrings.next==NULL);
 | |
| }
 |