mirror of
https://github.com/DarkPlacesEngine/gmqcc.git
synced 2025-03-22 02:31:28 +00:00
Added '...(idx,type)' to access varargs
This commit is contained in:
parent
cd543aad5e
commit
e149551744
2 changed files with 140 additions and 23 deletions
50
lexer.c
50
lexer.c
|
@ -1244,31 +1244,37 @@ int lex_do(lex_file *lex)
|
|||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ch == '.')
|
||||
{
|
||||
lex_tokench(lex, ch);
|
||||
/* peak ahead once */
|
||||
nextch = lex_getch(lex);
|
||||
if (nextch != '.') {
|
||||
lex_ungetch(lex, nextch);
|
||||
lex_endtoken(lex);
|
||||
return (lex->tok.ttype = ch);
|
||||
}
|
||||
/* peak ahead again */
|
||||
nextch = lex_getch(lex);
|
||||
if (nextch != '.') {
|
||||
lex_ungetch(lex, nextch);
|
||||
lex_ungetch(lex, '.');
|
||||
lex_endtoken(lex);
|
||||
return (lex->tok.ttype = ch);
|
||||
}
|
||||
/* fill the token to be "..." */
|
||||
lex_tokench(lex, ch);
|
||||
lex_tokench(lex, ch);
|
||||
if (ch == '.')
|
||||
{
|
||||
lex_tokench(lex, ch);
|
||||
/* peak ahead once */
|
||||
nextch = lex_getch(lex);
|
||||
if (nextch != '.') {
|
||||
lex_ungetch(lex, nextch);
|
||||
lex_endtoken(lex);
|
||||
return (lex->tok.ttype = TOKEN_DOTS);
|
||||
if (lex->flags.noops)
|
||||
return (lex->tok.ttype = ch);
|
||||
else
|
||||
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||
}
|
||||
/* peak ahead again */
|
||||
nextch = lex_getch(lex);
|
||||
if (nextch != '.') {
|
||||
lex_ungetch(lex, nextch);
|
||||
lex_ungetch(lex, '.');
|
||||
lex_endtoken(lex);
|
||||
if (lex->flags.noops)
|
||||
return (lex->tok.ttype = ch);
|
||||
else
|
||||
return (lex->tok.ttype = TOKEN_OPERATOR);
|
||||
}
|
||||
/* fill the token to be "..." */
|
||||
lex_tokench(lex, ch);
|
||||
lex_tokench(lex, ch);
|
||||
lex_endtoken(lex);
|
||||
return (lex->tok.ttype = TOKEN_DOTS);
|
||||
}
|
||||
|
||||
if (ch == ',' || ch == '.') {
|
||||
|
|
113
parser.c
113
parser.c
|
@ -105,7 +105,7 @@ typedef struct {
|
|||
size_t max_param_count;
|
||||
} parser_t;
|
||||
|
||||
static const ast_expression *intrinsic_debug_typestring = (ast_expression*)0x10;
|
||||
static ast_expression * const intrinsic_debug_typestring = (ast_expression*)0x1;
|
||||
|
||||
static void parser_enterblock(parser_t *parser);
|
||||
static bool parser_leaveblock(parser_t *parser);
|
||||
|
@ -121,6 +121,7 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
|
|||
static ast_expression* parse_expression(parser_t *parser, bool stopatcomma, bool with_labels);
|
||||
static ast_value* parser_create_array_setter_proto(parser_t *parser, ast_value *array, const char *funcname);
|
||||
static ast_value* parser_create_array_getter_proto(parser_t *parser, ast_value *array, const ast_expression *elemtype, const char *funcname);
|
||||
static ast_value *parse_typename(parser_t *parser, ast_value **storebase, ast_value *cached_typedef);
|
||||
|
||||
static void parseerror(parser_t *parser, const char *fmt, ...)
|
||||
{
|
||||
|
@ -1555,6 +1556,102 @@ static void parser_reclassify_token(parser_t *parser)
|
|||
}
|
||||
}
|
||||
|
||||
static ast_expression* parse_vararg_do(parser_t *parser)
|
||||
{
|
||||
ast_expression *idx, *out;
|
||||
ast_value *typevar;
|
||||
ast_value *funtype = parser->function->vtype;
|
||||
|
||||
lex_ctx ctx = parser_ctx(parser);
|
||||
|
||||
if (!parser_next(parser) || parser->tok != '(') {
|
||||
parseerror(parser, "expected parameter index and type in parenthesis");
|
||||
return NULL;
|
||||
}
|
||||
if (!parser_next(parser)) {
|
||||
parseerror(parser, "error parsing parameter index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
idx = parse_expression_leave(parser, true, false, false);
|
||||
if (!idx)
|
||||
return NULL;
|
||||
|
||||
if (parser->tok != ',') {
|
||||
ast_unref(idx);
|
||||
parseerror(parser, "expected comma after parameter index");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!parser_next(parser) || (parser->tok != TOKEN_IDENT && parser->tok != TOKEN_TYPENAME)) {
|
||||
ast_unref(idx);
|
||||
parseerror(parser, "expected typename for vararg");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
typevar = parse_typename(parser, NULL, NULL);
|
||||
if (!typevar) {
|
||||
ast_unref(idx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parser->tok != ')') {
|
||||
ast_unref(idx);
|
||||
ast_delete(typevar);
|
||||
parseerror(parser, "expected closing paren");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (!parser_next(parser)) {
|
||||
ast_unref(idx);
|
||||
ast_delete(typevar);
|
||||
parseerror(parser, "parse error after vararg");
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!parser->function->varargs) {
|
||||
ast_unref(idx);
|
||||
ast_delete(typevar);
|
||||
parseerror(parser, "function has no variable argument list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (funtype->expression.varparam &&
|
||||
!ast_compare_type((ast_expression*)typevar, (ast_expression*)funtype->expression.varparam))
|
||||
{
|
||||
char ty1[1024];
|
||||
char ty2[1024];
|
||||
ast_type_to_string((ast_expression*)typevar, ty1, sizeof(ty1));
|
||||
ast_type_to_string((ast_expression*)funtype->expression.varparam, ty2, sizeof(ty2));
|
||||
compile_error(ast_ctx(typevar),
|
||||
"function was declared to take varargs of type `%s`, requested type is: %s",
|
||||
ty2, ty1);
|
||||
}
|
||||
|
||||
out = (ast_expression*)ast_array_index_new(ctx, (ast_expression*)(parser->function->varargs), idx);
|
||||
ast_type_adopt(out, typevar);
|
||||
ast_delete(typevar);
|
||||
return out;
|
||||
}
|
||||
|
||||
static ast_expression* parse_vararg(parser_t *parser)
|
||||
{
|
||||
bool old_noops = parser->lex->flags.noops;
|
||||
enum parser_pot *old_pot = parser->pot;
|
||||
|
||||
ast_expression *out;
|
||||
|
||||
parser->pot = NULL;
|
||||
parser->lex->flags.noops = true;
|
||||
out = parse_vararg_do(parser);
|
||||
|
||||
parser->pot = old_pot;
|
||||
parser->lex->flags.noops = old_noops;
|
||||
return out;
|
||||
}
|
||||
|
||||
static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma, bool truthvalue, bool with_labels)
|
||||
{
|
||||
ast_expression *expr = NULL;
|
||||
|
@ -1613,6 +1710,20 @@ static ast_expression* parse_expression_leave(parser_t *parser, bool stopatcomma
|
|||
goto onerr;
|
||||
}
|
||||
}
|
||||
else if (parser->tok == TOKEN_DOTS)
|
||||
{
|
||||
ast_expression *va;
|
||||
if (wantop) {
|
||||
parseerror(parser, "expected operator or end of statement");
|
||||
goto onerr;
|
||||
}
|
||||
wantop = true;
|
||||
va = parse_vararg(parser);
|
||||
if (!va)
|
||||
goto onerr;
|
||||
vec_push(sy.out, syexp(parser_ctx(parser), va));
|
||||
DEBUGSHUNTDO(con_out("push `...`\n"));
|
||||
}
|
||||
else if (parser->tok == TOKEN_IDENT)
|
||||
{
|
||||
const char *ctoken = parser_tokval(parser);
|
||||
|
|
Loading…
Reference in a new issue