Merge pull request #45 from alliedmodders/methodmaps-inline
Introduce 4-token lookahead buffer.
This commit is contained in:
commit
c4f2b8348e
@ -306,6 +306,15 @@ typedef struct {
|
||||
char *str;
|
||||
} token_t;
|
||||
|
||||
// The method name buffer is larger since we can include our parent class's
|
||||
// name, a "." to separate it, and a "~" for constructors.
|
||||
#define METHOD_NAMEMAX sNAMEMAX * 2 + 2
|
||||
|
||||
typedef struct {
|
||||
token_t tok;
|
||||
char name[METHOD_NAMEMAX + 1];
|
||||
} token_ident_t;
|
||||
|
||||
/* macros for code generation */
|
||||
#define opcodes(n) ((n)*sizeof(cell)) /* opcode size */
|
||||
#define opargs(n) ((n)*sizeof(cell)) /* size of typical argument */
|
||||
@ -595,6 +604,8 @@ SC_FUNC int matchtoken(int token);
|
||||
SC_FUNC int tokeninfo(cell *val,char **str);
|
||||
SC_FUNC int needtoken(int token);
|
||||
SC_FUNC int expecttoken(int id, token_t *tok);
|
||||
SC_FUNC int matchsymbol(token_ident_t *ident);
|
||||
SC_FUNC int needsymbol(token_ident_t *ident);
|
||||
SC_FUNC void litadd(cell value);
|
||||
SC_FUNC void litinsert(cell value,int pos);
|
||||
SC_FUNC int alphanum(char c);
|
||||
|
@ -78,6 +78,12 @@ int pc_functag = 0;
|
||||
int pc_tag_string = 0;
|
||||
int pc_tag_void = 0;
|
||||
|
||||
typedef struct funcstub_setup_s {
|
||||
const char *name;
|
||||
int return_tag;
|
||||
int this_tag;
|
||||
} funcstub_setup_t;
|
||||
|
||||
static void resetglobals(void);
|
||||
static void initglobals(void);
|
||||
static char *get_extension(char *filename);
|
||||
@ -110,7 +116,7 @@ static cell initvector(int ident,int tag,cell size,int fillzero,
|
||||
static cell init(int ident,int *tag,int *errorfound);
|
||||
static int getstates(const char *funcname);
|
||||
static void attachstatelist(symbol *sym, int state_id);
|
||||
static symbol *funcstub(int fnative);
|
||||
static symbol *funcstub(int fnative, const funcstub_setup_t *setup);
|
||||
static int newfunc(char *firstname,int firsttag,int fpublic,int fstatic,int stock);
|
||||
static int declargs(symbol *sym,int chkshadow);
|
||||
static void doarg(char *name,int ident,int offset,int tags[],int numtags,
|
||||
@ -1564,10 +1570,10 @@ static void parse(void)
|
||||
} /* if */
|
||||
break;
|
||||
case tNATIVE:
|
||||
funcstub(TRUE); /* create a dummy function */
|
||||
funcstub(TRUE, NULL); /* create a dummy function */
|
||||
break;
|
||||
case tFORWARD:
|
||||
funcstub(FALSE);
|
||||
funcstub(FALSE, NULL);
|
||||
break;
|
||||
case '}':
|
||||
error(54); /* unmatched closing brace */
|
||||
@ -3346,16 +3352,57 @@ void define_constructor(methodmap_t *map, methodmap_method_t *method)
|
||||
sym->target = method->target;
|
||||
}
|
||||
|
||||
// Current lexer position is, we've parsed "public", an optional "native", and
|
||||
// a type expression.
|
||||
//
|
||||
// This returns true if there is a method bind, i.e. "() = Y".
|
||||
static int match_method_bind()
|
||||
{
|
||||
// The grammar here is a little complicated. We must differentiate
|
||||
// between two different rules:
|
||||
// public X() = Y;
|
||||
// public X() { ...
|
||||
//
|
||||
// If we parse up to '=', then it becomes harder to call newfunc() later,
|
||||
// since ideally we'd like to back up to the '('. To work around this we
|
||||
// use a hacked in lexer API to push older tokens back into the token
|
||||
// stream.
|
||||
token_t tok;
|
||||
if (lextok(&tok) != '(') {
|
||||
lexpush();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!matchtoken(')')) {
|
||||
for (int i = 0; i < 2; i++)
|
||||
lexpush();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!matchtoken('=')) {
|
||||
for (int i = 0; i < 3; i++)
|
||||
lexpush();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
methodmap_method_t *parse_method(methodmap_t *map)
|
||||
{
|
||||
int is_ctor = 0;
|
||||
int is_dtor = 0;
|
||||
int is_bind = 0;
|
||||
int is_native = 0;
|
||||
const char *spectype = layout_spec_name(map->spec);
|
||||
|
||||
// We keep a wider buffer since we do name munging.
|
||||
char ident[sNAMEMAX * 3 + 1] = "<unknown>";
|
||||
char bindname[sNAMEMAX * 3 + 1] = "<unknown>";
|
||||
// This stores the name of the method (for destructors, we add a ~).
|
||||
token_ident_t ident;
|
||||
strcpy(ident.name, "<unknown>");
|
||||
|
||||
// For binding syntax, like X() = Y, this stores the right-hand name.
|
||||
token_ident_t bindsource;
|
||||
strcpy(bindsource.name, "<unknown>");
|
||||
|
||||
needtoken(tPUBLIC);
|
||||
|
||||
@ -3363,80 +3410,100 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
||||
declinfo_t decl;
|
||||
if (matchtoken('~')) {
|
||||
// We got something like "public ~Blah = X"
|
||||
is_bind = 1;
|
||||
is_dtor = 1;
|
||||
if (needtoken(tSYMBOL)) {
|
||||
tokeninfo(&tok.val, &tok.str);
|
||||
strcpy(ident, tok.str);
|
||||
}
|
||||
needtoken('(');
|
||||
needtoken(')');
|
||||
needtoken('=');
|
||||
if (!expecttoken(tSYMBOL, &tok))
|
||||
is_bind = TRUE;
|
||||
is_dtor = TRUE;
|
||||
if (!needsymbol(&ident))
|
||||
return NULL;
|
||||
if (!needtoken('('))
|
||||
return NULL;
|
||||
if (!needtoken(')'))
|
||||
return NULL;
|
||||
if (!needtoken('='))
|
||||
return NULL;
|
||||
if (!needsymbol(&bindsource))
|
||||
return NULL;
|
||||
strcpy(bindname, tok.str);
|
||||
} else {
|
||||
int got_symbol;
|
||||
|
||||
is_native = matchtoken(tNATIVE);
|
||||
got_symbol = matchsymbol(&ident);
|
||||
|
||||
if (is_native) {
|
||||
// If we have a native, we should always get a type expression next.
|
||||
parse_decl(&decl, NULL, 0);
|
||||
} else {
|
||||
// Parsing "public Clone =" and "public Handle Clone = " requires two tokens
|
||||
// of lookahead. By the time we see the '=' in the first example, we'd have
|
||||
// expected a function name, but it's too late to back up - _lexpush is only
|
||||
// one token deep.
|
||||
//
|
||||
// If we see a symbol and a '=', we know it's a simple binding. Otherwise,
|
||||
// we have to take the token we got from lextok() and ask parse_decl() to
|
||||
// start parsing it as a type expression.
|
||||
int is_symbol = (lextok(&tok) == tSYMBOL);
|
||||
if (is_symbol) {
|
||||
// Save the string because matchtoken() will overwrite the token buffer.
|
||||
// Note we also have to repoint tok so parse_decl will point at our
|
||||
// local copy.
|
||||
strcpy(ident, tok.str);
|
||||
tok.str = ident;
|
||||
if (!is_native && got_symbol) {
|
||||
// We didn't see "native", but we saw a symbol. Match for '() =' which
|
||||
// would indicate a method bind.
|
||||
is_bind = match_method_bind();
|
||||
|
||||
if (matchtoken('(')) {
|
||||
needtoken(')');
|
||||
needtoken('=');
|
||||
|
||||
// Grab the name we're binding to.
|
||||
is_bind = 1;
|
||||
if (!expecttoken(tSYMBOL, &tok))
|
||||
return NULL;
|
||||
strcpy(bindname, tok.str);
|
||||
}
|
||||
if (is_bind) {
|
||||
// If we saw "X() =", then grab the right-hand name.
|
||||
if (!needsymbol(&bindsource))
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_bind) {
|
||||
// We didn't find an '=', so proceed with a normal function signature.
|
||||
parse_decl(&decl, &tok, 0);
|
||||
if (!is_bind) {
|
||||
// All we know at this point is that we do NOT have a method bind. Keep
|
||||
// pattern matching for an inline constructor, destructor, or method.
|
||||
if (!got_symbol) {
|
||||
// We never saw an initial symbol, so it should be a destructor. If we
|
||||
// don't see a '~', the current token (which is not a symbol) will fail
|
||||
// the needsymbol() check, and we'll bail out.
|
||||
is_dtor = matchtoken('~');
|
||||
if (!needsymbol(&ident))
|
||||
return NULL;
|
||||
} else if (matchtoken('(')) {
|
||||
// There's no type expression. this is probably a constructor.
|
||||
is_ctor = TRUE;
|
||||
} else {
|
||||
// Parse for type expression, priming it with the token we predicted
|
||||
// would be an identifier.
|
||||
if (!parse_decl(&decl, &ident.tok, 0))
|
||||
return NULL;
|
||||
|
||||
if (lextok(&tok) != tSYMBOL) {
|
||||
// Error, and if EOF, return. The lexpush is so we don't accidentally
|
||||
// skip over a terminator or something, since we scan to the end of the
|
||||
// line.
|
||||
lexpush();
|
||||
error(111);
|
||||
if (tok.id == 0)
|
||||
return NULL;
|
||||
}
|
||||
// Now, we should get an identifier.
|
||||
if (!needsymbol(&ident))
|
||||
return NULL;
|
||||
|
||||
strcpy(ident, tok.str);
|
||||
} // if (tok == symbol && matchtoken('='))
|
||||
} // if (is_native)
|
||||
// If the identifier is a constructor, error, since the user specified
|
||||
// a type.
|
||||
if (strcmp(ident.name, map->name) == 0)
|
||||
error(99, "constructor");
|
||||
}
|
||||
} else {
|
||||
is_ctor = (strcmp(ident.name, map->name) == 0);
|
||||
}
|
||||
} // if (matchtoken('~'))
|
||||
|
||||
// Do some preliminary verification of ctor/dtor names.
|
||||
if (is_dtor) {
|
||||
if (strcmp(ident.name, map->name) != 0)
|
||||
error(114, "destructor", spectype, map->name);
|
||||
} else if (is_ctor) {
|
||||
if (strcmp(ident.name, map->name) != 0)
|
||||
error(114, "constructor", spectype, map->name);
|
||||
}
|
||||
|
||||
symbol *target = NULL;
|
||||
if (is_bind) {
|
||||
target = findglb(bindname, sGLOBAL);
|
||||
target = findglb(bindsource.name, sGLOBAL);
|
||||
if (!target)
|
||||
error(17, bindname);
|
||||
error(17, bindsource.name);
|
||||
else if (target->ident != iFUNCTN)
|
||||
error(10);
|
||||
// if (decl.usage & uCONST)
|
||||
// error(112, map->name);
|
||||
|
||||
// funcstub_setup_t setup;
|
||||
// if (is_dtor)
|
||||
// setup.return_tag = -1;
|
||||
// else if (is_ctor)
|
||||
// setup.return_tag = map->tag;
|
||||
// else
|
||||
// setup.return_tag = pc_addtag(decl.tag);
|
||||
|
||||
// setup.this_tag = map->tag;
|
||||
|
||||
// if (is_native)
|
||||
// target = funcstub(TRUE, &setup);
|
||||
} else {
|
||||
error(10);
|
||||
}
|
||||
@ -3444,11 +3511,8 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
||||
if (!target)
|
||||
return NULL;
|
||||
|
||||
// Verify destructor targets.
|
||||
if (is_dtor) {
|
||||
// Make sure the dtor has the right name.
|
||||
if (strcmp(ident, map->name) != 0)
|
||||
error(114, spectype, map->name);
|
||||
|
||||
if (!(target->usage & uNATIVE)) {
|
||||
// Must be a native.
|
||||
error(118);
|
||||
@ -3457,7 +3521,7 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
||||
|
||||
if (target->tag != 0 && target->tag != pc_tag_void) {
|
||||
// Cannot return a value.
|
||||
error(99);
|
||||
error(99, "destructor");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3467,30 +3531,33 @@ methodmap_method_t *parse_method(methodmap_t *map)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Make sure the final name includes the ~.
|
||||
strcpy(ident, "~");
|
||||
strcat(ident, map->name);
|
||||
// Make sure the final name has "~" in it.
|
||||
strcpy(ident.name, "~");
|
||||
strcat(ident.name, map->name);
|
||||
}
|
||||
|
||||
// Verify constructor targets.
|
||||
if (is_ctor) {
|
||||
if (target->tag != map->tag)
|
||||
error(112, map->name);
|
||||
}
|
||||
|
||||
// Check that a method with this name doesn't already exist.
|
||||
for (size_t i = 0; i < map->nummethods; i++) {
|
||||
if (strcmp(map->methods[i]->name, ident) == 0) {
|
||||
error(103, ident, spectype);
|
||||
if (strcmp(map->methods[i]->name, ident.name) == 0) {
|
||||
error(103, ident.name, spectype);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
methodmap_method_t *method = (methodmap_method_t *)calloc(1, sizeof(methodmap_method_t));
|
||||
strcpy(method->name, ident);
|
||||
strcpy(method->name, ident.name);
|
||||
method->target = target;
|
||||
if (is_dtor)
|
||||
map->dtor = method;
|
||||
|
||||
// If the symbol is a constructor, we bypass the initial argument checks,
|
||||
// and instead require that it returns something with the same tag.
|
||||
if (strcmp(ident, map->name) == 0) {
|
||||
if (target->tag != map->tag)
|
||||
error(112, map->name);
|
||||
// If the symbol is a constructor, we bypass the initial argument checks.
|
||||
if (is_ctor) {
|
||||
define_constructor(map, method);
|
||||
return method;
|
||||
}
|
||||
@ -4477,7 +4544,7 @@ SC_FUNC char *funcdisplayname(char *dest,char *funcname)
|
||||
return dest;
|
||||
}
|
||||
|
||||
static symbol *funcstub(int fnative)
|
||||
static symbol *funcstub(int fnative, const funcstub_setup_t *setup)
|
||||
{
|
||||
int tok,tag,fpublic;
|
||||
char *str;
|
||||
@ -4494,25 +4561,35 @@ static symbol *funcstub(int fnative)
|
||||
litidx=0; /* clear the literal pool */
|
||||
assert(loctab.next==NULL); /* local symbol table should be empty */
|
||||
|
||||
tag=pc_addtag(NULL); /* get the tag of the return value */
|
||||
// Either use an explicit return tag, or find a new one.
|
||||
if (!setup || setup->return_tag == 0)
|
||||
tag = pc_addtag(NULL);
|
||||
else if (setup->return_tag == -1)
|
||||
tag = 0;
|
||||
else
|
||||
tag = setup->return_tag;
|
||||
|
||||
numdim=0;
|
||||
while (matchtoken('[')) {
|
||||
/* the function returns an array, get this tag for the index and the array
|
||||
* dimensions
|
||||
*/
|
||||
if (numdim == sDIMEN_MAX) {
|
||||
error(53); /* exceeding maximum number of dimensions */
|
||||
return NULL;
|
||||
} /* if */
|
||||
size=needsub(&idxtag[numdim],NULL); /* get size; size==0 for "var[]" */
|
||||
if (size==0)
|
||||
error(9); /* invalid array size */
|
||||
#if INT_MAX < LONG_MAX
|
||||
if (size > INT_MAX)
|
||||
error(125); /* overflow, exceeding capacity */
|
||||
#endif
|
||||
dim[numdim++]=(int)size;
|
||||
} /* while */
|
||||
if (!setup) {
|
||||
// Method functions can't return arrays, since it's broken anyway.
|
||||
while (matchtoken('[')) {
|
||||
/* the function returns an array, get this tag for the index and the array
|
||||
* dimensions
|
||||
*/
|
||||
if (numdim == sDIMEN_MAX) {
|
||||
error(53); /* exceeding maximum number of dimensions */
|
||||
return NULL;
|
||||
} /* if */
|
||||
size=needsub(&idxtag[numdim],NULL); /* get size; size==0 for "var[]" */
|
||||
if (size==0)
|
||||
error(9); /* invalid array size */
|
||||
#if INT_MAX < LONG_MAX
|
||||
if (size > INT_MAX)
|
||||
error(125); /* overflow, exceeding capacity */
|
||||
#endif
|
||||
dim[numdim++]=(int)size;
|
||||
} /* while */
|
||||
}
|
||||
|
||||
if (tag == pc_tag_string && numdim && dim[numdim-1])
|
||||
dim[numdim-1] = (size + sizeof(cell)-1) / sizeof(cell);
|
||||
@ -4591,7 +4668,10 @@ static symbol *funcstub(int fnative)
|
||||
} /* if */
|
||||
} /* if */
|
||||
} /* if */
|
||||
needtoken(tTERM);
|
||||
|
||||
// Don't assume inline if we're being setup.
|
||||
if (!setup)
|
||||
needtoken(tTERM);
|
||||
|
||||
/* attach the array to the function symbol */
|
||||
if (numdim>0) {
|
||||
|
@ -1,3 +1,4 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
/* Pawn compiler - File input, preprocessing and lexical analysis functions
|
||||
*
|
||||
* Copyright (c) ITB CompuPhase, 1997-2006
|
||||
@ -28,6 +29,7 @@
|
||||
#include <math.h>
|
||||
#include "lstring.h"
|
||||
#include "sc.h"
|
||||
#include "tokenbuffer.h"
|
||||
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
|
||||
#include <sclinux.h>
|
||||
#endif
|
||||
@ -1900,24 +1902,41 @@ static const unsigned char *packedstring(const unsigned char *lptr,int flags)
|
||||
* Global references: lptr (altered)
|
||||
* fline (referred to only)
|
||||
* litidx (referred to only)
|
||||
* _lextok, _lexval, _lexstr
|
||||
* _pushed
|
||||
*/
|
||||
|
||||
static int _pushed;
|
||||
static int _lextok;
|
||||
static cell _lexval;
|
||||
static char _lexstr[sLINEMAX+1];
|
||||
static int _lexnewline;
|
||||
|
||||
// lex() is called recursively, which messes up the lookahead buffer. To get
|
||||
// around this we use two separate token buffers.
|
||||
token_buffer_t sNormalBuffer;
|
||||
token_buffer_t sPreprocessBuffer;
|
||||
token_buffer_t *sTokenBuffer;
|
||||
|
||||
static full_token_t *current_token()
|
||||
{
|
||||
return &sTokenBuffer->tokens[sTokenBuffer->cursor];
|
||||
}
|
||||
|
||||
static full_token_t *last_token()
|
||||
{
|
||||
assert(sTokenBuffer->depth > 0);
|
||||
int cursor = sTokenBuffer->cursor + 1;
|
||||
if (cursor == MAX_TOKEN_DEPTH)
|
||||
cursor = 0;
|
||||
return &sTokenBuffer->tokens[cursor];
|
||||
}
|
||||
|
||||
SC_FUNC void lexinit(void)
|
||||
{
|
||||
stkidx=0; /* index for pushstk() and popstk() */
|
||||
iflevel=0; /* preprocessor: nesting of "#if" is currently 0 */
|
||||
skiplevel=0; /* preprocessor: not currently skipping */
|
||||
icomment=0; /* currently not in a multiline comment */
|
||||
_pushed=FALSE; /* no token pushed back into lex */
|
||||
_lexnewline=FALSE;
|
||||
memset(&sNormalBuffer, 0, sizeof(sNormalBuffer));
|
||||
memset(&sPreprocessBuffer, 0, sizeof(sPreprocessBuffer));
|
||||
sTokenBuffer = &sNormalBuffer;
|
||||
}
|
||||
|
||||
char *sc_tokens[] = {
|
||||
@ -1936,24 +1955,49 @@ char *sc_tokens[] = {
|
||||
"-label-", "-string-"
|
||||
};
|
||||
|
||||
static full_token_t *next_token_ptr()
|
||||
{
|
||||
assert(sTokenBuffer->depth == 0);
|
||||
sTokenBuffer->num_tokens++;
|
||||
sTokenBuffer->cursor++;
|
||||
if (sTokenBuffer->cursor == MAX_TOKEN_DEPTH)
|
||||
sTokenBuffer->cursor = 0;
|
||||
|
||||
return current_token();
|
||||
}
|
||||
|
||||
static void preprocess_in_lex()
|
||||
{
|
||||
sTokenBuffer = &sPreprocessBuffer;
|
||||
preprocess();
|
||||
sTokenBuffer = &sNormalBuffer;
|
||||
}
|
||||
|
||||
SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
{
|
||||
int i,toolong,newline;
|
||||
char **tokptr;
|
||||
const unsigned char *starttoken;
|
||||
|
||||
if (_pushed) {
|
||||
_pushed=FALSE; /* reset "_pushed" flag */
|
||||
*lexvalue=_lexval;
|
||||
*lexsym=_lexstr;
|
||||
return _lextok;
|
||||
} /* if */
|
||||
if (sTokenBuffer->depth > 0) {
|
||||
sTokenBuffer->depth--;
|
||||
sTokenBuffer->cursor++;
|
||||
if (sTokenBuffer->cursor == MAX_TOKEN_DEPTH)
|
||||
sTokenBuffer->cursor = 0;
|
||||
*lexvalue = current_token()->value;
|
||||
*lexsym = current_token()->str;
|
||||
return current_token()->id;
|
||||
}
|
||||
|
||||
full_token_t *tok = next_token_ptr();
|
||||
tok->id = 0;
|
||||
tok->value = 0;
|
||||
tok->str[0] = '\0';
|
||||
tok->len = 0;
|
||||
|
||||
*lexvalue = tok->value;
|
||||
*lexsym = tok->str;
|
||||
|
||||
_lextok=0; /* preset all values */
|
||||
_lexval=0;
|
||||
_lexstr[0]='\0';
|
||||
*lexvalue=_lexval;
|
||||
*lexsym=_lexstr;
|
||||
_lexnewline=FALSE;
|
||||
if (!freading)
|
||||
return 0;
|
||||
@ -1961,11 +2005,11 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
newline= (lptr==pline); /* does lptr point to start of line buffer */
|
||||
while (*lptr<=' ') { /* delete leading white space */
|
||||
if (*lptr=='\0') {
|
||||
preprocess(); /* preprocess resets "lptr" */
|
||||
preprocess_in_lex();
|
||||
if (!freading)
|
||||
return 0;
|
||||
if (lptr==term_expr) /* special sequence to terminate a pending expression */
|
||||
return (_lextok=tENDEXPR);
|
||||
return (tok->id = tENDEXPR);
|
||||
_lexnewline=TRUE; /* set this after preprocess(), because
|
||||
* preprocess() calls lex() recursively */
|
||||
newline=TRUE;
|
||||
@ -1986,63 +2030,66 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
tokptr=sc_tokens;
|
||||
while (i<=tMIDDLE) { /* match multi-character operators */
|
||||
if (*lptr==**tokptr && match(*tokptr,FALSE)) {
|
||||
_lextok=i;
|
||||
tok->id = i;
|
||||
if (pc_docexpr) /* optionally concatenate to documentation string */
|
||||
insert_autolist(*tokptr);
|
||||
return _lextok;
|
||||
return tok->id;
|
||||
} /* if */
|
||||
i+=1;
|
||||
tokptr+=1;
|
||||
} /* while */
|
||||
while (i<=tLAST) { /* match reserved words and compiler directives */
|
||||
if (*lptr==**tokptr && match(*tokptr,TRUE)) {
|
||||
_lextok=i;
|
||||
tok->id = i;
|
||||
errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
|
||||
if (pc_docexpr) /* optionally concatenate to documentation string */
|
||||
insert_autolist(*tokptr);
|
||||
return _lextok;
|
||||
return tok->id;
|
||||
} /* if */
|
||||
i+=1;
|
||||
tokptr+=1;
|
||||
} /* while */
|
||||
|
||||
starttoken=lptr; /* save start pointer (for concatenating to documentation string) */
|
||||
if ((i=number(&_lexval,lptr))!=0) { /* number */
|
||||
_lextok=tNUMBER;
|
||||
*lexvalue=_lexval;
|
||||
if ((i=number(&tok->value, lptr))!=0) { /* number */
|
||||
tok->id = tNUMBER;
|
||||
*lexvalue = tok->value;
|
||||
lptr+=i;
|
||||
} else if ((i=ftoi(&_lexval,lptr))!=0) {
|
||||
_lextok=tRATIONAL;
|
||||
*lexvalue=_lexval;
|
||||
} else if ((i=ftoi(&tok->value, lptr))!=0) {
|
||||
tok->id = tRATIONAL;
|
||||
*lexvalue = tok->value;
|
||||
lptr+=i;
|
||||
} else if (alpha(*lptr)) { /* symbol or label */
|
||||
/* Note: only sNAMEMAX characters are significant. The compiler
|
||||
* generates a warning if a symbol exceeds this length.
|
||||
*/
|
||||
_lextok=tSYMBOL;
|
||||
tok->id = tSYMBOL;
|
||||
i=0;
|
||||
toolong=0;
|
||||
while (alphanum(*lptr)){
|
||||
_lexstr[i]=*lptr;
|
||||
tok->str[i]=*lptr;
|
||||
lptr+=1;
|
||||
if (i<sNAMEMAX)
|
||||
i+=1;
|
||||
else
|
||||
toolong=1;
|
||||
} /* while */
|
||||
_lexstr[i]='\0';
|
||||
if (toolong)
|
||||
error(200,_lexstr,sNAMEMAX); /* symbol too long, truncated to sNAMEMAX chars */
|
||||
if (_lexstr[0]==PUBLIC_CHAR && _lexstr[1]=='\0') {
|
||||
_lextok=PUBLIC_CHAR; /* '@' all alone is not a symbol, it is an operator */
|
||||
} else if (_lexstr[0]=='_' && _lexstr[1]=='\0') {
|
||||
_lextok='_'; /* '_' by itself is not a symbol, it is a placeholder */
|
||||
tok->str[i]='\0';
|
||||
tok->len = i;
|
||||
if (toolong) {
|
||||
/* symbol too long, truncated to sNAMEMAX chars */
|
||||
error(200, tok->str, sNAMEMAX);
|
||||
}
|
||||
if (tok->str[0]==PUBLIC_CHAR && tok->str[1]=='\0') {
|
||||
tok->id = PUBLIC_CHAR; /* '@' all alone is not a symbol, it is an operator */
|
||||
} else if (tok->str[0]=='_' && tok->str[1]=='\0') {
|
||||
tok->id = '_'; /* '_' by itself is not a symbol, it is a placeholder */
|
||||
} /* if */
|
||||
if (*lptr==':' && *(lptr+1)!=':' && _lextok!=PUBLIC_CHAR) {
|
||||
if (*lptr==':' && *(lptr+1)!=':' && tok->id != PUBLIC_CHAR) {
|
||||
if (sc_allowtags) {
|
||||
_lextok=tLABEL; /* it wasn't a normal symbol, it was a label/tagname */
|
||||
tok->id = tLABEL; /* it wasn't a normal symbol, it was a label/tagname */
|
||||
lptr+=1; /* skip colon */
|
||||
} else if (find_constval(&tagname_tab,_lexstr,0)!=NULL) {
|
||||
} else if (find_constval(&tagname_tab,tok->str,0)!=NULL) {
|
||||
/* this looks like a tag override (because a tag with this name
|
||||
* exists), but tags are not allowed right now, so it is probably an
|
||||
* error
|
||||
@ -2061,9 +2108,9 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
{
|
||||
int stringflags,segmentflags;
|
||||
char *cat;
|
||||
_lextok=tSTRING;
|
||||
*lexvalue=_lexval=litidx;
|
||||
_lexstr[0]='\0';
|
||||
tok->id = tSTRING;
|
||||
*lexvalue = tok->value = litidx;
|
||||
tok->str[0]='\0';
|
||||
stringflags=-1; /* to mark the first segment */
|
||||
for ( ;; ) {
|
||||
if(*lptr=='!')
|
||||
@ -2082,9 +2129,9 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
stringflags=segmentflags;
|
||||
else if (stringflags!=segmentflags)
|
||||
error(238); /* mixing packed/unpacked/raw strings in concatenation */
|
||||
cat=strchr(_lexstr,'\0');
|
||||
cat=strchr(tok->str,'\0');
|
||||
assert(cat!=NULL);
|
||||
while (*lptr!='\"' && *lptr!='\0' && (cat-_lexstr)<sLINEMAX) {
|
||||
while (*lptr!='\"' && *lptr!='\0' && (cat-tok->str)<sLINEMAX) {
|
||||
if (*lptr!='\a') { /* ignore '\a' (which was inserted at a line concatenation) */
|
||||
*cat++=*lptr;
|
||||
if (*lptr==sc_ctrlchar && *(lptr+1)!='\0')
|
||||
@ -2093,6 +2140,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
lptr++;
|
||||
} /* while */
|
||||
*cat='\0'; /* terminate string */
|
||||
tok->len = (size_t)(cat - tok->str);
|
||||
if (*lptr=='\"')
|
||||
lptr+=1; /* skip final quote */
|
||||
else
|
||||
@ -2103,7 +2151,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
/* there is an ellipses, go on parsing (this time with full preprocessing) */
|
||||
while (*lptr<=' ') {
|
||||
if (*lptr=='\0') {
|
||||
preprocess(); /* preprocess resets "lptr" */
|
||||
preprocess_in_lex();
|
||||
assert(freading && lptr!=term_expr);
|
||||
} else {
|
||||
lptr++;
|
||||
@ -2113,7 +2161,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
lptr+=3;
|
||||
while (*lptr<=' ') {
|
||||
if (*lptr=='\0') {
|
||||
preprocess(); /* preprocess resets "lptr" */
|
||||
preprocess_in_lex();
|
||||
assert(freading && lptr!=term_expr);
|
||||
} else {
|
||||
lptr++;
|
||||
@ -2135,23 +2183,23 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
if (sc_packstr)
|
||||
stringflags ^= ISPACKED; /* invert packed/unpacked parameters */
|
||||
if ((stringflags & ISPACKED)!=0)
|
||||
packedstring((unsigned char *)_lexstr,stringflags);
|
||||
packedstring((unsigned char *)tok->str,stringflags);
|
||||
else
|
||||
unpackedstring((unsigned char *)_lexstr,stringflags);
|
||||
unpackedstring((unsigned char *)tok->str,stringflags);
|
||||
} else if (*lptr=='\'') { /* character literal */
|
||||
lptr+=1; /* skip quote */
|
||||
_lextok=tNUMBER;
|
||||
*lexvalue=_lexval=litchar(&lptr,UTF8MODE);
|
||||
tok->id = tNUMBER;
|
||||
*lexvalue = tok->value = litchar(&lptr,UTF8MODE);
|
||||
if (*lptr=='\'')
|
||||
lptr+=1; /* skip final quote */
|
||||
else
|
||||
error(27); /* invalid character constant (must be one character) */
|
||||
} else if (*lptr==';') { /* semicolumn resets "error" flag */
|
||||
_lextok=';';
|
||||
tok->id = ';';
|
||||
lptr+=1;
|
||||
errorset(sRESET,0); /* reset error flag (clear the "panic mode")*/
|
||||
} else {
|
||||
_lextok=*lptr; /* if every match fails, return the character */
|
||||
tok->id = *lptr; /* if every match fails, return the character */
|
||||
lptr+=1; /* increase the "lptr" pointer */
|
||||
} /* if */
|
||||
|
||||
@ -2163,7 +2211,7 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
free(docstr);
|
||||
} /* if */
|
||||
} /* if */
|
||||
return _lextok;
|
||||
return tok->id;
|
||||
}
|
||||
|
||||
/* lexpush
|
||||
@ -2180,8 +2228,14 @@ SC_FUNC int lex(cell *lexvalue,char **lexsym)
|
||||
*/
|
||||
SC_FUNC void lexpush(void)
|
||||
{
|
||||
assert(_pushed==FALSE);
|
||||
_pushed=TRUE;
|
||||
assert(sTokenBuffer->depth < MAX_TOKEN_DEPTH);
|
||||
assert(sTokenBuffer->depth < 1);
|
||||
sTokenBuffer->depth++;
|
||||
if (sTokenBuffer->cursor == 0)
|
||||
sTokenBuffer->cursor = MAX_TOKEN_DEPTH - 1;
|
||||
else
|
||||
sTokenBuffer->cursor--;
|
||||
assert(sTokenBuffer->depth <= sTokenBuffer->num_tokens);
|
||||
}
|
||||
|
||||
/* lexclr
|
||||
@ -2192,7 +2246,7 @@ SC_FUNC void lexpush(void)
|
||||
*/
|
||||
SC_FUNC void lexclr(int clreol)
|
||||
{
|
||||
_pushed=FALSE;
|
||||
sTokenBuffer->depth = 0;
|
||||
if (clreol) {
|
||||
lptr=(unsigned char*)strchr((char*)pline,'\0');
|
||||
assert(lptr!=NULL);
|
||||
@ -2243,10 +2297,10 @@ SC_FUNC int tokeninfo(cell *val,char **str)
|
||||
/* if the token was pushed back, tokeninfo() returns the token and
|
||||
* parameters of the *next* token, not of the *current* token.
|
||||
*/
|
||||
assert(!_pushed);
|
||||
*val=_lexval;
|
||||
*str=_lexstr;
|
||||
return _lextok;
|
||||
assert(sTokenBuffer->depth == 0);
|
||||
*val = current_token()->value;
|
||||
*str = current_token()->str;
|
||||
return current_token()->id;
|
||||
}
|
||||
|
||||
/* needtoken
|
||||
@ -2255,8 +2309,6 @@ SC_FUNC int tokeninfo(cell *val,char **str)
|
||||
* it isn't there (and returns 0/FALSE in that case). Like function matchtoken(),
|
||||
* this function returns 1 for "token found" and 2 for "statement termination
|
||||
* token" found; see function matchtoken() for details.
|
||||
*
|
||||
* Global references: _lextok;
|
||||
*/
|
||||
SC_FUNC int needtoken(int token)
|
||||
{
|
||||
@ -2267,17 +2319,17 @@ SC_FUNC int needtoken(int token)
|
||||
return t;
|
||||
} else {
|
||||
/* token already pushed back */
|
||||
assert(_pushed);
|
||||
assert(sTokenBuffer->depth > 0);
|
||||
if (token<256)
|
||||
sprintf(s1,"%c",(char)token); /* single character token */
|
||||
else
|
||||
strcpy(s1,sc_tokens[token-tFIRST]); /* multi-character symbol */
|
||||
if (!freading)
|
||||
strcpy(s2,"-end of file-");
|
||||
else if (_lextok<256)
|
||||
sprintf(s2,"%c",(char)_lextok);
|
||||
else if (current_token()->id < 256)
|
||||
sprintf(s2,"%c",(char)current_token()->id);
|
||||
else
|
||||
strcpy(s2,sc_tokens[_lextok-tFIRST]);
|
||||
strcpy(s2, sc_tokens[current_token()->id - tFIRST]);
|
||||
error(1,s1,s2); /* expected ..., but found ... */
|
||||
return FALSE;
|
||||
} /* if */
|
||||
@ -3057,3 +3109,23 @@ SC_FUNC int expecttoken(int id, token_t *tok)
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SC_FUNC int matchsymbol(token_ident_t *ident)
|
||||
{
|
||||
if (lextok(&ident->tok) != tSYMBOL) {
|
||||
lexpush();
|
||||
return FALSE;
|
||||
}
|
||||
strcpy(ident->name, ident->tok.str);
|
||||
ident->tok.str = ident->name;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
SC_FUNC int needsymbol(token_ident_t *ident)
|
||||
{
|
||||
if (!expecttoken(tSYMBOL, &ident->tok))
|
||||
return FALSE;
|
||||
strcpy(ident->name, ident->tok.str);
|
||||
ident->tok.str = ident->name;
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ static char *errmsg[] = {
|
||||
/*096*/ "could not find member \"%s\" in struct \"%s\"\n",
|
||||
/*097*/ "symbol \"%s\" does not have a matching type\n",
|
||||
/*098*/ "type \"%s\" should be \"%s\" in new-style declarations\n",
|
||||
/*099*/ "destructors cannot return values\n",
|
||||
/*099*/ "%s should not have an explicit return type\n",
|
||||
/*100*/ "function prototypes do not match\n",
|
||||
/*101*/ "specify either all dimensions or only the last dimension\n",
|
||||
/*102*/ "cannot find %s %s\n",
|
||||
@ -157,7 +157,7 @@ static char *errmsg[] = {
|
||||
/*111*/ "expected identifier - did you forget a type?\n",
|
||||
/*112*/ "constructor function must return tag %s\n",
|
||||
/*113*/ "cannot define constructor for \"%s\"; already exists as a %s\n",
|
||||
/*114*/ "destructor must have the same name as %s \"%s\"\n",
|
||||
/*114*/ "%s must have the same name as %s \"%s\"\n",
|
||||
/*115*/ "cannot use delete, %s %s has no destructor\n",
|
||||
/*116*/ "no methodmap or class was found for %s\n",
|
||||
/*117*/ "no destructor was found for %s %s\n",
|
||||
|
@ -79,10 +79,6 @@ typedef enum LayoutSpec_t
|
||||
Layout_Class
|
||||
} LayoutSpec;
|
||||
|
||||
// The method name buffer is larger since we can include our parent class's
|
||||
// name, a "." to separate it, and a "~" for constructors.
|
||||
#define METHOD_NAMEMAX sNAMEMAX * 2 + 2
|
||||
|
||||
typedef struct methodmap_method_s
|
||||
{
|
||||
char name[METHOD_NAMEMAX + 1];
|
||||
|
@ -1 +1 @@
|
||||
methodmap Handle has no destructor; delete cannot be used
|
||||
cannot use delete, methodmap Handle has no destructor
|
||||
|
@ -1 +1 @@
|
||||
destructors cannot return values
|
||||
destructor should not have an explicit return type
|
||||
|
28
sourcepawn/compiler/tokenbuffer.h
Normal file
28
sourcepawn/compiler/tokenbuffer.h
Normal file
@ -0,0 +1,28 @@
|
||||
// vim: set ts=8 sts=2 sw=2 tw=99 et:
|
||||
#ifndef _sourcepawn_compiler_token_stream_h_
|
||||
#define _sourcepawn_compiler_token_stream_h_
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
int value;
|
||||
char str[sLINEMAX + 1];
|
||||
size_t len;
|
||||
} full_token_t;
|
||||
|
||||
#define MAX_TOKEN_DEPTH 4
|
||||
|
||||
typedef struct {
|
||||
// Total number of tokens parsed.
|
||||
int num_tokens;
|
||||
|
||||
// Number of tokens that we've rewound back to.
|
||||
int depth;
|
||||
|
||||
// Most recently fetched token.
|
||||
int cursor;
|
||||
|
||||
// Circular token buffer.
|
||||
full_token_t tokens[MAX_TOKEN_DEPTH];
|
||||
} token_buffer_t;
|
||||
|
||||
#endif // _sourcepawn_compiler_token_stream_h_
|
Loading…
Reference in New Issue
Block a user