mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-02-07 06:51:10 +00:00
Allow string concatenation in the parser as well, for now only for immediate strings and __FUNC__, maybe later -fpermissive or somethign could allow it on const-delcared string variables
This commit is contained in:
parent
8ffdfbfd97
commit
66305c676a
6 changed files with 38 additions and 3 deletions
1
ast.c
1
ast.c
|
@ -316,6 +316,7 @@ ast_value* ast_value_new(lex_ctx ctx, const char *name, int t)
|
||||||
self->isfield = false;
|
self->isfield = false;
|
||||||
self->cvq = CV_NONE;
|
self->cvq = CV_NONE;
|
||||||
self->hasvalue = false;
|
self->hasvalue = false;
|
||||||
|
self->isimm = false;
|
||||||
self->uses = 0;
|
self->uses = 0;
|
||||||
memset(&self->constval, 0, sizeof(self->constval));
|
memset(&self->constval, 0, sizeof(self->constval));
|
||||||
|
|
||||||
|
|
1
ast.h
1
ast.h
|
@ -177,6 +177,7 @@ struct ast_value_s
|
||||||
|
|
||||||
int cvq; /* const/var qualifier */
|
int cvq; /* const/var qualifier */
|
||||||
bool isfield; /* this declares a field */
|
bool isfield; /* this declares a field */
|
||||||
|
bool isimm; /* an immediate, not just const */
|
||||||
bool hasvalue;
|
bool hasvalue;
|
||||||
union {
|
union {
|
||||||
double vfloat;
|
double vfloat;
|
||||||
|
|
26
parser.c
26
parser.c
|
@ -217,6 +217,7 @@ static ast_value* parser_const_float(parser_t *parser, double d)
|
||||||
out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT);
|
out = ast_value_new(ctx, "#IMMEDIATE", TYPE_FLOAT);
|
||||||
out->cvq = CV_CONST;
|
out->cvq = CV_CONST;
|
||||||
out->hasvalue = true;
|
out->hasvalue = true;
|
||||||
|
out->isimm = true;
|
||||||
out->constval.vfloat = d;
|
out->constval.vfloat = d;
|
||||||
vec_push(parser->imm_float, out);
|
vec_push(parser->imm_float, out);
|
||||||
return out;
|
return out;
|
||||||
|
@ -279,6 +280,7 @@ static ast_value* parser_const_string(parser_t *parser, const char *str, bool do
|
||||||
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
|
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_STRING);
|
||||||
out->cvq = CV_CONST;
|
out->cvq = CV_CONST;
|
||||||
out->hasvalue = true;
|
out->hasvalue = true;
|
||||||
|
out->isimm = true;
|
||||||
out->constval.vstring = parser_strdup(str);
|
out->constval.vstring = parser_strdup(str);
|
||||||
vec_push(parser->imm_string, out);
|
vec_push(parser->imm_string, out);
|
||||||
util_htseth(parser->ht_imm_string, str, hash, out);
|
util_htseth(parser->ht_imm_string, str, hash, out);
|
||||||
|
@ -296,6 +298,7 @@ static ast_value* parser_const_vector(parser_t *parser, vector v)
|
||||||
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR);
|
out = ast_value_new(parser_ctx(parser), "#IMMEDIATE", TYPE_VECTOR);
|
||||||
out->cvq = CV_CONST;
|
out->cvq = CV_CONST;
|
||||||
out->hasvalue = true;
|
out->hasvalue = true;
|
||||||
|
out->isimm = true;
|
||||||
out->constval.vvec = v;
|
out->constval.vvec = v;
|
||||||
vec_push(parser->imm_vector, out);
|
vec_push(parser->imm_vector, out);
|
||||||
return out;
|
return out;
|
||||||
|
@ -2182,8 +2185,27 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
|
||||||
wantop = true;
|
wantop = true;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parseerror(parser, "expected operator or end of statement");
|
/* in this case we might want to allow constant string concatenation */
|
||||||
goto onerr;
|
bool concatenated = false;
|
||||||
|
if (parser->tok == TOKEN_STRINGCONST && vec_size(sy.out)) {
|
||||||
|
ast_expression *lexpr = vec_last(sy.out).out;
|
||||||
|
if (ast_istype(lexpr, ast_value)) {
|
||||||
|
ast_value *last = (ast_value*)lexpr;
|
||||||
|
if (last->isimm == true && last->cvq == CV_CONST &&
|
||||||
|
last->hasvalue && last->expression.vtype == TYPE_STRING)
|
||||||
|
{
|
||||||
|
char *newstr = NULL;
|
||||||
|
util_asprintf(&newstr, "%s%s", last->constval.vstring, parser_tokval(parser));
|
||||||
|
vec_last(sy.out).out = (ast_expression*)parser_const_string(parser, newstr, false);
|
||||||
|
mem_d(newstr);
|
||||||
|
concatenated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!concatenated) {
|
||||||
|
parseerror(parser, "expected operator or end of statement");
|
||||||
|
goto onerr;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!parser_next(parser)) {
|
if (!parser_next(parser)) {
|
||||||
|
|
|
@ -1,3 +1,9 @@
|
||||||
void main() {
|
void main() {
|
||||||
|
#ifdef SIMPLE
|
||||||
print(__FUNC__, "\n");
|
print(__FUNC__, "\n");
|
||||||
|
#elifdef CONCATENATED
|
||||||
|
print(__FUNC__ "\n");
|
||||||
|
#else
|
||||||
|
# error this is wrong
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
I: predef_func.qc
|
I: predef_func.qc
|
||||||
D: simple __FUNC__ case
|
D: simple __FUNC__ case
|
||||||
T: -execute
|
T: -execute
|
||||||
C: -std=fte -fftepp-predefs
|
C: -std=fteqcc -DSIMPLE
|
||||||
M: main
|
M: main
|
||||||
|
|
5
tests/predef_func_concat.tmpl
Normal file
5
tests/predef_func_concat.tmpl
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
I: predef_func.qc
|
||||||
|
D: concatenated __FUNC__ case
|
||||||
|
T: -execute
|
||||||
|
C: -std=fteqcc -DCONCATENATED
|
||||||
|
M: main
|
Loading…
Reference in a new issue