508 lines
13 KiB
C
508 lines
13 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: sclist.c 3660 2006-11-05 13:05:09Z thiadmer $
|
||
*/
|
||
#include <assert.h>
|
||
#include <limits.h>
|
||
#include <stdlib.h>
|
||
#include <string.h>
|
||
#include "sc.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;
|
||
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 *list,char *string)
|
||
{
|
||
stringlist newlist;
|
||
|
||
assert(list!=NULL);
|
||
assert(string!=NULL);
|
||
if (list->data==NULL) {
|
||
/* inserted for the first time */
|
||
newlist.length=0;
|
||
newlist.size=2;
|
||
newlist.data=calloc(newlist.size,sizeof(char*));
|
||
newlist.strings=newlist.data;
|
||
if (newlist.data==NULL)
|
||
error(103); /* insufficient memory (fatal error) */
|
||
*list=newlist;
|
||
} else if (list->length==list->size ||
|
||
list->length==list->data+list->size-list->strings) {
|
||
/* allocate more elements */
|
||
newlist.length=list->length;
|
||
newlist.size=list->size+list->size/2;
|
||
newlist.data=realloc(list->data,newlist.size*sizeof(char*));
|
||
newlist.strings=newlist.data+(list->strings-list->data);
|
||
if (newlist.data==NULL)
|
||
error(103); /* insufficient memory (fatal error) */
|
||
memset(newlist.data+list->size,0,list->size/2*sizeof(char*));
|
||
*list=newlist;
|
||
} /* if */
|
||
if ((list->strings[list->length]=duplicatestring(string))==NULL)
|
||
error(103); /* insufficient memory (fatal error) */
|
||
list->length++;
|
||
return list;
|
||
}
|
||
|
||
static char *get_string(stringlist *list,int index)
|
||
{
|
||
assert(list!=NULL);
|
||
if (index>=0 && index<list->length)
|
||
return list->strings[index];
|
||
return NULL;
|
||
}
|
||
|
||
static int delete_string(stringlist *list,int index)
|
||
{
|
||
assert(list!=NULL);
|
||
assert(index==0);
|
||
if (list->length>0) {
|
||
free(list->strings[0]);
|
||
list->strings[0]=NULL;
|
||
list->strings++;
|
||
list->length--;
|
||
return TRUE;
|
||
} /* if */
|
||
return FALSE;
|
||
}
|
||
|
||
SC_FUNC void delete_stringtable(stringlist *list)
|
||
{
|
||
int i;
|
||
|
||
assert(list!=NULL);
|
||
for (i=0; i<list->size; i++)
|
||
free(list->data[i]);
|
||
free(list->data);
|
||
memset(list,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, 0, 0}; /* 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.strings==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);
|
||
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);
|
||
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;
|
||
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, 0, 0};
|
||
|
||
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.strings==NULL);
|
||
}
|
||
|
||
|
||
/* ----- documentation tags -------------------------------------- */
|
||
#if !defined SC_LIGHT
|
||
static stringlist docstrings = {NULL, NULL, 0, 0};
|
||
|
||
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)
|
||
{
|
||
assert(index==0);
|
||
delete_string(&docstrings, index);
|
||
}
|
||
|
||
SC_FUNC void delete_docstringtable(void)
|
||
{
|
||
delete_stringtable(&docstrings);
|
||
assert(docstrings.strings==NULL);
|
||
}
|
||
#endif /* !defined SC_LIGHT */
|
||
|
||
|
||
/* ----- autolisting --------------------------------------------- */
|
||
static stringlist autolist = {NULL, NULL, 0, 0};
|
||
|
||
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.strings==NULL);
|
||
}
|
||
|
||
|
||
/* ----- value pair list ----------------------------------------- */
|
||
static valuepair heaplist = {NULL, 0, 0};
|
||
|
||
SC_FUNC valuepair *push_heaplist(long first, long second)
|
||
{
|
||
valuepair *cur, *last;
|
||
if ((cur=malloc(sizeof(valuepair)))==NULL)
|
||
error(103); /* insufficient memory (fatal error) */
|
||
|
||
cur->first=first;
|
||
cur->second=second;
|
||
cur->next=NULL;
|
||
|
||
for (last=&heaplist; last->next!=NULL; last=last->next)
|
||
/* nothing */;
|
||
last->next=cur;
|
||
return cur;
|
||
}
|
||
|
||
SC_FUNC int popfront_heaplist(long *first, long *second)
|
||
{
|
||
valuepair *front=heaplist.next;
|
||
if (front==NULL)
|
||
return 0;
|
||
|
||
/* copy fields */
|
||
*first=front->first;
|
||
*second=front->second;
|
||
|
||
/* unlink and free */
|
||
heaplist.next=front->next;
|
||
free(front);
|
||
return 1;
|
||
}
|
||
|
||
SC_FUNC void delete_heaplisttable(void)
|
||
{
|
||
valuepair *cur;
|
||
while (heaplist.next!=NULL) {
|
||
cur=heaplist.next;
|
||
heaplist.next=cur->next;
|
||
free(cur);
|
||
} /* while */
|
||
}
|
||
|
||
|
||
/* ----- debug information --------------------------------------- */
|
||
static stringlist dbgstrings = {NULL, NULL, 0, 0};
|
||
|
||
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.strings==NULL);
|
||
}
|