Merge pull request #5 from peace-maker/pawn_stringconcat

Add string literal concatenation using ellipses "..." (bug 4261, PR #5, r=dvander).
This commit is contained in:
Nicholas Hastings 2014-06-11 08:16:04 -04:00
commit feb5050df1
5 changed files with 201 additions and 49 deletions

View File

@ -146,16 +146,6 @@ void pc_closesrc(void *handle)
fclose((FILE*)handle); fclose((FILE*)handle);
} }
/* pc_resetsrc()
* "position" may only hold a pointer that was previously obtained from
* pc_getpossrc()
*/
void pc_resetsrc(void *handle,void *position)
{
assert(handle!=NULL);
fsetpos((FILE*)handle,(fpos_t *)position);
}
/* pc_readsrc() /* pc_readsrc()
* Reads a single line from the source file (or up to a maximum number of * Reads a single line from the source file (or up to a maximum number of
* characters if the line in the input file is too long). * characters if the line in the input file is too long).
@ -174,12 +164,40 @@ int pc_writesrc(void *handle,unsigned char *source)
return fputs((char*)source,(FILE*)handle) >= 0; return fputs((char*)source,(FILE*)handle) >= 0;
} }
void *pc_getpossrc(void *handle) #define MAXPOSITIONS 4
{ static fpos_t srcpositions[MAXPOSITIONS];
static fpos_t lastpos; /* may need to have a LIFO stack of such positions */ static unsigned char srcposalloc[MAXPOSITIONS];
fgetpos((FILE*)handle,&lastpos); void *pc_getpossrc(void *handle,void *position)
return &lastpos; {
if (position==NULL) {
/* allocate a new slot */
int i;
for (i=0; i<MAXPOSITIONS && srcposalloc[i]!=0; i++)
/* nothing */;
assert(i<MAXPOSITIONS); /* if not, there is a queue overrun */
if (i>=MAXPOSITIONS)
return NULL;
position=&srcpositions[i];
srcposalloc[i]=1;
} else {
/* use the gived slot */
assert((fpos_t*)position>=srcpositions && (fpos_t*)position<srcpositions+sizeof(srcpositions));
} /* if */
fgetpos((FILE*)handle,(fpos_t*)position);
return position;
}
/* pc_resetsrc()
* "position" may only hold a pointer that was previously obtained from
* pc_getpossrc()
*/
void pc_resetsrc(void *handle,void *position)
{
assert(handle!=NULL);
assert(position!=NULL);
fsetpos((FILE*)handle,(fpos_t *)position);
/* note: the item is not cleared from the pool */
} }
int pc_eofsrc(void *handle) int pc_eofsrc(void *handle)

View File

@ -484,10 +484,10 @@ int pc_error(int number,char *message,char *filename,int firstline,int lastline,
void *pc_opensrc(char *filename); /* reading only */ void *pc_opensrc(char *filename); /* reading only */
void *pc_createsrc(char *filename); void *pc_createsrc(char *filename);
void pc_closesrc(void *handle); /* never delete */ void pc_closesrc(void *handle); /* never delete */
void pc_resetsrc(void *handle,void *position); /* reset to a position marked earlier */
char *pc_readsrc(void *handle,unsigned char *target,int maxchars); char *pc_readsrc(void *handle,unsigned char *target,int maxchars);
int pc_writesrc(void *handle,unsigned char *source); int pc_writesrc(void *handle,unsigned char *source);
void *pc_getpossrc(void *handle); /* mark the current position */ void *pc_getpossrc(void *handle,void *position); /* mark the current position */
void pc_resetsrc(void *handle,void *position); /* reset to a position marked earlier */
int pc_eofsrc(void *handle); int pc_eofsrc(void *handle);
/* output to intermediate (.ASM) file */ /* output to intermediate (.ASM) file */

View File

@ -333,7 +333,7 @@ int pc_compile(int argc, char *argv[])
} /* if */ } /* if */
/* do the first pass through the file (or possibly two or more "first passes") */ /* do the first pass through the file (or possibly two or more "first passes") */
sc_parsenum=0; sc_parsenum=0;
inpfmark=pc_getpossrc(inpf_org); inpfmark=pc_getpossrc(inpf_org,NULL);
do { do {
/* reset "defined" flag of all functions and global variables */ /* reset "defined" flag of all functions and global variables */
reduce_referrers(&glbtab); reduce_referrers(&glbtab);

View File

@ -38,8 +38,9 @@
#endif #endif
/* flags for litchar() */ /* flags for litchar() */
#define RAWMODE 1 #define RAWMODE 0x1
#define UTF8MODE 2 #define UTF8MODE 0x2
#define ISPACKED 0x4
static cell litchar(const unsigned char **lptr,int flags); static cell litchar(const unsigned char **lptr,int flags);
static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag); static symbol *find_symbol(const symbol *root,const char *name,int fnumber,int automaton,int *cmptag);
@ -1492,6 +1493,7 @@ static int substpattern(unsigned char *line,size_t buffersize,char *pattern,char
const unsigned char *p,*s,*e; const unsigned char *p,*s,*e;
unsigned char *args[10]; unsigned char *args[10];
int match,arg,len,argsnum=0; int match,arg,len,argsnum=0;
int stringize;
memset(args,0,sizeof args); memset(args,0,sizeof args);
@ -1588,11 +1590,18 @@ static int substpattern(unsigned char *line,size_t buffersize,char *pattern,char
if (match) { if (match) {
/* calculate the length of the substituted string */ /* calculate the length of the substituted string */
for (e=(unsigned char*)substitution,len=0; *e!='\0'; e++) { for (e=(unsigned char*)substitution,len=0; *e!='\0'; e++) {
if(*e=='#' && *(e+1)=='%' && isdigit(*(e+2)) && argsnum) {
stringize=1;
e++; /* skip '#' */
} else {
stringize=0;
} /* if */
if (*e=='%' && isdigit(*(e+1)) && argsnum) { if (*e=='%' && isdigit(*(e+1)) && argsnum) {
arg=*(e+1)-'0'; arg=*(e+1)-'0';
assert(arg>=0 && arg<=9); assert(arg>=0 && arg<=9);
assert(stringize==0 || stringize==1);
if (args[arg]!=NULL) { if (args[arg]!=NULL) {
len+=strlen((char*)args[arg]); len+=strlen((char*)args[arg])+2*stringize;
e++; e++;
} else { } else {
len++; len++;
@ -1608,12 +1617,22 @@ static int substpattern(unsigned char *line,size_t buffersize,char *pattern,char
/* substitute pattern */ /* substitute pattern */
strdel((char*)line,(int)(s-line)); strdel((char*)line,(int)(s-line));
for (e=(unsigned char*)substitution,s=line; *e!='\0'; e++) { for (e=(unsigned char*)substitution,s=line; *e!='\0'; e++) {
if (*e=='#' && *(e+1)=='%' && isdigit(*(e+2))) {
stringize=1;
e++; /* skip '#' */
} else {
stringize=0;
} /* if */
if (*e=='%' && isdigit(*(e+1))) { if (*e=='%' && isdigit(*(e+1))) {
arg=*(e+1)-'0'; arg=*(e+1)-'0';
assert(arg>=0 && arg<=9); assert(arg>=0 && arg<=9);
if (args[arg]!=NULL) { if (args[arg]!=NULL) {
if (stringize)
strins((char*)s++,"\"",1);
strins((char*)s,(char*)args[arg],strlen((char*)args[arg])); strins((char*)s,(char*)args[arg],strlen((char*)args[arg]));
s+=strlen((char*)args[arg]); s+=strlen((char*)args[arg]);
if (stringize)
strins((char*)s++,"\"",1);
} else { } else {
error(236); /* parameter does not exist, incorrect #define pattern */ error(236); /* parameter does not exist, incorrect #define pattern */
strins((char*)s,(char*)e,2); strins((char*)s,(char*)e,2);
@ -1702,6 +1721,61 @@ static void substallpatterns(unsigned char *line,int buffersize)
} }
#endif #endif
/* scanellipsis
* Look for ... in the string and (if not there) in the remainder of the file,
* but restore (or keep intact):
* - the current position in the file
* - the comment parsing state
* - the line buffer used by the lexical analyser
* - the active line number and the active file
*
* The function returns 1 if an ellipsis was found and 0 if not
*/
static int scanellipsis(const unsigned char *lptr)
{
static void *inpfmark=NULL;
unsigned char *localbuf;
short localcomment,found;
/* first look for the ellipsis in the remainder of the string */
while (*lptr<=' ' && *lptr!='\0')
lptr++;
if (lptr[0]=='.' && lptr[1]=='.' && lptr[2]=='.')
return 1;
if (*lptr!='\0')
return 0; /* stumbled on something that is not an ellipsis and not white-space */
/* the ellipsis was not on the active line, read more lines from the current
* file (but save its position first)
*/
if (inpf==NULL || pc_eofsrc(inpf))
return 0; /* quick exit: cannot read after EOF */
if ((localbuf=(unsigned char*)malloc((sLINEMAX+1)*sizeof(unsigned char)))==NULL)
return 0;
inpfmark=pc_getpossrc(inpf,inpfmark);
localcomment=icomment;
found=0;
/* read from the file, skip preprocessing, but strip off comments */
while (!found && pc_readsrc(inpf,localbuf,sLINEMAX)!=NULL) {
stripcom(localbuf);
lptr=localbuf;
/* skip white space */
while (*lptr<=' ' && *lptr!='\0')
lptr++;
if (lptr[0]=='.' && lptr[1]=='.' && lptr[2]=='.')
found=1;
else if (*lptr!='\0')
break; /* stumbled on something that is not an ellipsis and not white-space */
} /* while */
/* clean up & reset */
free(localbuf);
pc_resetsrc(inpf,inpfmark);
icomment=localcomment;
return found;
}
/* preprocess /* preprocess
* *
* Reads a line by readline() into "pline" and performs basic preprocessing: * Reads a line by readline() into "pline" and performs basic preprocessing:
@ -1865,7 +1939,7 @@ char *sc_tokens[] = {
SC_FUNC int lex(cell *lexvalue,char **lexsym) SC_FUNC int lex(cell *lexvalue,char **lexsym)
{ {
int i,toolong,newline,stringflags; int i,toolong,newline;
char **tokptr; char **tokptr;
const unsigned char *starttoken; const unsigned char *starttoken;
@ -1977,35 +2051,94 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
error(220); error(220);
} /* if */ } /* if */
} /* if */ } /* if */
} else if (*lptr=='\"' || (*lptr==sc_ctrlchar && *(lptr+1)=='\"')) } else if (*lptr=='\"' /* unpacked string literal */
{ /* unpacked string literal */ #if 0
|| (*lptr==sc_ctrlchar && *(lptr+1)=='\"') /* unpacked raw string */
|| (*lptr=='!' && *(lptr+1)=='\"') /* packed string */
|| (*lptr=='!' && *(lptr+1)==sc_ctrlchar && *(lptr+2)=='\"') /* packed raw string */
|| (*lptr==sc_ctrlchar && *(lptr+1)=='!' && *(lptr+2)=='\"') /* packed raw string */
#endif
)
{
int stringflags,segmentflags;
char *cat;
_lextok=tSTRING; _lextok=tSTRING;
stringflags= (*lptr==sc_ctrlchar) ? RAWMODE : 0;
*lexvalue=_lexval=litidx; *lexvalue=_lexval=litidx;
lptr+=1; /* skip double quote */ _lexstr[0]='\0';
if ((stringflags & RAWMODE)!=0) stringflags=-1; /* to mark the first segment */
for ( ;; ) {
if(*lptr=='!')
segmentflags= (*(lptr+1)==sc_ctrlchar) ? RAWMODE | ISPACKED : ISPACKED;
else if (*lptr==sc_ctrlchar)
segmentflags= (*(lptr+1)=='!') ? RAWMODE | ISPACKED : RAWMODE;
else
segmentflags=0;
if ((segmentflags & ISPACKED)!=0)
lptr+=1; /* skip '!' character */
if ((segmentflags & RAWMODE)!=0)
lptr+=1; /* skip "escape" character too */ lptr+=1; /* skip "escape" character too */
/* Note that this should always be packedstring() for SourcePawn */ assert(*lptr=='\"');
lptr=sc_packstr ? packedstring(lptr,stringflags) : unpackedstring(lptr,stringflags); lptr+=1;
if (stringflags==-1)
stringflags=segmentflags;
else if (stringflags!=segmentflags)
error(238); /* mixing packed/unpacked/raw strings in concatenation */
cat=strchr(_lexstr,'\0');
assert(cat!=NULL);
while (*lptr!='\"' && *lptr!='\0' && (cat-_lexstr)<sLINEMAX) {
if (*lptr!='\a') { /* ignore '\a' (which was inserted at a line concatenation) */
*cat++=*lptr;
if (*lptr==sc_ctrlchar && *(lptr+1)!='\0')
*cat++=*++lptr; /* skip escape character plus the escaped character */
} /* if */
lptr++;
} /* while */
*cat='\0'; /* terminate string */
if (*lptr=='\"') if (*lptr=='\"')
lptr+=1; /* skip final quote */ lptr+=1; /* skip final quote */
else else
error(37); /* invalid (non-terminated) string */ error(37); /* invalid (non-terminated) string */
} else if ((*lptr=='!' && *(lptr+1)=='\"') /* see whether an ellipsis is following the string */
|| (*lptr=='!' && *(lptr+1)==sc_ctrlchar && *(lptr+2)=='\"') if (!scanellipsis(lptr))
|| (*lptr==sc_ctrlchar && *(lptr+1)=='!' && *(lptr+2)=='\"')) break; /* no concatenation of string literals */
{ /* packed string literal */ /* there is an ellipses, go on parsing (this time with full preprocessing) */
_lextok=tSTRING; while (*lptr<=' ') {
stringflags= (*lptr==sc_ctrlchar || *(lptr+1)==sc_ctrlchar) ? RAWMODE : 0; if (*lptr=='\0') {
*lexvalue=_lexval=litidx; preprocess(); /* preprocess resets "lptr" */
lptr+=2; /* skip exclamation point and double quote */ assert(freading && lptr!=term_expr);
if ((stringflags & RAWMODE)!=0) } else {
lptr+=1; /* skip "escape" character too */ lptr++;
lptr=sc_packstr ? unpackedstring(lptr,stringflags) : packedstring(lptr,stringflags); } /* if */
if (*lptr=='\"') } /* while */
lptr+=1; /* skip final quote */ assert(freading && lptr[0]=='.' && lptr[1]=='.' && lptr[2]=='.');
lptr+=3;
while (*lptr<=' ') {
if (*lptr=='\0') {
preprocess(); /* preprocess resets "lptr" */
assert(freading && lptr!=term_expr);
} else {
lptr++;
} /* if */
} /* while */
if (!freading || !(*lptr=='\"'
#if 0
|| *lptr==sc_ctrlchar && *(lptr+1)=='\"'
|| *lptr=='!' && *(lptr+1)=='\"'
|| *lptr=='!' && *(lptr+1)==sc_ctrlchar && *(lptr+2)=='\"'
|| *lptr==sc_ctrlchar && *(lptr+1)=='!' && *(lptr+2)=='\"'
#endif
))
{
error(37); /* invalid string concatenation */
break;
} /* if */
} /* for */
if (sc_packstr)
stringflags ^= ISPACKED; /* invert packed/unpacked parameters */
if ((stringflags & ISPACKED)!=0)
packedstring((unsigned char *)_lexstr,stringflags);
else else
error(37); /* invalid (non-terminated) string */ unpackedstring((unsigned char *)_lexstr,stringflags);
} else if (*lptr=='\'') { /* character literal */ } else if (*lptr=='\'') { /* character literal */
lptr+=1; /* skip quote */ lptr+=1; /* skip quote */
_lextok=tNUMBER; _lextok=tNUMBER;

View File

@ -396,11 +396,12 @@ SC_FUNC int scan_utf8(FILE *fp,const char *filename)
#if defined NO_UTF8 #if defined NO_UTF8
return 0; return 0;
#else #else
void *resetpos=pc_getpossrc(fp); static void *resetpos=NULL;
int utf8=TRUE; int utf8=TRUE;
int firstchar=TRUE,bom_found=FALSE; int firstchar=TRUE,bom_found=FALSE;
const unsigned char *ptr; const unsigned char *ptr;
resetpos=pc_getpossrc(fp,resetpos);
while (utf8 && pc_readsrc(fp,pline,sLINEMAX)!=NULL) { while (utf8 && pc_readsrc(fp,pline,sLINEMAX)!=NULL) {
ptr=pline; ptr=pline;
if (firstchar) { if (firstchar) {